Skip to content

Instantly share code, notes, and snippets.

@heapwolf
Last active August 29, 2016 15:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heapwolf/26ff79b82e5f310e2d53 to your computer and use it in GitHub Desktop.
Save heapwolf/26ff79b82e5f310e2d53 to your computer and use it in GitHub Desktop.
a simple zero-touch, header only stack-trace provider for c++
#ifndef STACK_TRACE_H
#define STACK_TRACE_H
#include <iostream>
#include <signal.h>
#include <string>
#include <dlfcn.h>
#include <cxxabi.h>
#include <regex>
#include <execinfo.h>
struct Trace {
struct sigaction sa;
Trace() {
using namespace std;
auto backtrace_handler = [](int sig) {
string white = "\033[1;37m";
string blue = "\033[1;34m";
cout << white << "Error: ";
switch (sig) {
case SIGSEGV:
cout << "Segmentation fault" << endl;
break;
case SIGFPE:
cout << "Floating point exception" << endl;
break;
case SIGBUS:
cout << "An invalid pointer was dereferenced" << endl;
break;
}
void* callstack[128];
size_t size = backtrace(callstack, 128);
char** symbols = backtrace_symbols(callstack, size);
for (size_t i = 0; i < size; i++) {
Dl_info info;
int res = dladdr(callstack[i], &info);
string s = symbols[i];
int f = s.find_last_of(" + ");
s = s.substr(0, f - 2);
f = s.find_last_of(" ");
s = s.substr(f + 1, s.size());
int status = 0;
char* name = abi::__cxa_demangle(s.c_str(), NULL, NULL, &status);
if (status == 0 && string(name).find("Trace::Trace()") == string::npos) {
cout
<< white << " at " << blue << name
<< white << " in " << info.dli_fname << endl;
}
}
abort();
};
sa.sa_handler = backtrace_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
} trace;
#endif
@heapwolf
Copy link
Author

Given a total shitbird like this with say a floating point error or a seg fault...

#include "trace.hpp"

namespace sample {
  auto ohhai = [](int n) {

    auto f = [&]() {
      char* ptr = (char*)42;
      int v = *ptr;
      return v;
      //return 42/n;
    };

    f();
  };
}

void foo() {
  using namespace sample;
  auto x = [&]() {
    ohhai(0);
  };
  x();
}

int main() {
  foo();
}

We can get something like this...

image

as opposed to this useless turd...

image

@heapwolf
Copy link
Author

this may be possible by porting addr2line?? maybe a huge rabbit hole, elfutils etc.

@radare
Copy link

radare commented Sep 14, 2015

In r2land we have our own dwarf parser. it's not as bloated as the dwarfutils or the binutils ones, and it's under LGPL. Feel free to grab it and do whatever you need. We can discuss about changing the license of it if necessary.

@heapwolf
Copy link
Author

This really doesn't need improvement. just do ulimit -c unlimited, then lldb -c /cores/core.<pid> and type gui as the command. This will blow your mind, full scrollable version of your source file extracted from the dump, thread specific stack frames etc. etc.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment