X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fi386fbsd-tdep.c;h=fbff37c715d659511e56e4db304a754b597f3626;hb=9885948fc910a77d04f27a7683f5edd0989d818a;hp=b247b797e3717d5c7f640c0c2b2247e4ecbbe00b;hpb=abfcdd21a5402a3596c9ebc1d8c0c9b997544d84;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386fbsd-tdep.c b/gdb/i386fbsd-tdep.c index b247b797e3..fbff37c715 100644 --- a/gdb/i386fbsd-tdep.c +++ b/gdb/i386fbsd-tdep.c @@ -1,12 +1,12 @@ /* Target-dependent code for FreeBSD/i386. - Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003-2016 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,23 +15,177 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "arch-utils.h" #include "gdbcore.h" #include "osabi.h" #include "regcache.h" - -#include "gdb_assert.h" +#include "regset.h" +#include "i386fbsd-tdep.h" +#include "x86-xstate.h" #include "i386-tdep.h" #include "i387-tdep.h" #include "bsd-uthread.h" +#include "fbsd-tdep.h" #include "solib-svr4.h" +/* Support for signal handlers. */ + +/* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp + routine. */ + +/* FreeBSD/i386 supports three different signal trampolines, one for + versions before 4.0, a second for 4.x, and a third for 5.0 and + later. To complicate matters, FreeBSD/i386 binaries running under + an amd64 kernel use a different set of trampolines. These + trampolines differ from the i386 kernel trampolines in that they + omit a middle section that conditionally restores %gs. */ + +static const gdb_byte i386fbsd_sigtramp_start[] = +{ + 0x8d, 0x44, 0x24, 0x20, /* lea SIGF_UC(%esp),%eax */ + 0x50 /* pushl %eax */ +}; + +static const gdb_byte i386fbsd_sigtramp_middle[] = +{ + 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00, + /* testl $PSL_VM,UC_EFLAGS(%eax) */ + 0x75, 0x03, /* jne +3 */ + 0x8e, 0x68, 0x14 /* mov UC_GS(%eax),%gs */ +}; + +static const gdb_byte i386fbsd_sigtramp_end[] = +{ + 0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl $SYS_sigreturn,%eax */ + 0x50, /* pushl %eax */ + 0xcd, 0x80 /* int $0x80 */ +}; + +static const gdb_byte i386fbsd_freebsd4_sigtramp_start[] = +{ + 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_UC4(%esp),%eax */ + 0x50 /* pushl %eax */ +}; + +static const gdb_byte i386fbsd_freebsd4_sigtramp_middle[] = +{ + 0xf7, 0x40, 0x54, 0x00, 0x00, 0x02, 0x00, + /* testl $PSL_VM,UC4_EFLAGS(%eax) */ + 0x75, 0x03, /* jne +3 */ + 0x8e, 0x68, 0x14 /* mov UC4_GS(%eax),%gs */ +}; + +static const gdb_byte i386fbsd_freebsd4_sigtramp_end[] = +{ + 0xb8, 0x58, 0x01, 0x00, 0x00, /* movl $344,%eax */ + 0x50, /* pushl %eax */ + 0xcd, 0x80 /* int $0x80 */ +}; + +static const gdb_byte i386fbsd_osigtramp_start[] = +{ + 0x8d, 0x44, 0x24, 0x14, /* lea SIGF_SC(%esp),%eax */ + 0x50 /* pushl %eax */ +}; + +static const gdb_byte i386fbsd_osigtramp_middle[] = +{ + 0xf7, 0x40, 0x18, 0x00, 0x00, 0x02, 0x00, + /* testl $PSL_VM,SC_PS(%eax) */ + 0x75, 0x03, /* jne +3 */ + 0x8e, 0x68, 0x44 /* mov SC_GS(%eax),%gs */ +}; + +static const gdb_byte i386fbsd_osigtramp_end[] = +{ + 0xb8, 0x67, 0x00, 0x00, 0x00, /* movl $103,%eax */ + 0x50, /* pushl %eax */ + 0xcd, 0x80 /* int $0x80 */ +}; + +/* The three different trampolines are all the same size. */ +gdb_static_assert (sizeof i386fbsd_sigtramp_start + == sizeof i386fbsd_freebsd4_sigtramp_start); +gdb_static_assert (sizeof i386fbsd_sigtramp_start + == sizeof i386fbsd_osigtramp_start); +gdb_static_assert (sizeof i386fbsd_sigtramp_middle + == sizeof i386fbsd_freebsd4_sigtramp_middle); +gdb_static_assert (sizeof i386fbsd_sigtramp_middle + == sizeof i386fbsd_osigtramp_middle); +gdb_static_assert (sizeof i386fbsd_sigtramp_end + == sizeof i386fbsd_freebsd4_sigtramp_end); +gdb_static_assert (sizeof i386fbsd_sigtramp_end + == sizeof i386fbsd_osigtramp_end); + +/* We assume that the middle is the largest chunk below. */ +gdb_static_assert (sizeof i386fbsd_sigtramp_middle + > sizeof i386fbsd_sigtramp_start); +gdb_static_assert (sizeof i386fbsd_sigtramp_middle + > sizeof i386fbsd_sigtramp_end); + +static int +i386fbsd_sigtramp_p (struct frame_info *this_frame) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + gdb_byte buf[sizeof i386fbsd_sigtramp_middle]; + const gdb_byte *middle, *end; + + /* Look for a matching start. */ + if (!safe_frame_unwind_memory (this_frame, pc, buf, + sizeof i386fbsd_sigtramp_start)) + return 0; + if (memcmp (buf, i386fbsd_sigtramp_start, sizeof i386fbsd_sigtramp_start) + == 0) + { + middle = i386fbsd_sigtramp_middle; + end = i386fbsd_sigtramp_end; + } + else if (memcmp (buf, i386fbsd_freebsd4_sigtramp_start, + sizeof i386fbsd_freebsd4_sigtramp_start) == 0) + { + middle = i386fbsd_freebsd4_sigtramp_middle; + end = i386fbsd_freebsd4_sigtramp_end; + } + else if (memcmp (buf, i386fbsd_osigtramp_start, + sizeof i386fbsd_osigtramp_start) == 0) + { + middle = i386fbsd_osigtramp_middle; + end = i386fbsd_osigtramp_end; + } + else + return 0; + + /* Since the end is shorter than the middle, check for a matching end + next. */ + pc += sizeof i386fbsd_sigtramp_start; + if (!safe_frame_unwind_memory (this_frame, pc, buf, + sizeof i386fbsd_sigtramp_end)) + return 0; + if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) == 0) + return 1; + + /* If the end didn't match, check for a matching middle. */ + if (!safe_frame_unwind_memory (this_frame, pc, buf, + sizeof i386fbsd_sigtramp_middle)) + return 0; + if (memcmp (buf, middle, sizeof i386fbsd_sigtramp_middle) != 0) + return 0; + + /* The middle matched, check for a matching end. */ + pc += sizeof i386fbsd_sigtramp_middle; + if (!safe_frame_unwind_memory (this_frame, pc, buf, + sizeof i386fbsd_sigtramp_end)) + return 0; + if (memcmp (buf, end, sizeof i386fbsd_sigtramp_end) != 0) + return 0; + + return 1; +} + /* FreeBSD 3.0-RELEASE or later. */ /* From . */ @@ -46,8 +200,8 @@ static int i386fbsd_r_reg_offset[] = }; /* Sigtramp routine location. */ -CORE_ADDR i386fbsd_sigtramp_start_addr = 0xbfbfdf20; -CORE_ADDR i386fbsd_sigtramp_end_addr = 0xbfbfdff0; +CORE_ADDR i386fbsd_sigtramp_start_addr; +CORE_ADDR i386fbsd_sigtramp_end_addr; /* From . */ int i386fbsd_sc_reg_offset[] = @@ -84,11 +238,105 @@ static int i386fbsd_jmp_buf_reg_offset[] = 0 * 4 /* %eip */ }; +/* Get XSAVE extended state xcr0 from core dump. */ + +uint64_t +i386fbsd_core_read_xcr0 (bfd *abfd) +{ + asection *xstate = bfd_get_section_by_name (abfd, ".reg-xstate"); + uint64_t xcr0; + + if (xstate) + { + size_t size = bfd_section_size (abfd, xstate); + + /* Check extended state size. */ + if (size < X86_XSTATE_AVX_SIZE) + xcr0 = X86_XSTATE_SSE_MASK; + else + { + char contents[8]; + + if (! bfd_get_section_contents (abfd, xstate, contents, + I386_FBSD_XSAVE_XCR0_OFFSET, + 8)) + { + warning (_("Couldn't read `xcr0' bytes from " + "`.reg-xstate' section in core file.")); + return 0; + } + + xcr0 = bfd_get_64 (abfd, contents); + } + } + else + xcr0 = 0; + + return xcr0; +} + +/* Implement the core_read_description gdbarch method. */ + +static const struct target_desc * +i386fbsd_core_read_description (struct gdbarch *gdbarch, + struct target_ops *target, + bfd *abfd) +{ + return i386_target_description (i386fbsd_core_read_xcr0 (abfd)); +} + +/* Similar to i386_supply_fpregset, but use XSAVE extended state. */ + +static void +i386fbsd_supply_xstateregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *xstateregs, size_t len) +{ + i387_supply_xsave (regcache, regnum, xstateregs); +} + +/* Similar to i386_collect_fpregset, but use XSAVE extended state. */ + +static void +i386fbsd_collect_xstateregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *xstateregs, size_t len) +{ + i387_collect_xsave (regcache, regnum, xstateregs, 1); +} + +/* Register set definitions. */ + +static const struct regset i386fbsd_xstateregset = + { + NULL, + i386fbsd_supply_xstateregset, + i386fbsd_collect_xstateregset + }; + +/* Iterate over core file register note sections. */ + +static void +i386fbsd_iterate_over_regset_sections (struct gdbarch *gdbarch, + iterate_over_regset_sections_cb *cb, + void *cb_data, + const struct regcache *regcache) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + cb (".reg", tdep->sizeof_gregset, &i386_gregset, NULL, cb_data); + cb (".reg2", tdep->sizeof_fpregset, &i386_fpregset, NULL, cb_data); + + if (tdep->xcr0 & X86_XSTATE_AVX) + cb (".reg-xstate", X86_XSTATE_SIZE(tdep->xcr0), + &i386fbsd_xstateregset, "XSAVE extended state", cb_data); +} + static void i386fbsd_supply_uthread (struct regcache *regcache, int regnum, CORE_ADDR addr) { - char buf[4]; + gdb_byte buf[4]; int i; gdb_assert (regnum >= -1); @@ -108,7 +356,7 @@ static void i386fbsd_collect_uthread (const struct regcache *regcache, int regnum, CORE_ADDR addr) { - char buf[4]; + gdb_byte buf[4]; int i; gdb_assert (regnum >= -1); @@ -142,6 +390,8 @@ i386fbsdaout_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* FreeBSD uses -freg-struct-return by default. */ tdep->struct_return = reg_struct_return; + tdep->sigtramp_p = i386fbsd_sigtramp_p; + /* FreeBSD uses a different memory layout. */ tdep->sigtramp_start = i386fbsd_sigtramp_start_addr; tdep->sigtramp_end = i386fbsd_sigtramp_end_addr; @@ -208,6 +458,9 @@ i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + /* Generic FreeBSD support. */ + fbsd_init_abi (info, gdbarch); + /* Inherit stuff from older releases. We assume that FreeBSD 4.0-RELEASE always uses ELF. */ i386fbsd_init_abi (info, gdbarch); @@ -220,6 +473,15 @@ i386fbsd4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* FreeBSD 4.0 introduced a new `struct sigcontext'. */ tdep->sc_reg_offset = i386fbsd4_sc_reg_offset; tdep->sc_num_regs = ARRAY_SIZE (i386fbsd4_sc_reg_offset); + + tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET; + + /* Iterate over core file register note sections. */ + set_gdbarch_iterate_over_regset_sections + (gdbarch, i386fbsd_iterate_over_regset_sections); + + set_gdbarch_core_read_description (gdbarch, + i386fbsd_core_read_description); }