xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/nat/mips-linux-watch.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Copyright (C) 2009-2016 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 "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 (__FILE__, __LINE__,
36 		      _("Unrecognized watch register style"));
37     }
38 }
39 
40 /* Assuming usable watch registers REGS, return the reg_mask of
41    register N.  */
42 
43 static uint32_t
44 get_reg_mask (struct pt_watch_regs *regs, int n)
45 {
46   switch (regs->style)
47     {
48     case pt_watch_style_mips32:
49       return regs->mips32.watch_masks[n] & ~IRW_MASK;
50     case pt_watch_style_mips64:
51       return regs->mips64.watch_masks[n] & ~IRW_MASK;
52     default:
53       internal_error (__FILE__, __LINE__,
54 		      _("Unrecognized watch register style"));
55     }
56 }
57 
58 /* Assuming usable watch registers REGS, return the num_valid.  */
59 
60 uint32_t
61 mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
62 {
63   switch (regs->style)
64     {
65     case pt_watch_style_mips32:
66       return regs->mips32.num_valid;
67     case pt_watch_style_mips64:
68       return regs->mips64.num_valid;
69     default:
70       internal_error (__FILE__, __LINE__,
71 		      _("Unrecognized watch register style"));
72     }
73 }
74 
75 /* Assuming usable watch registers REGS, return the watchlo of
76    register N.  */
77 
78 CORE_ADDR
79 mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
80 {
81   switch (regs->style)
82     {
83     case pt_watch_style_mips32:
84       return regs->mips32.watchlo[n];
85     case pt_watch_style_mips64:
86       return regs->mips64.watchlo[n];
87     default:
88       internal_error (__FILE__, __LINE__,
89 		      _("Unrecognized watch register style"));
90     }
91 }
92 
93 /* Assuming usable watch registers REGS, set watchlo of register N to
94    VALUE.  */
95 
96 void
97 mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
98 			      CORE_ADDR value)
99 {
100   switch (regs->style)
101     {
102     case pt_watch_style_mips32:
103       /*  The cast will never throw away bits as 64 bit addresses can
104 	  never be used on a 32 bit kernel.  */
105       regs->mips32.watchlo[n] = (uint32_t) value;
106       break;
107     case pt_watch_style_mips64:
108       regs->mips64.watchlo[n] = value;
109       break;
110     default:
111       internal_error (__FILE__, __LINE__,
112 		      _("Unrecognized watch register style"));
113     }
114 }
115 
116 /* Assuming usable watch registers REGS, return the watchhi of
117    register N.  */
118 
119 uint32_t
120 mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
121 {
122   switch (regs->style)
123     {
124     case pt_watch_style_mips32:
125       return regs->mips32.watchhi[n];
126     case pt_watch_style_mips64:
127       return regs->mips64.watchhi[n];
128     default:
129       internal_error (__FILE__, __LINE__,
130 		      _("Unrecognized watch register style"));
131     }
132 }
133 
134 /* Assuming usable watch registers REGS, set watchhi of register N to
135    VALUE.  */
136 
137 void
138 mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
139 			      uint16_t value)
140 {
141   switch (regs->style)
142     {
143     case pt_watch_style_mips32:
144       regs->mips32.watchhi[n] = value;
145       break;
146     case pt_watch_style_mips64:
147       regs->mips64.watchhi[n] = value;
148       break;
149     default:
150       internal_error (__FILE__, __LINE__,
151 		      _("Unrecognized watch register style"));
152     }
153 }
154 
155 /* Read the watch registers of process LWPID and store it in
156    WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
157    registers are valid.  Return 1 if watch registers are usable.
158    Cached information is used unless FORCE is true.  */
159 
160 int
161 mips_linux_read_watch_registers (long lwpid,
162 				 struct pt_watch_regs *watch_readback,
163 				 int *watch_readback_valid, int force)
164 {
165   if (force || *watch_readback_valid == 0)
166     {
167       if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback, NULL) == -1)
168 	{
169 	  *watch_readback_valid = -1;
170 	  return 0;
171 	}
172       switch (watch_readback->style)
173 	{
174 	case pt_watch_style_mips32:
175 	  if (watch_readback->mips32.num_valid == 0)
176 	    {
177 	      *watch_readback_valid = -1;
178 	      return 0;
179 	    }
180 	  break;
181 	case pt_watch_style_mips64:
182 	  if (watch_readback->mips64.num_valid == 0)
183 	    {
184 	      *watch_readback_valid = -1;
185 	      return 0;
186 	    }
187 	  break;
188 	default:
189 	  *watch_readback_valid = -1;
190 	  return 0;
191 	}
192       /* Watch registers appear to be usable.  */
193       *watch_readback_valid = 1;
194     }
195   return (*watch_readback_valid == 1) ? 1 : 0;
196 }
197 
198 /* Convert GDB's TYPE to an IRW mask.  */
199 
200 uint32_t
201 mips_linux_watch_type_to_irw (enum target_hw_bp_type type)
202 {
203   switch (type)
204     {
205     case hw_write:
206       return W_MASK;
207     case hw_read:
208       return R_MASK;
209     case hw_access:
210       return (W_MASK | R_MASK);
211     default:
212       return 0;
213     }
214 }
215 
216 /* Set any low order bits in MASK that are not set.  */
217 
218 static CORE_ADDR
219 fill_mask (CORE_ADDR mask)
220 {
221   CORE_ADDR f = 1;
222 
223   while (f && f < mask)
224     {
225       mask |= f;
226       f <<= 1;
227     }
228   return mask;
229 }
230 
231 /* Try to add a single watch to the specified registers REGS.  The
232    address of added watch is ADDR, the length is LEN, and the mask
233    is IRW.  Return 1 on success, 0 on failure.  */
234 
235 int
236 mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
237 				CORE_ADDR addr, int len, uint32_t irw)
238 {
239   CORE_ADDR base_addr, last_byte, break_addr, segment_len;
240   CORE_ADDR mask_bits, t_low;
241   uint16_t t_hi;
242   int i, free_watches;
243   struct pt_watch_regs regs_copy;
244 
245   if (len <= 0)
246     return 0;
247 
248   last_byte = addr + len - 1;
249   mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
250   base_addr = addr & ~mask_bits;
251 
252   /* Check to see if it is covered by current registers.  */
253   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
254     {
255       t_low = mips_linux_watch_get_watchlo (regs, i);
256       if (t_low != 0 && irw == ((uint32_t) t_low & irw))
257 	{
258 	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
259 	  t_low &= ~(CORE_ADDR) t_hi;
260 	  if (addr >= t_low && last_byte <= (t_low + t_hi))
261 	    return 1;
262 	}
263     }
264   /* Try to find an empty register.  */
265   free_watches = 0;
266   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
267     {
268       t_low = mips_linux_watch_get_watchlo (regs, i);
269       if (t_low == 0
270 	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
271 	{
272 	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
273 	    {
274 	      /* It fits, we'll take it.  */
275 	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
276 	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
277 	      return 1;
278 	    }
279 	  else
280 	    {
281 	      /* It doesn't fit, but has the proper IRW capabilities.  */
282 	      free_watches++;
283 	    }
284 	}
285     }
286   if (free_watches > 1)
287     {
288       /* Try to split it across several registers.  */
289       regs_copy = *regs;
290       for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
291 	{
292 	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
293 	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
294 	  if (t_low == 0 && irw == (t_hi & irw))
295 	    {
296 	      t_low = addr & ~(CORE_ADDR) t_hi;
297 	      break_addr = t_low + t_hi + 1;
298 	      if (break_addr >= addr + len)
299 		segment_len = len;
300 	      else
301 		segment_len = break_addr - addr;
302 	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
303 	      mips_linux_watch_set_watchlo (&regs_copy, i,
304 					    (addr & ~mask_bits) | irw);
305 	      mips_linux_watch_set_watchhi (&regs_copy, i,
306 					    mask_bits & ~IRW_MASK);
307 	      if (break_addr >= addr + len)
308 		{
309 		  *regs = regs_copy;
310 		  return 1;
311 		}
312 	      len = addr + len - break_addr;
313 	      addr = break_addr;
314 	    }
315 	}
316     }
317   /* It didn't fit anywhere, we failed.  */
318   return 0;
319 }
320 
321 /* Fill in the watch registers REGS with the currently cached
322    watches CURRENT_WATCHES.  */
323 
324 void
325 mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
326 				struct pt_watch_regs *regs)
327 {
328   struct mips_watchpoint *w;
329   int i;
330 
331   /* Clear them out.  */
332   for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
333     {
334       mips_linux_watch_set_watchlo (regs, i, 0);
335       mips_linux_watch_set_watchhi (regs, i, 0);
336     }
337 
338   w = current_watches;
339   while (w)
340     {
341       uint32_t irw = mips_linux_watch_type_to_irw (w->type);
342 
343       i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
344       /* They must all fit, because we previously calculated that they
345 	 would.  */
346       gdb_assert (i);
347       w = w->next;
348     }
349 }
350