Posted on 2008-09-01 22:30 by Timo at Permlink with Comments. Tags: c++ code-snippet
Yesterday I was tasked to analyzed an inner function of a reasonably complex software package. The inner function was called thousands of times from many different parts of the program, a simple counter print-out showed that. However I was interested in which execution paths reach this inner function and how often the different parts access the function.
My straight-forward idea was to dump a stack backtrace each time the inner function is called, similar to the one printed by a debugger. However I needed some code snippet to dump the stack backtrace programmatically, without using gdb to halt the program each time.
Stack backtraces can be saved with backtrace(3), resolved into symbolic names using backtrace_symbols(3) and printed using backtrace_symbols_fd(3). These functions are well documented and fairly easy to use.
However I was debugging a C++ program, which made heavy use of templates and classes. C++ symbols names (including namespace, class and parameters) are mangled by the compiler into plain text symbols: e.g. the function N::A<int>::B::func(int) becomes the symbol _ZN1N1AIiE1B4funcEi. This makes the standard backtrace output very unreadable for C++ programs.
To demangle these strings the GNU libstdc++ library (integrated into the GNU Compiler Collection) provides a function called __cxa_demangle(). Combined with backtrace(3) a pretty stack backtrace can be outputted. The demangling function only works for programs compiled with g++.
The following header file contains a function print_stacktrace(), which uses backtrace(3), backtrace_symbols(3) and __cxa_demangle() to print a readable C++ stack backtrace.
You can freely use it for whatever purpose: download stacktrace.h. I hope you find this utility function useful.
To demonstrate the stack trace function I wrote the following small test source code. It calls print_stacktrace() four times from different functions, that were specifically crafted to produce complex names. I left it uncommented, because the functions have no real purpose.
When compiled with g++ -rdynamic -o test test.cc the program prints the following output:
Comment by Evgeny at 2008-11-13 05:13 UTC
Thanks a lot
By the way
Do you know any ways to obtain also function's arguments from stack?
Comment by Timo at 2008-11-14 07:20 UTC - http://idlebox.net
No, I know of no automated way to display arguments as well. gdb does that to a degree.
There is of course the fundamental problem of how to display arguments of unprintable types. I'm also not sure if a C/C++ function's signature is stored in a way that can be easily processed, but the mangled function name could provide at least integral type info. Walking the stack should be possible with some detailed fiddeling. Those are my basic ideas on that topic.
Greetings
Comment by Hans at 2010-08-11 08:28 UTC
That's so fantastic. Thank you!
Comment by alexei lebedev at 2010-10-10 03:05 UTC
there memory leak of the original funcname value on this line:
... funcname = ret; // use possibly realloc()-ed string
Comment by Timo at 2011-01-31 13:35 UTC - http://idlebox.net
Nope. That is not a memory leak, because the ret value is either funcname itself, or a new buffer for the name realloc()-ed with a larger size. See the return value of cxa_demangle() on the man page.
Timo
Comment by Joe at 2011-03-23 13:04 UTC
Thanks, that was very usefull.
Comment by mark dufour at 2011-06-04 16:52 UTC - http://shedskin.googlecode.com
wonderful, thanks! I used it in shedskin, a restricted-python-to-c++ compiler, to enable at least some kind of exception backtraces for now. now for those filenames and line numbers.. :-)
Comment by Nicholas at 2011-08-22 00:30 UTC
Awesome code snippet.
Comment by Julia at 2011-09-28 10:43 UTC - http://juliase@kth.se
Hello, This is great. But I need a line number in the source code as well (as the gdb-tool provides). I would like to extract it programmatically i.e. without starting gdb. Do you think it is possible? Can you give me a hint? Many thanks in advance. Kind regards :-)
Comment by Timo at 2011-10-10 09:25 UTC - http://idlebox.net
Nope. Sorry, I'm not aware of any method to read the debug info. Maybe the gdb manual will help.
Comment by Prasad H. L. at 2008-10-06 10:20 UTC
Thanks a lot for sharing your code! That was very useful!