Мне нужно поймать "фатальный" C++ exception, затем очистить журналы и заново выбросить первый, со своим собственным следом.
Однако мое текущее решение отображает (правильно) неправильную трассировку стека.
#include <exception>
#include <iostream>
void fatal(const std::exception & E)
{
// do - something - extremely - important
throw E;
}
int foo()
{
throw std::runtime_error("yet another foo function");
}
int main()
{
try
{
return foo();
}
catch (const std::exception & E)
{
fatal(E);
}
return -1;
}
Программа завершается
$ cat ./backtrace
backtrace
quit
$ ulimit -c unlimited
$ ./a.out
$ gdb -q ./a.out core -x ./backtrace
Результат
Program terminated with signal SIGABRT, Aborted.
..................................................
4 0x00007f496eb53701 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
5 0x00007f496eb53919 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
6 0x0000000000400d71 in fatal(std::exception const&) ()
7 0x0000000000400e5b in main ()
Я думал, что повторное создание исключения (с помощью const ref) было методом передачи исходной трассировки; Меня интересует обратная трассировка foo(), а не fatal().
В стандартном C++ нет ничего, что связывало бы исключение с «трассировкой». Что бы вы ни описывали, это относится к одной реализации. Вам нужно будет прочитать документацию по этой реализации. Между прочим, чтобы повторно вызвать исключение в обработчике исключений, все, что вам нужно сделать, это throw; - нет необходимости явно повторно генерировать исключение, которое было перехвачено. Имейте в виду, что вызывает terminate(), если нет активного исключения для повторного создания.





Я не уверен, что вы здесь пытаетесь выполнить, но чтобы повторно вызвать исключение, вам нужно написать throw; (без аргументов), throw E; сгенерирует новый экземпляр исключения, скопировав его из существующего объекта.
Не уверен, что это может помочь вам с трассировкой стека. "пройти исходную трассировку" не имеет большого смысла, потому что исключения в C++ не несут никаких обратных трассировок, и к моменту вызова вашего блока catch стек уже был очищен.
С вашим сценарием:
backtrace
quit
... вы увидите трассировку стека только тогда, когда подчиненный собирается выйти (или когда вы используете файл ядра, как в вашем примере, когда он уже вышел), потому что вы не сказали gdb где-либо остановиться.
Другой подход - использовать команду gdb catch throw плюс немного скриптов. Таким образом, вы можете записать трассировку стека на каждом throw. Вы можете сделать это так:
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) commands
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
> silent
> backtrace
> continue
> end
Это остановится на каждом throw и напечатает обратную трассировку. Однако вы не хотите печатать трассировки стека из фрейма fatal. Для этого вы можете использовать вспомогательную функцию gdb и сделать точку перехвата условной:
(gdb) cond 1 $_any_caller_matches("fatal", 10)
(Цифра «10» - это всего лишь предположение о том, сколько кадров может отделять fatal от внутренностей библиотеки C++, которые обрабатывают метание.)
На этот вопрос уже был дан ответ, но я хочу добавить, что в стандартный C++ 11 можно создавать правильные обратные трассировки:
std::nested_exception и std::throw_with_nestedВ StackOverflow здесь и здесь описано, как вы можете проследить ваши исключения внутри своего кода без необходимости в отладчике или громоздком журналировании, просто написав правильный обработчик исключений, который повторно генерирует вложенные исключения.
Однако для этого требуется, чтобы вы обернули все функции, которые вы хотите отслеживать, в блоки try/catch, но это позволяет вам выполнять большую настройку того, что происходит и какая информация печатается. Поскольку вы можете сделать это с любым производным классом исключений, вы можете добавить много информации в такую трассировку!
Вы также можете взглянуть на мой MWE на GitHub или мой библиотека "след", где обратная трассировка будет выглядеть примерно так:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Хорошо, я
throwed внутри блокcatch, отказавшись от области видимостиfatal()... и обратная трассировка такая, как ожидалось