summaryrefslogtreecommitdiff
path: root/devel/gdb/files/commit-cf424ae
diff options
context:
space:
mode:
Diffstat (limited to 'devel/gdb/files/commit-cf424ae')
-rw-r--r--devel/gdb/files/commit-cf424ae348
1 files changed, 348 insertions, 0 deletions
diff --git a/devel/gdb/files/commit-cf424ae b/devel/gdb/files/commit-cf424ae
new file mode 100644
index 000000000000..5e20c8072751
--- /dev/null
+++ b/devel/gdb/files/commit-cf424ae
@@ -0,0 +1,348 @@
+diff --git gdb/amd64fbsd-nat.c gdb/amd64fbsd-nat.c
+index 1c396e2..b1b261c 100644
+--- gdb/amd64fbsd-nat.c
++++ gdb/amd64fbsd-nat.c
+@@ -26,6 +26,7 @@
+ #include <sys/types.h>
+ #include <sys/ptrace.h>
+ #include <sys/sysctl.h>
++#include <sys/user.h>
+ #include <machine/reg.h>
+
+ #include "fbsd-nat.h"
+@@ -244,24 +245,31 @@ Please report this to <bug-gdb@gnu.org>."),
+
+ SC_RBP_OFFSET = offset;
+
+- /* FreeBSD provides a kern.ps_strings sysctl that we can use to
+- locate the sigtramp. That way we can still recognize a sigtramp
+- if its location is changed in a new kernel. Of course this is
+- still based on the assumption that the sigtramp is placed
+- directly under the location where the program arguments and
+- environment can be found. */
++#ifdef KERN_PROC_SIGTRAMP
++ /* Normally signal frames are detected via amd64fbsd_sigtramp_p.
++ However, FreeBSD 9.2 through 10.1 do not include the page holding
++ the signal code in core dumps. These releases do provide a
++ kern.proc.sigtramp.<pid> sysctl that returns the location of the
++ signal trampoline for a running process. We fetch the location
++ of the current (gdb) process and use this to identify signal
++ frames in core dumps from these releases. Note that this only
++ works for core dumps of 64-bit (FreeBSD/amd64) processes and does
++ not handle core dumps of 32-bit (FreeBSD/i386) processes. */
+ {
+- int mib[2];
+- long ps_strings;
++ int mib[4];
++ struct kinfo_sigtramp kst;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+- mib[1] = KERN_PS_STRINGS;
+- len = sizeof (ps_strings);
+- if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
++ mib[1] = KERN_PROC;
++ mib[2] = KERN_PROC_SIGTRAMP;
++ mib[3] = getpid ();
++ len = sizeof (kst);
++ if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
+ {
+- amd64fbsd_sigtramp_start_addr = ps_strings - 32;
+- amd64fbsd_sigtramp_end_addr = ps_strings;
++ amd64fbsd_sigtramp_start_addr = (uintptr_t) kst.ksigtramp_start;
++ amd64fbsd_sigtramp_end_addr = (uintptr_t) kst.ksigtramp_end;
+ }
+ }
++#endif
+ }
+diff --git gdb/amd64fbsd-tdep.c gdb/amd64fbsd-tdep.c
+index abb0cab..e11b0f3 100644
+--- gdb/amd64fbsd-tdep.c
++++ gdb/amd64fbsd-tdep.c
+@@ -31,6 +31,33 @@
+
+ /* Support for signal handlers. */
+
++/* Return whether THIS_FRAME corresponds to a FreeBSD sigtramp
++ routine. */
++
++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 */
++};
++
++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];
++
++ if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof buf))
++ return 0;
++ if (memcmp (buf, amd64fbsd_sigtramp_code, sizeof amd64fbsd_sigtramp_code) !=
++ 0)
++ return 0;
++
++ return 1;
++}
++
+ /* Assuming THIS_FRAME is for a BSD sigtramp routine, return the
+ address of the associated sigcontext structure. */
+
+@@ -88,8 +115,8 @@ static int amd64fbsd_r_reg_offset[] =
+ };
+
+ /* Location of the signal trampoline. */
+-CORE_ADDR amd64fbsd_sigtramp_start_addr = 0x7fffffffffc0ULL;
+-CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0ULL;
++CORE_ADDR amd64fbsd_sigtramp_start_addr;
++CORE_ADDR amd64fbsd_sigtramp_end_addr;
+
+ /* From <machine/signal.h>. */
+ int amd64fbsd_sc_reg_offset[] =
+@@ -199,6 +226,7 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+
+ amd64_init_abi (info, gdbarch);
+
++ tdep->sigtramp_p = amd64fbsd_sigtramp_p;
+ tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr;
+ tdep->sigtramp_end = amd64fbsd_sigtramp_end_addr;
+ tdep->sigcontext_addr = amd64fbsd_sigcontext_addr;
+diff --git gdb/i386fbsd-nat.c gdb/i386fbsd-nat.c
+index f4951d1..ad439e3 100644
+--- gdb/i386fbsd-nat.c
++++ gdb/i386fbsd-nat.c
+@@ -25,6 +25,7 @@
+ #include <sys/types.h>
+ #include <sys/ptrace.h>
+ #include <sys/sysctl.h>
++#include <sys/user.h>
+
+ #include "fbsd-nat.h"
+ #include "i386-tdep.h"
+@@ -148,25 +149,28 @@ _initialize_i386fbsd_nat (void)
+ /* Support debugging kernel virtual memory images. */
+ bsd_kvm_add_target (i386fbsd_supply_pcb);
+
+- /* FreeBSD provides a kern.ps_strings sysctl that we can use to
+- locate the sigtramp. That way we can still recognize a sigtramp
+- if its location is changed in a new kernel. Of course this is
+- still based on the assumption that the sigtramp is placed
+- directly under the location where the program arguments and
+- environment can be found. */
+-#ifdef KERN_PS_STRINGS
++#ifdef KERN_PROC_SIGTRAMP
++ /* Normally signal frames are detected via i386fbsd_sigtramp_p.
++ However, FreeBSD 9.2 through 10.1 do not include the page holding
++ the signal code in core dumps. These releases do provide a
++ kern.proc.sigtramp.<pid> sysctl that returns the location of the
++ signal trampoline for a running process. We fetch the location
++ of the current (gdb) process and use this to identify signal
++ frames in core dumps from these releases. */
+ {
+- int mib[2];
+- u_long ps_strings;
++ int mib[4];
++ struct kinfo_sigtramp kst;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+- mib[1] = KERN_PS_STRINGS;
+- len = sizeof (ps_strings);
+- if (sysctl (mib, 2, &ps_strings, &len, NULL, 0) == 0)
++ mib[1] = KERN_PROC;
++ mib[2] = KERN_PROC_SIGTRAMP;
++ mib[3] = getpid ();
++ len = sizeof (kst);
++ if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0)
+ {
+- i386fbsd_sigtramp_start_addr = ps_strings - 128;
+- i386fbsd_sigtramp_end_addr = ps_strings;
++ i386fbsd_sigtramp_start_addr = (uintptr_t) kst.ksigtramp_start;
++ i386fbsd_sigtramp_end_addr = (uintptr_t) kst.ksigtramp_end;
+ }
+ }
+ #endif
+diff --git gdb/i386fbsd-tdep.c gdb/i386fbsd-tdep.c
+index 8d237f0..d4516ee 100644
+--- gdb/i386fbsd-tdep.c
++++ 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;