[FASTFAT] Introduce a KDBG extension.
authorPierre Schweitzer <pierre@reactos.org>
Sat, 28 Apr 2018 07:34:10 +0000 (09:34 +0200)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 29 Apr 2018 10:15:11 +0000 (12:15 +0200)
This is a PoC of what it's possible to realize thanks to an
already existing hack in ntoskrnl :-).
With this extension, on the kdb:> prompt, you're able to type
in commands that will be handled by the FastFAT driver and not
by the kernel, allowing internal debug, not possible otherwise.

So far, three commands exist:
- ?fat.vols: lists all the mounted volumes by FastFAT
- ?fat.files: lists all the files on a specific volume (with their attributes)
- ?fat.setdbgfile: allows watching on specifics files lifetime

This is obviously only the begin and could be greatly improved.

For instance, this is what allowed to debug CORE-14557

drivers/filesystems/fastfat/CMakeLists.txt
drivers/filesystems/fastfat/cleanup.c
drivers/filesystems/fastfat/close.c
drivers/filesystems/fastfat/fcb.c
drivers/filesystems/fastfat/iface.c
drivers/filesystems/fastfat/kdbg.c [new file with mode: 0644]
drivers/filesystems/fastfat/vfat.h

index 087f9e3..cc69334 100644 (file)
@@ -15,6 +15,7 @@ list(APPEND SOURCE
     flush.c
     fsctl.c
     iface.c
+    kdbg.c
     misc.c
     pnp.c
     rw.c
index 580ed80..3ab4a10 100644 (file)
@@ -138,6 +138,9 @@ VfatCleanupFile(
         }
 
         FileObject->Flags |= FO_CLEANUP_COMPLETE;
+#ifdef KDBG
+        pFcb->Flags |= FCB_CLEANED_UP;
+#endif
 
         ExReleaseResourceLite(&pFcb->PagingIoResource);
         ExReleaseResourceLite(&pFcb->MainResource);
index b4e5fda..992ccac 100644 (file)
@@ -48,6 +48,9 @@ VfatCloseFile(
     }
     else
     {
+#ifdef KDBG
+        pFcb->Flags |= FCB_CLOSED;
+#endif
         vfatReleaseFCB(DeviceExt, pFcb);
     }
 
index f6734a6..33124bc 100644 (file)
 
 #define TAG_FCB 'BCFV'
 
+#ifdef KDBG
+extern UNICODE_STRING DebugFile;
+#endif
+
 /*  --------------------------------------------------------  PUBLICS  */
 
 static
@@ -267,6 +271,13 @@ VOID
 vfatDestroyFCB(
     PVFATFCB pFCB)
 {
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Destroying: %p (%wZ) %d\n", pFCB, &pFCB->PathNameU, pFCB->RefCount);
+    }
+#endif
+
     FsRtlUninitializeFileLock(&pFCB->FileLock);
     if (!vfatFCBIsRoot(pFCB) &&
         !BooleanFlagOn(pFCB->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME))
@@ -288,10 +299,28 @@ vfatFCBIsRoot(
 }
 
 VOID
+#ifndef KDBG
 vfatGrabFCB(
+#else
+_vfatGrabFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB)
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+)
 {
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Inc ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB->RefCount, pFCB->OpenHandleCount, pFCB, &pFCB->PathNameU, File, Line, Func);
+    }
+#endif
+
     ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
 
     ASSERT(pFCB != pVCB->VolumeFcb);
@@ -300,14 +329,32 @@ vfatGrabFCB(
 }
 
 VOID
+#ifndef KDBG
 vfatReleaseFCB(
+#else
+_vfatReleaseFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB)
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+)
 {
     PVFATFCB tmpFcb;
 
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Dec ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB->RefCount, pFCB->OpenHandleCount, pFCB, &pFCB->PathNameU, File, Line, Func);
+    }
+#else
     DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
            pFCB, &pFCB->PathNameU, pFCB->RefCount);
+#endif
 
     ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
 
@@ -605,6 +652,13 @@ vfatFCBInitializeCacheFromVolume(
 
     fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
 
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
+    }
+#endif
+
     newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
     if (newCCB == NULL)
     {
@@ -762,6 +816,13 @@ vfatAttachFCBToFileObject(
 
     UNREFERENCED_PARAMETER(vcb);
 
+#ifdef KDBG
+    if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
+    {
+        DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
+    }
+#endif
+
     newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
     if (newCCB == NULL)
     {
@@ -774,6 +835,11 @@ vfatAttachFCBToFileObject(
     fileObject->FsContext2 = newCCB;
     DPRINT("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU);
 
+#ifdef KDBG
+    fcb->Flags &= ~FCB_CLEANED_UP;
+    fcb->Flags &= ~FCB_CLOSED;
+#endif
+
     return STATUS_SUCCESS;
 }
 
index 02e570e..b73854d 100644 (file)
 #pragma alloc_text(INIT, DriverEntry)
 #endif
 
+#ifdef KDBG
+NTSTATUS
+NTAPI
+KdSystemDebugControl(IN ULONG Command,
+                     IN PVOID InputBuffer,
+                     IN ULONG InputBufferLength,
+                     OUT PVOID OutputBuffer,
+                     IN ULONG OutputBufferLength,
+                     IN OUT PULONG ReturnLength,
+                     IN KPROCESSOR_MODE PreviousMode);
+
+BOOLEAN
+NTAPI
+vfatKdbgHandler(
+    IN PCHAR Command,
+    IN ULONG Argc,
+    IN PCH Argv[]);
+#endif
 
 /* GLOBALS *****************************************************************/
 
@@ -137,6 +155,16 @@ DriverEntry(
     ExInitializeResourceLite(&VfatGlobalData->VolumeListLock);
     InitializeListHead(&VfatGlobalData->VolumeListHead);
     IoRegisterFileSystem(DeviceObject);
+
+#ifdef KDBG
+    {
+        BOOLEAN Registered;
+
+        Registered = KdSystemDebugControl('RbdK', vfatKdbgHandler, FALSE, NULL, 0, NULL, KernelMode);
+        DPRINT1("FastFAT KDBG extension registered: %s\n", (Registered ? "yes" : "no"));
+    }
+#endif
+
     return STATUS_SUCCESS;
 }
 
diff --git a/drivers/filesystems/fastfat/kdbg.c b/drivers/filesystems/fastfat/kdbg.c
new file mode 100644 (file)
index 0000000..b278329
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+* FILE:             drivers/filesystems/fastfat/kdbg.c
+* PURPOSE:          KDBG extension.
+* COPYRIGHT:        See COPYING in the top level directory
+* PROJECT:          ReactOS kernel
+* PROGRAMMER:       Pierre Schweitzer (pierre@reactos.org)
+*/
+
+/*  -------------------------------------------------------  INCLUDES  */
+
+#include "vfat.h"
+
+#define NDEBUG
+#include <debug.h>
+
+#include <stdio.h>
+
+/*  --------------------------------------------------------  DEFINES  */
+
+#ifdef KDBG
+UNICODE_STRING DebugFile = {0, 0, NULL};
+
+BOOLEAN
+NTAPI
+vfatKdbgHandler(
+    IN PCHAR Command,
+    IN ULONG Argc,
+    IN PCH Argv[])
+{
+    ULONG Len;
+
+    Len = strlen(Command);
+    if (Len < sizeof("?fat."))
+    {
+        return FALSE;
+    }
+
+    if (Command[0] != '?' || Command[1] != 'f' ||
+        Command[2] != 'a' || Command[3] != 't' ||
+        Command[4] != '.')
+    {
+        return FALSE;
+    }
+
+    Command += (sizeof("?fat.") - sizeof(ANSI_NULL));
+    if (strcmp(Command, "vols") == 0)
+    {
+        ULONG Count = 0;
+        PLIST_ENTRY ListEntry;
+        PDEVICE_EXTENSION DeviceExt;
+
+        for (ListEntry = VfatGlobalData->VolumeListHead.Flink;
+             ListEntry != &VfatGlobalData->VolumeListHead;
+             ListEntry = ListEntry->Flink)
+        {
+            DeviceExt = CONTAINING_RECORD(ListEntry, DEVICE_EXTENSION, VolumeListEntry);
+            DPRINT1("Volume: %p with VCB: %p\n", DeviceExt->VolumeDevice, DeviceExt);
+            ++Count;
+        }
+
+        if (Count == 0)
+        {
+            DPRINT1("No volume found\n");
+        }
+    }
+    else if (strcmp(Command, "files") == 0)
+    {
+        if (Argc != 2)
+        {
+            DPRINT1("Please provide a volume or a VCB!\n");
+        }
+        else
+        {
+            PLIST_ENTRY ListEntry;
+            PDEVICE_EXTENSION DeviceExt;
+
+            for (ListEntry = VfatGlobalData->VolumeListHead.Flink;
+                 ListEntry != &VfatGlobalData->VolumeListHead;
+                 ListEntry = ListEntry->Flink)
+            {
+                CHAR Volume[17];
+
+                DeviceExt = CONTAINING_RECORD(ListEntry, DEVICE_EXTENSION, VolumeListEntry);
+                sprintf(Volume, "%p", DeviceExt);
+                if (strcmp(Volume, Argv[1]) == 0)
+                {
+                    break;
+                }
+
+                sprintf(Volume, "%p", DeviceExt->VolumeDevice);
+                if (strcmp(Volume, Argv[1]) == 0)
+                {
+                    break;
+                }
+
+                DeviceExt = NULL;
+            }
+
+            if (DeviceExt == NULL)
+            {
+                DPRINT1("No volume %s found!\n", Argv[1]);
+            }
+            else
+            {
+                PVFATFCB Fcb;
+
+                for (ListEntry = DeviceExt->FcbListHead.Flink;
+                     ListEntry != &DeviceExt->FcbListHead;
+                     ListEntry = ListEntry->Flink)
+                {
+                    Fcb = CONTAINING_RECORD(ListEntry, VFATFCB, FcbListEntry);
+                    DPRINT1("FCB %p (ref: %d, oc: %d %s %s) for FO %p with path: %.*S\n",
+                            Fcb, Fcb->RefCount, Fcb->OpenHandleCount,
+                            ((Fcb->Flags & FCB_CLEANED_UP) ? "U" : "NU"),
+                            ((Fcb->Flags & FCB_CLOSED) ? "C" : "NC"),
+                            Fcb->FileObject, Fcb->PathNameU.Length, Fcb->PathNameU.Buffer);
+                }
+            }
+        }
+    }
+    else if (strcmp(Command, "setdbgfile") == 0)
+    {
+        if (Argc < 2)
+        {
+            if (DebugFile.Buffer != NULL)
+            {
+                ExFreePool(DebugFile.Buffer);
+                DebugFile.Length = 0;
+                DebugFile.MaximumLength = 0;
+            }
+
+            DPRINT1("Debug file reset\n");
+        }
+        else
+        {
+            NTSTATUS Status;
+            ANSI_STRING Source;
+
+            if (DebugFile.Buffer != NULL)
+            {
+                ExFreePool(DebugFile.Buffer);
+                DebugFile.Length = 0;
+                DebugFile.MaximumLength = 0;
+            }
+
+            RtlInitAnsiString(&Source, Argv[1]);
+            Status = RtlAnsiStringToUnicodeString(&DebugFile, &Source, TRUE);
+            if (NT_SUCCESS(Status))
+            {
+                DPRINT1("Debug file set to: %.*S\n", DebugFile.Length, DebugFile.Buffer);
+            }
+        }
+    }
+    else
+    {
+        DPRINT1("Unknown command: %s\n", Command);
+    }
+
+    return TRUE;
+}
+#endif
index 429120c..0de6a48 100644 (file)
@@ -409,6 +409,10 @@ extern PVFAT_GLOBAL_DATA VfatGlobalData;
 #define FCB_IS_PAGE_FILE        0x0008
 #define FCB_IS_VOLUME           0x0010
 #define FCB_IS_DIRTY            0x0020
+#ifdef KDBG
+#define FCB_CLEANED_UP          0x0040
+#define FCB_CLOSED              0x0080
+#endif
 
 #define NODE_TYPE_FCB ((CSHORT)0x0502)
 
@@ -898,14 +902,41 @@ vfatDestroyCCB(
     PVFATCCB pCcb);
 
 VOID
+#ifndef KDBG
 vfatGrabFCB(
+#else
+_vfatGrabFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB);
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+    );
 
 VOID
+#ifndef KDBG
 vfatReleaseFCB(
+#else
+_vfatReleaseFCB(
+#endif
     PDEVICE_EXTENSION pVCB,
-    PVFATFCB pFCB);
+    PVFATFCB pFCB
+#ifdef KDBG
+    ,
+    PCSTR File,
+    ULONG Line,
+    PCSTR Func
+#endif
+    );
+
+#ifdef KDBG
+#define vfatGrabFCB(v, f) _vfatGrabFCB(v, f, __FILE__, __LINE__, __FUNCTION__)
+#define vfatReleaseFCB(v, f) _vfatReleaseFCB(v, f, __FILE__, __LINE__, __FUNCTION__)
+#endif
 
 PVFATFCB
 vfatGrabFCBFromTable(