feat(libSceDbgThreadSanitizer): declare the TSan annotation calls and report the sanitizer disabled
Black Myth: Wukong (PPSA23226) exits at start-up with STATUS_DLL_NOT_FOUND after "Failed to load module: libs\libSceDbgThreadSanitizer.prx". The executable does not need the library: its bundled sce_module/libSceJobManager_nosubmission.prx lists it in DT_NEEDED and imports __tsan_acquire and __tsan_release from it, plus sceKernelIsThreadSanitizerEnabled from libkernel. The relinker converts every module in sce_module and loads it at start-up (only --module-dir directories are deferred), and GuestModuleBuilder adds each module's host dependencies to the executable's DT_NEEDED, which the Windows start-up stub loads. libSceDbgThreadSanitizer now exports __tsan_acquire and __tsan_release with the void(void* addr) signatures of LLVM compiler-rt's tsan_interface.h (llvm-project 87f0227cb601, LLVM 20.1.8). Both throw: AnyPS5 runs no race detector, and the module calls them only after sceKernelIsThreadSanitizerEnabled reports the sanitizer enabled. libkernel's sceKernelIsThreadSanitizerEnabled returns 0, as sceKernelIsAddressSanitizerEnabled does; its int(void) signature is assumed and recorded in the libkernel debt file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ea2bbefb2b
commit
0f77f3e07f
|
|
@ -0,0 +1,14 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void APS5_VABI __tsan_acquire(void*) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
void APS5_VABI __tsan_release(void*) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -952,6 +952,15 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_software_version PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_thread_sanitizer_tests ${LIBS_INCLUDE_DIR}/tests/GuestThreadSanitizer.cpp)
|
||||
target_include_directories(guest_thread_sanitizer_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_thread_sanitizer_tests PRIVATE libkernel libc)
|
||||
configure_windows_unwind(guest_thread_sanitizer_tests)
|
||||
add_test(NAME guest_thread_sanitizer COMMAND guest_thread_sanitizer_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_thread_sanitizer PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_system_command_tests ${LIBS_INCLUDE_DIR}/tests/GuestSystemCommand.cpp)
|
||||
target_include_directories(guest_system_command_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_system_command_tests PRIVATE libkernel libc)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,10 @@ int APS5_VABI sceKernelIsAddressSanitizerEnabled(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelIsThreadSanitizerEnabled(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MallocReplace* APS5_VABI sceKernelGetSanitizerMallocReplaceExternal(void) {
|
||||
static MallocReplace replacement{};
|
||||
return &replacement;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdlib>
|
||||
|
||||
extern "C" int APS5_VABI sceKernelIsThreadSanitizerEnabled(void);
|
||||
|
||||
int main() {
|
||||
if (sceKernelIsThreadSanitizerEnabled() != 0) std::abort();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# libSceDbgThreadSanitizer technical debt
|
||||
|
||||
### Unknown function info
|
||||
|
||||
- [__tsan_acquire, __tsan_release](../../../core/libs/prx/libSceDbgThreadSanitizer/Export.cpp) (libSceDbgThreadSanitizer, NIDs `XyX1104ACcU` and `IkoI44e0OXc`) - declared as throwing stubs: AnyPS5 runs no race detector. The `void (void* addr)` signatures are those of LLVM compiler-rt's [tsan_interface.h](https://github.com/llvm/llvm-project/blob/87f0227cb60147a26a1eeb4fb06e3b505e9c7261/compiler-rt/include/sanitizer/tsan_interface.h#L24-L25), whose names hash to the imported NIDs; that the console library has the same signatures is assumed. PPSA23226's bundled `libSceJobManager_nosubmission.prx` imports both and calls them only after [sceKernelIsThreadSanitizerEnabled](../../../core/libs/prx/libkernel/System/src/Sanitizer.cpp) reports the sanitizer enabled, which it never does here
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
- [sceKernelGetMainSocId and sceKernelGetCpumode](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) both return 0, and [sceKernelGetCpuFrequency](../../../core/libs/prx/libkernel/Time/Time.cpp) returns the host TSC frequency measured for `sceKernelGetTscFrequency`, not the console CPU clock. The PS5's SoC id and CPU mode are unknown; shadPS4's PS4 values are [0x710f10/0x740f30 and 0, 2 or 5 from the param.sfo CPU-mode flags](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1a/src/core/libraries/kernel/process.cpp). PPSA99203 only logs them (`[console] main SoC id: result=%#x out=%#x`, `CPU: %llu Hz, cpumode %d`), passing a pointer that `sceKernelGetMainSocId` leaves untouched
|
||||
- [sceKernelEnableDmemAliasing](../../../core/libs/prx/libkernel/DirectMemory/Export.cpp) (libkernel) returns 0 and changes nothing: direct memory can always be mapped more than once here, as `DoMapDirect` in [DirectMemory.cpp](../../../core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp) only checks that the physical pages are allocated, so there is no aliasing to turn on. [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1aacbc8db8253be685bf7ab4d9daae/src/core/libraries/kernel/memory.cpp#L39-L43) (PS4) sets a flag there that lifts the `EBUSY` its [`sceKernelMapDirectMemory2`](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1aacbc8db8253be685bf7ab4d9daae/src/core/libraries/kernel/memory.cpp#L299-L301), and [`sceKernelMapDirectMemory` for SDK 2.50 and later](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1aacbc8db8253be685bf7ab4d9daae/src/core/libraries/kernel/memory.cpp#L237-L242), return for direct memory that is [already mapped](https://github.com/shadps4-emu/shadPS4/blob/e0a466753a1aacbc8db8253be685bf7ab4d9daae/src/core/memory.cpp#L548-L553); that check is not applied here. The no-argument `int` signature follows shadPS4 and ProsperoEden (PPSA99008), which calls it before mapping the same direct memory again. Whether the PS5 refuses such a mapping without the call is unverified
|
||||
- [sceKernelInternalMemoryGetAvailableSize](../../../core/libs/prx/libkernel/DirectMemory/Export.cpp) (libkernel) reports 0 bytes and returns 0: what the console's internal memory pool holds and how large it is are unknown. The `int (size_t*)` signature is from [xUtilty](https://github.com/Backporter/xUtilty/blob/328a856af1ef/source/SystemWrapper.cpp#L85) (PS4). PPSA99203 calls it once beside `sceKernelAvailableFlexibleMemorySize` while starting its GS renderer and never reads the result ([GS.cpp](https://github.com/Swordpdf/PS5SX2/blob/b4cf55e87c34/pcsx2/GS/GS.cpp#L233-L247))
|
||||
- [sceKernelIsThreadSanitizerEnabled](../../../core/libs/prx/libkernel/System/src/Sanitizer.cpp) (libkernel, NID `LzoM-wVLJDE`) returns 0, as `sceKernelIsAddressSanitizerEnabled` does: a converted title never runs under the thread sanitizer, so a title that checks it skips the [libSceDbgThreadSanitizer](../../../core/libs/prx/libSceDbgThreadSanitizer/Export.cpp) annotation calls, which throw. PPSA23226's bundled `libSceJobManager_nosubmission.prx` makes those calls only when it reports nonzero
|
||||
|
||||
### Unknown function info
|
||||
|
||||
|
|
@ -86,6 +87,7 @@
|
|||
- [LinuxProtFromSce](../../../core/libs/prx/libkernel/DirectMemory/DirectMemory.cpp) (libkernel) - protection bits 0x100 and 0x200 are accepted and assumed not to affect host CPU access; host protection is derived only from the read, write and execute bits
|
||||
- [sched_get_priority_max, sched_get_priority_min](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) - measured on a PS5 (firmware 13.60): `SCHED_FIFO` (1) and `SCHED_RR` (3) report a maximum of 767 and a minimum of 256, and every other policy, `SCHED_OTHER` (2) included, returns -1 with `EINVAL`. `pthread_setschedparam` ignores the policy and does not check the priority, where the console rejects `SCHED_OTHER` and priorities below 256 with `EINVAL`
|
||||
- [inet_pton, inet_ntop](../../../core/libs/prx/libkernel/Socket/src/AddressConversion.cpp) (libkernel) - the text forms are assumed to be those of FreeBSD 11.4 and are unverified on a console: `inet_pton` accepts only four decimal parts without leading zeros for `AF_INET` and the RFC 4291 forms for `AF_INET6` (one `::` standing for at least one group, a dotted-quad tail only as the last 32 bits, no zone id), and `inet_ntop` prints lowercase hex with the first longest run of two or more zero groups compressed, and a dotted tail only for `::a.b.c.d` and `::ffff:a.b.c.d`. They no longer depend on the host resolver library
|
||||
- [sceKernelIsThreadSanitizerEnabled](../../../core/libs/prx/libkernel/System/src/Sanitizer.cpp) (libkernel, NID `LzoM-wVLJDE`) - no source gives the signature; `int (void)` is assumed from `sceKernelIsAddressSanitizerEnabled` and from PPSA23226's bundled `libSceJobManager_nosubmission.prx`, which passes no arguments and tests only the 32-bit result
|
||||
|
||||
### Functional
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue