Условии или в данных. Если же
на вкладке Data диалогового окна Breakpoints) фактические адреса выражений и данных. В программе AdvancedBP, показанной в листинге 5-1, требовалось установить точку прерывания глобального выражения, которая должна срабатывать, если "первый символ в имени глобальной переменной g_szGiobai изменится на "G". Для этого пришлось найти адрес переменной g_szciobai (он оказался равным 0x00404594) и установить (в поле Enter the expression to be evaluated на вкладке Data диалогового окна Breakpoints) точку прерывания выражения в формате:
Mchar*) Ox00404594='G'
Однако при пошаговом просмотре каждой инструкции будет показано неправильное выражение:
WO (0x00404594) =='G'
Мне так и не удалось найти подходящей точки прерывания глобального выражения, потому что очень трудно подыскать такое выражение, которое примет отладчик. Намного удобнее в этом случае воспользоваться точкой прерывания глобальной переменной.
/*00З*/ ttinclude <windows.h>
/*004*/ void LocBPFunc ( void)
/*005*/ { // {,AdvancedBP.cpp,}.6
/*006V printf ( "Hello from LocBPFuncW) ;
/*007*/ }
/*008*/ void SkipLocBPFunc ( void)
/*009*/ { // {,AdvancedBP.cpp,}.12 skip 99 times(s)
/*010*/ for ( int i = 0; i < 100; i++)
/*011*/ {
/*012*/ printf ( "SkipLocBPFunc iteration = %d\n", i);
/*013*/ }
/*014*/ }
/*015*/ void ExprTrueLocBP ( void)
/*016*/ { // {,AdvancedBP.cpp, } .20 when 'j=8'
/*017*/ int j = 0;
/*018*/ for ( int i = 0; i < 10; i++)
/*019*/ {
/*020*/ j = i * 2;
/*021*/ }
/*022*/ }
/*023*/ void DataChangeLocBP ( void)
/*024*/.{ // {,AdvancedBP.cpp,}.26 когда изменяется szBuff[5](length:1)
/*025*/ char szBuff[ 10 ];
/*026*/ strcpy ( szBuff, "String!");
/*027*/ }
/*028*/ char g_szGlobal[ 10 ];
/*029*/ int g_ilnt = 0;
/*030*/ void main ( void)
/*031*/ { // 0x401210 -> ТП-адрес точки входа в jmainCRTStartup
/*032*/ LocBPFunc ();
/*0ЗЗ*/ SkipLocBPFunc ();
/*034*/ ExprTrueLocBP ();
/*035*/ DataChangeLocBP ();
/*036*/
/*037*/ //{,,KERNEL32.DLL}_LoadLibraryA@4 <- с отладочными символами
/*038*/ //{,,KERNEL32.DLL}LoadLibrary <- без отладочных символов
/*039*/ LoadLibrary ( "KERNEL32.DLL");
/*040*/
/*041*/ // (char)Ox00404594=='G' <- ТП глобального выражения.
/*042*/ strcpy ( g_szGlobal, "Global!");
/*043*/
/*044*/ // (long)Ох4045АО <- ТП глобальной переменной.
/*045*/ g_ilnt = 0x42;
/*046*/
/*047*/ printf ( "Done!\n");
На рис. 5. 4 приведено диалоговое окно команды Edit|Breakpoints, в нижней части которого показан список Breakpoints, содержащий описания всех установленных в программе AdvancedBP точек прерывания. Флажки в левой части каждого описателя позволяют управлять активностью соответствующих ТП: включение флажка активизирует ТП, а выключение деактивизирует ее (что вынуждает отладчик не выполнять останов программы на этой ТП во время отладочного прохода).
Подобно точке прерывания глобального выражения, точка прерывания глобальной переменной работает наилучшим образом, если при ее установке задать шестнадцатеричный адрес, выполнить явное приведение типа адреса к длинному указателю и указать число элементов наблюдения равным 1. Когда содержимое памяти по этому адресу изменяется, отладчик останавливается. Например, в программе AdvancedBP можно модифицировать выражение *(char*)Ox00404594=='G' так, чтобы прерывание происходило тогда, когда содержимое ячейки памяти по этому адресу изменяется (а не просто содержит код символа "G"). Для этого нужно выполнить приведение адреса к типу long, Т.е. установить ТП по адресу "* (long*) (0x00404594) " (СМ.комментарий в строке 044). Чтобы задействовать отладочные регистры, в общем случае требуется одна или две попытки установить такие ТП с правильными выражениями. Еще раз отметим, что при приведении адреса к типу long не следует устанавливать (в поле Enter the number of elements to watch in an array or structure на вкладке Data диалогового окна Breakpoints) число элементов наблюдения больше 1. Значение в этом поле указывает, что контролируется запись в область памяти размером в двойное слово (DWORD), а из-за того что аппаратные регистры отладки не могут обрабатывать ссылки, превосходящие по размеру двойное слово, устанавливается пошаговый метод проверки памяти.
Рис. 5.4. Список описателей точек прерывания программы AdvancedBP с флажками активизации/деактивизации ТП
Хотя имеется четыре отладочных регистра, в этой программе только две глобальных точки прерывания, работающих одновременно. Если установить группу глобальных точек прерывания, то можно гарантировать, что отладчик будет выполнять программу в пошаговом режиме.
Точки прерывания глобальных переменных — превосходное средство для поиска наиболее сложных видов ошибок, связанных с неконтролируемой записью в память (wild writes). Как указывалось в главе 2, это происходит, когда при записи в память используется неинициализированный указатель, что вызывает непредсказуемую модификацию данных в памяти.
Чтобы открыть эту панель, нужно установить на подходящем исходном операторе простую позиционную точку прерывания и, не изменяя позиции курсора ввода, ввести команду Edit|Breakpoints, Затем в открывшемся диалоговом окне Breakpoints ввести в поле Break at вкладки Location номер строки (после символа "точка"), в которой установлена данная точка прерывания (например, .47), и нажать кнопку Condition (под полем Break at). — Пер.
Если же ввести в поле Enter the expression to be evaluated сам указатель pMyData (без звездочки), то прерывание произойдет, когда изменится сам указатель, указывающий на другую область памяти. — Пер.
Проблема обнаруживается только при аварийном завершении программы или искажении некоторых данных. Если проблема повторяется, т. е. хотя бы изредка искажается значение одной и той же переменной, установите на ней точку прерывания данного типа (т. е. ТП глобальной переменной), чтобы появилась возможность каждый раз узнавать о записи в эту область. Только подготовьтесь к тому, что прежде чем вы наткнетесь на первую случайную запись, точка прерывания много раз попадет на правильные (не случайные) записи в область этой переменной.