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
)
141 middle
= i386fbsd_sigtramp_middle
;
142 end
= i386fbsd_sigtramp_end
;
144 else if (memcmp (buf
, i386fbsd_freebsd4_sigtramp_start
,
145 sizeof i386fbsd_freebsd4_sigtramp_start
) == 0)
147 middle
= i386fbsd_freebsd4_sigtramp_middle
;
148 end
= i386fbsd_freebsd4_sigtramp_end
;
150 else if (memcmp (buf
, i386fbsd_osigtramp_start
,
151 sizeof i386fbsd_osigtramp_start
) == 0)
153 middle
= i386fbsd_osigtramp_middle
;
154 end
= i386fbsd_osigtramp_end
;
159 /* Since the end is shorter than the middle, check for a matching end
161 pc
+= sizeof i386fbsd_sigtramp_start
;
162 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
163 sizeof i386fbsd_sigtramp_end
))
165 if (memcmp (buf
, end
, sizeof i386fbsd_sigtramp_end
) == 0)
168 /* If the end didn't match, check for a matching middle. */
169 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
170 sizeof i386fbsd_sigtramp_middle
))
172 if (memcmp (buf
, middle
, sizeof i386fbsd_sigtramp_middle
) != 0)
175 /* The middle matched, check for a matching end. */
176 pc
+= sizeof i386fbsd_sigtramp_middle
;
177 if (!safe_frame_unwind_memory (this_frame
, pc
, buf
,
178 sizeof i386fbsd_sigtramp_end
))
180 if (memcmp (buf
, end
, sizeof i386fbsd_sigtramp_end
) != 0)
186 /* FreeBSD 3.0-RELEASE or later. */
188 /* From <machine/reg.h>. */
189 static int i386fbsd_r_reg_offset
[] =
191 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */
192 15 * 4, 4 * 4, /* %esp, %ebp */
193 3 * 4, 2 * 4, /* %esi, %edi */
194 12 * 4, 14 * 4, /* %eip, %eflags */
195 13 * 4, 16 * 4, /* %cs, %ss */
196 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */
199 /* Sigtramp routine location. */
200 CORE_ADDR i386fbsd_sigtramp_start_addr
;
201 CORE_ADDR i386fbsd_sigtramp_end_addr
;
203 /* From <machine/signal.h>. */
204 int i386fbsd_sc_reg_offset
[] =
206 8 + 14 * 4, /* %eax */
207 8 + 13 * 4, /* %ecx */
208 8 + 12 * 4, /* %edx */
209 8 + 11 * 4, /* %ebx */
210 8 + 0 * 4, /* %esp */
211 8 + 1 * 4, /* %ebp */
212 8 + 10 * 4, /* %esi */
213 8 + 9 * 4, /* %edi */
214 8 + 3 * 4, /* %eip */
215 8 + 4 * 4, /* %eflags */
220 8 + 15 * 4, /* %fs */
224 /* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
225 static int i386fbsd_jmp_buf_reg_offset
[] =
239 i386fbsd_supply_uthread (struct regcache
*regcache
,
240 int regnum
, CORE_ADDR addr
)
245 gdb_assert (regnum
>= -1);
247 for (i
= 0; i
< ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset
); i
++)
249 if (i386fbsd_jmp_buf_reg_offset
[i
] != -1
250 && (regnum
== -1 || regnum
== i
))
252 read_memory (addr
+ i386fbsd_jmp_buf_reg_offset
[i
], buf
, 4);
253 regcache_raw_supply (regcache
, i
, buf
);
259 i386fbsd_collect_uthread (const struct regcache
*regcache
,
260 int regnum
, CORE_ADDR addr
)
265 gdb_assert (regnum
>= -1);
267 for (i
= 0; i
< ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset
); i
++)
269 if (i386fbsd_jmp_buf_reg_offset
[i
] != -1
270 && (regnum
== -1 || regnum
== i
))
272 regcache_raw_collect (regcache
, i
, buf
);
273 write_memory (addr
+ i386fbsd_jmp_buf_reg_offset
[i
], buf
, 4);
279 i386fbsdaout_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
281 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
283 /* Obviously FreeBSD is BSD-based. */
284 i386bsd_init_abi (info
, gdbarch
);
286 /* FreeBSD has a different `struct reg', and reserves some space for
287 its FPU emulator in `struct fpreg'. */
288 tdep
->gregset_reg_offset
= i386fbsd_r_reg_offset
;
289 tdep
->gregset_num_regs
= ARRAY_SIZE (i386fbsd_r_reg_offset
);
290 tdep
->sizeof_gregset
= 18 * 4;
291 tdep
->sizeof_fpregset
= 176;
293 /* FreeBSD uses -freg-struct-return by default. */
294 tdep
->struct_return
= reg_struct_return
;
296 tdep
->sigtramp_p
= i386fbsd_sigtramp_p
;
298 /* FreeBSD uses a different memory layout. */
299 tdep
->sigtramp_start
= i386fbsd_sigtramp_start_addr
;
300 tdep
->sigtramp_end
= i386fbsd_sigtramp_end_addr
;
302 /* FreeBSD has a more complete `struct sigcontext'. */
303 tdep
->sc_reg_offset
= i386fbsd_sc_reg_offset
;
304 tdep
->sc_num_regs
= ARRAY_SIZE (i386fbsd_sc_reg_offset
);
306 /* FreeBSD provides a user-level threads implementation. */
307 bsd_uthread_set_supply_uthread (gdbarch
, i386fbsd_supply_uthread
);
308 bsd_uthread_set_collect_uthread (gdbarch
, i386fbsd_collect_uthread
);
312 i386fbsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
314 /* It's almost identical to FreeBSD a.out. */
315 i386fbsdaout_init_abi (info
, gdbarch
);
317 /* Except that it uses ELF. */
318 i386_elf_init_abi (info
, gdbarch
);
320 /* FreeBSD ELF uses SVR4-style shared libraries. */
321 set_solib_svr4_fetch_link_map_offsets
322 (gdbarch
, svr4_ilp32_fetch_link_map_offsets
);
325 /* FreeBSD 4.0-RELEASE or later. */
327 /* From <machine/reg.h>. */
328 static int i386fbsd4_r_reg_offset
[] =
330 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
331 16 * 4, 5 * 4, /* %esp, %ebp */
332 4 * 4, 3 * 4, /* %esi, %edi */
333 13 * 4, 15 * 4, /* %eip, %eflags */
334 14 * 4, 17 * 4, /* %cs, %ss */
335 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
338 /* From <machine/signal.h>. */
339 int i386fbsd4_sc_reg_offset
[] =
341 20 + 11 * 4, /* %eax */
342 20 + 10 * 4, /* %ecx */
343 20 + 9 * 4, /* %edx */
344 20 + 8 * 4, /* %ebx */
345 20 + 17 * 4, /* %esp */
346 20 + 6 * 4, /* %ebp */
347 20 + 5 * 4, /* %esi */
348 20 + 4 * 4, /* %edi */
349 20 + 14 * 4, /* %eip */
350 20 + 16 * 4, /* %eflags */
351 20 + 15 * 4, /* %cs */
352 20 + 18 * 4, /* %ss */
353 20 + 3 * 4, /* %ds */
354 20 + 2 * 4, /* %es */
355 20 + 1 * 4, /* %fs */
360 i386fbsd4_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
362 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
364 /* Generic FreeBSD support. */
365 fbsd_init_abi (info
, gdbarch
);
367 /* Inherit stuff from older releases. We assume that FreeBSD
368 4.0-RELEASE always uses ELF. */
369 i386fbsd_init_abi (info
, gdbarch
);
371 /* FreeBSD 4.0 introduced a new `struct reg'. */
372 tdep
->gregset_reg_offset
= i386fbsd4_r_reg_offset
;
373 tdep
->gregset_num_regs
= ARRAY_SIZE (i386fbsd4_r_reg_offset
);
374 tdep
->sizeof_gregset
= 19 * 4;
376 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
377 tdep
->sc_reg_offset
= i386fbsd4_sc_reg_offset
;
378 tdep
->sc_num_regs
= ARRAY_SIZE (i386fbsd4_sc_reg_offset
);
382 /* Provide a prototype to silence -Wmissing-prototypes. */
383 void _initialize_i386fbsd_tdep (void);
386 _initialize_i386fbsd_tdep (void)
388 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_FREEBSD_AOUT
,
389 i386fbsdaout_init_abi
);
390 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_FREEBSD_ELF
,