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 *****************************************************************/
33 RtlInitializeRangeListPackage(VOID
)
35 /* Setup the lookaside list for allocations (not used yet) */
36 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList
,
40 sizeof(RTL_RANGE_ENTRY
),
47 RtlpCheckForActiveDebugger(VOID
)
49 /* This check is meaningless in kernel-mode */
55 RtlpSetInDbgPrint(VOID
)
57 /* Nothing to set in kernel mode */
63 RtlpClearInDbgPrint(VOID
)
65 /* Nothing to clear in kernel mode */
77 RtlpAllocateMemory(ULONG Bytes
,
80 return ExAllocatePoolWithTag(PagedPool
,
86 #define TAG_USTR 'RTSU'
87 #define TAG_ASTR 'RTSA'
88 #define TAG_OSTR 'RTSO'
91 RtlpFreeMemory(PVOID Mem
,
94 if (Tag
== TAG_ASTR
|| Tag
== TAG_OSTR
|| Tag
== TAG_USTR
)
97 ExFreePoolWithTag(Mem
, Tag
);
104 RtlAcquirePebLock(VOID
)
113 RtlReleasePebLock(VOID
)
120 LdrShutdownThread(VOID
)
122 return STATUS_SUCCESS
;
128 RtlGetCurrentPeb(VOID
)
130 return ((PEPROCESS
)(KeGetCurrentThread()->ApcState
.Process
))->Peb
;
136 PRTL_CRITICAL_SECTION CriticalSection
)
139 return STATUS_SUCCESS
;
145 PRTL_CRITICAL_SECTION CriticalSection
)
148 return STATUS_SUCCESS
;
153 RtlInitializeHeapLock(
154 PRTL_CRITICAL_SECTION CriticalSection
)
157 return STATUS_SUCCESS
;
163 PRTL_CRITICAL_SECTION CriticalSection
)
166 return STATUS_SUCCESS
;
171 CHECK_PAGED_CODE_RTL(char *file
, int line
)
173 if(KeGetCurrentIrql() > APC_LEVEL
)
175 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file
, line
, KeGetCurrentIrql());
183 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
184 IN PCONTEXT ContextRecord
,
185 IN PVOID ContextData
,
188 /* Check the global flag */
189 if (NtGlobalFlag
& FLG_ENABLE_EXCEPTION_LOGGING
)
191 /* FIXME: Log this exception */
197 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
198 IN ULONG_PTR RegistrationFrameEnd
,
199 IN OUT PULONG_PTR StackLow
,
200 IN OUT PULONG_PTR StackHigh
)
205 /* Check if we are at DISPATCH or higher */
206 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
208 /* Get the PRCB and DPC Stack */
209 Prcb
= KeGetCurrentPrcb();
210 DpcStack
= (ULONG_PTR
)Prcb
->DpcStack
;
212 /* Check if we are in a DPC and the stack matches */
213 if ((Prcb
->DpcRoutineActive
) &&
214 (RegistrationFrameEnd
<= DpcStack
) &&
215 ((ULONG_PTR
)RegistrationFrame
>= DpcStack
- KERNEL_STACK_SIZE
))
217 /* Update the limits to the DPC Stack's */
218 *StackHigh
= DpcStack
;
219 *StackLow
= DpcStack
- KERNEL_STACK_SIZE
;
224 /* Not in DPC stack */
232 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
233 IN ULONG_PTR
*StackBegin
,
234 IN ULONG_PTR
*StackEnd
)
236 PKTHREAD Thread
= KeGetCurrentThread();
238 /* Don't even try at ISR level or later */
239 if (KeGetCurrentIrql() > DISPATCH_LEVEL
) return FALSE
;
241 /* Start with defaults */
242 *StackBegin
= Thread
->StackLimit
;
243 *StackEnd
= (ULONG_PTR
)Thread
->StackBase
;
245 /* Check if EBP is inside the stack */
246 if ((*StackBegin
<= Ebp
) && (Ebp
<= *StackEnd
))
248 /* Then make the stack start at EBP */
253 /* Now we're going to assume we're on the DPC stack */
254 *StackEnd
= (ULONG_PTR
)(KeGetPcr()->Prcb
->DpcStack
);
255 *StackBegin
= *StackEnd
- KERNEL_STACK_SIZE
;
257 /* Check if we seem to be on the DPC stack */
258 if ((*StackEnd
) && (*StackBegin
< Ebp
) && (Ebp
<= *StackEnd
))
260 /* We're on the DPC stack */
265 /* We're somewhere else entirely... use EBP for safety */
267 *StackEnd
= (ULONG_PTR
)PAGE_ALIGN(*StackBegin
);
280 RtlWalkFrameChain(OUT PVOID
*Callers
,
284 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
286 BOOLEAN Result
, StopSearch
= FALSE
;
288 PETHREAD Thread
= PsGetCurrentThread();
290 PKTRAP_FRAME TrapFrame
;
292 /* Get current EBP */
295 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
296 #elif defined(_MSC_VER)
299 #elif defined(_M_MIPS)
300 __asm__("move $sp, %0" : "=r" (Stack
) : );
301 #elif defined(_M_PPC)
302 __asm__("mr %0,1" : "=r" (Stack
) : );
303 #elif defined(_M_ARM)
304 __asm__("mov sp, %0" : "=r"(Stack
) : );
306 #error Unknown architecture
309 /* Set it as the stack begin limit as well */
310 StackBegin
= (ULONG_PTR
)Stack
;
312 /* Check if we're called for non-logging mode */
315 /* Get the actual safe limits */
316 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
319 if (!Result
) return 0;
322 /* Use a SEH block for maximum protection */
325 /* Check if we want the user-mode stack frame */
328 /* Get the trap frame and TEB */
329 TrapFrame
= KeGetTrapFrame(&Thread
->Tcb
);
330 Teb
= Thread
->Tcb
.Teb
;
332 /* Make sure we can trust the TEB and trap frame */
334 !(Thread
->SystemThread
) ||
335 (KeIsAttachedProcess()) ||
336 (KeGetCurrentIrql() >= DISPATCH_LEVEL
))
338 /* Invalid or unsafe attempt to get the stack */
342 /* Get the stack limits */
343 StackBegin
= (ULONG_PTR
)Teb
->NtTib
.StackLimit
;
344 StackEnd
= (ULONG_PTR
)Teb
->NtTib
.StackBase
;
346 Stack
= TrapFrame
->Ebp
;
347 #elif defined(_M_PPC)
348 Stack
= TrapFrame
->Gpr1
;
350 #error Unknown architecture
354 if (StackEnd
<= StackBegin
) return 0;
355 ProbeForRead((PVOID
)StackBegin
,
356 StackEnd
- StackBegin
,
360 /* Loop the frames */
361 for (i
= 0; i
< Count
; i
++)
364 * Leave if we're past the stack,
365 * if we're before the stack,
366 * or if we've reached ourselves.
368 if ((Stack
>= StackEnd
) ||
369 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
370 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
372 /* We're done or hit a bad address */
376 /* Get new stack and EIP */
377 NewStack
= *(PULONG_PTR
)Stack
;
378 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
380 /* Check if the new pointer is above the oldone and past the end */
381 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
383 /* Stop searching after this entry */
387 /* Also make sure that the EIP isn't a stack address */
388 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
390 /* Check if we reached a user-mode address */
391 if (!(Flags
) && !(Eip
& 0x80000000)) break; // FIXME: 3GB breakage
393 /* Save this frame */
394 Callers
[i
] = (PVOID
)Eip
;
396 /* Check if we should continue */
399 /* Return the next index */
404 /* Move to the next stack */
408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
415 /* Return frames parsed */
421 /* RTL Atom Tables ************************************************************/
424 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
426 ExInitializeFastMutex(&AtomTable
->FastMutex
);
428 return STATUS_SUCCESS
;
433 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
439 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
441 ExAcquireFastMutex(&AtomTable
->FastMutex
);
446 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
448 ExReleaseFastMutex(&AtomTable
->FastMutex
);
452 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
454 AtomTable
->ExHandleTable
= ExCreateHandleTable(NULL
);
455 return (AtomTable
->ExHandleTable
!= NULL
);
459 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
461 if (AtomTable
->ExHandleTable
)
463 ExSweepHandleTable(AtomTable
->ExHandleTable
,
466 ExDestroyHandleTable(AtomTable
->ExHandleTable
, NULL
);
467 AtomTable
->ExHandleTable
= NULL
;
472 RtlpAllocAtomTable(ULONG Size
)
474 PRTL_ATOM_TABLE Table
= ExAllocatePool(NonPagedPool
,
486 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
488 ExFreePool(AtomTable
);
491 PRTL_ATOM_TABLE_ENTRY
492 RtlpAllocAtomTableEntry(ULONG Size
)
494 PRTL_ATOM_TABLE_ENTRY Entry
;
496 Entry
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_ATMT
);
499 RtlZeroMemory(Entry
, Size
);
506 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
508 ExFreePoolWithTag(Entry
, TAG_ATMT
);
512 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
514 ExDestroyHandle(AtomTable
->ExHandleTable
,
515 (HANDLE
)((ULONG_PTR
)Entry
->HandleIndex
<< 2),
520 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
522 HANDLE_TABLE_ENTRY ExEntry
;
526 /* Initialize ex handle table entry */
527 ExEntry
.Object
= Entry
;
528 ExEntry
.GrantedAccess
= 0x1; /* FIXME - valid handle */
530 /* Create ex handle */
531 Handle
= ExCreateHandle(AtomTable
->ExHandleTable
,
533 if (!Handle
) return FALSE
;
535 /* Calculate HandleIndex (by getting rid of the first two bits) */
536 HandleIndex
= (USHORT
)((ULONG_PTR
)Handle
>> 2);
538 /* Index must be less than 0xC000 */
539 if (HandleIndex
>= 0xC000)
541 /* Destroy ex handle */
542 ExDestroyHandle(AtomTable
->ExHandleTable
,
550 /* Initialize atom table entry */
551 Entry
->HandleIndex
= HandleIndex
;
552 Entry
->Atom
= 0xC000 + HandleIndex
;
558 PRTL_ATOM_TABLE_ENTRY
559 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
561 PHANDLE_TABLE_ENTRY ExEntry
;
562 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
564 /* NOTE: There's no need to explicitly enter a critical region because it's
565 guaranteed that we're in a critical region right now (as we hold
566 the atom table lock) */
568 ExEntry
= ExMapHandleToPointer(AtomTable
->ExHandleTable
,
569 (HANDLE
)((ULONG_PTR
)Index
<< 2));
572 Entry
= ExEntry
->Object
;
574 ExUnlockHandleTableEntry(AtomTable
->ExHandleTable
,
582 * Ldr Resource support code
585 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
586 LPCWSTR name
, void *root
,
588 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
589 USHORT id
, void *root
, int want_dir
);
590 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
591 void *root
, int want_dir
);
593 /**********************************************************************
596 * Find a resource entry
598 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
599 ULONG level
, void **ret
, int want_dir
)
603 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
605 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
606 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
609 if (!level
--) goto done
;
610 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
611 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
612 if (!level
--) return STATUS_SUCCESS
;
615 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
616 return STATUS_RESOURCE_NAME_NOT_FOUND
;
617 if (!level
--) return STATUS_SUCCESS
;
618 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
622 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
624 return STATUS_RESOURCE_DATA_NOT_FOUND
;
628 return STATUS_SUCCESS
;