How to get a stack trace for C++ using gcc with line number information?

后端 未结 14 2010
长发绾君心
长发绾君心 2020-11-27 09:54

We use stack traces in proprietary assert like macro to catch developer mistakes - when error is caught, stack trace is printed.

I find gcc\'s pair

相关标签:
14条回答
  • 2020-11-27 10:57

    Use the google glog library for it. It has new BSD licence.

    It contains a GetStackTrace function in the stacktrace.h file.

    EDIT

    I found here http://blog.bigpixel.ro/2010/09/09/stack-unwinding-stack-trace-with-gcc/ that there is an utility called addr2line that translates program addresses into file names and line numbers.

    http://linuxcommand.org/man_pages/addr2line1.html

    0 讨论(0)
  • 2020-11-27 10:57

    Here's my third answer -- still trying to take advantage of core dumps.

    It wasn't completely clear in the question whether the "assert-like" macros were supposed to terminate the application (the way assert does) or they were supposed to continue executing after generating their stack-trace.

    In this answer, I'm addressing the case where you want to show a stack-trace and continue executing. I wrote the coredump() function below to generate a core dump, automatically extract the stack-trace from it, then continue executing the program.

    Usage is the same as that of assert(). The difference, of course, is that assert() terminates the program but coredump_assert() does not.

       #include <iostream>
       #include <sys/resource.h> 
       #include <cstdio>
       #include <cstdlib>
       #include <boost/lexical_cast.hpp>
       #include <string>
       #include <sys/wait.h>
       #include <unistd.h>
    
       std::string exename;
    
    // expression argument is for diagnostic purposes (shows up in call-stack)
    void coredump( char const * expression )
       {
    
       pid_t childpid = fork();
    
       if ( childpid == 0 ) // child process generates core dump
          {
          rlimit core_limit = { RLIM_INFINITY, RLIM_INFINITY };
          setrlimit( RLIMIT_CORE, &core_limit ); // enable core dumps
          abort(); // terminate child process and generate core dump
          }
    
    // give each core-file a unique name
       if ( childpid > 0 ) waitpid( childpid, 0, 0 );
       static int count=0;
       using std::string;
       string pid = boost::lexical_cast<string>(getpid());
       string newcorename = "core-"+boost::lexical_cast<string>(count++)+"."+pid;
       string rawcorename = "core."+boost::lexical_cast<string>(childpid);
       int rename_rval = rename(rawcorename.c_str(),newcorename.c_str()); // try with core.PID
       if ( rename_rval == -1 ) rename_rval = rename("core",newcorename.c_str()); // try with just core
       if ( rename_rval == -1 ) std::cerr<<"failed to capture core file\n";
    
      #if 1 // optional: dump stack trace and delete core file
       string cmd = "( CMDFILE=$(mktemp); echo 'bt' >${CMDFILE}; gdb 2>/dev/null --batch -x ${CMDFILE} "+exename+" "+newcorename+" ; unlink ${CMDFILE} )";
       int system_rval = system( ("bash -c '"+cmd+"'").c_str() );
       if ( system_rval == -1 ) std::cerr.flush(), perror("system() failed during stack trace"), fflush(stderr);
       unlink( newcorename.c_str() );
      #endif
    
       }
    
    #ifdef NDEBUG
       #define coredump_assert( expression ) ((void)(expression))
    #else
       #define coredump_assert( expression ) do { if ( !(expression) ) { coredump( #expression ); } } while (0)
    #endif
    
    void recursive( int i=0 )
       {
       coredump_assert( i < 2 );
       if ( i < 4 ) recursive(i+1);
       }
    
    int main( int argc, char * argv[] )
       {
       exename = argv[0]; // this is used to generate the stack trace
       recursive();
       }
    

    When I run the program, it displays three stack traces...

    Core was generated by `./temp.exe'.                                         
    Program terminated with signal 6, Aborted.
    [New process 24251]
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #1  0x00007f2818acbbc3 in abort () from /lib/libc.so.6
    #2  0x0000000000401a0e in coredump (expression=0x403303 "i < 2") at ./demo3.cpp:29
    #3  0x0000000000401f5f in recursive (i=2) at ./demo3.cpp:60
    #4  0x0000000000401f70 in recursive (i=1) at ./demo3.cpp:61
    #5  0x0000000000401f70 in recursive (i=0) at ./demo3.cpp:61
    #6  0x0000000000401f8b in main (argc=1, argv=0x7fffc229eb98) at ./demo3.cpp:66
    Core was generated by `./temp.exe'.
    Program terminated with signal 6, Aborted.
    [New process 24259]
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #1  0x00007f2818acbbc3 in abort () from /lib/libc.so.6
    #2  0x0000000000401a0e in coredump (expression=0x403303 "i < 2") at ./demo3.cpp:29
    #3  0x0000000000401f5f in recursive (i=3) at ./demo3.cpp:60
    #4  0x0000000000401f70 in recursive (i=2) at ./demo3.cpp:61
    #5  0x0000000000401f70 in recursive (i=1) at ./demo3.cpp:61
    #6  0x0000000000401f70 in recursive (i=0) at ./demo3.cpp:61
    #7  0x0000000000401f8b in main (argc=1, argv=0x7fffc229eb98) at ./demo3.cpp:66
    Core was generated by `./temp.exe'.
    Program terminated with signal 6, Aborted.
    [New process 24267]
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #0  0x00007f2818ac9fb5 in raise () from /lib/libc.so.6
    #1  0x00007f2818acbbc3 in abort () from /lib/libc.so.6
    #2  0x0000000000401a0e in coredump (expression=0x403303 "i < 2") at ./demo3.cpp:29
    #3  0x0000000000401f5f in recursive (i=4) at ./demo3.cpp:60
    #4  0x0000000000401f70 in recursive (i=3) at ./demo3.cpp:61
    #5  0x0000000000401f70 in recursive (i=2) at ./demo3.cpp:61
    #6  0x0000000000401f70 in recursive (i=1) at ./demo3.cpp:61
    #7  0x0000000000401f70 in recursive (i=0) at ./demo3.cpp:61
    #8  0x0000000000401f8b in main (argc=1, argv=0x7fffc229eb98) at ./demo3.cpp:66
    
    0 讨论(0)
提交回复
热议问题