Merge to trunk head (r46631)
[reactos.git] / ntoskrnl / rtl / libsupp.c
1 /*
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)
7 * Gunnar Dalsnes
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #define TAG_ATMT 'TotA' /* Atom table */
17
18 extern ULONG NtGlobalFlag;
19
20 typedef struct _RTL_RANGE_ENTRY
21 {
22 LIST_ENTRY Entry;
23 RTL_RANGE Range;
24 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY;
25
26 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
27 SIZE_T RtlpAllocDeallocQueryBufferSize = 128;
28
29 /* FUNCTIONS *****************************************************************/
30
31 VOID
32 NTAPI
33 RtlInitializeRangeListPackage(VOID)
34 {
35 /* Setup the lookaside list for allocations (not used yet) */
36 ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList,
37 NULL,
38 NULL,
39 POOL_COLD_ALLOCATION,
40 sizeof(RTL_RANGE_ENTRY),
41 'elRR',
42 16);
43 }
44
45 BOOLEAN
46 NTAPI
47 RtlpCheckForActiveDebugger(VOID)
48 {
49 /* This check is meaningless in kernel-mode */
50 return FALSE;
51 }
52
53 BOOLEAN
54 NTAPI
55 RtlpSetInDbgPrint(VOID)
56 {
57 /* Nothing to set in kernel mode */
58 return FALSE;
59 }
60
61 VOID
62 NTAPI
63 RtlpClearInDbgPrint(VOID)
64 {
65 /* Nothing to clear in kernel mode */
66 }
67
68 KPROCESSOR_MODE
69 NTAPI
70 RtlpGetMode()
71 {
72 return KernelMode;
73 }
74
75 PVOID
76 NTAPI
77 RtlpAllocateMemory(ULONG Bytes,
78 ULONG Tag)
79 {
80 return ExAllocatePoolWithTag(PagedPool,
81 (SIZE_T)Bytes,
82 Tag);
83 }
84
85
86 #define TAG_USTR 'RTSU'
87 #define TAG_ASTR 'RTSA'
88 #define TAG_OSTR 'RTSO'
89 VOID
90 NTAPI
91 RtlpFreeMemory(PVOID Mem,
92 ULONG Tag)
93 {
94 if (Tag == TAG_ASTR || Tag == TAG_OSTR || Tag == TAG_USTR)
95 ExFreePool(Mem);
96 else
97 ExFreePoolWithTag(Mem, Tag);
98 }
99
100 /*
101 * @implemented
102 */
103 VOID NTAPI
104 RtlAcquirePebLock(VOID)
105 {
106
107 }
108
109 /*
110 * @implemented
111 */
112 VOID NTAPI
113 RtlReleasePebLock(VOID)
114 {
115
116 }
117
118 NTSTATUS
119 NTAPI
120 LdrShutdownThread(VOID)
121 {
122 return STATUS_SUCCESS;
123 }
124
125
126 PPEB
127 NTAPI
128 RtlGetCurrentPeb(VOID)
129 {
130 return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb;
131 }
132
133 NTSTATUS
134 NTAPI
135 RtlDeleteHeapLock(
136 PRTL_CRITICAL_SECTION CriticalSection)
137 {
138 ASSERT(FALSE);
139 return STATUS_SUCCESS;
140 }
141
142 NTSTATUS
143 NTAPI
144 RtlEnterHeapLock(
145 PRTL_CRITICAL_SECTION CriticalSection)
146 {
147 ASSERT(FALSE);
148 return STATUS_SUCCESS;
149 }
150
151 NTSTATUS
152 NTAPI
153 RtlInitializeHeapLock(
154 PRTL_CRITICAL_SECTION CriticalSection)
155 {
156 ASSERT(FALSE);
157 return STATUS_SUCCESS;
158 }
159
160 NTSTATUS
161 NTAPI
162 RtlLeaveHeapLock(
163 PRTL_CRITICAL_SECTION CriticalSection)
164 {
165 ASSERT(FALSE);
166 return STATUS_SUCCESS;
167 }
168
169 #if DBG
170 VOID FASTCALL
171 CHECK_PAGED_CODE_RTL(char *file, int line)
172 {
173 if(KeGetCurrentIrql() > APC_LEVEL)
174 {
175 DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%d)\n", file, line, KeGetCurrentIrql());
176 ASSERT(FALSE);
177 }
178 }
179 #endif
180
181 VOID
182 NTAPI
183 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
184 IN PCONTEXT ContextRecord,
185 IN PVOID ContextData,
186 IN ULONG Size)
187 {
188 /* Check the global flag */
189 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
190 {
191 /* FIXME: Log this exception */
192 }
193 }
194
195 BOOLEAN
196 NTAPI
197 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
198 IN ULONG_PTR RegistrationFrameEnd,
199 IN OUT PULONG_PTR StackLow,
200 IN OUT PULONG_PTR StackHigh)
201 {
202 PKPRCB Prcb;
203 ULONG_PTR DpcStack;
204
205 /* Check if we are at DISPATCH or higher */
206 if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
207 {
208 /* Get the PRCB and DPC Stack */
209 Prcb = KeGetCurrentPrcb();
210 DpcStack = (ULONG_PTR)Prcb->DpcStack;
211
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))
216 {
217 /* Update the limits to the DPC Stack's */
218 *StackHigh = DpcStack;
219 *StackLow = DpcStack - KERNEL_STACK_SIZE;
220 return TRUE;
221 }
222 }
223
224 /* Not in DPC stack */
225 return FALSE;
226 }
227
228 #ifndef _ARM_
229
230 BOOLEAN
231 NTAPI
232 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
233 IN ULONG_PTR *StackBegin,
234 IN ULONG_PTR *StackEnd)
235 {
236 PKTHREAD Thread = KeGetCurrentThread();
237
238 /* Don't even try at ISR level or later */
239 if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE;
240
241 /* Start with defaults */
242 *StackBegin = Thread->StackLimit;
243 *StackEnd = (ULONG_PTR)Thread->StackBase;
244
245 /* Check if EBP is inside the stack */
246 if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd))
247 {
248 /* Then make the stack start at EBP */
249 *StackBegin = Ebp;
250 }
251 else
252 {
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;
256
257 /* Check if we seem to be on the DPC stack */
258 if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd))
259 {
260 /* We're on the DPC stack */
261 *StackBegin = Ebp;
262 }
263 else
264 {
265 /* We're somewhere else entirely... use EBP for safety */
266 *StackBegin = Ebp;
267 *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin);
268 }
269 }
270
271 /* Return success */
272 return TRUE;
273 }
274
275 /*
276 * @implemented
277 */
278 ULONG
279 NTAPI
280 RtlWalkFrameChain(OUT PVOID *Callers,
281 IN ULONG Count,
282 IN ULONG Flags)
283 {
284 ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
285 ULONG Eip;
286 BOOLEAN Result, StopSearch = FALSE;
287 ULONG i = 0;
288 PETHREAD Thread = PsGetCurrentThread();
289 PTEB Teb;
290 PKTRAP_FRAME TrapFrame;
291
292 /* Get current EBP */
293 #if defined(_M_IX86)
294 #if defined __GNUC__
295 __asm__("mov %%ebp, %0" : "=r" (Stack) : );
296 #elif defined(_MSC_VER)
297 __asm mov Stack, ebp
298 #endif
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) : );
305 #else
306 #error Unknown architecture
307 #endif
308
309 /* Set it as the stack begin limit as well */
310 StackBegin = (ULONG_PTR)Stack;
311
312 /* Check if we're called for non-logging mode */
313 if (!Flags)
314 {
315 /* Get the actual safe limits */
316 Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
317 &StackBegin,
318 &StackEnd);
319 if (!Result) return 0;
320 }
321
322 /* Use a SEH block for maximum protection */
323 _SEH2_TRY
324 {
325 /* Check if we want the user-mode stack frame */
326 if (Flags == 1)
327 {
328 /* Get the trap frame and TEB */
329 TrapFrame = KeGetTrapFrame(&Thread->Tcb);
330 Teb = Thread->Tcb.Teb;
331
332 /* Make sure we can trust the TEB and trap frame */
333 if (!(Teb) ||
334 !(Thread->SystemThread) ||
335 (KeIsAttachedProcess()) ||
336 (KeGetCurrentIrql() >= DISPATCH_LEVEL))
337 {
338 /* Invalid or unsafe attempt to get the stack */
339 return 0;
340 }
341
342 /* Get the stack limits */
343 StackBegin = (ULONG_PTR)Teb->NtTib.StackLimit;
344 StackEnd = (ULONG_PTR)Teb->NtTib.StackBase;
345 #ifdef _M_IX86
346 Stack = TrapFrame->Ebp;
347 #elif defined(_M_PPC)
348 Stack = TrapFrame->Gpr1;
349 #else
350 #error Unknown architecture
351 #endif
352
353 /* Validate them */
354 if (StackEnd <= StackBegin) return 0;
355 ProbeForRead((PVOID)StackBegin,
356 StackEnd - StackBegin,
357 sizeof(CHAR));
358 }
359
360 /* Loop the frames */
361 for (i = 0; i < Count; i++)
362 {
363 /*
364 * Leave if we're past the stack,
365 * if we're before the stack,
366 * or if we've reached ourselves.
367 */
368 if ((Stack >= StackEnd) ||
369 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
370 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
371 {
372 /* We're done or hit a bad address */
373 break;
374 }
375
376 /* Get new stack and EIP */
377 NewStack = *(PULONG_PTR)Stack;
378 Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
379
380 /* Check if the new pointer is above the oldone and past the end */
381 if (!((Stack < NewStack) && (NewStack < StackEnd)))
382 {
383 /* Stop searching after this entry */
384 StopSearch = TRUE;
385 }
386
387 /* Also make sure that the EIP isn't a stack address */
388 if ((StackBegin < Eip) && (Eip < StackEnd)) break;
389
390 /* Check if we reached a user-mode address */
391 if (!(Flags) && !(Eip & 0x80000000)) break; // FIXME: 3GB breakage
392
393 /* Save this frame */
394 Callers[i] = (PVOID)Eip;
395
396 /* Check if we should continue */
397 if (StopSearch)
398 {
399 /* Return the next index */
400 i++;
401 break;
402 }
403
404 /* Move to the next stack */
405 Stack = NewStack;
406 }
407 }
408 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
409 {
410 /* No index */
411 i = 0;
412 }
413 _SEH2_END;
414
415 /* Return frames parsed */
416 return i;
417 }
418
419 #endif
420
421 /* RTL Atom Tables ************************************************************/
422
423 NTSTATUS
424 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
425 {
426 ExInitializeFastMutex(&AtomTable->FastMutex);
427
428 return STATUS_SUCCESS;
429 }
430
431
432 VOID
433 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
434 {
435 }
436
437
438 BOOLEAN
439 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
440 {
441 ExAcquireFastMutex(&AtomTable->FastMutex);
442 return TRUE;
443 }
444
445 VOID
446 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
447 {
448 ExReleaseFastMutex(&AtomTable->FastMutex);
449 }
450
451 BOOLEAN
452 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
453 {
454 AtomTable->ExHandleTable = ExCreateHandleTable(NULL);
455 return (AtomTable->ExHandleTable != NULL);
456 }
457
458 VOID
459 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
460 {
461 if (AtomTable->ExHandleTable)
462 {
463 ExSweepHandleTable(AtomTable->ExHandleTable,
464 NULL,
465 NULL);
466 ExDestroyHandleTable(AtomTable->ExHandleTable, NULL);
467 AtomTable->ExHandleTable = NULL;
468 }
469 }
470
471 PRTL_ATOM_TABLE
472 RtlpAllocAtomTable(ULONG Size)
473 {
474 PRTL_ATOM_TABLE Table = ExAllocatePool(NonPagedPool,
475 Size);
476 if (Table != NULL)
477 {
478 RtlZeroMemory(Table,
479 Size);
480 }
481
482 return Table;
483 }
484
485 VOID
486 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
487 {
488 ExFreePool(AtomTable);
489 }
490
491 PRTL_ATOM_TABLE_ENTRY
492 RtlpAllocAtomTableEntry(ULONG Size)
493 {
494 PRTL_ATOM_TABLE_ENTRY Entry;
495
496 Entry = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_ATMT);
497 if (Entry != NULL)
498 {
499 RtlZeroMemory(Entry, Size);
500 }
501
502 return Entry;
503 }
504
505 VOID
506 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
507 {
508 ExFreePoolWithTag(Entry, TAG_ATMT);
509 }
510
511 VOID
512 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
513 {
514 ExDestroyHandle(AtomTable->ExHandleTable,
515 (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2),
516 NULL);
517 }
518
519 BOOLEAN
520 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
521 {
522 HANDLE_TABLE_ENTRY ExEntry;
523 HANDLE Handle;
524 USHORT HandleIndex;
525
526 /* Initialize ex handle table entry */
527 ExEntry.Object = Entry;
528 ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */
529
530 /* Create ex handle */
531 Handle = ExCreateHandle(AtomTable->ExHandleTable,
532 &ExEntry);
533 if (!Handle) return FALSE;
534
535 /* Calculate HandleIndex (by getting rid of the first two bits) */
536 HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2);
537
538 /* Index must be less than 0xC000 */
539 if (HandleIndex >= 0xC000)
540 {
541 /* Destroy ex handle */
542 ExDestroyHandle(AtomTable->ExHandleTable,
543 Handle,
544 NULL);
545
546 /* Return failure */
547 return FALSE;
548 }
549
550 /* Initialize atom table entry */
551 Entry->HandleIndex = HandleIndex;
552 Entry->Atom = 0xC000 + HandleIndex;
553
554 /* Return success */
555 return TRUE;
556 }
557
558 PRTL_ATOM_TABLE_ENTRY
559 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
560 {
561 PHANDLE_TABLE_ENTRY ExEntry;
562 PRTL_ATOM_TABLE_ENTRY Entry = NULL;
563
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) */
567
568 ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable,
569 (HANDLE)((ULONG_PTR)Index << 2));
570 if (ExEntry != NULL)
571 {
572 Entry = ExEntry->Object;
573
574 ExUnlockHandleTableEntry(AtomTable->ExHandleTable,
575 ExEntry);
576 }
577
578 return Entry;
579 }
580
581 /*
582 * Ldr Resource support code
583 */
584
585 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
586 LPCWSTR name, void *root,
587 int want_dir );
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 );
592
593 /**********************************************************************
594 * find_entry
595 *
596 * Find a resource entry
597 */
598 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
599 ULONG level, void **ret, int want_dir )
600 {
601 ULONG size;
602 void *root;
603 IMAGE_RESOURCE_DIRECTORY *resdirptr;
604
605 root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
606 if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
607 resdirptr = root;
608
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;
613
614 resdirptr = *ret;
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 */
619
620 resdirptr = *ret;
621
622 if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
623
624 return STATUS_RESOURCE_DATA_NOT_FOUND;
625
626 done:
627 *ret = resdirptr;
628 return STATUS_SUCCESS;
629 }
630
631
632 /* EOF */