[binutils-gdb] libctf: fix cv-qualified unnamed struct/union field lookup

Nick Alcock nix@sourceware.org
Fri Feb 28 14:17:58 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=fa4fe2753730f412c00a8a2bab36550c063dfe95

commit fa4fe2753730f412c00a8a2bab36550c063dfe95
Author: Nick Alcock <nick.alcock@oracle.com>
Date:   Mon Feb 24 18:11:25 2025 +0000

    libctf: fix cv-qualified unnamed struct/union field lookup
    
    GCC permits not only unnamed structs and unions, but cv-qualified ones.
    Our earlier fix in 6c3a38777b38a2ad87e2b2bcec4567578d1c83ec supported
    unnamed structs and unions, but only unqualified ones.
    
    Resolving away cvr-quals of nameless fields (and, irrelevantly, typedefs)
    is easy and fixes this problem.
    
    Tests adjusted accordingly.
    
    libctf/
            PR libctf/32746
            * ctf-types.c (ctf_member_next): Resolve away cv-quals.
            (ctf_member_info): Likewise.
            * testsuite/libctf-lookup/struct-iteration-ctf.c: Add a cv-qualified
            type or two: make sure to keep a non-qualified one.
            * testsuite/libctf-lookup/struct-iteration.c: Verify consistency
            of ctf_member_next and ctf_member_info.
            * testsuite/libctf-lookup/struct-iteration.lk: Adjust.
    
    Tested-by: Stephen Brennan <stephen.s.brennan@oracle.com>

Diff:
---
 libctf/ctf-types.c                                 | 33 +++++++++++++++++-----
 .../testsuite/libctf-lookup/struct-iteration-ctf.c |  7 +++--
 libctf/testsuite/libctf-lookup/struct-iteration.c  | 18 ++++++++++++
 libctf/testsuite/libctf-lookup/struct-iteration.lk | 10 ++++---
 4 files changed, 55 insertions(+), 13 deletions(-)

diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 067a5d8c3a0..044a1852c1a 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -187,10 +187,21 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	*membtype = memb.ctlm_type;
       offset = (unsigned long) CTF_LMEM_OFFSET (&memb);
 
-      if (membname[0] == 0
-	  && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT
-	      || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION))
-	i->ctn_type = memb.ctlm_type;
+      if (membname[0] == 0)
+	{
+	  ctf_id_t resolved;
+
+	  if ((resolved = ctf_type_resolve (fp, memb.ctlm_type)) == CTF_ERR)
+	    {
+	      if (ctf_errno (fp) != ECTF_NONREPRESENTABLE)
+		return -1;			/* errno is set for us.  */
+	      resolved = memb.ctlm_type;
+	    }
+
+	  if (ctf_type_kind (fp, resolved) == CTF_K_STRUCT
+	      || ctf_type_kind (fp, resolved) == CTF_K_UNION)
+	    i->ctn_type = resolved;
+	}
       i->ctn_n++;
 
       /* The callers might want automatic recursive sub-struct traversal.  */
@@ -1406,16 +1417,24 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
     {
       ctf_lmember_t memb;
       const char *membname;
+      ctf_id_t resolved;
 
       if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
         return (ctf_set_errno (ofp, ctf_errno (fp)));
 
       membname = ctf_strptr (fp, memb.ctlm_name);
 
+      if ((resolved = ctf_type_resolve (fp, memb.ctlm_type)) == CTF_ERR)
+	{
+	  if (ctf_errno (fp) != ECTF_NONREPRESENTABLE)
+	    return (ctf_set_errno (ofp, ctf_errno (fp)));
+	  resolved = memb.ctlm_type;
+	}
+
       if (membname[0] == 0
-	  && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT
-	      || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION)
-	  && (ctf_member_info (fp, memb.ctlm_type, name, mip) == 0))
+	  && (ctf_type_kind (fp, resolved) == CTF_K_STRUCT
+	      || ctf_type_kind (fp, resolved) == CTF_K_UNION)
+	  && (ctf_member_info (fp, resolved, name, mip) == 0))
 	{
 	  mip->ctm_offset += (unsigned long) CTF_LMEM_OFFSET (&memb);
 	  return 0;
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
index 7df67adaad4..0a50d2c35af 100644
--- a/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
+++ b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c
@@ -6,12 +6,12 @@ struct foo_t
   size_t bar;
   const char *baz;
   struct foo_t *self;
-  union
+  const volatile union
   {
     double should_not_appear;
     char *nor_should_this;
   } named;
-  struct
+  volatile const struct
   {
     long unnamed_sub_member;
     union
@@ -19,6 +19,9 @@ struct foo_t
       double one_more_level;
       long yes_really_one_more;
     };
+    struct {
+      int and_finally;
+    };
   };
   struct {};		/* Empty ones */
   union {};
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.c b/libctf/testsuite/libctf-lookup/struct-iteration.c
index b2408648e7e..fd89ca77f67 100644
--- a/libctf/testsuite/libctf-lookup/struct-iteration.c
+++ b/libctf/testsuite/libctf-lookup/struct-iteration.c
@@ -51,11 +51,29 @@ main (int argc, char *argv[])
   while ((offset = ctf_member_next (fp, type, &i, &name, &membtype,
 				    CTF_MN_RECURSE)) >= 0)
     {
+      ctf_membinfo_t memb;
       char *type_name = ctf_type_aname (fp, membtype);
 
       printf ("next test: %s, offset %zx, has type %lx/%s\n",
 	      name, offset, membtype, type_name);
       free (type_name);
+
+      /* Check that we can get the same member via ctf_member_info too.  */
+      if (name[0] != '\0')
+	{
+	  if (ctf_member_info (fp, type, name, &memb) != 0)
+	    {
+	      fprintf (stderr, "Cannot get member info for %s: %s\n",
+		       name, ctf_errmsg (ctf_errno (fp)));
+	      exit (1);
+	    }
+	  if (memb.ctm_offset != offset || memb.ctm_type != membtype)
+	    {
+	      fprintf (stderr, "ctf_member_info versus iteration comparison "
+		       "failure: types %lx/%lx, offsets %zx/%lx\n",
+		       membtype, memb.ctm_type, offset, memb.ctm_offset);
+	    }
+	}
     }
   if (ctf_errno (fp) != ECTF_NEXT_END)
     goto nerr;
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.lk b/libctf/testsuite/libctf-lookup/struct-iteration.lk
index fd644547f20..aecffd44c85 100644
--- a/libctf/testsuite/libctf-lookup/struct-iteration.lk
+++ b/libctf/testsuite/libctf-lookup/struct-iteration.lk
@@ -4,8 +4,8 @@ iter test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int
 iter test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t
 iter test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \*
 iter test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \*
-iter test: named, offset [0-9a-f]*, has type [0-9a-f]*/union 
-iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+iter test: named, offset [0-9a-f]*, has type [0-9a-f]*/volatile const union 
+iter test: , offset [0-9a-f]*, has type [0-9a-f]*/volatile const struct 
 iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
 iter test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
 iter test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int
@@ -13,12 +13,14 @@ next test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int
 next test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t
 next test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \*
 next test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \*
-next test: named, offset [0-9a-f]*, has type [0-9a-f]*/union 
-next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+next test: named, offset [0-9a-f]*, has type [0-9a-f]*/volatile const union 
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/volatile const struct 
 next test: unnamed_sub_member, offset [0-9a-f]*, has type [0-9a-f]*/long int
 next test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
 next test: one_more_level, offset [0-9a-f]*, has type [0-9a-f]*/double
 next test: yes_really_one_more, offset [0-9a-f]*, has type [0-9a-f]*/long int
 next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
+next test: and_finally, offset [0-9a-f]*, has type [0-9a-f]*/int
+next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct 
 next test: , offset [0-9a-f]*, has type [0-9a-f]*/union 
 next test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int


More information about the Binutils-cvs mailing list