Определение диапазонов исходного кода
Читатель, вероятно, не очень удивится тому, что здесь снова используется символьная машина DBGHELP.DLL (подробнее она описана в главе 4). Я полагал, что ее функции, работающие с именами исходных файлов и номерами строк исходного кода, позволят отыскивать адреса первой и последней строк рабочих кодов конкретного исходного файла (эту пару адресов я и называю диапазоном адресов). Вооружившись диапазоном адресов и методикой, которая обсуждалась в главе 12, можно было бы подключить функцию OutputDebugString и по адресу возврата определить, находится ли она в диапазоне адресов того исходного файла, из которого пользователь хочет получать предложения трассировки. Хотя этот подход теоретически довольно прост, но для его практической реализации мне пришлось изрядно потрудиться.
Не существует специальной API-функции, которая перечисляет диапазоны адресов исходных файлов, но я полагал, что смог бы обойтись функцией перечисления символов SymEnumerateSymbols. С помощью этой функции Я хотел извлечь первый символ, затем (находясь уже внутри собственной функции перечисления символов) переместиться обратно к началу исходного файла (с помощью функции SymGetLinePrev) и затем перейти к его концу с помощью функции symGetLineNext. В случае простых тестов функция SymEnumerateSymbols работала великолепно, но когда я провел аналогичное тестирование программы GENLIMODS.EXE, то заметил, что диапазоны исходного кода, полученные с помощью SymEnumerateSymbols, не соответствовали тому, что показывал дизассемблер при тестировании GENLIMODS.EXE. Казалось, что при моей методике пропускаются целые секции исходного файла.
Когда я вручную вычислил диапазоны, они получились похожими на перечисленные в табл. 14.1. Проблема возникала из-за того, что функции SymGetLineNext И SymGetLinePrev перечисляют только смежные (непрерывные) диапазоны. Из табл 14.1 видно, что исходные файлы со встроенными (inline) функциями находятся между первой и второй частями GENLIMODS.CPP. Я быстро понял, что это не ошибка, а скорее следствие работы компилятора.
Непонимание наблюдалось с моей стороны: я сосредотачивал свое внимание на исходном файле, когда на самом деле нужно было в первую очередь думать о диапазонах адресов.
Таблица 14.1. Примеры диапазонов адресов GENLIMODS.EXE
Начало
|
Конец
|
Исходный файл
|
0x00401900 |
0x0040 1A8A |
COMMANDLINE.CPP |
0x00401000 |
Ox00402F1F |
GENLIMODS.CPP |
0x00403450 |
0x00403774 |
RESSTRING.H |
0x00403700 |
0x00403700 |
GENLIMODS.H |
0x00403060 |
Ox004040F9 |
SYMBOLENGINE.H |
0x00404690 |
Ox004046AC |
GENLIMODS.CPP |
0x00407080 |
Ox0040852E |
LOMFILE.CPP |
0x00409050 |
Ox0040A532 |
READIGNOREFILES.CPP |
Ox0040C800 |
0x00400894 |
VERBOSE.CPP |