Replace the stub AvPlayer export set with a general-purpose player state
machine covering the full API surface: sceAvPlayerInit/InitEx/PostInit,
AddSource/AddSourceEx, Start/StartEx, Pause/Resume/Stop/Close, IsActive,
CurrentTime, JumpToTime, SetLooping, SetAvSyncMode, SetTrickSpeed,
SetAvailableBandwidth, StreamCount/EnableStream/DisableStream/ChangeStream/
GetStreamInfo(Ex), and GetVideoData(Ex)/GetAudioData.
No real decoder is wired up: the player tracks lifecycle and timing state
and serves a fixed-length blank clip on a wall-clock media clock, firing
the READY/PLAY/PAUSE/STOP event callbacks a title expects from a real
playback session. This is enough for titles that gate progression on
AvPlayer's polling/event surface rather than on decoded frame content.
The non-native libSceAvPlayer/Export.cpp now forwards to the native
implementation via #include rather than carrying its own duplicate stub
definitions, consistent with how other libSceX/libSceX.native pairs in
this tree share one implementation.
Replace the unimplemented stubs with a working NONE -> INITIALIZED ->
RUNNING -> FINISHED state machine for the message dialog PRX. Open()
best-effort parses the SceMsgDialogParam layout to pick a sensible
default button (auto-focus-no variants answer No, everything else
answers Yes/OK), then auto-finishes the dialog after a couple of status
polls so a title that waits on a dialog for user input never blocks
forever. Progress-bar mode is instead closed by the title itself via
sceMsgDialogClose, with a time cap as a safety net. GetResult now fills
in a real SceMsgDialogResult (mode/result/buttonId) instead of leaving
the caller's buffer untouched.
- Optimization/SrtWalker/SrtPlanBuilder.cpp: PlanBuilder::Collect now requires
RuntimeValidator(...).Run(inst) before folding an offset built from a Phi merging a
constant on one path with a per-invocation value on another. Confirmed upstream's
Collect is unchanged since the fork (still just offset->HasImmediate()), so a Phi
that reports HasImmediate() on its constant edge alone could still be folded into
the wrong, divergent SRT slot.
- RdnaDecoder + Translation: adds an IMAGE_BVH_INTERSECT_RAY (opcode 0xE6) decode path
and a TranslationContext::imageBvhIntersectRay stub that reports a clean hardware
miss (all result dwords 0xFFFFFFFF) instead of faulting on an undefined MIMG opcode.
No BVH/ray-tracing support exists upstream at all, so this is an honest "not
supported yet" stub, not a silent wrong answer.
- SpirvBackend/RectListShaders.cpp: raises the accepted spirvVersion ceiling to
0x10500 and truncates excess fragment interpolants to the tightest per-vertex
tessellation component limit instead of hard-refusing the whole rect-list draw.
A rect-list draw is a tile clear, so a pixel shader's result comes from its
constants and render target; truncated interpolants are simply left unwritten,
which upstream's own "missing" (unexported) parameter handling already tolerates.
Dropped after checking against current upstream (both would be redundant or
out of scope):
- ResourcePlanKnownToFail / SpirvWords (Recompiler.cpp/hpp): upstream already has an
equivalent mechanism for both. SourceEntry::planFailure (std::exception_ptr) already
memoizes and rethrows a failed IrResourcePlan build, and RecompileResult::spirv is
already the refcounted/hashed SharedSpirv class (see Recompiler.hpp), not a plain
vector. Porting either would have added a second, competing mechanism.
- ScalarInstructions.cpp SAVEEXEC changes: skipped. The audit could only confirm 3 of
6 64-bit SAVEEXEC cases were converted in the prior patch, which is a half-finished
edit rather than a complete correctness fix; not safe to port without re-deriving
sSaveexec()'s full semantics from scratch.
- ControlFlowInstructions.cpp vMovrelsB32/vMovreldB32 hardening (offset & 0xFF mask +
kMaxM0RelativeWindow cap): skipped as optional per review; upstream's core fix for
this file is otherwise already in place.
- All diagnostic-only stderr tracing (IrBuilderCore.cpp, ResourceTracker.cpp,
ShaderInfoCollector.cpp, SrtDescriptorEvaluation.cpp, SrtEvaluator.cpp,
SpirvMemoryInstructions.cpp) and the superseded Optimization/ResourceProgram.hpp
API (replaced upstream by CaptureResources/SourceHandle/ResourceCapture): not
ported, no functional change or already gone upstream.
Fills in guest-facing sceAgc* entry points across Acb/Cb/DcbDraw/DcbFlow/DcbState/Misc
that were still stubbed with NotImplemented_nid_no_patch on current upstream, one layer
below upstream's Recorder rearchitecture:
- Command/Control.{hpp,cpp} (new): WriteJump, WriteRewind, WritePredication,
WriteMemSemaphore helpers shared by the Acb/Dcb entry points below.
- Command/Memory.{hpp,cpp}: WriteCopyData, WriteAtomicMem helpers.
- Acb/Control.cpp: Jump/JumpGetSize, Rewind/RewindGetSize.
- Acb/Dispatch.cpp: DispatchIndirectGetSize.
- Acb/Memory.cpp: AcquireMemGetSize, CopyData(+Size), AtomicMem(+Size),
AtomicGdsGetSize, PrimeUtcl2(+Size).
- Acb/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize, EventWriteGetSize,
QueueEndOfShaderActionGetSize, MemSemaphore.
- Cb/Dispatch.cpp: DispatchGetSize only (sceAgcCbDispatch itself left untouched --
upstream's modifier mask 0xa038u|0x41u there is correct as-is).
- DcbDraw/DrawIndexed.cpp: DrawIndexMultiInstanced(+GetSize), still unimplemented
even after upstream's own indexed-draw work.
- DcbFlow/Control.cpp: Jump, Rewind(+Size), and a real WaitUntilSafeForRendering that
emits AgcDriver::RenderingWaitPacketHeader (recognized by the executor's fence wait
in Driver.cpp) instead of upstream's plain-NOP stub, which the executor does not
special-case.
- DcbFlow/Memory.cpp: AcquireMemGetSize, CopyData(+Size), DmaDataGetSize,
AtomicMem(+Size), AtomicGdsGetSize, WriteDataGetSize.
- DcbFlow/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize,
StallCommandBufferParserGetSize, MemSemaphore.
- DcbState/Predication.cpp: SetPredication only (the file's 3 GetSize functions are
left as upstream's diagnostic stubs, not real fixes).
- Misc/PacketInfo.cpp: sceAgcDcbGetSystemSoftwareVersion.
ABI correction: Command::WriteMemSemaphore takes the corrected 4-argument form
(address, waitForMailbox, signalType, operation). The Acb/DcbFlow sceAgc*MemSemaphore
entry points still expose the older (action, clientCode, address) guest signature;
their bodies now decode `action` into the signal/wait operation and the low two bits
of `clientCode` into signalType/waitForMailbox before calling the corrected helper.
Not ported (already superseded or out of scope per review): WriteMarker/WriteCustomNop/
WriteEventWrite/WriteCondExec/WriteDispatchIndirectAddress (duplicate upstream's
existing Marker/EventWrite/DispatchIndirect logic), Acb DmaData/DmaDataGetSize/
WriteData/EventWrite (already implemented upstream), DcbFlow EventWrite(+Size)
(upstream's version handles the 8-byte occlusion-address case more completely),
DcbDraw's other DrawIndex* entry points (already implemented upstream),
Misc/Trinity.cpp, Patch/WriteData.cpp, DcbState/Marker.cpp (all superseded by
upstream equivalents).
- DirectMemory: track each allocated block's type and extent in the
physical pool (DirectMemoryBlock), splitting the record on a partial
free, and expose DirectMemoryQueryBlock/DirectMemoryFreeRun. Wires
sceKernelDirectMemoryQuery to answer with the real allocated range
and type instead of a hardcoded one-page/type-3 guess, and
sceKernelAvailableDirectMemorySize to report the actual free run
instead of the whole remaining aperture. DirectMemory.cpp's mapping
path already tolerates MAP_FIXED overlap into a registered range and
already has honor-then-fallback address-hint handling and an
ignored-flags mask, so it is unchanged here.
- MemoryPoolExport: implement sceKernelMemoryPoolBatch/Commit/Decommit/
Expand/GetBlockStats/Reserve (previously all dead stubs) using the
existing DoMprotect/DirectMemoryAlloc/DoReserveVirtual primitives and
a small pool-state block counter.
- Module: wire sceKernelDlsym/sceKernelLoadStartModule/
sceKernelStopUnloadModule to the existing host-module loader
(dlopen_nid_postfix/dlsym_nid_postfix/dlclose_nid_postfix), replacing
dead stubs. sceKernelGetModuleInfoForUnwind/FromAddr are unrelated
and left as-is.
- Add FormattingWide.cpp implementing vswprintf_nid_postfix and
wprintf_nid_postfix, the only wide-char printf-family functions
upstream had left as unimplemented stubs (Formatting.cpp's checked
and unchecked narrow printf/scanf families are unaffected). Removes
the dead vswprintf_nid_postfix stub from Export.cpp.
- Add PreciseWait.hpp: std::condition_variable::wait_for cannot return
in under about one system tick on this MinGW toolchain regardless of
the requested budget, even with NtSetTimerResolution; PreciseSleepUs
uses a high-resolution waitable timer instead (~0.5ms vs ~15.6ms).
Header-only for now: its guest-side callers (Equeue/EventFlag/
Semaphore/AgcDriver wait loops) are out of scope for this change, so
it is not wired into them here.
Rework the local SaveData implementation into a general-purpose, title-agnostic
backend used by both the native library and the standard libSceSaveData path:
- Directory aliasing: long save directory names are hashed into short mount
point aliases (persisted to disk) so they fit the SDK's fixed-size mount
point buffer, with the aliases reversed on directory search.
- Wildcard directory-name search (%/_ patterns) with sorting and optional
reverse order, matching the DirNameSearch contract.
- Save-data "memory" slots: small per-user, per-slot blobs the title can
set up, read and write without mounting a directory, backed by files under
the save root with a companion parameter blob, size and range validation
on every access, and a dirty flag consulted on commit.
- Async-flavored operations (backup, commit, memory sync) that queue
SaveDataEvent records consumed through GetEventResult and can be bound to
kernel event flags, plus transaction-resource and cancel/abort bookkeeping.
- Atomic file writes (temp file + rename) so a mid-write crash never leaves a
torn save on disk, and corrected/duplicated SDK error code constants.
- Local storage app-status get/set/delete and transferring-mount support for
PS4-to-PS5 style save transfers.
The native library keeps its own lighter-weight mount/memory implementation
(short "/_sm/<slot>" mount point aliases via the path-alias table) while
gaining the same per-user memory-slot separation, atomic writes and bounds
checking; the two implementations were merged by hand where upstream had
independently touched the native Export.cpp in the same area (backup/event
queue, short mount points) to keep both sets of improvements.
None of this is game-specific: it is a general local save-data backend that
works for any title and tolerates any user id.
libSceNet: replace the always-fail stubs with a real offline network
stack. Sockets, epoll instances, memory pools and resolvers are tracked
in proper registries with create/destroy lifecycles; bind/listen/accept/
connect/send/recv/getsockopt/setsockopt/getsockname behave the way they
would on a console with no link up (bind and listen succeed locally,
connect/send fail with the errno a routeless host would give, blocking
calls such as accept/recv/epoll_wait return on close, abort or their
timeout). Infinite ("wait forever") timeouts are serviced in bounded
slices so a caller can never deadlock the process. Errno values match
the FreeBSD numbering the guest expects through sceNetErrnoLoc. Restored
sceNetGetsockopt and sceNetResolverStartAton (present upstream) using
the same registry-backed conventions as the rest of the rewrite.
libSceRudp: companion change giving the reliable-UDP library a genuine
context registry (init/create/bind/set-option/get-status) with
consistent error codes; connection attempts consistently fail since no
peer can ever be reached offline.
Forward relative motion, supported button transitions, and horizontal and vertical scrolling from the existing SDL event loop. Reset pressed buttons on focus loss without reporting a device disconnect, and track window close and refocus transitions.
Link libSceVideoOut to the mouse library using the existing Pad integration pattern. Add targeted coverage for API errors, event mapping, focus changes, history overflow, and reopening.
Co-authored-by: Copilot <[email protected]>
Keep the existing Export.cpp entry point and System V ABI while moving mouse state into the library implementation.`n`nTrack initialization, a single handle, button state, timestamps, and a bounded non-blocking event queue. Define and assert the guest MouseData layout and expose an input publisher for the host backend.
Co-authored-by: Copilot <[email protected]>
The Windows PE lazy-import GOT slot was written as a bare 4-byte RVA,
but the .reloc entries generated for the .gtls/data sections use
IMAGE_REL_BASED_DIR64, which only adds the load delta to whatever is
already stored at the slot. A bare RVA therefore resolved at runtime
to (loadBase - ImageBase + rva) instead of the intended stub address,
pointing into unmapped memory whenever the module was not loaded at
its preferred base.
Write the full 8-byte preferred-VA form (ImageBase + stubRva) instead,
matching DIR64 semantics, and generate a base relocation entry for
each lazy-stub GOT slot. The .reloc section is now built after the
lazy stubs are written into their target sections rather than before,
since it previously captured only the relocations known at that
point and missed the newly patched slots entirely.
fix(kernel,audioout,relinker): thread/mutex correctness fixes and --windows-gui
### libkernel (threads, mutexes, condition variables)
- **Deadlock in `scePthreadCondTimedwait` (normal/error-check mutexes):** `_owner` was not restored after the wait. If another thread locked and unlocked the mutex during the wait, the waiter woke up owning the mutex while `_owner` was empty. Its next `scePthreadMutexUnlock` returned `EPERM`, leaving the mutex locked forever (`lock → timedwait → unlock` pattern).
- **Wrong timeout code:** `SCE_KERNEL_ERROR_ETIMEDOUT` in `Cond.cpp` was `0x80020062`; it is `0x8002003C` (FreeBSD `ETIMEDOUT` = 60, matching `Semaphore.hpp`).
- **`scePthreadSelf()`** returned `nullptr` on Linux, and on both platforms for threads not created by `scePthreadCreate` (including the main thread). Such threads now get a lazily adopted, non-joinable handle (`scePthreadJoin`/`Detach` on it return `EINVAL`).
- **Linux `scePthreadExit`** skipped `FinishThread`, so `scePthreadJoin` got a garbage return value. Cleanup now runs from an RAII guard, so it survives glibc forced unwinding.
- **Linux detached threads** were never freed. They now use the same reference count as on Windows.
- **Recursive mutex unlock** by a non-owner, or with a zero count, was UB (`std::recursive_timed_mutex::unlock`). It now returns `SCE_KERNEL_ERROR_EPERM`, and `_owner`/`_count` are also saved and restored around a recursive cond wait.
- **`sceKernelLseek`** returned `int` instead of `off_t`; offsets above `INT_MAX` threw.
- **`sceKernelDeleteSema`** implemented: waiters are woken with `SCE_KERNEL_ERROR_EACCES` and the object is freed once they leave.
- `sceAudioOutOpen` accepted `freq == 0` / `len == 0`; the frequency was later used as a divisor. It now returns `SCE_AUDIO_OUT_ERROR_INVALID_SAMPLE_FREQ` / `INVALID_SIZE`.
On Linux scePthreadExit called pthread_exit, whose forced unwind runs
the personality routine of every guest frame. Those resolve to
libc.prx's __gxx_personality_v0, which cannot read libgcc's unwind
context and aborts, so guest_thread_self crashed on Linux.
Record a jump target in the thread start routine and longjmp back to it
from scePthreadExit instead. Like _endthreadex on Windows, this skips
the guest frames without unwinding them; the start routine still
releases the thread normally. Threads not created by scePthreadCreate
keep the pthread_exit fallback.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
Bring in the resolved#25 branch, which already carries upstream main
including boykopovar/AnyPS5#10, and re-apply the KernelErrors.hpp
refactor onto the rewritten files:
- Equeue: drop the local EQUEUE_ERROR_* constants and use the shared
SCE_KERNEL_ERROR_* names.
- Pthread Attr/Thread: drop local error constants and include
KernelErrors.hpp.
- Pthread Cond/Mutex: take upstream; they no longer define local
SCE_KERNEL_ERROR_* constants.
- Semaphore: drop KERNEL_SEMA_ERROR_* in favour of KernelErrors.hpp.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
Resolve conflicts with boykopovar/AnyPS5#10 (sce module loading) and
later upstream changes.
- Pthread Cond/Mutex: take upstream. It already releases mutex
ownership across condition waits, returns ETIMEDOUT 0x8002003C, and
rejects unlocks from non-owners for every mutex type.
- Pthread Thread: keep upstream's lifecycle, Windows adoption and job
affinity; re-apply the POSIX fixes on top: reference-counted
release on join/detach/exit, self-join rejection on both platforms,
and scePthreadSelf adoption for threads not created by
scePthreadCreate.
- Semaphore: keep upstream's TimedWait::Condition and wait tracing;
re-apply sceKernelDeleteSema waking waiters with EACCES.
- Relinker: keep --windows-gui alongside upstream's --skip-sce-module,
trampoline-aware Patch signature and new Python tests.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018emyZ4Rk8yoSJvxTFBe4DL
feat(fiber): implement fibers on linux
The state machine, the cross-thread resume handling and the entry trampoline are now shared between platforms. Only the context switch differs:
- `Aps5FiberSwitchStack` saves the SysV callee-saved set (`rbp rbx r12–r15`, MXCSR and the x87 control word) instead of the Win64 set.
- `Aps5FiberTrampoline` passes the fiber in `rdi`.
- There is no TIB to update, so `CurrentBounds`/`SetBounds` do nothing on Linux.
fix(agc): keep BGRA color targets resident between draws
BGRA color targets fail the exact guest-texture-format lookup and fall back to a synchronous framebuffer round-trip for every draw. This keeps them resident using compatible RGBA storage with the original BGRA attachment view. Presentation checks the actual display channel order, attachment views request only attachment usage, and host-write barriers include the host stage.
This follows the existing linked PRX/Vulkan path. It adds no interpreter, separate runtime process, or new shader compilation path.
feat(agc): ACB markers, index buffer unbinding and address in errors
- The DCB marker helpers move from an anonymous namespace in `DcbState/src/Marker.cpp` to `Agc::Marker::Push`/`Pop` (declared in `Marker.hpp`). The ACB entry points use the same helpers, so ACB and DCB markers produce the same custom NOP packets. `SetMarker` is a push followed by a pop, and returns the push packet, as on the DCB. The color is ignored on both, as before.
- `sceAgcDcbSetIndexBuffer` emits the packet with address 0 instead of rejecting it. A non-null address still has to be 2-byte aligned.
- `Agc::Command::CheckAddress` includes the rejected address in its message.
feat(agc): DMA_DATA cache policy hints and GDS source/destination
- **Cache policy:** the source (bits 13–14) and destination (bits 25–26) cache-policy fields of `DMA_DATA` dword 1 are accepted. They're cache hints with no effect on the copied data. The remaining reserved bits are still rejected.
- **GDS storage:** GDS is modelled as one 64 KiB, zero-initialised store shared by the whole device, behind a mutex.
- **GDS source/destination:** select `1` reads from or writes to that store:
- the validator requires the high address dword to be 0 and the range to fit inside the 64 KiB;
- `Execute` copies between memory, immediate data and GDS in any combination;
- `ResolveStore` returns nothing for a GDS destination, since there's no guest memory to write, and for a GDS source it resolves the bytes from the store.
- Register and prefetch destinations are still rejected.
- Nothing is faked for shaders: a shader that uses GDS still fails validation (unsupported descriptor role).
fix(agc): reject primitive restart only for indexed draws
- `DecodeState` still reads `0x24b` (so it stays in the recorded draw-key registers) but no longer rejects on it.
- `DrawRejection` takes an `indexed` flag, and reports restart only for indexed draws.
- The driver's draw path rejects an indexed draw with restart enabled before the precheck, so indexed draws with restart are still refused when the precheck is off. Restart itself is still not implemented.
fix(agc): keep a replaced Vulkan device alive
In the presenter path, after `PrepareForReplacement()` (which flushes cached textures, publishes shadows and waits for idle), the old device is kept in a function-local static list instead of being released. Its child objects stay valid for as long as anything still refers to them. The cost is one idle device for the life of the process; the replacement happens once, at the first flip.
feat(json2): implement sce::Json values, strings, arrays, objects, parser and null-access callback
- **Layouts:** `String`, `Array`, `Object` and `Value` are pointer-sized handles to host-side storage. The title stores `String`/`Array`/`Object` at an 8-byte stride and `Value` in 0x20-byte slots, so none of them can be bigger. The pair an `Object::iterator` dereferences to has its key at +0x00 and its `Value` at +0x10, which the title reads directly. Array and object iterators are 8 bytes.
- **Parser:** a strict RFC 8259 parser.
- Numbers: integers that fit `int64` become `Integer`, larger non-negative ones `UInteger`, and everything else `Real`.
- Strings: `\u` escapes, including surrogate pairs, are decoded to UTF-8.
- Errors: on any error `parse` returns a negative code (`0x80920101`) and leaves the target value untouched.
- **Serialisation:** compact output. Strings are escaped; reals use `%.17g`, and a non-finite real throws.
- **Null access:** a typed getter on a value of another type, a missing key or an out-of-range index goes through the null-access callback. The callback's result is used when its type matches (any type for `operator[]`). Otherwise a static default value of the requested type is returned. `terminate` clears the callback.
- **Integer getters:** `getInteger`/`getUInteger`/`getReal` convert between the integer kinds and to real where the value fits.
- `setGlobalNullAccessCallBack` (NID `00oCq0RwSAY`) was identified by hashing its mangled name.
- `MemAllocator`'s base constructor and destructor install the abstract class's vtable. A derived allocator replaces it with its own, so its entries (which throw, like a pure virtual call) run only if a pure virtual is called. `Initializer::initialize` throws on a null parameter instead of silently accepting it.
- Mutating a value that isn't the expected type (`referArray` on a string, etc.) throws.
feat(libkernel): pread, pwrite, getdents and getdirentries on linux
- **pread/pwrite:** use the existing `NativePread`/`NativePwrite` and don't move the file offset. A null buffer with a non-zero size returns `EFAULT`, a negative offset `EINVAL`, and host failures go through `SceErrorFromErrno`.
- **getdirentries:**
- reads host `getdents64` records and converts them to the FreeBSD `struct dirent` layout the guest expects (`d_fileno` u32, `d_reclen` u16, `d_type` u8, `d_namlen` u8, NUL-terminated name, record padded to 4 bytes);
- `*basep` gets the directory position from before the read;
- when a record doesn't fit in the guest buffer, the descriptor is moved with `lseek` back to that entry's cookie, so the next call resumes there;
- if not even the first record fits, the call returns `EINVAL` without consuming anything, and a name longer than 255 bytes returns `ENAMETOOLONG`.
- **getdents** is `getdirentries` without `basep`.
- Adds the guest `EFAULT`, `EINVAL` and `ENAMETOOLONG` constants.
feat(relinker): lower register-form EXTRQ and relocate following instructions for short sites
- **Lowering:** register-form EXTRQ is emitted out of line with SSE2 only. Two scratch XMM registers (distinct from both operands) are spilled; one gets the index (`src >> 8 & 63`), the other `(64 - length) & 63` (`length` masked to 6 bits, so 0 means 64). The destination is shifted right by the index, then left and right by the complement, which keeps the low `length` bits. INSERTQ register form is still reported as unsupported.
- **Short sites:** when a site is shorter than a `jmp rel32`, the converter extends it over the instructions that follow it until it's 5 bytes long:
- following EXTRQ/INSERTQ instructions (before any other instruction) are lowered into the same stub, via a new `MatchSequence`;
- other instructions are copied after the lowered body (`LowerOutOfLine`'s new `trailing` bytes), but only if they're sequential, have no RIP-relative operand and no branch target;
- anything else (a return, a branch, RIP-relative code, the segment ending) still fails the relink, as does a branch target inside the extended site.
- `docs/TechnicalDebt.md` now lists only the INSERTQ register form, MONITORX/MWAITX/CLZERO/RDPRU/MCOMMIT and SHA-NI.
feat(userservice): user name, user number and accessibility settings of the initial user
They report the initial user, following `sceUserServiceGetGamePresets`:
- **Name:** `Player`. A buffer shorter than 17 bytes returns `SCE_USER_SERVICE_ERROR_BUFFER_TOO_SHORT` (`0x8096000A`).
- **User number:** 1.
- **Accessibility settings:** 0, the setting-off value on a fresh console.
fix(libc): don't walk guest frame pointers when reporting an unhandled exception
Only log __builtin_return_address(0), which doesn't depend on the guest's frames. After the fix, the log prints the exception type and the terminate handler prints what().