Алгоритм для извлечения функции, исходного файла и номера строки из МАР-файла прост, но выполняется с применением шестнадцатеричной арифметики. Пусть, например, аварийный останов произошел по адресу 0x03901099 в модуле MAPDLL.DLL, показанном в листинге 8-1.
Прежде всего, нужно заглянуть в МАР-файлы своего проекта и найти файл, который содержит аварийный адрес. Сначала посмотрите на предпочтительный адрес загрузки и последний адрес в секции общих функций. Адрес ошибки должен находиться между этими значениями, если это не так, значит перед нами "неправильный" МАР-файл.
Чтобы отыскать функцию (или ближайшую общую функцию, если ошибка произошла в статической С-функции), найдите в колонке Rva+Base первый адрес, который превышает аварийный. Тогда предыдущий вход в МАР-файле и есть та функция, которая вызвала аварийный останов. Например, в листинге 8-1 первым адресом функции, превосходящим аварийный (0x3901099), является адрес Ox39010F6, следовательно, ошибку вызвала функция ?MapDLLHappyFunc@@YAPADPAD@z. Имя функции, которое начинается со знака вопроса, является декорированным именем (decorated name) языка C++. Чтобы транслировать это имя, передайте его как параметр команд- | ной строке программы UNDNAME.EXE из Platform SDK. Например, ?MapDLLHappyFunc@@YApADPAD@z переводится этой программой в обычное имя MapDLLHappyFunc, о чем, вероятно, можно было догадаться, просто взглянув на декорированное имя. Другие декорированные имена C++ расшифровы вать труднее, особенно когда используются перегруженные функции. Номер строки вычисляется по следующей формуле:
(crash address) — (preferred load address) — 0x1000
Напомним, что адреса указываются как смещение от начала первой секции кода, что и учитывает эта формула. Вероятно, нетрудно догадаться, почему вычитается предположительный адрес загрузки, но зачем вычитать еще и 0x1000? Адрес ошибки представляет собой смещение от начала секции кода, но эта секция не является первой частью двоичного файла. Его первой частью является РЕ заголовок, длина которого равна 0x1000 байт.