mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-06 13:30:00 +00:00
86 lines
3.1 KiB
C++
86 lines
3.1 KiB
C++
#include "SceTypes.hpp"
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
|
|
extern "C" {
|
|
[[noreturn]] void APS5_VABI EnterGuestMainStack_nid_no_patch(void* arguments, void (*entry)(void*));
|
|
int APS5_VABI scePthreadCreate(Pthread* thread, const PthreadAttr* attr, PthreadEntry entry, void* arg, const char* name);
|
|
int APS5_VABI scePthreadJoin(Pthread thread, void** retval);
|
|
int APS5_VABI sceKernelIsStack(void* addr, void** start, void** end);
|
|
}
|
|
|
|
#ifdef ANYPS5_ENABLE_ASAN
|
|
static constexpr std::uintptr_t GuestArenaOffset = 0x0000100000000000ull;
|
|
#else
|
|
static constexpr std::uintptr_t GuestArenaOffset = 0;
|
|
#endif
|
|
static constexpr std::uintptr_t ConsoleMainStackTop = 0x00000007EEFFC000ull + GuestArenaOffset;
|
|
static constexpr std::uintptr_t SmallestStack = 0x100000;
|
|
static int marker = 0;
|
|
|
|
#define Require(value) do { if (!(value)) { std::fprintf(stderr, "GuestMainStack failed at line %d\n", __LINE__); std::_Exit(1); } } while (false)
|
|
|
|
static char Permissions(std::uintptr_t address) {
|
|
std::FILE* maps = std::fopen("/proc/self/maps", "r");
|
|
Require(maps != nullptr);
|
|
char result = 0;
|
|
char line[512];
|
|
while (std::fgets(line, sizeof(line), maps) != nullptr) {
|
|
unsigned long long low = 0;
|
|
unsigned long long high = 0;
|
|
char permissions[5] = {};
|
|
if (std::sscanf(line, "%llx-%llx %4s", &low, &high, permissions) != 3 || address < low || address >= high) continue;
|
|
result = permissions[0] == 'r' && permissions[1] == 'w' ? 'w' : permissions[0] == 'r' ? 'r' : '-';
|
|
break;
|
|
}
|
|
std::fclose(maps);
|
|
return result;
|
|
}
|
|
|
|
struct WorkerContext {
|
|
std::atomic<bool> queried{false};
|
|
void* local = nullptr;
|
|
void* start = nullptr;
|
|
void* end = nullptr;
|
|
int result = -1;
|
|
};
|
|
|
|
static void* APS5_VABI Worker(void* arg) {
|
|
auto& context = *static_cast<WorkerContext*>(arg);
|
|
int local = 0;
|
|
context.local = &local;
|
|
context.result = sceKernelIsStack(&local, &context.start, &context.end);
|
|
context.queried.store(true);
|
|
return nullptr;
|
|
}
|
|
|
|
static void APS5_VABI Entry(void* arguments) {
|
|
Require(arguments == &marker);
|
|
int local = 0;
|
|
const auto address = reinterpret_cast<std::uintptr_t>(&local);
|
|
void* start = nullptr;
|
|
void* end = nullptr;
|
|
Require(sceKernelIsStack(&local, &start, &end) == 0);
|
|
const auto low = reinterpret_cast<std::uintptr_t>(start);
|
|
const auto high = reinterpret_cast<std::uintptr_t>(end);
|
|
Require(high == ConsoleMainStackTop);
|
|
Require(low <= address && address < high);
|
|
Require(high - low >= SmallestStack);
|
|
Require(Permissions(low) == 'w' && Permissions(high - 1) == 'w');
|
|
Require(Permissions(low - 1) == '-');
|
|
|
|
WorkerContext context;
|
|
Pthread thread = nullptr;
|
|
Require(scePthreadCreate(&thread, nullptr, Worker, &context, nullptr) == 0);
|
|
Require(scePthreadJoin(thread, nullptr) == 0);
|
|
Require(context.queried.load() && context.result == 0);
|
|
Require(reinterpret_cast<std::uintptr_t>(context.end) <= low || reinterpret_cast<std::uintptr_t>(context.start) >= high);
|
|
std::exit(0);
|
|
}
|
|
|
|
int main() {
|
|
EnterGuestMainStack_nid_no_patch(&marker, Entry);
|
|
}
|