Line 0
Link Here
|
|
|
1 |
commit 9978d70207d8a6bc7ff3c570814053c68e78b913 |
2 |
Author: John Baldwin <jhb@FreeBSD.org> |
3 |
Date: Wed Jan 4 09:41:58 2017 -0800 |
4 |
|
5 |
Add FreeBSD/mips architecture. |
6 |
|
7 |
This has been tested for the n64 and o32 ABIs. Signal frame unwinders for |
8 |
both ABIs are provided. FreeBSD/mips requires custom linkmap offsets since |
9 |
it contains an additional l_off member in 'struct link_map' that other |
10 |
FreeBSD platforms do not have. Support for collecting and supplying |
11 |
general purpose and floating point register sets are provided. Common |
12 |
routines for working with native format register sets are exported for |
13 |
use by the native target. |
14 |
|
15 |
gdb/ChangeLog: |
16 |
|
17 |
* Makefile.in (ALL_TARGET_OBS): Add mips-fbsd-tdep.o. |
18 |
(ALLDEPFILES): Add mips-fbsd-tdep.c. |
19 |
* NEWS: Mention new FreeBSD/mips target. |
20 |
* configure.tgt: Add mips*-*-freebsd*. |
21 |
* mips-fbsd-tdep.c: New file. |
22 |
* mips-fbsd-tdep.h: New file. |
23 |
|
24 |
gdb/doc/ChangeLog: |
25 |
|
26 |
* gdb.texinfo (Contributors): Add SRI International and University |
27 |
of Cambridge for FreeBSD/mips. |
28 |
|
29 |
diff --git gdb/Makefile.in gdb/Makefile.in |
30 |
index 7b2df86878..300c2cb702 100644 |
31 |
--- gdb/Makefile.in |
32 |
+++ gdb/Makefile.in |
33 |
@@ -685,6 +685,7 @@ ALL_TARGET_OBS = \ |
34 |
m88k-tdep.o \ |
35 |
mep-tdep.o \ |
36 |
microblaze-tdep.o microblaze-linux-tdep.o \ |
37 |
+ mips-fbsd-tdep.o \ |
38 |
mips-linux-tdep.o mips-sde-tdep.o \ |
39 |
mipsnbsd-tdep.o mips-tdep.o \ |
40 |
mn10300-linux-tdep.o mn10300-tdep.o \ |
41 |
@@ -1724,6 +1725,7 @@ ALLDEPFILES = \ |
42 |
m88k-tdep.c m88kbsd-nat.c \ |
43 |
microblaze-tdep.c microblaze-linux-tdep.c \ |
44 |
mingw-hdep.c common/mingw-strerror.c \ |
45 |
+ mips-fbsd-tdep.c \ |
46 |
mips-linux-nat.c mips-linux-tdep.c \ |
47 |
mips-sde-tdep.c \ |
48 |
mips-tdep.c \ |
49 |
diff --git gdb/configure.tgt gdb/configure.tgt |
50 |
index 7f1aac3742..9ee9f7a799 100644 |
51 |
--- gdb/configure.tgt |
52 |
+++ gdb/configure.tgt |
53 |
@@ -358,6 +358,11 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu) |
54 |
gdb_target_obs="mips-tdep.o mipsnbsd-tdep.o solib-svr4.o nbsd-tdep.o" |
55 |
gdb_sim=../sim/mips/libsim.a |
56 |
;; |
57 |
+mips*-*-freebsd*) |
58 |
+ # Target: MIPS running FreeBSD |
59 |
+ gdb_target_obs="mips-tdep.o mips-fbsd-tdep.o solib-svr4.o fbsd-tdep.o" |
60 |
+ gdb_sim=../sim/mips/libsim.a |
61 |
+ ;; |
62 |
mips64*-*-openbsd*) |
63 |
# Target: OpenBSD/mips64 |
64 |
gdb_target_obs="mips-tdep.o mips64obsd-tdep.o obsd-tdep.o solib-svr4.o" |
65 |
diff --git gdb/doc/gdb.texinfo gdb/doc/gdb.texinfo |
66 |
index 067a45b2de..179da5cdb3 100644 |
67 |
--- gdb/doc/gdb.texinfo |
68 |
+++ gdb/doc/gdb.texinfo |
69 |
@@ -541,6 +541,11 @@ Steve Tjiang, John Newlin, and Scott Foehner. |
70 |
Michael Eager and staff of Xilinx, Inc., contributed support for the |
71 |
Xilinx MicroBlaze architecture. |
72 |
|
73 |
+Initial support for the FreeBSD/mips target and native configuration |
74 |
+was developed by SRI International and the University of Cambridge |
75 |
+Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237 |
76 |
+("CTSRD"), as part of the DARPA CRASH research programme. |
77 |
+ |
78 |
@node Sample Session |
79 |
@chapter A Sample @value{GDBN} Session |
80 |
|
81 |
diff --git gdb/mips-fbsd-tdep.c gdb/mips-fbsd-tdep.c |
82 |
new file mode 100644 |
83 |
index 0000000000..733534ddac |
84 |
--- /dev/null |
85 |
+++ gdb/mips-fbsd-tdep.c |
86 |
@@ -0,0 +1,560 @@ |
87 |
+/* Target-dependent code for FreeBSD/mips. |
88 |
+ |
89 |
+ Copyright (C) 2017 Free Software Foundation, Inc. |
90 |
+ |
91 |
+ This file is part of GDB. |
92 |
+ |
93 |
+ This program is free software; you can redistribute it and/or modify |
94 |
+ it under the terms of the GNU General Public License as published by |
95 |
+ the Free Software Foundation; either version 3 of the License, or |
96 |
+ (at your option) any later version. |
97 |
+ |
98 |
+ This program is distributed in the hope that it will be useful, |
99 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
100 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
101 |
+ GNU General Public License for more details. |
102 |
+ |
103 |
+ You should have received a copy of the GNU General Public License |
104 |
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
105 |
+ |
106 |
+#include "defs.h" |
107 |
+#include "osabi.h" |
108 |
+#include "regset.h" |
109 |
+#include "trad-frame.h" |
110 |
+#include "tramp-frame.h" |
111 |
+ |
112 |
+#include "fbsd-tdep.h" |
113 |
+#include "mips-tdep.h" |
114 |
+#include "mips-fbsd-tdep.h" |
115 |
+ |
116 |
+#include "solib-svr4.h" |
117 |
+ |
118 |
+/* Shorthand for some register numbers used below. */ |
119 |
+#define MIPS_PC_REGNUM MIPS_EMBED_PC_REGNUM |
120 |
+#define MIPS_FP0_REGNUM MIPS_EMBED_FP0_REGNUM |
121 |
+#define MIPS_FSR_REGNUM MIPS_EMBED_FP0_REGNUM + 32 |
122 |
+ |
123 |
+/* Core file support. */ |
124 |
+ |
125 |
+/* Number of registers in `struct reg' from <machine/reg.h>. The |
126 |
+ first 38 follow the standard MIPS layout. The 39th holds |
127 |
+ IC_INT_REG on RM7K and RM9K processors. The 40th is a dummy for |
128 |
+ padding. */ |
129 |
+#define MIPS_FBSD_NUM_GREGS 40 |
130 |
+ |
131 |
+/* Number of registers in `struct fpreg' from <machine/reg.h>. The |
132 |
+ first 32 hold floating point registers. 33 holds the FSR. The |
133 |
+ 34th is a dummy for padding. */ |
134 |
+#define MIPS_FBSD_NUM_FPREGS 34 |
135 |
+ |
136 |
+/* Supply a single register. If the source register size matches the |
137 |
+ size the regcache expects, this can use regcache_raw_supply(). If |
138 |
+ they are different, this copies the source register into a buffer |
139 |
+ that can be passed to regcache_raw_supply(). */ |
140 |
+ |
141 |
+static void |
142 |
+mips_fbsd_supply_reg (struct regcache *regcache, int regnum, const void *addr, |
143 |
+ size_t len) |
144 |
+{ |
145 |
+ struct gdbarch *gdbarch = get_regcache_arch (regcache); |
146 |
+ |
147 |
+ if (register_size (gdbarch, regnum) == len) |
148 |
+ regcache_raw_supply (regcache, regnum, addr); |
149 |
+ else |
150 |
+ { |
151 |
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
152 |
+ gdb_byte buf[MAX_REGISTER_SIZE]; |
153 |
+ LONGEST val; |
154 |
+ |
155 |
+ val = extract_signed_integer ((const gdb_byte *) addr, len, byte_order); |
156 |
+ store_signed_integer (buf, register_size (gdbarch, regnum), byte_order, |
157 |
+ val); |
158 |
+ regcache_raw_supply (regcache, regnum, buf); |
159 |
+ } |
160 |
+} |
161 |
+ |
162 |
+/* Collect a single register. If the destination register size |
163 |
+ matches the size the regcache expects, this can use |
164 |
+ regcache_raw_supply(). If they are different, this fetches the |
165 |
+ register via regcache_raw_supply() into a buffer and then copies it |
166 |
+ into the final destination. */ |
167 |
+ |
168 |
+static void |
169 |
+mips_fbsd_collect_reg (const struct regcache *regcache, int regnum, void *addr, |
170 |
+ size_t len) |
171 |
+{ |
172 |
+ struct gdbarch *gdbarch = get_regcache_arch (regcache); |
173 |
+ |
174 |
+ if (register_size (gdbarch, regnum) == len) |
175 |
+ regcache_raw_collect (regcache, regnum, addr); |
176 |
+ else |
177 |
+ { |
178 |
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
179 |
+ gdb_byte buf[MAX_REGISTER_SIZE]; |
180 |
+ LONGEST val; |
181 |
+ |
182 |
+ regcache_raw_collect (regcache, regnum, buf); |
183 |
+ val = extract_signed_integer (buf, register_size (gdbarch, regnum), |
184 |
+ byte_order); |
185 |
+ store_signed_integer ((gdb_byte *) addr, len, byte_order, val); |
186 |
+ } |
187 |
+} |
188 |
+ |
189 |
+/* Supply the floating-point registers stored in FPREGS to REGCACHE. |
190 |
+ Each floating-point register in FPREGS is REGSIZE bytes in |
191 |
+ length. */ |
192 |
+ |
193 |
+void |
194 |
+mips_fbsd_supply_fpregs (struct regcache *regcache, int regnum, |
195 |
+ const void *fpregs, size_t regsize) |
196 |
+{ |
197 |
+ const gdb_byte *regs = (const gdb_byte *) fpregs; |
198 |
+ int i; |
199 |
+ |
200 |
+ for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++) |
201 |
+ if (regnum == i || regnum == -1) |
202 |
+ mips_fbsd_supply_reg (regcache, i, |
203 |
+ regs + (i - MIPS_FP0_REGNUM) * regsize, regsize); |
204 |
+} |
205 |
+ |
206 |
+/* Supply the general-purpose registers stored in GREGS to REGCACHE. |
207 |
+ Each general-purpose register in GREGS is REGSIZE bytes in |
208 |
+ length. */ |
209 |
+ |
210 |
+void |
211 |
+mips_fbsd_supply_gregs (struct regcache *regcache, int regnum, |
212 |
+ const void *gregs, size_t regsize) |
213 |
+{ |
214 |
+ const gdb_byte *regs = (const gdb_byte *) gregs; |
215 |
+ int i; |
216 |
+ |
217 |
+ for (i = 0; i <= MIPS_PC_REGNUM; i++) |
218 |
+ if (regnum == i || regnum == -1) |
219 |
+ mips_fbsd_supply_reg (regcache, i, regs + i * regsize, regsize); |
220 |
+} |
221 |
+ |
222 |
+/* Collect the floating-point registers from REGCACHE and store them |
223 |
+ in FPREGS. Each floating-point register in FPREGS is REGSIZE bytes |
224 |
+ in length. */ |
225 |
+ |
226 |
+void |
227 |
+mips_fbsd_collect_fpregs (const struct regcache *regcache, int regnum, |
228 |
+ void *fpregs, size_t regsize) |
229 |
+{ |
230 |
+ gdb_byte *regs = (gdb_byte *) fpregs; |
231 |
+ int i; |
232 |
+ |
233 |
+ for (i = MIPS_FP0_REGNUM; i <= MIPS_FSR_REGNUM; i++) |
234 |
+ if (regnum == i || regnum == -1) |
235 |
+ mips_fbsd_collect_reg (regcache, i, |
236 |
+ regs + (i - MIPS_FP0_REGNUM) * regsize, regsize); |
237 |
+} |
238 |
+ |
239 |
+/* Collect the general-purpose registers from REGCACHE and store them |
240 |
+ in GREGS. Each general-purpose register in GREGS is REGSIZE bytes |
241 |
+ in length. */ |
242 |
+ |
243 |
+void |
244 |
+mips_fbsd_collect_gregs (const struct regcache *regcache, int regnum, |
245 |
+ void *gregs, size_t regsize) |
246 |
+{ |
247 |
+ gdb_byte *regs = (gdb_byte *) gregs; |
248 |
+ int i; |
249 |
+ |
250 |
+ for (i = 0; i <= MIPS_PC_REGNUM; i++) |
251 |
+ if (regnum == i || regnum == -1) |
252 |
+ mips_fbsd_collect_reg (regcache, i, regs + i * regsize, regsize); |
253 |
+} |
254 |
+ |
255 |
+/* Supply register REGNUM from the buffer specified by FPREGS and LEN |
256 |
+ in the floating-point register set REGSET to register cache |
257 |
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ |
258 |
+ |
259 |
+static void |
260 |
+mips_fbsd_supply_fpregset (const struct regset *regset, |
261 |
+ struct regcache *regcache, |
262 |
+ int regnum, const void *fpregs, size_t len) |
263 |
+{ |
264 |
+ size_t regsize = mips_abi_regsize (get_regcache_arch (regcache)); |
265 |
+ |
266 |
+ gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); |
267 |
+ |
268 |
+ mips_fbsd_supply_fpregs (regcache, regnum, fpregs, regsize); |
269 |
+} |
270 |
+ |
271 |
+/* Collect register REGNUM from the register cache REGCACHE and store |
272 |
+ it in the buffer specified by FPREGS and LEN in the floating-point |
273 |
+ register set REGSET. If REGNUM is -1, do this for all registers in |
274 |
+ REGSET. */ |
275 |
+ |
276 |
+static void |
277 |
+mips_fbsd_collect_fpregset (const struct regset *regset, |
278 |
+ const struct regcache *regcache, |
279 |
+ int regnum, void *fpregs, size_t len) |
280 |
+{ |
281 |
+ size_t regsize = mips_abi_regsize (get_regcache_arch (regcache)); |
282 |
+ |
283 |
+ gdb_assert (len >= MIPS_FBSD_NUM_FPREGS * regsize); |
284 |
+ |
285 |
+ mips_fbsd_collect_fpregs (regcache, regnum, fpregs, regsize); |
286 |
+} |
287 |
+ |
288 |
+/* Supply register REGNUM from the buffer specified by GREGS and LEN |
289 |
+ in the general-purpose register set REGSET to register cache |
290 |
+ REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ |
291 |
+ |
292 |
+static void |
293 |
+mips_fbsd_supply_gregset (const struct regset *regset, |
294 |
+ struct regcache *regcache, int regnum, |
295 |
+ const void *gregs, size_t len) |
296 |
+{ |
297 |
+ size_t regsize = mips_abi_regsize (get_regcache_arch (regcache)); |
298 |
+ |
299 |
+ gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); |
300 |
+ |
301 |
+ mips_fbsd_supply_gregs (regcache, regnum, gregs, regsize); |
302 |
+} |
303 |
+ |
304 |
+/* Collect register REGNUM from the register cache REGCACHE and store |
305 |
+ it in the buffer specified by GREGS and LEN in the general-purpose |
306 |
+ register set REGSET. If REGNUM is -1, do this for all registers in |
307 |
+ REGSET. */ |
308 |
+ |
309 |
+static void |
310 |
+mips_fbsd_collect_gregset (const struct regset *regset, |
311 |
+ const struct regcache *regcache, |
312 |
+ int regnum, void *gregs, size_t len) |
313 |
+{ |
314 |
+ size_t regsize = mips_abi_regsize (get_regcache_arch (regcache)); |
315 |
+ |
316 |
+ gdb_assert (len >= MIPS_FBSD_NUM_GREGS * regsize); |
317 |
+ |
318 |
+ mips_fbsd_collect_gregs (regcache, regnum, gregs, regsize); |
319 |
+} |
320 |
+ |
321 |
+/* FreeBSD/mips register sets. */ |
322 |
+ |
323 |
+static const struct regset mips_fbsd_gregset = |
324 |
+{ |
325 |
+ NULL, |
326 |
+ mips_fbsd_supply_gregset, |
327 |
+ mips_fbsd_collect_gregset, |
328 |
+}; |
329 |
+ |
330 |
+static const struct regset mips_fbsd_fpregset = |
331 |
+{ |
332 |
+ NULL, |
333 |
+ mips_fbsd_supply_fpregset, |
334 |
+ mips_fbsd_collect_fpregset, |
335 |
+}; |
336 |
+ |
337 |
+/* Iterate over core file register note sections. */ |
338 |
+ |
339 |
+static void |
340 |
+mips_fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, |
341 |
+ iterate_over_regset_sections_cb *cb, |
342 |
+ void *cb_data, |
343 |
+ const struct regcache *regcache) |
344 |
+{ |
345 |
+ size_t regsize = mips_abi_regsize (gdbarch); |
346 |
+ |
347 |
+ cb (".reg", MIPS_FBSD_NUM_GREGS * regsize, &mips_fbsd_gregset, |
348 |
+ NULL, cb_data); |
349 |
+ cb (".reg2", MIPS_FBSD_NUM_FPREGS * regsize, &mips_fbsd_fpregset, |
350 |
+ NULL, cb_data); |
351 |
+} |
352 |
+ |
353 |
+/* Signal trampoline support. */ |
354 |
+ |
355 |
+#define FBSD_SYS_sigreturn 417 |
356 |
+ |
357 |
+#define MIPS_INST_LI_V0_SIGRETURN 0x24020000 + FBSD_SYS_sigreturn |
358 |
+#define MIPS_INST_SYSCALL 0x0000000c |
359 |
+#define MIPS_INST_BREAK 0x0000000d |
360 |
+ |
361 |
+#define O32_SIGFRAME_UCONTEXT_OFFSET (16) |
362 |
+#define O32_SIGSET_T_SIZE (16) |
363 |
+ |
364 |
+#define O32_UCONTEXT_ONSTACK (O32_SIGSET_T_SIZE) |
365 |
+#define O32_UCONTEXT_PC (O32_UCONTEXT_ONSTACK + 4) |
366 |
+#define O32_UCONTEXT_REGS (O32_UCONTEXT_PC + 4) |
367 |
+#define O32_UCONTEXT_SR (O32_UCONTEXT_REGS + 4 * 32) |
368 |
+#define O32_UCONTEXT_LO (O32_UCONTEXT_SR + 4) |
369 |
+#define O32_UCONTEXT_HI (O32_UCONTEXT_LO + 4) |
370 |
+#define O32_UCONTEXT_FPUSED (O32_UCONTEXT_HI + 4) |
371 |
+#define O32_UCONTEXT_FPREGS (O32_UCONTEXT_FPUSED + 4) |
372 |
+ |
373 |
+#define O32_UCONTEXT_REG_SIZE 4 |
374 |
+ |
375 |
+static void |
376 |
+mips_fbsd_sigframe_init (const struct tramp_frame *self, |
377 |
+ struct frame_info *this_frame, |
378 |
+ struct trad_frame_cache *cache, |
379 |
+ CORE_ADDR func) |
380 |
+{ |
381 |
+ struct gdbarch *gdbarch = get_frame_arch (this_frame); |
382 |
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
383 |
+ CORE_ADDR sp, ucontext_addr, addr; |
384 |
+ int regnum; |
385 |
+ gdb_byte buf[4]; |
386 |
+ |
387 |
+ /* We find the appropriate instance of `ucontext_t' at a |
388 |
+ fixed offset in the signal frame. */ |
389 |
+ sp = get_frame_register_signed (this_frame, |
390 |
+ MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); |
391 |
+ ucontext_addr = sp + O32_SIGFRAME_UCONTEXT_OFFSET; |
392 |
+ |
393 |
+ /* PC. */ |
394 |
+ regnum = mips_regnum (gdbarch)->pc; |
395 |
+ trad_frame_set_reg_addr (cache, |
396 |
+ regnum + gdbarch_num_regs (gdbarch), |
397 |
+ ucontext_addr + O32_UCONTEXT_PC); |
398 |
+ |
399 |
+ /* GPRs. */ |
400 |
+ for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + O32_UCONTEXT_REGS; |
401 |
+ regnum <= MIPS_RA_REGNUM; regnum++, addr += O32_UCONTEXT_REG_SIZE) |
402 |
+ trad_frame_set_reg_addr (cache, |
403 |
+ regnum + gdbarch_num_regs (gdbarch), |
404 |
+ addr); |
405 |
+ |
406 |
+ regnum = MIPS_PS_REGNUM; |
407 |
+ trad_frame_set_reg_addr (cache, |
408 |
+ regnum + gdbarch_num_regs (gdbarch), |
409 |
+ ucontext_addr + O32_UCONTEXT_SR); |
410 |
+ |
411 |
+ /* HI and LO. */ |
412 |
+ regnum = mips_regnum (gdbarch)->lo; |
413 |
+ trad_frame_set_reg_addr (cache, |
414 |
+ regnum + gdbarch_num_regs (gdbarch), |
415 |
+ ucontext_addr + O32_UCONTEXT_LO); |
416 |
+ regnum = mips_regnum (gdbarch)->hi; |
417 |
+ trad_frame_set_reg_addr (cache, |
418 |
+ regnum + gdbarch_num_regs (gdbarch), |
419 |
+ ucontext_addr + O32_UCONTEXT_HI); |
420 |
+ |
421 |
+ if (target_read_memory (ucontext_addr + O32_UCONTEXT_FPUSED, buf, 4) == 0 && |
422 |
+ extract_unsigned_integer (buf, 4, byte_order) != 0) |
423 |
+ { |
424 |
+ for (regnum = 0, addr = ucontext_addr + O32_UCONTEXT_FPREGS; |
425 |
+ regnum < 32; regnum++, addr += O32_UCONTEXT_REG_SIZE) |
426 |
+ trad_frame_set_reg_addr (cache, |
427 |
+ regnum + gdbarch_fp0_regnum (gdbarch), |
428 |
+ addr); |
429 |
+ trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, |
430 |
+ addr); |
431 |
+ } |
432 |
+ |
433 |
+ trad_frame_set_id (cache, frame_id_build (sp, func)); |
434 |
+} |
435 |
+ |
436 |
+#define MIPS_INST_ADDIU_A0_SP_O32 (0x27a40000 \ |
437 |
+ + O32_SIGFRAME_UCONTEXT_OFFSET) |
438 |
+ |
439 |
+static const struct tramp_frame mips_fbsd_sigframe = |
440 |
+{ |
441 |
+ SIGTRAMP_FRAME, |
442 |
+ MIPS_INSN32_SIZE, |
443 |
+ { |
444 |
+ { MIPS_INST_ADDIU_A0_SP_O32, -1 }, /* addiu a0, sp, SIGF_UC */ |
445 |
+ { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */ |
446 |
+ { MIPS_INST_SYSCALL, -1 }, /* syscall */ |
447 |
+ { MIPS_INST_BREAK, -1 }, /* break */ |
448 |
+ { TRAMP_SENTINEL_INSN, -1 } |
449 |
+ }, |
450 |
+ mips_fbsd_sigframe_init |
451 |
+}; |
452 |
+ |
453 |
+#define N64_SIGFRAME_UCONTEXT_OFFSET (32) |
454 |
+#define N64_SIGSET_T_SIZE (16) |
455 |
+ |
456 |
+#define N64_UCONTEXT_ONSTACK (N64_SIGSET_T_SIZE) |
457 |
+#define N64_UCONTEXT_PC (N64_UCONTEXT_ONSTACK + 8) |
458 |
+#define N64_UCONTEXT_REGS (N64_UCONTEXT_PC + 8) |
459 |
+#define N64_UCONTEXT_SR (N64_UCONTEXT_REGS + 8 * 32) |
460 |
+#define N64_UCONTEXT_LO (N64_UCONTEXT_SR + 8) |
461 |
+#define N64_UCONTEXT_HI (N64_UCONTEXT_LO + 8) |
462 |
+#define N64_UCONTEXT_FPUSED (N64_UCONTEXT_HI + 8) |
463 |
+#define N64_UCONTEXT_FPREGS (N64_UCONTEXT_FPUSED + 8) |
464 |
+ |
465 |
+#define N64_UCONTEXT_REG_SIZE 8 |
466 |
+ |
467 |
+static void |
468 |
+mips64_fbsd_sigframe_init (const struct tramp_frame *self, |
469 |
+ struct frame_info *this_frame, |
470 |
+ struct trad_frame_cache *cache, |
471 |
+ CORE_ADDR func) |
472 |
+{ |
473 |
+ struct gdbarch *gdbarch = get_frame_arch (this_frame); |
474 |
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); |
475 |
+ CORE_ADDR sp, ucontext_addr, addr; |
476 |
+ int regnum; |
477 |
+ gdb_byte buf[4]; |
478 |
+ |
479 |
+ /* We find the appropriate instance of `ucontext_t' at a |
480 |
+ fixed offset in the signal frame. */ |
481 |
+ sp = get_frame_register_signed (this_frame, |
482 |
+ MIPS_SP_REGNUM + gdbarch_num_regs (gdbarch)); |
483 |
+ ucontext_addr = sp + N64_SIGFRAME_UCONTEXT_OFFSET; |
484 |
+ |
485 |
+ /* PC. */ |
486 |
+ regnum = mips_regnum (gdbarch)->pc; |
487 |
+ trad_frame_set_reg_addr (cache, |
488 |
+ regnum + gdbarch_num_regs (gdbarch), |
489 |
+ ucontext_addr + N64_UCONTEXT_PC); |
490 |
+ |
491 |
+ /* GPRs. */ |
492 |
+ for (regnum = MIPS_ZERO_REGNUM, addr = ucontext_addr + N64_UCONTEXT_REGS; |
493 |
+ regnum <= MIPS_RA_REGNUM; regnum++, addr += N64_UCONTEXT_REG_SIZE) |
494 |
+ trad_frame_set_reg_addr (cache, |
495 |
+ regnum + gdbarch_num_regs (gdbarch), |
496 |
+ addr); |
497 |
+ |
498 |
+ regnum = MIPS_PS_REGNUM; |
499 |
+ trad_frame_set_reg_addr (cache, |
500 |
+ regnum + gdbarch_num_regs (gdbarch), |
501 |
+ ucontext_addr + N64_UCONTEXT_SR); |
502 |
+ |
503 |
+ /* HI and LO. */ |
504 |
+ regnum = mips_regnum (gdbarch)->lo; |
505 |
+ trad_frame_set_reg_addr (cache, |
506 |
+ regnum + gdbarch_num_regs (gdbarch), |
507 |
+ ucontext_addr + N64_UCONTEXT_LO); |
508 |
+ regnum = mips_regnum (gdbarch)->hi; |
509 |
+ trad_frame_set_reg_addr (cache, |
510 |
+ regnum + gdbarch_num_regs (gdbarch), |
511 |
+ ucontext_addr + N64_UCONTEXT_HI); |
512 |
+ |
513 |
+ if (target_read_memory (ucontext_addr + N64_UCONTEXT_FPUSED, buf, 4) == 0 && |
514 |
+ extract_unsigned_integer (buf, 4, byte_order) != 0) |
515 |
+ { |
516 |
+ for (regnum = 0, addr = ucontext_addr + N64_UCONTEXT_FPREGS; |
517 |
+ regnum < 32; regnum++, addr += N64_UCONTEXT_REG_SIZE) |
518 |
+ trad_frame_set_reg_addr (cache, |
519 |
+ regnum + gdbarch_fp0_regnum (gdbarch), |
520 |
+ addr); |
521 |
+ trad_frame_set_reg_addr (cache, mips_regnum (gdbarch)->fp_control_status, |
522 |
+ addr); |
523 |
+ } |
524 |
+ |
525 |
+ trad_frame_set_id (cache, frame_id_build (sp, func)); |
526 |
+} |
527 |
+ |
528 |
+#define MIPS_INST_DADDIU_A0_SP_N64 (0x67a40000 \ |
529 |
+ + N64_SIGFRAME_UCONTEXT_OFFSET) |
530 |
+ |
531 |
+static const struct tramp_frame mips64_fbsd_sigframe = |
532 |
+{ |
533 |
+ SIGTRAMP_FRAME, |
534 |
+ MIPS_INSN32_SIZE, |
535 |
+ { |
536 |
+ { MIPS_INST_DADDIU_A0_SP_N64, -1 }, /* daddiu a0, sp, SIGF_UC */ |
537 |
+ { MIPS_INST_LI_V0_SIGRETURN, -1 }, /* li v0, SYS_sigreturn */ |
538 |
+ { MIPS_INST_SYSCALL, -1 }, /* syscall */ |
539 |
+ { MIPS_INST_BREAK, -1 }, /* break */ |
540 |
+ { TRAMP_SENTINEL_INSN, -1 } |
541 |
+ }, |
542 |
+ mips64_fbsd_sigframe_init |
543 |
+}; |
544 |
+ |
545 |
+/* Shared library support. */ |
546 |
+ |
547 |
+/* FreeBSD/mips uses a slightly different `struct link_map' than the |
548 |
+ other FreeBSD platforms as it includes an additional `l_off' |
549 |
+ member. */ |
550 |
+ |
551 |
+static struct link_map_offsets * |
552 |
+mips_fbsd_ilp32_fetch_link_map_offsets (void) |
553 |
+{ |
554 |
+ static struct link_map_offsets lmo; |
555 |
+ static struct link_map_offsets *lmp = NULL; |
556 |
+ |
557 |
+ if (lmp == NULL) |
558 |
+ { |
559 |
+ lmp = &lmo; |
560 |
+ |
561 |
+ lmo.r_version_offset = 0; |
562 |
+ lmo.r_version_size = 4; |
563 |
+ lmo.r_map_offset = 4; |
564 |
+ lmo.r_brk_offset = 8; |
565 |
+ lmo.r_ldsomap_offset = -1; |
566 |
+ |
567 |
+ lmo.link_map_size = 24; |
568 |
+ lmo.l_addr_offset = 0; |
569 |
+ lmo.l_name_offset = 8; |
570 |
+ lmo.l_ld_offset = 12; |
571 |
+ lmo.l_next_offset = 16; |
572 |
+ lmo.l_prev_offset = 20; |
573 |
+ } |
574 |
+ |
575 |
+ return lmp; |
576 |
+} |
577 |
+ |
578 |
+static struct link_map_offsets * |
579 |
+mips_fbsd_lp64_fetch_link_map_offsets (void) |
580 |
+{ |
581 |
+ static struct link_map_offsets lmo; |
582 |
+ static struct link_map_offsets *lmp = NULL; |
583 |
+ |
584 |
+ if (lmp == NULL) |
585 |
+ { |
586 |
+ lmp = &lmo; |
587 |
+ |
588 |
+ lmo.r_version_offset = 0; |
589 |
+ lmo.r_version_size = 4; |
590 |
+ lmo.r_map_offset = 8; |
591 |
+ lmo.r_brk_offset = 16; |
592 |
+ lmo.r_ldsomap_offset = -1; |
593 |
+ |
594 |
+ lmo.link_map_size = 48; |
595 |
+ lmo.l_addr_offset = 0; |
596 |
+ lmo.l_name_offset = 16; |
597 |
+ lmo.l_ld_offset = 24; |
598 |
+ lmo.l_next_offset = 32; |
599 |
+ lmo.l_prev_offset = 40; |
600 |
+ } |
601 |
+ |
602 |
+ return lmp; |
603 |
+} |
604 |
+ |
605 |
+static void |
606 |
+mips_fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) |
607 |
+{ |
608 |
+ enum mips_abi abi = mips_abi (gdbarch); |
609 |
+ |
610 |
+ /* Generic FreeBSD support. */ |
611 |
+ fbsd_init_abi (info, gdbarch); |
612 |
+ |
613 |
+ set_gdbarch_software_single_step (gdbarch, mips_software_single_step); |
614 |
+ |
615 |
+ switch (abi) |
616 |
+ { |
617 |
+ case MIPS_ABI_O32: |
618 |
+ tramp_frame_prepend_unwinder (gdbarch, &mips_fbsd_sigframe); |
619 |
+ break; |
620 |
+ case MIPS_ABI_N32: |
621 |
+ break; |
622 |
+ case MIPS_ABI_N64: |
623 |
+ tramp_frame_prepend_unwinder (gdbarch, &mips64_fbsd_sigframe); |
624 |
+ break; |
625 |
+ } |
626 |
+ |
627 |
+ set_gdbarch_iterate_over_regset_sections |
628 |
+ (gdbarch, mips_fbsd_iterate_over_regset_sections); |
629 |
+ |
630 |
+ /* FreeBSD/mips has SVR4-style shared libraries. */ |
631 |
+ set_solib_svr4_fetch_link_map_offsets |
632 |
+ (gdbarch, (gdbarch_ptr_bit (gdbarch) == 32 ? |
633 |
+ mips_fbsd_ilp32_fetch_link_map_offsets : |
634 |
+ mips_fbsd_lp64_fetch_link_map_offsets)); |
635 |
+} |
636 |
+ |
637 |
+ |
638 |
+/* Provide a prototype to silence -Wmissing-prototypes. */ |
639 |
+void _initialize_mips_fbsd_tdep (void); |
640 |
+ |
641 |
+void |
642 |
+_initialize_mips_fbsd_tdep (void) |
643 |
+{ |
644 |
+ gdbarch_register_osabi (bfd_arch_mips, 0, GDB_OSABI_FREEBSD_ELF, |
645 |
+ mips_fbsd_init_abi); |
646 |
+} |
647 |
diff --git gdb/mips-fbsd-tdep.h gdb/mips-fbsd-tdep.h |
648 |
new file mode 100644 |
649 |
index 0000000000..8a197e6325 |
650 |
--- /dev/null |
651 |
+++ gdb/mips-fbsd-tdep.h |
652 |
@@ -0,0 +1,28 @@ |
653 |
+/* Common target dependent code for GDB on MIPS systems running FreeBSD. |
654 |
+ |
655 |
+ Copyright (C) 2017 Free Software Foundation, Inc. |
656 |
+ |
657 |
+ This file is part of GDB. |
658 |
+ |
659 |
+ This program is free software; you can redistribute it and/or modify |
660 |
+ it under the terms of the GNU General Public License as published by |
661 |
+ the Free Software Foundation; either version 3 of the License, or |
662 |
+ (at your option) any later version. |
663 |
+ |
664 |
+ This program is distributed in the hope that it will be useful, |
665 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of |
666 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
667 |
+ GNU General Public License for more details. |
668 |
+ |
669 |
+ You should have received a copy of the GNU General Public License |
670 |
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
671 |
+ |
672 |
+#ifndef MIPS_FBSD_TDEP_H |
673 |
+#define MIPS_FBSD_TDEP_H |
674 |
+ |
675 |
+void mips_fbsd_supply_fpregs (struct regcache *, int, const void *, size_t); |
676 |
+void mips_fbsd_supply_gregs (struct regcache *, int, const void *, size_t); |
677 |
+void mips_fbsd_collect_fpregs (const struct regcache *, int, void *, size_t); |
678 |
+void mips_fbsd_collect_gregs (const struct regcache *, int, void *, size_t); |
679 |
+ |
680 |
+#endif /* MIPS_FBSD_TDEP_H */ |