xref: /reactos/ntoskrnl/rtl/libsupp.c (revision 40462c92)
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 #define TAG_RTHL 'LHtR' /* Heap Lock */
18 
19 extern ULONG NtGlobalFlag;
20 
21 typedef struct _RTL_RANGE_ENTRY
22 {
23     LIST_ENTRY Entry;
24     RTL_RANGE Range;
25 } RTL_RANGE_ENTRY, *PRTL_RANGE_ENTRY;
26 
27 PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
28 SIZE_T RtlpAllocDeallocQueryBufferSize = 128;
29 
30 /* FUNCTIONS *****************************************************************/
31 
32 PVOID
33 NTAPI
34 RtlPcToFileHeader(
35     IN  PVOID PcValue,
36     OUT PVOID *BaseOfImage)
37 {
38     PLDR_DATA_TABLE_ENTRY LdrEntry;
39     BOOLEAN InSystem;
40 
41     /* Get the base for this file */
42     if ((ULONG_PTR)PcValue > (ULONG_PTR)MmHighestUserAddress)
43     {
44         /* We are in kernel */
45         *BaseOfImage = KiPcToFileHeader(PcValue, &LdrEntry, FALSE, &InSystem);
46     }
47     else
48     {
49         /* We are in user land */
50         *BaseOfImage = KiRosPcToUserFileHeader(PcValue, &LdrEntry);
51     }
52 
53     return *BaseOfImage;
54 }
55 
56 VOID
57 NTAPI
58 RtlInitializeRangeListPackage(VOID)
59 {
60     /* Setup the lookaside list for allocations (not used yet) */
61     ExInitializePagedLookasideList(&RtlpRangeListEntryLookasideList,
62                                    NULL,
63                                    NULL,
64                                    POOL_COLD_ALLOCATION,
65                                    sizeof(RTL_RANGE_ENTRY),
66                                    'elRR',
67                                    16);
68 }
69 
70 BOOLEAN
71 NTAPI
72 RtlpCheckForActiveDebugger(VOID)
73 {
74     /* This check is meaningless in kernel-mode */
75     return FALSE;
76 }
77 
78 BOOLEAN
79 NTAPI
80 RtlpSetInDbgPrint(VOID)
81 {
82     /* Nothing to set in kernel mode */
83     return FALSE;
84 }
85 
86 VOID
87 NTAPI
88 RtlpClearInDbgPrint(VOID)
89 {
90     /* Nothing to clear in kernel mode */
91 }
92 
93 KPROCESSOR_MODE
94 NTAPI
95 RtlpGetMode(VOID)
96 {
97    return KernelMode;
98 }
99 
100 PVOID
101 NTAPI
102 RtlpAllocateMemory(ULONG Bytes,
103                    ULONG Tag)
104 {
105     return ExAllocatePoolWithTag(PagedPool,
106                                  (SIZE_T)Bytes,
107                                  Tag);
108 }
109 
110 
111 #define TAG_USTR        'RTSU'
112 #define TAG_ASTR        'RTSA'
113 #define TAG_OSTR        'RTSO'
114 VOID
115 NTAPI
116 RtlpFreeMemory(PVOID Mem,
117                ULONG Tag)
118 {
119     if (Tag == TAG_ASTR || Tag == TAG_OSTR || Tag == TAG_USTR)
120         ExFreePool(Mem);
121     else
122         ExFreePoolWithTag(Mem, Tag);
123 }
124 
125 /*
126  * @implemented
127  */
128 VOID NTAPI
129 RtlAcquirePebLock(VOID)
130 {
131 
132 }
133 
134 /*
135  * @implemented
136  */
137 VOID NTAPI
138 RtlReleasePebLock(VOID)
139 {
140 
141 }
142 
143 NTSTATUS
144 NTAPI
145 LdrShutdownThread(VOID)
146 {
147     return STATUS_SUCCESS;
148 }
149 
150 
151 PPEB
152 NTAPI
153 RtlGetCurrentPeb(VOID)
154 {
155    return ((PEPROCESS)(KeGetCurrentThread()->ApcState.Process))->Peb;
156 }
157 
158 NTSTATUS
159 NTAPI
160 RtlDeleteHeapLock(IN OUT PHEAP_LOCK Lock)
161 {
162     ExDeleteResourceLite(&Lock->Resource);
163     ExFreePoolWithTag(Lock, TAG_RTHL);
164 
165     return STATUS_SUCCESS;
166 }
167 
168 NTSTATUS
169 NTAPI
170 RtlEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
171 {
172     KeEnterCriticalRegion();
173 
174     if (Exclusive)
175         ExAcquireResourceExclusiveLite(&Lock->Resource, TRUE);
176     else
177         ExAcquireResourceSharedLite(&Lock->Resource, TRUE);
178 
179     return STATUS_SUCCESS;
180 }
181 
182 BOOLEAN
183 NTAPI
184 RtlTryEnterHeapLock(IN OUT PHEAP_LOCK Lock, IN BOOLEAN Exclusive)
185 {
186     BOOLEAN Success;
187     KeEnterCriticalRegion();
188 
189     if (Exclusive)
190         Success = ExAcquireResourceExclusiveLite(&Lock->Resource, FALSE);
191     else
192         Success = ExAcquireResourceSharedLite(&Lock->Resource, FALSE);
193 
194     if (!Success)
195         KeLeaveCriticalRegion();
196 
197     return Success;
198 }
199 
200 NTSTATUS
201 NTAPI
202 RtlInitializeHeapLock(IN OUT PHEAP_LOCK *Lock)
203 {
204     PHEAP_LOCK HeapLock = ExAllocatePoolWithTag(NonPagedPool,
205                                                 sizeof(HEAP_LOCK),
206                                                 TAG_RTHL);
207     if (HeapLock == NULL)
208         return STATUS_NO_MEMORY;
209 
210     ExInitializeResourceLite(&HeapLock->Resource);
211     *Lock = HeapLock;
212 
213     return STATUS_SUCCESS;
214 }
215 
216 NTSTATUS
217 NTAPI
218 RtlLeaveHeapLock(IN OUT PHEAP_LOCK Lock)
219 {
220     ExReleaseResourceLite(&Lock->Resource);
221     KeLeaveCriticalRegion();
222 
223     return STATUS_SUCCESS;
224 }
225 
226 struct _HEAP;
227 
228 VOID
229 NTAPI
230 RtlpAddHeapToProcessList(struct _HEAP *Heap)
231 {
232     UNREFERENCED_PARAMETER(Heap);
233 }
234 
235 VOID
236 NTAPI
237 RtlpRemoveHeapFromProcessList(struct _HEAP *Heap)
238 {
239     UNREFERENCED_PARAMETER(Heap);
240 }
241 
242 VOID
243 RtlInitializeHeapManager(VOID)
244 {
245 }
246 
247 #if DBG
248 VOID FASTCALL
249 CHECK_PAGED_CODE_RTL(char *file, int line)
250 {
251   if(KeGetCurrentIrql() > APC_LEVEL)
252   {
253     DbgPrint("%s:%i: Pagable code called at IRQL > APC_LEVEL (%u)\n", file, line, KeGetCurrentIrql());
254     ASSERT(FALSE);
255   }
256 }
257 #endif
258 
259 VOID
260 NTAPI
261 RtlpSetHeapParameters(IN PRTL_HEAP_PARAMETERS Parameters)
262 {
263     /* Apply defaults for non-set parameters */
264     if (!Parameters->SegmentCommit) Parameters->SegmentCommit = MmHeapSegmentCommit;
265     if (!Parameters->SegmentReserve) Parameters->SegmentReserve = MmHeapSegmentReserve;
266     if (!Parameters->DeCommitFreeBlockThreshold) Parameters->DeCommitFreeBlockThreshold = MmHeapDeCommitFreeBlockThreshold;
267     if (!Parameters->DeCommitTotalFreeThreshold) Parameters->DeCommitTotalFreeThreshold = MmHeapDeCommitTotalFreeThreshold;
268 }
269 
270 VOID
271 NTAPI
272 RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord,
273                       IN PCONTEXT ContextRecord,
274                       IN PVOID ContextData,
275                       IN ULONG Size)
276 {
277     /* Check the global flag */
278     if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING)
279     {
280         /* FIXME: Log this exception */
281     }
282 }
283 
284 BOOLEAN
285 NTAPI
286 RtlpHandleDpcStackException(IN PEXCEPTION_REGISTRATION_RECORD RegistrationFrame,
287                             IN ULONG_PTR RegistrationFrameEnd,
288                             IN OUT PULONG_PTR StackLow,
289                             IN OUT PULONG_PTR StackHigh)
290 {
291     PKPRCB Prcb;
292     ULONG_PTR DpcStack;
293 
294     /* Check if we are at DISPATCH or higher */
295     if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
296     {
297         /* Get the PRCB and DPC Stack */
298         Prcb = KeGetCurrentPrcb();
299         DpcStack = (ULONG_PTR)Prcb->DpcStack;
300 
301         /* Check if we are in a DPC and the stack matches */
302         if ((Prcb->DpcRoutineActive) &&
303             (RegistrationFrameEnd <= DpcStack) &&
304             ((ULONG_PTR)RegistrationFrame >= DpcStack - KERNEL_STACK_SIZE))
305         {
306             /* Update the limits to the DPC Stack's */
307             *StackHigh = DpcStack;
308             *StackLow = DpcStack - KERNEL_STACK_SIZE;
309             return TRUE;
310         }
311     }
312 
313     /* Not in DPC stack */
314     return FALSE;
315 }
316 
317 #if !defined(_ARM_) && !defined(_AMD64_)
318 
319 BOOLEAN
320 NTAPI
321 RtlpCaptureStackLimits(IN ULONG_PTR Ebp,
322                        IN ULONG_PTR *StackBegin,
323                        IN ULONG_PTR *StackEnd)
324 {
325     PKTHREAD Thread = KeGetCurrentThread();
326 
327     /* Don't even try at ISR level or later */
328     if (KeGetCurrentIrql() > DISPATCH_LEVEL) return FALSE;
329 
330     /* Start with defaults */
331     *StackBegin = Thread->StackLimit;
332     *StackEnd = (ULONG_PTR)Thread->StackBase;
333 
334     /* Check if EBP is inside the stack */
335     if ((*StackBegin <= Ebp) && (Ebp <= *StackEnd))
336     {
337         /* Then make the stack start at EBP */
338         *StackBegin = Ebp;
339     }
340     else
341     {
342         /* Now we're going to assume we're on the DPC stack */
343         *StackEnd = (ULONG_PTR)(KeGetPcr()->Prcb->DpcStack);
344         *StackBegin = *StackEnd - KERNEL_STACK_SIZE;
345 
346         /* Check if we seem to be on the DPC stack */
347         if ((*StackEnd) && (*StackBegin < Ebp) && (Ebp <= *StackEnd))
348         {
349             /* We're on the DPC stack */
350             *StackBegin = Ebp;
351         }
352         else
353         {
354             /* We're somewhere else entirely... use EBP for safety */
355             *StackBegin = Ebp;
356             *StackEnd = (ULONG_PTR)PAGE_ALIGN(*StackBegin);
357         }
358     }
359 
360     /* Return success */
361     return TRUE;
362 }
363 
364 /*
365  * @implemented
366  */
367 ULONG
368 NTAPI
369 RtlWalkFrameChain(OUT PVOID *Callers,
370                   IN ULONG Count,
371                   IN ULONG Flags)
372 {
373     ULONG_PTR Stack, NewStack, StackBegin, StackEnd = 0;
374     ULONG Eip;
375     BOOLEAN Result, StopSearch = FALSE;
376     ULONG i = 0;
377     PETHREAD Thread = PsGetCurrentThread();
378     PTEB Teb;
379     PKTRAP_FRAME TrapFrame;
380 
381     /* Get current EBP */
382 #if defined(_M_IX86)
383 #if defined __GNUC__
384     __asm__("mov %%ebp, %0" : "=r" (Stack) : );
385 #elif defined(_MSC_VER)
386     __asm mov Stack, ebp
387 #endif
388 #elif defined(_M_MIPS)
389         __asm__("move $sp, %0" : "=r" (Stack) : );
390 #elif defined(_M_PPC)
391     __asm__("mr %0,1" : "=r" (Stack) : );
392 #elif defined(_M_ARM)
393     __asm__("mov sp, %0" : "=r"(Stack) : );
394 #else
395 #error Unknown architecture
396 #endif
397 
398     /* Set it as the stack begin limit as well */
399     StackBegin = (ULONG_PTR)Stack;
400 
401     /* Check if we're called for non-logging mode */
402     if (!Flags)
403     {
404         /* Get the actual safe limits */
405         Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
406                                         &StackBegin,
407                                         &StackEnd);
408         if (!Result) return 0;
409     }
410 
411     /* Use a SEH block for maximum protection */
412     _SEH2_TRY
413     {
414         /* Check if we want the user-mode stack frame */
415         if (Flags == 1)
416         {
417             /* Get the trap frame and TEB */
418             TrapFrame = KeGetTrapFrame(&Thread->Tcb);
419             Teb = Thread->Tcb.Teb;
420 
421             /* Make sure we can trust the TEB and trap frame */
422             if (!(Teb) ||
423                 (KeIsAttachedProcess()) ||
424                 (KeGetCurrentIrql() >= DISPATCH_LEVEL))
425             {
426                 /* Invalid or unsafe attempt to get the stack */
427                 _SEH2_YIELD(return 0;)
428             }
429 
430             /* Get the stack limits */
431             StackBegin = (ULONG_PTR)Teb->NtTib.StackLimit;
432             StackEnd = (ULONG_PTR)Teb->NtTib.StackBase;
433 #ifdef _M_IX86
434             Stack = TrapFrame->Ebp;
435 #elif defined(_M_PPC)
436             Stack = TrapFrame->Gpr1;
437 #else
438 #error Unknown architecture
439 #endif
440 
441             /* Validate them */
442             if (StackEnd <= StackBegin) _SEH2_YIELD(return 0);
443             ProbeForRead((PVOID)StackBegin,
444                          StackEnd - StackBegin,
445                          sizeof(CHAR));
446         }
447 
448         /* Loop the frames */
449         for (i = 0; i < Count; i++)
450         {
451             /*
452              * Leave if we're past the stack,
453              * if we're before the stack,
454              * or if we've reached ourselves.
455              */
456             if ((Stack >= StackEnd) ||
457                 (!i ? (Stack < StackBegin) : (Stack <= StackBegin)) ||
458                 ((StackEnd - Stack) < (2 * sizeof(ULONG_PTR))))
459             {
460                 /* We're done or hit a bad address */
461                 break;
462             }
463 
464             /* Get new stack and EIP */
465             NewStack = *(PULONG_PTR)Stack;
466             Eip = *(PULONG_PTR)(Stack + sizeof(ULONG_PTR));
467 
468             /* Check if the new pointer is above the oldone and past the end */
469             if (!((Stack < NewStack) && (NewStack < StackEnd)))
470             {
471                 /* Stop searching after this entry */
472                 StopSearch = TRUE;
473             }
474 
475             /* Also make sure that the EIP isn't a stack address */
476             if ((StackBegin < Eip) && (Eip < StackEnd)) break;
477 
478             /* Check if we reached a user-mode address */
479             if (!(Flags) && !(Eip & 0x80000000)) break; // FIXME: 3GB breakage
480 
481             /* Save this frame */
482             Callers[i] = (PVOID)Eip;
483 
484             /* Check if we should continue */
485             if (StopSearch)
486             {
487                 /* Return the next index */
488                 i++;
489                 break;
490             }
491 
492             /* Move to the next stack */
493             Stack = NewStack;
494         }
495     }
496     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
497     {
498         /* No index */
499         i = 0;
500     }
501     _SEH2_END;
502 
503     /* Return frames parsed */
504     return i;
505 }
506 
507 #endif
508 
509 #if defined(_M_AMD64) || defined(_M_ARM)
510 VOID
511 NTAPI
512 RtlpGetStackLimits(
513     OUT PULONG_PTR LowLimit,
514     OUT PULONG_PTR HighLimit)
515 {
516     PKTHREAD CurrentThread = KeGetCurrentThread();
517     *HighLimit = (ULONG_PTR)CurrentThread->InitialStack;
518     *LowLimit = (ULONG_PTR)CurrentThread->StackLimit;
519 }
520 #endif
521 
522 /* RTL Atom Tables ************************************************************/
523 
524 NTSTATUS
525 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
526 {
527    ExInitializeFastMutex(&AtomTable->FastMutex);
528 
529    return STATUS_SUCCESS;
530 }
531 
532 
533 VOID
534 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
535 {
536 }
537 
538 
539 BOOLEAN
540 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
541 {
542    ExAcquireFastMutex(&AtomTable->FastMutex);
543    return TRUE;
544 }
545 
546 VOID
547 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
548 {
549    ExReleaseFastMutex(&AtomTable->FastMutex);
550 }
551 
552 BOOLEAN
553 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
554 {
555    AtomTable->ExHandleTable = ExCreateHandleTable(NULL);
556    return (AtomTable->ExHandleTable != NULL);
557 }
558 
559 BOOLEAN
560 NTAPI
561 RtlpCloseHandleCallback(
562     IN PHANDLE_TABLE_ENTRY HandleTableEntry,
563     IN HANDLE Handle,
564     IN PVOID HandleTable)
565 {
566     /* Destroy and unlock the handle entry */
567     return ExDestroyHandle(HandleTable, Handle, HandleTableEntry);
568 }
569 
570 VOID
571 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
572 {
573    if (AtomTable->ExHandleTable)
574    {
575       ExSweepHandleTable(AtomTable->ExHandleTable,
576                          RtlpCloseHandleCallback,
577                          AtomTable->ExHandleTable);
578       ExDestroyHandleTable(AtomTable->ExHandleTable, NULL);
579       AtomTable->ExHandleTable = NULL;
580    }
581 }
582 
583 PRTL_ATOM_TABLE
584 RtlpAllocAtomTable(ULONG Size)
585 {
586    PRTL_ATOM_TABLE Table = ExAllocatePoolWithTag(NonPagedPool,
587                                                  Size,
588                                                  TAG_ATMT);
589    if (Table != NULL)
590    {
591       RtlZeroMemory(Table,
592                     Size);
593    }
594 
595    return Table;
596 }
597 
598 VOID
599 RtlpFreeAtomTable(PRTL_ATOM_TABLE AtomTable)
600 {
601    ExFreePoolWithTag(AtomTable, TAG_ATMT);
602 }
603 
604 PRTL_ATOM_TABLE_ENTRY
605 RtlpAllocAtomTableEntry(ULONG Size)
606 {
607     PRTL_ATOM_TABLE_ENTRY Entry;
608 
609     Entry = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_ATMT);
610     if (Entry != NULL)
611     {
612         RtlZeroMemory(Entry, Size);
613     }
614 
615     return Entry;
616 }
617 
618 VOID
619 RtlpFreeAtomTableEntry(PRTL_ATOM_TABLE_ENTRY Entry)
620 {
621     ExFreePoolWithTag(Entry, TAG_ATMT);
622 }
623 
624 VOID
625 RtlpFreeAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
626 {
627    ExDestroyHandle(AtomTable->ExHandleTable,
628                    (HANDLE)((ULONG_PTR)Entry->HandleIndex << 2),
629                    NULL);
630 }
631 
632 BOOLEAN
633 RtlpCreateAtomHandle(PRTL_ATOM_TABLE AtomTable, PRTL_ATOM_TABLE_ENTRY Entry)
634 {
635    HANDLE_TABLE_ENTRY ExEntry;
636    HANDLE Handle;
637    USHORT HandleIndex;
638 
639    /* Initialize ex handle table entry */
640    ExEntry.Object = Entry;
641    ExEntry.GrantedAccess = 0x1; /* FIXME - valid handle */
642 
643    /* Create ex handle */
644    Handle = ExCreateHandle(AtomTable->ExHandleTable,
645                            &ExEntry);
646    if (!Handle) return FALSE;
647 
648    /* Calculate HandleIndex (by getting rid of the first two bits) */
649    HandleIndex = (USHORT)((ULONG_PTR)Handle >> 2);
650 
651    /* Index must be less than 0xC000 */
652    if (HandleIndex >= 0xC000)
653    {
654        /* Destroy ex handle */
655        ExDestroyHandle(AtomTable->ExHandleTable,
656                        Handle,
657                        NULL);
658 
659        /* Return failure */
660        return FALSE;
661    }
662 
663    /* Initialize atom table entry */
664    Entry->HandleIndex = HandleIndex;
665    Entry->Atom = 0xC000 + HandleIndex;
666 
667    /* Return success */
668    return TRUE;
669 }
670 
671 PRTL_ATOM_TABLE_ENTRY
672 RtlpGetAtomEntry(PRTL_ATOM_TABLE AtomTable, ULONG Index)
673 {
674    PHANDLE_TABLE_ENTRY ExEntry;
675    PRTL_ATOM_TABLE_ENTRY Entry = NULL;
676 
677    /* NOTE: There's no need to explicitly enter a critical region because it's
678             guaranteed that we're in a critical region right now (as we hold
679             the atom table lock) */
680 
681    ExEntry = ExMapHandleToPointer(AtomTable->ExHandleTable,
682                                   (HANDLE)((ULONG_PTR)Index << 2));
683    if (ExEntry != NULL)
684    {
685       Entry = ExEntry->Object;
686 
687       ExUnlockHandleTableEntry(AtomTable->ExHandleTable,
688                                ExEntry);
689    }
690 
691    return Entry;
692 }
693 
694 /* Ldr SEH-Protected access to IMAGE_NT_HEADERS */
695 
696 /* Rtl SEH-Free version of this */
697 NTSTATUS
698 NTAPI
699 RtlpImageNtHeaderEx(
700     _In_ ULONG Flags,
701     _In_ PVOID Base,
702     _In_ ULONG64 Size,
703     _Out_ PIMAGE_NT_HEADERS *OutHeaders);
704 
705 /*
706  * @implemented
707  * @note: This is here, so that we do not drag SEH into rosload, freeldr and bootmgfw
708  */
709 NTSTATUS
710 NTAPI
711 RtlImageNtHeaderEx(
712     _In_ ULONG Flags,
713     _In_ PVOID Base,
714     _In_ ULONG64 Size,
715     _Out_ PIMAGE_NT_HEADERS *OutHeaders)
716 {
717     NTSTATUS Status;
718 
719     /* Assume failure. This is also done in RtlpImageNtHeaderEx, but this is guarded by SEH. */
720     if (OutHeaders != NULL)
721         *OutHeaders = NULL;
722 
723     _SEH2_TRY
724     {
725         Status = RtlpImageNtHeaderEx(Flags, Base, Size, OutHeaders);
726     }
727     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
728     {
729         /* Fail with the SEH error */
730         Status = _SEH2_GetExceptionCode();
731     }
732     _SEH2_END;
733 
734     return Status;
735 }
736 
737 /*
738  * Ldr Resource support code
739  */
740 
741 IMAGE_RESOURCE_DIRECTORY *find_entry_by_name( IMAGE_RESOURCE_DIRECTORY *dir,
742                                               LPCWSTR name, void *root,
743                                               int want_dir );
744 IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( IMAGE_RESOURCE_DIRECTORY *dir,
745                                             USHORT id, void *root, int want_dir );
746 IMAGE_RESOURCE_DIRECTORY *find_first_entry( IMAGE_RESOURCE_DIRECTORY *dir,
747                                             void *root, int want_dir );
748 
749 /**********************************************************************
750  *  find_entry
751  *
752  * Find a resource entry
753  */
754 NTSTATUS find_entry( PVOID BaseAddress, LDR_RESOURCE_INFO *info,
755                      ULONG level, void **ret, int want_dir )
756 {
757     ULONG size;
758     void *root;
759     IMAGE_RESOURCE_DIRECTORY *resdirptr;
760 
761     root = RtlImageDirectoryEntryToData( BaseAddress, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
762     if (!root) return STATUS_RESOURCE_DATA_NOT_FOUND;
763     if (size < sizeof(*resdirptr)) return STATUS_RESOURCE_DATA_NOT_FOUND;
764     resdirptr = root;
765 
766     if (!level--) goto done;
767     if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Type, root, want_dir || level )))
768         return STATUS_RESOURCE_TYPE_NOT_FOUND;
769     if (!level--) return STATUS_SUCCESS;
770 
771     resdirptr = *ret;
772     if (!(*ret = find_entry_by_name( resdirptr, (LPCWSTR)info->Name, root, want_dir || level )))
773         return STATUS_RESOURCE_NAME_NOT_FOUND;
774     if (!level--) return STATUS_SUCCESS;
775     if (level) return STATUS_INVALID_PARAMETER;  /* level > 3 */
776 
777     resdirptr = *ret;
778 
779     if ((*ret = find_first_entry( resdirptr, root, want_dir ))) return STATUS_SUCCESS;
780 
781     return STATUS_RESOURCE_DATA_NOT_FOUND;
782 
783 done:
784     *ret = resdirptr;
785     return STATUS_SUCCESS;
786 }
787 
788 NTSTATUS
789 NTAPI
790 RtlpSafeCopyMemory(
791    _Out_writes_bytes_all_(Length) VOID UNALIGNED *Destination,
792    _In_reads_bytes_(Length) CONST VOID UNALIGNED *Source,
793    _In_ SIZE_T Length)
794 {
795     _SEH2_TRY
796     {
797         RtlCopyMemory(Destination, Source, Length);
798     }
799     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
800     {
801         _SEH2_YIELD(return _SEH2_GetExceptionCode());
802     }
803     _SEH2_END;
804 
805     return STATUS_SUCCESS;
806 }
807 
808 BOOLEAN
809 NTAPI
810 RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord,
811                                  _In_ PCONTEXT Context)
812 {
813     /* In the kernel we don't have vectored exception handlers */
814     return FALSE;
815 }
816 
817 VOID
818 NTAPI
819 RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord,
820                                 _In_ PCONTEXT Context)
821 {
822     /* No vectored continue handlers either in kernel mode */
823     return;
824 }
825 
826 /* EOF */
827