* i386obsd-tdep.c (i386obsd_sigtramp_p): Use
[external/binutils.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   size_t buflen = sizeof sigreturn;
69   char *name, *buf;
70
71   /* If the function has a valid symbol name, it isn't a
72      trampoline.  */
73   find_pc_partial_function (pc, &name, NULL, NULL);
74   if (name != NULL)
75     return 0;
76
77   /* If the function lives in a valid section (even without a starting
78      point) it isn't a trampoline.  */
79   if (find_pc_section (pc) != NULL)
80     return 0;
81
82   /* Allocate buffer.  */
83   buf = alloca (buflen);
84
85   /* If we can't read the instructions at START_PC, return zero.  */
86   if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen))
87     return 0;
88
89   /* Check for sigreturn(2).  */
90   if (memcmp (buf, sigreturn, buflen) == 0)
91     return 1;
92
93   /* If we can't read the instructions at START_PC, return zero.  */
94   if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen))
95     return 0;
96
97   /* Check for sigreturn(2) (again).  */
98   if (memcmp (buf, sigreturn, buflen) == 0)
99     return 1;
100
101   return 0;
102 }
103 \f
104 /* Mapping between the general-purpose registers in `struct reg'
105    format and GDB's register cache layout.  */
106
107 /* From <machine/reg.h>.  */
108 static int i386obsd_r_reg_offset[] =
109 {
110   0 * 4,                        /* %eax */
111   1 * 4,                        /* %ecx */
112   2 * 4,                        /* %edx */
113   3 * 4,                        /* %ebx */
114   4 * 4,                        /* %esp */
115   5 * 4,                        /* %ebp */
116   6 * 4,                        /* %esi */
117   7 * 4,                        /* %edi */
118   8 * 4,                        /* %eip */
119   9 * 4,                        /* %eflags */
120   10 * 4,                       /* %cs */
121   11 * 4,                       /* %ss */
122   12 * 4,                       /* %ds */
123   13 * 4,                       /* %es */
124   14 * 4,                       /* %fs */
125   15 * 4                        /* %gs */
126 };
127
128 static void
129 i386obsd_aout_supply_regset (const struct regset *regset,
130                              struct regcache *regcache, int regnum,
131                              const void *regs, size_t len)
132 {
133   const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
134
135   gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
136
137   i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
138   i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
139 }
140
141 static const struct regset *
142 i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
143                                         const char *sect_name,
144                                         size_t sect_size)
145 {
146   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
147
148   /* OpenBSD a.out core dumps don't use seperate register sets for the
149      general-purpose and floating-point registers.  */
150
151   if (strcmp (sect_name, ".reg") == 0
152       && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
153     {
154       if (tdep->gregset == NULL)
155         tdep->gregset =
156           regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
157       return tdep->gregset;
158     }
159
160   return NULL;
161 }
162 \f
163
164 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
165 CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
166 CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
167
168 /* From <machine/signal.h>.  */
169 int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
170 {
171   10 * 4,                       /* %eax */
172   9 * 4,                        /* %ecx */
173   8 * 4,                        /* %edx */
174   7 * 4,                        /* %ebx */
175   14 * 4,                       /* %esp */
176   6 * 4,                        /* %ebp */
177   5 * 4,                        /* %esi */
178   4 * 4,                        /* %edi */
179   11 * 4,                       /* %eip */
180   13 * 4,                       /* %eflags */
181   12 * 4,                       /* %cs */
182   15 * 4,                       /* %ss */
183   3 * 4,                        /* %ds */
184   2 * 4,                        /* %es */
185   1 * 4,                        /* %fs */
186   0 * 4                         /* %gs */
187 };
188
189 static void 
190 i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
191 {
192   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
193
194   /* Obviously OpenBSD is BSD-based.  */
195   i386bsd_init_abi (info, gdbarch);
196
197   /* OpenBSD has a different `struct reg'.  */
198   tdep->gregset_reg_offset = i386obsd_r_reg_offset;
199   tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
200   tdep->sizeof_gregset = 16 * 4;
201
202   /* OpenBSD uses -freg-struct-return by default.  */
203   tdep->struct_return = reg_struct_return;
204
205   /* OpenBSD uses a different memory layout.  */
206   tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
207   tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
208   tdep->sigtramp_p = i386obsd_sigtramp_p;
209
210   /* OpenBSD has a `struct sigcontext' that's different from the
211      original 4.3 BSD.  */
212   tdep->sc_reg_offset = i386obsd_sc_reg_offset;
213   tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
214 }
215
216 /* OpenBSD a.out.  */
217
218 static void
219 i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
220 {
221   i386obsd_init_abi (info, gdbarch);
222
223   /* OpenBSD a.out has a single register set.  */
224   set_gdbarch_regset_from_core_section
225     (gdbarch, i386obsd_aout_regset_from_core_section);
226 }
227
228 /* OpenBSD ELF.  */
229
230 static void
231 i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
232 {
233   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
234
235   /* It's still OpenBSD.  */
236   i386obsd_init_abi (info, gdbarch);
237
238   /* But ELF-based.  */
239   i386_elf_init_abi (info, gdbarch);
240
241   /* OpenBSD ELF uses SVR4-style shared libraries.  */
242   set_gdbarch_in_solib_call_trampoline
243     (gdbarch, generic_in_solib_call_trampoline);
244   set_solib_svr4_fetch_link_map_offsets
245     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
246 }
247 \f
248
249 /* Provide a prototype to silence -Wmissing-prototypes.  */
250 void _initialize_i386obsd_tdep (void);
251
252 void
253 _initialize_i386obsd_tdep (void)
254 {
255   /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
256      indistingushable from NetBSD/i386 a.out binaries, building a GDB
257      that should support both these targets will probably not work as
258      expected.  */
259 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
260
261   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
262                           i386obsd_aout_init_abi);
263   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
264                           i386obsd_elf_init_abi);
265 }