| 660 | } |
| 661 | |
| 662 | void LoadUnique32BitSigreturn(VDSOMapping* Mapping, FEX::HLE::SyscallHandler* const Handler) { |
| 663 | // Hardcoded to one page for now |
| 664 | auto PageSize = sysconf(_SC_PAGESIZE); |
| 665 | PageSize = PageSize > 0 ? PageSize : FEXCore::Utils::FEX_PAGE_SIZE; |
| 666 | Mapping->OptionalMappingSize = PageSize; |
| 667 | |
| 668 | // First 64bit page |
| 669 | constexpr uintptr_t LOCATION_MAX = 0x1'0000'0000; |
| 670 | |
| 671 | // We need to have the sigret handler in the lower 32bits of memory space |
| 672 | // Scan top down and try to allocate a location |
| 673 | for (size_t Location = 0xFFFF'E000; Location != 0x0; Location -= PageSize) { |
| 674 | void* Ptr = |
| 675 | ::mmap(reinterpret_cast<void*>(Location), PageSize, PROT_READ | PROT_WRITE, MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
| 676 | |
| 677 | if (Ptr != MAP_FAILED && reinterpret_cast<uintptr_t>(Ptr) >= LOCATION_MAX) { |
| 678 | // Failed to map in the lower 32bits |
| 679 | // Try again |
| 680 | // Can happen in the case that host kernel ignores MAP_FIXED_NOREPLACE |
| 681 | ::munmap(Ptr, PageSize); |
| 682 | continue; |
| 683 | } |
| 684 | |
| 685 | if (Ptr != MAP_FAILED) { |
| 686 | Mapping->OptionalSigReturnMapping = Ptr; |
| 687 | break; |
| 688 | } |
| 689 | } |
| 690 | |
| 691 | // Can't do anything about this |
| 692 | // Here's hoping the application doesn't use signals |
| 693 | if (!Mapping->OptionalSigReturnMapping) { |
| 694 | return; |
| 695 | } |
| 696 | |
| 697 | // Signal return handlers need to be bit-exact to what the Linux kernel provides in VDSO. |
| 698 | // GDB and unwinding libraries key off of these instructions to understand if the stack frame is a signal frame or not. |
| 699 | // This two code sections match exactly what libSegFault expects. |
| 700 | // |
| 701 | // Typically this handlers are provided by the 32-bit VDSO thunk library, but that isn't available in all cases. |
| 702 | // Falling back to this generated code segment still allows a backtrace to work, just might not show |
| 703 | // the symbol as VDSO since there is no ELF to parse. |
| 704 | constexpr std::array<uint8_t, 9> sigreturn_32_code = { |
| 705 | 0x58, // pop eax |
| 706 | 0xb8, 0x77, 0x00, 0x00, 0x00, // mov eax, 0x77 |
| 707 | 0xcd, 0x80, // int 0x80 |
| 708 | 0x90, // nop |
| 709 | }; |
| 710 | |
| 711 | constexpr std::array<uint8_t, 7> rt_sigreturn_32_code = { |
| 712 | 0xb8, 0xad, 0x00, 0x00, 0x00, // mov eax, 0xad |
| 713 | 0xcd, 0x80, // int 0x80 |
| 714 | }; |
| 715 | |
| 716 | VDSOPointers.VDSO_kernel_sigreturn = Mapping->OptionalSigReturnMapping; |
| 717 | VDSOPointers.VDSO_kernel_rt_sigreturn = |
| 718 | reinterpret_cast<void*>(reinterpret_cast<uint64_t>(Mapping->OptionalSigReturnMapping) + sigreturn_32_code.size()); |
| 719 |
no test coverage detected