This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA/commit] amd64 - function returning record with field straddling 2 registers.


This is a change that we made 3 years ago and forgot to contribute.
I just noticed the problem again last week...  The problem occurs when
trying to print the valued returned by a function, when this value
is a record returned by register, and when this record contains
a field whose position causes the field value to be split between
registers.

Consider for instance the following type:

   type Rec is record
      X: Integer;
      S: String (1..8);
   end record;

And the following function returning a value of that type:

   function Bar return Rec is
   begin
      return (X => 42, S => "ABCDEFGH");
   end Bar;

Trying to call this function from GDB and print the return value
leads to:

    (gdb) p bar
    $1 = (x => 42, s => "ABCD["00"]["00"]["00"]["00"]")

The expected answer, of course, is:

    (gdb) p bar
    $2 = (x => 42, s => "ABCDEFGH")

The problem, as explained above, is in the treatment of fields that
are returned piecemeal over 2 registers.  The ABI is not completely
clear in this case on how to deal with this situation - it seems
that the ABI makes an implicit assumption that straddling fields
like these do not occur.  However, it seemed logical to apply the field
classification to both 8-bytes the field "touches".  This patch
implements this idea,  with a large comment explaining what we do,
and why we think it'll work.  No regression on x86_64-linux.

gdb/ChangeLog:

        From Paul Hilfinger  <hilfinger@adacore.com>
        * amd64-tdep.c (amd_classify_aggregate): Handle the case of
        a record of length <= 16 in which a field straddles the two
        eightbytes.

gdb/testsuite/ChangeLog:

        * gdb.ada/rec_return: New testcase.

I would like to commit in a few days if there are no objections.

---
 gdb/amd64-tdep.c                         |   30 +++++++++++++++++++
 gdb/testsuite/gdb.ada/rec_return.exp     |   46 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/rec_return/foo.adb |   24 +++++++++++++++
 gdb/testsuite/gdb.ada/rec_return/pck.adb |   27 +++++++++++++++++
 gdb/testsuite/gdb.ada/rec_return/pck.ads |   28 ++++++++++++++++++
 5 files changed, 155 insertions(+), 0 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/rec_return.exp
 create mode 100644 gdb/testsuite/gdb.ada/rec_return/foo.adb
 create mode 100644 gdb/testsuite/gdb.ada/rec_return/pck.adb
 create mode 100644 gdb/testsuite/gdb.ada/rec_return/pck.ads

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 74a38a8..9f5d330 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -352,6 +352,12 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
 	  struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, i));
 	  int pos = TYPE_FIELD_BITPOS (type, i) / 64;
 	  enum amd64_reg_class subclass[2];
+	  int bitsize = TYPE_FIELD_BITSIZE (type, i);
+	  int endpos;
+
+	  if (bitsize == 0)
+	    bitsize = TYPE_LENGTH (subtype) * 8;
+	  endpos = (TYPE_FIELD_BITPOS (type, i) + bitsize - 1) / 64;
 
 	  /* Ignore static fields.  */
 	  if (field_is_static (&TYPE_FIELD (type, i)))
@@ -361,6 +367,30 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
 
 	  amd64_classify (subtype, subclass);
 	  class[pos] = amd64_merge_classes (class[pos], subclass[0]);
+	  if (bitsize <= 64 && pos == 0 && endpos == 1)
+	    /* This is a bit of an odd case:  We have a field that would
+	       normally fit in one of the two eightbytes, except that
+	       it is placed in a way that this field straddles them.
+	       This has been seen with a structure containing an array.
+
+	       The ABI is a bit unclear in this case, but we assume that
+	       this field's class (stored in subclass[0]) must also be merged
+	       into class[1].  In other words, our field has a piece stored
+	       in the second eight-byte, and thus its class applies to
+	       the second eight-byte as well.
+
+	       In the case where the field length exceeds 8 bytes,
+	       it should not be necessary to merge the field class
+	       into class[1].  As LEN > 8, subclass[1] is necessarily
+	       different from AMD64_NO_CLASS.  If subclass[1] is equal
+	       to subclass[0], then the normal class[1]/subclass[1]
+	       merging will take care of everything.  For subclass[1]
+	       to be different from subclass[0], I can only see the case
+	       where we have a SSE/SSEUP or X87/X87UP pair, which both
+	       use up all 16 bytes of the aggregate, and are already
+	       handled just fine (because each portion sits on its own
+	       8-byte).  */
+	    class[1] = amd64_merge_classes (class[1], subclass[0]);
 	  if (pos == 0)
 	    class[1] = amd64_merge_classes (class[1], subclass[1]);
 	}
diff --git a/gdb/testsuite/gdb.ada/rec_return.exp b/gdb/testsuite/gdb.ada/rec_return.exp
new file mode 100644
index 0000000..8d7035c
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/rec_return.exp
@@ -0,0 +1,46 @@
+# Copyright 2010 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/>.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+load_lib "ada.exp"
+
+set testdir "rec_return"
+set testfile "${testdir}/foo"
+set srcfile ${srcdir}/${subdir}/${testfile}.adb
+set binfile ${objdir}/${subdir}/${testfile}
+
+file mkdir ${objdir}/${subdir}/${testdir}
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
+  return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
+if ![runto "foo.adb:$bp_location" ] then {
+  perror "Couldn't run ${testfile}"
+  return
+}
+
+gdb_test "print bar" \
+         "= \\(x => 42, s => \"ABCDEFGH\"\\)" \
+         "print bar"
+
diff --git a/gdb/testsuite/gdb.ada/rec_return/foo.adb b/gdb/testsuite/gdb.ada/rec_return/foo.adb
new file mode 100644
index 0000000..a32d817
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/rec_return/foo.adb
@@ -0,0 +1,24 @@
+--  Copyright 2010 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/>.
+
+with Pck; use Pck;
+
+procedure Foo is
+   Q: Rec;
+begin
+   Q := Bar; -- STOP HERE
+   Do_Nothing (Q'Address);
+end Foo;
+
diff --git a/gdb/testsuite/gdb.ada/rec_return/pck.adb b/gdb/testsuite/gdb.ada/rec_return/pck.adb
new file mode 100644
index 0000000..fb42164
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/rec_return/pck.adb
@@ -0,0 +1,27 @@
+--  Copyright 2010 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/>.
+
+package body Pck is
+   function Bar return Rec is
+   begin
+      return (X => 42, S => "ABCDEFGH");
+   end Bar;
+
+   procedure Do_Nothing (A : System.Address) is
+   begin
+      null;
+   end Do_Nothing;
+end Pck;
+
diff --git a/gdb/testsuite/gdb.ada/rec_return/pck.ads b/gdb/testsuite/gdb.ada/rec_return/pck.ads
new file mode 100644
index 0000000..a890f4a
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/rec_return/pck.ads
@@ -0,0 +1,28 @@
+--  Copyright 2010 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/>.
+
+with System;
+
+package Pck is
+   type Rec is record
+      X: Integer;
+      S: String (1..8);
+   end record;
+
+   function Bar return Rec;
+   procedure Do_Nothing (A : System.Address);
+
+end Pck;
+
-- 
1.6.3.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]