2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT User-Mode DLL
4 * FILE: lib/ntdll/rtl/libsup.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES *****************************************************************/
17 SIZE_T RtlpAllocDeallocQueryBufferSize
= PAGE_SIZE
;
18 PTEB LdrpTopLevelDllBeingLoadedTeb
= NULL
;
19 PVOID MmHighestUserAddress
= (PVOID
)MI_HIGHEST_USER_ADDRESS
;
21 /* FUNCTIONS ***************************************************************/
25 RtlpCheckForActiveDebugger(VOID
)
27 /* Return the flag in the PEB */
28 return NtCurrentPeb()->BeingDebugged
;
33 RtlpSetInDbgPrint(VOID
)
35 /* Check if it's already set and return TRUE if so */
36 if (NtCurrentTeb()->InDbgPrint
) return TRUE
;
38 /* Set it and return */
39 NtCurrentTeb()->InDbgPrint
= TRUE
;
45 RtlpClearInDbgPrint(VOID
)
48 NtCurrentTeb()->InDbgPrint
= FALSE
;
63 RtlGetCurrentPeb(VOID
)
65 return NtCurrentPeb();
72 RtlAcquirePebLock(VOID
)
74 PPEB Peb
= NtCurrentPeb ();
75 RtlEnterCriticalSection(Peb
->FastPebLock
);
82 RtlReleasePebLock(VOID
)
84 PPEB Peb
= NtCurrentPeb ();
85 RtlLeaveCriticalSection(Peb
->FastPebLock
);
93 RtlGetNtGlobalFlags(VOID
)
95 PPEB pPeb
= NtCurrentPeb();
96 return pPeb
->NtGlobalFlag
;
101 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock
)
103 return RtlDeleteCriticalSection(&Lock
->CriticalSection
);
108 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
110 UNREFERENCED_PARAMETER(Exclusive
);
112 return RtlEnterCriticalSection(&Lock
->CriticalSection
);
117 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
119 UNREFERENCED_PARAMETER(Exclusive
);
121 return RtlTryEnterCriticalSection(&Lock
->CriticalSection
);
126 RtlInitializeHeapLock(IN OUT PHEAP_LOCK
*Lock
)
128 return RtlInitializeCriticalSection(&(*Lock
)->CriticalSection
);
133 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock
)
135 return RtlLeaveCriticalSection(&Lock
->CriticalSection
);
140 RtlpAllocateMemory(UINT Bytes
,
143 UNREFERENCED_PARAMETER(Tag
);
145 return RtlAllocateHeap(RtlGetProcessHeap(),
153 RtlpFreeMemory(PVOID Mem
,
156 UNREFERENCED_PARAMETER(Tag
);
158 RtlFreeHeap(RtlGetProcessHeap(),
166 CHECK_PAGED_CODE_RTL(char *file
, int line
)
168 /* meaningless in user mode */
174 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters
)
179 Peb
= RtlGetCurrentPeb();
181 /* Apply defaults for non-set parameters */
182 if (!Parameters
->SegmentCommit
) Parameters
->SegmentCommit
= Peb
->HeapSegmentCommit
;
183 if (!Parameters
->SegmentReserve
) Parameters
->SegmentReserve
= Peb
->HeapSegmentReserve
;
184 if (!Parameters
->DeCommitFreeBlockThreshold
) Parameters
->DeCommitFreeBlockThreshold
= Peb
->HeapDeCommitFreeBlockThreshold
;
185 if (!Parameters
->DeCommitTotalFreeThreshold
) Parameters
->DeCommitTotalFreeThreshold
= Peb
->HeapDeCommitTotalFreeThreshold
;
190 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
191 IN ULONG_PTR RegistrationFrameEnd
,
192 IN OUT PULONG_PTR StackLow
,
193 IN OUT PULONG_PTR StackHigh
)
195 /* There's no such thing as a DPC stack in user-mode */
201 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
202 IN PCONTEXT ContextRecord
,
203 IN PVOID ContextData
,
206 /* Exception logging is not done in user-mode */
211 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
212 IN ULONG_PTR
*StackBegin
,
213 IN ULONG_PTR
*StackEnd
)
216 *StackBegin
= (ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
;
217 *StackEnd
= (ULONG_PTR
)NtCurrentTeb()->NtTib
.StackBase
;
227 RtlWalkFrameChain(OUT PVOID
*Callers
,
231 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
233 BOOLEAN Result
, StopSearch
= FALSE
;
236 /* Get current EBP */
239 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
240 #elif defined(_MSC_VER)
243 #elif defined(_M_MIPS)
244 __asm__("move $sp, %0" : "=r" (Stack
) : );
245 #elif defined(_M_PPC)
246 __asm__("mr %0,1" : "=r" (Stack
) : );
247 #elif defined(_M_ARM)
248 __asm__("mov sp, %0" : "=r"(Stack
) : );
250 #error Unknown architecture
253 /* Set it as the stack begin limit as well */
254 StackBegin
= (ULONG_PTR
)Stack
;
256 /* Check if we're called for non-logging mode */
259 /* Get the actual safe limits */
260 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
263 if (!Result
) return 0;
266 /* Use a SEH block for maximum protection */
269 /* Loop the frames */
270 for (i
= 0; i
< Count
; i
++)
273 * Leave if we're past the stack,
274 * if we're before the stack,
275 * or if we've reached ourselves.
277 if ((Stack
>= StackEnd
) ||
278 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
279 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
281 /* We're done or hit a bad address */
285 /* Get new stack and EIP */
286 NewStack
= *(PULONG_PTR
)Stack
;
287 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
289 /* Check if the new pointer is above the oldone and past the end */
290 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
292 /* Stop searching after this entry */
296 /* Also make sure that the EIP isn't a stack address */
297 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
299 /* FIXME: Check that EIP is inside a loaded module */
301 /* Save this frame */
302 Callers
[i
] = (PVOID
)Eip
;
304 /* Check if we should continue */
307 /* Return the next index */
312 /* Move to the next stack */
316 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
323 /* Return frames parsed */
332 OUT PULONG_PTR LowLimit
,
333 OUT PULONG_PTR HighLimit
)
335 *LowLimit
= (ULONG_PTR
)NtCurrentTeb()->NtTib
.StackLimit
;
336 *HighLimit
= (ULONG_PTR
)NtCurrentTeb()->NtTib
.StackBase
;
343 RtlIsThreadWithinLoaderCallout(VOID
)
345 return LdrpTopLevelDllBeingLoadedTeb
== NtCurrentTeb();
348 /* RTL Atom Tables ************************************************************/
350 typedef struct _RTL_ATOM_HANDLE
352 RTL_HANDLE_TABLE_ENTRY Handle
;
353 PRTL_ATOM_TABLE_ENTRY AtomEntry
;
354 } RTL_ATOM_HANDLE
, *PRTL_ATOM_HANDLE
;
357 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
359 RtlInitializeCriticalSection(&AtomTable
->CriticalSection
);
360 return STATUS_SUCCESS
;
365 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
367 RtlDeleteCriticalSection(&AtomTable
->CriticalSection
);
372 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
374 RtlEnterCriticalSection(&AtomTable
->CriticalSection
);
380 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
382 RtlLeaveCriticalSection(&AtomTable
->CriticalSection
);
386 /* handle functions */
389 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
391 RtlInitializeHandleTable(0xCFFF,
392 sizeof(RTL_ATOM_HANDLE
),
393 &AtomTable
->RtlHandleTable
);
399 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
401 RtlDestroyHandleTable(&AtomTable
->RtlHandleTable
);
405 RtlpAllocAtomTable(ULONG Size
)
407 return (PRTL_ATOM_TABLE
)RtlAllocateHeap(RtlGetProcessHeap(),
413 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
415 RtlFreeHeap(RtlGetProcessHeap(),
420 PRTL_ATOM_TABLE_ENTRY
421 RtlpAllocAtomTableEntry(ULONG Size
)
423 return (PRTL_ATOM_TABLE_ENTRY
)RtlAllocateHeap(RtlGetProcessHeap(),
429 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
431 RtlFreeHeap(RtlGetProcessHeap(),
437 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
439 PRTL_HANDLE_TABLE_ENTRY RtlHandleEntry
;
441 if (RtlIsValidIndexHandle(&AtomTable
->RtlHandleTable
,
442 (ULONG
)Entry
->HandleIndex
,
445 RtlFreeHandle(&AtomTable
->RtlHandleTable
,
451 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
454 PRTL_HANDLE_TABLE_ENTRY RtlHandle
;
456 RtlHandle
= RtlAllocateHandle(&AtomTable
->RtlHandleTable
,
458 if (RtlHandle
!= NULL
)
460 PRTL_ATOM_HANDLE AtomHandle
= (PRTL_ATOM_HANDLE
)RtlHandle
;
462 /* FIXME - Handle Indexes >= 0xC000 ?! */
463 if (HandleIndex
< 0xC000)
465 Entry
->HandleIndex
= (USHORT
)HandleIndex
;
466 Entry
->Atom
= 0xC000 + (USHORT
)HandleIndex
;
468 AtomHandle
->AtomEntry
= Entry
;
469 AtomHandle
->Handle
.Flags
= RTL_HANDLE_VALID
;
475 /* set the valid flag, otherwise RtlFreeHandle will fail! */
476 AtomHandle
->Handle
.Flags
= RTL_HANDLE_VALID
;
478 RtlFreeHandle(&AtomTable
->RtlHandleTable
,
486 PRTL_ATOM_TABLE_ENTRY
487 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
489 PRTL_HANDLE_TABLE_ENTRY RtlHandle
;
491 if (RtlIsValidIndexHandle(&AtomTable
->RtlHandleTable
,
495 PRTL_ATOM_HANDLE AtomHandle
= (PRTL_ATOM_HANDLE
)RtlHandle
;
497 return AtomHandle
->AtomEntry
;
505 * Ldr Resource support code
508 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
509 LPCWSTR name
, void *root
,
511 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
512 WORD id
, void *root
, int want_dir
);
513 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
514 void *root
, int want_dir
);
515 int push_language( USHORT
*list
, ULONG pos
, WORD lang
);
517 /**********************************************************************
520 * Find a resource entry
522 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
523 ULONG level
, void **ret
, int want_dir
)
527 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
528 USHORT list
[9]; /* list of languages to try */
530 LCID user_lcid
, system_lcid
;
532 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
533 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
534 if (size
< sizeof(*resdirptr
)) return STATUS_RESOURCE_DATA_NOT_FOUND
;
537 if (!level
--) goto done
;
538 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
539 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
540 if (!level
--) return STATUS_SUCCESS
;
543 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
544 return STATUS_RESOURCE_NAME_NOT_FOUND
;
545 if (!level
--) return STATUS_SUCCESS
;
546 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
548 /* 1. specified language */
549 pos
= push_language( list
, pos
, info
->Language
);
551 /* 2. specified language with neutral sublanguage */
552 pos
= push_language( list
, pos
, MAKELANGID( PRIMARYLANGID(info
->Language
), SUBLANG_NEUTRAL
) );
554 /* 3. neutral language with neutral sublanguage */
555 pos
= push_language( list
, pos
, MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
557 /* if no explicitly specified language, try some defaults */
558 if (PRIMARYLANGID(info
->Language
) == LANG_NEUTRAL
)
560 /* user defaults, unless SYS_DEFAULT sublanguage specified */
561 if (SUBLANGID(info
->Language
) != SUBLANG_SYS_DEFAULT
)
563 /* 4. current thread locale language */
564 pos
= push_language( list
, pos
, LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale
) );
566 if (NT_SUCCESS(NtQueryDefaultLocale(TRUE
, &user_lcid
)))
568 /* 5. user locale language */
569 pos
= push_language( list
, pos
, LANGIDFROMLCID(user_lcid
) );
571 /* 6. user locale language with neutral sublanguage */
572 pos
= push_language( list
, pos
, MAKELANGID( PRIMARYLANGID(user_lcid
), SUBLANG_NEUTRAL
) );
576 /* now system defaults */
578 if (NT_SUCCESS(NtQueryDefaultLocale(FALSE
, &system_lcid
)))
580 /* 7. system locale language */
581 pos
= push_language( list
, pos
, LANGIDFROMLCID( system_lcid
) );
583 /* 8. system locale language with neutral sublanguage */
584 pos
= push_language( list
, pos
, MAKELANGID( PRIMARYLANGID(system_lcid
), SUBLANG_NEUTRAL
) );
588 pos
= push_language( list
, pos
, MAKELANGID( LANG_ENGLISH
, SUBLANG_DEFAULT
) );
592 for (i
= 0; i
< pos
; i
++)
593 if ((*ret
= find_entry_by_id( resdirptr
, list
[i
], root
, want_dir
))) return STATUS_SUCCESS
;
595 /* if no explicitly specified language, return the first entry */
596 if (PRIMARYLANGID(info
->Language
) == LANG_NEUTRAL
)
598 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
600 return STATUS_RESOURCE_LANG_NOT_FOUND
;
604 return STATUS_SUCCESS
;
611 RtlPcToFileHeader(IN PVOID PcValue
,
614 PLIST_ENTRY ModuleListHead
;
616 PLDR_DATA_TABLE_ENTRY Module
;
617 PVOID ImageBase
= NULL
;
619 RtlEnterCriticalSection (NtCurrentPeb()->LoaderLock
);
620 ModuleListHead
= &NtCurrentPeb()->Ldr
->InLoadOrderModuleList
;
621 Entry
= ModuleListHead
->Flink
;
622 while (Entry
!= ModuleListHead
)
624 Module
= CONTAINING_RECORD(Entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderLinks
);
626 if ((ULONG_PTR
)PcValue
>= (ULONG_PTR
)Module
->DllBase
&&
627 (ULONG_PTR
)PcValue
< (ULONG_PTR
)Module
->DllBase
+ Module
->SizeOfImage
)
629 ImageBase
= Module
->DllBase
;
632 Entry
= Entry
->Flink
;
634 RtlLeaveCriticalSection (NtCurrentPeb()->LoaderLock
);
636 *BaseOfImage
= ImageBase
;
646 RtlDosApplyFileIsolationRedirection_Ustr(IN ULONG Flags
,
647 IN PUNICODE_STRING OriginalName
,
648 IN PUNICODE_STRING Extension
,
649 IN OUT PUNICODE_STRING StaticString
,
650 IN OUT PUNICODE_STRING DynamicString
,
651 IN OUT PUNICODE_STRING
*NewName
,
653 IN PSIZE_T FileNameSize
,
654 IN PSIZE_T RequiredLength
)
656 return STATUS_SXS_KEY_NOT_FOUND
;
665 RtlWow64EnableFsRedirection(IN BOOLEAN Wow64FsEnableRedirection
)
667 /* This is what Windows returns on x86 */
668 return STATUS_NOT_IMPLEMENTED
;
677 RtlWow64EnableFsRedirectionEx(IN PVOID Wow64FsEnableRedirection
,
678 OUT PVOID
*OldFsRedirectionLevel
)
680 /* This is what Windows returns on x86 */
681 return STATUS_NOT_IMPLEMENTED
;
690 RtlComputeImportTableHash(IN HANDLE FileHandle
,
692 IN ULONG ImportTableHashSize
)
695 return STATUS_NOT_IMPLEMENTED
;
701 _Out_writes_bytes_all_(Length
) VOID UNALIGNED
*Destination
,
702 _In_reads_bytes_(Length
) CONST VOID UNALIGNED
*Source
,
707 RtlCopyMemory(Destination
, Source
, Length
);
709 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
711 _SEH2_YIELD(return _SEH2_GetExceptionCode());
715 return STATUS_SUCCESS
;
718 /* FIXME: code duplication with kernel32/client/time.c */
721 RtlGetTickCount(VOID
)
723 ULARGE_INTEGER TickCount
;
726 TickCount
.QuadPart
= *((volatile ULONG64
*)&SharedUserData
->TickCount
);
730 TickCount
.HighPart
= (ULONG
)SharedUserData
->TickCount
.High1Time
;
731 TickCount
.LowPart
= SharedUserData
->TickCount
.LowPart
;
733 if (TickCount
.HighPart
== (ULONG
)SharedUserData
->TickCount
.High2Time
)
740 return (ULONG
)((UInt32x32To64(TickCount
.LowPart
,
741 SharedUserData
->TickCountMultiplier
) >> 24) +
742 UInt32x32To64((TickCount
.HighPart
<< 8) & 0xFFFFFFFF,
743 SharedUserData
->TickCountMultiplier
));