diff --git a/core/libs/prx/libkernel/System/src/Process.cpp b/core/libs/prx/libkernel/System/src/Process.cpp index 0d7b1a5bff4f..b3d5ed436b51 100644 --- a/core/libs/prx/libkernel/System/src/Process.cpp +++ b/core/libs/prx/libkernel/System/src/Process.cpp @@ -40,6 +40,7 @@ #endif extern "C" int* APS5_VABI __error_nid_postfix(); +extern "C" int APS5_VABI stat_nid_postfix(const char* path, FileStat* sb); namespace { @@ -347,6 +348,14 @@ int APS5_VABI execv_nid_postfix(const char* path, char* const* arguments) { return -1; } +int APS5_VABI execve_nid_postfix(const char* path, char* const* arguments, char* const* environment) { + (void)path; + (void)arguments; + (void)environment; + NotImplemented_nid_no_patch("execve: executable replacement"); + return -1; +} + int APS5_VABI sceKernelGetCurrentCpu(void) { #ifdef _WIN32 PROCESSOR_NUMBER processor{}; diff --git a/core/libs/tests/GuestExecvp.cpp b/core/libs/tests/GuestExecvp.cpp index ebf28b63a87d..24044df2f788 100644 --- a/core/libs/tests/GuestExecvp.cpp +++ b/core/libs/tests/GuestExecvp.cpp @@ -1,23 +1,29 @@ -#include "prx/libc/include/general/VabiMacros.hpp" +#include "prx/libc/include/General.hpp" #include #include #include -extern "C" int APS5_VABI execvp_nid_postfix(const char*, char* const*); -static void Require(bool value) { if (!value) std::abort(); } -static bool ReportsNotImplemented(const char* file, char* const* arguments) { +extern "C" { +int APS5_VABI execvp_nid_postfix(const char*, char* const*); +int APS5_VABI execv_nid_postfix(const char*, char* const*); +int APS5_VABI execve_nid_postfix(const char*, char* const*, char* const*); +} +template static bool Throws(TCall call, const std::string& message) { try { - execvp_nid_postfix(file, arguments); + call(); } catch (const std::runtime_error& error) { - return std::string(error.what()) == "execvp: executable replacement not implemented"; + return error.what() == message; } return false; } +static void Require(bool value) { if (!value) std::abort(); } int main() { - char shell[] = "sh"; - char option[] = "-c"; - char command[] = "exit 0"; - char* arguments[] = {shell, option, command, nullptr}; - Require(ReportsNotImplemented("sh", arguments)); - Require(ReportsNotImplemented("/bin/sh", arguments)); - Require(ReportsNotImplemented(nullptr, nullptr)); + char name[] = "sh"; + char* arguments[] = {name, nullptr}; + char variable[] = "HOME=/"; + char* environment[] = {variable, nullptr}; + Require(Throws([&] { execvp_nid_postfix("sh", arguments); }, "execvp: executable replacement not implemented")); + Require(Throws([&] { execvp_nid_postfix("/bin/sh", arguments); }, "execvp: executable replacement not implemented")); + Require(Throws([&] { execvp_nid_postfix(nullptr, nullptr); }, "execvp: executable replacement not implemented")); + Require(Throws([&] { execv_nid_postfix("/bin/sh", arguments); }, "execv: executable replacement not implemented")); + Require(Throws([&] { execve_nid_postfix("/bin/sh", arguments, environment); }, "execve: executable replacement not implemented")); } diff --git a/docs/dev/debt/libkernel.md b/docs/dev/debt/libkernel.md index 03abba3e13dc..cbc5f9504c54 100644 --- a/docs/dev/debt/libkernel.md +++ b/docs/dev/debt/libkernel.md @@ -131,6 +131,7 @@ - [dup and dup2](../../../core/libs/prx/libkernel/File/src/Stdio.cpp) (libkernel) throw for the combinations they do not model: `dup2` of a guest socket onto descriptors 0 to 2, whose host streams libc writes without the socket table, and on Windows duplicating a directory descriptor. Guest sockets share one socket object between the duplicates; the numbers come from the host descriptor table like those of files. The errno values for descriptor exhaustion are not verified against the console. - [waitpid](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) returns -1 with `ECHILD` (`EINVAL` for unknown options): nothing here creates a child process; child processes would need a real `waitpid`. - [execv](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) throws: replacing the process image is not supported, the same as `execvp`. PPSA97358 imports it and fails to load without it. +- [execve](../../../core/libs/prx/libkernel/System/src/Process.cpp) (libkernel) throws like `execvp`: replacing the process image is not supported. The console behavior for invalid arguments and executable path lookups is not modeled. - [kern.proc.pathname](../../../core/libs/prx/libkernel/System/src/SystemConfiguration.cpp) (libkernel) returns `/app0/eboot.bin` for pid -1 and the calling process, following FreeBSD's `sysctl_kern_proc_pathname`; the exact pathname on retail consoles remains unverified. - [machdep.cacheline_size](../../../core/libs/prx/libkernel/System/src/SystemConfiguration.cpp) (libkernel) returns -1 with `ENOENT`, matching FreeBSD amd64 where this sysctl OID is not defined. - [hw.model](../../../core/libs/prx/libkernel/System/src/SystemConfiguration.cpp) (libkernel) reports the host CPU's name, built as FreeBSD 11 builds `hw.model`: the CPUID brand string (leaves 0x80000002 to 0x80000004) without leading spaces ([identcpu.c](https://github.com/freebsd/freebsd-src/blob/release/11.0.0/sys/x86/x86/identcpu.c#L683-L691)). Trailing padding stays, as it does there, so an AMD host's name ends in spaces. The name a PS5 reports is unknown. A write returns -1 with `EPERM`. A host without an x86 CPUID brand string, such as an Apple Silicon Mac, throws. PPSA99203 only prints it (`[console] hw.model: %s`)