1b725ae77Skettenis /* Target-dependent code for MIPS systems running NetBSD.
2*11efff7fSkettenis Copyright 2002, 2003, 2004 Free Software Foundation, Inc.
3b725ae77Skettenis Contributed by Wasabi Systems, Inc.
4b725ae77Skettenis
5b725ae77Skettenis This file is part of GDB.
6b725ae77Skettenis
7b725ae77Skettenis This program is free software; you can redistribute it and/or modify
8b725ae77Skettenis it under the terms of the GNU General Public License as published by
9b725ae77Skettenis the Free Software Foundation; either version 2 of the License, or
10b725ae77Skettenis (at your option) any later version.
11b725ae77Skettenis
12b725ae77Skettenis This program is distributed in the hope that it will be useful,
13b725ae77Skettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
14b725ae77Skettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15b725ae77Skettenis GNU General Public License for more details.
16b725ae77Skettenis
17b725ae77Skettenis You should have received a copy of the GNU General Public License
18b725ae77Skettenis along with this program; if not, write to the Free Software
19b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330,
20b725ae77Skettenis Boston, MA 02111-1307, USA. */
21b725ae77Skettenis
22b725ae77Skettenis #include "defs.h"
23b725ae77Skettenis #include "gdbcore.h"
24b725ae77Skettenis #include "regcache.h"
25b725ae77Skettenis #include "target.h"
26b725ae77Skettenis #include "value.h"
27b725ae77Skettenis #include "osabi.h"
28b725ae77Skettenis
29b725ae77Skettenis #include "nbsd-tdep.h"
30b725ae77Skettenis #include "mipsnbsd-tdep.h"
31*11efff7fSkettenis #include "mips-tdep.h"
32b725ae77Skettenis
33b725ae77Skettenis #include "solib-svr4.h"
34b725ae77Skettenis
35b725ae77Skettenis /* Conveniently, GDB uses the same register numbering as the
36b725ae77Skettenis ptrace register structure used by NetBSD/mips. */
37b725ae77Skettenis
38b725ae77Skettenis void
mipsnbsd_supply_reg(char * regs,int regno)39b725ae77Skettenis mipsnbsd_supply_reg (char *regs, int regno)
40b725ae77Skettenis {
41b725ae77Skettenis int i;
42b725ae77Skettenis
43b725ae77Skettenis for (i = 0; i <= PC_REGNUM; i++)
44b725ae77Skettenis {
45b725ae77Skettenis if (regno == i || regno == -1)
46b725ae77Skettenis {
47b725ae77Skettenis if (CANNOT_FETCH_REGISTER (i))
48*11efff7fSkettenis regcache_raw_supply (current_regcache, i, NULL);
49b725ae77Skettenis else
50*11efff7fSkettenis regcache_raw_supply (current_regcache, i,
51*11efff7fSkettenis regs + (i * mips_isa_regsize (current_gdbarch)));
52b725ae77Skettenis }
53b725ae77Skettenis }
54b725ae77Skettenis }
55b725ae77Skettenis
56b725ae77Skettenis void
mipsnbsd_fill_reg(char * regs,int regno)57b725ae77Skettenis mipsnbsd_fill_reg (char *regs, int regno)
58b725ae77Skettenis {
59b725ae77Skettenis int i;
60b725ae77Skettenis
61b725ae77Skettenis for (i = 0; i <= PC_REGNUM; i++)
62b725ae77Skettenis if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
63*11efff7fSkettenis regcache_raw_collect (current_regcache, i,
64*11efff7fSkettenis regs + (i * mips_isa_regsize (current_gdbarch)));
65b725ae77Skettenis }
66b725ae77Skettenis
67b725ae77Skettenis void
mipsnbsd_supply_fpreg(char * fpregs,int regno)68b725ae77Skettenis mipsnbsd_supply_fpreg (char *fpregs, int regno)
69b725ae77Skettenis {
70b725ae77Skettenis int i;
71b725ae77Skettenis
72b725ae77Skettenis for (i = FP0_REGNUM;
73b725ae77Skettenis i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
74b725ae77Skettenis i++)
75b725ae77Skettenis {
76b725ae77Skettenis if (regno == i || regno == -1)
77b725ae77Skettenis {
78b725ae77Skettenis if (CANNOT_FETCH_REGISTER (i))
79*11efff7fSkettenis regcache_raw_supply (current_regcache, i, NULL);
80b725ae77Skettenis else
81*11efff7fSkettenis regcache_raw_supply (current_regcache, i,
82*11efff7fSkettenis fpregs + ((i - FP0_REGNUM) * mips_isa_regsize (current_gdbarch)));
83b725ae77Skettenis }
84b725ae77Skettenis }
85b725ae77Skettenis }
86b725ae77Skettenis
87b725ae77Skettenis void
mipsnbsd_fill_fpreg(char * fpregs,int regno)88b725ae77Skettenis mipsnbsd_fill_fpreg (char *fpregs, int regno)
89b725ae77Skettenis {
90b725ae77Skettenis int i;
91b725ae77Skettenis
92b725ae77Skettenis for (i = FP0_REGNUM; i <= mips_regnum (current_gdbarch)->fp_control_status;
93b725ae77Skettenis i++)
94b725ae77Skettenis if ((regno == i || regno == -1) && ! CANNOT_STORE_REGISTER (i))
95*11efff7fSkettenis regcache_raw_collect (current_regcache, i,
96*11efff7fSkettenis fpregs + ((i - FP0_REGNUM) * mips_isa_regsize (current_gdbarch)));
97b725ae77Skettenis }
98b725ae77Skettenis
99b725ae77Skettenis static void
fetch_core_registers(char * core_reg_sect,unsigned core_reg_size,int which,CORE_ADDR ignore)100b725ae77Skettenis fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which,
101b725ae77Skettenis CORE_ADDR ignore)
102b725ae77Skettenis {
103b725ae77Skettenis char *regs, *fpregs;
104b725ae77Skettenis
105b725ae77Skettenis /* We get everything from one section. */
106b725ae77Skettenis if (which != 0)
107b725ae77Skettenis return;
108b725ae77Skettenis
109b725ae77Skettenis regs = core_reg_sect;
110b725ae77Skettenis fpregs = core_reg_sect + SIZEOF_STRUCT_REG;
111b725ae77Skettenis
112b725ae77Skettenis /* Integer registers. */
113b725ae77Skettenis mipsnbsd_supply_reg (regs, -1);
114b725ae77Skettenis
115b725ae77Skettenis /* Floating point registers. */
116b725ae77Skettenis mipsnbsd_supply_fpreg (fpregs, -1);
117b725ae77Skettenis }
118b725ae77Skettenis
119b725ae77Skettenis static void
fetch_elfcore_registers(char * core_reg_sect,unsigned core_reg_size,int which,CORE_ADDR ignore)120b725ae77Skettenis fetch_elfcore_registers (char *core_reg_sect, unsigned core_reg_size, int which,
121b725ae77Skettenis CORE_ADDR ignore)
122b725ae77Skettenis {
123b725ae77Skettenis switch (which)
124b725ae77Skettenis {
125b725ae77Skettenis case 0: /* Integer registers. */
126b725ae77Skettenis if (core_reg_size != SIZEOF_STRUCT_REG)
127b725ae77Skettenis warning ("Wrong size register set in core file.");
128b725ae77Skettenis else
129b725ae77Skettenis mipsnbsd_supply_reg (core_reg_sect, -1);
130b725ae77Skettenis break;
131b725ae77Skettenis
132b725ae77Skettenis case 2: /* Floating point registers. */
133b725ae77Skettenis if (core_reg_size != SIZEOF_STRUCT_FPREG)
134b725ae77Skettenis warning ("Wrong size register set in core file.");
135b725ae77Skettenis else
136b725ae77Skettenis mipsnbsd_supply_fpreg (core_reg_sect, -1);
137b725ae77Skettenis break;
138b725ae77Skettenis
139b725ae77Skettenis default:
140b725ae77Skettenis /* Don't know what kind of register request this is; just ignore it. */
141b725ae77Skettenis break;
142b725ae77Skettenis }
143b725ae77Skettenis }
144b725ae77Skettenis
145b725ae77Skettenis static struct core_fns mipsnbsd_core_fns =
146b725ae77Skettenis {
147b725ae77Skettenis bfd_target_unknown_flavour, /* core_flavour */
148b725ae77Skettenis default_check_format, /* check_format */
149b725ae77Skettenis default_core_sniffer, /* core_sniffer */
150b725ae77Skettenis fetch_core_registers, /* core_read_registers */
151b725ae77Skettenis NULL /* next */
152b725ae77Skettenis };
153b725ae77Skettenis
154b725ae77Skettenis static struct core_fns mipsnbsd_elfcore_fns =
155b725ae77Skettenis {
156b725ae77Skettenis bfd_target_elf_flavour, /* core_flavour */
157b725ae77Skettenis default_check_format, /* check_format */
158b725ae77Skettenis default_core_sniffer, /* core_sniffer */
159b725ae77Skettenis fetch_elfcore_registers, /* core_read_registers */
160b725ae77Skettenis NULL /* next */
161b725ae77Skettenis };
162b725ae77Skettenis
163b725ae77Skettenis /* Under NetBSD/mips, signal handler invocations can be identified by the
164b725ae77Skettenis designated code sequence that is used to return from a signal handler.
165b725ae77Skettenis In particular, the return address of a signal handler points to the
166b725ae77Skettenis following code sequence:
167b725ae77Skettenis
168b725ae77Skettenis addu a0, sp, 16
169b725ae77Skettenis li v0, 295 # __sigreturn14
170b725ae77Skettenis syscall
171b725ae77Skettenis
172b725ae77Skettenis Each instruction has a unique encoding, so we simply attempt to match
173b725ae77Skettenis the instruction the PC is pointing to with any of the above instructions.
174b725ae77Skettenis If there is a hit, we know the offset to the start of the designated
175b725ae77Skettenis sequence and can then check whether we really are executing in the
176b725ae77Skettenis signal trampoline. If not, -1 is returned, otherwise the offset from the
177b725ae77Skettenis start of the return sequence is returned. */
178b725ae77Skettenis
179b725ae77Skettenis #define RETCODE_NWORDS 3
180b725ae77Skettenis #define RETCODE_SIZE (RETCODE_NWORDS * 4)
181b725ae77Skettenis
182b725ae77Skettenis static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
183b725ae77Skettenis {
184b725ae77Skettenis 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
185b725ae77Skettenis 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
186b725ae77Skettenis 0x0c, 0x00, 0x00, 0x00, /* syscall */
187b725ae77Skettenis };
188b725ae77Skettenis
189b725ae77Skettenis static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
190b725ae77Skettenis {
191b725ae77Skettenis 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
192b725ae77Skettenis 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
193b725ae77Skettenis 0x00, 0x00, 0x00, 0x0c, /* syscall */
194b725ae77Skettenis };
195b725ae77Skettenis
196b725ae77Skettenis static LONGEST
mipsnbsd_sigtramp_offset(CORE_ADDR pc)197b725ae77Skettenis mipsnbsd_sigtramp_offset (CORE_ADDR pc)
198b725ae77Skettenis {
199b725ae77Skettenis const char *retcode = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
200b725ae77Skettenis ? sigtramp_retcode_mipseb : sigtramp_retcode_mipsel;
201b725ae77Skettenis unsigned char ret[RETCODE_SIZE], w[4];
202b725ae77Skettenis LONGEST off;
203b725ae77Skettenis int i;
204b725ae77Skettenis
205*11efff7fSkettenis if (deprecated_read_memory_nobpt (pc, (char *) w, sizeof (w)) != 0)
206b725ae77Skettenis return -1;
207b725ae77Skettenis
208b725ae77Skettenis for (i = 0; i < RETCODE_NWORDS; i++)
209b725ae77Skettenis {
210b725ae77Skettenis if (memcmp (w, retcode + (i * 4), 4) == 0)
211b725ae77Skettenis break;
212b725ae77Skettenis }
213b725ae77Skettenis if (i == RETCODE_NWORDS)
214b725ae77Skettenis return -1;
215b725ae77Skettenis
216b725ae77Skettenis off = i * 4;
217b725ae77Skettenis pc -= off;
218b725ae77Skettenis
219*11efff7fSkettenis if (deprecated_read_memory_nobpt (pc, (char *) ret, sizeof (ret)) != 0)
220b725ae77Skettenis return -1;
221b725ae77Skettenis
222b725ae77Skettenis if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
223b725ae77Skettenis return off;
224b725ae77Skettenis
225b725ae77Skettenis return -1;
226b725ae77Skettenis }
227b725ae77Skettenis
228b725ae77Skettenis /* Figure out where the longjmp will land. We expect that we have
229b725ae77Skettenis just entered longjmp and haven't yet setup the stack frame, so
230b725ae77Skettenis the args are still in the argument regs. A0_REGNUM points at the
231b725ae77Skettenis jmp_buf structure from which we extract the PC that we will land
232b725ae77Skettenis at. The PC is copied into *pc. This routine returns true on
233b725ae77Skettenis success. */
234b725ae77Skettenis
235b725ae77Skettenis #define NBSD_MIPS_JB_PC (2 * 4)
236*11efff7fSkettenis #define NBSD_MIPS_JB_ELEMENT_SIZE mips_isa_regsize (current_gdbarch)
237b725ae77Skettenis #define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \
238b725ae77Skettenis NBSD_MIPS_JB_ELEMENT_SIZE)
239b725ae77Skettenis
240b725ae77Skettenis static int
mipsnbsd_get_longjmp_target(CORE_ADDR * pc)241b725ae77Skettenis mipsnbsd_get_longjmp_target (CORE_ADDR *pc)
242b725ae77Skettenis {
243b725ae77Skettenis CORE_ADDR jb_addr;
244b725ae77Skettenis char *buf;
245b725ae77Skettenis
246b725ae77Skettenis buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
247b725ae77Skettenis
248b725ae77Skettenis jb_addr = read_register (A0_REGNUM);
249b725ae77Skettenis
250b725ae77Skettenis if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
251b725ae77Skettenis NBSD_MIPS_JB_ELEMENT_SIZE))
252b725ae77Skettenis return 0;
253b725ae77Skettenis
254b725ae77Skettenis *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
255b725ae77Skettenis
256b725ae77Skettenis return 1;
257b725ae77Skettenis }
258b725ae77Skettenis
259b725ae77Skettenis static int
mipsnbsd_cannot_fetch_register(int regno)260b725ae77Skettenis mipsnbsd_cannot_fetch_register (int regno)
261b725ae77Skettenis {
262b725ae77Skettenis return (regno == ZERO_REGNUM
263b725ae77Skettenis || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
264b725ae77Skettenis }
265b725ae77Skettenis
266b725ae77Skettenis static int
mipsnbsd_cannot_store_register(int regno)267b725ae77Skettenis mipsnbsd_cannot_store_register (int regno)
268b725ae77Skettenis {
269b725ae77Skettenis return (regno == ZERO_REGNUM
270b725ae77Skettenis || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
271b725ae77Skettenis }
272b725ae77Skettenis
273b725ae77Skettenis /* NetBSD/mips uses a slightly different link_map structure from the
274b725ae77Skettenis other NetBSD platforms. */
275b725ae77Skettenis static struct link_map_offsets *
mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets(void)276b725ae77Skettenis mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets (void)
277b725ae77Skettenis {
278b725ae77Skettenis static struct link_map_offsets lmo;
279b725ae77Skettenis static struct link_map_offsets *lmp = NULL;
280b725ae77Skettenis
281b725ae77Skettenis if (lmp == NULL)
282b725ae77Skettenis {
283b725ae77Skettenis lmp = &lmo;
284b725ae77Skettenis
285b725ae77Skettenis lmo.r_debug_size = 16;
286b725ae77Skettenis
287b725ae77Skettenis lmo.r_map_offset = 4;
288b725ae77Skettenis lmo.r_map_size = 4;
289b725ae77Skettenis
290b725ae77Skettenis lmo.link_map_size = 24;
291b725ae77Skettenis
292b725ae77Skettenis lmo.l_addr_offset = 0;
293b725ae77Skettenis lmo.l_addr_size = 4;
294b725ae77Skettenis
295b725ae77Skettenis lmo.l_name_offset = 8;
296b725ae77Skettenis lmo.l_name_size = 4;
297b725ae77Skettenis
298b725ae77Skettenis lmo.l_next_offset = 16;
299b725ae77Skettenis lmo.l_next_size = 4;
300b725ae77Skettenis
301b725ae77Skettenis lmo.l_prev_offset = 20;
302b725ae77Skettenis lmo.l_prev_size = 4;
303b725ae77Skettenis }
304b725ae77Skettenis
305b725ae77Skettenis return lmp;
306b725ae77Skettenis }
307b725ae77Skettenis
308b725ae77Skettenis static struct link_map_offsets *
mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets(void)309b725ae77Skettenis mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets (void)
310b725ae77Skettenis {
311b725ae77Skettenis static struct link_map_offsets lmo;
312b725ae77Skettenis static struct link_map_offsets *lmp = NULL;
313b725ae77Skettenis
314b725ae77Skettenis if (lmp == NULL)
315b725ae77Skettenis {
316b725ae77Skettenis lmp = &lmo;
317b725ae77Skettenis
318b725ae77Skettenis lmo.r_debug_size = 32;
319b725ae77Skettenis
320b725ae77Skettenis lmo.r_map_offset = 8;
321b725ae77Skettenis lmo.r_map_size = 8;
322b725ae77Skettenis
323b725ae77Skettenis lmo.link_map_size = 48;
324b725ae77Skettenis
325b725ae77Skettenis lmo.l_addr_offset = 0;
326b725ae77Skettenis lmo.l_addr_size = 8;
327b725ae77Skettenis
328b725ae77Skettenis lmo.l_name_offset = 16;
329b725ae77Skettenis lmo.l_name_size = 8;
330b725ae77Skettenis
331b725ae77Skettenis lmo.l_next_offset = 32;
332b725ae77Skettenis lmo.l_next_size = 8;
333b725ae77Skettenis
334b725ae77Skettenis lmo.l_prev_offset = 40;
335b725ae77Skettenis lmo.l_prev_size = 8;
336b725ae77Skettenis }
337b725ae77Skettenis
338b725ae77Skettenis return lmp;
339b725ae77Skettenis }
340b725ae77Skettenis
341b725ae77Skettenis static void
mipsnbsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)342b725ae77Skettenis mipsnbsd_init_abi (struct gdbarch_info info,
343b725ae77Skettenis struct gdbarch *gdbarch)
344b725ae77Skettenis {
345b725ae77Skettenis set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
346b725ae77Skettenis
347b725ae77Skettenis set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
348b725ae77Skettenis set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
349b725ae77Skettenis
350b725ae77Skettenis set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
351b725ae77Skettenis
352b725ae77Skettenis set_solib_svr4_fetch_link_map_offsets (gdbarch,
353b725ae77Skettenis gdbarch_ptr_bit (gdbarch) == 32 ?
354b725ae77Skettenis mipsnbsd_ilp32_solib_svr4_fetch_link_map_offsets :
355b725ae77Skettenis mipsnbsd_lp64_solib_svr4_fetch_link_map_offsets);
356b725ae77Skettenis }
357b725ae77Skettenis
358b725ae77Skettenis void
_initialize_mipsnbsd_tdep(void)359b725ae77Skettenis _initialize_mipsnbsd_tdep (void)
360b725ae77Skettenis {
361b725ae77Skettenis gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
362b725ae77Skettenis mipsnbsd_init_abi);
363b725ae77Skettenis
364*11efff7fSkettenis deprecated_add_core_fns (&mipsnbsd_core_fns);
365*11efff7fSkettenis deprecated_add_core_fns (&mipsnbsd_elfcore_fns);
366b725ae77Skettenis }
367