From patchwork Tue Feb 10 23:34:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 5030 Received: (qmail 17341 invoked by alias); 10 Feb 2015 23:34:25 -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 17329 invoked by uid 89); 10 Feb 2015 23:34:25 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Tue, 10 Feb 2015 23:34:23 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t1ANYDOd017717 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Tue, 10 Feb 2015 18:34:14 -0500 Received: from [127.0.0.1] (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t1ANYAWR000566; Tue, 10 Feb 2015 18:34:11 -0500 Message-ID: <54DA9572.1010304@redhat.com> Date: Tue, 10 Feb 2015 23:34:10 +0000 From: Pedro Alves User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.3.0 MIME-Version: 1.0 To: John Baldwin CC: gdb-patches@sourceware.org Subject: Re: [PATCH] Fix signal trampoline detection/unwinding on recent FreeBSD/i386 and FreeBSD/amd64 References: <11386216.Yv1qECs4Mc@ralph.baldwin.cx> <1836606.R8FOmMR0ZG@ralph.baldwin.cx> <54DA3AFE.3060406@redhat.com> <1778386.0IyHlhpa5R@ralph.baldwin.cx> In-Reply-To: <1778386.0IyHlhpa5R@ralph.baldwin.cx> Thanks, updated patch looks good. Feel free to push. On 02/10/2015 07:14 PM, John Baldwin wrote: > On Tuesday, February 10, 2015 05:08:14 PM Pedro Alves wrote: >> On 02/10/2015 02:50 PM, John Baldwin wrote: >>>> + 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. */ >> >> I'm not sure I understand what does "but the signal trampoline >> location is not properly set for 32-bit processes" means. You mean >> it's not properly set because GDB is 64-bit; or it's not properly set >> in the kernel; or something else? > > The sysctl is designed to be used against the target process, but I did not > see an easy way to hook into each run and ptrace attach to invoke the sysctl > against the inferior directly. You'd do something like the patch below, on top of yours. Completely untested. Just for illustration. However, unless this info is recorded in core dumps, this is all of course broken for core file debugging ... Do we _really_ need to know the sigtramp location? What does the sigtramp disassembly look like? How about just detecting the sigtramp like other platforms do, by recognizing the instructions? On Linux, this is just: mov $__NR_rt_sigreturn, %rax syscall And is parsed in amd64_linux_sigtramp_p -> amd64_linux_sigtramp_start. Looking at: https://github.com/freebsd/freebsd/blob/master/sys/amd64/amd64/sigtramp.S It looks pretty much the same. That should make it always work correctly for (cross) core and remote debugging. ------------- From 3193c7b56d459d72d76031c299b939fee1afe265 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Tue, 10 Feb 2015 22:11:42 +0000 Subject: [PATCH] AMD64 FreeBSD: get sigtramp of the current inferior instead of gdb's. --- gdb/amd64fbsd-nat.c | 103 ++++++++++++++++++++++++++++--------------------- gdb/amd64fbsd-tdep.c | 27 ++++++++++--- gdb/target-debug.h | 8 ++++ gdb/target-delegates.c | 33 ++++++++++++++++ gdb/target.h | 12 ++++++ 5 files changed, 132 insertions(+), 51 deletions(-) diff --git a/gdb/amd64fbsd-nat.c b/gdb/amd64fbsd-nat.c index 762b13f..ca962e1 100644 --- a/gdb/amd64fbsd-nat.c +++ b/gdb/amd64fbsd-nat.c @@ -140,6 +140,62 @@ amd64fbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) } +static int +amd64fbsd_get_signal_trampoline (struct target_ops *ops, + struct mem_range *range) +{ +#ifdef KERN_PROC_SIGTRAMP + /* FreeBSD 9.2 and later provide a kern.proc.sigtramp. + sysctl that returns the location of the signal trampoline. */ + { + 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] = ptid_get_pid (inferior_ptid); + len = sizeof (kst); + if (sysctl (mib, 4, &kst, &len, NULL, 0) == 0) + { + CORE_ADDR start_addr = (uintptr_t) kst.ksigtramp_start; + CORE_ADDR end_addr = (uintptr_t) kst.ksigtramp_end; + + range->start = start_addr; + range->length = end_addr - start_addr; + return 1; + } + } +#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 + still based on the assumption that the sigtramp is placed + directly under the location where the program arguments and + environment can be found. */ + { + int mib[2]; + long ps_strings; + 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) + { + CORE_ADDR start_addr = ps_strings - 32; + CORE_ADDR end_addr = ps_strings; + + range->start = start_addr; + range->length = end_addr - start_addr; + return 1; + } + } +#endif + return 0; +} + static void (*super_mourn_inferior) (struct target_ops *ops); static void @@ -166,6 +222,8 @@ _initialize_amd64fbsd_nat (void) /* Add some extra features to the common *BSD/i386 target. */ t = amd64bsd_target (); + t->to_get_signal_trampoline = amd64fbsd_get_signal_trampoline; + #ifdef HAVE_PT_GETDBREGS x86_use_watchpoints (t); @@ -244,49 +302,4 @@ Please report this to ."), } SC_RBP_OFFSET = offset; - -#ifdef KERN_PROC_SIGTRAMP - /* FreeBSD 9.2 and later 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 - still based on the assumption that the sigtramp is placed - directly under the location where the program arguments and - environment can be found. */ - { - int mib[2]; - long ps_strings; - 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) - { - amd64fbsd_sigtramp_start_addr = ps_strings - 32; - amd64fbsd_sigtramp_end_addr = ps_strings; - } - } -#endif } diff --git a/gdb/amd64fbsd-tdep.c b/gdb/amd64fbsd-tdep.c index abb0cab..69cd186 100644 --- a/gdb/amd64fbsd-tdep.c +++ b/gdb/amd64fbsd-tdep.c @@ -87,10 +87,6 @@ static int amd64fbsd_r_reg_offset[] = -1 /* %gs */ }; -/* Location of the signal trampoline. */ -CORE_ADDR amd64fbsd_sigtramp_start_addr = 0x7fffffffffc0ULL; -CORE_ADDR amd64fbsd_sigtramp_end_addr = 0x7fffffffffe0ULL; - /* From . */ int amd64fbsd_sc_reg_offset[] = { @@ -182,6 +178,26 @@ amd64fbsd_collect_uthread (const struct regcache *regcache, } } +/* Return whether THIS_FRAME corresponds to a NetBSD sigtramp + routine. */ + +static int +amd64fbsd_sigtramp_p (struct frame_info *this_frame) +{ + struct mem_range range; + CORE_ADDR pc; + + if (!target_get_signal_trampoline (&range)) + { + /* Fallback to hardcoded location... */ + range.start = 0x7fffffffffc0ULL; + range.length = 0x7fffffffffe0ULL - range.start; + } + + pc = get_frame_pc (this_frame); + return address_in_mem_range (pc, &range); +} + static void amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -199,8 +215,7 @@ amd64fbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) amd64_init_abi (info, gdbarch); - tdep->sigtramp_start = amd64fbsd_sigtramp_start_addr; - tdep->sigtramp_end = amd64fbsd_sigtramp_end_addr; + 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); diff --git a/gdb/target-debug.h b/gdb/target-debug.h index 63ce12c..f114a07 100644 --- a/gdb/target-debug.h +++ b/gdb/target-debug.h @@ -193,4 +193,12 @@ target_debug_print_signals (unsigned char *sigs) fputs_unfiltered (" }", gdb_stdlog); } +static void +target_debug_print_struct_mem_range_p (struct mem_range *range) +{ + fprintf_unfiltered (gdb_stdlog, "[%s:%x]", + paddress (target_gdbarch (), range->start), + range->length); +} + #endif /* TARGET_DEBUG_H */ diff --git a/gdb/target-delegates.c b/gdb/target-delegates.c index e026179..4f9cb72 100644 --- a/gdb/target-delegates.c +++ b/gdb/target-delegates.c @@ -3764,6 +3764,35 @@ debug_done_generating_core (struct target_ops *self) fputs_unfiltered (")\n", gdb_stdlog); } +static int +delegate_get_signal_trampoline (struct target_ops *self, struct mem_range *arg1) +{ + self = self->beneath; + return self->to_get_signal_trampoline (self, arg1); +} + +static int +tdefault_get_signal_trampoline (struct target_ops *self, struct mem_range *arg1) +{ + return 0; +} + +static int +debug_get_signal_trampoline (struct target_ops *self, struct mem_range *arg1) +{ + int result; + fprintf_unfiltered (gdb_stdlog, "-> %s->to_get_signal_trampoline (...)\n", debug_target.to_shortname); + result = debug_target.to_get_signal_trampoline (&debug_target, arg1); + fprintf_unfiltered (gdb_stdlog, "<- %s->to_get_signal_trampoline (", debug_target.to_shortname); + target_debug_print_struct_target_ops_p (&debug_target); + fputs_unfiltered (", ", gdb_stdlog); + target_debug_print_struct_mem_range_p (arg1); + fputs_unfiltered (") = ", gdb_stdlog); + target_debug_print_int (result); + fputs_unfiltered ("\n", gdb_stdlog); + return result; +} + static void install_delegators (struct target_ops *ops) { @@ -4045,6 +4074,8 @@ install_delegators (struct target_ops *ops) ops->to_prepare_to_generate_core = delegate_prepare_to_generate_core; if (ops->to_done_generating_core == NULL) ops->to_done_generating_core = delegate_done_generating_core; + if (ops->to_get_signal_trampoline == NULL) + ops->to_get_signal_trampoline = delegate_get_signal_trampoline; } static void @@ -4189,6 +4220,7 @@ install_dummy_methods (struct target_ops *ops) ops->to_decr_pc_after_break = default_target_decr_pc_after_break; ops->to_prepare_to_generate_core = tdefault_prepare_to_generate_core; ops->to_done_generating_core = tdefault_done_generating_core; + ops->to_get_signal_trampoline = tdefault_get_signal_trampoline; } static void @@ -4333,4 +4365,5 @@ init_debug_target (struct target_ops *ops) ops->to_decr_pc_after_break = debug_decr_pc_after_break; ops->to_prepare_to_generate_core = debug_prepare_to_generate_core; ops->to_done_generating_core = debug_done_generating_core; + ops->to_get_signal_trampoline = debug_get_signal_trampoline; } diff --git a/gdb/target.h b/gdb/target.h index fb60123..e509e5e 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -1141,6 +1141,15 @@ struct target_ops void (*to_done_generating_core) (struct target_ops *) TARGET_DEFAULT_IGNORE (); + /* Return the current target's signal trampoline address range. + Return true on success, false if the information isn't + available. This is implemented on targets that need to query + the kernel for this information. Most ports we get at this + information through gdbarch/osabi instead. */ + int (*to_get_signal_trampoline) (struct target_ops *ops, + struct mem_range *range) + TARGET_DEFAULT_RETURN (0); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -2055,6 +2064,9 @@ extern int simple_verify_memory (struct target_ops* ops, int target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size); +#define target_get_signal_trampoline(range) \ + (*current_target.to_get_signal_trampoline) (¤t_target, range) + /* Routines for maintenance of the target structures... complete_target_initialization: Finalize a target_ops by filling in