xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/sparc-nat.c (revision 0ab5b340411a90c5db2463a3bd38d565fa784c5c)
1 /* Native-dependent code for SPARC.
2 
3    Copyright (C) 2003-2014 Free Software Foundation, Inc.
4 
5    This file is part of GDB.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19 
20 #include "defs.h"
21 #include "inferior.h"
22 #include "regcache.h"
23 #include "target.h"
24 
25 #include "gdb_assert.h"
26 #include <signal.h>
27 #include <string.h>
28 #include <sys/ptrace.h>
29 #include "gdb_wait.h"
30 #ifdef HAVE_MACHINE_REG_H
31 #include <machine/reg.h>
32 #endif
33 
34 #include "sparc-tdep.h"
35 #include "sparc-nat.h"
36 #include "inf-ptrace.h"
37 
38 /* With some trickery we can use the code in this file for most (if
39    not all) ptrace(2) based SPARC systems, which includes SunOS 4,
40    GNU/Linux and the various SPARC BSD's.
41 
42    First, we need a data structure for use with ptrace(2).  SunOS has
43    `struct regs' and `struct fp_status' in <machine/reg.h>.  BSD's
44    have `struct reg' and `struct fpreg' in <machine/reg.h>.  GNU/Linux
45    has the same structures as SunOS 4, but they're in <asm/reg.h>,
46    which is a kernel header.  As a general rule we avoid including
47    GNU/Linux kernel headers.  Fortunately GNU/Linux has a `gregset_t'
48    and a `fpregset_t' that are equivalent to `struct regs' and `struct
49    fp_status' in <sys/ucontext.h>, which is automatically included by
50    <signal.h>.  Settling on using the `gregset_t' and `fpregset_t'
51    typedefs, providing them for the other systems, therefore solves
52    the puzzle.  */
53 
54 #ifdef HAVE_MACHINE_REG_H
55 #ifdef HAVE_STRUCT_REG
56 typedef struct reg gregset_t;
57 typedef struct fpreg fpregset_t;
58 #else
59 typedef struct regs gregset_t;
60 typedef struct fp_status fpregset_t;
61 #endif
62 #endif
63 
64 /* Second, we need to remap the BSD ptrace(2) requests to their SunOS
65    equivalents.  GNU/Linux already follows SunOS here.  */
66 
67 #ifndef PTRACE_GETREGS
68 #define PTRACE_GETREGS PT_GETREGS
69 #endif
70 
71 #ifndef PTRACE_SETREGS
72 #define PTRACE_SETREGS PT_SETREGS
73 #endif
74 
75 #ifndef PTRACE_GETFPREGS
76 #define PTRACE_GETFPREGS PT_GETFPREGS
77 #endif
78 
79 #ifndef PTRACE_SETFPREGS
80 #define PTRACE_SETFPREGS PT_SETFPREGS
81 #endif
82 
83 /* Register set description.  */
84 const struct sparc_gregset *sparc_gregset;
85 const struct sparc_fpregset *sparc_fpregset;
86 void (*sparc_supply_gregset) (const struct sparc_gregset *,
87 			      struct regcache *, int , const void *);
88 void (*sparc_collect_gregset) (const struct sparc_gregset *,
89 			       const struct regcache *, int, void *);
90 void (*sparc_supply_fpregset) (const struct sparc_fpregset *,
91 			       struct regcache *, int , const void *);
92 void (*sparc_collect_fpregset) (const struct sparc_fpregset *,
93 				const struct regcache *, int , void *);
94 int (*sparc_gregset_supplies_p) (struct gdbarch *, int);
95 int (*sparc_fpregset_supplies_p) (struct gdbarch *, int);
96 
97 /* Determine whether `gregset_t' contains register REGNUM.  */
98 
99 int
100 sparc32_gregset_supplies_p (struct gdbarch *gdbarch, int regnum)
101 {
102   /* Integer registers.  */
103   if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
104       || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
105       || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
106       || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
107     return 1;
108 
109   /* Control registers.  */
110   if (regnum == SPARC32_PC_REGNUM
111       || regnum == SPARC32_NPC_REGNUM
112       || regnum == SPARC32_PSR_REGNUM
113       || regnum == SPARC32_Y_REGNUM)
114     return 1;
115 
116   return 0;
117 }
118 
119 /* Determine whether `fpregset_t' contains register REGNUM.  */
120 
121 int
122 sparc32_fpregset_supplies_p (struct gdbarch *gdbarch, int regnum)
123 {
124   /* Floating-point registers.  */
125   if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
126     return 1;
127 
128   /* Control registers.  */
129   if (regnum == SPARC32_FSR_REGNUM)
130     return 1;
131 
132   return 0;
133 }
134 
135 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
136    for all registers (including the floating-point registers).  */
137 
138 void
139 sparc_fetch_inferior_registers (struct target_ops *ops,
140 				struct regcache *regcache, int regnum)
141 {
142   struct gdbarch *gdbarch = get_regcache_arch (regcache);
143   int pid;
144 
145   pid = ptid_get_pid (inferior_ptid);
146 
147   if (regnum == SPARC_G0_REGNUM)
148     {
149       gdb_byte zero[8] = { 0 };
150 
151       regcache_raw_supply (regcache, SPARC_G0_REGNUM, &zero);
152       return;
153     }
154 
155   if (regnum == -1 || sparc_gregset_supplies_p (gdbarch, regnum))
156     {
157       gregset_t regs;
158 
159       if (ptrace (PTRACE_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, ptid_get_lwp (inferior_ptid)) == -1)
160 	perror_with_name (_("Couldn't get registers"));
161 
162       sparc_supply_gregset (sparc_gregset, regcache, -1, &regs);
163       if (regnum != -1)
164 	return;
165     }
166 
167   if (regnum == -1 || sparc_fpregset_supplies_p (gdbarch, regnum))
168     {
169       fpregset_t fpregs;
170 
171       if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, ptid_get_lwp (inferior_ptid)) == -1)
172 	perror_with_name (_("Couldn't get floating point status"));
173 
174       sparc_supply_fpregset (sparc_fpregset, regcache, -1, &fpregs);
175     }
176 }
177 
178 void
179 sparc_store_inferior_registers (struct target_ops *ops,
180 				struct regcache *regcache, int regnum)
181 {
182   struct gdbarch *gdbarch = get_regcache_arch (regcache);
183   int pid;
184 
185   pid = ptid_get_pid (inferior_ptid);
186 
187   if (regnum == -1 || sparc_gregset_supplies_p (gdbarch, regnum))
188     {
189       gregset_t regs;
190 
191       if (ptrace (PTRACE_GETREGS, pid, (PTRACE_TYPE_ARG3) &regs, ptid_get_lwp (inferior_ptid)) == -1)
192 	perror_with_name (_("Couldn't get registers"));
193 
194       sparc_collect_gregset (sparc_gregset, regcache, regnum, &regs);
195 
196       if (ptrace (PTRACE_SETREGS, pid, (PTRACE_TYPE_ARG3) &regs, ptid_get_lwp (inferior_ptid)) == -1)
197 	perror_with_name (_("Couldn't write registers"));
198 
199       /* Deal with the stack regs.  */
200       if (regnum == -1 || regnum == SPARC_SP_REGNUM
201 	  || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
202 	{
203 	  ULONGEST sp;
204 
205 	  regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
206 	  sparc_collect_rwindow (regcache, sp, regnum);
207 	}
208 
209       if (regnum != -1)
210 	return;
211     }
212 
213   if (regnum == -1 || sparc_fpregset_supplies_p (gdbarch, regnum))
214     {
215       fpregset_t fpregs, saved_fpregs;
216 
217       if (ptrace (PTRACE_GETFPREGS, pid, (PTRACE_TYPE_ARG3) &fpregs, ptid_get_lwp (inferior_ptid)) == -1)
218 	perror_with_name (_("Couldn't get floating-point registers"));
219 
220       memcpy (&saved_fpregs, &fpregs, sizeof (fpregs));
221       sparc_collect_fpregset (sparc_fpregset, regcache, regnum, &fpregs);
222 
223       /* Writing the floating-point registers will fail on NetBSD with
224 	 EINVAL if the inferior process doesn't have an FPU state
225 	 (i.e. if it didn't use the FPU yet).  Therefore we don't try
226 	 to write the registers if nothing changed.  */
227       if (memcmp (&saved_fpregs, &fpregs, sizeof (fpregs)) != 0)
228 	{
229 	  if (ptrace (PTRACE_SETFPREGS, pid,
230 		      (PTRACE_TYPE_ARG3) &fpregs, ptid_get_lwp (inferior_ptid)) == -1)
231 	    perror_with_name (_("Couldn't write floating-point registers"));
232 	}
233 
234       if (regnum != -1)
235 	return;
236     }
237 }
238 
239 
240 /* Fetch StackGhost Per-Process XOR cookie.  */
241 
242 static LONGEST
243 sparc_xfer_wcookie (struct target_ops *ops, enum target_object object,
244 		    const char *annex, gdb_byte *readbuf,
245 		    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
246 {
247   unsigned long wcookie = 0;
248   char *buf = (char *)&wcookie;
249 
250   gdb_assert (object == TARGET_OBJECT_WCOOKIE);
251   gdb_assert (readbuf && writebuf == NULL);
252 
253   if (offset == sizeof (unsigned long))
254     return 0;			/* Signal EOF.  */
255   if (offset > sizeof (unsigned long))
256     return -1;
257 
258 #ifdef PT_WCOOKIE
259   /* If PT_WCOOKIE is defined (by <sys/ptrace.h>), assume we're
260      running on an OpenBSD release that uses StackGhost (3.1 or
261      later).  Since release 3.6, OpenBSD uses a fully randomized
262      cookie.  */
263   {
264     int pid;
265 
266     pid = ptid_get_pid (inferior_ptid);
267 
268     /* Sanity check.  The proper type for a cookie is register_t, but
269        we can't assume that this type exists on all systems supported
270        by the code in this file.  */
271     gdb_assert (sizeof (wcookie) == sizeof (register_t));
272 
273     /* Fetch the cookie.  */
274     if (ptrace (PT_WCOOKIE, pid, (PTRACE_TYPE_ARG3) &wcookie, 0) == -1)
275       {
276 	if (errno != EINVAL)
277 	  perror_with_name (_("Couldn't get StackGhost cookie"));
278 
279 	/* Although PT_WCOOKIE is defined on OpenBSD 3.1 and later,
280 	   the request wasn't implemented until after OpenBSD 3.4.  If
281 	   the kernel doesn't support the PT_WCOOKIE request, assume
282 	   we're running on a kernel that uses non-randomized cookies.  */
283 	wcookie = 0x3;
284       }
285   }
286 #endif /* PT_WCOOKIE */
287 
288   if (len > sizeof (unsigned long) - offset)
289     len = sizeof (unsigned long) - offset;
290 
291   memcpy (readbuf, buf + offset, len);
292   return len;
293 }
294 
295 target_xfer_partial_ftype *inf_ptrace_xfer_partial;
296 
297 static LONGEST
298 sparc_xfer_partial (struct target_ops *ops, enum target_object object,
299 		    const char *annex, gdb_byte *readbuf,
300 		    const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
301 {
302   if (object == TARGET_OBJECT_WCOOKIE)
303     return sparc_xfer_wcookie (ops, object, annex, readbuf, writebuf,
304 			       offset, len);
305 
306   return inf_ptrace_xfer_partial (ops, object, annex, readbuf, writebuf,
307 				  offset, len);
308 }
309 
310 /* Create a prototype generic SPARC target.  The client can override
311    it with local methods.  */
312 
313 struct target_ops *
314 sparc_target (void)
315 {
316   struct target_ops *t;
317 
318   t = inf_ptrace_target ();
319   t->to_fetch_registers = sparc_fetch_inferior_registers;
320   t->to_store_registers = sparc_store_inferior_registers;
321   inf_ptrace_xfer_partial = t->to_xfer_partial;
322   t->to_xfer_partial = sparc_xfer_partial;
323   return t;
324 }
325 
326 
327 /* Provide a prototype to silence -Wmissing-prototypes.  */
328 void _initialize_sparc_nat (void);
329 
330 void
331 _initialize_sparc_nat (void)
332 {
333   /* Deafult to using SunOS 4 register sets.  */
334   if (sparc_gregset == NULL)
335     sparc_gregset = &sparc32_sunos4_gregset;
336   if (sparc_fpregset == NULL)
337     sparc_fpregset = &sparc32_sunos4_fpregset;
338   if (sparc_supply_gregset == NULL)
339     sparc_supply_gregset = sparc32_supply_gregset;
340   if (sparc_collect_gregset == NULL)
341     sparc_collect_gregset = sparc32_collect_gregset;
342   if (sparc_supply_fpregset == NULL)
343     sparc_supply_fpregset = sparc32_supply_fpregset;
344   if (sparc_collect_fpregset == NULL)
345     sparc_collect_fpregset = sparc32_collect_fpregset;
346   if (sparc_gregset_supplies_p == NULL)
347     sparc_gregset_supplies_p = sparc32_gregset_supplies_p;
348   if (sparc_fpregset_supplies_p == NULL)
349     sparc_fpregset_supplies_p = sparc32_fpregset_supplies_p;
350 }
351