[RFC][gdb] gdbarch_return_value selftest, powerpc failures

Tom de Vries tdevries@suse.de
Wed Jun 15 11:58:18 GMT 2022


Hi,

In PR29247 the following assert was reported:
...
(gdb) p t_structs_ldc(struct_val1)^M
gdb/ppc-sysv-tdep.c:1945: internal-error: ppc64_sysv_abi_return_value: \
  Assertion `ok' failed.^M
A problem internal to GDB has been detected,^M
further debugging may prove unreliable.^M
...

I had trouble finding a machine to easily reproduce this on, so I tried to
write a selftest that calls gdbarch_return_value for a function returning a
complex long double, for all arch/osabi combinations.

This allowed me to hit the same assert (though I can't be sure yet it's the
same root cause).  I also hit a couple of other asserts.

Interestingly, only for powerpc archs do we hit asserts, all other targets
pass.

By turning the asserts into errors (included in this patch for demonstration
purposes), catching them in the selftest and printing them as warning in
arch/osabi:fn:assert format, we get an overview of where things go wrong:
...
$ gdb -q -batch -ex "maint selftest gdbarch_return_value" 2>&1 | grep warning:
warning: powerpc:620/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:620/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:620/NetBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:620/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:630/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:630/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:630/NetBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:630/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:a35/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:a35/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:a35/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:common64/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:common64/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:common64/NetBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:common64/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:e500/AIX:rs6000_return_value: !ppc_floating_point_unit_p (gdbarch)
warning: powerpc:e500/LynxOS178:rs6000_lynx178_return_value: !ppc_floating_point_unit_p (gdbarch)
warning: powerpc:rs64ii/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:rs64ii/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:rs64ii/NetBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:rs64ii/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:rs64iii/none:ppc64_sysv_abi_return_value: !ok
warning: powerpc:rs64iii/FreeBSD:ppc64_sysv_abi_return_value: !ok
warning: powerpc:rs64iii/NetBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
warning: powerpc:rs64iii/OpenBSD:do_ppc_sysv_return_value: tdep->wordsize != 4
...

There are three clusters:
- 'ppc64_sysv_abi_return_value: !ok'
  For osabi none and FreeBSD, and some 64-bit powerpc archs.
- 'do_ppc_sysv_return_value: tdep->wordsize != 4'
  For osabi NetBSD and OpenBSD and the same set of 64-bit powerpc archs.
- 'rs6000{,_lynx178}_return_value: !ppc_floating_point_unit_p (gdbarch)'
  For osabi AIX and LynxOS178, and arch e500.

Based on the information from the selftest, I then managed to reproduce the
first cluster outside a selftest context using:
...
$ gdb -q -batch ./outputs/gdb.base/callfuncs/callfuncs \
  -ex "start" \
  -ex "set osabi none" \
  -ex "p t_structs_ldc(struct_val1)"
...
on a power9 machine with arch set to auto/powerpc:common64", and after
rebuilding with --enable-targets=all I managed the same with osabi FreeBSD.

Likewise for the second cluster, using "set osabi NetBSD/OpenBSD".

I didn't manage to reproduce the third cluster.

Using LynxOS178 and "set arch powerpc:e500" doesn't trigger an assert, AFAICT
because "set arch powerpc:e500" doesn't make "ppc_floating_point_unit_p
(gdbarch)" return false, so that probably needs a setup with an actual e500
executable.

Using AIX, I run into a SIGSEGV:
...
Thread 1 "gdb" received signal SIGSEGV, Segmentation fault.
0x0000000010bc4930 in xcoff_get_toc_offset (objfile=0x12874730) at \
  src/gdb/xcoffread.c:2848
2848        return XCOFF_DATA (objfile)->toc_offset;
(gdb) up
...
because of trying to dereference XCOFF_DATA (objfile) which is a nullptr:
...
(gdb) p xcoff_objfile_data_key.get (objfile)
$6 = (xcoff_symfile_info *) 0x0
...

So, it looks like at least the first two clusters, and the SIGSEGV need
fixing.

As for the third cluster, if we want to commit this selftest, we'll either
need to explicitly skip that case, or also fix it.

Any comments on the selftest, or how to fix the asserts/SIGSEGV are welcome.

Thanks,
- Tom

[gdb] gdbarch_return_value selftest, powerpc failures

---
 gdb/gdbarch-selftests.c   | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ppc-sysv-tdep.c       | 12 ++++++++----
 gdb/rs6000-aix-tdep.c     |  3 ++-
 gdb/rs6000-lynx178-tdep.c |  3 ++-
 4 files changed, 61 insertions(+), 6 deletions(-)

diff --git a/gdb/gdbarch-selftests.c b/gdb/gdbarch-selftests.c
index 198346bddec..3959d727e3b 100644
--- a/gdb/gdbarch-selftests.c
+++ b/gdb/gdbarch-selftests.c
@@ -122,6 +122,53 @@ register_to_value_test (struct gdbarch *gdbarch)
     }
 }
 
+static void
+gdbarch_return_value (struct gdbarch *gdbarch)
+{
+  const char *name = gdbarch_bfd_arch_info (gdbarch)->printable_name;
+
+  struct type *t = builtin_type (gdbarch)->builtin_long_double;
+  struct type *c = init_complex_type ("complex long double", t);
+  struct type *f = lookup_function_type (c);
+  struct value *v
+    = allocate_value_lazy (f);
+
+  struct gdbarch_info info;
+  info.bfd_arch_info = gdbarch_bfd_arch_info (gdbarch);
+
+  enum gdb_osabi it;
+  for (it = GDB_OSABI_UNKNOWN; it != GDB_OSABI_INVALID;
+       it = static_cast<enum gdb_osabi>(static_cast<int>(it) + 1))
+    {
+      if (it == GDB_OSABI_UNKNOWN)
+	continue;
+
+      info.osabi = it;
+
+      if (it != GDB_OSABI_NONE)
+	{
+	  if (!has_gdb_osabi_handler (info))
+	    /* Unsupported.  Skip to prevent warnings like:
+	       A handler for the OS ABI <x> is not built into this
+	       configuration of GDB.  Attempting to continue with the
+	       default <y> settings.  */
+	    continue;
+	}
+
+      gdbarch = gdbarch_find_by_info (info);
+      SELF_CHECK (gdbarch != NULL);
+
+      try
+	{
+	  gdbarch_return_value (gdbarch, v, c, nullptr, nullptr, nullptr);
+	}
+      catch (const gdb_exception_error &e)
+	{
+	  warning ("%s/%s:%s", name, gdbarch_osabi_name (info.osabi), e.what ());
+	}
+    }
+}
+
 } // namespace selftests
 
 void _initialize_gdbarch_selftests ();
@@ -130,4 +177,6 @@ _initialize_gdbarch_selftests ()
 {
   selftests::register_test_foreach_arch ("register_to_value",
 					 selftests::register_to_value_test);
+  selftests::register_test_foreach_arch ("gdbarch_return_value",
+					 selftests::gdbarch_return_value);
 }
diff --git a/gdb/ppc-sysv-tdep.c b/gdb/ppc-sysv-tdep.c
index 6c2fd1bfc99..2c7c0dbe615 100644
--- a/gdb/ppc-sysv-tdep.c
+++ b/gdb/ppc-sysv-tdep.c
@@ -679,7 +679,8 @@ do_ppc_sysv_return_value (struct gdbarch *gdbarch, struct type *func_type,
   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
   int opencl_abi = func_type? ppc_sysv_use_opencl_abi (func_type) : 0;
 
-  gdb_assert (tdep->wordsize == 4);
+  if (tdep->wordsize != 4)
+    error ("do_ppc_sysv_return_value: tdep->wordsize != 4");
 
   if (type->code () == TYPE_CODE_FLT
       && TYPE_LENGTH (type) <= 8
@@ -1942,7 +1943,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 	{
 	  ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
 						 readbuf, writebuf, i);
-	  gdb_assert (ok);
+	  if (!ok)
+	    error ("ppc64_sysv_abi_return_value: !ok");
 
 	  if (readbuf)
 	    readbuf += TYPE_LENGTH (eltype);
@@ -1968,7 +1970,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 	{
 	  ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
 						 readbuf, writebuf, i);
-	  gdb_assert (ok);
+	  if (!ok)
+	    error ("ppc64_sysv_abi_return_value: !ok");
 
 	  if (readbuf)
 	    readbuf += TYPE_LENGTH (eltype);
@@ -2024,7 +2027,8 @@ ppc64_sysv_abi_return_value (struct gdbarch *gdbarch, struct value *function,
 	{
 	  ok = ppc64_sysv_abi_return_value_base (gdbarch, eltype, regcache,
 						 readbuf, writebuf, i);
-	  gdb_assert (ok);
+	  if (!ok)
+	    error ("ppc64_sysv_abi_return_value: !ok");
 
 	  if (readbuf)
 	    readbuf += TYPE_LENGTH (eltype);
diff --git a/gdb/rs6000-aix-tdep.c b/gdb/rs6000-aix-tdep.c
index 867f21dc634..a729f15a24d 100644
--- a/gdb/rs6000-aix-tdep.c
+++ b/gdb/rs6000-aix-tdep.c
@@ -528,7 +528,8 @@ rs6000_return_value (struct gdbarch *gdbarch, struct value *function,
   /* The calling convention this function implements assumes the
      processor has floating-point registers.  We shouldn't be using it
      on PowerPC variants that lack them.  */
-  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+  if (!ppc_floating_point_unit_p (gdbarch))
+    error ("rs6000_return_value: !ppc_floating_point_unit_p (gdbarch)");
 
   /* AltiVec extension: Functions that declare a vector data type as a
      return value place that return value in VR2.  */
diff --git a/gdb/rs6000-lynx178-tdep.c b/gdb/rs6000-lynx178-tdep.c
index 844d0a4ede2..b7270b3bfc8 100644
--- a/gdb/rs6000-lynx178-tdep.c
+++ b/gdb/rs6000-lynx178-tdep.c
@@ -271,7 +271,8 @@ rs6000_lynx178_return_value (struct gdbarch *gdbarch, struct value *function,
   /* The calling convention this function implements assumes the
      processor has floating-point registers.  We shouldn't be using it
      on PowerPC variants that lack them.  */
-  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+  if (!ppc_floating_point_unit_p (gdbarch))
+    error ("rs6000_lynx178_return_value: !ppc_floating_point_unit_p (gdbarch)");
 
   /* AltiVec extension: Functions that declare a vector data type as a
      return value place that return value in VR2.  */


More information about the Gdb-patches mailing list