[6/8] FreeBSD x86: Use tramp-frame for signal frames.

Message ID 20210714140741.6460-7-jhb@FreeBSD.org
State New
Headers show
Series
  • Switch FreeBSD x86 to using register maps for GP registers
Related show

Commit Message

John Baldwin July 14, 2021, 2:07 p.m.
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  |  58 ----------
 gdb/amd64-fbsd-tdep.c | 183 ++++++++++++++++++------------
 gdb/amd64-tdep.h      |   3 -
 gdb/i386-bsd-nat.c    |   4 +-
 gdb/i386-fbsd-tdep.c  | 251 ++++++++++++++++++++++++++----------------
 gdb/i386-tdep.h       |   1 -
 6 files changed, 269 insertions(+), 231 deletions(-)

-- 
2.31.1

Patch

diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c
index 44dfb5a18f..91fc477d4d 100644
--- a/gdb/amd64-fbsd-nat.c
+++ b/gdb/amd64-fbsd-nat.c
@@ -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;
 }
diff --git a/gdb/amd64-fbsd-tdep.c b/gdb/amd64-fbsd-tdep.c
index b52fc6d431..648f929546 100644
--- a/gdb/amd64-fbsd-tdep.c
+++ b/gdb/amd64-fbsd-tdep.c
@@ -18,12 +18,11 @@ 
    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];
+  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);
 
-  /* 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;
+  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));
 }
-
 
-/* 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;
 
diff --git a/gdb/amd64-tdep.h b/gdb/amd64-tdep.h
index b2a29aa5f8..302ce6f2dd 100644
--- a/gdb/amd64-tdep.h
+++ b/gdb/amd64-tdep.h
@@ -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 */
diff --git a/gdb/i386-bsd-nat.c b/gdb/i386-bsd-nat.c
index 1fad6c5d48..7312c4bc12 100644
--- a/gdb/i386-bsd-nat.c
+++ b/gdb/i386-bsd-nat.c
@@ -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
 
diff --git a/gdb/i386-fbsd-tdep.c b/gdb/i386-fbsd-tdep.c
index 2aeb51dbec..6aa65e2aef 100644
--- a/gdb/i386-fbsd-tdep.c
+++ b/gdb/i386-fbsd-tdep.c
@@ -18,11 +18,11 @@ 
    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:
+
+   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;
+        ...
+   }
+
+   ucontext_t is defined as:
+
+   struct __ucontext {
+	   sigset_t	uc_sigmask;
+	   mcontext_t	uc_mcontext;
+	   ...
+   };
+
+   The mcontext_t contains the general purpose register set as well
+   as the floating point or XSAVE state.  */
+
+/* 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
+
+/* 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)
+{
+  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));
+}
+
+static const struct tramp_frame i386_fbsd_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 */
+    {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
+   trampoline.  This trampoline differs from the i386 kernel trampoline
    in that it omits a middle section that conditionally restores
    %gs.  */
 
-static const gdb_byte i386fbsd_sigtramp_start[] =
+static const struct tramp_frame i386_fbsd64_sigframe =
 {
-  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 */
-};
-
-/* 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];
-
-  /* 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;
-}
-
-/* From <machine/signal.h>.  */
-int i386fbsd_sc_reg_offset[] =
-{
-  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 */
+    {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);
 
diff --git a/gdb/i386-tdep.h b/gdb/i386-tdep.h
index 92f0257916..a3025f456d 100644
--- a/gdb/i386-tdep.h
+++ b/gdb/i386-tdep.h
@@ -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[];