Generally, you can view the function runtime stack by using an external debugger such as GDB. However, in some cases, to analyze program bugs (mainly for analysis of long-running programs ), it is very useful to print the function call stack when a program error occurs.
In the header file "execinfo. H", three functions are declared to obtain the function call stack of the current thread.
Function: int backtrace (void ** buffer, int
Size)
This function is used to obtain the call stack of the current thread. The obtained information is stored in the buffer. It is a pointer list. Parameter size
Used to specify how many void * elements can be stored in the buffer. The return value of a function is the number of actually obtained pointers. The maximum value is not greater than the size. The pointer in the buffer is actually the return address obtained from the stack. Each stack framework has a return address, note that the optimization options of Some compilers interfere with obtaining the correct call stack. In addition, the inline function does not have a stack framework. Deleting the framework pointer will make it impossible to parse the stack content correctly.
Function: Char ** backtrace_symbols (void * const
* Buffer, int size)
Backtrace_symbols converts the information obtained from the backtrace function into a string array.
The buffer parameter should be an array pointer obtained from the backtrace function. size is the number of elements in the array (the return value of Backtrace ). The Return Value of the function is a pointer to a string array, which is the same size as the buffer. each string contains a printable information relative to the corresponding elements in the buffer. it includes the function name, function offset address, and actual return address.
Currently, the function name and offset address can be obtained only by using the ELF binary format program and the difficulty. in other systems, only the return address in hexadecimal format can be obtained. in addition, you may need to pass the corresponding flag to the linker to support the function name function (for example, when using GNU
In the LD system, you need to pass (-rdynamic )).
The return value of this function is the space applied through the malloc function. Therefore, you must use the free function to release the pointer to call this function.
Note: if you cannot obtain sufficient space for a string, the return value of the function will be null.
Function: void backtrace_symbols_fd (void * const * buffer, int size,
Int FD)
Backtrace_symbols_fd and backtrace_symbols
A function has the same function. The difference is that it does not return a string array to the caller, but writes the result to a file with the file descriptor FD. Each function corresponds to a row. it does not need to call the malloc function, so it is applicable to situations where the function may fail to be called.
The following is an example of capturing exceptions using backtrace and printing the function call Stack:
# Include <signal. h> # include <stdio. h> # include <stdlib. h> # include <execinfo. h> # include <sys/types. h> # include <sys/STAT. h> # include <fcntl. h> # include <string. h> # include <unistd. h> # define print_debugstatic void print_reason (INT sig) {void * array [10]; size_t size; size = backtrace (array, 10); # ifdef print_debug char ** strings; int I; strings = backtrace_symbols (array, size); printf ("obtained % d stack FRA MES. \ n ", size); for (I = 0; I <size; I ++) printf (" % s \ n ", strings [I]); free (strings); char cmd [64] = "addr2line-C-f-e"; char * prog = cmd + strlen (CMD ); readlink ("/proc/self/EXE", prog, sizeof (CMD)-strlen (CMD)-1 ); // obtain the complete process path file * fp = popen (CMD, "W"); If (FP! = NULL) {for (I = 0; I <size; ++ I) {fprintf (FP, "% P \ n", array [I]);} pclose (FP) ;}# else int FD = open ("Err. log ", o_creat | o_wronly); backtrace_symbols_fd (array, size, FD); close (FD); # endif exit (0);} void die () {char * test1; char * Test2; char * test3; char * test4 = NULL; strcpy (test4, "AB");} void test1 () {die ();} int main (INT argc, char ** argv) {struct sigaction myaction; myaction. sa_handler = print_reason; sigemptyset (& myaction. sa_mask); myaction. sa_flags = sa_restart | sa_siginfo; sigaction (SIGSEGV, & myaction, null); // Invalid Memory Reference sigaction (SIGABRT, & myaction, null); // terminate test1 () abnormally ();}
The output from my local test is as follows:
Obtained 7 stack frames./root/workspace/test/Debug/test(__gxx_personality_v0+0x12d) [0x80486c1][0x71b440]/root/workspace/test/Debug/test(__gxx_personality_v0+0x2ac) [0x8048840]/root/workspace/test/Debug/test(__gxx_personality_v0+0x2c0) [0x8048854]/root/workspace/test/Debug/test(__gxx_personality_v0+0x339) [0x80488cd]/lib/libc.so.6(__libc_start_main+0xdc) [0xbf3e9c]/root/workspace/test/Debug/test(__gxx_personality_v0+0x5d) [0x80485f1]print_reason/root/workspace/test/Debug/../main.cpp:15????:0die()/root/workspace/test/Debug/../main.cpp:51test1()/root/workspace/test/Debug/../main.cpp:56main/root/workspace/test/Debug/../main.cpp:65????:0_start??:0