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