The debt entries only had the four index sections before; use Unknown
function info for the imports that fail a title to load and for the
signatures Orbital or the aerolib NID list do not give. Note that
sceSystemServiceShowDisplaySafeAreaSettings takes its (void) signature
from the sibling sceSystemServiceShowControllerSettings, not a reference.
AI-assisted: yes
Add boilerplate stubs for libSceAt9Enc, libSceAudiodecCpu, libSceAudiodecCpuHevag,
libSceM4aacEnc, libSceSulpha, libSceCamera, and libSceDepth2, each exporting its
known NIDs via NotImplemented_nid_no_patch. Include debt documentation with
sysmodule IDs and (where available) orbital-derived signatures.
Add sceSystemServiceShowDisplaySafeAreaSettings as a silent success stub and
document it under Silent stubs.
AI-assisted: yes
sceSystemServiceLoadExec found its own executable through /proc/self/exe
and replaced the process with fexecve after close_range, none of which
macOS has, so on macOS every call except "exit" threw. On macOS:
- the running executable's path comes from _NSGetExecutablePath, resolved
with std::filesystem::canonical, as libSceNpEntitlementAccess and
libSceFont already do;
- the target must be an x86-64 Mach-O executable (MH_MAGIC_64,
CPU_TYPE_X86_64, MH_EXECUTE) that the user may run;
- macOS has no fexecve, so the process is replaced by path with
posix_spawn and POSIX_SPAWN_SETEXEC; POSIX_SPAWN_CLOEXEC_DEFAULT closes
every descriptor but the standard streams, as close_range does on Linux;
- before the replacement the exit starts and the shutdown callbacks run
(LibcStartExit, then LibcRunShutdown), as on Linux, so guest threads
that call a stopped library wait instead of unwinding;
- descriptor 2 gets the host standard error back before the replacement,
as on Linux, and guest_system_load_exec_standard_error runs on macOS.
A launch without arguments keeps the Linux execv path, which macOS has.
guest_system_exit finds its own executable the same way on macOS.
Forever Launcher (PPSA99030) imports sceSystemServiceAddLocalProcessForPsmKit
and sceSystemServiceKillLocalProcessForPsmKit and stops at load without
them. AnyPS5 runs one process and starts no other, so both throw without
reading their arguments. The parameters follow the title's own firmware
probes (path, argv and a 0x90-byte parameter block; the kill takes the
returned handle), and the unknown results are recorded as technical debt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Metal Gear Solid 4 (PPSA18194) aborts on main when its launcher starts
the game: sceSystemServiceLoadExec runs the guest shutdown, a render
thread that then calls into the stopped AGC driver gets ProcessShutdown
back from LibcAwaitExit, and the exception unwinds into title code,
which terminates the process before the new executable starts.
LibcAwaitExit parks a thread only once an exit has been requested, and
LoadExec ran the shutdown without requesting one. It now starts the
shutdown the way exit does, so such threads wait until the process is
replaced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceSystemServiceParamGetInt answered 0 for the time zone (parameter 4)
and summer time (parameter 5), so the console looked set to UTC while
libSceRtc and libc convert local time with the host's zone. Titles add
the time zone in minutes and 60 more minutes when summer time is 1 to
UTC to get the local time (Apollo, GoldHEN's frame logger). Both now
follow the host's local time zone: summer time is whether it is in
effect, and the time zone is the current offset east of UTC less the
summer time shift while it is.
On Windows that shift is the C runtime's own summer time bias
(_get_dstbias), the one localtime_s applied, not a fixed 60 minutes.
The UCRT reads the system zone when libc.prx loads and keeps that
zone's bias after TZ is set later, so on a host whose system zone has
no summer time (the CI runner's UTC) a TZ of CET-1CEST shifted by 0 and
the time zone came out as 0. The cause and the change are screamm's,
from the review.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>