[2/2] aarch64: implement walking over the stack protector

Message ID 20140603050314.GC15355@redacted.bos.redhat.com
State New, archived
Headers

Commit Message

Kyle McMartin June 3, 2014, 5:03 a.m. UTC
  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  <kmcmarti@redhat.com>

	* 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  <kmcmarti@redhat.com>

	* 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
  

Comments

Andrew Pinski June 3, 2014, 5:42 a.m. UTC | #1
On Mon, Jun 2, 2014 at 10:03 PM, Kyle McMartin <kmcmarti@redhat.com> 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  <kmcmarti@redhat.com>
>
>         * 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  <kmcmarti@redhat.com>
>
>         * 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 <http://www.gnu.org/licenses/>.  */
> +
> +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
>
  
Kyle McMartin June 3, 2014, 2:51 p.m. UTC | #2
On Mon, Jun 02, 2014 at 10:42:32PM -0700, Andrew Pinski wrote:
> > +    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.
> 

I'll look into it. Thanks Andrew.

--Kyle

> 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 <http://www.gnu.org/licenses/>.  */
> > +
> > +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
> >
  
Kyle McMartin June 5, 2014, 8:06 p.m. UTC | #3
On Tue, Jun 03, 2014 at 10:51:08AM -0400, Kyle McMartin wrote:
> On Mon, Jun 02, 2014 at 10:42:32PM -0700, Andrew Pinski wrote:
> > > +    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.
> > 
> 
> I'll look into it. Thanks Andrew.
> 

Finally got a toolchain built that supports ilp32... looks like the
existing code should work for it. The only difference (not sure if it's
because of gcc HEAD or what) is using w1 instead of x0 repeated for the
ldr/str, which looks to be satisfied by the rt/rt2 tests and size=10
included in the decode_masked_match. I'll try to build a static ilp32
binary to test it meanwhile, but I've had some other issues with gcc
HEAD.

regards, Kyle
  
Andrew Pinski June 5, 2014, 8:35 p.m. UTC | #4
On Thu, Jun 5, 2014 at 1:06 PM, Kyle McMartin <kmcmarti@redhat.com> wrote:
> On Tue, Jun 03, 2014 at 10:51:08AM -0400, Kyle McMartin wrote:
>> On Mon, Jun 02, 2014 at 10:42:32PM -0700, Andrew Pinski wrote:
>> > > +    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.
>> >
>>
>> I'll look into it. Thanks Andrew.
>>
>
> Finally got a toolchain built that supports ilp32... looks like the
> existing code should work for it. The only difference (not sure if it's
> because of gcc HEAD or what) is using w1 instead of x0 repeated for the
> ldr/str, which looks to be satisfied by the rt/rt2 tests and size=10
> included in the decode_masked_match. I'll try to build a static ilp32
> binary to test it meanwhile, but I've had some other issues with gcc
> HEAD.

Glibc support is not there yet though.  I will take over the issue
with ILP32 then.  When this goes in, can you file a bug and assign it
to me (pinskia@gcc.gnu.org I think is my email for sourceware
bugzilla)?

Thanks,
Andrew Pinski


>
> regards, Kyle
  
Kyle McMartin June 5, 2014, 8:53 p.m. UTC | #5
On Thu, Jun 05, 2014 at 01:35:54PM -0700, Andrew Pinski wrote:
> > Finally got a toolchain built that supports ilp32... looks like the
> > existing code should work for it. The only difference (not sure if it's
> > because of gcc HEAD or what) is using w1 instead of x0 repeated for the
> > ldr/str, which looks to be satisfied by the rt/rt2 tests and size=10
> > included in the decode_masked_match. I'll try to build a static ilp32
> > binary to test it meanwhile, but I've had some other issues with gcc
> > HEAD.
> 
> Glibc support is not there yet though.  I will take over the issue
> with ILP32 then.  When this goes in, can you file a bug and assign it
> to me (pinskia@gcc.gnu.org I think is my email for sourceware
> bugzilla)?
> 

Will do. Just ran this sequence through the code 'by hand' and it seems
to work on ILP32, fwiw.

--Kyle
  

Patch

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 <http://www.gnu.org/licenses/>.  */
+
+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;.*"