Книга: 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);
}

Оглавление книги


Генерация: 2.387. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз