Adjust for the DragonFly ELF ABI
[dragonfly.git] / contrib / gdb-6 / gdb / i386fbsd-tdep.c
blob7dd2014ae9adf99f894fce3eaa086659c5f5ca64
1 /* Target-dependent code for FreeBSD/i386.
3 Copyright (C) 2003, 2004, 2005, 2007 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/>. */
20 #include "defs.h"
21 #include "arch-utils.h"
22 #include "gdbcore.h"
23 #include "osabi.h"
24 #include "regcache.h"
26 #include "gdb_assert.h"
28 #include "i386-tdep.h"
29 #include "i387-tdep.h"
30 #include "bsd-uthread.h"
31 #include "solib-svr4.h"
33 /* FreeBSD 3.0-RELEASE or later. */
35 /* From <machine/reg.h>. */
36 static int i386fbsd_r_reg_offset[] =
38 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */
39 15 * 4, 4 * 4, /* %esp, %ebp */
40 3 * 4, 2 * 4, /* %esi, %edi */
41 12 * 4, 14 * 4, /* %eip, %eflags */
42 13 * 4, 16 * 4, /* %cs, %ss */
43 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */
46 /* Sigtramp routine location. */
47 CORE_ADDR i386fbsd_sigtramp_start_addr = 0xbfbfdf20;
48 CORE_ADDR i386fbsd_sigtramp_end_addr = 0xbfbfdff0;
50 /* From <machine/signal.h>. */
51 int i386fbsd_sc_reg_offset[] =
53 8 + 14 * 4, /* %eax */
54 8 + 13 * 4, /* %ecx */
55 8 + 12 * 4, /* %edx */
56 8 + 11 * 4, /* %ebx */
57 8 + 0 * 4, /* %esp */
58 8 + 1 * 4, /* %ebp */
59 8 + 10 * 4, /* %esi */
60 8 + 9 * 4, /* %edi */
61 8 + 3 * 4, /* %eip */
62 8 + 4 * 4, /* %eflags */
63 8 + 7 * 4, /* %cs */
64 8 + 8 * 4, /* %ss */
65 8 + 6 * 4, /* %ds */
66 8 + 5 * 4, /* %es */
67 8 + 15 * 4, /* %fs */
68 8 + 16 * 4 /* %gs */
71 /* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
72 static int i386fbsd_jmp_buf_reg_offset[] =
74 -1, /* %eax */
75 -1, /* %ecx */
76 -1, /* %edx */
77 1 * 4, /* %ebx */
78 2 * 4, /* %esp */
79 3 * 4, /* %ebp */
80 4 * 4, /* %esi */
81 5 * 4, /* %edi */
82 0 * 4 /* %eip */
85 static void
86 i386fbsd_supply_uthread (struct regcache *regcache,
87 int regnum, CORE_ADDR addr)
89 char buf[4];
90 int i;
92 gdb_assert (regnum >= -1);
94 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
96 if (i386fbsd_jmp_buf_reg_offset[i] != -1
97 && (regnum == -1 || regnum == i))
99 read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
100 regcache_raw_supply (regcache, i, buf);
105 static void
106 i386fbsd_collect_uthread (const struct regcache *regcache,
107 int regnum, CORE_ADDR addr)
109 char buf[4];
110 int i;
112 gdb_assert (regnum >= -1);
114 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
116 if (i386fbsd_jmp_buf_reg_offset[i] != -1
117 && (regnum == -1 || regnum == i))
119 regcache_raw_collect (regcache, i, buf);
120 write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
125 static void
126 i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
128 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
130 /* Obviously FreeBSD is BSD-based. */
131 i386bsd_init_abi (info, gdbarch);
133 /* FreeBSD has a different `struct reg', and reserves some space for
134 its FPU emulator in `struct fpreg'. */
135 tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
136 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
137 tdep->sizeof_gregset = 18 * 4;
138 tdep->sizeof_fpregset = 176;
140 /* FreeBSD uses -freg-struct-return by default. */
141 tdep->struct_return = reg_struct_return;
143 /* FreeBSD uses a different memory layout. */
144 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
145 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
147 /* FreeBSD has a more complete `struct sigcontext'. */
148 tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
149 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
151 /* FreeBSD provides a user-level threads implementation. */
152 bsd_uthread_set_supply_uthread (gdbarch, i386fbsd_supply_uthread);
153 bsd_uthread_set_collect_uthread (gdbarch, i386fbsd_collect_uthread);
156 static void
157 i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
159 /* It's almost identical to FreeBSD a.out. */
160 i386fbsdaout_init_abi (info, gdbarch);
162 /* Except that it uses ELF. */
163 i386_elf_init_abi (info, gdbarch);
165 /* FreeBSD ELF uses SVR4-style shared libraries. */
166 set_solib_svr4_fetch_link_map_offsets
167 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
170 /* FreeBSD 4.0-RELEASE or later. */
172 /* From <machine/reg.h>. */
173 static int i386fbsd4_r_reg_offset[] =
175 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
176 16 * 4, 5 * 4, /* %esp, %ebp */
177 4 * 4, 3 * 4, /* %esi, %edi */
178 13 * 4, 15 * 4, /* %eip, %eflags */
179 14 * 4, 17 * 4, /* %cs, %ss */
180 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
183 /* From <machine/signal.h>. */
184 int i386fbsd4_sc_reg_offset[] =
186 20 + 11 * 4, /* %eax */
187 20 + 10 * 4, /* %ecx */
188 20 + 9 * 4, /* %edx */
189 20 + 8 * 4, /* %ebx */
190 20 + 17 * 4, /* %esp */
191 20 + 6 * 4, /* %ebp */
192 20 + 5 * 4, /* %esi */
193 20 + 4 * 4, /* %edi */
194 20 + 14 * 4, /* %eip */
195 20 + 16 * 4, /* %eflags */
196 20 + 15 * 4, /* %cs */
197 20 + 18 * 4, /* %ss */
198 20 + 3 * 4, /* %ds */
199 20 + 2 * 4, /* %es */
200 20 + 1 * 4, /* %fs */
201 20 + 0 * 4 /* %gs */
204 static void
205 i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
207 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
209 /* Inherit stuff from older releases. We assume that FreeBSD
210 4.0-RELEASE always uses ELF. */
211 i386fbsd_init_abi (info, gdbarch);
213 /* FreeBSD 4.0 introduced a new `struct reg'. */
214 tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
215 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
216 tdep->sizeof_gregset = 19 * 4;
218 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
219 tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
220 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
224 * Okay, I know this is blunt and shouldn't be in tdep,
225 * but in the long run we'll save quite some hassle with this.
228 #include <machine/reg.h>
229 static int i386dragonfly_r_reg_offset[] =
231 #define REGO(r) (offsetof(struct reg, r_ ## r))
232 REGO(eax),
233 REGO(ecx),
234 REGO(edx),
235 REGO(ebx),
236 REGO(esp),
237 REGO(ebp),
238 REGO(esi),
239 REGO(edi),
240 REGO(eip),
241 REGO(eflags),
242 REGO(cs),
243 REGO(ss),
244 REGO(ds),
245 REGO(es),
246 REGO(fs),
247 REGO(gs)
248 #undef REGO
251 #include <machine/signal.h>
252 int i386dragonfly_sc_reg_offset[] =
254 #define SCRO(r) (offsetof(struct sigcontext, sc_ ## r))
255 SCRO(eax),
256 SCRO(ecx),
257 SCRO(edx),
258 SCRO(ebx),
259 SCRO(esp),
260 SCRO(ebp),
261 SCRO(esi),
262 SCRO(edi),
263 SCRO(eip),
264 SCRO(eflags),
265 SCRO(cs),
266 SCRO(ss),
267 SCRO(ds),
268 SCRO(es),
269 SCRO(fs),
270 SCRO(gs)
271 #undef SCRO
274 static void
275 i386dragonfly_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
277 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
279 i386fbsd4_init_abi(info, gdbarch);
281 tdep->gregset_reg_offset = i386dragonfly_r_reg_offset;
282 tdep->gregset_num_regs = ARRAY_SIZE (i386dragonfly_r_reg_offset);
283 tdep->sizeof_gregset = sizeof(struct reg);
285 tdep->sc_reg_offset = i386dragonfly_sc_reg_offset;
286 tdep->sc_num_regs = ARRAY_SIZE (i386dragonfly_sc_reg_offset);
290 /* Provide a prototype to silence -Wmissing-prototypes. */
291 void _initialize_i386fbsd_tdep (void);
293 void
294 _initialize_i386fbsd_tdep (void)
296 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_AOUT,
297 i386fbsdaout_init_abi);
298 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_ELF,
299 i386fbsd4_init_abi);
300 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_DRAGONFLY_ELF,
301 i386dragonfly_init_abi);