mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
Exports pause (EDyhWelj7UY), sigwait (mrbHXqK8wkg) and sigwaitinfo (Uq5BGthgbl4) from libkernel. NIDs computed with tools/nid_names.py and matched in aerolib; ps5-payload-dev/sdk f5d40f02 sce_stubs/libkernel.c places all three in libkernel. They throw like the merged sigtimedwait (#3430), with the same message pattern: "sigwait: waiting for a pending signal", "sigwaitinfo: waiting for a pending signal" and "pause: waiting for a delivered signal". In FreeBSD 11.4 (8c639945) sigwaitinfo is kern_sigtimedwait without a timeout (sys/kern/kern_sig.c:1212), sigwait is the same wait returning the error number (kern_sig.c:1150, lib/libthr/thread/thr_sig.c:676-728) and pause is sigsuspend of the current mask (lib/libc/gen/pause.c:46-56). AnyPS5 never leaves a guest signal pending (blocked signals are dropped in Dispatch, raise delivers at once), so there is nothing to take, and raise, kill and pthread_kill run a handler only on the calling thread, so nothing can end a pause. Titles (predicted stops, registry order; not observed runs): - Ruffle PPSA68091, observed today "FAIL: unresolved ELF import 1t1-JoZ0sZQ from libSceLibcInternal.prx" (sinhf, #3519), predicted next "FAIL: unresolved ELF import EDyhWelj7UY from libkernel.prx" (pause, call site 0x8F7266). - RetroArch PPSA99169: pause (0x30DB1, an address table entry). - PS5MC PPSA99420: pause (0x3BD80F6, 0x3C9E220), sigwait (0x3C9E4C7), sigwaitinfo (0x3C9E588). - XPSemu PPSA97358: sigwait (0xE02AEC, 0x1101294, 0x1101368), QEMU's dummy vCPU thread and sigwait_compat thread. guest_sigtimedwait now also checks the three throws, with an empty set, a null info, a SIGINT raised while blocked, and that neither the output nor the blocked mask changes. TechnicalDebt records the call sites. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
82 lines
3.7 KiB
C++
82 lines
3.7 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
struct GuestSignalSet {
|
|
std::uint32_t bits[4];
|
|
};
|
|
struct GuestTimespec {
|
|
std::int64_t seconds;
|
|
std::int64_t nanoseconds;
|
|
};
|
|
using Handler = void (APS5_VABI *)(int);
|
|
extern "C" {
|
|
int APS5_VABI sigtimedwait_nid_postfix(const GuestSignalSet*, void*, const GuestTimespec*);
|
|
int APS5_VABI sigwaitinfo_nid_postfix(const GuestSignalSet*, void*);
|
|
int APS5_VABI sigwait_nid_postfix(const GuestSignalSet*, int*);
|
|
int APS5_VABI pause_nid_postfix(void);
|
|
Handler APS5_VABI signal_nid_postfix(int, Handler);
|
|
int APS5_VABI raise_nid_postfix(int);
|
|
int APS5_VABI _sigprocmask_nid_postfix(int, const GuestSignalSet*, GuestSignalSet*);
|
|
}
|
|
volatile int received = 0;
|
|
void APS5_VABI Callback(int value) { received = value; }
|
|
static void Require(bool value) { if (!value) std::abort(); }
|
|
template <typename TCall>
|
|
static bool ReportsNotImplemented(TCall call, const char* message) {
|
|
try {
|
|
call();
|
|
} catch (const std::runtime_error& error) {
|
|
return std::string(error.what()) == message;
|
|
}
|
|
return false;
|
|
}
|
|
static bool SigtimedwaitReportsNotImplemented(const GuestSignalSet* set, void* info, const GuestTimespec* timeout) {
|
|
return ReportsNotImplemented([&] { sigtimedwait_nid_postfix(set, info, timeout); }, "sigtimedwait: waiting for a pending signal not implemented");
|
|
}
|
|
static bool SigwaitinfoReportsNotImplemented(const GuestSignalSet* set, void* info) {
|
|
return ReportsNotImplemented([&] { sigwaitinfo_nid_postfix(set, info); }, "sigwaitinfo: waiting for a pending signal not implemented");
|
|
}
|
|
static bool SigwaitReportsNotImplemented(const GuestSignalSet* set, int* taken) {
|
|
return ReportsNotImplemented([&] { sigwait_nid_postfix(set, taken); }, "sigwait: waiting for a pending signal not implemented");
|
|
}
|
|
int main() {
|
|
const GuestSignalSet pipe{{1u << 12, 0, 0, 0}};
|
|
const GuestSignalSet empty{{0, 0, 0, 0}};
|
|
const GuestSignalSet interrupt{{1u << 1, 0, 0, 0}};
|
|
unsigned char info[64] = {};
|
|
const unsigned char untouched[64] = {};
|
|
const GuestTimespec poll{0, 0};
|
|
const GuestTimespec second{1, 0};
|
|
Require(SigtimedwaitReportsNotImplemented(&pipe, info, &poll));
|
|
Require(SigtimedwaitReportsNotImplemented(&pipe, nullptr, &second));
|
|
Require(SigtimedwaitReportsNotImplemented(&pipe, info, nullptr));
|
|
|
|
Require(SigwaitinfoReportsNotImplemented(&pipe, info));
|
|
Require(SigwaitinfoReportsNotImplemented(&pipe, nullptr));
|
|
Require(SigwaitinfoReportsNotImplemented(&empty, info));
|
|
Require(std::memcmp(info, untouched, sizeof(info)) == 0);
|
|
|
|
int taken = -1;
|
|
Require(SigwaitReportsNotImplemented(&pipe, &taken));
|
|
Require(SigwaitReportsNotImplemented(&empty, &taken));
|
|
Require(taken == -1);
|
|
|
|
Require(ReportsNotImplemented([] { pause_nid_postfix(); }, "pause: waiting for a delivered signal not implemented"));
|
|
|
|
GuestSignalSet previous{};
|
|
Require(signal_nid_postfix(2, Callback) != reinterpret_cast<Handler>(static_cast<std::uintptr_t>(-1)));
|
|
Require(_sigprocmask_nid_postfix(1, &interrupt, &previous) == 0);
|
|
Require(raise_nid_postfix(2) == 0 && received == 0);
|
|
Require(SigwaitReportsNotImplemented(&interrupt, &taken) && taken == -1);
|
|
Require(SigwaitinfoReportsNotImplemented(&interrupt, info));
|
|
Require(std::memcmp(info, untouched, sizeof(info)) == 0);
|
|
GuestSignalSet current{};
|
|
Require(_sigprocmask_nid_postfix(1, nullptr, ¤t) == 0 && current.bits[0] == (previous.bits[0] | interrupt.bits[0]));
|
|
Require(_sigprocmask_nid_postfix(3, &previous, nullptr) == 0);
|
|
Require(raise_nid_postfix(2) == 0 && received == 2);
|
|
Require(ReportsNotImplemented([] { pause_nid_postfix(); }, "pause: waiting for a delivered signal not implemented"));
|
|
}
|