如果是ROS 的 CMakeList.txt ,编译的时候需要加上一下选项,才可以生产debug版本,可以使用addr2line 定位问题。
catkin_make -DCMAKE_BUILD_TYPE=debug -DCATKIN_WHITELIST_PACKAGES="XXX"
还有一种方法是再CMakeList.txt 中加 SET(CMAKE_C_FLAGS_DEBUG "-g -Wall") ,但是这种方法在ROS中好像不生效。
转自:https://blog.csdn.net/chrovery/article/details/48035235
在Linux下写C/C++程序的程序员,时常与Core Dump相见。在内存越界访问,收到不能处理的信号,除零等错误出现时,我们精心或不精心写就的程序就直接一命呜呼了,Core Dump是Linux仁慈地留下的程序的尸体,帮助程序员们解决了一个又一个问题。
有时配置不给力,Linux直接毁尸灭迹,没有了Core文件;又有时,刚好磁盘空间不足,Core文件写不下了。没有Core文件的时候,如何知道程序在什么地方出错了呢?addr2line就在这时派上用场。
这是一个示例程序,func函数返回参数a除以参数b的结果。这里使用0作为除数,结果就是程序因为除以0导致错误,直接中断了。
[cpp] view plaincopy
- #include <stdio.h>
-
- int func(int a, int b)
- {
- return a / b;
- }
-
- int main()
- {
- int x = 10;
- int y = 0;
- printf("%d / %d = %d\n", x, y, func(x, y));
- return 0;
- }
使用
$ gcc -o test1 -g test1.c
编译程序,test1.c是程序文件名。执行程序,结果程序异常中断。查看系统dmesg信息,发现系统日志的错误信息:
[54106.016179] test1[8352] trap divide error ip:400506 sp:7fff2add87e0 error:0 in test1[400000+1000]
这条信息里的ip字段后面的数字就是test1程序出错时所程序执行的位置。使用addr2line就可以将400506转换成出错程序的位置:
$ addr2line -e test1 400506
/home/hanfoo/code/test/addr2line/test1.c:5
这里的test1.c:5指的就是test1.c的第5行
return a / b;
也正是这里出现的错误。addr2line帮助我们解决了问题。
addr2line如何找到的这一行呢。在可执行程序中都包含有调试信息,其中很重要的一份数据就是程序源程序的行号和编译后的机器代码之间的对应关系Line Number Table。DWARF格式的Line Number Table是一种高度压缩的数据,存储的是表格前后两行的差值,在解析调试信息时,需要按照规则在内存里重建Line Number Table才能使用。
Line Number Table存储在可执行程序的.debug_line域,使用命令
$ readelf -w test1
可以输出DWARF的调试信息,其中有两行
Special opcode 146: advance Address by 10 to 0x4004fe and Line by 1 to 5
Special opcode 160: advance Address by 11 to 0x400509 and Line by 1 to 6
这里说明机器二进制编码的0x4004fe位置开始,对应于源码中的第5行,0x400509开始就对应与源码的第6行了,所以400506这个地址对应的是源码第5行位置。
addr2line通过分析调试信息中的Line Number Table自动就能把源码中的出错位置找出来,再也不怕Linux毁尸灭迹了。
for example:
prebuilts/tools/gcc-sdk/addr2line -e out/target/product/z4dtg/obj/EXECUTABLES/xxxxx_intermediates/LINKED/xxxxxxxx 0x00007165
objdump同样可以用于debug crash问题
举例:
kernel中有如下crash
CPU: 0 PID: 155 Comm: khubd Tainted: P O 3.10.79 #10
20151010_15:57:32:000[ 3.788226] task: d2cae880 ti: d2d60000 task.ti: d2d60000
20151010_15:57:32:000[ 3.793612] PC is at device_del+0x28/0x194
20151010_15:57:32:000[ 3.797685] LR is at device_del+0x1c/0x194
20151010_15:57:32:000[ 3.801767] pc : [<c01ae980>] lr : [<c01ae974>] psr: 200f0013
可使用
arm-linux-guneabihf-objdump -D vmlinux | less 将所有symbol dump出来,然后查找device_del function,看偏移0x28位置处具体为什么会导致crash
Addr2line 工具(它是标准的 GNU Binutils 中的一部分)是一个可以将指令的地址和可执行映像转换成文件名、函数名和源代码行数的工具。这种功能对于将跟踪地址转换成很有意义的。
现在举一个具体的例子来说明addr2line具体用法,至于其他的特殊应用可以使用man来了解。
在一次系统死机的过程中,我们得到如下的信息,死机的模块是tejxapci.ko:
具体位置是:shtej_spanconfig+0x98/0x123
之后先使用#objdump -S tejxapci.ko 得到shtej_spanconfig的地址0x248a,加上0x98就是,0x2522
得到0x2522这个地址之后,运行#addr2line -e tejxapci -f 之后输入0x2522,addr2line就可以定位到对应的那一行代码了。
如果遇到objdump无法使用的情况,可以使用如下command来check ELF格式的bin档中的symbol list
readelf -s output/debug/vmlinux | grep xxx