If you port Android to your system or develop native libraries using NDK, you have a experience to see crash dump on logcat. That shows CPU registers and stack dumps of the process caused memory fault or other exception.
Who and how does the crash dump generate?
(Japanese version)
Example of crash dump
This is a log when the exception of SIGBUS (bus error) occurred on the page written before (in Japanese).
I/DEBUG ( 543): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG ( 543): Build fingerprint: 'generic/generic/generic/:Donut/Donut/eng.koba .20090827.140821:eng/test-keys' I/DEBUG ( 543): pid: 590, tid: 590 >>> zygote <<< I/DEBUG ( 543): signal 7 (SIGBUS), fault addr 00000000 I/DEBUG ( 543): r0 00001412 r1 4104bbe4 r2 4104bbdc r3 4104bbe4 I/DEBUG ( 543): r4 41748086 r5 4104bb94 r6 bef614e8 r7 ad00e640 I/DEBUG ( 543): r8 000012ad r9 4104bbdc 10 4104bb84 fp 00000000 I/DEBUG ( 543): ip 000000ad sp bef614a8 lr ad01071c pc ad01119c cpsr 20000010 I/DEBUG ( 543): #00 pc 0001119c /system/lib/libdvm.so I/DEBUG ( 543): #01 pc 00017d90 /system/lib/libdvm.so I/DEBUG ( 543): #02 pc 000177d4 /system/lib/libdvm.so I/DEBUG ( 543): #03 pc 00052974 /system/lib/libdvm.so I/DEBUG ( 543): #04 pc 00052992 /system/lib/libdvm.so
debuggerd
It is a process named debuggerd that has actually given this log.
system/core/debuggerd
It is started from init at boot time, and this process generates UNIX domain socket “Android:debuggerd” and waits to be connected.
Because tid (thread ID obtained by the gettid system call) is supposed to be written in the socket when connected, the ptrace system call is used and attached for the tid.
In a word, the process that caused the exception and dropped to the state of the neardeath, is put into the halt condition by debuggerd. In addition, the register and the memory of the process are read by the ptrace system call and it dumps it to the log.
system/core/debuggerd/debuggerd.c
I think this is good example to learn how to use the ptrace system call.
dynamic linker
Well, What part is there connecting it with socket “Android:debuggerd” where debuggerd opens? and how?
The source in the part is here.
bionic/linker/debugger.c
void debugger_init()
{
signal(SIGILL, debugger_signal_handler);
signal(SIGABRT, debugger_signal_handler);
signal(SIGBUS, debugger_signal_handler);
signal(SIGFPE, debugger_signal_handler);
signal(SIGSEGV, debugger_signal_handler);
signal(SIGSTKFLT, debugger_signal_handler);
signal(SIGPIPE, debugger_signal_handler);
}
This is the last part of bionic/linker/debugger.c. The handler of these signal is registered here. It connects it with socket “Android:debuggerd” where debuggerd opens by debugger_signal_handler.
In fact, this source is a part of the dynamic linker of bionic.
At first a dynamic linker works before main function is carried out. Then the dynamic linker maps dynamic link libraries on memory. At the time, it calls this function(debugger_init).
In other words, all programs which is dynamic linked have functionality to connect to debuggerd and generate crash dump, automatically and implicitly.
I think that this is a very good and smart way.
Pingback: How to read crash dump of Android « Koba's blog
Thank you for this overview, it’s inspiring.
Having read it, it is only logical to debug init-started programs
by inserting getpid()+kill(, SIGSEGV) at the right place.
In such case, this debugger is so useful.
http://www.kmckk.co.jp/eng/jet_index.html
(Actually this is our product.)
Not only init-started programs, this debugger can put break point on main() of init itself.