Как вы, возможно, знаете, мы можем использовать GDB и устанавливать точки останова в нашем коде, чтобы приостановить выполнение для отладки.
Мои вопросы: как GDB приостанавливает процесс и позволяет вам просматривать содержимое регистров, используя, i r
например. Разве эти регистры не используются другими процессами ОС постоянно? как они не перезаписываются?
Это только снимок контента, а не живые данные?
Ответы:
Это немного меняется в зависимости от архитектуры, но важные моменты применяются почти повсеместно:
Обслуживание прерываний приводит к тому, что состояние процессора (включая регистры) сохраняется в памяти перед запуском ISR и восстанавливается при выходе из ISR.
Если подпрограмма обработки прерываний меняет содержимое области памяти, в которой хранятся эти регистры, она может выполнить переключение контекста . Каждый поток имеет область памяти, где его регистры сохраняются, когда поток не запущен.
Переключение контекста управляется планировщиком потока, который учитывает, ожидает ли поток ввода-вывода, синхронизации, каков его приоритет, доставку сигнала и т. Д. Часто существует счетчик приостановок, который учитывается.
Отладчик может увеличивать число приостановок, что гарантирует, что поток не будет запущен. Затем он может проверить (и изменить) сохраненную в потоке копию регистров.
источник
В дополнение к замечательной информации @BenVoigt, позвольте мне сделать некоторые дополнения:
Точка останова устанавливается отладчиком путем замены значения машинного кода (инструкции или части инструкции) в отлаживаемом процессе на конкретную команду прерывания в месте в коде, которое соответствует желаемой (исходной) строке, для которой необходимо выполнить разрыв. Эта конкретная команда прерывания предназначена для использования в качестве точки останова - отладчик это знает, как и операционная система.
Когда отлаживаемый процесс / поток сталкивается с инструкцией прерывания, это запускает процесс, который описывает @Ben, который включает половину контекстного обмена, который приостанавливает текущий запущенный поток (который включает в себя сохранение его состояния ЦП в памяти) для возможного последующего возобновления. Так как эта ловушка является ловушкой точки останова, операционная система удерживает отлаживаемый процесс приостановленным, используя, возможно, механизм, описанный @Ben, и уведомляет и в конечном итоге возобновляет работу отладчика.
Затем отладчик использует системные вызовы для доступа к сохраненному состоянию отлаживаемого приостановленного процесса / потока.
Чтобы выполнить (возобновить) строку кода, которая прервалась (которая теперь имеет конкретную инструкцию прерывания), отладчик восстановит исходное значение машинного кода, которое было перезаписано инструкцией прерывания точки останова, возможно, установит другое прерывание где-нибудь еще (например, если пошаговое выполнение, или пользователь устанавливает новые точки останова) и помечает процесс / поток как работоспособный, возможно, используя механизм, описанный @Ben.
Фактические детали могут быть более сложными, так как сохранение длительной точки останова, для которой была достигнута ошибка, означает что-то вроде замены ловушки точки останова для реального кода, чтобы можно было запустить строку, а затем снова вернуть точку прерывания обратно ...
Как описывает @Ben, использование уже существующей функции приостановки / возобновления потока (переключение контекста / переключение многозадачности ), которая позволяет процессорам совместно использоваться несколькими процессами / потоками, используя квантование времени.
Это оба. Поскольку поток , который попал в точку останова приостанавливается, это снимок из данных в реальном времени (регистры процессора, и т.д ..) в момент приостановки и авторитетный мастер значений регистров процессора для восстановления в процессор Должен ли быть поточно возобновленной , Если вы используете пользовательский интерфейс отладчика для чтения и / или изменения регистров ЦП (отлаживаемого процесса), он будет считывать и / или изменять этот снимок / мастер с помощью системных вызовов.
источник
Строго говоря, по крайней мере в большинстве типичных случаев, сам GDB не приостанавливает выполнение. Скорее, GDB запрашивает ОС, а ОС приостанавливает выполнение.
Сначала это может показаться различием без разницы - но, честно говоря, разница действительно есть. Разница заключается в следующем: эта способность уже встроена в типичную ОС, потому что она должна быть в состоянии приостановить и возобновить выполнение потока в любом случае - когда поток не запланирован для запуска (например, ему нужен некоторый ресурс, который в настоящее время недоступно) ОС должна приостановить его, пока он не будет запланирован для запуска.
Для этого ОС обычно имеет блок памяти, выделенный для каждого потока, чтобы сохранить текущее состояние машины. Когда требуется приостановить поток, текущее состояние машины сохраняется в этой области. Когда ему необходимо возобновить поток, состояние машины восстанавливается из этой области.
Когда отладчику нужно приостановить поток, он делает паузу в ОС таким же образом, как и по другим причинам. Затем, чтобы прочитать состояние приостановленного потока, отладчик просматривает сохраненное состояние потока. Если вы изменяете состояние, отладчик записывает в сохраненное состояние, когда вступает в силу, когда поток возобновляется.
источник