简体   繁体   English

交叉编译时Boost堆栈跟踪不会破坏名称

[英]Boost stacktrace not demangling names when cross compiled

In order to generate a stack trace I am using boost::stacktrace .为了生成堆栈跟踪,我使用boost::stacktrace I have a build agent on Debian that is compiling a unix and a windows version of the program.我在 Debian 上有一个构建代理,它正在编译程序的 unix 和 windows 版本。 The Unix version is compiled using the native g++ installed and the windows cross compilation is created using mingw-w64 . Unix 版本使用安装的本机g++编译,Windows 交叉编译使用mingw-w64创建。 I am using the libbacktrace backend for both compilations.我在两个编译中都使用libbacktrace后端。 Both boost and libbacktrace are themselves compiled on the Debian machine using the same mingw-w64 compiler. boost 和 libbacktrace 本身都是在 Debian 机器上使用相同的 mingw-w64 编译器编译的。

In my CMakeLists.txt I specify: add_definitions(-DBOOST_STACKTRACE_USE_BACKTRACE)在我的CMakeLists.txt我指定: add_definitions(-DBOOST_STACKTRACE_USE_BACKTRACE)

A stacktrace is generated like this:堆栈跟踪是这样生成的:

namespace foo {
    class Bar {
    public:
        void fooBar() {
            std::cout << boost::stacktrace::stacktrace() << std::endl;
        }
    };
}

int main(int argc, char *argv[]) {
    foo::Bar bar;
    bar.fooBar();
}

This results in the following output (with -g and no optimization) when compiled on my computer (elementary OS) and when downloaded from the build server on my unix machine.在我的计算机(基本操作系统)上编译以及从我的 unix 机器上的构建服务器下载时,这会产生以下输出(带有 -g 且没有优化)。

 0# foo::Bar::fooBar() in /home/cromon/CLionProjects/test-proj/cmake-build-debug/test-proj
 1# main at /home/cromon/CLionProjects/test-proj/main.cpp:31
 2# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
 3# _start in /home/cromon/CLionProjects/test-proj/cmake-build-debug/test-proj

This is the output with the binary created on the build server on my unix machine:这是在我的 unix 机器上的构建服务器上创建的二进制文件的输出:

 0# foo::Bar::fooBar() in ./test-proj
 1# main at /opt/teamcity/2018.2/TeamCity/buildAgent/work/d79789e141c5605f/test-proj/main.cpp:31
 2# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
 3# _start in ./test-proj

Now if I am using the binary that was compiled using mingw on Unix on my Windows machine the following output can be observed现在,如果我在 Windows 机器上使用在 Unix 上使用 mingw 编译的二进制文件,可以观察到以下输出

0# ZN5boost10stacktrace16basic_stacktraceISaINS0_5frameEEE4initEyy at /opt/teamcity/boost/1_69/windows/include/boost-1_69/boost/stacktrace/stacktrace.hpp:75
1# ZN3foo3Bar6fooBarEv at /opt/teamcity/2018.2/TeamCity/buildAgent/work/eb975d0a928ba129/test_proj/main.cpp:22
2# main at /opt/teamcity/2018.2/TeamCity/buildAgent/work/eb975d0a928ba129/test_proj/main.cpp:31
3# _tmainCRTStartup at ./mingw-w64-crt/crt/crtexe.c:336
4# mainCRTStartup at ./mingw-w64-crt/crt/crtexe.c:214
5# register_frame_ctor in C:\WINDOWS\System32\KERNEL32.DLL
6# register_frame_ctor in C:\WINDOWS\SYSTEM32\ntdll.dll

I have also tried to loop through the frames and run a boost::core::demangle on them, but it fails to do so.我还尝试遍历帧并对它们运行boost::core::demangle ,但它没有这样做。

There is so far only one difference I can see between the compilation environment on unix and the runtime environment on my windows machine.到目前为止,我只能看到 unix 上的编译环境和我的 Windows 机器上的运行时环境之间的一个区别。 On Windows I have g++ of version 8.2.0 and on unix it is 6.3.0 .在 Windows 上,我有8.2.0版的g++ ,在 unix 上它是6.3.0 Is this causing any problems?这会导致任何问题吗? What else could cause the demangling to fail only on windows when cross compiled?交叉编译时,还有什么可能导致 demanling 仅在 Windows 上失败?

TL/DR: libbacktrace for some reason strips leading underscores and boost improperly calls backtrace_pcinfo -> Issue for libbacktrace and boost will be created (fixed in my local compilations) TL/DR:libbacktrace 由于某种原因去掉了前导下划线和 boost 不正确地调用backtrace_pcinfo -> 将创建 libbacktrace 和 boost 问题(在我的本地编译中修复)

More detailed response:更详细的回复:

I was able to figure out the weird behavior by creating a debug build of libbacktrace and stepping through the code.通过创建 libbacktrace 的调试版本并逐步执行代码,我能够找出奇怪的行为。 There is - in my opinion - a bug in both boost and libbacktrace.在我看来,boost 和 libbacktrace 都存在一个错误。

Very high level explanation how boost::stacktrace works when the libbacktrace backend is selected:选择 libbacktrace 后端时 boost::stacktrace 如何工作的非常高级的解释:

  • Call backtrace_pcinfo , this will read (on first call) and search through the DWARF debug information (at least the mingw implementation)调用backtrace_pcinfo ,这将读取(在第一次调用时)并搜索 DWARF 调试信息(至少是 mingw 实现)
  • If the previous call was successful it will return here since it will have gotten more than enough info (function, file, line)如果前一次调用成功,它将返回此处,因为它将获得足够多的信息(函数、文件、行)
  • If it returned zero, it will try to call backtrace_syminfo .如果它返回零,它将尝试调用backtrace_syminfo This will (for mingw) search the coff symbol table这将(对于 mingw)搜索 coff 符号表
  • If it returned zero you will get a raw address printed, otherwise at least the function name (no file/line)如果它返回零,你将得到一个原始地址打印,否则至少是函数名称(无文件/行)

The first bug/unexpected behavior I was able to trace back to libbacktrace (pun intended).我能够追溯到 libbacktrace(双关语)的第一个错误/意外行为。 The implementation in gcc/pecoff.c#440 for some reason strips the leading underscore if it is present.由于某些原因, gcc/pecoff.c#440 中的实现会去除前导下划线(如果存在)。 That is the reason the function names all lack their leading underscore and cannot be demangled.这就是函数名称都缺少其前导下划线并且不能被破坏的原因。 I think this can be considered a bug, or at least I dont see any other reason than a failed attempted at pretty printing symbols.我认为这可以被认为是一个错误,或者至少除了尝试漂亮的打印符号失败之外,我没有看到任何其他原因。

Now the attentive reader probably remembers from my question that I am using debug information, so it should not need to get into the coff symbol table but instead should use the DWARF debug information.现在细心的读者可能从我的问题中记得我正在使用调试信息,所以它应该不需要进入 coff 符号表,而是应该使用 DWARF 调试信息。 And this is where the bug with boost is located.这就是 boost 错误所在的地方。

backtrace_pcinfo has to be called with two callbacks.必须使用两个回调调用backtrace_pcinfo The first will receive the resolved symbol info (if any) and the second is an error callback.第一个将接收解析的符号信息(如果有),第二个是错误回调。 When a symbol is found the first callback is called and its return value is returned from backtrace_pcinfo or in code:当找到一个交易品种时,将调用第一个回调,并从backtrace_pcinfo或代码中返回其返回值:

return of backtrace_pcinfo : return state->fileline_fn (state, pc, callback, error_callback, data);返回backtrace_pcinfo : return state->fileline_fn (state, pc, callback, error_callback, data);

fileline_fn for mingw is the dwarf implementation dwarf_fileline which returns like this: mingw 的fileline_fn是矮人实现dwarf_fileline ,它返回如下:

ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
        data, &found);
if (ret != 0 || found)
  return ret;

dwarf_lookup_pc now returns what the callback returned when a symbol is found: return callback (data, pc, filename, lineno, function->name); dwarf_lookup_pc现在返回找到符号时回调返回的内容: return callback (data, pc, filename, lineno, function->name);

Now lets see how the callback looks boost is supplying:现在让我们看看 boost 提供的回调看起来如何:

inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
    pc_data& d = *static_cast<pc_data*>(data);
    if (d.filename && filename) {
        *d.filename = filename;
    }
    if (d.function && function) {
        *d.function = function;
    }
    d.line = lineno;
    return 0;
}

Since the return value is directly propagated to backtrace_pcinfo this means that this check will always go into the or case no matter if anything was found:由于返回值直接传播到backtrace_pcinfo这意味着无论是否找到任何内容,此检查将始终进入or情况:

        ::backtrace_pcinfo(
            state,
            reinterpret_cast<uintptr_t>(addr),
            boost::stacktrace::detail::libbacktrace_full_callback,
            boost::stacktrace::detail::libbacktrace_error_callback,
            &data
        ) 
        ||
        ::backtrace_syminfo(
            state,
            reinterpret_cast<uintptr_t>(addr),
            boost::stacktrace::detail::libbacktrace_syminfo_callback,
            boost::stacktrace::detail::libbacktrace_error_callback,
            &data
        );

This means it will always use the implementation that somehow strips the leading space.这意味着它将始终使用以某种方式去除前导空格的实现。 I changed the callback to return 1 and now everything is fine.我将回调更改为返回1 ,现在一切正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM