xref: /openbsd/gnu/usr.bin/binutils/gdb/s390-nat.c (revision 4cfece93)
1 /* S390 native-dependent code for GDB, the GNU debugger.
2    Copyright 2001, 2003 Free Software Foundation, Inc
3 
4    Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
5    for IBM Deutschland Entwicklung GmbH, IBM Corporation.
6 
7    This file is part of GDB.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22    02111-1307, USA.  */
23 
24 #include "defs.h"
25 #include "tm.h"
26 #include "regcache.h"
27 #include "inferior.h"
28 
29 #include "s390-tdep.h"
30 
31 #include <asm/ptrace.h>
32 #include <sys/ptrace.h>
33 #include <asm/types.h>
34 #include <sys/procfs.h>
35 #include <sys/user.h>
36 #include <sys/ucontext.h>
37 
38 
39 /* Map registers to gregset/ptrace offsets.
40    These arrays are defined in s390-tdep.c.  */
41 
42 #ifdef __s390x__
43 #define regmap_gregset s390x_regmap_gregset
44 #else
45 #define regmap_gregset s390_regmap_gregset
46 #endif
47 
48 #define regmap_fpregset s390_regmap_fpregset
49 
50 /* When debugging a 32-bit executable running under a 64-bit kernel,
51    we have to fix up the 64-bit registers we get from the kernel
52    to make them look like 32-bit registers.  */
53 #ifdef __s390x__
54 #define SUBOFF(i) \
55 	((TARGET_PTR_BIT == 32 \
56 	  && ((i) == S390_PSWA_REGNUM \
57 	      || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
58 #else
59 #define SUBOFF(i) 0
60 #endif
61 
62 
63 /* Fill GDB's register array with the general-purpose register values
64    in *REGP.  */
65 void
66 supply_gregset (gregset_t *regp)
67 {
68   int i;
69   for (i = 0; i < S390_NUM_REGS; i++)
70     if (regmap_gregset[i] != -1)
71       regcache_raw_supply (current_regcache, i,
72 			   (char *)regp + regmap_gregset[i] + SUBOFF (i));
73 }
74 
75 /* Fill register REGNO (if it is a general-purpose register) in
76    *REGP with the value in GDB's register array.  If REGNO is -1,
77    do this for all registers.  */
78 void
79 fill_gregset (gregset_t *regp, int regno)
80 {
81   int i;
82   for (i = 0; i < S390_NUM_REGS; i++)
83     if (regmap_gregset[i] != -1)
84       if (regno == -1 || regno == i)
85 	regcache_raw_collect (current_regcache, i,
86 			      (char *)regp + regmap_gregset[i] + SUBOFF (i));
87 }
88 
89 /* Fill GDB's register array with the floating-point register values
90    in *REGP.  */
91 void
92 supply_fpregset (fpregset_t *regp)
93 {
94   int i;
95   for (i = 0; i < S390_NUM_REGS; i++)
96     if (regmap_fpregset[i] != -1)
97       regcache_raw_supply (current_regcache, i,
98 			   ((char *)regp) + regmap_fpregset[i]);
99 }
100 
101 /* Fill register REGNO (if it is a general-purpose register) in
102    *REGP with the value in GDB's register array.  If REGNO is -1,
103    do this for all registers.  */
104 void
105 fill_fpregset (fpregset_t *regp, int regno)
106 {
107   int i;
108   for (i = 0; i < S390_NUM_REGS; i++)
109     if (regmap_fpregset[i] != -1)
110       if (regno == -1 || regno == i)
111         regcache_raw_collect (current_regcache, i,
112 			      ((char *)regp) + regmap_fpregset[i]);
113 }
114 
115 /* Find the TID for the current inferior thread to use with ptrace.  */
116 static int
117 s390_inferior_tid (void)
118 {
119   /* GNU/Linux LWP ID's are process ID's.  */
120   int tid = TIDGET (inferior_ptid);
121   if (tid == 0)
122     tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
123 
124   return tid;
125 }
126 
127 /* Fetch all general-purpose registers from process/thread TID and
128    store their values in GDB's register cache.  */
129 static void
130 fetch_regs (int tid)
131 {
132   gregset_t regs;
133   ptrace_area parea;
134 
135   parea.len = sizeof (regs);
136   parea.process_addr = (addr_t) &regs;
137   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
138   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
139     perror_with_name ("Couldn't get registers");
140 
141   supply_gregset (&regs);
142 }
143 
144 /* Store all valid general-purpose registers in GDB's register cache
145    into the process/thread specified by TID.  */
146 static void
147 store_regs (int tid, int regnum)
148 {
149   gregset_t regs;
150   ptrace_area parea;
151 
152   parea.len = sizeof (regs);
153   parea.process_addr = (addr_t) &regs;
154   parea.kernel_addr = offsetof (struct user_regs_struct, psw);
155   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
156     perror_with_name ("Couldn't get registers");
157 
158   fill_gregset (&regs, regnum);
159 
160   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
161     perror_with_name ("Couldn't write registers");
162 }
163 
164 /* Fetch all floating-point registers from process/thread TID and store
165    their values in GDB's register cache.  */
166 static void
167 fetch_fpregs (int tid)
168 {
169   fpregset_t fpregs;
170   ptrace_area parea;
171 
172   parea.len = sizeof (fpregs);
173   parea.process_addr = (addr_t) &fpregs;
174   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
175   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
176     perror_with_name ("Couldn't get floating point status");
177 
178   supply_fpregset (&fpregs);
179 }
180 
181 /* Store all valid floating-point registers in GDB's register cache
182    into the process/thread specified by TID.  */
183 static void
184 store_fpregs (int tid, int regnum)
185 {
186   fpregset_t fpregs;
187   ptrace_area parea;
188 
189   parea.len = sizeof (fpregs);
190   parea.process_addr = (addr_t) &fpregs;
191   parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
192   if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
193     perror_with_name ("Couldn't get floating point status");
194 
195   fill_fpregset (&fpregs, regnum);
196 
197   if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
198     perror_with_name ("Couldn't write floating point status");
199 }
200 
201 /* Fetch register REGNUM from the child process.  If REGNUM is -1, do
202    this for all registers.  */
203 void
204 fetch_inferior_registers (int regnum)
205 {
206   int tid = s390_inferior_tid ();
207 
208   if (regnum == -1
209       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
210     fetch_regs (tid);
211 
212   if (regnum == -1
213       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
214     fetch_fpregs (tid);
215 }
216 
217 /* Store register REGNUM back into the child process.  If REGNUM is
218    -1, do this for all registers.  */
219 void
220 store_inferior_registers (int regnum)
221 {
222   int tid = s390_inferior_tid ();
223 
224   if (regnum == -1
225       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
226     store_regs (tid, regnum);
227 
228   if (regnum == -1
229       || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
230     store_fpregs (tid, regnum);
231 }
232 
233 
234 /* Hardware-assisted watchpoint handling.  */
235 
236 /* We maintain a list of all currently active watchpoints in order
237    to properly handle watchpoint removal.
238 
239    The only thing we actually need is the total address space area
240    spanned by the watchpoints.  */
241 
242 struct watch_area
243 {
244   struct watch_area *next;
245   CORE_ADDR lo_addr;
246   CORE_ADDR hi_addr;
247 };
248 
249 static struct watch_area *watch_base = NULL;
250 
251 int
252 s390_stopped_by_watchpoint (void)
253 {
254   per_lowcore_bits per_lowcore;
255   ptrace_area parea;
256 
257   /* Speed up common case.  */
258   if (!watch_base)
259     return 0;
260 
261   parea.len = sizeof (per_lowcore);
262   parea.process_addr = (addr_t) & per_lowcore;
263   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
264   if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
265     perror_with_name ("Couldn't retrieve watchpoint status");
266 
267   return per_lowcore.perc_storage_alteration == 1
268 	 && per_lowcore.perc_store_real_address == 0;
269 }
270 
271 static void
272 s390_fix_watch_points (void)
273 {
274   int tid = s390_inferior_tid ();
275 
276   per_struct per_info;
277   ptrace_area parea;
278 
279   CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
280   struct watch_area *area;
281 
282   for (area = watch_base; area; area = area->next)
283     {
284       watch_lo_addr = min (watch_lo_addr, area->lo_addr);
285       watch_hi_addr = max (watch_hi_addr, area->hi_addr);
286     }
287 
288   parea.len = sizeof (per_info);
289   parea.process_addr = (addr_t) & per_info;
290   parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
291   if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
292     perror_with_name ("Couldn't retrieve watchpoint status");
293 
294   if (watch_base)
295     {
296       per_info.control_regs.bits.em_storage_alteration = 1;
297       per_info.control_regs.bits.storage_alt_space_ctl = 1;
298     }
299   else
300     {
301       per_info.control_regs.bits.em_storage_alteration = 0;
302       per_info.control_regs.bits.storage_alt_space_ctl = 0;
303     }
304   per_info.starting_addr = watch_lo_addr;
305   per_info.ending_addr = watch_hi_addr;
306 
307   if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
308     perror_with_name ("Couldn't modify watchpoint status");
309 }
310 
311 int
312 s390_insert_watchpoint (CORE_ADDR addr, int len)
313 {
314   struct watch_area *area = xmalloc (sizeof (struct watch_area));
315   if (!area)
316     return -1;
317 
318   area->lo_addr = addr;
319   area->hi_addr = addr + len - 1;
320 
321   area->next = watch_base;
322   watch_base = area;
323 
324   s390_fix_watch_points ();
325   return 0;
326 }
327 
328 int
329 s390_remove_watchpoint (CORE_ADDR addr, int len)
330 {
331   struct watch_area *area, **parea;
332 
333   for (parea = &watch_base; *parea; parea = &(*parea)->next)
334     if ((*parea)->lo_addr == addr
335 	&& (*parea)->hi_addr == addr + len - 1)
336       break;
337 
338   if (!*parea)
339     {
340       fprintf_unfiltered (gdb_stderr,
341 			  "Attempt to remove nonexistent watchpoint.\n");
342       return -1;
343     }
344 
345   area = *parea;
346   *parea = area->next;
347   xfree (area);
348 
349   s390_fix_watch_points ();
350   return 0;
351 }
352 
353 
354 int
355 kernel_u_size (void)
356 {
357   return sizeof (struct user);
358 }
359 
360