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 "gdbcore.h"
27#include "regcache.h"
28#include "regset.h"
29#include "osabi.h"
30#include "target.h"
31
32#include "gdb_assert.h"
33#include "gdb_string.h"
34
35#include "i386-tdep.h"
36#include "i387-tdep.h"
37#include "solib-svr4.h"
38
39/* Support for signal handlers.  */
40
41/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
42   in virtual memory.  The randomness makes it somewhat tricky to
43   detect it, but fortunately we can rely on the fact that the start
44   of the sigtramp routine is page-aligned.  By the way, the mapping
45   is read-only, so you cannot place a breakpoint in the signal
46   trampoline.  */
47
48/* Default page size.  */
49static const int i386obsd_page_size = 4096;
50
51/* Return whether PC is in an OpenBSD sigtramp routine.  */
52
53static int
54i386obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
55{
56  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
57  const char sigreturn[] =
58  {
59    0xb8,
60    0x67, 0x00, 0x00, 0x00,	/* movl $SYS_sigreturn, %eax */
61    0xcd, 0x80			/* int $0x80 */
62  };
63  char *buf;
64
65  /* Avoid reading memory from the target if possible.  If we're in a
66     named function, we're certainly not in a sigtramp routine
67     provided by the kernel.  Take synthetic function names into
68     account though.  */
69  if (name && name[0] != '<')
70    return 0;
71
72  /* If we can't read the instructions at START_PC, return zero.  */
73  buf = alloca (sizeof sigreturn);
74  if (target_read_memory (start_pc + 0x14, buf, sizeof sigreturn))
75    return 0;
76
77  /* Check for sigreturn(2).  */
78  if (memcmp (buf, sigreturn, sizeof sigreturn) == 0)
79    return 1;
80
81  /* Check for a traditional BSD sigtramp routine.  */
82  return i386bsd_pc_in_sigtramp (pc, name);
83}
84
85/* Return the start address of the sigtramp routine.  */
86
87static CORE_ADDR
88i386obsd_sigtramp_start (CORE_ADDR pc)
89{
90  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
91
92  if (i386bsd_pc_in_sigtramp (pc, NULL))
93    return i386bsd_sigtramp_start (pc);
94
95  return start_pc;
96}
97
98/* Return the end address of the sigtramp routine.  */
99
100static CORE_ADDR
101i386obsd_sigtramp_end (CORE_ADDR pc)
102{
103  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
104
105  if (i386bsd_pc_in_sigtramp (pc, NULL))
106    return i386bsd_sigtramp_end (pc);
107
108  return start_pc + 0x22;
109}
110
111/* Mapping between the general-purpose registers in `struct reg'
112   format and GDB's register cache layout.  */
113
114/* From <machine/reg.h>.  */
115static int i386obsd_r_reg_offset[] =
116{
117  0 * 4,			/* %eax */
118  1 * 4,			/* %ecx */
119  2 * 4,			/* %edx */
120  3 * 4,			/* %ebx */
121  4 * 4,			/* %esp */
122  5 * 4,			/* %ebp */
123  6 * 4,			/* %esi */
124  7 * 4,			/* %edi */
125  8 * 4,			/* %eip */
126  9 * 4,			/* %eflags */
127  10 * 4,			/* %cs */
128  11 * 4,			/* %ss */
129  12 * 4,			/* %ds */
130  13 * 4,			/* %es */
131  14 * 4,			/* %fs */
132  15 * 4			/* %gs */
133};
134
135static void
136i386obsd_aout_supply_regset (const struct regset *regset,
137			     struct regcache *regcache, int regnum,
138			     const void *regs, size_t len)
139{
140  const struct gdbarch_tdep *tdep = regset->descr;
141
142  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
143
144  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
145  i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
146}
147
148static const struct regset *
149i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
150					const char *sect_name,
151					size_t sect_size)
152{
153  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
154
155  /* OpenBSD a.out core dumps don't use seperate register sets for the
156     general-purpose and floating-point registers.  */
157
158  if (strcmp (sect_name, ".reg") == 0
159      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
160    {
161      if (tdep->gregset == NULL)
162	{
163	  tdep->gregset = XMALLOC (struct regset);
164	  tdep->gregset->descr = tdep;
165	  tdep->gregset->supply_regset = i386obsd_aout_supply_regset;
166	}
167      return tdep->gregset;
168    }
169
170  return NULL;
171}
172
173
174/* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
175CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
176CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
177
178/* From <machine/signal.h>.  */
179int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
180{
181  10 * 4,			/* %eax */
182  9 * 4,			/* %ecx */
183  8 * 4,			/* %edx */
184  7 * 4,			/* %ebx */
185  14 * 4,			/* %esp */
186  6 * 4,			/* %ebp */
187  5 * 4,			/* %esi */
188  4 * 4,			/* %edi */
189  11 * 4,			/* %eip */
190  13 * 4,			/* %eflags */
191  12 * 4,			/* %cs */
192  15 * 4,			/* %ss */
193  3 * 4,			/* %ds */
194  2 * 4,			/* %es */
195  1 * 4,			/* %fs */
196  0 * 4				/* %gs */
197};
198
199static void
200i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
201{
202  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
203
204  /* Obviously OpenBSD is BSD-based.  */
205  i386bsd_init_abi (info, gdbarch);
206
207  /* OpenBSD has a different `struct reg'.  */
208  tdep->gregset_reg_offset = i386obsd_r_reg_offset;
209  tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
210  tdep->sizeof_gregset = 16 * 4;
211
212  /* OpenBSD uses -freg-struct-return by default.  */
213  tdep->struct_return = reg_struct_return;
214
215  /* OpenBSD uses a different memory layout.  */
216  tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
217  tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
218  set_gdbarch_pc_in_sigtramp (gdbarch, i386obsd_pc_in_sigtramp);
219  set_gdbarch_sigtramp_start (gdbarch, i386obsd_sigtramp_start);
220  set_gdbarch_sigtramp_end (gdbarch, i386obsd_sigtramp_end);
221
222  /* OpenBSD has a `struct sigcontext' that's different from the
223     origional 4.3 BSD.  */
224  tdep->sc_reg_offset = i386obsd_sc_reg_offset;
225  tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
226}
227
228/* OpenBSD a.out.  */
229
230static void
231i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
232{
233  i386obsd_init_abi (info, gdbarch);
234
235  /* OpenBSD a.out has a single register set.  */
236  set_gdbarch_regset_from_core_section
237    (gdbarch, i386obsd_aout_regset_from_core_section);
238}
239
240/* OpenBSD ELF.  */
241
242static void
243i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
244{
245  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
246
247  /* It's still OpenBSD.  */
248  i386obsd_init_abi (info, gdbarch);
249
250  /* But ELF-based.  */
251  i386_elf_init_abi (info, gdbarch);
252
253  /* OpenBSD ELF uses SVR4-style shared libraries.  */
254  set_gdbarch_in_solib_call_trampoline
255    (gdbarch, generic_in_solib_call_trampoline);
256  set_solib_svr4_fetch_link_map_offsets
257    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
258}
259
260
261/* Provide a prototype to silence -Wmissing-prototypes.  */
262void _initialize_i386obsd_tdep (void);
263
264void
265_initialize_i386obsd_tdep (void)
266{
267  /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
268     indistingushable from NetBSD/i386 a.out binaries, building a GDB
269     that should support both these targets will probably not work as
270     expected.  */
271#define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
272
273  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
274			  i386obsd_aout_init_abi);
275  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
276			  i386obsd_elf_init_abi);
277}
278