HyperDbg Debugger
Loading...
Searching...
No Matches
Logging.c File Reference

Message logging and tracing implementation. More...

#include "pch.h"

Functions

BOOLEAN LogCheckVmxOperation ()
 Checks whether the message tracing operates on vmx-root mode or not.
BOOLEAN LogCheckImmediateSend (UINT32 OperationCode)
 Checks whether the immediate sending is needed or not.
BOOLEAN LogSendImmediateMessage (CHAR *OptionalBuffer, UINT32 OptionalBufferLength, UINT32 OperationCode)
 Checks whether the immediate sending is needed or not.
BOOLEAN LogInitialize (MESSAGE_TRACING_CALLBACKS *MsgTracingCallbacks)
 Initialize the buffer relating to log message tracing.
VOID LogUnInitialize ()
 Uninitialize the buffer relating to log message tracing.
BOOLEAN LogCallbackCheckIfBufferIsFull (BOOLEAN Priority)
 Checks whether the priority or regular buffer is full or not.
_Use_decl_annotations_ BOOLEAN LogCallbackSendBuffer (UINT32 OperationCode, PVOID Buffer, UINT32 BufferLength, BOOLEAN Priority)
 Save buffer to the pool.
UINT32 LogMarkAllAsRead (BOOLEAN IsVmxRoot)
 Mark all buffers as read.
BOOLEAN LogReadBuffer (BOOLEAN IsVmxRoot, PVOID BufferToSaveMessage, UINT32 *ReturnedLength)
 Attempt to read the buffer.
BOOLEAN LogCheckForNewMessage (BOOLEAN IsVmxRoot, BOOLEAN Priority)
 Check if new message is available or not.
BOOLEAN LogCallbackPrepareAndSendMessageToQueueWrapper (UINT32 OperationCode, BOOLEAN IsImmediateMessage, BOOLEAN ShowCurrentSystemTime, BOOLEAN Priority, const CHAR *Fmt, va_list ArgList)
 Prepare a printf-style message mapping and send string messages and tracing for logging and monitoring.
BOOLEAN LogCallbackPrepareAndSendMessageToQueue (UINT32 OperationCode, BOOLEAN IsImmediateMessage, BOOLEAN ShowCurrentSystemTime, BOOLEAN Priority, const CHAR *Fmt,...)
 Prepare a printf-style message mapping and send string messages and tracing for logging and monitoring.
BOOLEAN LogCallbackSendMessageToQueue (UINT32 OperationCode, BOOLEAN IsImmediateMessage, CHAR *LogMessage, UINT32 BufferLen, BOOLEAN Priority)
 Send string messages and tracing for logging and monitoring.
VOID LogNotifyUsermodeCallback (PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
 Complete the IRP in IRP Pending state and fill the usermode buffers with pool data.
BOOLEAN LogRegisterIrpBasedNotification (PVOID TargetIrp, LONG *Status)
 Register a new IRP Pending thread which listens for new buffers.
BOOLEAN LogRegisterEventBasedNotification (PVOID TargetIrp)
 Create an event-based usermode notifying mechanism.

Detailed Description

Message logging and tracing implementation.

Author
Sina Karvandi (sina@.nosp@m.hype.nosp@m.rdbg..nosp@m.org)
Version
0.1
Date
2020-04-11

Function Documentation

◆ LogCallbackCheckIfBufferIsFull()

BOOLEAN LogCallbackCheckIfBufferIsFull ( BOOLEAN Priority)

Checks whether the priority or regular buffer is full or not.

Parameters
PriorityWhether the buffer has priority
Returns
BOOLEAN Returns true if the buffer is full, otherwise, return false
263{
264 UINT32 Index;
265 BOOLEAN IsVmxRoot;
266 UINT32 CurrentIndexToWrite = NULL_ZERO;
267 UINT32 CurrentIndexToWritePriority = NULL_ZERO;
268
269 //
270 // Check that if we're in vmx root-mode
271 //
272 IsVmxRoot = LogCheckVmxOperation();
273
274 if (IsVmxRoot)
275 {
276 //
277 // Set the index
278 //
279 Index = 1;
280 }
281 else
282 {
283 //
284 // Set the index
285 //
286 Index = 0;
287 }
288
289 //
290 // check if the buffer is filled to it's maximum index or not
291 //
292 if (Priority)
293 {
294 CurrentIndexToWritePriority = g_MessageBufferInformation[Index].CurrentIndexToWritePriority;
295
296 if (g_MessageBufferInformation[Index].CurrentIndexToWritePriority > MaximumPacketsCapacityPriority - 1)
297 {
298 //
299 // start from the beginning
300 //
301 CurrentIndexToWritePriority = 0;
302 }
303 }
304 else
305 {
306 CurrentIndexToWrite = g_MessageBufferInformation[Index].CurrentIndexToWrite;
307
308 if (g_MessageBufferInformation[Index].CurrentIndexToWrite > MaximumPacketsCapacity - 1)
309 {
310 //
311 // start from the beginning
312 //
313 CurrentIndexToWrite = 0;
314 }
315 }
316
317 //
318 // Compute the start of the buffer header
319 //
320 BUFFER_HEADER * Header;
321
322 if (Priority)
323 {
324 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (CurrentIndexToWritePriority * (PacketChunkSize + sizeof(BUFFER_HEADER))));
325 }
326 else
327 {
328 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (CurrentIndexToWrite * (PacketChunkSize + sizeof(BUFFER_HEADER))));
329 }
330
331 //
332 // If the next item is valid, then it means the buffer is full and the next
333 // item will replace the previous (not served items)
334 //
335 return Header->Valid;
336}
BOOLEAN LogCheckVmxOperation()
Checks whether the message tracing operates on vmx-root mode or not.
Definition Logging.c:19
LOG_BUFFER_INFORMATION * g_MessageBufferInformation
Global Variable for buffer on all cores.
Definition Logging.h:104
struct _BUFFER_HEADER BUFFER_HEADER
Message buffer structure.
UCHAR BOOLEAN
Definition BasicTypes.h:35
#define NULL_ZERO
Definition BasicTypes.h:110
unsigned int UINT32
Definition BasicTypes.h:54
#define MaximumPacketsCapacity
Default buffer count of packets for message tracing.
Definition Constants.h:171
#define PacketChunkSize
Size of each packet.
Definition Constants.h:187
#define MaximumPacketsCapacityPriority
Default buffer count of packets for message tracing.
Definition Constants.h:177
BOOLEAN Valid
Definition Logging.h:61

◆ LogCallbackPrepareAndSendMessageToQueue()

BOOLEAN LogCallbackPrepareAndSendMessageToQueue ( UINT32 OperationCode,
BOOLEAN IsImmediateMessage,
BOOLEAN ShowCurrentSystemTime,
BOOLEAN Priority,
const CHAR * Fmt,
... )

Prepare a printf-style message mapping and send string messages and tracing for logging and monitoring.

Parameters
OperationCodeOptional operation code
IsImmediateMessageShould be sent immediately
ShowCurrentSystemTimeShow system-time
PriorityWhether the message has priority
FmtMessage format-string
...
Returns
BOOLEAN if it was successful then return TRUE, otherwise returns FALSE
1184{
1185 va_list ArgList;
1186 BOOLEAN Result;
1187
1188 va_start(ArgList, Fmt);
1189
1191 IsImmediateMessage,
1192 ShowCurrentSystemTime,
1193 Priority,
1194 Fmt,
1195 ArgList);
1196
1197 va_end(ArgList);
1198
1199 return Result;
1200}
BOOLEAN LogCallbackPrepareAndSendMessageToQueueWrapper(UINT32 OperationCode, BOOLEAN IsImmediateMessage, BOOLEAN ShowCurrentSystemTime, BOOLEAN Priority, const CHAR *Fmt, va_list ArgList)
Prepare a printf-style message mapping and send string messages and tracing for logging and monitorin...
Definition Logging.c:987

◆ LogCallbackPrepareAndSendMessageToQueueWrapper()

BOOLEAN LogCallbackPrepareAndSendMessageToQueueWrapper ( UINT32 OperationCode,
BOOLEAN IsImmediateMessage,
BOOLEAN ShowCurrentSystemTime,
BOOLEAN Priority,
const CHAR * Fmt,
va_list ArgList )

Prepare a printf-style message mapping and send string messages and tracing for logging and monitoring.

Parameters
OperationCodeOptional operation code
IsImmediateMessageShould be sent immediately
ShowCurrentSystemTimeShow system-time
PriorityWhether the message has priority
FmtMessage format-string
...
Returns
BOOLEAN if it was successful then return TRUE, otherwise returns FALSE
993{
994 INT32 SprintfResult;
995 SIZE_T WrittenSize;
996 BOOLEAN IsVmxRootMode;
997 BOOLEAN Result = FALSE; // by default, we assume error happens
998 CHAR * LogMessage = NULL;
999 CHAR * TempMessage = NULL;
1000 CHAR TimeBuffer[20] = {0};
1002
1003 //
1004 // Set Vmx State
1005 //
1006 IsVmxRootMode = LogCheckVmxOperation();
1007
1008 //
1009 // Set the buffer here, we avoid use stack (local variables) because stack might growth
1010 // and be problematic
1011 //
1012 if (IsVmxRootMode)
1013 {
1014 LogMessage = &g_VmxLogMessage[CurrentCore * PacketChunkSize];
1015 TempMessage = &g_VmxTempMessage[CurrentCore * PacketChunkSize];
1016 }
1017 else
1018 {
1019 //
1020 // To avoid buffer collision and buffer re-writing in VMX non-root, allocate pool
1021 //
1023
1024 if (LogMessage == NULL)
1025 {
1026 //
1027 // Insufficient space
1028 //
1029 return FALSE;
1030 }
1032
1033 if (TempMessage == NULL)
1034 {
1035 //
1036 // Insufficient space
1037 //
1038 PlatformMemFreePool(LogMessage);
1039 return FALSE;
1040 }
1041 }
1042
1043 if (ShowCurrentSystemTime)
1044 {
1045 //
1046 // It's actually not necessary to use -1 but because user-mode code might assume a null-terminated buffer so
1047 // it's better to use - 1
1048 //
1049
1050 //
1051 // We won't use this because we can't use in any IRQL
1052 // Status = RtlStringCchVPrintfA(TempMessage, PacketChunkSize - 1, Fmt, ArgList);
1053 //
1054 SprintfResult = vsprintf_s(TempMessage, PacketChunkSize - 1, Fmt, ArgList);
1055
1056 //
1057 // Check if the buffer passed the limit
1058 //
1059 if (SprintfResult == -1)
1060 {
1061 //
1062 // Probably the buffer is large that we can't store it
1063 //
1064 goto FreeBufferAndReturn;
1065 }
1066
1067 //
1068 // Fill the above with timer
1069 //
1070 TIME_FIELDS TimeFields;
1071 LARGE_INTEGER SystemTime, LocalTime;
1072 PlatformTimeQuerySystemTime(&SystemTime);
1073 PlatformTimeConvertToLocalTime(&SystemTime, &LocalTime);
1074 PlatformTimeConvertToTimeFields(&LocalTime, &TimeFields);
1075
1076 //
1077 // We won't use this because we can't use in any IRQL
1078 // Status = RtlStringCchPrintfA(TimeBuffer, RTL_NUMBER_OF(TimeBuffer),
1079 // "%02hd:%02hd:%02hd.%03hd", TimeFields.Hour,
1080 // TimeFields.Minute, TimeFields.Second,
1081 // TimeFields.Milliseconds);
1082 //
1083 //
1084 // Append time with previous message
1085 //
1086 // Status = RtlStringCchPrintfA(LogMessage, PacketChunkSize - 1, "(%s)\t %s", TimeBuffer, TempMessage);
1087 //
1088
1089 //
1090 // this function probably run without error, so there is no need to check the return value
1091 //
1092 sprintf_s(TimeBuffer, RTL_NUMBER_OF(TimeBuffer), "%02hd:%02hd:%02hd.%03hd", TimeFields.Hour, TimeFields.Minute, TimeFields.Second, TimeFields.Milliseconds);
1093
1094 //
1095 // Append time with previous message
1096 //
1097 SprintfResult = sprintf_s(LogMessage, PacketChunkSize - 1, "(%s - core : %d - vmx-root? %s)\t %s", TimeBuffer, CurrentCore, IsVmxRootMode ? "yes" : "no", TempMessage);
1098
1099 //
1100 // Check if the buffer passed the limit
1101 //
1102 if (SprintfResult == -1)
1103 {
1104 //
1105 // Probably the buffer is large that we can't store it
1106 //
1107 goto FreeBufferAndReturn;
1108 }
1109 }
1110 else
1111 {
1112 //
1113 // It's actually not necessary to use -1 but because user-mode code might assume a null-terminated buffer so
1114 // it's better to use - 1
1115 //
1116
1117 //
1118 // We won't use this because we can't use in any IRQL
1119 // Status = RtlStringCchVPrintfA(LogMessage, PacketChunkSize - 1, Fmt, ArgList);
1120 //
1121 SprintfResult = vsprintf_s(LogMessage, PacketChunkSize - 1, Fmt, ArgList);
1122
1123 //
1124 // Check if the buffer passed the limit
1125 //
1126 if (SprintfResult == -1)
1127 {
1128 //
1129 // Probably the buffer is large that we can't store it
1130 //
1131 goto FreeBufferAndReturn;
1132 }
1133 }
1134
1135 //
1136 // Use std function because they can be run in any IRQL
1137 // RtlStringCchLengthA(LogMessage, PacketChunkSize - 1, &WrittenSize);
1138 //
1139 WrittenSize = strnlen_s(LogMessage, PacketChunkSize - 1);
1140
1141 if (LogMessage[0] == '\0')
1142 {
1143 //
1144 // nothing to write
1145 //
1146 goto FreeBufferAndReturn;
1147 }
1148
1149 //
1150 // Send the prepared buffer (with no priority)
1151 //
1152 Result = LogCallbackSendMessageToQueue(OperationCode, IsImmediateMessage, LogMessage, (UINT32)WrittenSize, Priority);
1153
1154FreeBufferAndReturn:
1155
1156 if (!IsVmxRootMode)
1157 {
1158 PlatformMemFreePool(LogMessage);
1159 PlatformMemFreePool(TempMessage);
1160 }
1161
1162 return Result;
1163}
BOOLEAN LogCallbackSendMessageToQueue(UINT32 OperationCode, BOOLEAN IsImmediateMessage, CHAR *LogMessage, UINT32 BufferLen, BOOLEAN Priority)
Send string messages and tracing for logging and monitoring.
Definition Logging.c:1214
CHAR * g_VmxTempMessage
VMX temporary buffer for logging messages.
Definition Logging.h:29
CHAR * g_VmxLogMessage
VMX buffer for logging messages.
Definition Logging.h:23
ULONG PlatformCpuGetCurrentProcessorNumber(VOID)
Get the current logical processor number.
Definition PlatformCpu.c:47
PVOID PlatformMemAllocateNonPagedPool(SIZE_T NumberOfBytes)
Allocates non-paged pool memory.
Definition PlatformMem.c:208
PVOID PlatformMemFreePool(PVOID BufferAddress)
Frees a memory pool.
Definition PlatformMem.c:269
VOID PlatformTimeConvertToLocalTime(PLARGE_INTEGER SystemTime, PLARGE_INTEGER LocalTime)
Convert system time (UTC) to local time.
Definition PlatformTime.c:50
VOID PlatformTimeQuerySystemTime(PLARGE_INTEGER SystemTime)
Query the current system time.
Definition PlatformTime.c:25
VOID PlatformTimeConvertToTimeFields(PLARGE_INTEGER Time, PTIME_FIELDS TimeFields)
Convert a LARGE_INTEGER time value to a TIME_FIELDS structure.
Definition PlatformTime.c:75
signed int INT32
Definition BasicTypes.h:50
#define FALSE
Definition BasicTypes.h:113
char CHAR
Definition BasicTypes.h:33
unsigned long ULONG
Definition BasicTypes.h:31
NULL()
Definition test-case-generator.py:530

◆ LogCallbackSendBuffer()

_Use_decl_annotations_ BOOLEAN LogCallbackSendBuffer ( UINT32 OperationCode,
PVOID Buffer,
UINT32 BufferLength,
BOOLEAN Priority )

Save buffer to the pool.

Parameters
OperationCodeThe operation code that will be send to user mode
BufferBuffer to be send to user mode
BufferLengthLength of the buffer
PriorityWhether the buffer has priority
Returns
BOOLEAN Returns true if the buffer successfully set to be send to user mode and false if there was an error
351{
352 UINT32 Index;
353 BOOLEAN IsVmxRoot;
354 KIRQL OldIRQL = NULL_ZERO;
355
356 if (BufferLength > PacketChunkSize - 1 || BufferLength == 0)
357 {
358 //
359 // We can't save this huge buffer
360 //
361 return FALSE;
362 }
363
364 //
365 // Check that if we're in vmx root-mode
366 //
367 IsVmxRoot = LogCheckVmxOperation();
368
369 //
370 // Check if we're connected to remote debugger, send it directly to the debugger
371 // and the OPERATION_MANDATORY_DEBUGGEE_BIT should not be set because those operation
372 // codes that their MSB are set should be handled locally
373 //
374 if (LogCheckImmediateSend(OperationCode))
375 {
376 //
377 // if we're in vmx non-root then in order to avoid scheduling we raise the IRQL
378 // to DISPATCH_LEVEL because we will get the lock of sending over serial in the
379 // next function. In vmx-root RFLAGS.IF is cleared so no interrupt happens and
380 // we're safe to get the lock, the same approach is for KeAcquireSpinLock
381 //
382 if (!IsVmxRoot)
383 {
384 //
385 // vmx non-root
386 //
387 OldIRQL = PlatformIrqlRaiseToDpcLevel();
388 }
389
390 //
391 // Kernel debugger is active, we should send the bytes over serial
392 //
394 Buffer,
395 BufferLength,
396 OperationCode);
397
398 //
399 // Release the vmx non-root lock
400 //
401 if (!IsVmxRoot)
402 {
403 //
404 // vmx non-root
405 //
406 PlatformIrqlLower(OldIRQL);
407 }
408
409 return TRUE;
410 }
411
412 //
413 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
414 // if not we use the windows spinlock
415 //
416 if (IsVmxRoot)
417 {
418 //
419 // Set the index
420 //
421 Index = 1;
423 }
424 else
425 {
426 //
427 // Set the index
428 //
429 Index = 0;
430
431 //
432 // Acquire the lock
433 //
434 PlatformSpinlockAcquire(&g_MessageBufferInformation[Index].BufferLock, &OldIRQL);
435 }
436
437 //
438 // check if the buffer is filled to it's maximum index or not
439 //
440 if (Priority)
441 {
442 if (g_MessageBufferInformation[Index].CurrentIndexToWritePriority > MaximumPacketsCapacityPriority - 1)
443 {
444 //
445 // start from the beginning
446 //
447 g_MessageBufferInformation[Index].CurrentIndexToWritePriority = 0;
448 }
449 }
450 else
451 {
452 if (g_MessageBufferInformation[Index].CurrentIndexToWrite > MaximumPacketsCapacity - 1)
453 {
454 //
455 // start from the beginning
456 //
457 g_MessageBufferInformation[Index].CurrentIndexToWrite = 0;
458 }
459 }
460
461 //
462 // Compute the start of the buffer header
463 //
464 BUFFER_HEADER * Header;
465
466 if (Priority)
467 {
468 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (g_MessageBufferInformation[Index].CurrentIndexToWritePriority * (PacketChunkSize + sizeof(BUFFER_HEADER))));
469 }
470 else
471 {
472 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToWrite * (PacketChunkSize + sizeof(BUFFER_HEADER))));
473 }
474
475 //
476 // Set the header
477 //
478 Header->OperationNumber = OperationCode;
479 Header->BufferLength = BufferLength;
480 Header->Valid = TRUE;
481
482 //
483 // ******** Now it's time to fill the buffer ********
484 //
485
486 //
487 // compute the saving index
488 //
489 PVOID SavingBuffer;
490
491 if (Priority)
492 {
493 SavingBuffer = (PVOID)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (g_MessageBufferInformation[Index].CurrentIndexToWritePriority * (PacketChunkSize + sizeof(BUFFER_HEADER))) + sizeof(BUFFER_HEADER));
494 }
495 else
496 {
497 SavingBuffer = (PVOID)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToWrite * (PacketChunkSize + sizeof(BUFFER_HEADER))) + sizeof(BUFFER_HEADER));
498 }
499
500 //
501 // Copy the buffer
502 //
503 PlatformWriteMemory(SavingBuffer, Buffer, BufferLength);
504
505 //
506 // Increment the next index to write
507 //
508 if (Priority)
509 {
510 g_MessageBufferInformation[Index].CurrentIndexToWritePriority = g_MessageBufferInformation[Index].CurrentIndexToWritePriority + 1;
511 }
512 else
513 {
514 g_MessageBufferInformation[Index].CurrentIndexToWrite = g_MessageBufferInformation[Index].CurrentIndexToWrite + 1;
515 }
516
517 //
518 // check if there is any thread in IRP Pending state, so we can complete their request
519 //
520 if (g_GlobalNotifyRecord != NULL)
521 {
522 //
523 // there is some threads that needs to be completed
524 //
525
526 //
527 // set the target pool
528 //
529 g_GlobalNotifyRecord->CheckVmxRootMessagePool = IsVmxRoot;
530
531 //
532 // Insert dpc to queue
533 //
535
536 //
537 // set notify routine to null
538 //
540 }
541
542 //
543 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
544 // if not we use the windows spinlock
545 //
546 if (IsVmxRoot)
547 {
549 }
550 else
551 {
552 //
553 // Release the lock
554 //
555 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLock, OldIRQL);
556 }
557
558 return TRUE;
559}
BOOLEAN LogSendImmediateMessage(CHAR *OptionalBuffer, UINT32 OptionalBufferLength, UINT32 OperationCode)
Checks whether the immediate sending is needed or not.
Definition Logging.c:70
BOOLEAN LogCheckImmediateSend(UINT32 OperationCode)
Checks whether the immediate sending is needed or not.
Definition Logging.c:43
NOTIFY_RECORD * g_GlobalNotifyRecord
Save the state of the thread that waits for messages to deliver to user-mode.
Definition Logging.h:175
volatile LONG g_VmxRootLoggingLock
Vmx-root lock for logging.
Definition Logging.h:110
BOOLEAN PlatformDpcInsertQueueDpc(PRKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2)
Insert a DPC into the system DPC queue for execution.
Definition PlatformDpc.c:53
KIRQL PlatformIrqlRaiseToDpcLevel(VOID)
Raise the current IRQL to DISPATCH_LEVEL.
Definition PlatformIrql.c:24
VOID PlatformIrqlLower(KIRQL OldIrql)
Lower the current IRQL to the previously saved value.
Definition PlatformIrql.c:48
VOID PlatformWriteMemory(PVOID Address, PVOID Buffer, SIZE_T Size)
Writes data from a buffer to a memory address.
Definition PlatformMem.c:115
VOID PlatformSpinlockRelease(PKSPIN_LOCK SpinLock, KIRQL OldIrql)
Release a previously acquired kernel spinlock and restore IRQL.
Definition PlatformSpinlock.c:75
VOID PlatformSpinlockAcquire(PKSPIN_LOCK SpinLock, PKIRQL OldIrql)
Acquire a kernel spinlock, raising IRQL to DISPATCH_LEVEL.
Definition PlatformSpinlock.c:50
VOID SpinlockLock(volatile LONG *Lock)
Tries to get the lock and won't return until successfully get the lock.
Definition Spinlock.c:53
VOID SpinlockUnlock(volatile LONG *Lock)
Release the lock.
Definition Spinlock.c:162
void * PVOID
Definition BasicTypes.h:56
#define TRUE
Definition BasicTypes.h:114
UINT32 BufferLength
Definition Logging.h:60
UINT32 OperationNumber
Definition Logging.h:59

◆ LogCallbackSendMessageToQueue()

BOOLEAN LogCallbackSendMessageToQueue ( UINT32 OperationCode,
BOOLEAN IsImmediateMessage,
CHAR * LogMessage,
UINT32 BufferLen,
BOOLEAN Priority )

Send string messages and tracing for logging and monitoring.

Parameters
OperationCodeOptional operation code
IsImmediateMessageShould be sent immediately
LogMessageLink of message buffer
BufferLenLength of buffer
PriorityWhether the buffer has priority
Returns
BOOLEAN if it was successful then return TRUE, otherwise returns FALSE
1215{
1216 BOOLEAN Result;
1217 UINT32 Index;
1218 BOOLEAN IsVmxRootMode;
1219 KIRQL OldIRQL = NULL_ZERO;
1220
1221 //
1222 // Set Vmx State
1223 //
1224 IsVmxRootMode = LogCheckVmxOperation();
1225
1226#if UseWPPTracing
1227
1228 if (OperationCode == OPERATION_LOG_INFO_MESSAGE)
1229 {
1230 HypervisorTraceLevelMessage(
1231 TRACE_LEVEL_INFORMATION, // ETW Level defined in evntrace.h
1232 HVFS_LOG_INFO,
1233 "%s", // Flag defined in WPP_CONTROL_GUIDS
1234 LogMessage);
1235 }
1236 else if (OperationCode == OPERATION_LOG_WARNING_MESSAGE)
1237 {
1238 HypervisorTraceLevelMessage(
1239 TRACE_LEVEL_WARNING, // ETW Level defined in evntrace.h
1240 HVFS_LOG_WARNING,
1241 "%s", // Flag defined in WPP_CONTROL_GUIDS
1242 LogMessage);
1243 }
1244 else if (OperationCode == OPERATION_LOG_ERROR_MESSAGE)
1245 {
1246 HypervisorTraceLevelMessage(
1247 TRACE_LEVEL_ERROR, // ETW Level defined in evntrace.h
1248 HVFS_LOG_ERROR,
1249 "%s", // Flag defined in WPP_CONTROL_GUIDS
1250 LogMessage);
1251 }
1252 else
1253 {
1254 HypervisorTraceLevelMessage(
1255 TRACE_LEVEL_NONE, // ETW Level defined in evntrace.h
1256 HVFS_LOG,
1257 "%s", // Flag defined in WPP_CONTROL_GUIDS
1258 LogMessage);
1259 }
1260
1261#else
1262 if (IsImmediateMessage)
1263 {
1264 return LogCallbackSendBuffer(OperationCode, LogMessage, BufferLen, Priority);
1265 }
1266 else
1267 {
1268 //
1269 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
1270 // if not we use the windows spinlock
1271 //
1272 if (IsVmxRootMode)
1273 {
1274 //
1275 // Set the index
1276 //
1277 Index = 1;
1279 }
1280 else
1281 {
1282 //
1283 // Set the index
1284 //
1285 Index = 0;
1286
1287 //
1288 // Acquire the lock
1289 //
1290 PlatformSpinlockAcquire(&g_MessageBufferInformation[Index].BufferLockForNonImmMessage, &OldIRQL);
1291 }
1292 //
1293 // Set the result to True
1294 //
1295 Result = TRUE;
1296
1297 //
1298 // If log message WrittenSize is above the buffer then we have to send the previous buffer
1299 //
1300 if ((g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer + BufferLen) > PacketChunkSize - 1 && g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer != 0)
1301 {
1302 //
1303 // Send the previous buffer (non-immediate message),
1304 // accumulated messages don't have priority
1305 //
1307 (PVOID)g_MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage,
1308 g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer,
1309 FALSE);
1310
1311 //
1312 // Free the immediate buffer
1313 //
1314 g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer = 0;
1315 PlatformZeroMemory((PVOID)g_MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage, PacketChunkSize);
1316 }
1317
1318 //
1319 // We have to save the message
1320 //
1321 PlatformWriteMemory((PVOID)(g_MessageBufferInformation[Index].BufferForMultipleNonImmediateMessage +
1322 g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer),
1323 LogMessage,
1324 BufferLen);
1325
1326 //
1327 // add the length
1328 //
1329 g_MessageBufferInformation[Index].CurrentLengthOfNonImmBuffer += BufferLen;
1330
1331 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
1332 // if not we use the windows spinlock
1333 //
1334 if (IsVmxRootMode)
1335 {
1337 }
1338 else
1339 {
1340 //
1341 // Release the lock
1342 //
1343 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLockForNonImmMessage, OldIRQL);
1344 }
1345
1346 return Result;
1347 }
1348#endif
1349}
_Use_decl_annotations_ BOOLEAN LogCallbackSendBuffer(UINT32 OperationCode, PVOID Buffer, UINT32 BufferLength, BOOLEAN Priority)
Save buffer to the pool.
Definition Logging.c:350
volatile LONG g_VmxRootLoggingLockForNonImmBuffers
Vmx-root lock for logging.
Definition Logging.h:116
VOID PlatformZeroMemory(PVOID Destination, SIZE_T Size)
Zeros a memory block.
Definition PlatformMem.c:155
#define TRACE_LEVEL_WARNING
Definition Trace.h:32
#define TRACE_LEVEL_NONE
Definition Trace.h:29
#define TRACE_LEVEL_ERROR
Definition Trace.h:31
#define TRACE_LEVEL_INFORMATION
Definition Trace.h:33
#define OPERATION_LOG_ERROR_MESSAGE
Definition Constants.h:376
#define OPERATION_LOG_WARNING_MESSAGE
Definition Constants.h:375
#define OPERATION_LOG_INFO_MESSAGE
Message logs id that comes from kernel-mode to user-mode.
Definition Constants.h:374
#define OPERATION_LOG_NON_IMMEDIATE_MESSAGE
Definition Constants.h:377

◆ LogCheckForNewMessage()

BOOLEAN LogCheckForNewMessage ( BOOLEAN IsVmxRoot,
BOOLEAN Priority )

Check if new message is available or not.

Parameters
IsVmxRootCheck vmx root pool for message or check vmx non root pool
PriorityWhether the buffer has priority
Returns
BOOLEAN return of this function shows whether the read was successful or not (e.g FALSE shows there's no new buffer available.)
934{
935 UINT32 Index;
936
937 if (IsVmxRoot)
938 {
939 Index = 1;
940 }
941 else
942 {
943 Index = 0;
944 }
945
946 //
947 // Compute the current buffer to read
948 //
949 BUFFER_HEADER * Header;
950
951 if (Priority)
952 {
953 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (g_MessageBufferInformation[Index].CurrentIndexToSendPriority * (PacketChunkSize + sizeof(BUFFER_HEADER))));
954 }
955 else
956 {
957 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToSend * (PacketChunkSize + sizeof(BUFFER_HEADER))));
958 }
959
960 if (!Header->Valid)
961 {
962 //
963 // there is nothing to send
964 //
965 return FALSE;
966 }
967
968 //
969 // If we reached here, means that there is sth to send
970 //
971 return TRUE;
972}

◆ LogCheckImmediateSend()

BOOLEAN LogCheckImmediateSend ( UINT32 OperationCode)
inline

Checks whether the immediate sending is needed or not.

Returns
BOOLEAN
44{
45 CHECK_IMMEDIATE_MESSAGE_SENDING ImmediateMessageCheck = g_MsgTracingCallbacks.CheckImmediateMessageSending;
46
47 if (ImmediateMessageCheck == NULL)
48 {
49 //
50 // As the caller didn't defined a checker we assume there is no
51 // need to send messages immediately
52 //
53 return FALSE;
54 }
55
56 //
57 // The user specified a vmx checker
58 //
59 return ImmediateMessageCheck(OperationCode);
60}
MESSAGE_TRACING_CALLBACKS g_MsgTracingCallbacks
Global variable that holds callbacks.
Definition Logging.h:181
BOOLEAN(* CHECK_IMMEDIATE_MESSAGE_SENDING)(UINT32 OperationCode)
A function that checks whether the immediate message sending is needed or not.
Definition HyperLog.h:30

◆ LogCheckVmxOperation()

BOOLEAN LogCheckVmxOperation ( )
inline

Checks whether the message tracing operates on vmx-root mode or not.

Returns
BOOLEAN
20{
21 CHECK_VMX_OPERATION VmxOperationCheck = g_MsgTracingCallbacks.VmxOperationCheck;
22
23 if (VmxOperationCheck == NULL)
24 {
25 //
26 // As the caller didn't defined a checker for vmx operation, we assume
27 // that it's not operating on vmx-root
28 //
29 return FALSE;
30 }
31
32 //
33 // The user specified a vmx checker
34 //
35 return VmxOperationCheck();
36}
BOOLEAN(* CHECK_VMX_OPERATION)()
A function that checks whether the current operation is on vmx-root mode or not.
Definition HyperLog.h:23

◆ LogInitialize()

BOOLEAN LogInitialize ( MESSAGE_TRACING_CALLBACKS * MsgTracingCallbacks)

Initialize the buffer relating to log message tracing.

Parameters
MsgTracingCallbacksspecify the callbacks
Returns
BOOLEAN
99{
100 ULONG ProcessorsCount;
101
102 ProcessorsCount = PlatformCpuGetActiveProcessorCount();
103
104 //
105 // Initialize buffers for trace message and data messages
106 //(we have two buffers one for vmx root and one for vmx non-root)
107 //
109
111 {
112 return FALSE; // STATUS_INSUFFICIENT_RESOURCES
113 }
114
115 //
116 // Allocate g_VmxTempMessage and g_VmxLogMessage
117 //
120
121 if (!g_VmxTempMessage)
122 {
125 return FALSE; // STATUS_INSUFFICIENT_RESOURCES
126 }
127
130
131 if (!g_VmxLogMessage)
132 {
135
138
139 return FALSE; // STATUS_INSUFFICIENT_RESOURCES
140 }
141
142 //
143 // Initialize the lock for Vmx-root mode (HIGH_IRQL Spinlock)
144 //
146
147 //
148 // Allocate buffer for messages and initialize the core buffer information
149 //
150 for (UINT32 i = 0; i < 2; i++)
151 {
152 //
153 // initialize the lock
154 // Actually, only the 0th buffer use this spinlock but let initialize it
155 // for both but the second buffer spinlock is useless
156 // as we use our custom spinlock
157 //
159 PlatformSpinlockInitialize(&g_MessageBufferInformation[i].BufferLockForNonImmMessage);
160
161 //
162 // allocate the buffer for regular buffers
163 //
165 g_MessageBufferInformation[i].BufferForMultipleNonImmediateMessage = (UINT64)PlatformMemAllocateNonPagedPool(PacketChunkSize);
166
167 if (!g_MessageBufferInformation[i].BufferStartAddress ||
168 !g_MessageBufferInformation[i].BufferForMultipleNonImmediateMessage)
169 {
170 return FALSE; // STATUS_INSUFFICIENT_RESOURCES
171 }
172
173 //
174 // allocate the buffer for priority buffers
175 //
177
178 if (!g_MessageBufferInformation[i].BufferStartAddressPriority)
179 {
180 return FALSE; // STATUS_INSUFFICIENT_RESOURCES
181 }
182
183 //
184 // Zeroing the buffer
185 //
187 PlatformZeroMemory((PVOID)g_MessageBufferInformation[i].BufferForMultipleNonImmediateMessage, PacketChunkSize);
189
190 //
191 // Set the end address
192 //
193 g_MessageBufferInformation[i].BufferEndAddress = (UINT64)g_MessageBufferInformation[i].BufferStartAddress + LogBufferSize;
194 g_MessageBufferInformation[i].BufferEndAddressPriority = (UINT64)g_MessageBufferInformation[i].BufferStartAddressPriority + LogBufferSizePriority;
195 }
196
197 //
198 // Copy the callbacks into the global callback holder
199 //
201
202 return TRUE;
203}
struct _LOG_BUFFER_INFORMATION LOG_BUFFER_INFORMATION
Core-specific buffers.
ULONG PlatformCpuGetActiveProcessorCount(VOID)
Get the count of active logical processors.
Definition PlatformCpu.c:24
PVOID PlatformMemAllocateZeroedNonPagedPool(SIZE_T NumberOfBytes)
Allocates zeroed non-paged pool memory.
Definition PlatformMem.c:248
VOID PlatformSpinlockInitialize(PKSPIN_LOCK SpinLock)
Initialize a kernel spinlock.
Definition PlatformSpinlock.c:25
#define LogBufferSize
Final storage size of message tracing.
Definition Constants.h:208
#define LogBufferSizePriority
Final storage size of message tracing.
Definition Constants.h:215
struct _MESSAGE_TRACING_CALLBACKS MESSAGE_TRACING_CALLBACKS
Prototype of each function needed by message tracer.

◆ LogMarkAllAsRead()

UINT32 LogMarkAllAsRead ( BOOLEAN IsVmxRoot)

Mark all buffers as read.

Priority buffers won't be set as read

Parameters
IsVmxRootDetermine whether you want to read vmx root buffer or vmx non root buffer
Returns
UINT32 return count of messages that set to invalid
570{
571 UINT32 Index;
572 UINT32 ResultsOfBuffersSetToRead = 0;
573 KIRQL OldIRQL = NULL_ZERO;
574
575 //
576 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
577 // if not we use the windows spinlock
578 //
579 if (IsVmxRoot)
580 {
581 //
582 // Set the index
583 //
584 Index = 1;
585
586 //
587 // Acquire the lock
588 //
590 }
591 else
592 {
593 //
594 // Set the index
595 //
596 Index = 0;
597
598 //
599 // Acquire the lock
600 //
601 PlatformSpinlockAcquire(&g_MessageBufferInformation[Index].BufferLock, &OldIRQL);
602 }
603
604 //
605 // We have iterate through the all indexes
606 //
607 for (SIZE_T i = 0; i < MaximumPacketsCapacity; i++)
608 {
609 //
610 // Compute the current buffer to read
611 //
612 BUFFER_HEADER * Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress +
613 (g_MessageBufferInformation[Index].CurrentIndexToSend *
614 (PacketChunkSize + sizeof(BUFFER_HEADER))));
615
616 if (!Header->Valid)
617 {
618 //
619 // there is nothing to send
620 //
621
622 //
623 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
624 // if not we use the windows spinlock
625 //
626 if (IsVmxRoot)
627 {
629 }
630 else
631 {
632 //
633 // Release the lock
634 //
635 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLock, OldIRQL);
636 }
637
638 return ResultsOfBuffersSetToRead;
639 }
640
641 //
642 // If we reached here, means that there is sth to send
643 //
644 ResultsOfBuffersSetToRead++;
645
646 //
647 // Second, save the buffer contents
648 //
649 PVOID SendingBuffer = (PVOID)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToSend * (PacketChunkSize + sizeof(BUFFER_HEADER))) + sizeof(BUFFER_HEADER));
650
651 //
652 // Finally, set the current index to invalid as we sent it
653 //
654 Header->Valid = FALSE;
655
656 //
657 // Last step is to clear the current buffer (we can't do it once when CurrentIndexToSend is zero because
658 // there might be multiple messages on the start of the queue that didn't read yet)
659 // we don't free the header
660 //
661 PlatformZeroMemory(SendingBuffer, Header->BufferLength);
662
663 //
664 // Check to see whether we passed the index or not
665 //
666 if (g_MessageBufferInformation[Index].CurrentIndexToSend > MaximumPacketsCapacity - 2)
667 {
668 g_MessageBufferInformation[Index].CurrentIndexToSend = 0;
669 }
670 else
671 {
672 //
673 // Increment the next index to read
674 //
675 g_MessageBufferInformation[Index].CurrentIndexToSend = g_MessageBufferInformation[Index].CurrentIndexToSend + 1;
676 }
677 }
678
679 //
680 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
681 // if not we use the windows spinlock
682 //
683 if (IsVmxRoot)
684 {
686 }
687 else
688 {
689 //
690 // Release the lock
691 //
692 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLock, OldIRQL);
693 }
694
695 return ResultsOfBuffersSetToRead;
696}

◆ LogNotifyUsermodeCallback()

VOID LogNotifyUsermodeCallback ( PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2 )

Complete the IRP in IRP Pending state and fill the usermode buffers with pool data.

Parameters
Dpc
DeferredContext
SystemArgument1
SystemArgument2
Returns
VOID
1362{
1363 PNOTIFY_RECORD NotifyRecord;
1364 PIRP Irp;
1365 UINT32 Length;
1366
1367 UNREFERENCED_PARAMETER(Dpc);
1368 UNREFERENCED_PARAMETER(SystemArgument1);
1369 UNREFERENCED_PARAMETER(SystemArgument2);
1370
1371 NotifyRecord = DeferredContext;
1372
1373 ASSERT(NotifyRecord != NULL); // can't be NULL
1374 _Analysis_assume_(NotifyRecord != NULL);
1375
1376 switch (NotifyRecord->Type)
1377 {
1378 case IRP_BASED:
1379 Irp = NotifyRecord->Message.PendingIrp;
1380
1381 if (Irp != NULL)
1382 {
1383 PCHAR OutBuff; // pointer to output buffer
1384 ULONG InBuffLength; // Input buffer length
1385 ULONG OutBuffLength; // Output buffer length
1386 PIO_STACK_LOCATION IrpSp;
1387
1388 //
1389 // Make suree that concurrent calls to notify function never occurs
1390 //
1391 if (!(Irp->CurrentLocation <= Irp->StackCount + 1))
1392 {
1393 PlatformDbgPrint("Err, probably two or more functions called DPC for an object");
1394 return;
1395 }
1396
1398 InBuffLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
1399 OutBuffLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
1400
1401 if (!InBuffLength || !OutBuffLength)
1402 {
1403 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1404 PlatformIoCompleteRequest(Irp, IO_NO_INCREMENT);
1405 break;
1406 }
1407
1408 //
1409 // Check again that SystemBuffer is not null
1410 //
1411 if (!Irp->AssociatedIrp.SystemBuffer)
1412 {
1413 //
1414 // Buffer is invalid
1415 //
1416 return;
1417 }
1418
1419 OutBuff = Irp->AssociatedIrp.SystemBuffer;
1420 Length = 0;
1421
1422 //
1423 // Read Buffer might be empty (nothing to send)
1424 //
1425 if (!LogReadBuffer(NotifyRecord->CheckVmxRootMessagePool, OutBuff, &Length))
1426 {
1427 //
1428 // we have to return here as there is nothing to send here
1429 //
1430 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
1431 PlatformIoCompleteRequest(Irp, IO_NO_INCREMENT);
1432 break;
1433 }
1434
1435 Irp->IoStatus.Information = Length;
1436
1437 Irp->IoStatus.Status = STATUS_SUCCESS;
1438 PlatformIoCompleteRequest(Irp, IO_NO_INCREMENT);
1439 }
1440 break;
1441
1442 case EVENT_BASED:
1443 //
1444 // Signal the Event created in user-mode.
1445 //
1446 PlatformEventSet(NotifyRecord->Message.Event, 0, FALSE);
1447
1448 //
1449 // Dereference the object as we are done with it.
1450 //
1452
1453 break;
1454
1455 default:
1456 ASSERT(FALSE);
1457 break;
1458 }
1459
1460 if (NotifyRecord != NULL)
1461 {
1462 PlatformMemFreePool(NotifyRecord);
1463 }
1464}
BOOLEAN LogReadBuffer(BOOLEAN IsVmxRoot, PVOID BufferToSaveMessage, UINT32 *ReturnedLength)
Attempt to read the buffer.
Definition Logging.c:708
struct _NOTIFY_RECORD * PNOTIFY_RECORD
VOID PlatformDbgPrint(const CHAR *Format,...)
Print a debug message to the kernel debugger.
Definition PlatformDbg.c:26
VOID PlatformObjectDereference(PVOID Object)
Dereference a kernel object, decrementing its reference count.
Definition PlatformEvent.c:25
LONG PlatformEventSet(PKEVENT Event, KPRIORITY Increment, BOOLEAN Wait)
Signal (set) a kernel event object.
Definition PlatformEvent.c:51
PIO_STACK_LOCATION PlatformIoGetCurrentIrpStackLocation(PIRP Irp)
Get the current I/O stack location from an IRP.
Definition PlatformIo.c:25
VOID PlatformIoCompleteRequest(PIRP Irp, CCHAR PriorityBoost)
Complete an IRP and release it back to the I/O manager.
Definition PlatformIo.c:50
@ EVENT_BASED
Definition DataTypes.h:288
@ IRP_BASED
Definition DataTypes.h:287
union _NOTIFY_RECORD::@217351000120040342300302212137013326214173270134 Message
PIRP PendingIrp
Definition Logging.h:46
NOTIFY_TYPE Type
Definition Logging.h:41
PKEVENT Event
Definition Logging.h:45
BOOLEAN CheckVmxRootMessagePool
Definition Logging.h:50

◆ LogReadBuffer()

BOOLEAN LogReadBuffer ( BOOLEAN IsVmxRoot,
PVOID BufferToSaveMessage,
UINT32 * ReturnedLength )

Attempt to read the buffer.

Parameters
IsVmxRootDetermine whether you want to read vmx root buffer or vmx non root buffer
BufferToSaveMessageTarget buffer to save the message
ReturnedLengthThe actual length of the buffer that this function used it
Returns
BOOLEAN return of this function shows whether the read was successful or not (e.g FALSE shows there's no new buffer available.)
709{
710 UINT32 Index;
711 BOOLEAN PriorityMessageIsAvailable = FALSE;
712 KIRQL OldIRQL = NULL_ZERO;
713
714 //
715 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
716 // if not we use the windows spinlock
717 //
718 if (IsVmxRoot)
719 {
720 //
721 // Set the index
722 //
723 Index = 1;
724
725 //
726 // Acquire the lock
727 //
729 }
730 else
731 {
732 //
733 // Set the index
734 //
735 Index = 0;
736
737 //
738 // Acquire the lock
739 //
740 PlatformSpinlockAcquire(&g_MessageBufferInformation[Index].BufferLock, &OldIRQL);
741 }
742
743 //
744 // Compute the current buffer to read
745 //
746 BUFFER_HEADER * Header;
747
748 //
749 // Check for priority message
750 //
751 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (g_MessageBufferInformation[Index].CurrentIndexToSendPriority * (PacketChunkSize + sizeof(BUFFER_HEADER))));
752
753 if (!Header->Valid)
754 {
755 //
756 // Check for regular message
757 //
758 Header = (BUFFER_HEADER *)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToSend * (PacketChunkSize + sizeof(BUFFER_HEADER))));
759
760 if (!Header->Valid)
761 {
762 //
763 // there is nothing to send
764 //
765
766 //
767 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
768 // if not we use the windows spinlock
769 //
770 if (IsVmxRoot)
771 {
773 }
774 else
775 {
776 //
777 // Release the lock
778 //
779 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLock, OldIRQL);
780 }
781
782 return FALSE;
783 }
784 }
785 else
786 {
787 PriorityMessageIsAvailable = TRUE;
788 }
789
790 //
791 // If we reached here, means that there is sth to send
792 //
793
794 //
795 // First copy the header
796 //
797 PlatformWriteMemory(BufferToSaveMessage, &Header->OperationNumber, sizeof(UINT32));
798
799 //
800 // Second, save the buffer contents
801 //
802 PVOID SendingBuffer;
803
804 if (PriorityMessageIsAvailable)
805 {
806 SendingBuffer = (PVOID)((UINT64)g_MessageBufferInformation[Index].BufferStartAddressPriority + (g_MessageBufferInformation[Index].CurrentIndexToSendPriority * (PacketChunkSize + sizeof(BUFFER_HEADER))) + sizeof(BUFFER_HEADER));
807 }
808 else
809 {
810 SendingBuffer = (PVOID)((UINT64)g_MessageBufferInformation[Index].BufferStartAddress + (g_MessageBufferInformation[Index].CurrentIndexToSend * (PacketChunkSize + sizeof(BUFFER_HEADER))) + sizeof(BUFFER_HEADER));
811 }
812
813 //
814 // Because we want to pass the header of usermode header
815 //
816 PVOID SavingAddress = (PVOID)((UINT64)BufferToSaveMessage + sizeof(UINT32));
817
818 PlatformWriteMemory(SavingAddress, SendingBuffer, Header->BufferLength);
819
820#if ShowMessagesOnDebugger
821
822 //
823 // Means that show just messages
824 //
826 {
827 //
828 // We're in Dpc level here so it's safe to use DbgPrint
829 // DbgPrint limitation is 512 Byte
830 //
831 if (Header->BufferLength > DbgPrintLimitation)
832 {
833 for (SIZE_T i = 0; i <= Header->BufferLength / DbgPrintLimitation; i++)
834 {
835 if (i != 0)
836 {
837 PlatformDbgPrint("%s", (CHAR *)((UINT64)SendingBuffer + (DbgPrintLimitation * i) - 2));
838 }
839 else
840 {
841 PlatformDbgPrint("%s", (CHAR *)((UINT64)SendingBuffer + (DbgPrintLimitation * i)));
842 }
843 }
844 }
845 else
846 {
847 PlatformDbgPrint("%s", (CHAR *)SendingBuffer);
848 }
849 }
850#endif
851
852 //
853 // Finally, set the current index to invalid as we sent it
854 //
855 Header->Valid = FALSE;
856
857 //
858 // Set the length to show as the ReturnedByted in usermode ioctl function + size of header
859 //
860 *ReturnedLength = Header->BufferLength + sizeof(UINT32);
861
862 //
863 // Last step is to clear the current buffer (we can't do it once when CurrentIndexToSend is zero because
864 // there might be multiple messages on the start of the queue that didn't read yet)
865 // we don't free the header
866 //
867 PlatformZeroMemory(SendingBuffer, Header->BufferLength);
868
869 if (PriorityMessageIsAvailable)
870 {
871 //
872 // Check to see whether we passed the index or not
873 //
874 if (g_MessageBufferInformation[Index].CurrentIndexToSendPriority > MaximumPacketsCapacityPriority - 2)
875 {
876 g_MessageBufferInformation[Index].CurrentIndexToSendPriority = 0;
877 }
878 else
879 {
880 //
881 // Increment the next index to read
882 //
883 g_MessageBufferInformation[Index].CurrentIndexToSendPriority = g_MessageBufferInformation[Index].CurrentIndexToSendPriority + 1;
884 }
885 }
886 else
887 {
888 //
889 // Check to see whether we passed the index or not
890 //
891 if (g_MessageBufferInformation[Index].CurrentIndexToSend > MaximumPacketsCapacity - 2)
892 {
893 g_MessageBufferInformation[Index].CurrentIndexToSend = 0;
894 }
895 else
896 {
897 //
898 // Increment the next index to read
899 //
900 g_MessageBufferInformation[Index].CurrentIndexToSend = g_MessageBufferInformation[Index].CurrentIndexToSend + 1;
901 }
902 }
903
904 //
905 // Check if we're in Vmx-root, if it is then we use our customized HIGH_IRQL Spinlock,
906 // if not we use the windows spinlock
907 //
908 if (IsVmxRoot)
909 {
911 }
912 else
913 {
914 //
915 // Release the lock
916 //
917 PlatformSpinlockRelease(&g_MessageBufferInformation[Index].BufferLock, OldIRQL);
918 }
919
920 return TRUE;
921}
#define DbgPrintLimitation
limitation of Windows DbgPrint message size
Definition Constants.h:223

◆ LogRegisterEventBasedNotification()

BOOLEAN LogRegisterEventBasedNotification ( PVOID TargetIrp)

Create an event-based usermode notifying mechanism.

Parameters
TargetIrp
Returns
BOOLEAN
1595{
1596 PNOTIFY_RECORD NotifyRecord;
1597 NTSTATUS Status;
1598 PIO_STACK_LOCATION IrpStack;
1599 PREGISTER_NOTIFY_BUFFER RegisterEvent;
1600 PIRP Irp = (PIRP)TargetIrp;
1601
1603 RegisterEvent = (PREGISTER_NOTIFY_BUFFER)Irp->AssociatedIrp.SystemBuffer;
1604
1605 //
1606 // Allocate a record and save all the event context
1607 //
1609
1610 if (NULL == NotifyRecord)
1611 {
1612 PlatformDbgPrint("Err, unable to allocate memory for notify record\n");
1613 return FALSE;
1614 }
1615
1616 NotifyRecord->Type = EVENT_BASED;
1617
1618 PlatformDpcInitialize(&NotifyRecord->Dpc, // Dpc
1619 LogNotifyUsermodeCallback, // DeferredRoutine
1620 NotifyRecord // DeferredContext
1621 );
1622
1623 //
1624 // Get the object pointer from the handle
1625 // Note we must be in the context of the process that created the handle
1626 //
1627 Status = PlatformObjectReferenceByHandle(RegisterEvent->hEvent,
1628 SYNCHRONIZE | EVENT_MODIFY_STATE,
1629 *ExEventObjectType,
1630 Irp->RequestorMode,
1631 &NotifyRecord->Message.Event,
1632 NULL);
1633
1634 if (!NT_SUCCESS(Status))
1635 {
1636 PlatformDbgPrint("Err, unable to reference user mode event object, status = 0x%x\n", Status);
1637 PlatformMemFreePool(NotifyRecord);
1638 return FALSE;
1639 }
1640
1641 //
1642 // Insert dpc to the queue
1643 //
1644 PlatformDpcInsertQueueDpc(&NotifyRecord->Dpc, NotifyRecord, NULL);
1645
1646 return TRUE;
1647}
VOID LogNotifyUsermodeCallback(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2)
Complete the IRP in IRP Pending state and fill the usermode buffers with pool data.
Definition Logging.c:1361
struct _NOTIFY_RECORD NOTIFY_RECORD
The usermode request.
VOID PlatformDpcInitialize(PRKDPC Dpc, PKDEFERRED_ROUTINE DeferredRoutine, PVOID DeferredContext)
Initialize a DPC object.
Definition PlatformDpc.c:27
NTSTATUS PlatformObjectReferenceByHandle(HANDLE Handle, ACCESS_MASK DesiredAccess, POBJECT_TYPE ObjectType, KPROCESSOR_MODE AccessMode, PVOID *Object, POBJECT_HANDLE_INFORMATION HandleInformation)
Obtain a pointer to a kernel object by its user-mode handle and increment its reference count.
Definition PlatformEvent.c:80
PVOID PlatformMemAllocateNonPagedPoolWithQuota(SIZE_T NumberOfBytes)
Allocates non-paged pool memory with quota charging.
Definition PlatformMem.c:227
struct _REGISTER_NOTIFY_BUFFER * PREGISTER_NOTIFY_BUFFER

◆ LogRegisterIrpBasedNotification()

BOOLEAN LogRegisterIrpBasedNotification ( PVOID TargetIrp,
LONG * Status )

Register a new IRP Pending thread which listens for new buffers.

Parameters
TargetIrp
Status
Returns
BOOLEAN
1476{
1477 PNOTIFY_RECORD NotifyRecord;
1478 PIO_STACK_LOCATION IrpStack;
1479 PREGISTER_NOTIFY_BUFFER RegisterEvent;
1480 PIRP Irp = (PIRP)TargetIrp;
1481
1482 //
1483 // check if current core has another thread with pending IRP,
1484 // if no then put the current thread to pending
1485 // otherwise return and complete thread with STATUS_SUCCESS as
1486 // there is another thread waiting for message
1487 //
1488
1489 if (g_GlobalNotifyRecord == NULL)
1490 {
1492 RegisterEvent = (PREGISTER_NOTIFY_BUFFER)Irp->AssociatedIrp.SystemBuffer;
1493
1494 //
1495 // Allocate a record and save all the event context
1496 //
1498
1499 if (NULL == NotifyRecord)
1500 {
1501 *Status = (LONG)STATUS_INSUFFICIENT_RESOURCES;
1502 return FALSE;
1503 }
1504
1505 NotifyRecord->Type = IRP_BASED;
1506 NotifyRecord->Message.PendingIrp = Irp;
1507
1508 PlatformDpcInitialize(&NotifyRecord->Dpc, // Dpc
1509 LogNotifyUsermodeCallback, // DeferredRoutine
1510 NotifyRecord // DeferredContext
1511 );
1512
1514
1515 //
1516 // check for new message (for both Vmx-root mode or Vmx non root-mode)
1517 // First, we check for priority messages in both buffers then we check
1518 // for regular messages
1519 //
1521 {
1522 //
1523 // check vmx non-root (priority buffers)
1524 //
1525 NotifyRecord->CheckVmxRootMessagePool = FALSE;
1526
1527 //
1528 // Insert dpc to queue
1529 //
1530 PlatformDpcInsertQueueDpc(&NotifyRecord->Dpc, NotifyRecord, NULL);
1531 }
1532 else if (LogCheckForNewMessage(TRUE, TRUE))
1533 {
1534 //
1535 // check vmx root (priority buffers)
1536 //
1537 NotifyRecord->CheckVmxRootMessagePool = TRUE;
1538 //
1539 // Insert dpc to queue
1540 //
1541 PlatformDpcInsertQueueDpc(&NotifyRecord->Dpc, NotifyRecord, NULL);
1542 }
1544 {
1545 //
1546 // check vmx non-root
1547 //
1548 NotifyRecord->CheckVmxRootMessagePool = FALSE;
1549
1550 //
1551 // Insert dpc to queue
1552 //
1553 PlatformDpcInsertQueueDpc(&NotifyRecord->Dpc, NotifyRecord, NULL);
1554 }
1555 else if (LogCheckForNewMessage(TRUE, FALSE))
1556 {
1557 //
1558 // check vmx root
1559 //
1560 NotifyRecord->CheckVmxRootMessagePool = TRUE;
1561 //
1562 // Insert dpc to queue
1563 //
1564 PlatformDpcInsertQueueDpc(&NotifyRecord->Dpc, NotifyRecord, NULL);
1565 }
1566 else
1567 {
1568 //
1569 // Set the notify routine to the global structure
1570 //
1571 g_GlobalNotifyRecord = NotifyRecord;
1572 }
1573 //
1574 // We will return pending as we have marked the IRP pending
1575 //
1576
1577 *Status = (LONG)STATUS_PENDING;
1578 return TRUE;
1579 }
1580 else
1581 {
1582 *Status = (LONG)STATUS_SUCCESS;
1583 return TRUE;
1584 }
1585}
BOOLEAN LogCheckForNewMessage(BOOLEAN IsVmxRoot, BOOLEAN Priority)
Check if new message is available or not.
Definition Logging.c:933
VOID PlatformIoMarkIrpPending(PIRP Irp)
Mark the current IRP stack location as pending.
Definition PlatformIo.c:74
long LONG
Definition BasicTypes.h:28
KDPC Dpc
Definition Logging.h:49

◆ LogSendImmediateMessage()

BOOLEAN LogSendImmediateMessage ( CHAR * OptionalBuffer,
UINT32 OptionalBufferLength,
UINT32 OperationCode )
inline

Checks whether the immediate sending is needed or not.

Parameters
OptionalBuffer
OptionalBufferLength
OperationCode
Returns
BOOLEAN
73{
74 SEND_IMMEDIATE_MESSAGE SendImmediateMessage = g_MsgTracingCallbacks.SendImmediateMessage;
75
76 if (SendImmediateMessage == NULL)
77 {
78 //
79 // As the caller didn't defined a checker we assume there is no
80 // need to send messages immediately
81 //
82 return FALSE;
83 }
84
85 //
86 // The user specified a vmx checker
87 //
88 return SendImmediateMessage(OptionalBuffer, OptionalBufferLength, OperationCode);
89}
BOOLEAN(* SEND_IMMEDIATE_MESSAGE)(CHAR *OptionalBuffer, UINT32 OptionalBufferLength, UINT32 OperationCode)
A function that sends immediate messages.
Definition HyperLog.h:36

◆ LogUnInitialize()

VOID LogUnInitialize ( )

Uninitialize the buffer relating to log message tracing.

Returns
VOID
212{
213 //
214 // de-allocate buffer for messages and initialize the core buffer information (for vmx-root core)
215 //
216 for (int i = 0; i < 2; i++)
217 {
218 //
219 // Check if the buffer is allocated or not
220 //
222 {
223 continue; // No need to free the buffers
224 }
225
226 //
227 // Free each buffers
228 //
229 if (g_MessageBufferInformation[i].BufferStartAddress != NULL64_ZERO)
230 {
232 }
233
234 if (g_MessageBufferInformation[i].BufferStartAddressPriority != NULL64_ZERO)
235 {
236 PlatformMemFreePool((PVOID)g_MessageBufferInformation[i].BufferStartAddressPriority);
237 }
238
239 if (g_MessageBufferInformation[i].BufferForMultipleNonImmediateMessage != NULL64_ZERO)
240 {
241 PlatformMemFreePool((PVOID)g_MessageBufferInformation[i].BufferForMultipleNonImmediateMessage);
242 }
243 }
244
245 //
246 // de-allocate buffers for trace message and data messages if they are allocated
247 //
249 {
252 }
253}
#define NULL64_ZERO
Definition BasicTypes.h:111