From patchwork Thu Jan 7 17:44:54 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Tremblay X-Patchwork-Id: 10269 Received: (qmail 27245 invoked by alias); 7 Jan 2016 17:45:11 -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 27174 invoked by uid 89); 7 Jan 2016 17:45:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.1 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY autolearn=no version=3.3.2 spammy=tfind, pendfunc2, Manual, Our X-HELO: usplmg20.ericsson.net Received: from usplmg20.ericsson.net (HELO usplmg20.ericsson.net) (198.24.6.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-SHA encrypted) ESMTPS; Thu, 07 Jan 2016 17:45:07 +0000 Received: from EUSAAHC008.ericsson.se (Unknown_Domain [147.117.188.96]) by usplmg20.ericsson.net (Symantec Mail Security) with SMTP id BD.C4.06940.542AE865; Thu, 7 Jan 2016 18:37:09 +0100 (CET) Received: from elxa4wqvvz1.dyn.mo.ca.am.ericsson.se (147.117.188.8) by smtps-am.internal.ericsson.com (147.117.188.96) with Microsoft SMTP Server (TLS) id 14.3.248.2; Thu, 7 Jan 2016 12:45:04 -0500 From: Antoine Tremblay To: CC: Antoine Tremblay Subject: [PATCH 1/4] Teach arm unwinders to terminate gracefully Date: Thu, 7 Jan 2016 12:44:54 -0500 Message-ID: <1452188697-23870-2-git-send-email-antoine.tremblay@ericsson.com> In-Reply-To: <1452188697-23870-1-git-send-email-antoine.tremblay@ericsson.com> References: <1452188697-23870-1-git-send-email-antoine.tremblay@ericsson.com> MIME-Version: 1.0 X-IsSubscribed: yes When examining a trace buffer we have the following issue: ~~~ tfind start Register 13 is not available Found trace frame 0, tracepoint 2 #-1 0x40123556 in pendfunc2 ^^^ ~~~ The reason for this is that the target's stack pointer is unavailable when examining the trace buffer. What we are seeing is due to the 'tfind' command creating a sentinel frame and unwinding it. If an exception is thrown, we are left with the sentinel frame being displayed at level #-1. The exception is thrown when the prologue unwinder tries to read the stack pointer to construct an ID for the frame. This patch fixes this and similar issues by making all the arm unwinders catch NOT_AVAILABLE_ERROR exceptions when either register or memory is unreadable and report back to the frame core code with UNWIND_UNAVAILABLE. Note this commit log adapted from 7dfa3edc033c443036d9f2a3e01120f7fb54f498 which fixed a similar issue for aarch64. No regressions, tested on ubuntu 14.04 ARMv7 and x86. With gdbserver-{native,extended} / { -marm -mthumb } gdb/ChangeLog: * arm-tdep.c (struct arm_prologue_cache) : New field. (arm_make_prologue_cache): Swallow NOT_AVAIABLE_ERROR or set available_p. (arm_prologue_unwind_stop_reason): Return UNWIND_UNAVAILABLE if available_p is not set. (arm_prologue_this_id): Call frame_id_build_unavailable_stack if available_p is not set. (arm_make_stub_cache): Swallow NOT_AVAIABLE_ERROR or set available_p. (arm_stub_this_id): Call frame_id_build_unavailable_stack if available_p is not set. (arm_m_exception_cache): Swallow NOT_AVAIABLE_ERROR or set available_p. (arm_m_exception_this_id): Call frame_id_build_unavailable_stack if available_p is not set. --- gdb/arm-tdep.c | 142 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 47 deletions(-) diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c index 05d60bb..5ee7fb0 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -252,6 +252,9 @@ struct arm_prologue_cache to identify this frame. */ CORE_ADDR prev_sp; + /* Is the target available to read from ? */ + int available_p; + /* The frame base for this frame is just prev_sp - frame size. FRAMESIZE is the distance from the frame pointer to the initial stack pointer. */ @@ -1793,19 +1796,29 @@ arm_make_prologue_cache (struct frame_info *this_frame) cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - arm_scan_prologue (this_frame, cache); + TRY + { + arm_scan_prologue (this_frame, cache); + unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg); + if (unwound_fp == 0) + return cache; - unwound_fp = get_frame_register_unsigned (this_frame, cache->framereg); - if (unwound_fp == 0) - return cache; + cache->prev_sp = unwound_fp + cache->framesize; - cache->prev_sp = unwound_fp + cache->framesize; + /* Calculate actual addresses of saved registers using offsets + determined by arm_scan_prologue. */ + for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) + if (trad_frame_addr_p (cache->saved_regs, reg)) + cache->saved_regs[reg].addr += cache->prev_sp; - /* Calculate actual addresses of saved registers using offsets - determined by arm_scan_prologue. */ - for (reg = 0; reg < gdbarch_num_regs (get_frame_arch (this_frame)); reg++) - if (trad_frame_addr_p (cache->saved_regs, reg)) - cache->saved_regs[reg].addr += cache->prev_sp; + cache->available_p = 1; + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw_exception (ex); + } + END_CATCH return cache; } @@ -1823,6 +1836,9 @@ arm_prologue_unwind_stop_reason (struct frame_info *this_frame, *this_cache = arm_make_prologue_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; + if (!cache->available_p) + return UNWIND_UNAVAILABLE; + /* This is meant to halt the backtrace at "_start". */ pc = get_frame_pc (this_frame); if (pc <= gdbarch_tdep (get_frame_arch (this_frame))->lowest_pc) @@ -1851,16 +1867,23 @@ arm_prologue_this_id (struct frame_info *this_frame, *this_cache = arm_make_prologue_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; - /* Use function start address as part of the frame ID. If we cannot - identify the start address (due to missing symbol information), - fall back to just using the current PC. */ - pc = get_frame_pc (this_frame); - func = get_frame_func (this_frame); - if (!func) - func = pc; + if (!cache->available_p) + { + *this_id = frame_id_build_unavailable_stack (cache->prev_sp); + } + else + { + /* Use function start address as part of the frame ID. If we cannot + identify the start address (due to missing symbol information), + fall back to just using the current PC. */ + pc = get_frame_pc (this_frame); + func = get_frame_func (this_frame); + if (!func) + func = pc; - id = frame_id_build (cache->prev_sp, func); - *this_id = id; + id = frame_id_build (cache->prev_sp, func); + *this_id = id; + } } static struct value * @@ -2738,7 +2761,17 @@ arm_make_stub_cache (struct frame_info *this_frame) cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + TRY + { + cache->prev_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + cache->available_p = 1; + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw_exception (ex); + } + END_CATCH return cache; } @@ -2756,7 +2789,10 @@ arm_stub_this_id (struct frame_info *this_frame, *this_cache = arm_make_stub_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; - *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame)); + if (!cache->available_p) + *this_id = frame_id_build_unavailable_stack (cache->prev_sp); + else + *this_id = frame_id_build (cache->prev_sp, get_frame_pc (this_frame)); } static int @@ -2809,29 +2845,38 @@ arm_m_exception_cache (struct frame_info *this_frame) cache = FRAME_OBSTACK_ZALLOC (struct arm_prologue_cache); cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - unwound_sp = get_frame_register_unsigned (this_frame, - ARM_SP_REGNUM); - - /* The hardware saves eight 32-bit words, comprising xPSR, - ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in - "B1.5.6 Exception entry behavior" in - "ARMv7-M Architecture Reference Manual". */ - cache->saved_regs[0].addr = unwound_sp; - cache->saved_regs[1].addr = unwound_sp + 4; - cache->saved_regs[2].addr = unwound_sp + 8; - cache->saved_regs[3].addr = unwound_sp + 12; - cache->saved_regs[12].addr = unwound_sp + 16; - cache->saved_regs[14].addr = unwound_sp + 20; - cache->saved_regs[15].addr = unwound_sp + 24; - cache->saved_regs[ARM_PS_REGNUM].addr = unwound_sp + 28; - - /* If bit 9 of the saved xPSR is set, then there is a four-byte - aligner between the top of the 32-byte stack frame and the - previous context's stack pointer. */ - cache->prev_sp = unwound_sp + 32; - if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr) - && (xpsr & (1 << 9)) != 0) - cache->prev_sp += 4; + TRY + { + unwound_sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM); + /* The hardware saves eight 32-bit words, comprising xPSR, + ReturnAddress, LR (R14), R12, R3, R2, R1, R0. See details in + "B1.5.6 Exception entry behavior" in + "ARMv7-M Architecture Reference Manual". */ + cache->saved_regs[0].addr = unwound_sp; + cache->saved_regs[1].addr = unwound_sp + 4; + cache->saved_regs[2].addr = unwound_sp + 8; + cache->saved_regs[3].addr = unwound_sp + 12; + cache->saved_regs[12].addr = unwound_sp + 16; + cache->saved_regs[14].addr = unwound_sp + 20; + cache->saved_regs[15].addr = unwound_sp + 24; + cache->saved_regs[ARM_PS_REGNUM].addr = unwound_sp + 28; + + /* If bit 9 of the saved xPSR is set, then there is a four-byte + aligner between the top of the 32-byte stack frame and the + previous context's stack pointer. */ + cache->prev_sp = unwound_sp + 32; + if (safe_read_memory_integer (unwound_sp + 28, 4, byte_order, &xpsr) + && (xpsr & (1 << 9)) != 0) + cache->prev_sp += 4; + + cache->available_p = 1; + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw_exception (ex); + } + END_CATCH return cache; } @@ -2850,9 +2895,12 @@ arm_m_exception_this_id (struct frame_info *this_frame, *this_cache = arm_m_exception_cache (this_frame); cache = (struct arm_prologue_cache *) *this_cache; - /* Our frame ID for a stub frame is the current SP and LR. */ - *this_id = frame_id_build (cache->prev_sp, - get_frame_pc (this_frame)); + if (!cache->available_p) + *this_id = frame_id_build_unavailable_stack (cache->prev_sp); + else + /* Our frame ID for a stub frame is the current SP and LR. */ + *this_id = frame_id_build (cache->prev_sp, + get_frame_pc (this_frame)); } /* Implementation of function hook 'prev_register' in