Мы рассмотрели вопросы правильного размещения экспортируемых функций, и теперь читатель должен уверенно устанавливать позиционную (location) точку прерывания в любом месте приложения. Роль позиционных точек прерывания в отладочном процессе довольно значительна, но, как было указано в начале данной главы, к ним можно также добавить некоторый "интеллект" с целью повышения эффективности работы отладчика. Носителями этих "интеллектуальных" возможностей являются специальные модификаторы позиционных точек прерывания: счетчики пропусков, условные выражения и изменения переменных.
Счетчики пропусков
Самый простой модификатор позиционной точки прерывания (Tll) — это счетчик пропусков (skip count). Он указывает отладчику, что нужно вставить точку прерывания, но пропускать ее выполнение (т. е. не приостанавливать приложение в этой точке) указанное количество раз. С помощью этого модификатора легко решается проблема прерывания на нужной итерации цикла.
Добавлять счетчик пропусков к простой точке прерывания довольно легко. Сначала установите обычную позиционную точку прерывания и раскройте диалоговое окно Breakpoints. Выделите позиционную точку прерывания в списке Breakpoints, и щелкните кнопку Condition. Затем в нижнем редактируемом поле диалогового окна Breakpoint Condition введите нужное число пропусков точки прерывания.
Когда отладчик, наконец, остановит выполнение приложения в такой точке, он сообщит, сколько раз выполнялся помеченный им оператор. Если есть цикл, в котором имеет место аварийный останов, но неизвестно, на какой итерации это происходит, то нужно добавить позиционную точку прерывания со счетчиком пропусков к строке какого-нибудь оператора внутри цикла. Значение счетчика пропусков должно быть больше, чем общее число итераций цикла. Когда программа завершится аварийно, откройте диалоговое окно Breakpoints и посмотрите на точку прерывания, обозначенную в списке Breakpoints1. После строки описателя точки прерывания располагается остаток счетчика пропусков (в круглых скобках).
Знание различных псевдорегистров, которые обеспечивают доступ к регистровым и специальным значениям, а также творческий подход — вот два секрета применения условных выражений. Например, хотя отладчик Visual C++ не имеет явного метода для установки позиционной точки прерывания, которая срабатывает только в определенном потоке под Windows 2000, но если установить выражение @TIВ=линейный адрес TIB, то прерывание произойдет только на указанном потоке. Первый шаг заключается в том, чтобы ввести псевдорегистр @ТIB в окно Watch и найти линейный адрес информационного блока потока, на котором требуется выполнить прерывание. Чтобы активизировать поток, который надо проверить, можно использовать диалоговое окно Threads отладчика. Если, например, поток содержит в псевдорегистре @Т1В адрес, равный Ox7FFDEOOO, то выражение выглядит так: @TIB ==
Ox7FFDEOOO. Для Windows 98 нужно просмотреть регистр FS, который является уникальным для каждого потока, и задать выражение @FS == значение конкретного потока (thread specific value).
Для того чтобы выполнить прерывание, основанное на конкретном коде последней ошибки (last error code), можно использовать псевдорегистр @ERR. Например, чтобы выполнить прерывание после API-вызова, который, согласно документации Platform SDK, может сгенерировать последнюю ошибку ERROR_FILE_NOT_FOUND, выражение должно выглядеть так: @ERR==2. Числовое значение ошибки с идентификатором ERROR_FILE_NOT_FOUND можно найти в файле WINERROR.H. Все псевдорегистры перечислены в табл. 5.1.
Наконец, из-за того что нельзя вызывать функции в таких выражениях, прерывание на строке с конкретным (строчным) значением затруднительно.
TIB — Thread Information Block, информационный блок потока. — Пер.
В этом случае просто установите выражение, которое проверяет каждый символ, например, так:
(szBuff[0] = 'Р')-&& (szBuff [l] = 'a'j&& (SzBuff [2] == 'm').
Другой способ использования условных выражений в прерываниях: можно комбинировать их со счетчиком пропусков.
Такой прием позволяет выполнить прерывание, когда n-ое значение выражения станет равно true (где п — исходное значение счетчика пропусков).
Таблица 5.1. Выражения и псевдорегистры окна Watch
|
Псевдорегистр
|
Описание
|
|
©ERR |
Значение последней ошибки; то же значение возвращается API-функцией GetLastError |
|
©TIB |
Информационный блок текущего потока; необходим, потому что отладчик не обрабатывает формат FS:0 |
|
©CLK |
Недокументированный регистр часов; используется только в окне Watch |
|
@ЕАХ, @ЕВХ, ©ЁСХ, @EDX, ©ESI, ©EDI, ©EIP, ©ESP, ©EBP, ©EFL |
Регистры Intel CPU |
|
@CS, @DS, @ES, @SS, @FS, ©GS |
Сегментные регистры Intel CPU |
|
©STO, ©ST1, @ST2, ©ST3, ©ST4, ©ST5, ©ST6, ©ST7 |
Регистры чисел с плавающей точкой Intel CPU |