libctf, create: support addition of references to the unimplemented type
authorNick Alcock <nick.alcock@oracle.com>
Tue, 2 Jun 2020 19:04:24 +0000 (20:04 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Wed, 22 Jul 2020 16:57:21 +0000 (17:57 +0100)
The deduplicating linker adds types from the linker inputs to the output
via the same API everyone else does, so it's important that we can emit
everything that the compiler wants us to.  Unfortunately, the compiler
may represent the unimplemented type (used for compiler constructs that
CTF cannot currently encode) as type zero or as a type of kind
CTF_K_UNKNOWN, and we don't allow the addition of types that cite the
former.

Adding this support adds a tiny bit of extra complexity: additions of
structure members immediately following a member of the unimplemented
type must be via ctf_add_member_offset or ctf_add_member_encoded, since
we have no idea how big members of the unimplemented type are.
(Attempts to do otherwise return -ECTF_NONREPRESENTABLE, like other
attempts to do forbidden things with the unimplemented type.)

Even slices of the unimplemented type are permitted: this is the only
case in which you can slice a type that terminates in a non-integral
type, on the grounds that it was likely integral in the source code,
it's just that we can't represent that sort of integral type properly
yet.

libctf/
* ctf-create.c (ctf_add_reftype): Support refs to type zero.
(ctf_add_array): Support array contents of type zero.
(ctf_add_function): Support arguments and return types of
type zero.
(ctf_add_typedef): Support typedefs to type zero.
(ctf_add_member_offset): Support members of type zero,
unless added at unspecified (naturally-aligned) offset.

libctf/ChangeLog
libctf/ctf-create.c

index 74e977659a43c3b9251fb90e7e5b6ab12da91d61..cca704a4ec231137144f7744b00477ae2be8b522 100644 (file)
@@ -1,3 +1,13 @@
+2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
+
+       * ctf-create.c (ctf_add_reftype): Support refs to type zero.
+       (ctf_add_array): Support array contents of type zero.
+       (ctf_add_function): Support arguments and return types of
+       type zero.
+       (ctf_add_typedef): Support typedefs to type zero.
+       (ctf_add_member_offset): Support members of type zero,
+       unless added at unspecified (naturally-aligned) offset.
+
 2020-07-22  Nick Alcock  <nick.alcock@oracle.com>
 
        * ctf-error.c: Include <stddef.h>, for offsetof.
index 808da372de811c5e0f3cfe0e3ca491988ff77b59..67a3f199a961f6882cee406796b91ef80cb6bda9 100644 (file)
@@ -900,7 +900,7 @@ ctf_add_reftype (ctf_file_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
-  if (ctf_lookup_by_id (&tmp, ref) == NULL)
+  if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;            /* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, NULL, kind, &dtd)) == CTF_ERR)
@@ -957,12 +957,13 @@ ctf_add_slice (ctf_file_t *fp, uint32_t flag, ctf_id_t ref,
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
-  if ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL)
+  if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
     return CTF_ERR;            /* errno is set for us.  */
 
   kind = ctf_type_kind_unsliced (tmp, ref);
   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
-      (kind != CTF_K_ENUM))
+      (kind != CTF_K_ENUM)
+      && (ref != 0))
     return (ctf_set_errno (fp, ECTF_NOTINTFP));
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE, &dtd)) == CTF_ERR)
@@ -1008,7 +1009,8 @@ ctf_add_array (ctf_file_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
   if (arp == NULL)
     return (ctf_set_errno (fp, EINVAL));
 
-  if (ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
+  if (arp->ctr_contents != 0
+      && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
     return CTF_ERR;            /* errno is set for us.  */
 
   tmp = fp;
@@ -1062,13 +1064,14 @@ ctf_add_function (ctf_file_t *fp, uint32_t flag,
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
     vlen++;           /* Add trailing zero to indicate varargs (see below).  */
 
-  if (ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
+  if (ctc->ctc_return != 0
+      && ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
     return CTF_ERR;            /* errno is set for us.  */
 
   for (i = 0; i < ctc->ctc_argc; i++)
     {
       tmp = fp;
-      if (ctf_lookup_by_id (&tmp, argv[i]) == NULL)
+      if (argv[i] != 0 && ctf_lookup_by_id (&tmp, argv[i]) == NULL)
        return CTF_ERR;         /* errno is set for us.  */
     }
 
@@ -1259,7 +1262,7 @@ ctf_add_typedef (ctf_file_t *fp, uint32_t flag, const char *name,
   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
     return (ctf_set_errno (fp, EINVAL));
 
-  if (ctf_lookup_by_id (&tmp, ref) == NULL)
+  if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
     return CTF_ERR;            /* errno is set for us.  */
 
   if ((type = ctf_add_generic (fp, flag, name, CTF_K_TYPEDEF,
@@ -1387,7 +1390,20 @@ ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
       (malign = ctf_type_align (fp, type)) < 0)
-    return -1;                 /* errno is set for us.  */
+    {
+      /* The unimplemented type, and any type that resolves to it, has no size
+        and no alignment: it can correspond to any number of compiler-inserted
+        types.  */
+
+      if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
+       {
+         msize = 0;
+         malign = 0;
+         ctf_set_errno (fp, 0);
+       }
+      else
+       return -1;              /* errno is set for us.  */
+    }
 
   if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
@@ -1415,6 +1431,16 @@ ctf_add_member_offset (ctf_file_t *fp, ctf_id_t souid, const char *name,
          ctf_encoding_t linfo;
          ssize_t lsize;
 
+         /* Propagate any error from ctf_type_resolve.  If the last member was
+            of unimplemented type, this may be -ECTF_NONREPRESENTABLE: we
+            cannot insert right after such a member without explicit offset
+            specification, because its alignment and size is not known.  */
+         if (ltype == CTF_ERR)
+           {
+             free (dmd);
+             return -1;        /* errno is set for us.  */
+           }
+
          if (ctf_type_encoding (fp, ltype, &linfo) == 0)
            off += linfo.cte_bits;
          else if ((lsize = ctf_type_size (fp, ltype)) > 0)