Книга: Writing Windows WDM Device Drivers
Generating Events
Generating Events
Listing 13.5 shows the routines that provide the event logging, InitializeEventLog, and LogEvent. Later, I shall describe the Wdm3EventMessage function that provides a simpler interface.
InitializeEventLog is simply used to store a pointer to the main DriverObject. It then calls LogEvent to send a WDM3_MSG_LOGGING_STARTED event. If all's well, this should be displayed in the Event Viewer with the corresponding description, "Event logging enabled for Wdm3 Driver".
LogEvent does the bulk of the work in logging an NT event. It may be called at DISPATCH_ LEVEL or lower. Its first task is to decide the size of the error log packet. It then calls IoAllocateErrorLogEntry to obtain a suitably sized packet. It then fills the packet and sends it off using IoWriteErrorLogEntry.
LogEvent has parameters for the message ID (from the list in Wdm3Msg.h) and optionally an IRP pointer. If the IRP pointer is given, various fields in the packet are filled in with details of the IRP. LogEvent can also accept DumpData and Strings as parameters, for insertion into the event packet.
The basic IO_ERR0R_L0G_PACKET structure contains one dump data ULONG, but no insertion strings. It is an extendible structure. Zero or more dump data ULONGs can be provided, followed immediately by any NULL terminated wide strings. This makes calculating and filling the packet size slightly involved. LogEvent saves each string length in a temporary array of integers called StringSizes. Note that the maximum packet size, ERROR_LOG_MAXIMUM_SIZE, is only 0x98 bytes, so do not try to pass large insertion strings.
Listing 13.5 InitializeEventLog and LogEvent routines
void InitializeEventLog(IN PDRIVER_OBJECT DriverObject) {
SavedDriverObject = DriverObject;
// Log a message saying that logging is started.
LogEvent(WDM3_MSG_LOGGING_STARTED, NULL, // IRP
NULL, 0, // dump data
NULL, 0); // strings
}
bool LogEvent(IN NTSTATUS ErrorCode, IN PIRP Irp, IN ULONG DumpData[], IN int DumpDataCount, IN PWSTR Strings[], IN int StringCount) {
if (SavedDriverObject==NULL) return false;
// Start working out size of complete event packet
int size = sizeof(IO_ERROR_LOG_PACKET);
// Add in dump data size.
// Less one as DumpData already has 1 ULONG in IO_ERROR_LOG_PACKET
if (DumpDataCount>0) size += sizeof(ULONG) * (DumpDataCount-1);
// Add in space needed for insertion strings (inc terminating NULLs)
int* StringSizes = NULL;
if (StringCount>0) {
StringSizes = (int*)ExAllocatePool(NonPagedPool, StringCount*sizeof(int));
if (StringSizes==NULL) return false;
// Remember each string size
for (int i=0; i<StringCount; i++) {
StringSizes[i] = (int)GetWideStringSize(Strings[i]);
size += StringSizes[i ];
}
}
if (size>ERROR_LOG_MAXIMUM_SIZE) // 0x98!
{
if (StringSizes!=NULL) ExFreePool(StringSizes);
return false;
}
// Try to allocate the packet
PIO_ERROR_LOG_PACKET Packet = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(SavedDriverObject, size);
if (Packet==NULL) {
if (StringSizes!=NULL) ExFreePool(StringSizes);
return false;
}
// Fill in standard parts of the packet
Packet->ErrorCode = ErrorCode;
Packet->UniqueErrorValue = 0;
// Fill in IRP related fields
Packet->MajorFunctionCode = 0;
Packet->RetryCount = 0;
Packet->FinalStatus = 0;
Packet->SequenceNumber = 0;
Packet->IoControlCode = 0;
if (Irp!=NULL) {
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
Packet->MajorFunctionCode = IrpStack->MajorFunction;
Packet->FinalStatus = Irp->IoStatus.Status;
if (IrpStack->MajorFunction==IRP_MJ_DEVICE_CONTROL || IrpStack->MajorFunction==IRP_MJ_INTERNAL_DEVICE_CONTROL)
Packet->IoControlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
}
// Fill in dump data
if (DumpDataCount>0) {
Packet->DumpDataSize = (USHORT)(sizeof(ULONG)*DumpDataCount);
for (int i=0; i<DumpDataCount; i++) Packet->DumpData[i] = DumpData[i];
} else Packet->DumpDataSize = 0;
// Fill in insertion strings after DumpData
Packet->NumberOfStrings = (USHORT)StringCount;
if (StringCount>0) {
Packet->StringOffset = sizeof(IO_ERROR_L0G_PACKET) + (DumpDataCount-1) * sizeof(ULONG);
PUCHAR pInsertionString = (PUCHAR)Packet + Packet->StringOffset;
// Add each new string to the end
for (int i=0; i<StringCount; i++) {
RtlMoveMemory(pInsertionString, Strings[i], StringSizes[i]);
pInsertionString += StringSizes[i];
}
}
// Log the message
IoWriteErrorLogEntry(Packet);
if (StringSizes!=NULL) ExFreePool(StringSizes);
return true;
}
To make LogEvent easier to use, Wdm3 provides a function called Wdm3EventMessage that simply takes an ANSI string as an argument. This is passed as a wide string to LogEvent to be inserted in the WDM3_MESSAGE message. Wdm3EventMessage is shown in Listing 13.6.
Listing 13.6 Wdm3EventMessage routines
void Wdm3EventMessage(const char* Msg) {
int MsgLen = GetAnsiStringSize(Msg);
int wMsgLen = MsgLen*2;
PWSTR wMsg = (PWSTR)ExAllocatePool(NonPagedPool,wMsgLen);
if (wMsg==NULL) return;
// Brutally make into a wide string
for (int i=0; i<MsgLen; i++) wMsg[i] = (WCHAR)(unsigned char)Msg[i];
PWSTR Strings[1] = { wMsg };
LogEvent(WDM3_MESSAGE, NULL, // IRP
NULL, 0, // dump data
Strings, 1); // strings
ExFreePool(wMsg);
}
- Events
- 15.3.1. Shared Library Events in GDB
- Generating the sendmail.cf File
- Regenerating a striped set with parity
- Chapter 7 Delegates and Events
- Appendix C Generating Documentation for Your C# Applications
- Handling Events
- Implementing Events
- Difference between Events and Delegates
- Generating the Documentation
- Configuring and Generating an SDK
- Testing Wdm3 Events