xref: /openbsd-src/gnu/usr.bin/binutils/gdb/alphanbsd-tdep.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
1b725ae77Skettenis /* Target-dependent code for NetBSD/Alpha.
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
4b725ae77Skettenis    Contributed by Wasabi Systems, Inc.
5b725ae77Skettenis 
6b725ae77Skettenis    This file is part of GDB.
7b725ae77Skettenis 
8b725ae77Skettenis    This program is free software; you can redistribute it and/or modify
9b725ae77Skettenis    it under the terms of the GNU General Public License as published by
10b725ae77Skettenis    the Free Software Foundation; either version 2 of the License, or
11b725ae77Skettenis    (at your option) any later version.
12b725ae77Skettenis 
13b725ae77Skettenis    This program is distributed in the hope that it will be useful,
14b725ae77Skettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
15b725ae77Skettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16b725ae77Skettenis    GNU General Public License for more details.
17b725ae77Skettenis 
18b725ae77Skettenis    You should have received a copy of the GNU General Public License
19b725ae77Skettenis    along with this program; if not, write to the Free Software
20b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22b725ae77Skettenis 
23b725ae77Skettenis #include "defs.h"
24b725ae77Skettenis #include "gdbcore.h"
25b725ae77Skettenis #include "frame.h"
26b725ae77Skettenis #include "regcache.h"
27b725ae77Skettenis #include "value.h"
28b725ae77Skettenis #include "osabi.h"
29b725ae77Skettenis 
3052ba75afSkettenis #include "gdb_string.h"
31b725ae77Skettenis 
32b725ae77Skettenis #include "alpha-tdep.h"
33b725ae77Skettenis #include "alphabsd-tdep.h"
34b725ae77Skettenis #include "nbsd-tdep.h"
35*63addd46Skettenis #include "solib-svr4.h"
36b725ae77Skettenis 
37b725ae77Skettenis static void
fetch_core_registers(char * core_reg_sect,unsigned core_reg_size,int which,CORE_ADDR ignore)38b725ae77Skettenis fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
39b725ae77Skettenis                       CORE_ADDR ignore)
40b725ae77Skettenis {
41b725ae77Skettenis   char *regs, *fpregs;
42b725ae77Skettenis   int regno;
43b725ae77Skettenis 
44b725ae77Skettenis   /* Table to map a gdb register number to a trapframe register index.  */
45b725ae77Skettenis   static const int regmap[] =
46b725ae77Skettenis   {
47b725ae77Skettenis      0,   1,   2,   3,
48b725ae77Skettenis      4,   5,   6,   7,
49b725ae77Skettenis      8,   9,  10,  11,
50b725ae77Skettenis     12,  13,  14,  15,
51b725ae77Skettenis     30,  31,  32,  16,
52b725ae77Skettenis     17,  18,  19,  20,
53b725ae77Skettenis     21,  22,  23,  24,
54b725ae77Skettenis     25,  29,  26
55b725ae77Skettenis   };
56b725ae77Skettenis #define SIZEOF_TRAPFRAME (33 * 8)
57b725ae77Skettenis 
58b725ae77Skettenis   /* We get everything from one section.  */
59b725ae77Skettenis   if (which != 0)
60b725ae77Skettenis     return;
61b725ae77Skettenis 
62b725ae77Skettenis   regs = core_reg_sect;
63b725ae77Skettenis   fpregs = core_reg_sect + SIZEOF_TRAPFRAME;
64b725ae77Skettenis 
65b725ae77Skettenis   if (core_reg_size < (SIZEOF_TRAPFRAME + SIZEOF_STRUCT_FPREG))
66b725ae77Skettenis     {
67b725ae77Skettenis       warning ("Wrong size register set in core file.");
68b725ae77Skettenis       return;
69b725ae77Skettenis     }
70b725ae77Skettenis 
71b725ae77Skettenis   /* Integer registers.  */
72b725ae77Skettenis   for (regno = 0; regno < ALPHA_ZERO_REGNUM; regno++)
73*63addd46Skettenis     regcache_raw_supply (current_regcache, regno, regs + (regmap[regno] * 8));
74*63addd46Skettenis   regcache_raw_supply (current_regcache, ALPHA_ZERO_REGNUM, NULL);
75*63addd46Skettenis   regcache_raw_supply (current_regcache, PC_REGNUM, regs + (28 * 8));
76b725ae77Skettenis 
77b725ae77Skettenis   /* Floating point registers.  */
78b725ae77Skettenis   alphabsd_supply_fpreg (fpregs, -1);
79b725ae77Skettenis }
80b725ae77Skettenis 
81b725ae77Skettenis static void
fetch_elfcore_registers(char * core_reg_sect,unsigned core_reg_size,int which,CORE_ADDR ignore)82b725ae77Skettenis fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
83b725ae77Skettenis                          CORE_ADDR ignore)
84b725ae77Skettenis {
85b725ae77Skettenis   switch (which)
86b725ae77Skettenis     {
87b725ae77Skettenis     case 0:  /* Integer registers.  */
88b725ae77Skettenis       if (core_reg_size != SIZEOF_STRUCT_REG)
89b725ae77Skettenis 	warning ("Wrong size register set in core file.");
90b725ae77Skettenis       else
91b725ae77Skettenis 	alphabsd_supply_reg (core_reg_sect, -1);
92b725ae77Skettenis       break;
93b725ae77Skettenis 
94b725ae77Skettenis     case 2:  /* Floating point registers.  */
95b725ae77Skettenis       if (core_reg_size != SIZEOF_STRUCT_FPREG)
96b725ae77Skettenis 	warning ("Wrong size FP register set in core file.");
97b725ae77Skettenis       else
98b725ae77Skettenis 	alphabsd_supply_fpreg (core_reg_sect, -1);
99b725ae77Skettenis       break;
100b725ae77Skettenis 
101b725ae77Skettenis     default:
102b725ae77Skettenis       /* Don't know what kind of register request this is; just ignore it.  */
103b725ae77Skettenis       break;
104b725ae77Skettenis     }
105b725ae77Skettenis }
106b725ae77Skettenis 
107b725ae77Skettenis static struct core_fns alphanbsd_core_fns =
108b725ae77Skettenis {
109b725ae77Skettenis   bfd_target_unknown_flavour,		/* core_flavour */
110b725ae77Skettenis   default_check_format,			/* check_format */
111b725ae77Skettenis   default_core_sniffer,			/* core_sniffer */
112b725ae77Skettenis   fetch_core_registers,			/* core_read_registers */
113b725ae77Skettenis   NULL					/* next */
114b725ae77Skettenis };
115b725ae77Skettenis 
116b725ae77Skettenis static struct core_fns alphanbsd_elfcore_fns =
117b725ae77Skettenis {
118b725ae77Skettenis   bfd_target_elf_flavour,		/* core_flavour */
119b725ae77Skettenis   default_check_format,			/* check_format */
120b725ae77Skettenis   default_core_sniffer,			/* core_sniffer */
121b725ae77Skettenis   fetch_elfcore_registers,		/* core_read_registers */
122b725ae77Skettenis   NULL					/* next */
123b725ae77Skettenis };
124b725ae77Skettenis 
125b725ae77Skettenis /* Under NetBSD/alpha, signal handler invocations can be identified by the
126b725ae77Skettenis    designated code sequence that is used to return from a signal handler.
127b725ae77Skettenis    In particular, the return address of a signal handler points to the
128b725ae77Skettenis    following code sequence:
129b725ae77Skettenis 
130b725ae77Skettenis 	ldq	a0, 0(sp)
131b725ae77Skettenis 	lda	sp, 16(sp)
132b725ae77Skettenis 	lda	v0, 295(zero)	# __sigreturn14
133b725ae77Skettenis 	call_pal callsys
134b725ae77Skettenis 
135b725ae77Skettenis    Each instruction has a unique encoding, so we simply attempt to match
136b725ae77Skettenis    the instruction the PC is pointing to with any of the above instructions.
137b725ae77Skettenis    If there is a hit, we know the offset to the start of the designated
138b725ae77Skettenis    sequence and can then check whether we really are executing in the
139b725ae77Skettenis    signal trampoline.  If not, -1 is returned, otherwise the offset from the
140b725ae77Skettenis    start of the return sequence is returned.  */
141b725ae77Skettenis static const unsigned char sigtramp_retcode[] =
142b725ae77Skettenis {
143b725ae77Skettenis   0x00, 0x00, 0x1e, 0xa6,	/* ldq a0, 0(sp) */
144b725ae77Skettenis   0x10, 0x00, 0xde, 0x23,	/* lda sp, 16(sp) */
145b725ae77Skettenis   0x27, 0x01, 0x1f, 0x20,	/* lda v0, 295(zero) */
146b725ae77Skettenis   0x83, 0x00, 0x00, 0x00,	/* call_pal callsys */
147b725ae77Skettenis };
148b725ae77Skettenis #define RETCODE_NWORDS		4
149b725ae77Skettenis #define RETCODE_SIZE		(RETCODE_NWORDS * 4)
150b725ae77Skettenis 
151b725ae77Skettenis LONGEST
alphanbsd_sigtramp_offset(CORE_ADDR pc)152b725ae77Skettenis alphanbsd_sigtramp_offset (CORE_ADDR pc)
153b725ae77Skettenis {
154b725ae77Skettenis   unsigned char ret[RETCODE_SIZE], w[4];
155b725ae77Skettenis   LONGEST off;
156b725ae77Skettenis   int i;
157b725ae77Skettenis 
158*63addd46Skettenis   if (deprecated_read_memory_nobpt (pc, (char *) w, 4) != 0)
159b725ae77Skettenis     return -1;
160b725ae77Skettenis 
161b725ae77Skettenis   for (i = 0; i < RETCODE_NWORDS; i++)
162b725ae77Skettenis     {
163b725ae77Skettenis       if (memcmp (w, sigtramp_retcode + (i * 4), 4) == 0)
164b725ae77Skettenis 	break;
165b725ae77Skettenis     }
166b725ae77Skettenis   if (i == RETCODE_NWORDS)
167b725ae77Skettenis     return (-1);
168b725ae77Skettenis 
169b725ae77Skettenis   off = i * 4;
170b725ae77Skettenis   pc -= off;
171b725ae77Skettenis 
172*63addd46Skettenis   if (deprecated_read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
173b725ae77Skettenis     return -1;
174b725ae77Skettenis 
175b725ae77Skettenis   if (memcmp (ret, sigtramp_retcode, RETCODE_SIZE) == 0)
176b725ae77Skettenis     return off;
177b725ae77Skettenis 
178b725ae77Skettenis   return -1;
179b725ae77Skettenis }
180b725ae77Skettenis 
181b725ae77Skettenis static int
alphanbsd_pc_in_sigtramp(CORE_ADDR pc,char * func_name)182b725ae77Skettenis alphanbsd_pc_in_sigtramp (CORE_ADDR pc, char *func_name)
183b725ae77Skettenis {
184b725ae77Skettenis   return (nbsd_pc_in_sigtramp (pc, func_name)
185b725ae77Skettenis 	  || alphanbsd_sigtramp_offset (pc) >= 0);
186b725ae77Skettenis }
187b725ae77Skettenis 
188b725ae77Skettenis static CORE_ADDR
alphanbsd_sigcontext_addr(struct frame_info * frame)189b725ae77Skettenis alphanbsd_sigcontext_addr (struct frame_info *frame)
190b725ae77Skettenis {
191b725ae77Skettenis   /* FIXME: This is not correct for all versions of NetBSD/alpha.
192b725ae77Skettenis      We will probably need to disassemble the trampoline to figure
193b725ae77Skettenis      out which trampoline frame type we have.  */
194b725ae77Skettenis   return get_frame_base (frame);
195b725ae77Skettenis }
196b725ae77Skettenis 
197b725ae77Skettenis static void
alphanbsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)198b725ae77Skettenis alphanbsd_init_abi (struct gdbarch_info info,
199b725ae77Skettenis                     struct gdbarch *gdbarch)
200b725ae77Skettenis {
201b725ae77Skettenis   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
202b725ae77Skettenis 
203b725ae77Skettenis   /* Hook into the DWARF CFI frame unwinder.  */
204b725ae77Skettenis   alpha_dwarf2_init_abi (info, gdbarch);
205b725ae77Skettenis 
206b725ae77Skettenis   /* Hook into the MDEBUG frame unwinder.  */
207b725ae77Skettenis   alpha_mdebug_init_abi (info, gdbarch);
208b725ae77Skettenis 
209b725ae77Skettenis   /* NetBSD/alpha does not provide single step support via ptrace(2); we
210b725ae77Skettenis      must use software single-stepping.  */
211b725ae77Skettenis   set_gdbarch_software_single_step (gdbarch, alpha_software_single_step);
212b725ae77Skettenis 
213b725ae77Skettenis   set_solib_svr4_fetch_link_map_offsets (gdbarch,
214b725ae77Skettenis                                  nbsd_lp64_solib_svr4_fetch_link_map_offsets);
215b725ae77Skettenis 
216b725ae77Skettenis   tdep->dynamic_sigtramp_offset = alphanbsd_sigtramp_offset;
217*63addd46Skettenis   tdep->pc_in_sigtramp = alphanbsd_pc_in_sigtramp;
218b725ae77Skettenis   tdep->sigcontext_addr = alphanbsd_sigcontext_addr;
219b725ae77Skettenis 
220b725ae77Skettenis   tdep->jb_pc = 2;
221b725ae77Skettenis   tdep->jb_elt_size = 8;
222b725ae77Skettenis }
223b725ae77Skettenis 
224b725ae77Skettenis void
_initialize_alphanbsd_tdep(void)225b725ae77Skettenis _initialize_alphanbsd_tdep (void)
226b725ae77Skettenis {
227b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_NETBSD_ELF,
228b725ae77Skettenis                           alphanbsd_init_abi);
229b725ae77Skettenis   gdbarch_register_osabi (bfd_arch_alpha, 0, GDB_OSABI_OPENBSD_ELF,
230b725ae77Skettenis                           alphanbsd_init_abi);
231b725ae77Skettenis 
232*63addd46Skettenis   deprecated_add_core_fns (&alphanbsd_core_fns);
233*63addd46Skettenis   deprecated_add_core_fns (&alphanbsd_elfcore_fns);
234b725ae77Skettenis }
235