From 75faf5c41d7fc713b73cbb3523dcc6ca3855f98e Mon Sep 17 00:00:00 2001 From: Alan Hayward Date: Wed, 14 Aug 2019 15:47:05 +0100 Subject: [PATCH] AArch64: Allow additional sizes in prologue When saving registers to the stack at the start of a function, not all state needs to be saved. For example, only the first 64bits of float registers need saving. However, a program may choose to store extra state if it wishes, there is nothing preventing it doing so. The aarch64_analyze_prologue will error if it detects extra state being stored. Relex this restriction. Tested via aarch64-prologue test. gdb/ChangeLog: * aarch64-tdep.c (aarch64_analyze_prologue): Allow any valid register sizes. gdb/testsuite/ChangeLog: * gdb.arch/aarch64-prologue.c: New test. * gdb.arch/aarch64-prologue.exp: New file. --- gdb/ChangeLog | 5 ++ gdb/aarch64-tdep.c | 32 +++----- gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.arch/aarch64-prologue.c | 83 +++++++++++++++++++++ gdb/testsuite/gdb.arch/aarch64-prologue.exp | 36 +++++++++ 5 files changed, 139 insertions(+), 22 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/aarch64-prologue.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-prologue.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 15904da82c..6f7474f282 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2019-08-14 Alan Hayward + + * aarch64-tdep.c (aarch64_analyze_prologue): Allow any valid + register sizes. + 2019-08-14 Tom Tromey * darwin-nat.c: Include gdbarch.h. diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 9b6324f0fc..5e9f7b8ee0 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -387,17 +387,16 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, { unsigned rt = inst.operands[0].reg.regno; unsigned rn = inst.operands[1].addr.base_regno; - int is64 - = (aarch64_get_qualifier_esize (inst.operands[0].qualifier) == 8); + int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier); gdb_assert (aarch64_num_of_operands (inst.opcode) == 2); gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt); gdb_assert (inst.operands[1].type == AARCH64_OPND_ADDR_SIMM9); gdb_assert (!inst.operands[1].addr.offset.is_reg); - stack.store (pv_add_constant (regs[rn], - inst.operands[1].addr.offset.imm), - is64 ? 8 : 4, regs[rt]); + stack.store + (pv_add_constant (regs[rn], inst.operands[1].addr.offset.imm), + size, regs[rt]); } else if ((inst.opcode->iclass == ldstpair_off || (inst.opcode->iclass == ldstpair_indexed @@ -409,6 +408,7 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, unsigned rt2; unsigned rn = inst.operands[2].addr.base_regno; int32_t imm = inst.operands[2].addr.offset.imm; + int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier); gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt || inst.operands[0].type == AARCH64_OPND_Ft); @@ -430,17 +430,12 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, rt2 = inst.operands[1].reg.regno; if (inst.operands[0].type == AARCH64_OPND_Ft) { - /* Only bottom 64-bit of each V register (D register) need - to be preserved. */ - gdb_assert (inst.operands[0].qualifier == AARCH64_OPND_QLF_S_D); rt1 += AARCH64_X_REGISTER_COUNT; rt2 += AARCH64_X_REGISTER_COUNT; } - stack.store (pv_add_constant (regs[rn], imm), 8, - regs[rt1]); - stack.store (pv_add_constant (regs[rn], imm + 8), 8, - regs[rt2]); + stack.store (pv_add_constant (regs[rn], imm), size, regs[rt1]); + stack.store (pv_add_constant (regs[rn], imm + size), size, regs[rt2]); if (inst.operands[2].addr.writeback) regs[rn] = pv_add_constant (regs[rn], imm); @@ -457,21 +452,14 @@ aarch64_analyze_prologue (struct gdbarch *gdbarch, unsigned int rt = inst.operands[0].reg.regno; int32_t imm = inst.operands[1].addr.offset.imm; unsigned int rn = inst.operands[1].addr.base_regno; - bool is64 - = (aarch64_get_qualifier_esize (inst.operands[0].qualifier) == 8); + int size = aarch64_get_qualifier_esize (inst.operands[0].qualifier); gdb_assert (inst.operands[0].type == AARCH64_OPND_Rt || inst.operands[0].type == AARCH64_OPND_Ft); if (inst.operands[0].type == AARCH64_OPND_Ft) - { - /* Only bottom 64-bit of each V register (D register) need - to be preserved. */ - gdb_assert (inst.operands[0].qualifier == AARCH64_OPND_QLF_S_D); - rt += AARCH64_X_REGISTER_COUNT; - } + rt += AARCH64_X_REGISTER_COUNT; - stack.store (pv_add_constant (regs[rn], imm), - is64 ? 8 : 4, regs[rt]); + stack.store (pv_add_constant (regs[rn], imm), size, regs[rt]); if (inst.operands[1].addr.writeback) regs[rn] = pv_add_constant (regs[rn], imm); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index e4b9616dde..6c80a69e06 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-08-14 Alan Hayward + + * gdb.arch/aarch64-prologue.c: New test. + * gdb.arch/aarch64-prologue.exp: New file. + 2019-08-13 Tom de Vries * gdb.gdb/selftest.exp (send ^C to child process again): Accept also diff --git a/gdb/testsuite/gdb.arch/aarch64-prologue.c b/gdb/testsuite/gdb.arch/aarch64-prologue.c new file mode 100644 index 0000000000..aa664f704f --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-prologue.c @@ -0,0 +1,83 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2019 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 . */ + +#include + +extern void excessiveprologue (); + +void +innerfunc () +{ + printf ("inner\n"); +} + +/* excessiveprologue saves to the stack in multiple ways. */ + +asm ("\t.section .gnu.sgstubs,\"ax\",%progbits\n" + "\t.global excessiveprologue\n" + "\t.type excessiveprologue, %function\n" + "excessiveprologue:\n" + "\tstp x29, x30, [sp, #-208]!\n" + "\tmov x29, sp\n" + "\tstp w0,w1,[sp,16]\n" + "\tstp x2,x3,[sp,24]\n" + "\tstr w4,[sp,40]\n" + "\tstr x5,[sp,48]\n" + "\tstur w6,[sp,52]\n" + "\tstur x7,[sp,56]\n" + "\tstp s0,s1,[sp,64]\n" + "\tstp d2,d3,[sp,72]\n" + "\tstp q4,q5,[sp,96]\n" + "\tstr b6,[sp,128]\n" + "\tstr h7,[sp,132]\n" + "\tstr s8,[sp,136]\n" + "\tstr d9,[sp,140]\n" + "\tstr q10,[sp,148]\n" + "\tstur b11,[sp,164]\n" + "\tstur h12,[sp,160]\n" + "\tstur s13,[sp,172]\n" + "\tstur d14,[sp,176]\n" + "\tstur q15,[sp,184]\n" + "\tbl innerfunc\n" + "\tldp w0,w1,[sp,16]\n" + "\tldp x2,x3,[sp,24]\n" + "\tldr w4,[sp,40]\n" + "\tldr x5,[sp,48]\n" + "\tldur w6,[sp,52]\n" + "\tldur x7,[sp,56]\n" + "\tldp s0,s1,[sp,64]\n" + "\tldp d2,d3,[sp,72]\n" + "\tldp q4,q5,[sp,96]\n" + "\tldr b6,[sp,128]\n" + "\tldr h7,[sp,132]\n" + "\tldr s8,[sp,136]\n" + "\tldr d9,[sp,140]\n" + "\tldr q10,[sp,148]\n" + "\tldur b11,[sp,164]\n" + "\tldur h12,[sp,160]\n" + "\tldur s13,[sp,172]\n" + "\tldur d14,[sp,176]\n" + "\tldur q15,[sp,184]\n" + "\tldp x29, x30, [sp], #208\n" + "ret\n"); + +int +main (void) +{ + excessiveprologue (); + return 0; +} diff --git a/gdb/testsuite/gdb.arch/aarch64-prologue.exp b/gdb/testsuite/gdb.arch/aarch64-prologue.exp new file mode 100644 index 0000000000..e31261ad25 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-prologue.exp @@ -0,0 +1,36 @@ +# Copyright 2019 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 . + +# This file is part of the gdb testsuite. + +if {![is_aarch64_target]} { + verbose "Skipping ${gdb_test_file_name}." + return 1 +} + +standard_testfile +if { [prepare_for_testing "failed to prepare" $testfile $srcfile {nodebug}]} { + return -1 +} + +if ![runto_main] { + untested "could not run to main" + return -1 +} + +# Ensure gdb can break at excessiveprologue then continue. +gdb_breakpoint "excessiveprologue" +gdb_continue_to_breakpoint "excessiveprologue" +gdb_continue_to_end "excessiveprologue" "continue" 1 -- 2.34.1