KdPrintEx sends a string to the kernel debugger if certain conditions are met.
ULONG
KdPrintEx ( (
IN ULONG ComponentId,
IN ULONG Level,
IN PCHAR Format,
. . . . [arguments]
) ) ;
DPFLTR_IHVDRIVER_ID
DPFLTR_IHVVIDEO_ID
DPFLTR_IHVAUDIO_ID
DPFLTR_IHVNETWORK_ID
DPFLTR_IHVSTREAMING_ID
DPFLTR_IHVBUS_ID
If successful, KdPrintEx returns the NTSTATUS code STATUS_SUCCESS; otherwise, it returns the appropriate error code.
This routine is defined in ntddk.h and ndis.h; component filter IDs are defined in ntddk.h. Include ntddk.h.
This routine can only be used in Windows XP and later.
The KdPrintEx routine is identical to DbgPrintEx in code that is compiled in a checked build environment. This routine has no effect if compiled in a free build environment. Only kernel-mode drivers can call the KdPrintEx routine.
A call to this macro requires double parentheses.
Unless it is absolutely necessary, you should not obtain a string from user input or another process and pass it to KdPrintEx. If you do use a string that you did not create, you must verify that this is a valid format string, and that the format codes match the argument list in type and quantity. The best coding practice is for all Format strings to be static and defined at compile time.
KdPrintEx will either pass the specified string to the kernel debugger or do nothing at all, depending on the values of ComponentId, Level, and the corresponding component filter masks.
Each component has a separate filter mask. The components that are of interest to driver writers are IHVDRIVER, IHVVIDEO, IHVAUDIO, IHVNETWORK, IHVSTREAMING, and IHVBUS.
There are two ways to set a component filter mask:
Filter masks stored in the registry take effect during boot. Filter masks created by the debugger take effect immediately, and last until Windows is rebooted. A value set in the registry can be overridden by the debugger, but the component filter mask will return to the value specified in the registry if the system is rebooted.
Here is an example of how component filter masks can be set. Suppose that before the last boot, you created two values in the Debug Print Filter key: IHVVIDEO, with a value equal to DWORD 0x2, and IHVBUS, equal to DWORD 0x7FF. Now you issue the following commands in the kernel debugger:
kd> ed Kd_IHVVIDEO_Mask 0x8 kd> ed Kd_IHVAUDIO_Mask 0x7
At this point, the IHVVIDEO component has a filter mask of 0x8, the IHVAUDIO component has a filter mask of 0x7, and the IHVBUS component has a filter mask of 0x7FF.
There is also a system-wide mask called WIN2000. This is equal to one by default, though it can be changed through the registry or the debugger like all other components. When filtering is performed, each component filter mask is first ORed with the WIN2000 mask. So in this example, the IHVVIDEO mask is effectively equal to 0x9, and components whose filter mask have not been set at all (for instance, IHVSTREAMING) will have a filter mask of one.
When KdPrintEx is called in kernel-mode code, Windows compares the message importance specified by Level with the filter mask of the component specified by ComponentId. This comparison is performed as follows:
The following constants can be useful for setting the value of Level. They are defined in the DDK header ntddk.h and the SDK header ntrtl.h:
#define DPFLTR_ERROR_LEVEL 0 #define DPFLTR_WARNING_LEVEL 1 #define DPFLTR_TRACE_LEVEL 2 #define DPFLTR_INFO_LEVEL 3 #define DPFLTR_MASK 0x8000000
To make your driver compatible with the way Windows uses message levels, you should only set Level equal to DPFLTR_ERROR_LEVEL when a serious error occurs. (Because the WIN2000 system-wide filter is usually equal to one, these messages will be seen by anyone performing kernel debugging.) The warning, trace, and information levels should be used in the appropriate situations. Other bits can be freely used for any purposes that you find useful; this allows you to have a wide variety of message types which can be selectively seen or hidden.
Continuing the example from above, suppose that the following function calls occur in your driver:
KdPrintEx( DPFLTR_IHVVIDEO_ID, DPFLTR_INFO_LEVEL, "First message.\n"); KdPrintEx( DPFLTR_IHVAUDIO_ID, 7, "Second message.\n"); KdPrintEx( DPFLTR_IHVBUS_ID, DPFLTR_MASK & 0x10, "Third message.\n");
The first message will be transmitted, because DPFLTR_INFO_LEVEL is equal to 3. It is therefore treated as a bit shift, resulting in 0x8. This value is then ANDed with the effective IHVVIDEO component filter mask of 0x9, giving a nonzero result.
The second message will not be transmitted, because the Level value of 7 is treated as a bit shift, resulting in 0x80. This is then ANDed with the IHVAUDIO component filter mask of 0x7, giving a result of zero.
The third message will be transmitted, because DPFLTR_MASK & 0x10 is greater than 31, and is therefore treated as the literal DWORD 0x80000010. This is then ANDed with the IHVBUS component filter mask of 0x7FF, giving a nonzero result.
When the filter allows a message to be transmitted, the formatted string is sent to the DbgPrint Buffer. The contents of this buffer are displayed immediately in the Debugger Command window, unless this display has been disabled by using the Global Flags Editor (gflags.exe).
If this display has been disabled, the contents of the DbgPrint Buffer can only be viewed by using the !dbgprint extension command. For information on debugger extensions, see Debugging Tools for NT-Based Operating Systems.
There is no upper limit to the size of the Format string or the number of arguments. However, the DbgPrint buffer can only hold 512 bytes of information. Any output longer than this will be lost.