AnyPS5/docs/dev/debt/libc.md

39 KiB

libc technical debt

Unknown function info

  • _Mtx_trylock (libc, NID k6pGNMwJB08) - returns busy for a non-recursive mutex already owned by the caller, assumed to match _Mtx_lock's ownership handling; exact console behavior is unverified.
  • nearbyintf (libc, NID c+4r-T-tEIc) uses the host rounding mode, not the console's; console rounding mode state remains unverified.
  • _Thrd_sleep (libc, NID jfRI3snge3o) follows the Dinkumware threads library shipped with Visual C++ 2013 (xtime.c) and C11 Annex K, without console verification. It reads a 16-byte xtime (64-bit seconds and nanoseconds) on the guest CLOCK_REALTIME, normalizes the nanoseconds and sleeps through nanosleep, retrying on EINTR, so it is a cancellation point; a null xtime or one whose normalization overflows throws. The console's _Thrd_sleep (disassembled from a title's libc.prx) also takes an optional xtime* of remaining time and returns int; here the sleep is never cut short, so it returns 0 and leaves the remaining time untouched.
  • _Mtx_init_with_name (libc, NID tgioGpKtmbE) forwards to _Mtx_init and ignores the mutex name parameter.
  • _Cnd_timedwait (libc, NID McaImWKXong) follows the console's _Cnd_timedwait (disassembled from a title's libc.prx), where xtime is an absolute deadline converted against the current time: it returns _Thrd_timedout (2) on expiration and _Thrd_success (0) on notification. The console returns 4 for other internal pthread errors while this implementation throws.
  • Guest arena (libc) - the application map area is assumed to end at 0xFC_0000_0000, as SCE_KERNEL_APP_MAP_AREA_END_ADDR does on the PS4. On Windows, host allocations made in the arena before libc loads stay, and a fixed guest mapping over one throws
  • sceLibcInternalBacktraceForGame (libSceLibcInternal, implemented in libc) - (const char* heapName) and its return follow the libc.prx ASTRO BOT (PPSA21564 01.007.000) bundles: its four calls (0x6801, 0x7F46, 0xE75E, 0xEE02) are in the malloc_stats and sceLibcMspaceMallocStats paths, each after a [%s] ... line printed with the same heap name buffer, and the caller ignores the result and continues. The console's backtrace output is not reproduced: the heap name and the guest return address are written to the host standard error
  • sceLibcInternalHeapErrorReportForGame (libSceLibcInternal, implemented in libc) - (void* heap, void* block, uint32 error) follows the same libc.prx (call at 0xF634): it passes the heap, the block and the nonzero result of its block check, and then calls a function that never returns, so the report only has to return. The meaning of the error values is unknown; the three values and the guest return address are written to the host standard error
  • malloc_usable_size (libc) - with the default allocator it returns the size the block was requested with (the range registered for it), not the rounded-up chunk size Sony's allocator reports; both satisfy "at least the requested size", and bytes past the request would not be write-watched. With an application allocator it calls entry 9 of the replacement table (malloc_usable_size in KytyPS5's MallocReplace order) and throws when the table leaves it null, like malloc_stats_fast
  • reallocf (libSceLibcInternal, implemented in libc) - follows FreeBSD 11 lib/libc/stdlib/reallocf.c on top of this libc's realloc, not measured on the console: size 0 frees the block and returns null as realloc does here, so the block is not freed twice; when realloc fails because the application allocator returns null or the default heap rejects the size, the block is freed through the same allocator, errno is ENOMEM and null is returned. Other failures (an exhausted guest arena, an unknown pointer) throw, as they do for realloc
  • acosl (libc) - computed by the host's math library, like the other libc math functions here, not by the console's (FreeBSD msun ld80 code in Sony's libc.prx): results can differ from the console's in the last bit, and on Linux glibc sets errno to EDOM for acosl outside [-1, 1] where msun only raises the floating-point exception. long double is the x87 80-bit format, as Sony's frexpl uses it (fldt 0x8(%rsp), result in st(0))
  • atanl, sinl, cosl, tanl, sinhl, coshl, tanhl, expl, exp2l, logl, log10l and powl (libc) - computed by the host's math library, as acosl is, not by the console's FreeBSD msun ld80 code: results can differ from the console's in the last bit (glibc's log10l(1000) is not exactly 3), and on Linux glibc sets errno to EDOM or ERANGE where msun only raises the floating-point exception. ldexpl and truncl are exact operations and give the console's result; logb and remainder give the console's value too, but on Linux glibc sets errno (ERANGE for logb(0), EDOM for remainder by zero or of an infinity) where msun only raises the floating-point exception
  • std_execute_once (libc) - assumed to be the plain-named twin of std::_Execute_once (_ZSt13_Execute_onceRSt9once_flagPFiPvS1_PS1_ES1_, the callee of Dinkumware call_once): it delegates there and gets the [thread.once.callonce] semantics already verified for that symbol (one invocation per flag, concurrent callers block until it completes, and a failing or throwing invocation leaves the flag unready so the next caller runs it). The name equivalence is not confirmed on a title, and the callback convention (called with (null, arg, null), non-zero return meaning success) is the twin's, unverified for this symbol
  • Dinkumware mutexes and conditions (libc) use pointer-to-handle arguments, matching the console aerolib signatures reported in #3079. The title's _Mtx_lock maps 0 to _Thrd_success (0), 0x8002000b to _Thrd_busy (3), and other failures to _Thrd_error (4); its internal mutex init recognizes recursive flag 0x100, while every other type uses default attributes. The observed relock failure for a plain mutex suggests those defaults are error-checking, but that has not been confirmed on hardware. The title's _Mtx_unlock and _Cnd_wait return success regardless of their internal result. The host implementation treats invalid ownership preconditions as no-ops, and throws for invalid handles, host wait errors and destroying a locked mutex as debug guards; those cases are not confirmed against the console.
  • random, srandom, initstate, setstate (libc) follow FreeBSD 11 random.c: the additive feedback generator on a default 128-byte TYPE_3 table, good_rand seeding, state sizes rounded down to 8, 32, 64, 128 or 256 bytes, and setstate returning the previous state or null for a rear position past the degree. initstate below 8 bytes returns null without setting errno, as that file and its manual do (glibc sets EINVAL). FreeBSD does not lock the generator; here every call is serialised by one lock, so concurrent callers draw the serial sequence between them. A null state throws, where FreeBSD faults. That the console's libSceLibcInternal uses this FreeBSD code and not another generator is unverified
  • qsort (libc) follows FreeBSD 11 qsort.c: Bentley and McIlroy's quicksort, with insertion sort below 7 elements and after a partition pass that swaps nothing, so elements that compare equal end in FreeBSD's order and the comparator is called in the same sequence. That the console's libc uses this FreeBSD code is unverified
  • memcpy_s and memmove_s (libc) use the C11 K.3.7.1.1 and K.3.7.1.2 size constraints, with RSIZE_MAX taken as SIZE_MAX >> 1 as in memset_s. An oversized destination size returns ERANGE (34) without touching the destination; the console's RSIZE_MAX and exact error value are unverified. Constraint violations return an error without invoking the registered constraint handler, as before.
  • snwprintf_s (libc) - follows C11 K.3.9.1.3 with RSIZE_MAX assumed to be SIZE_MAX >> 1. A runtime-constraint violation only returns a negative value: set_constraint_handler_s is not exported and the console's default handler is unknown. An invalid multibyte %s argument is copied byte by byte instead of being reported as an encoding error, as in vswprintf
  • vsnprintf_s and vsscanf_s (libc) - vsnprintf_s forwards to vsnprintf semantics: the C11 K.3.7.1.5 runtime constraints (null buffer, size == 0, %n, null %s) are not checked, so size == 0 returns the would-be length instead of a negative value, and no constraint handler is invoked. vsscanf_s returns the count of items converted before an undersized %s/%c/%[ destination (0 when it is the first), not EOF. Neither is confirmed on a PS5 title
  • localeconv (libc, re-exported by libSceAmpr) - the 0x90-byte Dinkumware struct (empty monetary strings, CHAR_MAX for the 14 char fields, decimal_point ".", _False/_True "false"/"true") is read from the libc.prx that Astro's Playroom ships. It is a fixed C-locale table: whether the console changes it with setlocale is not known, and _Frac_grouping, _Frac_sep, _No, _Yes are empty strings as in that dump
  • set_constraint_handler_s (libc, re-exported by libSceAmpr) - the default handler is assumed to abort; each module keeps its own handler state, so a handler set through one library is not seen by the other. ctime_s and asctime_s follow the Dinkumware 26-byte format with EINVAL for a buffer under 26 bytes, a null pointer or an out-of-range weekday/month; ctime_s uses the guest time zone of localtime_s, and the console's exact checks are not verified
  • __udivti3 (libc, re-exported by libSceAmpr) - the hardware traps on a zero divisor; this throws instead
  • __umodti3 (libc) - the hardware traps on a zero divisor; this throws instead

Functional

  • Windows direct-memory backing reserves a paging-file section. A direct memory page mapped at one guest address is private write-watched memory at that address and is not committed in the section; a page mapped at a second address moves its whole resident run into the section (committed there) and every address becomes a view of it, tracked by write protection. An unmapped resident page that is not all zeros is kept in a private reservation until it is mapped again. Committed section contents remain across unmap/remap and are released when the backing and its remaining views are destroyed. A host import alias over part of a resident run is refused. Linux retains its existing backing. Peak gameplay memory and Windows versions other than the tested host remain unverified.
  • getc_unlocked, putc_unlocked (libc) - byte I/O uses the host unlocked operations; guest EOF/error flags and macro counters follow FileStream. Linux status queries use feof_unlocked/ferror_unlocked because glibc feof and ferror can acquire the stream lock. Windows uses the CRT no-lock byte operations and feof/ferror, verified under a held stream lock on UCRT. Console behavior and other host CRTs remain unverified.
  • ftrylockfile (libc) - tries the host CRT stream lock that flockfile, funlockfile and each locking host stdio call on the stream take, so it returns -1 while another thread holds the stream through flockfile or is inside such a call, and 0 when it acquires the lock or already owns it (recursively, released by as many funlockfile calls), as FreeBSD 11 _ftrylockfile does. A libc export holds the lock only for each host call it makes, not across several host calls or while it updates the guest FILE prefix. Linux uses glibc ftrylockfile. UCRT has no try variant of _lock_file, so Windows calls TryEnterCriticalSection on the CRITICAL_SECTION that _lock_file enters, found through the private UCRT stream layout (__crt_stdio_stream_data in ucrt/inc/corecrt_internal_stdio.h, unchanged from Windows SDK 10.0.19041 to 10.0.26100); another CRT or a change of that layout breaks it. A null or closed stream throws where FreeBSD dereferences it
  • Wide-character conversions (libc) - The wide wcsto* functions parse the ASCII prefix of the guest string, as the C locale accepts only ASCII white space and digits. wcsrtombs uses the guest's single-byte C locale through wcrtomb; other encodings and shift states are not supported
  • realpath (libc) follows FreeBSD 11's realpath.c except for symlinks. The console's guest filesystem has none, so a host symlink under the guest root is followed for existence and type but not expanded, and .. drops the previous component lexically, as Resolve does for every guest path. Through a host link linkdir -> sub/deep, linkdir/../x gives x beside the link, not beside its target.
  • strtod, strtof, strtold (libc) - NAN(n-char-sequence) converts to the quiet NaN that nan and nanf return, negated after a minus sign, and ignores the sequence as they ignore their tag. This is inferred from C17 7.12.11.2p2, which makes nan("n") equivalent to strtod("NAN(n)", NULL), and not observed on the console. No console nanl was observed, so strtold returns the x87 default quiet NaN (exponent 0x7fff, significand 0xc000000000000000)
  • nan and nanf (libc) return fixed quiet NaN values (0x7fc00000 and 0x7ff8000000000000), ignoring the tag argument as observed in the console's libc.prx (both exports load a global constant via mov rax,[rip+..]; vmovsd xmm0,[rax]; ret); VLC (PPSA85300) stops on nanf at start-up after strsep.
  • lgamma (libc) returns the host's lgamma but does not store the sign of Γ(x) in the guest's signgam, as FreeBSD 11's e_lgamma.c does through __ieee754_lgamma_r, because no guest signgam is exported. PPSA99004 imports it. Console behaviour is unverified
  • sinhf (libc) follows the sinhf of the libc.prx bundled with PPSA28319 (disassembly): FreeBSD msun's e_sinhf.c from before __ldexp_expf, which squares expf(|x| / 2) between logf(FLT_MAX) and the overflow threshold, calling msun's expm1f and expf, whose paths for the arguments it passes are inlined here. Past the threshold Sony's error helper sets errno to ERANGE before returning x * 1e37; msun itself sets no errno. That code, run on a Windows host, gives the same bits as this implementation for every finite argument up to the threshold, of both signs; it was not run on Linux. That the system libSceLibcInternal, which Ruffle (PPSA68091) and RetroArch (PPSA99169) import while bundling a zero-return libc.prx, has the same code is assumed
  • asinl (libc) follows the asinl of the libc.prx bundled with PPSA28319 (disassembly), FreeBSD msun's e_asinl.c with the ld80 invtrig.c coefficients, which the binary holds as the same 80-bit constants. For |x| > 1, the infinities and NaN, Sony's error helper raises FE_INVALID and sets errno to EDOM before returning (x - x) / (x - x), so a NaN argument also sets EDOM; msun itself sets no errno. 20 million random arguments in (-1, 1) give the same bits as that code run on a Windows host. The result needs the x87 precision control at 64 bits, as FreeBSD amd64 starts threads (control word 0x37f), but guest threads do not set it: on Windows a thread started by _beginthreadex runs at 53 bits (0x27f), where asinl(0.75) returns mantissa 0xd91a98ae3406e000 instead of 0xd91a98ae3406e041. The system libSceLibcInternal that RetroArch (PPSA99169) imports is assumed to have the same code
  • atanhf (libc) follows the atanhf of the libc.prx bundled with PPSA28319 (disassembly): FreeBSD msun's e_atanhf.c calling msun's log1pf, whose paths for the positive arguments it passes are inlined here; the exported log1pf is still the host's. For |x| > 1, the infinities and NaN, Sony's error helper raises FE_INVALID and sets errno to EDOM before returning (x - x) / (x - x), and for |x| = 1 it raises FE_DIVBYZERO and sets errno to ERANGE before returning x / 0; msun itself sets no errno. That code, run on a Windows host, gives the same bits, errno and floating-point exceptions as this implementation for all 2^32 arguments; it was not run on Linux. That the system libSceLibcInternal, which Dusklight (PPSA99305) imports while bundling a zero-return libc.prx, has the same code is assumed
  • On macOS the write watch write-protects watched pages and records the first write to each from a SIGBUS/SIGSEGV handler, because macOS has no counterpart to userfaultfd write-protect or MEM_WRITE_WATCH. The protection is real, so:
    • a system call that writes into a protected page fails with EFAULT instead of faulting. GuestArena::HostWrite lifts the protection for the calls it brackets (file reads and socket receives); a host call that writes guest memory without it (clock_gettime and the like into a watched page) fails;
    • code that changes the protection of watched pages, or maps over them, has to call GuestWriteWatchProtectionChanged, and code that asks the kernel for a page's protection has to ask GuestWriteWatchProtection first, since a watched page is read-only between a collection and the next write. Nothing calls either yet: the macOS memory paths are not in the tree;
    • the handler is installed when libc loads and passes other faults to the handler installed before it. A handler installed later has to do the same.
  • sceKernelSync (libkernel) flushes only the host files and directories recorded through RecordWrittenPath_nid_no_patch (the libc, libkernel, save data and app content file functions) and their changed parent directories. A host write in a library that does not record its path is not flushed by sceKernelSync
  • sceKernelSync (libkernel) on Windows skips a recorded file it cannot open for writing (read-only, or held open by a handle that denies write sharing), since FlushFileBuffers needs a writable handle. On Linux, it skips a recorded file it cannot open for reading. Such a file's data may not reach the disk before a host crash; the guest reads the same data either way
  • fopen streams (libc) on Windows share delete access, like the descriptors sceKernelOpen opens, so a file the guest holds open can be removed or renamed. A stream reopened with freopen still goes through _wfreopen, which does not share delete access. On Windows, opening a directory in a read mode fails with EACCES, where FreeBSD opens it; directory streams are not emulated
  • The _Unwind_Context that _Unwind_Backtrace passes to its callback starts with a table laid out like LLVM libunwind's AbstractUnwindCursor virtual table, because homebrew built with the ps5-payload-dev SDK links libunwind statically and reads the frames with its own _Unwind_GetIP (__unw_get_reg), which calls through that table. Only register reads and writes (validReg, getReg, setReg, with UNW_REG_IP and UNW_REG_SP), validFloatReg (always false) and isSignalFrame are answered; the other slots throw. The layout follows libunwind's UnwindCursor.hpp, not the console's own libSceLibcInternal, which is not checked
  • The Windows libc exception unwinder steps through frames of modules without the project's .ehmeta and .ehfram tables (system DLLs, and WinLibs GCC 15.2's libstdc++-6.dll and libwinpthread-1.dll, whose .eh_frame sections are empty) with their PE unwind data through RtlVirtualUnwind, but does not run Windows exception or termination handlers: it stops at a frame whose unwind data has one, such as a C++ cleanup through __gxx_personality_seh0 in libstdc++-6.dll or a system DLL function like qsort in ucrtbase.dll (Windows 10 22H2), and the exception is then reported as unhandled
  • The libc SSE4a trap emulation on Windows is superseded by --to-intel and remains only until the relinked title has been verified without it.
  • getifaddrs (libc) lists the host's IPv4 and IPv6 addresses in FreeBSD's ifaddrs and sockaddr layouts. FreeBSD's per-interface AF_LINK entries (MAC, index, MTU) and their if_data are not produced, so interfaces without an address are omitted. Names are the host's (Linux lo, eth0; Windows NDIS names such as ethernet_32769, or if<index> when one does not fit 15 bytes), not the console's. A Linux point-to-point address without a peer loses IFF_POINTOPOINT, and an IPv4 broadcast address the host omits is computed from the netmask. On Windows the flags are only IFF_UP, IFF_RUNNING, IFF_LOOPBACK, IFF_BROADCAST and IFF_MULTICAST, derived from the adapter: PPP and tunnel adapters get neither IFF_BROADCAST nor IFF_POINTOPOINT because their peer address is not reported, and an address whose prefix length the host reports as unspecified gets a host mask.
  • gethostname (libc) reports the fixed guest name AnyPS5 without querying the host machine name. Buffer copying, null queries and ENAMETOOLONG follow FreeBSD gethostname; the console's configurable hostname and its integration with sysctl and name resolution are unverified and not implemented.
  • wcsrtombs_s (libc) follows the console's libc.prx, but a runtime-constraint violation only returns its error: the default handler there writes the message and a newline to stderr before returning, which is not done here. Conversion uses the C locale of wcrtomb (MB_CUR_MAX 1), so the path where a multibyte character does not fit the remaining space is not reached
  • The narrow printf family (libc) converts 16-bit guest wide arguments to UTF-8 on both platforms, independently of the host locale. It does not use the guest's single-byte wcrtomb; the console's treatment of invalid UTF-16 and locale-specific encoding remains unverified. Linux retains host formatting for formats without wide arguments or %m, so a narrow %p and a NaN there still follow the host (glibc prints a null pointer as (nil), where FreeBSD prints 0x0, and a NaN with its sign, -nan, and with the + and space flags, where FreeBSD prints nan); argument positions above 99 (FreeBSD's NL_ARGMAX) throw when a format requires the guest formatter
  • collate::_Getcat (libc) builds the facet for the C locale only and throws for any other locale name. The console's libc.prx stores pointers to its collation state tables at offsets 0x10 and 0x18 of the facet; ours leaves them null, as only the facet's own functions read them. do_transform throws for input with embedded null characters, which the console drops depending on the output buffer size. Its result capacity (length | 15) and the over-aligned storage of results of 4080 characters or more follow the console's libc.prx code and are not checked on hardware.
  • The scanf family (libc), the _s forms included, on Linux throws for the 16-bit wide conversions (%ls, %lc, %l[, %S, %C): glibc would store a 32-bit wchar_t per character into the guest's 16-bit buffer. Windows hands %ls, %lc and %l[ to the host, whose wchar_t is 16 bits
  • The scanf family (libc) on Windows returns 0, as C17 and FreeBSD do, when input fails after only suppressed conversions have completed (sscanf("12", "%*d%d", &value)). Linux hands the format to glibc, which returns EOF there. On Windows the host stops a %x, %X, %i or %p after the x of a 0x that no hex digit follows (or that the width cuts off), and a float conversion (%e, %f, %g, %a) after the e of an exponent with no digits (1e), where C17 and FreeBSD stop before the x or the e
  • Guest path resolution falls back to ASCII case-insensitive component lookup, following shadPS4's host filesystem. PPSA03747 requests Skyrim.INI, Data/Video and lowercase archive/plugin names that differ from the dump's filenames. Exact host names take precedence; multiple fallback matches throw instead of selecting an arbitrary file. Existing parent names are resolved when creating a new file, and guest mount aliases use the same ASCII comparison. Results are not cached, so renames and newly created files remain visible. Unicode case folding and PS5 behaviour for case-colliding host entries are unverified; host roots are used as supplied. Explicit native Windows drive and UNC paths bypass guest parent-component validation.
  • tzname (libc) points at the host's zone names, read at load and again by tzset: the abbreviations a TZ string gives (EST5EDT is EST and EDT on both hosts), but on Windows without TZ the CRT's full names such as GMT Standard Time, which ICU's uprv_tzname (ES-DE in PPSA99169) cannot map to a zone ID. A zone with no daylight-saving time has tzname[1] empty on Windows and equal to tzname[0] on Linux, where FreeBSD leaves three spaces. The console's names are not known
  • localtime, mktime (libc) on Windows convert through the CRT's localtime_s and mktime, which accept about 1970 to January 3001 UTC and apply the CRT's daylight-saving rule. A time outside that range is converted a whole number of 400-year Gregorian cycles away, where the calendar repeats, so it gets the rule the CRT applies to that year and not the zone's historical one. gmtime converts every time whose year fits an int on both hosts.
  • strftime and asctime (libc) follow FreeBSD 11 strftime.c and asctime.c with the C locale on every host, not measured on the console; other locales are not implemented. %s follows FreeBSD 9 and 11 and is the local-time mktime of the broken-down time (current FreeBSD uses tm_gmtoff), which is -1 on Windows outside the range above. %Z is tm_zone, or tzname[tm_isdst != 0] when it is null and tm_isdst is not negative. The two-digit year warning FreeBSD writes to stderr when CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS is set is not written
  • wcsftime (libc) follows FreeBSD 11.4's wcsftime.c over this library's wcsrtombs, strftime and mbsrtowcs in the single-byte C locale of none.c, with the guest's 16-bit wchar_t, without console verification. It has the strftime gaps above. A format unit above 255 returns 0 with EILSEQ; an empty result, a result that does not fit and a null buffer return 0 with errno unchanged, discarding the ERANGE or EINVAL that the Windows CRT's strftime sets. A null format or tm throws, where FreeBSD dereferences it (a null tm is read there only when the format has a conversion that needs it)
  • syslog (libc) writes each message to stderr as [syslog:<priority>] <message>, with a newline added when missing, instead of sending it to the console's system log. Priority and facility handling follow FreeBSD's vsyslog: %m expands to the guest errno's message, unknown bits are reported (as priority 0x23, since FreeBSD passes LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID as the priority) and masked, a missing facility becomes LOG_USER or the facility set by openlog, and errno is preserved. openlog applies its identity and LOG_PID; a null identity retains the previous one, and a valid nonzero facility replaces the default. closelog clears the identity but retains the options and facility, as in FreeBSD 11; when no identity is set, FreeBSD falls back to the program name, which this backend does not emit. LOG_PERROR has no extra effect because stderr is the emulated log sink; LOG_NDELAY/LOG_ODELAY, LOG_NOWAIT and LOG_CONS have no daemon, child or console backend to control. setlogmask follows FreeBSD 11: the process-wide mask defaults to 0xff, zero queries it, and nonzero values replace it; masked messages are skipped before formatting, including the unknown-priority diagnostic. The console's mask behaviour is unverified
  • daemon (libc) throws: forking into the background is not supported. PPSA85300 imports it and fails to load without it. VLC 3.0 calls it only when its daemon option is set (libvlc.c), and the title starts libVLC with --ignore-config and without --daemon (player.cc)
  • Call tracing (APS5_TRACE_CALLS) exists on Windows only and records the entry of a call, not its arguments or its result. Nothing passes imports through TraceImport_nid_no_patch yet, so no title is traced. One process-wide ring keeps the last 65536 calls, so a thread that calls often pushes the others out. Calls are also counted per traced target since start-up; an import bound to a target already traced under another name is counted under the first name. The thunk saves the integer argument registers and xmm0 to xmm7; arguments in wider vector registers pass only as long as the recording code stays free of AVX instructions, which is not tested
  • _WStoul, _Iswctype, swscanf_s and swscanf (libc) - _WStoul is wcstoul and throws for a base other than 0 or 2 to 36. _Iswctype takes the class numbers of Dinkumware's xwcc.h (1 alnum to 11 xdigit, 12 blank) and throws for any other value, including the FreeBSD masks wctype returns; the numbering is not confirmed on the console's libc.prx. swscanf_s follows C11 7.29.2.2 and K.3.9.1.5, but reads the size argument as unsigned int like sscanf_s where K.3.9.1.5 specifies rsize_t; the console's width is unverified. A runtime-constraint violation (null buffer, format or receiving pointer) only returns EOF, and a too small array gets a null first element as in sscanf_s. A literal mismatch is a matching failure and a field that is only a prefix, such as 0x or 1e, does not convert, as C11 requires; FreeBSD's vfwscanf reports an input failure for the first and converts the second. Integers out of range are truncated from strtoll/strtoull. It throws for %p, %S, %C, unknown length modifiers, scanset ranges, %n with suppression or width, and narrow %s, %c or %[ input that the C-locale wcrtomb cannot convert. swscanf runs the same scanner without the size arguments of %s, %c and %[, as FreeBSD's swscanf.c passes its arguments to vswscanf, so everything above except the sizes applies to it; it also keeps the null buffer, format and receiving pointer checks returning EOF, where C leaves those undefined. Neither variant is confirmed on a PS5 title
  • flock (libkernel) on Windows shares one lock state between duplicated descriptors, following FreeBSD 11.4's flock(2). Independent opens have separate states; closing a descriptor or reopening a stream drops only its reference. Lock transitions on one open file description are serialized. The lock is a host LockFileEx lock on one byte at offset 2^63 - 2, which no file reaches, so it excludes other flock calls and leaves reads, writes and mapped views alone, like FreeBSD's advisory locks. Console behavior, signal interruption and concurrent closure of a descriptor while its lock call is pending are unverified.
  • std::_Throw_Cpp_error (libSceAmpr) follows Dinkumware's thread0.cpp as shipped with Visual C++ 2013 and in microsoft/STL, without console verification. _Cpp_error codes 0 to 6 throw a guest std::system_error whose error_code holds the FreeBSD errno of the errc value (EBUSY 16, EINVAL 22, ESRCH 3, ENOMEM 12, EPERM 1, EDEADLK 11, EAGAIN 35) and the generic category, and whose what() is the table message, ": " and the generic category's message for that errno, selected by the first matching errno entry in VC12's syserror.cpp; another code throws std::out_of_range on the host instead of reading past the table. The guest system_error is taken to be VC12's: the 16-byte runtime_error followed by error_code {int, const error_category*}, 32 bytes, so its copy constructor and assignment copy the code too. The generic category is a static libc object with VC12's error_category virtual order (destructors, name, message, default_error_condition, the two equivalent), not the console's _Error_objects<int>::_Generic_object, and the new generic_category() export returns that object; a title's inline category object in a bundled libc can still have a different identity. Its message and direct message export construct the existing GuestLocale::String model: a reserved eight-byte word, 16-byte inline buffer, length and capacity, with guest operator new storage above 15 bytes. This 40-byte string layout and virtual return ABI have not been verified against a console library. The deleting destructor still throws. _Syserror_map covers the 72 distinct Dinkumware errc values present in FreeBSD 11.4 errno.h, returning null for other values; category messages use unknown error for those. First-match aliases are EAGAIN/EWOULDBLOCK -> operation would block and ENOTSUP/EOPNOTSUPP -> not supported. STREAMS-only errno assignments absent from that header (ENODATA, ENOSR, ENOSTR, ETIME) are not inferred
  • Call tracing (--trace-imports, APS5_TRACE_CALLS) exists on Windows only and records the entry of a call, not its arguments or its result. One process-wide ring keeps the last 65536 calls, so a thread that calls often pushes the others out. Calls are also counted per traced target since start-up; an import bound to a target already traced under another name is counted under the first name. The thunk saves the integer argument registers and xmm0 to xmm7; arguments in wider vector registers pass only as long as the recording code stays free of AVX instructions, which is not tested
  • _Dtest (libc) follows Dinkumware double classification matching _FDtest: finite values return -1, subnormals -2, zeros 0, infinities 1, and NaNs 2.