From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 50152 invoked by alias); 17 Jul 2019 11:15:52 -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 49805 invoked by uid 89); 17 Jul 2019 11:15:47 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 spammy=reaction X-HELO: mail-wr1-f67.google.com Received: from mail-wr1-f67.google.com (HELO mail-wr1-f67.google.com) (209.85.221.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 17 Jul 2019 11:15:45 +0000 Received: by mail-wr1-f67.google.com with SMTP id n4so24405770wrs.3 for ; Wed, 17 Jul 2019 04:15:45 -0700 (PDT) Return-Path: Received: from ?IPv6:2001:8a0:f913:f700:56ee:75ff:fe8d:232b? ([2001:8a0:f913:f700:56ee:75ff:fe8d:232b]) by smtp.gmail.com with ESMTPSA id t185sm17209501wma.11.2019.07.17.04.15.42 (version=TLS1_3 cipher=AEAD-AES128-GCM-SHA256 bits=128/128); Wed, 17 Jul 2019 04:15:42 -0700 (PDT) Subject: Re: [PATCH] AArch64 pauth: Indicate unmasked addresses in backtrace To: Alan Hayward , "gdb-patches@sourceware.org" References: <20190717081336.68835-1-alan.hayward@arm.com> Cc: nd From: Pedro Alves Message-ID: Date: Wed, 17 Jul 2019 11:15:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.2.1 MIME-Version: 1.0 In-Reply-To: <20190717081336.68835-1-alan.hayward@arm.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2019-07/txt/msg00380.txt.bz2 On 7/17/19 9:14 AM, Alan Hayward wrote: > Armv8.3-a Pointer Authentication causes the function return address to be > obfuscated on entry to some functions. GDB must unmask the link register in > order to produce a backtrace. > > The following patch adds markers of to the bracktrace, to indicate > which addresses needed unmasking. > > For example, consider the following backtrace: > > (gdb) bt > 0 0x0000000000400490 in puts@plt () > 1 0x00000000004005dc in foo ("hello") at cbreak-lib.c:6 > 2 0x0000000000400604 in bar () at cbreak-lib.c:12 > 3 0x0000000000400620 in barbar () at cbreak.c:17 > 4 0x00000000004005b4 in main () at cbreak-3.c:10 > > The functions in the cbreak-lib use pointer auth, obfuscating the return address > to the previous function. The caused the addresses of bar and barbar to require > unmasking in order to unwind the backtrace. > > Alternatively, I considered replacing with a single chracter, such > as * for brevity reasons, but felt this would be non obvious for the user. I don't have a particular suggestion, though my first reaction was that it seemed a bit verbose. IMHO, the marker doesn't have to stand out and be expressive, since users can always look at the manual. Once they learn something, often being concise helps -- or in other words, once you learn what "" or "U" or whatever is, and you're used to it, what would you rather see? What's the main information you're looking for when staring at the backtrace? Thoughts like that should guide the output too, IMO. > > An extra bool is added alongside the prev_pc in the frame struture. At the > point at which the link register is unmasked, the AArch64 port calls into frame > to sets the bool. This seemed the most efficient way of doing it. > > aarch64_frame_unmask_address is designed to work for any address, however at > the momoment it is only used for the link address. An extra default parameter > is added to ensure it only caches for the link register. typo: "momoment" > > I expect this will potentially cause issues with some tests in the testsuite > when Armv8.3 pointer authentication is used. This should be fixed up in the > the future once real hardware is available for full testsuite testing. > > 2019-07-17 Alan Hayward > > * NEWS: Expand the Pointer Authentication entry. > * aarch64-tdep.c (aarch64_frame_unmask_address): Mark frame if > unmasking link register. > * frame.c (struct frame_info): Add masked variable. * frame.c (struct frame_info): Add "masked" variable. > (frame_set_previous_pc_masked) (frame_get_pc_masked): New function. (frame_set_previous_pc_masked, frame_get_pc_masked): New functions. > * frame.h (frame_set_previous_pc_masked) (frame_get_pc_masked): New > declaration. * frame.h (frame_set_previous_pc_masked, frame_get_pc_masked): New declarations. > --- a/gdb/aarch64-tdep.c > +++ b/gdb/aarch64-tdep.c > @@ -251,12 +251,13 @@ class instruction_reader : public abstract_instruction_reader > } // namespace > > /* If address signing is enabled, mask off the signature bits from ADDR, using > - the register values in THIS_FRAME. */ > + the register values in THIS_FRAME. IS_LR indicates if ADDR is from the link > + register for the current frame. */ > > static CORE_ADDR > aarch64_frame_unmask_address (struct gdbarch_tdep *tdep, > - struct frame_info *this_frame, > - CORE_ADDR addr) > + struct frame_info *this_frame, CORE_ADDR addr, > + bool is_lr = true) I didn't see anywhere in the patch that passes is_lr == true? Looks like the patch is a nop? > { > if (tdep->has_pauth () > && frame_unwind_register_unsigned (this_frame, > @@ -265,6 +266,11 @@ aarch64_frame_unmask_address (struct gdbarch_tdep *tdep, > int cmask_num = AARCH64_PAUTH_CMASK_REGNUM (tdep->pauth_reg_base); > CORE_ADDR cmask = frame_unwind_register_unsigned (this_frame, cmask_num); > addr = addr & ~cmask; > + > + /* If addr was taken from the Link Register, then record this in the > + frame. */ > + if (is_lr) > + frame_set_previous_pc_masked (this_frame); > } > > return addr; > diff --git a/gdb/frame.c b/gdb/frame.c > index 84e0397db9..b7bb44986e 100644 > --- a/gdb/frame.c > +++ b/gdb/frame.c > @@ -124,6 +124,8 @@ struct frame_info > struct { > enum cached_copy_status status; > CORE_ADDR value; > + /* Did VALUE require unmasking when being read. */ > + bool masked; > } prev_pc; > > /* Cached copy of the previous frame's function address. */ > @@ -161,6 +163,21 @@ struct frame_info > const char *stop_string; > }; > > +/* See frame.h. */ > + > +void > +frame_set_previous_pc_masked (struct frame_info *frame) > +{ > + frame->prev_pc.masked = true; > +} > + > +/* See frame.h. */ > + > +bool frame_get_pc_masked (struct frame_info *frame) Formatting -- line break after bool. > +{ > + return frame->next->prev_pc.masked; I think this should assert that there's a frame->next, and that its status is CC_VALUE. > +} > + How about making the naming of the setter/getter consistent with other setters/getters in the file, get_frame_type, get_frame_pc, get_frame_program_space, etc, etc. set_frame_previous_pc_masked get_frame_pc_masked ? > /* A frame stash used to speed up frame lookups. Create a hash table > to stash frames previously accessed from the frame cache for > quicker subsequent retrieval. The hash table is emptied whenever > diff --git a/gdb/frame.h b/gdb/frame.h > index a79eeeeab1..61c12ec0b2 100644 > --- a/gdb/frame.h > +++ b/gdb/frame.h > @@ -930,4 +930,13 @@ extern const gdb::option::option_def set_backtrace_option_defs[2]; > /* The values behind the global "set backtrace ..." settings. */ > extern set_backtrace_options user_set_backtrace_options; > > +/* Mark that the PC value is masked for the previous frame. */ > + > +extern void frame_set_previous_pc_masked (struct frame_info *frame); > + > +/* Get whether the PC value is masked for the given frame. */ > + > +extern bool frame_get_pc_masked (struct frame_info *frame); > + > + > #endif /* !defined (FRAME_H) */ > diff --git a/gdb/stack.c b/gdb/stack.c > index 9b1d1a6856..cef1c29a82 100644 > --- a/gdb/stack.c > +++ b/gdb/stack.c > @@ -1254,7 +1254,11 @@ print_frame (const frame_print_options &fp_opts, > { > annotate_frame_address (); > if (pc_p) > - uiout->field_core_addr ("addr", gdbarch, pc); > + { > + uiout->field_core_addr ("addr", gdbarch, pc); > + if (frame_get_pc_masked (frame)) > + uiout->text (""); Did you consider whether a MI frontend would want to show this in its address column? Also, sounds like you'd want to tweak fprint_frame too, for debugging. > + } > else > uiout->field_string ("addr", "", > ui_out_style_kind::ADDRESS); > Thanks, Pedro Alves