Author: ion
Date: Fri Feb 23 10:13:19 2007
New Revision: 25885
URL: 
http://svn.reactos.org/svn/reactos?rev=25885&view=rev
Log:
- Merge DbgUnLoadImageSymbols from KD branch.
- Rename LdrUnloadModule to MmUnloadSystemImage and:
  - Use MmSystemLoadLock.
  - Take into consideration the import list.
  - Honour load count.
  - Unload symbols if really unloading the image.
  - Dereference and clear imports.
  - Do proper LdrEntry cleanup.
- Stub MiDereferenceImports and MmCallDllInitialize.
- Implement MiLocateExportName and MiClearImports.
- We don't yet fully support reference counting imports...this is still TBD.
Modified:
    trunk/reactos/include/ndk/rtlfuncs.h
    trunk/reactos/lib/rtl/debug.c
    trunk/reactos/ntoskrnl/ex/sysinfo.c
    trunk/reactos/ntoskrnl/include/internal/ldr.h
    trunk/reactos/ntoskrnl/include/internal/mm.h
    trunk/reactos/ntoskrnl/io/iomgr/driver.c
    trunk/reactos/ntoskrnl/ldr/loader.c
    trunk/reactos/ntoskrnl/mm/sysldr.c
Modified: trunk/reactos/include/ndk/rtlfuncs.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/rtlfuncs.h?rev…
==============================================================================
--- trunk/reactos/include/ndk/rtlfuncs.h (original)
+++ trunk/reactos/include/ndk/rtlfuncs.h Fri Feb 23 10:13:19 2007
@@ -2514,6 +2514,14 @@
     IN ULONG ProcessId
 );
+VOID
+NTAPI
+DbgUnLoadImageSymbols(
+    IN PANSI_STRING Name,
+    IN PVOID Base,
+    IN ULONG_PTR ProcessId
+);
+
 //
 // Generic Table Functions
 //
Modified: trunk/reactos/lib/rtl/debug.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/debug.c?rev=25885&…
==============================================================================
--- trunk/reactos/lib/rtl/debug.c (original)
+++ trunk/reactos/lib/rtl/debug.c Fri Feb 23 10:13:19 2007
@@ -348,4 +348,25 @@
     DebugService2(Name, &SymbolInfo, BREAKPOINT_LOAD_SYMBOLS);
     return STATUS_SUCCESS;
 }
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+DbgUnLoadImageSymbols(IN PANSI_STRING Name,
+                      IN PVOID Base,
+                      IN ULONG_PTR ProcessId)
+{
+    KD_SYMBOLS_INFO SymbolInfo;
+
+    /* Setup the symbol data */
+    SymbolInfo.BaseOfDll = Base;
+    SymbolInfo.ProcessId = (PVOID)ProcessId;
+    SymbolInfo.CheckSum = SymbolInfo.SizeOfImage = 0;
+
+    /* Load the symbols */
+    DebugService2(Name, &SymbolInfo, BREAKPOINT_UNLOAD_SYMBOLS);
+}
+
 /* EOF */
Modified: trunk/reactos/ntoskrnl/ex/sysinfo.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/sysinfo.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/sysinfo.c (original)
+++ trunk/reactos/ntoskrnl/ex/sysinfo.c Fri Feb 23 10:13:19 2007
@@ -1495,7 +1495,7 @@
     if (!NtHeader)
     {
         /* Fail */
-        LdrUnloadModule(ModuleObject);
+        MmUnloadSystemImage(ModuleObject);
         return STATUS_INVALID_IMAGE_FORMAT;
     }
@@ -1514,7 +1514,7 @@
     ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
     /* Unload if we failed */
-    if (!NT_SUCCESS(Status)) LdrUnloadModule(ModuleObject);
+    if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
     return Status;
 }
Modified: trunk/reactos/ntoskrnl/include/internal/ldr.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ldr.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ldr.h Fri Feb 23 10:13:19 2007
@@ -6,77 +6,6 @@
 #define DRIVER_ROOT_NAME        L"\\Driver\\"
 #define FILESYSTEM_ROOT_NAME    L"\\FileSystem\\"
-extern ULONG_PTR LdrHalBase;
-
-NTSTATUS
-NTAPI
-LdrLoadInitialProcess(
-    PHANDLE ProcessHandle,
-    PHANDLE ThreadHandle
-);
-
-VOID
-NTAPI
-LdrLoadAutoConfigDrivers(VOID);
-
-NTSTATUS
-NTAPI
-LdrpMapImage(
-    HANDLE ProcessHandle,
-    HANDLE SectionHandle,
-    PVOID *ImageBase
-);
-
-NTSTATUS
-NTAPI
-LdrpLoadImage(
-    PUNICODE_STRING DriverName,
-    PVOID *ModuleBase,
-    PVOID *SectionPointer,
-    PVOID *EntryPoint,
-    PVOID *ExportDirectory
-);
-
-NTSTATUS
-NTAPI
-LdrpUnloadImage(PVOID ModuleBase);
-
-NTSTATUS
-NTAPI
-LdrpLoadAndCallImage(PUNICODE_STRING DriverName);
-
-NTSTATUS
-NTAPI
-LdrpQueryModuleInformation(
-    PVOID Buffer,
-    ULONG Size,
-    PULONG ReqSize
-);
-
-VOID
-NTAPI
-LdrInit1(VOID);
-
-VOID
-NTAPI
-LdrInitDebug(
-    PLOADER_MODULE Module,
-    PWCH Name
-);
-
-NTSTATUS
-NTAPI
-MmLoadSystemImage(IN PUNICODE_STRING FileName,
-                  IN PUNICODE_STRING NamePrefix OPTIONAL,
-                  IN PUNICODE_STRING LoadedName OPTIONAL,
-                  IN ULONG Flags,
-                  OUT PVOID *ModuleObject,
-                  OUT PVOID *ImageBaseAddress);
-
-NTSTATUS
-NTAPI
-LdrUnloadModule(PLDR_DATA_TABLE_ENTRY ModuleObject);
-
 PLDR_DATA_TABLE_ENTRY
 NTAPI
 LdrGetModuleObject(PUNICODE_STRING ModuleName);
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/mm.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/mm.h Fri Feb 23 10:13:19 2007
@@ -332,16 +332,6 @@
     BOOLEAN Dirty
 );
-
-/* FUNCTIONS */
-
-NTSTATUS
-NTAPI
-MmCheckSystemImage(
-    IN HANDLE ImageHandle,
-    IN BOOLEAN PurgeSection
-);
-
 /* aspace.c ******************************************************************/
 VOID
@@ -1429,6 +1419,8 @@
     OUT PULONG ResultLength
 );
+/* sysldr.c ******************************************************************/
+
 VOID
 NTAPI
 MiReloadBootLoadedDrivers(
@@ -1441,5 +1433,28 @@
     IN PLOADER_PARAMETER_BLOCK LoaderBlock
 );
+NTSTATUS
+NTAPI
+MmLoadSystemImage(
+    IN PUNICODE_STRING FileName,
+    IN PUNICODE_STRING NamePrefix OPTIONAL,
+    IN PUNICODE_STRING LoadedName OPTIONAL,
+    IN ULONG Flags,
+    OUT PVOID *ModuleObject,
+    OUT PVOID *ImageBaseAddress
+);
+
+NTSTATUS
+NTAPI
+MmUnloadSystemImage(
+    IN PVOID ImageHandle
+);
+
+NTSTATUS
+NTAPI
+MmCheckSystemImage(
+    IN HANDLE ImageHandle,
+    IN BOOLEAN PurgeSection
+);
 #endif
Modified: trunk/reactos/ntoskrnl/io/iomgr/driver.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/io/iomgr/driver.c…
==============================================================================
--- trunk/reactos/ntoskrnl/io/iomgr/driver.c (original)
+++ trunk/reactos/ntoskrnl/io/iomgr/driver.c Fri Feb 23 10:13:19 2007
@@ -1169,7 +1169,7 @@
       (*DriverObject->DriverUnload)(DriverObject);
    ObDereferenceObject(DriverObject);
    ObDereferenceObject(DriverObject);
-   LdrUnloadModule(ModuleObject);
+   MmUnloadSystemImage(ModuleObject);
    return STATUS_SUCCESS;
 }
@@ -1750,7 +1750,7 @@
    if (!NT_SUCCESS(Status))
    {
       DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
-      LdrUnloadModule(ModuleObject);
+      MmUnloadSystemImage(ModuleObject);
       IopFreeDeviceNode(DeviceNode);
       goto ReleaseCapturedString;
    }
Modified: trunk/reactos/ntoskrnl/ldr/loader.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ldr/loader.c?rev=…
==============================================================================
--- trunk/reactos/ntoskrnl/ldr/loader.c (original)
+++ trunk/reactos/ntoskrnl/ldr/loader.c Fri Feb 23 10:13:19 2007
@@ -133,30 +133,4 @@
     return(NULL);
 }
-//
-// Used when unloading drivers
-//
-NTSTATUS
-NTAPI
-LdrUnloadModule ( PLDR_DATA_TABLE_ENTRY ModuleObject )
-{
-    KIRQL Irql;
-
-    /* Remove the module from the module list */
-    KeAcquireSpinLock(&PsLoadedModuleSpinLock,&Irql);
-    RemoveEntryList(&ModuleObject->InLoadOrderLinks);
-    KeReleaseSpinLock(&PsLoadedModuleSpinLock, Irql);
-
-    /* Hook for KDB on unloading a driver. */
-    KDB_UNLOADDRIVER_HOOK(ModuleObject);
-
-    /* Free module section */
-    //  MmFreeSection(ModuleObject->DllBase);
-
-    ExFreePool(ModuleObject->FullDllName.Buffer);
-    ExFreePool(ModuleObject);
-
-    return(STATUS_SUCCESS);
-}
-
 /* EOF */
Modified: trunk/reactos/ntoskrnl/mm/sysldr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/sysldr.c?rev=2…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/sysldr.c (original)
+++ trunk/reactos/ntoskrnl/mm/sysldr.c Fri Feb 23 10:13:19 2007
@@ -20,6 +20,135 @@
 KMUTANT MmSystemLoadLock;
 /* FUNCTIONS *****************************************************************/
+
+NTSTATUS
+NTAPI
+MiDereferenceImports(IN PLOAD_IMPORTS ImportList)
+{
+    /* Check if there's no imports or if we're a boot driver */
+    if ((ImportList == (PVOID)-1) || (ImportList == (PVOID)-2))
+    {
+        /* Then there's nothing to do */
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, FIXME */
+    DPRINT1("Imports not dereferenced!\n");
+    return STATUS_UNSUCCESSFUL;
+}
+
+VOID
+NTAPI
+MiClearImports(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
+{
+    PAGED_CODE();
+
+    /* Check if there's no imports or we're a boot driver or only one entry */
+    if ((LdrEntry->LoadedImports == (PVOID)-1) ||
+        (LdrEntry->LoadedImports == (PVOID)-2) ||
+        ((ULONG_PTR)LdrEntry->LoadedImports & 1))
+    {
+        /* Nothing to do */
+        return;
+    }
+
+    /* Otherwise, free the import list */
+    ExFreePool(LdrEntry->LoadedImports);
+}
+
+PVOID
+NTAPI
+MiLocateExportName(IN PVOID DllBase,
+                   IN PCHAR ExportName)
+{
+    PULONG NameTable;
+    PUSHORT OrdinalTable;
+    PIMAGE_EXPORT_DIRECTORY ExportDirectory;
+    LONG Low = 0, Mid = 0, High, Ret;
+    USHORT Ordinal;
+    PVOID Function;
+    ULONG ExportSize;
+    PULONG ExportTable;
+    PAGED_CODE();
+
+    /* Get the export directory */
+    ExportDirectory = RtlImageDirectoryEntryToData(DllBase,
+                                                   TRUE,
+                                                   IMAGE_DIRECTORY_ENTRY_EXPORT,
+                                                   &ExportSize);
+    if (!ExportDirectory) return NULL;
+
+    /* Setup name tables */
+    NameTable = (PULONG)((ULONG_PTR)DllBase +
+                         ExportDirectory->AddressOfNames);
+    OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
+                             ExportDirectory->AddressOfNameOrdinals);
+
+    /* Do a binary search */
+    High = ExportDirectory->NumberOfNames - 1;
+    while (High >= Low)
+    {
+        /* Get new middle value */
+        Mid = (Low + High) >> 1;
+
+        /* Compare name */
+        Ret = strcmp(ExportName, (PCHAR)DllBase + NameTable[Mid]);
+        if (Ret < 0)
+        {
+            /* Update high */
+            High = Mid - 1;
+        }
+        else if (Ret > 0)
+        {
+            /* Update low */
+            Low = Mid + 1;
+        }
+        else
+        {
+            /* We got it */
+            break;
+        }
+    }
+
+    /* Check if we couldn't find it */
+    if (High < Low) return NULL;
+
+    /* Otherwise, this is the ordinal */
+    Ordinal = OrdinalTable[Mid];
+
+    /* Resolve the address and write it */
+    ExportTable = (PULONG)((ULONG_PTR)DllBase +
+                           ExportDirectory->AddressOfFunctions);
+    Function = (PVOID)((ULONG_PTR)DllBase + ExportTable[Ordinal]);
+
+    /* Check if the function is actually a forwarder */
+    if (((ULONG_PTR)Function > (ULONG_PTR)ExportDirectory) &&
+        ((ULONG_PTR)Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
+    {
+        /* It is, fail */
+        return NULL;
+    }
+
+    /* We found it */
+    return Function;
+}
+
+NTSTATUS
+NTAPI
+MmCallDllInitialize(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
+                    IN PLIST_ENTRY ListHead)
+{
+    PMM_DLL_INITIALIZE DllInit;
+
+    /* Try to see if the image exports a DllInitialize routine */
+    DllInit = (PMM_DLL_INITIALIZE)MiLocateExportName(LdrEntry->DllBase,
+                                                     "DllInitialize");
+    if (!DllInit) return STATUS_SUCCESS;
+
+    /* FIXME: TODO */
+    DPRINT1("DllInitialize not called!\n");
+    return STATUS_UNSUCCESSFUL;
+}
 VOID
 NTAPI
@@ -321,6 +450,92 @@
 NTSTATUS
 NTAPI
+MmUnloadSystemImage(IN PVOID ImageHandle)
+{
+    PLDR_DATA_TABLE_ENTRY LdrEntry = ImageHandle;
+    PVOID BaseAddress = LdrEntry->DllBase;
+    NTSTATUS Status;
+    ANSI_STRING TempName;
+    BOOLEAN HadEntry = FALSE;
+
+    /* Acquire the loader lock */
+    KeEnterCriticalRegion();
+    KeWaitForSingleObject(&MmSystemLoadLock,
+                          WrVirtualMemory,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    /* Check if this driver was loaded at boot and didn't get imports parsed */
+    if (LdrEntry->LoadedImports == (PVOID)-1) goto Done;
+
+    /* We should still be alive */
+    ASSERT(LdrEntry->LoadCount != 0);
+    LdrEntry->LoadCount--;
+
+    /* Check if we're still loaded */
+    if (LdrEntry->LoadCount) goto Done;
+
+    /* We should cleanup... are symbols loaded */
+    if (LdrEntry->Flags & LDRP_DEBUG_SYMBOLS_LOADED)
+    {
+        /* Create the ANSI name */
+        Status = RtlUnicodeStringToAnsiString(&TempName,
+                                              &LdrEntry->BaseDllName,
+                                              TRUE);
+        if (NT_SUCCESS(Status))
+        {
+            /* Unload the symbols */
+            DbgUnLoadImageSymbols(&TempName, BaseAddress, -1);
+            RtlFreeAnsiString(&TempName);
+        }
+    }
+
+    /* FIXME: Free the driver */
+    //MmFreeSection(LdrEntry->DllBase);
+
+    /* Check if we're linked in */
+    if (LdrEntry->InLoadOrderLinks.Flink)
+    {
+        /* Remove us */
+        MiProcessLoaderEntry(LdrEntry, FALSE);
+        HadEntry = TRUE;
+    }
+
+    /* Dereference and clear the imports */
+    MiDereferenceImports(LdrEntry->LoadedImports);
+    MiClearImports(LdrEntry);
+
+    /* Check if the entry needs to go away */
+    if (HadEntry)
+    {
+        /* Check if it had a name */
+        if (LdrEntry->FullDllName.Buffer)
+        {
+            /* Free it */
+            ExFreePool(LdrEntry->FullDllName.Buffer);
+        }
+
+        /* Check if we had a section */
+        if (LdrEntry->SectionPointer)
+        {
+            /* Dereference it */
+            ObDereferenceObject(LdrEntry->SectionPointer);
+        }
+
+        /* Free the entry */
+        ExFreePool(LdrEntry);
+    }
+
+    /* Release the system lock and return */
+Done:
+    KeReleaseMutant(&MmSystemLoadLock, 1, FALSE, FALSE);
+    KeLeaveCriticalRegion();
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
 MiResolveImageReferences(IN PVOID ImageBase,
                          IN PUNICODE_STRING ImageFileDirectory,
                          IN PUNICODE_STRING NamePrefix OPTIONAL,
@@ -406,8 +621,7 @@
         if ((GdiLink) && (NormalLink))
         {
             /* It's not, it's importing stuff it shouldn't be! */
-            DPRINT1("Invalid driver!\n");
-            //MiDereferenceImports(LoadedImports);
+            MiDereferenceImports(LoadedImports);
             if (LoadedImports) ExFreePool(LoadedImports);
             return STATUS_PROCEDURE_NOT_FOUND;
         }
@@ -432,7 +646,7 @@
         if (!NT_SUCCESS(Status))
         {
             /* Failed */
-            //MiDereferenceImports(LoadedImports);
+            MiDereferenceImports(LoadedImports);
             if (LoadedImports) ExFreePool(LoadedImports);
             return Status;
         }
@@ -517,7 +731,6 @@
                 else
                 {
                     /* Fill out the information for the error */
-                    DPRINT1("Failed to import: %S\n", DllName.Buffer);
                     *MissingDriver = DllName.Buffer;
                     *(PULONG)MissingDriver |= 1;
                     *MissingApi = NULL;
@@ -539,7 +752,6 @@
                 ASSERT(DllBase = DllEntry->DllBase);
                 /* Call the initialization routines */
-#if 0
                 Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
                 if (!NT_SUCCESS(Status))
                 {
@@ -548,16 +760,14 @@
                     while (TRUE);
                     Loaded = FALSE;
                 }
-#endif
             }
             /* Check if we failed by here */
             if (!NT_SUCCESS(Status))
             {
                 /* Cleanup and return */
-                DPRINT1("Failed loading import\n");
                 RtlFreeUnicodeString(&NameString);
-                //MiDereferenceImports(LoadedImports);
+                MiDereferenceImports(LoadedImports);
                 if (LoadedImports) ExFreePool(LoadedImports);
                 return Status;
             }
@@ -590,8 +800,7 @@
         if (!ExportDirectory)
         {
             /* Cleanup and return */
-            DPRINT1("Invalid driver: %wZ\n", &LdrEntry->BaseDllName);
-            //MiDereferenceImports(LoadedImports);
+            MiDereferenceImports(LoadedImports);
             if (LoadedImports) ExFreePool(LoadedImports);
             return STATUS_DRIVER_ENTRYPOINT_NOT_FOUND;
         }
@@ -620,7 +829,7 @@
                 if (!NT_SUCCESS(Status))
                 {
                     /* Cleanup and return */
-                    //MiDereferenceImports(LoadedImports);
+                    MiDereferenceImports(LoadedImports);
                     if (LoadedImports) ExFreePool(LoadedImports);
                     return Status;
                 }