[gdb/tui] Refactor prefresh call in tui_source_window_base::refresh_window
[binutils-gdb.git] / libctf / ctf-serialize.c
index 460ae1a510ed8e2934a05004cec4551a591171ed..ba830a2b0959ebe2dabb865b705c8bf811d33b6b 100644 (file)
@@ -1,5 +1,5 @@
 /* CTF dict creation.
-   Copyright (C) 2019-2021 Free Software Foundation, Inc.
+   Copyright (C) 2019-2023 Free Software Foundation, Inc.
 
    This file is part of libctf.
 
@@ -431,12 +431,12 @@ emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
   return 0;
 }
 
-/* Delete data symbols that have been assigned names from the variable section.
-   Must be called from within ctf_serialize, because that is the only place
-   you can safely delete variables without messing up ctf_rollback.  */
+/* Delete symbols that have been assigned names from the variable section.  Must
+   be called from within ctf_serialize, because that is the only place you can
+   safely delete variables without messing up ctf_rollback.  */
 
 static int
-symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
+symtypetab_delete_nonstatics (ctf_dict_t *fp, ctf_dict_t *symfp)
 {
   ctf_dvdef_t *dvd, *nvd;
   ctf_id_t type;
@@ -445,8 +445,10 @@ symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
     {
       nvd = ctf_list_next (dvd);
 
-      if (((type = (ctf_id_t) (uintptr_t)
-           ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+      if ((((type = (ctf_id_t) (uintptr_t)
+            ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+          || (type = (ctf_id_t) (uintptr_t)
+              ctf_dynhash_lookup (fp->ctf_funchash, dvd->dvd_name)) > 0)
          && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
          && type == dvd->dvd_type)
        ctf_dvd_delete (fp, dvd);
@@ -560,13 +562,12 @@ ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s,
 
   /* If we are filtering symbols out, those symbols that the linker has not
      reported have now been removed from the ctf_objthash and ctf_funchash.
-     Delete entries from the variable section that duplicate newly-added data
-     symbols.  There's no need to migrate new ones in, because the compiler
-     always emits both a variable and a data symbol simultaneously, and
-     filtering only happens at final link time.  */
+     Delete entries from the variable section that duplicate newly-added
+     symbols.  There's no need to migrate new ones in: we do that (if necessary)
+     in ctf_link_deduplicating_variables.  */
 
   if (s->filter_syms && s->symfp->ctf_dynsyms &&
-      symtypetab_delete_nonstatic_vars (fp, s->symfp) < 0)
+      symtypetab_delete_nonstatics (fp, s->symfp) < 0)
     return -1;
 
   return 0;
@@ -719,77 +720,6 @@ symerr:
 
 /* Type section.  */
 
-static unsigned char *
-ctf_copy_smembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
-  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-  ctf_member_t ctm;
-
-  for (; dmd != NULL; dmd = ctf_list_next (dmd))
-    {
-      ctf_member_t *copied;
-
-      ctm.ctm_name = 0;
-      ctm.ctm_type = (uint32_t) dmd->dmd_type;
-      ctm.ctm_offset = (uint32_t) dmd->dmd_offset;
-
-      memcpy (t, &ctm, sizeof (ctm));
-      copied = (ctf_member_t *) t;
-      if (dmd->dmd_name)
-       ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctm_name);
-
-      t += sizeof (ctm);
-    }
-
-  return t;
-}
-
-static unsigned char *
-ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
-  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-  ctf_lmember_t ctlm;
-
-  for (; dmd != NULL; dmd = ctf_list_next (dmd))
-    {
-      ctf_lmember_t *copied;
-
-      ctlm.ctlm_name = 0;
-      ctlm.ctlm_type = (uint32_t) dmd->dmd_type;
-      ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset);
-      ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset);
-
-      memcpy (t, &ctlm, sizeof (ctlm));
-      copied = (ctf_lmember_t *) t;
-      if (dmd->dmd_name)
-       ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctlm_name);
-
-      t += sizeof (ctlm);
-    }
-
-  return t;
-}
-
-static unsigned char *
-ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
-{
-  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-  ctf_enum_t cte;
-
-  for (; dmd != NULL; dmd = ctf_list_next (dmd))
-    {
-      ctf_enum_t *copied;
-
-      cte.cte_value = dmd->dmd_value;
-      memcpy (t, &cte, sizeof (cte));
-      copied = (ctf_enum_t *) t;
-      ctf_str_add_ref (fp, dmd->dmd_name, &copied->cte_name);
-      t += sizeof (cte);
-    }
-
-  return t;
-}
-
 /* Iterate through the dynamic type definition list and compute the
    size of the CTF type section.  */
 
@@ -804,8 +734,20 @@ ctf_type_sect_size (ctf_dict_t *fp)
     {
       uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
       uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+      size_t type_ctt_size = dtd->dtd_data.ctt_size;
+
+      /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
+        if possible.  */
+
+      if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
+       {
+         size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
 
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+         if (lsize <= CTF_MAX_SIZE)
+           type_ctt_size = lsize;
+       }
+
+      if (type_ctt_size != CTF_LSIZE_SENT)
        type_size += sizeof (ctf_stype_t);
       else
        type_size += sizeof (ctf_type_t);
@@ -827,7 +769,7 @@ ctf_type_sect_size (ctf_dict_t *fp)
          break;
        case CTF_K_STRUCT:
        case CTF_K_UNION:
-         if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+         if (type_ctt_size < CTF_LSTRUCT_THRESH)
            type_size += sizeof (ctf_member_t) * vlen;
          else
            type_size += sizeof (ctf_lmember_t) * vlen;
@@ -856,12 +798,24 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
     {
       uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
       uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
-
+      size_t type_ctt_size = dtd->dtd_data.ctt_size;
       size_t len;
       ctf_stype_t *copied;
       const char *name;
+      size_t i;
+
+      /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t
+        if possible.  */
+
+      if (kind == CTF_K_STRUCT || kind == CTF_K_UNION)
+       {
+         size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data);
+
+         if (lsize <= CTF_MAX_SIZE)
+           type_ctt_size = lsize;
+       }
 
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+      if (type_ctt_size != CTF_LSIZE_SENT)
        len = sizeof (ctf_stype_t);
       else
        len = sizeof (ctf_type_t);
@@ -870,7 +824,11 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
       copied = (ctf_stype_t *) t;  /* name is at the start: constant offset.  */
       if (copied->ctt_name
          && (name = ctf_strraw (fp, copied->ctt_name)) != NULL)
-       ctf_str_add_ref (fp, name, &copied->ctt_name);
+       {
+         ctf_str_add_ref (fp, name, &copied->ctt_name);
+         ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name);
+       }
+      copied->ctt_size = type_ctt_size;
       t += len;
 
       switch (kind)
@@ -892,21 +850,65 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
          break;
 
        case CTF_K_FUNCTION:
-         memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
+         /* Functions with no args also have no vlen.  */
+         if (dtd->dtd_vlen)
+           memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
          t += sizeof (uint32_t) * (vlen + (vlen & 1));
          break;
 
+         /* These need to be copied across element by element, depending on
+            their ctt_size.  */
        case CTF_K_STRUCT:
        case CTF_K_UNION:
-         if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
-           t = ctf_copy_smembers (fp, dtd, t);
+         {
+           ctf_lmember_t *dtd_vlen = (ctf_lmember_t *) dtd->dtd_vlen;
+           ctf_lmember_t *t_lvlen = (ctf_lmember_t *) t;
+           ctf_member_t *t_vlen = (ctf_member_t *) t;
+
+           for (i = 0; i < vlen; i++)
+             {
+               const char *name = ctf_strraw (fp, dtd_vlen[i].ctlm_name);
+
+               ctf_str_add_ref (fp, name, &dtd_vlen[i].ctlm_name);
+
+               if (type_ctt_size < CTF_LSTRUCT_THRESH)
+                 {
+                   t_vlen[i].ctm_name = dtd_vlen[i].ctlm_name;
+                   t_vlen[i].ctm_type = dtd_vlen[i].ctlm_type;
+                   t_vlen[i].ctm_offset = CTF_LMEM_OFFSET (&dtd_vlen[i]);
+                   ctf_str_add_ref (fp, name, &t_vlen[i].ctm_name);
+                 }
+               else
+                 {
+                   t_lvlen[i] = dtd_vlen[i];
+                   ctf_str_add_ref (fp, name, &t_lvlen[i].ctlm_name);
+                 }
+             }
+         }
+
+         if (type_ctt_size < CTF_LSTRUCT_THRESH)
+           t += sizeof (ctf_member_t) * vlen;
          else
-           t = ctf_copy_lmembers (fp, dtd, t);
+           t += sizeof (ctf_lmember_t) * vlen;
          break;
 
        case CTF_K_ENUM:
-         t = ctf_copy_emembers (fp, dtd, t);
-         break;
+         {
+           ctf_enum_t *dtd_vlen = (struct ctf_enum *) dtd->dtd_vlen;
+           ctf_enum_t *t_vlen = (struct ctf_enum *) t;
+
+           memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_enum) * vlen);
+           for (i = 0; i < vlen; i++)
+             {
+               const char *name = ctf_strraw (fp, dtd_vlen[i].cte_name);
+
+               ctf_str_add_ref (fp, name, &t_vlen[i].cte_name);
+               ctf_str_add_ref (fp, name, &dtd_vlen[i].cte_name);
+             }
+           t += sizeof (struct ctf_enum) * vlen;
+
+           break;
+         }
        }
     }
 
@@ -955,6 +957,7 @@ ctf_serialize (ctf_dict_t *fp)
   ctf_varent_t *dvarents;
   ctf_strs_writable_t strtab;
   int err;
+  int num_missed_str_refs;
 
   unsigned char *t;
   unsigned long i;
@@ -973,6 +976,16 @@ ctf_serialize (ctf_dict_t *fp)
   if (!(fp->ctf_flags & LCTF_DIRTY))
     return 0;
 
+  /* The strtab refs table must be empty at this stage.  Any refs already added
+     will be corrupted by any modifications, including reserialization, after
+     strtab finalization is complete.  Only this function, and functions it
+     calls, may add refs, and all memory locations (including in the dtds)
+     containing strtab offsets must be traversed as part of serialization, and
+     refs added.  */
+
+  if (!ctf_assert (fp, fp->ctf_str_num_refs == 0))
+    return -1;                                 /* errno is set for us.  */
+
   /* Fill in an initial CTF header.  We will leave the label, object,
      and function sections empty and only output a header, type section,
      and string table.  The type section begins at a 4-byte aligned
@@ -1052,6 +1065,12 @@ ctf_serialize (ctf_dict_t *fp)
 
   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
 
+  /* Every string added outside serialization by ctf_str_add_pending should
+     now have been added by ctf_add_ref.  */
+  num_missed_str_refs = ctf_dynset_elements (fp->ctf_str_pending_ref);
+  if (!ctf_assert (fp, num_missed_str_refs == 0))
+    goto err;                                  /* errno is set for us.  */
+
   /* Construct the final string table and fill out all the string refs with the
      final offsets.  Then purge the refs list, because we're about to move this
      strtab onto the end of the buf, invalidating all the offsets.  */
@@ -1113,6 +1132,7 @@ ctf_serialize (ctf_dict_t *fp)
   nfp->ctf_dynsyms = fp->ctf_dynsyms;
   nfp->ctf_ptrtab = fp->ctf_ptrtab;
   nfp->ctf_pptrtab = fp->ctf_pptrtab;
+  nfp->ctf_typemax = fp->ctf_typemax;
   nfp->ctf_dynsymidx = fp->ctf_dynsymidx;
   nfp->ctf_dynsymmax = fp->ctf_dynsymmax;
   nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len;
@@ -1153,8 +1173,10 @@ ctf_serialize (ctf_dict_t *fp)
   ctf_str_free_atoms (nfp);
   nfp->ctf_str_atoms = fp->ctf_str_atoms;
   nfp->ctf_prov_strtab = fp->ctf_prov_strtab;
+  nfp->ctf_str_pending_ref = fp->ctf_str_pending_ref;
   fp->ctf_str_atoms = NULL;
   fp->ctf_prov_strtab = NULL;
+  fp->ctf_str_pending_ref = NULL;
   memset (&fp->ctf_dtdefs, 0, sizeof (ctf_list_t));
   memset (&fp->ctf_errs_warnings, 0, sizeof (ctf_list_t));
   fp->ctf_add_processing = NULL;
@@ -1207,7 +1229,13 @@ err:
 
 /* File writing.  */
 
-/* Write the compressed CTF data stream to the specified gzFile descriptor.  */
+/* Write the compressed CTF data stream to the specified gzFile descriptor.  The
+   whole stream is compressed, and cannot be read by CTF opening functions in
+   this library until it is decompressed.  (The functions below this one leave
+   the header uncompressed, and the CTF opening functions work on them without
+   manual decompression.)
+
+   No support for (testing-only) endian-flipping.  */
 int
 ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
 {
@@ -1238,85 +1266,25 @@ ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
   return 0;
 }
 
-/* Compress the specified CTF data stream and write it to the specified file
-   descriptor.  */
-int
-ctf_compress_write (ctf_dict_t *fp, int fd)
-{
-  unsigned char *buf;
-  unsigned char *bp;
-  ctf_header_t h;
-  ctf_header_t *hp = &h;
-  ssize_t header_len = sizeof (ctf_header_t);
-  ssize_t compress_len;
-  ssize_t len;
-  int rc;
-  int err = 0;
-
-  if (ctf_serialize (fp) < 0)
-    return -1;                                 /* errno is set for us.  */
-
-  memcpy (hp, fp->ctf_header, header_len);
-  hp->cth_flags |= CTF_F_COMPRESS;
-  compress_len = compressBound (fp->ctf_size);
-
-  if ((buf = malloc (compress_len)) == NULL)
-    {
-      ctf_err_warn (fp, 0, 0, _("ctf_compress_write: cannot allocate %li bytes"),
-                   (unsigned long) compress_len);
-      return (ctf_set_errno (fp, ECTF_ZALLOC));
-    }
-
-  if ((rc = compress (buf, (uLongf *) &compress_len,
-                     fp->ctf_buf, fp->ctf_size)) != Z_OK)
-    {
-      err = ctf_set_errno (fp, ECTF_COMPRESS);
-      ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
-      goto ret;
-    }
-
-  while (header_len > 0)
-    {
-      if ((len = write (fd, hp, header_len)) < 0)
-       {
-         err = ctf_set_errno (fp, errno);
-         ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing header"));
-         goto ret;
-       }
-      header_len -= len;
-      hp += len;
-    }
-
-  bp = buf;
-  while (compress_len > 0)
-    {
-      if ((len = write (fd, bp, compress_len)) < 0)
-       {
-         err = ctf_set_errno (fp, errno);
-         ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
-         goto ret;
-       }
-      compress_len -= len;
-      bp += len;
-    }
-
-ret:
-  free (buf);
-  return err;
-}
-
 /* Optionally compress the specified CTF data stream and return it as a new
-   dynamically-allocated string.  */
+   dynamically-allocated string.  Possibly write it with reversed
+   endianness.  */
 unsigned char *
 ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
 {
   unsigned char *buf;
   unsigned char *bp;
   ctf_header_t *hp;
+  unsigned char *flipped, *src;
   ssize_t header_len = sizeof (ctf_header_t);
   ssize_t compress_len;
+  int flip_endian;
+  int uncompressed;
   int rc;
 
+  flip_endian = getenv ("LIBCTF_WRITE_FOREIGN_ENDIAN") != NULL;
+  uncompressed = (fp->ctf_size < threshold);
+
   if (ctf_serialize (fp) < 0)
     return NULL;                               /* errno is set for us.  */
 
@@ -1337,17 +1305,43 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
   bp = buf + sizeof (struct ctf_header);
   *size = sizeof (struct ctf_header);
 
-  if (fp->ctf_size < threshold)
+  if (uncompressed)
+    hp->cth_flags &= ~CTF_F_COMPRESS;
+  else
+    hp->cth_flags |= CTF_F_COMPRESS;
+
+  src = fp->ctf_buf;
+  flipped = NULL;
+
+  if (flip_endian)
     {
-      hp->cth_flags &= ~CTF_F_COMPRESS;
-      memcpy (bp, fp->ctf_buf, fp->ctf_size);
+      if ((flipped = malloc (fp->ctf_size)) == NULL)
+       {
+         ctf_set_errno (fp, ENOMEM);
+         ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
+                       (unsigned long) (fp->ctf_size + sizeof (struct ctf_header)));
+         return NULL;
+       }
+      ctf_flip_header (hp);
+      memcpy (flipped, fp->ctf_buf, fp->ctf_size);
+      if (ctf_flip (fp, fp->ctf_header, flipped, 1) < 0)
+       {
+         free (buf);
+         free (flipped);
+         return NULL;                          /* errno is set for us.  */
+       }
+      src = flipped;
+    }
+
+  if (uncompressed)
+    {
+      memcpy (bp, src, fp->ctf_size);
       *size += fp->ctf_size;
     }
   else
     {
-      hp->cth_flags |= CTF_F_COMPRESS;
       if ((rc = compress (bp, (uLongf *) &compress_len,
-                         fp->ctf_buf, fp->ctf_size)) != Z_OK)
+                         src, fp->ctf_size)) != Z_OK)
        {
          ctf_set_errno (fp, ECTF_COMPRESS);
          ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
@@ -1356,45 +1350,77 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
        }
       *size += compress_len;
     }
+
+  free (flipped);
+
   return buf;
 }
 
-/* Write the uncompressed CTF data stream to the specified file descriptor.  */
+/* Compress the specified CTF data stream and write it to the specified file
+   descriptor.  */
 int
-ctf_write (ctf_dict_t *fp, int fd)
+ctf_compress_write (ctf_dict_t *fp, int fd)
 {
-  const unsigned char *buf;
-  ssize_t resid;
+  unsigned char *buf;
+  unsigned char *bp;
+  size_t tmp;
+  ssize_t buf_len;
   ssize_t len;
+  int err = 0;
 
-  if (ctf_serialize (fp) < 0)
+  if ((buf = ctf_write_mem (fp, &tmp, 0)) == NULL)
     return -1;                                 /* errno is set for us.  */
 
-  resid = sizeof (ctf_header_t);
-  buf = (unsigned char *) fp->ctf_header;
-  while (resid != 0)
+  buf_len = tmp;
+  bp = buf;
+
+  while (buf_len > 0)
     {
-      if ((len = write (fd, buf, resid)) <= 0)
+      if ((len = write (fd, bp, buf_len)) < 0)
        {
-         ctf_err_warn (fp, 0, errno, _("ctf_write: error writing header"));
-         return (ctf_set_errno (fp, errno));
+         err = ctf_set_errno (fp, errno);
+         ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
+         goto ret;
        }
-      resid -= len;
-      buf += len;
+      buf_len -= len;
+      bp += len;
     }
 
-  resid = fp->ctf_size;
-  buf = fp->ctf_buf;
-  while (resid != 0)
+ret:
+  free (buf);
+  return err;
+}
+
+/* Write the uncompressed CTF data stream to the specified file descriptor.  */
+int
+ctf_write (ctf_dict_t *fp, int fd)
+{
+  unsigned char *buf;
+  unsigned char *bp;
+  size_t tmp;
+  ssize_t buf_len;
+  ssize_t len;
+  int err = 0;
+
+  if ((buf = ctf_write_mem (fp, &tmp, (size_t) -1)) == NULL)
+    return -1;                                 /* errno is set for us.  */
+
+  buf_len = tmp;
+  bp = buf;
+
+  while (buf_len > 0)
     {
-      if ((len = write (fd, buf, resid)) <= 0)
+      if ((len = write (fd, bp, buf_len)) < 0)
        {
-         ctf_err_warn (fp, 0, errno, _("ctf_write: error writing"));
-         return (ctf_set_errno (fp, errno));
+         err = ctf_set_errno (fp, errno);
+         ctf_err_warn (fp, 0, 0, _("ctf_compress_write: error writing"));
+         goto ret;
        }
-      resid -= len;
-      buf += len;
+      buf_len -= len;
+      bp += len;
     }
 
-  return 0;
+ret:
+  free (buf);
+  return err;
 }