summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2024-03-19 22:43:10 +0000
committerMark Wielaard <mark@klomp.org>2024-03-19 23:46:13 +0100
commit6583e50b1f145db9895882af52365b2e587440d8 (patch)
treea1021d0f11d86d455cd898a623d9753b6ba6a261
parentec5ce487c15dcd709d033dd5693b468ac34223ce (diff)
-rw-r--r--backends/riscv_retval.c123
-rw-r--r--tests/Makefile.am7
-rw-r--r--tests/funcretval_test_struct.c86
-rwxr-xr-xtests/funcretval_test_struct_riscv.bz2bin0 -> 3821 bytes
-rwxr-xr-xtests/run-funcretval-struct-native.sh22
-rwxr-xr-xtests/run-funcretval-struct.sh35
6 files changed, 262 insertions, 11 deletions
diff --git a/backends/riscv_retval.c b/backends/riscv_retval.c
index 0a1e02f8..50c451a4 100644
--- a/backends/riscv_retval.c
+++ b/backends/riscv_retval.c
@@ -1,6 +1,7 @@
/* Function return value location for Linux/RISC-V ABI.
Copyright (C) 2018 Sifive, Inc.
Copyright (C) 2013 Red Hat, Inc.
+ Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -105,23 +106,123 @@ pass_in_fpr_lp64d (const Dwarf_Op **locp, Dwarf_Word size)
return size <= 8 ? 1 : 4;
}
+/* Checks if we can "flatten" the given type, Only handles the simple
+ cases where we have a struct with one or two the same base type
+ elements. */
static int
-flatten_aggregate_arg (Dwarf_Die *typedie __attribute__ ((unused)),
- Dwarf_Die *arg0 __attribute__ ((unused)),
- Dwarf_Die *arg1 __attribute__ ((unused)))
+flatten_aggregate_arg (Dwarf_Die *typedie,
+ Dwarf_Word size,
+ Dwarf_Die *arg0,
+ Dwarf_Die *arg1)
{
- /* ??? */
+ int tag0, tag1;
+ Dwarf_Die member;
+ Dwarf_Word encoding0, encoding1;
+ Dwarf_Attribute attr;
+ Dwarf_Word size0, size1;
+
+ if (size < 8 || size > 16)
+ return 0;
+
+ if (dwarf_child (typedie, arg0) != 0)
+ return 0;
+
+ tag0 = dwarf_tag (arg0);
+ while (tag0 != -1 && tag0 != DW_TAG_member)
+ {
+ if (dwarf_siblingof (arg0, arg0) != 0)
+ return 0;
+ tag0 = dwarf_tag (arg0);
+ }
+
+ if (tag0 != DW_TAG_member)
+ return 0;
+
+ /* Remember where we are. */
+ member = *arg0;
+
+ tag0 = dwarf_peeled_die_type (arg0, arg0);
+ if (tag0 != DW_TAG_base_type)
+ return 0;
+
+ if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
+ || dwarf_formudata (&attr, &encoding0) != 0)
+ return 0;
+
+ if (dwarf_bytesize_aux (arg0, &size0) != 0)
+ return 0;
+
+ if (size == size0)
+ return 1; /* This one member is the whole size. */
+
+ if (size != 2 * size0)
+ return 0; /* We only handle two of the same. */
+
+ /* Look for another member with the same encoding. */
+ if (dwarf_siblingof (&member, arg1) != 0)
+ return 0;
+
+ tag1 = dwarf_tag (arg1);
+ while (tag1 != -1 && tag1 != DW_TAG_member)
+ {
+ if (dwarf_siblingof (arg1, arg1) != 0)
+ return 0;
+ tag1 = dwarf_tag (arg1);
+ }
+
+ if (tag1 != DW_TAG_member)
+ return 0;
+
+ tag1 = dwarf_peeled_die_type (arg1, arg1);
+ if (tag1 != DW_TAG_base_type)
+ return 0; /* We can only handle two equal base types for now. */
+
+ if (dwarf_attr_integrate (arg1, DW_AT_encoding, &attr) == NULL
+ || dwarf_formudata (&attr, &encoding1) != 0
+ || encoding0 != encoding1)
+ return 0; /* We can only handle two of the same for now. */
+
+ if (dwarf_bytesize_aux (arg1, &size1) != 0)
+ return 0;
+
+ if (size0 != size1)
+ return 0; /* We can only handle two of the same for now. */
+
return 1;
}
+/* arg0 and arg1 should be the peeled die types found by
+ flatten_aggregate_arg. */
static int
-pass_by_flattened_arg (const Dwarf_Op **locp __attribute__ ((unused)),
- Dwarf_Word size __attribute__ ((unused)),
- Dwarf_Die *arg0 __attribute__ ((unused)),
- Dwarf_Die *arg1 __attribute__ ((unused)))
+pass_by_flattened_arg (const Dwarf_Op **locp,
+ Dwarf_Word size,
+ Dwarf_Die *arg0,
+ Dwarf_Die *arg1 __attribute__((unused)))
{
- /* ??? */
- return -2;
+ /* For now we just assume arg0 and arg1 are the same type and
+ encoding. */
+ Dwarf_Word encoding;
+ Dwarf_Attribute attr;
+
+ if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
+ || dwarf_formudata (&attr, &encoding) != 0)
+ return -1;
+
+ switch (encoding)
+ {
+ case DW_ATE_boolean:
+ case DW_ATE_signed:
+ case DW_ATE_unsigned:
+ case DW_ATE_unsigned_char:
+ case DW_ATE_signed_char:
+ return pass_in_gpr_lp64 (locp, size);
+
+ case DW_ATE_float:
+ return pass_in_fpr_lp64d (locp, size);
+
+ default:
+ return -1;
+ }
}
int
@@ -158,7 +259,7 @@ riscv_return_value_location_lp64ifd (int fp, Dwarf_Die *functypedie,
provided the floating-point real is no more than FLEN bits wide and
the integer is no more than XLEN bits wide. */
if (tag == DW_TAG_structure_type
- && flatten_aggregate_arg (&typedie, &arg0, &arg1))
+ && flatten_aggregate_arg (&typedie, size, &arg0, &arg1))
return pass_by_flattened_arg (locp, size, &arg0, &arg1);
/* Aggregates larger than 2*XLEN bits are passed by reference. */
else if (size > 16)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9141074f..9315ec3b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -162,6 +162,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
run-addr2line-C-test.sh \
run-addr2line-i-test.sh run-addr2line-i-lex-test.sh \
run-addr2line-i-demangle-test.sh run-addr2line-alt-debugpath.sh \
+ run-funcretval-struct.sh \
run-varlocs.sh run-exprlocs.sh run-varlocs-vars.sh run-funcretval.sh \
run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \
run-backtrace-native-biarch.sh run-backtrace-native-core.sh \
@@ -284,6 +285,10 @@ funcretval_test__11_SOURCES = funcretval_test++11.cxx
TESTS += run-funcretval++11.sh
endif
+check_PROGRAMS += funcretval_test_struct
+funcretval_test_struct_SOURCES = funcretval_test_struct.c
+TESTS += run-funcretval-struct-native.sh
+
EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
run-ar-N.sh \
run-show-die-info.sh run-get-files.sh run-get-lines.sh \
@@ -478,6 +483,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile_aarch64_core.bz2 testfile_i686_core.bz2 \
addrx_constx-4.dwo.bz2 addrx_constx-5.dwo.bz2 \
testfile-addrx_constx-4.bz2 testfile-addrx_constx-5.bz2 \
+ run-funcretval-struct.sh funcretval_test_struct_riscv.bz2 \
run-funcretval.sh funcretval_test.c funcretval_test_aarch64.bz2 \
run-backtrace-data.sh run-backtrace-dwarf.sh cleanup-13.c \
run-backtrace-native.sh run-backtrace-native-biarch.sh \
@@ -635,6 +641,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile_nvidia_linemap.bz2 \
testfile-largealign.o.bz2 run-strip-largealign.sh \
run-funcretval++11.sh \
+ run-funcretval-struct-native.sh \
test-ar-duplicates.a.bz2 \
run-dwfl-core-noncontig.sh testcore-noncontig.bz2 \
testfile-dwarf5-line-clang.bz2 \
diff --git a/tests/funcretval_test_struct.c b/tests/funcretval_test_struct.c
new file mode 100644
index 00000000..df94bde0
--- /dev/null
+++ b/tests/funcretval_test_struct.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
+ This file is part of elfutils.
+
+ This file 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.
+
+ elfutils 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/>. */
+
+typedef struct
+ {
+ int q;
+ int r;
+ } div_t;
+
+typedef struct
+ {
+ long q;
+ long r;
+ } ldiv_t;
+
+typedef struct
+ {
+ float x;
+ float y;
+ } point_t;
+
+typedef struct
+ {
+ double x;
+ double y;
+ } dpoint_t;
+
+div_t __attribute__((__noinline__))
+div (int n, int d)
+{
+ div_t r;
+ r.q = n / d;
+ r.r = n % d;
+ return r;
+}
+
+ldiv_t __attribute__((__noinline__))
+ldiv (long n, long d)
+{
+ ldiv_t r;
+ r.q = n / d;
+ r.r = n % d;
+ return r;
+}
+
+point_t __attribute__((__noinline__))
+mkpt (float x, float y)
+{
+ point_t r;
+ r.x = x;
+ r.y = y;
+ return r;
+}
+
+dpoint_t __attribute__((__noinline__))
+dmkpt (double x, double y)
+{
+ dpoint_t r;
+ r.x = x;
+ r.y = y;
+ return r;
+}
+
+int
+main (void)
+{
+ div_t d = div (3, 2);
+ ldiv_t ld = ldiv (3, 2);
+ point_t p = mkpt (3.0f, 1.0f);
+ dpoint_t dp = dmkpt (3.0d, 1.0d);
+
+ return d.q - (int) p.y + ld.q - (int) dp.y;
+}
diff --git a/tests/funcretval_test_struct_riscv.bz2 b/tests/funcretval_test_struct_riscv.bz2
new file mode 100755
index 00000000..de3e5ba9
--- /dev/null
+++ b/tests/funcretval_test_struct_riscv.bz2
Binary files differ
diff --git a/tests/run-funcretval-struct-native.sh b/tests/run-funcretval-struct-native.sh
new file mode 100755
index 00000000..798edb3b
--- /dev/null
+++ b/tests/run-funcretval-struct-native.sh
@@ -0,0 +1,22 @@
+#! /bin/sh
+# Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# Just run it, we don't know what the native representation is.
+# But it should at least work and not error out.
+testrun $abs_builddir/funcretval -e $abs_builddir/funcretval_test_struct
diff --git a/tests/run-funcretval-struct.sh b/tests/run-funcretval-struct.sh
new file mode 100755
index 00000000..abd1c720
--- /dev/null
+++ b/tests/run-funcretval-struct.sh
@@ -0,0 +1,35 @@
+#! /bin/sh
+# Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# The test files are the native funcretval_test_struct files
+# funcretval_test_struct.c
+# See also run-funcretval-struct-native.sh
+
+testfiles funcretval_test_struct_riscv
+
+testrun_compare ${abs_top_builddir}/tests/funcretval \
+ -e funcretval_test_struct_riscv <<\EOF
+() main: return value location: {0x5a, 0}
+() dmkpt: return value location: {0x90, 0x2a} {0x93, 0x8} {0x90, 0x2b} {0x93, 0x8}
+() mkpt: return value location: {0x90, 0x2a}
+() ldiv: return value location: {0x5a, 0} {0x93, 0x8} {0x5b, 0} {0x93, 0x8}
+() div: return value location: {0x5a, 0}
+EOF
+
+exit 0