Add linux_get_hwcap
[external/binutils.git] / gdb / mips-fbsd-tdep.c
1 /* Target-dependent code for FreeBSD/mips.
2
3    Copyright (C) 2017-2019 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 /* 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
42    34th holds FIR on FreeBSD 12.0 and newer kernels.  On older kernels
43    it was a zero-filled dummy for padding.  */
44 #define MIPS_FBSD_NUM_FPREGS    34
45
46 /* Supply a single register.  The register size might not match, so use
47    regcache->raw_supply_integer ().  */
48
49 static void
50 mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
51                       size_t len)
52 {
53   regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true);
54 }
55
56 /* Collect a single register.  The register size might not match, so use
57    regcache->raw_collect_integer ().  */
58
59 static void
60 mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
61                        size_t len)
62 {
63   regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true);
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
70 void
71 mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum,
72                          const void *fpregs, size_t regsize)
73 {
74   struct gdbarch *gdbarch = regcache->arch ();
75   const gdb_byte *regs = (const gdb_byte *) fpregs;
76   int i, fp0num;
77
78   fp0num = mips_regnum (gdbarch)->fp0;
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);
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
99 void
100 mips_fbsd_supply_gregs (struct regcache *regcache, int regnum,
101                         const void *gregs, size_t regsize)
102 {
103   struct gdbarch *gdbarch = regcache->arch ();
104   const gdb_byte *regs = (const gdb_byte *) gregs;
105   int i;
106
107   for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
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
116 void
117 mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum,
118                           void *fpregs, size_t regsize)
119 {
120   struct gdbarch *gdbarch = regcache->arch ();
121   gdb_byte *regs = (gdb_byte *) fpregs;
122   int i, fp0num;
123
124   fp0num = mips_regnum (gdbarch)->fp0;
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);
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
143 void
144 mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum,
145                          void *gregs, size_t regsize)
146 {
147   struct gdbarch *gdbarch = regcache->arch ();
148   gdb_byte *regs = (gdb_byte *) gregs;
149   int i;
150
151   for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
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
160 static void
161 mips_fbsd_supply_fpregset (const struct regset *regset,
162                            struct regcache *regcache,
163                            int regnum, const void *fpregs, size_t len)
164 {
165   size_t regsize = mips_abi_regsize (regcache->arch ());
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
177 static void
178 mips_fbsd_collect_fpregset (const struct regset *regset,
179                             const struct regcache *regcache,
180                             int regnum, void *fpregs, size_t len)
181 {
182   size_t regsize = mips_abi_regsize (regcache->arch ());
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
193 static void
194 mips_fbsd_supply_gregset (const struct regset *regset,
195                           struct regcache *regcache, int regnum,
196                           const void *gregs, size_t len)
197 {
198   size_t regsize = mips_abi_regsize (regcache->arch ());
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
210 static void
211 mips_fbsd_collect_gregset (const struct regset *regset,
212                            const struct regcache *regcache,
213                            int regnum, void *gregs, size_t len)
214 {
215   size_t regsize = mips_abi_regsize (regcache->arch ());
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
224 static const struct regset mips_fbsd_gregset =
225 {
226   NULL,
227   mips_fbsd_supply_gregset,
228   mips_fbsd_collect_gregset,
229 };
230
231 static 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
240 static void
241 mips_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_NUM_GREGS * regsize,
249       &mips_fbsd_gregset, NULL, cb_data);
250   cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, MIPS_FBSD_NUM_FPREGS * regsize,
251       &mips_fbsd_fpregset, 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
276 static void
277 mips_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
322   if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0
323       && extract_unsigned_integer (buf, 4, byte_order) != 0)
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
340 static const struct tramp_frame mips_fbsd_sigframe =
341 {
342   SIGTRAMP_FRAME,
343   MIPS_INSN32_SIZE,
344   {
345     { MIPS_INST_ADDIU_A0_SP_O32, ULONGEST_MAX },        /* addiu   a0, sp, SIGF_UC */
346     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },        /* li      v0, SYS_sigreturn */
347     { MIPS_INST_SYSCALL, ULONGEST_MAX },                /* syscall */
348     { MIPS_INST_BREAK, ULONGEST_MAX },          /* break */
349     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
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
368 static void
369 mips64_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
414   if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0
415       && extract_unsigned_integer (buf, 4, byte_order) != 0)
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
429 #define MIPS_INST_ADDIU_A0_SP_N32 (0x27a40000 \
430                                    + N64_SIGFRAME_UCONTEXT_OFFSET)
431
432 static const struct tramp_frame mipsn32_fbsd_sigframe =
433 {
434   SIGTRAMP_FRAME,
435   MIPS_INSN32_SIZE,
436   {
437     { MIPS_INST_ADDIU_A0_SP_N32, ULONGEST_MAX },        /* addiu   a0, sp, SIGF_UC */
438     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },        /* li      v0, SYS_sigreturn */
439     { MIPS_INST_SYSCALL, ULONGEST_MAX },                /* syscall */
440     { MIPS_INST_BREAK, ULONGEST_MAX },          /* break */
441     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
442   },
443   mips64_fbsd_sigframe_init
444 };
445
446 #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
447                                     + N64_SIGFRAME_UCONTEXT_OFFSET)
448
449 static const struct tramp_frame mips64_fbsd_sigframe =
450 {
451   SIGTRAMP_FRAME,
452   MIPS_INSN32_SIZE,
453   {
454     { MIPS_INST_DADDIU_A0_SP_N64, ULONGEST_MAX },       /* daddiu  a0, sp, SIGF_UC */
455     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },        /* li      v0, SYS_sigreturn */
456     { MIPS_INST_SYSCALL, ULONGEST_MAX },                /* syscall */
457     { MIPS_INST_BREAK, ULONGEST_MAX },          /* break */
458     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
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
469 static struct link_map_offsets *
470 mips_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
496 static struct link_map_offsets *
497 mips_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
523 static void
524 mips_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:
539         tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe);
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 }
555
556 void
557 _initialize_mips_fbsd_tdep (void)
558 {
559   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
560                           mips_fbsd_init_abi);
561 }