xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/mips-fbsd-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1699b0f92Schristos /* Target-dependent code for FreeBSD/mips.
2699b0f92Schristos 
3*6881a400Schristos    Copyright (C) 2017-2023 Free Software Foundation, Inc.
4699b0f92Schristos 
5699b0f92Schristos    This file is part of GDB.
6699b0f92Schristos 
7699b0f92Schristos    This program is free software; you can redistribute it and/or modify
8699b0f92Schristos    it under the terms of the GNU General Public License as published by
9699b0f92Schristos    the Free Software Foundation; either version 3 of the License, or
10699b0f92Schristos    (at your option) any later version.
11699b0f92Schristos 
12699b0f92Schristos    This program is distributed in the hope that it will be useful,
13699b0f92Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
14699b0f92Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15699b0f92Schristos    GNU General Public License for more details.
16699b0f92Schristos 
17699b0f92Schristos    You should have received a copy of the GNU General Public License
18699b0f92Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19699b0f92Schristos 
20699b0f92Schristos #include "defs.h"
21699b0f92Schristos #include "osabi.h"
22699b0f92Schristos #include "regset.h"
23699b0f92Schristos #include "trad-frame.h"
24699b0f92Schristos #include "tramp-frame.h"
25699b0f92Schristos 
26699b0f92Schristos #include "fbsd-tdep.h"
27699b0f92Schristos #include "mips-tdep.h"
28699b0f92Schristos #include "mips-fbsd-tdep.h"
29699b0f92Schristos 
30699b0f92Schristos #include "solib-svr4.h"
31699b0f92Schristos 
32699b0f92Schristos /* Core file support. */
33699b0f92Schristos 
34699b0f92Schristos /* Number of registers in `struct reg' from <machine/reg.h>.  The
35699b0f92Schristos    first 38 follow the standard MIPS layout.  The 39th holds
36699b0f92Schristos    IC_INT_REG on RM7K and RM9K processors.  The 40th is a dummy for
37699b0f92Schristos    padding.  */
38699b0f92Schristos #define MIPS_FBSD_NUM_GREGS	40
39699b0f92Schristos 
40699b0f92Schristos /* Number of registers in `struct fpreg' from <machine/reg.h>.  The
41699b0f92Schristos    first 32 hold floating point registers.  33 holds the FSR.  The
427f2ac410Schristos    34th holds FIR on FreeBSD 12.0 and newer kernels.  On older kernels
437f2ac410Schristos    it was a zero-filled dummy for padding.  */
44699b0f92Schristos #define MIPS_FBSD_NUM_FPREGS	34
45699b0f92Schristos 
467f2ac410Schristos /* Supply a single register.  The register size might not match, so use
477f2ac410Schristos    regcache->raw_supply_integer ().  */
48699b0f92Schristos 
49699b0f92Schristos static void
50699b0f92Schristos mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
51699b0f92Schristos 		      size_t len)
52699b0f92Schristos {
537f2ac410Schristos   regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true);
54699b0f92Schristos }
55699b0f92Schristos 
567f2ac410Schristos /* Collect a single register.  The register size might not match, so use
577f2ac410Schristos    regcache->raw_collect_integer ().  */
58699b0f92Schristos 
59699b0f92Schristos static void
60699b0f92Schristos mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
61699b0f92Schristos 		       size_t len)
62699b0f92Schristos {
637f2ac410Schristos   regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true);
64699b0f92Schristos }
65699b0f92Schristos 
66699b0f92Schristos /* Supply the floating-point registers stored in FPREGS to REGCACHE.
67699b0f92Schristos    Each floating-point register in FPREGS is REGSIZE bytes in
68699b0f92Schristos    length.  */
69699b0f92Schristos 
70699b0f92Schristos void
71699b0f92Schristos mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum,
72699b0f92Schristos 			 const void *fpregs, size_t regsize)
73699b0f92Schristos {
747f2ac410Schristos   struct gdbarch *gdbarch = regcache->arch ();
75699b0f92Schristos   const gdb_byte *regs = (const gdb_byte *) fpregs;
767f2ac410Schristos   int i, fp0num;
77699b0f92Schristos 
787f2ac410Schristos   fp0num = mips_regnum (gdbarch)->fp0;
797f2ac410Schristos   for (i = 0; i <= 32; i++)
807f2ac410Schristos     if (regnum == fp0num + i || regnum == -1)
817f2ac410Schristos       mips_fbsd_supply_reg (regcache, fp0num + i,
827f2ac410Schristos 			    regs + i * regsize, regsize);
837f2ac410Schristos   if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1)
847f2ac410Schristos     mips_fbsd_supply_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
857f2ac410Schristos 			  regs + 32 * regsize, regsize);
867f2ac410Schristos   if ((regnum == mips_regnum (gdbarch)->fp_implementation_revision
877f2ac410Schristos        || regnum == -1)
887f2ac410Schristos       && extract_unsigned_integer (regs + 33 * regsize, regsize,
897f2ac410Schristos 				   gdbarch_byte_order (gdbarch)) != 0)
907f2ac410Schristos     mips_fbsd_supply_reg (regcache,
917f2ac410Schristos 			  mips_regnum (gdbarch)->fp_implementation_revision,
927f2ac410Schristos 			  regs + 33 * regsize, regsize);
93699b0f92Schristos }
94699b0f92Schristos 
95699b0f92Schristos /* Supply the general-purpose registers stored in GREGS to REGCACHE.
96699b0f92Schristos    Each general-purpose register in GREGS is REGSIZE bytes in
97699b0f92Schristos    length.  */
98699b0f92Schristos 
99699b0f92Schristos void
100699b0f92Schristos mips_fbsd_supply_gregs (struct regcache *regcache, int regnum,
101699b0f92Schristos 			const void *gregs, size_t regsize)
102699b0f92Schristos {
1037f2ac410Schristos   struct gdbarch *gdbarch = regcache->arch ();
104699b0f92Schristos   const gdb_byte *regs = (const gdb_byte *) gregs;
105699b0f92Schristos   int i;
106699b0f92Schristos 
1077f2ac410Schristos   for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
108699b0f92Schristos     if (regnum == i || regnum == -1)
109699b0f92Schristos       mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize);
110699b0f92Schristos }
111699b0f92Schristos 
112699b0f92Schristos /* Collect the floating-point registers from REGCACHE and store them
113699b0f92Schristos    in FPREGS.  Each floating-point register in FPREGS is REGSIZE bytes
114699b0f92Schristos    in length.  */
115699b0f92Schristos 
116699b0f92Schristos void
117699b0f92Schristos mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum,
118699b0f92Schristos 			  void *fpregs, size_t regsize)
119699b0f92Schristos {
1207f2ac410Schristos   struct gdbarch *gdbarch = regcache->arch ();
121699b0f92Schristos   gdb_byte *regs = (gdb_byte *) fpregs;
1227f2ac410Schristos   int i, fp0num;
123699b0f92Schristos 
1247f2ac410Schristos   fp0num = mips_regnum (gdbarch)->fp0;
1257f2ac410Schristos   for (i = 0; i < 32; i++)
1267f2ac410Schristos     if (regnum == fp0num + i || regnum == -1)
1277f2ac410Schristos       mips_fbsd_collect_reg (regcache, fp0num + i,
1287f2ac410Schristos 			     regs + i * regsize, regsize);
1297f2ac410Schristos   if (regnum == mips_regnum (gdbarch)->fp_control_status || regnum == -1)
1307f2ac410Schristos     mips_fbsd_collect_reg (regcache, mips_regnum (gdbarch)->fp_control_status,
1317f2ac410Schristos 			   regs + 32 * regsize, regsize);
1327f2ac410Schristos   if (regnum == mips_regnum (gdbarch)->fp_implementation_revision
1337f2ac410Schristos       || regnum == -1)
1347f2ac410Schristos     mips_fbsd_collect_reg (regcache,
1357f2ac410Schristos 			   mips_regnum (gdbarch)->fp_implementation_revision,
1367f2ac410Schristos 			   regs + 33 * regsize, regsize);
137699b0f92Schristos }
138699b0f92Schristos 
139699b0f92Schristos /* Collect the general-purpose registers from REGCACHE and store them
140699b0f92Schristos    in GREGS.  Each general-purpose register in GREGS is REGSIZE bytes
141699b0f92Schristos    in length.  */
142699b0f92Schristos 
143699b0f92Schristos void
144699b0f92Schristos mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum,
145699b0f92Schristos 			 void *gregs, size_t regsize)
146699b0f92Schristos {
1477f2ac410Schristos   struct gdbarch *gdbarch = regcache->arch ();
148699b0f92Schristos   gdb_byte *regs = (gdb_byte *) gregs;
149699b0f92Schristos   int i;
150699b0f92Schristos 
1517f2ac410Schristos   for (i = 0; i <= mips_regnum (gdbarch)->pc; i++)
152699b0f92Schristos     if (regnum == i || regnum == -1)
153699b0f92Schristos       mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize);
154699b0f92Schristos }
155699b0f92Schristos 
156699b0f92Schristos /* Supply register REGNUM from the buffer specified by FPREGS and LEN
157699b0f92Schristos    in the floating-point register set REGSET to register cache
158699b0f92Schristos    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
159699b0f92Schristos 
160699b0f92Schristos static void
161699b0f92Schristos mips_fbsd_supply_fpregset (const struct regset *regset,
162699b0f92Schristos 			   struct regcache *regcache,
163699b0f92Schristos 			   int regnum, const void *fpregs, size_t len)
164699b0f92Schristos {
1657f2ac410Schristos   size_t regsize = mips_abi_regsize (regcache->arch ());
166699b0f92Schristos 
167699b0f92Schristos   gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
168699b0f92Schristos 
169699b0f92Schristos   mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize);
170699b0f92Schristos }
171699b0f92Schristos 
172699b0f92Schristos /* Collect register REGNUM from the register cache REGCACHE and store
173699b0f92Schristos    it in the buffer specified by FPREGS and LEN in the floating-point
174699b0f92Schristos    register set REGSET.  If REGNUM is -1, do this for all registers in
175699b0f92Schristos    REGSET.  */
176699b0f92Schristos 
177699b0f92Schristos static void
178699b0f92Schristos mips_fbsd_collect_fpregset (const struct regset *regset,
179699b0f92Schristos 			    const struct regcache *regcache,
180699b0f92Schristos 			    int regnum, void *fpregs, size_t len)
181699b0f92Schristos {
1827f2ac410Schristos   size_t regsize = mips_abi_regsize (regcache->arch ());
183699b0f92Schristos 
184699b0f92Schristos   gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
185699b0f92Schristos 
186699b0f92Schristos   mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize);
187699b0f92Schristos }
188699b0f92Schristos 
189699b0f92Schristos /* Supply register REGNUM from the buffer specified by GREGS and LEN
190699b0f92Schristos    in the general-purpose register set REGSET to register cache
191699b0f92Schristos    REGCACHE.  If REGNUM is -1, do this for all registers in REGSET.  */
192699b0f92Schristos 
193699b0f92Schristos static void
194699b0f92Schristos mips_fbsd_supply_gregset (const struct regset *regset,
195699b0f92Schristos 			  struct regcache *regcache, int regnum,
196699b0f92Schristos 			  const void *gregs, size_t len)
197699b0f92Schristos {
1987f2ac410Schristos   size_t regsize = mips_abi_regsize (regcache->arch ());
199699b0f92Schristos 
200699b0f92Schristos   gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
201699b0f92Schristos 
202699b0f92Schristos   mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize);
203699b0f92Schristos }
204699b0f92Schristos 
205699b0f92Schristos /* Collect register REGNUM from the register cache REGCACHE and store
206699b0f92Schristos    it in the buffer specified by GREGS and LEN in the general-purpose
207699b0f92Schristos    register set REGSET.  If REGNUM is -1, do this for all registers in
208699b0f92Schristos    REGSET.  */
209699b0f92Schristos 
210699b0f92Schristos static void
211699b0f92Schristos mips_fbsd_collect_gregset (const struct regset *regset,
212699b0f92Schristos 			   const struct regcache *regcache,
213699b0f92Schristos 			   int regnum, void *gregs, size_t len)
214699b0f92Schristos {
2157f2ac410Schristos   size_t regsize = mips_abi_regsize (regcache->arch ());
216699b0f92Schristos 
217699b0f92Schristos   gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
218699b0f92Schristos 
219699b0f92Schristos   mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize);
220699b0f92Schristos }
221699b0f92Schristos 
222699b0f92Schristos /* FreeBSD/mips register sets.  */
223699b0f92Schristos 
224699b0f92Schristos static const struct regset mips_fbsd_gregset =
225699b0f92Schristos {
226699b0f92Schristos   NULL,
227699b0f92Schristos   mips_fbsd_supply_gregset,
228699b0f92Schristos   mips_fbsd_collect_gregset,
229699b0f92Schristos };
230699b0f92Schristos 
231699b0f92Schristos static const struct regset mips_fbsd_fpregset =
232699b0f92Schristos {
233699b0f92Schristos   NULL,
234699b0f92Schristos   mips_fbsd_supply_fpregset,
235699b0f92Schristos   mips_fbsd_collect_fpregset,
236699b0f92Schristos };
237699b0f92Schristos 
238699b0f92Schristos /* Iterate over core file register note sections.  */
239699b0f92Schristos 
240699b0f92Schristos static void
241699b0f92Schristos mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
242699b0f92Schristos 					iterate_over_regset_sections_cb *cb,
243699b0f92Schristos 					void *cb_data,
244699b0f92Schristos 					const struct regcache *regcache)
245699b0f92Schristos {
246699b0f92Schristos   size_t regsize = mips_abi_regsize (gdbarch);
247699b0f92Schristos 
2487f2ac410Schristos   cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, MIPS_FBSD_NUM_GREGS * regsize,
2497f2ac410Schristos       &mips_fbsd_gregset, NULL, cb_data);
2507f2ac410Schristos   cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, MIPS_FBSD_NUM_FPREGS * regsize,
2517f2ac410Schristos       &mips_fbsd_fpregset, NULL, cb_data);
252699b0f92Schristos }
253699b0f92Schristos 
254699b0f92Schristos /* Signal trampoline support.  */
255699b0f92Schristos 
256699b0f92Schristos #define FBSD_SYS_sigreturn	417
257699b0f92Schristos 
258699b0f92Schristos #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn
259699b0f92Schristos #define MIPS_INST_SYSCALL	0x0000000c
260699b0f92Schristos #define MIPS_INST_BREAK		0x0000000d
261699b0f92Schristos 
262699b0f92Schristos #define O32_SIGFRAME_UCONTEXT_OFFSET	(16)
263699b0f92Schristos #define O32_SIGSET_T_SIZE	(16)
264699b0f92Schristos 
265699b0f92Schristos #define O32_UCONTEXT_ONSTACK	(O32_SIGSET_T_SIZE)
266699b0f92Schristos #define O32_UCONTEXT_PC		(O32_UCONTEXT_ONSTACK + 4)
267699b0f92Schristos #define O32_UCONTEXT_REGS	(O32_UCONTEXT_PC + 4)
268699b0f92Schristos #define O32_UCONTEXT_SR		(O32_UCONTEXT_REGS + 4 * 32)
269699b0f92Schristos #define O32_UCONTEXT_LO		(O32_UCONTEXT_SR + 4)
270699b0f92Schristos #define O32_UCONTEXT_HI		(O32_UCONTEXT_LO + 4)
271699b0f92Schristos #define O32_UCONTEXT_FPUSED	(O32_UCONTEXT_HI + 4)
272699b0f92Schristos #define O32_UCONTEXT_FPREGS	(O32_UCONTEXT_FPUSED + 4)
273699b0f92Schristos 
274699b0f92Schristos #define O32_UCONTEXT_REG_SIZE	4
275699b0f92Schristos 
276699b0f92Schristos static void
277699b0f92Schristos mips_fbsd_sigframe_init (const struct tramp_frame *self,
278*6881a400Schristos 			 frame_info_ptr this_frame,
279699b0f92Schristos 			 struct trad_frame_cache *cache,
280699b0f92Schristos 			 CORE_ADDR func)
281699b0f92Schristos {
282699b0f92Schristos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
283699b0f92Schristos   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
284699b0f92Schristos   CORE_ADDR sp, ucontext_addr, addr;
285699b0f92Schristos   int regnum;
286699b0f92Schristos   gdb_byte buf[4];
287699b0f92Schristos 
288699b0f92Schristos   /* We find the appropriate instance of `ucontext_t' at a
289699b0f92Schristos      fixed offset in the signal frame.  */
290699b0f92Schristos   sp = get_frame_register_signed (this_frame,
291699b0f92Schristos 				  MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
292699b0f92Schristos   ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET;
293699b0f92Schristos 
294699b0f92Schristos   /* PC.  */
295699b0f92Schristos   regnum = mips_regnum (gdbarch)->pc;
296699b0f92Schristos   trad_frame_set_reg_addr (cache,
297699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
298699b0f92Schristos 			   ucontext_addr + O32_UCONTEXT_PC);
299699b0f92Schristos 
300699b0f92Schristos   /* GPRs.  */
301699b0f92Schristos   for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS;
302699b0f92Schristos        regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE)
303699b0f92Schristos     trad_frame_set_reg_addr (cache,
304699b0f92Schristos 			     regnum + gdbarch_num_regs (gdbarch),
305699b0f92Schristos 			     addr);
306699b0f92Schristos 
307699b0f92Schristos   regnum = MIPS_PS_REGNUM;
308699b0f92Schristos   trad_frame_set_reg_addr (cache,
309699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
310699b0f92Schristos 			   ucontext_addr + O32_UCONTEXT_SR);
311699b0f92Schristos 
312699b0f92Schristos   /* HI and LO.  */
313699b0f92Schristos   regnum = mips_regnum (gdbarch)->lo;
314699b0f92Schristos   trad_frame_set_reg_addr (cache,
315699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
316699b0f92Schristos 			   ucontext_addr + O32_UCONTEXT_LO);
317699b0f92Schristos   regnum = mips_regnum (gdbarch)->hi;
318699b0f92Schristos   trad_frame_set_reg_addr (cache,
319699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
320699b0f92Schristos 			   ucontext_addr + O32_UCONTEXT_HI);
321699b0f92Schristos 
322699b0f92Schristos   if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0
323699b0f92Schristos       && extract_unsigned_integer (buf, 4, byte_order) != 0)
324699b0f92Schristos     {
325699b0f92Schristos       for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS;
326699b0f92Schristos 	   regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE)
327699b0f92Schristos 	trad_frame_set_reg_addr (cache,
328699b0f92Schristos 				 regnum + gdbarch_fp0_regnum (gdbarch),
329699b0f92Schristos 				 addr);
330699b0f92Schristos       trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
331699b0f92Schristos 			       addr);
332699b0f92Schristos     }
333699b0f92Schristos 
334699b0f92Schristos   trad_frame_set_id (cache, frame_id_build (sp, func));
335699b0f92Schristos }
336699b0f92Schristos 
337699b0f92Schristos #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \
338699b0f92Schristos 				   + O32_SIGFRAME_UCONTEXT_OFFSET)
339699b0f92Schristos 
340699b0f92Schristos static const struct tramp_frame mips_fbsd_sigframe =
341699b0f92Schristos {
342699b0f92Schristos   SIGTRAMP_FRAME,
343699b0f92Schristos   MIPS_INSN32_SIZE,
344699b0f92Schristos   {
3457f2ac410Schristos     { MIPS_INST_ADDIU_A0_SP_O32, ULONGEST_MAX },	/* addiu   a0, sp, SIGF_UC */
3467f2ac410Schristos     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },	/* li      v0, SYS_sigreturn */
3477f2ac410Schristos     { MIPS_INST_SYSCALL, ULONGEST_MAX },		/* syscall */
3487f2ac410Schristos     { MIPS_INST_BREAK, ULONGEST_MAX },		/* break */
3497f2ac410Schristos     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
350699b0f92Schristos   },
351699b0f92Schristos   mips_fbsd_sigframe_init
352699b0f92Schristos };
353699b0f92Schristos 
354699b0f92Schristos #define N64_SIGFRAME_UCONTEXT_OFFSET	(32)
355699b0f92Schristos #define N64_SIGSET_T_SIZE	(16)
356699b0f92Schristos 
357699b0f92Schristos #define N64_UCONTEXT_ONSTACK	(N64_SIGSET_T_SIZE)
358699b0f92Schristos #define N64_UCONTEXT_PC		(N64_UCONTEXT_ONSTACK + 8)
359699b0f92Schristos #define N64_UCONTEXT_REGS	(N64_UCONTEXT_PC + 8)
360699b0f92Schristos #define N64_UCONTEXT_SR		(N64_UCONTEXT_REGS + 8 * 32)
361699b0f92Schristos #define N64_UCONTEXT_LO		(N64_UCONTEXT_SR + 8)
362699b0f92Schristos #define N64_UCONTEXT_HI		(N64_UCONTEXT_LO + 8)
363699b0f92Schristos #define N64_UCONTEXT_FPUSED	(N64_UCONTEXT_HI + 8)
364699b0f92Schristos #define N64_UCONTEXT_FPREGS	(N64_UCONTEXT_FPUSED + 8)
365699b0f92Schristos 
366699b0f92Schristos #define N64_UCONTEXT_REG_SIZE	8
367699b0f92Schristos 
368699b0f92Schristos static void
369699b0f92Schristos mips64_fbsd_sigframe_init (const struct tramp_frame *self,
370*6881a400Schristos 			   frame_info_ptr this_frame,
371699b0f92Schristos 			   struct trad_frame_cache *cache,
372699b0f92Schristos 			   CORE_ADDR func)
373699b0f92Schristos {
374699b0f92Schristos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
375699b0f92Schristos   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
376699b0f92Schristos   CORE_ADDR sp, ucontext_addr, addr;
377699b0f92Schristos   int regnum;
378699b0f92Schristos   gdb_byte buf[4];
379699b0f92Schristos 
380699b0f92Schristos   /* We find the appropriate instance of `ucontext_t' at a
381699b0f92Schristos      fixed offset in the signal frame.  */
382699b0f92Schristos   sp = get_frame_register_signed (this_frame,
383699b0f92Schristos 				  MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
384699b0f92Schristos   ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET;
385699b0f92Schristos 
386699b0f92Schristos   /* PC.  */
387699b0f92Schristos   regnum = mips_regnum (gdbarch)->pc;
388699b0f92Schristos   trad_frame_set_reg_addr (cache,
389699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
390699b0f92Schristos 			   ucontext_addr + N64_UCONTEXT_PC);
391699b0f92Schristos 
392699b0f92Schristos   /* GPRs.  */
393699b0f92Schristos   for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS;
394699b0f92Schristos        regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE)
395699b0f92Schristos     trad_frame_set_reg_addr (cache,
396699b0f92Schristos 			     regnum + gdbarch_num_regs (gdbarch),
397699b0f92Schristos 			     addr);
398699b0f92Schristos 
399699b0f92Schristos   regnum = MIPS_PS_REGNUM;
400699b0f92Schristos   trad_frame_set_reg_addr (cache,
401699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
402699b0f92Schristos 			   ucontext_addr + N64_UCONTEXT_SR);
403699b0f92Schristos 
404699b0f92Schristos   /* HI and LO.  */
405699b0f92Schristos   regnum = mips_regnum (gdbarch)->lo;
406699b0f92Schristos   trad_frame_set_reg_addr (cache,
407699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
408699b0f92Schristos 			   ucontext_addr + N64_UCONTEXT_LO);
409699b0f92Schristos   regnum = mips_regnum (gdbarch)->hi;
410699b0f92Schristos   trad_frame_set_reg_addr (cache,
411699b0f92Schristos 			   regnum + gdbarch_num_regs (gdbarch),
412699b0f92Schristos 			   ucontext_addr + N64_UCONTEXT_HI);
413699b0f92Schristos 
414699b0f92Schristos   if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0
415699b0f92Schristos       && extract_unsigned_integer (buf, 4, byte_order) != 0)
416699b0f92Schristos     {
417699b0f92Schristos       for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS;
418699b0f92Schristos 	   regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE)
419699b0f92Schristos 	trad_frame_set_reg_addr (cache,
420699b0f92Schristos 				 regnum + gdbarch_fp0_regnum (gdbarch),
421699b0f92Schristos 				 addr);
422699b0f92Schristos       trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
423699b0f92Schristos 			       addr);
424699b0f92Schristos     }
425699b0f92Schristos 
426699b0f92Schristos   trad_frame_set_id (cache, frame_id_build (sp, func));
427699b0f92Schristos }
428699b0f92Schristos 
4297f2ac410Schristos #define MIPS_INST_ADDIU_A0_SP_N32 (0x27a40000 \
4307f2ac410Schristos 				   + N64_SIGFRAME_UCONTEXT_OFFSET)
4317f2ac410Schristos 
4327f2ac410Schristos static const struct tramp_frame mipsn32_fbsd_sigframe =
4337f2ac410Schristos {
4347f2ac410Schristos   SIGTRAMP_FRAME,
4357f2ac410Schristos   MIPS_INSN32_SIZE,
4367f2ac410Schristos   {
4377f2ac410Schristos     { MIPS_INST_ADDIU_A0_SP_N32, ULONGEST_MAX },	/* addiu   a0, sp, SIGF_UC */
4387f2ac410Schristos     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },	/* li      v0, SYS_sigreturn */
4397f2ac410Schristos     { MIPS_INST_SYSCALL, ULONGEST_MAX },		/* syscall */
4407f2ac410Schristos     { MIPS_INST_BREAK, ULONGEST_MAX },		/* break */
4417f2ac410Schristos     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
4427f2ac410Schristos   },
4437f2ac410Schristos   mips64_fbsd_sigframe_init
4447f2ac410Schristos };
4457f2ac410Schristos 
446699b0f92Schristos #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
447699b0f92Schristos 				    + N64_SIGFRAME_UCONTEXT_OFFSET)
448699b0f92Schristos 
449699b0f92Schristos static const struct tramp_frame mips64_fbsd_sigframe =
450699b0f92Schristos {
451699b0f92Schristos   SIGTRAMP_FRAME,
452699b0f92Schristos   MIPS_INSN32_SIZE,
453699b0f92Schristos   {
4547f2ac410Schristos     { MIPS_INST_DADDIU_A0_SP_N64, ULONGEST_MAX },	/* daddiu  a0, sp, SIGF_UC */
4557f2ac410Schristos     { MIPS_INST_LI_V0_SIGRETURN, ULONGEST_MAX },	/* li      v0, SYS_sigreturn */
4567f2ac410Schristos     { MIPS_INST_SYSCALL, ULONGEST_MAX },		/* syscall */
4577f2ac410Schristos     { MIPS_INST_BREAK, ULONGEST_MAX },		/* break */
4587f2ac410Schristos     { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
459699b0f92Schristos   },
460699b0f92Schristos   mips64_fbsd_sigframe_init
461699b0f92Schristos };
462699b0f92Schristos 
463699b0f92Schristos /* Shared library support.  */
464699b0f92Schristos 
4657d62b00eSchristos /* FreeBSD/mips can use an alternate routine in the runtime linker to
4667d62b00eSchristos    resolve functions.  */
4677d62b00eSchristos 
4687d62b00eSchristos static CORE_ADDR
4697d62b00eSchristos mips_fbsd_skip_solib_resolver (struct gdbarch *gdbarch, CORE_ADDR pc)
4707d62b00eSchristos {
4717d62b00eSchristos   struct bound_minimal_symbol msym
4727d62b00eSchristos     = lookup_bound_minimal_symbol ("_mips_rtld_bind");
473*6881a400Schristos   if (msym.minsym != nullptr && msym.value_address () == pc)
4747d62b00eSchristos     return frame_unwind_caller_pc (get_current_frame ());
4757d62b00eSchristos 
4767d62b00eSchristos   return fbsd_skip_solib_resolver (gdbarch, pc);
4777d62b00eSchristos }
4787d62b00eSchristos 
479699b0f92Schristos /* FreeBSD/mips uses a slightly different `struct link_map' than the
480699b0f92Schristos    other FreeBSD platforms as it includes an additional `l_off'
481699b0f92Schristos    member.  */
482699b0f92Schristos 
483699b0f92Schristos static struct link_map_offsets *
484699b0f92Schristos mips_fbsd_ilp32_fetch_link_map_offsets (void)
485699b0f92Schristos {
486699b0f92Schristos   static struct link_map_offsets lmo;
487699b0f92Schristos   static struct link_map_offsets *lmp = NULL;
488699b0f92Schristos 
489699b0f92Schristos   if (lmp == NULL)
490699b0f92Schristos     {
491699b0f92Schristos       lmp = &lmo;
492699b0f92Schristos 
493699b0f92Schristos       lmo.r_version_offset = 0;
494699b0f92Schristos       lmo.r_version_size = 4;
495699b0f92Schristos       lmo.r_map_offset = 4;
496699b0f92Schristos       lmo.r_brk_offset = 8;
497699b0f92Schristos       lmo.r_ldsomap_offset = -1;
498*6881a400Schristos       lmo.r_next_offset = -1;
499699b0f92Schristos 
500699b0f92Schristos       lmo.link_map_size = 24;
501699b0f92Schristos       lmo.l_addr_offset = 0;
502699b0f92Schristos       lmo.l_name_offset = 8;
503699b0f92Schristos       lmo.l_ld_offset = 12;
504699b0f92Schristos       lmo.l_next_offset = 16;
505699b0f92Schristos       lmo.l_prev_offset = 20;
506699b0f92Schristos     }
507699b0f92Schristos 
508699b0f92Schristos   return lmp;
509699b0f92Schristos }
510699b0f92Schristos 
511699b0f92Schristos static struct link_map_offsets *
512699b0f92Schristos mips_fbsd_lp64_fetch_link_map_offsets (void)
513699b0f92Schristos {
514699b0f92Schristos   static struct link_map_offsets lmo;
515699b0f92Schristos   static struct link_map_offsets *lmp = NULL;
516699b0f92Schristos 
517699b0f92Schristos   if (lmp == NULL)
518699b0f92Schristos     {
519699b0f92Schristos       lmp = &lmo;
520699b0f92Schristos 
521699b0f92Schristos       lmo.r_version_offset = 0;
522699b0f92Schristos       lmo.r_version_size = 4;
523699b0f92Schristos       lmo.r_map_offset = 8;
524699b0f92Schristos       lmo.r_brk_offset = 16;
525699b0f92Schristos       lmo.r_ldsomap_offset = -1;
526*6881a400Schristos       lmo.r_next_offset = -1;
527699b0f92Schristos 
528699b0f92Schristos       lmo.link_map_size = 48;
529699b0f92Schristos       lmo.l_addr_offset = 0;
530699b0f92Schristos       lmo.l_name_offset = 16;
531699b0f92Schristos       lmo.l_ld_offset = 24;
532699b0f92Schristos       lmo.l_next_offset = 32;
533699b0f92Schristos       lmo.l_prev_offset = 40;
534699b0f92Schristos     }
535699b0f92Schristos 
536699b0f92Schristos   return lmp;
537699b0f92Schristos }
538699b0f92Schristos 
539699b0f92Schristos static void
540699b0f92Schristos mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
541699b0f92Schristos {
542699b0f92Schristos   enum mips_abi abi = mips_abi (gdbarch);
543699b0f92Schristos 
544699b0f92Schristos   /* Generic FreeBSD support.  */
545699b0f92Schristos   fbsd_init_abi (info, gdbarch);
546699b0f92Schristos 
547699b0f92Schristos   set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
548699b0f92Schristos 
549699b0f92Schristos   switch (abi)
550699b0f92Schristos     {
551699b0f92Schristos       case MIPS_ABI_O32:
552699b0f92Schristos 	tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe);
553699b0f92Schristos 	break;
554699b0f92Schristos       case MIPS_ABI_N32:
5557f2ac410Schristos 	tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe);
556699b0f92Schristos 	break;
557699b0f92Schristos       case MIPS_ABI_N64:
558699b0f92Schristos 	tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe);
559699b0f92Schristos 	break;
560699b0f92Schristos     }
561699b0f92Schristos 
562699b0f92Schristos   set_gdbarch_iterate_over_regset_sections
563699b0f92Schristos     (gdbarch, mips_fbsd_iterate_over_regset_sections);
564699b0f92Schristos 
5657d62b00eSchristos   set_gdbarch_skip_solib_resolver (gdbarch, mips_fbsd_skip_solib_resolver);
5667d62b00eSchristos 
567699b0f92Schristos   /* FreeBSD/mips has SVR4-style shared libraries.  */
568699b0f92Schristos   set_solib_svr4_fetch_link_map_offsets
569699b0f92Schristos     (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
570699b0f92Schristos 	       mips_fbsd_ilp32_fetch_link_map_offsets :
571699b0f92Schristos 	       mips_fbsd_lp64_fetch_link_map_offsets));
572699b0f92Schristos }
573699b0f92Schristos 
5747d62b00eSchristos void _initialize_mips_fbsd_tdep ();
575699b0f92Schristos void
5767d62b00eSchristos _initialize_mips_fbsd_tdep ()
577699b0f92Schristos {
578699b0f92Schristos   gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
579699b0f92Schristos 			  mips_fbsd_init_abi);
580699b0f92Schristos }
581