*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / mipsnbsd-tdep.c
CommitLineData
d1180b0f
MK
1/* Target-dependent code for NetBSD/mips.
2
6aba47ca 3 Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
e4cd0d6a 4
45888261
JT
5 Contributed by Wasabi Systems, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
197e01b6
EZ
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
45888261
JT
23
24#include "defs.h"
25#include "gdbcore.h"
26#include "regcache.h"
d1180b0f 27#include "regset.h"
45888261
JT
28#include "target.h"
29#include "value.h"
30#include "osabi.h"
31
d1180b0f 32#include "gdb_assert.h"
4c7d22cb
MK
33#include "gdb_string.h"
34
3d9b49b0 35#include "nbsd-tdep.h"
45888261 36#include "mipsnbsd-tdep.h"
1777c7b4 37#include "mips-tdep.h"
45888261
JT
38
39#include "solib-svr4.h"
40
d1180b0f
MK
41/* Shorthand for some register numbers used below. */
42#define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM
43#define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
44#define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
45
46/* Core file support. */
47
48/* Number of registers in `struct reg' from <machine/reg.h>. */
49#define MIPSNBSD_NUM_GREGS 38
50
51/* Number of registers in `struct fpreg' from <machine/reg.h>. */
52#define MIPSNBSD_NUM_FPREGS 33
53
54/* Supply register REGNUM from the buffer specified by FPREGS and LEN
55 in the floating-point register set REGSET to register cache
56 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
57
58static void
59mipsnbsd_supply_fpregset (const struct regset *regset,
60 struct regcache *regcache,
61 int regnum, const void *fpregs, size_t len)
62{
63 size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
64 const char *regs = fpregs;
65 int i;
66
67 gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
68
69 for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
70 {
71 if (regnum == i || regnum == -1)
72 regcache_raw_supply (regcache, i,
73 regs + (i - MIPS_FP0_REGNUM) * regsize);
74 }
75}
76
77/* Supply register REGNUM from the buffer specified by GREGS and LEN
78 in the general-purpose register set REGSET to register cache
79 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
80
81static void
82mipsnbsd_supply_gregset (const struct regset *regset,
83 struct regcache *regcache, int regnum,
84 const void *gregs, size_t len)
85{
86 size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
87 const char *regs = gregs;
88 int i;
89
90 gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
91
92 for (i = 0; i <= MIPS_PC_REGNUM; i++)
93 {
94 if (regnum == i || regnum == -1)
95 regcache_raw_supply (regcache, i, regs + i * regsize);
96 }
97
98 if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
99 {
100 regs += MIPSNBSD_NUM_GREGS * regsize;
101 len -= MIPSNBSD_NUM_GREGS * regsize;
102 mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
103 }
104}
105
106/* NetBSD/mips register sets. */
107
108static struct regset mipsnbsd_gregset =
109{
110 NULL,
111 mipsnbsd_supply_gregset
112};
113
114static struct regset mipsnbsd_fpregset =
115{
116 NULL,
117 mipsnbsd_supply_fpregset
118};
119
120/* Return the appropriate register set for the core section identified
121 by SECT_NAME and SECT_SIZE. */
122
123static const struct regset *
124mipsnbsd_regset_from_core_section (struct gdbarch *gdbarch,
125 const char *sect_name, size_t sect_size)
126{
127 size_t regsize = mips_isa_regsize (gdbarch);
128
129 if (strcmp (sect_name, ".reg") == 0
130 && sect_size >= MIPSNBSD_NUM_GREGS * regsize)
131 return &mipsnbsd_gregset;
132
133 if (strcmp (sect_name, ".reg2") == 0
134 && sect_size >= MIPSNBSD_NUM_FPREGS * regsize)
135 return &mipsnbsd_fpregset;
136
137 return NULL;
138}
139\f
140
45888261
JT
141/* Conveniently, GDB uses the same register numbering as the
142 ptrace register structure used by NetBSD/mips. */
143
144void
28f5035f 145mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
45888261
JT
146{
147 int i;
148
3e8c568d 149 for (i = 0; i <= gdbarch_pc_regnum (current_gdbarch); i++)
45888261
JT
150 {
151 if (regno == i || regno == -1)
152 {
8d4c1ba3 153 if (gdbarch_cannot_fetch_register (current_gdbarch, i))
28f5035f 154 regcache_raw_supply (regcache, i, NULL);
45888261 155 else
28f5035f 156 regcache_raw_supply (regcache, i,
23a6d369 157 regs + (i * mips_isa_regsize (current_gdbarch)));
45888261
JT
158 }
159 }
160}
161
162void
28f5035f 163mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
45888261
JT
164{
165 int i;
166
3e8c568d 167 for (i = 0; i <= gdbarch_pc_regnum (current_gdbarch); i++)
8d4c1ba3
UW
168 if ((regno == i || regno == -1)
169 && ! gdbarch_cannot_store_register (current_gdbarch, i))
28f5035f 170 regcache_raw_collect (regcache, i,
822c9732 171 regs + (i * mips_isa_regsize (current_gdbarch)));
45888261
JT
172}
173
174void
28f5035f 175mipsnbsd_supply_fpreg (struct regcache *regcache, const char *fpregs, int regno)
45888261
JT
176{
177 int i;
178
3e8c568d 179 for (i = gdbarch_fp0_regnum (current_gdbarch);
56cea623
AC
180 i <= mips_regnum (current_gdbarch)->fp_implementation_revision;
181 i++)
45888261
JT
182 {
183 if (regno == i || regno == -1)
184 {
8d4c1ba3 185 if (gdbarch_cannot_fetch_register (current_gdbarch, i))
28f5035f 186 regcache_raw_supply (regcache, i, NULL);
45888261 187 else
28f5035f 188 regcache_raw_supply (regcache, i,
3e8c568d
UW
189 fpregs
190 + ((i - gdbarch_fp0_regnum (current_gdbarch))
191 * mips_isa_regsize (current_gdbarch)));
45888261
JT
192 }
193 }
194}
195
196void
28f5035f 197mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
45888261
JT
198{
199 int i;
200
3e8c568d
UW
201 for (i = gdbarch_fp0_regnum (current_gdbarch);
202 i <= mips_regnum (current_gdbarch)->fp_control_status;
56cea623 203 i++)
8d4c1ba3
UW
204 if ((regno == i || regno == -1)
205 && ! gdbarch_cannot_store_register (current_gdbarch, i))
28f5035f 206 regcache_raw_collect (regcache, i,
3e8c568d
UW
207 fpregs + ((i - gdbarch_fp0_regnum
208 (current_gdbarch))
209 * mips_isa_regsize (current_gdbarch)));
45888261
JT
210}
211
45888261
JT
212/* Under NetBSD/mips, signal handler invocations can be identified by the
213 designated code sequence that is used to return from a signal handler.
214 In particular, the return address of a signal handler points to the
215 following code sequence:
216
217 addu a0, sp, 16
218 li v0, 295 # __sigreturn14
219 syscall
220
221 Each instruction has a unique encoding, so we simply attempt to match
222 the instruction the PC is pointing to with any of the above instructions.
223 If there is a hit, we know the offset to the start of the designated
224 sequence and can then check whether we really are executing in the
225 signal trampoline. If not, -1 is returned, otherwise the offset from the
226 start of the return sequence is returned. */
227
228#define RETCODE_NWORDS 3
229#define RETCODE_SIZE (RETCODE_NWORDS * 4)
230
231static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
232{
233 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
234 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
235 0x0c, 0x00, 0x00, 0x00, /* syscall */
236};
237
238static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
239{
240 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
241 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
242 0x00, 0x00, 0x00, 0x0c, /* syscall */
243};
244
245static LONGEST
4c7d22cb 246mipsnbsd_sigtramp_offset (struct frame_info *next_frame)
45888261 247{
4c7d22cb 248 CORE_ADDR pc = frame_pc_unwind (next_frame);
4c6b5505
UW
249 const char *retcode = gdbarch_byte_order (current_gdbarch)
250 == BFD_ENDIAN_BIG ? sigtramp_retcode_mipseb :
251 sigtramp_retcode_mipsel;
45888261
JT
252 unsigned char ret[RETCODE_SIZE], w[4];
253 LONGEST off;
254 int i;
255
4c7d22cb 256 if (!safe_frame_unwind_memory (next_frame, pc, w, sizeof (w)))
45888261
JT
257 return -1;
258
259 for (i = 0; i < RETCODE_NWORDS; i++)
260 {
261 if (memcmp (w, retcode + (i * 4), 4) == 0)
262 break;
263 }
264 if (i == RETCODE_NWORDS)
265 return -1;
266
267 off = i * 4;
268 pc -= off;
269
4c7d22cb 270 if (!safe_frame_unwind_memory (next_frame, pc, ret, sizeof (ret)))
45888261
JT
271 return -1;
272
273 if (memcmp (ret, retcode, RETCODE_SIZE) == 0)
274 return off;
275
276 return -1;
277}
278
45888261 279/* Figure out where the longjmp will land. We expect that we have
4c7d22cb
MK
280 just entered longjmp and haven't yet setup the stack frame, so the
281 args are still in the argument regs. MIPS_A0_REGNUM points at the
45888261
JT
282 jmp_buf structure from which we extract the PC that we will land
283 at. The PC is copied into *pc. This routine returns true on
284 success. */
285
286#define NBSD_MIPS_JB_PC (2 * 4)
1b13c4f6 287#define NBSD_MIPS_JB_ELEMENT_SIZE mips_isa_regsize (current_gdbarch)
45888261
JT
288#define NBSD_MIPS_JB_OFFSET (NBSD_MIPS_JB_PC * \
289 NBSD_MIPS_JB_ELEMENT_SIZE)
290
291static int
60ade65d 292mipsnbsd_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
45888261
JT
293{
294 CORE_ADDR jb_addr;
295 char *buf;
296
297 buf = alloca (NBSD_MIPS_JB_ELEMENT_SIZE);
298
60ade65d 299 jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
45888261
JT
300
301 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET, buf,
302 NBSD_MIPS_JB_ELEMENT_SIZE))
303 return 0;
304
7c0b4a20 305 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE);
45888261
JT
306
307 return 1;
308}
309
310static int
311mipsnbsd_cannot_fetch_register (int regno)
312{
4c7d22cb 313 return (regno == MIPS_ZERO_REGNUM
56cea623 314 || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
45888261
JT
315}
316
317static int
318mipsnbsd_cannot_store_register (int regno)
319{
4c7d22cb 320 return (regno == MIPS_ZERO_REGNUM
56cea623 321 || regno == mips_regnum (current_gdbarch)->fp_implementation_revision);
45888261
JT
322}
323
fabe86c8
MK
324/* Shared library support. */
325
326/* NetBSD/mips uses a slightly different `struct link_map' than the
45888261 327 other NetBSD platforms. */
fabe86c8 328
45888261 329static struct link_map_offsets *
fabe86c8 330mipsnbsd_ilp32_fetch_link_map_offsets (void)
45888261
JT
331{
332 static struct link_map_offsets lmo;
333 static struct link_map_offsets *lmp = NULL;
334
335 if (lmp == NULL)
336 {
337 lmp = &lmo;
338
e4cd0d6a
MK
339 lmo.r_version_offset = 0;
340 lmo.r_version_size = 4;
45888261 341 lmo.r_map_offset = 4;
e4cd0d6a 342 lmo.r_ldsomap_offset = -1;
45888261 343
fabe86c8 344 /* Everything we need is in the first 24 bytes. */
45888261 345 lmo.link_map_size = 24;
4c7d22cb 346 lmo.l_addr_offset = 4;
45888261 347 lmo.l_name_offset = 8;
cc10cae3 348 lmo.l_ld_offset = 12;
45888261 349 lmo.l_next_offset = 16;
45888261 350 lmo.l_prev_offset = 20;
45888261
JT
351 }
352
353 return lmp;
354}
355
356static struct link_map_offsets *
fabe86c8 357mipsnbsd_lp64_fetch_link_map_offsets (void)
45888261
JT
358{
359 static struct link_map_offsets lmo;
360 static struct link_map_offsets *lmp = NULL;
361
362 if (lmp == NULL)
363 {
364 lmp = &lmo;
365
e4cd0d6a
MK
366 lmo.r_version_offset = 0;
367 lmo.r_version_size = 4;
368 lmo.r_map_offset = 8;
369 lmo.r_ldsomap_offset = -1;
45888261 370
fabe86c8 371 /* Everything we need is in the first 40 bytes. */
45888261 372 lmo.link_map_size = 48;
45888261 373 lmo.l_addr_offset = 0;
45888261 374 lmo.l_name_offset = 16;
cc10cae3 375 lmo.l_ld_offset = 24;
45888261 376 lmo.l_next_offset = 32;
45888261 377 lmo.l_prev_offset = 40;
45888261
JT
378 }
379
380 return lmp;
381}
fabe86c8 382\f
45888261
JT
383
384static void
385mipsnbsd_init_abi (struct gdbarch_info info,
386 struct gdbarch *gdbarch)
387{
d1180b0f
MK
388 set_gdbarch_regset_from_core_section
389 (gdbarch, mipsnbsd_regset_from_core_section);
390
45888261
JT
391 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
392
393 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
394 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
395
396 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
397
fabe86c8
MK
398 /* NetBSD/mips has SVR4-style shared libraries. */
399 set_solib_svr4_fetch_link_map_offsets
400 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
401 mipsnbsd_ilp32_fetch_link_map_offsets :
402 mipsnbsd_lp64_fetch_link_map_offsets));
45888261 403}
d1180b0f
MK
404\f
405
406static enum gdb_osabi
407mipsnbsd_core_osabi_sniffer (bfd *abfd)
408{
409 if (strcmp (bfd_get_target (abfd), "netbsd-core") == 0)
410 return GDB_OSABI_NETBSD_ELF;
411
412 return GDB_OSABI_UNKNOWN;
413}
45888261
JT
414
415void
416_initialize_mipsnbsd_tdep (void)
417{
05816f70 418 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD_ELF,
45888261 419 mipsnbsd_init_abi);
45888261 420}
This page took 1.247728 seconds and 4 git commands to generate.