1130803Smarcel/* Native-dependent code for SPARC.
298944Sobrien
3130803Smarcel   Copyright 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel
598944Sobrien   This file is part of GDB.
698944Sobrien
798944Sobrien   This program is free software; you can redistribute it and/or modify
898944Sobrien   it under the terms of the GNU General Public License as published by
998944Sobrien   the Free Software Foundation; either version 2 of the License, or
1098944Sobrien   (at your option) any later version.
1198944Sobrien
1298944Sobrien   This program is distributed in the hope that it will be useful,
1398944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1498944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1598944Sobrien   GNU General Public License for more details.
1698944Sobrien
1798944Sobrien   You should have received a copy of the GNU General Public License
1898944Sobrien   along with this program; if not, write to the Free Software
1998944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2098944Sobrien   Boston, MA 02111-1307, USA.  */
2198944Sobrien
2298944Sobrien#include "defs.h"
2398944Sobrien#include "inferior.h"
24130803Smarcel#include "regcache.h"
2598944Sobrien#include "target.h"
2698944Sobrien
27130803Smarcel#include "gdb_assert.h"
2898944Sobrien#include <signal.h>
29130803Smarcel#include "gdb_string.h"
3098944Sobrien#include <sys/ptrace.h>
31130803Smarcel#include "gdb_wait.h"
32130803Smarcel#ifdef HAVE_MACHINE_REG_H
3398944Sobrien#include <machine/reg.h>
3498944Sobrien#endif
3598944Sobrien
36130803Smarcel#include "sparc-tdep.h"
37130803Smarcel#include "sparc-nat.h"
3898944Sobrien
39130803Smarcel/* With some trickery we can use the code in this file for most (if
40130803Smarcel   not all) ptrace(2) based SPARC systems, which includes SunOS 4,
41130803Smarcel   GNU/Linux and the various SPARC BSD's.
4298944Sobrien
43130803Smarcel   First, we need a data structure for use with ptrace(2).  SunOS has
44130803Smarcel   `struct regs' and `struct fp_status' in <machine/reg.h>.  BSD's
45130803Smarcel   have `struct reg' and `struct fpreg' in <machine/reg.h>.  GNU/Linux
46130803Smarcel   has the same structures as SunOS 4, but they're in <asm/reg.h>,
47130803Smarcel   which is a kernel header.  As a general rule we avoid including
48130803Smarcel   GNU/Linux kernel headers.  Fortunately GNU/Linux has a `gregset_t'
49130803Smarcel   and a `fpregset_t' that are equivalent to `struct regs' and `struct
50130803Smarcel   fp_status' in <sys/ucontext.h>, which is automatically included by
51130803Smarcel   <signal.h>.  Settling on using the `gregset_t' and `fpregset_t'
52130803Smarcel   typedefs, providing them for the other systems, therefore solves
53130803Smarcel   the puzzle.  */
5498944Sobrien
55130803Smarcel#ifdef HAVE_MACHINE_REG_H
56130803Smarcel#ifdef HAVE_STRUCT_REG
57130803Smarceltypedef struct reg gregset_t;
58130803Smarceltypedef struct fpreg fpregset_t;
59130803Smarcel#else
60130803Smarceltypedef struct regs gregset_t;
61130803Smarceltypedef struct fp_status fpregset_t;
62130803Smarcel#endif
63130803Smarcel#endif
64130803Smarcel
65130803Smarcel/* Second, we need to remap the BSD ptrace(2) requests to their SunOS
66130803Smarcel   equivalents.  GNU/Linux already follows SunOS here.  */
67130803Smarcel
68130803Smarcel#ifndef PTRACE_GETREGS
69130803Smarcel#define PTRACE_GETREGS PT_GETREGS
70130803Smarcel#endif
71130803Smarcel
72130803Smarcel#ifndef PTRACE_SETREGS
73130803Smarcel#define PTRACE_SETREGS PT_SETREGS
74130803Smarcel#endif
75130803Smarcel
76130803Smarcel#ifndef PTRACE_GETFPREGS
77130803Smarcel#define PTRACE_GETFPREGS PT_GETFPREGS
78130803Smarcel#endif
79130803Smarcel
80130803Smarcel#ifndef PTRACE_SETFPREGS
81130803Smarcel#define PTRACE_SETFPREGS PT_SETFPREGS
82130803Smarcel#endif
83130803Smarcel
84130803Smarcel/* Register set description.  */
85130803Smarcelconst struct sparc_gregset *sparc_gregset;
86130803Smarcelvoid (*sparc_supply_gregset) (const struct sparc_gregset *,
87130803Smarcel			      struct regcache *, int , const void *);
88130803Smarcelvoid (*sparc_collect_gregset) (const struct sparc_gregset *,
89130803Smarcel			       const struct regcache *, int, void *);
90130803Smarcelvoid (*sparc_supply_fpregset) (struct regcache *, int , const void *);
91130803Smarcelvoid (*sparc_collect_fpregset) (const struct regcache *, int , void *);
92130803Smarcelint (*sparc_gregset_supplies_p) (int);
93130803Smarcelint (*sparc_fpregset_supplies_p) (int);
94130803Smarcel
95130803Smarcel/* Determine whether `gregset_t' contains register REGNUM.  */
96130803Smarcel
97130803Smarcelint
98130803Smarcelsparc32_gregset_supplies_p (int regnum)
9998944Sobrien{
100130803Smarcel  /* Integer registers.  */
101130803Smarcel  if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
102130803Smarcel      || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
103130803Smarcel      || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
104130803Smarcel      || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
105130803Smarcel    return 1;
10698944Sobrien
107130803Smarcel  /* Control registers.  */
108130803Smarcel  if (regnum == SPARC32_PC_REGNUM
109130803Smarcel      || regnum == SPARC32_NPC_REGNUM
110130803Smarcel      || regnum == SPARC32_PSR_REGNUM
111130803Smarcel      || regnum == SPARC32_Y_REGNUM)
112130803Smarcel    return 1;
11398944Sobrien
114130803Smarcel  return 0;
115130803Smarcel}
11698944Sobrien
117130803Smarcel/* Determine whether `fpregset_t' contains register REGNUM.  */
11898944Sobrien
119130803Smarcelint
120130803Smarcelsparc32_fpregset_supplies_p (int regnum)
121130803Smarcel{
122130803Smarcel  /* Floating-point registers.  */
123130803Smarcel  if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
124130803Smarcel    return 1;
12598944Sobrien
126130803Smarcel  /* Control registers.  */
127130803Smarcel  if (regnum == SPARC32_FSR_REGNUM)
128130803Smarcel    return 1;
12998944Sobrien
130130803Smarcel  return 0;
131130803Smarcel}
132130803Smarcel
133130803Smarcel/* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
134130803Smarcel   for all registers (including the floating-point registers).  */
135130803Smarcel
136130803Smarcelvoid
137130803Smarcelfetch_inferior_registers (int regnum)
138130803Smarcel{
139130803Smarcel  struct regcache *regcache = current_regcache;
140130803Smarcel  int pid;
141130803Smarcel
142130803Smarcel  /* NOTE: cagney/2002-12-03: This code assumes that the currently
143130803Smarcel     selected light weight processes' registers can be written
144130803Smarcel     directly into the selected thread's register cache.  This works
145130803Smarcel     fine when given an 1:1 LWP:thread model (such as found on
146130803Smarcel     GNU/Linux) but will, likely, have problems when used on an N:1
147130803Smarcel     (userland threads) or N:M (userland multiple LWP) model.  In the
148130803Smarcel     case of the latter two, the LWP's registers do not necessarily
149130803Smarcel     belong to the selected thread (the LWP could be in the middle of
150130803Smarcel     executing the thread switch code).
151130803Smarcel
152130803Smarcel     These functions should instead be paramaterized with an explicit
153130803Smarcel     object (struct regcache, struct thread_info?) into which the LWPs
154130803Smarcel     registers can be written.  */
155130803Smarcel  pid = TIDGET (inferior_ptid);
156130803Smarcel  if (pid == 0)
157130803Smarcel    pid = PIDGET (inferior_ptid);
158130803Smarcel
159130803Smarcel  if (regnum == SPARC_G0_REGNUM)
16098944Sobrien    {
161130803Smarcel      regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
162130803Smarcel      return;
16398944Sobrien    }
16498944Sobrien
165130803Smarcel  if (regnum == -1 || sparc_gregset_supplies_p (regnum))
16698944Sobrien    {
167130803Smarcel      gregset_t regs;
168130803Smarcel
169130803Smarcel      if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
170130803Smarcel	perror_with_name ("Couldn't get registers");
171130803Smarcel
172130803Smarcel      sparc_supply_gregset (sparc_gregset, regcache, -1, &regs);
173130803Smarcel      if (regnum != -1)
174130803Smarcel	return;
17598944Sobrien    }
176130803Smarcel
177130803Smarcel  if (regnum == -1 || sparc_fpregset_supplies_p (regnum))
17898944Sobrien    {
179130803Smarcel      fpregset_t fpregs;
180130803Smarcel
181130803Smarcel      if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
182130803Smarcel	perror_with_name ("Couldn't get floating point status");
183130803Smarcel
184130803Smarcel      sparc_supply_fpregset (regcache, -1, &fpregs);
18598944Sobrien    }
18698944Sobrien}
18798944Sobrien
18898944Sobrienvoid
189130803Smarcelstore_inferior_registers (int regnum)
19098944Sobrien{
191130803Smarcel  struct regcache *regcache = current_regcache;
192130803Smarcel  int pid;
19398944Sobrien
194130803Smarcel  /* NOTE: cagney/2002-12-02: See comment in fetch_inferior_registers
195130803Smarcel     about threaded assumptions.  */
196130803Smarcel  pid = TIDGET (inferior_ptid);
197130803Smarcel  if (pid == 0)
198130803Smarcel    pid = PIDGET (inferior_ptid);
19998944Sobrien
200130803Smarcel  if (regnum == -1 || sparc_gregset_supplies_p (regnum))
20198944Sobrien    {
202130803Smarcel      gregset_t regs;
20398944Sobrien
204130803Smarcel      if (ptrace (PTRACE_GETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
205130803Smarcel	perror_with_name ("Couldn't get registers");
20698944Sobrien
207130803Smarcel      sparc_collect_gregset (sparc_gregset, regcache, regnum, &regs);
208130803Smarcel
209130803Smarcel      if (ptrace (PTRACE_SETREGS, pid, (PTRACE_ARG3_TYPE) &regs, 0) == -1)
210130803Smarcel	perror_with_name ("Couldn't write registers");
211130803Smarcel
212130803Smarcel      /* Deal with the stack regs.  */
213130803Smarcel      if (regnum == -1 || regnum == SPARC_SP_REGNUM
214130803Smarcel	  || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
21598944Sobrien	{
216130803Smarcel	  ULONGEST sp;
217130803Smarcel
218130803Smarcel	  regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
219130803Smarcel	  sparc_collect_rwindow (regcache, sp, regnum);
22098944Sobrien	}
22198944Sobrien
222130803Smarcel      if (regnum != -1)
223130803Smarcel	return;
22498944Sobrien    }
22598944Sobrien
226130803Smarcel  if (regnum == -1 || sparc_fpregset_supplies_p (regnum))
22798944Sobrien    {
228130803Smarcel      fpregset_t fpregs, saved_fpregs;
22998944Sobrien
230130803Smarcel      if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
231130803Smarcel	perror_with_name ("Couldn't get floating-point registers");
23298944Sobrien
233130803Smarcel      memcpy (&saved_fpregs, &fpregs, sizeof (fpregs));
234130803Smarcel      sparc_collect_fpregset (regcache, regnum, &fpregs);
23598944Sobrien
236130803Smarcel      /* Writing the floating-point registers will fail on NetBSD with
237130803Smarcel	 EINVAL if the inferior process doesn't have an FPU state
238130803Smarcel	 (i.e. if it didn't use the FPU yet).  Therefore we don't try
239130803Smarcel	 to write the registers if nothing changed.  */
240130803Smarcel      if (memcmp (&saved_fpregs, &fpregs, sizeof (fpregs)) != 0)
241130803Smarcel	{
242130803Smarcel	  if (ptrace (PTRACE_SETFPREGS, pid,
243130803Smarcel		      (PTRACE_ARG3_TYPE) &fpregs, 0) == -1)
244130803Smarcel	    perror_with_name ("Couldn't write floating-point registers");
245130803Smarcel	}
24698944Sobrien
247130803Smarcel      if (regnum != -1)
248130803Smarcel	return;
24998944Sobrien    }
25098944Sobrien}
25198944Sobrien
252130803Smarcel
253130803Smarcel/* Fetch StackGhost Per-Process XOR cookie.  */
25498944Sobrien
255130803SmarcelLONGEST
256130803Smarcelsparc_xfer_wcookie (struct target_ops *ops, enum target_object object,
257130803Smarcel		    const char *annex, void *readbuf, const void *writebuf,
258130803Smarcel		    ULONGEST offset, LONGEST len)
259130803Smarcel{
260130803Smarcel  unsigned long wcookie = 0;
261130803Smarcel  char *buf = (char *)&wcookie;
26298944Sobrien
263130803Smarcel  gdb_assert (object == TARGET_OBJECT_WCOOKIE);
264130803Smarcel  gdb_assert (readbuf && writebuf == NULL);
26598944Sobrien
266130803Smarcel  if (offset >= sizeof (unsigned long))
267130803Smarcel    return -1;
26898944Sobrien
269130803Smarcel#ifdef PT_WCOOKIE
270130803Smarcel  /* If PT_WCOOKIE is defined (by <sys/ptrace.h>), assume we're
271130803Smarcel     running on an OpenBSD release that uses StackGhost (3.1 or
272130803Smarcel     later).  As of release 3.4, OpenBSD doesn't use a randomized
273130803Smarcel     cookie yet, but a future release probably will.  */
274130803Smarcel  {
275130803Smarcel    int pid;
27698944Sobrien
277130803Smarcel    pid = TIDGET (inferior_ptid);
278130803Smarcel    if (pid == 0)
279130803Smarcel      pid = PIDGET (inferior_ptid);
28098944Sobrien
281130803Smarcel    /* Sanity check.  The proper type for a cookie is register_t, but
282130803Smarcel       we can't assume that this type exists on all systems supported
283130803Smarcel       by the code in this file.  */
284130803Smarcel    gdb_assert (sizeof (wcookie) == sizeof (register_t));
28598944Sobrien
286130803Smarcel    /* Fetch the cookie.  */
287130803Smarcel    if (ptrace (PT_WCOOKIE, pid, (PTRACE_ARG3_TYPE) &wcookie, 0) == -1)
28898944Sobrien      {
289130803Smarcel	if (errno != EINVAL)
290130803Smarcel	  perror_with_name ("Couldn't get StackGhost cookie");
29198944Sobrien
292130803Smarcel	/* Although PT_WCOOKIE is defined on OpenBSD 3.1 and later,
293130803Smarcel	   the request wasn't implemented until after OpenBSD 3.4.  If
294130803Smarcel	   the kernel doesn't support the PT_WCOOKIE request, assume
295130803Smarcel	   we're running on a kernel that uses non-randomized cookies.  */
296130803Smarcel	wcookie = 0x3;
29798944Sobrien      }
298130803Smarcel  }
299130803Smarcel#endif /* PT_WCOOKIE */
30098944Sobrien
301130803Smarcel  if (len > sizeof (unsigned long) - offset)
302130803Smarcel    len = sizeof (unsigned long) - offset;
30398944Sobrien
304130803Smarcel  memcpy (readbuf, buf + offset, len);
305130803Smarcel  return len;
30698944Sobrien}
30798944Sobrien
30898944Sobrien
309130803Smarcel/* Provide a prototype to silence -Wmissing-prototypes.  */
310130803Smarcelvoid _initialize_sparc_nat (void);
31198944Sobrien
31298944Sobrienvoid
313130803Smarcel_initialize_sparc_nat (void)
31498944Sobrien{
315130803Smarcel  /* Deafult to using SunOS 4 register sets.  */
316130803Smarcel  if (sparc_gregset == NULL)
317130803Smarcel    sparc_gregset = &sparc32_sunos4_gregset;
318130803Smarcel  if (sparc_supply_gregset == NULL)
319130803Smarcel    sparc_supply_gregset = sparc32_supply_gregset;
320130803Smarcel  if (sparc_collect_gregset == NULL)
321130803Smarcel    sparc_collect_gregset = sparc32_collect_gregset;
322130803Smarcel  if (sparc_supply_fpregset == NULL)
323130803Smarcel    sparc_supply_fpregset = sparc32_supply_fpregset;
324130803Smarcel  if (sparc_collect_fpregset == NULL)
325130803Smarcel    sparc_collect_fpregset = sparc32_collect_fpregset;
326130803Smarcel  if (sparc_gregset_supplies_p == NULL)
327130803Smarcel    sparc_gregset_supplies_p = sparc32_gregset_supplies_p;
328130803Smarcel  if (sparc_fpregset_supplies_p == NULL)
329130803Smarcel    sparc_fpregset_supplies_p = sparc32_fpregset_supplies_p;
33098944Sobrien}
331