fix(libSceSysmodule): return INVALID_VALUE for module id 0

Measured on a PS5 (firmware 13.60): sceSysmoduleIsLoaded,
sceSysmoduleLoadModule and sceSysmoduleUnloadModule with id 0, and the
Internal and InternalWithArg calls with id 0 or 0x80000000, return
0x805A1000 and leave the WithArg result untouched. They threw.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
hugodearaujo 2026-10-10 23:13:22 -03:00
parent a11c8f7f70
commit a61e2d35dd
2 changed files with 22 additions and 6 deletions

View File

@ -20,6 +20,7 @@ extern "C" void* APS5_VABI dlopen_nid_postfix(const char* path, int flags);
namespace {
constexpr int SCE_SYSMODULE_ERROR_INVALID_VALUE = static_cast<int>(0x805A1000);
constexpr int SCE_SYSMODULE_ERROR_UNLOADED = static_cast<int>(0x805A1001);
constexpr int kRtldNow = 2;
@ -117,7 +118,7 @@ int APS5_VABI sceSysmoduleGetModuleHandleInternal(std::uint32_t id, std::int32_t
int APS5_VABI sceSysmoduleIsLoaded(std::uint16_t id) {
if (id == 0) {
throw std::runtime_error("sceSysmoduleIsLoaded: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
APS5_LOG_OUT("unknown id: %u", static_cast<unsigned>(id));
@ -134,7 +135,7 @@ int APS5_VABI sceSysmoduleIsLoaded(std::uint16_t id) {
int APS5_VABI sceSysmoduleLoadModule(std::uint16_t id) {
if (id == 0) {
throw std::runtime_error("sceSysmoduleLoadModule: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
APS5_LOG_OUT("unknown id: %u", static_cast<unsigned>(id));
@ -151,7 +152,7 @@ int APS5_VABI sceSysmoduleLoadModuleInternalWithArg(std::uint32_t id, int argc,
(void)argv;
(void)unk;
if ((id & 0x7fffffffu) == 0) {
throw std::runtime_error("sceSysmoduleLoadModuleInternalWithArg: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
throw std::runtime_error(std::string("sceSysmoduleLoadModuleInternalWithArg: unknown id ") + std::to_string(id));
@ -166,7 +167,7 @@ int APS5_VABI sceSysmoduleLoadModuleInternalWithArg(std::uint32_t id, int argc,
int APS5_VABI sceSysmoduleUnloadModule(std::uint16_t id) {
if (id == 0) {
throw std::runtime_error("sceSysmoduleUnloadModule: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
APS5_LOG_OUT("unknown id: %u", static_cast<unsigned>(id));
@ -183,7 +184,7 @@ int APS5_VABI sceSysmoduleUnloadModule(std::uint16_t id) {
int APS5_VABI sceSysmoduleLoadModuleInternal(std::uint32_t id) {
if ((id & 0x7fffffffu) == 0) {
throw std::runtime_error("sceSysmoduleLoadModuleInternal: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
throw std::runtime_error(std::string("sceSysmoduleLoadModuleInternal: unknown id ") + std::to_string(id));
@ -195,7 +196,7 @@ int APS5_VABI sceSysmoduleLoadModuleInternal(std::uint32_t id) {
int APS5_VABI sceSysmoduleUnloadModuleInternal(std::uint32_t id) {
if ((id & 0x7fffffffu) == 0) {
throw std::runtime_error("sceSysmoduleUnloadModuleInternal: invalid id 0");
return SCE_SYSMODULE_ERROR_INVALID_VALUE;
}
if (!findModuleName(id)) {
throw std::runtime_error(std::string("sceSysmoduleUnloadModuleInternal: unknown id ") + std::to_string(id));

View File

@ -2,6 +2,7 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#include <initializer_list>
#include <stdexcept>
#include <string>
#ifdef __linux__
@ -17,6 +18,7 @@ int APS5_VABI sceSysmoduleLoadModule(std::uint16_t id);
int APS5_VABI sceSysmoduleUnloadModule(std::uint16_t id);
int APS5_VABI sceSysmoduleLoadModuleInternal(std::uint32_t id);
int APS5_VABI sceSysmoduleUnloadModuleInternal(std::uint32_t id);
int APS5_VABI sceSysmoduleLoadModuleInternalWithArg(std::uint32_t id, int argc, void* argv, std::uint64_t unk, int* ret);
int APS5_VABI sceSysmoduleGetModuleInfoForUnwind(std::uint64_t addr, int flags, ModuleInfoForUnwind* info);
int APS5_VABI sceSysmoduleGetModuleHandleInternal(std::uint32_t id, std::int32_t* handle);
int APS5_VABI sceKernelDlsym(std::int32_t handle, const char* symbol, void** addr);
@ -38,7 +40,9 @@ bool ThrowsRuntimeError(TFunction function) {
constexpr std::uint16_t kFiberModuleId = 0x0006;
constexpr std::uint16_t kUltModuleId = 0x0007;
constexpr int kInvalidValue = static_cast<int>(0x805A1000);
constexpr int kModuleUnloaded = static_cast<int>(0x805A1001);
constexpr std::uint32_t kInternalFlag = 0x80000000u;
constexpr std::uint16_t kTrophy2ModuleId = 0x0110;
#ifdef __linux__
@ -98,6 +102,17 @@ void CheckUnwindInfo() {
}
int main() {
Require(sceSysmoduleIsLoaded(0) == kInvalidValue);
Require(sceSysmoduleLoadModule(0) == kInvalidValue);
Require(sceSysmoduleUnloadModule(0) == kInvalidValue);
for (std::uint32_t id : {0u, kInternalFlag}) {
Require(sceSysmoduleLoadModuleInternal(id) == kInvalidValue);
Require(sceSysmoduleUnloadModuleInternal(id) == kInvalidValue);
int result = 0x5a5a5a5a;
Require(sceSysmoduleLoadModuleInternalWithArg(id, 0, nullptr, 0, &result) == kInvalidValue);
Require(result == 0x5a5a5a5a);
}
Require(sceSysmoduleIsLoaded(kFiberModuleId) == kModuleUnloaded);
Require(sceSysmoduleLoadModuleInternal(kFiberModuleId) == 0);
Require(sceSysmoduleIsLoaded(kFiberModuleId) == 0);