Нет следов символов из удаленных двоичных файлов в блокноте Google

Из документации блокнот Google выглядит так:

библиотека и набор инструментов, которые позволяют вам распространять приложение среди пользователей с удаленной отладочной информацией, предоставленной компилятором

Для доказательства приведенной выше цитаты мы попробуем это с этим минимальным образцом С++ 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 и 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::char_traits<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::char_traits<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::char_traits<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, вы получите следующую трассировку, предупреждающую вас о символах для основного двоичного файла:

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, libc.so.6, 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, ld-linux-x86-64.so.2, 7BFD5DF2BE95A34B86FD71080ACCAE8C0)
0x7fffbc1ad000 - 0x7fffbc1aefff  linux-gate.so  ???

Есть ли что-то еще, что мы должны рассмотреть?

Обновление от 21 мая 2001 г.

Фактический скрипт, который мы используем для генерации символов:

#!/bin/bash

#
# e.g ./dump.sh ./exec $PWD/dumps
#

set -e
set -u

DBG_INFO=$(realpath ${1})
DUMPS_DIR=$(realpath ${2:-$PWD/dumps})
DUMP_SYMS=${3:-~/WorkSpace/libraries/breakpad/src/tools/linux/dump_syms/dump_syms}
STAK_WALK=${4:-~/WorkSpace/libraries/breakpad/src/processor/minidump_stackwalk}

#
# Generate debug symbols
#
base=$(basename $DBG_INFO)
$DUMP_SYMS $DBG_INFO > $DUMPS_DIR/$base.sym

#
# Create dump dir structure
#
list=($(head -n1 $DUMPS_DIR/$base.sym))
hash=${list[3]}
mkdir -p $DUMPS_DIR/symbols/$base/$hash
mv $DUMPS_DIR/$base.sym $DUMPS_DIR/symbols/$base/$hash

#
# Produce stack trace
#
RED='\033[0;36m'
NC='\033[0m' # No Color
tree $DUMPS_DIR
for dmp in $DUMPS_DIR/*.dmp ; do
    filename=$(basename -- "${dmp}")
    filename="${filename%.*}"
    echo -e "generating stack trace for -> ${RED}${dmp}${NC}"
    $STAK_WALK ${dmp} $DUMPS_DIR/symbols > $DUMPS_DIR/${filename}.txt 2>/dev/null
done

person IMAN4K    schedule 30.04.2021    source источник
comment
Я не уверен, что правильно понял вопрос: я бы предположил, что в сборке релиза будут удалены символы отладки, поскольку это обычно считается правильным поведением? Если есть какая-то магия в Google Breakpad для создания этих мини-дампов (не знаю этот инструмент, но мне очень интересно :)), тогда ему нужен двоичный файл отладки, поскольку в выпуске нет никакой информации об отладке, верно?   -  person FloWil    schedule 03.05.2021
comment
Да. это правильно, вы должны получать аварийные дампы из вашего бинарного файла развернутого релиза точно так же, как Google Chrome или Mozilla Firefox, а затем выгружать его точно таким же бинарным файлом отладки   -  person IMAN4K    schedule 03.05.2021
comment
Да, я так и думал. Тем не менее, файл символов, сгенерированный breakpad и позже используемый для анализа входящих аварийных дампов, должен иметь отладочный исполняемый файл для получения информации, не так ли? При попытке сгенерировать файл символов из уже очищенного двоичного файла выпуска там не осталось информации для заполнения файла символов. Не знаю, применим ли файл символов, сгенерированный из двоичного файла отладки, к двоичному файлу выпуска, касающемуся аварийных дампов.   -  person FloWil    schedule 03.05.2021
comment
Да, это то, о чем мы должны позаботиться, на самом деле, у нас есть две версии двоичного файла: одна как Release и одна как RelWithDebInfo (как в CMake), но с ней все еще нет результата. , мне кажется, на этот процесс влияет уровень оптимизации, так что если вы попытаетесь сгенерировать трассировку для отладочной версии с -O2 символы пропадут! (шаги как раньше)   -  person IMAN4K    schedule 03.05.2021
comment
Не могли бы вы попробовать void __attribute__ ((noinline)) fault(unsigned after), нет staticни того, ни другого.   -  person Devolus    schedule 04.05.2021
comment
@Деволус. Я попробовал, и никакой разницы в процессе (я думаю, со встроенным или без него мы должны увидеть номер строки для точки сбоя), по-прежнему нет трассировки символов! еще более странно, что мы не смогли получить трассировку из сборки Release с символами отладки (RelWithDebInfo в CMake), это проблема с уровнем оптимизации или я пропустил что-то среднее!   -  person IMAN4K    schedule 04.05.2021


Ответы (3)


Я столкнулся с той же проблемой при попытке использовать minidump_stackwalk для релизной версии приложения. Я использую qmake и решил проблему, используя флаги CONFIG qmake force_debug_info и separate_debug_info. После сборки в папке сборки появится appName.debug исполняемый файл). Чтобы сбросить символы, просто скопируйте файл appName.debug куда-нибудь (например, создайте подпапку debug в папке сборки) и переименуйте его в appName. Наконец, вызовите dump_syms build_folder/debug/appName > appName.sym, и вы сможете выполнить minidump_stackwalk поверх релизной версии приложения.

PS: Думаю, есть подобное решение для CMake и других проектов.

person Rustem Husnutdinov    schedule 19.05.2021
comment
Нет смысла, .debug - это просто команда objcopy --only-keep-debug, запущенная в основном двоичном файле, чтобы разделить символы отладки. - person IMAN4K; 19.05.2021
comment
Возможно, я вас неправильно понял, но, как я вижу в вашем основном посте, вы пытаетесь использовать символы RelWithDebInfo для отладки версии Release. Это не сработает. Вам нужны символы, полученные из одного и того же двоичного файла. Уникальные идентификаторы должны быть одинаковыми и т. д. - person Rustem Husnutdinov; 20.05.2021
comment
Нам нужна точно такая же сборка, это правда, но дело в том, что если вы добавите минимальный уровень оптимизации к вашей предыдущей сборке (предположим, что обе имеют символы отладки), на выходе не будет символизированной трассировки! - person IMAN4K; 20.05.2021
comment
И, кстати, я прямо упоминаю тот же выпуск, но с символами отладки в исходном сообщении. - person IMAN4K; 20.05.2021

Вы отправляете двоичный файл, который не соответствует вашим отладочным символам.

Я думаю, что сама генерация символов в порядке. Однако вы отправляете сборку Release, в то время как ваши символы были сгенерированы для сборки RelWithDebinfo.

Если вы возьмете двоичный файл из сборки RelWithDebInfo и разделите его (т. е. примените к нему strip), вы должны получить очищенный двоичный файл, который вы можете отправить и который соответствует вашим извлеченным символам отладки.

person Andreas Rogge    schedule 09.05.2021
comment
Две конфигурации сборки по существу одинаковы, RelWithDebinfo — это сборка Release со встроенными символами отладки (-g). тем не менее, здесь есть основной момент: если вы добавите уровни оптимизации в сборку отладки (скажем, -O1), вы не сможете получить символы, подобные исходному сообщению! поэтому я предполагаю, что проблема с уровнем оптимизации - person IMAN4K; 09.05.2021
comment
Вы можете просто readelf -n генерировать полученные двоичные файлы и посмотреть, совпадает ли идентификатор сборки. Если они совпадают, символы должны работать во всех сборках, иначе — нет. Однако не воспользоваться этим шансом и сэкономить время, не создавая дважды, вероятно, проще и менее подвержено ошибкам. - person Andreas Rogge; 10.05.2021

минидамп не имеет символа.

В документации breakpad говорится, что разработчик создаст файлы символов для использования в Breakpad с помощью прилагаемых инструментов dump_syms или symupload или другого подходящего инструмента, и разместит файлы символов там, где поставщик символов процессора сможет их найти.

Поэтому используйте dump_syms для создания файла символов, например, './dump_sys ./my-binary › my.sym'.

Затем перед использованием minidump_stackwalk поместите файл символов в каталог, указанный в первой строке файла. См. symbolstore.py в репозитории Mozilla. https://github.com/MozillaReality/symbolgenerator

Наконец, сгенерируйте стек трассировки, используйте minidump_stackwalk, эта команда создаст стек трассировки и распечатает его.

person Lintong He    schedule 07.05.2021