没有来自 google breakpad 中剥离二进制文件的符号痕迹 2001 年 5 月 21 日更新

问题描述

documentation 开始,google breakpad 是:

允许您分发应用程序的库和工具套件 删除编译器提供的调试信息的用户

为了证明上述引用,我们将使用这个最小的 c++17 示例进行尝试:

#include <thread>
#include <filesystem>

#include <client/linux/handler/exception_handler.h>

namespace breakpad = google_breakpad;

static bool DumpCallback(const breakpad::MinidumpDescriptor& md,void* context,bool success) {
    (void)md;
    (void)context;
    return success;
}

static void fault(unsigned after) {
    std::this_thread::sleep_for(std::chrono::seconds{after});
    delete reinterpret_cast<std::string*>(0xFEE1DEAD);
}

int32_t main(int argc,char** argv) {
    (void)argc;
    (void)argv;

    auto pwd = std::filesystem::current_path();
    const auto dumpDir = pwd.string() + "/dumps";
    std::filesystem::create_directory(dumpDir);
    breakpad::MinidumpDescriptor md(dumpDir);
    new google_breakpad::ExceptionHandler(
        md,/* FilterCallback */ nullptr,DumpCallback,/* callback_context */ nullptr,true,-1
    );

    fault(1U);

    return EXIT_SUCCESS;
}

在正常的 Debug 构建中,这是预期的结果,因此如果我们尝试运行它,并处理生成的小型转储文件(借助 dump_syms 和 {{ 1}}) 结果是一个很好的符号跟踪:

minidump_stackwalk

但是在部署中,典型的情况是有两个发布版本,一个是普通的Operating system: Linux 0.0.0 Linux 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 cpu: amd64 family 6 model 58 stepping 9 1 cpu GPU: UNKNowN Crash reason: SIGSEGV /SEGV_MAPERR Crash address: 0xfee1dead Process uptime: not available Thread 0 (crashed) 0 core!std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char> >::_M_data() const [basic_string.h : 176 + 0x4] rax = 0x00000000fee1dead rdx = 0x00007ffc12803cc0 rcx = 0x00007fc328087bc1 rbx = 0x000055cdac272940 rsi = 0x00007ffc12803cc0 rdi = 0x00000000fee1dead rbp = 0x00007ffc12803c80 rsp = 0x00007ffc12803c80 r8 = 0x0000000000000000 r9 = 0x000055cdac276bd8 r10 = 0x0000000000000000 r11 = 0x0000000000000246 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1bc20 Found by: given as instruction pointer in context 1 core!std::__cxx11::basic_string<char,std::allocator<char> >::_M_is_local() const [basic_string.h : 211 + 0xc] rbx = 0x000055cdac272940 rbp = 0x00007ffc12803cb0 rsp = 0x00007ffc12803c90 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1bf0b Found by: call frame info 2 core!std::__cxx11::basic_string<char,std::allocator<char> >::_M_dispose() [basic_string.h : 220 + 0xc] rbx = 0x000055cdac272940 rbp = 0x00007ffc12803cd0 rsp = 0x00007ffc12803cc0 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1bc3e Found by: call frame info 3 core!std::__cxx11::basic_string<char,std::allocator<char> >::~basic_string() [basic_string.h : 657 + 0xc] rbx = 0x000055cdac272940 rbp = 0x00007ffc12803cf0 rsp = 0x00007ffc12803ce0 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1b5b6 Found by: call frame info 4 core!fault [main.cpp : 18 + 0xa] rbx = 0x000055cdac272940 rbp = 0x00007ffc12803d20 rsp = 0x00007ffc12803d00 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1b070 Found by: call frame info 5 core!main [main.cpp : 38 + 0xa] rbx = 0x000055cdac272940 rbp = 0x00007ffc12803ea0 rsp = 0x00007ffc12803d30 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x000055cdabc1b182 Found by: call frame info 6 libc.so.6 + 0x2409b rbx = 0x0000000000000000 rbp = 0x000055cdabc43ec0 rsp = 0x00007ffc12803eb0 r12 = 0x000055cdabc1af40 r13 = 0x00007ffc12803f80 r14 = 0x0000000000000000 r15 = 0x0000000000000000 rip = 0x00007fc327ed909b Found by: call frame info 7 core!fault [main.cpp : 19 + 0x3] rsp = 0x00007ffc12803ed0 rip = 0x000055cdabc1b082 Found by: stack scanning 8 core!google_breakpad::FileID::ElfFileIdentifier(google_breakpad::wasteful_vector<unsigned char>&) [file_id.cc : 158 + 0x10] rsp = 0x00007ffc12803ee8 rip = 0x000055cdabc1af40 Found by: stack scanning 9 ld-linux-x86-64.so.2 + 0xf476 rsp = 0x00007ffc12803f40 rip = 0x00007fc3283ef476 Found by: stack scanning 10 core!google_breakpad::FileID::ElfFileIdentifier(google_breakpad::wasteful_vector<unsigned char>&) [file_id.cc : 158 + 0x10] rsp = 0x00007ffc12803f58 rip = 0x000055cdabc1af40 Found by: stack scanning Loaded modules: 0x55cdabc08000 - 0x55cdabc43fff core ??? (main) 0x7fc327eb5000 - 0x7fc32801efff libc.so.6 ??? (WARNING: No symbols,libc.so.6,A8A9B91823C5CFE5E5B5D946D605D0920) 0x7fc328076000 - 0x7fc32808afff libpthread.so.0 ??? 0x7fc328097000 - 0x7fc3280aafff libgcc_s.so.1 ??? 0x7fc3280b1000 - 0x7fc32815cfff libm.so.6 ??? 0x7fc328234000 - 0x7fc328368fff libstdc++.so.6 ??? 0x7fc3283e0000 - 0x7fc3283fefff ld-linux-x86-64.so.2 ??? (WARNING: No symbols,ld-linux-x86-64.so.2,7BFD5DF2BE95A34B86FD71080ACCAE8C0) 0x7ffc12932000 - 0x7ffc12933fff linux-gate.so ??? ,另一个Release(同一个版本,但带有调试符号)。因此,如果您尝试与上述完全相同的例程,但使用从正常发布二进制文件(部署到客户端)和来自 RelWithDebInfo 二进制文件的符号生成的转储文件,您将收到以下跟踪警告您有关主二进制文件的符号:

RelWithDebInfo

还有什么需要我们考虑的吗?

2001 年 5 月 21 日更新

我们用于符号生成的实际脚本:

Operating system: Linux
                  0.0.0 Linux 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64
cpu: amd64
     family 6 model 58 stepping 9
     1 cpu

GPU: UNKNowN

Crash reason:  SIGSEGV /SEGV_MAPERR
Crash address: 0xfee1dead
Process uptime: not available

Thread 0 (crashed)
 0  core + 0xf26a
    rax = 0x0000000000000000   rdx = 0x00005604fdc66209
    rcx = 0x00007f77d9bcfbc1   rbx = 0x00007fffbc001120
    rsi = 0x00007fffbc0010b0   rdi = 0x00007fffbc0010b0
    rbp = 0x00007fffbc0011e0   rsp = 0x00007fffbc0010a0
     r8 = 0x0000000000000000    r9 = 0x00005604ff997be8
    r10 = 0x0000000000000000   r11 = 0x0000000000000246
    r12 = 0x00007fffbc0010e0   r13 = 0x00007fffbc0010c0
    r14 = 0x00007fffbc0010b0   r15 = 0x00005604ff993940
    rip = 0x00005604fdc6626a
    Found by: given as instruction pointer in context
 1  core + 0x36995
    rbp = 0x00007fffbc0011e0   rsp = 0x00007fffbc0011b0
    rip = 0x00005604fdc8d995
    Found by: stack scanning
 2  ld-linux-x86-64.so.2 + 0xf530
    rbp = 0x00007fffbc0011e0   rsp = 0x00007fffbc0011b8
    rip = 0x00007f77d9f37530
    Found by: stack scanning
 3  core + 0xf520
    rbp = 0x00007fffbc0011e0   rsp = 0x00007fffbc0011c8
    rip = 0x00005604fdc66520
    Found by: stack scanning
 4  core + 0x36950
    rsp = 0x00007fffbc0011e8   rip = 0x00005604fdc8d950
    Found by: stack scanning
 5  libc.so.6 + 0x2409b
    rsp = 0x00007fffbc0011f0   rip = 0x00007f77d9a2109b
    Found by: stack scanning
 6  core + 0xef90
    rsp = 0x00007fffbc001210   rip = 0x00005604fdc65f90
    Found by: stack scanning
 7  core + 0xf520
    rsp = 0x00007fffbc001228   rip = 0x00005604fdc66520
    Found by: stack scanning
 8  ld-linux-x86-64.so.2 + 0xf476
    rsp = 0x00007fffbc001280   rip = 0x00007f77d9f37476
    Found by: stack scanning
 9  core + 0xf520
    rsp = 0x00007fffbc001298   rip = 0x00005604fdc66520
    Found by: stack scanning
10  core + 0xf54a
    rsp = 0x00007fffbc0012b0   rip = 0x00005604fdc6654a
    Found by: stack scanning

Loaded modules:
0x5604fdc57000 - 0x5604fdc8dfff  core  ???  (main)  (WARNING: No symbols,core,C33015040F685CBAD56AEFBFD7109D4C0)
0x7f77d99fd000 - 0x7f77d9b66fff  libc.so.6  ???  (WARNING: No symbols,A8A9B91823C5CFE5E5B5D946D605D0920)
0x7f77d9bbe000 - 0x7f77d9bd2fff  libpthread.so.0  ???
0x7f77d9bdf000 - 0x7f77d9bf2fff  libgcc_s.so.1  ???
0x7f77d9bf9000 - 0x7f77d9ca4fff  libm.so.6  ???
0x7f77d9d7c000 - 0x7f77d9eb0fff  libstdc++.so.6  ???
0x7f77d9f28000 - 0x7f77d9f46fff  ld-linux-x86-64.so.2  ???  (WARNING: No symbols,7BFD5DF2BE95A34B86FD71080ACCAE8C0)
0x7fffbc1ad000 - 0x7fffbc1aefff  linux-gate.so  ???

解决方法

在尝试将 minidump_stackwalk 用于应用程序的发布版本时,我遇到了同样的问题。我正在使用 qmake 并使用 qmake 的 CONFIG 标志 force_debug_infoseparate_debug_info 解决了问题。构建后,构建文件夹中会出现 appName.debug 可执行文件)。要转储符号,只需将 appName.debug 文件复制到某处(例如,在构建文件夹中创建子文件夹 debug)并将其重命名为 appName。最后,调用 dump_syms build_folder/debug/appName > appName.sym,您将能够在应用程序的发布版本上执行 minidump_stackwalk。

PS:认为基于 CMake 的项目和其他项目有类似的解决方案。

,

您发送的二进制文件与您的调试符号不匹配。

我认为符号生成本身很好。但是,当您为 RelWithDebinfo 构建生成符号时,您正在发布发布构建。

如果你从你的 RelWithDebInfo 构建中取出二进制文件并剥离它(即在它上面使用 strip),你最终应该得到一个剥离的二进制文件,你可以发送它并且匹配你提取的调试符号。

,

小型转储没有符号。

breakpad 文档告诉开发人员将使用包含的 dump_syms 或 symupload 工具或其他合适的工具创建 Breakpad 使用的符号文件,并将符号文件放在处理器的符号供应商能够找到它们的地方。

所以使用dump_syms生成符号文件,例如'./dump_sys ./my-binary > my.sym'。

然后在使用 minidump_stackwalk 之前,将符号文件放在文件第一行指定的目录中。请参阅 Mozilla 存储库中的 symbolstore.py。 https://github.com/MozillaReality/symbolgenerator

最后,生成一个跟踪栈,使用minidump_stackwalk,这个命令生成跟踪栈并打印出来。