在用GDB調試器時可以查看所謂的Backtrace,它包含一系列的函數調用資訊,用命令backtrace或bt可以在GDB中查看函數調用棧的信 息。有些場合沒法使用GDB時,則可以用glibc庫函數中的一些相關函數來得到backtrace的資訊(在標頭檔execinfo.h中):
// 擷取將backstrace資訊,將地址存到buffer中。 // 參數size指定buffer的最大值,傳回值則是backstrace的實際大小 int backtrace (void **buffer, int size) // 根據buffer指定的地址,返回符號資訊。參數size指定返回符號資訊的大小 char ** backtrace_symbols (void *const *buffer, int size) // 類似backtrace_symbols()函數,但是不需要malloc空間來存放符號資訊, // 而是將結果寫到檔案描述符fd所代表的檔案中 void backtrace_symbols_fd (void *const *buffer, int size, int fd) |
使用函數backtrace_symbols()或者backtrace_symbols_fd()時,需要用-rdynamic編譯才能得到正確的符號名,否則只能得到位移地址。
下面的範例程式碼應用了backtrace()和backtrace_symbols()函數來列印backtrace的資訊:
1 #include <execinfo.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 5 /* Obtain a backtrace and print it to stdout. */ 6 void print_trace (void) 7 { 8 void *array[10]; 9 size_t size; 10 char **strings; 11 size_t i; 12 13 size = backtrace (array, 10); 14 strings = backtrace_symbols (array, size); 15 16 printf ("Obtained %zd stack frames.\n", size); 17 18 for (i = 0; i < size; i++) 19 printf ("%s\n", strings[i]); 20 21 free (strings); 22 } 23 24 /* A dummy function to make the backtrace more interesting. */ 25 void dummy_function (void) 26 { 27 print_trace (); 28 } 29 30 int main (void) 31 { 32 dummy_function (); 33 return 0; 34 } |
編譯啟動並執行結果如下:
# gcc bt.c -rdynamic -o bt # ./bt Obtained 5 stack frames. ./bt(print_trace+0x14) [0x80486e4] ./bt(dummy_function+0xb) [0x8048765] ./bt(main+0x15) [0x804877c] /lib/tls/libc.so.6(__libc_start_main+0xe4) [0x42015574] ./bt(backtrace_symbols+0x31) [0x8048641] |
你可以應用這些函數在程式異常退出時列印backtrace或將它儲存到某個檔案中,用於之後的分析