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 char sigreturn
[] =
66 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */
67 0xcd, 0x80 /* int $0x80 */
69 size_t buflen
= sizeof sigreturn
;
72 /* If the function has a valid symbol name, it isn't a
74 find_pc_partial_function (pc
, &name
, NULL
, NULL
);
78 /* If the function lives in a valid section (even without a starting
79 point) it isn't a trampoline. */
80 if (find_pc_section (pc
) != NULL
)
83 /* Allocate buffer. */
84 buf
= alloca (buflen
);
86 /* If we can't read the instructions at START_PC, return zero. */
87 if (!safe_frame_unwind_memory (next_frame
, start_pc
+ 0x0a, buf
, buflen
))
90 /* Check for sigreturn(2). */
91 if (memcmp (buf
, sigreturn
, buflen
) == 0)
94 /* If we can't read the instructions at START_PC, return zero. */
95 if (!safe_frame_unwind_memory (next_frame
, start_pc
+ 0x14, buf
, buflen
))
98 /* Check for sigreturn(2) (again). */
99 if (memcmp (buf
, sigreturn
, buflen
) == 0)
105 /* Mapping between the general-purpose registers in `struct reg'
106 format and GDB's register cache layout. */
108 /* From <machine/reg.h>. */
109 static int i386obsd_r_reg_offset
[] =
130 i386obsd_aout_supply_regset (const struct regset
*regset
,
131 struct regcache
*regcache
, int regnum
,
132 const void *regs
, size_t len
)
134 const struct gdbarch_tdep
*tdep
= gdbarch_tdep (regset
->arch
);
136 gdb_assert (len
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
);
138 i386_supply_gregset (regset
, regcache
, regnum
, regs
, tdep
->sizeof_gregset
);
139 i387_supply_fsave (regcache
, regnum
, (char *) regs
+ tdep
->sizeof_gregset
);
142 static const struct regset
*
143 i386obsd_aout_regset_from_core_section (struct gdbarch
*gdbarch
,
144 const char *sect_name
,
147 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
149 /* OpenBSD a.out core dumps don't use seperate register sets for the
150 general-purpose and floating-point registers. */
152 if (strcmp (sect_name
, ".reg") == 0
153 && sect_size
>= tdep
->sizeof_gregset
+ I387_SIZEOF_FSAVE
)
155 if (tdep
->gregset
== NULL
)
157 regset_alloc (gdbarch
, i386obsd_aout_supply_regset
, NULL
);
158 return tdep
->gregset
;
165 /* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */
166 CORE_ADDR i386obsd_sigtramp_start_addr
= 0xbfbfdf20;
167 CORE_ADDR i386obsd_sigtramp_end_addr
= 0xbfbfdff0;
169 /* From <machine/signal.h>. */
170 int i386obsd_sc_reg_offset
[I386_NUM_GREGS
] =
181 13 * 4, /* %eflags */
190 /* From /usr/src/lib/libpthread/arch/i386/uthread_machdep.c. */
191 static int i386obsd_uthread_reg_offset
[] =
211 /* Offset within the thread structure where we can find the saved
212 stack pointer (%esp). */
213 #define I386OBSD_UTHREAD_ESP_OFFSET 176
216 i386obsd_supply_uthread (struct regcache
*regcache
,
217 int regnum
, CORE_ADDR addr
)
219 CORE_ADDR sp_addr
= addr
+ I386OBSD_UTHREAD_ESP_OFFSET
;
224 gdb_assert (regnum
>= -1);
226 if (regnum
== -1 || regnum
== I386_ESP_REGNUM
)
230 /* Fetch stack pointer from thread structure. */
231 sp
= read_memory_unsigned_integer (sp_addr
, 4);
233 /* Adjust the stack pointer such that it looks as if we just
234 returned from _thread_machdep_switch. */
235 offset
= i386obsd_uthread_reg_offset
[I386_EIP_REGNUM
] + 4;
236 store_unsigned_integer (buf
, 4, sp
+ offset
);
237 regcache_raw_supply (regcache
, I386_ESP_REGNUM
, buf
);
240 for (i
= 0; i
< ARRAY_SIZE (i386obsd_uthread_reg_offset
); i
++)
242 if (i386obsd_uthread_reg_offset
[i
] != -1
243 && (regnum
== -1 || regnum
== i
))
245 /* Fetch stack pointer from thread structure (if we didn't
248 sp
= read_memory_unsigned_integer (sp_addr
, 4);
250 /* Read the saved register from the stack frame. */
251 read_memory (sp
+ i386obsd_uthread_reg_offset
[i
], buf
, 4);
252 regcache_raw_supply (regcache
, i
, buf
);
259 i386obsd_collect_uthread (const struct regcache
*regcache
,
260 int regnum
, CORE_ADDR addr
)
262 CORE_ADDR sp_addr
= addr
+ I386OBSD_UTHREAD_ESP_OFFSET
;
267 gdb_assert (regnum
>= -1);
269 if (regnum
== -1 || regnum
== I386_ESP_REGNUM
)
273 /* Calculate the stack pointer (frame pointer) that will be
274 stored into the thread structure. */
275 offset
= i386obsd_uthread_reg_offset
[I386_EIP_REGNUM
] + 4;
276 regcache_raw_collect (regcache
, I386_ESP_REGNUM
, buf
);
277 sp
= extract_unsigned_integer (buf
, 4) - offset
;
279 /* Store the stack pointer. */
280 write_memory_unsigned_integer (sp_addr
, 4, sp
);
282 /* The stack pointer was (potentially) modified. Make sure we
283 build a proper stack frame. */
287 for (i
= 0; i
< ARRAY_SIZE (i386obsd_uthread_reg_offset
); i
++)
289 if (i386obsd_uthread_reg_offset
[i
] != -1
290 && (regnum
== -1 || regnum
== i
))
292 /* Fetch stack pointer from thread structure (if we didn't
293 calculate it already). */
295 sp
= read_memory_unsigned_integer (sp_addr
, 4);
297 /* Write the register into the stack frame. */
298 regcache_raw_collect (regcache
, i
, buf
);
299 write_memory (sp
+ i386obsd_uthread_reg_offset
[i
], buf
, 4);
305 i386obsd_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
307 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
309 /* Obviously OpenBSD is BSD-based. */
310 i386bsd_init_abi (info
, gdbarch
);
312 /* OpenBSD has a different `struct reg'. */
313 tdep
->gregset_reg_offset
= i386obsd_r_reg_offset
;
314 tdep
->gregset_num_regs
= ARRAY_SIZE (i386obsd_r_reg_offset
);
315 tdep
->sizeof_gregset
= 16 * 4;
317 /* OpenBSD uses -freg-struct-return by default. */
318 tdep
->struct_return
= reg_struct_return
;
320 /* OpenBSD uses a different memory layout. */
321 tdep
->sigtramp_start
= i386obsd_sigtramp_start_addr
;
322 tdep
->sigtramp_end
= i386obsd_sigtramp_end_addr
;
323 tdep
->sigtramp_p
= i386obsd_sigtramp_p
;
325 /* OpenBSD has a `struct sigcontext' that's different from the
327 tdep
->sc_reg_offset
= i386obsd_sc_reg_offset
;
328 tdep
->sc_num_regs
= ARRAY_SIZE (i386obsd_sc_reg_offset
);
330 /* OpenBSD provides a user-level threads implementation. */
331 bsd_uthread_set_supply_uthread (gdbarch
, i386obsd_supply_uthread
);
332 bsd_uthread_set_collect_uthread (gdbarch
, i386obsd_collect_uthread
);
338 i386obsd_aout_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
340 i386obsd_init_abi (info
, gdbarch
);
342 /* OpenBSD a.out has a single register set. */
343 set_gdbarch_regset_from_core_section
344 (gdbarch
, i386obsd_aout_regset_from_core_section
);
350 i386obsd_elf_init_abi (struct gdbarch_info info
, struct gdbarch
*gdbarch
)
352 struct gdbarch_tdep
*tdep
= gdbarch_tdep (gdbarch
);
354 /* It's still OpenBSD. */
355 i386obsd_init_abi (info
, gdbarch
);
358 i386_elf_init_abi (info
, gdbarch
);
360 /* OpenBSD ELF uses SVR4-style shared libraries. */
361 set_solib_svr4_fetch_link_map_offsets
362 (gdbarch
, svr4_ilp32_fetch_link_map_offsets
);
366 /* Provide a prototype to silence -Wmissing-prototypes. */
367 void _initialize_i386obsd_tdep (void);
370 _initialize_i386obsd_tdep (void)
372 /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are
373 indistingushable from NetBSD/i386 a.out binaries, building a GDB
374 that should support both these targets will probably not work as
376 #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT
378 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_OPENBSD_AOUT
,
379 i386obsd_aout_init_abi
);
380 gdbarch_register_osabi (bfd_arch_i386
, 0, GDB_OSABI_OPENBSD_ELF
,
381 i386obsd_elf_init_abi
);