Fix inferior calls with variably-sized return type
authorTom Tromey <tromey@adacore.com>
Wed, 7 Sep 2022 15:52:44 +0000 (09:52 -0600)
committerTom Tromey <tromey@adacore.com>
Tue, 3 Jan 2023 15:45:01 +0000 (08:45 -0700)
This patch updates the gdbarch_return_value_as_value implementations
to work correctly with variably-sized return types.

gdb/aarch64-tdep.c
gdb/amd64-tdep.c
gdb/amd64-windows-tdep.c
gdb/arm-tdep.c
gdb/i386-tdep.c
gdb/riscv-tdep.c
gdb/sparc-tdep.c

index 0371387ac78ddaf6a333cff2db0fb79f4f12348a..6345cc1aac291062f5331f3a7e0cc1621f1f3461 100644 (file)
@@ -2334,6 +2334,9 @@ aarch64_return_in_memory (struct gdbarch *gdbarch, struct type *type)
   int elements;
   struct type *fundamental_type;
 
+  if (TYPE_HAS_DYNAMIC_LENGTH (type))
+    return 1;
+
   if (aapcs_is_vfp_call_or_return_candidate (type, &elements,
                                             &fundamental_type))
     {
@@ -2448,13 +2451,6 @@ aarch64_return_value (struct gdbarch *gdbarch, struct value *func_value,
                      struct type *valtype, struct regcache *regcache,
                      struct value **read_value, const gdb_byte *writebuf)
 {
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (valtype);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   if (valtype->code () == TYPE_CODE_STRUCT
       || valtype->code () == TYPE_CODE_UNION
       || valtype->code () == TYPE_CODE_ARRAY)
@@ -2470,12 +2466,12 @@ aarch64_return_value (struct gdbarch *gdbarch, struct value *func_value,
 
          aarch64_debug_printf ("return value in memory");
 
-         if (readbuf)
+         if (read_value != nullptr)
            {
              CORE_ADDR addr;
 
              regcache->cooked_read (AARCH64_STRUCT_RETURN_REGNUM, &addr);
-             read_memory (addr, readbuf, valtype->length ());
+             *read_value = value_at_non_lval (valtype, addr);
            }
 
          return RETURN_VALUE_ABI_RETURNS_ADDRESS;
@@ -2485,8 +2481,12 @@ aarch64_return_value (struct gdbarch *gdbarch, struct value *func_value,
   if (writebuf)
     aarch64_store_return_value (valtype, regcache, writebuf);
 
-  if (readbuf)
-    aarch64_extract_return_value (valtype, regcache, readbuf);
+  if (read_value)
+    {
+      *read_value = allocate_value (valtype);
+      aarch64_extract_return_value (valtype, regcache,
+                                   value_contents_raw (*read_value).data ());
+    }
 
   aarch64_debug_printf ("return value in registers");
 
index 69d1f86b47acc42f88341d93fb63fef6dd90f666..76e843ecc35fa1caf4e69b27b421fbccc69f9756 100644 (file)
@@ -801,13 +801,6 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
 
   gdb_assert (!(read_value && writebuf));
 
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (type);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   /* 1. Classify the return type with the classification algorithm.  */
   amd64_classify (type, theclass);
 
@@ -824,17 +817,24 @@ amd64_return_value (struct gdbarch *gdbarch, struct value *function,
         can always find the return value just after the function has
         returned.  */
 
-      if (readbuf)
+      if (read_value != nullptr)
        {
          ULONGEST addr;
 
          regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
-         read_memory (addr, readbuf, type->length ());
+         *read_value = value_at_non_lval (type, addr);
        }
 
       return RETURN_VALUE_ABI_RETURNS_ADDRESS;
     }
 
+  gdb_byte *readbuf = nullptr;
+  if (read_value != nullptr)
+    {
+      *read_value = allocate_value (type);
+      readbuf = value_contents_raw (*read_value).data ();
+    }
+
   /* 8. If the class is COMPLEX_X87, the real part of the value is
        returned in %st0 and the imaginary part in %st1.  */
   if (theclass[0] == AMD64_COMPLEX_X87)
index 6f7dbaa7002692f203732b5a9de4d085433a8552..411a6204a909d46721d3823cfc242acf9e34e0d3 100644 (file)
@@ -360,13 +360,6 @@ amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
   int len = type->length ();
   int regnum = -1;
 
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (type);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   /* See if our value is returned through a register.  If it is, then
      store the associated register number in REGNUM.  */
   switch (type->code ())
@@ -401,20 +394,24 @@ amd64_windows_return_value (struct gdbarch *gdbarch, struct value *function,
   if (regnum < 0)
     {
       /* RAX contains the address where the return value has been stored.  */
-      if (readbuf)
+      if (read_value != nullptr)
        {
          ULONGEST addr;
 
          regcache_raw_read_unsigned (regcache, AMD64_RAX_REGNUM, &addr);
-         read_memory (addr, readbuf, type->length ());
+         *read_value = value_at_non_lval (type, addr);
        }
       return RETURN_VALUE_ABI_RETURNS_ADDRESS;
     }
   else
     {
       /* Extract the return value from the register where it was stored.  */
-      if (readbuf)
-       regcache->raw_read_part (regnum, 0, len, readbuf);
+      if (read_value != nullptr)
+       {
+         *read_value = allocate_value (type);
+         regcache->raw_read_part (regnum, 0, len,
+                                  value_contents_raw (*read_value).data ());
+       }
       if (writebuf)
        regcache->raw_write_part (regnum, 0, len, writebuf);
       return RETURN_VALUE_REGISTER_CONVENTION;
index fa104392aece68c78d79def3efd5f01834cc9014..6eb68cc1f0d419728201fe729c2e2057504bb7d7 100644 (file)
@@ -8939,6 +8939,9 @@ arm_return_in_memory (struct gdbarch *gdbarch, struct type *type)
       && TYPE_CODE_ARRAY != code && TYPE_CODE_COMPLEX != code)
     return 0;
 
+  if (TYPE_HAS_DYNAMIC_LENGTH (type))
+    return 1;
+
   if (TYPE_CODE_ARRAY == code && type->is_vector ())
     {
       /* Vector values should be returned using ARM registers if they
@@ -9140,13 +9143,6 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function,
                  struct type *valtype, struct regcache *regcache,
                  struct value **read_value, const gdb_byte *writebuf)
 {
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (valtype);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   arm_gdbarch_tdep *tdep = gdbarch_tdep<arm_gdbarch_tdep> (gdbarch);
   struct type *func_type = function ? value_type (function) : NULL;
   enum arm_vfp_cprc_base_type vfp_base_type;
@@ -9158,6 +9154,14 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function,
       int reg_char = arm_vfp_cprc_reg_char (vfp_base_type);
       int unit_length = arm_vfp_cprc_unit_length (vfp_base_type);
       int i;
+
+      gdb_byte *readbuf = nullptr;
+      if (read_value != nullptr)
+       {
+         *read_value = allocate_value (valtype);
+         readbuf = value_contents_raw (*read_value).data ();
+       }
+
       for (i = 0; i < vfp_base_count; i++)
        {
          if (reg_char == 'q')
@@ -9209,12 +9213,12 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function,
       if (tdep->struct_return == pcc_struct_return
          || arm_return_in_memory (gdbarch, valtype))
        {
-         if (readbuf)
+         if (read_value != nullptr)
            {
              CORE_ADDR addr;
 
              regcache->cooked_read (ARM_A1_REGNUM, &addr);
-             read_memory (addr, readbuf, valtype->length ());
+             *read_value = value_at_non_lval (valtype, addr);
            }
          return RETURN_VALUE_ABI_RETURNS_ADDRESS;
        }
@@ -9228,8 +9232,12 @@ arm_return_value (struct gdbarch *gdbarch, struct value *function,
   if (writebuf)
     arm_store_return_value (valtype, regcache, writebuf);
 
-  if (readbuf)
-    arm_extract_return_value (valtype, regcache, readbuf);
+  if (read_value != nullptr)
+    {
+      *read_value = allocate_value (valtype);
+      gdb_byte *readbuf = value_contents_raw (*read_value).data ();
+      arm_extract_return_value (valtype, regcache, readbuf);
+    }
 
   return RETURN_VALUE_REGISTER_CONVENTION;
 }
index cc41dd80864941dd206149f77b54c2c46887f413..dc3cbeda49db420e70b0e147b455e8e96a9842b3 100644 (file)
@@ -3006,7 +3006,8 @@ i386_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
 
   if (struct_convention == pcc_struct_convention
       || (struct_convention == default_struct_convention
-         && tdep->struct_return == pcc_struct_return))
+         && tdep->struct_return == pcc_struct_return)
+      || TYPE_HAS_DYNAMIC_LENGTH (type))
     return 0;
 
   /* Structures consisting of a single `float', `double' or 'long
@@ -3034,13 +3035,6 @@ i386_return_value (struct gdbarch *gdbarch, struct value *function,
 {
   enum type_code code = type->code ();
 
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (type);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   if (((code == TYPE_CODE_STRUCT
        || code == TYPE_CODE_UNION
        || code == TYPE_CODE_ARRAY)
@@ -3068,12 +3062,12 @@ i386_return_value (struct gdbarch *gdbarch, struct value *function,
         a record, so the convention applied to records also applies
         to arrays.  */
 
-      if (readbuf)
+      if (read_value != nullptr)
        {
          ULONGEST addr;
 
          regcache_raw_read_unsigned (regcache, I386_EAX_REGNUM, &addr);
-         read_memory (addr, readbuf, type->length ());
+         *read_value = value_at_non_lval (type, addr);
        }
 
       return RETURN_VALUE_ABI_RETURNS_ADDRESS;
@@ -3097,8 +3091,12 @@ i386_return_value (struct gdbarch *gdbarch, struct value *function,
       return result;
     }
 
-  if (readbuf)
-    i386_extract_return_value (gdbarch, type, regcache, readbuf);
+  if (read_value != nullptr)
+    {
+      *read_value = allocate_value (type);
+      i386_extract_return_value (gdbarch, type, regcache,
+                                value_contents_raw (*read_value).data ());
+    }
   if (writebuf)
     i386_store_return_value (gdbarch, type, regcache, writebuf);
 
index bfda24ab3bef6dacfc7a87655f2b1c0164c53ef9..83c6113de50a45e6457433123d4bf1b2e3589a53 100644 (file)
@@ -2492,7 +2492,8 @@ static void
 riscv_call_arg_scalar_int (struct riscv_arg_info *ainfo,
                           struct riscv_call_info *cinfo)
 {
-  if (ainfo->length > (2 * cinfo->xlen))
+  if (TYPE_HAS_DYNAMIC_LENGTH (ainfo->type)
+      || ainfo->length > (2 * cinfo->xlen))
     {
       /* Argument is going to be passed by reference.  */
       ainfo->argloc[0].loc_type
@@ -2910,8 +2911,12 @@ riscv_arg_location (struct gdbarch *gdbarch,
       break;
 
     case TYPE_CODE_STRUCT:
-      riscv_call_arg_struct (ainfo, cinfo);
-      break;
+      if (!TYPE_HAS_DYNAMIC_LENGTH (ainfo->type))
+       {
+         riscv_call_arg_struct (ainfo, cinfo);
+         break;
+       }
+      /* FALLTHROUGH */
 
     default:
       riscv_call_arg_scalar_int (ainfo, cinfo);
@@ -3228,13 +3233,6 @@ riscv_return_value (struct gdbarch  *gdbarch,
   struct riscv_arg_info info;
   struct type *arg_type;
 
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (type);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   arg_type = check_typedef (type);
   riscv_arg_location (gdbarch, &info, &call_info, arg_type, false);
 
@@ -3246,15 +3244,15 @@ riscv_return_value (struct gdbarch  *gdbarch,
       gdb_printf (gdb_stdlog, "\n");
     }
 
-  if (readbuf != nullptr || writebuf != nullptr)
+  if (read_value != nullptr || writebuf != nullptr)
     {
       unsigned int arg_len;
       struct value *abi_val;
-      gdb_byte *old_readbuf = nullptr;
+      gdb_byte *readbuf = nullptr;
       int regnum;
 
       /* We only do one thing at a time.  */
-      gdb_assert (readbuf == nullptr || writebuf == nullptr);
+      gdb_assert (read_value == nullptr || writebuf == nullptr);
 
       /* In some cases the argument is not returned as the declared type,
         and we need to cast to or from the ABI type in order to
@@ -3295,7 +3293,6 @@ riscv_return_value (struct gdbarch  *gdbarch,
       else
        {
          abi_val = allocate_value (info.type);
-         old_readbuf = readbuf;
          readbuf = value_contents_raw (abi_val).data ();
        }
       arg_len = info.type->length ();
@@ -3375,8 +3372,17 @@ riscv_return_value (struct gdbarch  *gdbarch,
 
            regcache_cooked_read_unsigned (regcache, RISCV_A0_REGNUM,
                                           &addr);
-           if (readbuf != nullptr)
-             read_memory (addr, readbuf, info.length);
+           if (read_value != nullptr)
+             {
+               abi_val = value_at_non_lval (type, addr);
+               /* Also reset the expected type, so that the cast
+                  later on is a no-op.  If the cast is not a no-op,
+                  and if the return type is variably-sized, then the
+                  type of ABI_VAL will differ from ARG_TYPE due to
+                  dynamic type resolution, and so will most likely
+                  fail.  */
+               arg_type = value_type (abi_val);
+             }
            if (writebuf != nullptr)
              write_memory (addr, writebuf, info.length);
          }
@@ -3391,10 +3397,8 @@ riscv_return_value (struct gdbarch  *gdbarch,
       /* This completes the cast from abi type back to the declared type
         in the case that we are reading from the machine.  See the
         comment at the head of this block for more details.  */
-      if (readbuf != nullptr)
+      if (read_value != nullptr)
        {
-         struct value *arg_val;
-
          if (is_fixed_point_type (arg_type))
            {
              /* Convert abi_val to the actual return type, but
@@ -3405,15 +3409,13 @@ riscv_return_value (struct gdbarch  *gdbarch,
              unscaled.read (value_contents (abi_val),
                             type_byte_order (info.type),
                             info.type->is_unsigned ());
-             arg_val = allocate_value (arg_type);
-             unscaled.write (value_contents_raw (arg_val),
+             *read_value = allocate_value (arg_type);
+             unscaled.write (value_contents_raw (*read_value),
                              type_byte_order (arg_type),
                              arg_type->is_unsigned ());
            }
          else
-           arg_val = value_cast (arg_type, abi_val);
-         memcpy (old_readbuf, value_contents_raw (arg_val).data (),
-                 arg_type->length ());
+           *read_value = value_cast (arg_type, abi_val);
        }
     }
 
index 91cf391ec8ab5a50864694601ba414329380795b..55c84346f64700509d9cf2f1231f663ec2476c09 100644 (file)
@@ -1500,13 +1500,6 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
 {
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
 
-  gdb_byte *readbuf = nullptr;
-  if (read_value != nullptr)
-    {
-      *read_value = allocate_value (type);
-      readbuf = value_contents_raw (*read_value).data ();
-    }
-
   /* The psABI says that "...every stack frame reserves the word at
      %fp+64.  If a function returns a structure, union, or
      quad-precision value, this word should hold the address of the
@@ -1519,11 +1512,11 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
       ULONGEST sp;
       CORE_ADDR addr;
 
-      if (readbuf)
+      if (read_value != nullptr)
        {
          regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
          addr = read_memory_unsigned_integer (sp + 64, 4, byte_order);
-         read_memory (addr, readbuf, type->length ());
+         *read_value = value_at_non_lval (type, addr);
        }
       if (writebuf)
        {
@@ -1535,8 +1528,12 @@ sparc32_return_value (struct gdbarch *gdbarch, struct value *function,
       return RETURN_VALUE_ABI_PRESERVES_ADDRESS;
     }
 
-  if (readbuf)
-    sparc32_extract_return_value (type, regcache, readbuf);
+  if (read_value != nullptr)
+    {
+      *read_value = allocate_value (type);
+      gdb_byte *readbuf = value_contents_raw (*read_value).data ();
+      sparc32_extract_return_value (type, regcache, readbuf);
+    }
   if (writebuf)
     sparc32_store_return_value (type, regcache, writebuf);