diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4e73bf7e27..ba1300d57e 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2019-04-15 Leszek Swirski + + * amd64-tdep.c (amd64_classify_aggregate): Use cp_pass_by_reference + rather than a hand-rolled POD check when checking for forced MEMORY + classification. + 2019-04-15 Alan Hayward * aarch64-linux-nat.c (store_sveregs_to_thread): Set vector length. diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c index f4a1af9050..d4c96de571 100644 --- a/gdb/amd64-tdep.c +++ b/gdb/amd64-tdep.c @@ -541,17 +541,40 @@ amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2) static void amd64_classify (struct type *type, enum amd64_reg_class theclass[2]); -/* Return non-zero if TYPE is a non-POD structure or union type. */ +/* Return true if TYPE is a structure or union with unaligned fields. */ -static int -amd64_non_pod_p (struct type *type) +static bool +amd64_has_unaligned_fields (struct type *type) { - /* ??? A class with a base class certainly isn't POD, but does this - catch all non-POD structure types? */ - if (TYPE_CODE (type) == TYPE_CODE_STRUCT && TYPE_N_BASECLASSES (type) > 0) - return 1; + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION) + { + for (int i = 0; i < TYPE_NFIELDS (type); i++) + { + struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i)); + int bitpos = TYPE_FIELD_BITPOS (type, i); + int align = type_align(subtype); - return 0; + /* Ignore static fields, or empty fields, for example nested + empty structures. */ + if (field_is_static (&TYPE_FIELD (type, i)) + || (TYPE_FIELD_BITSIZE (type, i) == 0 + && TYPE_LENGTH (subtype) == 0)) + continue; + + if (bitpos % 8 != 0) + return true; + + int bytepos = bitpos / 8; + if (bytepos % align != 0) + return true; + + if (amd64_has_unaligned_fields(subtype)) + return true; + } + } + + return false; } /* Classify TYPE according to the rules for aggregate (structures and @@ -560,10 +583,9 @@ amd64_non_pod_p (struct type *type) static void amd64_classify_aggregate (struct type *type, enum amd64_reg_class theclass[2]) { - /* 1. If the size of an object is larger than two eightbytes, or in - C++, is a non-POD structure or union type, or contains + /* 1. If the size of an object is larger than two eightbytes, or it has unaligned fields, it has class memory. */ - if (TYPE_LENGTH (type) > 16 || amd64_non_pod_p (type)) + if (TYPE_LENGTH (type) > 16 || amd64_has_unaligned_fields (type)) { theclass[0] = theclass[1] = AMD64_MEMORY; return; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 7fb071adc6..d46422635b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-04-15 Leszek Swirski + + * gdb.arch/amd64-eval.cc: New file. + * gdb.arch/amd64-eval.exp: New file. + 2019-04-11 Alan Hayward * gdb.server/sysroot.c: New test. diff --git a/gdb/testsuite/gdb.arch/amd64-eval.cc b/gdb/testsuite/gdb.arch/amd64-eval.cc new file mode 100644 index 0000000000..a986a49db3 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-eval.cc @@ -0,0 +1,120 @@ +/* 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 +#include +#include +#include + +/* A simple structure with a single integer field. Should be returned in + a register. */ +struct SimpleBase +{ + SimpleBase (int32_t x) : x (x) {} + + int32_t x; +}; + +/* A simple structure derived from the simple base. Should be returned in + a register. */ +struct SimpleDerived : public SimpleBase +{ + SimpleDerived (int32_t x) : SimpleBase (x) {} +}; + +/* A structure derived from the simple base with a non-trivial destructor. + Should be returned on the stack. */ +struct NonTrivialDestructorDerived : public SimpleBase +{ + NonTrivialDestructorDerived (int32_t x) : SimpleBase (x) {} + ~NonTrivialDestructorDerived() { x = 1; } +}; + +/* A structure with unaligned fields. Should be returned on the stack. */ +struct UnalignedFields +{ + UnalignedFields (int32_t x, double y) : x (x), y (y) {} + + int32_t x; + double y; +} __attribute__((packed)); + +/* A structure with unaligned fields in its base class. Should be + returned on the stack. */ +struct UnalignedFieldsInBase : public UnalignedFields +{ + UnalignedFieldsInBase (int32_t x, double y, int32_t x2) + : UnalignedFields (x, y), x2 (x2) {} + + int32_t x2; +}; + +class Foo +{ +public: + SimpleBase + return_simple_base (int32_t x) + { + assert (this->tag == EXPECTED_TAG); + return SimpleBase (x); + } + + SimpleDerived + return_simple_derived (int32_t x) + { + assert (this->tag == EXPECTED_TAG); + return SimpleDerived (x); + } + + NonTrivialDestructorDerived + return_non_trivial_destructor (int32_t x) + { + assert (this->tag == EXPECTED_TAG); + return NonTrivialDestructorDerived (x); + } + + UnalignedFields + return_unaligned (int32_t x, double y) + { + assert (this->tag == EXPECTED_TAG); + return UnalignedFields (x, y); + } + + UnalignedFieldsInBase + return_unaligned_in_base (int32_t x, double y, int32_t x2) + { + assert (this->tag == EXPECTED_TAG); + return UnalignedFieldsInBase (x, y, x2); + } + +private: + /* Use a tag to detect if the "this" value is correct. */ + static const int EXPECTED_TAG = 0xF00F00F0; + int tag = EXPECTED_TAG; +}; + +int +main (int argc, char *argv[]) +{ + Foo foo; + foo.return_simple_base(1); + foo.return_simple_derived(2); + foo.return_non_trivial_destructor(3); + foo.return_unaligned(4, 5); + foo.return_unaligned_in_base(6, 7, 8); + return 0; // break-here +} diff --git a/gdb/testsuite/gdb.arch/amd64-eval.exp b/gdb/testsuite/gdb.arch/amd64-eval.exp new file mode 100644 index 0000000000..c33777d2b4 --- /dev/null +++ b/gdb/testsuite/gdb.arch/amd64-eval.exp @@ -0,0 +1,43 @@ +# 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 . + +# This testcase exercises evaluation with amd64 calling conventions. + +standard_testfile .cc + +if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ + { debug c++ }] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_breakpoint [gdb_get_line_number "break-here"] +gdb_continue_to_breakpoint "break-here" + +gdb_test "call foo.return_simple_base(12)" \ + " = {x = 12}" +gdb_test "call foo.return_simple_derived(34)" \ + " = { = {x = 34}, }" +gdb_test "call foo.return_non_trivial_destructor(56)" \ + " = { = {x = 56}, }" +gdb_test "call foo.return_unaligned(78, 9.25)" \ + " = {x = 78, y = 9.25}" +gdb_test "call foo.return_unaligned_in_base(23, 4.5, 67)" \ + " = { = {x = 23, y = 4.5}, x2 = 67}"