Как работает отладчик?

170

Я продолжаю задаваться вопросом, как работает отладчик? В частности, тот, который можно «прикрепить» к уже запущенному исполняемому файлу. Я понимаю, что компилятор переводит код на машинный язык, но тогда как отладчик «узнает», к чему он подключен?

ya23
источник
5
Статья Элая перенесена на eli.thegreenplace.net/2011/01/23/how-debuggers-work-part-1
окталист
@Oktalist Эта статья интересна, но рассказывает только об абстракции уровня API для отладки в Linux. Я думаю, что ОП хочет знать больше под капотом.
smwikipedia

Ответы:

96

Детали того, как работает отладчик, будут зависеть от того, что вы отлаживаете, и что такое ОС. Для нативной отладки в Windows вы можете найти некоторые подробности по MSDN: Win32 Debugging API .

Пользователь сообщает отладчику, к какому процессу подключаться, по имени или по идентификатору процесса. Если это имя, то отладчик будет искать идентификатор процесса и инициировать сеанс отладки с помощью системного вызова; под Windows это будет DebugActiveProcess .

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

Отладчик может читать и записывать виртуальную память целевого процесса и даже корректировать значения его регистров через API, предоставляемые ОС. Смотрите список функций отладки для Windows.

Отладчик может использовать информацию из файлов символов для преобразования адресов в имена переменных и местоположения в исходном коде. Информация о файле символов представляет собой отдельный набор API и не является основной частью ОС как таковой. В Windows это осуществляется через Debug Interface Access SDK .

Если вы отлаживаете управляемую среду (.NET, Java и т. Д.), Процесс, как правило, будет выглядеть одинаково, но детали будут другими, поскольку среда виртуальной машины предоставляет API отладки, а не базовую ОС.

Роб Уокер
источник
5
Этот вопрос может показаться глупым, но как ОС отслеживает достижение определенного адреса внутри программы. Например, точка взлома установлена ​​по адресу 0x7710cafe. При изменении указателя инструкций ОС (или, возможно, ЦП) придется сравнивать указатель инструкций со всеми адресами точек останова, или я ошибаюсь? Как это работает ..?
displayname
3
@StefanFalk Я написал ответ, который касается некоторых деталей более низкого уровня (на x86).
Джонатон Рейнхарт
Не могли бы вы объяснить, как именно имена переменных отображаются на адреса? Использует ли приложение одни и те же адреса памяти для переменных при каждом запуске? Я всегда предполагал, что он только что обнаружил отображение из доступной памяти, но никогда не задумывался о том, будут ли байты отображаться непосредственно в одно и то же место в области памяти приложения. Похоже, это будет серьезной проблемой безопасности.
Улица Джеймса Джошуа
@JamesJoshuaStreet Я мог бы представить, что это деталь, специфичная для отладчика.
moonman239
Этот ответ показывает что-то. Но я думаю, что op больше интересуется некоторыми деталями низкого уровня, а не некоторыми абстракциями API.
smwikipedia
63

Как я понимаю:

Для программных точек останова на x86 отладчик заменяет первый байт инструкции на CC( int3). Это делается с помощью WriteProcessMemoryWindows. Когда ЦП получает эту инструкцию и выполняет ее int3, это заставляет ЦП генерировать исключение отладки. ОС получает это прерывание, понимает, что процесс отлаживается, и уведомляет процесс отладчика о достижении точки останова.

После достижения точки останова и остановки процесса отладчик просматривает список точек останова и заменяет CCего байтом, который был там изначально. Наборы отладчика TF, ловушка Флаг в EFLAGS(путем модификации CONTEXT), и продолжает процесс. Флаг Trap заставляет ЦП автоматически генерировать одношаговое исключение ( INT 1) для следующей инструкции.

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

Я не уверен, что это именно то, как это реализовано всеми отладчиками, но я написал программу для Win32, которая умеет отлаживать себя с помощью этого механизма. Совершенно бесполезно, но познавательно.

Джонатон Рейнхарт
источник
25

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

Адам Розенфилд
источник
1
Говорит ли (2)нам что-то большее (или меньшее), чем «ptrace - системный вызов»?
Лазер
5
@eSKay, нет, не совсем. Это (2)номер раздела руководства. См. En.wikipedia.org/wiki/Man_page#Manual_sections для описания разделов руководства.
Адам Розенфилд
2
@AdamRosenfield За исключением того факта, что раздел 2 специально "Системные вызовы". Таким образом, косвенно, да, это говорит нам, что ptraceэто системный вызов.
Джонатон Рейнхарт
1
Более практически, то (2)говорит нам , что мы можем ввести man 2 ptraceи получить нужную справочную страницу - здесь не важно , потому что нет никакого другого ptraceк неоднозначности, но для сравнения man printfс man 3 printfна Linux.
тонкий
9

Если вы работаете в операционной системе Windows, хорошим ресурсом для этого будет «Отладка приложений для Microsoft .NET и Microsoft Windows» Джона Роббинса:

(или даже более старая версия: «Отладка приложений» )

В книге есть глава о том, как работает отладчик, который включает код для пары простых (но работающих) отладчиков.

Поскольку я не знаком с деталями отладки Unix / Linux, этот материал может вообще не относиться к другим ОС. Но я предполагаю, что в качестве введения в очень сложную тему концепции - если не детали и API - должны «портировать» на большинство любых ОС.

Майкл Берр
источник
3

Другим ценным источником для понимания отладки является руководство по процессору Intel (Руководство разработчика программного обеспечения Intel® 64 и IA-32 Architectures). В главе 3 тома 3А он представил аппаратную поддержку отладки, такую ​​как специальные исключения и регистры аппаратной отладки. Вот из этой главы:

Флаг T (trap), TSS - Генерирует исключение отладки (#DB), когда делается попытка переключиться на задачу с флагом T, установленным в его TSS.

Я не уверен, использует ли Window или Linux этот флаг или нет, но очень интересно прочитать эту главу.

Надеюсь, это кому-нибудь поможет.

Jiang
источник
2

Я думаю, что здесь есть два основных вопроса:

1. Как отладчик знает, что произошло исключение?

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

введите описание изображения здесь


2. Как отладчик знает, как остановиться на точке останова?

Упрощенный ответ : когда вы ставите точку останова в программе, отладчик заменяет ваш код в этой точке инструкцией int3, которая является программным прерыванием . В результате программа приостанавливается и вызывается отладчик.

InTheNameOfScience
источник
1

Насколько я понимаю, когда вы компилируете приложение или файл DLL, все, что он компилирует, содержит символы, представляющие функции и переменные.

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

DavidG
источник
2
Это просто про символы. Отладка намного больше, чем символы.
Джонатон Рейнхарт