1 /* Target-dependent code for FreeBSD/mips.
3 Copyright (C) 2017 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
23 #include "trad-frame.h"
24 #include "tramp-frame.h"
26 #include "fbsd-tdep.h"
27 #include "mips-tdep.h"
28 #include "mips-fbsd-tdep.h"
30 #include "solib-svr4.h"
32 /* Shorthand for some register numbers used below. */
33 #define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM
34 #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
35 #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
37 /* Core file support. */
39 /* Number of registers in `struct reg' from <machine/reg.h>. The
40 first 38 follow the standard MIPS layout. The 39th holds
41 IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for
43 #define MIPS_FBSD_NUM_GREGS 40
45 /* Number of registers in `struct fpreg' from <machine/reg.h>. The
46 first 32 hold floating point registers. 33 holds the FSR. The
47 34th is a dummy for padding. */
48 #define MIPS_FBSD_NUM_FPREGS 34
50 /* Supply a single register. If the source register size matches the
51 size the regcache expects, this can use regcache_raw_supply(). If
52 they are different, this copies the source register into a buffer
53 that can be passed to regcache_raw_supply(). */
56 mips_fbsd_supply_reg (struct regcache
*regcache
, int regnum
, const void *addr
,
59 struct gdbarch
*gdbarch
= get_regcache_arch (regcache
);
61 if (register_size (gdbarch
, regnum
) == len
)
62 regcache_raw_supply (regcache
, regnum
, addr
);
65 enum bfd_endian byte_order
= gdbarch_byte_order (gdbarch
);
66 gdb_byte buf
[MAX_REGISTER_SIZE
];
69 val
= extract_signed_integer ((const gdb_byte
*) addr
, len
, byte_order
);
70 store_signed_integer (buf
, register_size (gdbarch
, regnum
), byte_order
,
72 regcache_raw_supply (regcache
, regnum
, buf
);
76 /* Collect a single register. If the destination register size
77 matches the size the regcache expects, this can use
78 regcache_raw_supply(). If they are different, this fetches the
79 register via regcache_raw_supply() into a buffer and then copies it
80 into the final destination. */
83 mips_fbsd_collect_reg (const struct regcache
*regcache
, int regnum
, void *addr
,
86 struct gdbarch
*gdbarch
= get_regcache_arch (regcache
);
88 if (register_size (gdbarch
, regnum
) == len
)
89 regcache_raw_collect (regcache
, regnum
, addr
);
92 enum bfd_endian byte_order
= gdbarch_byte_order (gdbarch
);
93 gdb_byte buf
[MAX_REGISTER_SIZE
];
96 regcache_raw_collect (regcache
, regnum
, buf
);
97 val
= extract_signed_integer (buf
, register_size (gdbarch
, regnum
),
99 store_signed_integer ((gdb_byte
*) addr
, len
, byte_order
, val
);
103 /* Supply the floating-point registers stored in FPREGS to REGCACHE.
104 Each floating-point register in FPREGS is REGSIZE bytes in
108 mips_fbsd_supply_fpregs (struct regcache
*regcache
, int regnum
,
109 const void *fpregs
, size_t regsize
)
111 const gdb_byte
*regs
= (const gdb_byte
*) fpregs
;
114 for (i
= MIPS_FP0_REGNUM
; i
<= MIPS_FSR_REGNUM
; i
++)
115 if (regnum
== i
|| regnum
== -1)
116 mips_fbsd_supply_reg (regcache
, i
,
117 regs
+ (i
- MIPS_FP0_REGNUM
) * regsize
, regsize
);
120 /* Supply the general-purpose registers stored in GREGS to REGCACHE.
121 Each general-purpose register in GREGS is REGSIZE bytes in
125 mips_fbsd_supply_gregs (struct regcache
*regcache
, int regnum
,
126 const void *gregs
, size_t regsize
)
128 const gdb_byte
*regs
= (const gdb_byte
*) gregs
;
131 for (i
= 0; i
<= MIPS_PC_REGNUM
; i
++)
132 if (regnum
== i
|| regnum
== -1)
133 mips_fbsd_supply_reg (regcache
, i
, regs
+ i
* regsize
, regsize
);
136 /* Collect the floating-point registers from REGCACHE and store them
137 in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes
141 mips_fbsd_collect_fpregs (const struct regcache
*regcache
, int regnum
,
142 void *fpregs
, size_t regsize
)
144 gdb_byte
*regs
= (gdb_byte
*) fpregs
;
147 for (i
= MIPS_FP0_REGNUM
; i
<= MIPS_FSR_REGNUM
; i
++)
148 if (regnum
== i
|| regnum
== -1)
149 mips_fbsd_collect_reg (regcache
, i
,
150 regs
+ (i
- MIPS_FP0_REGNUM
) * regsize
, regsize
);
153 /* Collect the general-purpose registers from REGCACHE and store them
154 in GREGS. Each general-purpose register in GREGS is REGSIZE bytes
158 mips_fbsd_collect_gregs (const struct regcache
*regcache
, int regnum
,
159 void *gregs
, size_t regsize
)
161 gdb_byte
*regs
= (gdb_byte
*) gregs
;
164 for (i
= 0; i
<= MIPS_PC_REGNUM
; i
++)
165 if (regnum
== i
|| regnum
== -1)
166 mips_fbsd_collect_reg (regcache
, i
, regs
+ i
* regsize
, regsize
);
169 /* Supply register REGNUM from the buffer specified by FPREGS and LEN
170 in the floating-point register set REGSET to register cache
171 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
174 mips_fbsd_supply_fpregset (const struct regset
*regset
,
175 struct regcache
*regcache
,
176 int regnum
, const void *fpregs
, size_t len
)
178 size_t regsize
= mips_abi_regsize (get_regcache_arch (regcache
));
180 gdb_assert (len
>= MIPS_FBSD_NUM_FPREGS
* regsize
);
182 mips_fbsd_supply_fpregs (regcache
, regnum
, fpregs
, regsize
);
185 /* Collect register REGNUM from the register cache REGCACHE and store
186 it in the buffer specified by FPREGS and LEN in the floating-point
187 register set REGSET. If REGNUM is -1, do this for all registers in
191 mips_fbsd_collect_fpregset (const struct regset
*regset
,
192 const struct regcache
*regcache
,
193 int regnum
, void *fpregs
, size_t len
)
195 size_t regsize
= mips_abi_regsize (get_regcache_arch (regcache
));
197 gdb_assert (len
>= MIPS_FBSD_NUM_FPREGS
* regsize
);
199 mips_fbsd_collect_fpregs (regcache
, regnum
, fpregs
, regsize
);
202 /* Supply register REGNUM from the buffer specified by GREGS and LEN
203 in the general-purpose register set REGSET to register cache
204 REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
207 mips_fbsd_supply_gregset (const struct regset
*regset
,
208 struct regcache
*regcache
, int regnum
,
209 const void *gregs
, size_t len
)
211 size_t regsize
= mips_abi_regsize (get_regcache_arch (regcache
));
213 gdb_assert (len
>= MIPS_FBSD_NUM_GREGS
* regsize
);
215 mips_fbsd_supply_gregs (regcache
, regnum
, gregs
, regsize
);
218 /* Collect register REGNUM from the register cache REGCACHE and store
219 it in the buffer specified by GREGS and LEN in the general-purpose
220 register set REGSET. If REGNUM is -1, do this for all registers in
224 mips_fbsd_collect_gregset (const struct regset
*regset
,
225 const struct regcache
*regcache
,
226 int regnum
, void *gregs
, size_t len
)
228 size_t regsize
= mips_abi_regsize (get_regcache_arch (regcache
));
230 gdb_assert (len
>= MIPS_FBSD_NUM_GREGS
* regsize
);
232 mips_fbsd_collect_gregs (regcache
, regnum
, gregs
, regsize
);
235 /* FreeBSD/mips register sets. */
237 static const struct regset mips_fbsd_gregset
=
240 mips_fbsd_supply_gregset
,
241 mips_fbsd_collect_gregset
,
244 static const struct regset mips_fbsd_fpregset
=
247 mips_fbsd_supply_fpregset
,
248 mips_fbsd_collect_fpregset
,
251 /* Iterate over core file register note sections. */
254 mips_fbsd_iterate_over_regset_sections (struct gdbarch
*gdbarch
,
255 iterate_over_regset_sections_cb
*cb
,
257 const struct regcache
*regcache
)
259 size_t regsize
= mips_abi_regsize (gdbarch
);
261 cb (".reg", MIPS_FBSD_NUM_GREGS
* regsize
, &mips_fbsd_gregset
,
263 cb (".reg2", MIPS_FBSD_NUM_FPREGS
* regsize
, &mips_fbsd_fpregset
,
267 /* Signal trampoline support. */
269 #define FBSD_SYS_sigreturn 417
271 #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn
272 #define MIPS_INST_SYSCALL 0x0000000c
273 #define MIPS_INST_BREAK 0x0000000d
275 #define O32_SIGFRAME_UCONTEXT_OFFSET (16)
276 #define O32_SIGSET_T_SIZE (16)
278 #define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE)
279 #define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4)
280 #define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4)
281 #define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32)
282 #define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4)
283 #define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4)
284 #define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4)
285 #define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4)
287 #define O32_UCONTEXT_REG_SIZE 4
290 mips_fbsd_sigframe_init (const struct tramp_frame
*self
,
291 struct frame_info
*this_frame
,
292 struct trad_frame_cache
*cache
,
295 struct gdbarch
*gdbarch
= get_frame_arch (this_frame
);
296 enum bfd_endian byte_order
= gdbarch_byte_order (gdbarch
);
297 CORE_ADDR sp
, ucontext_addr
, addr
;
301 /* We find the appropriate instance of `ucontext_t' at a
302 fixed offset in the signal frame. */
303 sp
= get_frame_register_signed (this_frame
,
304 MIPS_SP_REGNUM
+ gdbarch_num_regs (gdbarch
));
305 ucontext_addr
= sp
+ O32_SIGFRAME_UCONTEXT_OFFSET
;
308 regnum
= mips_regnum (gdbarch
)->pc
;
309 trad_frame_set_reg_addr (cache
,
310 regnum
+ gdbarch_num_regs (gdbarch
),
311 ucontext_addr
+ O32_UCONTEXT_PC
);
314 for (regnum
= MIPS_ZERO_REGNUM
, addr
= ucontext_addr
+ O32_UCONTEXT_REGS
;
315 regnum
<= MIPS_RA_REGNUM
; regnum
++, addr
+= O32_UCONTEXT_REG_SIZE
)
316 trad_frame_set_reg_addr (cache
,
317 regnum
+ gdbarch_num_regs (gdbarch
),
320 regnum
= MIPS_PS_REGNUM
;
321 trad_frame_set_reg_addr (cache
,
322 regnum
+ gdbarch_num_regs (gdbarch
),
323 ucontext_addr
+ O32_UCONTEXT_SR
);
326 regnum
= mips_regnum (gdbarch
)->lo
;
327 trad_frame_set_reg_addr (cache
,
328 regnum
+ gdbarch_num_regs (gdbarch
),
329 ucontext_addr
+ O32_UCONTEXT_LO
);
330 regnum
= mips_regnum (gdbarch
)->hi
;
331 trad_frame_set_reg_addr (cache
,
332 regnum
+ gdbarch_num_regs (gdbarch
),
333 ucontext_addr
+ O32_UCONTEXT_HI
);
335 if (target_read_memory (ucontext_addr
+ O32_UCONTEXT_FPUSED
, buf
, 4) == 0
336 && extract_unsigned_integer (buf
, 4, byte_order
) != 0)
338 for (regnum
= 0, addr
= ucontext_addr
+ O32_UCONTEXT_FPREGS
;
339 regnum
< 32; regnum
++, addr
+= O32_UCONTEXT_REG_SIZE
)
340 trad_frame_set_reg_addr (cache
,
341 regnum
+ gdbarch_fp0_regnum (gdbarch
),
343 trad_frame_set_reg_addr (cache
, mips_regnum (gdbarch
)->fp_control_status
,
347 trad_frame_set_id (cache
, frame_id_build (sp
, func
));
350 #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \
351 + O32_SIGFRAME_UCONTEXT_OFFSET)
353 static const struct tramp_frame mips_fbsd_sigframe
=
358 { MIPS_INST_ADDIU_A0_SP_O32
, -1 }, /* addiu a0, sp, SIGF_UC */
359 { MIPS_INST_LI_V0_SIGRETURN
, -1 }, /* li v0, SYS_sigreturn */
360 { MIPS_INST_SYSCALL
, -1 }, /* syscall */
361 { MIPS_INST_BREAK
, -1 }, /* break */
362 { TRAMP_SENTINEL_INSN
, -1 }
364 mips_fbsd_sigframe_init
367 #define N64_SIGFRAME_UCONTEXT_OFFSET (32)
368 #define N64_SIGSET_T_SIZE (16)
370 #define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE)
371 #define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8)
372 #define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8)
373 #define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32)
374 #define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8)
375 #define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8)
376 #define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8)
377 #define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8)
379 #define N64_UCONTEXT_REG_SIZE 8
382 mips64_fbsd_sigframe_init (const struct tramp_frame
*self
,
383 struct frame_info
*this_frame
,
384 struct trad_frame_cache
*cache
,
387 struct gdbarch
*gdbarch
= get_frame_arch (this_frame
);
388 enum bfd_endian byte_order
= gdbarch_byte_order (gdbarch
);
389 CORE_ADDR sp
, ucontext_addr
, addr
;
393 /* We find the appropriate instance of `ucontext_t' at a
394 fixed offset in the signal frame. */
395 sp
= get_frame_register_signed (this_frame
,
396 MIPS_SP_REGNUM
+ gdbarch_num_regs (gdbarch
));
397 ucontext_addr
= sp
+ N64_SIGFRAME_UCONTEXT_OFFSET
;
400 regnum
= mips_regnum (gdbarch
)->pc
;
401 trad_frame_set_reg_addr (cache
,
402 regnum
+ gdbarch_num_regs (gdbarch
),
403 ucontext_addr
+ N64_UCONTEXT_PC
);
406 for (regnum
= MIPS_ZERO_REGNUM
, addr
= ucontext_addr
+ N64_UCONTEXT_REGS
;
407 regnum
<= MIPS_RA_REGNUM
; regnum
++, addr
+= N64_UCONTEXT_REG_SIZE
)
408 trad_frame_set_reg_addr (cache
,
409 regnum
+ gdbarch_num_regs (gdbarch
),
412 regnum
= MIPS_PS_REGNUM
;
413 trad_frame_set_reg_addr (cache
,
414 regnum
+ gdbarch_num_regs (gdbarch
),
415 ucontext_addr
+ N64_UCONTEXT_SR
);
418 regnum
= mips_regnum (gdbarch
)->lo
;
419 trad_frame_set_reg_addr (cache
,
420 regnum
+ gdbarch_num_regs (gdbarch
),
421 ucontext_addr
+ N64_UCONTEXT_LO
);
422 regnum
= mips_regnum (gdbarch
)->hi
;
423 trad_frame_set_reg_addr (cache
,
424 regnum
+ gdbarch_num_regs (gdbarch
),
425 ucontext_addr
+ N64_UCONTEXT_HI
);
427 if (target_read_memory (ucontext_addr
+ N64_UCONTEXT_FPUSED
, buf
, 4) == 0
428 && extract_unsigned_integer (buf
, 4, byte_order
) != 0)
430 for (regnum
= 0, addr
= ucontext_addr
+ N64_UCONTEXT_FPREGS
;
431 regnum
< 32; regnum
++, addr
+= N64_UCONTEXT_REG_SIZE
)
432 trad_frame_set_reg_addr (cache
,
433 regnum
+ gdbarch_fp0_regnum (gdbarch
),
435 trad_frame_set_reg_addr (cache
, mips_regnum (gdbarch
)->fp_control_status
,
439 trad_frame_set_id (cache
, frame_id_build (sp
, func
));
442 #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
443 + N64_SIGFRAME_UCONTEXT_OFFSET)
445 static const struct tramp_frame mips64_fbsd_sigframe
=
450 { MIPS_INST_DADDIU_A0_SP_N64
, -1 }, /* daddiu a0, sp, SIGF_UC */
451 { MIPS_INST_LI_V0_SIGRETURN
, -1 }, /* li v0, SYS_sigreturn */
452 { MIPS_INST_SYSCALL
, -1 }, /* syscall */
453 { MIPS_INST_BREAK
, -1 }, /* break */
454 { TRAMP_SENTINEL_INSN
, -1 }
456 mips64_fbsd_sigframe_init
459 /* Shared library support. */
461 /* FreeBSD/mips uses a slightly different `struct link_map' than the
462 other FreeBSD platforms as it includes an additional `l_off'
465 static struct link_map_offsets
*
466 mips_fbsd_ilp32_fetch_link_map_offsets (void)
468 static struct link_map_offsets lmo
;
469 static struct link_map_offsets
*lmp
= NULL
;
475 lmo
.r_version_offset
= 0;
476 lmo
.r_version_size
= 4;
477 lmo
.r_map_offset
= 4;
478 lmo
.r_brk_offset
= 8;
479 lmo
.r_ldsomap_offset
= -1;
481 lmo
.link_map_size
= 24;
482 lmo
.l_addr_offset
= 0;
483 lmo
.l_name_offset
= 8;
484 lmo
.l_ld_offset
= 12;
485 lmo
.l_next_offset
= 16;
486 lmo
.l_prev_offset
= 20;
492 static struct link_map_offsets
*
493 mips_fbsd_lp64_fetch_link_map_offsets (void)
495 static struct link_map_offsets lmo
;
496 static struct link_map_offsets
*lmp
= NULL
;
502 lmo
.r_version_offset
= 0;
503 lmo
.r_version_size
= 4;
504 lmo
.r_map_offset
= 8;
505 lmo
.r_brk_offset
= 16;
506 lmo
.r_ldsomap_offset
= -1;
508 lmo
.link_map_size
= 48;
509 lmo
.l_addr_offset
= 0;
510 lmo
.l_name_offset
= 16;
511 lmo
.l_ld_offset
= 24;
512 lmo
.l_next_offset
= 32;
513 lmo
.l_prev_offset
= 40;
520 mips_fbsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
522 enum mips_abi abi
= mips_abi (gdbarch
);
524 /* Generic FreeBSD support. */
525 fbsd_init_abi (info
, gdbarch
);
527 set_gdbarch_software_single_step (gdbarch
, mips_software_single_step
);
532 tramp_frame_prepend_unwinder (gdbarch
, &mips_fbsd_sigframe
);
537 tramp_frame_prepend_unwinder (gdbarch
, &mips64_fbsd_sigframe
);
541 set_gdbarch_iterate_over_regset_sections
542 (gdbarch
, mips_fbsd_iterate_over_regset_sections
);
544 /* FreeBSD/mips has SVR4-style shared libraries. */
545 set_solib_svr4_fetch_link_map_offsets
546 (gdbarch
, (gdbarch_ptr_bit (gdbarch
) == 32 ?
547 mips_fbsd_ilp32_fetch_link_map_offsets
:
548 mips_fbsd_lp64_fetch_link_map_offsets
));
552 /* Provide a prototype to silence -Wmissing-prototypes. */
553 void _initialize_mips_fbsd_tdep (void);
556 _initialize_mips_fbsd_tdep (void)
558 gdbarch_register_osabi (bfd_arch_mips
, 0, GDB_OSABI_FREEBSD
,