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) ®s, ptid_get_lwp (inferior_ptid)) == -1) 160 perror_with_name (_("Couldn't get registers")); 161 162 sparc_supply_gregset (sparc_gregset, regcache, -1, ®s); 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) ®s, ptid_get_lwp (inferior_ptid)) == -1) 192 perror_with_name (_("Couldn't get registers")); 193 194 sparc_collect_gregset (sparc_gregset, regcache, regnum, ®s); 195 196 if (ptrace (PTRACE_SETREGS, pid, (PTRACE_TYPE_ARG3) ®s, 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