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 LdrFindCreateProcessManifest(IN ULONG Flags
,
31 IN ULONG IdPathLength
,
32 IN PVOID OutDataEntry
)
35 return STATUS_NOT_IMPLEMENTED
;
40 LdrDestroyOutOfProcessImage(IN PVOID Image
)
43 return STATUS_NOT_IMPLEMENTED
;
48 LdrCreateOutOfProcessImage(IN ULONG Flags
,
49 IN HANDLE ProcessHandle
,
54 return STATUS_NOT_IMPLEMENTED
;
59 LdrAccessOutOfProcessResource(IN PVOID Unknown
,
66 return STATUS_NOT_IMPLEMENTED
;
71 LdrSetDllManifestProber(IN PVOID ProberFunction
)
78 LdrAlternateResourcesEnabled(VOID
)
80 /* ReactOS does not support this */
88 /* Generate a cookie */
89 return (((ULONG_PTR
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) |
90 (_InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
) & 0xFFFF);
98 LdrUnlockLoaderLock(IN ULONG Flags
,
99 IN ULONG Cookie OPTIONAL
)
101 NTSTATUS Status
= STATUS_SUCCESS
;
103 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
105 /* Check for valid flags */
106 if (Flags
& ~LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
108 /* Flags are invalid, check how to fail */
109 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
111 /* The caller wants us to raise status */
112 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
115 /* A normal failure */
116 return STATUS_INVALID_PARAMETER_1
;
119 /* If we don't have a cookie, just return */
120 if (!Cookie
) return STATUS_SUCCESS
;
122 /* Validate the cookie */
123 if ((Cookie
& 0xF0000000) ||
124 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
126 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
128 /* Invalid cookie, check how to fail */
129 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
131 /* The caller wants us to raise status */
132 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
135 /* A normal failure */
136 return STATUS_INVALID_PARAMETER_2
;
139 /* Ready to release the lock */
140 if (Flags
& LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
142 /* Do a direct leave */
143 RtlLeaveCriticalSection(&LdrpLoaderLock
);
147 /* Wrap this in SEH, since we're not supposed to raise */
151 RtlLeaveCriticalSection(&LdrpLoaderLock
);
153 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
155 /* We should use the LDR Filter instead */
156 Status
= _SEH2_GetExceptionCode();
170 LdrLockLoaderLock(IN ULONG Flags
,
171 OUT PULONG Disposition OPTIONAL
,
172 OUT PULONG_PTR Cookie OPTIONAL
)
174 NTSTATUS Status
= STATUS_SUCCESS
;
175 BOOLEAN InInit
= LdrpInLdrInit
;
177 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Disposition
, Cookie
);
179 /* Zero out the outputs */
180 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_INVALID
;
181 if (Cookie
) *Cookie
= 0;
183 /* Validate the flags */
184 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
|
185 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
187 /* Flags are invalid, check how to fail */
188 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
190 /* The caller wants us to raise status */
191 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
194 /* A normal failure */
195 return STATUS_INVALID_PARAMETER_1
;
198 /* Make sure we got a cookie */
201 /* No cookie check how to fail */
202 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
204 /* The caller wants us to raise status */
205 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
208 /* A normal failure */
209 return STATUS_INVALID_PARAMETER_3
;
212 /* Do or Do Not. There is no Try */
213 ASSERT((Disposition
!= NULL
) || !(Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
));
215 /* If the flag is set, make sure we have a valid pointer to use */
216 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Disposition
))
218 /* No pointer to return the data to */
219 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
221 /* The caller wants us to raise status */
222 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
226 return STATUS_INVALID_PARAMETER_2
;
229 /* Return now if we are in the init phase */
230 if (InInit
) return STATUS_SUCCESS
;
232 /* Check what locking semantic to use */
233 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
)
235 /* Check if we should enter or simply try */
236 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
239 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
242 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
247 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
248 *Cookie
= LdrpMakeCookie();
254 RtlEnterCriticalSection(&LdrpLoaderLock
);
256 /* See if result was requested */
257 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
258 *Cookie
= LdrpMakeCookie();
263 /* Wrap this in SEH, since we're not supposed to raise */
266 /* Check if we should enter or simply try */
267 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
270 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
273 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_NOT_ACQUIRED
;
278 *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
279 *Cookie
= LdrpMakeCookie();
285 RtlEnterCriticalSection(&LdrpLoaderLock
);
287 /* See if result was requested */
288 if (Disposition
) *Disposition
= LDR_LOCK_LOADER_LOCK_DISPOSITION_LOCK_ACQUIRED
;
289 *Cookie
= LdrpMakeCookie();
292 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
294 /* We should use the LDR Filter instead */
295 Status
= _SEH2_GetExceptionCode();
309 LdrLoadDll(IN PWSTR SearchPath OPTIONAL
,
310 IN PULONG DllCharacteristics OPTIONAL
,
311 IN PUNICODE_STRING DllName
,
312 OUT PVOID
*BaseAddress
)
314 WCHAR StringBuffer
[MAX_PATH
];
315 UNICODE_STRING DllString1
, DllString2
;
316 BOOLEAN RedirectedDll
= FALSE
;
319 PUNICODE_STRING OldTldDll
;
320 PTEB Teb
= NtCurrentTeb();
322 /* Initialize the strings */
323 RtlInitEmptyUnicodeString(&DllString2
, NULL
, 0);
324 DllString1
.Buffer
= StringBuffer
;
325 DllString1
.Length
= 0;
326 DllString1
.MaximumLength
= sizeof(StringBuffer
);
328 /* Check if the SxS Assemblies specify another file */
329 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
331 &LdrApiDefaultExtension
,
340 if (NT_SUCCESS(Status
))
343 RedirectedDll
= TRUE
;
345 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
347 /* Unrecoverable SxS failure; did we get a string? */
348 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
352 /* Lock the loader lock */
353 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
355 /* Check if there's a TLD DLL being loaded */
356 OldTldDll
= LdrpTopLevelDllBeingLoaded
;
359 /* This is a recursive load, do something about it? */
360 if ((ShowSnaps
) || (LdrpShowRecursiveLoads
) || (LdrpBreakOnRecursiveDllLoads
))
362 /* Print out debug messages */
363 DPRINT1("[%p, %p] LDR: Recursive DLL Load\n",
364 Teb
->RealClientId
.UniqueProcess
,
365 Teb
->RealClientId
.UniqueThread
);
366 DPRINT1("[%p, %p] Previous DLL being loaded \"%wZ\"\n",
367 Teb
->RealClientId
.UniqueProcess
,
368 Teb
->RealClientId
.UniqueThread
,
370 DPRINT1("[%p, %p] DLL being requested \"%wZ\"\n",
371 Teb
->RealClientId
.UniqueProcess
,
372 Teb
->RealClientId
.UniqueThread
,
375 /* Was it initializing too? */
376 if (!LdrpCurrentDllInitializer
)
378 DPRINT1("[%p, %p] LDR: No DLL Initializer was running\n",
379 Teb
->RealClientId
.UniqueProcess
,
380 Teb
->RealClientId
.UniqueThread
);
384 DPRINT1("[%p, %p] DLL whose initializer was currently running \"%wZ\"\n",
385 Teb
->ClientId
.UniqueProcess
,
386 Teb
->ClientId
.UniqueThread
,
387 &LdrpCurrentDllInitializer
->BaseDllName
);
392 /* Set this one as the TLD DLL being loaded*/
393 LdrpTopLevelDllBeingLoaded
= DllName
;
396 Status
= LdrpLoadDll(RedirectedDll
,
402 if (NT_SUCCESS(Status
))
404 Status
= STATUS_SUCCESS
;
406 else if ((Status
!= STATUS_NO_SUCH_FILE
) &&
407 (Status
!= STATUS_DLL_NOT_FOUND
) &&
408 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
) &&
409 (Status
!= STATUS_DLL_INIT_FAILED
))
411 // 85 == DPFLTR_LDR_ID;
413 DPFLTR_WARNING_LEVEL
,
414 "LDR: %s - failing because LdrpLoadDll(%wZ) returned status %x\n",
420 /* Restore the old TLD DLL */
421 LdrpTopLevelDllBeingLoaded
= OldTldDll
;
423 /* Release the lock */
424 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
426 /* Do we have a redirect string? */
427 if (DllString2
.Buffer
) RtlFreeUnicodeString(&DllString2
);
438 LdrFindEntryForAddress(PVOID Address
,
439 PLDR_DATA_TABLE_ENTRY
*Module
)
441 PLIST_ENTRY ListHead
, NextEntry
;
442 PLDR_DATA_TABLE_ENTRY LdrEntry
;
443 PIMAGE_NT_HEADERS NtHeader
;
444 PPEB_LDR_DATA Ldr
= NtCurrentPeb()->Ldr
;
445 ULONG_PTR DllBase
, DllEnd
;
447 DPRINT("LdrFindEntryForAddress(Address %p)\n", Address
);
450 if (!Ldr
) return STATUS_NO_MORE_ENTRIES
;
452 /* Get the current entry */
453 LdrEntry
= Ldr
->EntryInProgress
;
456 /* Get the NT Headers */
457 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
460 /* Get the Image Base */
461 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
462 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
464 /* Check if they match */
465 if (((ULONG_PTR
)Address
>= DllBase
) &&
466 ((ULONG_PTR
)Address
< DllEnd
))
470 return STATUS_SUCCESS
;
475 /* Loop the module list */
476 ListHead
= &Ldr
->InMemoryOrderModuleList
;
477 NextEntry
= ListHead
->Flink
;
478 while (NextEntry
!= ListHead
)
480 /* Get the entry and NT Headers */
481 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, InMemoryOrderModuleList
);
482 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
485 /* Get the Image Base */
486 DllBase
= (ULONG_PTR
)LdrEntry
->DllBase
;
487 DllEnd
= DllBase
+ NtHeader
->OptionalHeader
.SizeOfImage
;
489 /* Check if they match */
490 if (((ULONG_PTR
)Address
>= DllBase
) &&
491 ((ULONG_PTR
)Address
< DllEnd
))
495 return STATUS_SUCCESS
;
499 NextEntry
= NextEntry
->Flink
;
504 // 85 == DPFLTR_LDR_ID;
505 DbgPrintEx(85, DPFLTR_WARNING_LEVEL
, "LDR: %s() exiting 0x%08lx\n", __FUNCTION__
, STATUS_NO_MORE_ENTRIES
);
506 return STATUS_NO_MORE_ENTRIES
;
514 LdrGetDllHandleEx(IN ULONG Flags
,
515 IN PWSTR DllPath OPTIONAL
,
516 IN PULONG DllCharacteristics OPTIONAL
,
517 IN PUNICODE_STRING DllName
,
518 OUT PVOID
*DllHandle OPTIONAL
)
521 PLDR_DATA_TABLE_ENTRY LdrEntry
;
522 UNICODE_STRING RedirectName
, DllString1
, RawDllName
;
523 PUNICODE_STRING pRedirectName
, CompareName
;
525 BOOLEAN Locked
, RedirectedDll
;
527 ULONG LoadFlag
, Length
;
529 /* Initialize the strings */
530 RtlInitEmptyUnicodeString(&DllString1
, NULL
, 0);
531 RtlInitEmptyUnicodeString(&RawDllName
, NULL
, 0);
532 RedirectName
= *DllName
;
533 pRedirectName
= &RedirectName
;
535 /* Initialize state */
536 RedirectedDll
= Locked
= FALSE
;
540 /* Clear the handle */
541 if (DllHandle
) *DllHandle
= NULL
;
543 /* Check for a valid flag combination */
544 if ((Flags
& ~(LDR_GET_DLL_HANDLE_EX_PIN
| LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
)) ||
545 (!DllHandle
&& !(Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)))
547 DPRINT1("Flags are invalid or no DllHandle given\n");
548 Status
= STATUS_INVALID_PARAMETER
;
552 /* If not initializing */
555 /* Acquire the lock */
556 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
557 if (!NT_SUCCESS(Status
)) goto Quickie
;
559 /* Remember we own it */
563 /* Check if the SxS Assemblies specify another file */
564 Status
= RtlDosApplyFileIsolationRedirection_Ustr(TRUE
,
566 &LdrApiDefaultExtension
,
575 if (NT_SUCCESS(Status
))
578 RedirectedDll
= TRUE
;
580 else if (Status
!= STATUS_SXS_KEY_NOT_FOUND
)
582 /* Unrecoverable SxS failure; */
587 ASSERT(pRedirectName
== &RedirectName
);
590 /* Set default failure code */
591 Status
= STATUS_DLL_NOT_FOUND
;
593 /* Use the cache if we can */
594 if (LdrpGetModuleHandleCache
)
596 /* Check if we were redirected */
600 if (!(LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
))
605 /* Use the right name */
606 CompareName
= &LdrpGetModuleHandleCache
->FullDllName
;
611 if (LdrpGetModuleHandleCache
->Flags
& LDRP_REDIRECTED
)
616 /* Use the right name */
617 CompareName
= &LdrpGetModuleHandleCache
->BaseDllName
;
620 /* Check if the name matches */
621 if (RtlEqualUnicodeString(pRedirectName
,
626 LdrEntry
= LdrpGetModuleHandleCache
;
629 Status
= STATUS_SUCCESS
;
635 /* Find the name without the extension */
636 p1
= pRedirectName
->Buffer
;
638 p3
= &p1
[pRedirectName
->Length
/ sizeof(WCHAR
)];
645 else if (*p1
== L
'\\')
651 /* Check if no extension was found or if we got a slash */
652 if (!(p2
) || (*p2
== L
'\\') || (*p2
== L
'/'))
654 /* Check that we have space to add one */
655 Length
= pRedirectName
->Length
+
656 LdrApiDefaultExtension
.Length
+ sizeof(UNICODE_NULL
);
657 if (Length
>= UNICODE_STRING_MAX_BYTES
)
659 /* No space to add the extension */
660 Status
= STATUS_NAME_TOO_LONG
;
664 /* Setup the string */
665 RawDllName
.MaximumLength
= Length
;
666 ASSERT(Length
>= sizeof(UNICODE_NULL
));
667 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
669 RawDllName
.MaximumLength
);
670 if (!RawDllName
.Buffer
)
672 Status
= STATUS_NO_MEMORY
;
676 /* Copy the string and add extension */
677 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
678 RtlAppendUnicodeStringToString(&RawDllName
, &LdrApiDefaultExtension
);
682 /* Check if there's something in the name */
683 Length
= pRedirectName
->Length
;
686 /* Check and remove trailing period */
687 if (pRedirectName
->Buffer
[Length
/ sizeof(WCHAR
) - sizeof(ANSI_NULL
)] == '.')
689 /* Decrease the size */
690 pRedirectName
->Length
-= sizeof(WCHAR
);
694 /* Setup the string */
695 RawDllName
.MaximumLength
= pRedirectName
->Length
+ sizeof(WCHAR
);
696 RawDllName
.Buffer
= RtlAllocateHeap(RtlGetProcessHeap(),
698 RawDllName
.MaximumLength
);
699 if (!RawDllName
.Buffer
)
701 Status
= STATUS_NO_MEMORY
;
705 /* Copy the string */
706 RtlCopyUnicodeString(&RawDllName
, pRedirectName
);
709 /* Display debug string */
712 DPRINT1("LDR: LdrGetDllHandleEx, searching for %wZ from %ws\n",
714 DllPath
? ((ULONG_PTR
)DllPath
== 1 ? L
"" : DllPath
) : L
"");
718 if (LdrpCheckForLoadedDll(DllPath
,
720 ((ULONG_PTR
)DllPath
== 1) ? TRUE
: FALSE
,
724 /* Update cached entry */
725 LdrpGetModuleHandleCache
= LdrEntry
;
728 Status
= STATUS_SUCCESS
;
732 /* Make sure to NULL this */
736 /* The success path must have a valid loader entry */
737 ASSERT((LdrEntry
!= NULL
) == NT_SUCCESS(Status
));
739 /* Check if we got an entry and success */
740 DPRINT("Got LdrEntry->BaseDllName %wZ\n", LdrEntry
? &LdrEntry
->BaseDllName
: NULL
);
741 if ((LdrEntry
) && (NT_SUCCESS(Status
)))
743 /* Check if the DLL is locked */
744 if ((LdrEntry
->LoadCount
!= 0xFFFF) &&
745 !(Flags
& LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
))
747 /* Check what to do with the load count */
748 if (Flags
& LDR_GET_DLL_HANDLE_EX_PIN
)
751 LdrEntry
->LoadCount
= 0xFFFF;
752 LoadFlag
= LDRP_UPDATE_PIN
;
756 /* Increase the load count */
757 LdrEntry
->LoadCount
++;
758 LoadFlag
= LDRP_UPDATE_REFCOUNT
;
761 /* Update the load count now */
762 LdrpUpdateLoadCount2(LdrEntry
, LoadFlag
);
763 LdrpClearLoadInProgress();
766 /* Check if the caller is requesting the handle */
767 if (DllHandle
) *DllHandle
= LdrEntry
->DllBase
;
770 /* Free string if needed */
771 if (DllString1
.Buffer
) RtlFreeUnicodeString(&DllString1
);
773 /* Free the raw DLL Name if needed */
774 if (RawDllName
.Buffer
)
776 /* Free the heap-allocated buffer */
777 RtlFreeHeap(RtlGetProcessHeap(), 0, RawDllName
.Buffer
);
778 RawDllName
.Buffer
= NULL
;
784 LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
,
797 LdrGetDllHandle(IN PWSTR DllPath OPTIONAL
,
798 IN PULONG DllCharacteristics OPTIONAL
,
799 IN PUNICODE_STRING DllName
,
800 OUT PVOID
*DllHandle
)
802 /* Call the newer API */
803 return LdrGetDllHandleEx(LDR_GET_DLL_HANDLE_EX_UNCHANGED_REFCOUNT
,
815 LdrGetProcedureAddress(IN PVOID BaseAddress
,
816 IN PANSI_STRING Name
,
818 OUT PVOID
*ProcedureAddress
)
820 /* Call the internal routine and tell it to execute DllInit */
821 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
829 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
830 IN PLDR_CALLBACK Callback
,
831 IN PVOID CallbackContext
,
832 OUT PUSHORT ImageCharacteristics
)
834 FILE_STANDARD_INFORMATION FileStandardInfo
;
835 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
836 PIMAGE_SECTION_HEADER LastSection
= NULL
;
837 IO_STATUS_BLOCK IoStatusBlock
;
838 PIMAGE_NT_HEADERS NtHeader
;
839 HANDLE SectionHandle
;
842 BOOLEAN Result
, NoActualCheck
;
846 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
848 /* If the handle has the magic KnownDll flag, skip actual checksums */
849 NoActualCheck
= ((ULONG_PTR
)FileHandle
& 1);
851 /* Create the section */
852 Status
= NtCreateSection(&SectionHandle
,
859 if (!NT_SUCCESS(Status
))
861 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
865 /* Map the section */
868 Status
= NtMapViewOfSection(SectionHandle
,
878 if (!NT_SUCCESS(Status
))
880 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
881 NtClose(SectionHandle
);
885 /* Get the file information */
886 Status
= NtQueryInformationFile(FileHandle
,
889 sizeof(FILE_STANDARD_INFORMATION
),
890 FileStandardInformation
);
891 if (!NT_SUCCESS(Status
))
893 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
894 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
895 NtClose(SectionHandle
);
899 /* Protect with SEH */
902 /* Check if this is the KnownDll hack */
905 /* Don't actually do it */
910 /* Verify the checksum */
911 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
912 FileStandardInfo
.EndOfFile
.LowPart
,
913 FileStandardInfo
.EndOfFile
.LowPart
);
916 /* Check if a callback was supplied */
917 if ((Result
) && (Callback
))
919 /* Get the NT Header */
920 NtHeader
= RtlImageNtHeader(ViewBase
);
922 /* Check if caller requested this back */
923 if (ImageCharacteristics
)
925 /* Return to caller */
926 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
929 /* Get the Import Directory Data */
930 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
932 IMAGE_DIRECTORY_ENTRY_IMPORT
,
935 /* Make sure there is one */
938 /* Loop the imports */
939 while (ImportData
->Name
)
942 ImportName
= RtlImageRvaToVa(NtHeader
,
947 /* Notify the callback */
948 Callback(CallbackContext
, ImportName
);
954 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
956 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
961 /* Unmap file and close handle */
962 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
963 NtClose(SectionHandle
);
966 return Result
? Status
: STATUS_IMAGE_CHECKSUM_MISMATCH
;
971 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
973 OUT PRTL_PROCESS_MODULES ModuleInformation
,
975 OUT PULONG ReturnedSize OPTIONAL
)
977 PLIST_ENTRY ModuleListHead
, InitListHead
;
978 PLIST_ENTRY Entry
, InitEntry
;
979 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
980 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
981 NTSTATUS Status
= STATUS_SUCCESS
;
982 ULONG UsedSize
= sizeof(ULONG
);
983 ANSI_STRING AnsiString
;
986 DPRINT("LdrQueryProcessModuleInformation() called\n");
988 /* Acquire loader lock */
989 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
993 /* Check if we were given enough space */
996 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1000 ModuleInformation
->NumberOfModules
= 0;
1001 ModulePtr
= &ModuleInformation
->Modules
[0];
1002 Status
= STATUS_SUCCESS
;
1005 /* Traverse the list of modules */
1006 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1007 Entry
= ModuleListHead
->Flink
;
1009 while (Entry
!= ModuleListHead
)
1011 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1013 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
1015 /* Increase the used size */
1016 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
1018 if (UsedSize
> Size
)
1020 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1024 ModulePtr
->ImageBase
= Module
->DllBase
;
1025 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
1026 ModulePtr
->Flags
= Module
->Flags
;
1027 ModulePtr
->LoadCount
= Module
->LoadCount
;
1028 ModulePtr
->MappedBase
= NULL
;
1029 ModulePtr
->InitOrderIndex
= 0;
1030 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
1032 /* Now get init order index by traversing init list */
1033 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
1034 InitEntry
= InitListHead
->Flink
;
1036 while (InitEntry
!= InitListHead
)
1038 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
1040 /* Increase the index */
1041 ModulePtr
->InitOrderIndex
++;
1043 /* Quit the loop if our module is found */
1044 if (InitModule
== Module
) break;
1046 /* Advance to the next entry */
1047 InitEntry
= InitEntry
->Flink
;
1050 /* Prepare ANSI string with the module's name */
1051 AnsiString
.Length
= 0;
1052 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
1053 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
1054 RtlUnicodeStringToAnsiString(&AnsiString
,
1055 &Module
->FullDllName
,
1058 /* Calculate OffsetToFileName field */
1059 p
= strrchr(ModulePtr
->FullPathName
, '\\');
1061 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
1063 ModulePtr
->OffsetToFileName
= 0;
1065 /* Advance to the next module in the output list */
1068 /* Increase number of modules */
1069 if (ModuleInformation
)
1070 ModuleInformation
->NumberOfModules
++;
1073 /* Go to the next entry in the modules list */
1074 Entry
= Entry
->Flink
;
1077 /* Set returned size if it was provided */
1079 *ReturnedSize
= UsedSize
;
1081 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1083 /* Ignoring the exception */
1086 /* Release the lock */
1087 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
1089 DPRINT("LdrQueryProcessModuleInformation() done\n");
1099 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
1101 OUT PULONG ReturnedSize OPTIONAL
)
1103 /* Call Ex version of the API */
1104 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);
1112 LdrEnumerateLoadedModules(IN BOOLEAN ReservedFlag
,
1113 IN PLDR_ENUM_CALLBACK EnumProc
,
1116 PLIST_ENTRY ListHead
, ListEntry
;
1117 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1120 BOOLEAN Stop
= FALSE
;
1122 /* Check parameters */
1123 if ((ReservedFlag
) || !(EnumProc
)) return STATUS_INVALID_PARAMETER
;
1125 /* Acquire the loader lock */
1126 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1127 if (!NT_SUCCESS(Status
)) return Status
;
1129 /* Loop all the modules and call enum proc */
1130 ListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
1131 ListEntry
= ListHead
->Flink
;
1132 while (ListHead
!= ListEntry
)
1135 LdrEntry
= CONTAINING_RECORD(ListEntry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
1137 /* Call the enumeration proc inside SEH */
1140 EnumProc(LdrEntry
, Context
, &Stop
);
1142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1144 /* Ignoring the exception */
1147 /* Break if we were asked to stop enumeration */
1150 /* Release loader lock */
1151 Status
= LdrUnlockLoaderLock(0, Cookie
);
1153 /* Reset any successful status to STATUS_SUCCESS, but leave
1154 failure to the caller */
1155 if (NT_SUCCESS(Status
))
1156 Status
= STATUS_SUCCESS
;
1158 /* Return any possible failure status */
1162 /* Advance to the next module */
1163 ListEntry
= ListEntry
->Flink
;
1166 /* Release loader lock, it must succeed this time */
1167 Status
= LdrUnlockLoaderLock(0, Cookie
);
1168 ASSERT(NT_SUCCESS(Status
));
1170 /* Return success */
1171 return STATUS_SUCCESS
;
1179 LdrDisableThreadCalloutsForDll(IN PVOID BaseAddress
)
1181 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1185 DPRINT("LdrDisableThreadCalloutsForDll (BaseAddress %p)\n", BaseAddress
);
1187 /* Don't do it during shutdown */
1188 if (LdrpShutdownInProgress
) return STATUS_SUCCESS
;
1190 /* Check if we should grab the lock */
1195 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1196 if (!NT_SUCCESS(Status
)) return Status
;
1200 /* Make sure the DLL is valid and get its entry */
1201 Status
= STATUS_DLL_NOT_FOUND
;
1202 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1204 /* Get if it has a TLS slot */
1205 if (!LdrEntry
->TlsIndex
)
1207 /* It doesn't, so you're allowed to call this */
1208 LdrEntry
->Flags
|= LDRP_DONT_CALL_FOR_THREADS
;
1209 Status
= STATUS_SUCCESS
;
1213 /* Check if the lock was held */
1217 LdrUnlockLoaderLock(LDR_UNLOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1220 /* Return the status */
1229 LdrAddRefDll(IN ULONG Flags
,
1230 IN PVOID BaseAddress
)
1232 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1233 NTSTATUS Status
= STATUS_SUCCESS
;
1235 BOOLEAN Locked
= FALSE
;
1237 /* Check for invalid flags */
1238 if (Flags
& ~(LDR_ADDREF_DLL_PIN
))
1240 /* Fail with invalid parameter status if so */
1241 Status
= STATUS_INVALID_PARAMETER
;
1245 /* Acquire the loader lock if not in init phase */
1248 /* Acquire the lock */
1249 Status
= LdrLockLoaderLock(0, NULL
, &Cookie
);
1250 if (!NT_SUCCESS(Status
)) goto quickie
;
1254 /* Get this module's data table entry */
1255 if (LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1259 /* Shouldn't happen */
1260 Status
= STATUS_INTERNAL_ERROR
;
1264 /* If this is not a pinned module */
1265 if (LdrEntry
->LoadCount
!= 0xFFFF)
1267 /* Update its load count */
1268 if (Flags
& LDR_ADDREF_DLL_PIN
)
1270 /* Pin it by setting load count to -1 */
1271 LdrEntry
->LoadCount
= 0xFFFF;
1272 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_PIN
);
1276 /* Increase its load count by one */
1277 LdrEntry
->LoadCount
++;
1278 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_REFCOUNT
);
1281 /* Clear load in progress */
1282 LdrpClearLoadInProgress();
1287 /* There was an error getting this module's handle, return invalid param status */
1288 Status
= STATUS_INVALID_PARAMETER
;
1292 /* Check for error case */
1293 if (!NT_SUCCESS(Status
))
1295 /* Print debug information */
1296 if ((ShowSnaps
) || ((Status
!= STATUS_NO_SUCH_FILE
) &&
1297 (Status
!= STATUS_DLL_NOT_FOUND
) &&
1298 (Status
!= STATUS_OBJECT_NAME_NOT_FOUND
)))
1300 DPRINT1("LDR: LdrAddRefDll(%p) 0x%08lx\n", BaseAddress
, Status
);
1304 /* Release the lock if needed */
1305 if (Locked
) LdrUnlockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, Cookie
);
1314 LdrUnloadDll(IN PVOID BaseAddress
)
1316 NTSTATUS Status
= STATUS_SUCCESS
;
1317 PPEB Peb
= NtCurrentPeb();
1318 PLDR_DATA_TABLE_ENTRY LdrEntry
, CurrentEntry
;
1320 PLIST_ENTRY NextEntry
;
1321 LIST_ENTRY UnloadList
;
1322 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx
;
1324 ULONG ComSectionSize
;
1326 /* Get the LDR Lock */
1327 if (!LdrpInLdrInit
) RtlEnterCriticalSection(Peb
->LoaderLock
);
1329 /* Increase the unload count */
1330 LdrpActiveUnloadCount
++;
1333 if (LdrpShutdownInProgress
) goto Quickie
;
1335 /* Make sure the DLL is valid and get its entry */
1336 if (!LdrpCheckForLoadedDllHandle(BaseAddress
, &LdrEntry
))
1338 Status
= STATUS_DLL_NOT_FOUND
;
1342 /* Check the current Load Count */
1343 if (LdrEntry
->LoadCount
!= 0xFFFF)
1346 LdrEntry
->LoadCount
--;
1349 if (LdrEntry
->Flags
& LDRP_IMAGE_DLL
)
1351 /* Set up the Act Ctx */
1352 ActCtx
.Size
= sizeof(ActCtx
);
1353 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1354 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1356 /* Activate the ActCtx */
1357 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1358 LdrEntry
->EntryPointActivationContext
);
1360 /* Update the load count */
1361 LdrpUpdateLoadCount2(LdrEntry
, LDRP_UPDATE_DEREFCOUNT
);
1363 /* Release the context */
1364 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1369 /* The DLL is locked */
1373 /* Show debug message */
1374 if (ShowSnaps
) DPRINT1("LDR: UNINIT LIST\n");
1376 /* Check if this is our only unload and initialize the list if so */
1377 if (LdrpActiveUnloadCount
== 1) InitializeListHead(&LdrpUnloadHead
);
1379 /* Loop the modules to build the list */
1380 NextEntry
= Peb
->Ldr
->InInitializationOrderModuleList
.Blink
;
1381 while (NextEntry
!= &Peb
->Ldr
->InInitializationOrderModuleList
)
1384 LdrEntry
= CONTAINING_RECORD(NextEntry
,
1385 LDR_DATA_TABLE_ENTRY
,
1386 InInitializationOrderModuleList
);
1387 NextEntry
= NextEntry
->Blink
;
1390 LdrEntry
->Flags
&= ~LDRP_UNLOAD_IN_PROGRESS
;
1392 /* If the load count is now 0 */
1393 if (!LdrEntry
->LoadCount
)
1398 DPRINT1("(%lu) [%ws] %ws (%lx) deinit %p\n",
1399 LdrpActiveUnloadCount
,
1400 LdrEntry
->BaseDllName
.Buffer
,
1401 LdrEntry
->FullDllName
.Buffer
,
1402 (ULONG
)LdrEntry
->LoadCount
,
1403 LdrEntry
->EntryPoint
);
1406 /* FIXME: Call Shim Engine and notify */
1409 CurrentEntry
= LdrEntry
;
1410 RemoveEntryList(&CurrentEntry
->InInitializationOrderModuleList
);
1411 RemoveEntryList(&CurrentEntry
->InMemoryOrderModuleList
);
1412 RemoveEntryList(&CurrentEntry
->HashLinks
);
1414 /* If there's more then one active unload */
1415 if (LdrpActiveUnloadCount
> 1)
1417 /* Flush the cached DLL handle and clear the list */
1418 LdrpLoadedDllHandleCache
= NULL
;
1419 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1422 /* Add the entry on the unload list */
1423 InsertTailList(&LdrpUnloadHead
, &CurrentEntry
->HashLinks
);
1427 /* Only call the entrypoints once */
1428 if (LdrpActiveUnloadCount
> 1) goto Quickie
;
1430 /* Now loop the unload list and create our own */
1431 InitializeListHead(&UnloadList
);
1432 CurrentEntry
= NULL
;
1433 NextEntry
= LdrpUnloadHead
.Flink
;
1434 while (NextEntry
!= &LdrpUnloadHead
)
1436 /* Get the current entry */
1437 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1439 /* FIXME: Log the Unload Event */
1440 //LdrpRecordUnloadEvent(LdrEntry);
1442 /* Set the entry and clear it from the list */
1443 CurrentEntry
= LdrEntry
;
1444 LdrpLoadedDllHandleCache
= NULL
;
1445 CurrentEntry
->InMemoryOrderModuleList
.Flink
= NULL
;
1447 /* Move it from the global to the local list */
1448 RemoveEntryList(&CurrentEntry
->HashLinks
);
1449 InsertTailList(&UnloadList
, &CurrentEntry
->HashLinks
);
1451 /* Get the entrypoint */
1452 EntryPoint
= LdrEntry
->EntryPoint
;
1454 /* Check if we should call it */
1455 if ((EntryPoint
) && (LdrEntry
->Flags
& LDRP_PROCESS_ATTACH_CALLED
))
1460 DPRINT1("LDR: Calling deinit %p\n", EntryPoint
);
1463 /* Set up the Act Ctx */
1464 ActCtx
.Size
= sizeof(ActCtx
);
1465 ActCtx
.Format
= RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER
;
1466 RtlZeroMemory(&ActCtx
.Frame
, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME
));
1468 /* Activate the ActCtx */
1469 RtlActivateActivationContextUnsafeFast(&ActCtx
,
1470 LdrEntry
->EntryPointActivationContext
);
1472 /* Call the entrypoint */
1473 LdrpCallInitRoutine(LdrEntry
->EntryPoint
,
1478 /* Release the context */
1479 RtlDeactivateActivationContextUnsafeFast(&ActCtx
);
1482 /* Remove it from the list */
1483 RemoveEntryList(&CurrentEntry
->InLoadOrderLinks
);
1484 CurrentEntry
= NULL
;
1485 NextEntry
= LdrpUnloadHead
.Flink
;
1488 /* Now loop our local list */
1489 NextEntry
= UnloadList
.Flink
;
1490 while (NextEntry
!= &UnloadList
)
1493 LdrEntry
= CONTAINING_RECORD(NextEntry
, LDR_DATA_TABLE_ENTRY
, HashLinks
);
1494 NextEntry
= NextEntry
->Flink
;
1495 CurrentEntry
= LdrEntry
;
1497 /* Notify Application Verifier */
1498 if (Peb
->NtGlobalFlag
& FLG_HEAP_ENABLE_TAIL_CHECK
)
1500 DPRINT1("We don't support Application Verifier yet\n");
1506 DPRINT1("LDR: Unmapping [%ws]\n", LdrEntry
->BaseDllName
.Buffer
);
1509 /* Check if this is a .NET executable */
1510 CorImageData
= RtlImageDirectoryEntryToData(LdrEntry
->DllBase
,
1512 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR
,
1517 DPRINT1(".NET Images are not supported yet\n");
1520 /* Check if we should unmap*/
1521 if (!(CurrentEntry
->Flags
& LDR_COR_OWNS_UNMAP
))
1524 Status
= NtUnmapViewOfSection(NtCurrentProcess(),
1525 CurrentEntry
->DllBase
);
1526 ASSERT(NT_SUCCESS(Status
));
1529 /* Unload the alternate resource module, if any */
1530 LdrUnloadAlternateResourceModule(CurrentEntry
->DllBase
);
1532 /* FIXME: Send shutdown notification */
1533 //LdrpSendDllNotifications(CurrentEntry, 2, LdrpShutdownInProgress);
1535 /* Check if a Hotpatch is active */
1536 if (LdrEntry
->PatchInformation
)
1539 DPRINT1("We don't support Hotpatching yet\n");
1542 /* Deallocate the Entry */
1543 LdrpFinalizeAndDeallocateDataTableEntry(CurrentEntry
);
1545 /* If this is the cached entry, invalidate it */
1546 if (LdrpGetModuleHandleCache
== CurrentEntry
)
1548 LdrpGetModuleHandleCache
= NULL
;
1553 /* Decrease unload count */
1554 LdrpActiveUnloadCount
--;
1555 if (!LdrpInLdrInit
) RtlLeaveCriticalSection(Peb
->LoaderLock
);
1557 /* Return to caller */
1566 RtlDllShutdownInProgress(VOID
)
1568 /* Return the internal global */
1569 return LdrpShutdownInProgress
;
1575 PIMAGE_BASE_RELOCATION
1577 LdrProcessRelocationBlock(IN ULONG_PTR Address
,
1579 IN PUSHORT TypeOffset
,
1582 return LdrProcessRelocationBlockLongLong(Address
, Count
, TypeOffset
, Delta
);
1585 /* FIXME: Add to ntstatus.mc */
1586 #define STATUS_MUI_FILE_NOT_FOUND ((NTSTATUS)0xC00B0001L)
1593 LdrLoadAlternateResourceModule(IN PVOID Module
,
1596 /* Is MUI Support enabled? */
1597 if (!LdrAlternateResourcesEnabled()) return STATUS_SUCCESS
;
1600 return STATUS_MUI_FILE_NOT_FOUND
;
1608 LdrUnloadAlternateResourceModule(IN PVOID BaseAddress
)
1612 /* Acquire the loader lock */
1613 LdrLockLoaderLock(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_ON_ERRORS
, NULL
, &Cookie
);
1615 /* Check if there's any alternate resources loaded */
1616 if (AlternateResourceModuleCount
)
1621 /* Release the loader lock */
1622 LdrUnlockLoaderLock(1, Cookie
);
1633 LdrFlushAlternateResourceModules(VOID
)