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 #define LDR_LOCK_HELD 0x2
19 #define LDR_LOCK_FREE 0x1
21 LONG LdrpLoaderLockAcquisitonCount
;
23 /* FUNCTIONS *****************************************************************/
30 LdrUnlockLoaderLock(IN ULONG Flags
,
31 IN ULONG Cookie OPTIONAL
)
33 NTSTATUS Status
= STATUS_SUCCESS
;
35 DPRINT("LdrUnlockLoaderLock(%x %x)\n", Flags
, Cookie
);
37 /* Check for valid flags */
40 /* Flags are invalid, check how to fail */
41 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
43 /* The caller wants us to raise status */
44 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
48 /* A normal failure */
49 return STATUS_INVALID_PARAMETER_1
;
53 /* If we don't have a cookie, just return */
54 if (!Cookie
) return STATUS_SUCCESS
;
56 /* Validate the cookie */
57 if ((Cookie
& 0xF0000000) ||
58 ((Cookie
>> 16) ^ ((ULONG
)(NtCurrentTeb()->RealClientId
.UniqueThread
) & 0xFFF)))
60 DPRINT1("LdrUnlockLoaderLock() called with an invalid cookie!\n");
62 /* Invalid cookie, check how to fail */
63 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
65 /* The caller wants us to raise status */
66 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
70 /* A normal failure */
71 return STATUS_INVALID_PARAMETER_2
;
75 /* Ready to release the lock */
76 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
78 /* Do a direct leave */
79 RtlLeaveCriticalSection(&LdrpLoaderLock
);
83 /* Wrap this in SEH, since we're not supposed to raise */
87 RtlLeaveCriticalSection(&LdrpLoaderLock
);
89 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
91 /* We should use the LDR Filter instead */
92 Status
= _SEH2_GetExceptionCode();
106 LdrLockLoaderLock(IN ULONG Flags
,
107 OUT PULONG Result OPTIONAL
,
108 OUT PULONG Cookie OPTIONAL
)
111 NTSTATUS Status
= STATUS_SUCCESS
;
112 BOOLEAN InInit
= LdrpInLdrInit
;
114 DPRINT("LdrLockLoaderLock(%x %p %p)\n", Flags
, Result
, Cookie
);
116 /* Zero out the outputs */
117 if (Result
) *Result
= 0;
118 if (Cookie
) *Cookie
= 0;
120 /* Validate the flags */
121 if (Flags
& ~(LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
|
122 LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
))
124 /* Flags are invalid, check how to fail */
125 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
127 /* The caller wants us to raise status */
128 RtlRaiseStatus(STATUS_INVALID_PARAMETER_1
);
131 /* A normal failure */
132 return STATUS_INVALID_PARAMETER_1
;
135 /* Make sure we got a cookie */
138 /* No cookie check how to fail */
139 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
141 /* The caller wants us to raise status */
142 RtlRaiseStatus(STATUS_INVALID_PARAMETER_3
);
145 /* A normal failure */
146 return STATUS_INVALID_PARAMETER_3
;
149 /* If the flag is set, make sure we have a valid pointer to use */
150 if ((Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
) && !(Result
))
152 /* No pointer to return the data to */
153 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
155 /* The caller wants us to raise status */
156 RtlRaiseStatus(STATUS_INVALID_PARAMETER_2
);
160 return STATUS_INVALID_PARAMETER_2
;
163 /* Return now if we are in the init phase */
164 if (InInit
) return STATUS_SUCCESS
;
166 /* Check what locking semantic to use */
167 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_RAISE_STATUS
)
169 /* Check if we should enter or simply try */
170 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
173 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
176 *Result
= LDR_LOCK_HELD
;
182 *Result
= LDR_LOCK_FREE
;
188 RtlEnterCriticalSection(&LdrpLoaderLock
);
190 /* See if result was requested */
191 if (Result
) *Result
= LDR_LOCK_FREE
;
194 /* Increase the acquisition count */
195 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
197 /* Generate a cookie */
198 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
202 /* Wrap this in SEH, since we're not supposed to raise */
205 /* Check if we should enter or simply try */
206 if (Flags
& LDR_LOCK_LOADER_LOCK_FLAG_TRY_ONLY
)
209 if (!RtlTryEnterCriticalSection(&LdrpLoaderLock
))
212 *Result
= LDR_LOCK_HELD
;
213 _SEH2_YIELD(return STATUS_SUCCESS
);
218 *Result
= LDR_LOCK_FREE
;
224 RtlEnterCriticalSection(&LdrpLoaderLock
);
226 /* See if result was requested */
227 if (Result
) *Result
= LDR_LOCK_FREE
;
230 /* Increase the acquisition count */
231 OldCount
= _InterlockedIncrement(&LdrpLoaderLockAcquisitonCount
);
233 /* Generate a cookie */
234 *Cookie
= (((ULONG
)NtCurrentTeb()->RealClientId
.UniqueThread
& 0xFFF) << 16) | OldCount
;
236 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
238 /* We should use the LDR Filter instead */
239 Status
= _SEH2_GetExceptionCode();
253 LdrVerifyImageMatchesChecksum(IN HANDLE FileHandle
,
254 IN PLDR_CALLBACK Callback
,
255 IN PVOID CallbackContext
,
256 OUT PUSHORT ImageCharacteristics
)
258 FILE_STANDARD_INFORMATION FileStandardInfo
;
259 PIMAGE_IMPORT_DESCRIPTOR ImportData
;
260 PIMAGE_SECTION_HEADER LastSection
;
261 IO_STATUS_BLOCK IoStatusBlock
;
262 PIMAGE_NT_HEADERS NtHeader
;
263 HANDLE SectionHandle
;
265 PVOID ViewBase
= NULL
;
271 DPRINT("LdrVerifyImageMatchesChecksum() called\n");
273 /* Create the section */
274 Status
= NtCreateSection(&SectionHandle
,
281 if (!NT_SUCCESS(Status
))
283 DPRINT1 ("NtCreateSection() failed (Status 0x%x)\n", Status
);
287 /* Map the section */
288 Status
= NtMapViewOfSection(SectionHandle
,
298 if (!NT_SUCCESS(Status
))
300 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
301 NtClose(SectionHandle
);
305 /* Get the file information */
306 Status
= NtQueryInformationFile(FileHandle
,
309 sizeof(FILE_STANDARD_INFORMATION
),
310 FileStandardInformation
);
311 if (!NT_SUCCESS(Status
))
313 DPRINT1("NtMapViewOfSection() failed (Status 0x%x)\n", Status
);
314 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
315 NtClose(SectionHandle
);
319 /* Protect with SEH */
322 /* Verify the checksum */
323 Result
= LdrVerifyMappedImageMatchesChecksum(ViewBase
,
325 FileStandardInfo
.EndOfFile
.LowPart
);
327 /* Check if a callback was supplied */
328 if (Result
&& Callback
)
330 /* Get the NT Header */
331 NtHeader
= RtlImageNtHeader(ViewBase
);
333 /* Check if caller requested this back */
334 if (ImageCharacteristics
)
336 /* Return to caller */
337 *ImageCharacteristics
= NtHeader
->FileHeader
.Characteristics
;
340 /* Get the Import Directory Data */
341 ImportData
= RtlImageDirectoryEntryToData(ViewBase
,
343 IMAGE_DIRECTORY_ENTRY_IMPORT
,
346 /* Make sure there is one */
349 /* Loop the imports */
350 while (ImportData
->Name
)
353 ImportName
= RtlImageRvaToVa(NtHeader
,
358 /* Notify the callback */
359 Callback(CallbackContext
, ImportName
);
365 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
367 /* Fail the request returning STATUS_IMAGE_CHECKSUM_MISMATCH */
372 /* Unmap file and close handle */
373 NtUnmapViewOfSection(NtCurrentProcess(), ViewBase
);
374 NtClose(SectionHandle
);
377 return !Result
? STATUS_IMAGE_CHECKSUM_MISMATCH
: Status
;
385 LdrGetProcedureAddress_(IN PVOID BaseAddress
,
386 IN PANSI_STRING Name
,
388 OUT PVOID
*ProcedureAddress
)
390 /* Call the internal routine and tell it to execute DllInit */
391 return LdrpGetProcedureAddress(BaseAddress
, Name
, Ordinal
, ProcedureAddress
, TRUE
);
397 LdrQueryProcessModuleInformationEx(IN ULONG ProcessId
,
399 IN PRTL_PROCESS_MODULES ModuleInformation
,
401 OUT PULONG ReturnedSize OPTIONAL
)
403 PLIST_ENTRY ModuleListHead
, InitListHead
;
404 PLIST_ENTRY Entry
, InitEntry
;
405 PLDR_DATA_TABLE_ENTRY Module
, InitModule
;
406 PRTL_PROCESS_MODULE_INFORMATION ModulePtr
= NULL
;
407 NTSTATUS Status
= STATUS_SUCCESS
;
408 ULONG UsedSize
= sizeof(ULONG
);
409 ANSI_STRING AnsiString
;
412 DPRINT("LdrQueryProcessModuleInformation() called\n");
414 /* Acquire loader lock */
415 RtlEnterCriticalSection(NtCurrentPeb()->LoaderLock
);
417 /* Check if we were given enough space */
420 Status
= STATUS_INFO_LENGTH_MISMATCH
;
424 ModuleInformation
->NumberOfModules
= 0;
425 ModulePtr
= &ModuleInformation
->Modules
[0];
426 Status
= STATUS_SUCCESS
;
429 /* Traverse the list of modules */
432 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
433 Entry
= ModuleListHead
->Flink
;
435 while (Entry
!= ModuleListHead
)
437 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
439 DPRINT(" Module %wZ\n", &Module
->FullDllName
);
441 /* Increase the used size */
442 UsedSize
+= sizeof(RTL_PROCESS_MODULE_INFORMATION
);
446 Status
= STATUS_INFO_LENGTH_MISMATCH
;
450 ModulePtr
->ImageBase
= Module
->DllBase
;
451 ModulePtr
->ImageSize
= Module
->SizeOfImage
;
452 ModulePtr
->Flags
= Module
->Flags
;
453 ModulePtr
->LoadCount
= Module
->LoadCount
;
454 ModulePtr
->MappedBase
= NULL
;
455 ModulePtr
->InitOrderIndex
= 0;
456 ModulePtr
->LoadOrderIndex
= ModuleInformation
->NumberOfModules
;
458 /* Now get init order index by traversing init list */
459 InitListHead
= &NtCurrentPeb()->Ldr
->InInitializationOrderModuleList
;
460 InitEntry
= InitListHead
->Flink
;
462 while (InitEntry
!= InitListHead
)
464 InitModule
= CONTAINING_RECORD(InitEntry
, LDR_DATA_TABLE_ENTRY
, InInitializationOrderModuleList
);
466 /* Increase the index */
467 ModulePtr
->InitOrderIndex
++;
469 /* Quit the loop if our module is found */
470 if (InitModule
== Module
) break;
472 /* Advance to the next entry */
473 InitEntry
= InitEntry
->Flink
;
476 /* Prepare ANSI string with the module's name */
477 AnsiString
.Length
= 0;
478 AnsiString
.MaximumLength
= sizeof(ModulePtr
->FullPathName
);
479 AnsiString
.Buffer
= ModulePtr
->FullPathName
;
480 RtlUnicodeStringToAnsiString(&AnsiString
,
481 &Module
->FullDllName
,
484 /* Calculate OffsetToFileName field */
485 p
= strrchr(ModulePtr
->FullPathName
, '\\');
487 ModulePtr
->OffsetToFileName
= p
- ModulePtr
->FullPathName
+ 1;
489 ModulePtr
->OffsetToFileName
= 0;
491 /* Advance to the next module in the output list */
494 /* Increase number of modules */
495 if (ModuleInformation
)
496 ModuleInformation
->NumberOfModules
++;
499 /* Go to the next entry in the modules list */
500 Entry
= Entry
->Flink
;
503 /* Set returned size if it was provided */
505 *ReturnedSize
= UsedSize
;
507 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
509 /* Ignoring the exception */
512 /* Release the lock */
513 RtlLeaveCriticalSection(NtCurrentPeb()->LoaderLock
);
515 DPRINT("LdrQueryProcessModuleInformation() done\n");
525 LdrQueryProcessModuleInformation(IN PRTL_PROCESS_MODULES ModuleInformation
,
527 OUT PULONG ReturnedSize OPTIONAL
)
529 /* Call Ex version of the API */
530 return LdrQueryProcessModuleInformationEx(0, 0, ModuleInformation
, Size
, ReturnedSize
);