Fix memory corruption in Guile command interface
[deliverable/binutils-gdb.git] / gdb / i386fbsd-tdep.c
CommitLineData
8a96bc77
MK
1/* Target-dependent code for FreeBSD/i386.
2
32d0add0 3 Copyright (C) 2003-2015 Free Software Foundation, Inc.
8a96bc77
MK
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
8a96bc77
MK
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
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
8a96bc77
MK
19
20#include "defs.h"
21#include "arch-utils.h"
fa565c2b 22#include "gdbcore.h"
8a96bc77 23#include "osabi.h"
fa565c2b
MK
24#include "regcache.h"
25
8a96bc77
MK
26#include "i386-tdep.h"
27#include "i387-tdep.h"
fa565c2b 28#include "bsd-uthread.h"
490496c3 29#include "fbsd-tdep.h"
7e654c37 30#include "solib-svr4.h"
8a96bc77 31
cf424aef
JB
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 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;
150 } else
151 return 0;
152
153 /* Since the end is shorter than the middle, check for a matching end
154 next. */
155 pc += sizeof i386fbsd_sigtramp_start;
156 if (!safe_frame_unwind_memory (this_frame, pc, buf,
157 sizeof i386fbsd_sigtramp_end))
158 return 0;
159 if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) == 0)
160 return 1;
161
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))
165 return 0;
166 if (memcmp (buf, middle, sizeof i386fbsd_sigtramp_middle) != 0)
167 return 0;
168
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))
173 return 0;
174 if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) != 0)
175 return 0;
176
177 return 1;
178}
179
8a96bc77
MK
180/* FreeBSD 3.0-RELEASE or later. */
181
182/* From <machine/reg.h>. */
183static int i386fbsd_r_reg_offset[] =
184{
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 */
191};
192
5d93ae8c 193/* Sigtramp routine location. */
cf424aef
JB
194CORE_ADDR i386fbsd_sigtramp_start_addr;
195CORE_ADDR i386fbsd_sigtramp_end_addr;
8a96bc77
MK
196
197/* From <machine/signal.h>. */
abfcdd21 198int i386fbsd_sc_reg_offset[] =
8a96bc77
MK
199{
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 */
210 8 + 7 * 4, /* %cs */
211 8 + 8 * 4, /* %ss */
212 8 + 6 * 4, /* %ds */
213 8 + 5 * 4, /* %es */
214 8 + 15 * 4, /* %fs */
215 8 + 16 * 4 /* %gs */
216};
217
1c02b2a5 218/* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
fa565c2b
MK
219static int i386fbsd_jmp_buf_reg_offset[] =
220{
221 -1, /* %eax */
222 -1, /* %ecx */
223 -1, /* %edx */
224 1 * 4, /* %ebx */
225 2 * 4, /* %esp */
226 3 * 4, /* %ebp */
227 4 * 4, /* %esi */
228 5 * 4, /* %edi */
229 0 * 4 /* %eip */
230};
231
232static void
233i386fbsd_supply_uthread (struct regcache *regcache,
234 int regnum, CORE_ADDR addr)
235{
e362b510 236 gdb_byte buf[4];
fa565c2b
MK
237 int i;
238
239 gdb_assert (regnum >= -1);
240
241 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
242 {
243 if (i386fbsd_jmp_buf_reg_offset[i] != -1
244 && (regnum == -1 || regnum == i))
245 {
246 read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
247 regcache_raw_supply (regcache, i, buf);
248 }
249 }
250}
251
252static void
253i386fbsd_collect_uthread (const struct regcache *regcache,
254 int regnum, CORE_ADDR addr)
255{
e362b510 256 gdb_byte buf[4];
fa565c2b
MK
257 int i;
258
259 gdb_assert (regnum >= -1);
260
261 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
262 {
263 if (i386fbsd_jmp_buf_reg_offset[i] != -1
264 && (regnum == -1 || regnum == i))
265 {
266 regcache_raw_collect (regcache, i, buf);
267 write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
268 }
269 }
270}
271
8a96bc77
MK
272static void
273i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
274{
275 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
276
277 /* Obviously FreeBSD is BSD-based. */
278 i386bsd_init_abi (info, gdbarch);
279
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;
286
287 /* FreeBSD uses -freg-struct-return by default. */
288 tdep->struct_return = reg_struct_return;
289
cf424aef
JB
290 tdep->sigtramp_p = i386fbsd_sigtramp_p;
291
8a96bc77 292 /* FreeBSD uses a different memory layout. */
5d93ae8c
MK
293 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
294 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
8a96bc77
MK
295
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);
fa565c2b
MK
299
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);
8a96bc77
MK
303}
304
305static void
306i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
307{
308 /* It's almost identical to FreeBSD a.out. */
309 i386fbsdaout_init_abi (info, gdbarch);
310
311 /* Except that it uses ELF. */
312 i386_elf_init_abi (info, gdbarch);
313
314 /* FreeBSD ELF uses SVR4-style shared libraries. */
7e654c37
MK
315 set_solib_svr4_fetch_link_map_offsets
316 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
8a96bc77
MK
317}
318
319/* FreeBSD 4.0-RELEASE or later. */
320
321/* From <machine/reg.h>. */
322static int i386fbsd4_r_reg_offset[] =
323{
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 */
330};
331
332/* From <machine/signal.h>. */
333int i386fbsd4_sc_reg_offset[] =
334{
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 */
350 20 + 0 * 4 /* %gs */
351};
352
353static void
354i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
355{
356 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
357
490496c3
AA
358 /* Generic FreeBSD support. */
359 fbsd_init_abi (info, gdbarch);
360
8a96bc77
MK
361 /* Inherit stuff from older releases. We assume that FreeBSD
362 4.0-RELEASE always uses ELF. */
363 i386fbsd_init_abi (info, gdbarch);
364
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;
369
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);
373}
374
375\f
376/* Provide a prototype to silence -Wmissing-prototypes. */
377void _initialize_i386fbsd_tdep (void);
378
379void
380_initialize_i386fbsd_tdep (void)
381{
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,
385 i386fbsd4_init_abi);
386}
This page took 0.861854 seconds and 4 git commands to generate.