* i386obsd-tdep.c (i386obsd_sigtramp_p): Adjust for changed signal
[binutils-gdb.git] / gdb / i386obsd-tdep.c
1 /* Target-dependent code for OpenBSD/i386.
2
3 Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
4 2003, 2004
5 Free Software Foundation, Inc.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24 #include "defs.h"
25 #include "arch-utils.h"
26 #include "frame.h"
27 #include "gdbcore.h"
28 #include "regcache.h"
29 #include "regset.h"
30 #include "symtab.h"
31 #include "objfiles.h"
32 #include "osabi.h"
33 #include "target.h"
34
35 #include "gdb_assert.h"
36 #include "gdb_string.h"
37
38 #include "i386-tdep.h"
39 #include "i387-tdep.h"
40 #include "solib-svr4.h"
41
42 /* Support for signal handlers. */
43
44 /* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
45 in virtual memory. The randomness makes it somewhat tricky to
46 detect it, but fortunately we can rely on the fact that the start
47 of the sigtramp routine is page-aligned. By the way, the mapping
48 is read-only, so you cannot place a breakpoint in the signal
49 trampoline. */
50
51 /* Default page size. */
52 static const int i386obsd_page_size = 4096;
53
54 /* Return whether the frame preceding NEXT_FRAME corresponds to an
55 OpenBSD sigtramp routine. */
56
57 static int
58 i386obsd_sigtramp_p (struct frame_info *next_frame)
59 {
60 CORE_ADDR pc = frame_pc_unwind (next_frame);
61 CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
62 const char sigreturn[] =
63 {
64 0xb8,
65 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
66 0xcd, 0x80 /* int $0x80 */
67 };
68 char *name, *buf;
69
70 /* If the function has a valid symbol name, it isn't a
71 trampoline. */
72 find_pc_partial_function (pc, &name, NULL, NULL);
73 if (name != NULL)
74 return 0;
75
76 /* If the function lives in a valid section (even without a starting
77 point) it isn't a trampoline. */
78 if (find_pc_section (pc) != NULL)
79 return 0;
80
81 /* Allocate buffer. */
82 buf = alloca (sizeof sigreturn);
83
84 /* If we can't read the instructions at START_PC, return zero. */
85 if (target_read_memory (start_pc + 0x0a, buf, sizeof sigreturn))
86 return 0;
87
88 /* Check for sigreturn(2). */
89 if (memcmp (buf, sigreturn, sizeof sigreturn) == 0)
90 return 1;
91
92 /* If we can't read the instructions at START_PC, return zero. */
93 if (target_read_memory (start_pc + 0x14, buf, sizeof sigreturn))
94 return 0;
95
96 /* Check for sigreturn(2) (again). */
97 if (memcmp (buf, sigreturn, sizeof sigreturn) == 0)
98 return 1;
99
100 return 0;
101 }
102 \f
103 /* Mapping between the general-purpose registers in `struct reg'
104 format and GDB's register cache layout. */
105
106 /* From <machine/reg.h>. */
107 static int i386obsd_r_reg_offset[] =
108 {
109 0 * 4, /* %eax */
110 1 * 4, /* %ecx */
111 2 * 4, /* %edx */
112 3 * 4, /* %ebx */
113 4 * 4, /* %esp */
114 5 * 4, /* %ebp */
115 6 * 4, /* %esi */
116 7 * 4, /* %edi */
117 8 * 4, /* %eip */
118 9 * 4, /* %eflags */
119 10 * 4, /* %cs */
120 11 * 4, /* %ss */
121 12 * 4, /* %ds */
122 13 * 4, /* %es */
123 14 * 4, /* %fs */
124 15 * 4 /* %gs */
125 };
126
127 static void
128 i386obsd_aout_supply_regset (const struct regset *regset,
129 struct regcache *regcache, int regnum,
130 const void *regs, size_t len)
131 {
132 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
133
134 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
135
136 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
137 i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
138 }
139
140 static const struct regset *
141 i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
142 const char *sect_name,
143 size_t sect_size)
144 {
145 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
146
147 /* OpenBSD a.out core dumps don't use seperate register sets for the
148 general-purpose and floating-point registers. */
149
150 if (strcmp (sect_name, ".reg") == 0
151 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
152 {
153 if (tdep->gregset == NULL)
154 tdep->gregset =
155 regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
156 return tdep->gregset;
157 }
158
159 return NULL;
160 }
161 \f
162
163 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
164 CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
165 CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
166
167 /* From <machine/signal.h>. */
168 int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
169 {
170 10 * 4, /* %eax */
171 9 * 4, /* %ecx */
172 8 * 4, /* %edx */
173 7 * 4, /* %ebx */
174 14 * 4, /* %esp */
175 6 * 4, /* %ebp */
176 5 * 4, /* %esi */
177 4 * 4, /* %edi */
178 11 * 4, /* %eip */
179 13 * 4, /* %eflags */
180 12 * 4, /* %cs */
181 15 * 4, /* %ss */
182 3 * 4, /* %ds */
183 2 * 4, /* %es */
184 1 * 4, /* %fs */
185 0 * 4 /* %gs */
186 };
187
188 static void
189 i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
190 {
191 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
192
193 /* Obviously OpenBSD is BSD-based. */
194 i386bsd_init_abi (info, gdbarch);
195
196 /* OpenBSD has a different `struct reg'. */
197 tdep->gregset_reg_offset = i386obsd_r_reg_offset;
198 tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
199 tdep->sizeof_gregset = 16 * 4;
200
201 /* OpenBSD uses -freg-struct-return by default. */
202 tdep->struct_return = reg_struct_return;
203
204 /* OpenBSD uses a different memory layout. */
205 tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
206 tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
207 tdep->sigtramp_p = i386obsd_sigtramp_p;
208
209 /* OpenBSD has a `struct sigcontext' that's different from the
210 original 4.3 BSD. */
211 tdep->sc_reg_offset = i386obsd_sc_reg_offset;
212 tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
213 }
214
215 /* OpenBSD a.out. */
216
217 static void
218 i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
219 {
220 i386obsd_init_abi (info, gdbarch);
221
222 /* OpenBSD a.out has a single register set. */
223 set_gdbarch_regset_from_core_section
224 (gdbarch, i386obsd_aout_regset_from_core_section);
225 }
226
227 /* OpenBSD ELF. */
228
229 static void
230 i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
231 {
232 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
233
234 /* It's still OpenBSD. */
235 i386obsd_init_abi (info, gdbarch);
236
237 /* But ELF-based. */
238 i386_elf_init_abi (info, gdbarch);
239
240 /* OpenBSD ELF uses SVR4-style shared libraries. */
241 set_gdbarch_in_solib_call_trampoline
242 (gdbarch, generic_in_solib_call_trampoline);
243 set_solib_svr4_fetch_link_map_offsets
244 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
245 }
246 \f
247
248 /* Provide a prototype to silence -Wmissing-prototypes. */
249 void _initialize_i386obsd_tdep (void);
250
251 void
252 _initialize_i386obsd_tdep (void)
253 {
254 /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
255 indistingushable from NetBSD/i386 a.out binaries, building a GDB
256 that should support both these targets will probably not work as
257 expected. */
258 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
259
260 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
261 i386obsd_aout_init_abi);
262 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
263 i386obsd_elf_init_abi);
264 }