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");
22 ULONG AlternateResourceModuleCount
;
24 /* FUNCTIONS *****************************************************************/
28 LdrAlternateResourcesEnabled(VOID
)
30 /* ReactOS does not support this */
38 /* Generate a cookie */
39 return (((ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) |
40 (_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
) & 0xFFFF);
48 LdrUnlockLoaderLock(IN ULONG Flags
,
49 IN ULONG Cookie OPTIONAL
)
51 NTSTATUS Status
= STATUS_SUCCESS
;
53 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
55 /* Check for valid flags */
56 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
58 /* Flags are invalid, check how to fail */
59 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
61 /* The caller wants us to raise status */
62 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
65 /* A normal failure */
66 return STATUS_INVALID_PARAMETER_1
;
69 /* If we don't have a cookie, just return */
70 if (!Cookie
) return STATUS_SUCCESS
;
72 /* Validate the cookie */
73 if ((Cookie
& 0xF0000000) ||
74 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
76 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
78 /* Invalid cookie, check how to fail */
79 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
81 /* The caller wants us to raise status */
82 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
85 /* A normal failure */
86 return STATUS_INVALID_PARAMETER_2
;
89 /* Ready to release the lock */
90 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
92 /* Do a direct leave */
93 RtlLeaveCriticalSection(&LdrpLoaderLock
);
97 /* Wrap this in SEH, since we're not supposed to raise */
101 RtlLeaveCriticalSection(&LdrpLoaderLock
);
103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
105 /* We should use the LDR Filter instead */
106 Status
= _SEH2_GetExceptionCode();
120 LdrLockLoaderLock(IN ULONG Flags
,
121 OUT PULONG Disposition OPTIONAL
,
122 OUT PULONG_PTR Cookie OPTIONAL
)
124 NTSTATUS Status
= STATUS_SUCCESS
;
125 BOOLEAN InInit
= LdrpInLdrInit
;
127 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
129 /* Zero out the outputs */
130 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
131 if (Cookie
) *Cookie
= 0;
133 /* Validate the flags */
134 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
135 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
137 /* Flags are invalid, check how to fail */
138 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
140 /* The caller wants us to raise status */
141 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
144 /* A normal failure */
145 return STATUS_INVALID_PARAMETER_1
;
148 /* Make sure we got a cookie */
151 /* No cookie check how to fail */
152 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
154 /* The caller wants us to raise status */
155 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
158 /* A normal failure */
159 return STATUS_INVALID_PARAMETER_3
;
162 /* Do or Do Not. There is no Try */
163 ASSERT((Disposition
!= NULL
) || !(Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
));
165 /* If the flag is set, make sure we have a valid pointer to use */
166 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
168 /* No pointer to return the data to */
169 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
171 /* The caller wants us to raise status */
172 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
176 return STATUS_INVALID_PARAMETER_2
;
179 /* Return now if we are in the init phase */
180 if (InInit
) return STATUS_SUCCESS
;
182 /* Check what locking semantic to use */
183 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
185 /* Check if we should enter or simply try */
186 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
189 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
192 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
197 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
198 *Cookie
= LdrpMakeCookie();
204 RtlEnterCriticalSection(&LdrpLoaderLock
);
206 /* See if result was requested */
207 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
208 *Cookie
= LdrpMakeCookie();
213 /* Wrap this in SEH, since we're not supposed to raise */
216 /* Check if we should enter or simply try */
217 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
220 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
223 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
228 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
229 *Cookie
= LdrpMakeCookie();
235 RtlEnterCriticalSection(&LdrpLoaderLock
);
237 /* See if result was requested */
238 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
239 *Cookie
= LdrpMakeCookie();
242 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
244 /* We should use the LDR Filter instead */
245 Status
= _SEH2_GetExceptionCode();
259 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
260 IN PULONG DllCharacteristics OPTIONAL
,
261 IN PUNICODE_STRING DllName
,
262 OUT PVOID
*BaseAddress
)
264 WCHAR StringBuffer
[MAX_PATH
];
265 UNICODE_STRING DllString1
, DllString2
;
266 BOOLEAN RedirectedDll
= FALSE
;
269 PUNICODE_STRING OldTldDll
;
270 PTEB Teb
= NtCurrentTeb();
272 /* Initialize the strings */
273 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
274 DllString1
.Buffer
= StringBuffer
;
275 DllString1
.Length
= 0;
276 DllString1
.MaximumLength
= sizeof(StringBuffer
);
278 /* Check if the SxS Assemblies specify another file */
279 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
281 &LdrApiDefaultExtension
,
290 if (NT_SUCCESS(Status
))
293 RedirectedDll
= TRUE
;
295 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
297 /* Unrecoverable SxS failure; did we get a string? */
298 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
302 /* Lock the loader lock */
303 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
305 /* Check if there's a TLD DLL being loaded */
306 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
309 /* This is a recursive load, do something about it? */
310 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
312 /* Print out debug messages */
313 DPRINT1("[%lx, %lx] LDR: Recursive DLL Load\n",
314 Teb
->RealClientId
.UniqueProcess
,
315 Teb
->RealClientId
.UniqueThread
);
316 DPRINT1("[%lx, %lx] Previous DLL being loaded \"%wZ\"\n",
317 Teb
->RealClientId
.UniqueProcess
,
318 Teb
->RealClientId
.UniqueThread
,
320 DPRINT1("[%lx, %lx] DLL being requested \"%wZ\"\n",
321 Teb
->RealClientId
.UniqueProcess
,
322 Teb
->RealClientId
.UniqueThread
,
325 /* Was it initializing too? */
326 if (!LdrpCurrentDllInitializer
)
328 DPRINT1("[%lx, %lx] LDR: No DLL Initializer was running\n",
329 Teb
->RealClientId
.UniqueProcess
,
330 Teb
->RealClientId
.UniqueThread
);
334 DPRINT1("[%lx, %lx] DLL whose initializer was currently running \"%wZ\"\n",
335 Teb
->ClientId
.UniqueProcess
,
336 Teb
->ClientId
.UniqueThread
,
337 &LdrpCurrentDllInitializer
->BaseDllName
);
342 /* Set this one as the TLD DLL being loaded*/
343 LdrpTopLevelDllBeingLoaded
= DllName
;
346 Status
= LdrpLoadDll(RedirectedDll
,
352 if (NT_SUCCESS(Status
))
354 Status
= STATUS_SUCCESS
;
356 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
357 (Status
!= STATUS_DLL_NOT_FOUND
) &&
358 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
359 (Status
!= STATUS_DLL_INIT_FAILED
))
361 // 85 == DPFLTR_LDR_ID;
363 DPFLTR_WARNING_LEVEL
,
364 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
370 /* Restore the old TLD DLL */
371 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
373 /* Release the lock */
374 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
376 /* Do we have a redirect string? */
377 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
388 LdrFindEntryForAddress(PVOID Address
,
389 PLDR_DATA_TABLE_ENTRY
*Module
)
391 PLIST_ENTRY ListHead
, NextEntry
;
392 PLDR_DATA_TABLE_ENTRY LdrEntry
;
393 PIMAGE_NT_HEADERS NtHeader
;
394 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
395 ULONG_PTR DllBase
, DllEnd
;
397 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
400 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
402 /* Get the current entry */
403 LdrEntry
= Ldr
->EntryInProgress
;
406 /* Get the NT Headers */
407 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
410 /* Get the Image Base */
411 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
412 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
414 /* Check if they match */
415 if (((ULONG_PTR
)Address
>= DllBase
) &&
416 ((ULONG_PTR
)Address
< DllEnd
))
420 return STATUS_SUCCESS
;
425 /* Loop the module list */
426 ListHead
= &Ldr
->InMemoryOrderModuleList
;
427 NextEntry
= ListHead
->Flink
;
428 while (NextEntry
!= ListHead
)
430 /* Get the entry and NT Headers */
431 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
432 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
435 /* Get the Image Base */
436 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
437 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
439 /* Check if they match */
440 if (((ULONG_PTR
)Address
>= DllBase
) &&
441 ((ULONG_PTR
)Address
< DllEnd
))
445 return STATUS_SUCCESS
;
449 NextEntry
= NextEntry
->Flink
;
454 // 85 == DPFLTR_LDR_ID;
455 DbgPrintEx(85, DPFLTR_WARNING_LEVEL
, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__
, STATUS_NO_MORE_ENTRIES
);
456 return STATUS_NO_MORE_ENTRIES
;
464 LdrGetDllHandleEx(IN ULONG Flags
,
465 IN PWSTR DllPath OPTIONAL
,
466 IN PULONG DllCharacteristics OPTIONAL
,
467 IN PUNICODE_STRING DllName
,
468 OUT PVOID
*DllHandle OPTIONAL
)
471 PLDR_DATA_TABLE_ENTRY LdrEntry
;
472 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
473 PUNICODE_STRING pRedirectName
, CompareName
;
475 BOOLEAN Locked
, RedirectedDll
;
477 ULONG LoadFlag
, Length
;
479 /* Initialize the strings */
480 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
481 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
482 RedirectName
= *DllName
;
483 pRedirectName
= &RedirectName
;
485 /* Initialize state */
486 RedirectedDll
= Locked
= FALSE
;
490 /* Clear the handle */
491 if (DllHandle
) *DllHandle
= NULL
;
493 /* Check for a valid flag combination */
494 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
495 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
497 DPRINT1("Flags are invalid or no DllHandle given\n");
498 Status
= STATUS_INVALID_PARAMETER
;
502 /* If not initializing */
505 /* Acquire the lock */
506 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
507 if (!NT_SUCCESS(Status
)) goto Quickie
;
509 /* Remember we own it */
513 /* Check if the SxS Assemblies specify another file */
514 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
516 &LdrApiDefaultExtension
,
525 if (NT_SUCCESS(Status
))
528 RedirectedDll
= TRUE
;
530 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
532 /* Unrecoverable SxS failure; */
537 ASSERT(pRedirectName
== &RedirectName
);
540 /* Set default failure code */
541 Status
= STATUS_DLL_NOT_FOUND
;
543 /* Use the cache if we can */
544 if (LdrpGetModuleHandleCache
)
546 /* Check if we were redirected */
550 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
555 /* Use the right name */
556 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
561 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
566 /* Use the right name */
567 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
570 /* Check if the name matches */
571 if (RtlEqualUnicodeString(pRedirectName
,
576 LdrEntry
= LdrpGetModuleHandleCache
;
579 Status
= STATUS_SUCCESS
;
585 /* Find the name without the extension */
586 p1
= pRedirectName
->Buffer
;
588 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
595 else if (*p1
== L
'\\')
601 /* Check if no extension was found or if we got a slash */
602 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
604 /* Check that we have space to add one */
605 Length
= pRedirectName
->Length
+
606 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
607 if (Length
>= UNICODE_STRING_MAX_BYTES
)
609 /* No space to add the extension */
610 Status
= STATUS_NAME_TOO_LONG
;
614 /* Setup the string */
615 RawDllName
.MaximumLength
= Length
;
616 ASSERT(Length
>= sizeof(UNICODE_NULL
));
617 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
619 RawDllName
.MaximumLength
);
620 if (!RawDllName
.Buffer
)
622 Status
= STATUS_NO_MEMORY
;
626 /* Copy the string and add extension */
627 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
628 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
632 /* Check if there's something in the name */
633 Length
= pRedirectName
->Length
;
636 /* Check and remove trailing period */
637 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
639 /* Decrease the size */
640 pRedirectName
->Length
-= sizeof(WCHAR
);
644 /* Setup the string */
645 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
646 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
648 RawDllName
.MaximumLength
);
649 if (!RawDllName
.Buffer
)
651 Status
= STATUS_NO_MEMORY
;
655 /* Copy the string */
656 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
659 /* Display debug string */
662 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
664 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
668 if (LdrpCheckForLoadedDll(DllPath
,
670 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
674 /* Update cached entry */
675 LdrpGetModuleHandleCache
= LdrEntry
;
678 Status
= STATUS_SUCCESS
;
682 /* Make sure to NULL this */
686 /* The success path must have a valid loader entry */
687 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
689 /* Check if we got an entry and success */
690 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
691 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
693 /* Check if the DLL is locked */
694 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
695 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
697 /* Check what to do with the load count */
698 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
701 LdrEntry
->LoadCount
= 0xFFFF;
702 LoadFlag
= LDRP_UPDATE_PIN
;
706 /* Increase the load count */
707 LdrEntry
->LoadCount
++;
708 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
711 /* Update the load count now */
712 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
713 LdrpClearLoadInProgress();
716 /* Check if the caller is requesting the handle */
717 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
720 /* Free string if needed */
721 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
723 /* Free the raw DLL Name if needed */
724 if (RawDllName
.Buffer
)
726 /* Free the heap-allocated buffer */
727 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
728 RawDllName
.Buffer
= NULL
;
734 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
747 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
748 IN PULONG DllCharacteristics OPTIONAL
,
749 IN PUNICODE_STRING DllName
,
750 OUT PVOID
*DllHandle
)
752 /* Call the newer API */
753 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
765 LdrGetProcedureAddress(IN PVOID BaseAddress
,
766 IN PANSI_STRING Name
,
768 OUT PVOID
*ProcedureAddress
)
770 /* Call the internal routine and tell it to execute DllInit */
771 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
779 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
780 IN PLDR_CALLBACK Callback
,
781 IN PVOID CallbackContext
,
782 OUT PUSHORT ImageCharacteristics
)
784 FILE_STANDARD_INFORMATION FileStandardInfo
;
785 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
786 PIMAGE_SECTION_HEADER LastSection
= NULL
;
787 IO_STATUS_BLOCK IoStatusBlock
;
788 PIMAGE_NT_HEADERS NtHeader
;
789 HANDLE SectionHandle
;
792 BOOLEAN Result
, NoActualCheck
;
796 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
798 /* If the handle has the magic KnownDll flag, skip actual checksums */
799 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
801 /* Create the section */
802 Status
= NtCreateSection(&SectionHandle
,
809 if (!NT_SUCCESS(Status
))
811 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
815 /* Map the section */
818 Status
= NtMapViewOfSection(SectionHandle
,
828 if (!NT_SUCCESS(Status
))
830 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
831 NtClose(SectionHandle
);
835 /* Get the file information */
836 Status
= NtQueryInformationFile(FileHandle
,
839 sizeof(FILE_STANDARD_INFORMATION
),
840 FileStandardInformation
);
841 if (!NT_SUCCESS(Status
))
843 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
844 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
845 NtClose(SectionHandle
);
849 /* Protect with SEH */
852 /* Check if this is the KnownDll hack */
855 /* Don't actually do it */
860 /* Verify the checksum */
861 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
862 FileStandardInfo
.EndOfFile
.LowPart
,
863 FileStandardInfo
.EndOfFile
.LowPart
);
866 /* Check if a callback was supplied */
867 if ((Result
) && (Callback
))
869 /* Get the NT Header */
870 NtHeader
= RtlImageNtHeader(ViewBase
);
872 /* Check if caller requested this back */
873 if (ImageCharacteristics
)
875 /* Return to caller */
876 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
879 /* Get the Import Directory Data */
880 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
882 IMAGE_DIRECTORY_ENTRY_IMPORT
,
885 /* Make sure there is one */
888 /* Loop the imports */
889 while (ImportData
->Name
)
892 ImportName
= RtlImageRvaToVa(NtHeader
,
897 /* Notify the callback */
898 Callback(CallbackContext
, ImportName
);
904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
906 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
911 /* Unmap file and close handle */
912 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
913 NtClose(SectionHandle
);
916 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
921 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
923 OUT PRTL_PROCESS_MODULES ModuleInformation
,
925 OUT PULONG ReturnedSize OPTIONAL
)
927 PLIST_ENTRY ModuleListHead
, InitListHead
;
928 PLIST_ENTRY Entry
, InitEntry
;
929 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
930 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
931 NTSTATUS Status
= STATUS_SUCCESS
;
932 ULONG UsedSize
= sizeof(ULONG
);
933 ANSI_STRING AnsiString
;
936 DPRINT("LdrQueryProcessModuleInformation() called\n");
938 /* Acquire loader lock */
939 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
943 /* Check if we were given enough space */
946 Status
= STATUS_INFO_LENGTH_MISMATCH
;
950 ModuleInformation
->NumberOfModules
= 0;
951 ModulePtr
= &ModuleInformation
->Modules
[0];
952 Status
= STATUS_SUCCESS
;
955 /* Traverse the list of modules */
956 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
957 Entry
= ModuleListHead
->Flink
;
959 while (Entry
!= ModuleListHead
)
961 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
963 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
965 /* Increase the used size */
966 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
970 Status
= STATUS_INFO_LENGTH_MISMATCH
;
974 ModulePtr
->ImageBase
= Module
->DllBase
;
975 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
976 ModulePtr
->Flags
= Module
->Flags
;
977 ModulePtr
->LoadCount
= Module
->LoadCount
;
978 ModulePtr
->MappedBase
= NULL
;
979 ModulePtr
->InitOrderIndex
= 0;
980 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
982 /* Now get init order index by traversing init list */
983 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
984 InitEntry
= InitListHead
->Flink
;
986 while (InitEntry
!= InitListHead
)
988 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
990 /* Increase the index */
991 ModulePtr
->InitOrderIndex
++;
993 /* Quit the loop if our module is found */
994 if (InitModule
== Module
) break;
996 /* Advance to the next entry */
997 InitEntry
= InitEntry
->Flink
;
1000 /* Prepare ANSI string with the module's name */
1001 AnsiString
.Length
= 0;
1002 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
1003 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
1004 RtlUnicodeStringToAnsiString(&AnsiString
,
1005 &Module
->FullDllName
,
1008 /* Calculate OffsetToFileName field */
1009 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1011 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1013 ModulePtr
->OffsetToFileName
= 0;
1015 /* Advance to the next module in the output list */
1018 /* Increase number of modules */
1019 if (ModuleInformation
)
1020 ModuleInformation
->NumberOfModules
++;
1023 /* Go to the next entry in the modules list */
1024 Entry
= Entry
->Flink
;
1027 /* Set returned size if it was provided */
1029 *ReturnedSize
= UsedSize
;
1031 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1033 /* Ignoring the exception */
1036 /* Release the lock */
1037 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1039 DPRINT("LdrQueryProcessModuleInformation() done\n");
1049 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
1051 OUT PULONG ReturnedSize OPTIONAL
)
1053 /* Call Ex version of the API */
1054 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1062 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag
,
1063 IN PLDR_ENUM_CALLBACK EnumProc
,
1066 PLIST_ENTRY ListHead
, ListEntry
;
1067 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1070 BOOLEAN Stop
= FALSE
;
1072 /* Check parameters */
1073 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1075 /* Acquire the loader lock */
1076 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1077 if (!NT_SUCCESS(Status
)) return Status
;
1079 /* Loop all the modules and call enum proc */
1080 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1081 ListEntry
= ListHead
->Flink
;
1082 while (ListHead
!= ListEntry
)
1085 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1087 /* Call the enumeration proc inside SEH */
1090 EnumProc(LdrEntry
, Context
, &Stop
);
1092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1094 /* Ignoring the exception */
1097 /* Break if we were asked to stop enumeration */
1100 /* Release loader lock */
1101 Status
= LdrUnlockLoaderLock(0, Cookie
);
1103 /* Reset any successful status to STATUS_SUCCESS, but leave
1104 failure to the caller */
1105 if (NT_SUCCESS(Status
))
1106 Status
= STATUS_SUCCESS
;
1108 /* Return any possible failure status */
1112 /* Advance to the next module */
1113 ListEntry
= ListEntry
->Flink
;
1116 /* Release loader lock, it must succeed this time */
1117 Status
= LdrUnlockLoaderLock(0, Cookie
);
1118 ASSERT(NT_SUCCESS(Status
));
1120 /* Return success */
1121 return STATUS_SUCCESS
;
1129 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1131 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1135 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1137 /* Don't do it during shutdown */
1138 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1140 /* Check if we should grab the lock */
1145 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1146 if (!NT_SUCCESS(Status
)) return Status
;
1150 /* Make sure the DLL is valid and get its entry */
1151 Status
= STATUS_DLL_NOT_FOUND
;
1152 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1154 /* Get if it has a TLS slot */
1155 if (!LdrEntry
->TlsIndex
)
1157 /* It doesn't, so you're allowed to call this */
1158 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1159 Status
= STATUS_SUCCESS
;
1163 /* Check if the lock was held */
1167 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1170 /* Return the status */
1179 LdrAddRefDll(IN ULONG Flags
,
1180 IN PVOID BaseAddress
)
1182 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1183 NTSTATUS Status
= STATUS_SUCCESS
;
1185 BOOLEAN Locked
= FALSE
;
1187 /* Check for invalid flags */
1188 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1190 /* Fail with invalid parameter status if so */
1191 Status
= STATUS_INVALID_PARAMETER
;
1195 /* Acquire the loader lock if not in init phase */
1198 /* Acquire the lock */
1199 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1200 if (!NT_SUCCESS(Status
)) goto quickie
;
1204 /* Get this module's data table entry */
1205 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1209 /* Shouldn't happen */
1210 Status
= STATUS_INTERNAL_ERROR
;
1214 /* If this is not a pinned module */
1215 if (LdrEntry
->LoadCount
!= 0xFFFF)
1217 /* Update its load count */
1218 if (Flags
& LDR_ADDREF_DLL_PIN
)
1220 /* Pin it by setting load count to -1 */
1221 LdrEntry
->LoadCount
= 0xFFFF;
1222 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1226 /* Increase its load count by one */
1227 LdrEntry
->LoadCount
++;
1228 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1231 /* Clear load in progress */
1232 LdrpClearLoadInProgress();
1237 /* There was an error getting this module's handle, return invalid param status */
1238 Status
= STATUS_INVALID_PARAMETER
;
1242 /* Check for error case */
1243 if (!NT_SUCCESS(Status
))
1245 /* Print debug information */
1246 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1247 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1248 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1250 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
);
1254 /* Release the lock if needed */
1255 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1264 LdrUnloadDll(IN PVOID BaseAddress
)
1266 NTSTATUS Status
= STATUS_SUCCESS
;
1267 PPEB Peb
= NtCurrentPeb();
1268 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1270 PLIST_ENTRY NextEntry
;
1271 LIST_ENTRY UnloadList
;
1272 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1274 ULONG ComSectionSize
;
1276 /* Get the LDR Lock */
1277 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1279 /* Increase the unload count */
1280 LdrpActiveUnloadCount
++;
1283 if (LdrpShutdownInProgress
) goto Quickie
;
1285 /* Make sure the DLL is valid and get its entry */
1286 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1288 Status
= STATUS_DLL_NOT_FOUND
;
1292 /* Check the current Load Count */
1293 if (LdrEntry
->LoadCount
!= 0xFFFF)
1296 LdrEntry
->LoadCount
--;
1299 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1301 /* Set up the Act Ctx */
1302 ActCtx
.Size
= sizeof(ActCtx
);
1303 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1304 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1306 /* Activate the ActCtx */
1307 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1308 LdrEntry
->EntryPointActivationContext
);
1310 /* Update the load count */
1311 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1313 /* Release the context */
1314 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1319 /* The DLL is locked */
1323 /* Show debug message */
1324 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1326 /* Check if this is our only unload and initialize the list if so */
1327 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1329 /* Loop the modules to build the list */
1330 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1331 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1334 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1335 LDR_DATA_TABLE_ENTRY
,
1336 InInitializationOrderModuleList
);
1337 NextEntry
= NextEntry
->Blink
;
1340 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1342 /* If the load count is now 0 */
1343 if (!LdrEntry
->LoadCount
)
1348 DPRINT1("(%d) [%ws] %ws (%lx) deinit %lx\n",
1349 LdrpActiveUnloadCount
,
1350 LdrEntry
->BaseDllName
.Buffer
,
1351 LdrEntry
->FullDllName
.Buffer
,
1352 (ULONG
)LdrEntry
->LoadCount
,
1353 LdrEntry
->EntryPoint
);
1356 /* FIXME: Call Shim Engine and notify */
1359 CurrentEntry
= LdrEntry
;
1360 RemoveEntryList(&CurrentEntry
->InInitializationOrderModuleList
);
1361 RemoveEntryList(&CurrentEntry
->InMemoryOrderModuleList
);
1362 RemoveEntryList(&CurrentEntry
->HashLinks
);
1364 /* If there's more then one active unload */
1365 if (LdrpActiveUnloadCount
> 1)
1367 /* Flush the cached DLL handle and clear the list */
1368 LdrpLoadedDllHandleCache
= NULL
;
1369 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1372 /* Add the entry on the unload list */
1373 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1377 /* Only call the entrypoints once */
1378 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1380 /* Now loop the unload list and create our own */
1381 InitializeListHead(&UnloadList
);
1382 CurrentEntry
= NULL
;
1383 NextEntry
= LdrpUnloadHead
.Flink
;
1384 while (NextEntry
!= &LdrpUnloadHead
)
1386 /* Get the current entry */
1387 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1389 /* FIXME: Log the Unload Event */
1390 //LdrpRecordUnloadEvent(LdrEntry);
1392 /* Set the entry and clear it from the list */
1393 CurrentEntry
= LdrEntry
;
1394 LdrpLoadedDllHandleCache
= NULL
;
1395 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1397 /* Move it from the global to the local list */
1398 RemoveEntryList(&CurrentEntry
->HashLinks
);
1399 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1401 /* Get the entrypoint */
1402 EntryPoint
= LdrEntry
->EntryPoint
;
1404 /* Check if we should call it */
1405 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1410 DPRINT1("LDR: Calling deinit %lx\n", EntryPoint
);
1413 /* Set up the Act Ctx */
1414 ActCtx
.Size
= sizeof(ActCtx
);
1415 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1416 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1418 /* Activate the ActCtx */
1419 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1420 LdrEntry
->EntryPointActivationContext
);
1422 /* Call the entrypoint */
1423 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1428 /* Release the context */
1429 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1432 /* Remove it from the list */
1433 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1434 CurrentEntry
= NULL
;
1435 NextEntry
= LdrpUnloadHead
.Flink
;
1438 /* Now loop our local list */
1439 NextEntry
= UnloadList
.Flink
;
1440 while (NextEntry
!= &UnloadList
)
1443 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1444 NextEntry
= NextEntry
->Flink
;
1445 CurrentEntry
= LdrEntry
;
1447 /* Notify Application Verifier */
1448 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1450 DPRINT1("We don't support Application Verifier yet\n");
1456 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1459 /* Check if this is a .NET executable */
1460 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1462 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1467 DPRINT1(".NET Images are not supported yet\n");
1470 /* Check if we should unmap*/
1471 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1474 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1475 CurrentEntry
->DllBase
);
1476 ASSERT(NT_SUCCESS(Status
));
1479 /* Unload the alternate resource module, if any */
1480 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1482 /* FIXME: Send shutdown notification */
1483 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1485 /* Check if a Hotpatch is active */
1486 if (LdrEntry
->PatchInformation
)
1489 DPRINT1("We don't support Hotpatching yet\n");
1492 /* Deallocate the Entry */
1493 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1495 /* If this is the cached entry, invalidate it */
1496 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1498 LdrpGetModuleHandleCache
= NULL
;
1503 /* Decrease unload count */
1504 LdrpActiveUnloadCount
--;
1505 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1507 /* Return to caller */
1516 RtlDllShutdownInProgress(VOID
)
1518 /* Return the internal global */
1519 return LdrpShutdownInProgress
;
1525 PIMAGE_BASE_RELOCATION
1527 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
1529 IN PUSHORT TypeOffset
,
1532 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1540 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)
1544 /* Acquire the loader lock */
1545 LdrLockLoaderLock(TRUE
, NULL
, &Cookie
);
1547 /* Check if there's any alternate resources loaded */
1548 if (AlternateResourceModuleCount
)
1553 /* Release the loader lock */
1554 LdrUnlockLoaderLock(1, Cookie
);
1560 /* FIXME: Add to ntstatus.mc */
1561 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1568 LdrLoadAlternateResourceModule(IN PVOID Module
,
1571 /* Is MUI Support enabled? */
1572 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS
;
1575 return STATUS_MUI_FILE_NOT_FOUND
;