Use correct OSABI constant for FreeBSD/mips binaries.
[external/binutils.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 }