利用backtrace跟蹤程序的調用堆棧

經過backtrace()函數能夠得到當前的程序堆棧地址. 提供一個指針數組, backtrace()函數會把調用堆棧的地址填到裏面.
#include <execinfo.h>
int backtrace(void **buffer, int size);

爲了跟蹤動態庫, 須要給gcc添加-rdynamic參數. 另外, 爲了看到函數名, 行號等調試信息, 還要添加-g參數.
-rdynamic參數的涵義: This instructs the linker to add all symbols, not only used ones, to the  dynamic symbol table. This option is needed for some uses of dlopen or to  allow obtaining backtraces from within a program

backtrace_symbols()能夠將堆棧地址轉換成可讀的信息用於打印, 但不是很具體, 沒法顯示出函數名和行號, 經過binutils的addr2line能夠作到這一點. 調用方式爲:  addr2line -Cif -e 文件名 地址

對於動態庫中的函數, 文件名是動態庫的. backtrace給出的堆棧地址是通過map的, 所以須要將映射後的地址還原. 映射的基地址可經過讀取/proc/self/maps獲得.

對於程序運行環境沒有addr2line工具的狀況, 如嵌入式平臺, 能夠打印出地址, 在PC上用交叉工具鏈的addr2line工具分析.

對於一些系統或第三方沒有加-g編譯的so庫, addr2line可能看不到函數名和行號的信息, 這時使用dladdr()函數可看到一些導出函數的函數名. dladdr()要使用backtrace()得到的原始地址, 不是還原後的.

經過 sigaction()註冊一些系統信號的處理回調, 如 SIGSEGV, 能夠在 Segmentation fault時打印程序堆棧.

因爲C++的符號是通過 name mangling, 爲了顯示的友好性, 可先作 demangle.

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
[01] 0x7ffbda2dd5ca   0x5ca            func: function_so_static, file: /data/callstack/test_so.c L7, module: /data/callstack/libtest.so
[02] 0x7ffbda2dd5da   0x5da            func: function_so, file: /data/callstack/test_so.c L13, module: /data/callstack/libtest.so
[03] 0x401c5e         0x401c5e         func: function_callso, file: /data/callstack/test.c L19, module: /data/callstack/callstack
[04] 0x401d12         0x401d12         func: main, file: /data/callstack/test.c L44, module: /data/callstack/callstack
[05] 0x7ffbd9f3e76d   0x2176d          func: __libc_start_main, file: unknown, module: /lib/x86_64-linux-gnu/libc.so.6
[06] 0x400f59         0x400f59         func: _start, file: unknown, module: /data/callstack/callstack
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

代碼下載地址:
https://github.com/thinkphoebe/callstack.git

參考:
http://blog.csdn.net/littlefang/article/details/17654419
http://blog.bigpixel.ro/2010/09/stack-unwinding-stack-trace-with-gcc/




附件列表

相關文章
相關標籤/搜索