mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
sceCoredumpWriteUserData (Dbbkj6YHWdo) and sceCoredumpDebugTextOut
(dei8oUx6DbU) get the signatures of Orbital's db_types.json (cc408367)
and SharpProspero's KernelSystem.cs (5dfdb4b0): ssize_t (const void*,
size_t) and void (const char*, int). WriteUserData moves out of
Unimplemented.cpp.
User data belongs to the core dump handler: the Vita's
sceCoredumpWriteUserData returns 0x800A0003 ("No user-data capture is
active") outside it (vita-headers e66ebe90), and the RED engine's PS4
crash handler makes every coredump call from its handler (Vangaurd
4f86d2b0). The handler is never invoked here, so WriteUserData returns
SCE_COREDUMP_ERROR_NOT_IN_COREDUMP_HANDLER (0x81180003, shadPS4
coredump_error.h e0a46675) sign-extended and keeps nothing; a null,
empty or wrapping buffer throws because the order of the console's
checks is unknown. DebugTextOut prints its text to stderr with the
[coredump] prefix; a negative length or a null text with a nonzero
length throws.
Evidence: Broken Sword Reforged (PPSA21480) reaches the family through
its sibling, #3704 comment 6113687542: "`ERROR agc_graphics.cpp:266
Sony call failed with code 8a6c9018` (the resource registration error,
followed by the error dialog), then `sceCoredumpWriteUserString not
implemented`." WriteUserString has no declaration in any source and
keeps throwing; its TechnicalDebt entry records the call. 007 First
Light (PPSA11386) imports WriteUserData (#2523) without calling it
before its stop.
Test: guest_coredump_user_data.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
75 lines
2.8 KiB
C++
75 lines
2.8 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <thread>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceCoredumpRegisterCoredumpHandler(uint64_t handler, size_t stackSize, uint64_t context);
|
|
int APS5_VABI sceCoredumpUnregisterCoredumpHandler(void);
|
|
int64_t APS5_VABI sceCoredumpWriteUserData(const void* data, size_t size);
|
|
void APS5_VABI sceCoredumpDebugTextOut(const char* str, int len);
|
|
}
|
|
|
|
namespace {
|
|
constexpr int64_t NotInCoredumpHandler = static_cast<int32_t>(0x81180003u);
|
|
bool handlerRan = false;
|
|
int handlerContext = 0;
|
|
|
|
int APS5_VABI Handler(void*) {
|
|
handlerRan = true;
|
|
return 0;
|
|
}
|
|
|
|
void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
template <typename TCall>
|
|
bool Throws(TCall call, const char* function) {
|
|
try { call(); }
|
|
catch (const std::runtime_error& error) { return std::strstr(error.what(), function) != nullptr; }
|
|
return false;
|
|
}
|
|
|
|
void RequireWritesRefused(const std::array<unsigned char, 64>& region) {
|
|
Require(sceCoredumpWriteUserData(region.data(), region.size()) == NotInCoredumpHandler);
|
|
Require(sceCoredumpWriteUserData(region.data(), 1) == NotInCoredumpHandler);
|
|
int64_t fromThread = 0;
|
|
std::thread([&] { fromThread = sceCoredumpWriteUserData(region.data(), region.size()); }).join();
|
|
Require(fromThread == NotInCoredumpHandler);
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
std::array<unsigned char, 64> region{};
|
|
for (size_t index = 0; index < region.size(); ++index) region[index] = static_cast<unsigned char>(index * 5 + 1);
|
|
const auto original = region;
|
|
const char text[] = "coredump text\n";
|
|
|
|
Require(NotInCoredumpHandler < 0);
|
|
RequireWritesRefused(region);
|
|
sceCoredumpDebugTextOut(text, static_cast<int>(sizeof(text) - 1));
|
|
sceCoredumpDebugTextOut(text, 8);
|
|
sceCoredumpDebugTextOut(text, 0);
|
|
sceCoredumpDebugTextOut(nullptr, 0);
|
|
|
|
Require(sceCoredumpRegisterCoredumpHandler(reinterpret_cast<uint64_t>(&Handler), 16 * 1024, reinterpret_cast<uint64_t>(&handlerContext)) == 0);
|
|
RequireWritesRefused(region);
|
|
sceCoredumpDebugTextOut(text, static_cast<int>(sizeof(text) - 1));
|
|
Require(!handlerRan);
|
|
|
|
Require(Throws([&] { sceCoredumpWriteUserData(nullptr, region.size()); }, "sceCoredumpWriteUserData"));
|
|
Require(Throws([&] { sceCoredumpWriteUserData(region.data(), 0); }, "sceCoredumpWriteUserData"));
|
|
Require(Throws([&] { sceCoredumpWriteUserData(region.data(), SIZE_MAX); }, "sceCoredumpWriteUserData"));
|
|
Require(Throws([&] { sceCoredumpDebugTextOut(nullptr, 4); }, "sceCoredumpDebugTextOut"));
|
|
Require(Throws([&] { sceCoredumpDebugTextOut(text, -1); }, "sceCoredumpDebugTextOut"));
|
|
|
|
Require(sceCoredumpUnregisterCoredumpHandler() == 0);
|
|
RequireWritesRefused(region);
|
|
Require(region == original);
|
|
Require(!handlerRan);
|
|
return 0;
|
|
}
|