From patchwork Wed Feb 4 15:47:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 4911 Received: (qmail 18222 invoked by alias); 4 Feb 2015 15:47:18 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 17456 invoked by uid 89); 4 Feb 2015 15:47:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=BAYES_00, SPF_HELO_PASS, SPF_SOFTFAIL autolearn=no version=3.3.2 X-HELO: bigwig.baldwin.cx Received: from bigwig.baldwin.cx (HELO bigwig.baldwin.cx) (96.47.65.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (CAMELLIA256-SHA encrypted) ESMTPS; Wed, 04 Feb 2015 15:47:16 +0000 Received: from ralph.baldwin.cx (pool-173-54-116-245.nwrknj.fios.verizon.net [173.54.116.245]) by bigwig.baldwin.cx (Postfix) with ESMTPSA id 5F360B926 for ; Wed, 4 Feb 2015 10:47:12 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: Fix signal trampoline detection/unwinding on recent FreeBSD/i386 and FreeBSD/amd64 Date: Wed, 04 Feb 2015 10:47:07 -0500 Message-ID: <11386216.Yv1qECs4Mc@ralph.baldwin.cx> User-Agent: KMail/4.14.2 (FreeBSD/10.1-STABLE; KDE/4.14.2; amd64; ; ) MIME-Version: 1.0 This patch fixes two issues with signal frame unwinding on recent FreeBSD/x86: First, FreeBSD moved the signal trampoline code into a global shared page exported by the kernel a few releases ago. To try to make this easier to detect, FreeBSD added a new per-process sysctl node that exports the starting and ending address of the signal trampoline code. This sysctl works on all platforms that FreeBSD supports no matter where the signal trampoline lives, but I have only updated i386 and amd64 in this patch. Second, amd64fbsd_sigcontext_addr was using frame_unwind_register_unsigned to fetch the stack pointer which resulted in infinite recursion. I've changed it to use get_frame_register() to match the sigcontext_addr methods in the i386-bsd and amd64-linux targets instead. Changelog: 2015-xx-xx John Baldwin * amd64fbsd-nat.c (_initialize_amd64fbsd_nat): Use the KERN_PROC_SIGTRAMP sysctl to locate the signal trampoline. * i386fbsd-nat.c (_initialize_i386fbsd_nat): Likewise. * amd64fbsd-tdep.c (amd64fbsd_sigcontext_addr): Fix infinite recursion. diff --git a/gdb/amd64fbsd-nat.c b/gdb/amd64fbsd-nat.c index 1c396e2..6227681 100644 --- a/gdb/amd64fbsd-nat.c +++ b/gdb/amd64fbsd-nat.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "fbsd-nat.h" @@ -244,6 +245,29 @@ Please report this to ."), SC_RBP_OFFSET = offset; +#ifdef KERN_PROC_SIGTRAMP + /* Newer versions of FreeBSD provide a kern.proc.sigtramp. + sysctl that returns the location of the signal trampoline. + Note that this fetches the address for the current (gdb) process. + This will be correct for other 64-bit processes, but the signal + trampoline location is not properly set for 32-bit processes. */ + { + int mib[4]; + struct kinfo_sigtramp kst; + size_t len; + + mib[0] = CTL_KERN; + 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 = (uintptr_t)kst.ksigtramp_start; + amd64fbsd_sigtramp_end_addr = (uintptr_t)kst.ksigtramp_end; + } + } +#else /* 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 @@ -264,4 +288,5 @@ Please report this to ."), amd64fbsd_sigtramp_end_addr = ps_strings; } } +#endif } diff --git a/gdb/amd64fbsd-tdep.c b/gdb/amd64fbsd-tdep.c index 2d49cdf..abb0cab 100644 --- a/gdb/amd64fbsd-tdep.c +++ b/gdb/amd64fbsd-tdep.c @@ -37,12 +37,16 @@ static CORE_ADDR amd64fbsd_sigcontext_addr (struct frame_info *this_frame) { + 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 . */ - sp = frame_unwind_register_unsigned (this_frame, AMD64_RSP_REGNUM); + get_frame_register (this_frame, AMD64_RSP_REGNUM, buf); + sp = extract_unsigned_integer (buf, 8, byte_order); return sp + 16; } diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c index f4951d1..5293f0f 100644 --- a/gdb/i386fbsd-nat.c +++ b/gdb/i386fbsd-nat.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "fbsd-nat.h" #include "i386-tdep.h" @@ -148,13 +149,34 @@ _initialize_i386fbsd_nat (void) /* Support debugging kernel virtual memory images. */ bsd_kvm_add_target (i386fbsd_supply_pcb); +#ifdef KERN_PROC_SIGTRAMP + /* Newer versions of FreeBSD provide a kern.proc.sigtramp. + sysctl that returns the location of the signal trampoline. + Note that this fetches the address for the current (gdb) process, + but should be correct for other processes. */ + { + int mib[4]; + struct kinfo_sigtramp kst; + size_t len; + + mib[0] = CTL_KERN; + 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 = (uintptr_t)kst.ksigtramp_start; + i386fbsd_sigtramp_end_addr = (uintptr_t)kst.ksigtramp_end; + } + } +#elif defined(KERN_PS_STRINGS) /* 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 { int mib[2]; u_long ps_strings;