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