1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
|
/* Copyright (C) 2011-2024 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef NAT_LINUX_PTRACE_H
#define NAT_LINUX_PTRACE_H
#include "nat/gdb_ptrace.h"
#include "gdbsupport/gdb_wait.h"
#ifdef __UCLIBC__
#if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__))
/* PTRACE_TEXT_ADDR and friends. */
#include <asm/ptrace.h>
#define HAS_NOMMU
#endif
#endif
#if !defined(PTRACE_TYPE_ARG3)
#define PTRACE_TYPE_ARG3 void *
#endif
#if !defined(PTRACE_TYPE_ARG4)
#define PTRACE_TYPE_ARG4 void *
#endif
#ifndef PTRACE_GETSIGINFO
# define PTRACE_GETSIGINFO 0x4202
# define PTRACE_SETSIGINFO 0x4203
#endif /* PTRACE_GETSIGINF */
#ifndef PTRACE_GETREGSET
#define PTRACE_GETREGSET 0x4204
#endif
#ifndef PTRACE_SETREGSET
#define PTRACE_SETREGSET 0x4205
#endif
/* If the system headers did not provide the constants, hard-code the normal
values. */
#ifndef PTRACE_EVENT_FORK
#define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
#define PTRACE_O_TRACEVFORK 0x00000004
#define PTRACE_O_TRACECLONE 0x00000008
#define PTRACE_O_TRACEEXEC 0x00000010
#define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040
/* Wait extended result codes for the above trace options. */
#define PTRACE_EVENT_FORK 1
#define PTRACE_EVENT_VFORK 2
#define PTRACE_EVENT_CLONE 3
#define PTRACE_EVENT_EXEC 4
#define PTRACE_EVENT_VFORK_DONE 5
#define PTRACE_EVENT_EXIT 6
#endif /* PTRACE_EVENT_FORK */
#ifndef PTRACE_O_EXITKILL
/* Only defined in Linux Kernel 3.8 or later. */
#define PTRACE_O_EXITKILL 0x00100000
#endif
#if (defined __bfin__ || defined __frv__ || defined __sh__) \
&& !defined PTRACE_GETFDPIC
#define PTRACE_GETFDPIC 31
#define PTRACE_GETFDPIC_EXEC 0
#define PTRACE_GETFDPIC_INTERP 1
#endif
/* We can't always assume that this flag is available, but all systems
with the ptrace event handlers also have __WALL, so it's safe to use
in some contexts. */
#ifndef __WALL
#define __WALL 0x40000000 /* Wait for any child. */
#endif
/* Whether a breakpoint/watchpoint triggered can be determined from
the si_code of SIGTRAP's siginfo_t (TRAP_BRKPT/TRAP_HWBKPT). That
is, since the kernel can tell us whether the thread executed a
software breakpoint, we trust it. The kernel will be determining
that from the hardware (e.g., from which exception was raised in
the CPU). Relying on whether a breakpoint is planted in memory at
the time the SIGTRAP is processed to determine whether the thread
stopped for a software breakpoint can be too late. E.g., the
breakpoint could have been removed since. Or the thread could have
stepped an instruction the size of a breakpoint instruction, and
before the stop is processed a breakpoint is inserted at its
address. Getting these wrong is disastrous on decr_pc_after_break
architectures. The moribund location mechanism helps with that
somewhat but it is an heuristic, and can well fail. Getting that
information out of the kernel and ultimately out of the CPU is the
way to go. */
/* The x86 kernel gets some of the si_code values backwards, like
this:
| what | si_code |
|------------------------------------------+-------------|
| software breakpoints (int3) | SI_KERNEL |
| single-steps | TRAP_TRACE |
| single-stepping a syscall | TRAP_BRKPT |
| user sent SIGTRAP | 0 |
| exec SIGTRAP (when no PTRACE_EVENT_EXEC) | 0 |
| hardware breakpoints/watchpoints | TRAP_HWBKPT |
That is, it reports SI_KERNEL for software breakpoints (and only
for those), and TRAP_BRKPT for single-stepping a syscall... If the
kernel is ever fixed, we'll just have to detect it like we detect
optional ptrace features: by forking and debugging ourselves,
running to a breakpoint and checking what comes out of
siginfo->si_code.
The ppc kernel does use TRAP_BRKPT for software breakpoints
in PowerPC code, but it uses SI_KERNEL for software breakpoints
in SPU code on a Cell/B.E. However, SI_KERNEL is never seen
on a SIGTRAP for any other reason.
The MIPS kernel up until 4.5 used SI_KERNEL for all kernel
generated traps. Since:
- MIPS doesn't do hardware single-step.
- We don't need to care about exec SIGTRAPs --- we assume
PTRACE_EVENT_EXEC is available.
- The MIPS kernel doesn't support hardware breakpoints.
on MIPS, all we need to care about is distinguishing between
software breakpoints and hardware watchpoints, which can be done by
peeking the debug registers.
Beginning with Linux 4.6, the MIPS port reports proper TRAP_BRKPT and
TRAP_HWBKPT codes, so we also match them.
The generic Linux target code should use GDB_ARCH_IS_TRAP_* instead
of TRAP_* to abstract out these peculiarities. */
#if defined __i386__ || defined __x86_64__
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == SI_KERNEL)
# define GDB_ARCH_IS_TRAP_HWBKPT(X) ((X) == TRAP_HWBKPT)
#elif defined __powerpc__
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == SI_KERNEL || (X) == TRAP_BRKPT)
# define GDB_ARCH_IS_TRAP_HWBKPT(X) ((X) == TRAP_HWBKPT)
#elif defined __mips__
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == SI_KERNEL || (X) == TRAP_BRKPT)
# define GDB_ARCH_IS_TRAP_HWBKPT(X) ((X) == SI_KERNEL || (X) == TRAP_HWBKPT)
#else
# define GDB_ARCH_IS_TRAP_BRKPT(X) ((X) == TRAP_BRKPT)
# define GDB_ARCH_IS_TRAP_HWBKPT(X) ((X) == TRAP_HWBKPT)
#endif
#ifndef TRAP_HWBKPT
# define TRAP_HWBKPT 4
#endif
extern std::string linux_ptrace_attach_fail_reason (pid_t pid);
/* Find all possible reasons we could have failed to attach to PTID
and return them as a string. ERR is the error PTRACE_ATTACH failed
with (an errno). */
extern std::string linux_ptrace_attach_fail_reason_string (ptid_t ptid, int err);
extern void linux_ptrace_init_warnings (void);
extern void linux_check_ptrace_features (void);
extern void linux_enable_event_reporting (pid_t pid, int attached);
extern void linux_disable_event_reporting (pid_t pid);
extern int linux_ptrace_get_extended_event (int wstat);
extern int linux_is_extended_waitstatus (int wstat);
extern int linux_wstatus_maybe_breakpoint (int wstat);
#endif /* NAT_LINUX_PTRACE_H */
|