2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User Mode Library
4 * FILE: dll/ntdll/ldr/ldrapi.c
5 * PURPOSE: PE Loader Public APIs
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Aleksey Bragin (aleksey@reactos.org)
10 /* INCLUDES *****************************************************************/
16 /* GLOBALS *******************************************************************/
18 LIST_ENTRY LdrpUnloadHead
;
19 LONG LdrpLoaderLockAcquisitonCount
;
20 BOOLEAN LdrpShowRecursiveLoads
, LdrpBreakOnRecursiveDllLoads
;
21 UNICODE_STRING LdrApiDefaultExtension
= RTL_CONSTANT_STRING(L
".DLL");
23 /* FUNCTIONS *****************************************************************/
29 /* Generate a cookie */
30 return (((ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) |
31 _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
39 LdrUnlockLoaderLock(IN ULONG Flags
,
40 IN ULONG Cookie OPTIONAL
)
42 NTSTATUS Status
= STATUS_SUCCESS
;
44 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
46 /* Check for valid flags */
47 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
49 /* Flags are invalid, check how to fail */
50 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
52 /* The caller wants us to raise status */
53 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
56 /* A normal failure */
57 return STATUS_INVALID_PARAMETER_1
;
60 /* If we don't have a cookie, just return */
61 if (!Cookie
) return STATUS_SUCCESS
;
63 /* Validate the cookie */
64 if ((Cookie
& 0xF0000000) ||
65 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
67 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
69 /* Invalid cookie, check how to fail */
70 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
72 /* The caller wants us to raise status */
73 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
76 /* A normal failure */
77 return STATUS_INVALID_PARAMETER_2
;
80 /* Ready to release the lock */
81 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
83 /* Do a direct leave */
84 RtlLeaveCriticalSection(&LdrpLoaderLock
);
88 /* Wrap this in SEH, since we're not supposed to raise */
92 RtlLeaveCriticalSection(&LdrpLoaderLock
);
94 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
96 /* We should use the LDR Filter instead */
97 Status
= _SEH2_GetExceptionCode();
111 LdrLockLoaderLock(IN ULONG Flags
,
112 OUT PULONG Disposition OPTIONAL
,
113 OUT PULONG_PTR Cookie OPTIONAL
)
115 NTSTATUS Status
= STATUS_SUCCESS
;
116 BOOLEAN InInit
= LdrpInLdrInit
;
118 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
120 /* Zero out the outputs */
121 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
122 if (Cookie
) *Cookie
= 0;
124 /* Validate the flags */
125 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
126 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
128 /* Flags are invalid, check how to fail */
129 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
131 /* The caller wants us to raise status */
132 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
135 /* A normal failure */
136 return STATUS_INVALID_PARAMETER_1
;
139 /* Make sure we got a cookie */
142 /* No cookie check how to fail */
143 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
145 /* The caller wants us to raise status */
146 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
149 /* A normal failure */
150 return STATUS_INVALID_PARAMETER_3
;
153 /* Do or Do Not. There is no Try */
154 ASSERT((Disposition
!= NULL
) || !(Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
));
156 /* If the flag is set, make sure we have a valid pointer to use */
157 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
159 /* No pointer to return the data to */
160 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
162 /* The caller wants us to raise status */
163 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
167 return STATUS_INVALID_PARAMETER_2
;
170 /* Return now if we are in the init phase */
171 if (InInit
) return STATUS_SUCCESS
;
173 /* Check what locking semantic to use */
174 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
176 /* Check if we should enter or simply try */
177 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
180 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
183 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
188 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
189 *Cookie
= LdrpMakeCookie();
195 RtlEnterCriticalSection(&LdrpLoaderLock
);
197 /* See if result was requested */
198 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
199 *Cookie
= LdrpMakeCookie();
204 /* Wrap this in SEH, since we're not supposed to raise */
207 /* Check if we should enter or simply try */
208 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
211 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
214 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
219 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
220 *Cookie
= LdrpMakeCookie();
226 RtlEnterCriticalSection(&LdrpLoaderLock
);
228 /* See if result was requested */
229 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
230 *Cookie
= LdrpMakeCookie();
233 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
235 /* We should use the LDR Filter instead */
236 Status
= _SEH2_GetExceptionCode();
250 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
251 IN PULONG DllCharacteristics OPTIONAL
,
252 IN PUNICODE_STRING DllName
,
253 OUT PVOID
*BaseAddress
)
255 WCHAR StringBuffer
[MAX_PATH
];
256 UNICODE_STRING DllString1
, DllString2
;
257 BOOLEAN RedirectedDll
= FALSE
;
260 PUNICODE_STRING OldTldDll
;
261 PTEB Teb
= NtCurrentTeb();
263 /* Initialize the strings */
264 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
265 DllString1
.Buffer
= StringBuffer
;
266 DllString1
.Length
= 0;
267 DllString1
.MaximumLength
= sizeof(StringBuffer
);
269 /* Check if the SxS Assemblies specify another file */
270 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
272 &LdrApiDefaultExtension
,
281 if (NT_SUCCESS(Status
))
284 RedirectedDll
= TRUE
;
286 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
288 /* Unrecoverable SxS failure; did we get a string? */
289 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
293 /* Lock the loader lock */
294 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
296 /* Check if there's a TLD DLL being loaded */
297 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
300 /* This is a recursive load, do something about it? */
301 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
303 /* Print out debug messages */
304 DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
305 Teb
->RealClientId
.UniqueProcess
,
306 Teb
->RealClientId
.UniqueThread
);
307 DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n",
308 Teb
->RealClientId
.UniqueProcess
,
309 Teb
->RealClientId
.UniqueThread
,
311 DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n",
312 Teb
->RealClientId
.UniqueProcess
,
313 Teb
->RealClientId
.UniqueThread
,
316 /* Was it initializing too? */
317 if (!LdrpCurrentDllInitializer
)
319 DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
320 Teb
->RealClientId
.UniqueProcess
,
321 Teb
->RealClientId
.UniqueThread
);
325 DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n",
326 Teb
->ClientId
.UniqueProcess
,
327 Teb
->ClientId
.UniqueThread
,
328 &LdrpCurrentDllInitializer
->BaseDllName
);
333 /* Set this one as the TLD DLL being loaded*/
334 LdrpTopLevelDllBeingLoaded
= DllName
;
337 Status
= LdrpLoadDll(RedirectedDll
,
343 if (NT_SUCCESS(Status
))
345 Status
= STATUS_SUCCESS
;
347 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
348 (Status
!= STATUS_DLL_NOT_FOUND
) &&
349 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
350 (Status
!= STATUS_DLL_INIT_FAILED
))
352 // 85 == DPFLTR_LDR_ID;
354 DPFLTR_WARNING_LEVEL
,
355 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
361 /* Restore the old TLD DLL */
362 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
364 /* Release the lock */
365 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
367 /* Do we have a redirect string? */
368 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
379 LdrFindEntryForAddress(PVOID Address
,
380 PLDR_DATA_TABLE_ENTRY
*Module
)
382 PLIST_ENTRY ListHead
, NextEntry
;
383 PLDR_DATA_TABLE_ENTRY LdrEntry
;
384 PIMAGE_NT_HEADERS NtHeader
;
385 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
386 ULONG_PTR DllBase
, DllEnd
;
388 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
391 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
393 /* Get the current entry */
394 LdrEntry
= Ldr
->EntryInProgress
;
397 /* Get the NT Headers */
398 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
401 /* Get the Image Base */
402 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
403 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
405 /* Check if they match */
406 if (((ULONG_PTR
)Address
>= DllBase
) &&
407 ((ULONG_PTR
)Address
< DllEnd
))
411 return STATUS_SUCCESS
;
416 /* Loop the module list */
417 ListHead
= &Ldr
->InMemoryOrderModuleList
;
418 NextEntry
= ListHead
->Flink
;
419 while (NextEntry
!= ListHead
)
421 /* Get the entry and NT Headers */
422 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
423 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
426 /* Get the Image Base */
427 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
428 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
430 /* Check if they match */
431 if (((ULONG_PTR
)Address
>= DllBase
) &&
432 ((ULONG_PTR
)Address
< DllEnd
))
436 return STATUS_SUCCESS
;
440 NextEntry
= NextEntry
->Flink
;
445 // 85 == DPFLTR_LDR_ID;
446 DbgPrintEx(85, DPFLTR_WARNING_LEVEL
, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__
, STATUS_NO_MORE_ENTRIES
);
447 return STATUS_NO_MORE_ENTRIES
;
455 LdrGetDllHandleEx(IN ULONG Flags
,
456 IN PWSTR DllPath OPTIONAL
,
457 IN PULONG DllCharacteristics OPTIONAL
,
458 IN PUNICODE_STRING DllName
,
459 OUT PVOID
*DllHandle OPTIONAL
)
462 PLDR_DATA_TABLE_ENTRY LdrEntry
;
463 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
464 PUNICODE_STRING pRedirectName
, CompareName
;
466 BOOLEAN Locked
, RedirectedDll
;
468 ULONG LoadFlag
, Length
;
470 /* Initialize the strings */
471 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
472 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
473 RedirectName
= *DllName
;
474 pRedirectName
= &RedirectName
;
476 /* Initialize state */
477 RedirectedDll
= Locked
= FALSE
;
481 /* Clear the handle */
482 if (DllHandle
) *DllHandle
= NULL
;
484 /* Check for a valid flag combination */
485 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
486 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
488 DPRINT1("Flags are invalid or no DllHandle given\n");
489 Status
= STATUS_INVALID_PARAMETER
;
493 /* If not initializing */
496 /* Acquire the lock */
497 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
498 if (!NT_SUCCESS(Status
)) goto Quickie
;
500 /* Remember we own it */
504 /* Check if the SxS Assemblies specify another file */
505 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
507 &LdrApiDefaultExtension
,
516 if (NT_SUCCESS(Status
))
519 RedirectedDll
= TRUE
;
521 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
523 /* Unrecoverable SxS failure; */
528 ASSERT(pRedirectName
== &RedirectName
);
531 /* Set default failure code */
532 Status
= STATUS_DLL_NOT_FOUND
;
534 /* Use the cache if we can */
535 if (LdrpGetModuleHandleCache
)
537 /* Check if we were redirected */
541 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
546 /* Use the right name */
547 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
552 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
557 /* Use the right name */
558 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
561 /* Check if the name matches */
562 if (RtlEqualUnicodeString(pRedirectName
,
567 LdrEntry
= LdrpGetModuleHandleCache
;
570 Status
= STATUS_SUCCESS
;
576 /* Find the name without the extension */
577 p1
= pRedirectName
->Buffer
;
579 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
586 else if (*p1
== L
'\\')
592 /* Check if no extension was found or if we got a slash */
593 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
595 /* Check that we have space to add one */
596 Length
= pRedirectName
->Length
+
597 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
598 if (Length
>= UNICODE_STRING_MAX_BYTES
)
600 /* No space to add the extension */
601 Status
= STATUS_NAME_TOO_LONG
;
605 /* Setup the string */
606 RawDllName
.MaximumLength
= Length
;
607 ASSERT(Length
>= sizeof(UNICODE_NULL
));
608 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
610 RawDllName
.MaximumLength
);
611 if (!RawDllName
.Buffer
)
613 Status
= STATUS_NO_MEMORY
;
617 /* Copy the string and add extension */
618 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
619 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
623 /* Check if there's something in the name */
624 Length
= pRedirectName
->Length
;
627 /* Check and remove trailing period */
628 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
630 /* Decrease the size */
631 pRedirectName
->Length
-= sizeof(WCHAR
);
635 /* Setup the string */
636 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
637 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
639 RawDllName
.MaximumLength
);
640 if (!RawDllName
.Buffer
)
642 Status
= STATUS_NO_MEMORY
;
646 /* Copy the string */
647 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
650 /* Display debug string */
653 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
655 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
659 if (LdrpCheckForLoadedDll(DllPath
,
661 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
665 /* Update cached entry */
666 LdrpGetModuleHandleCache
= LdrEntry
;
669 Status
= STATUS_SUCCESS
;
673 /* Make sure to NULL this */
677 /* The success path must have a valid loader entry */
678 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
680 /* Check if we got an entry and success */
681 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
682 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
684 /* Check if the DLL is locked */
685 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
686 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
688 /* Check what to do with the load count */
689 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
692 LdrEntry
->LoadCount
= 0xFFFF;
693 LoadFlag
= LDRP_UPDATE_PIN
;
697 /* Increase the load count */
698 LdrEntry
->LoadCount
++;
699 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
702 /* Update the load count now */
703 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
704 LdrpClearLoadInProgress();
707 /* Check if the caller is requesting the handle */
708 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
711 /* Free string if needed */
712 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
714 /* Free the raw DLL Name if needed */
715 if (RawDllName
.Buffer
)
717 /* Free the heap-allocated buffer */
718 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
719 RawDllName
.Buffer
= NULL
;
725 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
738 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
739 IN PULONG DllCharacteristics OPTIONAL
,
740 IN PUNICODE_STRING DllName
,
741 OUT PVOID
*DllHandle
)
743 /* Call the newer API */
744 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
756 LdrGetProcedureAddress(IN PVOID BaseAddress
,
757 IN PANSI_STRING Name
,
759 OUT PVOID
*ProcedureAddress
)
761 /* Call the internal routine and tell it to execute DllInit */
762 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
770 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
771 IN PLDR_CALLBACK Callback
,
772 IN PVOID CallbackContext
,
773 OUT PUSHORT ImageCharacteristics
)
775 FILE_STANDARD_INFORMATION FileStandardInfo
;
776 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
777 PIMAGE_SECTION_HEADER LastSection
;
778 IO_STATUS_BLOCK IoStatusBlock
;
779 PIMAGE_NT_HEADERS NtHeader
;
780 HANDLE SectionHandle
;
783 BOOLEAN Result
, NoActualCheck
;
787 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
789 /* If the handle has the magic KnownDll flag, skip actual checksums */
790 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
792 /* Create the section */
793 Status
= NtCreateSection(&SectionHandle
,
800 if (!NT_SUCCESS(Status
))
802 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
806 /* Map the section */
809 Status
= NtMapViewOfSection(SectionHandle
,
819 if (!NT_SUCCESS(Status
))
821 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
822 NtClose(SectionHandle
);
826 /* Get the file information */
827 Status
= NtQueryInformationFile(FileHandle
,
830 sizeof(FILE_STANDARD_INFORMATION
),
831 FileStandardInformation
);
832 if (!NT_SUCCESS(Status
))
834 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
835 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
836 NtClose(SectionHandle
);
840 /* Protect with SEH */
843 /* Check if this is the KnownDll hack */
846 /* Don't actually do it */
851 /* Verify the checksum */
852 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
853 FileStandardInfo
.EndOfFile
.LowPart
,
854 FileStandardInfo
.EndOfFile
.LowPart
);
857 /* Check if a callback was supplied */
858 if ((Result
) && (Callback
))
860 /* Get the NT Header */
861 NtHeader
= RtlImageNtHeader(ViewBase
);
863 /* Check if caller requested this back */
864 if (ImageCharacteristics
)
866 /* Return to caller */
867 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
870 /* Get the Import Directory Data */
871 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
873 IMAGE_DIRECTORY_ENTRY_IMPORT
,
876 /* Make sure there is one */
879 /* Loop the imports */
880 while (ImportData
->Name
)
883 ImportName
= RtlImageRvaToVa(NtHeader
,
888 /* Notify the callback */
889 Callback(CallbackContext
, ImportName
);
895 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
897 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
902 /* Unmap file and close handle */
903 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
904 NtClose(SectionHandle
);
907 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
912 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
914 IN PRTL_PROCESS_MODULES ModuleInformation
,
916 OUT PULONG ReturnedSize OPTIONAL
)
918 PLIST_ENTRY ModuleListHead
, InitListHead
;
919 PLIST_ENTRY Entry
, InitEntry
;
920 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
921 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
922 NTSTATUS Status
= STATUS_SUCCESS
;
923 ULONG UsedSize
= sizeof(ULONG
);
924 ANSI_STRING AnsiString
;
927 DPRINT("LdrQueryProcessModuleInformation() called\n");
929 /* Acquire loader lock */
930 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
932 /* Check if we were given enough space */
935 Status
= STATUS_INFO_LENGTH_MISMATCH
;
939 ModuleInformation
->NumberOfModules
= 0;
940 ModulePtr
= &ModuleInformation
->Modules
[0];
941 Status
= STATUS_SUCCESS
;
944 /* Traverse the list of modules */
947 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
948 Entry
= ModuleListHead
->Flink
;
950 while (Entry
!= ModuleListHead
)
952 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
954 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
956 /* Increase the used size */
957 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
961 Status
= STATUS_INFO_LENGTH_MISMATCH
;
965 ModulePtr
->ImageBase
= Module
->DllBase
;
966 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
967 ModulePtr
->Flags
= Module
->Flags
;
968 ModulePtr
->LoadCount
= Module
->LoadCount
;
969 ModulePtr
->MappedBase
= NULL
;
970 ModulePtr
->InitOrderIndex
= 0;
971 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
973 /* Now get init order index by traversing init list */
974 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
975 InitEntry
= InitListHead
->Flink
;
977 while (InitEntry
!= InitListHead
)
979 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
981 /* Increase the index */
982 ModulePtr
->InitOrderIndex
++;
984 /* Quit the loop if our module is found */
985 if (InitModule
== Module
) break;
987 /* Advance to the next entry */
988 InitEntry
= InitEntry
->Flink
;
991 /* Prepare ANSI string with the module's name */
992 AnsiString
.Length
= 0;
993 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
994 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
995 RtlUnicodeStringToAnsiString(&AnsiString
,
996 &Module
->FullDllName
,
999 /* Calculate OffsetToFileName field */
1000 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1002 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1004 ModulePtr
->OffsetToFileName
= 0;
1006 /* Advance to the next module in the output list */
1009 /* Increase number of modules */
1010 if (ModuleInformation
)
1011 ModuleInformation
->NumberOfModules
++;
1014 /* Go to the next entry in the modules list */
1015 Entry
= Entry
->Flink
;
1018 /* Set returned size if it was provided */
1020 *ReturnedSize
= UsedSize
;
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1024 /* Ignoring the exception */
1027 /* Release the lock */
1028 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1030 DPRINT("LdrQueryProcessModuleInformation() done\n");
1040 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
1042 OUT PULONG ReturnedSize OPTIONAL
)
1044 /* Call Ex version of the API */
1045 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1053 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag
,
1054 IN PLDR_ENUM_CALLBACK EnumProc
,
1057 PLIST_ENTRY ListHead
, ListEntry
;
1058 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1061 BOOLEAN Stop
= FALSE
;
1063 /* Check parameters */
1064 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1066 /* Acquire the loader lock */
1067 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1068 if (!NT_SUCCESS(Status
)) return Status
;
1070 /* Loop all the modules and call enum proc */
1071 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1072 ListEntry
= ListHead
->Flink
;
1073 while (ListHead
!= ListEntry
)
1076 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1078 /* Call the enumeration proc inside SEH */
1081 EnumProc(LdrEntry
, Context
, &Stop
);
1083 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1085 /* Ignoring the exception */
1088 /* Break if we were asked to stop enumeration */
1091 /* Release loader lock */
1092 Status
= LdrUnlockLoaderLock(0, Cookie
);
1094 /* Reset any successful status to STATUS_SUCCESS, but leave
1095 failure to the caller */
1096 if (NT_SUCCESS(Status
))
1097 Status
= STATUS_SUCCESS
;
1099 /* Return any possible failure status */
1103 /* Advance to the next module */
1104 ListEntry
= ListEntry
->Flink
;
1107 /* Release loader lock, it must succeed this time */
1108 Status
= LdrUnlockLoaderLock(0, Cookie
);
1109 ASSERT(NT_SUCCESS(Status
));
1111 /* Return success */
1112 return STATUS_SUCCESS
;
1120 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1122 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1126 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1128 /* Don't do it during shutdown */
1129 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1131 /* Check if we should grab the lock */
1136 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1137 if (!NT_SUCCESS(Status
)) return Status
;
1141 /* Make sure the DLL is valid and get its entry */
1142 Status
= STATUS_DLL_NOT_FOUND
;
1143 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1145 /* Get if it has a TLS slot */
1146 if (!LdrEntry
->TlsIndex
)
1148 /* It doesn't, so you're allowed to call this */
1149 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1150 Status
= STATUS_SUCCESS
;
1154 /* Check if the lock was held */
1158 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1161 /* Return the status */
1170 LdrAddRefDll(IN ULONG Flags
,
1171 IN PVOID BaseAddress
)
1173 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1174 NTSTATUS Status
= STATUS_SUCCESS
;
1176 BOOLEAN Locked
= FALSE
;
1178 /* Check for invalid flags */
1179 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1181 /* Fail with invalid parameter status if so */
1182 Status
= STATUS_INVALID_PARAMETER
;
1186 /* Acquire the loader lock if not in init phase */
1189 /* Acquire the lock */
1190 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1191 if (!NT_SUCCESS(Status
)) goto quickie
;
1195 /* Get this module's data table entry */
1196 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1200 /* Shouldn't happen */
1201 Status
= STATUS_INTERNAL_ERROR
;
1205 /* If this is not a pinned module */
1206 if (LdrEntry
->LoadCount
!= 0xFFFF)
1208 /* Update its load count */
1209 if (Flags
& LDR_ADDREF_DLL_PIN
)
1211 /* Pin it by setting load count to -1 */
1212 LdrEntry
->LoadCount
= 0xFFFF;
1213 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1217 /* Increase its load count by one */
1218 LdrEntry
->LoadCount
++;
1219 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1222 /* Clear load in progress */
1223 LdrpClearLoadInProgress();
1228 /* There was an error getting this module's handle, return invalid param status */
1229 Status
= STATUS_INVALID_PARAMETER
;
1233 /* Check for error case */
1234 if (!NT_SUCCESS(Status
))
1236 /* Print debug information */
1237 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1238 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1239 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1241 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
);
1245 /* Release the lock if needed */
1246 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1255 LdrUnloadDll(IN PVOID BaseAddress
)
1257 NTSTATUS Status
= STATUS_SUCCESS
;
1258 PPEB Peb
= NtCurrentPeb();
1259 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1261 PLIST_ENTRY NextEntry
;
1262 LIST_ENTRY UnloadList
;
1263 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1265 ULONG ComSectionSize
;
1267 /* Get the LDR Lock */
1268 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1270 /* Increase the unload count */
1271 LdrpActiveUnloadCount
++;
1274 if (LdrpShutdownInProgress
) goto Quickie
;
1276 /* Make sure the DLL is valid and get its entry */
1277 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1279 Status
= STATUS_DLL_NOT_FOUND
;
1283 /* Check the current Load Count */
1284 if (LdrEntry
->LoadCount
!= 0xFFFF)
1287 LdrEntry
->LoadCount
--;
1290 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1292 /* Set up the Act Ctx */
1293 ActCtx
.Size
= sizeof(ActCtx
);
1294 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1295 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1297 /* Activate the ActCtx */
1298 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1299 LdrEntry
->EntryPointActivationContext
);
1301 /* Update the load count */
1302 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1304 /* Release the context */
1305 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1310 /* The DLL is locked */
1314 /* Show debug message */
1315 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1317 /* Check if this is our only unload and initialize the list if so */
1318 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1320 /* Loop the modules to build the list */
1321 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1322 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1325 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1326 LDR_DATA_TABLE_ENTRY
,
1327 InInitializationOrderModuleList
);
1328 NextEntry
= NextEntry
->Blink
;
1331 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1333 /* If the load count is now 0 */
1334 if (!LdrEntry
->LoadCount
)
1339 DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n",
1340 LdrpActiveUnloadCount
,
1341 LdrEntry
->BaseDllName
.Buffer
,
1342 LdrEntry
->FullDllName
.Buffer
,
1343 (ULONG
)LdrEntry
->LoadCount
,
1344 LdrEntry
->EntryPoint
);
1347 /* FIXME: Call Shim Engine and notify */
1350 CurrentEntry
= LdrEntry
;
1351 RemoveEntryList(&CurrentEntry
->InInitializationOrderModuleList
);
1352 RemoveEntryList(&CurrentEntry
->InMemoryOrderModuleList
);
1353 RemoveEntryList(&CurrentEntry
->HashLinks
);
1355 /* If there's more then one active unload */
1356 if (LdrpActiveUnloadCount
> 1)
1358 /* Flush the cached DLL handle and clear the list */
1359 LdrpLoadedDllHandleCache
= NULL
;
1360 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1363 /* Add the entry on the unload list */
1364 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1368 /* Only call the entrypoints once */
1369 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1371 /* Now loop the unload list and create our own */
1372 InitializeListHead(&UnloadList
);
1373 CurrentEntry
= NULL
;
1374 NextEntry
= LdrpUnloadHead
.Flink
;
1375 while (NextEntry
!= &LdrpUnloadHead
)
1377 /* If we have an active entry */
1381 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1382 CurrentEntry
= NULL
;
1384 /* Reset list pointers */
1385 NextEntry
= LdrpUnloadHead
.Flink
;
1386 if (NextEntry
== &LdrpUnloadHead
) break;
1389 /* Get the current entry */
1390 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1392 /* FIXME: Log the Unload Event */
1393 //LdrpRecordUnloadEvent(LdrEntry);
1395 /* Set the entry and clear it from the list */
1396 CurrentEntry
= LdrEntry
;
1397 LdrpLoadedDllHandleCache
= NULL
;
1398 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1400 /* Move it from the global to the local list */
1401 RemoveEntryList(&CurrentEntry
->HashLinks
);
1402 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1404 /* Get the entrypoint */
1405 EntryPoint
= LdrEntry
->EntryPoint
;
1407 /* Check if we should call it */
1408 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1413 DPRINT1("LDR: Calling deinit %lx\n", EntryPoint
);
1416 /* Set up the Act Ctx */
1417 ActCtx
.Size
= sizeof(ActCtx
);
1418 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1419 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1421 /* Activate the ActCtx */
1422 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1423 LdrEntry
->EntryPointActivationContext
);
1425 /* Call the entrypoint */
1426 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1431 /* Release the context */
1432 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1435 /* Remove it from the list */
1436 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1437 CurrentEntry
= NULL
;
1438 NextEntry
= LdrpUnloadHead
.Flink
;
1441 /* Now loop our local list */
1442 NextEntry
= UnloadList
.Flink
;
1443 while (NextEntry
!= &UnloadList
)
1446 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1447 NextEntry
= NextEntry
->Flink
;
1448 CurrentEntry
= LdrEntry
;
1450 /* Notify Application Verifier */
1451 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1453 DPRINT1("We don't support Application Verifier yet\n");
1459 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1462 /* Check if this is a .NET executable */
1463 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1465 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1470 DPRINT1(".NET Images are not supported yet\n");
1473 /* Check if we should unmap*/
1474 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1477 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1478 CurrentEntry
->DllBase
);
1479 ASSERT(NT_SUCCESS(Status
));
1482 /* Unload the alternate resource module, if any */
1483 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1485 /* FIXME: Send shutdown notification */
1486 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1488 /* Check if a Hotpatch is active */
1489 if (LdrEntry
->PatchInformation
)
1492 DPRINT1("We don't support Hotpatching yet\n");
1495 /* Deallocate the Entry */
1496 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1498 /* If this is the cached entry, invalidate it */
1499 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1501 LdrpGetModuleHandleCache
= NULL
;
1506 /* Decrease unload count */
1507 LdrpActiveUnloadCount
--;
1508 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1510 /* Return to caller */
1519 RtlDllShutdownInProgress(VOID
)
1521 /* Return the internal global */
1522 return LdrpShutdownInProgress
;
1528 PIMAGE_BASE_RELOCATION
1530 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
1532 IN PUSHORT TypeOffset
,
1535 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1543 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)
1545 static BOOLEAN WarnedOnce
= FALSE
;
1546 if (WarnedOnce
== FALSE
) { UNIMPLEMENTED
; WarnedOnce
= TRUE
; }