今天遇到个这样的需求,希望能当动态链接库中抛出异常时,能把调用栈打印出来。经过在google上一翻搜寻,找到了一些线索。 我的文件目录如下:当前目录下是main.cpp 和test/ test下面是A.h, A.cpp(定义一个类)和backtrace.h, backtrace.cpp
第一步,实现打印调用栈,backtrace函数实现如下: backtrace.cpp #include "backtrace.h" #include <unistd.h> // let prog point to the end of "cmd" int r = readlink("/proc/self/exe", prog, sizeof(cmd) - (prog-cmd)-1); FILE* fp = popen(cmd, "w"); main.cpp include <stdio.h> int main() 按如下编译,注意-g 和 -rdynamic参数。 [Charlie@localhost so]$ g++ -g -rdynamic -Itest main.cpp test/backtrace.cpp 下面的??表示无法得到代码文件名,必要时可能进行过滤。 第二步,尝试在动态链接库中打印调用栈。 A.cpp #include "A.h" A::A() main.cpp中相关改动为: int main() 首先编译生成动态链接库: [Charlie@localhost test]$ g++ -g -rdynamic -o libA.so -shared A.cpp backtrace.cpp [Charlie@localhost so]$ ./a.out 结果非常遗憾,只有main函数能打出文件名和行数。动态链接库中不能打出来。 动态库不行,试试静态库呢?凭直觉应该是行的,因为它和直接编译链接差不多嘛。 cd 到test下面, [Charlie@localhost test]$ g++ -g -rdynamic -c backtrace.cpp A.cpp 编译生成.o文件,再用ar将其打成.a文件。
结论:利用backtrace借助addr2line命令可以在运行时打出函数调用栈信息,这种办法对静态链接有效,对动态库不行(暂时没发现行)。 |
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
///
GCC提供了两个内置函数用来在运行时取得函数调用栈中的返回地址和框架地址 如果使用glibc 2.1或更新版本,可以使用backtrace()函数,参看<execinfo.h>,其他系统可能有不同的技术支持。
一个例子
$ g++ t.cpp -rdynamic -ldl -o t $ ./t ret address [80488ff] call address [bfffb938] 1: 0x80488ff _Z8MyFunc_Bv+0 (./t) |