Commit | Line | Data |
---|---|---|
387360da JB |
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 | ||
387360da JB |
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 | |
7755ddb7 JB |
42 | 34th holds FIR on FreeBSD 12.0 and newer kernels. On older kernels |
43 | it was a zero-filled dummy for padding. */ | |
387360da JB |
44 | #define MIPS_FBSD_NUM_FPREGS 34 |
45 | ||
b057297a AH |
46 | /* Supply a single register. The register size might not match, so use |
47 | regcache->raw_supply_integer (). */ | |
387360da JB |
48 | |
49 | static void | |
50 | mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr, | |
51 | size_t len) | |
52 | { | |
b057297a | 53 | regcache->raw_supply_integer (regnum, (const gdb_byte *) addr, len, true); |
387360da JB |
54 | } |
55 | ||
b057297a AH |
56 | /* Collect a single register. The register size might not match, so use |
57 | regcache->raw_collect_integer (). */ | |
387360da JB |
58 | |
59 | static void | |
60 | mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr, | |
61 | size_t len) | |
62 | { | |
b057297a | 63 | regcache->raw_collect_integer (regnum, (gdb_byte *) addr, len, true); |
387360da JB |
64 | } |
65 | ||
66 | /* Supply the floating-point registers stored in FPREGS to REGCACHE. | |
67 | Each floating-point register in FPREGS is REGSIZE bytes in | |
68 | length. */ | |
69 | ||
70 | void | |
71 | mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum, | |
72 | const void *fpregs, size_t regsize) | |
73 | { | |
ac7936df | 74 | struct gdbarch *gdbarch = regcache->arch (); |
387360da | 75 | const gdb_byte *regs = (const gdb_byte *) fpregs; |
7755ddb7 | 76 | int i, fp0num; |
387360da | 77 | |
f7241d4f | 78 | fp0num = mips_regnum (gdbarch)->fp0; |
7755ddb7 JB |
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); | |
387360da JB |
93 | } |
94 | ||
95 | /* Supply the general-purpose registers stored in GREGS to REGCACHE. | |
96 | Each general-purpose register in GREGS is REGSIZE bytes in | |
97 | length. */ | |
98 | ||
99 | void | |
100 | mips_fbsd_supply_gregs (struct regcache *regcache, int regnum, | |
101 | const void *gregs, size_t regsize) | |
102 | { | |
ac7936df | 103 | struct gdbarch *gdbarch = regcache->arch (); |
387360da JB |
104 | const gdb_byte *regs = (const gdb_byte *) gregs; |
105 | int i; | |
106 | ||
f7241d4f | 107 | for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) |
387360da JB |
108 | if (regnum == i || regnum == -1) |
109 | mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize); | |
110 | } | |
111 | ||
112 | /* Collect the floating-point registers from REGCACHE and store them | |
113 | in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes | |
114 | in length. */ | |
115 | ||
116 | void | |
117 | mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum, | |
118 | void *fpregs, size_t regsize) | |
119 | { | |
ac7936df | 120 | struct gdbarch *gdbarch = regcache->arch (); |
387360da | 121 | gdb_byte *regs = (gdb_byte *) fpregs; |
7755ddb7 | 122 | int i, fp0num; |
387360da | 123 | |
f7241d4f | 124 | fp0num = mips_regnum (gdbarch)->fp0; |
7755ddb7 JB |
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); | |
387360da JB |
137 | } |
138 | ||
139 | /* Collect the general-purpose registers from REGCACHE and store them | |
140 | in GREGS. Each general-purpose register in GREGS is REGSIZE bytes | |
141 | in length. */ | |
142 | ||
143 | void | |
144 | mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum, | |
145 | void *gregs, size_t regsize) | |
146 | { | |
ac7936df | 147 | struct gdbarch *gdbarch = regcache->arch (); |
387360da JB |
148 | gdb_byte *regs = (gdb_byte *) gregs; |
149 | int i; | |
150 | ||
f7241d4f | 151 | for (i = 0; i <= mips_regnum (gdbarch)->pc; i++) |
387360da JB |
152 | if (regnum == i || regnum == -1) |
153 | mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize); | |
154 | } | |
155 | ||
156 | /* Supply register REGNUM from the buffer specified by FPREGS and LEN | |
157 | in the floating-point register set REGSET to register cache | |
158 | REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ | |
159 | ||
160 | static void | |
161 | mips_fbsd_supply_fpregset (const struct regset *regset, | |
162 | struct regcache *regcache, | |
163 | int regnum, const void *fpregs, size_t len) | |
164 | { | |
ac7936df | 165 | size_t regsize = mips_abi_regsize (regcache->arch ()); |
387360da JB |
166 | |
167 | gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); | |
168 | ||
169 | mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize); | |
170 | } | |
171 | ||
172 | /* Collect register REGNUM from the register cache REGCACHE and store | |
173 | it in the buffer specified by FPREGS and LEN in the floating-point | |
174 | register set REGSET. If REGNUM is -1, do this for all registers in | |
175 | REGSET. */ | |
176 | ||
177 | static void | |
178 | mips_fbsd_collect_fpregset (const struct regset *regset, | |
179 | const struct regcache *regcache, | |
180 | int regnum, void *fpregs, size_t len) | |
181 | { | |
ac7936df | 182 | size_t regsize = mips_abi_regsize (regcache->arch ()); |
387360da JB |
183 | |
184 | gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); | |
185 | ||
186 | mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize); | |
187 | } | |
188 | ||
189 | /* Supply register REGNUM from the buffer specified by GREGS and LEN | |
190 | in the general-purpose register set REGSET to register cache | |
191 | REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ | |
192 | ||
193 | static void | |
194 | mips_fbsd_supply_gregset (const struct regset *regset, | |
195 | struct regcache *regcache, int regnum, | |
196 | const void *gregs, size_t len) | |
197 | { | |
ac7936df | 198 | size_t regsize = mips_abi_regsize (regcache->arch ()); |
387360da JB |
199 | |
200 | gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); | |
201 | ||
202 | mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize); | |
203 | } | |
204 | ||
205 | /* Collect register REGNUM from the register cache REGCACHE and store | |
206 | it in the buffer specified by GREGS and LEN in the general-purpose | |
207 | register set REGSET. If REGNUM is -1, do this for all registers in | |
208 | REGSET. */ | |
209 | ||
210 | static void | |
211 | mips_fbsd_collect_gregset (const struct regset *regset, | |
212 | const struct regcache *regcache, | |
213 | int regnum, void *gregs, size_t len) | |
214 | { | |
ac7936df | 215 | size_t regsize = mips_abi_regsize (regcache->arch ()); |
387360da JB |
216 | |
217 | gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); | |
218 | ||
219 | mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize); | |
220 | } | |
221 | ||
222 | /* FreeBSD/mips register sets. */ | |
223 | ||
224 | static const struct regset mips_fbsd_gregset = | |
225 | { | |
226 | NULL, | |
227 | mips_fbsd_supply_gregset, | |
228 | mips_fbsd_collect_gregset, | |
229 | }; | |
230 | ||
231 | static const struct regset mips_fbsd_fpregset = | |
232 | { | |
233 | NULL, | |
234 | mips_fbsd_supply_fpregset, | |
235 | mips_fbsd_collect_fpregset, | |
236 | }; | |
237 | ||
238 | /* Iterate over core file register note sections. */ | |
239 | ||
240 | static void | |
241 | mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, | |
242 | iterate_over_regset_sections_cb *cb, | |
243 | void *cb_data, | |
244 | const struct regcache *regcache) | |
245 | { | |
246 | size_t regsize = mips_abi_regsize (gdbarch); | |
247 | ||
248 | cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, &mips_fbsd_gregset, | |
249 | NULL, cb_data); | |
250 | cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, &mips_fbsd_fpregset, | |
251 | NULL, cb_data); | |
252 | } | |
253 | ||
254 | /* Signal trampoline support. */ | |
255 | ||
256 | #define FBSD_SYS_sigreturn 417 | |
257 | ||
258 | #define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn | |
259 | #define MIPS_INST_SYSCALL 0x0000000c | |
260 | #define MIPS_INST_BREAK 0x0000000d | |
261 | ||
262 | #define O32_SIGFRAME_UCONTEXT_OFFSET (16) | |
263 | #define O32_SIGSET_T_SIZE (16) | |
264 | ||
265 | #define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE) | |
266 | #define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4) | |
267 | #define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4) | |
268 | #define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32) | |
269 | #define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4) | |
270 | #define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4) | |
271 | #define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4) | |
272 | #define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4) | |
273 | ||
274 | #define O32_UCONTEXT_REG_SIZE 4 | |
275 | ||
276 | static void | |
277 | mips_fbsd_sigframe_init (const struct tramp_frame *self, | |
278 | struct frame_info *this_frame, | |
279 | struct trad_frame_cache *cache, | |
280 | CORE_ADDR func) | |
281 | { | |
282 | struct gdbarch *gdbarch = get_frame_arch (this_frame); | |
283 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | |
284 | CORE_ADDR sp, ucontext_addr, addr; | |
285 | int regnum; | |
286 | gdb_byte buf[4]; | |
287 | ||
288 | /* We find the appropriate instance of `ucontext_t' at a | |
289 | fixed offset in the signal frame. */ | |
290 | sp = get_frame_register_signed (this_frame, | |
291 | MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); | |
292 | ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET; | |
293 | ||
294 | /* PC. */ | |
295 | regnum = mips_regnum (gdbarch)->pc; | |
296 | trad_frame_set_reg_addr (cache, | |
297 | regnum + gdbarch_num_regs (gdbarch), | |
298 | ucontext_addr + O32_UCONTEXT_PC); | |
299 | ||
300 | /* GPRs. */ | |
301 | for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS; | |
302 | regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE) | |
303 | trad_frame_set_reg_addr (cache, | |
304 | regnum + gdbarch_num_regs (gdbarch), | |
305 | addr); | |
306 | ||
307 | regnum = MIPS_PS_REGNUM; | |
308 | trad_frame_set_reg_addr (cache, | |
309 | regnum + gdbarch_num_regs (gdbarch), | |
310 | ucontext_addr + O32_UCONTEXT_SR); | |
311 | ||
312 | /* HI and LO. */ | |
313 | regnum = mips_regnum (gdbarch)->lo; | |
314 | trad_frame_set_reg_addr (cache, | |
315 | regnum + gdbarch_num_regs (gdbarch), | |
316 | ucontext_addr + O32_UCONTEXT_LO); | |
317 | regnum = mips_regnum (gdbarch)->hi; | |
318 | trad_frame_set_reg_addr (cache, | |
319 | regnum + gdbarch_num_regs (gdbarch), | |
320 | ucontext_addr + O32_UCONTEXT_HI); | |
321 | ||
1c33cd7f YQ |
322 | if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0 |
323 | && extract_unsigned_integer (buf, 4, byte_order) != 0) | |
387360da JB |
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, -1 }, /* addiu a0, sp, SIGF_UC */ | |
346 | { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */ | |
347 | { MIPS_INST_SYSCALL, -1 }, /* syscall */ | |
348 | { MIPS_INST_BREAK, -1 }, /* break */ | |
349 | { TRAMP_SENTINEL_INSN, -1 } | |
350 | }, | |
351 | mips_fbsd_sigframe_init | |
352 | }; | |
353 | ||
354 | #define N64_SIGFRAME_UCONTEXT_OFFSET (32) | |
355 | #define N64_SIGSET_T_SIZE (16) | |
356 | ||
357 | #define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE) | |
358 | #define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8) | |
359 | #define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8) | |
360 | #define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32) | |
361 | #define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8) | |
362 | #define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8) | |
363 | #define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8) | |
364 | #define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8) | |
365 | ||
366 | #define N64_UCONTEXT_REG_SIZE 8 | |
367 | ||
368 | static void | |
369 | mips64_fbsd_sigframe_init (const struct tramp_frame *self, | |
370 | struct frame_info *this_frame, | |
371 | struct trad_frame_cache *cache, | |
372 | CORE_ADDR func) | |
373 | { | |
374 | struct gdbarch *gdbarch = get_frame_arch (this_frame); | |
375 | enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); | |
376 | CORE_ADDR sp, ucontext_addr, addr; | |
377 | int regnum; | |
378 | gdb_byte buf[4]; | |
379 | ||
380 | /* We find the appropriate instance of `ucontext_t' at a | |
381 | fixed offset in the signal frame. */ | |
382 | sp = get_frame_register_signed (this_frame, | |
383 | MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); | |
384 | ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET; | |
385 | ||
386 | /* PC. */ | |
387 | regnum = mips_regnum (gdbarch)->pc; | |
388 | trad_frame_set_reg_addr (cache, | |
389 | regnum + gdbarch_num_regs (gdbarch), | |
390 | ucontext_addr + N64_UCONTEXT_PC); | |
391 | ||
392 | /* GPRs. */ | |
393 | for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS; | |
394 | regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE) | |
395 | trad_frame_set_reg_addr (cache, | |
396 | regnum + gdbarch_num_regs (gdbarch), | |
397 | addr); | |
398 | ||
399 | regnum = MIPS_PS_REGNUM; | |
400 | trad_frame_set_reg_addr (cache, | |
401 | regnum + gdbarch_num_regs (gdbarch), | |
402 | ucontext_addr + N64_UCONTEXT_SR); | |
403 | ||
404 | /* HI and LO. */ | |
405 | regnum = mips_regnum (gdbarch)->lo; | |
406 | trad_frame_set_reg_addr (cache, | |
407 | regnum + gdbarch_num_regs (gdbarch), | |
408 | ucontext_addr + N64_UCONTEXT_LO); | |
409 | regnum = mips_regnum (gdbarch)->hi; | |
410 | trad_frame_set_reg_addr (cache, | |
411 | regnum + gdbarch_num_regs (gdbarch), | |
412 | ucontext_addr + N64_UCONTEXT_HI); | |
413 | ||
1c33cd7f YQ |
414 | if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0 |
415 | && extract_unsigned_integer (buf, 4, byte_order) != 0) | |
387360da JB |
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 | ||
a80a6471 JB |
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, -1 }, /* addiu a0, sp, SIGF_UC */ | |
438 | { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */ | |
439 | { MIPS_INST_SYSCALL, -1 }, /* syscall */ | |
440 | { MIPS_INST_BREAK, -1 }, /* break */ | |
441 | { TRAMP_SENTINEL_INSN, -1 } | |
442 | }, | |
443 | mips64_fbsd_sigframe_init | |
444 | }; | |
445 | ||
387360da JB |
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, -1 }, /* daddiu a0, sp, SIGF_UC */ | |
455 | { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */ | |
456 | { MIPS_INST_SYSCALL, -1 }, /* syscall */ | |
457 | { MIPS_INST_BREAK, -1 }, /* break */ | |
458 | { TRAMP_SENTINEL_INSN, -1 } | |
459 | }, | |
460 | mips64_fbsd_sigframe_init | |
461 | }; | |
462 | ||
463 | /* Shared library support. */ | |
464 | ||
465 | /* FreeBSD/mips uses a slightly different `struct link_map' than the | |
466 | other FreeBSD platforms as it includes an additional `l_off' | |
467 | member. */ | |
468 | ||
469 | static struct link_map_offsets * | |
470 | mips_fbsd_ilp32_fetch_link_map_offsets (void) | |
471 | { | |
472 | static struct link_map_offsets lmo; | |
473 | static struct link_map_offsets *lmp = NULL; | |
474 | ||
475 | if (lmp == NULL) | |
476 | { | |
477 | lmp = &lmo; | |
478 | ||
479 | lmo.r_version_offset = 0; | |
480 | lmo.r_version_size = 4; | |
481 | lmo.r_map_offset = 4; | |
482 | lmo.r_brk_offset = 8; | |
483 | lmo.r_ldsomap_offset = -1; | |
484 | ||
485 | lmo.link_map_size = 24; | |
486 | lmo.l_addr_offset = 0; | |
487 | lmo.l_name_offset = 8; | |
488 | lmo.l_ld_offset = 12; | |
489 | lmo.l_next_offset = 16; | |
490 | lmo.l_prev_offset = 20; | |
491 | } | |
492 | ||
493 | return lmp; | |
494 | } | |
495 | ||
496 | static struct link_map_offsets * | |
497 | mips_fbsd_lp64_fetch_link_map_offsets (void) | |
498 | { | |
499 | static struct link_map_offsets lmo; | |
500 | static struct link_map_offsets *lmp = NULL; | |
501 | ||
502 | if (lmp == NULL) | |
503 | { | |
504 | lmp = &lmo; | |
505 | ||
506 | lmo.r_version_offset = 0; | |
507 | lmo.r_version_size = 4; | |
508 | lmo.r_map_offset = 8; | |
509 | lmo.r_brk_offset = 16; | |
510 | lmo.r_ldsomap_offset = -1; | |
511 | ||
512 | lmo.link_map_size = 48; | |
513 | lmo.l_addr_offset = 0; | |
514 | lmo.l_name_offset = 16; | |
515 | lmo.l_ld_offset = 24; | |
516 | lmo.l_next_offset = 32; | |
517 | lmo.l_prev_offset = 40; | |
518 | } | |
519 | ||
520 | return lmp; | |
521 | } | |
522 | ||
523 | static void | |
524 | mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) | |
525 | { | |
526 | enum mips_abi abi = mips_abi (gdbarch); | |
527 | ||
528 | /* Generic FreeBSD support. */ | |
529 | fbsd_init_abi (info, gdbarch); | |
530 | ||
531 | set_gdbarch_software_single_step (gdbarch, mips_software_single_step); | |
532 | ||
533 | switch (abi) | |
534 | { | |
535 | case MIPS_ABI_O32: | |
536 | tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe); | |
537 | break; | |
538 | case MIPS_ABI_N32: | |
a80a6471 | 539 | tramp_frame_prepend_unwinder (gdbarch, &mipsn32_fbsd_sigframe); |
387360da JB |
540 | break; |
541 | case MIPS_ABI_N64: | |
542 | tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe); | |
543 | break; | |
544 | } | |
545 | ||
546 | set_gdbarch_iterate_over_regset_sections | |
547 | (gdbarch, mips_fbsd_iterate_over_regset_sections); | |
548 | ||
549 | /* FreeBSD/mips has SVR4-style shared libraries. */ | |
550 | set_solib_svr4_fetch_link_map_offsets | |
551 | (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ? | |
552 | mips_fbsd_ilp32_fetch_link_map_offsets : | |
553 | mips_fbsd_lp64_fetch_link_map_offsets)); | |
554 | } | |
387360da JB |
555 | |
556 | void | |
557 | _initialize_mips_fbsd_tdep (void) | |
558 | { | |
c988ac1d | 559 | gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD, |
387360da JB |
560 | mips_fbsd_init_abi); |
561 | } |