plugify 1.2.6
Loading...
Searching...
No Matches
debugging.hpp
1#pragma once
2
3#include "macro.hpp"
4
5#if PLUGIFY_STACKTRACE_SUPPORT
6
7#include <debugging>
8
9#else // PLUGIFY_STACKTRACE_SUPPORT
10
11#if PLUGIFY_PLATFORM_WINDOWS
12#include <windows.h>
13#include <intrin.h>
14#elif PLUGIFY_PLATFORM_SWITCH
15#include <nn/diag/diag_Debugger.h>
16#elif PLUGIFY_PLATFORM_ORBIS || PLUGIFY_PLATFORM_PROSPERO
17#include <libdbg.h>
18#elif PLUGIFY_PLATFORM_APPLE
19#include <mach/mach_init.h>
20#include <mach/task.h>
21#elif PLUGIFY_PLATFORM_LINUX
22#include <cerrno>
23#include <cstring>
24#include <fcntl.h>
25#include <unistd.h>
26#endif
27
28#endif // PLUGIFY_STACKTRACE_SUPPORT
29
30namespace plg {
31#if PLUGIFY_STACKTRACE_SUPPORT
32
33 using std::breakpoint;
34 using std::breakpoint_if_debugging;
35 using std::is_debugger_present;
36
37#else // PLUGIFY_STACKTRACE_SUPPORT
38
39#if PLUGIFY_PLATFORM_WINDOWS
40
41 inline bool is_debugger_present() noexcept {
42 return (IsDebuggerPresent() != FALSE);
43 }
44
45#elif PLUGIFY_PLATFORM_SWITCH
46
47 inline bool is_debugger_present() noexcept {
48 return nn::diag::IsDebuggerAttached();
49 }
50
51#elif PLUGIFY_PLATFORM_ORBIS || PLUGIFY_PLATFORM_PROSPERO
52
53 inline bool is_debugger_present() noexcept {
54 return sceDbgIsDebuggerAttached() != 0;
55 }
56
57#elif PLUGIFY_PLATFORM_APPLE
58
59 inline bool is_debugger_present() noexcept {
60 mach_msg_type_number_t count = 0;
61 exception_mask_t masks[EXC_TYPES_COUNT];
62 mach_port_t ports[EXC_TYPES_COUNT];
63 exception_behavior_t behaviors[EXC_TYPES_COUNT];
64 thread_state_flavor_t flavors[EXC_TYPES_COUNT];
65 exception_mask_t mask = EXC_MASK_ALL & ~(EXC_MASK_RESOURCE | EXC_MASK_GUARD);
66
67 kern_return_t result = task_get_exception_ports(mach_task_self(), mask, masks, &count, ports, behaviors, flavors);
68 if (result != KERN_SUCCESS)
69 return false;
70
71 for (mach_msg_type_number_t i = 0; i < count; ++i)
72 if (MACH_PORT_VALID(ports[i]))
73 return true;
74
75 return false;
76 }
77
78#elif PLUGIFY_PLATFORM_LINUX
79
80 namespace detail {
81 namespace debugging {
82 inline bool parse_proc_status_line(char* buf, size_t size) noexcept {
83 if (std::strncmp(buf, "TracerPid:\t", 11) != 0) {
84 return false;
85 }
86 unsigned long long pid = 0;
87 size_t pos = 11;
88 while (pos < size) {
89 auto byte = static_cast<unsigned char>(buf[pos]);
90 if (!(static_cast<unsigned char>('0') <= byte && byte <= static_cast<unsigned char>('9'))) {
91 return false;
92 }
93 uint8_t digit = static_cast<uint8_t>(byte - static_cast<unsigned char>('0'));
94 pid = (pid * 10) + digit;
95 pos++;
96 }
97 return (pid != 0);
98 }
99
100 inline bool parse_proc_status() noexcept {
101 int olderrno = errno;
102 bool detected_debugger = false;
103 int error = 0;
104 int fd = -1;
105 bool open_done = false;
106 while (!open_done) {
107 int res = open("/proc/self/status", O_RDONLY);
108 if (res >= 0) {
109 fd = res;
110 open_done = true;
111 } else if (errno != EINTR) {
112 error = errno;
113 open_done = true;
114 }
115 }
116 if (error != 0) {
117 errno = olderrno;
118 return false;
119 }
120 if (fd < 0) {
121 errno = olderrno;
122 return false;
123 }
124 bool eof = false;
125 uint8_t iobuf[1024];
126 size_t iobuf_size = 0;
127 char linebuf[128];
128 size_t linebuf_size = 0;
129 while (!eof) {
130 ssize_t bytes_read = read(fd, iobuf, sizeof(iobuf));
131 if (bytes_read == -1) {
132 if (errno == EINTR) {
133 continue;
134 }
135 } else if (bytes_read == 0) {
136 eof = true;
137 }
138 iobuf_size = static_cast<size_t>(bytes_read);
139 for (size_t i = 0; i < iobuf_size; ++i) {
140 if (iobuf[i] == static_cast<unsigned char>('\n')) {
141 if (parse_proc_status_line(linebuf, linebuf_size)) {
142 detected_debugger = true;
143 }
144 linebuf_size = 0;
145 } else {
146 if (linebuf_size < sizeof(linebuf)) {
147 linebuf[linebuf_size] = static_cast<char>(iobuf[i]);
148 linebuf_size++;
149 }
150 }
151 }
152 if (linebuf_size > 0) {
153 if (parse_proc_status_line(linebuf, linebuf_size)) {
154 detected_debugger = true;
155 }
156 linebuf_size = 0;
157 }
158 }
159 bool close_done = false;
160 while (!close_done) {
161 int res = close(fd);
162 if (res == 0) {
163 fd = -1;
164 close_done = true;
165 } else if (errno != EINTR) {
166 error = errno;
167 close_done = true;
168 }
169 }
170 if (error != 0) {
171 errno = olderrno;
172 return false;
173 }
174 errno = olderrno;
175 return detected_debugger;
176 }
177
178 } // namespace debugging
179 } // namespace detail
180
181 PLUGIFY_NOINLINE inline bool is_debugger_present() noexcept {
182 return plg::detail::debugging::parse_proc_status();
183 }
184
185#else
186
187 inline bool is_debugger_present() noexcept {
188 return false;
189 }
190
191#endif
192
193 PLUGIFY_FORCE_INLINE void breakpoint() noexcept {
194#if PLUGIFY_COMPILER_MSVC
195 __debugbreak();
196#elif PLUGIFY_COMPILER_CLANG
197 __builtin_debugtrap();
198#elif PLUGIFY_COMPILER_GCC
199 __builtin_trap();
200#else
201# error "Unsupported platform for breakpoint"
202#endif
203 }
204
205 PLUGIFY_FORCE_INLINE void breakpoint_if_debugging() noexcept {
206 if (plg::is_debugger_present()) {
207 plg::breakpoint();
208 }
209 }
210
211#endif // PLUGIFY_STACKTRACE_SUPPORT
212} // namespace plg