1130803Smarcel/* Low level DECstation interface to ptrace, for GDB when running native.
2130803Smarcel   Copyright 1988, 1989, 1991, 1992, 1993, 1995, 1996, 1999, 2000, 2001
3130803Smarcel   Free Software Foundation, Inc.
4130803Smarcel   Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
5130803Smarcel   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "defs.h"
25130803Smarcel#include "inferior.h"
26130803Smarcel#include "gdbcore.h"
27130803Smarcel#include "regcache.h"
28130803Smarcel#include <sys/ptrace.h>
29130803Smarcel#include <sys/types.h>
30130803Smarcel#include <sys/param.h>
31130803Smarcel#include <sys/user.h>
32130803Smarcel#undef JB_S0
33130803Smarcel#undef JB_S1
34130803Smarcel#undef JB_S2
35130803Smarcel#undef JB_S3
36130803Smarcel#undef JB_S4
37130803Smarcel#undef JB_S5
38130803Smarcel#undef JB_S6
39130803Smarcel#undef JB_S7
40130803Smarcel#undef JB_SP
41130803Smarcel#undef JB_S8
42130803Smarcel#undef JB_PC
43130803Smarcel#undef JB_SR
44130803Smarcel#undef NJBREGS
45130803Smarcel#include <setjmp.h>		/* For JB_XXX.  */
46130803Smarcel
47130803Smarcel/* Size of elements in jmpbuf */
48130803Smarcel
49130803Smarcel#define JB_ELEMENT_SIZE 4
50130803Smarcel
51130803Smarcel/* Map gdb internal register number to ptrace ``address''.
52130803Smarcel   These ``addresses'' are defined in DECstation <sys/ptrace.h> */
53130803Smarcel
54130803Smarcelstatic int
55130803Smarcelregister_ptrace_addr (int regno)
56130803Smarcel{
57130803Smarcel  return (regno < 32 ? GPR_BASE + regno
58130803Smarcel	  : regno == mips_regnum (current_gdbarch)->pc ? PC
59130803Smarcel	  : regno == mips_regnum (current_gdbarch)->cause ? CAUSE
60130803Smarcel	  : regno == mips_regnum (current_gdbarch)->hi ? MMHI
61130803Smarcel	  : regno == mips_regnum (current_gdbarch)->lo ? MMLO
62130803Smarcel	  : regno == mips_regnum (current_gdbarch)->fp_control_status ? FPC_CSR
63130803Smarcel	  : regno == mips_regnum (current_gdbarch)->fp_implementation_revision ? FPC_EIR
64130803Smarcel	  : regno >= FP0_REGNUM ? FPR_BASE + (regno - FP0_REGNUM)
65130803Smarcel	  : 0);
66130803Smarcel}
67130803Smarcel
68130803Smarcelstatic void fetch_core_registers (char *, unsigned, int, CORE_ADDR);
69130803Smarcel
70130803Smarcel/* Get all registers from the inferior */
71130803Smarcel
72130803Smarcelvoid
73130803Smarcelfetch_inferior_registers (int regno)
74130803Smarcel{
75130803Smarcel  unsigned int regaddr;
76130803Smarcel  char buf[MAX_REGISTER_SIZE];
77130803Smarcel  int i;
78130803Smarcel  char zerobuf[MAX_REGISTER_SIZE];
79130803Smarcel  memset (zerobuf, 0, MAX_REGISTER_SIZE);
80130803Smarcel
81130803Smarcel  deprecated_registers_fetched ();
82130803Smarcel
83130803Smarcel  for (regno = 1; regno < NUM_REGS; regno++)
84130803Smarcel    {
85130803Smarcel      regaddr = register_ptrace_addr (regno);
86130803Smarcel      for (i = 0; i < DEPRECATED_REGISTER_RAW_SIZE (regno); i += sizeof (int))
87130803Smarcel	{
88130803Smarcel	  *(int *) &buf[i] = ptrace (PT_READ_U, PIDGET (inferior_ptid),
89130803Smarcel				     (PTRACE_ARG3_TYPE) regaddr, 0);
90130803Smarcel	  regaddr += sizeof (int);
91130803Smarcel	}
92130803Smarcel      supply_register (regno, buf);
93130803Smarcel    }
94130803Smarcel
95130803Smarcel  supply_register (ZERO_REGNUM, zerobuf);
96130803Smarcel  /* Frame ptr reg must appear to be 0; it is faked by stack handling code. */
97130803Smarcel  supply_register (DEPRECATED_FP_REGNUM, zerobuf);
98130803Smarcel}
99130803Smarcel
100130803Smarcel/* Store our register values back into the inferior.
101130803Smarcel   If REGNO is -1, do this for all registers.
102130803Smarcel   Otherwise, REGNO specifies which register (so we can save time).  */
103130803Smarcel
104130803Smarcelvoid
105130803Smarcelstore_inferior_registers (int regno)
106130803Smarcel{
107130803Smarcel  unsigned int regaddr;
108130803Smarcel  char buf[80];
109130803Smarcel
110130803Smarcel  if (regno > 0)
111130803Smarcel    {
112130803Smarcel      if (regno == ZERO_REGNUM || regno == PS_REGNUM
113130803Smarcel	  || regno == mips_regnum (current_gdbarch)->badvaddr
114130803Smarcel	  || regno == mips_regnum (current_gdbarch)->cause
115130803Smarcel	  || regno == mips_regnum (current_gdbarch)->fp_implementation_revision
116130803Smarcel	  || regno == DEPRECATED_FP_REGNUM
117130803Smarcel	  || (regno >= FIRST_EMBED_REGNUM && regno <= LAST_EMBED_REGNUM))
118130803Smarcel	return;
119130803Smarcel      regaddr = register_ptrace_addr (regno);
120130803Smarcel      errno = 0;
121130803Smarcel      ptrace (PT_WRITE_U, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) regaddr,
122130803Smarcel	      read_register (regno));
123130803Smarcel      if (errno != 0)
124130803Smarcel	{
125130803Smarcel	  sprintf (buf, "writing register number %d", regno);
126130803Smarcel	  perror_with_name (buf);
127130803Smarcel	}
128130803Smarcel    }
129130803Smarcel  else
130130803Smarcel    {
131130803Smarcel      for (regno = 0; regno < NUM_REGS; regno++)
132130803Smarcel	store_inferior_registers (regno);
133130803Smarcel    }
134130803Smarcel}
135130803Smarcel
136130803Smarcel
137130803Smarcel/* Figure out where the longjmp will land.
138130803Smarcel   We expect the first arg to be a pointer to the jmp_buf structure from which
139130803Smarcel   we extract the pc (JB_PC) that we will land at.  The pc is copied into PC.
140130803Smarcel   This routine returns true on success. */
141130803Smarcel
142130803Smarcelint
143130803Smarcelget_longjmp_target (CORE_ADDR *pc)
144130803Smarcel{
145130803Smarcel  CORE_ADDR jb_addr;
146130803Smarcel  char *buf;
147130803Smarcel
148130803Smarcel  buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
149130803Smarcel  jb_addr = read_register (A0_REGNUM);
150130803Smarcel
151130803Smarcel  if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
152130803Smarcel			  TARGET_PTR_BIT / TARGET_CHAR_BIT))
153130803Smarcel    return 0;
154130803Smarcel
155130803Smarcel  *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
156130803Smarcel
157130803Smarcel  return 1;
158130803Smarcel}
159130803Smarcel
160130803Smarcel/* Extract the register values out of the core file and store
161130803Smarcel   them where `read_register' will find them.
162130803Smarcel
163130803Smarcel   CORE_REG_SECT points to the register values themselves, read into memory.
164130803Smarcel   CORE_REG_SIZE is the size of that area.
165130803Smarcel   WHICH says which set of registers we are handling (0 = int, 2 = float
166130803Smarcel   on machines where they are discontiguous).
167130803Smarcel   REG_ADDR is the offset from u.u_ar0 to the register values relative to
168130803Smarcel   core_reg_sect.  This is used with old-fashioned core files to
169130803Smarcel   locate the registers in a large upage-plus-stack ".reg" section.
170130803Smarcel   Original upage address X is at location core_reg_sect+x+reg_addr.
171130803Smarcel */
172130803Smarcel
173130803Smarcelstatic void
174130803Smarcelfetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
175130803Smarcel		      CORE_ADDR reg_addr)
176130803Smarcel{
177130803Smarcel  int regno;
178130803Smarcel  unsigned int addr;
179130803Smarcel  int bad_reg = -1;
180130803Smarcel  reg_ptr = -reg_addr;	/* Original u.u_ar0 is -reg_addr. */
181130803Smarcel
182130803Smarcel  char zerobuf[MAX_REGISTER_SIZE];
183130803Smarcel  memset (zerobuf, 0, MAX_REGISTER_SIZE);
184130803Smarcel
185130803Smarcel
186130803Smarcel  /* If u.u_ar0 was an absolute address in the core file, relativize it now,
187130803Smarcel     so we can use it as an offset into core_reg_sect.  When we're done,
188130803Smarcel     "register 0" will be at core_reg_sect+reg_ptr, and we can use
189130803Smarcel     register_addr to offset to the other registers.  If this is a modern
190130803Smarcel     core file without a upage, reg_ptr will be zero and this is all a big
191130803Smarcel     NOP.  */
192130803Smarcel  if (reg_ptr > core_reg_size)
193130803Smarcel#ifdef KERNEL_U_ADDR
194130803Smarcel    reg_ptr -= KERNEL_U_ADDR;
195130803Smarcel#else
196130803Smarcel    error ("Old mips core file can't be processed on this machine.");
197130803Smarcel#endif
198130803Smarcel
199130803Smarcel  for (regno = 0; regno < NUM_REGS; regno++)
200130803Smarcel    {
201130803Smarcel      addr = register_addr (regno, reg_ptr);
202130803Smarcel      if (addr >= core_reg_size)
203130803Smarcel	{
204130803Smarcel	  if (bad_reg < 0)
205130803Smarcel	    bad_reg = regno;
206130803Smarcel	}
207130803Smarcel      else
208130803Smarcel	{
209130803Smarcel	  supply_register (regno, core_reg_sect + addr);
210130803Smarcel	}
211130803Smarcel    }
212130803Smarcel  if (bad_reg >= 0)
213130803Smarcel    {
214130803Smarcel      error ("Register %s not found in core file.", REGISTER_NAME (bad_reg));
215130803Smarcel    }
216130803Smarcel  supply_register (ZERO_REGNUM, zerobuf);
217130803Smarcel  /* Frame ptr reg must appear to be 0; it is faked by stack handling code. */
218130803Smarcel  supply_register (DEPRECATED_FP_REGNUM, zerobuf);
219130803Smarcel}
220130803Smarcel
221130803Smarcel/* Return the address in the core dump or inferior of register REGNO.
222130803Smarcel   BLOCKEND is the address of the end of the user structure.  */
223130803Smarcel
224130803SmarcelCORE_ADDR
225130803Smarcelregister_addr (int regno, CORE_ADDR blockend)
226130803Smarcel{
227130803Smarcel  CORE_ADDR addr;
228130803Smarcel
229130803Smarcel  if (regno < 0 || regno >= NUM_REGS)
230130803Smarcel    error ("Invalid register number %d.", regno);
231130803Smarcel
232130803Smarcel  REGISTER_U_ADDR (addr, blockend, regno);
233130803Smarcel
234130803Smarcel  return addr;
235130803Smarcel}
236130803Smarcel
237130803Smarcel
238130803Smarcel/* Register that we are able to handle mips core file formats.
239130803Smarcel   FIXME: is this really bfd_target_unknown_flavour? */
240130803Smarcel
241130803Smarcelstatic struct core_fns mips_core_fns =
242130803Smarcel{
243130803Smarcel  bfd_target_unknown_flavour,		/* core_flavour */
244130803Smarcel  default_check_format,			/* check_format */
245130803Smarcel  default_core_sniffer,			/* core_sniffer */
246130803Smarcel  fetch_core_registers,			/* core_read_registers */
247130803Smarcel  NULL					/* next */
248130803Smarcel};
249130803Smarcel
250130803Smarcelvoid
251130803Smarcel_initialize_core_mips (void)
252130803Smarcel{
253130803Smarcel  add_core_fns (&mips_core_fns);
254130803Smarcel}
255