Sunday, June 19, 2011

Removing conditional macros when tracing C/C++ code with Vim

Working with source code buried in conditional macros(#if, #ifdef, #ifndef, ...) is sometimes really annoying, especially when we are trying to get the whole picture of what it does instead of every details in it.

Simply expanding the conditionals with gcc -E usually doesn't help in this situation. Expansion of macros as well as the header files even makes the picture muddier. The unifdef(1) utility come in handy for this.
$ man unifdef(1)

UNIFDEF(1) Programmer's Manual UNIFDEF(1) NAME unifdef, unifdefall — remove preprocessor conditionals from code SYNOPSIS unifdef [-bBcdeKknsStV] [-Ipath] [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [-o outfile] [infile] unifdefall [-Ipath] ... file
Apply it as vim filter command repeatedly and incrementally until you get your picture clear enough.
 vim /tmp/dummy.c

#if (LOG_LEVEL > 3) #define log printk #else #define log(...) #endif #ifdef ENABLE_FOO void foo_xxx() { ... } #endif #ifdef ENABLE_BAR void bar_yyy() { ... } #endif
:%! unifdef -k -UENABLE_FOO
 vim /tmp/dummy.c

#if (LOG_LEVEL > 3) #define log printk #else #define log(...) #endif #ifdef ENABLE_BAR void bar_yyy() { ... } #endif
:%! unifdef -k -DENABLE_BAR -DLOG_LEVEL=4
 vim /tmp/dummy.c

#define log printk void bar_yyy() { ... }

Note that:
By default, unifdef ignores #if and #elif lines with constant expressions; it can be told to process them by specifying the -k flag on the command line.

Thursday, April 14, 2011

[tip] Transform file or directory names during the extraction of tarball

Suppose we have a tarball containing a directory structure of root filesystem for an embedded device. ex:
  rootfs/
  rootfs/init.rc
  rootfs/dev/...
  rootfs/etc/...
  rootfs/usr/...
We'd like to extract the contained directory structure under the rootfs/ directly into the root directory of a mounted partition, for example, /mnt/sdb1. Otherwise, we will have to deal with the relocation of the device node files(rootfs/dev/...), which is a little bit cumbersome.

To skip the containing folder 'rootfs/', we can specify the --transform option during the extracting process,
tar xvfj ~/rootfs.tar.bz2 -C /mnt/sdb1/ --transform 's/rootfs//'
and yield the following extracted directory structure.
  /mnt/sdb1/
  /mnt/sdb1/init.rc
  /mnt/sdb1/dev/...
  /mnt/sdb1/etc/...
  /mnt/sdb1/usr/...

Friday, April 08, 2011

[setting] Error occurred while mounting usb stick via the device notifier

[reference] https://bbs.archlinux.org/viewtopic.php?pid=909650 draugdel @ 2011-03-26 10:08:27
Error occurred while mounting usb stick via the device notifier
org.freedesktop.UDisks.Error.PermissionDenied: Not Authorized
Sol: Add a file named with .pkla suffix in /etc/polkit-1/localauthority/50-local.d/
ex:
/etc/polkit-1/localauthority/50-local.d/mount.pkla

and stuff the following contents into it
[Mount system internal media for group storage]
Identity=unix-group:storage
Action=org.freedesktop.udisks.filesystem-*
ResultAny=yes
ResultInactive=yes
ResultActive=yes

Sunday, February 06, 2011

Zygote Initialization Flow

The code flow of zygote initialization is rather complicated, especially when the JNIs are extensively involved. My IDE often fails to cross reference between them. So I log the code flow here and the location they are defined as well.

Sunday, December 05, 2010

Loopers, MessageQueues, and Handlers (Part1)

Loopers, MessageQueues, and Handlers provide one of the facilities for processes and threads to communicate with each other. They are also one of the basis to implement the Services of Android framework. The relationship between these classes and how they interact with each other are not so easy to be seen through at the first glance. And that's why there are so many articles talking about them. This post does not intend to show they are used, but focus on the relationship between them.

Sunday, June 20, 2010

Log of instructions for JNI


Reference:
Edit HelloWorld.java
HelloWorld.java

class HelloWorld { private native void print(); public static void main(String[] args) { new HelloWorld().print(); } static { System.loadLibrary("HelloWorld"); } }
Compile the JAVA class -- HelloWorld.class
  $ javac HelloWorld.java
Generate the NATIVE header file -- HelloWorld.h
  $ javah -jni HelloWorld
HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloWorld */ #ifndef _Included_HelloWorld #define _Included_HelloWorld #ifdef __cplusplus extern "C" { #endif /* * Class: HelloWorld * Method: print * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
Implement the NATIVE method -- HelloWorld.c
HelloWorld.c

#include <stdio.h> #include <jni.h> #include "HelloWorld.h" JNIEXPORT void JNICALL Java_HelloWorld_print (JNIEnv *env, jobject obj) { printf("Hello World\n"); return; }
Compile the NATIVE source code and build the NATIVE library
  $ gcc -c -fPIC HelloWorld.c -I$JAVA_HOME/include -I$JAVA_HOME/include/linux
  $ gcc -shared HelloWorld.o -o libHelloWorld.so
Add "current" directory to the search path of share libraries
  $ export LD_LIBRARY_PATH=.
Run the HelloWorld JAVA program
  $ java HelloWorld

Hello World