gdb 调试COREDUMP方法

COREDUMP是NE进程的内存现场, 其中包含了出现NE时的局部变量,
全局变量等信息, 这些信息有助于我们结合代码分析问题。
gdb路径 :prebuilts/gdb/linux-x86/bin/gdb
建议在源码根目录下执行, 可以通过gdb查看源码和打印变量成员.

常用指令说明帮助指令cmd 为对应命令, 会显示该命令所支持的参数和功能。

1.help [cmd]

cmd 为对应命令, 会显示该命令所支持的参数和功能

2.设置 so 库路径

set solib-search-path [path]

path 为带符号的库路径, 一般是指向 track.zip 中 symbol/system/lib 这个目

3.设置崩溃程序的路径

file [path]

path 为带符号的可执行程序路径, 一般指向 track.zip 中 symbol/system/bin/ 这个目录下的文件。 所有的 java
进程都执行的是 app_process32 或者 app_process64

4.加载COREDUMP文件

core-file [path]

path 指向 PROCESS_COREDUMP 文件的路径

5.查看堆栈

bt

#0  0xaafe4ca6 in inline_tgkill (sig=6, pid=<optimized out>, tid=<optimized out>) at bionic/libc/bionic/abort.cpp:43
#1  abort () at bionic/libc/bionic/abort.cpp:68
#2  0xaaea8cd0 in __android_log_assert (cond=<optimized out>, tag=0x0, fmt=<optimized out>) 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=<optimized out>) at bionic/libc/bionic/clone.cpp:52
#7  0x00000000 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

如果想同时看本地

bt full

#0  0xaafe4ca6 in inline_tgkill (sig=6, pid=<optimized out>, tid=<optimized out>) 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 = <optimized out>
#2  0xaaea8cd0 in __android_log_assert (cond=<optimized out>, tag=0x0, fmt=<optimized out>) at system/core/liblog/logger_write.c:608
        buf = "TimeCheck timeout for IAudioFlinger", '\000' <repeats 705 times>...
        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 = <optimized out>
        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 = <optimized out>
#6  0xaafe5e6a in __start_thread (fn=0xab02b2ef <__pthread_start(void*)>, arg=<optimized out>) at bionic/libc/bionic/clone.cpp:52
        self = 0xa9540970
        status = <optimized out>
#7  0x00000000 in ?? ()
No symbol table info available.
Backtrace stopped: previous frame identical to this frame (corrupt stack?)

6.跳函数帧

f [id]

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.查看该函数帧的信息

可以当前所在帧查看它前一帧和后一帧, 参数地址和相关寄存器值。

info frame

寄存器的信息

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.查看汇编

disass/m

建议参数 /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 <android::TimeCheck::TimeCheckThread::threadLoop()+276>)

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 <android::TimeCheck::TimeCheckThread::threadLoop()+46>

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 <android::TimeCheck::TimeCheckThread::threadLoop()+62>

75	            endTimeNs = mMonitorRequests.keyAt(0);
   0xaaa61214 <+52>:	ldrd	r6, r4, [r0]

76	            tag = mMonitorRequests.valueAt(0);
   0xaaa61218 <+56>:	ldr.w	r8, [r0, #8]
---Type <return> to continue, or q <return> to quit---p
   0xaaa612ce <+238>:	subs	r1, r1, r2
   0xaaa612d0 <+240>:	bne.n	0xaaa612d8 <android::TimeCheck::TimeCheckThread::threadLoop()+248>
   0xaaa612e2 <+258>:	ldr	r0, [pc, #20]	; (0xaaa612f8 <android::TimeCheck::TimeCheckThread::threadLoop()+280>)
   0xaaa612e4 <+260>:	ldr	r2, [pc, #20]	; (0xaaa612fc <android::TimeCheck::TimeCheckThread::threadLoop()+284>)
   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 命令
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 <thread_data_t::trampoline(thread_data_t const*)>, 
  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} <repeats 127 times>}, dlerror_buffer = '\000' <repeats 511 times>, 
  bionic_tls = 0xad3a2000}

x 命令
x 命令默认是打印内存。同样是打印 (char)pid, x 命令会访问对应的内存地址, 而p只是打印了值。 x pid 相
当于是 p *pid

x 命令的基本格式:

x/nfu <addr>
n 表示要显示的内存单元个数
f 表示显示方式, 基本取值如下:
x 表示十六进制格式显示变量
d 表示十进制格式显示变量
u 表示十进制无符号显示变量
o 表示八进制格式显示变量
t 表示二进制格式显示变量
u 表示一个地址单元的长度
b 表示单字节
h 表示双字节
w 表示四字节
g 表示八字节

猜你喜欢

转载自blog.csdn.net/chi_wy/article/details/82854541