diff --git a/elfutils-0.190-riscv-flatten.patch b/elfutils-0.190-riscv-flatten.patch new file mode 100644 index 0000000..a96d339 --- /dev/null +++ b/elfutils-0.190-riscv-flatten.patch @@ -0,0 +1,359 @@ +From e39336df6588c3f9853be7d02819aee262ba2121 Mon Sep 17 00:00:00 2001 +From: Mark Wielaard +Date: Tue, 19 Mar 2024 22:43:10 +0000 +Subject: [PATCH] riscv: Partial implementation of flatten_aggregate + +dwfl_module_return_value_location would fail on riscv for functions +which return a (small) struct. This patch implements the simplest +cases of flatten_aggregate in backends/riscv_retval.c. It just handles +structs containing one or two members of the same base type which fit +completely or in pieces in one or two general or floating point +registers. + +It also adds a specific test case run-funcretval-struct.sh containing +small structs of ints, longs, floats and doubles. All these testscases +now work for riscv. There is already a slightly more extensive +testcase for this in tests/run-funcretval.sh but that only has a +testcase for aarch64. + + * backends/riscv_retval.c (flatten_aggregate_arg): Implement + for the simple cases where we have a struct with one or two + members of the same base type. + (pass_by_flattened_arg): Likewise. Call either + pass_in_gpr_lp64 or pass_in_fpr_lp64d. + (riscv_return_value_location_lp64ifd): Call + flatten_aggregate_arg including size. + * tests/Makefile.am (TESTS): Add run-funcretval-struct.sh + and run-funcretval-struct-native.sh. + (check_PROGRAMS): Add funcretval_test_struct. + (funcretval_test_struct_SOURCES): New. + (EXTRA_DIST): Add run-funcretval-struct.sh, + funcretval_test_struct_riscv.bz2 and + run-funcretval-struct-native.sh. + * tests/funcretval_test_struct_riscv.bz2: New test binary. + * tests/run-funcretval-struct-native.sh: New test. + * tests/run-funcretval-struct.sh: Likewise. + +https://sourceware.org/bugzilla/show_bug.cgi?id=31142 + +Signed-off-by: Mark Wielaard +--- + backends/riscv_retval.c | 123 ++++++++++++++++++++++--- + tests/Makefile.am | 7 ++ + tests/funcretval_test_struct.c | 86 +++++++++++++++++ + tests/funcretval_test_struct_riscv.bz2 | Bin 0 -> 3821 bytes + tests/run-funcretval-struct-native.sh | 22 +++++ + tests/run-funcretval-struct.sh | 35 +++++++ + 6 files changed, 262 insertions(+), 11 deletions(-) + create mode 100644 tests/funcretval_test_struct.c + create mode 100755 tests/funcretval_test_struct_riscv.bz2 + create mode 100755 tests/run-funcretval-struct-native.sh + create mode 100755 tests/run-funcretval-struct.sh + +Fedora NOTE: Both the riscv specific test files weren't included + (funcretval_test_struct_riscv.bz2 and run-funcretval-struct.sh) + Because it contained a binary test. The native test is included + though. + +diff --git a/backends/riscv_retval.c b/backends/riscv_retval.c +index 0a1e02f81cd2..50c451a4ba32 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 + 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 9141074fe44c..9315ec3bbe4c 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -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 \ +@@ -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 000000000000..df94bde0a42d +--- /dev/null ++++ b/tests/funcretval_test_struct.c +@@ -0,0 +1,86 @@ ++/* Copyright (C) 2024 Mark J. Wielaard ++ 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 . */ ++ ++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/run-funcretval-struct-native.sh b/tests/run-funcretval-struct-native.sh +new file mode 100755 +index 000000000000..798edb3b61b3 +--- /dev/null ++++ b/tests/run-funcretval-struct-native.sh +@@ -0,0 +1,22 @@ ++#! /bin/sh ++# Copyright (C) 2024 Mark J. Wielaard ++# 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 . ++ ++. $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 +-- +2.44.0 + diff --git a/elfutils.spec b/elfutils.spec index 4620d62..7dbc791 100644 --- a/elfutils.spec +++ b/elfutils.spec @@ -4,7 +4,7 @@ Name: elfutils Version: 0.191 -%global baserelease 4 +%global baserelease 5 Release: %{baserelease}%{?dist} URL: http://elfutils.org/ %global source_url ftp://sourceware.org/pub/elfutils/%{version}/ @@ -75,6 +75,8 @@ BuildRequires: gettext-devel # For s390x... FDO package notes are bogus. Patch1: elfutils-0.186-fdo-swap.patch +Patch2: elfutils-0.190-riscv-flatten.patch + %description Elfutils is a collection of utilities, including stack (to show backtraces), nm (for listing symbols from object files), size @@ -483,6 +485,9 @@ exit 0 %systemd_postun_with_restart debuginfod.service %changelog +* Tue Jun 25 2024 Mark Wielaard - 0.191-5 +- Add elfutils-0.190-riscv-flatten.patch + * Mon Jun 24 2024 Troy Dawson - 0.191-4 - Bump release for June 2024 mass rebuild