Fix reading of .debug_str_offsets{,.dwo} twice.
[deliverable/binutils-gdb.git] / gdb / i386fbsd-tdep.c
... / ...
CommitLineData
1/* Target-dependent code for FreeBSD/i386.
2
3 Copyright (C) 2003-2015 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 "arch-utils.h"
22#include "gdbcore.h"
23#include "osabi.h"
24#include "regcache.h"
25
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"
31
32/* Support for signal handlers. */
33
34/* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
35 routine. */
36
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. */
43
44static const gdb_byte i386fbsd_sigtramp_start[] =
45{
46 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
47 0x50 /* pushl %eax */
48};
49
50static const gdb_byte i386fbsd_sigtramp_middle[] =
51{
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 */
56};
57
58static const gdb_byte i386fbsd_sigtramp_end[] =
59{
60 0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl $SYS_sigreturn,%eax */
61 0x50, /* pushl %eax */
62 0xcd, 0x80 /* int $0x80 */
63};
64
65static const gdb_byte i386fbsd_freebsd4_sigtramp_start[] =
66{
67 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */
68 0x50 /* pushl %eax */
69};
70
71static const gdb_byte i386fbsd_freebsd4_sigtramp_middle[] =
72{
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 */
77};
78
79static const gdb_byte i386fbsd_freebsd4_sigtramp_end[] =
80{
81 0xb8, 0x58, 0x01, 0x00, 0x00, /* movl $344,%eax */
82 0x50, /* pushl %eax */
83 0xcd, 0x80 /* int $0x80 */
84};
85
86static const gdb_byte i386fbsd_osigtramp_start[] =
87{
88 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */
89 0x50 /* pushl %eax */
90};
91
92static const gdb_byte i386fbsd_osigtramp_middle[] =
93{
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 */
98};
99
100static const gdb_byte i386fbsd_osigtramp_end[] =
101{
102 0xb8, 0x67, 0x00, 0x00, 0x00, /* movl $103,%eax */
103 0x50, /* pushl %eax */
104 0xcd, 0x80 /* int $0x80 */
105};
106
107/* The three different trampolines are all the same size. */
108gdb_static_assert (sizeof i386fbsd_sigtramp_start
109 == sizeof i386fbsd_freebsd4_sigtramp_start);
110gdb_static_assert (sizeof i386fbsd_sigtramp_start
111 == sizeof i386fbsd_osigtramp_start);
112gdb_static_assert (sizeof i386fbsd_sigtramp_middle
113 == sizeof i386fbsd_freebsd4_sigtramp_middle);
114gdb_static_assert (sizeof i386fbsd_sigtramp_middle
115 == sizeof i386fbsd_osigtramp_middle);
116gdb_static_assert (sizeof i386fbsd_sigtramp_end
117 == sizeof i386fbsd_freebsd4_sigtramp_end);
118gdb_static_assert (sizeof i386fbsd_sigtramp_end
119 == sizeof i386fbsd_osigtramp_end);
120
121/* We assume that the middle is the largest chunk below. */
122gdb_static_assert (sizeof i386fbsd_sigtramp_middle
123 > sizeof i386fbsd_sigtramp_start);
124gdb_static_assert (sizeof i386fbsd_sigtramp_middle
125 > sizeof i386fbsd_sigtramp_end);
126
127static int
128i386fbsd_sigtramp_p (struct frame_info *this_frame)
129{
130 CORE_ADDR pc = get_frame_pc (this_frame);
131 gdb_byte buf[sizeof i386fbsd_sigtramp_middle];
132 const gdb_byte *middle, *end;
133
134 /* Look for a matching start. */
135 if (!safe_frame_unwind_memory (this_frame, pc, buf,
136 sizeof i386fbsd_sigtramp_start))
137 return 0;
138 if (memcmp (buf, i386fbsd_sigtramp_start, sizeof i386fbsd_sigtramp_start)
139 == 0)
140 {
141 middle = i386fbsd_sigtramp_middle;
142 end = i386fbsd_sigtramp_end;
143 }
144 else if (memcmp (buf, i386fbsd_freebsd4_sigtramp_start,
145 sizeof i386fbsd_freebsd4_sigtramp_start) == 0)
146 {
147 middle = i386fbsd_freebsd4_sigtramp_middle;
148 end = i386fbsd_freebsd4_sigtramp_end;
149 }
150 else if (memcmp (buf, i386fbsd_osigtramp_start,
151 sizeof i386fbsd_osigtramp_start) == 0)
152 {
153 middle = i386fbsd_osigtramp_middle;
154 end = i386fbsd_osigtramp_end;
155 }
156 else
157 return 0;
158
159 /* Since the end is shorter than the middle, check for a matching end
160 next. */
161 pc += sizeof i386fbsd_sigtramp_start;
162 if (!safe_frame_unwind_memory (this_frame, pc, buf,
163 sizeof i386fbsd_sigtramp_end))
164 return 0;
165 if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) == 0)
166 return 1;
167
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))
171 return 0;
172 if (memcmp (buf, middle, sizeof i386fbsd_sigtramp_middle) != 0)
173 return 0;
174
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))
179 return 0;
180 if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) != 0)
181 return 0;
182
183 return 1;
184}
185
186/* FreeBSD 3.0-RELEASE or later. */
187
188/* From <machine/reg.h>. */
189static int i386fbsd_r_reg_offset[] =
190{
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 */
197};
198
199/* Sigtramp routine location. */
200CORE_ADDR i386fbsd_sigtramp_start_addr;
201CORE_ADDR i386fbsd_sigtramp_end_addr;
202
203/* From <machine/signal.h>. */
204int i386fbsd_sc_reg_offset[] =
205{
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 */
216 8 + 7 * 4, /* %cs */
217 8 + 8 * 4, /* %ss */
218 8 + 6 * 4, /* %ds */
219 8 + 5 * 4, /* %es */
220 8 + 15 * 4, /* %fs */
221 8 + 16 * 4 /* %gs */
222};
223
224/* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
225static int i386fbsd_jmp_buf_reg_offset[] =
226{
227 -1, /* %eax */
228 -1, /* %ecx */
229 -1, /* %edx */
230 1 * 4, /* %ebx */
231 2 * 4, /* %esp */
232 3 * 4, /* %ebp */
233 4 * 4, /* %esi */
234 5 * 4, /* %edi */
235 0 * 4 /* %eip */
236};
237
238static void
239i386fbsd_supply_uthread (struct regcache *regcache,
240 int regnum, CORE_ADDR addr)
241{
242 gdb_byte buf[4];
243 int i;
244
245 gdb_assert (regnum >= -1);
246
247 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
248 {
249 if (i386fbsd_jmp_buf_reg_offset[i] != -1
250 && (regnum == -1 || regnum == i))
251 {
252 read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
253 regcache_raw_supply (regcache, i, buf);
254 }
255 }
256}
257
258static void
259i386fbsd_collect_uthread (const struct regcache *regcache,
260 int regnum, CORE_ADDR addr)
261{
262 gdb_byte buf[4];
263 int i;
264
265 gdb_assert (regnum >= -1);
266
267 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
268 {
269 if (i386fbsd_jmp_buf_reg_offset[i] != -1
270 && (regnum == -1 || regnum == i))
271 {
272 regcache_raw_collect (regcache, i, buf);
273 write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
274 }
275 }
276}
277
278static void
279i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
280{
281 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
282
283 /* Obviously FreeBSD is BSD-based. */
284 i386bsd_init_abi (info, gdbarch);
285
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;
292
293 /* FreeBSD uses -freg-struct-return by default. */
294 tdep->struct_return = reg_struct_return;
295
296 tdep->sigtramp_p = i386fbsd_sigtramp_p;
297
298 /* FreeBSD uses a different memory layout. */
299 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
300 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
301
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);
305
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);
309}
310
311static void
312i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
313{
314 /* It's almost identical to FreeBSD a.out. */
315 i386fbsdaout_init_abi (info, gdbarch);
316
317 /* Except that it uses ELF. */
318 i386_elf_init_abi (info, gdbarch);
319
320 /* FreeBSD ELF uses SVR4-style shared libraries. */
321 set_solib_svr4_fetch_link_map_offsets
322 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
323}
324
325/* FreeBSD 4.0-RELEASE or later. */
326
327/* From <machine/reg.h>. */
328static int i386fbsd4_r_reg_offset[] =
329{
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 */
336};
337
338/* From <machine/signal.h>. */
339int i386fbsd4_sc_reg_offset[] =
340{
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 */
356 20 + 0 * 4 /* %gs */
357};
358
359static void
360i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
361{
362 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
363
364 /* Generic FreeBSD support. */
365 fbsd_init_abi (info, gdbarch);
366
367 /* Inherit stuff from older releases. We assume that FreeBSD
368 4.0-RELEASE always uses ELF. */
369 i386fbsd_init_abi (info, gdbarch);
370
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;
375
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);
379}
380
381\f
382/* Provide a prototype to silence -Wmissing-prototypes. */
383void _initialize_i386fbsd_tdep (void);
384
385void
386_initialize_i386fbsd_tdep (void)
387{
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,
391 i386fbsd4_init_abi);
392}
This page took 0.024863 seconds and 4 git commands to generate.