1 /* Copyright (C) 2009-2023 Free Software Foundation, Inc.
2 Contributed by ARM Ltd.
4 This file is part of GDB.
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.
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.
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/>. */
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"
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>
37 /* See aarch64-linux-hw-point.h */
39 bool kernel_supports_any_contiguous_range
= true;
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. */
48 debug_reg_change_callback (struct lwp_info
*lwp
, int is_watchpoint
,
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
;
58 info
= XCNEW (struct arch_lwp_info
);
59 lwp_set_arch_private_info (lwp
, info
);
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));
71 dr_changed_ptr
= is_watchpoint
? &info
->dr_changed_wp
72 : &info
->dr_changed_bp
;
73 dr_changed
= *dr_changed_ptr
;
76 && (idx
<= (is_watchpoint
? aarch64_num_wp_regs
77 : aarch64_num_bp_regs
)));
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
;
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
))
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));
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. */
106 aarch64_notify_debug_reg_change (ptid_t ptid
,
107 int is_watchpoint
, unsigned int idx
)
109 ptid_t pid_ptid
= ptid_t (ptid
.pid ());
111 iterate_over_lwps (pid_ptid
, [=] (struct lwp_info
*info
)
113 return debug_reg_change_callback (info
,
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. */
130 aarch64_downgrade_regs (struct aarch64_debug_reg_state
*state
)
132 for (int i
= 0; i
< aarch64_num_wp_regs
; ++i
)
133 if ((state
->dr_ctrl_wp
[i
] & 1) != 0)
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 };
140 for (const uint8_t old_mask
: old_valid
)
141 if (mask_orig
<= old_mask
)
146 gdb_assert (mask
!= 0);
148 /* No update needed for this watchpoint? */
149 if (mask
== mask_orig
)
151 state
->dr_ctrl_wp
[i
] |= mask
<< 5;
153 = align_down (state
->dr_addr_wp
[i
], AARCH64_HWP_ALIGNMENT
);
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
])
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;
170 aarch64_notify_debug_reg_change (current_lwp_ptid (),
171 1 /* is_watchpoint */, i
);
175 /* Call ptrace to set the thread TID's hardware breakpoint/watchpoint
176 registers with data from *STATE. */
179 aarch64_linux_set_debug_regs (struct aarch64_debug_reg_state
*state
,
180 int tid
, int watchpoint
)
184 struct user_hwdebug_state regs
;
185 const CORE_ADDR
*addr
;
186 const unsigned int *ctrl
;
188 memset (®s
, 0, sizeof (regs
));
189 iov
.iov_base
= ®s
;
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
;
195 iov
.iov_len
= (offsetof (struct user_hwdebug_state
, dbg_regs
)
196 + count
* sizeof (regs
.dbg_regs
[0]));
198 for (i
= 0; i
< count
; i
++)
200 regs
.dbg_regs
[i
].addr
= addr
[i
];
201 regs
.dbg_regs
[i
].ctrl
= ctrl
[i
];
204 if (ptrace (PTRACE_SETREGSET
, tid
,
205 watchpoint
? NT_ARM_HW_WATCH
: NT_ARM_HW_BREAK
,
208 /* Handle Linux kernels with the PR external/20207 bug. */
209 if (watchpoint
&& errno
== EINVAL
210 && kernel_supports_any_contiguous_range
)
212 kernel_supports_any_contiguous_range
= false;
213 aarch64_downgrade_regs (state
);
214 aarch64_linux_set_debug_regs (state
, tid
, watchpoint
);
217 error (_("Unexpected error setting hardware debug registers"));
221 /* Return true if debug arch level is compatible for hw watchpoints
225 compatible_debug_arch (unsigned int debug_arch
)
227 if (debug_arch
== AARCH64_DEBUG_ARCH_V8
)
229 if (debug_arch
== AARCH64_DEBUG_ARCH_V8_1
)
231 if (debug_arch
== AARCH64_DEBUG_ARCH_V8_2
)
233 if (debug_arch
== AARCH64_DEBUG_ARCH_V8_4
)
239 /* Get the hardware debug register capacity information from the
240 process represented by TID. */
243 aarch64_linux_get_debug_reg_capacity (int tid
)
246 struct user_hwdebug_state dreg_state
;
248 iov
.iov_base
= &dreg_state
;
249 iov
.iov_len
= sizeof (dreg_state
);
251 /* Get hardware watchpoint register info. */
252 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_HW_WATCH
, &iov
) == 0
253 && compatible_debug_arch (AARCH64_DEBUG_ARCH (dreg_state
.dbg_info
)))
255 aarch64_num_wp_regs
= AARCH64_DEBUG_NUM_SLOTS (dreg_state
.dbg_info
);
256 if (aarch64_num_wp_regs
> AARCH64_HWP_MAX_NUM
)
258 warning (_("Unexpected number of hardware watchpoint registers"
259 " reported by ptrace, got %d, expected %d."),
260 aarch64_num_wp_regs
, AARCH64_HWP_MAX_NUM
);
261 aarch64_num_wp_regs
= AARCH64_HWP_MAX_NUM
;
266 warning (_("Unable to determine the number of hardware watchpoints"
268 aarch64_num_wp_regs
= 0;
271 /* Get hardware breakpoint register info. */
272 if (ptrace (PTRACE_GETREGSET
, tid
, NT_ARM_HW_BREAK
, &iov
) == 0
273 && compatible_debug_arch (AARCH64_DEBUG_ARCH (dreg_state
.dbg_info
)))
275 aarch64_num_bp_regs
= AARCH64_DEBUG_NUM_SLOTS (dreg_state
.dbg_info
);
276 if (aarch64_num_bp_regs
> AARCH64_HBP_MAX_NUM
)
278 warning (_("Unexpected number of hardware breakpoint registers"
279 " reported by ptrace, got %d, expected %d."),
280 aarch64_num_bp_regs
, AARCH64_HBP_MAX_NUM
);
281 aarch64_num_bp_regs
= AARCH64_HBP_MAX_NUM
;
286 warning (_("Unable to determine the number of hardware breakpoints"
288 aarch64_num_bp_regs
= 0;