ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

AnyPS5 异常处理实录:Guest 信号与 Windows SEH 的完整对接实现

AnyPS5 异常处理实录:Guest 信号与 Windows SEH 的完整对接实现 AnyPS5 异常处理实录Guest 信号与 Windows SEH 的完整对接实现【免费下载链接】AnyPS5Tool for automatic PS5 executables porting to Linux and Windows项目地址: https://gitcode.com/GitHub_Trending/an/AnyPS5AnyPS5 是一款将 PS5 可执行文件自动移植到 Linux 和 Windows 的工具。移植后程序跑得起来只是第一步更关键的是当客端程序游戏出错时宿主机的异常机制必须接得住、报得清、还能继续跑。这篇文章带你完整看懂 AnyPS5 中 Guest 信号、Windows SEH 与 C 异常运行时三套机制是如何协同工作的。为什么移植后的程序会死法不同PS5 游戏在 PlayStation 系统上通过POSIX 信号SIGSEGV、SIGINT 等感知和响应错误而 Windows 宿主机上硬件故障走的是SEH结构化异常处理通道Linux 宿主机则沿用标准信号。同一个访问非法内存的指令在三种系统里表现为三种不同的事件。AnyPS5 的解法可以概括为三层层级职责核心文件Guest 信号层把客端信号号翻译成宿主机信号并调度回调Signals.cppWindows SEH 层拦截致命故障输出诊断报告或就地修复CrashReport.cppC 异常运行时完整实现 Itanium ABI 的 try/catch 展开Runtime.cppGuest 信号如何把 POSIX 信号桥接到宿主机客端游戏调用signal(15, handler)注册的信号号是 PS5 的编号。AnyPS5 在 Signals.cpp 中维护了一张映射表把客端信号号翻译成宿主机原生信号2 → SIGINT中断4 → SIGILL非法指令6 → SIGABRT中止8 → SIGFPE浮点错误11 → SIGSEGV段错误15 → SIGTERM终止客端调用signal_nid_postfix时系统会把宿主机信号绑定到一个Dispatch分发器当真实信号到达时分发器反向查表得到客端信号号检查是否被sigprocmask屏蔽然后调用客端注册的处理函数。这里有一个很巧妙的细节在 Windows 上CRT 每次投递信号后会重置处理器因此分发器会在每次触发时重新注册自己源码注释Preserve the guests persistent registration across CRT delivery保证客端注册的信号处理常驻有效而不是只活一次。对应的验证测试见 GuestSignals.cpp——它完整覆盖了注册、raise、忽略、屏蔽掩码查询与恢复等所有路径包括错误信号号返回errno22的标准行为。Windows SEH 对接让致命故障变成一份事故报告Windows 上最有价值的对接在 CrashReport.cpp。程序启动时通过AddVectoredExceptionHandler注册一个向量化异常处理器所有硬件故障都会先流经这里处理流程是一条拦截流水线客端内存写入修复如果是写访问违例且命中客端内存区域直接放行继续执行写监视点Watchpoint开发调试用把某个 8 字节地址的页设为只读任何写入都会触发单步陷阱报告是谁、从哪条指令、写了什么值——专治这个数据为什么被改类灵异问题SSE4a 指令仿真PS5 的 Zen 2 芯片有 AMD 专属的 EXTRQ/INSERTQ 指令游戏真的会用它们。在 Intel 宿主上这些指令会抛出非法指令异常处理器就地在故障线程的 CONTEXT 上仿真执行游戏完全无感知致命故障报告若以上都不匹配且属于致命错误则打印一份完整事故报告后终止。这份报告的信息密度非常高全部 15 个通用寄存器的值以及每个寄存器所指向的 8 个字方便识别坏指针来自哪个结构体帧指针链回溯出的调用栈每一帧都解析成模块名偏移栈上可执行地址的返回地址候选——即使栈帧已被破坏也能给出最近刚返回过哪些地址进程内所有其他线程的现场快照逐一挂起、抓取 CONTEXT、恢复。此外还提供了几个开关型环境变量详见下文速查表比如挂死看门狗程序卡死指定秒数后主动 dump 全部线程再触发 abort。 报告刻意绕过 CRT 的 stderr 流锁直接WriteFile到句柄——因为故障线程自己可能正持有这个锁比如在 printf 内部崩的否则报告代码会再次死锁。C 异常运行时让移植游戏的 try/catch 照常工作大量 PS5 游戏使用 C 异常。AnyPS5 在 core/libs/prx/libc/src/exception/ 下完整实现了一套Itanium ABI 异常运行时__cxa_throw与展开抛异常后沿栈逐帧搜索由 personality 例程Personality.cpp 中的__gxx_personality_v0解析 LSDA 展开表匹配到 catch 后跳转落地类型匹配不只是简单相等判断而是遍历单继承/多继承基类链和指针类型链含 const/volatile 修饰处理菱形继承偏移调整——catch (const Base)能否接住throw Derived在这里被精确裁决exception_ptr跨线程传递ExceptionPointer.cpp 通过引用计数实现异常对象在多个线程间 rethrow析构恰好一次terminate 兜底未捕获异常会走 Runtime.cpp 中的DefaultTerminate打印terminate called after throwing an instance of 类型名 what()类型名还会做 C demangle最后 abort。跨 DLL 抛异常客端代码在移植后的 EXE/DLL 中宿主侧捕获同样是受支持的——这正是移植场景下的常态。验证一切正常两套针对性异常测试WindowsExceptions.cpp在 Windows 目标上跑通typed catch、基类 catch、catch-all、rethrow、析构顺序、跨 DLL 异常六项断言外加 RTTI 类型表与exception_ptr四线程 rethrow 测试GuestSignals.cpp覆盖信号注册/忽略/屏蔽的完整状态机运行器 run_exception_tests.py 负责编排这些用例的执行。实用环境变量速查表 ️环境变量作用APS5_WATCH_WRITEELF地址监视客端数据写入报告每次写操作来源APS5_WATCH_ADDR绝对地址监视后映射区域的地址后台线程等待页提交后布防APS5_NO_SSE4A_EMULATION1关闭 SSE4a 仿真让故障按致命错误报告APS5_TRACE_SSE4A1逐条打印被仿真的 extrq/insertq 指令APS5_HANG_DUMP_SECS秒挂死看门狗超时后 dump 全线程并 abortAPS5_TRACE_EXIT进程退出时打印静态析构栈总结AnyPS5 的异常处理体现了移植工具的核心功力不是让 PS5 的异常体系在宿主机上原样存在而是为每一层故障都找到宿主的等价物并保留客端视角的语义。Guest 信号层维持了 POSIX 语义的一致性SEH 层把 Windows 的硬件故障变成了可读的诊断甚至就地修复 SSE4a 这类平台差异C 运行时层则保证了游戏逻辑层的 try/catch 行为与原版一致。对想理解跨平台异常桥接如何落地的读者这三个目录libkernel/System/src/Signals.cpp、libc/src/specifics/windows/CrashReport.cpp、libc/src/exception/是绝佳的阅读起点。【免费下载链接】AnyPS5Tool for automatic PS5 executables porting to Linux and Windows项目地址: https://gitcode.com/GitHub_Trending/an/AnyPS5创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表