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 ******************************************************************/
14 #include <internal/debug.h>
16 extern ULONG NtGlobalFlag
;
18 typedef struct _RTL_RANGE_ENTRY
22 } RTL_RANGE_ENTRY
, *PRTL_RANGE_ENTRY
;
24 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList
;
25 SIZE_T RtlpAllocDeallocQueryBufferSize
= 128;
27 /* FUNCTIONS *****************************************************************/
31 RtlInitializeRangeListPackage(VOID
)
33 /* Setup the lookaside list for allocations (not used yet) */
34 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList
,
38 sizeof(RTL_RANGE_ENTRY
),
39 TAG('R', 'R', 'l', 'e'),
45 RtlpCheckForActiveDebugger(BOOLEAN Type
)
47 /* This check is meaningless in kernel-mode */
53 RtlpSetInDbgPrint(IN BOOLEAN NewValue
)
55 /* This check is meaningless in kernel-mode */
68 RtlpAllocateMemory(ULONG Bytes
,
71 return ExAllocatePoolWithTag(PagedPool
,
79 RtlpFreeMemory(PVOID Mem
,
82 ExFreePoolWithTag(Mem
,
90 RtlAcquirePebLock(VOID
)
99 RtlReleasePebLock(VOID
)
106 LdrShutdownThread(VOID
)
108 return STATUS_SUCCESS
;
116 return ((PEPROCESS
)(KeGetCurrentThread()->ApcState
.Process
))->Peb
;
122 PRTL_CRITICAL_SECTION CriticalSection
)
125 return STATUS_SUCCESS
;
131 PRTL_CRITICAL_SECTION CriticalSection
)
134 return STATUS_SUCCESS
;
139 RtlInitializeHeapLock(
140 PRTL_CRITICAL_SECTION CriticalSection
)
143 return STATUS_SUCCESS
;
149 PRTL_CRITICAL_SECTION CriticalSection
)
152 return STATUS_SUCCESS
;
157 CHECK_PAGED_CODE_RTL(char *file
, int line
)
159 if(KeGetCurrentIrql() > APC_LEVEL
)
161 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file
, line
, KeGetCurrentIrql());
169 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord
,
170 IN PCONTEXT ContextRecord
,
171 IN PVOID ContextData
,
174 /* Check the global flag */
175 if (NtGlobalFlag
& FLG_ENABLE_EXCEPTION_LOGGING
)
177 /* FIXME: Log this exception */
183 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame
,
184 IN ULONG_PTR RegistrationFrameEnd
,
185 IN OUT PULONG_PTR StackLow
,
186 IN OUT PULONG_PTR StackHigh
)
191 /* Check if we are at DISPATCH or higher */
192 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
194 /* Get the PRCB and DPC Stack */
195 Prcb
= KeGetCurrentPrcb();
196 DpcStack
= (ULONG_PTR
)Prcb
->DpcStack
;
198 /* Check if we are in a DPC and the stack matches */
199 if ((Prcb
->DpcRoutineActive
) &&
200 (RegistrationFrameEnd
<= DpcStack
) &&
201 ((ULONG_PTR
)RegistrationFrame
>= DpcStack
- KERNEL_STACK_SIZE
))
203 /* Update the limits to the DPC Stack's */
204 *StackHigh
= DpcStack
;
205 *StackLow
= DpcStack
- KERNEL_STACK_SIZE
;
210 /* Not in DPC stack */
214 #if !defined(_ARM_) && !defined(_AMD64_)
218 RtlpCaptureStackLimits(IN ULONG_PTR Ebp
,
219 IN ULONG_PTR
*StackBegin
,
220 IN ULONG_PTR
*StackEnd
)
222 PKTHREAD Thread
= KeGetCurrentThread();
224 /* Don't even try at ISR level or later */
225 if (KeGetCurrentIrql() > DISPATCH_LEVEL
) return FALSE
;
227 /* Start with defaults */
228 *StackBegin
= Thread
->StackLimit
;
229 *StackEnd
= (ULONG_PTR
)Thread
->StackBase
;
231 /* Check if EBP is inside the stack */
232 if ((*StackBegin
<= Ebp
) && (Ebp
<= *StackEnd
))
234 /* Then make the stack start at EBP */
239 /* Now we're going to assume we're on the DPC stack */
240 *StackEnd
= (ULONG_PTR
)(KeGetPcr()->Prcb
->DpcStack
);
241 *StackBegin
= *StackEnd
- KERNEL_STACK_SIZE
;
243 /* Check if we seem to be on the DPC stack */
244 if ((*StackEnd
) && (*StackBegin
< Ebp
) && (Ebp
<= *StackEnd
))
246 /* We're on the DPC stack */
251 /* We're somewhere else entirely... use EBP for safety */
253 *StackEnd
= (ULONG_PTR
)PAGE_ALIGN(*StackBegin
);
266 RtlWalkFrameChain(OUT PVOID
*Callers
,
270 ULONG_PTR Stack
, NewStack
, StackBegin
, StackEnd
= 0;
272 BOOLEAN Result
, StopSearch
= FALSE
;
274 PKTHREAD Thread
= KeGetCurrentThread();
276 PKTRAP_FRAME TrapFrame
;
278 /* Get current EBP */
281 __asm__("mov %%ebp, %0" : "=r" (Stack
) : );
282 #elif defined(_MSC_VER)
285 #elif defined(_M_MIPS)
286 __asm__("move $sp, %0" : "=r" (Stack
) : );
287 #elif defined(_M_PPC)
288 __asm__("mr %0,1" : "=r" (Stack
) : );
289 #elif defined(_M_ARM)
290 __asm__("mov sp, %0" : "=r"(Stack
) : );
292 #error Unknown architecture
295 /* Set it as the stack begin limit as well */
296 StackBegin
= (ULONG_PTR
)Stack
;
298 /* Check if we're called for non-logging mode */
301 /* Get the actual safe limits */
302 Result
= RtlpCaptureStackLimits((ULONG_PTR
)Stack
,
305 if (!Result
) return 0;
308 /* Use a SEH block for maximum protection */
311 /* Check if we want the user-mode stack frame */
314 /* Get the trap frame and TEB */
315 TrapFrame
= Thread
->TrapFrame
;
318 /* Make sure we can trust the TEB and trap frame */
320 !((PVOID
)((ULONG_PTR
)TrapFrame
& 0x80000000)) ||
321 ((PVOID
)TrapFrame
<= (PVOID
)Thread
->StackLimit
) ||
322 ((PVOID
)TrapFrame
>= (PVOID
)Thread
->StackBase
) ||
323 (KeIsAttachedProcess()) ||
324 (KeGetCurrentIrql() >= DISPATCH_LEVEL
))
326 /* Invalid or unsafe attempt to get the stack */
330 /* Get the stack limits */
331 StackBegin
= (ULONG_PTR
)Teb
->Tib
.StackLimit
;
332 StackEnd
= (ULONG_PTR
)Teb
->Tib
.StackBase
;
334 Stack
= TrapFrame
->Ebp
;
335 #elif defined(_M_PPC)
336 Stack
= TrapFrame
->Gpr1
;
340 if (StackEnd
<= StackBegin
) return 0;
341 ProbeForRead((PVOID
)StackBegin
,
342 StackEnd
- StackBegin
,
346 /* Loop the frames */
347 for (i
= 0; i
< Count
; i
++)
350 * Leave if we're past the stack,
351 * if we're before the stack,
352 * or if we've reached ourselves.
354 if ((Stack
>= StackEnd
) ||
355 (!i
? (Stack
< StackBegin
) : (Stack
<= StackBegin
)) ||
356 ((StackEnd
- Stack
) < (2 * sizeof(ULONG_PTR
))))
358 /* We're done or hit a bad address */
362 /* Get new stack and EIP */
363 NewStack
= *(PULONG_PTR
)Stack
;
364 Eip
= *(PULONG_PTR
)(Stack
+ sizeof(ULONG_PTR
));
366 /* Check if the new pointer is above the oldone and past the end */
367 if (!((Stack
< NewStack
) && (NewStack
< StackEnd
)))
369 /* Stop searching after this entry */
373 /* Also make sure that the EIP isn't a stack address */
374 if ((StackBegin
< Eip
) && (Eip
< StackEnd
)) break;
376 /* Check if we reached a user-mode address */
377 if (!(Flags
) && !(Eip
& 0x80000000)) break;
379 /* Save this frame */
380 Callers
[i
] = (PVOID
)Eip
;
382 /* Check if we should continue */
385 /* Return the next index */
390 /* Move to the next stack */
401 /* Return frames parsed */
407 /* RTL Atom Tables ************************************************************/
410 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
412 ExInitializeFastMutex(&AtomTable
->FastMutex
);
414 return STATUS_SUCCESS
;
419 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
425 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
427 ExAcquireFastMutex(&AtomTable
->FastMutex
);
432 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
434 ExReleaseFastMutex(&AtomTable
->FastMutex
);
438 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
440 AtomTable
->ExHandleTable
= ExCreateHandleTable(NULL
);
441 return (AtomTable
->ExHandleTable
!= NULL
);
445 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
447 if (AtomTable
->ExHandleTable
)
449 ExSweepHandleTable(AtomTable
->ExHandleTable
,
452 ExDestroyHandleTable(AtomTable
->ExHandleTable
, NULL
);
453 AtomTable
->ExHandleTable
= NULL
;
458 RtlpAllocAtomTable(ULONG Size
)
460 PRTL_ATOM_TABLE Table
= ExAllocatePool(NonPagedPool
,
472 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable
)
474 ExFreePool(AtomTable
);
477 PRTL_ATOM_TABLE_ENTRY
478 RtlpAllocAtomTableEntry(ULONG Size
)
480 PRTL_ATOM_TABLE_ENTRY Entry
= ExAllocatePool(NonPagedPool
,
492 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry
)
498 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
500 ExDestroyHandle(AtomTable
->ExHandleTable
,
501 (HANDLE
)((ULONG_PTR
)Entry
->HandleIndex
<< 2),
506 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable
, PRTL_ATOM_TABLE_ENTRY Entry
)
508 HANDLE_TABLE_ENTRY ExEntry
;
512 ExEntry
.Object
= Entry
;
513 ExEntry
.GrantedAccess
= 0x1; /* FIXME - valid handle */
515 Handle
= ExCreateHandle(AtomTable
->ExHandleTable
,
519 HandleIndex
= (USHORT
)((ULONG_PTR
)Handle
>> 2);
520 /* FIXME - Handle Indexes >= 0xC000 ?! */
521 if ((ULONG_PTR
)HandleIndex
>> 2 < 0xC000)
523 Entry
->HandleIndex
= HandleIndex
;
524 Entry
->Atom
= 0xC000 + HandleIndex
;
529 ExDestroyHandle(AtomTable
->ExHandleTable
,
537 PRTL_ATOM_TABLE_ENTRY
538 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable
, ULONG Index
)
540 PHANDLE_TABLE_ENTRY ExEntry
;
541 PRTL_ATOM_TABLE_ENTRY Entry
= NULL
;
543 /* NOTE: There's no need to explicitly enter a critical region because it's
544 guaranteed that we're in a critical region right now (as we hold
545 the atom table lock) */
547 ExEntry
= ExMapHandleToPointer(AtomTable
->ExHandleTable
,
548 (HANDLE
)((ULONG_PTR
)Index
<< 2));
551 Entry
= ExEntry
->Object
;
553 ExUnlockHandleTableEntry(AtomTable
->ExHandleTable
,
560 /* FIXME - RtlpCreateUnicodeString is obsolete and should be removed ASAP! */
562 RtlpCreateUnicodeString(
563 IN OUT PUNICODE_STRING UniDest
,
565 IN POOL_TYPE PoolType
)
569 Length
= (wcslen (Source
) + 1) * sizeof(WCHAR
);
570 UniDest
->Buffer
= ExAllocatePoolWithTag(PoolType
, Length
, TAG('U', 'S', 'T', 'R'));
571 if (UniDest
->Buffer
== NULL
)
574 RtlCopyMemory (UniDest
->Buffer
,
578 UniDest
->MaximumLength
= (USHORT
)Length
;
579 UniDest
->Length
= (USHORT
)Length
- sizeof (WCHAR
);
585 * Ldr Resource support code
588 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_name( IMAGE_RESOURCE_DIRECTORY
*dir
,
589 LPCWSTR name
, void *root
,
591 IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( IMAGE_RESOURCE_DIRECTORY
*dir
,
592 USHORT id
, void *root
, int want_dir
);
593 IMAGE_RESOURCE_DIRECTORY
*find_first_entry( IMAGE_RESOURCE_DIRECTORY
*dir
,
594 void *root
, int want_dir
);
596 /**********************************************************************
599 * Find a resource entry
601 NTSTATUS
find_entry( PVOID BaseAddress
, LDR_RESOURCE_INFO
*info
,
602 ULONG level
, void **ret
, int want_dir
)
606 IMAGE_RESOURCE_DIRECTORY
*resdirptr
;
608 root
= RtlImageDirectoryEntryToData( BaseAddress
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
609 if (!root
) return STATUS_RESOURCE_DATA_NOT_FOUND
;
612 if (!level
--) goto done
;
613 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Type
, root
, want_dir
|| level
)))
614 return STATUS_RESOURCE_TYPE_NOT_FOUND
;
615 if (!level
--) return STATUS_SUCCESS
;
618 if (!(*ret
= find_entry_by_name( resdirptr
, (LPCWSTR
)info
->Name
, root
, want_dir
|| level
)))
619 return STATUS_RESOURCE_NAME_NOT_FOUND
;
620 if (!level
--) return STATUS_SUCCESS
;
621 if (level
) return STATUS_INVALID_PARAMETER
; /* level > 3 */
625 if ((*ret
= find_first_entry( resdirptr
, root
, want_dir
))) return STATUS_SUCCESS
;
627 return STATUS_RESOURCE_DATA_NOT_FOUND
;
631 return STATUS_SUCCESS
;