以编程方式获取调试信息

时间:2014-11-24 19:21:35

标签: c++ debugging c++11 debug-symbols

使用

#include <execinfo.h>

可以访问用于展开堆栈的方法,至少在大多数Linux配置上都是如此。但是,这允许人们将char *提取到某个NTBS(空终止字节字符串),它显示一些信息,但不是全部,特别是不是:

  • 文件名
  • 行号
  • 功能名称

我编写了一个bash脚本,它可以使用objdump和指令的文本地址来推断行号和文件,但是它的使用是繁琐的,因为我必须手动将多个堆栈帧的地址粘贴到它。

鉴于g ++允许使用-g命令行选项包含调试符号,如何以编程方式在c ++中解析和访问它们?像gdb和valgrind这样的调试器也能够在运行时以某种方式访问​​这些信息:我假设他们使用了一些库,或者如果他们实现它自己将功能导出为API。例如,valgrind在include / pub_tool_debuginfo.h中定义了一些有趣的函数声明。不幸的是,我找不到任何其他东西。我创建了这个作为起点:

#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;
}


}

来源:http://ideone.com/RWoADT

是否有任何建议要附加此代码以输出人类可读的调试信息?

作为一个注释,我正在实现这个用于mex,一个使用g [++ | cc]的matlab编译器。每当我使用该功能时,程序都处于“良好”状态,即检测到错误但是确实发生了错误;像分段错误。

例如,可以检查sqrt的参数是否为非负数,如果不是,则使用stck :: stacktrace来显示发生的位置。

更新

我认为这些信息不是在运行时直接提供的(虽然我不确定),但仅在可执行文件文件中提供,而不是在可执行文件文本中提供在记忆中。 (如果我错了,请纠正我。

因此我觉得无法解析可执行文件文件,例如通过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 个答案:

没有答案