Add inclusive range support for Rust
[deliverable/binutils-gdb.git] / gdb / mips-fbsd-tdep.c
CommitLineData
387360da
JB
1/* Target-dependent code for FreeBSD/mips.
2
e2882c85 3 Copyright (C) 2017-2018 Free Software Foundation, Inc.
387360da
JB
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 3 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, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "osabi.h"
22#include "regset.h"
23#include "trad-frame.h"
24#include "tramp-frame.h"
25
26#include "fbsd-tdep.h"
27#include "mips-tdep.h"
28#include "mips-fbsd-tdep.h"
29
30#include "solib-svr4.h"
31
387360da
JB
32/* Core file support. */
33
34/* Number of registers in `struct reg' from <machine/reg.h>. The
35 first 38 follow the standard MIPS layout. The 39th holds
36 IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for
37 padding. */
38#define MIPS_FBSD_NUM_GREGS 40
39
40/* Number of registers in `struct fpreg' from <machine/reg.h>. The
41 first 32 hold floating point registers. 33 holds the FSR. The
7755ddb7
JB
42 34th holds FIR on FreeBSD 12.0 and newer kernels. On older kernels
43 it was a zero-filled dummy for padding. */
387360da
JB
44#define MIPS_FBSD_NUM_FPREGS 34
45
b057297a
AH
46/* Supply a single register. The register size might not match, so use
47 regcache->raw_supply_integer (). */
387360da
JB
48
49static void
50mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
51 size_t len)
52{
b057297a 53 regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true);
387360da
JB
54}
55
b057297a
AH
56/* Collect a single register. The register size might not match, so use
57 regcache->raw_collect_integer (). */
387360da
JB
58
59static void
60mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
61 size_t len)
62{
b057297a 63 regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true);
387360da
JB
64}
65
66/* Supply the floating-point registers stored in FPREGS to REGCACHE.
67 Each floating-point register in FPREGS is REGSIZE bytes in
68 length. */
69
70void
71mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum,
72 const void *fpregs, size_t regsize)
73{
ac7936df 74 struct gdbarch *gdbarch = regcache->arch ();
387360da 75 const gdb_byte *regs = (const gdb_byte *) fpregs;
7755ddb7 76 int i, fp0num;
387360da 77
f7241d4f 78 fp0num = mips_regnum (gdbarch)->fp0;
7755ddb7
JB
79 for (i = 0; i <= 32; i++)
80 if (regnum == fp0num + i || regnum == -1)
81 mips_fbsd_supply_reg (regcache, fp0num + i,
82 regs + i * regsize, regsize);
83 if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1)
84 mips_fbsd_supply_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
85 regs + 32 * regsize, regsize);
86 if ((regnum == mips_regnum (gdbarch)->fp_implementation_revision
87 || regnum == -1)
88 && extract_unsigned_integer (regs + 33 * regsize, regsize,
89 gdbarch_byte_order (gdbarch)) != 0)
90 mips_fbsd_supply_reg (regcache,
91 mips_regnum (gdbarch)->fp_implementation_revision,
92 regs + 33 * regsize, regsize);
387360da
JB
93}
94
95/* Supply the general-purpose registers stored in GREGS to REGCACHE.
96 Each general-purpose register in GREGS is REGSIZE bytes in
97 length. */
98
99void
100mips_fbsd_supply_gregs (struct regcache *regcache, int regnum,
101 const void *gregs, size_t regsize)
102{
ac7936df 103 struct gdbarch *gdbarch = regcache->arch ();
387360da
JB
104 const gdb_byte *regs = (const gdb_byte *) gregs;
105 int i;
106
f7241d4f 107 for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
387360da
JB
108 if (regnum == i || regnum == -1)
109 mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize);
110}
111
112/* Collect the floating-point registers from REGCACHE and store them
113 in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes
114 in length. */
115
116void
117mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum,
118 void *fpregs, size_t regsize)
119{
ac7936df 120 struct gdbarch *gdbarch = regcache->arch ();
387360da 121 gdb_byte *regs = (gdb_byte *) fpregs;
7755ddb7 122 int i, fp0num;
387360da 123
f7241d4f 124 fp0num = mips_regnum (gdbarch)->fp0;
7755ddb7
JB
125 for (i = 0; i < 32; i++)
126 if (regnum == fp0num + i || regnum == -1)
127 mips_fbsd_collect_reg (regcache, fp0num + i,
128 regs + i * regsize, regsize);
129 if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1)
130 mips_fbsd_collect_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
131 regs + 32 * regsize, regsize);
132 if (regnum == mips_regnum (gdbarch)->fp_implementation_revision
133 || regnum == -1)
134 mips_fbsd_collect_reg (regcache,
135 mips_regnum (gdbarch)->fp_implementation_revision,
136 regs + 33 * regsize, regsize);
387360da
JB
137}
138
139/* Collect the general-purpose registers from REGCACHE and store them
140 in GREGS. Each general-purpose register in GREGS is REGSIZE bytes
141 in length. */
142
143void
144mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum,
145 void *gregs, size_t regsize)
146{
ac7936df 147 struct gdbarch *gdbarch = regcache->arch ();
387360da
JB
148 gdb_byte *regs = (gdb_byte *) gregs;
149 int i;
150
f7241d4f 151 for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
387360da
JB
152 if (regnum == i || regnum == -1)
153 mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize);
154}
155
156/* Supply register REGNUM from the buffer specified by FPREGS and LEN
157 in the floating-point register set REGSET to register cache
158 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
159
160static void
161mips_fbsd_supply_fpregset (const struct regset *regset,
162 struct regcache *regcache,
163 int regnum, const void *fpregs, size_t len)
164{
ac7936df 165 size_t regsize = mips_abi_regsize (regcache->arch ());
387360da
JB
166
167 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
168
169 mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize);
170}
171
172/* Collect register REGNUM from the register cache REGCACHE and store
173 it in the buffer specified by FPREGS and LEN in the floating-point
174 register set REGSET. If REGNUM is -1, do this for all registers in
175 REGSET. */
176
177static void
178mips_fbsd_collect_fpregset (const struct regset *regset,
179 const struct regcache *regcache,
180 int regnum, void *fpregs, size_t len)
181{
ac7936df 182 size_t regsize = mips_abi_regsize (regcache->arch ());
387360da
JB
183
184 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
185
186 mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize);
187}
188
189/* Supply register REGNUM from the buffer specified by GREGS and LEN
190 in the general-purpose register set REGSET to register cache
191 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
192
193static void
194mips_fbsd_supply_gregset (const struct regset *regset,
195 struct regcache *regcache, int regnum,
196 const void *gregs, size_t len)
197{
ac7936df 198 size_t regsize = mips_abi_regsize (regcache->arch ());
387360da
JB
199
200 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
201
202 mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize);
203}
204
205/* Collect register REGNUM from the register cache REGCACHE and store
206 it in the buffer specified by GREGS and LEN in the general-purpose
207 register set REGSET. If REGNUM is -1, do this for all registers in
208 REGSET. */
209
210static void
211mips_fbsd_collect_gregset (const struct regset *regset,
212 const struct regcache *regcache,
213 int regnum, void *gregs, size_t len)
214{
ac7936df 215 size_t regsize = mips_abi_regsize (regcache->arch ());
387360da
JB
216
217 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
218
219 mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize);
220}
221
222/* FreeBSD/mips register sets. */
223
224static const struct regset mips_fbsd_gregset =
225{
226 NULL,
227 mips_fbsd_supply_gregset,
228 mips_fbsd_collect_gregset,
229};
230
231static const struct regset mips_fbsd_fpregset =
232{
233 NULL,
234 mips_fbsd_supply_fpregset,
235 mips_fbsd_collect_fpregset,
236};
237
238/* Iterate over core file register note sections. */
239
240static void
241mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
242 iterate_over_regset_sections_cb *cb,
243 void *cb_data,
244 const struct regcache *regcache)
245{
246 size_t regsize = mips_abi_regsize (gdbarch);
247
248 cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, &mips_fbsd_gregset,
249 NULL, cb_data);
250 cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, &mips_fbsd_fpregset,
251 NULL, cb_data);
252}
253
254/* Signal trampoline support. */
255
256#define FBSD_SYS_sigreturn 417
257
258#define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn
259#define MIPS_INST_SYSCALL 0x0000000c
260#define MIPS_INST_BREAK 0x0000000d
261
262#define O32_SIGFRAME_UCONTEXT_OFFSET (16)
263#define O32_SIGSET_T_SIZE (16)
264
265#define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE)
266#define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4)
267#define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4)
268#define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32)
269#define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4)
270#define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4)
271#define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4)
272#define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4)
273
274#define O32_UCONTEXT_REG_SIZE 4
275
276static void
277mips_fbsd_sigframe_init (const struct tramp_frame *self,
278 struct frame_info *this_frame,
279 struct trad_frame_cache *cache,
280 CORE_ADDR func)
281{
282 struct gdbarch *gdbarch = get_frame_arch (this_frame);
283 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
284 CORE_ADDR sp, ucontext_addr, addr;
285 int regnum;
286 gdb_byte buf[4];
287
288 /* We find the appropriate instance of `ucontext_t' at a
289 fixed offset in the signal frame. */
290 sp = get_frame_register_signed (this_frame,
291 MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
292 ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET;
293
294 /* PC. */
295 regnum = mips_regnum (gdbarch)->pc;
296 trad_frame_set_reg_addr (cache,
297 regnum + gdbarch_num_regs (gdbarch),
298 ucontext_addr + O32_UCONTEXT_PC);
299
300 /* GPRs. */
301 for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS;
302 regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE)
303 trad_frame_set_reg_addr (cache,
304 regnum + gdbarch_num_regs (gdbarch),
305 addr);
306
307 regnum = MIPS_PS_REGNUM;
308 trad_frame_set_reg_addr (cache,
309 regnum + gdbarch_num_regs (gdbarch),
310 ucontext_addr + O32_UCONTEXT_SR);
311
312 /* HI and LO. */
313 regnum = mips_regnum (gdbarch)->lo;
314 trad_frame_set_reg_addr (cache,
315 regnum + gdbarch_num_regs (gdbarch),
316 ucontext_addr + O32_UCONTEXT_LO);
317 regnum = mips_regnum (gdbarch)->hi;
318 trad_frame_set_reg_addr (cache,
319 regnum + gdbarch_num_regs (gdbarch),
320 ucontext_addr + O32_UCONTEXT_HI);
321
1c33cd7f
YQ
322 if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0
323 && extract_unsigned_integer (buf, 4, byte_order) != 0)
387360da
JB
324 {
325 for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS;
326 regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE)
327 trad_frame_set_reg_addr (cache,
328 regnum + gdbarch_fp0_regnum (gdbarch),
329 addr);
330 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
331 addr);
332 }
333
334 trad_frame_set_id (cache, frame_id_build (sp, func));
335}
336
337#define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \
338 + O32_SIGFRAME_UCONTEXT_OFFSET)
339
340static const struct tramp_frame mips_fbsd_sigframe =
341{
342 SIGTRAMP_FRAME,
343 MIPS_INSN32_SIZE,
344 {
345 { MIPS_INST_ADDIU_A0_SP_O32, -1 }, /* addiu a0, sp, SIGF_UC */
346 { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */
347 { MIPS_INST_SYSCALL, -1 }, /* syscall */
348 { MIPS_INST_BREAK, -1 }, /* break */
349 { TRAMP_SENTINEL_INSN, -1 }
350 },
351 mips_fbsd_sigframe_init
352};
353
354#define N64_SIGFRAME_UCONTEXT_OFFSET (32)
355#define N64_SIGSET_T_SIZE (16)
356
357#define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE)
358#define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8)
359#define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8)
360#define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32)
361#define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8)
362#define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8)
363#define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8)
364#define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8)
365
366#define N64_UCONTEXT_REG_SIZE 8
367
368static void
369mips64_fbsd_sigframe_init (const struct tramp_frame *self,
370 struct frame_info *this_frame,
371 struct trad_frame_cache *cache,
372 CORE_ADDR func)
373{
374 struct gdbarch *gdbarch = get_frame_arch (this_frame);
375 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
376 CORE_ADDR sp, ucontext_addr, addr;
377 int regnum;
378 gdb_byte buf[4];
379
380 /* We find the appropriate instance of `ucontext_t' at a
381 fixed offset in the signal frame. */
382 sp = get_frame_register_signed (this_frame,
383 MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
384 ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET;
385
386 /* PC. */
387 regnum = mips_regnum (gdbarch)->pc;
388 trad_frame_set_reg_addr (cache,
389 regnum + gdbarch_num_regs (gdbarch),
390 ucontext_addr + N64_UCONTEXT_PC);
391
392 /* GPRs. */
393 for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS;
394 regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE)
395 trad_frame_set_reg_addr (cache,
396 regnum + gdbarch_num_regs (gdbarch),
397 addr);
398
399 regnum = MIPS_PS_REGNUM;
400 trad_frame_set_reg_addr (cache,
401 regnum + gdbarch_num_regs (gdbarch),
402 ucontext_addr + N64_UCONTEXT_SR);
403
404 /* HI and LO. */
405 regnum = mips_regnum (gdbarch)->lo;
406 trad_frame_set_reg_addr (cache,
407 regnum + gdbarch_num_regs (gdbarch),
408 ucontext_addr + N64_UCONTEXT_LO);
409 regnum = mips_regnum (gdbarch)->hi;
410 trad_frame_set_reg_addr (cache,
411 regnum + gdbarch_num_regs (gdbarch),
412 ucontext_addr + N64_UCONTEXT_HI);
413
1c33cd7f
YQ
414 if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0
415 && extract_unsigned_integer (buf, 4, byte_order) != 0)
387360da
JB
416 {
417 for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS;
418 regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE)
419 trad_frame_set_reg_addr (cache,
420 regnum + gdbarch_fp0_regnum (gdbarch),
421 addr);
422 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
423 addr);
424 }
425
426 trad_frame_set_id (cache, frame_id_build (sp, func));
427}
428
a80a6471
JB
429#define MIPS_INST_ADDIU_A0_SP_N32 (0x27a40000 \
430 + N64_SIGFRAME_UCONTEXT_OFFSET)
431
432static const struct tramp_frame mipsn32_fbsd_sigframe =
433{
434 SIGTRAMP_FRAME,
435 MIPS_INSN32_SIZE,
436 {
437 { MIPS_INST_ADDIU_A0_SP_N32, -1 }, /* addiu a0, sp, SIGF_UC */
438 { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */
439 { MIPS_INST_SYSCALL, -1 }, /* syscall */
440 { MIPS_INST_BREAK, -1 }, /* break */
441 { TRAMP_SENTINEL_INSN, -1 }
442 },
443 mips64_fbsd_sigframe_init
444};
445
387360da
JB
446#define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
447 + N64_SIGFRAME_UCONTEXT_OFFSET)
448
449static const struct tramp_frame mips64_fbsd_sigframe =
450{
451 SIGTRAMP_FRAME,
452 MIPS_INSN32_SIZE,
453 {
454 { MIPS_INST_DADDIU_A0_SP_N64, -1 }, /* daddiu a0, sp, SIGF_UC */
455 { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */
456 { MIPS_INST_SYSCALL, -1 }, /* syscall */
457 { MIPS_INST_BREAK, -1 }, /* break */
458 { TRAMP_SENTINEL_INSN, -1 }
459 },
460 mips64_fbsd_sigframe_init
461};
462
463/* Shared library support. */
464
465/* FreeBSD/mips uses a slightly different `struct link_map' than the
466 other FreeBSD platforms as it includes an additional `l_off'
467 member. */
468
469static struct link_map_offsets *
470mips_fbsd_ilp32_fetch_link_map_offsets (void)
471{
472 static struct link_map_offsets lmo;
473 static struct link_map_offsets *lmp = NULL;
474
475 if (lmp == NULL)
476 {
477 lmp = &lmo;
478
479 lmo.r_version_offset = 0;
480 lmo.r_version_size = 4;
481 lmo.r_map_offset = 4;
482 lmo.r_brk_offset = 8;
483 lmo.r_ldsomap_offset = -1;
484
485 lmo.link_map_size = 24;
486 lmo.l_addr_offset = 0;
487 lmo.l_name_offset = 8;
488 lmo.l_ld_offset = 12;
489 lmo.l_next_offset = 16;
490 lmo.l_prev_offset = 20;
491 }
492
493 return lmp;
494}
495
496static struct link_map_offsets *
497mips_fbsd_lp64_fetch_link_map_offsets (void)
498{
499 static struct link_map_offsets lmo;
500 static struct link_map_offsets *lmp = NULL;
501
502 if (lmp == NULL)
503 {
504 lmp = &lmo;
505
506 lmo.r_version_offset = 0;
507 lmo.r_version_size = 4;
508 lmo.r_map_offset = 8;
509 lmo.r_brk_offset = 16;
510 lmo.r_ldsomap_offset = -1;
511
512 lmo.link_map_size = 48;
513 lmo.l_addr_offset = 0;
514 lmo.l_name_offset = 16;
515 lmo.l_ld_offset = 24;
516 lmo.l_next_offset = 32;
517 lmo.l_prev_offset = 40;
518 }
519
520 return lmp;
521}
522
523static void
524mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
525{
526 enum mips_abi abi = mips_abi (gdbarch);
527
528 /* Generic FreeBSD support. */
529 fbsd_init_abi (info, gdbarch);
530
531 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
532
533 switch (abi)
534 {
535 case MIPS_ABI_O32:
536 tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe);
537 break;
538 case MIPS_ABI_N32:
a80a6471 539 tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe);
387360da
JB
540 break;
541 case MIPS_ABI_N64:
542 tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe);
543 break;
544 }
545
546 set_gdbarch_iterate_over_regset_sections
547 (gdbarch, mips_fbsd_iterate_over_regset_sections);
548
549 /* FreeBSD/mips has SVR4-style shared libraries. */
550 set_solib_svr4_fetch_link_map_offsets
551 (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
552 mips_fbsd_ilp32_fetch_link_map_offsets :
553 mips_fbsd_lp64_fetch_link_map_offsets));
554}
387360da
JB
555
556void
557_initialize_mips_fbsd_tdep (void)
558{
c988ac1d 559 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
387360da
JB
560 mips_fbsd_init_abi);
561}
This page took 0.167712 seconds and 4 git commands to generate.