diff options
author | John Baldwin <jhb@freebsd.org> | 2015-02-25 09:51:42 -0500 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2015-02-26 11:10:25 +0000 |
commit | cf424aef0af89903abdd6c4e055684929e4990af (patch) | |
tree | 2dd568a48d7a0ee4bd6d523e9acb7b09e62fe332 /gdb/i386fbsd-tdep.c | |
parent | c5cb74eeb3ea13a9fbeb0ec26b5bad10c4b92e4a (diff) | |
download | gdb-cf424aef0af89903abdd6c4e055684929e4990af.zip gdb-cf424aef0af89903abdd6c4e055684929e4990af.tar.gz gdb-cf424aef0af89903abdd6c4e055684929e4990af.tar.bz2 |
Rework signal frame probing for FreeBSD/x86
- Use signal frame sniffers that look for the signal trampoline
instruction sequence to detect most signal frames.
- FreeBSD kernels between 9.2 and 10.1 inclusive do not include the
signal trampoline code in process core dumps. To detect signal
frames for core dumps under these kernels, use the
kern.proc.sigtramp.<pid> sysctl to fetch the location of the signal
trampoline in the gdb process and assume that PC values within this
location are signal frames. This depends on that location being
identical for all binaries.
gdb/ChangeLog:
2015-02-25 John Baldwin <jhb@FreeBSD.org>
* amd64fbsd-nat.c: Include sys/user.h.
(_initialize_amd64fbsd_nat): Use the KERN_PROC_SIGTRAMP sysctl
instead of KERN_PS_STRINGS to locate the signal trampoline.
* i386fbsd-nat.c: Include sys/user.h.
(_initialize_i386fbsd_nat): Use the KERN_PROC_SIGTRAMP sysctl
instead of KERN_PS_STRINGS to locate the signal trampoline.
* amd64fbsd-tdep.c (amd64fbsd_sigtramp_code): New.
(amd64fbsd_sigtramp_p): New.
(amd64fbsd_sigtramp_start_addr, amd64fbsd_sigtramp_end_addr): No
longer set default values.
(amd64fbsd_init_abi): Set "sigtramp_p" to "amd64fbsd_sigtramp_p".
* i386fbsd-tdep.c (i386fbsd_sigtramp_start)
(i386fbsd_sigtramp_middle, i386fbsd_sigtramp_end)
(i386fbsd_freebsd4_sigtramp_start)
(i386fbsd_freebsd4_sigtramp_middle)
(i386fbsd_freebsd4_sigtramp_end, i386fbsd_osigtramp_start)
(i386fbsd_osigtramp_middle, i386fbsd_osigtramp_end): New.
(i386fbsd_sigtramp_p): New.
(i386fbsd_sigtramp_start_addr, i386fbsd_sigtramp_end_addr): No
longer set default values.
(i386fbsd_init_abi): Set "sigtramp_p" to "i386fbsd_sigtramp_p".
Diffstat (limited to 'gdb/i386fbsd-tdep.c')
-rw-r--r-- | gdb/i386fbsd-tdep.c | 154 |
1 files changed, 152 insertions, 2 deletions
diff --git a/gdb/i386fbsd-tdep.c b/gdb/i386fbsd-tdep.c index 8d237f0..d4516ee 100644 --- a/gdb/i386fbsd-tdep.c +++ b/gdb/i386fbsd-tdep.c @@ -29,6 +29,154 @@ #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 <machine/reg.h>. */ @@ -43,8 +191,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 <machine/signal.h>. */ int i386fbsd_sc_reg_offset[] = @@ -139,6 +287,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; |