ngryman/ribs

View on GitHub
src/debug.cc

Summary

Maintainability
Test Coverage
/*!
 * ribs
 * Copyright (c) 2013-2014 Nicolas Gryman <ngryman@gmail.com>
 * LGPL Licensed
 */

#include "debug.h"

using namespace std;
using namespace ribs;

#ifdef DEBUG

#include <execinfo.h>
#include <cxxabi.h>
#include <iostream>

static inline string parseBinary(string& symbol);
static inline string parseFunction(string& symbol);

void Debug::PrintStackTrace(string text) {
    if (!text.empty())
        cerr << text << endl;

    auto frames = Debug::StackTrace();
    for (auto it = frames.begin(); it != frames.end(); it++)
        cerr << '\t' << *it << endl;
}

vector<string> Debug::StackTrace(int start, int maxFrames) {
    auto frames = vector<string>();

    // storage array for stack trace address data
    void* addrs[maxFrames];

    // retrieve current stack addresses
    int addrsLen = backtrace(addrs, sizeof(addrs) / sizeof(void*));
    if (0 == addrsLen) return frames;

    // resolve addresses into strings containing "filename(function+address)",
    // this array must be free()-ed
    char** symbols = backtrace_symbols(addrs, addrsLen);

    // iterate over all found symbols, except the first which is the address
    // of this function
    //
    // format of a symbol is:
    //   binary(function+address)
    //
    for (int i = start; i < addrsLen; i++) {
        auto symbol = string(symbols[i]);
        auto frame = string(
            parseBinary(symbol) +
            ": " +
            parseFunction(symbol)
        );

        frames.push_back(frame);
    }

    free(symbols);

    return frames;
}

static inline string parseBinary(string& symbol) {
    size_t pos;
    string binary;

    // extract full binary name
    pos = symbol.find('(');
    binary = symbol.substr(0, pos);

    // only keep the base name
    pos = binary.rfind('/');
    if (string::npos != pos)
        binary = binary.substr(pos + 1);

    return binary;
}

static inline string parseFunction(string& symbol) {
    string function;
    size_t lpos, rpos;

    lpos = symbol.find('(') + 1;
    rpos = symbol.find('+');
    if (string::npos == rpos)
        rpos = symbol.find(')');

    function = symbol.substr(lpos, rpos - lpos);

    int status;
    size_t nameLength = 256;
    char name[nameLength];

    abi::__cxa_demangle(&function[0], name, &nameLength, &status);
    if (0 == status)
        function = name;

    return function;
}

#else

vector<string> Debug::StackTrace(int start, int maxFrames) { return vector<string>(); }

#endif