Работа с процессами и потоками исполнения
В отладчике GDB для работы с процессами используются объекты, которые называются инфериорами (англ. inferiors). Процесс каждой программы, которую нужно отладить, должен быть привязан к отдельному инфериору. Переключение между инфериорами соответствует переключению фокуса отладки в контекст другого процесса. Отладочные символы для программы, которую требуется отладить, нужно загружать после переключения на инфериор, который привязан к процессу этой программы.
При запуске отладчика GDB автоматически создается инфериор. При подключении отладчика GDB к GDB-серверу ядра исполнение кода решения останавливается, и этот инфериор автоматически привязывается к процессу, содержащему поток исполнения, в контексте которого останавливается исполнение кода решения. Остальные требуемые инфериоры могут быть созданы, привязаны к процессам и отвязаны от процессов вручную или автоматически. В первом случае нужно использовать GDB-команды для работы с инфериорами. Во втором случае требуется настроить обработку событий жизненного цикла процессов.
GDB-команды для работы с инфериорами
Для работы с инфериорами нужно использовать следующие GDB-команды:
info inferiors
Выводит список инфериоров. Текущий инфериор отмечается символом
*
. (Контекст процесса, ассоциированного с текущим инфериором, находится в фокусе отладки.)add-inferior
Создает инфериор.
inferior
<номер инфериора
>Переключает на другой инфериор.
attach
<PID
>Привязывает текущий инфериор к процессу с идентификатором PID. Чтобы вывести список процессов, нужно выполнить GDB-команду
info os processes
.detach
Отвязывает текущий инфериор от процесса.
Настройка обработки событий жизненного цикла процессов
GDB-сервер ядра сообщает отладчику GDB о наступлении следующих событий:
- создание дочернего процесса;
- запуск начального потока исполнения дочернего процесса;
- завершение процесса.
Отладчик GDB обрабатывает событие 1 только в том случае, если существует инфериор, привязанный к родительскому процессу. Для обработки события 2 необходимо, чтобы отладчик GDB предварительно обработал событие 1 при создании дочернего процесса. При этом событие 2 обрабатывается, даже если родительский процесс уже отвязан от инфериора, например, по причине завершения.
Чтобы настроить обработку событий 1 и 2, нужно использовать следующие GDB-команды:
set follow-fork-mode
{child
|parent
}Указывает отладчику GDB перейти в контекст дочернего процесса (
child
) или остаться в контексте родительского процесса (parent
) при наступлении события 1. Второй вариант выполняется по умолчанию.set detach-on-fork
{on
|off
}Указывает отладчику GDB оставить родительский или дочерний процесс привязанным к инфериору (
on
) или оставить родительский процесс привязанным к инфериору, а также создать новый инфериор и привязать его к дочернему процессу (off
) при наступлении события 1. Первый вариант выполняется по умолчанию. При этом, какой процесс привязан к инфериору (родительский или дочерний), зависит от параметра GDB-командыset follow-fork-mode
.set follow-exec-mode
{new
|same
}Указывает отладчику GDB создать новый инфериор и привязать его к дочернему процессу (
new
) или не делать этого (same
) при наступлении события 2. Второй вариант выполняется по умолчанию.
Рекомендуется настроить обработку событий 1 и 2 следующим образом:
Такая конфигурация обеспечивает обработку событий 1 и 2 отладчиком GDB следующим образом:
- При наступлении события 1 создается новый инфериор, который привязывается к дочернему процессу.
- При наступлении события 1 родительский процесс остается привязанным к инфериору.
- При наступлении события 2 не создается новый инфериор для дочернего процесса.
Обработку отладчиком GDB события 2 можно использовать для остановки исполнения программы до передачи управления функции main()
, чтобы не применять бесконечный цикл.
Чтобы исполнение программы остановилось при наступлении события 2, нужно использовать следующую GDB-команду:
Эта GDB-команда обеспечивает остановку исполнения каждого дочернего процесса, при создании которого было обработано событие 1. Чтобы выполнить остановку исполнения отдельных процессов, нужно использовать следующую GDB-команду:
Последующий вызов этой GDB-команды отменяет предыдущий, а ее вызов без параметров означает остановку каждого дочернего процесса, при создании которого было обработано событие 1.
Событие 3 обрабатывается отладчиком GDB только в том случае, если созданы инфериоры, привязанные к завершившимся процессам. При обработке этого события отладчик GDB отвязывает инфериор от завершившегося процесса. Обработку события 3 не требуется настраивать.
GDB-команды для работы с потоками исполнения
Чтобы вывести список потоков исполнения, которые содержатся в процессах, привязанных к инфериорам, нужно выполнить следующую GDB-команду:
Текущий поток исполнения отмечается символом *
. (Контекст текущего потока исполнения находится в фокусе отладки.)
Чтобы перейти в контекст другого потока исполнения, нужно выполнить следующую GDB-команду:
Переход в контекст другого потока исполнения приводит к переключению на другой инфериор, если этот поток исполнения содержится процессе, привязанном к инфериору, который не является текущим.