Пре-процессор трассировки программного обеспечения Windows
Пре-проце́ссор трассиро́вки програ́ммного обеспе́чения Windows (англ. Windows software trace preprocessor) — это препроцессор, который упрощает использование трассировки событий через WMI для реализации эффективной программной трассировки software tracing в драйверах и приложениях, предназначенных для операционных систем, начиная с Windows 2000 и новее.
WPP был создан компанией Microsoft и входит в состав Windows DDK. Хотя WPP применим в различных задачах, он не включён в Windows SDK и, в основном, используется для драйверов и вспомогательного программного обеспечения, производимого разработчиками, приобретшими Windows DDK.
Предыстория
Программная трассировка — это специализированный вариант журналирования, используемый для записи информации о выполнении программы. Эти данные обычно применяются для отладки. В отличие от журнала событий, основное предназначение которого — формировать записи о событиях для целей аудита системными администраторами или анализа административными инструментами, программная трассировка служит, в первую очередь, вспомогательным инструментом для разработчиков. В связи с этим многие нефункциональные требования к журналу событий, например, локализация сообщений или стандартизированный формат вывода) не ставятся перед большинством сценариев программной трассировки. С другой стороны, трассировка предъявляет особые требования к производительности, которые обычно не столь критичны для журналирования событий. Примером такого применения является техника трассировки входа/выхода (in/out tracing), при которой сообщения генерируются при входе и выходе из функций или методов, чтобы разработчик мог визуально проследить путь выполнения, включая значения аргументов и результатов, в отладчике или текстовом журнале. Такой подход, полезный для разработчиков, может серьёзно ухудшить производительность, если трассировку нельзя отключить, либо на этапе компиляции через условную компиляцию, либо во время выполнения с помощью флагов[1].
Дополнительные специфические аспекты программной трассировки:
- В проприетарном ПО трассировочные данные могут содержать чувствительную информацию о исходном коде продукта;
- Если трассировка может включаться или отключаться во время выполнения, многие способы трассировки требуют включения значительного объёма дополнительных данных в исполняемый файл, что может косвенно ухудшить производительность даже при выключенной трассировке;
- Если включение или отключение трассировки осуществляется на этапе компиляции, получение трассировочных данных с пользовательского компьютера зависит от наличия и установки особой, трассировочной сборки программы;
- Некоторые виды программного обеспечения должны отвечать строгим требованиям к производительности даже при активной трассировке.
Из-за первых двух соображений традиционно для программной трассировки используется условная компиляция для включения или удаления трассировочных сообщений и соответствующих данных. Например, с помощью C-препроцессора можно определить макрос DebugOut следующим образом:
#ifdef _DEBUG
#define DebugOut(msg, ...) \
DebugPrintf(__FUNCTION__ "(" __FILE__ ":" TO_STRING(__LINE__) ")\t" \
msg, __VA_ARGS__)
#else
#define DebugOut(msg, ...)
#endif
где TO_STRING — макрос для преобразования номера строки (__LINE__) в строку, а DebugPrintf — функция, подобная printf, выводящая сообщения в отладчик.
Тогда следующая строка кода:
DebugOut("Error %d occurred\n", error_code);
выведет сообщение примерно такого вида (только в отладочной сборке):
SomeFunction(file.c:78) Error 217 occurred
Другой подход, особенно для трассировки входа/выхода, заключается в использовании инструментирования. Этот способ может решить большую часть упомянутых проблем, но обычно доступен только для управляемого кода.
Трассировка событий WMI — это пример технологии, специально оптимизированной для трассировки в производительно чувствительном коде, таком как драйверы. Она также позволяет управлять распространением чувствительных трассировочных данных, так как человекочитаемые строки сообщений («Error %d occurred\n» в примере выше) определяются отдельно от кода и, таким образом, не попадают в сам продукт (в коде используется номер сообщения). Однако имеются следующие ограничения:
- Трассировка событий WMI не позволяет автоматически генерировать часть сообщения вида
«SomeFunction(file.c:78)». Это свойственно всем подобным технологиям, а не только трассировке событий WMI; - Требование отделять человекочитаемую часть трассировочного сообщения от кода может снижать читабельность исходного кода;
- Использование такого подхода может привести к существенной дополнительной работе даже для единичных трассировочных сообщений.
Принцип работы WPP
Пре-процессор трассировки программного обеспечения Windows (WPP) запускается до этапа компиляции, то есть даже раньше C-препроцессора, и для каждого обрабатываемого файла генерирует заголовок трассировочных сообщений (по умолчанию — файл filename.tmh, где filename — имя исходного файла). Этот заголовочный файл требуется явно включать в исходный код, например:
// Файл: file.cxx // Пример использования WPP #include "file.tmh"
Понимание C/C++-синтаксиса у WPP весьма ограничено: он не разворачивает макросы (кроме особых случаев, когда это необходимо), не обрабатывает препроцессорные директивы (pragmas) и не выполняет семантического анализа.
Разработчик указывает один или несколько трассировочных макросов, которые должно обрабатывать WPP, с помощью конфигурационного файла, специальных аннотаций в комментариях, параметров командной строки либо их комбинации. Каждый раз, когда WPP находит указанный макрос в исходном коде, он генерирует для него соответствующий макрос сообщения трассировки. Иными словами, если, к примеру, макрос трассировки называется DoTrace, WPP создаёт отдельный макрос сообщения для каждого его вхождения. Формально эти макросы различаются по имени файла и номеру строки, а сам WPP определяет исходный макрос таким образом, чтобы при каждом вхождении он раскрывался в отдельный макрос сообщения.
То, как генерируются макросы сообщений трассировки, определяется шаблонным файлом (его формат не задокументирован). Стандартные шаблоны, прилагаемые к WPP, предполагают включение строки трассировочного сообщения в виде аннотации (используется возможность __annotation компилятора Microsoft). Эти строки не попадают в компилируемый код, но включаются в файл символов отладчика в таком формате, который понимают утилиты, входящие в состав WPP. Макросы сообщений трассировки содержат также логику для включения/выключения трассировки по флагам и обращения к API трассировки событий WMI.
Ограничения
- WPP не разворачивает макросы и не распознаёт вызов трассировочного макроса внутри определения другого макроса. Например, если
DoTrace— трассировочный макрос, аCheckForErrorsопределён так:
#define CheckForErrors(error_code) \
if (IsError(error_code)) \
{ \
DoTrace("Error %d occurred\n", err); \
HandleError(error_code); \
}
то для DoTrace внутри CheckForErrors WPP не сгенерирует соответствующие макросы сообщений трассировки. Существует отдельный обходной механизм для подобных случаев, но определённый класс макросов остаётся невыражаемым даже с его помощью.
- Стандартный шаблон генерирует код, корректно работающий только с компилятором Microsoft. Хотя это не является фундаментальным ограничением самого препроцессора, отсутствие документации по формату шаблонов на практике приводит к тому, что WPP применяется только с этим компилятором;
- В ранних версиях WPP возникали ошибки компиляции при включении в исходный файл более одного заголовочного файла трассировки (например, если исходный файл с трассировкой включал заголовок, содержащий трассировку во встроенных функциях). В последних версиях эта проблема решена. Следует отметить, что это ограничение обусловлено шаблоном, а не самим WPP;
- Так как макросы сообщений трассировки различаются по файлу и номеру строки, в каждой строке исходного кода может содержаться только один трассировочный макрос.
Примечания
- ↑ Кожевников Александр Николаевич. Система анализа длительности ключевых операций на основе трассировки программного обеспечения // Инновации в науке. — 2019. — Вып. 6 (94). — ISSN 2308-6009.
Литература
- WPP Software Tracing Reference (англ.). Microsoft Learn. Microsoft. Дата обращения: 27 июня 2024. Архивировано 1 января 2024 года.