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 TAG('A', 't', 'o', 'T') /* 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 *****************************************************************/
36 PLDR_DATA_TABLE_ENTRY LdrEntry
;
40 /* Get the base for this file */
41 if ((ULONG_PTR
)Address
> (ULONG_PTR
)MmHighestUserAddress
)
43 /* We are in kernel */
44 p
= KiPcToFileHeader(Address
, &LdrEntry
, FALSE
, &InSystem
);
48 /* We are in user land */
49 p
= KiRosPcToUserFileHeader(Address
, &LdrEntry
);
57 RtlInitializeRangeListPackage(VOID
)
59 /* Setup the lookaside list for allocations (not used yet) */
60 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList
,
64 sizeof(RTL_RANGE_ENTRY
),
65 TAG('R', 'R', 'l', 'e'),
71 RtlpCheckForActiveDebugger(BOOLEAN Type
)
73 /* This check is meaningless in kernel-mode */
79 RtlpSetInDbgPrint(IN BOOLEAN NewValue
)
81 /* This check is meaningless in kernel-mode */
94 RtlpAllocateMemory(ULONG Bytes
,
97 return ExAllocatePoolWithTag(PagedPool
,
103 #define TAG_USTR TAG('U', 'S', 'T', 'R')
104 #define TAG_ASTR TAG('A', 'S', 'T', 'R')
105 #define TAG_OSTR TAG('O', 'S', 'T', 'R')
108 RtlpFreeMemory(PVOID Mem
,
111 if (Tag
== TAG_ASTR
|| Tag
== TAG_OSTR
|| Tag
== TAG_USTR
)
114 ExFreePoolWithTag(Mem
, Tag
);
121 RtlAcquirePebLock(VOID
)
130 RtlReleasePebLock(VOID
)
137 LdrShutdownThread(VOID
)
139 return STATUS_SUCCESS
;
145 RtlGetCurrentPeb(VOID
)
147 return ((PEPROCESS
)(KeGetCurrentThread()->ApcState
.Process
))->Peb
;
153 PRTL_CRITICAL_SECTION CriticalSection
)
156 return STATUS_SUCCESS
;
162 PRTL_CRITICAL_SECTION CriticalSection
)
165 return STATUS_SUCCESS
;
170 RtlInitializeHeapLock(
171 PRTL_CRITICAL_SECTION CriticalSection
)
174 return STATUS_SUCCESS
;
180 PRTL_CRITICAL_SECTION CriticalSection
)
183 return STATUS_SUCCESS
;
188 CHECK_PAGED_CODE_RTL(char *file
, int line
)
190 if(KeGetCurrentIrql() > APC_LEVEL
)
192 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file
, line
, KeGetCurrentIrql());
200 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
201 IN PCONTEXT ContextRecord
,
202 IN PVOID ContextData
,
205 /* Check the global flag */
206 if (NtGlobalFlag
& FLG_ENABLE_EXCEPTION_LOGGING
)
208 /* FIXME: Log this exception */
214 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
215 IN ULONG_PTR RegistrationFrameEnd
,
216 IN OUT PULONG_PTR StackLow
,
217 IN OUT PULONG_PTR StackHigh
)
222 /* Check if we are at DISPATCH or higher */
223 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
225 /* Get the PRCB and DPC Stack */
226 Prcb
= KeGetCurrentPrcb();
227 DpcStack
= (ULONG_PTR
)Prcb
->DpcStack
;
229 /* Check if we are in a DPC and the stack matches */
230 if ((Prcb
->DpcRoutineActive
) &&
231 (RegistrationFrameEnd
<= DpcStack
) &&
232 ((ULONG_PTR
)RegistrationFrame
>= DpcStack
- KERNEL_STACK_SIZE
))
234 /* Update the limits to the DPC Stack's */
235 *StackHigh
= DpcStack
;
236 *StackLow
= DpcStack
- KERNEL_STACK_SIZE
;
241 /* Not in DPC stack */
245 #if !defined(_ARM_) && !defined(_AMD64_)
249 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
250 IN ULONG_PTR
*StackBegin
,
251 IN ULONG_PTR
*StackEnd
)
253 PKTHREAD Thread
= KeGetCurrentThread();
255 /* Don't even try at ISR level or later */
256 if (KeGetCurrentIrql() > DISPATCH_LEVEL
) return FALSE
;
258 /* Start with defaults */
259 *StackBegin
= Thread
->StackLimit
;
260 *StackEnd
= (ULONG_PTR
)Thread
->StackBase
;
262 /* Check if EBP is inside the stack */
263 if ((*StackBegin
<= Ebp
) && (Ebp
<= *StackEnd
))
265 /* Then make the stack start at EBP */
270 /* Now we're going to assume we're on the DPC stack */
271 *StackEnd
= (ULONG_PTR
)(KeGetPcr()->Prcb
->DpcStack
);
272 *StackBegin
= *StackEnd
- KERNEL_STACK_SIZE
;
274 /* Check if we seem to be on the DPC stack */
275 if ((*StackEnd
) && (*StackBegin
< Ebp
) && (Ebp
<= *StackEnd
))
277 /* We're on the DPC stack */
282 /* We're somewhere else entirely... use EBP for safety */
284 *StackEnd
= (ULONG_PTR
)PAGE_ALIGN(*StackBegin
);
297 RtlWalkFrameChain(OUT PVOID
*Callers
,
301 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
303 BOOLEAN Result
, StopSearch
= FALSE
;
305 PKTHREAD Thread
= KeGetCurrentThread();
307 PKTRAP_FRAME TrapFrame
;
309 /* Get current EBP */
312 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
313 #elif defined(_MSC_VER)
316 #elif defined(_M_MIPS)
317 __asm__("move $sp, %0" : "=r" (Stack
) : );
318 #elif defined(_M_PPC)
319 __asm__("mr %0,1" : "=r" (Stack
) : );
320 #elif defined(_M_ARM)
321 __asm__("mov sp, %0" : "=r"(Stack
) : );
323 #error Unknown architecture
326 /* Set it as the stack begin limit as well */
327 StackBegin
= (ULONG_PTR
)Stack
;
329 /* Check if we're called for non-logging mode */
332 /* Get the actual safe limits */
333 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
336 if (!Result
) return 0;
339 /* Use a SEH block for maximum protection */
342 /* Check if we want the user-mode stack frame */
345 /* Get the trap frame and TEB */
346 TrapFrame
= Thread
->TrapFrame
;
349 /* Make sure we can trust the TEB and trap frame */
351 !((PVOID
)((ULONG_PTR
)TrapFrame
& 0x80000000)) ||
352 ((PVOID
)TrapFrame
<= (PVOID
)Thread
->StackLimit
) ||
353 ((PVOID
)TrapFrame
>= (PVOID
)Thread
->StackBase
) ||
354 (KeIsAttachedProcess()) ||
355 (KeGetCurrentIrql() >= DISPATCH_LEVEL
))
357 /* Invalid or unsafe attempt to get the stack */
361 /* Get the stack limits */
362 StackBegin
= (ULONG_PTR
)Teb
->Tib
.StackLimit
;
363 StackEnd
= (ULONG_PTR
)Teb
->Tib
.StackBase
;
365 Stack
= TrapFrame
->Ebp
;
366 #elif defined(_M_PPC)
367 Stack
= TrapFrame
->Gpr1
;
371 if (StackEnd
<= StackBegin
) return 0;
372 ProbeForRead((PVOID
)StackBegin
,
373 StackEnd
- StackBegin
,
377 /* Loop the frames */
378 for (i
= 0; i
< Count
; i
++)
381 * Leave if we're past the stack,
382 * if we're before the stack,
383 * or if we've reached ourselves.
385 if ((Stack
>= StackEnd
) ||
386 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
387 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
389 /* We're done or hit a bad address */
393 /* Get new stack and EIP */
394 NewStack
= *(PULONG_PTR
)Stack
;
395 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
397 /* Check if the new pointer is above the oldone and past the end */
398 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
400 /* Stop searching after this entry */
404 /* Also make sure that the EIP isn't a stack address */
405 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
407 /* Check if we reached a user-mode address */
408 if (!(Flags
) && !(Eip
& 0x80000000)) break;
410 /* Save this frame */
411 Callers
[i
] = (PVOID
)Eip
;
413 /* Check if we should continue */
416 /* Return the next index */
421 /* Move to the next stack */
432 /* Return frames parsed */
442 OUT PULONG_PTR LowLimit
,
443 OUT PULONG_PTR HighLimit
)
445 PKTHREAD CurrentThread
= KeGetCurrentThread();
446 *HighLimit
= (ULONG_PTR
)CurrentThread
->InitialStack
;
447 *LowLimit
= (ULONG_PTR
)CurrentThread
->StackLimit
;
451 /* RTL Atom Tables ************************************************************/
454 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
456 ExInitializeFastMutex(&AtomTable
->FastMutex
);
458 return STATUS_SUCCESS
;
463 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
469 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
471 ExAcquireFastMutex(&AtomTable
->FastMutex
);
476 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
478 ExReleaseFastMutex(&AtomTable
->FastMutex
);
482 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
484 AtomTable
->ExHandleTable
= ExCreateHandleTable(NULL
);
485 return (AtomTable
->ExHandleTable
!= NULL
);
489 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
491 if (AtomTable
->ExHandleTable
)
493 ExSweepHandleTable(AtomTable
->ExHandleTable
,
496 ExDestroyHandleTable(AtomTable
->ExHandleTable
, NULL
);
497 AtomTable
->ExHandleTable
= NULL
;
502 RtlpAllocAtomTable(ULONG Size
)
504 PRTL_ATOM_TABLE Table
= ExAllocatePool(NonPagedPool
,
516 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
518 ExFreePool(AtomTable
);
521 PRTL_ATOM_TABLE_ENTRY
522 RtlpAllocAtomTableEntry(ULONG Size
)
524 PRTL_ATOM_TABLE_ENTRY Entry
;
526 Entry
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_ATMT
);
529 RtlZeroMemory(Entry
, Size
);
536 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
538 ExFreePoolWithTag(Entry
, TAG_ATMT
);
542 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
544 ExDestroyHandle(AtomTable
->ExHandleTable
,
545 (HANDLE
)((ULONG_PTR
)Entry
->HandleIndex
<< 2),
550 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
552 HANDLE_TABLE_ENTRY ExEntry
;
556 ExEntry
.Object
= Entry
;
557 ExEntry
.GrantedAccess
= 0x1; /* FIXME - valid handle */
559 Handle
= ExCreateHandle(AtomTable
->ExHandleTable
,
563 HandleIndex
= (USHORT
)((ULONG_PTR
)Handle
>> 2);
564 /* FIXME - Handle Indexes >= 0xC000 ?! */
565 if ((ULONG_PTR
)HandleIndex
>> 2 < 0xC000)
567 Entry
->HandleIndex
= HandleIndex
;
568 Entry
->Atom
= 0xC000 + HandleIndex
;
573 ExDestroyHandle(AtomTable
->ExHandleTable
,
581 PRTL_ATOM_TABLE_ENTRY
582 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
584 PHANDLE_TABLE_ENTRY ExEntry
;
585 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
587 /* NOTE: There's no need to explicitly enter a critical region because it's
588 guaranteed that we're in a critical region right now (as we hold
589 the atom table lock) */
591 ExEntry
= ExMapHandleToPointer(AtomTable
->ExHandleTable
,
592 (HANDLE
)((ULONG_PTR
)Index
<< 2));
595 Entry
= ExEntry
->Object
;
597 ExUnlockHandleTableEntry(AtomTable
->ExHandleTable
,
605 * Ldr Resource support code
608 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
609 LPCWSTR name
, void *root
,
611 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
612 USHORT id
, void *root
, int want_dir
);
613 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
614 void *root
, int want_dir
);
616 /**********************************************************************
619 * Find a resource entry
621 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
622 ULONG level
, void **ret
, int want_dir
)
626 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
628 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
629 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
632 if (!level
--) goto done
;
633 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
634 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
635 if (!level
--) return STATUS_SUCCESS
;
638 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
639 return STATUS_RESOURCE_NAME_NOT_FOUND
;
640 if (!level
--) return STATUS_SUCCESS
;
641 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
645 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
647 return STATUS_RESOURCE_DATA_NOT_FOUND
;
651 return STATUS_SUCCESS
;