Fix ARI warning
[deliverable/binutils-gdb.git] / gdb / mips-fbsd-tdep.c
1 /* Target-dependent code for FreeBSD/mips.
2
3 Copyright (C) 2017 Free Software Foundation, 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 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
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
36
37 /* Core file support. */
38
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
42 padding. */
43 #define MIPS_FBSD_NUM_GREGS 40
44
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
49
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(). */
54
55 static void
56 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
57 size_t len)
58 {
59 struct gdbarch *gdbarch = get_regcache_arch (regcache);
60
61 if (register_size (gdbarch, regnum) == len)
62 regcache_raw_supply (regcache, regnum, addr);
63 else
64 {
65 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
66 gdb_byte buf[MAX_REGISTER_SIZE];
67 LONGEST val;
68
69 val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
70 store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
71 val);
72 regcache_raw_supply (regcache, regnum, buf);
73 }
74 }
75
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. */
81
82 static void
83 mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
84 size_t len)
85 {
86 struct gdbarch *gdbarch = get_regcache_arch (regcache);
87
88 if (register_size (gdbarch, regnum) == len)
89 regcache_raw_collect (regcache, regnum, addr);
90 else
91 {
92 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
93 gdb_byte buf[MAX_REGISTER_SIZE];
94 LONGEST val;
95
96 regcache_raw_collect (regcache, regnum, buf);
97 val = extract_signed_integer (buf, register_size (gdbarch, regnum),
98 byte_order);
99 store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
100 }
101 }
102
103 /* Supply the floating-point registers stored in FPREGS to REGCACHE.
104 Each floating-point register in FPREGS is REGSIZE bytes in
105 length. */
106
107 void
108 mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum,
109 const void *fpregs, size_t regsize)
110 {
111 const gdb_byte *regs = (const gdb_byte *) fpregs;
112 int i;
113
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);
118 }
119
120 /* Supply the general-purpose registers stored in GREGS to REGCACHE.
121 Each general-purpose register in GREGS is REGSIZE bytes in
122 length. */
123
124 void
125 mips_fbsd_supply_gregs (struct regcache *regcache, int regnum,
126 const void *gregs, size_t regsize)
127 {
128 const gdb_byte *regs = (const gdb_byte *) gregs;
129 int i;
130
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);
134 }
135
136 /* Collect the floating-point registers from REGCACHE and store them
137 in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes
138 in length. */
139
140 void
141 mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum,
142 void *fpregs, size_t regsize)
143 {
144 gdb_byte *regs = (gdb_byte *) fpregs;
145 int i;
146
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);
151 }
152
153 /* Collect the general-purpose registers from REGCACHE and store them
154 in GREGS. Each general-purpose register in GREGS is REGSIZE bytes
155 in length. */
156
157 void
158 mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum,
159 void *gregs, size_t regsize)
160 {
161 gdb_byte *regs = (gdb_byte *) gregs;
162 int i;
163
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);
167 }
168
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. */
172
173 static void
174 mips_fbsd_supply_fpregset (const struct regset *regset,
175 struct regcache *regcache,
176 int regnum, const void *fpregs, size_t len)
177 {
178 size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
179
180 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
181
182 mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize);
183 }
184
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
188 REGSET. */
189
190 static void
191 mips_fbsd_collect_fpregset (const struct regset *regset,
192 const struct regcache *regcache,
193 int regnum, void *fpregs, size_t len)
194 {
195 size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
196
197 gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
198
199 mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize);
200 }
201
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. */
205
206 static void
207 mips_fbsd_supply_gregset (const struct regset *regset,
208 struct regcache *regcache, int regnum,
209 const void *gregs, size_t len)
210 {
211 size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
212
213 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
214
215 mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize);
216 }
217
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
221 REGSET. */
222
223 static void
224 mips_fbsd_collect_gregset (const struct regset *regset,
225 const struct regcache *regcache,
226 int regnum, void *gregs, size_t len)
227 {
228 size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
229
230 gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
231
232 mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize);
233 }
234
235 /* FreeBSD/mips register sets. */
236
237 static const struct regset mips_fbsd_gregset =
238 {
239 NULL,
240 mips_fbsd_supply_gregset,
241 mips_fbsd_collect_gregset,
242 };
243
244 static const struct regset mips_fbsd_fpregset =
245 {
246 NULL,
247 mips_fbsd_supply_fpregset,
248 mips_fbsd_collect_fpregset,
249 };
250
251 /* Iterate over core file register note sections. */
252
253 static void
254 mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
255 iterate_over_regset_sections_cb *cb,
256 void *cb_data,
257 const struct regcache *regcache)
258 {
259 size_t regsize = mips_abi_regsize (gdbarch);
260
261 cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, &mips_fbsd_gregset,
262 NULL, cb_data);
263 cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, &mips_fbsd_fpregset,
264 NULL, cb_data);
265 }
266
267 /* Signal trampoline support. */
268
269 #define FBSD_SYS_sigreturn 417
270
271 #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn
272 #define MIPS_INST_SYSCALL 0x0000000c
273 #define MIPS_INST_BREAK 0x0000000d
274
275 #define O32_SIGFRAME_UCONTEXT_OFFSET (16)
276 #define O32_SIGSET_T_SIZE (16)
277
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)
286
287 #define O32_UCONTEXT_REG_SIZE 4
288
289 static void
290 mips_fbsd_sigframe_init (const struct tramp_frame *self,
291 struct frame_info *this_frame,
292 struct trad_frame_cache *cache,
293 CORE_ADDR func)
294 {
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;
298 int regnum;
299 gdb_byte buf[4];
300
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;
306
307 /* PC. */
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);
312
313 /* GPRs. */
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),
318 addr);
319
320 regnum = MIPS_PS_REGNUM;
321 trad_frame_set_reg_addr (cache,
322 regnum + gdbarch_num_regs (gdbarch),
323 ucontext_addr + O32_UCONTEXT_SR);
324
325 /* HI and LO. */
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);
334
335 if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0
336 && extract_unsigned_integer (buf, 4, byte_order) != 0)
337 {
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),
342 addr);
343 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
344 addr);
345 }
346
347 trad_frame_set_id (cache, frame_id_build (sp, func));
348 }
349
350 #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \
351 + O32_SIGFRAME_UCONTEXT_OFFSET)
352
353 static const struct tramp_frame mips_fbsd_sigframe =
354 {
355 SIGTRAMP_FRAME,
356 MIPS_INSN32_SIZE,
357 {
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 }
363 },
364 mips_fbsd_sigframe_init
365 };
366
367 #define N64_SIGFRAME_UCONTEXT_OFFSET (32)
368 #define N64_SIGSET_T_SIZE (16)
369
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)
378
379 #define N64_UCONTEXT_REG_SIZE 8
380
381 static void
382 mips64_fbsd_sigframe_init (const struct tramp_frame *self,
383 struct frame_info *this_frame,
384 struct trad_frame_cache *cache,
385 CORE_ADDR func)
386 {
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;
390 int regnum;
391 gdb_byte buf[4];
392
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;
398
399 /* PC. */
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);
404
405 /* GPRs. */
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),
410 addr);
411
412 regnum = MIPS_PS_REGNUM;
413 trad_frame_set_reg_addr (cache,
414 regnum + gdbarch_num_regs (gdbarch),
415 ucontext_addr + N64_UCONTEXT_SR);
416
417 /* HI and LO. */
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);
426
427 if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0
428 && extract_unsigned_integer (buf, 4, byte_order) != 0)
429 {
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),
434 addr);
435 trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
436 addr);
437 }
438
439 trad_frame_set_id (cache, frame_id_build (sp, func));
440 }
441
442 #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
443 + N64_SIGFRAME_UCONTEXT_OFFSET)
444
445 static const struct tramp_frame mips64_fbsd_sigframe =
446 {
447 SIGTRAMP_FRAME,
448 MIPS_INSN32_SIZE,
449 {
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 }
455 },
456 mips64_fbsd_sigframe_init
457 };
458
459 /* Shared library support. */
460
461 /* FreeBSD/mips uses a slightly different `struct link_map' than the
462 other FreeBSD platforms as it includes an additional `l_off'
463 member. */
464
465 static struct link_map_offsets *
466 mips_fbsd_ilp32_fetch_link_map_offsets (void)
467 {
468 static struct link_map_offsets lmo;
469 static struct link_map_offsets *lmp = NULL;
470
471 if (lmp == NULL)
472 {
473 lmp = &lmo;
474
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;
480
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;
487 }
488
489 return lmp;
490 }
491
492 static struct link_map_offsets *
493 mips_fbsd_lp64_fetch_link_map_offsets (void)
494 {
495 static struct link_map_offsets lmo;
496 static struct link_map_offsets *lmp = NULL;
497
498 if (lmp == NULL)
499 {
500 lmp = &lmo;
501
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;
507
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;
514 }
515
516 return lmp;
517 }
518
519 static void
520 mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
521 {
522 enum mips_abi abi = mips_abi (gdbarch);
523
524 /* Generic FreeBSD support. */
525 fbsd_init_abi (info, gdbarch);
526
527 set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
528
529 switch (abi)
530 {
531 case MIPS_ABI_O32:
532 tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe);
533 break;
534 case MIPS_ABI_N32:
535 break;
536 case MIPS_ABI_N64:
537 tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe);
538 break;
539 }
540
541 set_gdbarch_iterate_over_regset_sections
542 (gdbarch, mips_fbsd_iterate_over_regset_sections);
543
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));
549 }
550 \f
551
552 /* Provide a prototype to silence -Wmissing-prototypes. */
553 void _initialize_mips_fbsd_tdep (void);
554
555 void
556 _initialize_mips_fbsd_tdep (void)
557 {
558 gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
559 mips_fbsd_init_abi);
560 }
This page took 0.042625 seconds and 5 git commands to generate.