X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fi386obsd-tdep.c;h=9ef868d6ec45a9ce48fa195800a1792ecdced2af;hb=c5fa424560dd1098617ee6df456a7d4b4fb5f9f1;hp=8bbce84fb29f0f4fefabf96873eb62e7bd004cb3;hpb=05816f706ec4cb2e789828fa8edb8ea30593933b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386obsd-tdep.c b/gdb/i386obsd-tdep.c index 8bbce84fb2..9ef868d6ec 100644 --- a/gdb/i386obsd-tdep.c +++ b/gdb/i386obsd-tdep.c @@ -1,5 +1,7 @@ /* Target-dependent code for OpenBSD/i386. - Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002 + + Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002, + 2003, 2004 Free Software Foundation, Inc. This file is part of GDB. @@ -21,69 +23,168 @@ #include "defs.h" #include "arch-utils.h" +#include "frame.h" #include "gdbcore.h" #include "regcache.h" +#include "regset.h" +#include "symtab.h" +#include "objfiles.h" +#include "osabi.h" +#include "target.h" + +#include "gdb_assert.h" +#include "gdb_string.h" #include "i386-tdep.h" #include "i387-tdep.h" +#include "solib-svr4.h" -/* Provide a prototype to silence -Wmissing-prototypes. */ -void _initialize_i386obsd_tdep (void); +/* Support for signal handlers. */ -#define SIZEOF_STRUCT_REG (16 * 4) +/* Since OpenBSD 3.2, the sigtramp routine is mapped at a random page + in virtual memory. The randomness makes it somewhat tricky to + detect it, but fortunately we can rely on the fact that the start + of the sigtramp routine is page-aligned. By the way, the mapping + is read-only, so you cannot place a breakpoint in the signal + trampoline. */ -static void -i386obsd_supply_reg (char *regs, int regno) -{ - int i; +/* Default page size. */ +static const int i386obsd_page_size = 4096; - for (i = 0; i <= 15; i++) - if (regno == i || regno == -1) - supply_register (i, regs + i * 4); -} +/* Return whether the frame preceding NEXT_FRAME corresponds to an + OpenBSD sigtramp routine. */ -static void -fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, int which, - CORE_ADDR ignore) +static int +i386obsd_sigtramp_p (struct frame_info *next_frame) { - char *regs, *fsave; + CORE_ADDR pc = frame_pc_unwind (next_frame); + CORE_ADDR start_pc = (pc & ~(i386obsd_page_size - 1)); + const char sigreturn[] = + { + 0xb8, + 0x67, 0x00, 0x00, 0x00, /* movl $SYS_sigreturn, %eax */ + 0xcd, 0x80 /* int $0x80 */ + }; + size_t buflen = sizeof sigreturn; + char *name, *buf; - /* We get everything from one section. */ - if (which != 0) - return; + /* If the function has a valid symbol name, it isn't a + trampoline. */ + find_pc_partial_function (pc, &name, NULL, NULL); + if (name != NULL) + return 0; - if (core_reg_size < (SIZEOF_STRUCT_REG + 108)) - { - warning ("Wrong size register set in core file."); - return; - } + /* If the function lives in a valid section (even without a starting + point) it isn't a trampoline. */ + if (find_pc_section (pc) != NULL) + return 0; + + /* Allocate buffer. */ + buf = alloca (buflen); + + /* If we can't read the instructions at START_PC, return zero. */ + if (!safe_frame_unwind_memory (next_frame, start_pc + 0x0a, buf, buflen)) + return 0; + + /* Check for sigreturn(2). */ + if (memcmp (buf, sigreturn, buflen) == 0) + return 1; - regs = core_reg_sect; - fsave = core_reg_sect + SIZEOF_STRUCT_REG; + /* If we can't read the instructions at START_PC, return zero. */ + if (!safe_frame_unwind_memory (next_frame, start_pc + 0x14, buf, buflen)) + return 0; - /* Integer registers. */ - i386obsd_supply_reg (regs, -1); + /* Check for sigreturn(2) (again). */ + if (memcmp (buf, sigreturn, buflen) == 0) + return 1; - /* Floating point registers. */ - i387_supply_fsave (fsave); + return 0; } + +/* Mapping between the general-purpose registers in `struct reg' + format and GDB's register cache layout. */ -static struct core_fns i386obsd_core_fns = +/* From . */ +static int i386obsd_r_reg_offset[] = { - bfd_target_unknown_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_core_registers, /* core_read_registers */ - NULL /* next */ + 0 * 4, /* %eax */ + 1 * 4, /* %ecx */ + 2 * 4, /* %edx */ + 3 * 4, /* %ebx */ + 4 * 4, /* %esp */ + 5 * 4, /* %ebp */ + 6 * 4, /* %esi */ + 7 * 4, /* %edi */ + 8 * 4, /* %eip */ + 9 * 4, /* %eflags */ + 10 * 4, /* %cs */ + 11 * 4, /* %ss */ + 12 * 4, /* %ds */ + 13 * 4, /* %es */ + 14 * 4, /* %fs */ + 15 * 4 /* %gs */ }; + +static void +i386obsd_aout_supply_regset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *regs, size_t len) +{ + const struct gdbarch_tdep *tdep = gdbarch_tdep (regset->arch); + + gdb_assert (len >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE); + + i386_supply_gregset (regset, regcache, regnum, regs, tdep->sizeof_gregset); + i387_supply_fsave (regcache, regnum, (char *) regs + tdep->sizeof_gregset); +} + +static const struct regset * +i386obsd_aout_regset_from_core_section (struct gdbarch *gdbarch, + const char *sect_name, + size_t sect_size) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* OpenBSD a.out core dumps don't use seperate register sets for the + general-purpose and floating-point registers. */ + + if (strcmp (sect_name, ".reg") == 0 + && sect_size >= tdep->sizeof_gregset + I387_SIZEOF_FSAVE) + { + if (tdep->gregset == NULL) + tdep->gregset = + regset_alloc (gdbarch, i386obsd_aout_supply_regset, NULL); + return tdep->gregset; + } + + return NULL; +} -CORE_ADDR i386obsd_sigtramp_start = 0xbfbfdf20; -CORE_ADDR i386obsd_sigtramp_end = 0xbfbfdff0; +/* Sigtramp routine location for OpenBSD 3.1 and earlier releases. */ +CORE_ADDR i386obsd_sigtramp_start_addr = 0xbfbfdf20; +CORE_ADDR i386obsd_sigtramp_end_addr = 0xbfbfdff0; /* From . */ -int i386obsd_sc_pc_offset = 44; -int i386obsd_sc_sp_offset = 56; +int i386obsd_sc_reg_offset[I386_NUM_GREGS] = +{ + 10 * 4, /* %eax */ + 9 * 4, /* %ecx */ + 8 * 4, /* %edx */ + 7 * 4, /* %ebx */ + 14 * 4, /* %esp */ + 6 * 4, /* %ebp */ + 5 * 4, /* %esi */ + 4 * 4, /* %edi */ + 11 * 4, /* %eip */ + 13 * 4, /* %eflags */ + 12 * 4, /* %cs */ + 15 * 4, /* %ss */ + 3 * 4, /* %ds */ + 2 * 4, /* %es */ + 1 * 4, /* %fs */ + 0 * 4 /* %gs */ +}; static void i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) @@ -93,24 +194,64 @@ i386obsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* Obviously OpenBSD is BSD-based. */ i386bsd_init_abi (info, gdbarch); + /* OpenBSD has a different `struct reg'. */ + tdep->gregset_reg_offset = i386obsd_r_reg_offset; + tdep->gregset_num_regs = ARRAY_SIZE (i386obsd_r_reg_offset); + tdep->sizeof_gregset = 16 * 4; + /* OpenBSD uses -freg-struct-return by default. */ tdep->struct_return = reg_struct_return; /* OpenBSD uses a different memory layout. */ - tdep->sigtramp_start = i386obsd_sigtramp_start; - tdep->sigtramp_end = i386obsd_sigtramp_end; + tdep->sigtramp_start = i386obsd_sigtramp_start_addr; + tdep->sigtramp_end = i386obsd_sigtramp_end_addr; + tdep->sigtramp_p = i386obsd_sigtramp_p; /* OpenBSD has a `struct sigcontext' that's different from the - origional 4.3 BSD. */ - tdep->sc_pc_offset = i386obsd_sc_pc_offset; - tdep->sc_sp_offset = i386obsd_sc_sp_offset; + original 4.3 BSD. */ + tdep->sc_reg_offset = i386obsd_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (i386obsd_sc_reg_offset); +} + +/* OpenBSD a.out. */ + +static void +i386obsd_aout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + i386obsd_init_abi (info, gdbarch); + + /* OpenBSD a.out has a single register set. */ + set_gdbarch_regset_from_core_section + (gdbarch, i386obsd_aout_regset_from_core_section); +} + +/* OpenBSD ELF. */ + +static void +i386obsd_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + /* It's still OpenBSD. */ + i386obsd_init_abi (info, gdbarch); + + /* But ELF-based. */ + i386_elf_init_abi (info, gdbarch); + + /* OpenBSD ELF uses SVR4-style shared libraries. */ + set_gdbarch_in_solib_call_trampoline + (gdbarch, generic_in_solib_call_trampoline); + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); } + + +/* Provide a prototype to silence -Wmissing-prototypes. */ +void _initialize_i386obsd_tdep (void); void _initialize_i386obsd_tdep (void) { - add_core_fns (&i386obsd_core_fns); - /* FIXME: kettenis/20021020: Since OpenBSD/i386 binaries are indistingushable from NetBSD/i386 a.out binaries, building a GDB that should support both these targets will probably not work as @@ -118,5 +259,7 @@ _initialize_i386obsd_tdep (void) #define GDB_OSABI_OPENBSD_AOUT GDB_OSABI_NETBSD_AOUT gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_AOUT, - i386obsd_init_abi); + i386obsd_aout_init_abi); + gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_OPENBSD_ELF, + i386obsd_elf_init_abi); }