Как GDB приостанавливает исполнение

16

Как вы, возможно, знаете, мы можем использовать GDB и устанавливать точки останова в нашем коде, чтобы приостановить выполнение для отладки.

Мои вопросы: как GDB приостанавливает процесс и позволяет вам просматривать содержимое регистров, используя, i rнапример. Разве эти регистры не используются другими процессами ОС постоянно? как они не перезаписываются?

Это только снимок контента, а не живые данные?

Джо
источник
2
Почему все регистры не перезаписываются, когда ОС решает на секунду приостановить вашу программу и запустить другую?
user253751
CppCon 2018: Саймон Брэнд «Как работают отладчики C ++» youtube.com/watch?v=0DDrseUomfU
Роберт

Ответы:

24

Это немного меняется в зависимости от архитектуры, но важные моменты применяются почти повсеместно:

  • Обслуживание прерываний приводит к тому, что состояние процессора (включая регистры) сохраняется в памяти перед запуском ISR и восстанавливается при выходе из ISR.

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

  • Переключение контекста управляется планировщиком потока, который учитывает, ожидает ли поток ввода-вывода, синхронизации, каков его приоритет, доставку сигнала и т. Д. Часто существует счетчик приостановок, который учитывается.

  • Отладчик может увеличивать число приостановок, что гарантирует, что поток не будет запущен. Затем он может проверить (и изменить) сохраненную в потоке копию регистров.

Бен Фойгт
источник
14

В дополнение к замечательной информации @BenVoigt, позвольте мне сделать некоторые дополнения:

Точка останова устанавливается отладчиком путем замены значения машинного кода (инструкции или части инструкции) в отлаживаемом процессе на конкретную команду прерывания в месте в коде, которое соответствует желаемой (исходной) строке, для которой необходимо выполнить разрыв. Эта конкретная команда прерывания предназначена для использования в качестве точки останова - отладчик это знает, как и операционная система.

Когда отлаживаемый процесс / поток сталкивается с инструкцией прерывания, это запускает процесс, который описывает @Ben, который включает половину контекстного обмена, который приостанавливает текущий запущенный поток (который включает в себя сохранение его состояния ЦП в памяти) для возможного последующего возобновления. Так как эта ловушка является ловушкой точки останова, операционная система удерживает отлаживаемый процесс приостановленным, используя, возможно, механизм, описанный @Ben, и уведомляет и в конечном итоге возобновляет работу отладчика.

Затем отладчик использует системные вызовы для доступа к сохраненному состоянию отлаживаемого приостановленного процесса / потока.

Чтобы выполнить (возобновить) строку кода, которая прервалась (которая теперь имеет конкретную инструкцию прерывания), отладчик восстановит исходное значение машинного кода, которое было перезаписано инструкцией прерывания точки останова, возможно, установит другое прерывание где-нибудь еще (например, если пошаговое выполнение, или пользователь устанавливает новые точки останова) и помечает процесс / поток как работоспособный, возможно, используя механизм, описанный @Ben.

Фактические детали могут быть более сложными, так как сохранение длительной точки останова, для которой была достигнута ошибка, означает что-то вроде замены ловушки точки останова для реального кода, чтобы можно было запустить строку, а затем снова вернуть точку прерывания обратно ...

Разве эти регистры не используются другими процессами ОС постоянно? как они не перезаписываются?

Как описывает @Ben, использование уже существующей функции приостановки / возобновления потока (переключение контекста / переключение многозадачности ), которая позволяет процессорам совместно использоваться несколькими процессами / потоками, используя квантование времени.

Это только снимок контента, а не живые данные?

Это оба. Поскольку поток , который попал в точку останова приостанавливается, это снимок из данных в реальном времени (регистры процессора, и т.д ..) в момент приостановки и авторитетный мастер значений регистров процессора для восстановления в процессор Должен ли быть поточно возобновленной , Если вы используете пользовательский интерфейс отладчика для чтения и / или изменения регистров ЦП (отлаживаемого процесса), он будет считывать и / или изменять этот снимок / мастер с помощью системных вызовов.

Эрик Эйдт
источник
1
Ну, большинство процессорных архитектур поддерживают ловушки отладки, которые, например, срабатывают, когда IP (указатель инструкции) равен адресу, сохраненному в регистре точки останова, что избавляет от необходимости переписывать код. (Сопоставляя регистры, отличные от IP, вы можете получить точки останова данных, а перехватывая после каждой инструкции, вы можете получить пошаговое выполнение). То, что вы описали, также возможно, конечно, если код не находится в постоянной памяти.
Бен Фойгт
В последнем параграфе «Если вы изменяете регистры ЦП ...», я думаю, вы имеете в виду «Если вы изменяете сохраненную копию регистров CUP ...» Затем, когда ОС возобновляет процесс, эти измененные данные записываются обратно. к фактическим регистрам.
jamesqf
@jamesqf, да, спасибо!
Эрик Эйдт
@BenVoigt, согласился. хотя в то время как отладчики могут обрабатывать неограниченное количество точек останова, аппаратные средства могут обрабатывать ноль или несколько, поэтому отладчик должен выполнять некоторые манипуляции.
Эрик Эйдт
@jamesqf: описание того, что это копия, немного вводит в заблуждение. Это официальное хранилище для состояния потока, пока поток не работает.
Бен Фойгт
5

Строго говоря, по крайней мере в большинстве типичных случаев, сам GDB не приостанавливает выполнение. Скорее, GDB запрашивает ОС, а ОС приостанавливает выполнение.

Сначала это может показаться различием без разницы - но, честно говоря, разница действительно есть. Разница заключается в следующем: эта способность уже встроена в типичную ОС, потому что она должна быть в состоянии приостановить и возобновить выполнение потока в любом случае - когда поток не запланирован для запуска (например, ему нужен некоторый ресурс, который в настоящее время недоступно) ОС должна приостановить его, пока он не будет запланирован для запуска.

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

Когда отладчику нужно приостановить поток, он делает паузу в ОС таким же образом, как и по другим причинам. Затем, чтобы прочитать состояние приостановленного потока, отладчик просматривает сохраненное состояние потока. Если вы изменяете состояние, отладчик записывает в сохраненное состояние, когда вступает в силу, когда поток возобновляется.

Джерри Гроб
источник