交叉编译工具链addr2line用于将一个二进制文件中的地址转换为对应的源代码行号。它通常被用于调试崩溃时的堆栈跟踪信息,以便开发人员可以更容易地定位代码中的错误。
addr2line的语法如下:
addr2line [options] addr1 [addr2 ...]
其中,addr1、addr2等为需要转换的地址。下面是常用的参数及其解释:
-b <file>:指定二进制文件路径。
-e <file>:同 -b,但是只能指定一个文件。
-f:显示函数名。
-s:显示源文件名和行号。
-i:显示文件名、行号和函数名。
-C:启用名称修饰(C++符号)。
-h:显示帮助信息。
下面是一个使用addr2line的例子
#include <stdlib.h>
int main()
{
char *str = NULL;
str[0] = 'a';
return 0;
}
该代码中有一个明显的错误,即对NULL指针进行了解引用,这将导致程序崩溃。我们可以使用addr2line来找到这个错误的源代码位置。首先,我们使用arm-linux-gcc编译该程序:
arm-linux-gcc -g -o test test.c
运行该程序,并捕获崩溃信息:
# ./test
Segmentation fault
我们得到了一个崩溃信息,但是并没有太大的用处。
使用gdb调试coredump(若没有生成coredump文件,请输入ulimit -a
命令查看是否core文件被限制)
# gdb ./test /tmp/core-test-1473-791622919
<忽略gdb介绍等信息>
[New LWP 1473]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/libthread_db.so.1".
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x0001035e in main () at main.c:5
5 main.c: No such file or directory.
(gdb) bt
#0 0x0001035e in main () at main.c:5
可以看到,gdb打印了地址和对应的行号
0x0001035e in main () at main.c:5
将此地址在服务器上使用addr2line工具转换
# arm-linux-gnueabihf-addr2line -e test -f -i 0x0001035e
main
/home/zjh/helloworld/main.c:5
以上代码可以改得更方便一些
#include <stdio.h>
#include <stdlib.h>
int add(void)
{
int a = 1;
int b = 2;
return a+b;
}
int main()
{
add();
printf("%p\n",add);
return 0;
}
运行,打印出add函数的地址
# ./test
0x104b1
在服务器上查询此地址
# arm-linux-gnueabihf-addr2line -e test -f -i 0x104b1
add
/home/zjh/helloworld/main.c:9
这里显示的是函数末尾的行号