mips-fbsd-tdep.c revision 1.1 1 1.1 christos /* Target-dependent code for FreeBSD/mips.
2 1.1 christos
3 1.1 christos Copyright (C) 2017 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This file is part of GDB.
6 1.1 christos
7 1.1 christos This program is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3 of the License, or
10 1.1 christos (at your option) any later version.
11 1.1 christos
12 1.1 christos This program is distributed in the hope that it will be useful,
13 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 christos GNU General Public License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 1.1 christos
20 1.1 christos #include "defs.h"
21 1.1 christos #include "osabi.h"
22 1.1 christos #include "regset.h"
23 1.1 christos #include "trad-frame.h"
24 1.1 christos #include "tramp-frame.h"
25 1.1 christos
26 1.1 christos #include "fbsd-tdep.h"
27 1.1 christos #include "mips-tdep.h"
28 1.1 christos #include "mips-fbsd-tdep.h"
29 1.1 christos
30 1.1 christos #include "solib-svr4.h"
31 1.1 christos
32 1.1 christos /* Shorthand for some register numbers used below. */
33 1.1 christos #define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM
34 1.1 christos #define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM
35 1.1 christos #define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32
36 1.1 christos
37 1.1 christos /* Core file support. */
38 1.1 christos
39 1.1 christos /* Number of registers in `struct reg' from <machine/reg.h>. The
40 1.1 christos first 38 follow the standard MIPS layout. The 39th holds
41 1.1 christos IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for
42 1.1 christos padding. */
43 1.1 christos #define MIPS_FBSD_NUM_GREGS 40
44 1.1 christos
45 1.1 christos /* Number of registers in `struct fpreg' from <machine/reg.h>. The
46 1.1 christos first 32 hold floating point registers. 33 holds the FSR. The
47 1.1 christos 34th is a dummy for padding. */
48 1.1 christos #define MIPS_FBSD_NUM_FPREGS 34
49 1.1 christos
50 1.1 christos /* Supply a single register. If the source register size matches the
51 1.1 christos size the regcache expects, this can use regcache_raw_supply(). If
52 1.1 christos they are different, this copies the source register into a buffer
53 1.1 christos that can be passed to regcache_raw_supply(). */
54 1.1 christos
55 1.1 christos static void
56 1.1 christos mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr,
57 1.1 christos size_t len)
58 1.1 christos {
59 1.1 christos struct gdbarch *gdbarch = get_regcache_arch (regcache);
60 1.1 christos
61 1.1 christos if (register_size (gdbarch, regnum) == len)
62 1.1 christos regcache_raw_supply (regcache, regnum, addr);
63 1.1 christos else
64 1.1 christos {
65 1.1 christos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
66 1.1 christos gdb_byte buf[MAX_REGISTER_SIZE];
67 1.1 christos LONGEST val;
68 1.1 christos
69 1.1 christos val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order);
70 1.1 christos store_signed_integer (buf, register_size (gdbarch, regnum), byte_order,
71 1.1 christos val);
72 1.1 christos regcache_raw_supply (regcache, regnum, buf);
73 1.1 christos }
74 1.1 christos }
75 1.1 christos
76 1.1 christos /* Collect a single register. If the destination register size
77 1.1 christos matches the size the regcache expects, this can use
78 1.1 christos regcache_raw_supply(). If they are different, this fetches the
79 1.1 christos register via regcache_raw_supply() into a buffer and then copies it
80 1.1 christos into the final destination. */
81 1.1 christos
82 1.1 christos static void
83 1.1 christos mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr,
84 1.1 christos size_t len)
85 1.1 christos {
86 1.1 christos struct gdbarch *gdbarch = get_regcache_arch (regcache);
87 1.1 christos
88 1.1 christos if (register_size (gdbarch, regnum) == len)
89 1.1 christos regcache_raw_collect (regcache, regnum, addr);
90 1.1 christos else
91 1.1 christos {
92 1.1 christos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
93 1.1 christos gdb_byte buf[MAX_REGISTER_SIZE];
94 1.1 christos LONGEST val;
95 1.1 christos
96 1.1 christos regcache_raw_collect (regcache, regnum, buf);
97 1.1 christos val = extract_signed_integer (buf, register_size (gdbarch, regnum),
98 1.1 christos byte_order);
99 1.1 christos store_signed_integer ((gdb_byte *) addr, len, byte_order, val);
100 1.1 christos }
101 1.1 christos }
102 1.1 christos
103 1.1 christos /* Supply the floating-point registers stored in FPREGS to REGCACHE.
104 1.1 christos Each floating-point register in FPREGS is REGSIZE bytes in
105 1.1 christos length. */
106 1.1 christos
107 1.1 christos void
108 1.1 christos mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum,
109 1.1 christos const void *fpregs, size_t regsize)
110 1.1 christos {
111 1.1 christos const gdb_byte *regs = (const gdb_byte *) fpregs;
112 1.1 christos int i;
113 1.1 christos
114 1.1 christos for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
115 1.1 christos if (regnum == i || regnum == -1)
116 1.1 christos mips_fbsd_supply_reg (regcache, i,
117 1.1 christos regs + (i - MIPS_FP0_REGNUM) * regsize, regsize);
118 1.1 christos }
119 1.1 christos
120 1.1 christos /* Supply the general-purpose registers stored in GREGS to REGCACHE.
121 1.1 christos Each general-purpose register in GREGS is REGSIZE bytes in
122 1.1 christos length. */
123 1.1 christos
124 1.1 christos void
125 1.1 christos mips_fbsd_supply_gregs (struct regcache *regcache, int regnum,
126 1.1 christos const void *gregs, size_t regsize)
127 1.1 christos {
128 1.1 christos const gdb_byte *regs = (const gdb_byte *) gregs;
129 1.1 christos int i;
130 1.1 christos
131 1.1 christos for (i = 0; i <= MIPS_PC_REGNUM; i++)
132 1.1 christos if (regnum == i || regnum == -1)
133 1.1 christos mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize);
134 1.1 christos }
135 1.1 christos
136 1.1 christos /* Collect the floating-point registers from REGCACHE and store them
137 1.1 christos in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes
138 1.1 christos in length. */
139 1.1 christos
140 1.1 christos void
141 1.1 christos mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum,
142 1.1 christos void *fpregs, size_t regsize)
143 1.1 christos {
144 1.1 christos gdb_byte *regs = (gdb_byte *) fpregs;
145 1.1 christos int i;
146 1.1 christos
147 1.1 christos for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++)
148 1.1 christos if (regnum == i || regnum == -1)
149 1.1 christos mips_fbsd_collect_reg (regcache, i,
150 1.1 christos regs + (i - MIPS_FP0_REGNUM) * regsize, regsize);
151 1.1 christos }
152 1.1 christos
153 1.1 christos /* Collect the general-purpose registers from REGCACHE and store them
154 1.1 christos in GREGS. Each general-purpose register in GREGS is REGSIZE bytes
155 1.1 christos in length. */
156 1.1 christos
157 1.1 christos void
158 1.1 christos mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum,
159 1.1 christos void *gregs, size_t regsize)
160 1.1 christos {
161 1.1 christos gdb_byte *regs = (gdb_byte *) gregs;
162 1.1 christos int i;
163 1.1 christos
164 1.1 christos for (i = 0; i <= MIPS_PC_REGNUM; i++)
165 1.1 christos if (regnum == i || regnum == -1)
166 1.1 christos mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize);
167 1.1 christos }
168 1.1 christos
169 1.1 christos /* Supply register REGNUM from the buffer specified by FPREGS and LEN
170 1.1 christos in the floating-point register set REGSET to register cache
171 1.1 christos REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
172 1.1 christos
173 1.1 christos static void
174 1.1 christos mips_fbsd_supply_fpregset (const struct regset *regset,
175 1.1 christos struct regcache *regcache,
176 1.1 christos int regnum, const void *fpregs, size_t len)
177 1.1 christos {
178 1.1 christos size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
179 1.1 christos
180 1.1 christos gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
181 1.1 christos
182 1.1 christos mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize);
183 1.1 christos }
184 1.1 christos
185 1.1 christos /* Collect register REGNUM from the register cache REGCACHE and store
186 1.1 christos it in the buffer specified by FPREGS and LEN in the floating-point
187 1.1 christos register set REGSET. If REGNUM is -1, do this for all registers in
188 1.1 christos REGSET. */
189 1.1 christos
190 1.1 christos static void
191 1.1 christos mips_fbsd_collect_fpregset (const struct regset *regset,
192 1.1 christos const struct regcache *regcache,
193 1.1 christos int regnum, void *fpregs, size_t len)
194 1.1 christos {
195 1.1 christos size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
196 1.1 christos
197 1.1 christos gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize);
198 1.1 christos
199 1.1 christos mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize);
200 1.1 christos }
201 1.1 christos
202 1.1 christos /* Supply register REGNUM from the buffer specified by GREGS and LEN
203 1.1 christos in the general-purpose register set REGSET to register cache
204 1.1 christos REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */
205 1.1 christos
206 1.1 christos static void
207 1.1 christos mips_fbsd_supply_gregset (const struct regset *regset,
208 1.1 christos struct regcache *regcache, int regnum,
209 1.1 christos const void *gregs, size_t len)
210 1.1 christos {
211 1.1 christos size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
212 1.1 christos
213 1.1 christos gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
214 1.1 christos
215 1.1 christos mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize);
216 1.1 christos }
217 1.1 christos
218 1.1 christos /* Collect register REGNUM from the register cache REGCACHE and store
219 1.1 christos it in the buffer specified by GREGS and LEN in the general-purpose
220 1.1 christos register set REGSET. If REGNUM is -1, do this for all registers in
221 1.1 christos REGSET. */
222 1.1 christos
223 1.1 christos static void
224 1.1 christos mips_fbsd_collect_gregset (const struct regset *regset,
225 1.1 christos const struct regcache *regcache,
226 1.1 christos int regnum, void *gregs, size_t len)
227 1.1 christos {
228 1.1 christos size_t regsize = mips_abi_regsize (get_regcache_arch (regcache));
229 1.1 christos
230 1.1 christos gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize);
231 1.1 christos
232 1.1 christos mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize);
233 1.1 christos }
234 1.1 christos
235 1.1 christos /* FreeBSD/mips register sets. */
236 1.1 christos
237 1.1 christos static const struct regset mips_fbsd_gregset =
238 1.1 christos {
239 1.1 christos NULL,
240 1.1 christos mips_fbsd_supply_gregset,
241 1.1 christos mips_fbsd_collect_gregset,
242 1.1 christos };
243 1.1 christos
244 1.1 christos static const struct regset mips_fbsd_fpregset =
245 1.1 christos {
246 1.1 christos NULL,
247 1.1 christos mips_fbsd_supply_fpregset,
248 1.1 christos mips_fbsd_collect_fpregset,
249 1.1 christos };
250 1.1 christos
251 1.1 christos /* Iterate over core file register note sections. */
252 1.1 christos
253 1.1 christos static void
254 1.1 christos mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch,
255 1.1 christos iterate_over_regset_sections_cb *cb,
256 1.1 christos void *cb_data,
257 1.1 christos const struct regcache *regcache)
258 1.1 christos {
259 1.1 christos size_t regsize = mips_abi_regsize (gdbarch);
260 1.1 christos
261 1.1 christos cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, &mips_fbsd_gregset,
262 1.1 christos NULL, cb_data);
263 1.1 christos cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, &mips_fbsd_fpregset,
264 1.1 christos NULL, cb_data);
265 1.1 christos }
266 1.1 christos
267 1.1 christos /* Signal trampoline support. */
268 1.1 christos
269 1.1 christos #define FBSD_SYS_sigreturn 417
270 1.1 christos
271 1.1 christos #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn
272 1.1 christos #define MIPS_INST_SYSCALL 0x0000000c
273 1.1 christos #define MIPS_INST_BREAK 0x0000000d
274 1.1 christos
275 1.1 christos #define O32_SIGFRAME_UCONTEXT_OFFSET (16)
276 1.1 christos #define O32_SIGSET_T_SIZE (16)
277 1.1 christos
278 1.1 christos #define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE)
279 1.1 christos #define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4)
280 1.1 christos #define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4)
281 1.1 christos #define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32)
282 1.1 christos #define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4)
283 1.1 christos #define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4)
284 1.1 christos #define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4)
285 1.1 christos #define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4)
286 1.1 christos
287 1.1 christos #define O32_UCONTEXT_REG_SIZE 4
288 1.1 christos
289 1.1 christos static void
290 1.1 christos mips_fbsd_sigframe_init (const struct tramp_frame *self,
291 1.1 christos struct frame_info *this_frame,
292 1.1 christos struct trad_frame_cache *cache,
293 1.1 christos CORE_ADDR func)
294 1.1 christos {
295 1.1 christos struct gdbarch *gdbarch = get_frame_arch (this_frame);
296 1.1 christos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
297 1.1 christos CORE_ADDR sp, ucontext_addr, addr;
298 1.1 christos int regnum;
299 1.1 christos gdb_byte buf[4];
300 1.1 christos
301 1.1 christos /* We find the appropriate instance of `ucontext_t' at a
302 1.1 christos fixed offset in the signal frame. */
303 1.1 christos sp = get_frame_register_signed (this_frame,
304 1.1 christos MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
305 1.1 christos ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET;
306 1.1 christos
307 1.1 christos /* PC. */
308 1.1 christos regnum = mips_regnum (gdbarch)->pc;
309 1.1 christos trad_frame_set_reg_addr (cache,
310 1.1 christos regnum + gdbarch_num_regs (gdbarch),
311 1.1 christos ucontext_addr + O32_UCONTEXT_PC);
312 1.1 christos
313 1.1 christos /* GPRs. */
314 1.1 christos for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS;
315 1.1 christos regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE)
316 1.1 christos trad_frame_set_reg_addr (cache,
317 1.1 christos regnum + gdbarch_num_regs (gdbarch),
318 1.1 christos addr);
319 1.1 christos
320 1.1 christos regnum = MIPS_PS_REGNUM;
321 1.1 christos trad_frame_set_reg_addr (cache,
322 1.1 christos regnum + gdbarch_num_regs (gdbarch),
323 1.1 christos ucontext_addr + O32_UCONTEXT_SR);
324 1.1 christos
325 1.1 christos /* HI and LO. */
326 1.1 christos regnum = mips_regnum (gdbarch)->lo;
327 1.1 christos trad_frame_set_reg_addr (cache,
328 1.1 christos regnum + gdbarch_num_regs (gdbarch),
329 1.1 christos ucontext_addr + O32_UCONTEXT_LO);
330 1.1 christos regnum = mips_regnum (gdbarch)->hi;
331 1.1 christos trad_frame_set_reg_addr (cache,
332 1.1 christos regnum + gdbarch_num_regs (gdbarch),
333 1.1 christos ucontext_addr + O32_UCONTEXT_HI);
334 1.1 christos
335 1.1 christos if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0
336 1.1 christos && extract_unsigned_integer (buf, 4, byte_order) != 0)
337 1.1 christos {
338 1.1 christos for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS;
339 1.1 christos regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE)
340 1.1 christos trad_frame_set_reg_addr (cache,
341 1.1 christos regnum + gdbarch_fp0_regnum (gdbarch),
342 1.1 christos addr);
343 1.1 christos trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
344 1.1 christos addr);
345 1.1 christos }
346 1.1 christos
347 1.1 christos trad_frame_set_id (cache, frame_id_build (sp, func));
348 1.1 christos }
349 1.1 christos
350 1.1 christos #define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \
351 1.1 christos + O32_SIGFRAME_UCONTEXT_OFFSET)
352 1.1 christos
353 1.1 christos static const struct tramp_frame mips_fbsd_sigframe =
354 1.1 christos {
355 1.1 christos SIGTRAMP_FRAME,
356 1.1 christos MIPS_INSN32_SIZE,
357 1.1 christos {
358 1.1 christos { MIPS_INST_ADDIU_A0_SP_O32, -1 }, /* addiu a0, sp, SIGF_UC */
359 1.1 christos { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */
360 1.1 christos { MIPS_INST_SYSCALL, -1 }, /* syscall */
361 1.1 christos { MIPS_INST_BREAK, -1 }, /* break */
362 1.1 christos { TRAMP_SENTINEL_INSN, -1 }
363 1.1 christos },
364 1.1 christos mips_fbsd_sigframe_init
365 1.1 christos };
366 1.1 christos
367 1.1 christos #define N64_SIGFRAME_UCONTEXT_OFFSET (32)
368 1.1 christos #define N64_SIGSET_T_SIZE (16)
369 1.1 christos
370 1.1 christos #define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE)
371 1.1 christos #define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8)
372 1.1 christos #define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8)
373 1.1 christos #define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32)
374 1.1 christos #define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8)
375 1.1 christos #define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8)
376 1.1 christos #define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8)
377 1.1 christos #define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8)
378 1.1 christos
379 1.1 christos #define N64_UCONTEXT_REG_SIZE 8
380 1.1 christos
381 1.1 christos static void
382 1.1 christos mips64_fbsd_sigframe_init (const struct tramp_frame *self,
383 1.1 christos struct frame_info *this_frame,
384 1.1 christos struct trad_frame_cache *cache,
385 1.1 christos CORE_ADDR func)
386 1.1 christos {
387 1.1 christos struct gdbarch *gdbarch = get_frame_arch (this_frame);
388 1.1 christos enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
389 1.1 christos CORE_ADDR sp, ucontext_addr, addr;
390 1.1 christos int regnum;
391 1.1 christos gdb_byte buf[4];
392 1.1 christos
393 1.1 christos /* We find the appropriate instance of `ucontext_t' at a
394 1.1 christos fixed offset in the signal frame. */
395 1.1 christos sp = get_frame_register_signed (this_frame,
396 1.1 christos MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch));
397 1.1 christos ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET;
398 1.1 christos
399 1.1 christos /* PC. */
400 1.1 christos regnum = mips_regnum (gdbarch)->pc;
401 1.1 christos trad_frame_set_reg_addr (cache,
402 1.1 christos regnum + gdbarch_num_regs (gdbarch),
403 1.1 christos ucontext_addr + N64_UCONTEXT_PC);
404 1.1 christos
405 1.1 christos /* GPRs. */
406 1.1 christos for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS;
407 1.1 christos regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE)
408 1.1 christos trad_frame_set_reg_addr (cache,
409 1.1 christos regnum + gdbarch_num_regs (gdbarch),
410 1.1 christos addr);
411 1.1 christos
412 1.1 christos regnum = MIPS_PS_REGNUM;
413 1.1 christos trad_frame_set_reg_addr (cache,
414 1.1 christos regnum + gdbarch_num_regs (gdbarch),
415 1.1 christos ucontext_addr + N64_UCONTEXT_SR);
416 1.1 christos
417 1.1 christos /* HI and LO. */
418 1.1 christos regnum = mips_regnum (gdbarch)->lo;
419 1.1 christos trad_frame_set_reg_addr (cache,
420 1.1 christos regnum + gdbarch_num_regs (gdbarch),
421 1.1 christos ucontext_addr + N64_UCONTEXT_LO);
422 1.1 christos regnum = mips_regnum (gdbarch)->hi;
423 1.1 christos trad_frame_set_reg_addr (cache,
424 1.1 christos regnum + gdbarch_num_regs (gdbarch),
425 1.1 christos ucontext_addr + N64_UCONTEXT_HI);
426 1.1 christos
427 1.1 christos if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0
428 1.1 christos && extract_unsigned_integer (buf, 4, byte_order) != 0)
429 1.1 christos {
430 1.1 christos for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS;
431 1.1 christos regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE)
432 1.1 christos trad_frame_set_reg_addr (cache,
433 1.1 christos regnum + gdbarch_fp0_regnum (gdbarch),
434 1.1 christos addr);
435 1.1 christos trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status,
436 1.1 christos addr);
437 1.1 christos }
438 1.1 christos
439 1.1 christos trad_frame_set_id (cache, frame_id_build (sp, func));
440 1.1 christos }
441 1.1 christos
442 1.1 christos #define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \
443 1.1 christos + N64_SIGFRAME_UCONTEXT_OFFSET)
444 1.1 christos
445 1.1 christos static const struct tramp_frame mips64_fbsd_sigframe =
446 1.1 christos {
447 1.1 christos SIGTRAMP_FRAME,
448 1.1 christos MIPS_INSN32_SIZE,
449 1.1 christos {
450 1.1 christos { MIPS_INST_DADDIU_A0_SP_N64, -1 }, /* daddiu a0, sp, SIGF_UC */
451 1.1 christos { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */
452 1.1 christos { MIPS_INST_SYSCALL, -1 }, /* syscall */
453 1.1 christos { MIPS_INST_BREAK, -1 }, /* break */
454 1.1 christos { TRAMP_SENTINEL_INSN, -1 }
455 1.1 christos },
456 1.1 christos mips64_fbsd_sigframe_init
457 1.1 christos };
458 1.1 christos
459 1.1 christos /* Shared library support. */
460 1.1 christos
461 1.1 christos /* FreeBSD/mips uses a slightly different `struct link_map' than the
462 1.1 christos other FreeBSD platforms as it includes an additional `l_off'
463 1.1 christos member. */
464 1.1 christos
465 1.1 christos static struct link_map_offsets *
466 1.1 christos mips_fbsd_ilp32_fetch_link_map_offsets (void)
467 1.1 christos {
468 1.1 christos static struct link_map_offsets lmo;
469 1.1 christos static struct link_map_offsets *lmp = NULL;
470 1.1 christos
471 1.1 christos if (lmp == NULL)
472 1.1 christos {
473 1.1 christos lmp = &lmo;
474 1.1 christos
475 1.1 christos lmo.r_version_offset = 0;
476 1.1 christos lmo.r_version_size = 4;
477 1.1 christos lmo.r_map_offset = 4;
478 1.1 christos lmo.r_brk_offset = 8;
479 1.1 christos lmo.r_ldsomap_offset = -1;
480 1.1 christos
481 1.1 christos lmo.link_map_size = 24;
482 1.1 christos lmo.l_addr_offset = 0;
483 1.1 christos lmo.l_name_offset = 8;
484 1.1 christos lmo.l_ld_offset = 12;
485 1.1 christos lmo.l_next_offset = 16;
486 1.1 christos lmo.l_prev_offset = 20;
487 1.1 christos }
488 1.1 christos
489 1.1 christos return lmp;
490 1.1 christos }
491 1.1 christos
492 1.1 christos static struct link_map_offsets *
493 1.1 christos mips_fbsd_lp64_fetch_link_map_offsets (void)
494 1.1 christos {
495 1.1 christos static struct link_map_offsets lmo;
496 1.1 christos static struct link_map_offsets *lmp = NULL;
497 1.1 christos
498 1.1 christos if (lmp == NULL)
499 1.1 christos {
500 1.1 christos lmp = &lmo;
501 1.1 christos
502 1.1 christos lmo.r_version_offset = 0;
503 1.1 christos lmo.r_version_size = 4;
504 1.1 christos lmo.r_map_offset = 8;
505 1.1 christos lmo.r_brk_offset = 16;
506 1.1 christos lmo.r_ldsomap_offset = -1;
507 1.1 christos
508 1.1 christos lmo.link_map_size = 48;
509 1.1 christos lmo.l_addr_offset = 0;
510 1.1 christos lmo.l_name_offset = 16;
511 1.1 christos lmo.l_ld_offset = 24;
512 1.1 christos lmo.l_next_offset = 32;
513 1.1 christos lmo.l_prev_offset = 40;
514 1.1 christos }
515 1.1 christos
516 1.1 christos return lmp;
517 1.1 christos }
518 1.1 christos
519 1.1 christos static void
520 1.1 christos mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
521 1.1 christos {
522 1.1 christos enum mips_abi abi = mips_abi (gdbarch);
523 1.1 christos
524 1.1 christos /* Generic FreeBSD support. */
525 1.1 christos fbsd_init_abi (info, gdbarch);
526 1.1 christos
527 1.1 christos set_gdbarch_software_single_step (gdbarch, mips_software_single_step);
528 1.1 christos
529 1.1 christos switch (abi)
530 1.1 christos {
531 1.1 christos case MIPS_ABI_O32:
532 1.1 christos tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe);
533 1.1 christos break;
534 1.1 christos case MIPS_ABI_N32:
535 1.1 christos break;
536 1.1 christos case MIPS_ABI_N64:
537 1.1 christos tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe);
538 1.1 christos break;
539 1.1 christos }
540 1.1 christos
541 1.1 christos set_gdbarch_iterate_over_regset_sections
542 1.1 christos (gdbarch, mips_fbsd_iterate_over_regset_sections);
543 1.1 christos
544 1.1 christos /* FreeBSD/mips has SVR4-style shared libraries. */
545 1.1 christos set_solib_svr4_fetch_link_map_offsets
546 1.1 christos (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ?
547 1.1 christos mips_fbsd_ilp32_fetch_link_map_offsets :
548 1.1 christos mips_fbsd_lp64_fetch_link_map_offsets));
549 1.1 christos }
550 1.1 christos
551 1.1 christos
553 1.1 christos /* Provide a prototype to silence -Wmissing-prototypes. */
554 1.1 christos void _initialize_mips_fbsd_tdep (void);
555 1.1 christos
556 1.1 christos void
557 1.1 christos _initialize_mips_fbsd_tdep (void)
558 1.1 christos {
559 1.1 christos gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD,
560 1.1 christos mips_fbsd_init_abi);
561 }
562