mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-08-05 21:50:21 +08:00
FreeBSD x86: Use tramp-frame for signal frames.
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.
This commit is contained in:
@ -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;
|
||||
|
||||
|
Reference in New Issue
Block a user