使用
#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;
}
}
是否有任何建议要附加此代码以输出人类可读的调试信息?
作为一个注释,我正在实现这个用于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;
}
}