Препроцессор трассировки программного обеспечения Windows
![]() | В этой статье есть несколько проблем. Пожалуйста, помогите улучшить его или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалять эти шаблонные сообщения )
|
Препроцессор Windows трассировки программного обеспечения ( WPP ; препроцессор и связанные с ним инструменты поддержки известны как WPP Software Tracing ) — это препроцессор , который упрощает использование трассировки событий WMI для реализации эффективной трассировки программного обеспечения в драйверах и приложениях , предназначенных для операционных систем Windows 2000 и более поздних версий. WPP был создан Microsoft и включен в Windows DDK . Хотя WPP имеет широкую область применения, он не включен в Windows SDK и поэтому в основном используется для драйверов и программного обеспечения поддержки драйверов, выпускаемых поставщиками программного обеспечения, приобретающими Windows DDK.
Фон
[ редактировать ]Трассировка программного обеспечения — это специализированное использование журнала для записи информации о выполнении программы. Эта информация обычно используется для отладки . В отличие от регистрации событий , основной целью которой является создание записей о событиях, которые могут быть проверены ( системными администраторами см., например, «Просмотр событий» ) или проанализированы инструментами управления, трассировка программного обеспечения — это, прежде всего, средство отладки для разработчиков программного обеспечения . Таким образом, многие из нефункциональных требований к регистрации событий, такие как локализуемость или стандартный формат вывода, явно не являются целями для большинства приложений трассировки программного обеспечения. С другой стороны, к программной трассировке предъявляются особые требования к производительности , которые обычно не так важны при регистрации событий. Например, одно из распространенных применений трассировки программного обеспечения, трассировка входа/выхода , создает выходные данные в точке входа и возвращает функции или методы, чтобы разработчик мог визуально отслеживать путь выполнения, часто включая параметры и возвращаемые значения , в отладчике или в текстовом виде. -файл журнала (его можно рассматривать как во время выполнения аналог диаграммы последовательности ). Этот тип трассировки, хотя и полезен для разработчиков, может сильно снизить производительность программного продукта, если его нельзя отключить (либо во время компиляции с помощью условной компиляции, либо во время выполнения с помощью флагов ).
Дополнительные соображения, касающиеся отслеживания программного обеспечения, включают следующее:
- В несвободном программном обеспечении продукта данные отслеживания могут включать конфиденциальную информацию об исходном коде .
- Если трассировка включена или отключена во время выполнения, многие методы трассировки требуют включения в двоичный файл значительного объема дополнительных данных, что может косвенно снизить производительность, даже если трассировка отключена.
- Если трассировка включена или отключена во время компиляции, получение данных трассировки для проблемы на компьютере клиента зависит от желания и возможности клиента установить специальную версию вашего программного обеспечения с поддержкой трассировки.
- Некоторые типы программного обеспечения, например драйверы, должны соответствовать строгим требованиям к производительности даже при включенной трассировке.
В связи с первыми двумя соображениями традиционные методы трассировки программного обеспечения используют условную компиляцию для включения или отключения трассировки (и включения данных трассировки) во время компиляции. Например, используя препроцессор C , можно определить макрос DebugOut
следующее:
#ifdef _DEBUG #define DebugOut(msg, ...) \ DebugPrintf(__FUNCTION__ "(" __FILE__ ":" TO_STRING(__LINE__) ")\t" \ msg, __VAR_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 запускается до компиляции (другими словами, даже до препроцессора C) и генерирует заголовок сообщения трассировки для каждого обрабатываемого файла (по умолчанию этот заголовок имеет вид filename.tmh
, где filename
— имя обработанного исходного файла). Затем этот заголовок должен быть явно включен в исходный файл, например:
// File: file.cxx // This file is an example of using WPP #include "file.tmh"
Понимание WPP синтаксиса C / C++ очень ограничено. В частности, он не расширяет макросы (за исключением особых случаев, когда это необходимо), не обрабатывает прагмы и не выполняет какой-либо семантический анализ.
Разработчик указывает один или несколько макросов трассировки, которые WPP должен обрабатывать, с помощью файла конфигурации, специальных аннотаций в комментариях, параметров командной строки или некоторой комбинации этих методов. Каждый раз, когда WPP встречает один из макросов, которые он должен обрабатывать, он генерирует макрос сообщения трассировки. Другими словами, если, например, DoTrace
является макросом трассировки, 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); \ }
тогда WPP не будет генерировать макросы сообщений трассировки для DoTrace
где CheckForErrors
происходит. WPP предоставляет специальное решение этой проблемы, но все еще существует небольшой класс макросов, которые невозможно выразить даже с помощью этого решения.
- Файл шаблона по умолчанию генерирует код, который будет правильно работать только с компилятором Microsoft. Хотя это не является внутренним ограничением препроцессора, тот факт, что файл шаблона (который контролирует, какой код генерируется в заголовке сообщения трассировки) использует недокументированный формат, означает, что на практике WPP будет правильно работать только с компилятором Microsoft.
- Более ранние версии WPP вызывали ошибки компиляции, когда в исходный файл было включено более одного заголовка макроса трассировки (например, если исходный файл с трассировкой включал заголовок, который имел трассировку во встроенных функциях). Это исправлено в самой последней версии. Обратите внимание, что это также ограничение файла шаблона, а не самого инструмента WPP.
- Поскольку макросы сообщений трассировки неоднозначны по номеру файла и строки, в каждой строке исходного кода может быть только один макрос трассировки.