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