Как вы извлекаете информацию о локальной переменной (адрес и тип) из программы Delphi или отладочную информацию, созданную компилятором?

105

Моя цель:

  • Учитывая приостановленный поток в 32- или 64-разрядной программе Windows, скомпилированной с помощью Delphi, пройти по стеку (выполнимо)
  • Учитывая записи стека, для перечисления локальных переменных в каждом методе и их значений. То есть, по крайней мере, найти их адрес и тип (integer32 / 64 / signed / unsigned, string, float, record, class ...), комбинацию которых можно использовать для поиска их значения.

Первое - это нормально, и этот вопрос касается второго. На высоком уровне, как вы перечисляете локальные переменные с учетом записи в стеке в Delphi?


На низком уровне я исследовал вот что:

RTTI: не перечисляет такую ​​информацию о методах. Я никогда не думал, что это реальный вариант, но все равно перечисляю его здесь.

Отладочная информация: загрузка отладочной информации, созданной для отладочной сборки.

  • Файлы карты: даже файл подробной карты (файл текстового формата! Откройте его и посмотрите) не содержит информации о локальных переменных. По сути, это список адресов и номеров строк исходного файла. Отлично подходит для обращения к файлу и корреляции строк, например, синие точки в желобе; не очень подходит для более подробной информации
  • Информация об удаленной отладке (файл RSM) - неизвестная информация о его содержимом или формате.
  • Файлы TD32 / TDS: мое текущее направление исследований. Они содержат глобальные и локальные символы и много другой информации.

Вот проблемы, с которыми я сталкиваюсь здесь:

  • Документации по формату файлов TD32 (которую я могу найти) нет.
  • Большая часть моих знаний о них получена из кода Jedi JCL, использующего их (JclTD32.pas), и я не уверен, как использовать этот код, и достаточно ли обширны структуры, чтобы отображать локальные вары. Я почти уверен, что он будет обрабатывать глобальные символы, но я очень не уверен в локальных. Существует большое количество определенных констант и без документации по формату, чтобы прочитать, что они означают, я остаюсь гадать. Однако эти константы и их имена должны откуда-то взяться.
  • Источник, который я могу найти с помощью информации TDS , не загружает и не обрабатывает локальные символы.

Если это правильный подход, тогда возникает вопрос: «Есть ли документация для формата файла TDS / TD32 и есть ли какие-либо образцы кода, которые загружают локальные переменные?»

Образец кода не обязателен, но может быть очень полезен, даже если он минимален.

Дэвид
источник
2
На самом деле я не использовал модули Jedi JCL для доступа к информации TD32 - у меня есть собственная проприетарная библиотека для этого, но похоже, что вся основная сантехника, которая вам понадобится, есть в JclTD32.pas. Тем не менее, я не могу найти демонстрационного кода для доступа к информации о переменных, но образец, который есть (в .. \ jcl \ examples \ windows \ debug \ sourceloc), показывает, как получить информацию о номере строки из данных TD32, поэтому вы должны иметь возможность опираться на это, чтобы получить то, что вам нужно. Пожалуйста, сообщите здесь, что вы узнали :)
500 - Внутренняя ошибка сервера
2
@ 500-InternalServerError Спасибо. Информацию о номере строки легко получить (даже в файлах карты), но можете ли вы предоставить какую-либо информацию о том, что вы видите в коде JCL, которая конкретно относится к локальным символам? Кроме того, из любопытства, какая у вас проприетарная библиотека TD32 и опубликована / доступна для общего пользования или предназначена только для внутреннего пользования?
Дэвид
3
Каждый символ процедуры / функции / метода под ним, в свою очередь, содержит список символов, которые являются локальными для него. Похоже, что большинство определений есть в отряде джедаев, но некоторые из них без комментариев. Я предлагаю создать крошечные тестовые приложения и посмотреть, что возвращает перечисление символов. Код, который у меня есть, является проприетарным, и я не могу его публиковать. В любом случае это не касается темы локальных переменных. Но информация, на которой он основан, является полуобщественной, поэтому я могу помочь, если вы наткнетесь на определенные стены.
500 - Внутренняя ошибка сервера
4
tds2pdb ( code.google.com/p/map2dbg ), похоже, имеет парсер для файлов tds. Хотя это код C #.
Graymatter
4
Да, раньше был неофициальный документ, но затем Borland (в то время) решила выпустить вместо этого dll для доступа к отладочной информации, чтобы они могли изменить внутренний формат и не обновлять документацию. К сожалению, сейчас я не могу найти ни исходный документ, ни dll. Предлагаю вам обратиться в службу технической поддержки Embarcadero и спросить об этом.
500 - Внутренняя ошибка сервера

Ответы:

2

Проверьте, не были ли какие-либо символы отладки в двоичном формате. Также возможно использование GDB (в Windows его порт). Было бы здорово, если бы вы нашли файл .dbg или .dSYM. Они содержат исходный код, например.

gdb> list foo
56 void foo()
57 {
58  bar();
59  sighandler_t fnc = signal(SIGHUP, SIG_IGN);
60  raise(SIGHUP);
61  signal(SIGHUP, fnc);
62  baz(fnc);
63 }

Если у вас нет файлов отладки, вы можете попробовать получить MinGW или Cygwin и использовать nm (1) ( страница руководства ). Он будет читать имена символов из двоичного файла. Они могут содержать несколько типов, например, C ++:

int abc::def::Ghi::jkl(const std::string, int, const void*)

Не забудьте добавить --demangleопцию, иначе вы получите что-то вроде:

__ZN11MRasterFont21getRasterForCharacterEh

вместо того:

MRasterFont::getRasterForCharacter(unsigned char)
Верхний секрет
источник
2
Якуб, спасибо за ответ. К сожалению, мне, вероятно, нужно прочитать конкретный формат отладки - TDS. Приложения Delphi не компилируются с GDB-совместимой отладочной информацией в Windows. Я не уверен, как nm поможет, поскольку он будет полагаться на определенный формат файла отладки, который, вероятно, не тот, который генерирует Delphi. Или я неправильно понял ваш ответ - например, может ли GDB читать символы Delphi?
Дэвид
@DavidM, ваш комментарий очень важен. Попробуйте найти порт GNU Binutils или GNU Debugger в Windows (я знаю только порт Binutils). Для GDB есть библиотека BFD. Он также используется в Binutils. Он позволяет читать файлы нескольких форматов и распознавать их по магическим номерам. Если ничего не получается, используйте инструмент под названием strings. Он будет извлекать строки из любого двоичного файла. См. Страницу руководства . Это напечатает строки, которые могут, но не должны быть полезны
Top Sekret
0

Взгляните на http://download.xskernel.org/docs/file%20formats/omf/borland.txt Справочник по открытой архитектуре. Он старый, но, возможно, вы найдете соответствующую информацию о формате файла.

Muetze1
источник
Не могли бы вы добавить контекст, в будущем ссылка может стать неработающей.
Hintham
Ссылка содержит официальный документ от Borland о формате файла OMF, используемом компилятором Borland, и других форматах двоичных файлов, используемых Borland. Несколько лет назад я взглянул на формат файла TDS, и мне показалось, что некоторые его части совместимы с документированными форматами файлов. При попытке собрать любую информацию о локальных переменных из файла TDS следует использовать связанную документацию или ссылаться на нее. Если ссылка не работает, мой ответ будет бесполезным, а необходимая информация будет потеряна. Связанный «Справочник по открытой архитектуре» был частью старых выпусков Turbo Pascal и C.
Muetze1