原文出處 http://blog.csdn.net/yetyongjin/article/details/7759144
以下不能windows + mingw下執(zhí)行. windows下參考 http://code.google.com/p/backtrace-mingw/
我們知道,GDB的backtrace命令可以查看堆棧信息。但很多時(shí)候,GDB根本用不上。比如說(shuō),在線上環(huán)境中可能沒有GDB,即使有,也不太可能讓我們直接在上面調(diào)試。如果能讓程序自己輸出調(diào)用棧,那是最好不過了。本文介紹和調(diào)用椎棧相關(guān)的幾個(gè)函數(shù)。
NAME
backtrace, backtrace_symbols, backtrace_symbols_fd - support for application self-debugging
SYNOPSIS
#include <execinfo.h>
int backtrace(void **buffer, int size);
char **backtrace_symbols(void *const *buffer, int size);
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
以上內(nèi)容源自這幾個(gè)函數(shù)的man手冊(cè)。
先簡(jiǎn)單介紹一下這幾個(gè)函數(shù)的功能:
l backtrace:獲取當(dāng)前的調(diào)用棧信息,結(jié)果存儲(chǔ)在buffer中,返回值為棧的深度,參數(shù)size限制棧的最大深度,即最大取size步的棧信息。
l backtrace_symbols:把backtrace獲取的棧信息轉(zhuǎn)化為字符串,以字符指針數(shù)組的形式返回,參數(shù)size限定轉(zhuǎn)換的深度,一般用backtrace調(diào)用的返回值。
l backtrace_symbols_fd:它的功能和backtrace_symbols差不多,只不過它不把轉(zhuǎn)換結(jié)果返回給調(diào)用方,而是寫入fd指定的文件描述符。
Man手冊(cè)里,給出了一個(gè)簡(jiǎn)單的實(shí)例,我們看一下:
1 #include<execinfo.h>
2 #include<stdio.h>
3 #include<stdlib.h>
4 #include<unistd.h>
5 6 void myfunc3(
void) {
7 int j, nptrs;
8 #define SIZE 100
9 void *buffer[100];
10 char **strings;
11 nptrs = backtrace(buffer, SIZE);
12 printf("backtrace() returned %d addresses\n", nptrs);
13 /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
14 * would produce similar output to the following: */15 16 strings = backtrace_symbols(buffer, nptrs);
17 if (strings == NULL) {
18 perror("backtrace_symbols");
19 exit(EXIT_FAILURE);
20 }
21 22 for (j = 0; j < nptrs; j++)
23 printf("%s\n", strings[j]);
24 free(strings);
25 }
26 27 static void myfunc2(
void) {
/* "static" means don't export the symbol
*/28 myfunc3();
29 }
30 31 void myfunc(
int ncalls) {
32 if (ncalls > 1)
33 myfunc(ncalls - 1);
34 else35 myfunc2();
36 }
37 38 int main(
int argc,
char *argv[]) {
39 if (argc != 2) {
40 fprintf(stderr,"%s num-calls\n", argv[0]);
41 exit(EXIT_FAILURE);
42 }
43 myfunc(atoi(argv[1]));
44 exit(EXIT_SUCCESS);
45 }
46 編譯:
# cc prog.c -o prog
運(yùn)行:
# ./prog 0
backtrace() returned 6 addresses
./prog() [0x80485a3]
./prog() [0x8048630]
./prog() [0x8048653]
./prog() [0x80486a7]
這樣,是輸出了調(diào)用棧,不過只是以十六進(jìn)制輸出函數(shù)地址而已,可讀性很差。仔細(xì)看下man手冊(cè),原來(lái)很簡(jiǎn)單,編譯時(shí)加上個(gè)參數(shù):
重新編譯:
# cc -rdynamic prog.c -o prog
通過gcc手冊(cè),我們可以也解下參數(shù)的說(shuō)明:
-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.
再執(zhí)行:
# ./prog 0
backtrace() returned 6 addresses
./prog(myfunc3+0x1f) [0x8048763]
./prog() [0x80487f0]
./prog(myfunc+0x21) [0x8048813]
./prog(main+0x52) [0x8048867]
/lib/libc.so.6(__libc_start_main+0xe6) [0xaf9cc6]
./prog() [0x80486b1]
這回,可以看到函數(shù)名了。