这篇博客旨在记录日常工作中遇到的GDB的基本调试功能,以供日后参考。

1 set sysroot [rootfs]

由于工作于嵌入式环境,因此不免经常需要调试目标系统(target)的crash问题,这时候一般需要以下几步:

  1. 在host上安装一个可以分析target文件格式的GDB (例如: gdb-multiarch)
  2. 将target的rootfs解压缩到host上(例如:/tmp/rootfs)
  3. 由于大部分嵌入式系统为了节省空间,其二进制文件都是去debug信息的(stripped, 一般通过strip完成),因此需要找到与crash相关的带debug信息的文件(一般通过objcopy --only-keep-debug 生成),在对应的二进制的同目录下的创建一个.debug目录,然后将debug信息文件名改为和对应二进制文件相同,并置于.debug目录
  4. 打开gdb,加载core文件,然后在gdb shell中输入set sysroot /tmp/rootfs, 然后输入bt. 如果core文件是完整的并且所有相关文件的debug版都已经放在相应位置,那么此时你应该可以看到完整的调用信息

2 add-symbol-file [file] [address]

接着上一节,如果core是不完整的,那么在加载core文件以后,会看到如下信息:

Warning: xxx/core is truncated: expected core file size >= 412385280, found: 287272960.

此时,上面的方法你可能就会得到一堆问号:

#0  0x2861bac4 in ?? ()
#1  0x2861bab0 in ?? ()
#2  0x2861bab0 in ?? ()
  1. 找到最后的调用地址: 0x2861bab0
  2. 找到记录了core发生时记录了内存地址映射的文件(例如,cortex.dump),在其中找到0x2861bab0这个地址是在哪个二进制文件中的, 并且找到该文件的起始地址(假设是0x28610000
  3. 找到该二进制文件,找到它的.text段的偏移地址。例如:

                                            Address  Offset Size   EntSize   Flag  Link Info Align
     [10] .text             PROGBITS        0002ce90 02ce90 059cd4 00        AX    0    0    8
                                                     ^
    
  4. 两个地址相加,计算得到该二进制文件的.text在内存中的起始地址:0x2ce90 + 0x28610000 = 0x2863ce90
  5. 执行[1]中的步骤,在执行set sysroot之后,再执行add-symbol-file [带debug信息的二进制文件] [0x2863ce90]。然后,执行bt

3 Print Real Class

Given a base class pointer(ptr), which actually points to the derived class. One can try following method to see the real class of this pointer:

4 添加文件搜索路径

有时候要加断点的时候需要指定某个文件中的某一行,此时gdb会去搜索这个文件,搜索的路径(source path) 可以通过 show dir 看到。

如果文件所在的路径不在source path里,要通过 dir <path> 加入进去。

详见这里