Do not consider reference types as dynamic
[deliverable/binutils-gdb.git] / gdb / i386fbsd-tdep.c
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
44 static const gdb_byte i386fbsd_sigtramp_start[] =
45 {
46 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */
47 0x50 /* pushl %eax */
48 };
49
50 static 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
58 static 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
65 static const gdb_byte i386fbsd_freebsd4_sigtramp_start[] =
66 {
67 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */
68 0x50 /* pushl %eax */
69 };
70
71 static 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
79 static 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
86 static const gdb_byte i386fbsd_osigtramp_start[] =
87 {
88 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */
89 0x50 /* pushl %eax */
90 };
91
92 static 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
100 static 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. */
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);
120
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);
126
127 static int
128 i386fbsd_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>. */
189 static 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. */
200 CORE_ADDR i386fbsd_sigtramp_start_addr;
201 CORE_ADDR i386fbsd_sigtramp_end_addr;
202
203 /* From <machine/signal.h>. */
204 int 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. */
225 static 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
238 static void
239 i386fbsd_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
258 static void
259 i386fbsd_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
278 static void
279 i386fbsdaout_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
311 static void
312 i386fbsd_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>. */
328 static 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>. */
339 int 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
359 static void
360 i386fbsd4_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. */
383 void _initialize_i386fbsd_tdep (void);
384
385 void
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.039168 seconds and 4 git commands to generate.