binutils工具集之---addr2line
Posted 悄然拔尖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了binutils工具集之---addr2line相关的知识,希望对你有一定的参考价值。
addr2line用于得到程序指令地址所对应的函数,以及函数所在的源文件名和行号。
在不少嵌入式开发环境中,编译器的名称往往不是gcc,而是想arm-rtems-gcc这样的,对于这种命名形式的编译器,读者通常可以找到arm-rtems-addr2line ,arm-rtems-objdump等相应名称的工具,这是GNU工具集的一种命名惯例。
本文并不是binutils工具集的完整参考手册,当需要得到更为详细的帮助信息时,可以参照对应工具的man和info信息。另一个更为简单的方法时运行相应的工具并指定--help参数,可以获得该工具的简单帮助信息。
用法:addr2line [选项] [地址]
将地址转换成文件名/行号对。
如果没有在命令行中给出地址,就从标准输入中读取它们
选项是:
@<file> 读取选项从 <file>
-a --addresses 显示地址
-b --target=<bfdname> 设置二进位文件格式
-e --exe=<executable><name> 设置输入文件名称(默认为 a.out)
-i --inlines 解开内联函数
-j --section=<name> 读取相对于段的偏移而非地址
-p --pretty-print 让输出对人类更可读
-s --basenames 去除目录名
-f --functions 显示函数名
-C --demangle[=style] 解码函数名
-h --help 显示本帮助
实战操练:
建立main.c文件如下:
输入:
gcc -g main.c -o app -Wall
一定要加-g选项,不然没有调试信息。
编译没有任何警告(作为gcc来说不应该啊^_^)
运行
显示段错误。使用dmesg(该命令可以参考https://linux.cn/article-3587-1.html)追踪:
注意最后一行 app 可执行文件的描述:segfault(段错误)ip为4004e6这就是程序执行出错的位置。这时,addr2line登场:
显示在在我的目录下 main.c的第七行出现段错误,现在回过头去看第一幅图片,你应该会发现addr2line准确地得到了我们想要调试的东西。
一般常用的两个option为-f和-e。
下面,我们再来做一件有意思的事情:
main.c如下:
运行如下:
这里的地址是通过程序打印而获得,在现实工作中往往是程序崩溃是通过某种方式获得地址,比如上面的dmesg,或者在嵌入式系统的一些IDE上也有类似功能。通过nm -n指令可以看到函数对应的开始地址:只取foo和main函数截图如下:
可以看出foo函数是有大小的,foo函数的大小就是main的地址减去foo的地址。如果传递给addr2line的地址是400526-400541之间的任意地址会输出什么呢?
测试结果表明,addr2line可以通过函数的任一地址找到所属函数的相关信息。
根据地址找到了函数名,现在我们写一个c++程序main.cpp如下 图:
运行如下:
首先和C语言一样,addr2line找到了foo函数入口在main.cpp的第五行,(也可以看出函数调用是从大括号处开始),但是函数名却是_Z3f00v,这就有点奇怪了,怎么不是foo呢?这是因为c++的重载使得这一现象产生。从C语言的角度来看c++的重载函数名称必须不同,为了做到这一点,c++编译器的处理方法就是对于每一个函数,将根据输入参数采取一定的编码方式,形成不同的c函数名,这个过程就是名字分裂过程。如上的 _Z3f00v就是c++程序中foo()函数的名字分裂后的形式。毕竟c++是从C语言上发展而来的。
我们可以通过--demangle选项获得函数名:
--demangle=gnu-v3用于还原foo()函数。
以上是关于binutils工具集之---addr2line的主要内容,如果未能解决你的问题,请参考以下文章