GDB
Хороший туториал - https://beej.us/guide/bggdb/
peda
peda - удобное окружение для GDB
https://github.com/longld/peda
Установка:
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinitСборка
Чтобы было удобно пользоваться gdb, при сборке нужно использовать флаги -g и -O0
История команд
set history save on
set history filename ~/.gdb_historyОсновные команды
b main.c:175- установить брейкпойнт в main.c:175b start_work- установить брейкпойнт в начало функции start_workb start_work if b == 0- установить брейкпойнт с условиемp a- вывод переменной аp *a- вывод значения по адресу аbt- текущий бэктрэйс
Watchpoints
watch expr- установить брейкпойнт на запись выражения exprrwatch expr- установить брейкпойнт на чтение выражения exprawatch expr- установить брейкпойнт на чтение и запись выражения expr
Список можно получить по info watchpoints. Любой вотчпойнт из списка можно удалить по delete N.
Установка вотчпойнта на поле класса:
(gdb) p &bar
$1 = (int *) 0x10793ad0
(gdb) watch *0x10793ad0Написание скриптов
Вот такой скрипт установит брейкпойнты в функции gst_object_ref  и gst_object_unref, которые будут срабатывать, когда первый аргумент ($rdi) указывает на тот же адрес, что и переменная audioconvert. При каждом срабатывании брейкпойнта будет печетаться стектрейс и выполнение продолжится дальше.
set pagination off 
break main.cpp:69
run
set $conv=audioconvert
break gst_object_ref if ($rdi == $conv)
commands
bt
cont
end
break gst_object_unref if ($rdi == $conv)
commands
bt
cont
end
contКлючевое слово commands позволяет задать несколько действий, которые будут выполнены, когда сработает этот брейкпойнт. Список действий заключен между commands и end.
set pagination off - указывает, что при выводе стектрейса не нужно останавливать выполнение и выводить "нажмите пробел для следующей страницы".
Выполнение скрипта
Сохраняем скрипт в файл script.txt затем делаем:
gdb -x script.txtПроход по бэктрэйсу
gdb$ p $rbp
$15 = (void *) 0x7fffffffe5c0		# в регистре rbp хранится адрес начала фрейма предыдущей функции, то есть предыдущее значение rbp. В $15 теперь хранится как раз оно.
gdb$ p *(long*)$15
$16 = 0x7fffffffe5d0				# получаем значение адреса, лежащего в регистре $rbp. то есть адрес пред-предыдущего фрейма.
gdb$ p *(long*)$16 
$17 = 0x7fffffffe5e0				# и так далее...
gdb$ p *(long*)$17
$18 = 0x7fffffffe600
gdb$ p *(long*)$18
$19 = 0x400c70						# а здесь адрес уже подозрительно маленький, наверно лежит в сегменте .code, а значит мы добрались до верха стектрейса
gdb$ p *(long*)$19
$20 = 0x41d7894956415741Чтение значения регистра
gdb$ p $rbp				# прочесть значение регистра rbp
gdb$ p ($rbp)			# прочесть значение по адресу, лежащему в регистре rbp
gdb$ p ($rbp + 8)		# прочесть значение по адресу, лежащему на 8 байт выше, чем адрес в регистре rbpОтладка SIGSEGV
Если на SIGSEGV установлен хэндлер, то по умолчанию GDB в него не будет заходить, потому что ловит сигнал раньше программы и завершает ее выполнение. Чтобы зайти в хэндлер, надо сделать так:
handle SIGSEGV pass
handle SIGSEGV nostop