通过编程方式获取backtrace

本文转载至:

在用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编译才能得到正确的符号名,否则只能得到偏移地址。

关于 -rdynamic ,请参考:

`-rdynamic'
     Pass the flag `-export-dynamic' to the ELF linker, on targets that
     support it. 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()和backtrace_symbols()函数来打印backtrace的信息:

 #include 
 #include 
 #include 

 /* Obtain a backtrace and print it to stdout. */
 void print_trace (void)
 {
   void *array[10];
   size_t size;
   char **strings;
   size_t i;

   size = backtrace (array, 10);
   strings = backtrace_symbols (array, size);

   printf ("Obtained %zd stack frames./n", size);

   for (i = 0; i < size; i++)
      printf ("%s/n", strings[i]);

   free (strings);
 }

 /* A dummy function to make the backtrace more interesting. */
 void dummy_function (void)
 {
   print_trace ();
 }

 int main (void)
 {
   dummy_function ();
   return 0;
 }


编译运行的结果如下:

# 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或将它保存到某个文件中,用于之后的分析。

更详细的介绍可以参考http://www.linuxjournal.com/article/6391

你可能感兴趣的:(调试)