Programmatically get debug information

956 views Asked by At

Using

#include <execinfo.h>

one can access methods for unwinding the stack, at least on a most linux configurations. However, this allows one to fetch a char * to some NTBS (null terminated byte string) which shows some information, but not all of it, especially not:

  • file names
  • line numbers
  • function names

I have written a bash-script which can deduce a line number and a file using objdump and the text address of the instruction, however its use is tedious as I have to copy paste the address of multiple stack frames to it manually.

Given that g++ allows one to include debugging symbols with the -g command line option, how can I parse and access them in c++ programmatically? Debuggers like gdb and valgrind are also capable of accessing this information at runtime somehow: I'm assuming they use some library for that or if they implement it themselves export the functionality as an API. For example, valgrind defines some interesting function declarations in include/pub_tool_debuginfo.h. Unfortunately, I couldn't find anything else. I created this as a starting point:

#include <execinfo.h>

namespace stck {


class stacktrace_t {};

stacktrace_t stacktrace;

std::ostream &operator<<(std::ostream &out, stacktrace_t) {
  out << "stacktrace:\n";

  size_t max = 256;
  void **stackframes = new void *[max];
  size_t numel;
  while ((numel = backtrace(stackframes, max)) >= max) {
    max *= 2;
    delete[] stackframes;
    stackframes = new void *[max];
  }

  char **symbols = backtrace_symbols(stackframes, numel);
  for(size_t i = 0; i < numel; ++i)
    out << symbols[i] << '\n';

  delete[] stackframes;
  return out;
}


}

source: http://ideone.com/RWoADT

Are there any suggestions to append this code to also output human readable debugging information?

As a note, I'm implementing this for usage with mex, a matlab compiler which uses g[++|cc]. Whenever I'm using the functionality, the program is in a 'good' state, that is an error is detected but noting really has has happened; like a segmentation fault.

For example, one could check if the argument of sqrt is non-negative, and if not use the stck::stacktrace to show where this happened.

update

I think the information is not directly available at runtime (although I'm not sure), but is only available in the executable file, not in the executable text in memory. (Please correct me if I'm wrong.

Hence I think there is no way around parsing the executable file, for example via addre2line:

namespace stck {

std::string getstackframe(char *frame) {
  std::string fr(frame);
  size_t loc0 = fr.find("(");
  size_t loc1 = fr.find(")");
  std::stringstream ss;
  ss << "addr2line -e " << fr.substr(0, loc0) << " -pfC " << fr.substr(loc0 + 2, loc1 - loc0 - 2);

  FILE* pipe = popen(ss.str().c_str(), "r");
  char buffer[128];

  std::stringstream result;
  while(!feof(pipe))
    if (fgets(buffer, 128, pipe) != NULL)
      result << buffer;

  pclose(pipe);
  return result.str();
}

class stacktrace_t {};

stacktrace_t stacktrace;

std::ostream &operator<<(std::ostream &out, stacktrace_t) {
  out << "stacktrace:\n";

  size_t max = 256;
  void **stackframes = new void *[max];
  size_t numel;
  while ((numel = backtrace(stackframes, max)) >= max) {
    max *= 2;
    delete[] stackframes;
    stackframes = new void *[max];
  }

  char **symbols = backtrace_symbols(stackframes, numel);
  for(size_t i = 0; i < numel; ++i)
    out << getstackframe(symbols[i]);

  out << '\n';

  delete[] stackframes;
  return out;
}


}
0

There are 0 answers