Android NDK tombstone分析工具
在Andoird Native库发生异常的时候,Linux会发生不同级别的sig,来结构相关进程的运行,同时会产生tombstone trace文件用于记录发生崩溃寄存器和堆栈的状态。
这里面的涉及的知识点很多,但该文主要是介绍一下这种情况debug的工具stack.py。
1,keypoint
a,Android sig/进程间通讯
b,Linux 内存管理/ 用户空间和内核空间
c,Arm汇编
d,Android库的链接Linker
2,tombstone的结构大概如下
1 | *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** |
2 | Build fingerprint: 'MBX/k200/k200:4.4.2/KOT49H/20140717:user/test-keys' |
3 | Revision: '11' |
4 | pid: 455, tid: 486, name: InputDispatcher >>> system_server <<< |
5 | signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00290238 |
6 | r0 00290008 r1 00000230 r2 00000003 r3 00290008 |
7 | r4 64a42042 r5 677d9eac r6 677f16e8 r7 000003f2 |
8 | r8 41656d40 r9 00000002 sl 00000000 fp 68088ca0 |
9 | ip 000000f2 sp 68088b38 lr 00000000 pc 4165a9d8 cpsr 200b0010 |
10 | d0 677d9fd84b000000 d1 626e402800010000 |
11 | d2 002e00640069006f d3 00650074006e0069 |
12 | d4 006c0061006e0072 d5 006c006f0070002e |
13 | d6 002e007900630069 d7 00790065004b0049 |
14 | d8 0000000000000000 d9 0000000000000000 |
15 | d10 0000000000000000 d11 0000000000000000 |
16 | d12 0000000000000000 d13 0000000000000000 |
17 | d14 0000000000000000 d15 0000000000000000 |
18 | d16 3d5e000000000000 d17 3d5e000000000000 |
19 | d18 408f400000000000 d19 41168cb340000000 |
20 | d20 4020f5c28f5c28f6 d21 408a800000000000 |
21 | d22 40b4c3e100000000 d23 3ff0000000000000 |
22 | d24 41f2a05f20000000 d25 40b3880000000000 |
23 | d26 408a800000000000 d27 4053000000000000 |
24 | d28 0000000000000000 d29 0000000000000000 |
25 | d30 0100010001000100 d31 0100010001000100 |
26 | scr 20000010 |
27 | |
28 | backtrace: |
29 | #00 pc 000219d8 /system/lib/libdvm.so |
30 | #01 pc 0002dfa0 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) |
31 | #02 pc 0002b638 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184) |
32 | #03 pc 00060581 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336) |
33 | #04 pc 0004c9cd /system/lib/libdvm.so |
34 | #05 pc 00009de9 /system/lib/libandroid_servers.so |
35 | #06 pc 0000a2b7 /system/lib/libandroid_servers.so (android::NativeInputManager::interceptKeyBeforeDispatching(android::sp<android::InputWindowHandle> const&, android::KeyEvent const*, unsigned int)+58) |
36 | #07 pc 00020a49 /system/lib/libinputservice.so (android::InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(android::InputDispatcher::CommandEntry*)+60) |
37 | #08 pc 00022487 /system/lib/libinputservice.so (android::InputDispatcher::runCommandsLockedInterruptible()+58) |
38 | #09 pc 0002571b /system/lib/libinputservice.so (android::InputDispatcher::dispatchOnce()+50) |
39 | #10 pc 0001fb61 /system/lib/libinputservice.so (android::InputDispatcherThread::threadLoop()+8) |
40 | #11 pc 0000e9ed /system/lib/libutils.so (android::Thread::_threadLoop(void*)+104) |
41 | #12 pc 0004d4b1 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+68) |
42 | #13 pc 0000e58f /system/lib/libutils.so |
43 | #14 pc 0000d200 /system/lib/libc.so (__thread_entry+72) |
44 | #15 pc 0000d398 /system/lib/libc.so (pthread_create+240) |
45 |
其中backtrace就是当时system_server接收到signal 11时,堆栈调用的信息,这些信息很重要,能帮忙还原发生异常的现场。signal 11的定义在这里$android_root/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/sysroot/usr/include/bits/signum.h
1 | /* Signals. */ |
2 | #define SIGHUP 1 /* Hangup (POSIX). */ |
3 | #define SIGINT 2 /* Interrupt (ANSI). */ |
4 | #define SIGQUIT 3 /* Quit (POSIX). */ |
5 | #define SIGILL 4 /* Illegal instruction (ANSI). */ |
6 | #define SIGTRAP 5 /* Trace trap (POSIX). */ |
7 | #define SIGABRT 6 /* Abort (ANSI). */ |
8 | #define SIGIOT 6 /* IOT trap (4.2 BSD). */ |
9 | #define SIGBUS 7 /* BUS error (4.2 BSD). */ |
10 | #define SIGFPE 8 /* Floating-point exception (ANSI). */ |
11 | #define SIGKILL 9 /* Kill, unblockable (POSIX). */ |
12 | #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ |
13 | #define SIGSEGV 11 /* Segmentation violation (ANSI). */ |
14 | #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ |
15 | #define SIGPIPE 13 /* Broken pipe (POSIX). */ |
16 | #define SIGALRM 14 /* Alarm clock (POSIX). */ |
17 | #define SIGTERM 15 /* Termination (ANSI). */ |
18 | #define SIGSTKFLT 16 /* Stack fault. */ |
19 | #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ |
20 | #define SIGCHLD 17 /* Child status has changed (POSIX). */ |
21 | #define SIGCONT 18 /* Continue (POSIX). */ |
22 | #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ |
23 | #define SIGTSTP 20 /* Keyboard stop (POSIX). */ |
24 | #define SIGTTIN 21 /* Background read from tty (POSIX). */ |
25 | #define SIGTTOU 22 /* Background write to tty (POSIX). */ |
26 | #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ |
27 | #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ |
28 | #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ |
29 | #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ |
30 | #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ |
31 | #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ |
32 | #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ |
33 | #define SIGIO 29 /* I/O now possible (4.2 BSD). */ |
34 | #define SIGPWR 30 /* Power failure restart (System V). */ |
35 | #define SIGSYS 31 /* Bad system call. */ |
36 | #define SIGUNUSED 31 |
stack.py工具就是要把backtrace通过addr2line工具一次性把15个addr对应到代码。
先看一下帮助,在主机上执行
python stack.py --help
1 | build/core/envsetup.mk:10: /version_defaults.mk: No such file or directory |
2 | build/core/envsetup.mk:115: /product_config.mk: No such file or directory |
3 | make: *** No rule to make target `/product_config.mk'. Stop. |
4 | |
5 | usage: stack.py [options] [FILE] |
6 | |
7 | --symbols-dir=path |
8 | the path to a symbols dir, such as =/tmp/out/target/product/dream/symbols |
9 | |
10 | --symbols-zip=path |
11 | the path to a symbols zip file, such as =dream-symbols-12345.zip |
12 | |
13 | --auto |
14 | attempt to: |
15 | 1) automatically find the build number in the crash |
16 | 2) if it's an official build, download the symbols |
17 | from the build server, and use them |
18 | |
19 | FILE should contain a stack trace in it somewhere |
20 | the tool will find that and re-print it with |
21 | source files and line numbers. If you don't |
22 | pass FILE, or if file is -, it reads from |
23 | stdin. |
tombstone生成文件一般位于手机中/data/tombstone/文件夹下面,工具使用如下:
1 | python stack.py --symbols-dir=out/target/product/$yourproduct/symbols/ tombstone-00 |
1 | Searching for native crashes in tombstone-0718 |
2 | Reading symbols from out/target/product/k200/symbols/ |
3 | pid: 455, tid: 486, name: InputDispatcher >>> system_server <<< |
4 | signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00290238 |
5 | r0 00290008 r1 00000230 r2 00000003 r3 00290008 |
6 | r4 64a42042 r5 677d9eac r6 677f16e8 r7 000003f2 |
7 | r8 41656d40 r9 00000002 sl 00000000 fp 68088ca0 |
8 | ip 000000f2 sp 68088b38 lr 00000000 pc 4165a9d8 |
9 | |
10 | Stack Trace: |
11 | ADDR FUNCTION FILE:LINE |
12 | 000219d8 dalvik_inst /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/dalvik/vm/mterp/out/InterpAsm-armv7-a-neon.S:7358 |
13 | 0002dfa0 dvmMterpStd(Thread*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/dalvik/vm/mterp/Mterp.cpp:105 |
14 | 0002b638 dvmInterpret(Thread*, Method const*, JValue*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/dalvik/vm/interp/Interp.cpp:1961 |
15 | 00060581 dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/dalvik/vm/interp/Stack.cpp:526 |
16 | 0004c9cd CallLongMethodV /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/dalvik/vm/Jni.cpp:1968 |
17 | 00009de9 _JNIEnv::CallLongMethod(_jobject*, _jmethodID*, ...) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/libnativehelper/include/nativehelper/jni.h:625 |
18 | 0000a2b7 android::NativeInputManager::interceptKeyBeforeDispatching(android::sp<android::InputWindowHandle> const&, android::KeyEvent const*, unsigned int) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp:938 |
19 | 00020a49 android::InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(android::InputDispatcher::CommandEntry*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/services/input/InputDispatcher.cpp:3478 |
20 | 00022487 android::InputDispatcher::runCommandsLockedInterruptible() /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/services/input/InputDispatcher.cpp:615 (discriminator 3) |
21 | 0002571b android::InputDispatcher::dispatchOnce() /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/services/input/InputDispatcher.cpp:237 |
22 | 0001fb61 android::InputDispatcherThread::threadLoop() /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/services/input/InputDispatcher.cpp:4484 |
23 | 0000e9ed android::Thread::_threadLoop(void*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/system/core/libutils/Threads.cpp:770 |
24 | 0004d4b1 android::AndroidRuntime::javaThreadShell(void*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/frameworks/base/core/jni/AndroidRuntime.cpp:1000 |
25 | 0000e58f thread_data_t::trampoline(thread_data_t const*) /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/system/core/libutils/Threads.cpp:95 |
26 | 0000d200 __thread_entry /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/bionic/libc/bionic/pthread_create.cpp:105 |
27 | 0000d398 pthread_create /mnt/nfsroot/gangfeng.xu/work/kk-amlogic-dev/bionic/libc/bionic/pthread_create.cpp:224 |
很方便吧,不用一个一个的去找了。
工具链接如下:
stack.py
refer to:
https://sites.google.com/a/itspaclub.com/www/android-debug/7-how-to-debug-native-code
http://stackoverflow.com/questions/5106581/how-to-get-longer-stacktrace-tombstone-from-android
http://blog.csdn.net/helldevil/article/details/6682211