ZeroErr
Loading...
Searching...
No Matches
debugbreak.h
Go to the documentation of this file.
1/* Copyright (c) 2011-2021, Scott Tsai
2 *
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26#ifndef DEBUG_BREAK_H
27#define DEBUG_BREAK_H
28
29#ifdef _MSC_VER
30
31#define debug_break __debugbreak
32
33#else
34
35#ifdef __cplusplus
36extern "C" {
37#endif
38
39#define DEBUG_BREAK_USE_TRAP_INSTRUCTION 1
40#define DEBUG_BREAK_USE_BULTIN_TRAP 2
41#define DEBUG_BREAK_USE_SIGTRAP 3
42
43#if defined(__i386__) || defined(__x86_64__)
44#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
45__inline__ static void trap_instruction(void) { __asm__ volatile("int $0x03"); }
46#elif defined(__thumb__)
47#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
48/* FIXME: handle __THUMB_INTERWORK__ */
49__attribute__((always_inline)) __inline__ static void trap_instruction(void) {
50 /* See 'arm-linux-tdep.c' in GDB source.
51 * Both instruction sequences below work. */
52#if 1
53 /* 'eabi_linux_thumb_le_breakpoint' */
54 __asm__ volatile(".inst 0xde01");
55#else
56 /* 'eabi_linux_thumb2_le_breakpoint' */
57 __asm__ volatile(".inst.w 0xf7f0a000");
58#endif
59
60 /* Known problem:
61 * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB.
62 * 'step' would keep getting stuck on the same instruction.
63 *
64 * Workaround: use the new GDB commands 'debugbreak-step' and
65 * 'debugbreak-continue' that become available
66 * after you source the script from GDB:
67 *
68 * $ gdb -x debugbreak-gdb.py <... USUAL ARGUMENTS ...>
69 *
70 * 'debugbreak-step' would jump over the breakpoint instruction with
71 * roughly equivalent of:
72 * (gdb) set $instruction_len = 2
73 * (gdb) tbreak *($pc + $instruction_len)
74 * (gdb) jump *($pc + $instruction_len)
75 */
76}
77#elif defined(__arm__) && !defined(__thumb__)
78#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
79__attribute__((always_inline)) __inline__ static void trap_instruction(void) {
80 /* See 'arm-linux-tdep.c' in GDB source,
81 * 'eabi_linux_arm_le_breakpoint' */
82 __asm__ volatile(".inst 0xe7f001f0");
83 /* Known problem:
84 * Same problem and workaround as Thumb mode */
85}
86#elif defined(__aarch64__) && defined(__APPLE__)
87#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_BULTIN_DEBUGTRAP
88#elif defined(__aarch64__)
89#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
90__attribute__((always_inline)) __inline__ static void trap_instruction(void) {
91 /* See 'aarch64-tdep.c' in GDB source,
92 * 'aarch64_default_breakpoint' */
93 __asm__ volatile(".inst 0xd4200000");
94}
95#elif defined(__powerpc__)
96/* PPC 32 or 64-bit, big or little endian */
97#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
98__attribute__((always_inline)) __inline__ static void trap_instruction(void) {
99 /* See 'rs6000-tdep.c' in GDB source,
100 * 'rs6000_breakpoint' */
101 __asm__ volatile(".4byte 0x7d821008");
102
103 /* Known problem:
104 * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB.
105 * 'step' stuck on the same instruction ("twge r2,r2").
106 *
107 * The workaround is the same as ARM Thumb mode: use debugbreak-gdb.py
108 * or manually jump over the instruction. */
109}
110#elif defined(__riscv)
111/* RISC-V 32 or 64-bit, whether the "C" extension
112 * for compressed, 16-bit instructions are supported or not */
113#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION
114__attribute__((always_inline)) __inline__ static void trap_instruction(void) {
115 /* See 'riscv-tdep.c' in GDB source,
116 * 'riscv_sw_breakpoint_from_kind' */
117 __asm__ volatile(".4byte 0x00100073");
118}
119#else
120#define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_SIGTRAP
121#endif
122
123
124#ifndef DEBUG_BREAK_IMPL
125#error "debugbreak.h is not supported on this target"
126#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_TRAP_INSTRUCTION
127__attribute__((always_inline)) __inline__ static void debug_break(void) { trap_instruction(); }
128#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_DEBUGTRAP
129__attribute__((always_inline)) __inline__ static void debug_break(void) { __builtin_debugtrap(); }
130#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_TRAP
131__attribute__((always_inline)) __inline__ static void debug_break(void) { __builtin_trap(); }
132#elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_SIGTRAP
133#include <signal.h>
134__attribute__((always_inline)) __inline__ static void debug_break(void) { raise(SIGTRAP); }
135#else
136#error "invalid DEBUG_BREAK_IMPL value"
137#endif
138
139#ifdef __cplusplus
140}
141#endif
142
143#endif /* ifdef _MSC_VER */
144
145
146// Here is for checking the debugger is running
147
148#include <fstream>
149
150#ifdef IS_DEBUGGER_ACTIVE
151__attribute__((always_inline)) __inline__ static bool isDebuggerActive() {
152 return IS_DEBUGGER_ACTIVE();
153}
154#else // IS_DEBUGGER_ACTIVE
155#ifdef __linux__
156class ErrnoGuard {
157public:
158 ErrnoGuard() : m_oldErrno(errno) {}
159 ~ErrnoGuard() { errno = m_oldErrno; }
160
161private:
162 int m_oldErrno;
163};
164// See the comments in Catch2 for the reasoning behind this implementation:
165// https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102
166__attribute__((always_inline)) __inline__ static bool isDebuggerActive() {
167 ErrnoGuard guard;
168 std::ifstream in("/proc/self/status");
169 for (std::string line; std::getline(in, line);) {
170 static const int PREFIX_LEN = 11;
171 if (line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) {
172 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
173 }
174 }
175 return false;
176}
177#elif defined(__APPLE__)
178// The following function is taken directly from the following technical note:
179// https://developer.apple.com/library/archive/qa/qa1361/_index.html
180// Returns true if the current process is being debugged (either
181// running under the debugger or has a debugger attached post facto).
182__attribute__((always_inline)) __inline__ static bool isDebuggerActive() {
183 int mib[4];
184 kinfo_proc info;
185 size_t size;
186 // Initialize the flags so that, if sysctl fails for some bizarre
187 // reason, we get a predictable result.
188 info.kp_proc.p_flag = 0;
189 // Initialize mib, which tells sysctl the info we want, in this case
190 // we're looking for information about a specific process ID.
191 mib[0] = CTL_KERN;
192 mib[1] = KERN_PROC;
193 mib[2] = KERN_PROC_PID;
194 mib[3] = getpid();
195 // Call sysctl.
196 size = sizeof(info);
197 if (sysctl(mib, (sizeof(mib) / sizeof(*mib)), &info, &size, 0, 0) != 0) {
198 std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n";
199 return false;
200 }
201 // We're being debugged if the P_TRACED flag is set.
202 return ((info.kp_proc.p_flag & P_TRACED) != 0);
203}
204#elif defined(__MINGW32__) || defined(__MINGW64__)
205extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
206__attribute__((always_inline)) __inline__ static bool isDebuggerActive() {
207 return ::IsDebuggerPresent() != 0;
208}
209#elif defined(_MSC_VER)
210extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
211inline __forceinline static bool isDebuggerActive() {
212 return ::IsDebuggerPresent() != 0;
213}
214#else
215
216__attribute__((always_inline)) __inline__ static bool isDebuggerActive() { return false; }
217#endif
218#endif // IS_DEBUGGER_ACTIVE
219
220
221#endif /* ifndef DEBUG_BREAK_H */
__attribute__((always_inline)) __inline__ static void debug_break(void)
Definition debugbreak.h:134