Print the call stack information in a C + + program
We know that GdB's backtrace command can view stack information. But a lot of times, GDB doesn't use it at all. For example, there may be no gdb in the online environment, even if there is, it is unlikely that we can directly debug on it. It's best if you can get the program to output the call stack itself. This article describes and calls several functions related to the vertebral stack.
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); |
The above is derived from the man Manual of these functions.
Let's take a brief look at the functions of these functions:
L BackTrace: Gets the current call stack information, the result is stored in buffer, the return value is the depth of the stack, the parameter size limits the maximum depth of the stack, that is, the maximum size step of the stack information.
L Backtrace_symbols: Convert the stack information obtained by backtrace into a string, returned as an array of character pointers, the parameter size limits the depth of the conversion, and is generally used with the return value of the BackTrace call.
L BACKTRACE_SYMBOLS_FD: Its function is similar to Backtrace_symbols, except that it does not return the result of the conversion to the caller, but rather writes the file descriptor specified by FD.
Man Handbook, give a simple example, let's look at:
#include <execinfo.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void Myfunc3 (void) { Int J, Nptrs; #define SIZE 100 void *buffer[100]; Char **strings; Nptrs = backtrace (buffer, SIZE); printf ("BackTrace () returned%d addresses\n", nptrs); /* The call BACKTRACE_SYMBOLS_FD (buffer, nptrs, Stdout_fileno) * would produce similar output to the following: */ strings = Backtrace_symbols (buffer, nptrs); if (strings = = NULL) { Perror ("Backtrace_symbols"); Exit (Exit_failure); } for (j = 0; J < Nptrs; J + +) printf ("%s\n", Strings[j]); Free (strings); } Staticvoid/* "Static" means don ' t export the symbol ... * * Myfunc2 (void) { Myfunc3 (); } void MyFunc (int ncalls) { if (Ncalls > 1) MyFunc (NCALLS-1); Else MYFUNC2 (); } Int Main (int Argc,char *argv[]) { if (argc! = 2) { fprintf (stderr, "%s num-calls\n", argv[0]); Exit (Exit_failure); } MyFunc (Atoi (argv[1)); Exit (exit_success); } |
Compile:
Run:
#./prog 0 BackTrace () returned 6 addresses ./prog () [0X80485A3] ./prog () [0x8048630] ./prog () [0x8048653] ./prog () [0X80486A7] |
This is the output of the call stack, but only the hexadecimal output function address, very poor readability. Look closely at the man Handbook, originally very simple, compile with a parameter:
Recompile:
# cc-rdynamic Prog.c-o Prog |
With the GCC manual, we can also solve the parameter description:
-rdynamic Pass the flag-export-dynamic to the ELF linker, on targets. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option was needed for some uses of ' dlopen ' or to ' allow obtaining backtraces ' from within a program. |
Re-execution:
#./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] |
This time, you can see the function name. Isn't it cool?
Print the call stack in a C or c+ program. Turn