]> Git Repo - binutils.git/blob - gdb/nat/aarch64-linux-hw-point.c
Automatic date update in version.in
[binutils.git] / gdb / nat / aarch64-linux-hw-point.c
1 /* Copyright (C) 2009-2022 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
236   return false;
237 }
238
239 /* Get the hardware debug register capacity information from the
240    process represented by TID.  */
241
242 void
243 aarch64_linux_get_debug_reg_capacity (int tid)
244 {
245   struct iovec iov;
246   struct user_hwdebug_state dreg_state;
247
248   iov.iov_base = &dreg_state;
249   iov.iov_len = sizeof (dreg_state);
250
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)))
254     {
255       aarch64_num_wp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
256       if (aarch64_num_wp_regs > AARCH64_HWP_MAX_NUM)
257         {
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;
262         }
263     }
264   else
265     {
266       warning (_("Unable to determine the number of hardware watchpoints"
267                  " available."));
268       aarch64_num_wp_regs = 0;
269     }
270
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)))
274     {
275       aarch64_num_bp_regs = AARCH64_DEBUG_NUM_SLOTS (dreg_state.dbg_info);
276       if (aarch64_num_bp_regs > AARCH64_HBP_MAX_NUM)
277         {
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;
282         }
283     }
284   else
285     {
286       warning (_("Unable to determine the number of hardware breakpoints"
287                  " available."));
288       aarch64_num_bp_regs = 0;
289     }
290 }
This page took 0.04067 seconds and 4 git commands to generate.