mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-08 09:40:23 +01:00
rx: add filesystem utility, cross platform runDebugger implementation
This commit is contained in:
parent
05759b33b2
commit
c5be529f96
|
|
@ -6,6 +6,7 @@ add_library(${PROJECT_NAME} OBJECT
|
|||
src/debug.cpp
|
||||
src/die.cpp
|
||||
src/FileLock.cpp
|
||||
src/filesystem.cpp
|
||||
src/hexdump.cpp
|
||||
src/Mappable.cpp
|
||||
src/mem.cpp
|
||||
|
|
|
|||
12
rx/include/rx/filesystem.hpp
Normal file
12
rx/include/rx/filesystem.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rx {
|
||||
// Get the full path to the current executable
|
||||
std::string getExecutablePath();
|
||||
|
||||
// Find an executable by name in system PATH
|
||||
// Returns the full path if found, empty string otherwise
|
||||
std::string findExecutable(const std::string &name);
|
||||
} // namespace rx
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
#include "debug.hpp"
|
||||
#include "Process.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "print.hpp"
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -15,7 +15,6 @@
|
|||
#else
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/limits.h>
|
||||
#include <sys/ptrace.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
|
@ -86,37 +85,36 @@ void rx::waitForDebugger() {
|
|||
}
|
||||
|
||||
void rx::runDebugger() {
|
||||
#ifdef __linux__
|
||||
int pid = ::getpid();
|
||||
char path[PATH_MAX];
|
||||
::readlink("/proc/self/exe", path, sizeof(path));
|
||||
if (fork()) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
waitForDebugger();
|
||||
auto pid = getCurrentProcessId();
|
||||
auto path = rx::getExecutablePath();
|
||||
|
||||
auto pidString = std::to_string(pid);
|
||||
|
||||
// Find gdb in PATH
|
||||
auto gdbPath = rx::findExecutable("gdb");
|
||||
|
||||
if (gdbPath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto pidString = std::to_string(pid);
|
||||
const char *gdbPath = "/usr/bin/gdb";
|
||||
std::vector<std::string> args = {
|
||||
path,
|
||||
pidString,
|
||||
"-iex",
|
||||
"set pagination off",
|
||||
"-ex",
|
||||
"handle SIGSYS nostop noprint",
|
||||
"-ex",
|
||||
"handle SIGUSR1 nostop noprint"
|
||||
// TODO: collect elfs
|
||||
// "-ex", "add-symbol-file <path to elf> 0x400000"
|
||||
};
|
||||
|
||||
std::list<std::string> storage;
|
||||
std::vector<const char *> argv;
|
||||
argv.push_back(gdbPath);
|
||||
argv.push_back(path);
|
||||
argv.push_back(pidString.c_str());
|
||||
argv.push_back("-iex");
|
||||
argv.push_back("set pagination off");
|
||||
argv.push_back("-ex");
|
||||
argv.push_back("handle SIGSYS nostop noprint");
|
||||
argv.push_back("-ex");
|
||||
argv.push_back("handle SIGUSR1 nostop noprint");
|
||||
// TODO: collect elfs
|
||||
// argv.push_back("-ex");
|
||||
// argv.push_back("add-symbol-file <path to elf> 0x400000");
|
||||
argv.push_back(nullptr);
|
||||
|
||||
execv(gdbPath, (char **)argv.data());
|
||||
#endif
|
||||
ProcessId debuggerPid = rx::spawn(gdbPath, args);
|
||||
if (debuggerPid != static_cast<ProcessId>(-1)) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
waitForDebugger();
|
||||
}
|
||||
}
|
||||
|
||||
void rx::breakpoint() {
|
||||
|
|
|
|||
248
rx/src/filesystem.cpp
Normal file
248
rx/src/filesystem.cpp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
#include <rx/filesystem.hpp>
|
||||
#include <rx/types.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
#include <climits>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#elif defined(__NetBSD__) | defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__sun)
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
std::string rx::getExecutablePath() {
|
||||
#ifdef _WIN32
|
||||
wchar_t path[MAX_PATH];
|
||||
DWORD len = ::GetModuleFileNameW(nullptr, path, MAX_PATH);
|
||||
if (len == 0 || len == MAX_PATH) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Convert wide string to narrow string
|
||||
int size =
|
||||
::WideCharToMultiByte(CP_UTF8, 0, path, -1, nullptr, 0, nullptr, nullptr);
|
||||
if (size <= 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string result(size - 1, '\0');
|
||||
::WideCharToMultiByte(CP_UTF8, 0, path, -1, result.data(), size, nullptr,
|
||||
nullptr);
|
||||
return result;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
char path[PATH_MAX];
|
||||
uint32_t size = sizeof(path);
|
||||
if (_NSGetExecutablePath(path, &size) == 0) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// Buffer too small, allocate larger
|
||||
std::string result(size, '\0');
|
||||
if (_NSGetExecutablePath(result.data(), &size) == 0) {
|
||||
result.resize(size - 1); // Remove null terminator
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
|
||||
#elif defined(__linux__) || defined(__ANDROID__)
|
||||
char path[PATH_MAX];
|
||||
ssize_t len = ::readlink("/proc/self/exe", path, sizeof(path) - 1);
|
||||
if (len == -1) {
|
||||
return {};
|
||||
}
|
||||
path[len] = '\0';
|
||||
return path;
|
||||
|
||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
char path[PATH_MAX];
|
||||
size_t len = sizeof(path);
|
||||
if (sysctl(mib, 4, path, &len, nullptr, 0) == 0) {
|
||||
return path;
|
||||
}
|
||||
return {};
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
|
||||
char path[PATH_MAX];
|
||||
size_t len = sizeof(path);
|
||||
if (sysctl(mib, 4, path, &len, nullptr, 0) == 0) {
|
||||
return path;
|
||||
}
|
||||
return {};
|
||||
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD doesn't provide a direct way to get executable path
|
||||
// Return empty string as fallback
|
||||
return {};
|
||||
|
||||
#elif defined(__sun)
|
||||
// Solaris
|
||||
const char *path = getexecname();
|
||||
if (path) {
|
||||
if (path[0] == '/') {
|
||||
return std::string(path);
|
||||
}
|
||||
// Relative path, need to prepend current directory
|
||||
char cwd[PATH_MAX];
|
||||
if (getcwd(cwd, sizeof(cwd))) {
|
||||
return std::string(cwd) + "/" + path;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
|
||||
#else
|
||||
#error "rx::filesystem::getExecutablePath not implemented for this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string rx::findExecutable(const std::string &name) {
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// On Windows, search PATH with automatic .exe extension handling
|
||||
std::vector<std::string> extensions;
|
||||
|
||||
// Check if name already has an extension
|
||||
bool hasExtension = name.find('.') != std::string::npos;
|
||||
if (hasExtension) {
|
||||
extensions.push_back("");
|
||||
} else {
|
||||
// Try common executable extensions
|
||||
const char *pathExt = std::getenv("PATHEXT");
|
||||
if (pathExt) {
|
||||
std::string pathExtStr = pathExt;
|
||||
size_t start = 0;
|
||||
while (start < pathExtStr.size()) {
|
||||
size_t end = pathExtStr.find(';', start);
|
||||
if (end == std::string::npos) {
|
||||
end = pathExtStr.size();
|
||||
}
|
||||
std::string ext = pathExtStr.substr(start, end - start);
|
||||
extensions.push_back(ext);
|
||||
start = end + 1;
|
||||
}
|
||||
} else {
|
||||
extensions = {".exe", ".bat", ".cmd", ".com"};
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it's an absolute or relative path
|
||||
if (name.find('\\') != std::string::npos ||
|
||||
name.find('/') != std::string::npos ||
|
||||
(name.size() >= 2 && name[1] == ':')) {
|
||||
// It's a path, check if file exists
|
||||
for (const auto &ext : extensions) {
|
||||
std::string fullPath = name + ext;
|
||||
DWORD attrs = ::GetFileAttributesA(fullPath.c_str());
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES &&
|
||||
!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// Search in PATH
|
||||
const char *pathEnv = std::getenv("PATH");
|
||||
if (!pathEnv) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string_view pathStr = pathEnv;
|
||||
size_t start = 0;
|
||||
while (start < pathStr.size()) {
|
||||
size_t end = pathStr.find(';', start);
|
||||
if (end == std::string::npos) {
|
||||
end = pathStr.size();
|
||||
}
|
||||
|
||||
auto dir = std::string(pathStr.substr(start, end - start));
|
||||
if (!dir.empty()) {
|
||||
// Add separator if needed
|
||||
if (dir.back() != '\\' && dir.back() != '/') {
|
||||
dir += '\\';
|
||||
}
|
||||
|
||||
for (const auto &ext : extensions) {
|
||||
std::string fullPath = dir + name + ext;
|
||||
DWORD attrs = ::GetFileAttributesA(fullPath.c_str());
|
||||
if (attrs != INVALID_FILE_ATTRIBUTES &&
|
||||
!(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
return {};
|
||||
|
||||
#else
|
||||
// Unix-like systems
|
||||
// Check if it's already a path (contains /)
|
||||
if (name.find('/') != std::string::npos) {
|
||||
struct stat st;
|
||||
if (stat(name.c_str(), &st) == 0 && S_ISREG(st.st_mode) &&
|
||||
(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
|
||||
return name;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// Search in PATH
|
||||
const char *pathEnv = std::getenv("PATH");
|
||||
if (!pathEnv) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string pathStr = pathEnv;
|
||||
size_t start = 0;
|
||||
while (start < pathStr.size()) {
|
||||
size_t end = pathStr.find(':', start);
|
||||
if (end == std::string::npos) {
|
||||
end = pathStr.size();
|
||||
}
|
||||
|
||||
std::string dir = pathStr.substr(start, end - start);
|
||||
if (!dir.empty()) {
|
||||
// Add separator if needed
|
||||
if (dir.back() != '/') {
|
||||
dir += '/';
|
||||
}
|
||||
|
||||
std::string fullPath = dir + name;
|
||||
struct stat st;
|
||||
if (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode) &&
|
||||
(st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
|
||||
return fullPath;
|
||||
}
|
||||
}
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
Loading…
Reference in a new issue