gas/
[deliverable/binutils-gdb.git] / gdb / i386obsd-tdep.c
CommitLineData
005328e3 1/* Target-dependent code for OpenBSD/i386.
67457012 2
60a6eeb6 3 Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
a28109e0 4 2003, 2004, 2005
005328e3
MK
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"
911bc6ee 26#include "frame.h"
005328e3
MK
27#include "gdbcore.h"
28#include "regcache.h"
67457012 29#include "regset.h"
911bc6ee
MK
30#include "symtab.h"
31#include "objfiles.h"
4be87837 32#include "osabi.h"
5d93ae8c 33#include "target.h"
005328e3 34
67457012
MK
35#include "gdb_assert.h"
36#include "gdb_string.h"
37
005328e3
MK
38#include "i386-tdep.h"
39#include "i387-tdep.h"
60a6eeb6 40#include "solib-svr4.h"
a28109e0 41#include "bsd-uthread.h"
005328e3 42
5d93ae8c
MK
43/* Support for signal handlers. */
44
45/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page
46 in virtual memory. The randomness makes it somewhat tricky to
47 detect it, but fortunately we can rely on the fact that the start
48 of the sigtramp routine is page-aligned. By the way, the mapping
49 is read-only, so you cannot place a breakpoint in the signal
50 trampoline. */
51
52/* Default page size. */
53static const int i386obsd_page_size = 4096;
54
377d9ebd 55/* Return whether the frame preceding NEXT_FRAME corresponds to an
911bc6ee 56 OpenBSD sigtramp routine. */
5d93ae8c
MK
57
58static int
911bc6ee 59i386obsd_sigtramp_p (struct frame_info *next_frame)
5d93ae8c 60{
911bc6ee 61 CORE_ADDR pc = frame_pc_unwind (next_frame);
5d93ae8c 62 CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1));
63c0089f 63 const gdb_byte sigreturn[] =
5d93ae8c
MK
64 {
65 0xb8,
66 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
67 0xcd, 0x80 /* int $0x80 */
68 };
c822af0c 69 size_t buflen = sizeof sigreturn;
63c0089f
MK
70 gdb_byte *buf;
71 char *name;
5d93ae8c 72
911bc6ee
MK
73 /* If the function has a valid symbol name, it isn't a
74 trampoline. */
75 find_pc_partial_function (pc, &name, NULL, NULL);
76 if (name != NULL)
77 return 0;
78
79 /* If the function lives in a valid section (even without a starting
80 point) it isn't a trampoline. */
81 if (find_pc_section (pc) != NULL)
5d93ae8c
MK
82 return 0;
83
9c8e3411 84 /* Allocate buffer. */
c822af0c 85 buf = alloca (buflen);
9c8e3411
MK
86
87 /* If we can't read the instructions at START_PC, return zero. */
c822af0c 88 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen))
5d93ae8c
MK
89 return 0;
90
91 /* Check for sigreturn(2). */
c822af0c 92 if (memcmp (buf, sigreturn, buflen) == 0)
5d93ae8c
MK
93 return 1;
94
9c8e3411 95 /* If we can't read the instructions at START_PC, return zero. */
c822af0c 96 if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen))
9c8e3411
MK
97 return 0;
98
99 /* Check for sigreturn(2) (again). */
c822af0c 100 if (memcmp (buf, sigreturn, buflen) == 0)
9c8e3411
MK
101 return 1;
102
911bc6ee 103 return 0;
5d93ae8c
MK
104}
105\f
106/* Mapping between the general-purpose registers in `struct reg'
107 format and GDB's register cache layout. */
108
67457012
MK
109/* From <machine/reg.h>. */
110static int i386obsd_r_reg_offset[] =
111{
112 0 * 4, /* %eax */
113 1 * 4, /* %ecx */
114 2 * 4, /* %edx */
115 3 * 4, /* %ebx */
116 4 * 4, /* %esp */
117 5 * 4, /* %ebp */
118 6 * 4, /* %esi */
119 7 * 4, /* %edi */
120 8 * 4, /* %eip */
121 9 * 4, /* %eflags */
122 10 * 4, /* %cs */
123 11 * 4, /* %ss */
124 12 * 4, /* %ds */
125 13 * 4, /* %es */
126 14 * 4, /* %fs */
127 15 * 4 /* %gs */
128};
005328e3
MK
129
130static void
67457012
MK
131i386obsd_aout_supply_regset (const struct regset *regset,
132 struct regcache *regcache, int regnum,
133 const void *regs, size_t len)
005328e3 134{
9ea75c57 135 const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch);
67457012
MK
136
137 gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE);
005328e3 138
67457012
MK
139 i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset);
140 i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset);
005328e3
MK
141}
142
49cfa46f 143static const struct regset *
67457012
MK
144i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch,
145 const char *sect_name,
146 size_t sect_size)
005328e3 147{
67457012 148 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
005328e3 149
67457012
MK
150 /* OpenBSD a.out core dumps don't use seperate register sets for the
151 general-purpose and floating-point registers. */
005328e3 152
67457012
MK
153 if (strcmp (sect_name, ".reg") == 0
154 && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE)
005328e3 155 {
67457012 156 if (tdep->gregset == NULL)
9ea75c57
MK
157 tdep->gregset =
158 regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL);
67457012 159 return tdep->gregset;
005328e3
MK
160 }
161
67457012 162 return NULL;
005328e3 163}
005328e3
MK
164\f
165
5d93ae8c
MK
166/* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
167CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20;
168CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0;
005328e3
MK
169
170/* From <machine/signal.h>. */
a3386186
MK
171int i386obsd_sc_reg_offset[I386_NUM_GREGS] =
172{
173 10 * 4, /* %eax */
174 9 * 4, /* %ecx */
175 8 * 4, /* %edx */
176 7 * 4, /* %ebx */
177 14 * 4, /* %esp */
178 6 * 4, /* %ebp */
179 5 * 4, /* %esi */
180 4 * 4, /* %edi */
181 11 * 4, /* %eip */
182 13 * 4, /* %eflags */
183 12 * 4, /* %cs */
184 15 * 4, /* %ss */
185 3 * 4, /* %ds */
186 2 * 4, /* %es */
187 1 * 4, /* %fs */
188 0 * 4 /* %gs */
189};
005328e3 190
a28109e0
MK
191/* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
192static int i386obsd_uthread_reg_offset[] =
193{
194 11 * 4, /* %eax */
195 10 * 4, /* %ecx */
196 9 * 4, /* %edx */
197 8 * 4, /* %ebx */
198 -1, /* %esp */
199 6 * 4, /* %ebp */
200 5 * 4, /* %esi */
201 4 * 4, /* %edi */
202 12 * 4, /* %eip */
203 -1, /* %eflags */
204 13 * 4, /* %cs */
205 -1, /* %ss */
206 3 * 4, /* %ds */
207 2 * 4, /* %es */
208 1 * 4, /* %fs */
209 0 * 4 /* %gs */
210};
211
212/* Offset within the thread structure where we can find the saved
213 stack pointer (%esp). */
214#define I386OBSD_UTHREAD_ESP_OFFSET 176
215
216static void
217i386obsd_supply_uthread (struct regcache *regcache,
218 int regnum, CORE_ADDR addr)
219{
220 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
221 CORE_ADDR sp = 0;
63c0089f 222 gdb_byte buf[4];
a28109e0
MK
223 int i;
224
225 gdb_assert (regnum >= -1);
226
227 if (regnum == -1 || regnum == I386_ESP_REGNUM)
228 {
229 int offset;
230
231 /* Fetch stack pointer from thread structure. */
232 sp = read_memory_unsigned_integer (sp_addr, 4);
233
234 /* Adjust the stack pointer such that it looks as if we just
235 returned from _thread_machdep_switch. */
236 offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
237 store_unsigned_integer (buf, 4, sp + offset);
238 regcache_raw_supply (regcache, I386_ESP_REGNUM, buf);
239 }
240
241 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
242 {
243 if (i386obsd_uthread_reg_offset[i] != -1
244 && (regnum == -1 || regnum == i))
245 {
246 /* Fetch stack pointer from thread structure (if we didn't
247 do so already). */
248 if (sp == 0)
249 sp = read_memory_unsigned_integer (sp_addr, 4);
250
251 /* Read the saved register from the stack frame. */
252 read_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
253 regcache_raw_supply (regcache, i, buf);
254 }
255 }
256
257}
258
259static void
260i386obsd_collect_uthread (const struct regcache *regcache,
261 int regnum, CORE_ADDR addr)
262{
263 CORE_ADDR sp_addr = addr + I386OBSD_UTHREAD_ESP_OFFSET;
264 CORE_ADDR sp = 0;
63c0089f 265 gdb_byte buf[4];
a28109e0
MK
266 int i;
267
268 gdb_assert (regnum >= -1);
269
270 if (regnum == -1 || regnum == I386_ESP_REGNUM)
271 {
272 int offset;
273
274 /* Calculate the stack pointer (frame pointer) that will be
275 stored into the thread structure. */
276 offset = i386obsd_uthread_reg_offset[I386_EIP_REGNUM] + 4;
277 regcache_raw_collect (regcache, I386_ESP_REGNUM, buf);
278 sp = extract_unsigned_integer (buf, 4) - offset;
279
280 /* Store the stack pointer. */
281 write_memory_unsigned_integer (sp_addr, 4, sp);
282
283 /* The stack pointer was (potentially) modified. Make sure we
284 build a proper stack frame. */
285 regnum = -1;
286 }
287
288 for (i = 0; i < ARRAY_SIZE (i386obsd_uthread_reg_offset); i++)
289 {
290 if (i386obsd_uthread_reg_offset[i] != -1
291 && (regnum == -1 || regnum == i))
292 {
293 /* Fetch stack pointer from thread structure (if we didn't
294 calculate it already). */
295 if (sp == 0)
296 sp = read_memory_unsigned_integer (sp_addr, 4);
297
298 /* Write the register into the stack frame. */
299 regcache_raw_collect (regcache, i, buf);
300 write_memory (sp + i386obsd_uthread_reg_offset[i], buf, 4);
301 }
302 }
303}
304
005328e3
MK
305static void
306i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
307{
308 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
309
310 /* Obviously OpenBSD is BSD-based. */
311 i386bsd_init_abi (info, gdbarch);
312
67457012
MK
313 /* OpenBSD has a different `struct reg'. */
314 tdep->gregset_reg_offset = i386obsd_r_reg_offset;
315 tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset);
316 tdep->sizeof_gregset = 16 * 4;
317
005328e3
MK
318 /* OpenBSD uses -freg-struct-return by default. */
319 tdep->struct_return = reg_struct_return;
320
321 /* OpenBSD uses a different memory layout. */
5d93ae8c
MK
322 tdep->sigtramp_start = i386obsd_sigtramp_start_addr;
323 tdep->sigtramp_end = i386obsd_sigtramp_end_addr;
911bc6ee 324 tdep->sigtramp_p = i386obsd_sigtramp_p;
005328e3
MK
325
326 /* OpenBSD has a `struct sigcontext' that's different from the
f2e7c15d 327 original 4.3 BSD. */
a3386186 328 tdep->sc_reg_offset = i386obsd_sc_reg_offset;
67457012 329 tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset);
a28109e0
MK
330
331 /* OpenBSD provides a user-level threads implementation. */
332 bsd_uthread_set_supply_uthread (gdbarch, i386obsd_supply_uthread);
333 bsd_uthread_set_collect_uthread (gdbarch, i386obsd_collect_uthread);
005328e3 334}
60a6eeb6
MK
335
336/* OpenBSD a.out. */
337
338static void
339i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
340{
341 i386obsd_init_abi (info, gdbarch);
342
343 /* OpenBSD a.out has a single register set. */
344 set_gdbarch_regset_from_core_section
345 (gdbarch, i386obsd_aout_regset_from_core_section);
346}
347
348/* OpenBSD ELF. */
349
350static void
351i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
352{
353 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
354
355 /* It's still OpenBSD. */
356 i386obsd_init_abi (info, gdbarch);
357
358 /* But ELF-based. */
359 i386_elf_init_abi (info, gdbarch);
360
361 /* OpenBSD ELF uses SVR4-style shared libraries. */
60a6eeb6
MK
362 set_solib_svr4_fetch_link_map_offsets
363 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
364}
67457012
MK
365\f
366
367/* Provide a prototype to silence -Wmissing-prototypes. */
368void _initialize_i386obsd_tdep (void);
005328e3
MK
369
370void
371_initialize_i386obsd_tdep (void)
372{
005328e3
MK
373 /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
374 indistingushable from NetBSD/i386 a.out binaries, building a GDB
375 that should support both these targets will probably not work as
376 expected. */
377#define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
378
05816f70 379 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT,
60a6eeb6
MK
380 i386obsd_aout_init_abi);
381 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF,
382 i386obsd_elf_init_abi);
005328e3 383}
This page took 0.36347 seconds and 4 git commands to generate.