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