Export to GitHub

android-ndk-stacktrace-analyzer - Usage.wiki


Preliminary

This tool will parse two files:

  • logcat from your android device, containing a stacktrace - the stuff that looks like:

12-10 22:20:04.839 I/DEBUG ( 551): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 12-10 22:20:04.839 I/DEBUG ( 551): Build fingerprint: 'generic/sdk/generic/:1.5/CUPCAKE/150240:eng/test-keys' 12-10 22:20:04.839 I/DEBUG ( 551): pid: 1003, tid: 1003 >>> com.example <<< 12-10 22:20:04.849 I/DEBUG ( 551): signal 11 (SIGSEGV), fault addr 00000004 12-10 22:20:04.849 I/DEBUG ( 551): r0 00000000 r1 0019ed48 r2 00000001 r3 0019eae4 12-10 22:20:04.859 I/DEBUG ( 551): r4 0019ea9c r5 0019ed48 r6 001935b0 r7 0000a9d0 12-10 22:20:04.859 I/DEBUG ( 551): r8 00000001 r9 0019eae4 10 804df39c fp 0019ea9c 12-10 22:20:04.869 I/DEBUG ( 551): ip 00000071 sp beb6f4a8 lr 8041d8d9 pc 8041cc6c cpsr 00000030 12-10 22:20:04.948 I/DEBUG ( 551): #00 pc 0000e3b4 /system/lib/libdvm.so 12-10 22:20:04.948 I/DEBUG ( 551): stack: 12-10 22:20:04.948 I/DEBUG ( 551): beb6f468 00000000 12-10 22:20:04.959 I/DEBUG ( 551): beb6f46c 0019ede3 [heap] 12-10 22:20:04.959 I/DEBUG ( 551): beb6f470 00000002 ...

The logcat file can have more than one stack trace - in which case, all stack traces will be processed.

  • asm file of the library being debugged. You generate this file by using the NDK's objdump tool:

...android-ndk/android-ndk-1.6_r1/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/arm-eabi-objdump -S mylib.so > mylib.asm

Running

Use the script by running: python parse_stack.py <asm-file> <logcat-file>

Output

A sample output of the script would be:

0x0001d9dc: native_func_3 + 0x095c 0x0001d8d4: native_func_2 + 0x0854 0x0001cc6c: native_func_1 + 0x0048 0x0001b768:Java_com_example_MyClass_jniFunc + 0x0084

Each of these lines represents a function call (actually - a return address, which points to the instruction immediately after the function call).

In our case, Java_com_example_MyClass_jniFunc called native_func_1 which called native_func_2, and so on.

native_func_1 called native_func_2 when it was 0x48 bytes inside the function (again - return address).

You can try to analyze exactly what happened there from looking at the assembly code - in our example, at address 0x0001cc6c.