mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
On Windows the call returned no eh_frame_hdr for every address, so a title's own libc (its libunwind) found no frame information and terminated on the first C++ exception thrown in guest code. PPSA12544 died that way after its intro cinematic: IL2CPP raised an AmbiguousMatchException that Unity catches and logs, and the runtime called terminate instead. For an address in a relinked guest image the call now returns the PT_GNU_EH_FRAME segment named by .ehmeta, the eh_frame it points to and its size, and the image as seg0; host images keep the empty answer. AI-assisted: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.1 KiB
C++
54 lines
2.1 KiB
C++
#include "SceTypes.hpp"
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <windows.h>
|
|
|
|
extern "C" int APS5_VABI sceKernelGetModuleInfoForUnwind(uint64_t addr, int flags, ModuleInfoForUnwind* info);
|
|
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
__attribute__((section(".ehmeta"), used)) static volatile std::uint32_t ehMeta = 0;
|
|
|
|
struct alignas(4) FrameHeader {
|
|
std::uint8_t version = 1;
|
|
std::uint8_t framePointerEncoding = 0x1b;
|
|
std::uint8_t countEncoding = 0x03;
|
|
std::uint8_t tableEncoding = 0x3b;
|
|
std::int32_t frames = 0;
|
|
std::uint32_t count = 0;
|
|
};
|
|
|
|
struct alignas(4) Frames {
|
|
std::uint32_t cieLength = 12;
|
|
std::uint32_t cieId = 0;
|
|
std::uint8_t cie[8] = {1, 0, 1, 0x78, 16, 0, 0, 0};
|
|
std::uint32_t terminator = 0;
|
|
};
|
|
|
|
static FrameHeader header;
|
|
static Frames frames;
|
|
|
|
int main() {
|
|
const auto base = reinterpret_cast<std::uint64_t>(GetModuleHandleW(nullptr));
|
|
header.frames = static_cast<std::int32_t>(reinterpret_cast<std::intptr_t>(&frames) - reinterpret_cast<std::intptr_t>(&header.frames));
|
|
DWORD old = 0;
|
|
Require(VirtualProtect(const_cast<std::uint32_t*>(&ehMeta), sizeof(ehMeta), PAGE_READWRITE, &old));
|
|
ehMeta = static_cast<std::uint32_t>(reinterpret_cast<std::uint64_t>(&header) - base);
|
|
|
|
ModuleInfoForUnwind info{};
|
|
Require(sceKernelGetModuleInfoForUnwind(reinterpret_cast<std::uint64_t>(&main), 0, &info) == 0);
|
|
Require(info.st_size == sizeof(ModuleInfoForUnwind));
|
|
Require(info.eh_frame_hdr_addr == reinterpret_cast<std::uint64_t>(&header));
|
|
Require(info.eh_frame_addr == reinterpret_cast<std::uint64_t>(&frames));
|
|
Require(info.eh_frame_size == 4 + 12);
|
|
Require(info.seg0_addr == base);
|
|
const auto* dos = reinterpret_cast<const IMAGE_DOS_HEADER*>(base);
|
|
const auto* nt = reinterpret_cast<const IMAGE_NT_HEADERS64*>(base + dos->e_lfanew);
|
|
Require(info.seg0_size == nt->OptionalHeader.SizeOfImage);
|
|
|
|
ModuleInfoForUnwind host{};
|
|
Require(sceKernelGetModuleInfoForUnwind(reinterpret_cast<std::uint64_t>(&GetModuleHandleW), 0, &host) == 0);
|
|
Require(host.eh_frame_hdr_addr == 0 && host.eh_frame_addr == 0 && host.eh_frame_size == 0);
|
|
}
|