From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 50645 invoked by alias); 7 Jul 2015 12:53:14 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 50627 invoked by uid 89); 7 Jul 2015 12:53:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.0 required=5.0 tests=AWL,BAYES_00,SPF_PASS autolearn=ham version=3.3.2 X-HELO: eu-smtp-delivery-143.mimecast.com Received: from eu-smtp-delivery-143.mimecast.com (HELO eu-smtp-delivery-143.mimecast.com) (207.82.80.143) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 07 Jul 2015 12:53:12 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.140]) by eu-smtp-1.mimecast.com with ESMTP id uk-mta-14-4sUdDcSFQp6L6scT2Ivjsw-9 Received: from e105615-lin.cambridge.arm.com ([10.1.2.79]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 7 Jul 2015 13:52:00 +0100 From: Pierre Langlois To: gdb-patches@sourceware.org Cc: Pierre Langlois Subject: [PATCH 4/8] [AArch64] Teach prologue unwinder to terminate gracefully Date: Tue, 07 Jul 2015 12:53:00 -0000 Message-Id: <1436273518-5959-5-git-send-email-pierre.langlois@arm.com> In-Reply-To: <1436273518-5959-1-git-send-email-pierre.langlois@arm.com> References: <1436273518-5959-1-git-send-email-pierre.langlois@arm.com> X-MC-Unique: 4sUdDcSFQp6L6scT2Ivjsw-9 Content-Type: text/plain; charset=WINDOWS-1252 Content-Transfer-Encoding: quoted-printable X-IsSubscribed: yes X-SW-Source: 2015-07/txt/msg00164.txt.bz2 Without debugging information, we have the following issue when examining a trace buffer: ~~~ ... (gdb) trace f Tracepoint 3 at 0x7fb7fc28c0 (gdb) tstart (gdb) continue ... (gdb) tstop (gdb) tfind start Register 31 is not available. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Found trace frame 0, tracepoint 3 #-1 0x0000007fb7fc28c0 in f () ... ^^^ ~~~ 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 by making the prologue unwinder catch NOT_AVAILABLE_ERROR exceptions when either registers or memory is unreadable and report back to the frame core code with UNWIND_UNAVAILABLE. The following test cases now pass when enabling tracepoints: PASS: gdb.trace/report.exp: live: 9.1: tdump, args collected PASS: gdb.trace/report.exp: live: 9.1: tdump, locals collected PASS: gdb.trace/report.exp: live: 12.3: trace report #3 PASS: gdb.trace/report.exp: tfile: 9.1: tdump, args collected PASS: gdb.trace/report.exp: tfile: 9.1: tdump, locals collected PASS: gdb.trace/report.exp: tfile: 12.3: trace report #3 PASS: gdb.trace/collection.exp: collect local string: collected local string PASS: gdb.trace/collection.exp: collect long local string: collected local = string PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing foo: tfind 0 PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing foo: p/d x PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing foo: p/d y PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing foo: p/d z PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing foo: tfind none PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: trace bar PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: tstart PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: continue PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: tstop PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: tfind 0 PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: p/d x PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: p/d y PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: p/d z PASS: gdb.trace/unavailable-dwarf-piece.exp: tracing bar: tfind none gdb/ChangeLog: * aarch64-tdep.c (aarch64_prologue_cache) : New field. (aarch64_make_prologue_cache_1): New function, factored out from aarch64_make_prologue_cache. Do not allocate cache. Set available_p. (aarch64_make_prologue_cache): Reimplement wrapping aarch64_make_prologue_cache_1, and swallowing NOT_AVAILABLE_ERROR. (aarch64_prologue_frame_unwind_stop_reason): New function. Return UNWIND_UNAVAILABLE if available_p is not set. (aarch64_prologue_unwind): Install it. (aarch64_prologue_this_id): Move prev_pc and prev_sp limit checks into aarch64_prologue_frame_unwind_stop_reason. Call frame_id_build_unavailable_stack if available_p is not set. --- gdb/aarch64-tdep.c | 82 +++++++++++++++++++++++++++++++++++++++-----------= ---- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 6a38f18..87a6d61 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -162,6 +162,9 @@ struct aarch64_prologue_cache to identify this frame. */ CORE_ADDR prev_sp; =20 + /* 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. */ @@ -944,28 +947,21 @@ aarch64_scan_prologue (struct frame_info *this_frame, /* Allocate an aarch64_prologue_cache and fill it with information about the prologue of *THIS_FRAME. */ =20 -static struct aarch64_prologue_cache * -aarch64_make_prologue_cache (struct frame_info *this_frame, void **this_ca= che) +static void +aarch64_make_prologue_cache_1 (struct frame_info *this_frame, + struct aarch64_prologue_cache *cache) { - struct aarch64_prologue_cache *cache; CORE_ADDR unwound_fp; int reg; =20 - if (*this_cache) - return *this_cache; - - cache =3D FRAME_OBSTACK_ZALLOC (struct aarch64_prologue_cache); - cache->saved_regs =3D trad_frame_alloc_saved_regs (this_frame); - *this_cache =3D cache; - aarch64_scan_prologue (this_frame, cache); =20 if (cache->framereg =3D=3D -1) - return cache; + return; =20 unwound_fp =3D get_frame_register_unsigned (this_frame, cache->framereg); if (unwound_fp =3D=3D 0) - return cache; + return; =20 cache->prev_sp =3D unwound_fp + cache->framesize; =20 @@ -977,9 +973,56 @@ aarch64_make_prologue_cache (struct frame_info *this_f= rame, void **this_cache) =20 cache->func =3D get_frame_func (this_frame); =20 + cache->available_p =3D 1; +} + +static struct aarch64_prologue_cache * +aarch64_make_prologue_cache (struct frame_info *this_frame, void **this_ca= che) +{ + struct aarch64_prologue_cache *cache; + + if (*this_cache) + return *this_cache; + + cache =3D FRAME_OBSTACK_ZALLOC (struct aarch64_prologue_cache); + cache->saved_regs =3D trad_frame_alloc_saved_regs (this_frame); + *this_cache =3D cache; + + TRY + { + aarch64_make_prologue_cache_1 (this_frame, cache); + } + CATCH (ex, RETURN_MASK_ERROR) + { + if (ex.error !=3D NOT_AVAILABLE_ERROR) + throw_exception (ex); + } + END_CATCH + return cache; } =20 +static enum unwind_stop_reason +aarch64_prologue_frame_unwind_stop_reason (struct frame_info *this_frame, + void **this_cache) +{ + struct aarch64_prologue_cache *cache + =3D aarch64_make_prologue_cache (this_frame, this_cache); + + if (!cache->available_p) + return UNWIND_UNAVAILABLE; + + /* Halt the backtrace at "_start". */ + if (cache->prev_pc <=3D gdbarch_tdep (get_frame_arch (this_frame))->lowe= st_pc) + return UNWIND_OUTERMOST; + + /* We've hit a wall, stop. */ + if (cache->prev_sp =3D=3D 0) + return UNWIND_OUTERMOST; + + return UNWIND_NO_REASON; +} + /* Our frame ID for a normal frame is the current function's starting PC and the caller's SP when we were called. */ =20 @@ -990,15 +1033,10 @@ aarch64_prologue_this_id (struct frame_info *this_fr= ame, struct aarch64_prologue_cache *cache =3D aarch64_make_prologue_cache (this_frame, this_cache); =20 - /* This is meant to halt the backtrace at "_start". */ - if (cache->prev_pc <=3D gdbarch_tdep (get_frame_arch (this_frame))->lowe= st_pc) - return; - - /* If we've hit a wall, stop. */ - if (cache->prev_sp =3D=3D 0) - return; - - *this_id =3D frame_id_build (cache->prev_sp, cache->func); + if (!cache->available_p) + *this_id =3D frame_id_build_unavailable_stack (cache->func); + else + *this_id =3D frame_id_build (cache->prev_sp, cache->func); } =20 /* Implement the "prev_register" frame_unwind method. */ @@ -1049,7 +1087,7 @@ aarch64_prologue_prev_register (struct frame_info *th= is_frame, struct frame_unwind aarch64_prologue_unwind =3D { NORMAL_FRAME, - default_frame_unwind_stop_reason, + aarch64_prologue_frame_unwind_stop_reason, aarch64_prologue_this_id, aarch64_prologue_prev_register, NULL, --=20 2.1.0