GDBserver self tests
[deliverable/binutils-gdb.git] / gdb / mips-nbsd-tdep.c
1 /* Target-dependent code for NetBSD/mips.
2
3 Copyright (C) 2002-2017 Free Software Foundation, Inc.
4
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 3 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, see <http://www.gnu.org/licenses/>. */
21
22 #include "defs.h"
23 #include "gdbcore.h"
24 #include "regcache.h"
25 #include "regset.h"
26 #include "target.h"
27 #include "value.h"
28 #include "osabi.h"
29
30 #include "nbsd-tdep.h"
31 #include "mips-nbsd-tdep.h"
32 #include "mips-tdep.h"
33
34 #include "solib-svr4.h"
35
36 /* Shorthand for some register numbers used below. */
37 #define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM
38 #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
39 #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
40
41 /* Core file support. */
42
43 /* Number of registers in `struct reg' from <machine/reg.h>. */
44 #define MIPSNBSD_NUM_GREGS 38
45
46 /* Number of registers in `struct fpreg' from <machine/reg.h>. */
47 #define MIPSNBSD_NUM_FPREGS 33
48
49 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
50 in the floating-point register set REGSET to register cache
51 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
52
53 static void
54 mipsnbsd_supply_fpregset (const struct regset *regset,
55 struct regcache *regcache,
56 int regnum, const void *fpregs, size_t len)
57 {
58 size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
59 const char *regs = (const char *) fpregs;
60 int i;
61
62 gdb_assert (len >= MIPSNBSD_NUM_FPREGS * regsize);
63
64 for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
65 {
66 if (regnum == i || regnum == -1)
67 regcache_raw_supply (regcache, i,
68 regs + (i - MIPS_FP0_REGNUM) * regsize);
69 }
70 }
71
72 /* Supply register REGNUM from the buffer specified by GREGS and LEN
73 in the general-purpose register set REGSET to register cache
74 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
75
76 static void
77 mipsnbsd_supply_gregset (const struct regset *regset,
78 struct regcache *regcache, int regnum,
79 const void *gregs, size_t len)
80 {
81 size_t regsize = mips_isa_regsize (get_regcache_arch (regcache));
82 const char *regs = (const char *) gregs;
83 int i;
84
85 gdb_assert (len >= MIPSNBSD_NUM_GREGS * regsize);
86
87 for (i = 0; i <= MIPS_PC_REGNUM; i++)
88 {
89 if (regnum == i || regnum == -1)
90 regcache_raw_supply (regcache, i, regs + i * regsize);
91 }
92
93 if (len >= (MIPSNBSD_NUM_GREGS + MIPSNBSD_NUM_FPREGS) * regsize)
94 {
95 regs += MIPSNBSD_NUM_GREGS * regsize;
96 len -= MIPSNBSD_NUM_GREGS * regsize;
97 mipsnbsd_supply_fpregset (regset, regcache, regnum, regs, len);
98 }
99 }
100
101 /* NetBSD/mips register sets. */
102
103 static const struct regset mipsnbsd_gregset =
104 {
105 NULL,
106 mipsnbsd_supply_gregset,
107 NULL,
108 REGSET_VARIABLE_SIZE
109 };
110
111 static const struct regset mipsnbsd_fpregset =
112 {
113 NULL,
114 mipsnbsd_supply_fpregset
115 };
116
117 /* Iterate over core file register note sections. */
118
119 static void
120 mipsnbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
121 iterate_over_regset_sections_cb *cb,
122 void *cb_data,
123 const struct regcache *regcache)
124 {
125 size_t regsize = mips_isa_regsize (gdbarch);
126
127 cb (".reg", MIPSNBSD_NUM_GREGS * regsize, &mipsnbsd_gregset,
128 NULL, cb_data);
129 cb (".reg2", MIPSNBSD_NUM_FPREGS * regsize, &mipsnbsd_fpregset,
130 NULL, cb_data);
131 }
132 \f
133
134 /* Conveniently, GDB uses the same register numbering as the
135 ptrace register structure used by NetBSD/mips. */
136
137 void
138 mipsnbsd_supply_reg (struct regcache *regcache, const char *regs, int regno)
139 {
140 struct gdbarch *gdbarch = get_regcache_arch (regcache);
141 int i;
142
143 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
144 {
145 if (regno == i || regno == -1)
146 {
147 if (gdbarch_cannot_fetch_register (gdbarch, i))
148 regcache_raw_supply (regcache, i, NULL);
149 else
150 regcache_raw_supply (regcache, i,
151 regs + (i * mips_isa_regsize (gdbarch)));
152 }
153 }
154 }
155
156 void
157 mipsnbsd_fill_reg (const struct regcache *regcache, char *regs, int regno)
158 {
159 struct gdbarch *gdbarch = get_regcache_arch (regcache);
160 int i;
161
162 for (i = 0; i <= gdbarch_pc_regnum (gdbarch); i++)
163 if ((regno == i || regno == -1)
164 && ! gdbarch_cannot_store_register (gdbarch, i))
165 regcache_raw_collect (regcache, i,
166 regs + (i * mips_isa_regsize (gdbarch)));
167 }
168
169 void
170 mipsnbsd_supply_fpreg (struct regcache *regcache,
171 const char *fpregs, int regno)
172 {
173 struct gdbarch *gdbarch = get_regcache_arch (regcache);
174 int i;
175
176 for (i = gdbarch_fp0_regnum (gdbarch);
177 i <= mips_regnum (gdbarch)->fp_implementation_revision;
178 i++)
179 {
180 if (regno == i || regno == -1)
181 {
182 if (gdbarch_cannot_fetch_register (gdbarch, i))
183 regcache_raw_supply (regcache, i, NULL);
184 else
185 regcache_raw_supply (regcache, i,
186 fpregs
187 + ((i - gdbarch_fp0_regnum (gdbarch))
188 * mips_isa_regsize (gdbarch)));
189 }
190 }
191 }
192
193 void
194 mipsnbsd_fill_fpreg (const struct regcache *regcache, char *fpregs, int regno)
195 {
196 struct gdbarch *gdbarch = get_regcache_arch (regcache);
197 int i;
198
199 for (i = gdbarch_fp0_regnum (gdbarch);
200 i <= mips_regnum (gdbarch)->fp_control_status;
201 i++)
202 if ((regno == i || regno == -1)
203 && ! gdbarch_cannot_store_register (gdbarch, i))
204 regcache_raw_collect (regcache, i,
205 fpregs + ((i - gdbarch_fp0_regnum (gdbarch))
206 * mips_isa_regsize (gdbarch)));
207 }
208
209 #if 0
210
211 /* Under NetBSD/mips, signal handler invocations can be identified by the
212 designated code sequence that is used to return from a signal handler.
213 In particular, the return address of a signal handler points to the
214 following code sequence:
215
216 addu a0, sp, 16
217 li v0, 295 # __sigreturn14
218 syscall
219
220 Each instruction has a unique encoding, so we simply attempt to match
221 the instruction the PC is pointing to with any of the above instructions.
222 If there is a hit, we know the offset to the start of the designated
223 sequence and can then check whether we really are executing in the
224 signal trampoline. If not, -1 is returned, otherwise the offset from the
225 start of the return sequence is returned. */
226
227 #define RETCODE_NWORDS 3
228 #define RETCODE_SIZE (RETCODE_NWORDS * 4)
229
230 static const unsigned char sigtramp_retcode_mipsel[RETCODE_SIZE] =
231 {
232 0x10, 0x00, 0xa4, 0x27, /* addu a0, sp, 16 */
233 0x27, 0x01, 0x02, 0x24, /* li v0, 295 */
234 0x0c, 0x00, 0x00, 0x00, /* syscall */
235 };
236
237 static const unsigned char sigtramp_retcode_mipseb[RETCODE_SIZE] =
238 {
239 0x27, 0xa4, 0x00, 0x10, /* addu a0, sp, 16 */
240 0x24, 0x02, 0x01, 0x27, /* li v0, 295 */
241 0x00, 0x00, 0x00, 0x0c, /* syscall */
242 };
243
244 #endif
245
246 /* Figure out where the longjmp will land. We expect that we have
247 just entered longjmp and haven't yet setup the stack frame, so the
248 args are still in the argument regs. MIPS_A0_REGNUM points at the
249 jmp_buf structure from which we extract the PC that we will land
250 at. The PC is copied into *pc. This routine returns true on
251 success. */
252
253 #define NBSD_MIPS_JB_PC (2 * 4)
254 #define NBSD_MIPS_JB_ELEMENT_SIZE(gdbarch) mips_isa_regsize (gdbarch)
255 #define NBSD_MIPS_JB_OFFSET(gdbarch) (NBSD_MIPS_JB_PC * \
256 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch))
257
258 static int
259 mipsnbsd_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
260 {
261 struct gdbarch *gdbarch = get_frame_arch (frame);
262 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
263 CORE_ADDR jb_addr;
264 gdb_byte *buf;
265
266 buf = (gdb_byte *) alloca (NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch));
267
268 jb_addr = get_frame_register_unsigned (frame, MIPS_A0_REGNUM);
269
270 if (target_read_memory (jb_addr + NBSD_MIPS_JB_OFFSET (gdbarch), buf,
271 NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch)))
272 return 0;
273
274 *pc = extract_unsigned_integer (buf, NBSD_MIPS_JB_ELEMENT_SIZE (gdbarch),
275 byte_order);
276 return 1;
277 }
278
279 static int
280 mipsnbsd_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
281 {
282 return (regno == MIPS_ZERO_REGNUM
283 || regno == mips_regnum (gdbarch)->fp_implementation_revision);
284 }
285
286 static int
287 mipsnbsd_cannot_store_register (struct gdbarch *gdbarch, int regno)
288 {
289 return (regno == MIPS_ZERO_REGNUM
290 || regno == mips_regnum (gdbarch)->fp_implementation_revision);
291 }
292
293 /* Shared library support. */
294
295 /* NetBSD/mips uses a slightly different `struct link_map' than the
296 other NetBSD platforms. */
297
298 static struct link_map_offsets *
299 mipsnbsd_ilp32_fetch_link_map_offsets (void)
300 {
301 static struct link_map_offsets lmo;
302 static struct link_map_offsets *lmp = NULL;
303
304 if (lmp == NULL)
305 {
306 lmp = &lmo;
307
308 lmo.r_version_offset = 0;
309 lmo.r_version_size = 4;
310 lmo.r_map_offset = 4;
311 lmo.r_brk_offset = 8;
312 lmo.r_ldsomap_offset = -1;
313
314 /* Everything we need is in the first 24 bytes. */
315 lmo.link_map_size = 24;
316 lmo.l_addr_offset = 4;
317 lmo.l_name_offset = 8;
318 lmo.l_ld_offset = 12;
319 lmo.l_next_offset = 16;
320 lmo.l_prev_offset = 20;
321 }
322
323 return lmp;
324 }
325
326 static struct link_map_offsets *
327 mipsnbsd_lp64_fetch_link_map_offsets (void)
328 {
329 static struct link_map_offsets lmo;
330 static struct link_map_offsets *lmp = NULL;
331
332 if (lmp == NULL)
333 {
334 lmp = &lmo;
335
336 lmo.r_version_offset = 0;
337 lmo.r_version_size = 4;
338 lmo.r_map_offset = 8;
339 lmo.r_brk_offset = 16;
340 lmo.r_ldsomap_offset = -1;
341
342 /* Everything we need is in the first 40 bytes. */
343 lmo.link_map_size = 48;
344 lmo.l_addr_offset = 0;
345 lmo.l_name_offset = 16;
346 lmo.l_ld_offset = 24;
347 lmo.l_next_offset = 32;
348 lmo.l_prev_offset = 40;
349 }
350
351 return lmp;
352 }
353 \f
354
355 static void
356 mipsnbsd_init_abi (struct gdbarch_info info,
357 struct gdbarch *gdbarch)
358 {
359 set_gdbarch_iterate_over_regset_sections
360 (gdbarch, mipsnbsd_iterate_over_regset_sections);
361
362 set_gdbarch_get_longjmp_target (gdbarch, mipsnbsd_get_longjmp_target);
363
364 set_gdbarch_cannot_fetch_register (gdbarch, mipsnbsd_cannot_fetch_register);
365 set_gdbarch_cannot_store_register (gdbarch, mipsnbsd_cannot_store_register);
366
367 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
368
369 /* NetBSD/mips has SVR4-style shared libraries. */
370 set_solib_svr4_fetch_link_map_offsets
371 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
372 mipsnbsd_ilp32_fetch_link_map_offsets :
373 mipsnbsd_lp64_fetch_link_map_offsets));
374 }
375 \f
376
377 /* Provide a prototype to silence -Wmissing-prototypes. */
378 extern initialize_file_ftype _initialize_mipsnbsd_tdep;
379
380 void
381 _initialize_mipsnbsd_tdep (void)
382 {
383 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_NETBSD,
384 mipsnbsd_init_abi);
385 }
This page took 0.042281 seconds and 4 git commands to generate.