1130803Smarcel/* S390 native-dependent code for GDB, the GNU debugger.
2130803Smarcel   Copyright 2001, 2003 Free Software Foundation, Inc
3130803Smarcel
4130803Smarcel   Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
5130803Smarcel   for IBM Deutschland Entwicklung GmbH, IBM Corporation.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22130803Smarcel   02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "defs.h"
25130803Smarcel#include "tm.h"
26130803Smarcel#include "regcache.h"
27130803Smarcel#include "inferior.h"
28130803Smarcel
29130803Smarcel#include "s390-tdep.h"
30130803Smarcel
31130803Smarcel#include <asm/ptrace.h>
32130803Smarcel#include <sys/ptrace.h>
33130803Smarcel#include <asm/types.h>
34130803Smarcel#include <sys/procfs.h>
35130803Smarcel#include <sys/user.h>
36130803Smarcel#include <sys/ucontext.h>
37130803Smarcel
38130803Smarcel
39130803Smarcel/* Map registers to gregset/ptrace offsets.
40130803Smarcel   These arrays are defined in s390-tdep.c.  */
41130803Smarcel
42130803Smarcel#ifdef __s390x__
43130803Smarcel#define regmap_gregset s390x_regmap_gregset
44130803Smarcel#else
45130803Smarcel#define regmap_gregset s390_regmap_gregset
46130803Smarcel#endif
47130803Smarcel
48130803Smarcel#define regmap_fpregset s390_regmap_fpregset
49130803Smarcel
50130803Smarcel/* When debugging a 32-bit executable running under a 64-bit kernel,
51130803Smarcel   we have to fix up the 64-bit registers we get from the kernel
52130803Smarcel   to make them look like 32-bit registers.  */
53130803Smarcel#ifdef __s390x__
54130803Smarcel#define SUBOFF(i) \
55130803Smarcel	((TARGET_PTR_BIT == 32 \
56130803Smarcel	  && ((i) == S390_PSWA_REGNUM \
57130803Smarcel	      || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0)
58130803Smarcel#else
59130803Smarcel#define SUBOFF(i) 0
60130803Smarcel#endif
61130803Smarcel
62130803Smarcel
63130803Smarcel/* Fill GDB's register array with the general-purpose register values
64130803Smarcel   in *REGP.  */
65130803Smarcelvoid
66130803Smarcelsupply_gregset (gregset_t *regp)
67130803Smarcel{
68130803Smarcel  int i;
69130803Smarcel  for (i = 0; i < S390_NUM_REGS; i++)
70130803Smarcel    if (regmap_gregset[i] != -1)
71130803Smarcel      regcache_raw_supply (current_regcache, i,
72130803Smarcel			   (char *)regp + regmap_gregset[i] + SUBOFF (i));
73130803Smarcel}
74130803Smarcel
75130803Smarcel/* Fill register REGNO (if it is a general-purpose register) in
76130803Smarcel   *REGP with the value in GDB's register array.  If REGNO is -1,
77130803Smarcel   do this for all registers.  */
78130803Smarcelvoid
79130803Smarcelfill_gregset (gregset_t *regp, int regno)
80130803Smarcel{
81130803Smarcel  int i;
82130803Smarcel  for (i = 0; i < S390_NUM_REGS; i++)
83130803Smarcel    if (regmap_gregset[i] != -1)
84130803Smarcel      if (regno == -1 || regno == i)
85130803Smarcel	regcache_raw_collect (current_regcache, i,
86130803Smarcel			      (char *)regp + regmap_gregset[i] + SUBOFF (i));
87130803Smarcel}
88130803Smarcel
89130803Smarcel/* Fill GDB's register array with the floating-point register values
90130803Smarcel   in *REGP.  */
91130803Smarcelvoid
92130803Smarcelsupply_fpregset (fpregset_t *regp)
93130803Smarcel{
94130803Smarcel  int i;
95130803Smarcel  for (i = 0; i < S390_NUM_REGS; i++)
96130803Smarcel    if (regmap_fpregset[i] != -1)
97130803Smarcel      regcache_raw_supply (current_regcache, i,
98130803Smarcel			   ((char *)regp) + regmap_fpregset[i]);
99130803Smarcel}
100130803Smarcel
101130803Smarcel/* Fill register REGNO (if it is a general-purpose register) in
102130803Smarcel   *REGP with the value in GDB's register array.  If REGNO is -1,
103130803Smarcel   do this for all registers.  */
104130803Smarcelvoid
105130803Smarcelfill_fpregset (fpregset_t *regp, int regno)
106130803Smarcel{
107130803Smarcel  int i;
108130803Smarcel  for (i = 0; i < S390_NUM_REGS; i++)
109130803Smarcel    if (regmap_fpregset[i] != -1)
110130803Smarcel      if (regno == -1 || regno == i)
111130803Smarcel        regcache_raw_collect (current_regcache, i,
112130803Smarcel			      ((char *)regp) + regmap_fpregset[i]);
113130803Smarcel}
114130803Smarcel
115130803Smarcel/* Find the TID for the current inferior thread to use with ptrace.  */
116130803Smarcelstatic int
117130803Smarcels390_inferior_tid (void)
118130803Smarcel{
119130803Smarcel  /* GNU/Linux LWP ID's are process ID's.  */
120130803Smarcel  int tid = TIDGET (inferior_ptid);
121130803Smarcel  if (tid == 0)
122130803Smarcel    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
123130803Smarcel
124130803Smarcel  return tid;
125130803Smarcel}
126130803Smarcel
127130803Smarcel/* Fetch all general-purpose registers from process/thread TID and
128130803Smarcel   store their values in GDB's register cache.  */
129130803Smarcelstatic void
130130803Smarcelfetch_regs (int tid)
131130803Smarcel{
132130803Smarcel  gregset_t regs;
133130803Smarcel  ptrace_area parea;
134130803Smarcel
135130803Smarcel  parea.len = sizeof (regs);
136130803Smarcel  parea.process_addr = (addr_t) &regs;
137130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
138130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
139130803Smarcel    perror_with_name ("Couldn't get registers");
140130803Smarcel
141130803Smarcel  supply_gregset (&regs);
142130803Smarcel}
143130803Smarcel
144130803Smarcel/* Store all valid general-purpose registers in GDB's register cache
145130803Smarcel   into the process/thread specified by TID.  */
146130803Smarcelstatic void
147130803Smarcelstore_regs (int tid, int regnum)
148130803Smarcel{
149130803Smarcel  gregset_t regs;
150130803Smarcel  ptrace_area parea;
151130803Smarcel
152130803Smarcel  parea.len = sizeof (regs);
153130803Smarcel  parea.process_addr = (addr_t) &regs;
154130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, psw);
155130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
156130803Smarcel    perror_with_name ("Couldn't get registers");
157130803Smarcel
158130803Smarcel  fill_gregset (&regs, regnum);
159130803Smarcel
160130803Smarcel  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
161130803Smarcel    perror_with_name ("Couldn't write registers");
162130803Smarcel}
163130803Smarcel
164130803Smarcel/* Fetch all floating-point registers from process/thread TID and store
165130803Smarcel   their values in GDB's register cache.  */
166130803Smarcelstatic void
167130803Smarcelfetch_fpregs (int tid)
168130803Smarcel{
169130803Smarcel  fpregset_t fpregs;
170130803Smarcel  ptrace_area parea;
171130803Smarcel
172130803Smarcel  parea.len = sizeof (fpregs);
173130803Smarcel  parea.process_addr = (addr_t) &fpregs;
174130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
175130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
176130803Smarcel    perror_with_name ("Couldn't get floating point status");
177130803Smarcel
178130803Smarcel  supply_fpregset (&fpregs);
179130803Smarcel}
180130803Smarcel
181130803Smarcel/* Store all valid floating-point registers in GDB's register cache
182130803Smarcel   into the process/thread specified by TID.  */
183130803Smarcelstatic void
184130803Smarcelstore_fpregs (int tid, int regnum)
185130803Smarcel{
186130803Smarcel  fpregset_t fpregs;
187130803Smarcel  ptrace_area parea;
188130803Smarcel
189130803Smarcel  parea.len = sizeof (fpregs);
190130803Smarcel  parea.process_addr = (addr_t) &fpregs;
191130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs);
192130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0)
193130803Smarcel    perror_with_name ("Couldn't get floating point status");
194130803Smarcel
195130803Smarcel  fill_fpregset (&fpregs, regnum);
196130803Smarcel
197130803Smarcel  if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0)
198130803Smarcel    perror_with_name ("Couldn't write floating point status");
199130803Smarcel}
200130803Smarcel
201130803Smarcel/* Fetch register REGNUM from the child process.  If REGNUM is -1, do
202130803Smarcel   this for all registers.  */
203130803Smarcelvoid
204130803Smarcelfetch_inferior_registers (int regnum)
205130803Smarcel{
206130803Smarcel  int tid = s390_inferior_tid ();
207130803Smarcel
208130803Smarcel  if (regnum == -1
209130803Smarcel      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
210130803Smarcel    fetch_regs (tid);
211130803Smarcel
212130803Smarcel  if (regnum == -1
213130803Smarcel      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
214130803Smarcel    fetch_fpregs (tid);
215130803Smarcel}
216130803Smarcel
217130803Smarcel/* Store register REGNUM back into the child process.  If REGNUM is
218130803Smarcel   -1, do this for all registers.  */
219130803Smarcelvoid
220130803Smarcelstore_inferior_registers (int regnum)
221130803Smarcel{
222130803Smarcel  int tid = s390_inferior_tid ();
223130803Smarcel
224130803Smarcel  if (regnum == -1
225130803Smarcel      || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
226130803Smarcel    store_regs (tid, regnum);
227130803Smarcel
228130803Smarcel  if (regnum == -1
229130803Smarcel      || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1))
230130803Smarcel    store_fpregs (tid, regnum);
231130803Smarcel}
232130803Smarcel
233130803Smarcel
234130803Smarcel/* Hardware-assisted watchpoint handling.  */
235130803Smarcel
236130803Smarcel/* We maintain a list of all currently active watchpoints in order
237130803Smarcel   to properly handle watchpoint removal.
238130803Smarcel
239130803Smarcel   The only thing we actually need is the total address space area
240130803Smarcel   spanned by the watchpoints.  */
241130803Smarcel
242130803Smarcelstruct watch_area
243130803Smarcel{
244130803Smarcel  struct watch_area *next;
245130803Smarcel  CORE_ADDR lo_addr;
246130803Smarcel  CORE_ADDR hi_addr;
247130803Smarcel};
248130803Smarcel
249130803Smarcelstatic struct watch_area *watch_base = NULL;
250130803Smarcel
251130803Smarcelint
252130803Smarcels390_stopped_by_watchpoint (void)
253130803Smarcel{
254130803Smarcel  per_lowcore_bits per_lowcore;
255130803Smarcel  ptrace_area parea;
256130803Smarcel
257130803Smarcel  /* Speed up common case.  */
258130803Smarcel  if (!watch_base)
259130803Smarcel    return 0;
260130803Smarcel
261130803Smarcel  parea.len = sizeof (per_lowcore);
262130803Smarcel  parea.process_addr = (addr_t) & per_lowcore;
263130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
264130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
265130803Smarcel    perror_with_name ("Couldn't retrieve watchpoint status");
266130803Smarcel
267130803Smarcel  return per_lowcore.perc_storage_alteration == 1
268130803Smarcel	 && per_lowcore.perc_store_real_address == 0;
269130803Smarcel}
270130803Smarcel
271130803Smarcelstatic void
272130803Smarcels390_fix_watch_points (void)
273130803Smarcel{
274130803Smarcel  int tid = s390_inferior_tid ();
275130803Smarcel
276130803Smarcel  per_struct per_info;
277130803Smarcel  ptrace_area parea;
278130803Smarcel
279130803Smarcel  CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
280130803Smarcel  struct watch_area *area;
281130803Smarcel
282130803Smarcel  for (area = watch_base; area; area = area->next)
283130803Smarcel    {
284130803Smarcel      watch_lo_addr = min (watch_lo_addr, area->lo_addr);
285130803Smarcel      watch_hi_addr = max (watch_hi_addr, area->hi_addr);
286130803Smarcel    }
287130803Smarcel
288130803Smarcel  parea.len = sizeof (per_info);
289130803Smarcel  parea.process_addr = (addr_t) & per_info;
290130803Smarcel  parea.kernel_addr = offsetof (struct user_regs_struct, per_info);
291130803Smarcel  if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
292130803Smarcel    perror_with_name ("Couldn't retrieve watchpoint status");
293130803Smarcel
294130803Smarcel  if (watch_base)
295130803Smarcel    {
296130803Smarcel      per_info.control_regs.bits.em_storage_alteration = 1;
297130803Smarcel      per_info.control_regs.bits.storage_alt_space_ctl = 1;
298130803Smarcel    }
299130803Smarcel  else
300130803Smarcel    {
301130803Smarcel      per_info.control_regs.bits.em_storage_alteration = 0;
302130803Smarcel      per_info.control_regs.bits.storage_alt_space_ctl = 0;
303130803Smarcel    }
304130803Smarcel  per_info.starting_addr = watch_lo_addr;
305130803Smarcel  per_info.ending_addr = watch_hi_addr;
306130803Smarcel
307130803Smarcel  if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0)
308130803Smarcel    perror_with_name ("Couldn't modify watchpoint status");
309130803Smarcel}
310130803Smarcel
311130803Smarcelint
312130803Smarcels390_insert_watchpoint (CORE_ADDR addr, int len)
313130803Smarcel{
314130803Smarcel  struct watch_area *area = xmalloc (sizeof (struct watch_area));
315130803Smarcel  if (!area)
316130803Smarcel    return -1;
317130803Smarcel
318130803Smarcel  area->lo_addr = addr;
319130803Smarcel  area->hi_addr = addr + len - 1;
320130803Smarcel
321130803Smarcel  area->next = watch_base;
322130803Smarcel  watch_base = area;
323130803Smarcel
324130803Smarcel  s390_fix_watch_points ();
325130803Smarcel  return 0;
326130803Smarcel}
327130803Smarcel
328130803Smarcelint
329130803Smarcels390_remove_watchpoint (CORE_ADDR addr, int len)
330130803Smarcel{
331130803Smarcel  struct watch_area *area, **parea;
332130803Smarcel
333130803Smarcel  for (parea = &watch_base; *parea; parea = &(*parea)->next)
334130803Smarcel    if ((*parea)->lo_addr == addr
335130803Smarcel	&& (*parea)->hi_addr == addr + len - 1)
336130803Smarcel      break;
337130803Smarcel
338130803Smarcel  if (!*parea)
339130803Smarcel    {
340130803Smarcel      fprintf_unfiltered (gdb_stderr,
341130803Smarcel			  "Attempt to remove nonexistent watchpoint.\n");
342130803Smarcel      return -1;
343130803Smarcel    }
344130803Smarcel
345130803Smarcel  area = *parea;
346130803Smarcel  *parea = area->next;
347130803Smarcel  xfree (area);
348130803Smarcel
349130803Smarcel  s390_fix_watch_points ();
350130803Smarcel  return 0;
351130803Smarcel}
352130803Smarcel
353130803Smarcel
354130803Smarcelint
355130803Smarcelkernel_u_size (void)
356130803Smarcel{
357130803Smarcel  return sizeof (struct user);
358130803Smarcel}
359130803Smarcel
360