2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/rtl/libsupp.c
5 * PURPOSE: RTL Support Routines
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
16 #define TAG_ATMT 'TotA' /* Atom table */
17 #define TAG_RTHL 'LHtR' /* Heap Lock */
19 extern ULONG NtGlobalFlag
;
21 typedef struct _RTL_RANGE_ENTRY
25 } RTL_RANGE_ENTRY
, *PRTL_RANGE_ENTRY
;
27 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList
;
28 SIZE_T RtlpAllocDeallocQueryBufferSize
= 128;
30 /* FUNCTIONS *****************************************************************/
36 OUT PVOID
*BaseOfImage
)
38 PLDR_DATA_TABLE_ENTRY LdrEntry
;
41 /* Get the base for this file */
42 if ((ULONG_PTR
)PcValue
> (ULONG_PTR
)MmHighestUserAddress
)
44 /* We are in kernel */
45 *BaseOfImage
= KiPcToFileHeader(PcValue
, &LdrEntry
, FALSE
, &InSystem
);
49 /* We are in user land */
50 *BaseOfImage
= KiRosPcToUserFileHeader(PcValue
, &LdrEntry
);
58 RtlInitializeRangeListPackage(VOID
)
60 /* Setup the lookaside list for allocations (not used yet) */
61 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList
,
65 sizeof(RTL_RANGE_ENTRY
),
72 RtlpCheckForActiveDebugger(VOID
)
74 /* This check is meaningless in kernel-mode */
80 RtlpSetInDbgPrint(VOID
)
82 /* Nothing to set in kernel mode */
88 RtlpClearInDbgPrint(VOID
)
90 /* Nothing to clear in kernel mode */
102 RtlpAllocateMemory(ULONG Bytes
,
105 return ExAllocatePoolWithTag(PagedPool
,
111 #define TAG_USTR 'RTSU'
112 #define TAG_ASTR 'RTSA'
113 #define TAG_OSTR 'RTSO'
116 RtlpFreeMemory(PVOID Mem
,
119 if (Tag
== TAG_ASTR
|| Tag
== TAG_OSTR
|| Tag
== TAG_USTR
)
122 ExFreePoolWithTag(Mem
, Tag
);
129 RtlAcquirePebLock(VOID
)
138 RtlReleasePebLock(VOID
)
145 LdrShutdownThread(VOID
)
147 return STATUS_SUCCESS
;
153 RtlGetCurrentPeb(VOID
)
155 return ((PEPROCESS
)(KeGetCurrentThread()->ApcState
.Process
))->Peb
;
160 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock
)
162 ExDeleteResourceLite(&Lock
->Resource
);
163 ExFreePoolWithTag(Lock
, TAG_RTHL
);
165 return STATUS_SUCCESS
;
170 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
172 KeEnterCriticalRegion();
175 ExAcquireResourceExclusiveLite(&Lock
->Resource
, TRUE
);
177 ExAcquireResourceSharedLite(&Lock
->Resource
, TRUE
);
179 return STATUS_SUCCESS
;
184 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
187 KeEnterCriticalRegion();
190 Success
= ExAcquireResourceExclusiveLite(&Lock
->Resource
, FALSE
);
192 Success
= ExAcquireResourceSharedLite(&Lock
->Resource
, FALSE
);
195 KeLeaveCriticalRegion();
202 RtlInitializeHeapLock(IN OUT PHEAP_LOCK
*Lock
)
204 PHEAP_LOCK HeapLock
= ExAllocatePoolWithTag(NonPagedPool
,
207 if (HeapLock
== NULL
)
208 return STATUS_NO_MEMORY
;
210 ExInitializeResourceLite(&HeapLock
->Resource
);
213 return STATUS_SUCCESS
;
218 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock
)
220 ExReleaseResourceLite(&Lock
->Resource
);
221 KeLeaveCriticalRegion();
223 return STATUS_SUCCESS
;
230 RtlpAddHeapToProcessList(struct _HEAP
*Heap
)
232 UNREFERENCED_PARAMETER(Heap
);
237 RtlpRemoveHeapFromProcessList(struct _HEAP
*Heap
)
239 UNREFERENCED_PARAMETER(Heap
);
243 RtlInitializeHeapManager(VOID
)
249 CHECK_PAGED_CODE_RTL(char *file
, int line
)
251 if(KeGetCurrentIrql() > APC_LEVEL
)
253 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%u)\n", file
, line
, KeGetCurrentIrql());
261 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters
)
263 /* Apply defaults for non-set parameters */
264 if (!Parameters
->SegmentCommit
) Parameters
->SegmentCommit
= MmHeapSegmentCommit
;
265 if (!Parameters
->SegmentReserve
) Parameters
->SegmentReserve
= MmHeapSegmentReserve
;
266 if (!Parameters
->DeCommitFreeBlockThreshold
) Parameters
->DeCommitFreeBlockThreshold
= MmHeapDeCommitFreeBlockThreshold
;
267 if (!Parameters
->DeCommitTotalFreeThreshold
) Parameters
->DeCommitTotalFreeThreshold
= MmHeapDeCommitTotalFreeThreshold
;
272 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
273 IN PCONTEXT ContextRecord
,
274 IN PVOID ContextData
,
277 /* Check the global flag */
278 if (NtGlobalFlag
& FLG_ENABLE_EXCEPTION_LOGGING
)
280 /* FIXME: Log this exception */
286 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
287 IN ULONG_PTR RegistrationFrameEnd
,
288 IN OUT PULONG_PTR StackLow
,
289 IN OUT PULONG_PTR StackHigh
)
294 /* Check if we are at DISPATCH or higher */
295 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
297 /* Get the PRCB and DPC Stack */
298 Prcb
= KeGetCurrentPrcb();
299 DpcStack
= (ULONG_PTR
)Prcb
->DpcStack
;
301 /* Check if we are in a DPC and the stack matches */
302 if ((Prcb
->DpcRoutineActive
) &&
303 (RegistrationFrameEnd
<= DpcStack
) &&
304 ((ULONG_PTR
)RegistrationFrame
>= DpcStack
- KERNEL_STACK_SIZE
))
306 /* Update the limits to the DPC Stack's */
307 *StackHigh
= DpcStack
;
308 *StackLow
= DpcStack
- KERNEL_STACK_SIZE
;
313 /* Not in DPC stack */
317 #if !defined(_ARM_) && !defined(_AMD64_)
321 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
322 IN ULONG_PTR
*StackBegin
,
323 IN ULONG_PTR
*StackEnd
)
325 PKTHREAD Thread
= KeGetCurrentThread();
327 /* Don't even try at ISR level or later */
328 if (KeGetCurrentIrql() > DISPATCH_LEVEL
) return FALSE
;
330 /* Start with defaults */
331 *StackBegin
= Thread
->StackLimit
;
332 *StackEnd
= (ULONG_PTR
)Thread
->StackBase
;
334 /* Check if EBP is inside the stack */
335 if ((*StackBegin
<= Ebp
) && (Ebp
<= *StackEnd
))
337 /* Then make the stack start at EBP */
342 /* Now we're going to assume we're on the DPC stack */
343 *StackEnd
= (ULONG_PTR
)(KeGetPcr()->Prcb
->DpcStack
);
344 *StackBegin
= *StackEnd
- KERNEL_STACK_SIZE
;
346 /* Check if we seem to be on the DPC stack */
347 if ((*StackEnd
) && (*StackBegin
< Ebp
) && (Ebp
<= *StackEnd
))
349 /* We're on the DPC stack */
354 /* We're somewhere else entirely... use EBP for safety */
356 *StackEnd
= (ULONG_PTR
)PAGE_ALIGN(*StackBegin
);
369 RtlWalkFrameChain(OUT PVOID
*Callers
,
373 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
375 BOOLEAN Result
, StopSearch
= FALSE
;
377 PETHREAD Thread
= PsGetCurrentThread();
379 PKTRAP_FRAME TrapFrame
;
381 /* Get current EBP */
384 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
385 #elif defined(_MSC_VER)
388 #elif defined(_M_MIPS)
389 __asm__("move $sp, %0" : "=r" (Stack
) : );
390 #elif defined(_M_PPC)
391 __asm__("mr %0,1" : "=r" (Stack
) : );
392 #elif defined(_M_ARM)
393 __asm__("mov sp, %0" : "=r"(Stack
) : );
395 #error Unknown architecture
398 /* Set it as the stack begin limit as well */
399 StackBegin
= (ULONG_PTR
)Stack
;
401 /* Check if we're called for non-logging mode */
404 /* Get the actual safe limits */
405 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
408 if (!Result
) return 0;
411 /* Use a SEH block for maximum protection */
414 /* Check if we want the user-mode stack frame */
417 /* Get the trap frame and TEB */
418 TrapFrame
= KeGetTrapFrame(&Thread
->Tcb
);
419 Teb
= Thread
->Tcb
.Teb
;
421 /* Make sure we can trust the TEB and trap frame */
423 (KeIsAttachedProcess()) ||
424 (KeGetCurrentIrql() >= DISPATCH_LEVEL
))
426 /* Invalid or unsafe attempt to get the stack */
427 _SEH2_YIELD(return 0;)
430 /* Get the stack limits */
431 StackBegin
= (ULONG_PTR
)Teb
->NtTib
.StackLimit
;
432 StackEnd
= (ULONG_PTR
)Teb
->NtTib
.StackBase
;
434 Stack
= TrapFrame
->Ebp
;
435 #elif defined(_M_PPC)
436 Stack
= TrapFrame
->Gpr1
;
438 #error Unknown architecture
442 if (StackEnd
<= StackBegin
) _SEH2_YIELD(return 0);
443 ProbeForRead((PVOID
)StackBegin
,
444 StackEnd
- StackBegin
,
448 /* Loop the frames */
449 for (i
= 0; i
< Count
; i
++)
452 * Leave if we're past the stack,
453 * if we're before the stack,
454 * or if we've reached ourselves.
456 if ((Stack
>= StackEnd
) ||
457 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
458 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
460 /* We're done or hit a bad address */
464 /* Get new stack and EIP */
465 NewStack
= *(PULONG_PTR
)Stack
;
466 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
468 /* Check if the new pointer is above the oldone and past the end */
469 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
471 /* Stop searching after this entry */
475 /* Also make sure that the EIP isn't a stack address */
476 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
478 /* Check if we reached a user-mode address */
479 if (!(Flags
) && !(Eip
& 0x80000000)) break; // FIXME: 3GB breakage
481 /* Save this frame */
482 Callers
[i
] = (PVOID
)Eip
;
484 /* Check if we should continue */
487 /* Return the next index */
492 /* Move to the next stack */
496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
503 /* Return frames parsed */
509 #if defined(_M_AMD64) || defined(_M_ARM)
513 OUT PULONG_PTR LowLimit
,
514 OUT PULONG_PTR HighLimit
)
516 PKTHREAD CurrentThread
= KeGetCurrentThread();
517 *HighLimit
= (ULONG_PTR
)CurrentThread
->InitialStack
;
518 *LowLimit
= (ULONG_PTR
)CurrentThread
->StackLimit
;
522 /* RTL Atom Tables ************************************************************/
525 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
527 ExInitializeFastMutex(&AtomTable
->FastMutex
);
529 return STATUS_SUCCESS
;
534 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
540 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
542 ExAcquireFastMutex(&AtomTable
->FastMutex
);
547 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
549 ExReleaseFastMutex(&AtomTable
->FastMutex
);
553 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
555 AtomTable
->ExHandleTable
= ExCreateHandleTable(NULL
);
556 return (AtomTable
->ExHandleTable
!= NULL
);
561 RtlpCloseHandleCallback(
562 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
564 IN PVOID HandleTable
)
566 /* Destroy and unlock the handle entry */
567 return ExDestroyHandle(HandleTable
, Handle
, HandleTableEntry
);
571 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
573 if (AtomTable
->ExHandleTable
)
575 ExSweepHandleTable(AtomTable
->ExHandleTable
,
576 RtlpCloseHandleCallback
,
577 AtomTable
->ExHandleTable
);
578 ExDestroyHandleTable(AtomTable
->ExHandleTable
, NULL
);
579 AtomTable
->ExHandleTable
= NULL
;
584 RtlpAllocAtomTable(ULONG Size
)
586 PRTL_ATOM_TABLE Table
= ExAllocatePoolWithTag(NonPagedPool
,
599 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
601 ExFreePoolWithTag(AtomTable
, TAG_ATMT
);
604 PRTL_ATOM_TABLE_ENTRY
605 RtlpAllocAtomTableEntry(ULONG Size
)
607 PRTL_ATOM_TABLE_ENTRY Entry
;
609 Entry
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_ATMT
);
612 RtlZeroMemory(Entry
, Size
);
619 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
621 ExFreePoolWithTag(Entry
, TAG_ATMT
);
625 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
627 ExDestroyHandle(AtomTable
->ExHandleTable
,
628 (HANDLE
)((ULONG_PTR
)Entry
->HandleIndex
<< 2),
633 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
635 HANDLE_TABLE_ENTRY ExEntry
;
639 /* Initialize ex handle table entry */
640 ExEntry
.Object
= Entry
;
641 ExEntry
.GrantedAccess
= 0x1; /* FIXME - valid handle */
643 /* Create ex handle */
644 Handle
= ExCreateHandle(AtomTable
->ExHandleTable
,
646 if (!Handle
) return FALSE
;
648 /* Calculate HandleIndex (by getting rid of the first two bits) */
649 HandleIndex
= (USHORT
)((ULONG_PTR
)Handle
>> 2);
651 /* Index must be less than 0xC000 */
652 if (HandleIndex
>= 0xC000)
654 /* Destroy ex handle */
655 ExDestroyHandle(AtomTable
->ExHandleTable
,
663 /* Initialize atom table entry */
664 Entry
->HandleIndex
= HandleIndex
;
665 Entry
->Atom
= 0xC000 + HandleIndex
;
671 PRTL_ATOM_TABLE_ENTRY
672 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
674 PHANDLE_TABLE_ENTRY ExEntry
;
675 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
677 /* NOTE: There's no need to explicitly enter a critical region because it's
678 guaranteed that we're in a critical region right now (as we hold
679 the atom table lock) */
681 ExEntry
= ExMapHandleToPointer(AtomTable
->ExHandleTable
,
682 (HANDLE
)((ULONG_PTR
)Index
<< 2));
685 Entry
= ExEntry
->Object
;
687 ExUnlockHandleTableEntry(AtomTable
->ExHandleTable
,
695 * Ldr Resource support code
698 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
699 LPCWSTR name
, void *root
,
701 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
702 USHORT id
, void *root
, int want_dir
);
703 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
704 void *root
, int want_dir
);
706 /**********************************************************************
709 * Find a resource entry
711 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
712 ULONG level
, void **ret
, int want_dir
)
716 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
718 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
719 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
720 if (size
< sizeof(*resdirptr
)) return STATUS_RESOURCE_DATA_NOT_FOUND
;
723 if (!level
--) goto done
;
724 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
725 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
726 if (!level
--) return STATUS_SUCCESS
;
729 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
730 return STATUS_RESOURCE_NAME_NOT_FOUND
;
731 if (!level
--) return STATUS_SUCCESS
;
732 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
736 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
738 return STATUS_RESOURCE_DATA_NOT_FOUND
;
742 return STATUS_SUCCESS
;
748 _Out_writes_bytes_all_(Length
) VOID UNALIGNED
*Destination
,
749 _In_reads_bytes_(Length
) CONST VOID UNALIGNED
*Source
,
754 RtlCopyMemory(Destination
, Source
, Length
);
756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
758 _SEH2_YIELD(return _SEH2_GetExceptionCode());
762 return STATUS_SUCCESS
;
767 RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord
,
768 _In_ PCONTEXT Context
)
770 /* In the kernel we don't have vectored exception handlers */
776 RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord
,
777 _In_ PCONTEXT Context
)
779 /* No vectored continue handlers either in kernel mode */