your feedback send to: debugger@fyzor.com     
C++ debugger
Навигатор
Главная
Скриншоты
Документация
Скачать
Исходники
Плагины
API
История
Легенда
Связь
Ссылки
Почта
Search
Search Site With Google
Надежный хостинг по доступным ценам!

Плагины

Вы можете подключать свои собственные DLL-модули (плагины) к отладчику. Это может вам понадобиться по двум причинам:

  1. Вы хотите расширить функциональность отладчика по своему усмотрению.

  2. У вас есть компилятор, отладочная информация которого не поддерживается стандартными загрузчиками, входящими в состав отладчика, и вы хотите написать загрузчик, который читает ее.

Подключение

Плагины подключаются к отладчику через четыре экспортируемые плагином функции:
PLUGIN_Init
обязательна
Вызывается в момент загрузки плагина. Кроме того, по ее наличию отладчик отличает модуль плагина от остальных не являющихся плагинами.
PLUGIN_Shutdown Вызывается перед самой выгрузкой модуля из памяти отладчика. Может использоваться плагином для освобождения своих ресурсов.
PLUGIN_Prop Вызывается из окна управления отладчиком. Может использоваться для редактирования внутренних опций плагина. Опции предпочтительно сохранять в реестр.
PLUGIN_LoadDebugInfoВызывается для загрузки отладочных символов из модуля, загружаемого в отладочный процесс. Должна возвращать TRUE, если символы прочитаны.

Сами плагины могут вызывать функции отладчика, которые объявлены в файле zdapi.h, копию которого можно скопировать из окна управления плагинами отладчика. Подробнее об этих функциях отладчика читайте здесь.

Порядок загрузки плагинов

Все плагины должны находиться в одной директории, которая определяется в опциях плагинов, открывающихся клавишей ALT+F5.

Плагины загружаются в момент загрузки самого отладчика по следующиму алгоритму: отладчик открывает директорию плагинов, и последовательно загружает каждый *.dll модуль из директории. Если этот DLL-модуль имеет функцию PLUGIN_Init, то он считается плагином и остается в памяти, иначе он из нее выгружается.

Кроме того, плагины могут быть перезагружены после смены пути плагинов. В этом случае все загруженные модули сначала выгружаются, после чего из нового пути загружаются другие модули.

Принцип использования плагина

Примеры работающих плагинов с исходными файлами на Си вы можете скачать отсюда. Здесь же будет описан краткий алгоритм работы. Он прост: первой в вашем плагине вызывается функция PLUGIN_Init (), которая используется для инциализации ваших переменных. Она же может установить заголовок вашего модуля, который будет использован отладчиком в качестве комментария к модулю в окне управления плагинами. В это строку можно также выводить форматы, загрузку которых поддерживает плагин, или же просто его назначение.

Далее отладчик обращается к плагинам в момент загрузки любого из модулей отлаживаемого процесса. Он последовательно вызывает функции PLUGIN_LoadDebugInfoдля всех плагинов поочередно, до тех пор пока функция одного из них не возвратит TRUE, что означает, что символы из модуля DLL загружены нормально. Если ни одна функция не возвратит TRUE, то формат отладки считается неопознанным и отладочная информация становится недоступна.

Функция, вызываемая отладчиком в качестве загрузчика, объявлена следующим образом:

BOOL PLUGIN_LoadDebugInfo(BYTE*FileRoot, BYTE*DebugRoot);

В момент вызова параметр #FileRoot указывает на область памяти, куда загружен файл модуля.

Обратите внимание, что это - не указатель памяти модуля в отлаживаемом процессе, а лишь область, куда загружена точная копия файла модуля. Cам DLL-модуль, как исполняемая часть отлаживаемой программы находится всегда в контексте отлаживаемого процесса, а его секции обычно смещены в памяти относительно их положения в файле. Эти две причины делают неудобным извлечение символов прямо из него, гораздо удобнее извлекать их прямо из файла.

Параметр #DebugRoot указывает на область памяти, где находятся данные отладки. Этот параметр передается для удобства, так как его можно самостоятельно вычислить из первого, зная формат заголовка исполняемого файла, который приводится ниже.

Формат исполняемых файлов

Если Вы хотите написать загрузчик отладочной информации, то вам, возможно, понадобится информация о формате самого исполняемого файла. Это может потребоваться только в очень редких случаях, когда по каким-либо причинам отладочная информация хранится не в стандартном месте. В остальных же случаях можно использовать указатель #DebugRoot, который указывает на отладочные данные в модуле.

В следущей таблице представлена структура заголовка стандартного исполняемого *.exe или *.dll файла. Поля, которые могут оказаться полезными, выделены жирным шрифтом. Более подробная информация на этот счет доступна в MSDN, а все структуры объявлены в файле winnt.h.

Тип данныхИмя Полезное содержание
IMAGE_DOS_HEADER DosHeader Указатель NT заголовка
пропуск переменной длины...
DWORD Signature 'PE'
IMAGE_FILE_HEADER FileHeader Кол-во секций и характеристики модуля
IMAGE_OPTIONAL_HEADER32 OptionalHeader Точка входа, база образа, размеры, версия и другое
IMAGE_DATA_DIRECTORY Export Экспортируемые символы
IMAGE_DATA_DIRECTORY Import Импортируемые символы
IMAGE_DATA_DIRECTORY Resource Ресурсы
IMAGE_DATA_DIRECTORY Exception Exception Directory
IMAGE_DATA_DIRECTORY Security Security Directory
IMAGE_DATA_DIRECTORY BaseReloc Base Relocation Table
IMAGE_DATA_DIRECTORY Debug Директория отладочных символов
IMAGE_DATA_DIRECTORY Copyright/Architecture Architecture Specific Data
IMAGE_DATA_DIRECTORY GlobalPtr RVA of GP
IMAGE_DATA_DIRECTORY TLS TLS Directory
IMAGE_DATA_DIRECTORY LoadConfig Load Configuration Directory
IMAGE_DATA_DIRECTORY BoundImport Bound Import Directory in headers
IMAGE_DATA_DIRECTORY IAT Import Address Table
IMAGE_DATA_DIRECTORY DelayImport Delay Load Import Descriptors
IMAGE_DATA_DIRECTORY COM_Descriptor COM Runtime descriptor
пропуск переменной длины (обычно нулевой)...
IMAGE_SECTION_HEADER Sections [] Секции разных данных, включая ресурсы и секции кода (обычно одна). Каждая секция имеет символьное имя длиной до восьми символов.

Здесь следует отметить одну тонкость: все секции в исполняемом файле хранятся в компактном виде - ради экономии места промежутки между ними искусственно уменьшены. Но после загрузки их в память в качестве исполняемого модуля, их адреса выравниваются системой по границам страниц.

По этой причине многие значения в заголовках имеют пометку VA (virtual address), означающий, что их реальное значение действительно только после выравнивания. Поэтому для определения реального смещения таких значения в самом файле из адреса следует вычитать значение #delta, вычисляемое по следующей формуле:

delta = section->VirtualAddress - section->PointerToRawData

Где #section - это секция, в пределах которой находится какой-либо VirtualAddress. Для ее нахождения можно написать функцию FindSectionByVA, которая сканирует секции и определяет в какой из них лежит заданный VA.

Разработчикам компиляторов

К ним у меня одна просьба: перестать изобретать велосипед, забыть всякие "бинарные" форматы и использовать для отладочной информации обычный текст, анализируя который можно понять его формат. В качестве основы описания структур, перечисления и переменных можно использовать Си-подобный синтаксис. Он очень легко поддается анализу, и извлечению из него информации.

Самое главное достоинство такого подхода в том, что его информативная избыточность делает его расширяемым снизу вверх.

Если вы хотите, чтобы для вашего компилятора существавал отладчик, то позаботьтесь о доступности его формата отладки.

Пример плагина

В этом окне представлен пример простого плагина, который в момент инициализации создает команды, доступные через диалог управления плагинами. При вызове одной из команд, на экран выскакивает окно с соответствующим сообщением.

Автор проекта и сайта: Sapunov Vladimir
(c) Копирайт 2005-2008