1 /* Target-dependent code for FreeBSD/mips.
2 
3    Copyright (C) 2017-2021 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
mips_fbsd_supply_reg(struct regcache * regcache,int regnum,const void * addr,size_t len)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
mips_fbsd_collect_reg(const struct regcache * regcache,int regnum,void * addr,size_t len)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
mips_fbsd_supply_fpregs(struct regcache * regcache,int regnum,const void * fpregs,size_t regsize)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
mips_fbsd_supply_gregs(struct regcache * regcache,int regnum,const void * gregs,size_t regsize)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
mips_fbsd_collect_fpregs(const struct regcache * regcache,int regnum,void * fpregs,size_t regsize)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
mips_fbsd_collect_gregs(const struct regcache * regcache,int regnum,void * gregs,size_t regsize)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
mips_fbsd_supply_fpregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * fpregs,size_t len)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
mips_fbsd_collect_fpregset(const struct regset * regset,const struct regcache * regcache,int regnum,void * fpregs,size_t len)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
mips_fbsd_supply_gregset(const struct regset * regset,struct regcache * regcache,int regnum,const void * gregs,size_t len)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
mips_fbsd_collect_gregset(const struct regset * regset,const struct regcache * regcache,int regnum,void * gregs,size_t len)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
mips_fbsd_iterate_over_regset_sections(struct gdbarch * gdbarch,iterate_over_regset_sections_cb * cb,void * cb_data,const struct regcache * regcache)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
mips_fbsd_sigframe_init(const struct tramp_frame * self,struct frame_info * this_frame,struct trad_frame_cache * cache,CORE_ADDR func)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
mips64_fbsd_sigframe_init(const struct tramp_frame * self,struct frame_info * this_frame,struct trad_frame_cache * cache,CORE_ADDR func)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 can use an alternate routine in the runtime linker to
466    resolve functions.  */
467 
468 static CORE_ADDR
mips_fbsd_skip_solib_resolver(struct gdbarch * gdbarch,CORE_ADDR pc)469 mips_fbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
470 {
471   struct bound_minimal_symbol msym
472     = lookup_bound_minimal_symbol ("_mips_rtld_bind");
473   if (msym.minsym != nullptr && BMSYMBOL_VALUE_ADDRESS (msym) == pc)
474     return frame_unwind_caller_pc (get_current_frame ());
475 
476   return fbsd_skip_solib_resolver (gdbarch, pc);
477 }
478 
479 /* FreeBSD/mips uses a slightly different `struct link_map' than the
480    other FreeBSD platforms as it includes an additional `l_off'
481    member.  */
482 
483 static struct link_map_offsets *
mips_fbsd_ilp32_fetch_link_map_offsets(void)484 mips_fbsd_ilp32_fetch_link_map_offsets (void)
485 {
486   static struct link_map_offsets lmo;
487   static struct link_map_offsets *lmp = NULL;
488 
489   if (lmp == NULL)
490     {
491       lmp = &lmo;
492 
493       lmo.r_version_offset = 0;
494       lmo.r_version_size = 4;
495       lmo.r_map_offset = 4;
496       lmo.r_brk_offset = 8;
497       lmo.r_ldsomap_offset = -1;
498 
499       lmo.link_map_size = 24;
500       lmo.l_addr_offset = 0;
501       lmo.l_name_offset = 8;
502       lmo.l_ld_offset = 12;
503       lmo.l_next_offset = 16;
504       lmo.l_prev_offset = 20;
505     }
506 
507   return lmp;
508 }
509 
510 static struct link_map_offsets *
mips_fbsd_lp64_fetch_link_map_offsets(void)511 mips_fbsd_lp64_fetch_link_map_offsets (void)
512 {
513   static struct link_map_offsets lmo;
514   static struct link_map_offsets *lmp = NULL;
515 
516   if (lmp == NULL)
517     {
518       lmp = &lmo;
519 
520       lmo.r_version_offset = 0;
521       lmo.r_version_size = 4;
522       lmo.r_map_offset = 8;
523       lmo.r_brk_offset = 16;
524       lmo.r_ldsomap_offset = -1;
525 
526       lmo.link_map_size = 48;
527       lmo.l_addr_offset = 0;
528       lmo.l_name_offset = 16;
529       lmo.l_ld_offset = 24;
530       lmo.l_next_offset = 32;
531       lmo.l_prev_offset = 40;
532     }
533 
534   return lmp;
535 }
536 
537 static void
mips_fbsd_init_abi(struct gdbarch_info info,struct gdbarch * gdbarch)538 mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
539 {
540   enum mips_abi abi = mips_abi (gdbarch);
541 
542   /* Generic FreeBSD support.  */
543   fbsd_init_abi (info, gdbarch);
544 
545   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
546 
547   switch (abi)
548     {
549       case MIPS_ABI_O32:
550 	tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe);
551 	break;
552       case MIPS_ABI_N32:
553 	tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe);
554 	break;
555       case MIPS_ABI_N64:
556 	tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe);
557 	break;
558     }
559 
560   set_gdbarch_iterate_over_regset_sections
561     (gdbarch, mips_fbsd_iterate_over_regset_sections);
562 
563   set_gdbarch_skip_solib_resolver (gdbarch, mips_fbsd_skip_solib_resolver);
564 
565   /* FreeBSD/mips has SVR4-style shared libraries.  */
566   set_solib_svr4_fetch_link_map_offsets
567     (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
568 	       mips_fbsd_ilp32_fetch_link_map_offsets :
569 	       mips_fbsd_lp64_fetch_link_map_offsets));
570 }
571 
572 void _initialize_mips_fbsd_tdep ();
573 void
_initialize_mips_fbsd_tdep()574 _initialize_mips_fbsd_tdep ()
575 {
576   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
577 			  mips_fbsd_init_abi);
578 }
579