The core of any tracing implementation is the function that generates the trace message itself. You insert a trace message function in the code at appropriate points and then configure the function to place useful information into the message. The generated message can include any information that is useful, typically some literal text to define the message context plus the values of any interesting variables. WPP trace messages can be generated in three primary ways:
By using the default DoTraceMessage macro.
The WPP preprocessor converts DoTraceMessage into the appropriate ETW function call. The ETW function varies depending on the version of Windows for which the driver is compiled and whether the driver runs in user mode or kernel mode.
By converting debug print statements to trace messages.
You can instruct the WPP preprocessor to convert existing debug print statements to equivalent trace message functions.
By using custom trace message functions.
These functions are useful if DoTraceMessage does not support your driver's requirements. Examples of custom trace message functions are given later in this chapter.
Be careful about exposing security or privacy data in trace messages. Any trace consumer that can access your driver's TMH files or PDB file can format and read your driver's trace log.
The DoTraceMessage macro is the default way to generate trace messages. DoTraceMessage has the following format:
DoTraceMessage (Flag, Message, MessageVariables…);
The macro has the following parameters:
Any of a set of user-defined trace flags that trace consumers can use to specify which trace messages should be generated. Examples of how to define and use these flags are given in "How to Support Software Tracing in a Driver" later in this chapter.
A string constant that defines the format of the trace message, similar to the format string that printf uses. The string can include standard printf format specifications such as %d and %s, plus literal text. WPP also supports some special formats, such as %!NTSTATUS! and %!HRESULT!, that display string equivalents of kernel-mode status values and user-mode HRESULT values, respectively.
A comma-delimited list of variables whose values are added to the message string according to the format that the Message argument specifies.
Tip See "DoTraceMessage" in the WDK for a detailed description-online at http://go.microsoft.com/fwlink/?LinkId=80611.
To direct WPP to convert debug print statements, include the following option in the RUN_WPP directive in your project's Sources file:
DebugPrintFunction is the name of your debug print function. This directive instructs the WPP preprocessor to replace all instances of DebugPrintFunction with equivalent WPP macros.
The RUN_WPP directive is discussed in "How to Support Software Tracing in a Driver" later in this chapter.
Most trace message functions allow you to set one or more conditions on the message. For example, you can use a condition to specify whether a trace message is simply informational or is associated with a warning or error condition. DoTraceMessage has a single condition, which takes user-defined message flags. You can also implement a custom trace message function that uses a different condition or multiple conditions.
Conditions are used to categorize messages. A trace consumer can configure a session so that the associated trace providers generate messages only from the selected categories. This feature allows a trace consumer to increase the signal-to-noise ratio of the message log by restricting it to only a selected subset of trace messages.
For example, if a message condition takes the standard trace levels as defined in Eventtrace.h, a trace consumer can configure a session to view only error and warning messages and to omit informational messages. A custom trace message function could have an additional condition that indicates which part of the driver the message is coming from. A trace consumer could then use those conditions to view only those error messages that are associated with IOCTL requests.
If DoTraceMessage does not meet the requirements of your driver, you can define one or more custom trace message functions. The general format that a custom trace message function must follow is similar to that used by DoTraceMessage. The difference is that custom trace message functions can support different conditions, including multiple conditions, as shown in the following example:
FunctionName (Condition1, Condition2,…, "Message", MessageVariables…)
The parameters for custom trace message functions are as follows:
A comma-delimited list of one or more conditions. All parameters that appear before the message are interpreted as conditions. The trace message is generated only if all conditions are true.
A string constant that defines the format of the trace message. The format specifications are the same as those for DoTraceMessage.
A comma-separated list of driver-defined variables whose values are added to the message according to the format specified by the Message argument.
To use a custom trace message function, you must configure your project so that the WPP processor recognizes the custom function and correctly handles the output. See "UMDF Example: RUN_WPP for the Fx2_Driver Sample" later in this chapter for an example of how to implement custom trace message functions.