]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/i386fbsd-tdep.c
2011-04-27 Pedro Alves <pedro@codesourcery.com>
[thirdparty/binutils-gdb.git] / gdb / i386fbsd-tdep.c
CommitLineData
8a96bc77
MK
1/* Target-dependent code for FreeBSD/i386.
2
7b6bb8da 3 Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
0fb0cc75 4 Free Software Foundation, Inc.
8a96bc77
MK
5
6 This file is part of GDB.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
a9762ec7 10 the Free Software Foundation; either version 3 of the License, or
8a96bc77
MK
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
a9762ec7 19 along with this program. If not, see <http://www.gnu.org/licenses/>. */
8a96bc77
MK
20
21#include "defs.h"
22#include "arch-utils.h"
fa565c2b 23#include "gdbcore.h"
8a96bc77 24#include "osabi.h"
fa565c2b
MK
25#include "regcache.h"
26
27#include "gdb_assert.h"
8a96bc77
MK
28
29#include "i386-tdep.h"
30#include "i387-tdep.h"
fa565c2b 31#include "bsd-uthread.h"
7e654c37 32#include "solib-svr4.h"
8a96bc77
MK
33
34/* FreeBSD 3.0-RELEASE or later. */
35
36/* From <machine/reg.h>. */
37static int i386fbsd_r_reg_offset[] =
38{
39 9 * 4, 8 * 4, 7 * 4, 6 * 4, /* %eax, %ecx, %edx, %ebx */
40 15 * 4, 4 * 4, /* %esp, %ebp */
41 3 * 4, 2 * 4, /* %esi, %edi */
42 12 * 4, 14 * 4, /* %eip, %eflags */
43 13 * 4, 16 * 4, /* %cs, %ss */
44 1 * 4, 0 * 4, -1, -1 /* %ds, %es, %fs, %gs */
45};
46
5d93ae8c
MK
47/* Sigtramp routine location. */
48CORE_ADDR i386fbsd_sigtramp_start_addr = 0xbfbfdf20;
49CORE_ADDR i386fbsd_sigtramp_end_addr = 0xbfbfdff0;
8a96bc77
MK
50
51/* From <machine/signal.h>. */
abfcdd21 52int i386fbsd_sc_reg_offset[] =
8a96bc77
MK
53{
54 8 + 14 * 4, /* %eax */
55 8 + 13 * 4, /* %ecx */
56 8 + 12 * 4, /* %edx */
57 8 + 11 * 4, /* %ebx */
58 8 + 0 * 4, /* %esp */
59 8 + 1 * 4, /* %ebp */
60 8 + 10 * 4, /* %esi */
61 8 + 9 * 4, /* %edi */
62 8 + 3 * 4, /* %eip */
63 8 + 4 * 4, /* %eflags */
64 8 + 7 * 4, /* %cs */
65 8 + 8 * 4, /* %ss */
66 8 + 6 * 4, /* %ds */
67 8 + 5 * 4, /* %es */
68 8 + 15 * 4, /* %fs */
69 8 + 16 * 4 /* %gs */
70};
71
1c02b2a5 72/* From /usr/src/lib/libc/i386/gen/_setjmp.S. */
fa565c2b
MK
73static int i386fbsd_jmp_buf_reg_offset[] =
74{
75 -1, /* %eax */
76 -1, /* %ecx */
77 -1, /* %edx */
78 1 * 4, /* %ebx */
79 2 * 4, /* %esp */
80 3 * 4, /* %ebp */
81 4 * 4, /* %esi */
82 5 * 4, /* %edi */
83 0 * 4 /* %eip */
84};
85
86static void
87i386fbsd_supply_uthread (struct regcache *regcache,
88 int regnum, CORE_ADDR addr)
89{
90 char buf[4];
91 int i;
92
93 gdb_assert (regnum >= -1);
94
95 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
96 {
97 if (i386fbsd_jmp_buf_reg_offset[i] != -1
98 && (regnum == -1 || regnum == i))
99 {
100 read_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
101 regcache_raw_supply (regcache, i, buf);
102 }
103 }
104}
105
106static void
107i386fbsd_collect_uthread (const struct regcache *regcache,
108 int regnum, CORE_ADDR addr)
109{
110 char buf[4];
111 int i;
112
113 gdb_assert (regnum >= -1);
114
115 for (i = 0; i < ARRAY_SIZE (i386fbsd_jmp_buf_reg_offset); i++)
116 {
117 if (i386fbsd_jmp_buf_reg_offset[i] != -1
118 && (regnum == -1 || regnum == i))
119 {
120 regcache_raw_collect (regcache, i, buf);
121 write_memory (addr + i386fbsd_jmp_buf_reg_offset[i], buf, 4);
122 }
123 }
124}
125
8a96bc77
MK
126static void
127i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
128{
129 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
130
131 /* Obviously FreeBSD is BSD-based. */
132 i386bsd_init_abi (info, gdbarch);
133
134 /* FreeBSD has a different `struct reg', and reserves some space for
135 its FPU emulator in `struct fpreg'. */
136 tdep->gregset_reg_offset = i386fbsd_r_reg_offset;
137 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd_r_reg_offset);
138 tdep->sizeof_gregset = 18 * 4;
139 tdep->sizeof_fpregset = 176;
140
141 /* FreeBSD uses -freg-struct-return by default. */
142 tdep->struct_return = reg_struct_return;
143
144 /* FreeBSD uses a different memory layout. */
5d93ae8c
MK
145 tdep->sigtramp_start = i386fbsd_sigtramp_start_addr;
146 tdep->sigtramp_end = i386fbsd_sigtramp_end_addr;
8a96bc77
MK
147
148 /* FreeBSD has a more complete `struct sigcontext'. */
149 tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
150 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
fa565c2b
MK
151
152 /* FreeBSD provides a user-level threads implementation. */
153 bsd_uthread_set_supply_uthread (gdbarch, i386fbsd_supply_uthread);
154 bsd_uthread_set_collect_uthread (gdbarch, i386fbsd_collect_uthread);
8a96bc77
MK
155}
156
157static void
158i386fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
159{
160 /* It's almost identical to FreeBSD a.out. */
161 i386fbsdaout_init_abi (info, gdbarch);
162
163 /* Except that it uses ELF. */
164 i386_elf_init_abi (info, gdbarch);
165
166 /* FreeBSD ELF uses SVR4-style shared libraries. */
7e654c37
MK
167 set_solib_svr4_fetch_link_map_offsets
168 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
8a96bc77
MK
169}
170
171/* FreeBSD 4.0-RELEASE or later. */
172
173/* From <machine/reg.h>. */
174static int i386fbsd4_r_reg_offset[] =
175{
176 10 * 4, 9 * 4, 8 * 4, 7 * 4, /* %eax, %ecx, %edx, %ebx */
177 16 * 4, 5 * 4, /* %esp, %ebp */
178 4 * 4, 3 * 4, /* %esi, %edi */
179 13 * 4, 15 * 4, /* %eip, %eflags */
180 14 * 4, 17 * 4, /* %cs, %ss */
181 2 * 4, 1 * 4, 0 * 4, 18 * 4 /* %ds, %es, %fs, %gs */
182};
183
184/* From <machine/signal.h>. */
185int i386fbsd4_sc_reg_offset[] =
186{
187 20 + 11 * 4, /* %eax */
188 20 + 10 * 4, /* %ecx */
189 20 + 9 * 4, /* %edx */
190 20 + 8 * 4, /* %ebx */
191 20 + 17 * 4, /* %esp */
192 20 + 6 * 4, /* %ebp */
193 20 + 5 * 4, /* %esi */
194 20 + 4 * 4, /* %edi */
195 20 + 14 * 4, /* %eip */
196 20 + 16 * 4, /* %eflags */
197 20 + 15 * 4, /* %cs */
198 20 + 18 * 4, /* %ss */
199 20 + 3 * 4, /* %ds */
200 20 + 2 * 4, /* %es */
201 20 + 1 * 4, /* %fs */
202 20 + 0 * 4 /* %gs */
203};
204
205static void
206i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
207{
208 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
209
210 /* Inherit stuff from older releases. We assume that FreeBSD
211 4.0-RELEASE always uses ELF. */
212 i386fbsd_init_abi (info, gdbarch);
213
214 /* FreeBSD 4.0 introduced a new `struct reg'. */
215 tdep->gregset_reg_offset = i386fbsd4_r_reg_offset;
216 tdep->gregset_num_regs = ARRAY_SIZE (i386fbsd4_r_reg_offset);
217 tdep->sizeof_gregset = 19 * 4;
218
219 /* FreeBSD 4.0 introduced a new `struct sigcontext'. */
220 tdep->sc_reg_offset = i386fbsd4_sc_reg_offset;
221 tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset);
222}
223
224\f
225/* Provide a prototype to silence -Wmissing-prototypes. */
226void _initialize_i386fbsd_tdep (void);
227
228void
229_initialize_i386fbsd_tdep (void)
230{
231 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_AOUT,
232 i386fbsdaout_init_abi);
233 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_FREEBSD_ELF,
234 i386fbsd4_init_abi);
235}