9 #define NTSTRSAFE_NO_CB_FUNCTIONS 10 #include <ntstrsafe.h> 13 #pragma prefast(disable : 30030) 79 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
83 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
92 _In_z_
const char *function_name,
93 _In_z_
const char *log_message,
94 _Out_
char *log_buffer,
95 _In_ SIZE_T log_buffer_length);
99 static NTSTATUS
LogpPut(_In_z_
char *message, _In_ ULONG attribute);
101 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
104 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
123 _IRQL_requires_max_(PASSIVE_LEVEL)
static NTSTATUS
132 #if defined(ALLOC_PRAGMA) 133 #pragma alloc_text(INIT, LogInitialization) 134 #pragma alloc_text(INIT, LogpInitializeBufferInfo) 135 #pragma alloc_text(PAGE, LogpInitializeLogFile) 136 #pragma alloc_text(INIT, LogRegisterReinitialization) 137 #pragma alloc_text(PAGE, LogpReinitializationRoutine) 138 #pragma alloc_text(PAGE, LogIrpShutdownHandler) 139 #pragma alloc_text(PAGE, LogTermination) 140 #pragma alloc_text(PAGE, LogpFinalizeBufferInfo) 141 #pragma alloc_text(PAGE, LogpBufferFlushThreadRoutine) 142 #pragma alloc_text(PAGE, LogpSleep) 158 _Use_decl_annotations_ NTSTATUS
162 auto status = STATUS_SUCCESS;
167 bool need_reinitialization =
false;
170 if (status == STATUS_REINITIALIZATION_NEEDED) {
171 need_reinitialization =
true;
172 }
else if (!NT_SUCCESS(status)) {
179 (need_reinitialization ?
"partially " :
""));
180 if (!NT_SUCCESS(status)) {
187 return (need_reinitialization ? STATUS_REINITIALIZATION_NEEDED
201 NT_ASSERT(log_file_path);
206 auto status = RtlStringCchCopyW(
209 if (!NT_SUCCESS(status)) {
213 status = ExInitializeResourceLite(&info->
resource);
214 if (!NT_SUCCESS(status)) {
224 return STATUS_INSUFFICIENT_RESOURCES;
231 return STATUS_INSUFFICIENT_RESOURCES;
249 if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
251 status = STATUS_REINITIALIZATION_NEEDED;
252 }
else if (!NT_SUCCESS(status)) {
264 return STATUS_SUCCESS;
268 UNICODE_STRING log_file_path_u = {};
271 OBJECT_ATTRIBUTES oa = {};
272 InitializeObjectAttributes(&oa, &log_file_path_u,
273 OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
nullptr,
276 IO_STATUS_BLOCK io_status = {};
277 auto status = ZwCreateFile(
278 &info->
log_file_handle, FILE_APPEND_DATA | SYNCHRONIZE, &oa, &io_status,
279 nullptr, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN_IF,
280 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
nullptr, 0);
281 if (!NT_SUCCESS(status)) {
288 nullptr,
nullptr,
nullptr,
290 if (!NT_SUCCESS(status)) {
306 PDRIVER_OBJECT driver_object) {
308 IoRegisterBootDriverReinitialization(
315 _DRIVER_OBJECT *driver_object, PVOID context, ULONG count) {
317 UNREFERENCED_PARAMETER(driver_object);
318 UNREFERENCED_PARAMETER(count);
320 _Analysis_assume_(context);
324 NT_ASSERT(NT_SUCCESS(status));
325 if (NT_SUCCESS(status)) {
342 while (info.log_buffer_head[0]) {
369 if (!NT_SUCCESS(status)) {
391 ExDeleteResourceLite(&info->
resource);
398 const char *function_name,
399 const char *format, ...) {
400 auto status = STATUS_SUCCESS;
407 va_start(args, format);
408 char log_message[412];
409 status = RtlStringCchVPrintfA(log_message, RTL_NUMBER_OF(log_message), format,
412 if (!NT_SUCCESS(status)) {
416 if (log_message[0] ==
'\0') {
418 return STATUS_INVALID_PARAMETER;
421 const auto pure_level = level & 0xf0;
422 const auto attribute = level & 0x0f;
427 static_assert(RTL_NUMBER_OF(message) <= 512,
428 "One log message should not exceed 512 bytes.");
429 status =
LogpMakePrefix(pure_level, function_name, log_message, message,
430 RTL_NUMBER_OF(message));
431 if (!NT_SUCCESS(status)) {
436 status =
LogpPut(message, attribute);
437 if (!NT_SUCCESS(status)) {
446 ULONG level,
const char *function_name,
const char *log_message,
447 char *log_buffer, SIZE_T log_buffer_length) {
448 char const *level_string =
nullptr;
451 level_string =
"DBG\t";
454 level_string =
"INF\t";
457 level_string =
"WRN\t";
460 level_string =
"ERR\t";
463 return STATUS_INVALID_PARAMETER;
466 auto status = STATUS_SUCCESS;
468 char time_buffer[20] = {};
471 TIME_FIELDS time_fields;
472 LARGE_INTEGER system_time, local_time;
473 KeQuerySystemTime(&system_time);
474 ExSystemTimeToLocalTime(&system_time, &local_time);
475 RtlTimeToTimeFields(&local_time, &time_fields);
477 status = RtlStringCchPrintfA(time_buffer, RTL_NUMBER_OF(time_buffer),
478 "%02hd:%02hd:%02hd.%03hd\t", time_fields.Hour,
479 time_fields.Minute, time_fields.Second,
480 time_fields.Milliseconds);
481 if (!NT_SUCCESS(status)) {
487 char function_name_buffer[50] = {};
490 status = RtlStringCchPrintfA(function_name_buffer,
491 RTL_NUMBER_OF(function_name_buffer),
"%-40s\t",
493 if (!NT_SUCCESS(status)) {
499 char processro_number[10] = {};
502 RtlStringCchPrintfA(processro_number, RTL_NUMBER_OF(processro_number),
503 "#%lu\t", KeGetCurrentProcessorNumberEx(
nullptr));
504 if (!NT_SUCCESS(status)) {
515 status = RtlStringCchPrintfA(
516 log_buffer, log_buffer_length,
"%s%s%s%5Iu\t%5Iu\t%-15s\t%s%s\r\n",
517 time_buffer, level_string, processro_number,
518 reinterpret_cast<ULONG_PTR>(PsGetProcessId(PsGetCurrentProcess())),
519 reinterpret_cast<ULONG_PTR>(PsGetCurrentThreadId()),
528 const char *function_name) {
529 if (!function_name) {
533 auto ptr = function_name;
534 auto name = function_name;
544 _Use_decl_annotations_
static NTSTATUS
LogpPut(
char *message, ULONG attribute) {
545 auto status = STATUS_SUCCESS;
548 KeGetCurrentIrql() < CLOCK_LEVEL);
556 #pragma warning(push) 557 #pragma warning(disable : 28123) 558 if (!KeAreAllApcsDisabled()) {
587 NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
589 auto status = STATUS_SUCCESS;
593 ExEnterCriticalRegionAndAcquireResourceExclusive(&info->
resource);
597 KLOCK_QUEUE_HANDLE lock_handle = {};
598 KeAcquireInStackQueuedSpinLock(&info->
spin_lock, &lock_handle);
605 KeReleaseInStackQueuedSpinLock(&lock_handle);
608 IO_STATUS_BLOCK io_status = {};
609 for (
auto current_log_entry = old_log_buffer; current_log_entry[0]; ) {
614 const auto current_log_entry_length = strlen(current_log_entry);
616 &io_status, current_log_entry,
617 static_cast<ULONG>(current_log_entry_length),
nullptr,
619 if (!NT_SUCCESS(status)) {
631 current_log_entry += current_log_entry_length + 1;
633 old_log_buffer[0] =
'\0';
635 ExReleaseResourceAndLeaveCriticalRegion(&info->
resource);
642 NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
644 IO_STATUS_BLOCK io_status = {};
646 ZwWriteFile(info.
log_file_handle,
nullptr,
nullptr,
nullptr, &io_status,
647 const_cast<char *>(message),
648 static_cast<ULONG>(strlen(message)),
nullptr,
nullptr);
649 if (!NT_SUCCESS(status)) {
665 KLOCK_QUEUE_HANDLE lock_handle = {};
666 const auto old_irql = KeGetCurrentIrql();
667 if (old_irql < DISPATCH_LEVEL) {
668 KeAcquireInStackQueuedSpinLock(&info->
spin_lock, &lock_handle);
670 KeAcquireInStackQueuedSpinLockAtDpcLevel(&info->
spin_lock, &lock_handle);
672 NT_ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
681 if (NT_SUCCESS(status)) {
682 const auto message_length = strlen(message) + 1;
684 used_buffer_size += message_length;
693 if (old_irql < DISPATCH_LEVEL) {
694 KeReleaseInStackQueuedSpinLock(&lock_handle);
696 KeReleaseInStackQueuedSpinLockFromDpcLevel(&lock_handle);
706 const auto location_of_cr = strlen(message) - 2;
707 message[location_of_cr] =
'\n';
708 message[location_of_cr + 1] =
'\0';
709 DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL,
"%s", message);
754 void *start_context) {
756 auto status = STATUS_SUCCESS;
757 auto info =
reinterpret_cast<LogBufferInfo *
>(start_context);
760 PsGetCurrentThreadId());
762 while (info->buffer_flush_thread_should_be_alive) {
764 if (info->log_buffer_head[0]) {
765 NT_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
766 NT_ASSERT(!KeAreAllApcsDisabled());
774 PsTerminateSystemThread(status);
778 _Use_decl_annotations_
static NTSTATUS
LogpSleep(LONG millisecond) {
781 LARGE_INTEGER interval = {};
782 interval.QuadPart = -(10000ll * millisecond);
783 return KeDelayExecutionThread(KernelMode, FALSE, &interval);
798 return (message[0] & 0x80) != 0;
803 if (!KD_DEBUGGER_NOT_PRESENT) {
811 _In_
unsigned __int64 _Options,
812 _Out_writes_opt_z_(_BufferCount)
char *_Buffer, _In_
size_t _BufferCount,
813 _In_z_ _Printf_format_string_params_(2)
char const *_Format,
814 _In_opt_ _locale_t _Locale, va_list _ArgList) {
815 UNREFERENCED_PARAMETER(_Options);
816 UNREFERENCED_PARAMETER(_Locale);
819 using _vsnprintf_type =
int __cdecl(
char *,
size_t,
const char *, va_list);
820 static _vsnprintf_type *local__vsnprintf =
nullptr;
821 if (!local__vsnprintf) {
822 UNICODE_STRING proc_name_U = {};
823 RtlInitUnicodeString(&proc_name_U, L
"_vsnprintf");
824 local__vsnprintf =
reinterpret_cast<_vsnprintf_type *
>(
825 MmGetSystemRoutineAddress(&proc_name_U));
827 return local__vsnprintf(_Buffer, _BufferCount, _Format, _ArgList);
833 _In_
unsigned __int64 _Options,
834 _Out_writes_opt_z_(_BufferCount)
wchar_t *_Buffer, _In_
size_t _BufferCount,
835 _In_z_ _Printf_format_string_params_(2)
wchar_t const *_Format,
836 _In_opt_ _locale_t _Locale, va_list _ArgList) {
837 UNREFERENCED_PARAMETER(_Options);
838 UNREFERENCED_PARAMETER(_Locale);
841 using _vsnwprintf_type =
842 int __cdecl(
wchar_t *,
size_t,
const wchar_t *, va_list);
843 static _vsnwprintf_type *local__vsnwprintf =
nullptr;
844 if (!local__vsnwprintf) {
845 UNICODE_STRING proc_name_U = {};
846 RtlInitUnicodeString(&proc_name_U, L
"_vsnwprintf");
847 local__vsnwprintf =
reinterpret_cast<_vsnwprintf_type *
>(
848 MmGetSystemRoutineAddress(&proc_name_U));
851 return local__vsnwprintf(_Buffer, _BufferCount, _Format, _ArgList);
NTSTATUS LogInitialization(ULONG flag, const wchar_t *log_file_path)
volatile char * log_buffer_tail
static NTSTATUS LogpWriteMessageToFile(_In_z_ const char *message, _In_ const LogBufferInfo &info)
#define HYPERPLATFORM_LOG_INFO(format,...)
#define HYPERPLATFORM_LOG_DEBUG(format,...)
Logs a message as respective severity.
static void LogpDbgBreak()
_Check_return_opt_ int __cdecl __stdio_common_vsprintf(_In_ unsigned __int64 _Options, _Out_writes_opt_z_(_BufferCount) char *_Buffer, _In_ size_t _BufferCount, _In_z_ _Printf_format_string_params_(2) char const *_Format, _In_opt_ _locale_t _Locale, va_list _ArgList)
static const auto kLogpBufferSizeInPages
void LogTermination()
Terminates the log system. Should be called from a DriverUnload routine.
volatile bool buffer_flush_thread_started
static const auto kLogpLevelOptSafe
Save this log to buffer and not try to write to a log file.
static const auto kLogOptDisableFunctionName
For LogInitialization(). Do not log a current function name.
static const auto kLogpLogFlushIntervalMsec
static const auto kLogpBufferUsableSize
static bool LogpIsDbgPrintNeeded()
static void LogpSetPrintedBit(_In_z_ char *message, _In_ bool on)
static DRIVER_REINITIALIZE LogpReinitializationRoutine
_Check_return_opt_ int __cdecl __stdio_common_vswprintf(_In_ unsigned __int64 _Options, _Out_writes_opt_z_(_BufferCount) wchar_t *_Buffer, _In_ size_t _BufferCount, _In_z_ _Printf_format_string_params_(2) wchar_t const *_Format, _In_opt_ _locale_t _Locale, va_list _ArgList)
static const auto kLogPutLevelDisable
For LogInitialization(). Disables all levels of logs.
static const auto kLogpLevelDebug
Bit mask for DEBUG level logs.
static void LogpDoDbgPrint(_In_z_ char *message)
static bool LogpIsLogFileEnabled(_In_ const LogBufferInfo &info)
static bool LogpIsLogFileActivated(_In_ const LogBufferInfo &info)
static bool LogpIsPrinted(_In_z_ char *message)
static const auto kLogOptDisableProcessorNumber
For LogInitialization(). Do not log a current processor number.
NTSTATUS LogpPrint(ULONG level, const char *function_name, const char *format,...)
static const auto kLogpLevelInfo
Bit mask for INFO level logs.
static const auto kLogpLevelError
Bit mask for ERROR level logs.
volatile char * log_buffer_head
bool resource_initialized
static bool LogpIsLogNeeded(_In_ ULONG level)
NTKERNELAPI UCHAR *NTAPI PsGetProcessImageFileName(_In_ PEPROCESS process)
static NTSTATUS LogpMakePrefix(_In_ ULONG level, _In_z_ const char *function_name, _In_z_ const char *log_message, _Out_ char *log_buffer, _In_ SIZE_T log_buffer_length)
volatile bool buffer_flush_thread_should_be_alive
static NTSTATUS LogpInitializeLogFile(_Inout_ LogBufferInfo *info)
static const ULONG kLogpPoolTag
void LogIrpShutdownHandler()
Terminates the log system. Should be called from an IRP_MJ_SHUTDOWN handler.
static const auto kLogpBufferSize
static const auto kLogOptDisableDbgPrint
For LogInitialization(). Do not log to debug buffer.
static NTSTATUS LogpBufferMessage(_In_z_ const char *message, _Inout_ LogBufferInfo *info)
HANDLE buffer_flush_thread_handle
static KSTART_ROUTINE LogpBufferFlushThreadRoutine
static NTSTATUS LogpPut(_In_z_ char *message, _In_ ULONG attribute)
static auto g_logp_debug_flag
void LogRegisterReinitialization(PDRIVER_OBJECT driver_object)
static const auto kLogOptDisableTime
For LogInitialization(). Do not log a current time.
static const auto kLogpLevelWarn
Bit mask for WARN level logs.
static LogBufferInfo g_logp_log_buffer_info
Declares interfaces to logging functions.
static const char * LogpFindBaseFunctionName(_In_z_ const char *function_name)
static NTSTATUS LogpFlushLogBuffer(_Inout_ LogBufferInfo *info)
wchar_t log_file_path[200]
static void LogpFinalizeBufferInfo(_In_ LogBufferInfo *info)
static NTSTATUS LogpSleep(_In_ LONG millisecond)
static NTSTATUS LogpInitializeBufferInfo(_In_ const wchar_t *log_file_path, _Inout_ LogBufferInfo *info)