From patchwork Thu Nov 3 14:32:56 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antoine Tremblay X-Patchwork-Id: 17160 Received: (qmail 53025 invoked by alias); 3 Nov 2016 14:33: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 53008 invoked by uid 89); 3 Nov 2016 14:33:16 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, SPF_PASS autolearn=ham version=3.3.2 spammy=halt, H*RU:!Symantec, HX-Envelope-From:sk:antoine, H*r:Security X-HELO: usplmg21.ericsson.net Received: from usplmg21.ericsson.net (HELO usplmg21.ericsson.net) (198.24.6.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 03 Nov 2016 14:33:14 +0000 Received: from EUSAAHC002.ericsson.se (Unknown_Domain [147.117.188.78]) by (Symantec Mail Security) with SMTP id 1C.A1.02571.046FA185; Thu, 3 Nov 2016 09:33:05 +0100 (CET) Received: from elxa4wqvvz1.dyn.mo.ca.am.ericsson.se (147.117.188.8) by smtps-am.internal.ericsson.com (147.117.188.78) with Microsoft SMTP Server (TLS) id 14.3.319.2; Thu, 3 Nov 2016 10:33:08 -0400 From: Antoine Tremblay To: CC: Antoine Tremblay Subject: [PATCH V2 1/5] Teach arm unwinders to terminate gracefully Date: Thu, 3 Nov 2016 10:32:56 -0400 Message-ID: <20161103143300.24934-2-antoine.tremblay@ericsson.com> In-Reply-To: <20161103143300.24934-1-antoine.tremblay@ericsson.com> References: <20161103143300.24934-1-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 645825f..75343dd 100644 --- a/gdb/arm-tdep.c +++ b/gdb/arm-tdep.c @@ -258,6 +258,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. */ @@ -1847,19 +1850,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; } @@ -1877,6 +1890,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) @@ -1905,16 +1921,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 * @@ -2894,7 +2917,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; } @@ -2912,7 +2945,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 @@ -2965,29 +3001,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; } @@ -3006,9 +3051,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