rpcsx/rx/src/debug.cpp

141 lines
3 KiB
C++
Raw Normal View History

2024-11-24 12:05:46 +01:00
#include "debug.hpp"
2025-10-16 10:29:16 +02:00
#include "Process.hpp"
#include "print.hpp"
2024-11-24 12:05:46 +01:00
#include <fstream>
#include <list>
#include <thread>
#include <vector>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#ifdef _WIN32
#include <windows.h>
#else
#ifdef __linux__
2024-11-24 12:05:46 +01:00
#include <linux/limits.h>
#include <sys/ptrace.h>
#endif
2024-11-24 12:05:46 +01:00
#include <unistd.h>
#endif
2024-11-24 12:05:46 +01:00
bool rx::isDebuggerPresent() {
#ifdef _WIN32
return ::IsDebuggerPresent();
#elif defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__NetBSD__) || defined(__OpenBSD__)
int mib[] = {
CTL_KERN,
KERN_PROC,
KERN_PROC_PID,
getpid(),
#if defined(__NetBSD__) || defined(__OpenBSD__)
sizeof(struct kinfo_proc),
1,
#endif
};
u_int miblen = std::size(mib);
struct kinfo_proc info;
usz size = sizeof(info);
if (sysctl(mib, miblen, &info, &size, NULL, 0)) {
return false;
}
return info.KP_FLAGS & P_TRACED;
#elif defined(__linux__)
2024-11-24 12:05:46 +01:00
std::ifstream in("/proc/self/status");
std::string line;
while (std::getline(in, line)) {
const std::string_view tracerPrefix = "TracerPid:\t";
if (!line.starts_with(tracerPrefix)) {
continue;
}
std::string_view tracer = line;
tracer.remove_prefix(tracerPrefix.size());
if (tracer.size() == 1 && tracer[0] == '0')
return false;
return true;
}
return false;
#endif
2024-11-24 12:05:46 +01:00
}
void rx::waitForDebugger() {
if (isDebuggerPresent()) {
return;
}
2025-10-16 10:29:16 +02:00
rx::println(stderr, "waiting for debugger, pid {}", getCurrentProcessId());
2024-11-24 12:05:46 +01:00
while (!isDebuggerPresent()) {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
rx::println(stderr, "debugger was attached");
2024-11-24 12:05:46 +01:00
std::this_thread::sleep_for(std::chrono::seconds(3));
breakpoint();
}
void rx::runDebugger() {
#ifdef __linux__
2024-11-24 12:05:46 +01:00
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();
return;
}
auto pidString = std::to_string(pid);
const char *gdbPath = "/usr/bin/gdb";
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
}
2024-11-24 12:05:46 +01:00
void rx::breakpoint() {
#if __has_builtin(__builtin_debugtrap)
__builtin_debugtrap();
#elif defined(__GNUC__)
#if defined(__i386__) || defined(__x86_64__)
2024-11-24 12:05:46 +01:00
__asm__ volatile("int3");
#elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
__asm__ volatile("brk 0x42");
#endif
#elif defined(_M_X64)
__debugbreak();
2024-11-24 12:05:46 +01:00
#endif
}
void rx::breakpointIfDebugging() {
if (isDebuggerPresent()) {
breakpoint();
}
}