Формат MAP-файла, генерируемый компилятором или линкеро
Модератор: Модераторы
-
Alexey_Melky
- новенький
- Сообщения: 21
- Зарегистрирован: 14.05.2005 14:55:31
Формат MAP-файла, генерируемый компилятором или линкеро
FPC 2.2.0 + lazarus, собранный из текущей ветви 0.9.25.
Скомпилировал небольшой тестовый проект под Win32. При выполнении проекта было сгенерировано исключение.
Чтобы выяснить, где (в каком модуле, при выполнении какой строки кода) произошло исключение, попытался проанализировать и распарсить вручную MAP-файл, созданный компилятором или линкером. Обнаружил, что информация о модулях и строках не присутствует в этом файле.
Может быть кто-нибудь знает, как по адресу исключения вычислить строку кода на которой оно произошло? Одним из условий должно быть отсутствие в исполняемом файле отладочной и символьной информации. Возможно, такую информацию пр и компиляции можно сохранить в отдельный от исполняемого модуля файл?
Так, например map-файл, полученный при сборке проекта компилятором Delphi содержит исчерпывающую информацию о том, где именно искать код, вызвавший исключение. Мало того, имеется инструментарий, производящий автоматический парсинг такого MAP-файла и позволяющий наполнить содержательными данными callstack.
Скомпилировал небольшой тестовый проект под Win32. При выполнении проекта было сгенерировано исключение.
Чтобы выяснить, где (в каком модуле, при выполнении какой строки кода) произошло исключение, попытался проанализировать и распарсить вручную MAP-файл, созданный компилятором или линкером. Обнаружил, что информация о модулях и строках не присутствует в этом файле.
Может быть кто-нибудь знает, как по адресу исключения вычислить строку кода на которой оно произошло? Одним из условий должно быть отсутствие в исполняемом файле отладочной и символьной информации. Возможно, такую информацию пр и компиляции можно сохранить в отдельный от исполняемого модуля файл?
Так, например map-файл, полученный при сборке проекта компилятором Delphi содержит исчерпывающую информацию о том, где именно искать код, вызвавший исключение. Мало того, имеется инструментарий, производящий автоматический парсинг такого MAP-файла и позволяющий наполнить содержательными данными callstack.
- Brainenjii
- энтузиаст
- Сообщения: 1351
- Зарегистрирован: 10.05.2007 00:04:46
-
Alexey_Melky
- новенький
- Сообщения: 21
- Зарегистрирован: 14.05.2005 14:55:31
Brainenjii писал(а):Может не в тему, но посмотрите в опциях компилятора->связывание - там есть возможность генерировать информацию о строках и для дебаггера...
Если имеется ввиду опция -gl, то она включена. Тем не менее, повторюсь, что информация о строках нужна при выполнении программы на компе, где нет ни среды разработки, ни отладчика.
Для чего это нужно? Я собрал релиз некоего проекта, получил исполняемый файл, MAP-файл или какой-нибудь другой, описывающий соответствие адресов строкам исходных файлов. Исполняемый файл передается пользователям.
И, если возникает исключение у пользователя программы, программист, получив информацию об адресе, смог бы определить какая часть кода ответственна за произошедшее.
- Sergei I. Gorelkin
- энтузиаст
- Сообщения: 1409
- Зарегистрирован: 24.07.2005 14:40:41
- Откуда: Зеленоград
Cheb писал(а):Юнит lineinfo нихрена не пашет, ищет эту информацию не в том формате, в котором современный компилятор её добавляет в екзешник.
Да вы на дату этого юнита смотрели? 2000 год!
По умолчанию fpc генерит дебаг инфу в формате stabs (ключик -g) и ее понимает юнит lineinfo.
Ключик -gw генерит дебаг инфу в более современном формате dwarf. Для него, как было сказано, есть юнит lnfodwrf.pp
Насколько я знаю, виндовый gdb до сих пор не понимает dwarf. Поэтому "современность" это понятие относительное
-
Alexey_Melky
- новенький
- Сообщения: 21
- Зарегистрирован: 14.05.2005 14:55:31
Большое спасибо всем, кто ответил. На данный момент видится следующее решение: компилировать проект с отладочной информацией, находить ее, например как это делает модуль lineinfo, записывать в отдельный файл, а затем прогонять загручный модуль через утилиту strip. Затем, если в процессе работы возникает исключение, загрузить отладочную инфу из отдельного файла и использовать тот же lineinfo.
Припахал lnfodwrf, модифицировав её так, чтобы можно было указывать имя dll вручную. Вроде, запустилось... И дало на выходе кашу.
Включённая отладка показала, что оно нормально парсит один блок отладочной информации (относящийся к основному dpr библиотеки), а при переходе к следующему - неправильно вычисляет его смещение и идёт вразнос.
Надо разбираться, что там где не так, а у меня совершенно времени нет.
Включённая отладка показала, что оно нормально парсит один блок отладочной информации (относящийся к основному dpr библиотеки), а при переходе к следующему - неправильно вычисляет его смещение и идёт вразнос.
Надо разбираться, что там где не так, а у меня совершенно времени нет.
Я уже близок к успеху.
Причина нерабочей linfodwrf - в небольших непредсказуемых сдвигах между модулями отладочной информации ( в районе одного-трёх байт). Я пока не смог выявить в них закономерность, поэтому моя модификация парсера использует хак, подбирая сдвиг методом перебора пока заголовок блока не станет похож на настоящий.
Увы, это *не* выравнивание на 32 или 64 бита - сдвиги действительно случайные.
Естественно, я строю свой модуль на совершенно других принципах (хотя код из linfodwrf выдираю вовсю). Один модуль умеет извлекать информацию о строках из екзешника, другой - парсить уже выдранную. ИМО, так гораздо гибче. Можно, например, выдрать эту инфу в отдельный файл, а остальную отладочную информацию (сотни килобайт) прибить strip'ом.
Мой модуль гораздо уже специализирован - жрёт только elf32.
Причина нерабочей linfodwrf - в небольших непредсказуемых сдвигах между модулями отладочной информации ( в районе одного-трёх байт). Я пока не смог выявить в них закономерность, поэтому моя модификация парсера использует хак, подбирая сдвиг методом перебора пока заголовок блока не станет похож на настоящий.
Увы, это *не* выравнивание на 32 или 64 бита - сдвиги действительно случайные.
Естественно, я строю свой модуль на совершенно других принципах (хотя код из linfodwrf выдираю вовсю). Один модуль умеет извлекать информацию о строках из екзешника, другой - парсить уже выдранную. ИМО, так гораздо гибче. Можно, например, выдрать эту инфу в отдельный файл, а остальную отладочную информацию (сотни килобайт) прибить strip'ом.
Мой модуль гораздо уже специализирован - жрёт только elf32.
