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 */
18 extern ULONG NtGlobalFlag
;
20 typedef struct _RTL_RANGE_ENTRY
24 } RTL_RANGE_ENTRY
, *PRTL_RANGE_ENTRY
;
26 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList
;
27 SIZE_T RtlpAllocDeallocQueryBufferSize
= 128;
29 /* FUNCTIONS *****************************************************************/
35 OUT PVOID
*BaseOfImage
)
37 PLDR_DATA_TABLE_ENTRY LdrEntry
;
40 /* Get the base for this file */
41 if ((ULONG_PTR
)PcValue
> (ULONG_PTR
)MmHighestUserAddress
)
43 /* We are in kernel */
44 *BaseOfImage
= KiPcToFileHeader(PcValue
, &LdrEntry
, FALSE
, &InSystem
);
48 /* We are in user land */
49 *BaseOfImage
= KiRosPcToUserFileHeader(PcValue
, &LdrEntry
);
57 RtlInitializeRangeListPackage(VOID
)
59 /* Setup the lookaside list for allocations (not used yet) */
60 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList
,
64 sizeof(RTL_RANGE_ENTRY
),
71 RtlpCheckForActiveDebugger(VOID
)
73 /* This check is meaningless in kernel-mode */
79 RtlpSetInDbgPrint(VOID
)
81 /* Nothing to set in kernel mode */
87 RtlpClearInDbgPrint(VOID
)
89 /* Nothing to clear in kernel mode */
101 RtlpAllocateMemory(ULONG Bytes
,
104 return ExAllocatePoolWithTag(PagedPool
,
110 #define TAG_USTR 'RTSU'
111 #define TAG_ASTR 'RTSA'
112 #define TAG_OSTR 'RTSO'
115 RtlpFreeMemory(PVOID Mem
,
118 if (Tag
== TAG_ASTR
|| Tag
== TAG_OSTR
|| Tag
== TAG_USTR
)
121 ExFreePoolWithTag(Mem
, Tag
);
128 RtlAcquirePebLock(VOID
)
137 RtlReleasePebLock(VOID
)
144 LdrShutdownThread(VOID
)
146 return STATUS_SUCCESS
;
152 RtlGetCurrentPeb(VOID
)
154 return ((PEPROCESS
)(KeGetCurrentThread()->ApcState
.Process
))->Peb
;
159 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock
)
161 ExDeleteResourceLite(&Lock
->Resource
);
164 return STATUS_SUCCESS
;
169 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
171 KeEnterCriticalRegion();
174 ExAcquireResourceExclusiveLite(&Lock
->Resource
, TRUE
);
176 ExAcquireResourceSharedLite(&Lock
->Resource
, TRUE
);
178 return STATUS_SUCCESS
;
183 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock
, IN BOOLEAN Exclusive
)
186 KeEnterCriticalRegion();
189 Success
= ExAcquireResourceExclusiveLite(&Lock
->Resource
, FALSE
);
191 Success
= ExAcquireResourceSharedLite(&Lock
->Resource
, FALSE
);
194 KeLeaveCriticalRegion();
201 RtlInitializeHeapLock(IN OUT PHEAP_LOCK
*Lock
)
203 PHEAP_LOCK HeapLock
= ExAllocatePool(NonPagedPool
, sizeof(HEAP_LOCK
));
204 if (HeapLock
== NULL
)
205 return STATUS_NO_MEMORY
;
207 ExInitializeResourceLite(&HeapLock
->Resource
);
210 return STATUS_SUCCESS
;
215 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock
)
217 ExReleaseResourceLite(&Lock
->Resource
);
218 KeLeaveCriticalRegion();
220 return STATUS_SUCCESS
;
227 RtlpAddHeapToProcessList(struct _HEAP
*Heap
)
229 UNREFERENCED_PARAMETER(Heap
);
234 RtlpRemoveHeapFromProcessList(struct _HEAP
*Heap
)
236 UNREFERENCED_PARAMETER(Heap
);
240 RtlInitializeHeapManager(VOID
)
246 CHECK_PAGED_CODE_RTL(char *file
, int line
)
248 if(KeGetCurrentIrql() > APC_LEVEL
)
250 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%u)\n", file
, line
, KeGetCurrentIrql());
258 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters
)
260 /* Apply defaults for non-set parameters */
261 if (!Parameters
->SegmentCommit
) Parameters
->SegmentCommit
= MmHeapSegmentCommit
;
262 if (!Parameters
->SegmentReserve
) Parameters
->SegmentReserve
= MmHeapSegmentReserve
;
263 if (!Parameters
->DeCommitFreeBlockThreshold
) Parameters
->DeCommitFreeBlockThreshold
= MmHeapDeCommitFreeBlockThreshold
;
264 if (!Parameters
->DeCommitTotalFreeThreshold
) Parameters
->DeCommitTotalFreeThreshold
= MmHeapDeCommitTotalFreeThreshold
;
269 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
270 IN PCONTEXT ContextRecord
,
271 IN PVOID ContextData
,
274 /* Check the global flag */
275 if (NtGlobalFlag
& FLG_ENABLE_EXCEPTION_LOGGING
)
277 /* FIXME: Log this exception */
283 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
284 IN ULONG_PTR RegistrationFrameEnd
,
285 IN OUT PULONG_PTR StackLow
,
286 IN OUT PULONG_PTR StackHigh
)
291 /* Check if we are at DISPATCH or higher */
292 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
294 /* Get the PRCB and DPC Stack */
295 Prcb
= KeGetCurrentPrcb();
296 DpcStack
= (ULONG_PTR
)Prcb
->DpcStack
;
298 /* Check if we are in a DPC and the stack matches */
299 if ((Prcb
->DpcRoutineActive
) &&
300 (RegistrationFrameEnd
<= DpcStack
) &&
301 ((ULONG_PTR
)RegistrationFrame
>= DpcStack
- KERNEL_STACK_SIZE
))
303 /* Update the limits to the DPC Stack's */
304 *StackHigh
= DpcStack
;
305 *StackLow
= DpcStack
- KERNEL_STACK_SIZE
;
310 /* Not in DPC stack */
314 #if !defined(_ARM_) && !defined(_AMD64_)
318 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
319 IN ULONG_PTR
*StackBegin
,
320 IN ULONG_PTR
*StackEnd
)
322 PKTHREAD Thread
= KeGetCurrentThread();
324 /* Don't even try at ISR level or later */
325 if (KeGetCurrentIrql() > DISPATCH_LEVEL
) return FALSE
;
327 /* Start with defaults */
328 *StackBegin
= Thread
->StackLimit
;
329 *StackEnd
= (ULONG_PTR
)Thread
->StackBase
;
331 /* Check if EBP is inside the stack */
332 if ((*StackBegin
<= Ebp
) && (Ebp
<= *StackEnd
))
334 /* Then make the stack start at EBP */
339 /* Now we're going to assume we're on the DPC stack */
340 *StackEnd
= (ULONG_PTR
)(KeGetPcr()->Prcb
->DpcStack
);
341 *StackBegin
= *StackEnd
- KERNEL_STACK_SIZE
;
343 /* Check if we seem to be on the DPC stack */
344 if ((*StackEnd
) && (*StackBegin
< Ebp
) && (Ebp
<= *StackEnd
))
346 /* We're on the DPC stack */
351 /* We're somewhere else entirely... use EBP for safety */
353 *StackEnd
= (ULONG_PTR
)PAGE_ALIGN(*StackBegin
);
366 RtlWalkFrameChain(OUT PVOID
*Callers
,
370 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
372 BOOLEAN Result
, StopSearch
= FALSE
;
374 PETHREAD Thread
= PsGetCurrentThread();
376 PKTRAP_FRAME TrapFrame
;
378 /* Get current EBP */
381 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
382 #elif defined(_MSC_VER)
385 #elif defined(_M_MIPS)
386 __asm__("move $sp, %0" : "=r" (Stack
) : );
387 #elif defined(_M_PPC)
388 __asm__("mr %0,1" : "=r" (Stack
) : );
389 #elif defined(_M_ARM)
390 __asm__("mov sp, %0" : "=r"(Stack
) : );
392 #error Unknown architecture
395 /* Set it as the stack begin limit as well */
396 StackBegin
= (ULONG_PTR
)Stack
;
398 /* Check if we're called for non-logging mode */
401 /* Get the actual safe limits */
402 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
405 if (!Result
) return 0;
408 /* Use a SEH block for maximum protection */
411 /* Check if we want the user-mode stack frame */
414 /* Get the trap frame and TEB */
415 TrapFrame
= KeGetTrapFrame(&Thread
->Tcb
);
416 Teb
= Thread
->Tcb
.Teb
;
418 /* Make sure we can trust the TEB and trap frame */
420 (KeIsAttachedProcess()) ||
421 (KeGetCurrentIrql() >= DISPATCH_LEVEL
))
423 /* Invalid or unsafe attempt to get the stack */
424 _SEH2_YIELD(return 0;)
427 /* Get the stack limits */
428 StackBegin
= (ULONG_PTR
)Teb
->NtTib
.StackLimit
;
429 StackEnd
= (ULONG_PTR
)Teb
->NtTib
.StackBase
;
431 Stack
= TrapFrame
->Ebp
;
432 #elif defined(_M_PPC)
433 Stack
= TrapFrame
->Gpr1
;
435 #error Unknown architecture
439 if (StackEnd
<= StackBegin
) _SEH2_YIELD(return 0);
440 ProbeForRead((PVOID
)StackBegin
,
441 StackEnd
- StackBegin
,
445 /* Loop the frames */
446 for (i
= 0; i
< Count
; i
++)
449 * Leave if we're past the stack,
450 * if we're before the stack,
451 * or if we've reached ourselves.
453 if ((Stack
>= StackEnd
) ||
454 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
455 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
457 /* We're done or hit a bad address */
461 /* Get new stack and EIP */
462 NewStack
= *(PULONG_PTR
)Stack
;
463 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
465 /* Check if the new pointer is above the oldone and past the end */
466 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
468 /* Stop searching after this entry */
472 /* Also make sure that the EIP isn't a stack address */
473 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
475 /* Check if we reached a user-mode address */
476 if (!(Flags
) && !(Eip
& 0x80000000)) break; // FIXME: 3GB breakage
478 /* Save this frame */
479 Callers
[i
] = (PVOID
)Eip
;
481 /* Check if we should continue */
484 /* Return the next index */
489 /* Move to the next stack */
493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
500 /* Return frames parsed */
510 OUT PULONG_PTR LowLimit
,
511 OUT PULONG_PTR HighLimit
)
513 PKTHREAD CurrentThread
= KeGetCurrentThread();
514 *HighLimit
= (ULONG_PTR
)CurrentThread
->InitialStack
;
515 *LowLimit
= (ULONG_PTR
)CurrentThread
->StackLimit
;
519 /* RTL Atom Tables ************************************************************/
522 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
524 ExInitializeFastMutex(&AtomTable
->FastMutex
);
526 return STATUS_SUCCESS
;
531 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
537 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
539 ExAcquireFastMutex(&AtomTable
->FastMutex
);
544 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
546 ExReleaseFastMutex(&AtomTable
->FastMutex
);
550 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
552 AtomTable
->ExHandleTable
= ExCreateHandleTable(NULL
);
553 return (AtomTable
->ExHandleTable
!= NULL
);
558 RtlpCloseHandleCallback(
559 IN PHANDLE_TABLE_ENTRY HandleTableEntry
,
561 IN PVOID HandleTable
)
563 /* Destroy and unlock the handle entry */
564 return ExDestroyHandle(HandleTable
, Handle
, HandleTableEntry
);
568 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
570 if (AtomTable
->ExHandleTable
)
572 ExSweepHandleTable(AtomTable
->ExHandleTable
,
573 RtlpCloseHandleCallback
,
574 AtomTable
->ExHandleTable
);
575 ExDestroyHandleTable(AtomTable
->ExHandleTable
, NULL
);
576 AtomTable
->ExHandleTable
= NULL
;
581 RtlpAllocAtomTable(ULONG Size
)
583 PRTL_ATOM_TABLE Table
= ExAllocatePool(NonPagedPool
,
595 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
597 ExFreePool(AtomTable
);
600 PRTL_ATOM_TABLE_ENTRY
601 RtlpAllocAtomTableEntry(ULONG Size
)
603 PRTL_ATOM_TABLE_ENTRY Entry
;
605 Entry
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_ATMT
);
608 RtlZeroMemory(Entry
, Size
);
615 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
617 ExFreePoolWithTag(Entry
, TAG_ATMT
);
621 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
623 ExDestroyHandle(AtomTable
->ExHandleTable
,
624 (HANDLE
)((ULONG_PTR
)Entry
->HandleIndex
<< 2),
629 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
631 HANDLE_TABLE_ENTRY ExEntry
;
635 /* Initialize ex handle table entry */
636 ExEntry
.Object
= Entry
;
637 ExEntry
.GrantedAccess
= 0x1; /* FIXME - valid handle */
639 /* Create ex handle */
640 Handle
= ExCreateHandle(AtomTable
->ExHandleTable
,
642 if (!Handle
) return FALSE
;
644 /* Calculate HandleIndex (by getting rid of the first two bits) */
645 HandleIndex
= (USHORT
)((ULONG_PTR
)Handle
>> 2);
647 /* Index must be less than 0xC000 */
648 if (HandleIndex
>= 0xC000)
650 /* Destroy ex handle */
651 ExDestroyHandle(AtomTable
->ExHandleTable
,
659 /* Initialize atom table entry */
660 Entry
->HandleIndex
= HandleIndex
;
661 Entry
->Atom
= 0xC000 + HandleIndex
;
667 PRTL_ATOM_TABLE_ENTRY
668 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
670 PHANDLE_TABLE_ENTRY ExEntry
;
671 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
673 /* NOTE: There's no need to explicitly enter a critical region because it's
674 guaranteed that we're in a critical region right now (as we hold
675 the atom table lock) */
677 ExEntry
= ExMapHandleToPointer(AtomTable
->ExHandleTable
,
678 (HANDLE
)((ULONG_PTR
)Index
<< 2));
681 Entry
= ExEntry
->Object
;
683 ExUnlockHandleTableEntry(AtomTable
->ExHandleTable
,
691 * Ldr Resource support code
694 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
695 LPCWSTR name
, void *root
,
697 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
698 USHORT id
, void *root
, int want_dir
);
699 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
700 void *root
, int want_dir
);
702 /**********************************************************************
705 * Find a resource entry
707 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
708 ULONG level
, void **ret
, int want_dir
)
712 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
714 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
715 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
716 if (size
< sizeof(*resdirptr
)) return STATUS_RESOURCE_DATA_NOT_FOUND
;
719 if (!level
--) goto done
;
720 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
721 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
722 if (!level
--) return STATUS_SUCCESS
;
725 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
726 return STATUS_RESOURCE_NAME_NOT_FOUND
;
727 if (!level
--) return STATUS_SUCCESS
;
728 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
732 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
734 return STATUS_RESOURCE_DATA_NOT_FOUND
;
738 return STATUS_SUCCESS
;
744 _Out_writes_bytes_all_(Length
) VOID UNALIGNED
*Destination
,
745 _In_reads_bytes_(Length
) CONST VOID UNALIGNED
*Source
,
750 RtlCopyMemory(Destination
, Source
, Length
);
752 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
754 _SEH2_YIELD(return _SEH2_GetExceptionCode());
758 return STATUS_SUCCESS
;
763 RtlCallVectoredExceptionHandlers(
764 _In_ PEXCEPTION_RECORD ExceptionRecord
,
765 _In_ PCONTEXT Context
)
767 /* In the kernel we don't have vectored exception handlers */