Как работает отладчик: машина времени для вашего кода
Отладчик умеет то, что кажется магией: останавливать живую программу в любой точке, заглядывать внутрь её переменных и выполнять код по одной строчке. Под капотом — хитрый сговор с операционной системой и процессором.
Отладчик — это программа, которая берёт другую программу под контроль и умеет замораживать её в любой момент, чтобы вы заглянули внутрь.
Без отладчика вы догадываетесь о причинах ошибки. С отладчиком — останавливаете программу за миг до сбоя и смотрите своими глазами, что именно пошло не так.
Каждый новичок сначала отлаживает код печатью: расставляет print по всему файлу, чтобы понять, что происходит. Это работает, но грубо. Отладчик делает то же самое, только в тысячу раз тоньше — и понимание того, как он устроен, превращает его из загадочной кнопки в мощный инструмент.
Главный фокус: точки останова
Точка останова (breakpoint) — это пометка на строке кода: «дойдёшь сюда — остановись». Когда выполнение доходит до неё, программа замирает, а вы получаете управление. Но как остановить программу на конкретной команде?
Самый распространённый трюк прекрасен своей наглостью. Отладчик берёт команду по нужному адресу и временно подменяет первый её байт специальной командой-ловушкой (на многих процессорах это инструкция с кодом 0xCC). Когда процессор доходит до неё, он не выполняет вашу строку, а сообщает операционной системе: «здесь сработала ловушка». Система будит отладчик, тот получает контроль, а оригинальный байт он бережно сохранил и вернёт на место, когда вы продолжите.
Кто кому хозяин
Чтобы всё это работало, отладчик и отлаживаемая программа состоят в особых отношениях. Операционная система предоставляет специальный механизм (в Unix-системах он называется ptrace), который позволяет одному процессу контролировать другой: останавливать его, читать и менять его память, заглядывать в регистры процессора.
То есть отладчик — это не часть вашей программы, а отдельный надзиратель, которому система выдала особые полномочия. Поэтому он может то, что обычной программе запрещено: рыться в чужой памяти.
Откуда он знает имена переменных
Процессор оперирует адресами, а не именами. Откуда же отладчик знает, что по адресу 0x7ffe… лежит ваша переменная счёт? Из отладочной информации. Когда вы компилируете программу в «отладочном» режиме, компилятор вкладывает в неё карту: какая переменная где лежит, какой строке исходника соответствует какая машинная команда, как называются функции.
Вот почему сборка «для отладки» крупнее и медленнее, а в «релизной» сборке этой информации нет — и отлаживать её куда труднее: видны голые адреса вместо понятных имён.
Шаг за шагом
Пошаговое выполнение — ещё один фокус. Процессоры умеют работать в пошаговом режиме: выполнить ровно одну команду и снова отдать управление. Отладчик включает этот режим, и программа продвигается на один машинный шаг. Поскольку отладчик знает соответствие команд и строк исходника, он выполняет столько команд, сколько нужно для одной вашей строки, и снова замирает. Так рождаются кнопки «шаг вперёд» и «зайти внутрь функции».
Стек вызовов как на ладони
Когда программа остановлена, отладчик читает стек — и реконструирует всю цепочку вызовов: какая функция кого вызвала, чтобы добраться до текущей точки. Это и есть тот самый «traceback», который вы видите при ошибке. Только в отладчике вы можете перемещаться по этой цепочке вверх и вниз, разглядывая локальные переменные каждой функции по дороге.
Условия и наблюдение
Современные отладчики идут дальше простых остановок:
- Условные точки останова — «остановись, только если
i == 100». Отладчик на каждом проходе проверяет условие и будит вас лишь когда оно истинно. - Точки наблюдения (watchpoints) — «останови программу, как только кто-нибудь изменит эту переменную». Бесценно, когда значение портится непонятно где.
Почему стоит освоить
Печать в консоль показывает только то, о чём вы догадались спросить заранее. Отладчик позволяет задавать вопросы программе уже после того, как она остановилась: посмотреть любую переменную, пройти назад по стеку, изменить значение на лету и продолжить. Это разница между «гадать по следам» и «допросить свидетеля на месте». А зная, что под капотом — подменённые байты, полномочия от ОС и карта от компилятора, вы перестаёте воспринимать отладчик как магию и начинаете пользоваться им в полную силу.