With GDB's BT command it is easy to print the native call stack, such as:
(GDB) bt#0 Tgkill () at Bionic/libc/arch-arm/bionic/tgkill. S:46#1 0x40061030 in Pthread_kill (t=<optimized out>, sig=6) at Bionic/libc/bionic/pthread_kill.cpp:49#2 0x400612 Raise (sig=6) at Bionic/libc/bionic/raise.cpp:32#3 0x4005ff9e in __libc_android_abort () at Bionic/libc/bionic/abor T.cpp:65#4 0x4006f850 in Abort () at Bionic/libc/arch-arm/bionic/abort_arm. S:41#5 0x7217b50c in DebugBreak () at external/chromium_org/base/debug/debugger_posix.cc:233#6 base::d ebug:: Breakdebugger () at External/chromium_org/base/debug/debugger_posix.cc:257#7 0x7217910e in base::android:: Checkexception ([email protected]=0x414cefa8) at External/chromium_org/base/android/jni_android.cc:204#8 0X72B2D0DC in Java_contentviewcore_settitle (title=0xbe500021, obj=0x240001d, env=0x414cefa8) at out/target/product/ Pisces/obj/gyp/shared_intermediates/content/jni/contentviewcore_jni.h:1282#9 Content::ContentViewCoreImpl:: Settitle (this=<optimized out>, title= ...) at External/chromium_org/content/browser/android/content_view_core_impl.cc:437#10 0X72B89DFC in Content::webcontentsimpl:: Updatetitleforentry ([email protected]=0x76b22280, [Email protected]=0x7a0cf7b0, title= ...) At external/chromium_org/content/browser/web_contents/web_contents_impl.cc:2717 ...
Sometimes we want to know the Java call stack when native crash, and we can use the data in GDVM to derive the Java stack.
We know that there is a threadlist in GDVM, which is a line threads that can traverse all the threads in the current process through this list.
(GDB) p gdvm->threadlist$1 = (thread *) 0x414d0558 (GDB) p * (thread *) 0x414d0558$3 = { ... ThreadId = 1, ... Status = Thread_native, systemtid = 23405, interpstackstart = 0x6d557000 "", threadobj = 0x416b2ca8, JNIEnv = 0x414cefa8, prev = 0x0, next = 0x7b88a3a8, ...} (GDB) p * (Thread *) 0x7b88a3a8$4 = { ... ThreadId = ... Status = Thread_native, systemtid = 25905, interpstackstart = 0x77ead000 <address 0x77ead000 out of BOUNDS&G t;, threadobj = 0x42dacd70, jnienv = 0x7a0cff28, prev = 0x414d0558, next = 0x7a095de0, c23/> ...}
...
With the info thread command, you can see that the problematic thread is a 23405 thread, which is the main path.
(GDB) info thread ID Target ID Frame 23412 LWP recvmsg () at Bionic/libc/arch-arm/syscalls /recvmsg. S:9 . LWP 23451 __futex_syscall3 () at Bionic/libc/arch-arm/bionic/futex_arm. s:39 ... 5 LWP 23460 __futex_syscall3 () at Bionic/libc/arch-arm/bionic/futex_arm. s:39 4 LWP 23418 __ioctl () at Bionic/libc/arch-arm/syscalls/__ioctl. S:9 3 LWP 25905 __ioctl () at Bionic/libc/arch-arm/syscalls/__ioctl. S:9 2 LWP 23417 __ioctl () at Bionic/libc/arch-arm/syscalls/__ioctl. S:9* 1 LWP 23405 Tgkill () at Bionic/libc/arch-arm/bionic/tgkill. s:46
The next step is to derive the call stack for the main thread:
(GDB) p * (thread*) 0x414d0558$3 = { Interpsave = { pc = 0x6e601544, curframe = 0x6d556e20, ... c5/>}, threadId = 1, ... Status = Thread_native, systemtid = 23405, interpstackstart = 0x6d557000 "", threadobj = 0x416b2ca8, jnienv = 0x414cefa8, ... Prev = 0x0, next = 0x7b88a3a8, ...}
From the Interpsave Curframe can deduce the topmost stacksavearea, due to:
#define SAVEAREA_FROM_FP (_FP) ((stacksavearea*) (_FP)-1)
So the top-level Stacksavearea are:
(GDB) p * (stacksavearea*) (0x6d556e20-sizeof (Stacksavearea)) $ = { Prevframe = 0x6d556e40, savedpc = 0x7015e73c, method = 0x6d7d6068, ...}
Take method:
(GDB) p * (method*) 0x6d7d6068$6 = { clazz = 0x4187f7b8, accessflags = 258, methodindex = 0, regi Sterssize = 3, outssize = 0, inssize = 3, name = 0x701b6c59 <address 0x701b6c59 out of Bounds>
Classobject of the method corresponding to:
(GDB) p * (classobject*) 0x4187f7b8$7 = { descriptor = 0x7019bc6d <address 0x7019bc6d out of Bounds> ...}
Against the map table, it was found that this descriptor address is the Dex file for Webviewchromium:
7012e000-701ef000 R--p 00000000 b3:1b 40987 /data/dalvik-cache/[email protected]@[email protected]
The address of the descriptor is subtracted from the start address of Dex, and the address of the class name string in Dex is offset:
(gdb) p/x 0x7019bc6d-0x7012e000$8 = 0x6dc6d
Pull out of this Dex file from your phone and use Hexdump to view:
$ hexdump-c-n64-s0x6dc6d [email protected]@[email protected]0006dc6d 4c 6f 6d 2f 6e + 6f | lcom/android/org|0006dc7d 2f, 6f 6d, 6d 2f, all in, 2f | /chromium/base/s|0006dc8d 6d 4d------------------ 6e | Ystemmessagehand|0006dc9d 6c 3b XX 2b 4c + 6f 6d 2f 6e 6f | Ler;. +lcom/andro|
The name of this class is Com/android/org/chromium/base/systemmessagehandler .
The method has a name member, which represents the function name, and its offset address is:
(GDB) p * (method*) 0x6d7d6068$6 = { Clazz = 0x4187f7b8, accessflags = 258, methodindex = 0, registerssize = 3, outssize = 0, inssize = 3, 0x701b6c59 <address 0x701b6c59 out of Bounds>, 0x88c5 9
You can also use Hexdump to get the function name:
$ hexdump-c-n32-s0x88c59 [email protected]@[email protected]00088c59 6e, 6f, 6e 4c 6f 6 F 4f | Nativedorunloopo|00088c69 6e (6e)---- 6f nCE. Nativedocum|
The topmost function is named nativedorunlooponce ().
Looking at the second top, the second top-level frame is saved in the Prevframe member of the top-level Stacksavearea:
(GDB) p * (stacksavearea*) (0x6d556e20-sizeof (Stacksavearea)) $ = { Prevframe = 0x6d556e40, ...} (GDB) p * (stacksavearea*) (0x6d556e20-sizeof (Stacksavearea)) $ = { Prevframe = 0x6d556e40, savedpc = 0x7015e73c , method = 0x6d7d6068, ...} (GDB) p * (stacksavearea*) (0x6d556e40-sizeof (Stacksavearea)) $ = { Prevframe = 0x6d556e64, savedpc = 0x6edd27f0, method = 0x6d7d6150, ...} (GDB) p * (method*) 0x6d7d6150$13 = { Clazz = 0x4187f7b8, accessflags = 1, Methodindex = +, registers Size = 4, outssize = 3, inssize = 2, name = 0x701b091d <address 0x701b091d out of Bounds>
Clazz and the top floor are the same as the Com/android/org/chromium/base/systemmessagehandler.
Offset address of method name:
(gdb) p/x 0x701b091d-0x7012e000$17 = 0x8291d
The function is named Handlemessage ():
$ hexdump-c-n32-s0x8291d [email protected]@[email protected]0008291d 6e 6c 4d 73 73 61 67 65 00 0e | Handlemessage. h|0008292d 6e 6c, 4e, all-in -a -|andlenavigate h|
Then deduce the next stack:
(GDB) p * (stacksavearea*) (0x6d556e64-sizeof (stacksavearea)) $34 = {Prevframe = 0x6d556e84, savedpc = 0x6efdd434, method = 0x6d5f75a0, ...} (GDB) p * (method*) 0x6d5f75a0$35 = {Clazz = 0x416e0ad8, AccessFlags = 1, Methodindex = one, registerssize = 3, Outssiz E = 2, inssize = 2, name = 0x6f28d6c6 <address 0x6f28d6c6 out of Bounds> (GDB) p * (classobject*) 0x416e0ad8$36 = {... descriptor = <address 0x6f1e621b out of Bounds>, ...} 6ec32000-6edaa000 R--p 00000000 b3:1b 40972/data/dalvik-cache/[email protected]@[email protected] ... 6f127000-6f586000 r--p 004f5000 b3:1b 40972/data/dalvik-cache/[email protected]@[email protected] (GDB) p/ X 0x6f1e621b-0x6ec32000$40 = 0x5b421b$ hexdump-c-n32-s0x5b421b [email protected]@[email protected] 005b421b 4c 6e, 6f, 2f, 6f, 2f, 6e 64 | LANDROID/OS/HAND|005B422B 6c 3b, 1a 4c, 6e, 6f |ler, 2f 6f landroid/o| (GDB) p/x 0x6f28d6c6-0x6ec32000$41= 0x65b6c6$ hexdump-c-n32-s0x65b6c6 [email protected]@[email protected]0065b6c6 4d The |dispatchmessage.| 0065b6d6 0d, 4d 6f 76 65 64 00 11 | dispatchmoved..|
The resulting call stack is probably:
Com.android.org.chromium.base.SystemMessageHandler.nativeDoRunLoopOncecom.android.org.chromium.base.SystemMessageHandler . HandleMessageandroid.os.Handler.dispatchMessage.
Using GDB to derive the Java stack of DVM