1 /* Target-dependent code for OpenBSD/i386.
3 Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002,
5 Free Software Foundation, Inc.
7 This file is part of GDB.
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.
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.
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. */
25 #include "arch-utils.h"
35 #include "gdb_assert.h"
36 #include "gdb_string.h"
38 #include "i386-tdep.h"
39 #include "i387-tdep.h"
40 #include "solib-svr4.h"
41 #include "bsd-uthread.h"
43 /* Support for signal handlers. */
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
52 /* Default page size. */
53 static const int i386obsd_page_size
= 4096;
55 /* Return whether the frame preceding NEXT_FRAME corresponds to an
56 OpenBSD sigtramp routine. */
59 i386obsd_sigtramp_p (struct frame_info
*next_frame
)
61 CORE_ADDR pc
= frame_pc_unwind (next_frame
);
62 CORE_ADDR start_pc
= (pc
& ~(i386obsd_page_size
- 1));
63 const gdb_byte sigreturn
[] =
66 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
67 0xcd, 0x80 /* int $0x80 */
69 size_t buflen
= sizeof sigreturn
;
73 /* If the function has a valid symbol name, it isn't a
75 find_pc_partial_function (pc
, &name
, NULL
, NULL
);
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
)
84 /* Allocate buffer. */
85 buf
= alloca (buflen
);
87 /* If we can't read the instructions at START_PC, return zero. */
88 if (!safe_frame_unwind_memory (next_frame
, start_pc
+ 0x0a, buf
, buflen
))
91 /* Check for sigreturn(2). */
92 if (memcmp (buf
, sigreturn
, buflen
) == 0)
95 /* If we can't read the instructions at START_PC, return zero. */
96 if (!safe_frame_unwind_memory (next_frame
, start_pc
+ 0x14, buf
, buflen
))
99 /* Check for sigreturn(2) (again). */
100 if (memcmp (buf
, sigreturn
, buflen
) == 0)
106 /* Mapping between the general-purpose registers in `struct reg'
107 format and GDB's register cache layout. */
109 /* From <machine/reg.h>. */
110 static int i386obsd_r_reg_offset
[] =
131 i386obsd_aout_supply_regset (const struct regset
*regset
,
132 struct regcache
*regcache
, int regnum
,
133 const void *regs
, size_t len
)
135 const struct gdbarch_tdep
*tdep
= gdbarch_tdep (regset
->arch
);
137 gdb_assert (len
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
);
139 i386_supply_gregset (regset
, regcache
, regnum
, regs
, tdep
->sizeof_gregset
);
140 i387_supply_fsave (regcache
, regnum
, (char *) regs
+ tdep
->sizeof_gregset
);
143 static const struct regset
*
144 i386obsd_aout_regset_from_core_section (struct gdbarch
*gdbarch
,
145 const char *sect_name
,
148 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
150 /* OpenBSD a.out core dumps don't use seperate register sets for the
151 general-purpose and floating-point registers. */
153 if (strcmp (sect_name
, ".reg") == 0
154 && sect_size
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
)
156 if (tdep
->gregset
== NULL
)
158 regset_alloc (gdbarch
, i386obsd_aout_supply_regset
, NULL
);
159 return tdep
->gregset
;
166 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
167 CORE_ADDR i386obsd_sigtramp_start_addr
= 0xbfbfdf20;
168 CORE_ADDR i386obsd_sigtramp_end_addr
= 0xbfbfdff0;
170 /* From <machine/signal.h>. */
171 int i386obsd_sc_reg_offset
[I386_NUM_GREGS
] =
182 13 * 4, /* %eflags */
191 /* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
192 static int i386obsd_uthread_reg_offset
[] =
212 /* Offset within the thread structure where we can find the saved
213 stack pointer (%esp). */
214 #define I386OBSD_UTHREAD_ESP_OFFSET 176
217 i386obsd_supply_uthread (struct regcache
*regcache
,
218 int regnum
, CORE_ADDR addr
)
220 CORE_ADDR sp_addr
= addr
+ I386OBSD_UTHREAD_ESP_OFFSET
;
225 gdb_assert (regnum
>= -1);
227 if (regnum
== -1 || regnum
== I386_ESP_REGNUM
)
231 /* Fetch stack pointer from thread structure. */
232 sp
= read_memory_unsigned_integer (sp_addr
, 4);
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
);
241 for (i
= 0; i
< ARRAY_SIZE (i386obsd_uthread_reg_offset
); i
++)
243 if (i386obsd_uthread_reg_offset
[i
] != -1
244 && (regnum
== -1 || regnum
== i
))
246 /* Fetch stack pointer from thread structure (if we didn't
249 sp
= read_memory_unsigned_integer (sp_addr
, 4);
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
);
260 i386obsd_collect_uthread (const struct regcache
*regcache
,
261 int regnum
, CORE_ADDR addr
)
263 CORE_ADDR sp_addr
= addr
+ I386OBSD_UTHREAD_ESP_OFFSET
;
268 gdb_assert (regnum
>= -1);
270 if (regnum
== -1 || regnum
== I386_ESP_REGNUM
)
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
;
280 /* Store the stack pointer. */
281 write_memory_unsigned_integer (sp_addr
, 4, sp
);
283 /* The stack pointer was (potentially) modified. Make sure we
284 build a proper stack frame. */
288 for (i
= 0; i
< ARRAY_SIZE (i386obsd_uthread_reg_offset
); i
++)
290 if (i386obsd_uthread_reg_offset
[i
] != -1
291 && (regnum
== -1 || regnum
== i
))
293 /* Fetch stack pointer from thread structure (if we didn't
294 calculate it already). */
296 sp
= read_memory_unsigned_integer (sp_addr
, 4);
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);
306 i386obsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
308 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
310 /* Obviously OpenBSD is BSD-based. */
311 i386bsd_init_abi (info
, gdbarch
);
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;
318 /* OpenBSD uses -freg-struct-return by default. */
319 tdep
->struct_return
= reg_struct_return
;
321 /* OpenBSD uses a different memory layout. */
322 tdep
->sigtramp_start
= i386obsd_sigtramp_start_addr
;
323 tdep
->sigtramp_end
= i386obsd_sigtramp_end_addr
;
324 tdep
->sigtramp_p
= i386obsd_sigtramp_p
;
326 /* OpenBSD has a `struct sigcontext' that's different from the
328 tdep
->sc_reg_offset
= i386obsd_sc_reg_offset
;
329 tdep
->sc_num_regs
= ARRAY_SIZE (i386obsd_sc_reg_offset
);
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
);
339 i386obsd_aout_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
341 i386obsd_init_abi (info
, gdbarch
);
343 /* OpenBSD a.out has a single register set. */
344 set_gdbarch_regset_from_core_section
345 (gdbarch
, i386obsd_aout_regset_from_core_section
);
351 i386obsd_elf_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
353 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
355 /* It's still OpenBSD. */
356 i386obsd_init_abi (info
, gdbarch
);
359 i386_elf_init_abi (info
, gdbarch
);
361 /* OpenBSD ELF uses SVR4-style shared libraries. */
362 set_solib_svr4_fetch_link_map_offsets
363 (gdbarch
, svr4_ilp32_fetch_link_map_offsets
);
367 /* Provide a prototype to silence -Wmissing-prototypes. */
368 void _initialize_i386obsd_tdep (void);
371 _initialize_i386obsd_tdep (void)
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
377 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
379 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_OPENBSD_AOUT
,
380 i386obsd_aout_init_abi
);
381 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_OPENBSD_ELF
,
382 i386obsd_elf_init_abi
);