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) ®s, 0) == -1) 170130803Smarcel perror_with_name ("Couldn't get registers"); 171130803Smarcel 172130803Smarcel sparc_supply_gregset (sparc_gregset, regcache, -1, ®s); 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) ®s, 0) == -1) 205130803Smarcel perror_with_name ("Couldn't get registers"); 20698944Sobrien 207130803Smarcel sparc_collect_gregset (sparc_gregset, regcache, regnum, ®s); 208130803Smarcel 209130803Smarcel if (ptrace (PTRACE_SETREGS, pid, (PTRACE_ARG3_TYPE) ®s, 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