печать стека вызовов на языке C или c++
есть ли способ сбросить стек вызовов в запущенном процессе в C или c++ каждый раз, когда вызывается определенная функция? Что я имею в виду что-то вроде этого:
void foo()
{
print_stack_trace();
// foo's body
return
}
здесь print_stack_trace работает аналогично caller в Perl.
или что-то вроде этого:
int main (void)
{
// will print out debug info every time foo() is called
register_stack_trace_function(foo);
// etc...
}
здесь register_stack_trace_function помещает какую-то внутреннюю точку останова, которая приведет к печати трассировки стека всякий раз, когда foo называется.
делает что-нибудь вроде это существует в какой-то стандартной библиотеки C?
Я работаю на Linux, используя GCC.
фон
у меня есть тестовый запуск, который ведет себя по-разному на основе некоторых параметров командной строки, которые не должны влиять на это поведение. Мой код имеет генератор псевдослучайных чисел, который, как я предполагаю, вызывается по-разному на основе этих переключателей. Я хочу иметь возможность запускать тест с каждым набором переключателей и посмотреть, вызывается ли генератор случайных чисел по-разному для каждого из них.
10 ответов:
для решения только для linux вы можете использовать backtrace (3) это просто возвращает массив
void *(фактически каждый из них указывает на обратный адрес из соответствующего кадра стека). Чтобы перевести их на что-то полезное, есть backtrace_symbols(3).обратите внимание Примечания раздел в backtrace (3):
имена символов могут быть недоступны без использования специального линкера опции. Для систем, использующих компоновщик GNU, необходимо использовать - rdynamic linker выбор. Обратите внимание, что имена "статических" функций не отображаются, и не будет доступно в обратном направлении.
нет стандартизированного способа сделать это. Для windows функциональность предоставляется в DbgHelp библиотека
есть ли способ сбросить стек вызовов в запущенном процессе в C или c++ каждый раз, когда вызывается определенная функция?
вы можете использовать макрофункцию вместо оператора return в конкретной функции.
например, вместо использования return,
int foo(...) { if (error happened) return -1; ... do something ... return 0 }вы можете использовать функцию макроса.
#include "c-callstack.h" int foo(...) { if (error happened) NL_RETURN(-1); ... do something ... NL_RETURN(0); }всякий раз, когда происходит ошибка в функции, вы увидите стек вызовов в стиле Java, как показано на рисунке под.
Error(code:-1) at : so_topless_ranking_server (sample.c:23) Error(code:-1) at : nanolat_database (sample.c:31) Error(code:-1) at : nanolat_message_queue (sample.c:39) Error(code:-1) at : main (sample.c:47)полный исходный код доступен здесь.
можно использовать Мака для этого. Он обычно используется для сбора трассировки стека во время сбоя, но он также может выводить его для запущенной программы.
теперь вот хорошая часть: он может выводить фактические значения параметров для каждой функции в стеке и даже локальные переменные, счетчики циклов и т. д.
вы можете реализовать себя:
используйте глобальный (строковый)стек и в начале каждой функции нажмите имя функции и такие другие значения (например, параметры) на этот стек; при выходе из функции поп его снова.
напишите функцию, которая будет распечатывать содержимое стека при его вызове, и используйте ее в функции, где вы хотите видеть стек вызовов.
Это может звучать как много работы, но очень полезно.
конечно, следующий вопрос: будет ли этого достаточно ?
основной недостаток Stack-traces заключается в том, что у вас есть точная вызываемая функция, у вас нет ничего другого, как значение ее аргументов, что очень полезно для отладки.
Если у вас есть доступ к gcc и gdb, я бы предложил использовать
assertдля проверки конкретного условия и создания дампа памяти, если он не выполняется. Конечно, это означает, что процесс остановится, но у вас будет полноценный отчет вместо простой трассировки стека.Если вы хотите менее навязчивый способ, вы всегда можете использовать ведение журнала. Есть очень эффективные лесозаготовительные объекты там, как Pantheios например. Что еще раз может дать вам гораздо более точное представление о том, что происходит.
еще один ответ на старый поток.
когда мне нужно это сделать, я обычно просто использую
system()иpstackчто-то вроде этого:
#include <sys/types.h> #include <unistd.h> #include <string> #include <sstream> #include <cstdlib> void f() { pid_t myPid = getpid(); std::string pstackCommand = "pstack "; std::stringstream ss; ss << myPid; pstackCommand += ss.str(); system(pstackCommand.c_str()); } void g() { f(); } void h() { g(); } int main() { h(); }выводит
#0 0x00002aaaab62d61e in waitpid () from /lib64/libc.so.6 #1 0x00002aaaab5bf609 in do_system () from /lib64/libc.so.6 #2 0x0000000000400c3c in f() () #3 0x0000000000400cc5 in g() () #4 0x0000000000400cd1 in h() () #5 0x0000000000400cdd in main ()это должно работать на Linux, FreeBSD и Solaris. Я не думаю, что macOS имеет pstack или простой эквивалент, но это поток, кажется, есть альтернатива.
Я знаю, что эта тема старая, но я думаю, что это может быть полезно для других людей. Если вы используете gcc, вы можете использовать его функции инструмента (-finstrument-functions option) для регистрации любого вызова функции (вход и выход). Взгляните на это для получения дополнительной информации:http://hacktalks.blogspot.fr/2013/08/gcc-instrument-functions.html
таким образом, вы можете, например, нажимать и вставлять каждый вызов в стек, и когда вы хотите распечатать его, вы просто смотрите на то, что у вас есть в вашем стек.
Я проверил его, он отлично работает и очень удобно
UPDATE: вы также можете найти информацию о опции компиляции-finstrument-functions в документе GCC относительно опций инструментирования:https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html
вы можете использовать GNU profiler. Он также показывает график вызовов! команда
gprofи вам нужно скомпилировать свой код с некоторой опцией.
есть ли способ сбросить стек вызовов в запущенном процессе в C или c++ каждый раз, когда вызывается определенная функция?
нет нет, хотя платформозависимые решения могут существовать.
Comments