From patchwork Tue Jun 3 05:03:15 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kyle McMartin X-Patchwork-Id: 1253 Received: (qmail 10497 invoked by alias); 3 Jun 2014 05:03:20 -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 10487 invoked by uid 89); 3 Jun 2014 05:03:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.7 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN, RP_MATCHES_RCVD, SPF_HELO_PASS, SPF_PASS, UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 03 Jun 2014 05:03:18 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5353Hex023993 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Tue, 3 Jun 2014 01:03:17 -0400 Received: from redacted.bos.redhat.com ([10.18.17.143]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5353FWX002991 (version=TLSv1/SSLv3 cipher=AES128-GCM-SHA256 bits=128 verify=NO) for ; Tue, 3 Jun 2014 01:03:16 -0400 Date: Tue, 3 Jun 2014 01:03:15 -0400 From: Kyle McMartin To: gdb-patches@sourceware.org Subject: [PATCH 2/2] aarch64: implement walking over the stack protector Message-ID: <20140603050314.GC15355@redacted.bos.redhat.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20140603050011.GA15355@redacted.bos.redhat.com> User-Agent: Mutt/1.5.23 (2014-03-12) X-IsSubscribed: yes 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] + + 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;.*"