FreeBSD x86: Use tramp-frame for signal frames.
authorJohn Baldwin <jhb@FreeBSD.org>
Fri, 28 Jan 2022 19:14:37 +0000 (11:14 -0800)
committerJohn Baldwin <jhb@FreeBSD.org>
Fri, 28 Jan 2022 19:14:37 +0000 (11:14 -0800)
Use a register map to describe the registers in mcontext_t as part of
the signal frame as is done on several other FreeBSD arches.  This
permits fetching the fsbase and gsbase register values from the signal
frame for both amd64 and i386 and permits fetching additional segment
registers stored as 16-bit values on amd64.

While signal frames on FreeBSD do contain floating point/XSAVE state,
these unwinders do not attempt to supply those registers.  The
existing x86 signal frame uwinders do not support these registers, and
the only existing functions which handle FSAVE/FXSAVE/XSAVE state all
work with regcaches.  In the future these unwinders could create a
tempory regcache, collect floating point registers, and then supply
values out of the regcache into the trad-frame.

gdb/amd64-fbsd-nat.c
gdb/amd64-fbsd-tdep.c
gdb/amd64-tdep.h
gdb/i386-bsd-nat.c
gdb/i386-fbsd-tdep.c
gdb/i386-tdep.h

index 3c79a40687b9c7364d3d39f8e5e9a9dc7dfb365d..f9bd45de4554de2248cac4554deccb75d8789676 100644 (file)
@@ -213,8 +213,6 @@ void _initialize_amd64fbsd_nat ();
 void
 _initialize_amd64fbsd_nat ()
 {
-  int offset;
-
   amd64_native_gregset32_reg_offset = amd64fbsd32_r_reg_offset;
   amd64_native_gregset64_reg_offset = amd64fbsd64_r_reg_offset;
 
@@ -222,60 +220,4 @@ _initialize_amd64fbsd_nat ()
 
   /* Support debugging kernel virtual memory images.  */
   bsd_kvm_add_target (amd64fbsd_supply_pcb);
-
-  /* To support the recognition of signal handlers, i386-bsd-tdep.c
-     hardcodes some constants.  Inclusion of this file means that we
-     are compiling a native debugger, which means that we can use the
-     system header files and sysctl(3) to get at the relevant
-     information.  */
-
-#define SC_REG_OFFSET amd64fbsd_sc_reg_offset
-
-  /* We only check the program counter, stack pointer and frame
-     pointer since these members of `struct sigcontext' are essential
-     for providing backtraces.  */
-
-#define SC_RIP_OFFSET SC_REG_OFFSET[AMD64_RIP_REGNUM]
-#define SC_RSP_OFFSET SC_REG_OFFSET[AMD64_RSP_REGNUM]
-#define SC_RBP_OFFSET SC_REG_OFFSET[AMD64_RBP_REGNUM]
-
-  /* Override the default value for the offset of the program counter
-     in the sigcontext structure.  */
-  offset = offsetof (struct sigcontext, sc_rip);
-
-  if (SC_RIP_OFFSET != offset)
-    {
-      warning (_("\
-offsetof (struct sigcontext, sc_rip) yields %d instead of %d.\n\
-Please report this to <bug-gdb@gnu.org>."),
-              offset, SC_RIP_OFFSET);
-    }
-
-  SC_RIP_OFFSET = offset;
-
-  /* Likewise for the stack pointer.  */
-  offset = offsetof (struct sigcontext, sc_rsp);
-
-  if (SC_RSP_OFFSET != offset)
-    {
-      warning (_("\
-offsetof (struct sigcontext, sc_rsp) yields %d instead of %d.\n\
-Please report this to <bug-gdb@gnu.org>."),
-              offset, SC_RSP_OFFSET);
-    }
-
-  SC_RSP_OFFSET = offset;
-
-  /* And the frame pointer.  */
-  offset = offsetof (struct sigcontext, sc_rbp);
-
-  if (SC_RBP_OFFSET != offset)
-    {
-      warning (_("\
-offsetof (struct sigcontext, sc_rbp) yields %d instead of %d.\n\
-Please report this to <bug-gdb@gnu.org>."),
-              offset, SC_RBP_OFFSET);
-    }
-
-  SC_RBP_OFFSET = offset;
 }
index f61ca74d88a568e8abd96a5dc69a39ad10e6eead..fa363776fc01aa75fd0b5969dcb149c0241627d7 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "arch-utils.h"
-#include "frame.h"
-#include "gdbcore.h"
-#include "regcache.h"
 #include "osabi.h"
 #include "regset.h"
+#include "target.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
 #include "i386-fbsd-tdep.h"
 #include "gdbsupport/x86-xstate.h"
 
@@ -70,6 +69,49 @@ static const struct regcache_map_entry amd64_fbsd_gregmap[] =
   { 0 }
 };
 
+/* This layout including fsbase and gsbase was adopted in FreeBSD
+   8.0.  */
+
+static const struct regcache_map_entry amd64_fbsd_mcregmap[] =
+{
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_onstack */
+  { 1, AMD64_RDI_REGNUM, 0 },
+  { 1, AMD64_RSI_REGNUM, 0 },
+  { 1, AMD64_RDX_REGNUM, 0 },
+  { 1, AMD64_RCX_REGNUM, 0 },
+  { 1, AMD64_R8_REGNUM, 0 },
+  { 1, AMD64_R9_REGNUM, 0 },
+  { 1, AMD64_RAX_REGNUM, 0 },
+  { 1, AMD64_RBX_REGNUM, 0 },
+  { 1, AMD64_RBP_REGNUM, 0 },
+  { 1, AMD64_R10_REGNUM, 0 },
+  { 1, AMD64_R11_REGNUM, 0 },
+  { 1, AMD64_R12_REGNUM, 0 },
+  { 1, AMD64_R13_REGNUM, 0 },
+  { 1, AMD64_R14_REGNUM, 0 },
+  { 1, AMD64_R15_REGNUM, 0 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_trapno */
+  { 1, AMD64_FS_REGNUM, 2 },
+  { 1, AMD64_GS_REGNUM, 2 },
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_addr */
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_flags */
+  { 1, AMD64_ES_REGNUM, 2 },
+  { 1, AMD64_DS_REGNUM, 2 },
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_err */
+  { 1, AMD64_RIP_REGNUM, 0 },
+  { 1, AMD64_CS_REGNUM, 8 },
+  { 1, AMD64_EFLAGS_REGNUM, 8 },
+  { 1, AMD64_RSP_REGNUM, 0 },
+  { 1, AMD64_SS_REGNUM, 8 },
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_len */
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_fpformat */
+  { 1, REGCACHE_MAP_SKIP, 8 }, /* mc_ownedfp */
+  { 64, REGCACHE_MAP_SKIP, 8 },        /* mc_fpstate */
+  { 1, AMD64_FSBASE_REGNUM, 0 },
+  { 1, AMD64_GSBASE_REGNUM, 0 },
+  { 0 }
+};
+
 /* Register set definitions.  */
 
 const struct regset amd64_fbsd_gregset =
@@ -79,80 +121,86 @@ const struct regset amd64_fbsd_gregset =
 
 /* Support for signal handlers.  */
 
-/* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
-   routine.  */
+/* In a signal frame, rsp points to a 'struct sigframe' which is
+   defined as:
 
-static const gdb_byte amd64fbsd_sigtramp_code[] =
-{
-  0x48, 0x8d, 0x7c, 0x24, 0x10, /* lea     SIGF_UC(%rsp),%rdi */
-  0x6a, 0x00,                  /* pushq   $0 */
-  0x48, 0xc7, 0xc0, 0xa1, 0x01, 0x00, 0x00,
-                               /* movq    $SYS_sigreturn,%rax */
-  0x0f, 0x05                    /* syscall */
-};
+   struct sigframe {
+       union {
+               __siginfohandler_t      *sf_action;
+               __sighandler_t          *sf_handler;
+       } sf_ahu;
+       ucontext_t      sf_uc;
+        ...
+   }
 
-static int
-amd64fbsd_sigtramp_p (struct frame_info *this_frame)
-{
-  CORE_ADDR pc = get_frame_pc (this_frame);
-  gdb_byte buf[sizeof amd64fbsd_sigtramp_code];
+   ucontext_t is defined as:
 
-  if (!safe_frame_unwind_memory (this_frame, pc, buf))
-    return 0;
-  if (memcmp (buf, amd64fbsd_sigtramp_code, sizeof amd64fbsd_sigtramp_code)
-      != 0)
-    return 0;
+   struct __ucontext {
+          sigset_t     uc_sigmask;
+          mcontext_t   uc_mcontext;
+          ...
+   };
 
-  return 1;
-}
+   The mcontext_t contains the general purpose register set as well
+   as the floating point or XSAVE state.  */
 
-/* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
-   address of the associated sigcontext structure.  */
+/* NB: There is an 8 byte padding hole between sf_ahu and sf_uc. */
+#define AMD64_SIGFRAME_UCONTEXT_OFFSET                 16
+#define AMD64_UCONTEXT_MCONTEXT_OFFSET         16
+#define AMD64_SIZEOF_MCONTEXT_T                        800
 
-static CORE_ADDR
-amd64fbsd_sigcontext_addr (struct frame_info *this_frame)
+/* Implement the "init" method of struct tramp_frame.  */
+
+static void
+amd64_fbsd_sigframe_init (const struct tramp_frame *self,
+                         struct frame_info *this_frame,
+                         struct trad_frame_cache *this_cache,
+                         CORE_ADDR func)
 {
   struct gdbarch *gdbarch = get_frame_arch (this_frame);
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
-  CORE_ADDR sp;
-  gdb_byte buf[8];
-
-  /* The `struct sigcontext' (which really is an `ucontext_t' on
-     FreeBSD/amd64) lives at a fixed offset in the signal frame.  See
-     <machine/sigframe.h>.  */
-  get_frame_register (this_frame, AMD64_RSP_REGNUM, buf);
-  sp = extract_unsigned_integer (buf, 8, byte_order);
-  return sp + 16;
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM);
+  CORE_ADDR mcontext_addr
+    = (sp
+       + AMD64_SIGFRAME_UCONTEXT_OFFSET
+       + AMD64_UCONTEXT_MCONTEXT_OFFSET);
+
+  trad_frame_set_reg_regmap (this_cache, amd64_fbsd_mcregmap, mcontext_addr,
+                            AMD64_SIZEOF_MCONTEXT_T);
+
+  /* Don't bother with floating point or XSAVE state for now.  The
+     current helper routines for parsing FXSAVE and XSAVE state only
+     work with regcaches.  This could perhaps create a temporary
+     regcache, collect the register values from mc_fpstate and
+     mc_xfpustate, and then set register values in the trad_frame.  */
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
 }
-\f
 
-/* From <machine/signal.h>.  */
-int amd64fbsd_sc_reg_offset[] =
+static const struct tramp_frame amd64_fbsd_sigframe =
 {
-  24 + 6 * 8,                  /* %rax */
-  24 + 7 * 8,                  /* %rbx */
-  24 + 3 * 8,                  /* %rcx */
-  24 + 2 * 8,                  /* %rdx */
-  24 + 1 * 8,                  /* %rsi */
-  24 + 0 * 8,                  /* %rdi */
-  24 + 8 * 8,                  /* %rbp */
-  24 + 22 * 8,                 /* %rsp */
-  24 + 4 * 8,                  /* %r8 ...  */
-  24 + 5 * 8,
-  24 + 9 * 8,
-  24 + 10 * 8,
-  24 + 11 * 8,
-  24 + 12 * 8,
-  24 + 13 * 8,
-  24 + 14 * 8,                 /* ... %r15 */
-  24 + 19 * 8,                 /* %rip */
-  24 + 21 * 8,                 /* %eflags */
-  24 + 20 * 8,                 /* %cs */
-  24 + 23 * 8,                 /* %ss */
-  -1,                          /* %ds */
-  -1,                          /* %es */
-  -1,                          /* %fs */
-  -1                           /* %gs */
+  SIGTRAMP_FRAME,
+  1,
+  {
+    {0x48, ULONGEST_MAX},              /* lea     SIGF_UC(%rsp),%rdi */
+    {0x8d, ULONGEST_MAX},
+    {0x7c, ULONGEST_MAX},
+    {0x24, ULONGEST_MAX},
+    {0x10, ULONGEST_MAX},
+    {0x6a, ULONGEST_MAX},              /* pushq   $0 */
+    {0x00, ULONGEST_MAX},
+    {0x48, ULONGEST_MAX},              /* movq    $SYS_sigreturn,%rax */
+    {0xc7, ULONGEST_MAX},
+    {0xc0, ULONGEST_MAX},
+    {0xa1, ULONGEST_MAX},
+    {0x01, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x0f, ULONGEST_MAX},              /* syscall */
+    {0x05, ULONGEST_MAX},
+    {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
+  },
+  amd64_fbsd_sigframe_init
 };
 
 /* Implement the core_read_description gdbarch method.  */
@@ -245,10 +293,7 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   amd64_init_abi (info, gdbarch,
                  amd64_target_description (X86_XSTATE_SSE_MASK, true));
 
-  tdep->sigtramp_p = amd64fbsd_sigtramp_p;
-  tdep->sigcontext_addr = amd64fbsd_sigcontext_addr;
-  tdep->sc_reg_offset = amd64fbsd_sc_reg_offset;
-  tdep->sc_num_regs = ARRAY_SIZE (amd64fbsd_sc_reg_offset);
+  tramp_frame_prepend_unwinder (gdbarch, &amd64_fbsd_sigframe);
 
   tdep->xsave_xcr0_offset = I386_FBSD_XSAVE_XCR0_OFFSET;
 
index cdc1d6f6df4e3048cd2379e089259804a15c5608..c18766e71c46a5db593d4d20a8939cf98bf3204b 100644 (file)
@@ -144,7 +144,4 @@ extern int amd64nbsd_r_reg_offset[];
 /* Variables exported from amd64-obsd-tdep.c.  */
 extern int amd64obsd_r_reg_offset[];
 
-/* Variables exported from amd64-fbsd-tdep.c.  */
-extern int amd64fbsd_sc_reg_offset[];
-
 #endif /* amd64-tdep.h */
index a04478ac5a776a82df35f99d905e64f5633e8d64..c112b02c2e1ba8418edb47bbd632f871c2c1fdf4 100644 (file)
@@ -350,9 +350,7 @@ _initialize_i386bsd_nat ()
      system header files and sysctl(3) to get at the relevant
      information.  */
 
-#if defined (__FreeBSD_version)
-#define SC_REG_OFFSET i386fbsd_sc_reg_offset
-#elif defined (OpenBSD)
+#if defined (OpenBSD)
 #define SC_REG_OFFSET i386obsd_sc_reg_offset
 #endif
 
index 6d720d8377f16a8a4ea735a728100d6e70062e0a..6a656ddf09c2179d9f629c7dd85d57d05f595ed5 100644 (file)
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "arch-utils.h"
-#include "gdbcore.h"
 #include "osabi.h"
 #include "regcache.h"
 #include "regset.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
 #include "i386-fbsd-tdep.h"
 #include "gdbsupport/x86-xstate.h"
 
@@ -61,6 +61,41 @@ static const struct regcache_map_entry i386_fbsd_gregmap[] =
   { 0 }
 };
 
+/* This layout including fsbase and gsbase was adopted in FreeBSD
+   8.0.  */
+
+static const struct regcache_map_entry i386_fbsd_mcregmap[] =
+{
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_onstack */
+  { 1, I386_GS_REGNUM, 4 },
+  { 1, I386_FS_REGNUM, 4 },
+  { 1, I386_ES_REGNUM, 4 },
+  { 1, I386_DS_REGNUM, 4 },
+  { 1, I386_EDI_REGNUM, 0 },
+  { 1, I386_ESI_REGNUM, 0 },
+  { 1, I386_EBP_REGNUM, 0 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* isp */
+  { 1, I386_EBX_REGNUM, 0 },
+  { 1, I386_EDX_REGNUM, 0 },
+  { 1, I386_ECX_REGNUM, 0 },
+  { 1, I386_EAX_REGNUM, 0 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_trapno */
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_err */
+  { 1, I386_EIP_REGNUM, 0 },
+  { 1, I386_CS_REGNUM, 4 },
+  { 1, I386_EFLAGS_REGNUM, 0 },
+  { 1, I386_ESP_REGNUM, 0 },
+  { 1, I386_SS_REGNUM, 4 },
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_len */
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_fpformat */
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_ownedfp */
+  { 1, REGCACHE_MAP_SKIP, 4 }, /* mc_flags */
+  { 128, REGCACHE_MAP_SKIP, 4 },/* mc_fpstate */
+  { 1, I386_FSBASE_REGNUM, 0 },
+  { 1, I386_GSBASE_REGNUM, 0 },
+  { 0 }
+};
+
 /* Register set definitions.  */
 
 const struct regset i386_fbsd_gregset =
@@ -70,102 +105,127 @@ const struct regset i386_fbsd_gregset =
 
 /* Support for signal handlers.  */
 
-/* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
-   routine.  */
+/* In a signal frame, esp points to a 'struct sigframe' which is
+   defined as:
 
-/* FreeBSD/i386 binaries running under an amd64 kernel use a different
-   trampoline This trampoline differs from the i386 kernel trampoline
-   in that it omits a middle section that conditionally restores
-   %gs.  */
+   struct sigframe {
+       register_t      sf_signum;
+       register_t      sf_siginfo;
+       register_t      sf_ucontext;
+       register_t      sf_addr;
+       union {
+               __siginfohandler_t      *sf_action;
+               __sighandler_t          *sf_handler;
+       } sf_ahu;
+       ucontext_t      sf_uc;
+        ...
+   }
 
-static const gdb_byte i386fbsd_sigtramp_start[] =
-{
-  0x8d, 0x44, 0x24, 0x20,       /* lea     SIGF_UC(%esp),%eax */
-  0x50                         /* pushl   %eax */
-};
+   ucontext_t is defined as:
 
-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 */
-};
+   struct __ucontext {
+          sigset_t     uc_sigmask;
+          mcontext_t   uc_mcontext;
+          ...
+   };
 
-static const gdb_byte i386fbsd_sigtramp_end[] =
-{
-  0xb8, 0xa1, 0x01, 0x00, 0x00, /* movl   $SYS_sigreturn,%eax */
-  0x50,                        /* pushl   %eax */
-  0xcd, 0x80                   /* int     $0x80 */
-};
+   The mcontext_t contains the general purpose register set as well
+   as the floating point or XSAVE state.  */
 
-/* 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);
+/* NB: There is a 12 byte padding hole between sf_ahu and sf_uc. */
+#define I386_SIGFRAME_UCONTEXT_OFFSET          32
+#define I386_UCONTEXT_MCONTEXT_OFFSET          16
+#define I386_SIZEOF_MCONTEXT_T                 640
 
-static int
-i386fbsd_sigtramp_p (struct frame_info *this_frame)
+/* Implement the "init" method of struct tramp_frame.  */
+
+static void
+i386_fbsd_sigframe_init (const struct tramp_frame *self,
+                        struct frame_info *this_frame,
+                        struct trad_frame_cache *this_cache,
+                        CORE_ADDR func)
 {
-  CORE_ADDR pc = get_frame_pc (this_frame);
-  gdb_byte buf[sizeof i386fbsd_sigtramp_middle];
-
-  /* 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)
-    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, i386fbsd_sigtramp_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, i386fbsd_sigtramp_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, i386fbsd_sigtramp_end, sizeof i386fbsd_sigtramp_end) != 0)
-    return 0;
-
-  return 1;
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+  CORE_ADDR mcontext_addr
+    = (sp
+       + I386_SIGFRAME_UCONTEXT_OFFSET
+       + I386_UCONTEXT_MCONTEXT_OFFSET);
+
+  trad_frame_set_reg_regmap (this_cache, i386_fbsd_mcregmap, mcontext_addr,
+                            I386_SIZEOF_MCONTEXT_T);
+
+  /* Don't bother with floating point or XSAVE state for now.  The
+     current helper routines for parsing FXSAVE and XSAVE state only
+     work with regcaches.  This could perhaps create a temporary
+     regcache, collect the register values from mc_fpstate and
+     mc_xfpustate, and then set register values in the trad_frame.  */
+
+  trad_frame_set_id (this_cache, frame_id_build (sp, func));
 }
 
-/* From <machine/signal.h>.  */
-int i386fbsd_sc_reg_offset[] =
+static const struct tramp_frame i386_fbsd_sigframe =
 {
-  20 + 11 * 4,                 /* %eax */
-  20 + 10 * 4,                 /* %ecx */
-  20 + 9 * 4,                  /* %edx */
-  20 + 8 * 4,                  /* %ebx */
-  20 + 17 * 4,                 /* %esp */
-  20 + 6 * 4,                  /* %ebp */
-  20 + 5 * 4,                  /* %esi */
-  20 + 4 * 4,                  /* %edi */
-  20 + 14 * 4,                 /* %eip */
-  20 + 16 * 4,                 /* %eflags */
-  20 + 15 * 4,                 /* %cs */
-  20 + 18 * 4,                 /* %ss */
-  20 + 3 * 4,                  /* %ds */
-  20 + 2 * 4,                  /* %es */
-  20 + 1 * 4,                  /* %fs */
-  20 + 0 * 4                   /* %gs */
+  SIGTRAMP_FRAME,
+  1,
+  {
+    {0x8d, ULONGEST_MAX},              /* lea     SIGF_UC(%esp),%eax */
+    {0x44, ULONGEST_MAX},
+    {0x24, ULONGEST_MAX},
+    {0x20, ULONGEST_MAX},
+    {0x50, ULONGEST_MAX},              /* pushl   %eax */
+    {0xf7, ULONGEST_MAX},              /* testl   $PSL_VM,UC_EFLAGS(%eax) */
+    {0x40, ULONGEST_MAX},
+    {0x54, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x02, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x75, ULONGEST_MAX},              /* jne     +3 */
+    {0x03, ULONGEST_MAX},
+    {0x8e, ULONGEST_MAX},              /* mov     UC_GS(%eax),%gs */
+    {0x68, ULONGEST_MAX},
+    {0x14, ULONGEST_MAX},
+    {0xb8, ULONGEST_MAX},              /* movl   $SYS_sigreturn,%eax */
+    {0xa1, ULONGEST_MAX},
+    {0x01, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x50, ULONGEST_MAX},              /* pushl   %eax */
+    {0xcd, ULONGEST_MAX},              /* int     $0x80 */
+    {0x80, ULONGEST_MAX},
+    {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
+  },
+  i386_fbsd_sigframe_init
+};
+
+/* FreeBSD/i386 binaries running under an amd64 kernel use a different
+   trampoline.  This trampoline differs from the i386 kernel trampoline
+   in that it omits a middle section that conditionally restores
+   %gs.  */
+
+static const struct tramp_frame i386_fbsd64_sigframe =
+{
+  SIGTRAMP_FRAME,
+  1,
+  {
+    {0x8d, ULONGEST_MAX},              /* lea     SIGF_UC(%esp),%eax */
+    {0x44, ULONGEST_MAX},
+    {0x24, ULONGEST_MAX},
+    {0x20, ULONGEST_MAX},
+    {0x50, ULONGEST_MAX},              /* pushl   %eax */
+    {0xb8, ULONGEST_MAX},              /* movl   $SYS_sigreturn,%eax */
+    {0xa1, ULONGEST_MAX},
+    {0x01, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x00, ULONGEST_MAX},
+    {0x50, ULONGEST_MAX},              /* pushl   %eax */
+    {0xcd, ULONGEST_MAX},              /* int     $0x80 */
+    {0x80, ULONGEST_MAX},
+    {TRAMP_SENTINEL_INSN, ULONGEST_MAX}
+  },
+  i386_fbsd_sigframe_init
 };
 
 /* Get XSAVE extended state xcr0 from core dump.  */
@@ -308,11 +368,8 @@ i386fbsd_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 has a more complete `struct sigcontext'.  */
-  tdep->sc_reg_offset = i386fbsd_sc_reg_offset;
-  tdep->sc_num_regs = ARRAY_SIZE (i386fbsd_sc_reg_offset);
+  tramp_frame_prepend_unwinder (gdbarch, &i386_fbsd_sigframe);
+  tramp_frame_prepend_unwinder (gdbarch, &i386_fbsd64_sigframe);
 
   i386_elf_init_abi (info, gdbarch);
 
index 62d94da53b03a0666051a337c2dd450fcd579048..eb58dd68e73d19618937602101442b48a1425d9d 100644 (file)
@@ -474,7 +474,6 @@ extern int i386_mpx_enabled (void);
 extern void i386bsd_init_abi (struct gdbarch_info, struct gdbarch *);
 extern CORE_ADDR i386obsd_sigtramp_start_addr;
 extern CORE_ADDR i386obsd_sigtramp_end_addr;
-extern int i386fbsd_sc_reg_offset[];
 extern int i386obsd_sc_reg_offset[];
 extern int i386bsd_sc_reg_offset[];