Using
#include <execinfo.h>
人们可以访问用于展开堆栈的方法,至少在大多数 Linux 配置上是这样。但是,这允许将 char * 获取到某些 NTBS(空终止字节字符串),该 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;
}
}
source: http://ideone.com/RWoADT http://ideone.com/RWoADT
是否有任何建议附加此代码以输出人类可读的调试信息?
请注意,我正在实现此功能以与 mex 一起使用,mex 是一个使用 g[++|cc] 的 matlab 编译器。每当我使用该功能时,程序都处于“良好”状态,即检测到错误,但注意到确实发生了;就像分段错误一样。
例如,可以检查 sqrt 的参数是否非负,如果不是,则使用 stck::stacktrace 来显示发生这种情况的位置。
update
我认为这些信息在运行时不能直接获得(虽然我不确定),但只能在可执行文件中获得file,不在可执行文件中text在记忆中。 (如果我错了,请纠正我。
因此我认为没有办法解析可执行文件file,例如通过 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;
}
}