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

Как сделать интересные функции печати gdb, так как они называются, отступом в зависимости от того, насколько глубоко они находятся в стеке?

Я хочу сказать что-то вроде (составленное):

(gdb) trace Foo* Bar* printf

И gdb напечатайте все функции, которые начинаются с Foo или Bar, как они называются. Вид вроде gnu cflow, за исключением использования отладочных символов и только функций печати, которые фактически вызываются, а не все возможные потоки вызовов.

Инструменты, которые не помогут включить cachegrind, callgrind и oprofile, которые упорядочивают результаты, с помощью которых функции вызывались чаще всего. Мне нужен порядок вызова.

Подстановочный знак (или эквивалент) необходим, так как существует много функций Foo и Bar. Хотя я бы согласился на запись абсолютно каждой функции. Или, возможно, указывая gdb на запись всех функций в определенной библиотеке.

Некоторые мастера GDB должны иметь script для этого общего задания!

Ответ 1

В вашем случае я перейду к команде define в gdb, что позволит вам определить функцию, которая может принимать до 10 аргументов.

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

define functiontrace
if $arg0
    break $arg0
    commands
        where
        continue
        end
    end

if $arg1
...

Аргументы к определяемой пользователем функции в gdb называются $arg0- $arg9. Кроме того, вы можете просто записать каждую функцию, которую вы хотите отслеживать в функции, вместо использования $arg0-9.

Примечание. Это не будет иметь отступ по глубине в трассировке стека, но будет печатать трассировку стека при каждом вызове функции. Я считаю этот подход более полезным, чем strace и т.д., Потому что он будет регистрировать любую функцию, которую вы хотите, систему, библиотеку, локальную или другую.

Ответ 3

Там rbreak cmd принимает регулярное выражение для установки контрольных точек. Вы можете использовать:

(gdb) rbreak Foo.*
(gdb) rbreak Bar.*
(gdb) break printf

Подробные сведения о контрольных точках см. в этом.

Затем используйте commands для печати каждой функции по ее вызову. Например. пусть α = номер последней точки останова (вы можете проверить ее с помощью i br, если вы пропустили), а затем выполните:

(gdb) commands 1-α
Type commands for breakpoint(s) 1-α, one per line.
End with a line saying just "end".
>silent
>bt 1
>c
>end
(gdb) 

Некоторая разработка: silent подавляет ненужные информационные сообщения, bt 1 печатает последний кадр backtrace (т.е. текущую функцию), c является ярлыком для continue, для продолжения исполнения и end это просто разделитель списка команд.

NB: если вы трассируете библиотечные функции, вам может потребоваться ожидание загрузки lib. Например. установите разрыв на main или любую другую функцию, запустите приложение до этой точки и только затем установите точки останова, которые вы хотели.

Ответ 4

Вы видели яркую отличную ссылку на аналогичную запись здесь?

Он использует readelf для получения интересных символов, команд gdb для получения трассировки и awk для склеивания всего этого.

В основном вам нужно изменить его команду gdb script, чтобы удалить 1 глубину из backtrace, чтобы увидеть стек и фильтровать определенные функции, и переформатировать вывод с помощью awk/python/(...) script, чтобы представить его как дерево. (Я признаю, что я слишком ленив, чтобы сделать это сейчас...)

Ответ 5

Вы можете вызвать gdb в пакетном режиме (с использованием опции -x), сломать, где вам нужно, и запросить обратную трассировку (bt), затем вы фильтруете результат с помощью grep или egrep.

Отступы сложнее, однако вывод bt упорядочен, поэтому у вас есть текущая функция в верхней части трассы и main в самом низу.

Итак, вы создаете файл с командами:

br <function name where to break>
run
bt
kill
quit

затем запустите gdb <program> -x<command file>

Фильтровать строки, начинающиеся с #<digit> - вы получаете трассировку стека.