]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/tdep] Fix gdb.ada/finish-var-size.exp on ppc64le-linux
authorTom de Vries <tdevries@suse.de>
Sun, 1 Jun 2025 12:06:01 +0000 (14:06 +0200)
committerTom de Vries <tdevries@suse.de>
Sun, 1 Jun 2025 12:06:01 +0000 (14:06 +0200)
On openSUSE Tumbleweed ppc64le-linux using gcc 14.3.0, with a gdb 16.3 based
package and test-case gdb.ada/finish-var-size.exp, I run into:
...
(gdb) finish^M
Run till exit from #0  pck.get (value=true) at pck.adb:19^M
0x0000000100004a20 in p () at finish-var-size/p.adb:18^M
18        V : Result_T := Get (True);^M
Value returned is $1 = <error reading variable: \
  Cannot access memory at address 0x0>^M
(gdb) FAIL: gdb.ada/finish-var-size.exp: finish
...

Function pck.get returns type Result_T:
...
  type Array_Type is array (1 .. 64) of Integer;

  type Maybe_Array (Defined : Boolean := False) is
    record
      Arr : Array_Type;
      Arr2 : Array_Type;
    end record;

  type Result_T (Defined : Boolean := False) is
    record
      case Defined is
        when False =>
          Arr : Maybe_Array;
        when True =>
          Payload : Boolean;
      end case;
    end record;
...
and uses r3 as address of the return value, which means
RETURN_VALUE_STRUCT_CONVENTION, but while executing finish_command we do:
...
      return_value
= gdbarch_return_value_as_value (gdbarch,
                                         read_var_value (sm->function, nullptr,
                                                         callee_frame),
                                         val_type, nullptr, nullptr, nullptr);
...
and get:
...
(gdb) p return_value
$1 = RETURN_VALUE_REGISTER_CONVENTION
...

This is caused by this check in ppc64_sysv_abi_return_value:
...
   /* In the ELFv2 ABI, aggregate types of up to 16 bytes are
      returned in registers r3:r4.  */
   if (tdep->elf_abi == POWERPC_ELF_V2
       && valtype->length () <= 16
...
which succeeds because valtype->length () == 0.

Fix this by also checking for !TYPE_HAS_DYNAMIC_LENGTH (valtype).

[ I also tested a version of this patch using "!is_dynamic_type (valtype)"
instead, but ran into a regression in test-case gdb.ada/variant-record.exp,
because type T:
...
    Length : constant Positive := 8;
    subtype Name_T is String (1 .. Length);

    type A_Record_T is
      record
        X1 : Natural;
        X2 : Natural;
      end record;

    type Yes_No_T is (Yes, No);
    type T (Well : Yes_No_T := Yes) is
      record
case Well is
          when Yes =>
            Name : Name_T;
          when No =>
            Unique_Name : A_Record_T;
end case;
      end record;
...
while being dynamic, also has a non-zero size, and is small enough to be
returned in registers r3:r4. ]

Fixing this causes the test-case to fail with the familiar:
...
warning: Cannot determine the function return value.
Try compiling with -fvar-tracking.
...
and indeed using -fvar-tracking makes the test-case pass.

Tested on ppc64le-linux.

PR tdep/33000
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33000

gdb/ppc-sysv-tdep.c
gdb/testsuite/gdb.ada/finish-var-size.exp

index bcf4e2a1c89bdb2cf9a4afd71b351e0d7b0b6183..cae5aa62572ecc1ef91c9132f79b95eb074b1237 100644 (file)
@@ -2112,6 +2112,7 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
   /* In the ELFv2 ABI, aggregate types of up to 16 bytes are
      returned in registers r3:r4.  */
   if (tdep->elf_abi == POWERPC_ELF_V2
+      && !TYPE_HAS_DYNAMIC_LENGTH (valtype)
       && valtype->length () <= 16
       && (valtype->code () == TYPE_CODE_STRUCT
          || valtype->code () == TYPE_CODE_UNION
index e038ed43ce29ee112ffda51fb00b6eb63a143526..ae300862a4d2f774fd29329dd9ba05cb4fcb5d02 100644 (file)
@@ -22,7 +22,13 @@ require {expr [gcc_major_version] >= 12}
 
 standard_ada_testfile p
 
-if {[gdb_compile_ada "${srcfile}" "${binfile}" executable debug] != ""} {
+set opts {}
+lappend opts debug
+if { [have_fvar_tracking] } {
+    lappend opts additional_flags=-fvar-tracking
+}
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable $opts] != ""} {
   return -1
 }