From patchwork Thu Apr 17 10:15:16 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 594 Return-Path: X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx22.g.dreamhost.com (mx2.sub5.homie.mail.dreamhost.com [208.113.200.128]) by wilcox.dreamhost.com (Postfix) with ESMTP id DCD4936007C for ; Thu, 17 Apr 2014 03:15:52 -0700 (PDT) Received: by homiemail-mx22.g.dreamhost.com (Postfix, from userid 14314964) id 9B7E14A466A0; Thu, 17 Apr 2014 03:15:52 -0700 (PDT) X-Original-To: gdb@patchwork.siddhesh.in Delivered-To: x14314964@homiemail-mx22.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx22.g.dreamhost.com (Postfix) with ESMTPS id 745194A4666F for ; Thu, 17 Apr 2014 03:15:52 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type; q=dns; s=default; b=S1+iV zIJbhnN9TZ9oIZ4JEFQCW43B3aurZYq8r/Tgkc7iYPvuAdkolrsH+BZ4oKeTn0YC noYne1UmVp00GvD8jtT3EeNQ+iN+3iryDtapr2+4HW09XnUS0g5gj709b8Tzs4S0 Z1A1nRDqjTHSbJXIzM5U8TDdNO8V7hEWaJyars= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type; s=default; bh=3Rh3gRcO0Aj +br7bBfTJ7Q/NuLg=; b=yiOl0tDvR3xnt4rN9CoAlQS+TPMcRQbLozE5jzU6pvW 2rSqVLk0GDhdnyqYeFp5OXXi2ZGHRsjE0r5ge/pY9vsy7PCXHedPkweIDt4L2mzP 1yWcshkQFwyXlmD7O1K65kK4JAbYwdnrnNbN2XuQTNDgyeeKbvnH+iQHuKnFscKI = Received: (qmail 31778 invoked by alias); 17 Apr 2014 10:15:34 -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 31598 invoked by uid 89); 17 Apr 2014 10:15:33 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.1 required=5.0 tests=AWL, BAYES_00, RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-gw1-out.broadcom.com Received: from mail-gw1-out.broadcom.com (HELO mail-gw1-out.broadcom.com) (216.31.210.62) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 17 Apr 2014 10:15:30 +0000 Received: from irvexchcas06.broadcom.com (HELO IRVEXCHCAS06.corp.ad.broadcom.com) ([10.9.208.53]) by mail-gw1-out.broadcom.com with ESMTP; 17 Apr 2014 04:19:30 -0700 Received: from IRVEXCHSMTP3.corp.ad.broadcom.com (10.9.207.53) by IRVEXCHCAS06.corp.ad.broadcom.com (10.9.208.53) with Microsoft SMTP Server (TLS) id 14.3.174.1; Thu, 17 Apr 2014 03:15:29 -0700 Received: from mail-irva-13.broadcom.com (10.10.10.20) by IRVEXCHSMTP3.corp.ad.broadcom.com (10.9.207.53) with Microsoft SMTP Server id 14.3.174.1; Thu, 17 Apr 2014 03:15:29 -0700 Received: from xl-cam-21.broadcom.com (xl-cam-21.cam.broadcom.com [10.177.132.81]) by mail-irva-13.broadcom.com (Postfix) with ESMTP id C2968EAD4F; Thu, 17 Apr 2014 03:15:28 -0700 (PDT) Received: by xl-cam-21.broadcom.com (Postfix, from userid 15136) id 149792CE89A1; Thu, 17 Apr 2014 11:15:28 +0100 (BST) From: Andrew Burgess To: CC: Andrew Burgess Subject: [PATCH v2 4/4] Add a TRY_CATCH to get_prev_frame to better handle errors during unwind. Date: Thu, 17 Apr 2014 11:15:16 +0100 Message-ID: <1397729716-8985-5-git-send-email-aburgess@broadcom.com> In-Reply-To: <533EC5B7.6080600@broadcom.com> References: <533EC5B7.6080600@broadcom.com> MIME-Version: 1.0 X-IsSubscribed: yes X-DH-Original-To: gdb@patchwork.siddhesh.in gdb/ChangeLog: * frame.c (struct frame_info): Add stop_string field. (get_prev_frame_2): Renamed from get_prev_frame_1. (get_prev_frame_1): Old content moved into get_prev_frame_2. Call get_prev_frame_2 inside TRY_CATCH, handle errors. (frame_stop_reason_string): New function definition. * frame.h (frame_stop_reason_string): New function declaration. * stack.c (frame_info): Switch to frame_stop_reason_string. (backtrace_command_1): Switch to frame_stop_reason_string. * unwind_stop_reason.def: Add UNWIND_MISC_ERROR. gdb/testsuite/ChangeLog: * gdb.arch/amd64-invalid-stack-middle.exp: Update expected results. * gdb.arch/amd64-invalid-stack-top.exp: Likewise. ~ChangeLog~ --- gdb/frame.c | 69 ++++++++++++++++++++-- gdb/frame.h | 6 ++ gdb/stack.c | 4 +- .../gdb.arch/amd64-invalid-stack-middle.exp | 22 +------ gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp | 22 +------ gdb/unwind_stop_reasons.def | 5 +- 6 files changed, 81 insertions(+), 47 deletions(-) diff --git a/gdb/frame.c b/gdb/frame.c index 5a6e0c7..65ba49b 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -146,6 +146,10 @@ struct frame_info /* The reason why we could not set PREV, or UNWIND_NO_REASON if we could. Only valid when PREV_P is set. */ enum unwind_stop_reason stop_reason; + + /* A frame specific string describing the STOP_REASON in more detail. + Only valid when PREV_P is set, but even then may still be NULL. */ + const char *stop_string; }; /* A frame stash used to speed up frame lookups. Create a hash table @@ -1793,14 +1797,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame) return prev_frame; } -/* Return a "struct frame_info" corresponding to the frame that called - THIS_FRAME. Returns NULL if there is no such frame. - - Unlike get_prev_frame, this function always tries to unwind the - frame. */ +/* Helper function for get_prev_frame_1, this is called inside a + TRY_CATCH block. Return the frame that called THIS_FRAME or NULL if + there is no such frame. This may throw an exception. */ static struct frame_info * -get_prev_frame_1 (struct frame_info *this_frame) +get_prev_frame_2 (struct frame_info *this_frame) { struct gdbarch *gdbarch; @@ -1950,6 +1952,41 @@ get_prev_frame_1 (struct frame_info *this_frame) return get_prev_frame_if_no_cycle (this_frame); } +/* Return a "struct frame_info" corresponding to the frame that called + THIS_FRAME. Returns NULL if there is no such frame. + + Unlike get_prev_frame, this function always tries to unwind the + frame. */ + +static struct frame_info * +get_prev_frame_1 (struct frame_info *this_frame) +{ + volatile struct gdb_exception ex; + struct frame_info *prev_frame = NULL; + + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + prev_frame = get_prev_frame_2 (this_frame); + } + if (ex.reason < 0) + { + this_frame->stop_reason = UNWIND_MISC_ERROR; + if (ex.message != NULL) + { + char *stop_string; + + /* The error needs to live as long as the frame does. */ + stop_string = + FRAME_OBSTACK_CALLOC (strlen (ex.message) + 1, char); + strcpy (stop_string, ex.message); + this_frame->stop_string = stop_string; + } + prev_frame = NULL; + } + + return prev_frame; +} + /* Construct a new "struct frame_info" and link it previous to this_frame. */ @@ -2571,6 +2608,26 @@ deprecated_frame_stop_reason_string (enum unwind_stop_reason reason) } } +/* Return a possibly frame specific string explaining why the unwind + stopped at frame FI. Must only be called if there is no previous + frame. */ + +const char * +frame_stop_reason_string (struct frame_info *fi) +{ + gdb_assert (fi->prev_p); + gdb_assert (fi->prev == NULL); + + /* Return the specific string if we have one. */ + if (fi->stop_string) + return fi->stop_string; + + /* Return the generic string if we have nothing better. At some point + if DEPRECATED_FRAME_STOP_REASON_STRING is not used anywhere else then + its content could be moved into here. */ + return deprecated_frame_stop_reason_string (fi->stop_reason); +} + /* Return the enum symbol name of REASON as a string, to use in debug output. */ diff --git a/gdb/frame.h b/gdb/frame.h index 7db5382..1a5614d 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -500,6 +500,12 @@ enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *); const char *deprecated_frame_stop_reason_string (enum unwind_stop_reason); +/* Return a possibly frame specific string explaining why the unwind + stopped here. Should only be called for frames that don't have a + previous frame. If there's no specific reason stored for a frame then + a generic reason string will be returned. */ +const char *frame_stop_reason_string (struct frame_info *); + /* Unwind the stack frame so that the value of REGNUM, in the previous (up, older) frame is returned. If VALUEP is NULL, don't fetch/compute the value. Instead just return the location of the diff --git a/gdb/stack.c b/gdb/stack.c index 4fa9dd6..3f8ecfb 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -1528,7 +1528,7 @@ frame_info (char *addr_exp, int from_tty) reason = get_frame_unwind_stop_reason (fi); if (reason != UNWIND_NO_REASON) printf_filtered (_(" Outermost frame: %s\n"), - deprecated_frame_stop_reason_string (reason)); + frame_stop_reason_string (fi)); } else if (get_frame_type (fi) == TAILCALL_FRAME) puts_filtered (" tail call frame"); @@ -1847,7 +1847,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters, reason = get_frame_unwind_stop_reason (trailing); if (reason >= UNWIND_FIRST_ERROR) printf_filtered (_("Backtrace stopped: %s\n"), - deprecated_frame_stop_reason_string (reason)); + frame_stop_reason_string (trailing)); } } } diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp index ef70a4f..b53ad41 100644 --- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp +++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp @@ -43,27 +43,11 @@ if ![runto breakpt] { return -1 } -gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \ +gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \ "first backtrace, with error message" -send_gdb "bt\n" -gdb_expect { - -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" { - # Currently gdb will not display the error message associated with - # the truncated backtrace after the first backtrace has been - # completed. Ideally, we would do this. If this case is ever hit - # then we have started to display the backtrace in all cases and - # the xpass should becomd a pass, and the previous pass case below - # should be removed, or changed to a fail. - xpass "second backtrace, with error message" - } - -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" { - pass "second backtrace, without error message" - } - timeout { - fail "second backtrace (timeout)" - } -} +gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \ + "second backtrace, with error message" clean_restart ${binfile} diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp index 6598cd4..52869a2 100644 --- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp +++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp @@ -46,27 +46,11 @@ if ![runto breakpt] { # Use 'bt no-filters' here as the python filters will raise their own # error during initialisation, the no-filters case is simpler. -gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \ +gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \ "first backtrace, with error message" -send_gdb "bt no-filters\n" -gdb_expect { - -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" { - # Currently gdb will not display the error message associated with - # the truncated backtrace after the first backtrace has been - # completed. Ideally, we would do this. If this case is ever hit - # then we have started to display the backtrace in all cases and - # the xpass should becomd a pass, and the previous pass case below - # should be removed, or changed to a fail. - xpass "second backtrace, with error message" - } - -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" { - pass "second backtrace, without error message" - } - timeout { - fail "second backtrace (timeout)" - } -} +gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \ + "second backtrace, with error message" clean_restart ${binfile} diff --git a/gdb/unwind_stop_reasons.def b/gdb/unwind_stop_reasons.def index d7da7ea..84cfb75 100644 --- a/gdb/unwind_stop_reasons.def +++ b/gdb/unwind_stop_reasons.def @@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)") one to unwind further. */ SET (UNWIND_NO_SAVED_PC, "frame did not save the PC") +/* The frame unwinder threw some other error which we caught. */ +SET (UNWIND_MISC_ERROR, "miscellaneous error while unwinding") + #endif /* SET */ @@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON) #endif #ifdef LAST_ENTRY -LAST_ENTRY (UNWIND_NO_SAVED_PC) +LAST_ENTRY (UNWIND_MISC_ERROR) #endif