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