#include "debug.hpp" #include "Process.hpp" #include "print.hpp" #include #include #include #include #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #ifdef _WIN32 #include #else #ifdef __linux__ #include #include #endif #include #endif 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__) 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 } void rx::waitForDebugger() { if (isDebuggerPresent()) { return; } rx::println(stderr, "waiting for debugger, pid {}", getCurrentProcessId()); while (!isDebuggerPresent()) { std::this_thread::sleep_for(std::chrono::seconds(1)); } rx::println(stderr, "debugger was attached"); std::this_thread::sleep_for(std::chrono::seconds(3)); breakpoint(); } 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(); return; } auto pidString = std::to_string(pid); const char *gdbPath = "/usr/bin/gdb"; std::list storage; std::vector 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 0x400000"); argv.push_back(nullptr); execv(gdbPath, (char **)argv.data()); #endif } void rx::breakpoint() { #if __has_builtin(__builtin_debugtrap) __builtin_debugtrap(); #elif defined(__GNUC__) #if defined(__i386__) || defined(__x86_64__) __asm__ volatile("int3"); #elif defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) __asm__ volatile("brk 0x42"); #endif #elif defined(_M_X64) __debugbreak(); #endif } void rx::breakpointIfDebugging() { if (isDebuggerPresent()) { breakpoint(); } }