Библиотека сайта rus-linux.net
GDB
Глава 4 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: GDB
Автор: Stan Shebs
Перевод: А.Панин
4.7. Часть, ответственная за работу с символами
Часть GDB, отвечающая за работу с символами главным образом предназначена для чтения исполняемого файла, извлечения из него любой найденной информации о символах и добавления этой информации в таблицу символов.
Процесс чтения начинается с библиотеки BFD. BFD является разновидностью универсальной библиотеки для обработки бинарных файлов и файлов с объектным кодом; работая в любой системе, она может читать и записывать файлы в оригинальном формате Unix a.out
, формате COFF (используемом в System V Unix и MS Windows), формате ELF (используемом в современных системах Unix, GNU/Linux и большинстве встраиваемых систем), а также в некоторых других форматах. Внутренне устройство этой библиотеки представлено сложной структурой макросов языка C, которые преобразуются в код, в котором объединяются запутанные особенности форматов фалов объектного кода для множества различных систем. Представленная в 1990 году, библиотека BFD также используется ассемблером и линковщиком GNU, а ее способность формирования файлов объектного кода для любой целевой системы делает ее ключевым программным компонентом при кроссплатформенной разработке с использованием инструментов, предоставляемых проектом GNU. (Перенос библиотеки BFD на другие платформы является также первым ключевым шагом процесса переноса набора инструментов на новую целевую платформу.)
GDB использует библиотеку BFD исключительно для чтения файлов, а именно для извлечения блоков данных из исполняемого файла и помещения их в пространство памяти процесса GDB. После этого GDB может использовать собственные функции чтения данных, разделенные на два уровня. Первый уровень позволяет получить базовую информацию о символах или "минимум данных для символов", который представлен только самими именами символов, которые требуются линковщику для выполнения работы. Эти имена являются всего лишь строками с адресами и ничем больше; будем считать, что адреса в текстовых секциях соответствуют функциям, адреса в секциях данных соответствуют данным, и так далее.
Второй уровень позволяет получить подробную информацию о символах, которая обычно имеет свой собственный формат, отличающийся от базового формата исполняемого файла; например, информация в формате данных отладки DWARF хранится в секциях файла формата ELF со специальными названиями. В отличие от нее, информация в старом формате данных отладки stabs
, применяемом в Berkley Unix, использует специально обозначенные символы из основной таблицы символов.
Код, предназначенный для чтения информации о символах, является в какой-то мере сложным для чтения, так как различные форматы информации о символах позволяют кодировать любые разновидности информации о типах, которая в свою очередь будет использоваться в исходной программе, но в рамках каждого из форматов это действие осуществляется своим уникальным способом. Часть GDB, ответственная за чтение данных символов, просто обрабатывает данные определенного формата и формирует символы GDB, руководствуясь предположением об их соответствии в рамках используемого формата.
Частичные таблицы символов
Для программы значительного размера (такой, как Emacs или Firefox) формирование таблицы символов может занять достаточно длительный промежуток времени, возможно даже несколько минут. Измерения четко указывают на то, что это время тратится не на чтение фала, как кто-либо мог предположить, а на формирование таблицы символов в пространстве памяти GDB. В этом случае приходится обрабатывать буквально миллионы небольших взаимосвязанных объектов, что занимает время.
Доступ к большей части информации о символах никогда не будет осуществлен в рамках сессии, так как она является локальной для функций, которые пользователь скорее всего никогда не будет использовать. Таким образом, в тот момент, когда отладчик GDB в первый раз извлекает информацию о символах программы, он производит поверхностный обзор информации о символах и ищет исключительно глобально видимые символы, записывая их в таблицу символов. Информация о символах для функции или метода в полном объеме извлекается только тогда, когда пользователь останавливает выполнение программы в этой функции.
Частичные таблицы символов позволяют GDB стартовать в течение нескольких секунд, даже при работе с программами значительного размера. (Символы разделяемых библиотек также загружаются динамически, но процесс их загрузки кардинально отличается. Обычно GDB использует специфичную для используемой системы технику получения оповещения о загрузке библиотеки, после чего формирует таблицу символов с функциями и соответствующими им адресами, полученными от динамического линковщика.)
Поддержка языков программирования
Поддержка языков программирования в основном заключается в реализации системы разбора выражений и вывода значений. Детали реализации системы разбора выражений зависят от языка программирования, но в общем случае она базируется на системе анализа грамматики Yacc, взаимодействующей со специально разработанным лексическим анализатором. В соответствии с целями разработки GDB, заключающимися в обеспечении гибкости при работе в интерактивном режиме, система разбора выражений не должна быть особенно строгой; например, если она сможет определить подходящий тип данных для выражения, она просто будет рассматривать случай использования этого типа без предъявления пользователю требования, заключающегося в необходимости добавления операции приведения или преобразования типа.
Так как система разбора выражений не должна обрабатывать объявления или декларации типов, она гораздо проще полноценной системы разбора выражений языка программирования. Аналогично, в случае вывода значений приходится иметь дело с множеством типов значений, которые следует выводить и обычно специфичная для языка программирования функция вывода данных может вызвать необходимый код для непосредственного выполнения задачи.
Продолжение статьи: Часть, ответственная за работу в целевой системе