1130803Smarcel/* Target-dependent code for OpenBSD/amd64.
2130803Smarcel
3130803Smarcel   Copyright 2003, 2004 Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   This file is part of GDB.
6130803Smarcel
7130803Smarcel   This program is free software; you can redistribute it and/or modify
8130803Smarcel   it under the terms of the GNU General Public License as published by
9130803Smarcel   the Free Software Foundation; either version 2 of the License, or
10130803Smarcel   (at your option) any later version.
11130803Smarcel
12130803Smarcel   This program is distributed in the hope that it will be useful,
13130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
14130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15130803Smarcel   GNU General Public License for more details.
16130803Smarcel
17130803Smarcel   You should have received a copy of the GNU General Public License
18130803Smarcel   along with this program; if not, write to the Free Software
19130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
20130803Smarcel   Boston, MA 02111-1307, USA.  */
21130803Smarcel
22130803Smarcel#include "defs.h"
23130803Smarcel#include "frame.h"
24130803Smarcel#include "gdbcore.h"
25130803Smarcel#include "osabi.h"
26130803Smarcel#include "regset.h"
27130803Smarcel#include "target.h"
28130803Smarcel
29130803Smarcel#include "gdb_assert.h"
30130803Smarcel#include "gdb_string.h"
31130803Smarcel
32130803Smarcel#include "amd64-tdep.h"
33130803Smarcel#include "i387-tdep.h"
34130803Smarcel#include "solib-svr4.h"
35130803Smarcel
36130803Smarcel/* Support for core dumps.  */
37130803Smarcel
38130803Smarcelstatic void
39130803Smarcelamd64obsd_supply_regset (const struct regset *regset,
40130803Smarcel			 struct regcache *regcache, int regnum,
41130803Smarcel			 const void *regs, size_t len)
42130803Smarcel{
43130803Smarcel  const struct gdbarch_tdep *tdep = regset->descr;
44130803Smarcel
45130803Smarcel  gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE);
46130803Smarcel
47130803Smarcel  i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
48130803Smarcel  amd64_supply_fxsave (regcache, regnum, (char *)regs + tdep->sizeof_gregset);
49130803Smarcel}
50130803Smarcel
51130803Smarcelstatic const struct regset *
52130803Smarcelamd64obsd_regset_from_core_section (struct gdbarch *gdbarch,
53130803Smarcel				    const char *sect_name, size_t sect_size)
54130803Smarcel{
55130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
56130803Smarcel
57130803Smarcel  /* OpenBSD core dumps don't use seperate register sets for the
58130803Smarcel     general-purpose and floating-point registers.  */
59130803Smarcel
60130803Smarcel  if (strcmp (sect_name, ".reg") == 0
61130803Smarcel      && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FXSAVE)
62130803Smarcel    {
63130803Smarcel      if (tdep->gregset == NULL)
64130803Smarcel	{
65130803Smarcel	  tdep->gregset = XMALLOC (struct regset);
66130803Smarcel	  tdep->gregset->descr = tdep;
67130803Smarcel	  tdep->gregset->supply_regset = amd64obsd_supply_regset;
68130803Smarcel	}
69130803Smarcel      return tdep->gregset;
70130803Smarcel    }
71130803Smarcel
72130803Smarcel  return NULL;
73130803Smarcel}
74130803Smarcel
75130803Smarcel
76130803Smarcel/* Support for signal handlers.  */
77130803Smarcel
78130803Smarcelstatic const int amd64obsd_page_size = 4096;
79130803Smarcel
80130803Smarcelstatic int
81130803Smarcelamd64obsd_pc_in_sigtramp (CORE_ADDR pc, char *name)
82130803Smarcel{
83130803Smarcel  CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1));
84130803Smarcel  const char sigreturn[] =
85130803Smarcel  {
86130803Smarcel    0x48, 0xc7, 0xc0,
87130803Smarcel    0x67, 0x00, 0x00, 0x00,	/* movq $SYS_sigreturn, %rax */
88130803Smarcel    0xcd, 0x80			/* int $0x80 */
89130803Smarcel  };
90130803Smarcel  char *buf;
91130803Smarcel
92130803Smarcel  if (name)
93130803Smarcel    return 0;
94130803Smarcel
95130803Smarcel  /* If we can't read the instructions at START_PC, return zero.  */
96130803Smarcel  buf = alloca (sizeof sigreturn);
97130803Smarcel  if (target_read_memory (start_pc + 0x7, buf, sizeof sigreturn))
98130803Smarcel    return 0;
99130803Smarcel
100130803Smarcel  /* Check for sigreturn(2).  */
101130803Smarcel  if (memcmp (buf, sigreturn, sizeof sigreturn))
102130803Smarcel    return 0;
103130803Smarcel
104130803Smarcel  return 1;
105130803Smarcel}
106130803Smarcel
107130803Smarcel/* Assuming NEXT_FRAME is for a frame following a BSD sigtramp
108130803Smarcel   routine, return the address of the associated sigcontext structure.  */
109130803Smarcel
110130803Smarcelstatic CORE_ADDR
111130803Smarcelamd64obsd_sigcontext_addr (struct frame_info *next_frame)
112130803Smarcel{
113130803Smarcel  /* The %rsp register points at `struct sigcontext' upon entry of a
114130803Smarcel     signal trampoline.  */
115130803Smarcel  return frame_unwind_register_unsigned (next_frame, AMD64_RSP_REGNUM);
116130803Smarcel}
117130803Smarcel
118130803Smarcel/* OpenBSD 3.5 or later.  */
119130803Smarcel
120130803Smarcel/* Mapping between the general-purpose registers in `struct reg'
121130803Smarcel   format and GDB's register cache layout.  */
122130803Smarcel
123130803Smarcel/* From <machine/reg.h>.  */
124130803Smarcelint amd64obsd_r_reg_offset[] =
125130803Smarcel{
126130803Smarcel  14 * 8,			/* %rax */
127130803Smarcel  13 * 8,			/* %rbx */
128130803Smarcel  3 * 8,			/* %rcx */
129130803Smarcel  2 * 8,			/* %rdx */
130130803Smarcel  1 * 8,			/* %rsi */
131130803Smarcel  0 * 8,			/* %rdi */
132130803Smarcel  12 * 8,			/* %rbp */
133130803Smarcel  15 * 8,			/* %rsp */
134130803Smarcel  4 * 8,			/* %r8 .. */
135130803Smarcel  5 * 8,
136130803Smarcel  6 * 8,
137130803Smarcel  7 * 8,
138130803Smarcel  8 * 8,
139130803Smarcel  9 * 8,
140130803Smarcel  10 * 8,
141130803Smarcel  11 * 8,			/* ... %r15 */
142130803Smarcel  16 * 8,			/* %rip */
143130803Smarcel  17 * 8,			/* %eflags */
144130803Smarcel  18 * 8,			/* %cs */
145130803Smarcel  19 * 8,			/* %ss */
146130803Smarcel  20 * 8,			/* %ds */
147130803Smarcel  21 * 8,			/* %es */
148130803Smarcel  22 * 8,			/* %fs */
149130803Smarcel  23 * 8			/* %gs */
150130803Smarcel};
151130803Smarcel
152130803Smarcel/* From <machine/signal.h>.  */
153130803Smarcelstatic int amd64obsd_sc_reg_offset[] =
154130803Smarcel{
155130803Smarcel  14 * 8,			/* %rax */
156130803Smarcel  13 * 8,			/* %rbx */
157130803Smarcel  3 * 8,			/* %rcx */
158130803Smarcel  2 * 8,			/* %rdx */
159130803Smarcel  1 * 8,			/* %rsi */
160130803Smarcel  0 * 8,			/* %rdi */
161130803Smarcel  12 * 8,			/* %rbp */
162130803Smarcel  24 * 8,			/* %rsp */
163130803Smarcel  4 * 8,			/* %r8 ... */
164130803Smarcel  5 * 8,
165130803Smarcel  6 * 8,
166130803Smarcel  7 * 8,
167130803Smarcel  8 * 8,
168130803Smarcel  9 * 8,
169130803Smarcel  10 * 8,
170130803Smarcel  11 * 8,			/* ... %r15 */
171130803Smarcel  21 * 8,			/* %rip */
172130803Smarcel  23 * 8,			/* %eflags */
173130803Smarcel  22 * 8,			/* %cs */
174130803Smarcel  25 * 8,			/* %ss */
175130803Smarcel  18 * 8,			/* %ds */
176130803Smarcel  17 * 8,			/* %es */
177130803Smarcel  16 * 8,			/* %fs */
178130803Smarcel  15 * 8			/* %gs */
179130803Smarcel};
180130803Smarcel
181130803Smarcelstatic void
182130803Smarcelamd64obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
183130803Smarcel{
184130803Smarcel  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
185130803Smarcel
186130803Smarcel  amd64_init_abi (info, gdbarch);
187130803Smarcel
188130803Smarcel  /* Initialize general-purpose register set details.  */
189130803Smarcel  tdep->gregset_reg_offset = amd64obsd_r_reg_offset;
190130803Smarcel  tdep->gregset_num_regs = ARRAY_SIZE (amd64obsd_r_reg_offset);
191130803Smarcel  tdep->sizeof_gregset = 24 * 8;
192130803Smarcel
193130803Smarcel  set_gdbarch_regset_from_core_section (gdbarch,
194130803Smarcel					amd64obsd_regset_from_core_section);
195130803Smarcel
196130803Smarcel  tdep->jb_pc_offset = 7 * 8;
197130803Smarcel
198130803Smarcel  set_gdbarch_pc_in_sigtramp (gdbarch, amd64obsd_pc_in_sigtramp);
199130803Smarcel  tdep->sigcontext_addr = amd64obsd_sigcontext_addr;
200130803Smarcel  tdep->sc_reg_offset = amd64obsd_sc_reg_offset;
201130803Smarcel  tdep->sc_num_regs = ARRAY_SIZE (amd64obsd_sc_reg_offset);
202130803Smarcel
203130803Smarcel  /* OpenBSD uses SVR4-style shared libraries.  */
204130803Smarcel  set_solib_svr4_fetch_link_map_offsets
205130803Smarcel    (gdbarch, svr4_lp64_fetch_link_map_offsets);
206130803Smarcel}
207130803Smarcel
208130803Smarcel
209130803Smarcel/* Provide a prototype to silence -Wmissing-prototypes.  */
210130803Smarcelvoid _initialize_amd64obsd_tdep (void);
211130803Smarcel
212130803Smarcelvoid
213130803Smarcel_initialize_amd64obsd_tdep (void)
214130803Smarcel{
215130803Smarcel  /* The OpenBSD/amd64 native dependent code makes this assumption.  */
216130803Smarcel  gdb_assert (ARRAY_SIZE (amd64obsd_r_reg_offset) == AMD64_NUM_GREGS);
217130803Smarcel
218130803Smarcel  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
219130803Smarcel			  GDB_OSABI_OPENBSD_ELF, amd64obsd_init_abi);
220130803Smarcel
221130803Smarcel  /* OpenBSD uses traditional (a.out) NetBSD-style core dumps.  */
222130803Smarcel  gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64,
223130803Smarcel			  GDB_OSABI_NETBSD_AOUT, amd64obsd_init_abi);
224130803Smarcel}
225