From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 20436 invoked by alias); 3 Jun 2014 05:42:37 -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 20420 invoked by uid 89); 3 Jun 2014 05:42:36 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.6 required=5.0 tests=AWL,BAYES_00,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,SPF_PASS,UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mail-vc0-f182.google.com Received: from mail-vc0-f182.google.com (HELO mail-vc0-f182.google.com) (209.85.220.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 03 Jun 2014 05:42:34 +0000 Received: by mail-vc0-f182.google.com with SMTP id id10so6262024vcb.13 for ; Mon, 02 Jun 2014 22:42:32 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.58.29.106 with SMTP id j10mr7961513veh.31.1401774152095; Mon, 02 Jun 2014 22:42:32 -0700 (PDT) Received: by 10.58.243.98 with HTTP; Mon, 2 Jun 2014 22:42:32 -0700 (PDT) In-Reply-To: <20140603050314.GC15355@redacted.bos.redhat.com> References: <20140603050011.GA15355@redacted.bos.redhat.com> <20140603050314.GC15355@redacted.bos.redhat.com> Date: Tue, 03 Jun 2014 05:42:00 -0000 Message-ID: Subject: Re: [PATCH 2/2] aarch64: implement walking over the stack protector From: Andrew Pinski To: Kyle McMartin Cc: "gdb-patches@sourceware.org" Content-Type: text/plain; charset=UTF-8 X-IsSubscribed: yes X-SW-Source: 2014-06/txt/msg00061.txt.bz2 On Mon, Jun 2, 2014 at 10:03 PM, Kyle McMartin wrote: > Stepping into a function which contains the stack protector sequences > currently stops inside the prologue, resulting in us claiming to be on > the opening bracket or similar, instead of a useful statement inside the > function. Fix that by analysing the prologue instruction, and attempt to > walk through the sequence of instructions which set up the stack > protector canary. > > gdb/ > 2014-06-03 Kyle McMartin > > * aarch64-tdep.c (aarch64_skip_stack_chk_guard): New. > (aarch64_skip_prologue): Skip over stack protector setup if possible. > > gdb/testsuite/ > 2014-06-03 Kyle McMartin > > * gdb.arch/aarch64-stack_chk_guard.c: New file. > * gdb.arch/aarch64-stack_chk_guard.exp: New file. > --- > gdb/aarch64-tdep.c | 99 +++++++++++++++++++++- > gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.c | 28 ++++++ > gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.exp | 43 ++++++++++ > 3 files changed, 169 insertions(+), 1 deletion(-) > create mode 100644 gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.c > create mode 100644 gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.exp > > diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c > index 9550f42..0c900ce 100644 > --- a/gdb/aarch64-tdep.c > +++ b/gdb/aarch64-tdep.c > @@ -852,6 +852,99 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, > return start; > } > > +/* Attempt to skip the stack protector instructions in a function prologue. > + If PC points to the first instruction of the sequence, return the > + address of the instruction after the stack protector sequence. Otherwise, > + return the original PC. > + > + On AArch64, the stack protector sequence is composed of four instructions: > + > + adrp x0, __stack_chk_guard > + add x0, x0, #:lo12:__stack_chk_guard > + ldr x0, [x0] > + str x0, [x29, #end-of-stack] Can you expand this for ILP32? The sequence is the same except to use w0 instead of x0. Otherwise I can put it on my todo list to after I submit the gdb support for ILP32. Thanks, Andrew Pinski > + > + Which loads the address of __stack_chk_guard, then loads the guard from it, > + and stores it at the end of the stack. */ > + > +static CORE_ADDR > +aarch64_skip_stack_chk_guard (CORE_ADDR pc, struct gdbarch *gdbarch) > +{ > + enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch); > + CORE_ADDR addr = pc; > + CORE_ADDR loc = pc; > + uint32_t insn; > + int64_t imm; > + int32_t imm32; > + unsigned rd, rd2, rn, rt; > + int page; > + const int insn_size = 4; > + struct bound_minimal_symbol stack_chk_guard; > + > + /* Attempt to find the label formation of __stack_chk_guard. */ > + insn = read_memory_unsigned_integer (loc, insn_size, byte_order_for_code); > + if (!decode_adrp (loc, insn, &page, &rd, &imm)) > + return pc; > + > + /* Bail if we saw an ADR instruction, not an ADRP. */ > + if (!page) > + return pc; > + > + loc += insn_size; > + addr &= ~((1 << 12) - 1); > + addr += imm; > + > + insn = read_memory_unsigned_integer (loc, insn_size, byte_order_for_code); > + if (!decode_add_sub_imm (loc, insn, &rd2, &rn, &imm32)) > + return pc; > + > + /* Ensure ADD register matches the ADRP instruction. */ > + if (rn != rd) > + return pc; > + > + loc += insn_size; > + addr += imm32; > + > + /* See if we calculated the address of the __stack_chk_guard symbol. */ > + stack_chk_guard = lookup_minimal_symbol_by_pc (addr); > + if (stack_chk_guard.minsym > + && strncmp (MSYMBOL_LINKAGE_NAME (stack_chk_guard.minsym), > + "__stack_chk_guard", strlen ("__stack_chk_guard")) != 0) > + return pc; > + > + /* Check if the next instruction is a load from the same registers. */ > + insn = read_memory_unsigned_integer (loc, insn_size, byte_order_for_code); > + if (decode_masked_match (insn, 0xffc00000, 0xf9400000)) > + { > + rt = insn & 0x1F; > + rn = (insn >> 5) & 0x1F; > + > + if (rn != rd2) > + return pc; > + } > + else > + return pc; > + > + /* Finally, look for a store of the guard to the stack. */ > + loc += insn_size; > + insn = read_memory_unsigned_integer (loc, insn_size, byte_order_for_code); > + if (decode_masked_match (insn, 0xffc00000, 0xf9000000)) > + { > + unsigned rt2 = insn & 0x1F; > + > + /* Check we're storing the guard from the previous load instruction. */ > + if (rt2 != rt) > + return pc; > + } > + else > + return pc; > + > + /* If we've made it this far, we've walked through the 4 instruction > + sequence around __stack_chk_guard, and can skip over it in the function > + prologue. */ > + return loc + insn_size; > +} > + > /* Implement the "skip_prologue" gdbarch method. */ > > static CORE_ADDR > @@ -871,7 +964,11 @@ aarch64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) > = skip_prologue_using_sal (gdbarch, func_addr); > > if (post_prologue_pc != 0) > - return max (pc, post_prologue_pc); > + { > + post_prologue_pc = aarch64_skip_stack_chk_guard (post_prologue_pc, > + gdbarch); > + return max (pc, post_prologue_pc); > + } > } > > /* Can't determine prologue from the symbol table, need to examine > diff --git a/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.c b/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.c > new file mode 100644 > index 0000000..3cf52d9 > --- /dev/null > +++ b/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.c > @@ -0,0 +1,28 @@ > +/* This file is part of GDB, the GNU debugger. > + > + Copyright 2014 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +int stack_chk_guard_fn(void) > +{ > + /* Needs to be large enough to trigger -fstack-protector. */ > + char stack[64]; > + return 0; /* Post function prologue statement. */ > +} > + > +int main(void) > +{ > + return stack_chk_guard_fn(); > +} > diff --git a/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.exp b/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.exp > new file mode 100644 > index 0000000..7f60867 > --- /dev/null > +++ b/gdb/testsuite/gdb.arch/aarch64-stack_chk_guard.exp > @@ -0,0 +1,43 @@ > +# Copyright 2014 Free Software Foundation, Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 3 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program; if not, write to the Free Software > +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. > +# > +# This file is part of the gdb testsuite. > + > +# Test that we single step past the __stack_chk_guard setup in the > +# prologue of functions. > + > +if {![istarget "aarch64*"]} { > + verbose "Skipping ${gdb_test_file_name}." > + return > +} > + > +standard_testfile > +set additional_flags "additional_flags=-fstack-protector" > +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } { > + unsupported "compiler does not support -fstack-protector" > + return > +} > + > +clean_restart "${binfile}" > +if ![runto_main] { > + untested "could not run to main" > + return -1 > +} > + > +gdb_breakpoint "stack_chk_guard_fn" > + > +# Previously, we'd see a { as we're still in the function prologue. > +gdb_continue_to_breakpoint "continue into stack_chk_guard_fn" ".*return 0;.*" > -- > 1.9.3 >