COREDUMP是NE进程的内存现场, 其中包含了出现NE时的局部变量,
全局变量等信息, 这些信息有助于我们结合代码分析问题。
gdb路径 :prebuilts/gdb/linux-x86/bin/gdb
建议在源码根目录下执行, 可以通过gdb查看源码和打印变量成员.
常用指令说明帮助指令cmd 为对应命令, 会显示该命令所支持的参数和功能。
1.help [cmd]
cmd 为对应命令, 会显示该命令所支持的参数和功能
2.设置 so 库路径
path 为带符号的库路径, 一般是指向 track.zip 中 symbol/system/lib 这个目录
3.设置崩溃程序的路径
path 为带符号的可执行程序路径, 一般指向 track.zip 中 symbol/system/bin/ 这个目录下的文件。 所有的 java
进程都执行的是 app_process32 或者 app_process64
4.加载COREDUMP文件
path 指向 PROCESS_COREDUMP 文件的路径
5.查看堆栈
#0 0xaafe4ca6 in inline_tgkill (sig=6, pid=, tid=) at bionic/libc/bionic/abort.cpp:43
#1 abort () at bionic/libc/bionic/abort.cpp:68
#2 0xaaea8cd0 in __android_log_assert (cond=, tag=0x0, fmt=) at system/core/liblog/logger_write.c:608
#3 0xaaa612f2 in android::TimeCheck::TimeCheckThread::threadLoop (this=0xaa69e2c0) at frameworks/av/media/libmedia/TimeCheck.cpp:84
#4 0xacaab08c in android::Thread::_threadLoop (user=0xaa69e2c0) at system/core/libutils/Threads.cpp:744
#5 0xab02b306 in __pthread_start (arg=0xa9540970) at bionic/libc/bionic/pthread_create.cpp:254
#6 0xaafe5e6a in __start_thread (fn=0xab02b2ef <__pthread_start(void*)>, arg=) at bionic/libc/bionic/clone.cpp:52
#7 0x00000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
如果想同时看本地
#0 0xaafe4ca6 in inline_tgkill (sig=6, pid=, tid=) at bionic/libc/bionic/abort.cpp:43
No locals.
#1 abort () at bionic/libc/bionic/abort.cpp:68
pid = 23403
mask = {__bits = {4294967263, 4294967295}}
tid = 23465
sa =
#2 0xaaea8cd0 in __android_log_assert (cond=, tag=0x0, fmt=) at system/core/liblog/logger_write.c:608
buf = "TimeCheck timeout for IAudioFlinger", '\000' ...
iov = {{iov_base = 0xa95404d8, iov_len = 35}, {iov_base = 0xaaeb49b4, iov_len = 1}}
#3 0xaaa612f2 in android::TimeCheck::TimeCheckThread::threadLoop (this=0xaa69e2c0) at frameworks/av/media/libmedia/TimeCheck.cpp:84
status = -110
tag = 0xaac9d943 "IAudioFlinger"
#4 0xacaab08c in android::Thread::_threadLoop (user=0xaa69e2c0) at system/core/libutils/Threads.cpp:744
strong =
weak = {m_ptr = 0xaa69e2c0, m_refs = 0xaa6988f0}
first = false
#5 0xab02b306 in __pthread_start (arg=0xa9540970) at bionic/libc/bionic/pthread_create.cpp:254
thread = 0xa9540970
result =
#6 0xaafe5e6a in __start_thread (fn=0xab02b2ef <__pthread_start(void*)>, arg=) at bionic/libc/bionic/clone.cpp:52
self = 0xa9540970
status =
#7 0x00000000 in ?? ()
No symbol table info available.
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
6.跳函数帧
id 就是 # 对应的数字
#3 0xaaa612f2 in android::TimeCheck::TimeCheckThread::threadLoop (this=0xaa69e2c0) at frameworks/av/media/libmedia/TimeCheck.cpp:84
84 LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "TimeCheck timeout for %s", tag);
7.查看该函数帧的信息
可以当前所在帧查看它前一帧和后一帧, 参数地址和相关寄存器值。
寄存器的信息
Stack level 3, frame at 0xa9540920:
pc = 0xaaa612f2 in android::TimeCheck::TimeCheckThread::threadLoop (frameworks/av/media/libmedia/TimeCheck.cpp:84); saved pc = 0xacaab08c
called by frame at 0xa9540958, caller of frame at 0xa95408f0
source language c++.
Arglist at 0xa95408f0, args: this=0xaa69e2c0
Locals at 0xa95408f0, Previous frame's sp is 0xa9540920
Saved registers:
r4 at 0xa9540900, r5 at 0xa9540904, r6 at 0xa9540908, r7 at 0xa954090c, r8 at 0xa9540910, r9 at 0xa9540914, r10 at 0xa9540918, lr at 0xa954091c
8.查看汇编
建议参数 /m, 可以结合源码查看, 前提是gdb的工作路径在源码根目录下
Dump of assembler code for function android::TimeCheck::TimeCheckThread::threadLoop():
62 {
0xaaa611e0 <+0>: stmdb sp!, {r4, r5, r6, r7, r8, r9, r10, lr}
0xaaa611e4 <+4>: sub sp, #16
0xaaa611e6 <+6>: mov r5, r0
0xaaa611e8 <+8>: ldr r0, [pc, #264] ; (0xaaa612f4 )
63 status_t status = TIMED_OUT;
64 const char *tag;
65 {
66 AutoMutex _l(mMutex);
67
68 if (exitPending()) {
0xaaa611fc <+28>: mov r0, r5
0xaaa611fe <+30>: bl 0xaaa63664
0xaaa61202 <+34>: cbz r0, 0xaaa6120e
69 return false;
70 }
71
72 nsecs_t endTimeNs = INT64_MAX;
73 // KeyedVector mMonitorRequests is ordered so take first entry as next timeout
74 if (mMonitorRequests.size() != 0) {
0xaaa61210 <+48>: cbz r0, 0xaaa6121e
75 endTimeNs = mMonitorRequests.keyAt(0);
0xaaa61214 <+52>: ldrd r6, r4, [r0]
76 tag = mMonitorRequests.valueAt(0);
0xaaa61218 <+56>: ldr.w r8, [r0, #8]
---Type to continue, or q to quit---p
0xaaa612ce <+238>: subs r1, r1, r2
0xaaa612d0 <+240>: bne.n 0xaaa612d8
0xaaa612e2 <+258>: ldr r0, [pc, #20] ; (0xaaa612f8 )
0xaaa612e4 <+260>: ldr r2, [pc, #20] ; (0xaaa612fc )
0xaaa612e6 <+262>: movs r1, #0
0xaaa612e8 <+264>: mov r3, r8
0xaaa612ea <+266>: add r0, pc
0xaaa612ec <+268>: add r2, pc
0xaaa612ee <+270>: bl 0xaaa63224
=> 0xaaa612f2 <+274>: nop
0xaaa612f4 <+276>: andeq r6, r0, r10, lsr #21
0xaaa612f8 <+280>: andeq r4, r0, r8, lsl r5
0xaaa612fc <+284>: andeq r4, r0, r9, lsr #10
0xaaa61300 <+288>: ldrdeq r6, [r0], -r2
85 return true;
86 }
0xaaa612d2 <+242>: add sp, #16
0xaaa612d4 <+244>: ldmia.w sp!, {r4, r5, r6, r7, r8, r9, r10, pc}
0xaaa612d8 <+248>: bl 0xaaa63194
End of assembler dump.
9.变量打印
p 命令可以打印变量的值。
“{
默认情况下, gdb只支持基本类型的变量, 可以用类似C的类型转换打印
在源码下, 可以支持结构体的解析和成员打印
(gdb) p g_thread_list
$3 = (pthread_internal_t *) 0xa9540970
(gdb) p *g_thread_list
$4 = {next = 0xa987f970, prev = 0x0, tid = 23465, cached_pid_ = 23403, attr = {flags = 1, stack_base = 0xa9443000, stack_size = 1038704, guard_size = 4096,
sched_policy = 0, sched_priority = 0}, join_state = THREAD_DETACHED, cleanup_stack = 0x0, start_routine = 0xacaaacbd ,
start_routine_arg = 0xaa698900, return_value = 0x0, alternate_signal_stack = 0xad39c000, startup_handshake_lock = {state = Lock::LockedWithoutWaiter,
process_shared = false}, mmap_size = 1040384, thread_local_dtors = 0x0, tls = {0xa95409c0, 0xa9540970, 0x0, 0x0, 0x0, 0xbc50cae2, 0x0, 0x0, 0x0}, key_data = {{seq = 1,
data = 0xaa693d80}, {seq = 0, data = 0x0}, {seq = 1, data = 0x0}, {seq = 0, data = 0x0} }, dlerror_buffer = '\000' ,
bionic_tls = 0xad3a2000}
examine命令(缩写为x)来查看内存地址中的值。
比如:
char *c = "hello world";
(gdb) x/s 0x100000f2e
0x100000f2e: "hello world"
(gdb) p (char *)0x100000f2e
$3 = 0x100000f2e "hello world"
将第一个字符改为大写:
(gdb) p *(char *)0x100000f2e='H'
$4 = 72 'H'
(gdb) p c
$5 = 0x100000f2e "Hello world"
修改内存:
(gdb) set {unsigned int}0x100000f2e=0x0
(gdb) x/10cb 0x100000f2e
0x100000f2e: 0 '\0' 0 '\0' 0 '\0' 0 '\0' 111 'o' 32 ' ' 119 'w' 111 'o'
0x100000f36: 114 'r' 108 'l'
(gdb) p c
$10 = 0x100000f2e ""
x 命令默认是打印内存。同样是打印 (char)pid, x 命令会访问对应的内存地址, 而p只是打印了值。 x pid 相
当于是 p *pid
x 命令的基本格式:
x/nfu
n 表示要显示的内存单元个数
f 表示显示方式, 基本取值如下:
x 表示十六进制格式显示变量
d 表示十进制格式显示变量
u 表示十进制无符号显示变量
o 表示八进制格式显示变量
t 表示二进制格式显示变量
u 表示一个地址单元的长度
b 表示单字节
h 表示双字节
w 表示四字节
g 表示八字节
显示被调试文件的详细信息。
显示所有的函数名称。
显示当函数中的局部变量信息。
显示被调试程序的执行状态。
查看所有的寄存器包括浮点寄存器
查看指定寄存器
有一组专用的gdb变量可以用来检查和修改计算机的通用寄存器,gdb提供了目前每一台计算机中实际使用的4个寄存器的标准名字: