1130803Smarcel/* Target-dependent code for NetBSD/Alpha.
2130803Smarcel
3130803Smarcel   Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel   Contributed by Wasabi Systems, Inc.
5130803Smarcel
6130803Smarcel   This file is part of GDB.
7130803Smarcel
8130803Smarcel   This program is free software; you can redistribute it and/or modify
9130803Smarcel   it under the terms of the GNU General Public License as published by
10130803Smarcel   the Free Software Foundation; either version 2 of the License, or
11130803Smarcel   (at your option) any later version.
12130803Smarcel
13130803Smarcel   This program is distributed in the hope that it will be useful,
14130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130803Smarcel   GNU General Public License for more details.
17130803Smarcel
18130803Smarcel   You should have received a copy of the GNU General Public License
19130803Smarcel   along with this program; if not, write to the Free Software
20130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
21130803Smarcel   Boston, MA 02111-1307, USA.  */
22130803Smarcel
23130803Smarcel#include "defs.h"
24130803Smarcel#include "gdbcore.h"
25130803Smarcel#include "frame.h"
26130803Smarcel#include "regcache.h"
27130803Smarcel#include "value.h"
28130803Smarcel#include "osabi.h"
29130803Smarcel
30130803Smarcel#include "solib-svr4.h"
31130803Smarcel
32130803Smarcel#include "alpha-tdep.h"
33130803Smarcel#include "alphabsd-tdep.h"
34130803Smarcel#include "nbsd-tdep.h"
35130803Smarcel
36130803Smarcelstatic void
37130803Smarcelfetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
38130803Smarcel                      CORE_ADDR ignore)
39130803Smarcel{
40130803Smarcel  char *regs, *fpregs;
41130803Smarcel  int regno;
42130803Smarcel
43130803Smarcel  /* Table to map a gdb register number to a trapframe register index.  */
44130803Smarcel  static const int regmap[] =
45130803Smarcel  {
46130803Smarcel     0,   1,   2,   3,
47130803Smarcel     4,   5,   6,   7,
48130803Smarcel     8,   9,  10,  11,
49130803Smarcel    12,  13,  14,  15,
50130803Smarcel    30,  31,  32,  16,
51130803Smarcel    17,  18,  19,  20,
52130803Smarcel    21,  22,  23,  24,
53130803Smarcel    25,  29,  26
54130803Smarcel  };
55130803Smarcel#define SIZEOF_TRAPFRAME (33 * 8)
56130803Smarcel
57130803Smarcel  /* We get everything from one section.  */
58130803Smarcel  if (which != 0)
59130803Smarcel    return;
60130803Smarcel
61130803Smarcel  regs = core_reg_sect;
62130803Smarcel  fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
63130803Smarcel
64130803Smarcel  if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
65130803Smarcel    {
66130803Smarcel      warning ("Wrong size register set in core file.");
67130803Smarcel      return;
68130803Smarcel    }
69130803Smarcel
70130803Smarcel  /* Integer registers.  */
71130803Smarcel  for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
72130803Smarcel    supply_register (regno, regs + (regmap[regno] * 8));
73130803Smarcel  supply_register (ALPHA_ZERO_REGNUM, NULL);
74130803Smarcel  supply_register (PC_REGNUM, regs + (28 * 8));
75130803Smarcel
76130803Smarcel  /* Floating point registers.  */
77130803Smarcel  alphabsd_supply_fpreg (fpregs, -1);
78130803Smarcel}
79130803Smarcel
80130803Smarcelstatic void
81130803Smarcelfetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
82130803Smarcel                         CORE_ADDR ignore)
83130803Smarcel{
84130803Smarcel  switch (which)
85130803Smarcel    {
86130803Smarcel    case 0:  /* Integer registers.  */
87130803Smarcel      if (core_reg_size != SIZEOF_STRUCT_REG)
88130803Smarcel	warning ("Wrong size register set in core file.");
89130803Smarcel      else
90130803Smarcel	alphabsd_supply_reg (core_reg_sect, -1);
91130803Smarcel      break;
92130803Smarcel
93130803Smarcel    case 2:  /* Floating point registers.  */
94130803Smarcel      if (core_reg_size != SIZEOF_STRUCT_FPREG)
95130803Smarcel	warning ("Wrong size FP register set in core file.");
96130803Smarcel      else
97130803Smarcel	alphabsd_supply_fpreg (core_reg_sect, -1);
98130803Smarcel      break;
99130803Smarcel
100130803Smarcel    default:
101130803Smarcel      /* Don't know what kind of register request this is; just ignore it.  */
102130803Smarcel      break;
103130803Smarcel    }
104130803Smarcel}
105130803Smarcel
106130803Smarcelstatic struct core_fns alphanbsd_core_fns =
107130803Smarcel{
108130803Smarcel  bfd_target_unknown_flavour,		/* core_flavour */
109130803Smarcel  default_check_format,			/* check_format */
110130803Smarcel  default_core_sniffer,			/* core_sniffer */
111130803Smarcel  fetch_core_registers,			/* core_read_registers */
112130803Smarcel  NULL					/* next */
113130803Smarcel};
114130803Smarcel
115130803Smarcelstatic struct core_fns alphanbsd_elfcore_fns =
116130803Smarcel{
117130803Smarcel  bfd_target_elf_flavour,		/* core_flavour */
118130803Smarcel  default_check_format,			/* check_format */
119130803Smarcel  default_core_sniffer,			/* core_sniffer */
120130803Smarcel  fetch_elfcore_registers,		/* core_read_registers */
121130803Smarcel  NULL					/* next */
122130803Smarcel};
123130803Smarcel
124130803Smarcel/* Under NetBSD/alpha, signal handler invocations can be identified by the
125130803Smarcel   designated code sequence that is used to return from a signal handler.
126130803Smarcel   In particular, the return address of a signal handler points to the
127130803Smarcel   following code sequence:
128130803Smarcel
129130803Smarcel	ldq	a0, 0(sp)
130130803Smarcel	lda	sp, 16(sp)
131130803Smarcel	lda	v0, 295(zero)	# __sigreturn14
132130803Smarcel	call_pal callsys
133130803Smarcel
134130803Smarcel   Each instruction has a unique encoding, so we simply attempt to match
135130803Smarcel   the instruction the PC is pointing to with any of the above instructions.
136130803Smarcel   If there is a hit, we know the offset to the start of the designated
137130803Smarcel   sequence and can then check whether we really are executing in the
138130803Smarcel   signal trampoline.  If not, -1 is returned, otherwise the offset from the
139130803Smarcel   start of the return sequence is returned.  */
140130803Smarcelstatic const unsigned char sigtramp_retcode[] =
141130803Smarcel{
142130803Smarcel  0x00, 0x00, 0x1e, 0xa6,	/* ldq a0, 0(sp) */
143130803Smarcel  0x10, 0x00, 0xde, 0x23,	/* lda sp, 16(sp) */
144130803Smarcel  0x27, 0x01, 0x1f, 0x20,	/* lda v0, 295(zero) */
145130803Smarcel  0x83, 0x00, 0x00, 0x00,	/* call_pal callsys */
146130803Smarcel};
147130803Smarcel#define RETCODE_NWORDS		4
148130803Smarcel#define RETCODE_SIZE		(RETCODE_NWORDS * 4)
149130803Smarcel
150130803SmarcelLONGEST
151130803Smarcelalphanbsd_sigtramp_offset (CORE_ADDR pc)
152130803Smarcel{
153130803Smarcel  unsigned char ret[RETCODE_SIZE], w[4];
154130803Smarcel  LONGEST off;
155130803Smarcel  int i;
156130803Smarcel
157130803Smarcel  if (read_memory_nobpt (pc, (char *) w, 4) != 0)
158130803Smarcel    return -1;
159130803Smarcel
160130803Smarcel  for (i = 0; i < RETCODE_NWORDS; i++)
161130803Smarcel    {
162130803Smarcel      if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
163130803Smarcel	break;
164130803Smarcel    }
165130803Smarcel  if (i == RETCODE_NWORDS)
166130803Smarcel    return (-1);
167130803Smarcel
168130803Smarcel  off = i * 4;
169130803Smarcel  pc -= off;
170130803Smarcel
171130803Smarcel  if (read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
172130803Smarcel    return -1;
173130803Smarcel
174130803Smarcel  if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
175130803Smarcel    return off;
176130803Smarcel
177130803Smarcel  return -1;
178130803Smarcel}
179130803Smarcel
180130803Smarcelstatic int
181130803Smarcelalphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
182130803Smarcel{
183130803Smarcel  return (nbsd_pc_in_sigtramp (pc, func_name)
184130803Smarcel	  || alphanbsd_sigtramp_offset (pc) >= 0);
185130803Smarcel}
186130803Smarcel
187130803Smarcelstatic CORE_ADDR
188130803Smarcelalphanbsd_sigcontext_addr (struct frame_info *frame)
189130803Smarcel{
190130803Smarcel  /* FIXME: This is not correct for all versions of NetBSD/alpha.
191130803Smarcel     We will probably need to disassemble the trampoline to figure
192130803Smarcel     out which trampoline frame type we have.  */
193130803Smarcel  return get_frame_base (frame);
194130803Smarcel}
195130803Smarcel
196130803Smarcelstatic void
197130803Smarcelalphanbsd_init_abi (struct gdbarch_info info,
198130803Smarcel                    struct gdbarch *gdbarch)
199130803Smarcel{
200130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
201130803Smarcel
202130803Smarcel  /* Hook into the DWARF CFI frame unwinder.  */
203130803Smarcel  alpha_dwarf2_init_abi (info, gdbarch);
204130803Smarcel
205130803Smarcel  /* Hook into the MDEBUG frame unwinder.  */
206130803Smarcel  alpha_mdebug_init_abi (info, gdbarch);
207130803Smarcel
208130803Smarcel  set_gdbarch_pc_in_sigtramp (gdbarch, alphanbsd_pc_in_sigtramp);
209130803Smarcel
210130803Smarcel  /* NetBSD/alpha does not provide single step support via ptrace(2); we
211130803Smarcel     must use software single-stepping.  */
212130803Smarcel  set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
213130803Smarcel
214130803Smarcel  set_solib_svr4_fetch_link_map_offsets (gdbarch,
215130803Smarcel                                 nbsd_lp64_solib_svr4_fetch_link_map_offsets);
216130803Smarcel
217130803Smarcel  tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
218130803Smarcel  tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
219130803Smarcel
220130803Smarcel  tdep->jb_pc = 2;
221130803Smarcel  tdep->jb_elt_size = 8;
222130803Smarcel}
223130803Smarcel
224130803Smarcelvoid
225130803Smarcel_initialize_alphanbsd_tdep (void)
226130803Smarcel{
227130803Smarcel  gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
228130803Smarcel                          alphanbsd_init_abi);
229130803Smarcel  gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
230130803Smarcel                          alphanbsd_init_abi);
231130803Smarcel
232130803Smarcel  add_core_fns (&alphanbsd_core_fns);
233130803Smarcel  add_core_fns (&alphanbsd_elfcore_fns);
234130803Smarcel}
235