- 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.

svn path=/trunk/; revision=25885
This commit is contained in:
Alex Ionescu 2007-02-23 07:13:19 +00:00
parent bae0317c7c
commit 86c4790af3
8 changed files with 278 additions and 122 deletions

View file

@ -2514,6 +2514,14 @@ DbgLoadImageSymbols(
IN ULONG ProcessId
);
VOID
NTAPI
DbgUnLoadImageSymbols(
IN PANSI_STRING Name,
IN PVOID Base,
IN ULONG_PTR ProcessId
);
//
// Generic Table Functions
//

View file

@ -348,4 +348,25 @@ DbgLoadImageSymbols(IN PANSI_STRING Name,
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 */

View file

@ -1495,7 +1495,7 @@ SSI_DEF(SystemExtendServiceTableInformation)
if (!NtHeader)
{
/* Fail */
LdrUnloadModule(ModuleObject);
MmUnloadSystemImage(ModuleObject);
return STATUS_INVALID_IMAGE_FORMAT;
}
@ -1514,7 +1514,7 @@ SSI_DEF(SystemExtendServiceTableInformation)
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
/* Unload if we failed */
if (!NT_SUCCESS(Status)) LdrUnloadModule(ModuleObject);
if (!NT_SUCCESS(Status)) MmUnloadSystemImage(ModuleObject);
return Status;
}

View file

@ -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);

View file

@ -332,16 +332,6 @@ typedef VOID
BOOLEAN Dirty
);
/* FUNCTIONS */
NTSTATUS
NTAPI
MmCheckSystemImage(
IN HANDLE ImageHandle,
IN BOOLEAN PurgeSection
);
/* aspace.c ******************************************************************/
VOID
@ -1429,6 +1419,8 @@ MiQueryVirtualMemory(
OUT PULONG ResultLength
);
/* sysldr.c ******************************************************************/
VOID
NTAPI
MiReloadBootLoadedDrivers(
@ -1441,5 +1433,28 @@ MiInitializeLoadedModuleList(
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

View file

@ -1169,7 +1169,7 @@ IopUnloadDriver(PUNICODE_STRING DriverServiceName, BOOLEAN UnloadPnpDrivers)
(*DriverObject->DriverUnload)(DriverObject);
ObDereferenceObject(DriverObject);
ObDereferenceObject(DriverObject);
LdrUnloadModule(ModuleObject);
MmUnloadSystemImage(ModuleObject);
return STATUS_SUCCESS;
}
@ -1750,7 +1750,7 @@ NtLoadDriver(IN PUNICODE_STRING DriverServiceName)
if (!NT_SUCCESS(Status))
{
DPRINT("IopInitializeDriver() failed (Status %lx)\n", Status);
LdrUnloadModule(ModuleObject);
MmUnloadSystemImage(ModuleObject);
IopFreeDeviceNode(DeviceNode);
goto ReleaseCapturedString;
}

View file

@ -133,30 +133,4 @@ LdrGetModuleObject ( PUNICODE_STRING ModuleName )
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 */

View file

@ -21,6 +21,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
MiProcessLoaderEntry(IN PLDR_DATA_TABLE_ENTRY LdrEntry,
@ -319,6 +448,92 @@ MiSnapThunk(IN PVOID DllBase,
return Status;
}
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,
@ -406,8 +621,7 @@ MiResolveImageReferences(IN PVOID ImageBase,
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 @@ MiResolveImageReferences(IN PVOID ImageBase,
if (!NT_SUCCESS(Status))
{
/* Failed */
//MiDereferenceImports(LoadedImports);
MiDereferenceImports(LoadedImports);
if (LoadedImports) ExFreePool(LoadedImports);
return Status;
}
@ -517,7 +731,6 @@ CheckDllState:
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 @@ CheckDllState:
ASSERT(DllBase = DllEntry->DllBase);
/* Call the initialization routines */
#if 0
Status = MmCallDllInitialize(DllEntry, &PsLoadedModuleList);
if (!NT_SUCCESS(Status))
{
@ -548,16 +760,14 @@ CheckDllState:
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 @@ CheckDllState:
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 @@ CheckDllState:
if (!NT_SUCCESS(Status))
{
/* Cleanup and return */
//MiDereferenceImports(LoadedImports);
MiDereferenceImports(LoadedImports);
if (LoadedImports) ExFreePool(LoadedImports);
return Status;
}