]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/nat/aarch64-linux-hw-point.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / nat / aarch64-linux-hw-point.c
1 /* Copyright (C) 2009-2024 Free Software Foundation, Inc.
2 Contributed by ARM Ltd.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #include "gdbsupport/common-defs.h"
20 #include "gdbsupport/break-common.h"
21 #include "gdbsupport/common-regcache.h"
22 #include "nat/linux-nat.h"
23 #include "aarch64-linux-hw-point.h"
24
25 #include <sys/uio.h>
26
27 /* The order in which <sys/ptrace.h> and <asm/ptrace.h> are included
28 can be important. <sys/ptrace.h> often declares various PTRACE_*
29 enums. <asm/ptrace.h> often defines preprocessor constants for
30 these very same symbols. When that's the case, build errors will
31 result when <asm/ptrace.h> is included before <sys/ptrace.h>. */
32 #include <sys/ptrace.h>
33 #include <asm/ptrace.h>
34
35 #include <elf.h>
36
37 /* See aarch64-linux-hw-point.h */
38
39 bool kernel_supports_any_contiguous_range = true;
40
41 /* Helper for aarch64_notify_debug_reg_change. Records the
42 information about the change of one hardware breakpoint/watchpoint
43 setting for the thread LWP.
44 N.B. The actual updating of hardware debug registers is not
45 carried out until the moment the thread is resumed. */
46
47 static int
48 debug_reg_change_callback (struct lwp_info *lwp, int is_watchpoint,
49 unsigned int idx)
50 {
51 int tid = ptid_of_lwp (lwp).lwp ();
52 struct arch_lwp_info *info = lwp_arch_private_info (lwp);
53 dr_changed_t *dr_changed_ptr;
54 dr_changed_t dr_changed;
55
56 if (info == NULL)
57 {
58 info = XCNEW (struct arch_lwp_info);
59 lwp_set_arch_private_info (lwp, info);
60 }
61
62 if (show_debug_regs)
63 {
64 debug_printf ("debug_reg_change_callback: \n\tOn entry:\n");
65 debug_printf ("\ttid%d, dr_changed_bp=0x%s, "
66 "dr_changed_wp=0x%s\n", tid,
67 phex (info->dr_changed_bp, 8),
68 phex (info->dr_changed_wp, 8));
69 }
70
71 dr_changed_ptr = is_watchpoint ? &info->dr_changed_wp
72 : &info->dr_changed_bp;
73 dr_changed = *dr_changed_ptr;
74
75 gdb_assert (idx >= 0
76 && (idx <= (is_watchpoint ? aarch64_num_wp_regs
77 : aarch64_num_bp_regs)));
78
79 /* The actual update is done later just before resuming the lwp,
80 we just mark that one register pair needs updating. */
81 DR_MARK_N_CHANGED (dr_changed, idx);
82 *dr_changed_ptr = dr_changed;
83
84 /* If the lwp isn't stopped, force it to momentarily pause, so
85 we can update its debug registers. */
86 if (!lwp_is_stopped (lwp))
87 linux_stop_lwp (lwp);
88
89 if (show_debug_regs)
90 {
91 debug_printf ("\tOn exit:\n\ttid%d, dr_changed_bp=0x%s, "
92 "dr_changed_wp=0x%s\n", tid,
93 phex (info->dr_changed_bp, 8),
94 phex (info->dr_changed_wp, 8));
95 }
96
97 return 0;
98 }
99
100 /* Notify each thread that their IDXth breakpoint/watchpoint register
101 pair needs to be updated. The message will be recorded in each
102 thread's arch-specific data area, the actual updating will be done
103 when the thread is resumed. */
104
105 void
106 aarch64_notify_debug_reg_change (ptid_t ptid,
107 int is_watchpoint, unsigned int idx)
108 {
109 ptid_t pid_ptid = ptid_t (ptid.pid ());
110
111 iterate_over_lwps (pid_ptid, [=] (struct lwp_info *info)
112 {
113 return debug_reg_change_callback (info,
114 is_watchpoint,
115 idx);
116 });
117 }
118
119 /* Reconfigure STATE to be compatible with Linux kernels with the PR
120 external/20207 bug. This is called when
121 KERNEL_SUPPORTS_ANY_CONTIGUOUS_RANGE transitions to false. Note we
122 don't try to support combining watchpoints with matching (and thus
123 shared) masks, as it's too late when we get here. On buggy
124 kernels, GDB will try to first setup the perfect matching ranges,
125 which will run out of registers before this function can merge
126 them. It doesn't look like worth the effort to improve that, given
127 eventually buggy kernels will be phased out. */
128
129 static void
130 aarch64_downgrade_regs (struct aarch64_debug_reg_state *state)
131 {
132 for (int i = 0; i < aarch64_num_wp_regs; ++i)
133 if ((state->dr_ctrl_wp[i] & 1) != 0)
134 {
135 gdb_assert (state->dr_ref_count_wp[i] != 0);
136 uint8_t mask_orig = (state->dr_ctrl_wp[i] >> 5) & 0xff;
137 gdb_assert (mask_orig != 0);
138 static const uint8_t old_valid[] = { 0x01, 0x03, 0x0f, 0xff };
139 uint8_t mask = 0;
140 for (const uint8_t old_mask : old_valid)
141 if (mask_orig <= old_mask)
142 {
143 mask = old_mask;
144 break;
145 }
146 gdb_assert (mask != 0);
147
148 /* No update needed for this watchpoint? */
149 if (mask == mask_orig)
150 continue;
151 state->dr_ctrl_wp[i] |= mask << 5;
152 state->dr_addr_wp[i]
153 = align_down (state->dr_addr_wp[i], AARCH64_HWP_ALIGNMENT);
154
155 /* Try to match duplicate entries. */
156 for (int j = 0; j < i; ++j)
157 if ((state->dr_ctrl_wp[j] & 1) != 0
158 && state->dr_addr_wp[j] == state->dr_addr_wp[i]
159 && state->dr_addr_orig_wp[j] == state->dr_addr_orig_wp[i]
160 && state->dr_ctrl_wp[j] == state->dr_ctrl_wp[i])
161 {
162 state->dr_ref_count_wp[j] += state->dr_ref_count_wp[i];
163 state->dr_ref_count_wp[i] = 0;
164 state->dr_addr_wp[i] = 0;
165 state->dr_addr_orig_wp[i] = 0;
166 state->dr_ctrl_wp[i] &= ~1;
167 break;
168 }
169
170 aarch64_notify_debug_reg_change (current_lwp_ptid (),
171 1 /* is_watchpoint */, i);
172 }
173 }
174
175 /* Call ptrace to set the thread TID's hardware breakpoint/watchpoint
176 registers with data from *STATE. */
177
178 void
179 aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state *state,
180 int tid, int watchpoint)
181 {
182 int i, count;
183 struct iovec iov;
184 struct user_hwdebug_state regs;
185 const CORE_ADDR *addr;
186 const unsigned int *ctrl;
187
188 memset (&regs, 0, sizeof (regs));
189 iov.iov_base = &regs;
190 count = watchpoint ? aarch64_num_wp_regs : aarch64_num_bp_regs;
191 addr = watchpoint ? state->dr_addr_wp : state->dr_addr_bp;
192 ctrl = watchpoint ? state->dr_ctrl_wp : state->dr_ctrl_bp;
193 if (count == 0)
194 return;
195 iov.iov_len = (offsetof (struct user_hwdebug_state, dbg_regs)
196 + count * sizeof (regs.dbg_regs[0]));
197
198 for (i = 0; i < count; i++)
199 {
200 regs.dbg_regs[i].addr = addr[i];
201 regs.dbg_regs[i].ctrl = ctrl[i];
202 }
203
204 if (ptrace (PTRACE_SETREGSET, tid,
205 watchpoint ? NT_ARM_HW_WATCH : NT_ARM_HW_BREAK,
206 (void *) &iov))
207 {
208 /* Handle Linux kernels with the PR external/20207 bug. */
209 if (watchpoint && errno == EINVAL
210 && kernel_supports_any_contiguous_range)
211 {
212 kernel_supports_any_contiguous_range = false;
213 aarch64_downgrade_regs (state);
214 aarch64_linux_set_debug_regs (state, tid, watchpoint);
215 return;
216 }
217 error (_("Unexpected error setting hardware debug registers"));
218 }
219 }
220
221 /* Return true if debug arch level is compatible for hw watchpoints
222 and breakpoints. */
223
224 static bool
225 compatible_debug_arch (unsigned int debug_arch)
226 {
227 if (debug_arch == AARCH64_DEBUG_ARCH_V8)
228 return true;
229 if (debug_arch == AARCH64_DEBUG_ARCH_V8_1)
230 return true;
231 if (debug_arch == AARCH64_DEBUG_ARCH_V8_2)
232 return true;
233 if (debug_arch == AARCH64_DEBUG_ARCH_V8_4)
234 return true;
235 if (debug_arch == AARCH64_DEBUG_ARCH_V8_8)
236 return true;
237 if (debug_arch == AARCH64_DEBUG_ARCH_V8_9)
238 return true;
239
240 return false;
241 }
242
243 /* Get the hardware debug register capacity information from the
244 process represented by TID. */
245
246 void
247 aarch64_linux_get_debug_reg_capacity (int tid)
248 {
249 struct iovec iov;
250 struct user_hwdebug_state dreg_state;
251
252 iov.iov_base = &dreg_state;
253 iov.iov_len = sizeof (dreg_state);
254
255 /* Get hardware watchpoint register info. */
256 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_HW_WATCH, &iov) == 0
257 && compatible_debug_arch (AARCH64_DEBUG_ARCH (dreg_state.dbg_info)))
258 {
259 aarch64_num_wp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
260 if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
261 {
262 warning (_("Unexpected number of hardware watchpoint registers"
263 " reported by ptrace, got %d, expected %d."),
264 aarch64_num_wp_regs, AARCH64_HWP_MAX_NUM);
265 aarch64_num_wp_regs = AARCH64_HWP_MAX_NUM;
266 }
267 }
268 else
269 {
270 warning (_("Unable to determine the number of hardware watchpoints"
271 " available."));
272 aarch64_num_wp_regs = 0;
273 }
274
275 /* Get hardware breakpoint register info. */
276 if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_HW_BREAK, &iov) == 0
277 && compatible_debug_arch (AARCH64_DEBUG_ARCH (dreg_state.dbg_info)))
278 {
279 aarch64_num_bp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
280 if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
281 {
282 warning (_("Unexpected number of hardware breakpoint registers"
283 " reported by ptrace, got %d, expected %d."),
284 aarch64_num_bp_regs, AARCH64_HBP_MAX_NUM);
285 aarch64_num_bp_regs = AARCH64_HBP_MAX_NUM;
286 }
287 }
288 else
289 {
290 warning (_("Unable to determine the number of hardware breakpoints"
291 " available."));
292 aarch64_num_bp_regs = 0;
293 }
294 }