Files
AnyPS5/docs/dev/debt/libSceLibcInternal.md
T
David 1d67426ede feat(libSceLibcInternal): implement getopt and getopt_long
Export getopt (VUtibKJCt1o) and getopt_long (8VVXJxB5nlk) from
libSceLibcInternal together with the guest variables optind
(zCnSJWp-Qj8), optarg (zG0BNJOZdm4), opterr (yaFXXViLWPw), optopt
(FwzVaZ8Vnus) and optreset (CZNm+oNmB-I). The NIDs were computed with
tools/nid_names.py and all seven are in aerolib; the PS5 payload SDK
f5d40f02 lists the functions and the five objects in
sce_stubs/libSceLibcInternal.c.

Titles (predicted stops from registry order, not observed runs):
- XPSemu PPSA97358, after execv/execve, the signal waits, the
  credential setters, mlockall and tcsendbreak:
  "FAIL: unresolved ELF import VUtibKJCt1o from libSceLibcInternal.prx"
  (getopt idx 204, 10 call sites from 0xF6C23D), then optind (207),
  optreset (208), optarg (209).
- RetroArch PPSA99169: getopt_long (idx 554, call sites 0xD2FC0C,
  0xD3002A), optind (553), optarg (555).

Behaviour follows FreeBSD release/11.4.0 8c639945: getopt is
lib/libc/stdlib/getopt.c (no permutation, GNU "::" optional argument,
lone "-" as an option when listed), getopt_long is getopt_internal
from lib/libc/stdlib/getopt_long.c with GNU_COMPATIBLE (permutation,
POSIXLY_CORRECT read through the guest getenv on the first call and on
optreset, "+" and "-" prefixes, "W;", optind 0 as a reset, abbreviation
and ambiguity rules and the GNU warning texts). Warnings are written to
the guest stderr stream as "<__progname>: <message>", as warnx does.
The struct option layout and argument kinds are include/getopt.h.
The code lives in libSceLibcInternal because __progname is a libkernel
export that libc cannot link.

A null getopt option string, a null argument vector or argument, a
negative optind and an optind moved inside a pending permutation throw
where FreeBSD faults. getopt_long_only is not exported.

guest_getopt runs the FreeBSD getopt_test cases (contrib/netbsd-tests
t_getopt.sh with the h_getopt and h_getopt_long result format) plus
grouped and optional arguments, "--", permutation order, "+" and "-"
prefixes, optreset and optind 0 restarts, POSIXLY_CORRECT, all three
long argument kinds, abbreviations, ambiguity, flag pointers, "W;",
optopt with opterr 0 and the exact stderr text.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit a2740166d93920c301e1add23ceea762b4acad27)
2026-10-12 18:46:43 +00:00

3.5 KiB

libSceLibcInternal technical debt

Unknown function info

  • _sceLibcInternalThreadAtexit, _sceLibcInternalThreadDtors (libSceLibcInternal) - FreeBSD __cxa_thread_atexit semantics assumed; a null or non-image destructor and an allocation failure throw
  • _sceLibcInternalForceTlsDestructor (libSceLibcInternal) - behaviour follows sceLibcForceTlsDestructor(int) in a title's libc.prx (disassembly): the calling thread's destructors whose dso belongs to the module run newest first, only if the dso's module is loaded and the dso points to itself, in up to 4 passes. The return type is unknown (that function returns nothing), 0 is returned. The module of each dso is looked up when the destructors are forced, not when they are registered as libc.prx does

Functional

  • makecontext (libSceLibcInternal) follows FreeBSD 11's lib/libc/amd64/gen/makecontext.c: at most six arguments, a stack of at least MINSIGSTKSZ (2048) bytes, and exit(0) when the function returns with no uc_link. The console's version is not verified
  • makecontext (libSceLibcInternal) on Windows pins its stack writable until a later makecontext stack overlaps it, since nothing tells the library when the guest frees the stack
  • Thread exit destructors (libSceLibcInternal) run when a libkernel thread finishes; on the main or a host thread only _sceLibcInternalThreadDtors runs them, as exit does, else they are dropped
  • fstatvfs (libSceLibcInternal) converts _fstatfs to the 88-byte struct statvfs as FreeBSD 9.2's sfs2svfs does (f_bsize from the transfer size, f_frsize from the block size, f_favail equal to f_ffree, f_fsid 0, ST_RDONLY and ST_NOSUID only). Differences: f_namemax is the statfs value, not fpathconf(_PC_NAME_MAX); negative f_bavail and f_ffree wrap to unsigned without EOVERFLOW, as the same-width copy in FreeBSD does; inode counts are 0 on Windows, inherited from _fstatfs; a null output returns EFAULT after the descriptor is validated, where FreeBSD would fault. Layout and conversion are unverified against the PS5 library (PS5MC imports fstatvfs but was not run)
  • getopt, getopt_long (libSceLibcInternal) follow FreeBSD 11 getopt.c and getopt_long.c with GNU_COMPATIBLE: getopt does not permute, getopt_long permutes unless POSIXLY_CORRECT is set in the guest environment or the option string starts with +, and the exported opterr, optind, optopt, optreset and optarg start at 1, 1, 0, 0 and null. Warnings go to the guest's current stderr prefixed with __progname, where FreeBSD's warnx keeps the stderr of its first call. A null getopt option string, a null argument vector or argument, a negative optind and an optind moved inside a pending permutation throw where FreeBSD faults. getopt_long_only is not exported. That the console's libSceLibcInternal uses this FreeBSD code is unverified