objdump 调试
objdump,gnu 开发工具包中的反汇编调试工具。详细的最新的文档说明情况可通过 man
objdump 来查阅,此处不在赘述。这里主要讲一下在 linux 下使用该工具调试追踪 segment
fault(段错误)这一常见问题的方法。
一些前置条件说明:
1、当应用程序发生异常退出时,内核中会捕捉到退出时的异常情况,比如 PC 值、LR
值、SP 值等等。一般情况下,应用程序崩溃,栈地址都是异常的,所以 PC 值和 LR 值成为
定位回溯程序的关注对象。PC 值指出现异常时 PC 指针指向的地址,也即程序运行到了哪一
行;LR 值指出现异常时,如果有子程序调用或者 BX 等跳转,会将调用或跳转前的 PC 值存
入到 LR 中。这些参数的信息可以通过命令 dmesg 输出查询,但如果系统有重启过,我们将
无法通过该命令查询到程序崩溃时的异常信息。幸运的是,我们通过在内核中定制输出相关
信息到特定文件的方式,保证了无论在系统断电或重启后也会完美保存异常信息的 log,保
存文件为/mnt/log。
2、虽然通过 objdump 可以完美反汇编目标文件,但如果你在汇编代码上的造诣不深,
想通过反汇编未添加调试信息的目标文件来定位问题点,那将是一个很痛苦的过程。一般情
况下我们运行的程序是未添加调试信息的,所以当运行这些程序出现问题时,尽可能的不要
试图去直接反汇编出现问题的目标文件来定位问题,而是要重新编译一份加入调试信息
(make CFLAGS=-g)的代码,然后再反汇编定位,只需保证两者是同一份代码即可(加入调
试信息不会对真正的代码信息造成任何影响)。
3、很多情况是当异常出现时,PC 值停留在共享库里,而共享库中的程序段内容的地址
是在程序运行时才加载到内存空间的,所以无法保证每次运行该地址都是相同的。那么此时
我们就需要通过/proc/$(pid)/下的 maps 文件中的信息来获取当前运行时的具体地址。
有了以上的前置条件说明,接下来的理解起来相对就简单了。下面以实际的例子来看下
调试过程,看看是否能够定位准确。
例 1:当异常出现在应用程序中时:
在 void CreateAllPages(void)函数中,我们添加 5717 和 5730 两行,这是一个典型的访问
未分配空间的指针引起的异常: