1 /* Target-dependent code for FreeBSD/i386.
3 Copyright (C) 2003-2015 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
21 #include "arch-utils.h"
26 #include "i386-tdep.h"
27 #include "i387-tdep.h"
28 #include "bsd-uthread.h"
29 #include "fbsd-tdep.h"
30 #include "solib-svr4.h"
32 /* Support for signal handlers. */
34 /* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
37 /* FreeBSD/i386 supports three different signal trampolines, one for
38 versions before 4.0, a second for 4.x, and a third for 5.0 and
39 later. To complicate matters, FreeBSD/i386 binaries running under
40 an amd64 kernel use a different set of trampolines. These
41 trampolines differ from the i386 kernel trampolines in that they
42 omit a middle section that conditionally restores %gs. */
44 static const gdb_byte i386fbsd_sigtramp_start
[] =
46 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
50 static const gdb_byte i386fbsd_sigtramp_middle
[] =
52 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00,
53 /* testl $PSL_VM,UC_EFLAGS(%eax) */
54 0x75, 0x03, /* jne +3 */
55 0x8e, 0x68, 0x14 /* mov UC_GS(%eax),%gs */
58 static const gdb_byte i386fbsd_sigtramp_end
[] =
60 0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl $SYS_sigreturn,%eax */
61 0x50, /* pushl %eax */
62 0xcd, 0x80 /* int $0x80 */
65 static const gdb_byte i386fbsd_freebsd4_sigtramp_start
[] =
67 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */
71 static const gdb_byte i386fbsd_freebsd4_sigtramp_middle
[] =
73 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00,
74 /* testl $PSL_VM,UC4_EFLAGS(%eax) */
75 0x75, 0x03, /* jne +3 */
76 0x8e, 0x68, 0x14 /* mov UC4_GS(%eax),%gs */
79 static const gdb_byte i386fbsd_freebsd4_sigtramp_end
[] =
81 0xb8, 0x58, 0x01, 0x00, 0x00, /* movl $344,%eax */
82 0x50, /* pushl %eax */
83 0xcd, 0x80 /* int $0x80 */
86 static const gdb_byte i386fbsd_osigtramp_start
[] =
88 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */
92 static const gdb_byte i386fbsd_osigtramp_middle
[] =
94 0xf7, 0x40, 0x18, 0x00, 0x00, 0x02, 0x00,
95 /* testl $PSL_VM,SC_PS(%eax) */
96 0x75, 0x03, /* jne +3 */
97 0x8e, 0x68, 0x44 /* mov SC_GS(%eax),%gs */
100 static const gdb_byte i386fbsd_osigtramp_end
[] =
102 0xb8, 0x67, 0x00, 0x00, 0x00, /* movl $103,%eax */
103 0x50, /* pushl %eax */
104 0xcd, 0x80 /* int $0x80 */
107 /* The three different trampolines are all the same size. */
108 gdb_static_assert (sizeof i386fbsd_sigtramp_start
==
109 sizeof i386fbsd_freebsd4_sigtramp_start
);
110 gdb_static_assert (sizeof i386fbsd_sigtramp_start
==
111 sizeof i386fbsd_osigtramp_start
);
112 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
==
113 sizeof i386fbsd_freebsd4_sigtramp_middle
);
114 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
==
115 sizeof i386fbsd_osigtramp_middle
);
116 gdb_static_assert (sizeof i386fbsd_sigtramp_end
==
117 sizeof i386fbsd_freebsd4_sigtramp_end
);
118 gdb_static_assert (sizeof i386fbsd_sigtramp_end
==
119 sizeof i386fbsd_osigtramp_end
);
121 /* We assume that the middle is the largest chunk below. */
122 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
>
123 sizeof i386fbsd_sigtramp_start
);
124 gdb_static_assert (sizeof i386fbsd_sigtramp_middle
>
125 sizeof i386fbsd_sigtramp_end
);
128 i386fbsd_sigtramp_p (struct frame_info
*this_frame
)
130 CORE_ADDR pc
= get_frame_pc (this_frame
);
131 gdb_byte buf
[sizeof i386fbsd_sigtramp_middle
];
132 const gdb_byte
*middle
, *end
;
134 /* Look for a matching start. */
135 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
136 sizeof i386fbsd_sigtramp_start
))
138 if (memcmp (buf
, i386fbsd_sigtramp_start
, sizeof i386fbsd_sigtramp_start
) ==
140 middle
= i386fbsd_sigtramp_middle
;
141 end
= i386fbsd_sigtramp_end
;
142 } else if (memcmp (buf
, i386fbsd_freebsd4_sigtramp_start
,
143 sizeof i386fbsd_freebsd4_sigtramp_start
) == 0) {
144 middle
= i386fbsd_freebsd4_sigtramp_middle
;
145 end
= i386fbsd_freebsd4_sigtramp_end
;
146 } else if (memcmp (buf
, i386fbsd_osigtramp_start
,
147 sizeof i386fbsd_osigtramp_start
) == 0) {
148 middle
= i386fbsd_osigtramp_middle
;
149 end
= i386fbsd_osigtramp_end
;
153 /* Since the end is shorter than the middle, check for a matching end
155 pc
+= sizeof i386fbsd_sigtramp_start
;
156 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
157 sizeof i386fbsd_sigtramp_end
))
159 if (memcmp (buf
, end
, sizeof i386fbsd_sigtramp_end
) == 0)
162 /* If the end didn't match, check for a matching middle. */
163 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
164 sizeof i386fbsd_sigtramp_middle
))
166 if (memcmp (buf
, middle
, sizeof i386fbsd_sigtramp_middle
) != 0)
169 /* The middle matched, check for a matching end. */
170 pc
+= sizeof i386fbsd_sigtramp_middle
;
171 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
172 sizeof i386fbsd_sigtramp_end
))
174 if (memcmp (buf
, end
, sizeof i386fbsd_sigtramp_end
) != 0)
180 /* FreeBSD 3.0-RELEASE or later. */
182 /* From <machine/reg.h>. */
183 static int i386fbsd_r_reg_offset
[] =
185 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */
186 15 * 4, 4 * 4, /* %esp, %ebp */
187 3 * 4, 2 * 4, /* %esi, %edi */
188 12 * 4, 14 * 4, /* %eip, %eflags */
189 13 * 4, 16 * 4, /* %cs, %ss */
190 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */
193 /* Sigtramp routine location. */
194 CORE_ADDR i386fbsd_sigtramp_start_addr
;
195 CORE_ADDR i386fbsd_sigtramp_end_addr
;
197 /* From <machine/signal.h>. */
198 int i386fbsd_sc_reg_offset
[] =
200 8 + 14 * 4, /* %eax */
201 8 + 13 * 4, /* %ecx */
202 8 + 12 * 4, /* %edx */
203 8 + 11 * 4, /* %ebx */
204 8 + 0 * 4, /* %esp */
205 8 + 1 * 4, /* %ebp */
206 8 + 10 * 4, /* %esi */
207 8 + 9 * 4, /* %edi */
208 8 + 3 * 4, /* %eip */
209 8 + 4 * 4, /* %eflags */
214 8 + 15 * 4, /* %fs */
218 /* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
219 static int i386fbsd_jmp_buf_reg_offset
[] =
233 i386fbsd_supply_uthread (struct regcache
*regcache
,
234 int regnum
, CORE_ADDR addr
)
239 gdb_assert (regnum
>= -1);
241 for (i
= 0; i
< ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset
); i
++)
243 if (i386fbsd_jmp_buf_reg_offset
[i
] != -1
244 && (regnum
== -1 || regnum
== i
))
246 read_memory (addr
+ i386fbsd_jmp_buf_reg_offset
[i
], buf
, 4);
247 regcache_raw_supply (regcache
, i
, buf
);
253 i386fbsd_collect_uthread (const struct regcache
*regcache
,
254 int regnum
, CORE_ADDR addr
)
259 gdb_assert (regnum
>= -1);
261 for (i
= 0; i
< ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset
); i
++)
263 if (i386fbsd_jmp_buf_reg_offset
[i
] != -1
264 && (regnum
== -1 || regnum
== i
))
266 regcache_raw_collect (regcache
, i
, buf
);
267 write_memory (addr
+ i386fbsd_jmp_buf_reg_offset
[i
], buf
, 4);
273 i386fbsdaout_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
275 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
277 /* Obviously FreeBSD is BSD-based. */
278 i386bsd_init_abi (info
, gdbarch
);
280 /* FreeBSD has a different `struct reg', and reserves some space for
281 its FPU emulator in `struct fpreg'. */
282 tdep
->gregset_reg_offset
= i386fbsd_r_reg_offset
;
283 tdep
->gregset_num_regs
= ARRAY_SIZE (i386fbsd_r_reg_offset
);
284 tdep
->sizeof_gregset
= 18 * 4;
285 tdep
->sizeof_fpregset
= 176;
287 /* FreeBSD uses -freg-struct-return by default. */
288 tdep
->struct_return
= reg_struct_return
;
290 tdep
->sigtramp_p
= i386fbsd_sigtramp_p
;
292 /* FreeBSD uses a different memory layout. */
293 tdep
->sigtramp_start
= i386fbsd_sigtramp_start_addr
;
294 tdep
->sigtramp_end
= i386fbsd_sigtramp_end_addr
;
296 /* FreeBSD has a more complete `struct sigcontext'. */
297 tdep
->sc_reg_offset
= i386fbsd_sc_reg_offset
;
298 tdep
->sc_num_regs
= ARRAY_SIZE (i386fbsd_sc_reg_offset
);
300 /* FreeBSD provides a user-level threads implementation. */
301 bsd_uthread_set_supply_uthread (gdbarch
, i386fbsd_supply_uthread
);
302 bsd_uthread_set_collect_uthread (gdbarch
, i386fbsd_collect_uthread
);
306 i386fbsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
308 /* It's almost identical to FreeBSD a.out. */
309 i386fbsdaout_init_abi (info
, gdbarch
);
311 /* Except that it uses ELF. */
312 i386_elf_init_abi (info
, gdbarch
);
314 /* FreeBSD ELF uses SVR4-style shared libraries. */
315 set_solib_svr4_fetch_link_map_offsets
316 (gdbarch
, svr4_ilp32_fetch_link_map_offsets
);
319 /* FreeBSD 4.0-RELEASE or later. */
321 /* From <machine/reg.h>. */
322 static int i386fbsd4_r_reg_offset
[] =
324 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
325 16 * 4, 5 * 4, /* %esp, %ebp */
326 4 * 4, 3 * 4, /* %esi, %edi */
327 13 * 4, 15 * 4, /* %eip, %eflags */
328 14 * 4, 17 * 4, /* %cs, %ss */
329 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
332 /* From <machine/signal.h>. */
333 int i386fbsd4_sc_reg_offset
[] =
335 20 + 11 * 4, /* %eax */
336 20 + 10 * 4, /* %ecx */
337 20 + 9 * 4, /* %edx */
338 20 + 8 * 4, /* %ebx */
339 20 + 17 * 4, /* %esp */
340 20 + 6 * 4, /* %ebp */
341 20 + 5 * 4, /* %esi */
342 20 + 4 * 4, /* %edi */
343 20 + 14 * 4, /* %eip */
344 20 + 16 * 4, /* %eflags */
345 20 + 15 * 4, /* %cs */
346 20 + 18 * 4, /* %ss */
347 20 + 3 * 4, /* %ds */
348 20 + 2 * 4, /* %es */
349 20 + 1 * 4, /* %fs */
354 i386fbsd4_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
356 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
358 /* Generic FreeBSD support. */
359 fbsd_init_abi (info
, gdbarch
);
361 /* Inherit stuff from older releases. We assume that FreeBSD
362 4.0-RELEASE always uses ELF. */
363 i386fbsd_init_abi (info
, gdbarch
);
365 /* FreeBSD 4.0 introduced a new `struct reg'. */
366 tdep
->gregset_reg_offset
= i386fbsd4_r_reg_offset
;
367 tdep
->gregset_num_regs
= ARRAY_SIZE (i386fbsd4_r_reg_offset
);
368 tdep
->sizeof_gregset
= 19 * 4;
370 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
371 tdep
->sc_reg_offset
= i386fbsd4_sc_reg_offset
;
372 tdep
->sc_num_regs
= ARRAY_SIZE (i386fbsd4_sc_reg_offset
);
376 /* Provide a prototype to silence -Wmissing-prototypes. */
377 void _initialize_i386fbsd_tdep (void);
380 _initialize_i386fbsd_tdep (void)
382 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_FREEBSD_AOUT
,
383 i386fbsdaout_init_abi
);
384 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_FREEBSD_ELF
,