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 命令可以打印变量的值。

“{<type>} <addr>”表示一个指向内存地址<addr>的类型为type的一个对象。


默认情况下, 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 命令

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

up 栈帧号 选定栈帧上移

down 栈帧号  选定栈帧下移

info files

显示被调试文件的详细信息。 


info func

显示所有的函数名称。 


info local

显示当函数中的局部变量信息。 


info prog

显示被调试程序的执行状态。

info all-registers:

查看所有的寄存器包括浮点寄存器

info registers < registersName>

查看指定寄存器

 

机器语言工具

有一组专用的gdb变量可以用来检查和修改计算机的通用寄存器,gdb提供了目前每一台计算机中实际使用的4个寄存器的标准名字:

  • $pc : 程序计数器
  • $fp : 帧指针(当前堆栈帧)
  • $sp : 栈指针
  • $ps : 处理器状态
  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值