TL / DR: libbacktrace по какой-то причине удаляет лидирующие подчеркивания и неправильно увеличивает вызовы backtrace_pcinfo
-> Будет создана проблема для libbacktrace и boost (исправлено в моих локальных компиляциях)
Более подробный ответ:
Мне удалось выяснить странное поведение путем создания отладочной сборки libbacktrace и пошагового выполнения кода. На мой взгляд, есть ошибка в boost и libbacktrace.
Объяснение очень высокого уровня, как работает boost :: stacktrace, когда выбран бэкэнд libbacktrace:
- Вызовите
backtrace_pcinfo
, это будет считывать (при первом вызове) и искать в отладочной информации DWARF (по крайней мере, в реализации mingw)
- Если предыдущий вызов был успешным, он вернется сюда, поскольку получит более чем достаточно информации (функция, файл, строка)
- Если он вернул ноль, он попытается вызвать
backtrace_syminfo
. Это (для mingw) будет искать таблицу символов coff
- Если он вернул ноль, вы получите распечатанный необработанный адрес, в противном случае как минимум имя функции (без файла / строки)
Первая ошибка / неожиданное поведение, которое я смог отследить до libbacktrace (каламбур). Реализация в gcc / pecoff.c # 440 по какой-то причине удаляет начальное подчеркивание, если оно присутствует. По этой причине всем именам функций не хватает начального подчеркивания, и они не могут быть разделены. Я думаю, что это можно считать ошибкой, или, по крайней мере, я не вижу другой причины, кроме неудачной попытки печати красивых символов.
Теперь внимательный читатель, вероятно, помнит из моего вопроса, что я использую отладочную информацию, поэтому он не должен попадать в таблицу символов coff, а вместо этого должен использовать отладочную информацию DWARF. И именно здесь находится ошибка с boost.
backtrace_pcinfo
должен вызываться с двумя обратными вызовами. Первый получит информацию о разрешенном символе (если есть), а второй - обратный вызов ошибки. Когда символ найден, вызывается первый обратный вызов, и его возвращаемое значение возвращается из backtrace_pcinfo
или в коде:
возврат backtrace_pcinfo
: return state->fileline_fn (state, pc, callback, error_callback, data);
fileline_fn
для mingw - это карликовая реализация dwarf_fileline
, которая возвращается так:
ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback,
data, &found);
if (ret != 0 || found)
return ret;
dwarf_lookup_pc
теперь возвращает результат обратного вызова при обнаружении символа: return callback (data, pc, filename, lineno, function->name);
Теперь давайте посмотрим, как обеспечивает обратный вызов:
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;
}
Поскольку возвращаемое значение напрямую распространяется на 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
);
Это означает, что он всегда будет использовать реализацию, которая каким-то образом удаляет начальное пространство. Я изменил обратный вызов для возврата 1
и теперь все в порядке.