Список всех вызовов функций, выполненных в приложении

Как мы можем перечислить все функции, вызываемые в приложении. Я пытался использовать GDB, но его список следов только до вызова основной функции.

Мне нужен более глубокий список, т.е. список всех функций, вызываемых основной функцией, и функции, вызываемой из этих вызываемых функций, и так далее.

Есть ли способ получить это в GDB? Или не могли бы вы дать мне советы, как это получить?

5 ответов

Решение

Как мы можем перечислить все функции, вызываемые в приложении

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

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

nm /path/to/a.out | egrep ' [TW] '

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

(gdb) set logging on     # collect trace in gdb.txt
(gdb) set confirm off    # you wouldn't want to confirm every one of them
(gdb) rbreak .           # set a breakpoint on each function

Как только вы продолжите, вы достигнете точки останова для каждой вызванной функции. Использовать disable а также continue Команды для продвижения вперед. Я не верю, что есть простой способ автоматизировать это, если только вы не хотите использовать скрипты Python.

Уже упоминалось gprof это еще один хороший вариант.

Вы хотите график звонков. Инструмент, который вы хотите использовать, это не GDB, это gprof, Вы компилируете свою программу с -pg а затем запустить его. Когда он запускает файл gmon.out будет произведено. Затем вы обрабатываете этот файл gprof и наслаждайтесь выводом.

запись истории вызовов

https://sourceware.org/gdb/onlinedocs/gdb/Process-Record-and-Replay.html

Это должно стать отличной возможностью для аппаратного ускорения, если вы один из немногих (2015 г.) с процессором, поддерживающим Intel Processor Tracing (Intel PT, intel_pt в /proc/cpuinfo).

Документы GDB утверждают, что он может производить выходные данные, такие как:

(gdb) list 1, 10
1   void foo (void)
2   {
3   }
4
5   void bar (void)
6   {
7     ...
8     foo ();
9     ...
10  }
(gdb) record function-call-history /ilc
1  bar     inst 1,4     at foo.c:6,8
2    foo   inst 5,10    at foo.c:2,3
3  bar     inst 11,13   at foo.c:9,10

Перед его использованием необходимо выполнить:

start
record btrace

где неработающий ЦП отказывает:

 Target does not support branch tracing.

Поддержка ЦП обсуждается далее: Как запустить историю команд записи и историю вызовов функций в GDB?

Связанные темы:

Для встраиваемых систем вы также рассматриваете JTAG и поддерживающее оборудование, например, ARM DSTREAM, но поддержка x86 выглядит не очень хорошо: отладка ядра x86 с использованием аппаратного отладчика

Этот вопрос может нуждаться в уточнении, чтобы выбрать между тем, что в настоящее время 2 ответа. Зависит от того, что вам нужно:

1) Вам необходимо знать, сколько раз каждая функция вызывается в формате прямого списка / графика функций, соответствующих количеству вызовов. Это может привести к неоднозначным / неубедительным результатам, если ваш код не является процедурным (то есть функции, вызывающие другие функции в структуре разветвления без неоднозначности того, что вызывает что). Это базовая функциональность gprof, которая требует перекомпиляции с флагом -pg.

2) Вам нужен список функций в том порядке, в котором они были вызваны, это зависит от вашей программы, которая является наилучшей / выполнимой опцией: a) Если ваша программа запускается и завершается без ошибок времени выполнения, вы можете использовать для этой цели gprof. б) Опция ELSE, описанная выше с использованием dbg с логированием и точками останова, - это оставленная опция, которую я изучил, прочитав это.

3) Вам нужно знать не только порядок, но, например, аргументы функции для каждого вызова. Моя текущая работа - моделирование в физике переноса частиц, так что это было бы АБСОЛЮТНО полезно для отслеживания того, откуда приходят аномальные результаты... т.е. когда аргументы, передаваемые вокруг, перестают иметь смысл. Я полагаю, что один из способов сделать это - это вариация того, что делал Employed Russian, за исключением использования следующего:

(GDB) информация аргументы

Регистрация результатов этой команды с каждой точкой останова (устанавливается при каждом вызове функции) дает аргументы текущей функции.

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

      gdb <your-binary>

(gdb) b theMostChildFunction ## put breakpoint on the desired function
(gdb) r ## run the program
(gdb) bt ## backtrace starting from the breakpoint

В противном случае в Linux вы можете использоватьинструмент для отслеживания программ и вызовов их функций. Преимущество этого в том, что он отслеживает все процессы, включая дочерние процессы, а также показывает процент использования функций в программе.

Вы можете установить так:

      sudo apt install linux-tools-generic
sudo apt install linux-cloud-tools-generic

Перед использованием вам также может потребоваться временно снять некоторые ограничения ядра:

      sudo sh -c 'echo 0 >/proc/sys/kernel/kptr_restrict'
sudo sh -c 'echo 0 >/proc/sys/kernel/perf_event_paranoid' 
sudo sh -c 'echo 0 >/proc/sys/kernel/yama/ptrace_scope'

После этого вы можете запустить двоичный файл вашей программы следующим образом:

      perf record -g -s -a <your-binary-and-its-flags>

Затем вы можете посмотреть вывод на терминал следующим образом:

      perf report

или в текстовом файле следующим образом:

      perf report -i perf.data > output.txt
vim output.txt

когда вы записываете вызовы функций с помощьюperfтакже вы можете захотеть отфильтровать вызовы ядра с помощью--all-userфлаг:

      perf record -g -s -a --all-user <your-binary-and-its-flags>

Для получения дополнительной информации вы можете посмотреть здесь: https://perf.wiki.kernel.org/index.php/Tutorial

Другие вопросы по тегам