1130803Smarcel/* Target-dependent code for OpenBSD/i386.
2130803Smarcel
3130803Smarcel   Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
4130803Smarcel   2003, 2004
5130803Smarcel   Free Software Foundation, Inc.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "defs.h"
25130803Smarcel#include "arch-utils.h"
26130803Smarcel#include "gdbcore.h"
27130803Smarcel#include "regcache.h"
28130803Smarcel#include "regset.h"
29130803Smarcel#include "osabi.h"
30130803Smarcel#include "target.h"
31130803Smarcel
32130803Smarcel#include "gdb_assert.h"
33130803Smarcel#include "gdb_string.h"
34130803Smarcel
35130803Smarcel#include "i386-tdep.h"
36130803Smarcel#include "i387-tdep.h"
37130803Smarcel#include "solib-svr4.h"
38130803Smarcel
39130803Smarcel/* Support for signal handlers.  */
40130803Smarcel
41130803Smarcel/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
42130803Smarcel   in virtual memory.  The randomness makes it somewhat tricky to
43130803Smarcel   detect it, but fortunately we can rely on the fact that the start
44130803Smarcel   of the sigtramp routine is page-aligned.  By the way, the mapping
45130803Smarcel   is read-only, so you cannot place a breakpoint in the signal
46130803Smarcel   trampoline.  */
47130803Smarcel
48130803Smarcel/* Default page size.  */
49130803Smarcelstatic const int i386obsd_page_size = 4096;
50130803Smarcel
51130803Smarcel/* Return whether PC is in an OpenBSD sigtramp routine.  */
52130803Smarcel
53130803Smarcelstatic int
54130803Smarceli386obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
55130803Smarcel{
56130803Smarcel  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
57130803Smarcel  const char sigreturn[] =
58130803Smarcel  {
59130803Smarcel    0xb8,
60130803Smarcel    0x67, 0x00, 0x00, 0x00,	/* movl $SYS_sigreturn, %eax */
61130803Smarcel    0xcd, 0x80			/* int $0x80 */
62130803Smarcel  };
63130803Smarcel  char *buf;
64130803Smarcel
65130803Smarcel  /* Avoid reading memory from the target if possible.  If we're in a
66130803Smarcel     named function, we're certainly not in a sigtramp routine
67130803Smarcel     provided by the kernel.  Take synthetic function names into
68130803Smarcel     account though.  */
69130803Smarcel  if (name && name[0] != '<')
70130803Smarcel    return 0;
71130803Smarcel
72130803Smarcel  /* If we can't read the instructions at START_PC, return zero.  */
73130803Smarcel  buf = alloca (sizeof sigreturn);
74130803Smarcel  if (target_read_memory (start_pc + 0x14, buf, sizeof sigreturn))
75130803Smarcel    return 0;
76130803Smarcel
77130803Smarcel  /* Check for sigreturn(2).  */
78130803Smarcel  if (memcmp (buf, sigreturn, sizeof sigreturn) == 0)
79130803Smarcel    return 1;
80130803Smarcel
81130803Smarcel  /* Check for a traditional BSD sigtramp routine.  */
82130803Smarcel  return i386bsd_pc_in_sigtramp (pc, name);
83130803Smarcel}
84130803Smarcel
85130803Smarcel/* Return the start address of the sigtramp routine.  */
86130803Smarcel
87130803Smarcelstatic CORE_ADDR
88130803Smarceli386obsd_sigtramp_start (CORE_ADDR pc)
89130803Smarcel{
90130803Smarcel  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
91130803Smarcel
92130803Smarcel  if (i386bsd_pc_in_sigtramp (pc, NULL))
93130803Smarcel    return i386bsd_sigtramp_start (pc);
94130803Smarcel
95130803Smarcel  return start_pc;
96130803Smarcel}
97130803Smarcel
98130803Smarcel/* Return the end address of the sigtramp routine.  */
99130803Smarcel
100130803Smarcelstatic CORE_ADDR
101130803Smarceli386obsd_sigtramp_end (CORE_ADDR pc)
102130803Smarcel{
103130803Smarcel  CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
104130803Smarcel
105130803Smarcel  if (i386bsd_pc_in_sigtramp (pc, NULL))
106130803Smarcel    return i386bsd_sigtramp_end (pc);
107130803Smarcel
108130803Smarcel  return start_pc + 0x22;
109130803Smarcel}
110130803Smarcel
111130803Smarcel/* Mapping between the general-purpose registers in `struct reg'
112130803Smarcel   format and GDB's register cache layout.  */
113130803Smarcel
114130803Smarcel/* From <machine/reg.h>.  */
115130803Smarcelstatic int i386obsd_r_reg_offset[] =
116130803Smarcel{
117130803Smarcel  0 * 4,			/* %eax */
118130803Smarcel  1 * 4,			/* %ecx */
119130803Smarcel  2 * 4,			/* %edx */
120130803Smarcel  3 * 4,			/* %ebx */
121130803Smarcel  4 * 4,			/* %esp */
122130803Smarcel  5 * 4,			/* %ebp */
123130803Smarcel  6 * 4,			/* %esi */
124130803Smarcel  7 * 4,			/* %edi */
125130803Smarcel  8 * 4,			/* %eip */
126130803Smarcel  9 * 4,			/* %eflags */
127130803Smarcel  10 * 4,			/* %cs */
128130803Smarcel  11 * 4,			/* %ss */
129130803Smarcel  12 * 4,			/* %ds */
130130803Smarcel  13 * 4,			/* %es */
131130803Smarcel  14 * 4,			/* %fs */
132130803Smarcel  15 * 4			/* %gs */
133130803Smarcel};
134130803Smarcel
135130803Smarcelstatic void
136130803Smarceli386obsd_aout_supply_regset (const struct regset *regset,
137130803Smarcel			     struct regcache *regcache, int regnum,
138130803Smarcel			     const void *regs, size_t len)
139130803Smarcel{
140130803Smarcel  const struct gdbarch_tdep *tdep = regset->descr;
141130803Smarcel
142130803Smarcel  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
143130803Smarcel
144130803Smarcel  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
145130803Smarcel  i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
146130803Smarcel}
147130803Smarcel
148130803Smarcelstatic const struct regset *
149130803Smarceli386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
150130803Smarcel					const char *sect_name,
151130803Smarcel					size_t sect_size)
152130803Smarcel{
153130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
154130803Smarcel
155130803Smarcel  /* OpenBSD a.out core dumps don't use seperate register sets for the
156130803Smarcel     general-purpose and floating-point registers.  */
157130803Smarcel
158130803Smarcel  if (strcmp (sect_name, ".reg") == 0
159130803Smarcel      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
160130803Smarcel    {
161130803Smarcel      if (tdep->gregset == NULL)
162130803Smarcel	{
163130803Smarcel	  tdep->gregset = XMALLOC (struct regset);
164130803Smarcel	  tdep->gregset->descr = tdep;
165130803Smarcel	  tdep->gregset->supply_regset = i386obsd_aout_supply_regset;
166130803Smarcel	}
167130803Smarcel      return tdep->gregset;
168130803Smarcel    }
169130803Smarcel
170130803Smarcel  return NULL;
171130803Smarcel}
172130803Smarcel
173130803Smarcel
174130803Smarcel/* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
175130803SmarcelCORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
176130803SmarcelCORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
177130803Smarcel
178130803Smarcel/* From <machine/signal.h>.  */
179130803Smarcelint i386obsd_sc_reg_offset[I386_NUM_GREGS] =
180130803Smarcel{
181130803Smarcel  10 * 4,			/* %eax */
182130803Smarcel  9 * 4,			/* %ecx */
183130803Smarcel  8 * 4,			/* %edx */
184130803Smarcel  7 * 4,			/* %ebx */
185130803Smarcel  14 * 4,			/* %esp */
186130803Smarcel  6 * 4,			/* %ebp */
187130803Smarcel  5 * 4,			/* %esi */
188130803Smarcel  4 * 4,			/* %edi */
189130803Smarcel  11 * 4,			/* %eip */
190130803Smarcel  13 * 4,			/* %eflags */
191130803Smarcel  12 * 4,			/* %cs */
192130803Smarcel  15 * 4,			/* %ss */
193130803Smarcel  3 * 4,			/* %ds */
194130803Smarcel  2 * 4,			/* %es */
195130803Smarcel  1 * 4,			/* %fs */
196130803Smarcel  0 * 4				/* %gs */
197130803Smarcel};
198130803Smarcel
199130803Smarcelstatic void
200130803Smarceli386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
201130803Smarcel{
202130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
203130803Smarcel
204130803Smarcel  /* Obviously OpenBSD is BSD-based.  */
205130803Smarcel  i386bsd_init_abi (info, gdbarch);
206130803Smarcel
207130803Smarcel  /* OpenBSD has a different `struct reg'.  */
208130803Smarcel  tdep->gregset_reg_offset = i386obsd_r_reg_offset;
209130803Smarcel  tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
210130803Smarcel  tdep->sizeof_gregset = 16 * 4;
211130803Smarcel
212130803Smarcel  /* OpenBSD uses -freg-struct-return by default.  */
213130803Smarcel  tdep->struct_return = reg_struct_return;
214130803Smarcel
215130803Smarcel  /* OpenBSD uses a different memory layout.  */
216130803Smarcel  tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
217130803Smarcel  tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
218130803Smarcel  set_gdbarch_pc_in_sigtramp (gdbarch, i386obsd_pc_in_sigtramp);
219130803Smarcel  set_gdbarch_sigtramp_start (gdbarch, i386obsd_sigtramp_start);
220130803Smarcel  set_gdbarch_sigtramp_end (gdbarch, i386obsd_sigtramp_end);
221130803Smarcel
222130803Smarcel  /* OpenBSD has a `struct sigcontext' that's different from the
223130803Smarcel     origional 4.3 BSD.  */
224130803Smarcel  tdep->sc_reg_offset = i386obsd_sc_reg_offset;
225130803Smarcel  tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
226130803Smarcel}
227130803Smarcel
228130803Smarcel/* OpenBSD a.out.  */
229130803Smarcel
230130803Smarcelstatic void
231130803Smarceli386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
232130803Smarcel{
233130803Smarcel  i386obsd_init_abi (info, gdbarch);
234130803Smarcel
235130803Smarcel  /* OpenBSD a.out has a single register set.  */
236130803Smarcel  set_gdbarch_regset_from_core_section
237130803Smarcel    (gdbarch, i386obsd_aout_regset_from_core_section);
238130803Smarcel}
239130803Smarcel
240130803Smarcel/* OpenBSD ELF.  */
241130803Smarcel
242130803Smarcelstatic void
243130803Smarceli386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
244130803Smarcel{
245130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
246130803Smarcel
247130803Smarcel  /* It's still OpenBSD.  */
248130803Smarcel  i386obsd_init_abi (info, gdbarch);
249130803Smarcel
250130803Smarcel  /* But ELF-based.  */
251130803Smarcel  i386_elf_init_abi (info, gdbarch);
252130803Smarcel
253130803Smarcel  /* OpenBSD ELF uses SVR4-style shared libraries.  */
254130803Smarcel  set_gdbarch_in_solib_call_trampoline
255130803Smarcel    (gdbarch, generic_in_solib_call_trampoline);
256130803Smarcel  set_solib_svr4_fetch_link_map_offsets
257130803Smarcel    (gdbarch, svr4_ilp32_fetch_link_map_offsets);
258130803Smarcel}
259130803Smarcel
260130803Smarcel
261130803Smarcel/* Provide a prototype to silence -Wmissing-prototypes.  */
262130803Smarcelvoid _initialize_i386obsd_tdep (void);
263130803Smarcel
264130803Smarcelvoid
265130803Smarcel_initialize_i386obsd_tdep (void)
266130803Smarcel{
267130803Smarcel  /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
268130803Smarcel     indistingushable from NetBSD/i386 a.out binaries, building a GDB
269130803Smarcel     that should support both these targets will probably not work as
270130803Smarcel     expected.  */
271130803Smarcel#define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
272130803Smarcel
273130803Smarcel  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
274130803Smarcel			  i386obsd_aout_init_abi);
275130803Smarcel  gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
276130803Smarcel			  i386obsd_elf_init_abi);
277130803Smarcel}
278