]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/gdb/gdb/i386obsd-tdep.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / gdb / 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 "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.  */
49 static const int i386obsd_page_size = 4096;
50
51 /* Return whether PC is in an OpenBSD sigtramp routine.  */
52
53 static int
54 i386obsd_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
87 static CORE_ADDR
88 i386obsd_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
100 static CORE_ADDR
101 i386obsd_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 \f
111 /* Mapping between the general-purpose registers in `struct reg'
112    format and GDB's register cache layout.  */
113
114 /* From <machine/reg.h>.  */
115 static 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
135 static void
136 i386obsd_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
148 static const struct regset *
149 i386obsd_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 \f
173
174 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases.  */
175 CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
176 CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
177
178 /* From <machine/signal.h>.  */
179 int 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
199 static void 
200 i386obsd_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
230 static void
231 i386obsd_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
242 static void
243 i386obsd_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 \f
260
261 /* Provide a prototype to silence -Wmissing-prototypes.  */
262 void _initialize_i386obsd_tdep (void);
263
264 void
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 }