1130803Smarcel/* Native support for MIPS running SVR4, for GDB.
2130803Smarcel   Copyright 1994, 1995, 2000, 2001 Free Software Foundation, Inc.
3130803Smarcel
4130803Smarcel   This file is part of GDB.
5130803Smarcel
6130803Smarcel   This program is free software; you can redistribute it and/or modify
7130803Smarcel   it under the terms of the GNU General Public License as published by
8130803Smarcel   the Free Software Foundation; either version 2 of the License, or
9130803Smarcel   (at your option) any later version.
10130803Smarcel
11130803Smarcel   This program is distributed in the hope that it will be useful,
12130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
13130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14130803Smarcel   GNU General Public License for more details.
15130803Smarcel
16130803Smarcel   You should have received a copy of the GNU General Public License
17130803Smarcel   along with this program; if not, write to the Free Software
18130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
19130803Smarcel   Boston, MA 02111-1307, USA.  */
20130803Smarcel
21130803Smarcel#include "defs.h"
22130803Smarcel#include "inferior.h"
23130803Smarcel#include "gdbcore.h"
24130803Smarcel#include "target.h"
25130803Smarcel#include "regcache.h"
26130803Smarcel
27130803Smarcel#include <sys/time.h>
28130803Smarcel#include <sys/procfs.h>
29130803Smarcel#include <setjmp.h>		/* For JB_XXX.  */
30130803Smarcel
31130803Smarcel/* Prototypes for supply_gregset etc. */
32130803Smarcel#include "gregset.h"
33130803Smarcel
34130803Smarcel/* Size of elements in jmpbuf */
35130803Smarcel
36130803Smarcel#define JB_ELEMENT_SIZE 4
37130803Smarcel
38130803Smarcel/*
39130803Smarcel * See the comment in m68k-tdep.c regarding the utility of these functions.
40130803Smarcel *
41130803Smarcel * These definitions are from the MIPS SVR4 ABI, so they may work for
42130803Smarcel * any MIPS SVR4 target.
43130803Smarcel */
44130803Smarcel
45130803Smarcelvoid
46130803Smarcelsupply_gregset (gregset_t *gregsetp)
47130803Smarcel{
48130803Smarcel  int regi;
49130803Smarcel  greg_t *regp = &(*gregsetp)[0];
50130803Smarcel  char zerobuf[MAX_REGISTER_SIZE];
51130803Smarcel  memset (zerobuf, 0, MAX_REGISTER_SIZE);
52130803Smarcel
53130803Smarcel  for (regi = 0; regi <= CXT_RA; regi++)
54130803Smarcel    supply_register (regi, (char *) (regp + regi));
55130803Smarcel
56130803Smarcel  supply_register (mips_regnum (current_gdbarch)->pc,
57130803Smarcel		   (char *) (regp + CXT_EPC));
58130803Smarcel  supply_register (mips_regnum (current_gdbarch)->hi,
59130803Smarcel		   (char *) (regp + CXT_MDHI));
60130803Smarcel  supply_register (mips_regnum (current_gdbarch)->lo,
61130803Smarcel		   (char *) (regp + CXT_MDLO));
62130803Smarcel  supply_register (mips_regnum (current_gdbarch)->cause,
63130803Smarcel		   (char *) (regp + CXT_CAUSE));
64130803Smarcel
65130803Smarcel  /* Fill inaccessible registers with zero.  */
66130803Smarcel  supply_register (PS_REGNUM, zerobuf);
67130803Smarcel  supply_register (mips_regnum (current_gdbarch)->badvaddr, zerobuf);
68130803Smarcel  supply_register (DEPRECATED_FP_REGNUM, zerobuf);
69130803Smarcel  supply_register (UNUSED_REGNUM, zerobuf);
70130803Smarcel  for (regi = FIRST_EMBED_REGNUM; regi <= LAST_EMBED_REGNUM; regi++)
71130803Smarcel    supply_register (regi, zerobuf);
72130803Smarcel}
73130803Smarcel
74130803Smarcelvoid
75130803Smarcelfill_gregset (gregset_t *gregsetp, int regno)
76130803Smarcel{
77130803Smarcel  int regi;
78130803Smarcel  greg_t *regp = &(*gregsetp)[0];
79130803Smarcel
80130803Smarcel  for (regi = 0; regi <= 32; regi++)
81130803Smarcel    if ((regno == -1) || (regno == regi))
82130803Smarcel      *(regp + regi) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (regi)];
83130803Smarcel
84130803Smarcel  if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->pc))
85130803Smarcel    *(regp + CXT_EPC) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->pc)];
86130803Smarcel
87130803Smarcel  if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->cause))
88130803Smarcel    *(regp + CXT_CAUSE) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->cause)];
89130803Smarcel
90130803Smarcel  if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->hi))
91130803Smarcel    *(regp + CXT_MDHI) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->hi)];
92130803Smarcel
93130803Smarcel  if ((regno == -1) || (regno == mips_regnum (current_gdbarch)->lo))
94130803Smarcel    *(regp + CXT_MDLO) = *(greg_t *) & deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->lo)];
95130803Smarcel}
96130803Smarcel
97130803Smarcel/*
98130803Smarcel * Now we do the same thing for floating-point registers.
99130803Smarcel * We don't bother to condition on FP0 regnum since any
100130803Smarcel * reasonable MIPS configuration has an R3010 in it.
101130803Smarcel *
102130803Smarcel * Again, see the comments in m68k-tdep.c.
103130803Smarcel */
104130803Smarcel
105130803Smarcelvoid
106130803Smarcelsupply_fpregset (fpregset_t *fpregsetp)
107130803Smarcel{
108130803Smarcel  int regi;
109130803Smarcel  char zerobuf[MAX_REGISTER_SIZE];
110130803Smarcel  memset (zerobuf, 0, MAX_REGISTER_SIZE);
111130803Smarcel
112130803Smarcel  for (regi = 0; regi < 32; regi++)
113130803Smarcel    supply_register (mips_regnum (current_gdbarch)->fp0 + regi,
114130803Smarcel		     (char *) &fpregsetp->fp_r.fp_regs[regi]);
115130803Smarcel
116130803Smarcel  supply_register (mips_regnum (current_gdbarch)->fp_control_status,
117130803Smarcel		   (char *) &fpregsetp->fp_csr);
118130803Smarcel
119130803Smarcel  /* FIXME: how can we supply FCRIR?  The ABI doesn't tell us. */
120130803Smarcel  supply_register (mips_regnum (current_gdbarch)->fp_implementation_revision,
121130803Smarcel		   zerobuf);
122130803Smarcel}
123130803Smarcel
124130803Smarcelvoid
125130803Smarcelfill_fpregset (fpregset_t *fpregsetp, int regno)
126130803Smarcel{
127130803Smarcel  int regi;
128130803Smarcel  char *from, *to;
129130803Smarcel
130130803Smarcel  for (regi = mips_regnum (current_gdbarch)->fp0;
131130803Smarcel       regi < mips_regnum (current_gdbarch)->fp0 + 32; regi++)
132130803Smarcel    {
133130803Smarcel      if ((regno == -1) || (regno == regi))
134130803Smarcel	{
135130803Smarcel	  from = (char *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regi)];
136130803Smarcel	  to = (char *) &(fpregsetp->fp_r.fp_regs[regi - mips_regnum (current_gdbarch)->fp0]);
137130803Smarcel	  memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (regi));
138130803Smarcel	}
139130803Smarcel    }
140130803Smarcel
141130803Smarcel  if ((regno == -1)
142130803Smarcel      || (regno == mips_regnum (current_gdbarch)->fp_control_status))
143130803Smarcel    fpregsetp->fp_csr = *(unsigned *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (mips_regnum (current_gdbarch)->fp_control_status)];
144130803Smarcel}
145130803Smarcel
146130803Smarcel
147130803Smarcel/* Figure out where the longjmp will land.
148130803Smarcel   We expect the first arg to be a pointer to the jmp_buf structure from which
149130803Smarcel   we extract the pc (_JB_PC) that we will land at.  The pc is copied into PC.
150130803Smarcel   This routine returns true on success. */
151130803Smarcel
152130803Smarcelint
153130803Smarcelget_longjmp_target (CORE_ADDR *pc)
154130803Smarcel{
155130803Smarcel  char *buf;
156130803Smarcel  CORE_ADDR jb_addr;
157130803Smarcel
158130803Smarcel  buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
159130803Smarcel  jb_addr = read_register (A0_REGNUM);
160130803Smarcel
161130803Smarcel  if (target_read_memory (jb_addr + _JB_PC * JB_ELEMENT_SIZE, buf,
162130803Smarcel			  TARGET_PTR_BIT / TARGET_CHAR_BIT))
163130803Smarcel    return 0;
164130803Smarcel
165130803Smarcel  *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
166130803Smarcel
167130803Smarcel  return 1;
168130803Smarcel}
169