3#include "plg/config.hpp"
5#if __has_include(<debugging>)
7#if defined(__cpp_lib_debugging) && __cpp_lib_debugging >= 202403L
8#define PLUGIFY_HAS_STD_DEBUGGING 1
10#define PLUGIFY_HAS_STD_DEBUGGING 0
13#define PLUGIFY_HAS_STD_DEBUGGING 0
16#if !PLUGIFY_HAS_STD_DEBUGGING
17#if PLUGIFY_PLATFORM_WINDOWS
20#elif PLUGIFY_PLATFORM_SWITCH
21#include <nn/diag/diag_Debugger.h>
22#elif PLUGIFY_PLATFORM_ORBIS || PLUGIFY_PLATFORM_PROSPERO
24#elif PLUGIFY_PLATFORM_APPLE
25#include <mach/mach_init.h>
27#elif PLUGIFY_PLATFORM_LINUX
36#if PLUGIFY_PLATFORM_WINDOWS
38 inline bool is_debugger_present() noexcept {
39 return (IsDebuggerPresent() != FALSE);
42#elif PLUGIFY_PLATFORM_SWITCH
44 inline bool is_debugger_present() noexcept {
45 return nn::diag::IsDebuggerAttached();
48#elif PLUGIFY_PLATFORM_ORBIS || PLUGIFY_PLATFORM_PROSPERO
50 inline bool is_debugger_present() noexcept {
51 return sceDbgIsDebuggerAttached() != 0;
54#elif PLUGIFY_PLATFORM_APPLE
56 inline bool is_debugger_present() noexcept {
57 mach_msg_type_number_t count = 0;
58 exception_mask_t masks[EXC_TYPES_COUNT];
59 mach_port_t ports[EXC_TYPES_COUNT];
60 exception_behavior_t behaviors[EXC_TYPES_COUNT];
61 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
62 exception_mask_t mask = EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD);
64 kern_return_t result = task_get_exception_ports(mach_task_self(), mask, masks, &count, ports, behaviors, flavors);
65 if (result != KERN_SUCCESS)
68 for (mach_msg_type_number_t i = 0; i < count; ++i)
69 if (MACH_PORT_VALID(ports[i]))
75#elif PLUGIFY_PLATFORM_LINUX
79 inline bool parse_proc_status_line(
char* buf,
size_t size)
noexcept {
80 if (std::strncmp(buf,
"TracerPid:\t", 11) != 0) {
83 unsigned long long pid = 0;
86 auto byte =
static_cast<unsigned char>(buf[pos]);
87 if (!(
static_cast<unsigned char>(
'0') <=
byte &&
byte <=
static_cast<unsigned char>(
'9'))) {
90 uint8_t digit =
static_cast<uint8_t
>(
byte -
static_cast<unsigned char>(
'0'));
91 pid = (pid * 10) + digit;
97 inline bool parse_proc_status() noexcept {
99 bool detected_debugger =
false;
102 bool open_done =
false;
104 int res = open(
"/proc/self/status", O_RDONLY);
108 }
else if (errno != EINTR) {
123 size_t iobuf_size = 0;
125 size_t linebuf_size = 0;
127 ssize_t bytes_read = read(fd, iobuf,
sizeof(iobuf));
128 if (bytes_read == -1) {
129 if (errno == EINTR) {
132 }
else if (bytes_read == 0) {
135 iobuf_size =
static_cast<size_t>(bytes_read);
136 for (
size_t i = 0; i < iobuf_size; ++i) {
137 if (iobuf[i] ==
static_cast<unsigned char>(
'\n')) {
138 if (parse_proc_status_line(linebuf, linebuf_size)) {
139 detected_debugger =
true;
143 if (linebuf_size <
sizeof(linebuf)) {
144 linebuf[linebuf_size] =
static_cast<char>(iobuf[i]);
149 if (linebuf_size > 0) {
150 if (parse_proc_status_line(linebuf, linebuf_size)) {
151 detected_debugger =
true;
156 bool close_done =
false;
157 while (!close_done) {
162 }
else if (errno != EINTR) {
172 return detected_debugger;
178 inline bool is_debugger_present() noexcept {
179 return plg::detail::debugging::parse_proc_status();
184 inline bool is_debugger_present() noexcept {
190 inline void breakpoint() noexcept {
191#if PLUGIFY_COMPILER_MSVC
193#elif PLUGIFY_COMPILER_CLANG
194 __builtin_debugtrap();
195#elif PLUGIFY_COMPILER_GCC
198# error "Unsupported platform for breakpoint"
202 inline void breakpoint_if_debugging() noexcept {
203 if (plg::is_debugger_present()) {
210 using plg::breakpoint;
211 using plg::breakpoint_if_debugging;
212 using plg::is_debugger_present;