]> Git Repo - binutils.git/blob - gdb/nat/mips-linux-watch.c
Automatic date update in version.in
[binutils.git] / gdb / nat / mips-linux-watch.c
1 /* Copyright (C) 2009-2022 Free Software Foundation, Inc.
2
3    This file is part of GDB.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include "gdbsupport/common-defs.h"
19 #include "nat/gdb_ptrace.h"
20 #include "mips-linux-watch.h"
21
22 /* Assuming usable watch registers REGS, return the irw_mask of
23    register N.  */
24
25 uint32_t
26 mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
27 {
28   switch (regs->style)
29     {
30     case pt_watch_style_mips32:
31       return regs->mips32.watch_masks[n] & IRW_MASK;
32     case pt_watch_style_mips64:
33       return regs->mips64.watch_masks[n] & IRW_MASK;
34     default:
35       internal_error (_("Unrecognized watch register style"));
36     }
37 }
38
39 /* Assuming usable watch registers REGS, return the reg_mask of
40    register N.  */
41
42 static uint32_t
43 get_reg_mask (struct pt_watch_regs *regs, int n)
44 {
45   switch (regs->style)
46     {
47     case pt_watch_style_mips32:
48       return regs->mips32.watch_masks[n] & ~IRW_MASK;
49     case pt_watch_style_mips64:
50       return regs->mips64.watch_masks[n] & ~IRW_MASK;
51     default:
52       internal_error (_("Unrecognized watch register style"));
53     }
54 }
55
56 /* Assuming usable watch registers REGS, return the num_valid.  */
57
58 uint32_t
59 mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
60 {
61   switch (regs->style)
62     {
63     case pt_watch_style_mips32:
64       return regs->mips32.num_valid;
65     case pt_watch_style_mips64:
66       return regs->mips64.num_valid;
67     default:
68       internal_error (_("Unrecognized watch register style"));
69     }
70 }
71
72 /* Assuming usable watch registers REGS, return the watchlo of
73    register N.  */
74
75 CORE_ADDR
76 mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
77 {
78   switch (regs->style)
79     {
80     case pt_watch_style_mips32:
81       return regs->mips32.watchlo[n];
82     case pt_watch_style_mips64:
83       return regs->mips64.watchlo[n];
84     default:
85       internal_error (_("Unrecognized watch register style"));
86     }
87 }
88
89 /* Assuming usable watch registers REGS, set watchlo of register N to
90    VALUE.  */
91
92 void
93 mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
94                               CORE_ADDR value)
95 {
96   switch (regs->style)
97     {
98     case pt_watch_style_mips32:
99       /*  The cast will never throw away bits as 64 bit addresses can
100           never be used on a 32 bit kernel.  */
101       regs->mips32.watchlo[n] = (uint32_t) value;
102       break;
103     case pt_watch_style_mips64:
104       regs->mips64.watchlo[n] = value;
105       break;
106     default:
107       internal_error (_("Unrecognized watch register style"));
108     }
109 }
110
111 /* Assuming usable watch registers REGS, return the watchhi of
112    register N.  */
113
114 uint32_t
115 mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
116 {
117   switch (regs->style)
118     {
119     case pt_watch_style_mips32:
120       return regs->mips32.watchhi[n];
121     case pt_watch_style_mips64:
122       return regs->mips64.watchhi[n];
123     default:
124       internal_error (_("Unrecognized watch register style"));
125     }
126 }
127
128 /* Assuming usable watch registers REGS, set watchhi of register N to
129    VALUE.  */
130
131 void
132 mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
133                               uint16_t value)
134 {
135   switch (regs->style)
136     {
137     case pt_watch_style_mips32:
138       regs->mips32.watchhi[n] = value;
139       break;
140     case pt_watch_style_mips64:
141       regs->mips64.watchhi[n] = value;
142       break;
143     default:
144       internal_error (_("Unrecognized watch register style"));
145     }
146 }
147
148 /* Read the watch registers of process LWPID and store it in
149    WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
150    registers are valid.  Return 1 if watch registers are usable.
151    Cached information is used unless FORCE is true.  */
152
153 int
154 mips_linux_read_watch_registers (long lwpid,
155                                  struct pt_watch_regs *watch_readback,
156                                  int *watch_readback_valid, int force)
157 {
158   if (force || *watch_readback_valid == 0)
159     {
160       if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback, NULL) == -1)
161         {
162           *watch_readback_valid = -1;
163           return 0;
164         }
165       switch (watch_readback->style)
166         {
167         case pt_watch_style_mips32:
168           if (watch_readback->mips32.num_valid == 0)
169             {
170               *watch_readback_valid = -1;
171               return 0;
172             }
173           break;
174         case pt_watch_style_mips64:
175           if (watch_readback->mips64.num_valid == 0)
176             {
177               *watch_readback_valid = -1;
178               return 0;
179             }
180           break;
181         default:
182           *watch_readback_valid = -1;
183           return 0;
184         }
185       /* Watch registers appear to be usable.  */
186       *watch_readback_valid = 1;
187     }
188   return (*watch_readback_valid == 1) ? 1 : 0;
189 }
190
191 /* Convert GDB's TYPE to an IRW mask.  */
192
193 uint32_t
194 mips_linux_watch_type_to_irw (enum target_hw_bp_type type)
195 {
196   switch (type)
197     {
198     case hw_write:
199       return W_MASK;
200     case hw_read:
201       return R_MASK;
202     case hw_access:
203       return (W_MASK | R_MASK);
204     default:
205       return 0;
206     }
207 }
208
209 /* Set any low order bits in MASK that are not set.  */
210
211 static CORE_ADDR
212 fill_mask (CORE_ADDR mask)
213 {
214   CORE_ADDR f = 1;
215
216   while (f && f < mask)
217     {
218       mask |= f;
219       f <<= 1;
220     }
221   return mask;
222 }
223
224 /* Try to add a single watch to the specified registers REGS.  The
225    address of added watch is ADDR, the length is LEN, and the mask
226    is IRW.  Return 1 on success, 0 on failure.  */
227
228 int
229 mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
230                                 CORE_ADDR addr, int len, uint32_t irw)
231 {
232   CORE_ADDR base_addr, last_byte, break_addr, segment_len;
233   CORE_ADDR mask_bits, t_low;
234   uint16_t t_hi;
235   int i, free_watches;
236   struct pt_watch_regs regs_copy;
237
238   if (len <= 0)
239     return 0;
240
241   last_byte = addr + len - 1;
242   mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
243   base_addr = addr & ~mask_bits;
244
245   /* Check to see if it is covered by current registers.  */
246   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
247     {
248       t_low = mips_linux_watch_get_watchlo (regs, i);
249       if (t_low != 0 && irw == ((uint32_t) t_low & irw))
250         {
251           t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
252           t_low &= ~(CORE_ADDR) t_hi;
253           if (addr >= t_low && last_byte <= (t_low + t_hi))
254             return 1;
255         }
256     }
257   /* Try to find an empty register.  */
258   free_watches = 0;
259   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
260     {
261       t_low = mips_linux_watch_get_watchlo (regs, i);
262       if (t_low == 0
263           && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
264         {
265           if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
266             {
267               /* It fits, we'll take it.  */
268               mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
269               mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
270               return 1;
271             }
272           else
273             {
274               /* It doesn't fit, but has the proper IRW capabilities.  */
275               free_watches++;
276             }
277         }
278     }
279   if (free_watches > 1)
280     {
281       /* Try to split it across several registers.  */
282       regs_copy = *regs;
283       for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
284         {
285           t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
286           t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
287           if (t_low == 0 && irw == (t_hi & irw))
288             {
289               t_low = addr & ~(CORE_ADDR) t_hi;
290               break_addr = t_low + t_hi + 1;
291               if (break_addr >= addr + len)
292                 segment_len = len;
293               else
294                 segment_len = break_addr - addr;
295               mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
296               mips_linux_watch_set_watchlo (&regs_copy, i,
297                                             (addr & ~mask_bits) | irw);
298               mips_linux_watch_set_watchhi (&regs_copy, i,
299                                             mask_bits & ~IRW_MASK);
300               if (break_addr >= addr + len)
301                 {
302                   *regs = regs_copy;
303                   return 1;
304                 }
305               len = addr + len - break_addr;
306               addr = break_addr;
307             }
308         }
309     }
310   /* It didn't fit anywhere, we failed.  */
311   return 0;
312 }
313
314 /* Fill in the watch registers REGS with the currently cached
315    watches CURRENT_WATCHES.  */
316
317 void
318 mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
319                                 struct pt_watch_regs *regs)
320 {
321   struct mips_watchpoint *w;
322   int i;
323
324   /* Clear them out.  */
325   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
326     {
327       mips_linux_watch_set_watchlo (regs, i, 0);
328       mips_linux_watch_set_watchhi (regs, i, 0);
329     }
330
331   w = current_watches;
332   while (w)
333     {
334       uint32_t irw = mips_linux_watch_type_to_irw (w->type);
335
336       i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
337       /* They must all fit, because we previously calculated that they
338          would.  */
339       gdb_assert (i);
340       w = w->next;
341     }
342 }
This page took 0.046678 seconds and 4 git commands to generate.