generating stack trace on OS X

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#include <iostream>
#include <execinfo.h>
#include <cxxabi.h>
#include <string>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <memory>

class StackTraceGenerator
{
private:

    //  this is a pure utils class
    //  cannot be instantiated
    //
    StackTraceGenerator() = delete;
    StackTraceGenerator(const StackTraceGenerator&) = delete;
    StackTraceGenerator& operator=(const StackTraceGenerator&) = delete;
    ~StackTraceGenerator() = delete;

public:

    static std::vector<std::string> GetTrace()
    {
        //  record stack trace upto 128 frames
        int callstack[128] = {};

        // collect stack frames
        int  frames = backtrace((void**) callstack, 128);

        // get the human-readable symbols (mangled)
        char** strs = backtrace_symbols((void**) callstack, frames);

        std::vecto<std::string>r stackFrames;
        stackFrames.reserve(frames);

        for (int i = 0; i < frames; ++i)
        {
            char functionSymbol[1024] = {};
            char moduleName[1024] = {};
            int  offset = 0;
            char addr[48] = {};

            /*

             Typically this is how the backtrace looks like:

             0   <app/lib-name>     0x0000000100000e98 _Z5tracev + 72
             1   <app/lib-name>     0x00000001000015c1 _ZNK7functorclEv + 17
             2   <app/lib-name>     0x0000000100000f71 _Z3fn0v + 17
             3   <app/lib-name>     0x0000000100000f89 _Z3fn1v + 9
             4   <app/lib-name>     0x0000000100000f99 _Z3fn2v + 9
             5   <app/lib-name>     0x0000000100000fa9 _Z3fn3v + 9
             6   <app/lib-name>     0x0000000100000fb9 _Z3fn4v + 9
             7   <app/lib-name>     0x0000000100000fc9 _Z3fn5v + 9
             8   <app/lib-name>     0x0000000100000fd9 _Z3fn6v + 9
             9   <app/lib-name>     0x0000000100001018 main + 56
             10  libdyld.dylib      0x00007fff91b647e1 start + 0

             */

            // split the string, take out chunks out of stack trace
            // we are primarily interested in module, function and address
            sscanf(strs[i], "%*s %s %s %s %*s %d",
                   &moduleName, &addr, &functionSymbol, &offset);

            int   validCppName = 0;
            //  if this is a C++ library, symbol will be demangled
            //  on success function returns 0
            //
            char* functionName = abi::__cxa_demangle(functionSymbol,
                                                     NULL, 0, &validCppName);

            char stackFrame[4096] = {};
            if (validCppName == 0) // success
            {
                sprintf(stackFrame, "(%s)\t0x%s — %s + %d",
                        moduleName, addr, functionName, offset);
            }
            else
            {
                //  in the above traceback (in comments) last entry is not
                //  from C++ binary, last frame, libdyld.dylib, is printed
                //  from here
                sprintf(stackFrame, "(%s)\t0x%s — %s + %d",
                        moduleName, addr, functionName, offset);
            }

            if (functionName)
            {
                free(functionName);
            }

            std::string frameStr(stackFrame);
            stackFrames.push_back(frameStr);
        }
        free(strs);

        return stackFrames;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
struct StackTracePrinter
{
    void operator()() const
    {
        auto frames = StackTraceGenerator::GetTrace();
        std::for_each(frames.cbegin(), frames.cend(),
                      [](const std::string& frame)
                        {std::cout << frame << std::endl;});
    }
};

void fn0()
{
    StackTracePrinter stPrinter;
    stPrinter();
}


And the output is:

/wp-content/uploads/2013/04/stack-trace.png

 

Related Links (click to expand..)