diff --git a/build/VStudio/winfsp_sys.vcxproj b/build/VStudio/winfsp_sys.vcxproj
index 8843ec77..659fb9e7 100644
--- a/build/VStudio/winfsp_sys.vcxproj
+++ b/build/VStudio/winfsp_sys.vcxproj
@@ -187,6 +187,7 @@
+
diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters
index 7ee41c66..7c248ca6 100644
--- a/build/VStudio/winfsp_sys.vcxproj.filters
+++ b/build/VStudio/winfsp_sys.vcxproj.filters
@@ -125,6 +125,9 @@
Source
+
+ Source
+
diff --git a/src/sys/debug.c b/src/sys/debug.c
index 5d51d915..e9f31163 100644
--- a/src/sys/debug.c
+++ b/src/sys/debug.c
@@ -22,6 +22,10 @@
#include
#if DBG
+
+#undef STATUS_INSUFFICIENT_RESOURCES
+#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)
+
#define SYM(x) case x: return #x;
#define SYMBRC(x) case x: return "[" #x "]";
@@ -330,4 +334,5 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result)
NtStatusSym(Result),
(LONGLONG)Irp->IoStatus.Information);
}
+
#endif
diff --git a/src/sys/driver.c b/src/sys/driver.c
index a03c385a..1ec81b31 100644
--- a/src/sys/driver.c
+++ b/src/sys/driver.c
@@ -38,6 +38,8 @@ NTSTATUS DriverEntry(
{
FSP_ENTER_DRV();
+ FSP_TRACE_INIT();
+
/* setup the driver object */
DriverObject->MajorFunction[IRP_MJ_CREATE] = FspCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = FspClose;
@@ -157,6 +159,8 @@ exit:
FspSiloFinalize();
if (InitDoneGRes)
ExDeleteResourceLite(&FspDeviceGlobalResource);
+
+ FSP_TRACE_FINI();
}
#pragma prefast(suppress:28175, "We are in DriverEntry: ok to access DriverName")
diff --git a/src/sys/driver.h b/src/sys/driver.h
index 9ceb7ded..2f0dc0a3 100644
--- a/src/sys/driver.h
+++ b/src/sys/driver.h
@@ -147,6 +147,40 @@ VOID FspDebugLogIrp(const char *func, PIRP Irp, NTSTATUS Result);
#define DEBUGTEST_EX(C, Percent, Deflt) (Deflt)
#endif
+/* trace */
+#if FSP_TRACE_ENABLED
+VOID FspTraceInitialize(VOID);
+VOID FspTraceFinalize(VOID);
+VOID FspTrace(const char *file, int line, const char *func);
+VOID FspTraceNtStatus(const char *file, int line, const char *func, NTSTATUS Status);
+#define FSP_TRACE_INIT() \
+ (FspTraceInitialize(), FSP_TRACE())
+#define FSP_TRACE_FINI() \
+ (FSP_TRACE(), FspTraceFinalize())
+#define FSP_TRACE() \
+ FspTrace( \
+ __FILE__, \
+ __LINE__, \
+ __FUNCTION__)
+#define FSP_TRACE_NTSTATUS(Status) \
+ FspTraceNtStatus( \
+ __FILE__, \
+ __LINE__, \
+ __FUNCTION__, \
+ Status)
+#else
+#define FSP_TRACE_INIT() \
+ ((VOID)0)
+#define FSP_TRACE_FINI() \
+ ((VOID)0)
+#define FSP_TRACE() \
+ ((VOID)0)
+#define FSP_TRACE_NTSTATUS(Result) \
+ ((VOID)0)
+#endif
+#undef STATUS_INSUFFICIENT_RESOURCES
+#define STATUS_INSUFFICIENT_RESOURCES (FSP_TRACE_NTSTATUS(0xC000009AL), (NTSTATUS)0xC000009AL)
+
/* FSP_ENTER/FSP_LEAVE */
#if DBG
#define FSP_DEBUGLOG_(fmt, rfmt, ...) \
diff --git a/src/sys/trace.c b/src/sys/trace.c
new file mode 100644
index 00000000..8d7da42a
--- /dev/null
+++ b/src/sys/trace.c
@@ -0,0 +1,142 @@
+/**
+ * @file sys/trace.c
+ *
+ * @copyright 2015-2020 Bill Zissimopoulos
+ */
+/*
+ * This file is part of WinFsp.
+ *
+ * You can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 3 as published by the Free Software
+ * Foundation.
+ *
+ * Licensees holding a valid commercial license may use this software
+ * in accordance with the commercial license agreement provided in
+ * conjunction with the software. The terms and conditions of any such
+ * commercial license agreement shall govern, supersede, and render
+ * ineffective any application of the GPLv3 license to this software,
+ * notwithstanding of any reference thereto in the software or
+ * associated repository.
+ */
+
+#include
+
+#if FSP_TRACE_ENABLED
+
+#undef STATUS_INSUFFICIENT_RESOURCES
+#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)
+
+static struct
+{
+ HANDLE Handle;
+ PKEVENT Event;
+} FspLowMemoryCondition, FspLowNonPagedPoolCondition, FspLowPagedPoolCondition;
+
+VOID FspTrace(const char *file, int line, const char *func)
+{
+ for (const char *p = file; '\0' != *p; p++)
+ if ('\\' == *p)
+ file = p + 1;
+
+ ASSERT(DISPATCH_LEVEL >= KeGetCurrentIrql());
+ DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_TRACE_LEVEL,
+ DRIVER_NAME ": %s[%s:%d]\n", func, file, line);
+}
+
+VOID FspTraceNtStatus(const char *file, int line, const char *func, NTSTATUS Status)
+{
+ for (const char *p = file; '\0' != *p; p++)
+ if ('\\' == *p)
+ file = p + 1;
+
+ ASSERT(DISPATCH_LEVEL >= KeGetCurrentIrql());
+ BOOLEAN LowMemoryCondition, LowNonPagedPoolCondition, LowPagedPoolCondition;
+ switch (Status)
+ {
+ case STATUS_INSUFFICIENT_RESOURCES:
+ LowMemoryCondition = 0 != FspLowMemoryCondition.Event &&
+ !!KeReadStateEvent(FspLowMemoryCondition.Event);
+ LowNonPagedPoolCondition = 0 != FspLowNonPagedPoolCondition.Event &&
+ !!KeReadStateEvent(FspLowNonPagedPoolCondition.Event);
+ LowPagedPoolCondition = 0 != FspLowPagedPoolCondition.Event &&
+ !!KeReadStateEvent(FspLowPagedPoolCondition.Event);
+ DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_TRACE_LEVEL,
+ DRIVER_NAME ": %s[%s:%d]: STATUS_INSUFFICIENT_RESOURCE (Memory=%c%c%c)\n",
+ func, file, line,
+ LowMemoryCondition ? 'M' : '-',
+ LowNonPagedPoolCondition ? 'N' : '-',
+ LowPagedPoolCondition ? 'P' : '-');
+ break;
+ default:
+ DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_TRACE_LEVEL,
+ DRIVER_NAME ": %s[%s:%d]: Status=%lx\n",
+ func, file, line,
+ Status);
+ break;
+ }
+}
+
+static PKEVENT FspOpenEvent(PWSTR Name, PHANDLE PHandle)
+{
+ UNICODE_STRING ObjectName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE Handle;
+ PKEVENT Event;
+ NTSTATUS Result;
+
+ *PHandle = 0;
+
+ RtlInitUnicodeString(&ObjectName, Name);
+ InitializeObjectAttributes(&ObjectAttributes,
+ &ObjectName, OBJ_KERNEL_HANDLE, 0, 0);
+ Result = ZwOpenEvent(&Handle,
+ EVENT_ALL_ACCESS, &ObjectAttributes);
+ if (!NT_SUCCESS(Result))
+ return 0;
+
+ Result = ObReferenceObjectByHandle(Handle,
+ 0, *ExEventObjectType, KernelMode, &Event, 0);
+ if (!NT_SUCCESS(Result))
+ {
+ ZwClose(Handle);
+ return 0;
+ }
+
+ *PHandle = Handle;
+
+ return Event;
+}
+
+static VOID FspCloseEvent(PKEVENT Event, HANDLE Handle)
+{
+ if (0 != Event)
+ ObDereferenceObject(Event);
+
+ if (0 != Handle)
+ ZwClose(Handle);
+}
+
+VOID FspTraceInitialize(VOID)
+{
+#define OPEN_EVENT(NAME) \
+ (Fsp ## NAME.Event = FspOpenEvent(L"\\KernelObjects\\" #NAME, &Fsp ## NAME.Handle))
+
+ OPEN_EVENT(LowMemoryCondition);
+ OPEN_EVENT(LowNonPagedPoolCondition);
+ OPEN_EVENT(LowPagedPoolCondition);
+
+#undef OPEN_EVENT
+}
+
+VOID FspTraceFinalize(VOID)
+{
+#define CLOSE_EVENT(NAME) \
+ (FspCloseEvent(Fsp ## NAME.Event, Fsp ## NAME.Handle), Fsp ## NAME.Event = 0, Fsp ## NAME.Handle = 0)
+
+ CLOSE_EVENT(LowMemoryCondition);
+ CLOSE_EVENT(LowNonPagedPoolCondition);
+ CLOSE_EVENT(LowPagedPoolCondition);
+
+#undef CLOSE_EVENT
+}
+#endif