A few days ago to help colleagues follow a program inexplicable exit, no core dump (of course ulimit is open) problem. We know that under normal circumstances, if the program exits due to an abnormal condition, it should produce a core dump, and if the program exits normally, it should call the exit () related function directly or indirectly. Based on this fact, I think of this method, at the beginning of the program, through the system provided by the atexit (), the system to register a callback function, when the program call exit () exit, the callback function will be called, and then we in the callback function to print out the current function call stack, This lets you know where exit () is called, so the above problem is solved. The above method is very effective to solve similar problems. In the above, I mentioned in the "callback function print out the current function call stack", I believe that careful friends should notice this, the main content of this article is detailed introduction, how to print in the program of the current function call stack.
I have written a topic for the "introduction of a few about the C + + program debugging function" article, see here, please reader friends First look at the previous article, because this article is based on the previous article. I used the two functions of BackTrace () and Backtrace_symbols (), and here is a simple example where we can introduce the specific method:
12345678910111213141516171819202122232425262728293031323334353637383940414243 |
#include <execinfo .h> #include <stdio .h> #include <stdlib .h> void fun1 (); void fun2 (); void Fun3 (); void Print_stacktrace (); int main () { fun3 ();} void Fun1 () { printf ("Stackstrace begin:\n"); Print_stacktrace ();} void Fun2 () { fun1 (),} void Fun3 () { fun2 ();} void Print_stacktrace () { int size = +; void * ARRAY[16]; int stack_num = backtrace (array, size); char * * StackTrace = backtrace_symbols (array, stack_num); for (int i = 0; i < stack_num; ++i) { printf ("%s\n", Stacktrace[i]); } Free (stacktrace);} |
(Description: The following introduction uses the environment is Ubuntu 11.04, x86_64, gcc-4.5.2)
- 1. Compile the run in the following way:
12345678910 |
[Email protected]:~/work/test$ gcc test.cc-o test1[email protected]:~/work/test$./test1stackstrace begin:./test1 () [ 0x400645]./test1 () [0x400607]./test1 () [0x400612]./test1 () [0x40061d]./test1 () [0x4005ed]/lib/x86_64-linux-gnu/ Libc.so.6 (__LIBC_START_MAIN+0XFF) [0x7f5c59a91eff]./test1 () [0x400529] |
From the above results, we do see the function of the call stack, but all are 16 binary address, will be a little bit uncomfortable. Of course we can get the corresponding function of each address by disassembly, but this is a bit of a hassle. No hurry, and listen to me slowly, to see the 2nd step.
- 2. Compile the run in the following way:
12345678910 |
[Email protected]:~/work/test$ gcc test.cc-rdynamic-o test2[email protected]:~/work/test$./test2stackstrace begin:./ Test2 (_z16print_stacktracev+0x26) [0x4008e5]./test2 (_z4fun1v+0x13) [0x4008a7]./test2 (_z4fun2v+0x9) [0x4008b2]./ Test2 (_z4fun3v+0x9) [0x4008bd]./test2 (main+0x9) [0x40088d]/lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xff ) [0x7f9370186eff]./test2 () [0X4007C9] |
Finally, you can see the function's name, compare the 2 and 1 compilation process, 2:1 more than a-rdynamic option, let's see what this option is (from GCC mannual note):
12 |
-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. |
As you can see from the above note, the main function of the linker is to have all the symbols added to the dynamic symbol table, which is understood. But here's another problem, where the function names are mangle and need demangle to see the original function. About the mangle/demangle mechanism of C + +, do not know the friend can search on the searching engine, I here is not much on the introduction. Here's how to use commands to Demangle, and with the C++filt command you can:
12 |
[Email protected]:~/work/test$ c++filt < << "_z16print_stacktracev" Print_stacktrace () |
Writing here, most of the work is OK. But do not know whether people think of such a problem, the same function can be called in the code in multiple places, if we just know the function, and do not know where to invoke, sometimes is not convenient, bingo, this also has the method, can be done by Address2line command, We use the Test2 compiled in the 2nd step to do the experiment (Address2line-f option can play the function name, the-C option can also be Demangle):
1234 |
[Email protected]:~/work/test$ addr2line-a 0x4008a7-e test2-f0x00000000004008a7_z4fun1v??:0 |
Oh no, how to punch out the location information is garbled? No hurry, and look at our 3rd step.
- 3. Compile the run in the following way:
1234567891011121314 |
[Email protected]:~/work/test$ gcc test.cc-rdynamic-g-o test3[email protected]:~/work/test$./test3stackstrace begin: ./TEST3 (_z16print_stacktracev+0x26) [0x4008e5]./test3 (_z4fun1v+0x13) [0x4008a7]./test3 (_Z4fun2v+0x9) [0x4008b2]./ Test3 (_z4fun3v+0x9) [0x4008bd]./test3 (main+0x9) [0x40088d]/lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0xff ) [0x7fa9558c1eff]./test3 () [0x4007c9][email protected]:~/work/test$ addr2line-a 0x4008a7-e test3-f- C0X00000000004008A7FUN1 ()/home/wuzesheng/work/test/test.cc:20 |
Looking at the results above, we not only get the call stack, but also get the name of each function, as well as the location of the call, done. Here to explain that the 3rd step than the 2nd step more than a-G option, the main role of the-G option is to generate debugging information, location information is the scope of debugging information, often with GDB's friends believe that this option is not unfamiliar.
Good text to the topfollow me to collect this article
C + + Print stack information