public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 00/16] libctf: mostly cleanups and refactoring
@ 2021-03-06  0:40 Nick Alcock
  2021-03-06  0:40 ` [PATCH 01/16] libctf: fix some tabdamage and move some code around Nick Alcock
                   ` (15 more replies)
  0 siblings, 16 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This series is mostly cleanups and refactoring in preparation for the
changes that will go into CTFv4, splitting serialization and dict writeout
into its own file and refactoring the representation of types in writable
dicts to use the same representation as used in written-out CTF dicts, and
to expand all CTF representations into their largest form for in-memory
processing, and to shrink them down to their smallest possible form only at
serialization time, so that code creating and querying types only needs to
handle one representation (the largest form used in written-out CTF dicts)
rather than three (the large form, the small form, and a form used only by
writable dicts).  This will make it practical to add more compact
representations in v4.

There are also a couple of bugfixes, highly unlikely to be visible in any
current use case, since they mostly relate either to error-handling or to
writing out a dict and then doing something else with it, something the
linker does not do and neither will users who merely consume .ctf sections
produced by the linker.

Jammed in the middle is one top-level possible fix for bug 27482, which
might need review as it is top-level. (The reporter has not yet confirmed
that this fixes his bug, either, but it might!)

The usual great big pile of tests passed (including, now, just over a
thousand Gentoo packages successfully built with nary a CTF-related linker
warning).

Nick Alcock (16):
  libctf: fix some tabdamage and move some code around
  libctf: split serialization and file writeout into its own file
  libctf: fix comment above ctf_dict_t
  libctf: split up ctf_serialize
  libctf: fix GNU style for do {} while
  libctf: eliminate dtd_u, part 1: int/float/slice
  libctf: eliminate dtd_u, part 2: arrays
  libctf: eliminate dtd_u, part 3: functions
  Add install dependencies for ld -> bfd and libctf -> bfd
  libctf: don't lose track of all valid types upon serialization
  libctf: do not corrupt strings across ctf_serialize
  libctf: eliminate dtd_u, part 4: enums
  libctf: eliminate dtd_u, part 5: structs / unions
  libctf: types: unify code dealing with small-vs-large struct members
  libctf: a couple of small error-handling fixes
  libctf: support encodings for enums

 Makefile.def                                  |    6 +-
 Makefile.in                                   |    4 +-
 ld/testsuite/ld-ctf/slice.c                   |    3 +
 ld/testsuite/ld-ctf/slice.d                   |    4 +-
 libctf/Makefile.am                            |    4 +-
 libctf/Makefile.in                            |   44 +-
 libctf/ctf-archive.c                          |    3 +-
 libctf/ctf-create.c                           | 1893 +++--------------
 libctf/ctf-dedup.c                            |   90 +-
 libctf/ctf-dump.c                             |    8 +-
 libctf/ctf-hash.c                             |    6 +
 libctf/ctf-impl.h                             |   42 +-
 libctf/ctf-link.c                             |   92 +-
 libctf/ctf-lookup.c                           |   15 +-
 libctf/ctf-open.c                             |    7 +-
 libctf/ctf-serialize.c                        | 1419 ++++++++++++
 libctf/ctf-string.c                           |   78 +-
 libctf/ctf-types.c                            |  540 ++---
 libctf/swap.h                                 |   24 +-
 .../testsuite/libctf-lookup/enum-many-ctf.c   |   10 +
 libctf/testsuite/libctf-lookup/enum-many.lk   |  101 +
 .../libctf-lookup/struct-iteration.c          |    6 +-
 .../type-add-unnamed-struct-ctf.c             |    1 +
 .../type-add-unnamed-struct.c                 |    4 +-
 .../type-add-unnamed-struct.lk                |    1 +
 .../reserialize-strtab-corruption.c           |   91 +
 .../reserialize-strtab-corruption.lk          |    5 +
 28 files changed, 2414 insertions(+), 2095 deletions(-)
 create mode 100644 libctf/ctf-serialize.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum-many-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum-many.lk
 create mode 100644 libctf/testsuite/libctf-writable/reserialize-strtab-corruption.c
 create mode 100644 libctf/testsuite/libctf-writable/reserialize-strtab-corruption.lk

-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/16] libctf: fix some tabdamage and move some code around
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 02/16] libctf: split serialization and file writeout into its own file Nick Alcock
                   ` (14 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

ctf-link.c is unnecessarily confusing because cdtf_link_lazy_open is
positioned near functions that have nothing to do with opening files.

Move it around, and fix some tabdamage that's crept in lately.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-link.c (ctf_link_lazy_open): Move up in the file, to near
	ctf_link_add_ctf.
	* ctf-lookup.c (ctf_lookup_symbol_idx): Repair tabdamage.
	(ctf_lookup_by_sym_or_name): Likewise.
	* testsuite/libctf-lookup/struct-iteration.c: Likewise.
	* testsuite/libctf-regression/type-add-unnamed-struct.c: Likewise.
---
 libctf/ctf-link.c                             | 92 +++++++++----------
 libctf/ctf-lookup.c                           | 12 +--
 .../libctf-lookup/struct-iteration.c          |  6 +-
 .../type-add-unnamed-struct.c                 |  2 +-
 4 files changed, 56 insertions(+), 56 deletions(-)

diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 5471fccd0f7..cc99f818970 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -189,6 +189,52 @@ ctf_link_add_ctf (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name)
   return ctf_link_add (fp, ctf, name, NULL, 0);
 }
 
+/* Lazily open a CTF archive for linking, if not already open.
+
+   Returns the number of files contained within the opened archive (0 for none),
+   or -1 on error, as usual.  */
+static ssize_t
+ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
+{
+  size_t count;
+  int err;
+
+  if (input->clin_arc)
+    return ctf_archive_count (input->clin_arc);
+
+  if (input->clin_fp)
+    return 1;
+
+  /* See ctf_link_add_ctf.  */
+#if defined (PIC) || !NOBFD
+  input->clin_arc = ctf_open (input->clin_filename, NULL, &err);
+#else
+  ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
+		input->clin_filename);
+  ctf_set_errno (fp, ECTF_NEEDSBFD);
+  return -1;
+#endif
+
+  /* Having no CTF sections is not an error.  We just don't need to do
+     anything.  */
+
+  if (!input->clin_arc)
+    {
+      if (err == ECTF_NOCTFDATA)
+	return 0;
+
+      ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
+		    input->clin_filename);
+      ctf_set_errno (fp, err);
+      return -1;
+    }
+
+  if ((count = ctf_archive_count (input->clin_arc)) == 0)
+    ctf_arc_close (input->clin_arc);
+
+  return (ssize_t) count;
+}
+
 /* Return a per-CU output CTF dictionary suitable for the given CU, creating and
    interning it if need be.  */
 
@@ -461,52 +507,6 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
   return 0;
 }
 
-/* Lazily open a CTF archive for linking, if not already open.
-
-   Returns the number of files contained within the opened archive (0 for none),
-   or -1 on error, as usual.  */
-static ssize_t
-ctf_link_lazy_open (ctf_dict_t *fp, ctf_link_input_t *input)
-{
-  size_t count;
-  int err;
-
-  if (input->clin_arc)
-    return ctf_archive_count (input->clin_arc);
-
-  if (input->clin_fp)
-    return 1;
-
-  /* See ctf_link_add_ctf.  */
-#if defined (PIC) || !NOBFD
-  input->clin_arc = ctf_open (input->clin_filename, NULL, &err);
-#else
-  ctf_err_warn (fp, 0, ECTF_NEEDSBFD, _("cannot open %s lazily"),
-		input->clin_filename);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
-  return -1;
-#endif
-
-  /* Having no CTF sections is not an error.  We just don't need to do
-     anything.  */
-
-  if (!input->clin_arc)
-    {
-      if (err == ECTF_NOCTFDATA)
-	return 0;
-
-      ctf_err_warn (fp, 0, err, _("opening CTF %s failed"),
-		    input->clin_filename);
-      ctf_set_errno (fp, err);
-      return -1;
-    }
-
-  if ((count = ctf_archive_count (input->clin_arc)) == 0)
-    ctf_arc_close (input->clin_arc);
-
-  return (ssize_t) count;
-}
-
 typedef struct link_sort_inputs_cb_arg
 {
   int is_cu_mapped;
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 6e17e5f4c54..2e78cf49276 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -592,9 +592,9 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 				       cache->ctf_symhash_latest) < 0)
 		goto oom;
 	    if (strcmp (sym.st_name, symname) == 0)
-              return cache->ctf_symhash_latest++;
-          }
-          break;
+	      return cache->ctf_symhash_latest++;
+	  }
+	  break;
 	case sizeof (Elf32_Sym):
 	  {
 	    Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data;
@@ -607,8 +607,8 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
 				       cache->ctf_symhash_latest) < 0)
 		goto oom;
 	    if (strcmp (sym.st_name, symname) == 0)
-              return cache->ctf_symhash_latest++;
-          }
+	      return cache->ctf_symhash_latest++;
+	  }
 	  break;
 	default:
 	  ctf_set_errno (fp, ECTF_SYMTAB);
@@ -902,7 +902,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
 	  if (symidx > fp->ctf_dynsymmax)
 	    goto try_parent;
 
-          sym = fp->ctf_dynsymidx[symidx];
+	  sym = fp->ctf_dynsymidx[symidx];
 	  err = ECTF_NOTYPEDAT;
 	  if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
 	    goto try_parent;
diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.c b/libctf/testsuite/libctf-lookup/struct-iteration.c
index 080edfadca4..005aba124d4 100644
--- a/libctf/testsuite/libctf-lookup/struct-iteration.c
+++ b/libctf/testsuite/libctf-lookup/struct-iteration.c
@@ -4,13 +4,13 @@
 
 static int
 print_struct (const char *name, ctf_id_t membtype, unsigned long offset,
-              void *fp_)
+	      void *fp_)
 {
   ctf_dict_t *fp = (ctf_dict_t *) fp_;
   char *type_name = ctf_type_aname (fp, membtype);
 
   printf ("iter test: %s, offset %lx, has type %lx/%s\n",
-          name, offset, membtype, type_name);
+	  name, offset, membtype, type_name);
   free (type_name);
 
   return 0;
@@ -54,7 +54,7 @@ main (int argc, char *argv[])
       char *type_name = ctf_type_aname (fp, membtype);
 
       printf ("next test: %s, offset %lx, has type %lx/%s\n",
-              name, offset, membtype, type_name);
+	      name, offset, membtype, type_name);
       free (type_name);
     }
   if (ctf_errno (fp) != ECTF_NEXT_END)
diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
index 98be257991a..43c3934add4 100644
--- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
+++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
@@ -47,7 +47,7 @@ main (int argc, char *argv[])
   for (walk = membs; *walk != NULL; walk++)
     {
       if (ctf_member_info (dyn, newtype, *walk, &mi) < 0)
-        goto lookup_err;
+	goto lookup_err;
       printf ("Looked up %s, type %lx, offset %lx\n", *walk, (long) mi.ctm_type, mi.ctm_offset);
     }
 
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 02/16] libctf: split serialization and file writeout into its own file
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
  2021-03-06  0:40 ` [PATCH 01/16] libctf: fix some tabdamage and move some code around Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 03/16] libctf: fix comment above ctf_dict_t Nick Alcock
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

The code to serialize CTF dicts just gets bigger and bigger as the
dictionary's complexity grows: adding symtypetabs almost doubled it on
its own.  It's long past time to split this out into its own source
file, accompanied by the functions that do the actual writeout.

This leaves ctf-create.c populated exclusively by functions related to
actual writable dict creation (ctf_add_*, ctf_create etc), and leaves
both files a much more reasonable size.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-create.c (symtypetab_delete_nonstatic_vars): Move
	into ctf-serialize.c.
	(ctf_symtab_skippable): Likewise.
	(CTF_SYMTYPETAB_EMIT_FUNCTION): Likewise.
	(CTF_SYMTYPETAB_EMIT_PAD): Likewise.
	(CTF_SYMTYPETAB_FORCE_INDEXED): Likewise.
	(symtypetab_density): Likewise.
	(emit_symtypetab): Likewise.
	(emit_symtypetab_index): Likewise.
	(ctf_copy_smembers): Likewise.
	(ctf_copy_lmembers): Likewise.
	(ctf_copy_emembers): Likewise.
	(ctf_sort_var): Likewise.
	(ctf_serialize): Likewise.
	(ctf_gzwrite): Likewise.
	(ctf_compress_write): Likewise.
	(ctf_write_mem): Likewise.
	(ctf_write): Likewise.
	* ctf-serialize.c: New file.
	* Makefile.am (libctf_nobfd_la_SOURCES): Add it.
	* Makefile.in: Regenerate.
---
 libctf/Makefile.am     |    4 +-
 libctf/Makefile.in     |   44 +-
 libctf/ctf-create.c    | 1311 +--------------------------------------
 libctf/ctf-serialize.c | 1332 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1367 insertions(+), 1324 deletions(-)
 create mode 100644 libctf/ctf-serialize.c

diff --git a/libctf/Makefile.am b/libctf/Makefile.am
index 03fd6cce0e0..e586d25fb37 100644
--- a/libctf/Makefile.am
+++ b/libctf/Makefile.am
@@ -46,8 +46,8 @@ libctf_nobfd_la_LDFLAGS = -version-info 0:0:0 @SHARED_LDFLAGS@ @VERSION_FLAGS@
 libctf_nobfd_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=1
 libctf_nobfd_la_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c ctf-decl.c ctf-error.c \
 			  ctf-hash.c ctf-labels.c ctf-dedup.c ctf-link.c ctf-lookup.c \
-			  ctf-open.c ctf-sha1.c ctf-string.c ctf-subr.c ctf-types.c \
-			  ctf-util.c
+			  ctf-open.c ctf-serialize.c ctf-sha1.c ctf-string.c ctf-subr.c \
+			  ctf-types.c ctf-util.c
 if NEED_CTF_QSORT_R
 libctf_nobfd_la_SOURCES += ctf-qsort_r.c
 endif
diff --git a/libctf/Makefile.in b/libctf/Makefile.in
index e3ee89534e7..5cfa100f9cc 100644
--- a/libctf/Makefile.in
+++ b/libctf/Makefile.in
@@ -168,8 +168,9 @@ am__DEPENDENCIES_1 =
 libctf_nobfd_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
 am__libctf_nobfd_la_SOURCES_DIST = ctf-archive.c ctf-dump.c \
 	ctf-create.c ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c \
-	ctf-dedup.c ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c \
-	ctf-string.c ctf-subr.c ctf-types.c ctf-util.c ctf-qsort_r.c
+	ctf-dedup.c ctf-link.c ctf-lookup.c ctf-open.c ctf-serialize.c \
+	ctf-sha1.c ctf-string.c ctf-subr.c ctf-types.c ctf-util.c \
+	ctf-qsort_r.c
 @NEED_CTF_QSORT_R_TRUE@am__objects_1 = libctf_nobfd_la-ctf-qsort_r.lo
 am_libctf_nobfd_la_OBJECTS = libctf_nobfd_la-ctf-archive.lo \
 	libctf_nobfd_la-ctf-dump.lo libctf_nobfd_la-ctf-create.lo \
@@ -177,9 +178,10 @@ am_libctf_nobfd_la_OBJECTS = libctf_nobfd_la-ctf-archive.lo \
 	libctf_nobfd_la-ctf-hash.lo libctf_nobfd_la-ctf-labels.lo \
 	libctf_nobfd_la-ctf-dedup.lo libctf_nobfd_la-ctf-link.lo \
 	libctf_nobfd_la-ctf-lookup.lo libctf_nobfd_la-ctf-open.lo \
-	libctf_nobfd_la-ctf-sha1.lo libctf_nobfd_la-ctf-string.lo \
-	libctf_nobfd_la-ctf-subr.lo libctf_nobfd_la-ctf-types.lo \
-	libctf_nobfd_la-ctf-util.lo $(am__objects_1)
+	libctf_nobfd_la-ctf-serialize.lo libctf_nobfd_la-ctf-sha1.lo \
+	libctf_nobfd_la-ctf-string.lo libctf_nobfd_la-ctf-subr.lo \
+	libctf_nobfd_la-ctf-types.lo libctf_nobfd_la-ctf-util.lo \
+	$(am__objects_1)
 libctf_nobfd_la_OBJECTS = $(am_libctf_nobfd_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -195,17 +197,19 @@ am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 libctf_la_DEPENDENCIES = ../bfd/libbfd.la $(am__DEPENDENCIES_2)
 am__libctf_la_SOURCES_DIST = ctf-archive.c ctf-dump.c ctf-create.c \
 	ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c ctf-dedup.c \
-	ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c ctf-string.c \
-	ctf-subr.c ctf-types.c ctf-util.c ctf-qsort_r.c ctf-open-bfd.c
+	ctf-link.c ctf-lookup.c ctf-open.c ctf-serialize.c ctf-sha1.c \
+	ctf-string.c ctf-subr.c ctf-types.c ctf-util.c ctf-qsort_r.c \
+	ctf-open-bfd.c
 @NEED_CTF_QSORT_R_TRUE@am__objects_2 = libctf_la-ctf-qsort_r.lo
 am__objects_3 = libctf_la-ctf-archive.lo libctf_la-ctf-dump.lo \
 	libctf_la-ctf-create.lo libctf_la-ctf-decl.lo \
 	libctf_la-ctf-error.lo libctf_la-ctf-hash.lo \
 	libctf_la-ctf-labels.lo libctf_la-ctf-dedup.lo \
 	libctf_la-ctf-link.lo libctf_la-ctf-lookup.lo \
-	libctf_la-ctf-open.lo libctf_la-ctf-sha1.lo \
-	libctf_la-ctf-string.lo libctf_la-ctf-subr.lo \
-	libctf_la-ctf-types.lo libctf_la-ctf-util.lo $(am__objects_2)
+	libctf_la-ctf-open.lo libctf_la-ctf-serialize.lo \
+	libctf_la-ctf-sha1.lo libctf_la-ctf-string.lo \
+	libctf_la-ctf-subr.lo libctf_la-ctf-types.lo \
+	libctf_la-ctf-util.lo $(am__objects_2)
 am_libctf_la_OBJECTS = $(am__objects_3) libctf_la-ctf-open-bfd.lo
 libctf_la_OBJECTS = $(am_libctf_la_OBJECTS)
 libctf_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -470,8 +474,8 @@ libctf_nobfd_la_LDFLAGS = -version-info 0:0:0 @SHARED_LDFLAGS@ @VERSION_FLAGS@
 libctf_nobfd_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=1
 libctf_nobfd_la_SOURCES = ctf-archive.c ctf-dump.c ctf-create.c \
 	ctf-decl.c ctf-error.c ctf-hash.c ctf-labels.c ctf-dedup.c \
-	ctf-link.c ctf-lookup.c ctf-open.c ctf-sha1.c ctf-string.c \
-	ctf-subr.c ctf-types.c ctf-util.c $(am__append_1)
+	ctf-link.c ctf-lookup.c ctf-open.c ctf-serialize.c ctf-sha1.c \
+	ctf-string.c ctf-subr.c ctf-types.c ctf-util.c $(am__append_1)
 libctf_la_LIBADD = ../bfd/libbfd.la $(libctf_nobfd_la_LIBADD)
 libctf_la_CPPFLAGS = $(AM_CPPFLAGS) -DNOBFD=0
 libctf_la_LDFLAGS = $(libctf_nobfd_la_LDFLAGS)
@@ -623,6 +627,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-open-bfd.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-open.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-qsort_r.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-serialize.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-sha1.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-string.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_la-ctf-subr.Plo@am__quote@
@@ -640,6 +645,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-lookup.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-open.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-qsort_r.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-serialize.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-sha1.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-string.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libctf_nobfd_la-ctf-subr.Plo@am__quote@
@@ -744,6 +750,13 @@ libctf_nobfd_la-ctf-open.lo: ctf-open.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_nobfd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctf_nobfd_la-ctf-open.lo `test -f 'ctf-open.c' || echo '$(srcdir)/'`ctf-open.c
 
+libctf_nobfd_la-ctf-serialize.lo: ctf-serialize.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_nobfd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctf_nobfd_la-ctf-serialize.lo -MD -MP -MF $(DEPDIR)/libctf_nobfd_la-ctf-serialize.Tpo -c -o libctf_nobfd_la-ctf-serialize.lo `test -f 'ctf-serialize.c' || echo '$(srcdir)/'`ctf-serialize.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctf_nobfd_la-ctf-serialize.Tpo $(DEPDIR)/libctf_nobfd_la-ctf-serialize.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-serialize.c' object='libctf_nobfd_la-ctf-serialize.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_nobfd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctf_nobfd_la-ctf-serialize.lo `test -f 'ctf-serialize.c' || echo '$(srcdir)/'`ctf-serialize.c
+
 libctf_nobfd_la-ctf-sha1.lo: ctf-sha1.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_nobfd_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctf_nobfd_la-ctf-sha1.lo -MD -MP -MF $(DEPDIR)/libctf_nobfd_la-ctf-sha1.Tpo -c -o libctf_nobfd_la-ctf-sha1.lo `test -f 'ctf-sha1.c' || echo '$(srcdir)/'`ctf-sha1.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctf_nobfd_la-ctf-sha1.Tpo $(DEPDIR)/libctf_nobfd_la-ctf-sha1.Plo
@@ -863,6 +876,13 @@ libctf_la-ctf-open.lo: ctf-open.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctf_la-ctf-open.lo `test -f 'ctf-open.c' || echo '$(srcdir)/'`ctf-open.c
 
+libctf_la-ctf-serialize.lo: ctf-serialize.c
+@am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctf_la-ctf-serialize.lo -MD -MP -MF $(DEPDIR)/libctf_la-ctf-serialize.Tpo -c -o libctf_la-ctf-serialize.lo `test -f 'ctf-serialize.c' || echo '$(srcdir)/'`ctf-serialize.c
+@am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctf_la-ctf-serialize.Tpo $(DEPDIR)/libctf_la-ctf-serialize.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ctf-serialize.c' object='libctf_la-ctf-serialize.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libctf_la-ctf-serialize.lo `test -f 'ctf-serialize.c' || echo '$(srcdir)/'`ctf-serialize.c
+
 libctf_la-ctf-sha1.lo: ctf-sha1.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libctf_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libctf_la-ctf-sha1.lo -MD -MP -MF $(DEPDIR)/libctf_la-ctf-sha1.Tpo -c -o libctf_la-ctf-sha1.lo `test -f 'ctf-sha1.c' || echo '$(srcdir)/'`ctf-sha1.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/libctf_la-ctf-sha1.Tpo $(DEPDIR)/libctf_la-ctf-sha1.Plo
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 3f2c5dacb03..b2e08623f22 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -1,4 +1,4 @@
-/* CTF file creation.
+/* CTF dict creation.
    Copyright (C) 2019-2021 Free Software Foundation, Inc.
 
    This file is part of libctf.
@@ -19,13 +19,8 @@
 
 #include <ctf-impl.h>
 #include <sys/param.h>
-#include <assert.h>
 #include <string.h>
 #include <unistd.h>
-#include <zlib.h>
-
-#include <elf.h>
-#include "elf-bfd.h"
 
 #ifndef EOVERFLOW
 #define EOVERFLOW ERANGE
@@ -167,497 +162,6 @@ ctf_create (int *errp)
   return NULL;
 }
 
-/* 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.  */
-
-static int
-symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
-{
-  ctf_dvdef_t *dvd, *nvd;
-  ctf_id_t type;
-
-  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
-    {
-      nvd = ctf_list_next (dvd);
-
-      if (((type = (ctf_id_t) (uintptr_t)
-	    ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
-	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
-	  && type == dvd->dvd_type)
-	ctf_dvd_delete (fp, dvd);
-    }
-
-  return 0;
-}
-
-/* Determine if a symbol is "skippable" and should never appear in the
-   symtypetab sections.  */
-
-int
-ctf_symtab_skippable (ctf_link_sym_t *sym)
-{
-  /* Never skip symbols whose name is not yet known.  */
-  if (sym->st_nameidx_set)
-    return 0;
-
-  return (sym->st_name == NULL || sym->st_name[0] == 0
-	  || sym->st_shndx == SHN_UNDEF
-	  || strcmp (sym->st_name, "_START_") == 0
-	  || strcmp (sym->st_name, "_END_") == 0
-	  || (sym->st_type == STT_OBJECT && sym->st_shndx == SHN_EXTABS
-	      && sym->st_value == 0));
-}
-
-/* Symtypetab emission flags.  */
-
-#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1
-#define CTF_SYMTYPETAB_EMIT_PAD 0x2
-#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4
-
-/* Get the number of symbols in a symbol hash, the count of symbols, the maximum
-   seen, the eventual size, without any padding elements, of the func/data and
-   (if generated) index sections, and the size of accumulated padding elements.
-   The linker-reported set of symbols is found in SYMFP: it may be NULL if
-   symbol filtering is not desired, in which case CTF_SYMTYPETAB_FORCE_INDEXED
-   will always be set in the flags.
-
-   Also figure out if any symbols need to be moved to the variable section, and
-   add them (if not already present).  */
-
-_libctf_nonnull_ ((1,3,4,5,6,7,8))
-static int
-symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
-		    size_t *count, size_t *max, size_t *unpadsize,
-		    size_t *padsize, size_t *idxsize, int flags)
-{
-  ctf_next_t *i = NULL;
-  const void *name;
-  const void *ctf_sym;
-  ctf_dynhash_t *linker_known = NULL;
-  int err;
-  int beyond_max = 0;
-
-  *count = 0;
-  *max = 0;
-  *unpadsize = 0;
-  *idxsize = 0;
-  *padsize = 0;
-
-  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-    {
-      /* Make a dynhash citing only symbols reported by the linker of the
-	 appropriate type, then traverse all potential-symbols we know the types
-	 of, removing them from linker_known as we go.  Once this is done, the
-	 only symbols remaining in linker_known are symbols we don't know the
-	 types of: we must emit pads for those symbols that are below the
-	 maximum symbol we will emit (any beyond that are simply skipped).
-
-	 If there are none, this symtypetab will be empty: just report that.  */
-
-      if (!symfp->ctf_dynsyms)
-	return 0;
-
-      if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
-					      NULL, NULL)) == NULL)
-	return (ctf_set_errno (fp, ENOMEM));
-
-      while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
-				       &name, &ctf_sym)) == 0)
-	{
-	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
-
-	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-	       && sym->st_type != STT_FUNC)
-	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-		  && sym->st_type != STT_OBJECT))
-	    continue;
-
-	  if (ctf_symtab_skippable (sym))
-	    continue;
-
-	  /* This should only be true briefly before all the names are
-	     finalized, long before we get this far.  */
-	  if (!ctf_assert (fp, !sym->st_nameidx_set))
-	    return -1;				/* errno is set for us.  */
-
-	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
-	    {
-	      ctf_dynhash_destroy (linker_known);
-	      return (ctf_set_errno (fp, ENOMEM));
-	    }
-	}
-      if (err != ECTF_NEXT_END)
-	{
-	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
-				  "serialization"));
-	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
-	}
-    }
-
-  while ((err = ctf_dynhash_cnext (symhash, &i, &name, NULL)) == 0)
-    {
-      ctf_link_sym_t *sym;
-
-      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-	{
-	  /* Linker did not report symbol in symtab.  Remove it from the
-	     set of known data symbols and continue.  */
-	  if ((sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, name)) == NULL)
-	    {
-	      ctf_dynhash_remove (symhash, name);
-	      continue;
-	    }
-
-	  /* We don't remove skippable symbols from the symhash because we don't
-	     want them to be migrated into variables.  */
-	  if (ctf_symtab_skippable (sym))
-	    continue;
-
-	  if ((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-	      && sym->st_type != STT_FUNC)
-	    {
-	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
-					"function but is of type %x.  "
-					"The symbol type lookup tables "
-					"are probably corrupted"),
-			    sym->st_name, sym->st_symidx, sym->st_type);
-	      ctf_dynhash_remove (symhash, name);
-	      continue;
-	    }
-	  else if (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-		   && sym->st_type != STT_OBJECT)
-	    {
-	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
-					"data object but is of type %x.  "
-					"The symbol type lookup tables "
-					"are probably corrupted"),
-			    sym->st_name, sym->st_symidx, sym->st_type);
-	      ctf_dynhash_remove (symhash, name);
-	      continue;
-	    }
-
-	  ctf_dynhash_remove (linker_known, name);
-	}
-      *unpadsize += sizeof (uint32_t);
-      (*count)++;
-
-      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-	{
-	  if (*max < sym->st_symidx)
-	    *max = sym->st_symidx;
-	}
-      else
-	(*max)++;
-    }
-  if (err != ECTF_NEXT_END)
-    {
-      ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
-				  "serialization"));
-      ctf_dynhash_destroy (linker_known);
-      return (ctf_set_errno (fp, err));
-    }
-
-  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-    {
-      while ((err = ctf_dynhash_cnext (linker_known, &i, NULL, &ctf_sym)) == 0)
-	{
-	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
-
-	  if (sym->st_symidx > *max)
-	    beyond_max++;
-	}
-      if (err != ECTF_NEXT_END)
-	{
-	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
-				      "during CTF serialization"));
-	  ctf_dynhash_destroy (linker_known);
-	  return (ctf_set_errno (fp, err));
-	}
-    }
-
-  *idxsize = *count * sizeof (uint32_t);
-  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-    *padsize = (ctf_dynhash_elements (linker_known) - beyond_max) * sizeof (uint32_t);
-
-  ctf_dynhash_destroy (linker_known);
-  return 0;
-}
-
-/* Emit an objt or func symtypetab into DP in a particular order defined by an
-   array of ctf_link_sym_t or symbol names passed in.  The index has NIDX
-   elements in it: unindexed output would terminate at symbol OUTMAX and is in
-   any case no larger than SIZE bytes.  Some index elements are expected to be
-   skipped: see symtypetab_density.  The linker-reported set of symbols (if any)
-   is found in SYMFP. */
-static int
-emit_symtypetab (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
-		 ctf_link_sym_t **idx, const char **nameidx, uint32_t nidx,
-		 uint32_t outmax, int size, int flags)
-{
-  uint32_t i;
-  uint32_t *dpp = dp;
-  ctf_dynhash_t *symhash;
-
-  ctf_dprintf ("Emitting table of size %i, outmax %u, %u symtypetab entries, "
-	       "flags %i\n", size, outmax, nidx, flags);
-
-  /* Empty table? Nothing to do.  */
-  if (size == 0)
-    return 0;
-
-  if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-    symhash = fp->ctf_funchash;
-  else
-    symhash = fp->ctf_objthash;
-
-  for (i = 0; i < nidx; i++)
-    {
-      const char *sym_name;
-      void *type;
-
-      /* If we have a linker-reported set of symbols, we may be given that set
-	 to work from, or a set of symbol names.  In both cases we want to look
-	 at the corresponding linker-reported symbol (if any).  */
-      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-	{
-	  ctf_link_sym_t *this_link_sym;
-
-	  if (idx)
-	    this_link_sym = idx[i];
-	  else
-	    this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, nameidx[i]);
-
-	  /* Unreported symbol number.  No pad, no nothing.  */
-	  if (!this_link_sym)
-	    continue;
-
-	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
-	     table.  */
-	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-	       && this_link_sym->st_type != STT_FUNC)
-	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-		  && this_link_sym->st_type != STT_OBJECT))
-	    continue;
-
-	  if (ctf_symtab_skippable (this_link_sym))
-	    continue;
-
-	  sym_name = this_link_sym->st_name;
-
-	  /* Linker reports symbol of a different type to the symbol we actually
-	     added?  Skip the symbol.  No pad, since the symbol doesn't actually
-	     belong in this table at all.  (Warned about in
-	     symtypetab_density.)  */
-	  if ((this_link_sym->st_type == STT_FUNC)
-	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
-	    continue;
-
-	  if ((this_link_sym->st_type == STT_OBJECT)
-	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
-	    continue;
-	}
-      else
-	sym_name = nameidx[i];
-
-      /* Symbol in index but no type set? Silently skip and (optionally)
-	 pad.  (In force-indexed mode, this is also where we track symbols of
-	 the wrong type for this round of insertion.)  */
-      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
-	{
-	  if (flags & CTF_SYMTYPETAB_EMIT_PAD)
-	    *dpp++ = 0;
-	  continue;
-	}
-
-      if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) < size))
-	return -1;				/* errno is set for us.  */
-
-      *dpp++ = (ctf_id_t) (uintptr_t) type;
-
-      /* When emitting unindexed output, all later symbols are pads: stop
-	 early.  */
-      if ((flags & CTF_SYMTYPETAB_EMIT_PAD) && idx[i]->st_symidx == outmax)
-	break;
-    }
-
-  return 0;
-}
-
-/* Emit an objt or func symtypetab index into DP in a paticular order defined by
-   an array of symbol names passed in.  Stop at NIDX.  The linker-reported set
-   of symbols (if any) is found in SYMFP. */
-static int
-emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
-		       const char **idx, uint32_t nidx, int size, int flags)
-{
-  uint32_t i;
-  uint32_t *dpp = dp;
-  ctf_dynhash_t *symhash;
-
-  ctf_dprintf ("Emitting index of size %i, %u entries reported by linker, "
-	       "flags %i\n", size, nidx, flags);
-
-  /* Empty table? Nothing to do.  */
-  if (size == 0)
-    return 0;
-
-  if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-    symhash = fp->ctf_funchash;
-  else
-    symhash = fp->ctf_objthash;
-
-  /* Indexes should always be unpadded.  */
-  if (!ctf_assert (fp, !(flags & CTF_SYMTYPETAB_EMIT_PAD)))
-    return -1;					/* errno is set for us.  */
-
-  for (i = 0; i < nidx; i++)
-    {
-      const char *sym_name;
-      void *type;
-
-      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
-	{
-	  ctf_link_sym_t *this_link_sym;
-
-	  this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, idx[i]);
-
-	  /* This is an index: unreported symbols should never appear in it.  */
-	  if (!ctf_assert (fp, this_link_sym != NULL))
-	    return -1;				/* errno is set for us.  */
-
-	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
-	     table.  */
-	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-	       && this_link_sym->st_type != STT_FUNC)
-	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
-		  && this_link_sym->st_type != STT_OBJECT))
-	    continue;
-
-	  if (ctf_symtab_skippable (this_link_sym))
-	    continue;
-
-	  sym_name = this_link_sym->st_name;
-
-	  /* Linker reports symbol of a different type to the symbol we actually
-	     added?  Skip the symbol.  */
-	  if ((this_link_sym->st_type == STT_FUNC)
-	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
-	    continue;
-
-	  if ((this_link_sym->st_type == STT_OBJECT)
-	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
-	    continue;
-	}
-      else
-	sym_name = idx[i];
-
-      /* Symbol in index and reported by linker, but no type set? Silently skip
-	 and (optionally) pad.  (In force-indexed mode, this is also where we
-	 track symbols of the wrong type for this round of insertion.)  */
-      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
-	continue;
-
-      ctf_str_add_ref (fp, sym_name, dpp++);
-
-      if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) <= size))
-	return -1;				/* errno is set for us.  */
-    }
-
-  return 0;
-}
-
-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;
-}
-
-/* Sort a newly-constructed static variable array.  */
-
-typedef struct ctf_sort_var_arg_cb
-{
-  ctf_dict_t *fp;
-  ctf_strs_t *strtab;
-} ctf_sort_var_arg_cb_t;
-
-static int
-ctf_sort_var (const void *one_, const void *two_, void *arg_)
-{
-  const ctf_varent_t *one = one_;
-  const ctf_varent_t *two = two_;
-  ctf_sort_var_arg_cb_t *arg = arg_;
-
-  return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
-		  ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
-}
-
 /* Compatibility: just update the threshold for ctf_discard.  */
 int
 ctf_update (ctf_dict_t *fp)
@@ -669,627 +173,6 @@ ctf_update (ctf_dict_t *fp)
   return 0;
 }
 
-/* If the specified CTF dict is writable and has been modified, reload this dict
-   with the updated type definitions, ready for serialization.  In order to make
-   this code and the rest of libctf as simple as possible, we perform updates by
-   taking the dynamic type definitions and creating an in-memory CTF dict
-   containing the definitions, and then call ctf_simple_open_internal() on it.
-   We perform one extra trick here for the benefit of callers and to keep our
-   code simple: ctf_simple_open_internal() will return a new ctf_dict_t, but we
-   want to keep the fp constant for the caller, so after
-   ctf_simple_open_internal() returns, we use memcpy to swap the interior of the
-   old and new ctf_dict_t's, and then free the old.  */
-int
-ctf_serialize (ctf_dict_t *fp)
-{
-  ctf_dict_t ofp, *nfp;
-  ctf_header_t hdr, *hdrp;
-  ctf_dtdef_t *dtd;
-  ctf_dvdef_t *dvd;
-  ctf_varent_t *dvarents;
-  ctf_strs_writable_t strtab;
-
-  unsigned char *t;
-  unsigned long i;
-  size_t buf_size, type_size, objt_size, func_size;
-  size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize;
-  size_t funcidx_size, objtidx_size;
-  size_t nvars, nfuncs, nobjts, maxobjt, maxfunc;
-  size_t nsymtypes = 0;
-  const char **sym_name_order = NULL;
-  unsigned char *buf = NULL, *newbuf;
-  int err;
-
-  /* Symtab filtering. If filter_syms is true, symfp is set: otherwise,
-     CTF_SYMTYPETAB_FORCE_INDEXED is set in symflags.  */
-  int filter_syms = 0;
-  int sort_syms = 1;
-  int symflags = 0;
-  ctf_dict_t *symfp = NULL;
-
-  if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
-
-  /* Update required?  */
-  if (!(fp->ctf_flags & LCTF_DIRTY))
-    return 0;
-
-  /* If doing a writeout as part of linking, and the link flags request it,
-     filter out reported symbols from the variable section, and filter out all
-     other symbols from the symtypetab sections.  (If we are not linking, the
-     symbols are sorted; if we are linking, don't bother sorting if we are not
-     filtering out reported symbols: this is almost certaily an ld -r and only
-     the linker is likely to consume these symtypetabs again.  The linker
-     doesn't care what order the symtypetab entries is in, since it only
-     iterates over symbols and does not use the ctf_lookup_by_symbol* API.)  */
-
-  if (fp->ctf_flags & LCTF_LINKING)
-    {
-      filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);
-      if (!filter_syms)
-	sort_syms = 0;
-    }
-
-  /* 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
-     boundary past the CTF header itself (at relative offset zero).  The flag
-     indicating a new-style function info section (an array of CTF_K_FUNCTION
-     type IDs in the types section) is flipped on.  */
-
-  memset (&hdr, 0, sizeof (hdr));
-  hdr.cth_magic = CTF_MAGIC;
-  hdr.cth_version = CTF_VERSION;
-
-  /* This is a new-format func info section, and the symtab and strtab come out
-     of the dynsym and dynstr these days.  */
-  hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
-
-  /* Iterate through the dynamic type definition list and compute the
-     size of the CTF type section we will need to generate.  */
-
-  for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
-       dtd != NULL; dtd = ctf_list_next (dtd))
-    {
-      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
-      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
-
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
-	type_size += sizeof (ctf_stype_t);
-      else
-	type_size += sizeof (ctf_type_t);
-
-      switch (kind)
-	{
-	case CTF_K_INTEGER:
-	case CTF_K_FLOAT:
-	  type_size += sizeof (uint32_t);
-	  break;
-	case CTF_K_ARRAY:
-	  type_size += sizeof (ctf_array_t);
-	  break;
-	case CTF_K_SLICE:
-	  type_size += sizeof (ctf_slice_t);
-	  break;
-	case CTF_K_FUNCTION:
-	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
-	  break;
-	case CTF_K_STRUCT:
-	case CTF_K_UNION:
-	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
-	    type_size += sizeof (ctf_member_t) * vlen;
-	  else
-	    type_size += sizeof (ctf_lmember_t) * vlen;
-	  break;
-	case CTF_K_ENUM:
-	  type_size += sizeof (ctf_enum_t) * vlen;
-	  break;
-	}
-    }
-
-  /* Find the dict to which the linker has reported symbols, if any.  */
-
-  if (filter_syms)
-    {
-      if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms)
-	symfp = fp->ctf_parent;
-      else
-	symfp = fp;
-    }
-
-  /* If not filtering, keep all potential symbols in an unsorted, indexed
-     dict.  */
-  if (!filter_syms)
-    symflags = CTF_SYMTYPETAB_FORCE_INDEXED;
-  else
-    hdr.cth_flags |= CTF_F_IDXSORTED;
-
-  if (!ctf_assert (fp, (filter_syms && symfp)
-		   || (!filter_syms && !symfp
-		       && ((symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0))))
-    return -1;
-
-  /* Work out the sizes of the object and function sections, and work out the
-     number of pad (unassigned) symbols in each, and the overall size of the
-     sections.  */
-
-  if (symtypetab_density (fp, symfp, fp->ctf_objthash, &nobjts, &maxobjt,
-			  &objt_unpadsize, &objt_padsize, &objtidx_size,
-			  symflags) < 0)
-    return -1;					/* errno is set for us.  */
-
-  ctf_dprintf ("Object symtypetab: %i objects, max %i, unpadded size %i, "
-	       "%i bytes of pads, index size %i\n", (int) nobjts, (int) maxobjt,
-	       (int) objt_unpadsize, (int) objt_padsize, (int) objtidx_size);
-
-  if (symtypetab_density (fp, symfp, fp->ctf_funchash, &nfuncs, &maxfunc,
-			  &func_unpadsize, &func_padsize, &funcidx_size,
-			  symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
-    return -1;					/* errno is set for us.  */
-
-  ctf_dprintf ("Function symtypetab: %i functions, max %i, unpadded size %i, "
-	       "%i bytes of pads, index size %i\n", (int) nfuncs, (int) maxfunc,
-	       (int) func_unpadsize, (int) func_padsize, (int) funcidx_size);
-
-  /* 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.  */
-
-  if (filter_syms && symfp->ctf_dynsyms &&
-      symtypetab_delete_nonstatic_vars (fp, symfp) < 0)
-    return -1;
-
-  /* It is worth indexing each section if it would save space to do so, due to
-     reducing the number of pads sufficiently.  A pad is the same size as a
-     single index entry: but index sections compress relatively poorly compared
-     to constant pads, so it takes a lot of contiguous padding to equal one
-     index section entry.  It would be nice to be able to *verify* whether we
-     would save space after compression rather than guessing, but this seems
-     difficult, since it would require complete reserialization.  Regardless, if
-     the linker has not reported any symbols (e.g. if this is not a final link
-     but just an ld -r), we must emit things in indexed fashion just as the
-     compiler does.  */
-
-  objt_size = objt_unpadsize;
-  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
-      && ((objt_padsize + objt_unpadsize) * CTF_INDEX_PAD_THRESHOLD
-	  > objt_padsize))
-    {
-      objt_size += objt_padsize;
-      objtidx_size = 0;
-    }
-
-  func_size = func_unpadsize;
-  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
-      && ((func_padsize + func_unpadsize) * CTF_INDEX_PAD_THRESHOLD
-	  > func_padsize))
-    {
-      func_size += func_padsize;
-      funcidx_size = 0;
-    }
-
-  /* Computing the number of entries in the CTF variable section is much
-     simpler.  */
-
-  for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
-       dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
-
-  /* Compute the size of the CTF buffer we need, sans only the string table,
-     then allocate a new buffer and memcpy the finished header to the start of
-     the buffer.  (We will adjust this later with strtab length info.)  */
-
-  hdr.cth_lbloff = hdr.cth_objtoff = 0;
-  hdr.cth_funcoff = hdr.cth_objtoff + objt_size;
-  hdr.cth_objtidxoff = hdr.cth_funcoff + func_size;
-  hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size;
-  hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size;
-  hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
-  hdr.cth_stroff = hdr.cth_typeoff + type_size;
-  hdr.cth_strlen = 0;
-
-  buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
-
-  if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
-
-  memcpy (buf, &hdr, sizeof (ctf_header_t));
-  t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
-
-  hdrp = (ctf_header_t *) buf;
-  if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
-    ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
-  if (fp->ctf_cuname != NULL)
-    ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
-
-  /* Sort the linker's symbols into name order if need be.  */
-
-  if ((objtidx_size != 0) || (funcidx_size != 0))
-    {
-      ctf_next_t *i = NULL;
-      void *symname;
-      const char **walk;
-
-      if (filter_syms)
-	{
-	  if (symfp->ctf_dynsyms)
-	    nsymtypes = ctf_dynhash_elements (symfp->ctf_dynsyms);
-	  else
-	    nsymtypes = 0;
-	}
-      else
-	nsymtypes = ctf_dynhash_elements (fp->ctf_objthash)
-	  + ctf_dynhash_elements (fp->ctf_funchash);
-
-      if ((sym_name_order = calloc (nsymtypes, sizeof (const char *))) == NULL)
-	goto oom;
-
-      walk = sym_name_order;
-
-      if (filter_syms)
-	{
-	  if (symfp->ctf_dynsyms)
-	    {
-	      while ((err = ctf_dynhash_next_sorted (symfp->ctf_dynsyms, &i,
-						     &symname, NULL,
-						     ctf_dynhash_sort_by_name,
-						     NULL)) == 0)
-		*walk++ = (const char *) symname;
-	      if (err != ECTF_NEXT_END)
-		goto symerr;
-	    }
-	}
-      else
-	{
-	  ctf_hash_sort_f sort_fun = NULL;
-
-	  /* Since we partition the set of symbols back into objt and func,
-	     we can sort the two independently without harm.  */
-	  if (sort_syms)
-	    sort_fun = ctf_dynhash_sort_by_name;
-
-	  while ((err = ctf_dynhash_next_sorted (fp->ctf_objthash, &i, &symname,
-						 NULL, sort_fun, NULL)) == 0)
-	    *walk++ = (const char *) symname;
-	  if (err != ECTF_NEXT_END)
-	    goto symerr;
-
-	  while ((err = ctf_dynhash_next_sorted (fp->ctf_funchash, &i, &symname,
-						 NULL, sort_fun, NULL)) == 0)
-	    *walk++ = (const char *) symname;
-	  if (err != ECTF_NEXT_END)
-	    goto symerr;
-	}
-    }
-
-  /* Emit the object and function sections, and if necessary their indexes.
-     Emission is done in symtab order if there is no index, and in index
-     (name) order otherwise.  */
-
-  if ((objtidx_size == 0) && symfp && symfp->ctf_dynsymidx)
-    {
-      ctf_dprintf ("Emitting unindexed objt symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
-			   NULL, symfp->ctf_dynsymmax + 1, maxobjt, objt_size,
-			   symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0)
-	goto err;				/* errno is set for us.  */
-    }
-  else
-    {
-      ctf_dprintf ("Emitting indexed objt symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
-			   nsymtypes, maxobjt, objt_size, symflags) < 0)
-	goto err;				/* errno is set for us.  */
-    }
-
-  t += objt_size;
-
-  if ((funcidx_size == 0) && symfp && symfp->ctf_dynsymidx)
-    {
-      ctf_dprintf ("Emitting unindexed func symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
-			   NULL, symfp->ctf_dynsymmax + 1, maxfunc,
-			   func_size, symflags | CTF_SYMTYPETAB_EMIT_FUNCTION
-			   | CTF_SYMTYPETAB_EMIT_PAD) < 0)
-	goto err;				/* errno is set for us.  */
-    }
-  else
-    {
-      ctf_dprintf ("Emitting indexed func symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
-			   nsymtypes, maxfunc, func_size,
-			   symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
-	goto err;				/* errno is set for us.  */
-    }
-
-  t += func_size;
-
-  if (objtidx_size > 0)
-    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
-			       nsymtypes, objtidx_size, symflags) < 0)
-      goto err;
-
-  t += objtidx_size;
-
-  if (funcidx_size > 0)
-    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
-			       nsymtypes, funcidx_size,
-			       symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
-      goto err;
-
-  t += funcidx_size;
-  free (sym_name_order);
-  sym_name_order = NULL;
-
-  /* Work over the variable list, translating everything into ctf_varent_t's and
-     prepping the string table.  */
-
-  dvarents = (ctf_varent_t *) t;
-  for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
-       dvd = ctf_list_next (dvd), i++)
-    {
-      ctf_varent_t *var = &dvarents[i];
-
-      ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name);
-      var->ctv_type = (uint32_t) dvd->dvd_type;
-    }
-  assert (i == nvars);
-
-  t += sizeof (ctf_varent_t) * nvars;
-
-  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
-
-  /* We now take a final lap through the dynamic type definition list and copy
-     the appropriate type records to the output buffer, noting down the
-     strings as we go.  */
-
-  for (dtd = ctf_list_next (&fp->ctf_dtdefs);
-       dtd != NULL; dtd = ctf_list_next (dtd))
-    {
-      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
-      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
-
-      ctf_array_t cta;
-      uint32_t encoding;
-      size_t len;
-      ctf_stype_t *copied;
-      const char *name;
-
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
-	len = sizeof (ctf_stype_t);
-      else
-	len = sizeof (ctf_type_t);
-
-      memcpy (t, &dtd->dtd_data, len);
-      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);
-      t += len;
-
-      switch (kind)
-	{
-	case CTF_K_INTEGER:
-	case CTF_K_FLOAT:
-	  if (kind == CTF_K_INTEGER)
-	    {
-	      encoding = CTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
-				       dtd->dtd_u.dtu_enc.cte_offset,
-				       dtd->dtd_u.dtu_enc.cte_bits);
-	    }
-	  else
-	    {
-	      encoding = CTF_FP_DATA (dtd->dtd_u.dtu_enc.cte_format,
-				      dtd->dtd_u.dtu_enc.cte_offset,
-				      dtd->dtd_u.dtu_enc.cte_bits);
-	    }
-	  memcpy (t, &encoding, sizeof (encoding));
-	  t += sizeof (encoding);
-	  break;
-
-	case CTF_K_SLICE:
-	  memcpy (t, &dtd->dtd_u.dtu_slice, sizeof (struct ctf_slice));
-	  t += sizeof (struct ctf_slice);
-	  break;
-
-	case CTF_K_ARRAY:
-	  cta.cta_contents = (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents;
-	  cta.cta_index = (uint32_t) dtd->dtd_u.dtu_arr.ctr_index;
-	  cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
-	  memcpy (t, &cta, sizeof (cta));
-	  t += sizeof (cta);
-	  break;
-
-	case CTF_K_FUNCTION:
-	  {
-	    uint32_t *argv = (uint32_t *) (uintptr_t) t;
-	    uint32_t argc;
-
-	    for (argc = 0; argc < vlen; argc++)
-	      *argv++ = dtd->dtd_u.dtu_argv[argc];
-
-	    if (vlen & 1)
-	      *argv++ = 0;	/* Pad to 4-byte boundary.  */
-
-	    t = (unsigned char *) argv;
-	    break;
-	  }
-
-	case CTF_K_STRUCT:
-	case CTF_K_UNION:
-	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
-	    t = ctf_copy_smembers (fp, dtd, t);
-	  else
-	    t = ctf_copy_lmembers (fp, dtd, t);
-	  break;
-
-	case CTF_K_ENUM:
-	  t = ctf_copy_emembers (fp, dtd, t);
-	  break;
-	}
-    }
-  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
-
-  /* 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.  */
-  strtab = ctf_str_write_strtab (fp);
-  ctf_str_purge_refs (fp);
-
-  if (strtab.cts_strs == NULL)
-    goto oom;
-
-  /* Now the string table is constructed, we can sort the buffer of
-     ctf_varent_t's.  */
-  ctf_sort_var_arg_cb_t sort_var_arg = { fp, (ctf_strs_t *) &strtab };
-  ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var,
-	       &sort_var_arg);
-
-  if ((newbuf = ctf_realloc (fp, buf, buf_size + strtab.cts_len)) == NULL)
-    {
-      free (strtab.cts_strs);
-      goto oom;
-    }
-  buf = newbuf;
-  memcpy (buf + buf_size, strtab.cts_strs, strtab.cts_len);
-  hdrp = (ctf_header_t *) buf;
-  hdrp->cth_strlen = strtab.cts_len;
-  buf_size += hdrp->cth_strlen;
-  free (strtab.cts_strs);
-
-  /* Finally, we are ready to ctf_simple_open() the new dict.  If this is
-     successful, we then switch nfp and fp and free the old dict.  */
-
-  if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0,
-				       0, NULL, 0, fp->ctf_syn_ext_strtab,
-				       1, &err)) == NULL)
-    {
-      free (buf);
-      return (ctf_set_errno (fp, err));
-    }
-
-  (void) ctf_setmodel (nfp, ctf_getmodel (fp));
-
-  nfp->ctf_parent = fp->ctf_parent;
-  nfp->ctf_parent_unreffed = fp->ctf_parent_unreffed;
-  nfp->ctf_refcnt = fp->ctf_refcnt;
-  nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
-  if (nfp->ctf_dynbase == NULL)
-    nfp->ctf_dynbase = buf;		/* Make sure buf is freed on close.  */
-  nfp->ctf_dthash = fp->ctf_dthash;
-  nfp->ctf_dtdefs = fp->ctf_dtdefs;
-  nfp->ctf_dvhash = fp->ctf_dvhash;
-  nfp->ctf_dvdefs = fp->ctf_dvdefs;
-  nfp->ctf_dtoldid = fp->ctf_dtoldid;
-  nfp->ctf_add_processing = fp->ctf_add_processing;
-  nfp->ctf_snapshots = fp->ctf_snapshots + 1;
-  nfp->ctf_specific = fp->ctf_specific;
-  nfp->ctf_nfuncidx = fp->ctf_nfuncidx;
-  nfp->ctf_nobjtidx = fp->ctf_nobjtidx;
-  nfp->ctf_objthash = fp->ctf_objthash;
-  nfp->ctf_funchash = fp->ctf_funchash;
-  nfp->ctf_dynsyms = fp->ctf_dynsyms;
-  nfp->ctf_ptrtab = fp->ctf_ptrtab;
-  nfp->ctf_pptrtab = fp->ctf_pptrtab;
-  nfp->ctf_dynsymidx = fp->ctf_dynsymidx;
-  nfp->ctf_dynsymmax = fp->ctf_dynsymmax;
-  nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len;
-  nfp->ctf_pptrtab_len = fp->ctf_pptrtab_len;
-  nfp->ctf_link_inputs = fp->ctf_link_inputs;
-  nfp->ctf_link_outputs = fp->ctf_link_outputs;
-  nfp->ctf_errs_warnings = fp->ctf_errs_warnings;
-  nfp->ctf_funcidx_names = fp->ctf_funcidx_names;
-  nfp->ctf_objtidx_names = fp->ctf_objtidx_names;
-  nfp->ctf_funcidx_sxlate = fp->ctf_funcidx_sxlate;
-  nfp->ctf_objtidx_sxlate = fp->ctf_objtidx_sxlate;
-  nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset;
-  nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
-  nfp->ctf_pptrtab_typemax = fp->ctf_pptrtab_typemax;
-  nfp->ctf_in_flight_dynsyms = fp->ctf_in_flight_dynsyms;
-  nfp->ctf_link_in_cu_mapping = fp->ctf_link_in_cu_mapping;
-  nfp->ctf_link_out_cu_mapping = fp->ctf_link_out_cu_mapping;
-  nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping;
-  nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer;
-  nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg;
-  nfp->ctf_link_variable_filter = fp->ctf_link_variable_filter;
-  nfp->ctf_link_variable_filter_arg = fp->ctf_link_variable_filter_arg;
-  nfp->ctf_symsect_little_endian = fp->ctf_symsect_little_endian;
-  nfp->ctf_link_flags = fp->ctf_link_flags;
-  nfp->ctf_dedup_atoms = fp->ctf_dedup_atoms;
-  nfp->ctf_dedup_atoms_alloc = fp->ctf_dedup_atoms_alloc;
-  memcpy (&nfp->ctf_dedup, &fp->ctf_dedup, sizeof (fp->ctf_dedup));
-
-  nfp->ctf_snapshot_lu = fp->ctf_snapshots;
-
-  memcpy (&nfp->ctf_lookups, fp->ctf_lookups, sizeof (fp->ctf_lookups));
-  nfp->ctf_structs = fp->ctf_structs;
-  nfp->ctf_unions = fp->ctf_unions;
-  nfp->ctf_enums = fp->ctf_enums;
-  nfp->ctf_names = fp->ctf_names;
-
-  fp->ctf_dthash = NULL;
-  ctf_str_free_atoms (nfp);
-  nfp->ctf_str_atoms = fp->ctf_str_atoms;
-  nfp->ctf_prov_strtab = fp->ctf_prov_strtab;
-  fp->ctf_str_atoms = NULL;
-  fp->ctf_prov_strtab = 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;
-  fp->ctf_ptrtab = NULL;
-  fp->ctf_pptrtab = NULL;
-  fp->ctf_funcidx_names = NULL;
-  fp->ctf_objtidx_names = NULL;
-  fp->ctf_funcidx_sxlate = NULL;
-  fp->ctf_objtidx_sxlate = NULL;
-  fp->ctf_objthash = NULL;
-  fp->ctf_funchash = NULL;
-  fp->ctf_dynsyms = NULL;
-  fp->ctf_dynsymidx = NULL;
-  fp->ctf_link_inputs = NULL;
-  fp->ctf_link_outputs = NULL;
-  fp->ctf_syn_ext_strtab = NULL;
-  fp->ctf_link_in_cu_mapping = NULL;
-  fp->ctf_link_out_cu_mapping = NULL;
-  fp->ctf_link_type_mapping = NULL;
-  fp->ctf_dedup_atoms = NULL;
-  fp->ctf_dedup_atoms_alloc = NULL;
-  fp->ctf_parent_unreffed = 1;
-
-  fp->ctf_dvhash = NULL;
-  memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
-  memset (fp->ctf_lookups, 0, sizeof (fp->ctf_lookups));
-  memset (&fp->ctf_in_flight_dynsyms, 0, sizeof (fp->ctf_in_flight_dynsyms));
-  memset (&fp->ctf_dedup, 0, sizeof (fp->ctf_dedup));
-  fp->ctf_structs.ctn_writable = NULL;
-  fp->ctf_unions.ctn_writable = NULL;
-  fp->ctf_enums.ctn_writable = NULL;
-  fp->ctf_names.ctn_writable = NULL;
-
-  memcpy (&ofp, fp, sizeof (ctf_dict_t));
-  memcpy (fp, nfp, sizeof (ctf_dict_t));
-  memcpy (nfp, &ofp, sizeof (ctf_dict_t));
-
-  nfp->ctf_refcnt = 1;				/* Force nfp to be freed.  */
-  ctf_dict_close (nfp);
-
-  return 0;
-
-symerr:
-  ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
-  goto err;
-oom:
-  free (buf);
-  free (sym_name_order);
-  return (ctf_set_errno (fp, EAGAIN));
-err:
-  free (buf);
-  free (sym_name_order);
-  return -1;					/* errno is set for us.  */
-}
-
 ctf_names_t *
 ctf_name_table (ctf_dict_t *fp, int kind)
 {
@@ -3038,195 +1921,3 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
 
   return id;
 }
-
-/* Write the compressed CTF data stream to the specified gzFile descriptor.  */
-int
-ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
-{
-  const unsigned char *buf;
-  ssize_t resid;
-  ssize_t len;
-
-  resid = sizeof (ctf_header_t);
-  buf = (unsigned char *) fp->ctf_header;
-  while (resid != 0)
-    {
-      if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
-      resid -= len;
-      buf += len;
-    }
-
-  resid = fp->ctf_size;
-  buf = fp->ctf_buf;
-  while (resid != 0)
-    {
-      if ((len = gzwrite (fd, buf, resid)) <= 0)
-	return (ctf_set_errno (fp, errno));
-      resid -= len;
-      buf += len;
-    }
-
-  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.  */
-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;
-  ssize_t header_len = sizeof (ctf_header_t);
-  ssize_t compress_len;
-  int rc;
-
-  if (ctf_serialize (fp) < 0)
-    return NULL;				/* errno is set for us.  */
-
-  compress_len = compressBound (fp->ctf_size);
-  if (fp->ctf_size < threshold)
-    compress_len = fp->ctf_size;
-  if ((buf = malloc (compress_len
-		     + sizeof (struct ctf_header))) == NULL)
-    {
-      ctf_set_errno (fp, ENOMEM);
-      ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
-		    (unsigned long) (compress_len + sizeof (struct ctf_header)));
-      return NULL;
-    }
-
-  hp = (ctf_header_t *) buf;
-  memcpy (hp, fp->ctf_header, header_len);
-  bp = buf + sizeof (struct ctf_header);
-  *size = sizeof (struct ctf_header);
-
-  if (fp->ctf_size < threshold)
-    {
-      hp->cth_flags &= ~CTF_F_COMPRESS;
-      memcpy (bp, fp->ctf_buf, 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)
-	{
-	  ctf_set_errno (fp, ECTF_COMPRESS);
-	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
-	  free (buf);
-	  return NULL;
-	}
-      *size += compress_len;
-    }
-  return buf;
-}
-
-/* Write the uncompressed CTF data stream to the specified file descriptor.  */
-int
-ctf_write (ctf_dict_t *fp, int fd)
-{
-  const unsigned char *buf;
-  ssize_t resid;
-  ssize_t len;
-
-  if (ctf_serialize (fp) < 0)
-    return -1;					/* errno is set for us.  */
-
-  resid = sizeof (ctf_header_t);
-  buf = (unsigned char *) fp->ctf_header;
-  while (resid != 0)
-    {
-      if ((len = write (fd, buf, resid)) <= 0)
-	{
-	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing header"));
-	  return (ctf_set_errno (fp, errno));
-	}
-      resid -= len;
-      buf += len;
-    }
-
-  resid = fp->ctf_size;
-  buf = fp->ctf_buf;
-  while (resid != 0)
-    {
-      if ((len = write (fd, buf, resid)) <= 0)
-	{
-	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing"));
-	  return (ctf_set_errno (fp, errno));
-	}
-      resid -= len;
-      buf += len;
-    }
-
-  return 0;
-}
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
new file mode 100644
index 00000000000..e0bd98c51a8
--- /dev/null
+++ b/libctf/ctf-serialize.c
@@ -0,0 +1,1332 @@
+/* CTF dict creation.
+   Copyright (C) 2019-2021 Free Software Foundation, Inc.
+
+   This file is part of libctf.
+
+   libctf is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+   See the GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <ctf-impl.h>
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include <elf.h>
+#include "elf-bfd.h"
+
+/* 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.  */
+
+static int
+symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
+{
+  ctf_dvdef_t *dvd, *nvd;
+  ctf_id_t type;
+
+  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
+    {
+      nvd = ctf_list_next (dvd);
+
+      if (((type = (ctf_id_t) (uintptr_t)
+	    ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
+	  && type == dvd->dvd_type)
+	ctf_dvd_delete (fp, dvd);
+    }
+
+  return 0;
+}
+
+/* Determine if a symbol is "skippable" and should never appear in the
+   symtypetab sections.  */
+
+int
+ctf_symtab_skippable (ctf_link_sym_t *sym)
+{
+  /* Never skip symbols whose name is not yet known.  */
+  if (sym->st_nameidx_set)
+    return 0;
+
+  return (sym->st_name == NULL || sym->st_name[0] == 0
+	  || sym->st_shndx == SHN_UNDEF
+	  || strcmp (sym->st_name, "_START_") == 0
+	  || strcmp (sym->st_name, "_END_") == 0
+	  || (sym->st_type == STT_OBJECT && sym->st_shndx == SHN_EXTABS
+	      && sym->st_value == 0));
+}
+
+/* Symtypetab emission flags.  */
+
+#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1
+#define CTF_SYMTYPETAB_EMIT_PAD 0x2
+#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4
+
+/* Get the number of symbols in a symbol hash, the count of symbols, the maximum
+   seen, the eventual size, without any padding elements, of the func/data and
+   (if generated) index sections, and the size of accumulated padding elements.
+   The linker-reported set of symbols is found in SYMFP: it may be NULL if
+   symbol filtering is not desired, in which case CTF_SYMTYPETAB_FORCE_INDEXED
+   will always be set in the flags.
+
+   Also figure out if any symbols need to be moved to the variable section, and
+   add them (if not already present).  */
+
+_libctf_nonnull_ ((1,3,4,5,6,7,8))
+static int
+symtypetab_density (ctf_dict_t *fp, ctf_dict_t *symfp, ctf_dynhash_t *symhash,
+		    size_t *count, size_t *max, size_t *unpadsize,
+		    size_t *padsize, size_t *idxsize, int flags)
+{
+  ctf_next_t *i = NULL;
+  const void *name;
+  const void *ctf_sym;
+  ctf_dynhash_t *linker_known = NULL;
+  int err;
+  int beyond_max = 0;
+
+  *count = 0;
+  *max = 0;
+  *unpadsize = 0;
+  *idxsize = 0;
+  *padsize = 0;
+
+  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+    {
+      /* Make a dynhash citing only symbols reported by the linker of the
+	 appropriate type, then traverse all potential-symbols we know the types
+	 of, removing them from linker_known as we go.  Once this is done, the
+	 only symbols remaining in linker_known are symbols we don't know the
+	 types of: we must emit pads for those symbols that are below the
+	 maximum symbol we will emit (any beyond that are simply skipped).
+
+	 If there are none, this symtypetab will be empty: just report that.  */
+
+      if (!symfp->ctf_dynsyms)
+	return 0;
+
+      if ((linker_known = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
+					      NULL, NULL)) == NULL)
+	return (ctf_set_errno (fp, ENOMEM));
+
+      while ((err = ctf_dynhash_cnext (symfp->ctf_dynsyms, &i,
+				       &name, &ctf_sym)) == 0)
+	{
+	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
+
+	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+	       && sym->st_type != STT_FUNC)
+	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+		  && sym->st_type != STT_OBJECT))
+	    continue;
+
+	  if (ctf_symtab_skippable (sym))
+	    continue;
+
+	  /* This should only be true briefly before all the names are
+	     finalized, long before we get this far.  */
+	  if (!ctf_assert (fp, !sym->st_nameidx_set))
+	    return -1;				/* errno is set for us.  */
+
+	  if (ctf_dynhash_cinsert (linker_known, name, ctf_sym) < 0)
+	    {
+	      ctf_dynhash_destroy (linker_known);
+	      return (ctf_set_errno (fp, ENOMEM));
+	    }
+	}
+      if (err != ECTF_NEXT_END)
+	{
+	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols during "
+				  "serialization"));
+	  ctf_dynhash_destroy (linker_known);
+	  return (ctf_set_errno (fp, err));
+	}
+    }
+
+  while ((err = ctf_dynhash_cnext (symhash, &i, &name, NULL)) == 0)
+    {
+      ctf_link_sym_t *sym;
+
+      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+	{
+	  /* Linker did not report symbol in symtab.  Remove it from the
+	     set of known data symbols and continue.  */
+	  if ((sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, name)) == NULL)
+	    {
+	      ctf_dynhash_remove (symhash, name);
+	      continue;
+	    }
+
+	  /* We don't remove skippable symbols from the symhash because we don't
+	     want them to be migrated into variables.  */
+	  if (ctf_symtab_skippable (sym))
+	    continue;
+
+	  if ((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+	      && sym->st_type != STT_FUNC)
+	    {
+	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
+					"function but is of type %x.  "
+					"The symbol type lookup tables "
+					"are probably corrupted"),
+			    sym->st_name, sym->st_symidx, sym->st_type);
+	      ctf_dynhash_remove (symhash, name);
+	      continue;
+	    }
+	  else if (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+		   && sym->st_type != STT_OBJECT)
+	    {
+	      ctf_err_warn (fp, 1, 0, _("symbol %s (%x) added to CTF as a "
+					"data object but is of type %x.  "
+					"The symbol type lookup tables "
+					"are probably corrupted"),
+			    sym->st_name, sym->st_symidx, sym->st_type);
+	      ctf_dynhash_remove (symhash, name);
+	      continue;
+	    }
+
+	  ctf_dynhash_remove (linker_known, name);
+	}
+      *unpadsize += sizeof (uint32_t);
+      (*count)++;
+
+      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+	{
+	  if (*max < sym->st_symidx)
+	    *max = sym->st_symidx;
+	}
+      else
+	(*max)++;
+    }
+  if (err != ECTF_NEXT_END)
+    {
+      ctf_err_warn (fp, 0, err, _("iterating over CTF symtypetab during "
+				  "serialization"));
+      ctf_dynhash_destroy (linker_known);
+      return (ctf_set_errno (fp, err));
+    }
+
+  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+    {
+      while ((err = ctf_dynhash_cnext (linker_known, &i, NULL, &ctf_sym)) == 0)
+	{
+	  ctf_link_sym_t *sym = (ctf_link_sym_t *) ctf_sym;
+
+	  if (sym->st_symidx > *max)
+	    beyond_max++;
+	}
+      if (err != ECTF_NEXT_END)
+	{
+	  ctf_err_warn (fp, 0, err, _("iterating over linker-known symbols "
+				      "during CTF serialization"));
+	  ctf_dynhash_destroy (linker_known);
+	  return (ctf_set_errno (fp, err));
+	}
+    }
+
+  *idxsize = *count * sizeof (uint32_t);
+  if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+    *padsize = (ctf_dynhash_elements (linker_known) - beyond_max) * sizeof (uint32_t);
+
+  ctf_dynhash_destroy (linker_known);
+  return 0;
+}
+
+/* Emit an objt or func symtypetab into DP in a particular order defined by an
+   array of ctf_link_sym_t or symbol names passed in.  The index has NIDX
+   elements in it: unindexed output would terminate at symbol OUTMAX and is in
+   any case no larger than SIZE bytes.  Some index elements are expected to be
+   skipped: see symtypetab_density.  The linker-reported set of symbols (if any)
+   is found in SYMFP. */
+static int
+emit_symtypetab (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
+		 ctf_link_sym_t **idx, const char **nameidx, uint32_t nidx,
+		 uint32_t outmax, int size, int flags)
+{
+  uint32_t i;
+  uint32_t *dpp = dp;
+  ctf_dynhash_t *symhash;
+
+  ctf_dprintf ("Emitting table of size %i, outmax %u, %u symtypetab entries, "
+	       "flags %i\n", size, outmax, nidx, flags);
+
+  /* Empty table? Nothing to do.  */
+  if (size == 0)
+    return 0;
+
+  if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+    symhash = fp->ctf_funchash;
+  else
+    symhash = fp->ctf_objthash;
+
+  for (i = 0; i < nidx; i++)
+    {
+      const char *sym_name;
+      void *type;
+
+      /* If we have a linker-reported set of symbols, we may be given that set
+	 to work from, or a set of symbol names.  In both cases we want to look
+	 at the corresponding linker-reported symbol (if any).  */
+      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+	{
+	  ctf_link_sym_t *this_link_sym;
+
+	  if (idx)
+	    this_link_sym = idx[i];
+	  else
+	    this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, nameidx[i]);
+
+	  /* Unreported symbol number.  No pad, no nothing.  */
+	  if (!this_link_sym)
+	    continue;
+
+	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
+	     table.  */
+	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+	       && this_link_sym->st_type != STT_FUNC)
+	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+		  && this_link_sym->st_type != STT_OBJECT))
+	    continue;
+
+	  if (ctf_symtab_skippable (this_link_sym))
+	    continue;
+
+	  sym_name = this_link_sym->st_name;
+
+	  /* Linker reports symbol of a different type to the symbol we actually
+	     added?  Skip the symbol.  No pad, since the symbol doesn't actually
+	     belong in this table at all.  (Warned about in
+	     symtypetab_density.)  */
+	  if ((this_link_sym->st_type == STT_FUNC)
+	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
+	    continue;
+
+	  if ((this_link_sym->st_type == STT_OBJECT)
+	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
+	    continue;
+	}
+      else
+	sym_name = nameidx[i];
+
+      /* Symbol in index but no type set? Silently skip and (optionally)
+	 pad.  (In force-indexed mode, this is also where we track symbols of
+	 the wrong type for this round of insertion.)  */
+      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
+	{
+	  if (flags & CTF_SYMTYPETAB_EMIT_PAD)
+	    *dpp++ = 0;
+	  continue;
+	}
+
+      if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) < size))
+	return -1;				/* errno is set for us.  */
+
+      *dpp++ = (ctf_id_t) (uintptr_t) type;
+
+      /* When emitting unindexed output, all later symbols are pads: stop
+	 early.  */
+      if ((flags & CTF_SYMTYPETAB_EMIT_PAD) && idx[i]->st_symidx == outmax)
+	break;
+    }
+
+  return 0;
+}
+
+/* Emit an objt or func symtypetab index into DP in a paticular order defined by
+   an array of symbol names passed in.  Stop at NIDX.  The linker-reported set
+   of symbols (if any) is found in SYMFP. */
+static int
+emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
+		       const char **idx, uint32_t nidx, int size, int flags)
+{
+  uint32_t i;
+  uint32_t *dpp = dp;
+  ctf_dynhash_t *symhash;
+
+  ctf_dprintf ("Emitting index of size %i, %u entries reported by linker, "
+	       "flags %i\n", size, nidx, flags);
+
+  /* Empty table? Nothing to do.  */
+  if (size == 0)
+    return 0;
+
+  if (flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+    symhash = fp->ctf_funchash;
+  else
+    symhash = fp->ctf_objthash;
+
+  /* Indexes should always be unpadded.  */
+  if (!ctf_assert (fp, !(flags & CTF_SYMTYPETAB_EMIT_PAD)))
+    return -1;					/* errno is set for us.  */
+
+  for (i = 0; i < nidx; i++)
+    {
+      const char *sym_name;
+      void *type;
+
+      if (!(flags & CTF_SYMTYPETAB_FORCE_INDEXED))
+	{
+	  ctf_link_sym_t *this_link_sym;
+
+	  this_link_sym = ctf_dynhash_lookup (symfp->ctf_dynsyms, idx[i]);
+
+	  /* This is an index: unreported symbols should never appear in it.  */
+	  if (!ctf_assert (fp, this_link_sym != NULL))
+	    return -1;				/* errno is set for us.  */
+
+	  /* Symbol of the wrong type, or skippable?  This symbol is not in this
+	     table.  */
+	  if (((flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+	       && this_link_sym->st_type != STT_FUNC)
+	      || (!(flags & CTF_SYMTYPETAB_EMIT_FUNCTION)
+		  && this_link_sym->st_type != STT_OBJECT))
+	    continue;
+
+	  if (ctf_symtab_skippable (this_link_sym))
+	    continue;
+
+	  sym_name = this_link_sym->st_name;
+
+	  /* Linker reports symbol of a different type to the symbol we actually
+	     added?  Skip the symbol.  */
+	  if ((this_link_sym->st_type == STT_FUNC)
+	      && (ctf_dynhash_lookup (fp->ctf_objthash, sym_name)))
+	    continue;
+
+	  if ((this_link_sym->st_type == STT_OBJECT)
+	      && (ctf_dynhash_lookup (fp->ctf_funchash, sym_name)))
+	    continue;
+	}
+      else
+	sym_name = idx[i];
+
+      /* Symbol in index and reported by linker, but no type set? Silently skip
+	 and (optionally) pad.  (In force-indexed mode, this is also where we
+	 track symbols of the wrong type for this round of insertion.)  */
+      if ((type = ctf_dynhash_lookup (symhash, sym_name)) == NULL)
+	continue;
+
+      ctf_str_add_ref (fp, sym_name, dpp++);
+
+      if (!ctf_assert (fp, (((char *) dpp) - (char *) dp) <= size))
+	return -1;				/* errno is set for us.  */
+    }
+
+  return 0;
+}
+
+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;
+}
+
+/* Sort a newly-constructed static variable array.  */
+
+typedef struct ctf_sort_var_arg_cb
+{
+  ctf_dict_t *fp;
+  ctf_strs_t *strtab;
+} ctf_sort_var_arg_cb_t;
+
+static int
+ctf_sort_var (const void *one_, const void *two_, void *arg_)
+{
+  const ctf_varent_t *one = one_;
+  const ctf_varent_t *two = two_;
+  ctf_sort_var_arg_cb_t *arg = arg_;
+
+  return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
+		  ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
+}
+
+/* If the specified CTF dict is writable and has been modified, reload this dict
+   with the updated type definitions, ready for serialization.  In order to make
+   this code and the rest of libctf as simple as possible, we perform updates by
+   taking the dynamic type definitions and creating an in-memory CTF dict
+   containing the definitions, and then call ctf_simple_open_internal() on it.
+   We perform one extra trick here for the benefit of callers and to keep our
+   code simple: ctf_simple_open_internal() will return a new ctf_dict_t, but we
+   want to keep the fp constant for the caller, so after
+   ctf_simple_open_internal() returns, we use memcpy to swap the interior of the
+   old and new ctf_dict_t's, and then free the old.  */
+int
+ctf_serialize (ctf_dict_t *fp)
+{
+  ctf_dict_t ofp, *nfp;
+  ctf_header_t hdr, *hdrp;
+  ctf_dtdef_t *dtd;
+  ctf_dvdef_t *dvd;
+  ctf_varent_t *dvarents;
+  ctf_strs_writable_t strtab;
+
+  unsigned char *t;
+  unsigned long i;
+  size_t buf_size, type_size, objt_size, func_size;
+  size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize;
+  size_t funcidx_size, objtidx_size;
+  size_t nvars, nfuncs, nobjts, maxobjt, maxfunc;
+  size_t nsymtypes = 0;
+  const char **sym_name_order = NULL;
+  unsigned char *buf = NULL, *newbuf;
+  int err;
+
+  /* Symtab filtering. If filter_syms is true, symfp is set: otherwise,
+     CTF_SYMTYPETAB_FORCE_INDEXED is set in symflags.  */
+  int filter_syms = 0;
+  int sort_syms = 1;
+  int symflags = 0;
+  ctf_dict_t *symfp = NULL;
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  /* Update required?  */
+  if (!(fp->ctf_flags & LCTF_DIRTY))
+    return 0;
+
+  /* If doing a writeout as part of linking, and the link flags request it,
+     filter out reported symbols from the variable section, and filter out all
+     other symbols from the symtypetab sections.  (If we are not linking, the
+     symbols are sorted; if we are linking, don't bother sorting if we are not
+     filtering out reported symbols: this is almost certaily an ld -r and only
+     the linker is likely to consume these symtypetabs again.  The linker
+     doesn't care what order the symtypetab entries is in, since it only
+     iterates over symbols and does not use the ctf_lookup_by_symbol* API.)  */
+
+  if (fp->ctf_flags & LCTF_LINKING)
+    {
+      filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);
+      if (!filter_syms)
+	sort_syms = 0;
+    }
+
+  /* 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
+     boundary past the CTF header itself (at relative offset zero).  The flag
+     indicating a new-style function info section (an array of CTF_K_FUNCTION
+     type IDs in the types section) is flipped on.  */
+
+  memset (&hdr, 0, sizeof (hdr));
+  hdr.cth_magic = CTF_MAGIC;
+  hdr.cth_version = CTF_VERSION;
+
+  /* This is a new-format func info section, and the symtab and strtab come out
+     of the dynsym and dynstr these days.  */
+  hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
+
+  /* Iterate through the dynamic type definition list and compute the
+     size of the CTF type section we will need to generate.  */
+
+  for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
+       dtd != NULL; dtd = ctf_list_next (dtd))
+    {
+      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+	type_size += sizeof (ctf_stype_t);
+      else
+	type_size += sizeof (ctf_type_t);
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  type_size += sizeof (uint32_t);
+	  break;
+	case CTF_K_ARRAY:
+	  type_size += sizeof (ctf_array_t);
+	  break;
+	case CTF_K_SLICE:
+	  type_size += sizeof (ctf_slice_t);
+	  break;
+	case CTF_K_FUNCTION:
+	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
+	  break;
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+	    type_size += sizeof (ctf_member_t) * vlen;
+	  else
+	    type_size += sizeof (ctf_lmember_t) * vlen;
+	  break;
+	case CTF_K_ENUM:
+	  type_size += sizeof (ctf_enum_t) * vlen;
+	  break;
+	}
+    }
+
+  /* Find the dict to which the linker has reported symbols, if any.  */
+
+  if (filter_syms)
+    {
+      if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms)
+	symfp = fp->ctf_parent;
+      else
+	symfp = fp;
+    }
+
+  /* If not filtering, keep all potential symbols in an unsorted, indexed
+     dict.  */
+  if (!filter_syms)
+    symflags = CTF_SYMTYPETAB_FORCE_INDEXED;
+  else
+    hdr.cth_flags |= CTF_F_IDXSORTED;
+
+  if (!ctf_assert (fp, (filter_syms && symfp)
+		   || (!filter_syms && !symfp
+		       && ((symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0))))
+    return -1;
+
+  /* Work out the sizes of the object and function sections, and work out the
+     number of pad (unassigned) symbols in each, and the overall size of the
+     sections.  */
+
+  if (symtypetab_density (fp, symfp, fp->ctf_objthash, &nobjts, &maxobjt,
+			  &objt_unpadsize, &objt_padsize, &objtidx_size,
+			  symflags) < 0)
+    return -1;					/* errno is set for us.  */
+
+  ctf_dprintf ("Object symtypetab: %i objects, max %i, unpadded size %i, "
+	       "%i bytes of pads, index size %i\n", (int) nobjts, (int) maxobjt,
+	       (int) objt_unpadsize, (int) objt_padsize, (int) objtidx_size);
+
+  if (symtypetab_density (fp, symfp, fp->ctf_funchash, &nfuncs, &maxfunc,
+			  &func_unpadsize, &func_padsize, &funcidx_size,
+			  symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+    return -1;					/* errno is set for us.  */
+
+  ctf_dprintf ("Function symtypetab: %i functions, max %i, unpadded size %i, "
+	       "%i bytes of pads, index size %i\n", (int) nfuncs, (int) maxfunc,
+	       (int) func_unpadsize, (int) func_padsize, (int) funcidx_size);
+
+  /* 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.  */
+
+  if (filter_syms && symfp->ctf_dynsyms &&
+      symtypetab_delete_nonstatic_vars (fp, symfp) < 0)
+    return -1;
+
+  /* It is worth indexing each section if it would save space to do so, due to
+     reducing the number of pads sufficiently.  A pad is the same size as a
+     single index entry: but index sections compress relatively poorly compared
+     to constant pads, so it takes a lot of contiguous padding to equal one
+     index section entry.  It would be nice to be able to *verify* whether we
+     would save space after compression rather than guessing, but this seems
+     difficult, since it would require complete reserialization.  Regardless, if
+     the linker has not reported any symbols (e.g. if this is not a final link
+     but just an ld -r), we must emit things in indexed fashion just as the
+     compiler does.  */
+
+  objt_size = objt_unpadsize;
+  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
+      && ((objt_padsize + objt_unpadsize) * CTF_INDEX_PAD_THRESHOLD
+	  > objt_padsize))
+    {
+      objt_size += objt_padsize;
+      objtidx_size = 0;
+    }
+
+  func_size = func_unpadsize;
+  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
+      && ((func_padsize + func_unpadsize) * CTF_INDEX_PAD_THRESHOLD
+	  > func_padsize))
+    {
+      func_size += func_padsize;
+      funcidx_size = 0;
+    }
+
+  /* Computing the number of entries in the CTF variable section is much
+     simpler.  */
+
+  for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
+       dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
+
+  /* Compute the size of the CTF buffer we need, sans only the string table,
+     then allocate a new buffer and memcpy the finished header to the start of
+     the buffer.  (We will adjust this later with strtab length info.)  */
+
+  hdr.cth_lbloff = hdr.cth_objtoff = 0;
+  hdr.cth_funcoff = hdr.cth_objtoff + objt_size;
+  hdr.cth_objtidxoff = hdr.cth_funcoff + func_size;
+  hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size;
+  hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size;
+  hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
+  hdr.cth_stroff = hdr.cth_typeoff + type_size;
+  hdr.cth_strlen = 0;
+
+  buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
+
+  if ((buf = malloc (buf_size)) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  memcpy (buf, &hdr, sizeof (ctf_header_t));
+  t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
+
+  hdrp = (ctf_header_t *) buf;
+  if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
+    ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
+  if (fp->ctf_cuname != NULL)
+    ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
+
+  /* Sort the linker's symbols into name order if need be.  */
+
+  if ((objtidx_size != 0) || (funcidx_size != 0))
+    {
+      ctf_next_t *i = NULL;
+      void *symname;
+      const char **walk;
+
+      if (filter_syms)
+	{
+	  if (symfp->ctf_dynsyms)
+	    nsymtypes = ctf_dynhash_elements (symfp->ctf_dynsyms);
+	  else
+	    nsymtypes = 0;
+	}
+      else
+	nsymtypes = ctf_dynhash_elements (fp->ctf_objthash)
+	  + ctf_dynhash_elements (fp->ctf_funchash);
+
+      if ((sym_name_order = calloc (nsymtypes, sizeof (const char *))) == NULL)
+	goto oom;
+
+      walk = sym_name_order;
+
+      if (filter_syms)
+	{
+	  if (symfp->ctf_dynsyms)
+	    {
+	      while ((err = ctf_dynhash_next_sorted (symfp->ctf_dynsyms, &i,
+						     &symname, NULL,
+						     ctf_dynhash_sort_by_name,
+						     NULL)) == 0)
+		*walk++ = (const char *) symname;
+	      if (err != ECTF_NEXT_END)
+		goto symerr;
+	    }
+	}
+      else
+	{
+	  ctf_hash_sort_f sort_fun = NULL;
+
+	  /* Since we partition the set of symbols back into objt and func,
+	     we can sort the two independently without harm.  */
+	  if (sort_syms)
+	    sort_fun = ctf_dynhash_sort_by_name;
+
+	  while ((err = ctf_dynhash_next_sorted (fp->ctf_objthash, &i, &symname,
+						 NULL, sort_fun, NULL)) == 0)
+	    *walk++ = (const char *) symname;
+	  if (err != ECTF_NEXT_END)
+	    goto symerr;
+
+	  while ((err = ctf_dynhash_next_sorted (fp->ctf_funchash, &i, &symname,
+						 NULL, sort_fun, NULL)) == 0)
+	    *walk++ = (const char *) symname;
+	  if (err != ECTF_NEXT_END)
+	    goto symerr;
+	}
+    }
+
+  /* Emit the object and function sections, and if necessary their indexes.
+     Emission is done in symtab order if there is no index, and in index
+     (name) order otherwise.  */
+
+  if ((objtidx_size == 0) && symfp && symfp->ctf_dynsymidx)
+    {
+      ctf_dprintf ("Emitting unindexed objt symtypetab\n");
+      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
+			   NULL, symfp->ctf_dynsymmax + 1, maxobjt, objt_size,
+			   symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0)
+	goto err;				/* errno is set for us.  */
+    }
+  else
+    {
+      ctf_dprintf ("Emitting indexed objt symtypetab\n");
+      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
+			   nsymtypes, maxobjt, objt_size, symflags) < 0)
+	goto err;				/* errno is set for us.  */
+    }
+
+  t += objt_size;
+
+  if ((funcidx_size == 0) && symfp && symfp->ctf_dynsymidx)
+    {
+      ctf_dprintf ("Emitting unindexed func symtypetab\n");
+      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
+			   NULL, symfp->ctf_dynsymmax + 1, maxfunc,
+			   func_size, symflags | CTF_SYMTYPETAB_EMIT_FUNCTION
+			   | CTF_SYMTYPETAB_EMIT_PAD) < 0)
+	goto err;				/* errno is set for us.  */
+    }
+  else
+    {
+      ctf_dprintf ("Emitting indexed func symtypetab\n");
+      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
+			   nsymtypes, maxfunc, func_size,
+			   symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+	goto err;				/* errno is set for us.  */
+    }
+
+  t += func_size;
+
+  if (objtidx_size > 0)
+    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
+			       nsymtypes, objtidx_size, symflags) < 0)
+      goto err;
+
+  t += objtidx_size;
+
+  if (funcidx_size > 0)
+    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
+			       nsymtypes, funcidx_size,
+			       symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+      goto err;
+
+  t += funcidx_size;
+  free (sym_name_order);
+  sym_name_order = NULL;
+
+  /* Work over the variable list, translating everything into ctf_varent_t's and
+     prepping the string table.  */
+
+  dvarents = (ctf_varent_t *) t;
+  for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
+       dvd = ctf_list_next (dvd), i++)
+    {
+      ctf_varent_t *var = &dvarents[i];
+
+      ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name);
+      var->ctv_type = (uint32_t) dvd->dvd_type;
+    }
+  assert (i == nvars);
+
+  t += sizeof (ctf_varent_t) * nvars;
+
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
+
+  /* We now take a final lap through the dynamic type definition list and copy
+     the appropriate type records to the output buffer, noting down the
+     strings as we go.  */
+
+  for (dtd = ctf_list_next (&fp->ctf_dtdefs);
+       dtd != NULL; dtd = ctf_list_next (dtd))
+    {
+      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+      ctf_array_t cta;
+      uint32_t encoding;
+      size_t len;
+      ctf_stype_t *copied;
+      const char *name;
+
+      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+	len = sizeof (ctf_stype_t);
+      else
+	len = sizeof (ctf_type_t);
+
+      memcpy (t, &dtd->dtd_data, len);
+      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);
+      t += len;
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  if (kind == CTF_K_INTEGER)
+	    {
+	      encoding = CTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
+				       dtd->dtd_u.dtu_enc.cte_offset,
+				       dtd->dtd_u.dtu_enc.cte_bits);
+	    }
+	  else
+	    {
+	      encoding = CTF_FP_DATA (dtd->dtd_u.dtu_enc.cte_format,
+				      dtd->dtd_u.dtu_enc.cte_offset,
+				      dtd->dtd_u.dtu_enc.cte_bits);
+	    }
+	  memcpy (t, &encoding, sizeof (encoding));
+	  t += sizeof (encoding);
+	  break;
+
+	case CTF_K_SLICE:
+	  memcpy (t, &dtd->dtd_u.dtu_slice, sizeof (struct ctf_slice));
+	  t += sizeof (struct ctf_slice);
+	  break;
+
+	case CTF_K_ARRAY:
+	  cta.cta_contents = (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents;
+	  cta.cta_index = (uint32_t) dtd->dtd_u.dtu_arr.ctr_index;
+	  cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
+	  memcpy (t, &cta, sizeof (cta));
+	  t += sizeof (cta);
+	  break;
+
+	case CTF_K_FUNCTION:
+	  {
+	    uint32_t *argv = (uint32_t *) (uintptr_t) t;
+	    uint32_t argc;
+
+	    for (argc = 0; argc < vlen; argc++)
+	      *argv++ = dtd->dtd_u.dtu_argv[argc];
+
+	    if (vlen & 1)
+	      *argv++ = 0;	/* Pad to 4-byte boundary.  */
+
+	    t = (unsigned char *) argv;
+	    break;
+	  }
+
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+	    t = ctf_copy_smembers (fp, dtd, t);
+	  else
+	    t = ctf_copy_lmembers (fp, dtd, t);
+	  break;
+
+	case CTF_K_ENUM:
+	  t = ctf_copy_emembers (fp, dtd, t);
+	  break;
+	}
+    }
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
+
+  /* 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.  */
+  strtab = ctf_str_write_strtab (fp);
+  ctf_str_purge_refs (fp);
+
+  if (strtab.cts_strs == NULL)
+    goto oom;
+
+  /* Now the string table is constructed, we can sort the buffer of
+     ctf_varent_t's.  */
+  ctf_sort_var_arg_cb_t sort_var_arg = { fp, (ctf_strs_t *) &strtab };
+  ctf_qsort_r (dvarents, nvars, sizeof (ctf_varent_t), ctf_sort_var,
+	       &sort_var_arg);
+
+  if ((newbuf = ctf_realloc (fp, buf, buf_size + strtab.cts_len)) == NULL)
+    {
+      free (strtab.cts_strs);
+      goto oom;
+    }
+  buf = newbuf;
+  memcpy (buf + buf_size, strtab.cts_strs, strtab.cts_len);
+  hdrp = (ctf_header_t *) buf;
+  hdrp->cth_strlen = strtab.cts_len;
+  buf_size += hdrp->cth_strlen;
+  free (strtab.cts_strs);
+
+  /* Finally, we are ready to ctf_simple_open() the new dict.  If this is
+     successful, we then switch nfp and fp and free the old dict.  */
+
+  if ((nfp = ctf_simple_open_internal ((char *) buf, buf_size, NULL, 0,
+				       0, NULL, 0, fp->ctf_syn_ext_strtab,
+				       1, &err)) == NULL)
+    {
+      free (buf);
+      return (ctf_set_errno (fp, err));
+    }
+
+  (void) ctf_setmodel (nfp, ctf_getmodel (fp));
+
+  nfp->ctf_parent = fp->ctf_parent;
+  nfp->ctf_parent_unreffed = fp->ctf_parent_unreffed;
+  nfp->ctf_refcnt = fp->ctf_refcnt;
+  nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY;
+  if (nfp->ctf_dynbase == NULL)
+    nfp->ctf_dynbase = buf;		/* Make sure buf is freed on close.  */
+  nfp->ctf_dthash = fp->ctf_dthash;
+  nfp->ctf_dtdefs = fp->ctf_dtdefs;
+  nfp->ctf_dvhash = fp->ctf_dvhash;
+  nfp->ctf_dvdefs = fp->ctf_dvdefs;
+  nfp->ctf_dtoldid = fp->ctf_dtoldid;
+  nfp->ctf_add_processing = fp->ctf_add_processing;
+  nfp->ctf_snapshots = fp->ctf_snapshots + 1;
+  nfp->ctf_specific = fp->ctf_specific;
+  nfp->ctf_nfuncidx = fp->ctf_nfuncidx;
+  nfp->ctf_nobjtidx = fp->ctf_nobjtidx;
+  nfp->ctf_objthash = fp->ctf_objthash;
+  nfp->ctf_funchash = fp->ctf_funchash;
+  nfp->ctf_dynsyms = fp->ctf_dynsyms;
+  nfp->ctf_ptrtab = fp->ctf_ptrtab;
+  nfp->ctf_pptrtab = fp->ctf_pptrtab;
+  nfp->ctf_dynsymidx = fp->ctf_dynsymidx;
+  nfp->ctf_dynsymmax = fp->ctf_dynsymmax;
+  nfp->ctf_ptrtab_len = fp->ctf_ptrtab_len;
+  nfp->ctf_pptrtab_len = fp->ctf_pptrtab_len;
+  nfp->ctf_link_inputs = fp->ctf_link_inputs;
+  nfp->ctf_link_outputs = fp->ctf_link_outputs;
+  nfp->ctf_errs_warnings = fp->ctf_errs_warnings;
+  nfp->ctf_funcidx_names = fp->ctf_funcidx_names;
+  nfp->ctf_objtidx_names = fp->ctf_objtidx_names;
+  nfp->ctf_funcidx_sxlate = fp->ctf_funcidx_sxlate;
+  nfp->ctf_objtidx_sxlate = fp->ctf_objtidx_sxlate;
+  nfp->ctf_str_prov_offset = fp->ctf_str_prov_offset;
+  nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
+  nfp->ctf_pptrtab_typemax = fp->ctf_pptrtab_typemax;
+  nfp->ctf_in_flight_dynsyms = fp->ctf_in_flight_dynsyms;
+  nfp->ctf_link_in_cu_mapping = fp->ctf_link_in_cu_mapping;
+  nfp->ctf_link_out_cu_mapping = fp->ctf_link_out_cu_mapping;
+  nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping;
+  nfp->ctf_link_memb_name_changer = fp->ctf_link_memb_name_changer;
+  nfp->ctf_link_memb_name_changer_arg = fp->ctf_link_memb_name_changer_arg;
+  nfp->ctf_link_variable_filter = fp->ctf_link_variable_filter;
+  nfp->ctf_link_variable_filter_arg = fp->ctf_link_variable_filter_arg;
+  nfp->ctf_symsect_little_endian = fp->ctf_symsect_little_endian;
+  nfp->ctf_link_flags = fp->ctf_link_flags;
+  nfp->ctf_dedup_atoms = fp->ctf_dedup_atoms;
+  nfp->ctf_dedup_atoms_alloc = fp->ctf_dedup_atoms_alloc;
+  memcpy (&nfp->ctf_dedup, &fp->ctf_dedup, sizeof (fp->ctf_dedup));
+
+  nfp->ctf_snapshot_lu = fp->ctf_snapshots;
+
+  memcpy (&nfp->ctf_lookups, fp->ctf_lookups, sizeof (fp->ctf_lookups));
+  nfp->ctf_structs = fp->ctf_structs;
+  nfp->ctf_unions = fp->ctf_unions;
+  nfp->ctf_enums = fp->ctf_enums;
+  nfp->ctf_names = fp->ctf_names;
+
+  fp->ctf_dthash = NULL;
+  ctf_str_free_atoms (nfp);
+  nfp->ctf_str_atoms = fp->ctf_str_atoms;
+  nfp->ctf_prov_strtab = fp->ctf_prov_strtab;
+  fp->ctf_str_atoms = NULL;
+  fp->ctf_prov_strtab = 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;
+  fp->ctf_ptrtab = NULL;
+  fp->ctf_pptrtab = NULL;
+  fp->ctf_funcidx_names = NULL;
+  fp->ctf_objtidx_names = NULL;
+  fp->ctf_funcidx_sxlate = NULL;
+  fp->ctf_objtidx_sxlate = NULL;
+  fp->ctf_objthash = NULL;
+  fp->ctf_funchash = NULL;
+  fp->ctf_dynsyms = NULL;
+  fp->ctf_dynsymidx = NULL;
+  fp->ctf_link_inputs = NULL;
+  fp->ctf_link_outputs = NULL;
+  fp->ctf_syn_ext_strtab = NULL;
+  fp->ctf_link_in_cu_mapping = NULL;
+  fp->ctf_link_out_cu_mapping = NULL;
+  fp->ctf_link_type_mapping = NULL;
+  fp->ctf_dedup_atoms = NULL;
+  fp->ctf_dedup_atoms_alloc = NULL;
+  fp->ctf_parent_unreffed = 1;
+
+  fp->ctf_dvhash = NULL;
+  memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t));
+  memset (fp->ctf_lookups, 0, sizeof (fp->ctf_lookups));
+  memset (&fp->ctf_in_flight_dynsyms, 0, sizeof (fp->ctf_in_flight_dynsyms));
+  memset (&fp->ctf_dedup, 0, sizeof (fp->ctf_dedup));
+  fp->ctf_structs.ctn_writable = NULL;
+  fp->ctf_unions.ctn_writable = NULL;
+  fp->ctf_enums.ctn_writable = NULL;
+  fp->ctf_names.ctn_writable = NULL;
+
+  memcpy (&ofp, fp, sizeof (ctf_dict_t));
+  memcpy (fp, nfp, sizeof (ctf_dict_t));
+  memcpy (nfp, &ofp, sizeof (ctf_dict_t));
+
+  nfp->ctf_refcnt = 1;				/* Force nfp to be freed.  */
+  ctf_dict_close (nfp);
+
+  return 0;
+
+symerr:
+  ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
+  goto err;
+oom:
+  free (buf);
+  free (sym_name_order);
+  return (ctf_set_errno (fp, EAGAIN));
+err:
+  free (buf);
+  free (sym_name_order);
+  return -1;					/* errno is set for us.  */
+}
+
+
+/* Write the compressed CTF data stream to the specified gzFile descriptor.  */
+int
+ctf_gzwrite (ctf_dict_t *fp, gzFile fd)
+{
+  const unsigned char *buf;
+  ssize_t resid;
+  ssize_t len;
+
+  resid = sizeof (ctf_header_t);
+  buf = (unsigned char *) fp->ctf_header;
+  while (resid != 0)
+    {
+      if ((len = gzwrite (fd, buf, resid)) <= 0)
+	return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  resid = fp->ctf_size;
+  buf = fp->ctf_buf;
+  while (resid != 0)
+    {
+      if ((len = gzwrite (fd, buf, resid)) <= 0)
+	return (ctf_set_errno (fp, errno));
+      resid -= len;
+      buf += len;
+    }
+
+  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.  */
+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;
+  ssize_t header_len = sizeof (ctf_header_t);
+  ssize_t compress_len;
+  int rc;
+
+  if (ctf_serialize (fp) < 0)
+    return NULL;				/* errno is set for us.  */
+
+  compress_len = compressBound (fp->ctf_size);
+  if (fp->ctf_size < threshold)
+    compress_len = fp->ctf_size;
+  if ((buf = malloc (compress_len
+		     + sizeof (struct ctf_header))) == NULL)
+    {
+      ctf_set_errno (fp, ENOMEM);
+      ctf_err_warn (fp, 0, 0, _("ctf_write_mem: cannot allocate %li bytes"),
+		    (unsigned long) (compress_len + sizeof (struct ctf_header)));
+      return NULL;
+    }
+
+  hp = (ctf_header_t *) buf;
+  memcpy (hp, fp->ctf_header, header_len);
+  bp = buf + sizeof (struct ctf_header);
+  *size = sizeof (struct ctf_header);
+
+  if (fp->ctf_size < threshold)
+    {
+      hp->cth_flags &= ~CTF_F_COMPRESS;
+      memcpy (bp, fp->ctf_buf, 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)
+	{
+	  ctf_set_errno (fp, ECTF_COMPRESS);
+	  ctf_err_warn (fp, 0, 0, _("zlib deflate err: %s"), zError (rc));
+	  free (buf);
+	  return NULL;
+	}
+      *size += compress_len;
+    }
+  return buf;
+}
+
+/* Write the uncompressed CTF data stream to the specified file descriptor.  */
+int
+ctf_write (ctf_dict_t *fp, int fd)
+{
+  const unsigned char *buf;
+  ssize_t resid;
+  ssize_t len;
+
+  if (ctf_serialize (fp) < 0)
+    return -1;					/* errno is set for us.  */
+
+  resid = sizeof (ctf_header_t);
+  buf = (unsigned char *) fp->ctf_header;
+  while (resid != 0)
+    {
+      if ((len = write (fd, buf, resid)) <= 0)
+	{
+	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing header"));
+	  return (ctf_set_errno (fp, errno));
+	}
+      resid -= len;
+      buf += len;
+    }
+
+  resid = fp->ctf_size;
+  buf = fp->ctf_buf;
+  while (resid != 0)
+    {
+      if ((len = write (fd, buf, resid)) <= 0)
+	{
+	  ctf_err_warn (fp, 0, errno, _("ctf_write: error writing"));
+	  return (ctf_set_errno (fp, errno));
+	}
+      resid -= len;
+      buf += len;
+    }
+
+  return 0;
+}
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 03/16] libctf: fix comment above ctf_dict_t
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
  2021-03-06  0:40 ` [PATCH 01/16] libctf: fix some tabdamage and move some code around Nick Alcock
  2021-03-06  0:40 ` [PATCH 02/16] libctf: split serialization and file writeout into its own file Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 04/16] libctf: split up ctf_serialize Nick Alcock
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

It is perfectly possible to have dynamically allocated data owned by a
specific dict: you just have to teach ctf_serialize about it.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dict_t): Fix comment.
---
 libctf/ctf-impl.h | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 78a41ff4932..5567b4c61f5 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -372,11 +372,12 @@ typedef struct ctf_dedup
    ctf_dict_t typedef appears in <ctf-api.h> and declares a forward tag.
    (A ctf_file_t typedef also appears there, for historical reasons.)
 
-   NOTE: ctf_serialize() requires that everything inside of ctf_dict either be
-   an immediate value, a pointer to dynamically allocated data *outside* of the
-   ctf_dict itself, or a pointer to statically allocated data.  If you add a
-   pointer to ctf_dict that points to something within the ctf_dict itself, you
-   must make corresponding changes to ctf_serialize().  */
+   NOTE: ctf_serialize requires that everything inside of ctf_dict either be an
+   immediate value, a pointer to dynamically allocated data *outside* of the
+   ctf_dict itself, a pointer to statically allocated data, or specially handled
+   in ctf_serialize.  If you add a pointer to ctf_dict that points to something
+   within the ctf_dict itself, you must make corresponding changes to
+   ctf_serialize.  */
 
 struct ctf_dict
 {
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 04/16] libctf: split up ctf_serialize
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (2 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 03/16] libctf: fix comment above ctf_dict_t Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 05/16] libctf: fix GNU style for do {} while Nick Alcock
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

ctf_serialize and its various pieces may be split out into a separate
file now, but ctf_serialize is still far too long and disordered, mixing
header initialization, sizing of multiple CTF sections, sorting and
emission of multiple CTF sections, strtab construction and ctf_dict_t
copying into a single ugly organically-grown mess.

Fix the worst of this by migrating all section sizing and emission into
separate functions, two per section (or class of section in the case of
the symtypetabs).  Only the variable section is now sized and emitted
directly in ctf_serialize (because it only takes about three lines to do
so).

The section sizes themselves are still maintained by ctf_serialize so
that it can work out the header offsets, but ctf_symtypetab_sect_sizes
and ctf_emit_symtypetab_sects share a lot of extra state: migrate that
into a shared structure, emit_symtypetab_state_t.

(Test results unchanged.)

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-serialize.c: General reshuffling, and...
	(emit_symtypetab_state_t): New, migrated from
	local variables in ctf_serialize.
	(ctf_serialize): Split out most section sizing and
	emission.
	(ctf_symtypetab_sect_sizes): New (split out).
	(ctf_emit_symtypetab_sects): Likewise.
	(ctf_type_sect_size): Likewise.
	(ctf_emit_type_sect): Likewise.
---
 libctf/ctf-serialize.c | 731 +++++++++++++++++++++++------------------
 1 file changed, 413 insertions(+), 318 deletions(-)

diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index e0bd98c51a8..1e2c98b473a 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -26,29 +26,39 @@
 #include <elf.h>
 #include "elf-bfd.h"
 
-/* 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.  */
+/* Symtypetab sections.  */
 
-static int
-symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
+/* Symtypetab emission flags.  */
+
+#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1
+#define CTF_SYMTYPETAB_EMIT_PAD 0x2
+#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4
+
+/* Properties of symtypetab emission, shared by symtypetab section
+   sizing and symtypetab emission itself.  */
+
+typedef struct emit_symtypetab_state
 {
-  ctf_dvdef_t *dvd, *nvd;
-  ctf_id_t type;
+  /* True if linker-reported symbols are being filtered out.  symfp is set if
+     this is true: otherwise, indexing is forced and the symflags indicate as
+     much. */
+  int filter_syms;
 
-  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
-    {
-      nvd = ctf_list_next (dvd);
+  /* True if symbols are being sorted.  */
+  int sort_syms;
 
-      if (((type = (ctf_id_t) (uintptr_t)
-	    ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
-	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
-	  && type == dvd->dvd_type)
-	ctf_dvd_delete (fp, dvd);
-    }
+  /* Flags for symtypetab emission.  */
+  int symflags;
 
-  return 0;
-}
+  /* The dict to which the linker has reported symbols.  */
+  ctf_dict_t *symfp;
+
+  /* The maximum number of objects seen.  */
+  size_t maxobjt;
+
+  /* The maximum number of func info entris seen.  */
+  size_t maxfunc;
+} emit_symtypetab_state_t;
 
 /* Determine if a symbol is "skippable" and should never appear in the
    symtypetab sections.  */
@@ -68,12 +78,6 @@ ctf_symtab_skippable (ctf_link_sym_t *sym)
 	      && sym->st_value == 0));
 }
 
-/* Symtypetab emission flags.  */
-
-#define CTF_SYMTYPETAB_EMIT_FUNCTION 0x1
-#define CTF_SYMTYPETAB_EMIT_PAD 0x2
-#define CTF_SYMTYPETAB_FORCE_INDEXED 0x4
-
 /* Get the number of symbols in a symbol hash, the count of symbols, the maximum
    seen, the eventual size, without any padding elements, of the func/data and
    (if generated) index sections, and the size of accumulated padding elements.
@@ -427,140 +431,40 @@ emit_symtypetab_index (ctf_dict_t *fp, ctf_dict_t *symfp, uint32_t *dp,
   return 0;
 }
 
-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;
-}
+/* 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.  */
 
-static unsigned char *
-ctf_copy_emembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
+static int
+symtypetab_delete_nonstatic_vars (ctf_dict_t *fp, ctf_dict_t *symfp)
 {
-  ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-  ctf_enum_t cte;
+  ctf_dvdef_t *dvd, *nvd;
+  ctf_id_t type;
 
-  for (; dmd != NULL; dmd = ctf_list_next (dmd))
+  for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
     {
-      ctf_enum_t *copied;
+      nvd = ctf_list_next (dvd);
 
-      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);
+      if (((type = (ctf_id_t) (uintptr_t)
+	    ctf_dynhash_lookup (fp->ctf_objthash, dvd->dvd_name)) > 0)
+	  && ctf_dynhash_lookup (symfp->ctf_dynsyms, dvd->dvd_name) != NULL
+	  && type == dvd->dvd_type)
+	ctf_dvd_delete (fp, dvd);
     }
 
-  return t;
+  return 0;
 }
 
-/* Sort a newly-constructed static variable array.  */
-
-typedef struct ctf_sort_var_arg_cb
-{
-  ctf_dict_t *fp;
-  ctf_strs_t *strtab;
-} ctf_sort_var_arg_cb_t;
-
+/* Figure out the sizes of the symtypetab sections, their indexed state,
+   etc.  */
 static int
-ctf_sort_var (const void *one_, const void *two_, void *arg_)
-{
-  const ctf_varent_t *one = one_;
-  const ctf_varent_t *two = two_;
-  ctf_sort_var_arg_cb_t *arg = arg_;
-
-  return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
-		  ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
-}
-
-/* If the specified CTF dict is writable and has been modified, reload this dict
-   with the updated type definitions, ready for serialization.  In order to make
-   this code and the rest of libctf as simple as possible, we perform updates by
-   taking the dynamic type definitions and creating an in-memory CTF dict
-   containing the definitions, and then call ctf_simple_open_internal() on it.
-   We perform one extra trick here for the benefit of callers and to keep our
-   code simple: ctf_simple_open_internal() will return a new ctf_dict_t, but we
-   want to keep the fp constant for the caller, so after
-   ctf_simple_open_internal() returns, we use memcpy to swap the interior of the
-   old and new ctf_dict_t's, and then free the old.  */
-int
-ctf_serialize (ctf_dict_t *fp)
+ctf_symtypetab_sect_sizes (ctf_dict_t *fp, emit_symtypetab_state_t *s,
+			   ctf_header_t *hdr, size_t *objt_size,
+			   size_t *func_size, size_t *objtidx_size,
+			   size_t *funcidx_size)
 {
-  ctf_dict_t ofp, *nfp;
-  ctf_header_t hdr, *hdrp;
-  ctf_dtdef_t *dtd;
-  ctf_dvdef_t *dvd;
-  ctf_varent_t *dvarents;
-  ctf_strs_writable_t strtab;
-
-  unsigned char *t;
-  unsigned long i;
-  size_t buf_size, type_size, objt_size, func_size;
+  size_t nfuncs, nobjts;
   size_t objt_unpadsize, func_unpadsize, objt_padsize, func_padsize;
-  size_t funcidx_size, objtidx_size;
-  size_t nvars, nfuncs, nobjts, maxobjt, maxfunc;
-  size_t nsymtypes = 0;
-  const char **sym_name_order = NULL;
-  unsigned char *buf = NULL, *newbuf;
-  int err;
-
-  /* Symtab filtering. If filter_syms is true, symfp is set: otherwise,
-     CTF_SYMTYPETAB_FORCE_INDEXED is set in symflags.  */
-  int filter_syms = 0;
-  int sort_syms = 1;
-  int symflags = 0;
-  ctf_dict_t *symfp = NULL;
-
-  if (!(fp->ctf_flags & LCTF_RDWR))
-    return (ctf_set_errno (fp, ECTF_RDONLY));
-
-  /* Update required?  */
-  if (!(fp->ctf_flags & LCTF_DIRTY))
-    return 0;
 
   /* If doing a writeout as part of linking, and the link flags request it,
      filter out reported symbols from the variable section, and filter out all
@@ -571,124 +475,59 @@ ctf_serialize (ctf_dict_t *fp)
      doesn't care what order the symtypetab entries is in, since it only
      iterates over symbols and does not use the ctf_lookup_by_symbol* API.)  */
 
+  s->sort_syms = 1;
   if (fp->ctf_flags & LCTF_LINKING)
     {
-      filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);
-      if (!filter_syms)
-	sort_syms = 0;
-    }
-
-  /* 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
-     boundary past the CTF header itself (at relative offset zero).  The flag
-     indicating a new-style function info section (an array of CTF_K_FUNCTION
-     type IDs in the types section) is flipped on.  */
-
-  memset (&hdr, 0, sizeof (hdr));
-  hdr.cth_magic = CTF_MAGIC;
-  hdr.cth_version = CTF_VERSION;
-
-  /* This is a new-format func info section, and the symtab and strtab come out
-     of the dynsym and dynstr these days.  */
-  hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
-
-  /* Iterate through the dynamic type definition list and compute the
-     size of the CTF type section we will need to generate.  */
-
-  for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
-       dtd != NULL; dtd = ctf_list_next (dtd))
-    {
-      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
-      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
-
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
-	type_size += sizeof (ctf_stype_t);
-      else
-	type_size += sizeof (ctf_type_t);
-
-      switch (kind)
-	{
-	case CTF_K_INTEGER:
-	case CTF_K_FLOAT:
-	  type_size += sizeof (uint32_t);
-	  break;
-	case CTF_K_ARRAY:
-	  type_size += sizeof (ctf_array_t);
-	  break;
-	case CTF_K_SLICE:
-	  type_size += sizeof (ctf_slice_t);
-	  break;
-	case CTF_K_FUNCTION:
-	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
-	  break;
-	case CTF_K_STRUCT:
-	case CTF_K_UNION:
-	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
-	    type_size += sizeof (ctf_member_t) * vlen;
-	  else
-	    type_size += sizeof (ctf_lmember_t) * vlen;
-	  break;
-	case CTF_K_ENUM:
-	  type_size += sizeof (ctf_enum_t) * vlen;
-	  break;
-	}
+      s->filter_syms = !(fp->ctf_link_flags & CTF_LINK_NO_FILTER_REPORTED_SYMS);
+      if (!s->filter_syms)
+	s->sort_syms = 0;
     }
 
   /* Find the dict to which the linker has reported symbols, if any.  */
 
-  if (filter_syms)
+  if (s->filter_syms)
     {
       if (!fp->ctf_dynsyms && fp->ctf_parent && fp->ctf_parent->ctf_dynsyms)
-	symfp = fp->ctf_parent;
+	s->symfp = fp->ctf_parent;
       else
-	symfp = fp;
+	s->symfp = fp;
     }
 
   /* If not filtering, keep all potential symbols in an unsorted, indexed
      dict.  */
-  if (!filter_syms)
-    symflags = CTF_SYMTYPETAB_FORCE_INDEXED;
+  if (!s->filter_syms)
+    s->symflags = CTF_SYMTYPETAB_FORCE_INDEXED;
   else
-    hdr.cth_flags |= CTF_F_IDXSORTED;
+    hdr->cth_flags |= CTF_F_IDXSORTED;
 
-  if (!ctf_assert (fp, (filter_syms && symfp)
-		   || (!filter_syms && !symfp
-		       && ((symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0))))
+  if (!ctf_assert (fp, (s->filter_syms && s->symfp)
+		   || (!s->filter_syms && !s->symfp
+		       && ((s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED) != 0))))
     return -1;
 
   /* Work out the sizes of the object and function sections, and work out the
      number of pad (unassigned) symbols in each, and the overall size of the
      sections.  */
 
-  if (symtypetab_density (fp, symfp, fp->ctf_objthash, &nobjts, &maxobjt,
-			  &objt_unpadsize, &objt_padsize, &objtidx_size,
-			  symflags) < 0)
+  if (symtypetab_density (fp, s->symfp, fp->ctf_objthash, &nobjts, &s->maxobjt,
+			  &objt_unpadsize, &objt_padsize, objtidx_size,
+			  s->symflags) < 0)
     return -1;					/* errno is set for us.  */
 
   ctf_dprintf ("Object symtypetab: %i objects, max %i, unpadded size %i, "
-	       "%i bytes of pads, index size %i\n", (int) nobjts, (int) maxobjt,
-	       (int) objt_unpadsize, (int) objt_padsize, (int) objtidx_size);
+	       "%i bytes of pads, index size %i\n", (int) nobjts,
+	       (int) s->maxobjt, (int) objt_unpadsize, (int) objt_padsize,
+	       (int) *objtidx_size);
 
-  if (symtypetab_density (fp, symfp, fp->ctf_funchash, &nfuncs, &maxfunc,
-			  &func_unpadsize, &func_padsize, &funcidx_size,
-			  symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+  if (symtypetab_density (fp, s->symfp, fp->ctf_funchash, &nfuncs, &s->maxfunc,
+			  &func_unpadsize, &func_padsize, funcidx_size,
+			  s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
     return -1;					/* errno is set for us.  */
 
   ctf_dprintf ("Function symtypetab: %i functions, max %i, unpadded size %i, "
-	       "%i bytes of pads, index size %i\n", (int) nfuncs, (int) maxfunc,
-	       (int) func_unpadsize, (int) func_padsize, (int) funcidx_size);
-
-  /* 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.  */
-
-  if (filter_syms && symfp->ctf_dynsyms &&
-      symtypetab_delete_nonstatic_vars (fp, symfp) < 0)
-    return -1;
+	       "%i bytes of pads, index size %i\n", (int) nfuncs,
+	       (int) s->maxfunc, (int) func_unpadsize, (int) func_padsize,
+	       (int) *funcidx_size);
 
   /* It is worth indexing each section if it would save space to do so, due to
      reducing the number of pads sufficiently.  A pad is the same size as a
@@ -701,58 +540,50 @@ ctf_serialize (ctf_dict_t *fp)
      but just an ld -r), we must emit things in indexed fashion just as the
      compiler does.  */
 
-  objt_size = objt_unpadsize;
-  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
+  *objt_size = objt_unpadsize;
+  if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
       && ((objt_padsize + objt_unpadsize) * CTF_INDEX_PAD_THRESHOLD
 	  > objt_padsize))
     {
-      objt_size += objt_padsize;
-      objtidx_size = 0;
+      *objt_size += objt_padsize;
+      *objtidx_size = 0;
     }
 
-  func_size = func_unpadsize;
-  if (!(symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
+  *func_size = func_unpadsize;
+  if (!(s->symflags & CTF_SYMTYPETAB_FORCE_INDEXED)
       && ((func_padsize + func_unpadsize) * CTF_INDEX_PAD_THRESHOLD
 	  > func_padsize))
     {
-      func_size += func_padsize;
-      funcidx_size = 0;
+      *func_size += func_padsize;
+      *funcidx_size = 0;
     }
 
-  /* Computing the number of entries in the CTF variable section is much
-     simpler.  */
+  /* 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.  */
 
-  for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
-       dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
+  if (s->filter_syms && s->symfp->ctf_dynsyms &&
+      symtypetab_delete_nonstatic_vars (fp, s->symfp) < 0)
+    return -1;
 
-  /* Compute the size of the CTF buffer we need, sans only the string table,
-     then allocate a new buffer and memcpy the finished header to the start of
-     the buffer.  (We will adjust this later with strtab length info.)  */
+  return 0;
+}
 
-  hdr.cth_lbloff = hdr.cth_objtoff = 0;
-  hdr.cth_funcoff = hdr.cth_objtoff + objt_size;
-  hdr.cth_objtidxoff = hdr.cth_funcoff + func_size;
-  hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size;
-  hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size;
-  hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
-  hdr.cth_stroff = hdr.cth_typeoff + type_size;
-  hdr.cth_strlen = 0;
+static int
+ctf_emit_symtypetab_sects (ctf_dict_t *fp, emit_symtypetab_state_t *s,
+			   unsigned char **tptr, size_t objt_size,
+			   size_t func_size, size_t objtidx_size,
+			   size_t funcidx_size)
+{
+  unsigned char *t = *tptr;
+  size_t nsymtypes = 0;
+  const char **sym_name_order = NULL;
+  int err;
 
-  buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
-
-  if ((buf = malloc (buf_size)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
-
-  memcpy (buf, &hdr, sizeof (ctf_header_t));
-  t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
-
-  hdrp = (ctf_header_t *) buf;
-  if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
-    ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
-  if (fp->ctf_cuname != NULL)
-    ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
-
-  /* Sort the linker's symbols into name order if need be.  */
+  /* Sort the linker's symbols into name order if need be.  */
 
   if ((objtidx_size != 0) || (funcidx_size != 0))
     {
@@ -760,10 +591,10 @@ ctf_serialize (ctf_dict_t *fp)
       void *symname;
       const char **walk;
 
-      if (filter_syms)
+      if (s->filter_syms)
 	{
-	  if (symfp->ctf_dynsyms)
-	    nsymtypes = ctf_dynhash_elements (symfp->ctf_dynsyms);
+	  if (s->symfp->ctf_dynsyms)
+	    nsymtypes = ctf_dynhash_elements (s->symfp->ctf_dynsyms);
 	  else
 	    nsymtypes = 0;
 	}
@@ -776,11 +607,11 @@ ctf_serialize (ctf_dict_t *fp)
 
       walk = sym_name_order;
 
-      if (filter_syms)
+      if (s->filter_syms)
 	{
-	  if (symfp->ctf_dynsyms)
+	  if (s->symfp->ctf_dynsyms)
 	    {
-	      while ((err = ctf_dynhash_next_sorted (symfp->ctf_dynsyms, &i,
+	      while ((err = ctf_dynhash_next_sorted (s->symfp->ctf_dynsyms, &i,
 						     &symname, NULL,
 						     ctf_dynhash_sort_by_name,
 						     NULL)) == 0)
@@ -795,7 +626,7 @@ ctf_serialize (ctf_dict_t *fp)
 
 	  /* Since we partition the set of symbols back into objt and func,
 	     we can sort the two independently without harm.  */
-	  if (sort_syms)
+	  if (s->sort_syms)
 	    sort_fun = ctf_dynhash_sort_by_name;
 
 	  while ((err = ctf_dynhash_next_sorted (fp->ctf_objthash, &i, &symname,
@@ -816,82 +647,209 @@ ctf_serialize (ctf_dict_t *fp)
      Emission is done in symtab order if there is no index, and in index
      (name) order otherwise.  */
 
-  if ((objtidx_size == 0) && symfp && symfp->ctf_dynsymidx)
+  if ((objtidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx)
     {
       ctf_dprintf ("Emitting unindexed objt symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
-			   NULL, symfp->ctf_dynsymmax + 1, maxobjt, objt_size,
-			   symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0)
+      if (emit_symtypetab (fp, s->symfp, (uint32_t *) t,
+			   s->symfp->ctf_dynsymidx, NULL,
+			   s->symfp->ctf_dynsymmax + 1, s->maxobjt,
+			   objt_size, s->symflags | CTF_SYMTYPETAB_EMIT_PAD) < 0)
 	goto err;				/* errno is set for us.  */
     }
   else
     {
       ctf_dprintf ("Emitting indexed objt symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
-			   nsymtypes, maxobjt, objt_size, symflags) < 0)
+      if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL,
+			   sym_name_order, nsymtypes, s->maxobjt,
+			   objt_size, s->symflags) < 0)
 	goto err;				/* errno is set for us.  */
     }
 
   t += objt_size;
 
-  if ((funcidx_size == 0) && symfp && symfp->ctf_dynsymidx)
+  if ((funcidx_size == 0) && s->symfp && s->symfp->ctf_dynsymidx)
     {
       ctf_dprintf ("Emitting unindexed func symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, symfp->ctf_dynsymidx,
-			   NULL, symfp->ctf_dynsymmax + 1, maxfunc,
-			   func_size, symflags | CTF_SYMTYPETAB_EMIT_FUNCTION
+      if (emit_symtypetab (fp, s->symfp, (uint32_t *) t,
+			   s->symfp->ctf_dynsymidx, NULL,
+			   s->symfp->ctf_dynsymmax + 1, s->maxfunc,
+			   func_size, s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION
 			   | CTF_SYMTYPETAB_EMIT_PAD) < 0)
 	goto err;				/* errno is set for us.  */
     }
   else
     {
       ctf_dprintf ("Emitting indexed func symtypetab\n");
-      if (emit_symtypetab (fp, symfp, (uint32_t *) t, NULL, sym_name_order,
-			   nsymtypes, maxfunc, func_size,
-			   symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+      if (emit_symtypetab (fp, s->symfp, (uint32_t *) t, NULL, sym_name_order,
+			   nsymtypes, s->maxfunc, func_size,
+			   s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
 	goto err;				/* errno is set for us.  */
     }
 
   t += func_size;
 
   if (objtidx_size > 0)
-    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
-			       nsymtypes, objtidx_size, symflags) < 0)
+    if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order,
+			       nsymtypes, objtidx_size, s->symflags) < 0)
       goto err;
 
   t += objtidx_size;
 
   if (funcidx_size > 0)
-    if (emit_symtypetab_index (fp, symfp, (uint32_t *) t, sym_name_order,
+    if (emit_symtypetab_index (fp, s->symfp, (uint32_t *) t, sym_name_order,
 			       nsymtypes, funcidx_size,
-			       symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
+			       s->symflags | CTF_SYMTYPETAB_EMIT_FUNCTION) < 0)
       goto err;
 
   t += funcidx_size;
   free (sym_name_order);
-  sym_name_order = NULL;
+  *tptr = t;
 
-  /* Work over the variable list, translating everything into ctf_varent_t's and
-     prepping the string table.  */
+  return 0;
 
-  dvarents = (ctf_varent_t *) t;
-  for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
-       dvd = ctf_list_next (dvd), i++)
+ oom:
+  ctf_set_errno (fp, EAGAIN);
+  goto err;
+symerr:
+  ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
+ err:
+  free (sym_name_order);
+  return -1;
+}
+
+/* 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_varent_t *var = &dvarents[i];
+      ctf_member_t *copied;
 
-      ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name);
-      var->ctv_type = (uint32_t) dvd->dvd_type;
+      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);
     }
-  assert (i == nvars);
 
-  t += sizeof (ctf_varent_t) * nvars;
+  return t;
+}
 
-  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
+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.  */
+
+static size_t
+ctf_type_sect_size (ctf_dict_t *fp)
+{
+  ctf_dtdef_t *dtd;
+  size_t type_size;
+
+  for (type_size = 0, dtd = ctf_list_next (&fp->ctf_dtdefs);
+       dtd != NULL; dtd = ctf_list_next (dtd))
+    {
+      uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+      uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+
+      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+	type_size += sizeof (ctf_stype_t);
+      else
+	type_size += sizeof (ctf_type_t);
+
+      switch (kind)
+	{
+	case CTF_K_INTEGER:
+	case CTF_K_FLOAT:
+	  type_size += sizeof (uint32_t);
+	  break;
+	case CTF_K_ARRAY:
+	  type_size += sizeof (ctf_array_t);
+	  break;
+	case CTF_K_SLICE:
+	  type_size += sizeof (ctf_slice_t);
+	  break;
+	case CTF_K_FUNCTION:
+	  type_size += sizeof (uint32_t) * (vlen + (vlen & 1));
+	  break;
+	case CTF_K_STRUCT:
+	case CTF_K_UNION:
+	  if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH)
+	    type_size += sizeof (ctf_member_t) * vlen;
+	  else
+	    type_size += sizeof (ctf_lmember_t) * vlen;
+	  break;
+	case CTF_K_ENUM:
+	  type_size += sizeof (ctf_enum_t) * vlen;
+	  break;
+	}
+    }
 
-  /* We now take a final lap through the dynamic type definition list and copy
-     the appropriate type records to the output buffer, noting down the
-     strings as we go.  */
+  return type_size;
+}
+
+/* Take a final lap through the dynamic type definition list and copy the
+   appropriate type records to the output buffer, noting down the strings as
+   we go.  */
+
+static void
+ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
+{
+  unsigned char *t = *tptr;
+  ctf_dtdef_t *dtd;
 
   for (dtd = ctf_list_next (&fp->ctf_dtdefs);
        dtd != NULL; dtd = ctf_list_next (dtd))
@@ -978,6 +936,147 @@ ctf_serialize (ctf_dict_t *fp)
 	  break;
 	}
     }
+
+  *tptr = t;
+}
+
+/* Variable section.  */
+
+/* Sort a newly-constructed static variable array.  */
+
+typedef struct ctf_sort_var_arg_cb
+{
+  ctf_dict_t *fp;
+  ctf_strs_t *strtab;
+} ctf_sort_var_arg_cb_t;
+
+static int
+ctf_sort_var (const void *one_, const void *two_, void *arg_)
+{
+  const ctf_varent_t *one = one_;
+  const ctf_varent_t *two = two_;
+  ctf_sort_var_arg_cb_t *arg = arg_;
+
+  return (strcmp (ctf_strraw_explicit (arg->fp, one->ctv_name, arg->strtab),
+		  ctf_strraw_explicit (arg->fp, two->ctv_name, arg->strtab)));
+}
+
+/* Overall serialization.  */
+
+/* If the specified CTF dict is writable and has been modified, reload this dict
+   with the updated type definitions, ready for serialization.  In order to make
+   this code and the rest of libctf as simple as possible, we perform updates by
+   taking the dynamic type definitions and creating an in-memory CTF dict
+   containing the definitions, and then call ctf_simple_open_internal() on it.
+   We perform one extra trick here for the benefit of callers and to keep our
+   code simple: ctf_simple_open_internal() will return a new ctf_dict_t, but we
+   want to keep the fp constant for the caller, so after
+   ctf_simple_open_internal() returns, we use memcpy to swap the interior of the
+   old and new ctf_dict_t's, and then free the old.  */
+int
+ctf_serialize (ctf_dict_t *fp)
+{
+  ctf_dict_t ofp, *nfp;
+  ctf_header_t hdr, *hdrp;
+  ctf_dvdef_t *dvd;
+  ctf_varent_t *dvarents;
+  ctf_strs_writable_t strtab;
+  int err;
+
+  unsigned char *t;
+  unsigned long i;
+  size_t buf_size, type_size, objt_size, func_size;
+  size_t funcidx_size, objtidx_size;
+  size_t nvars;
+  unsigned char *buf = NULL, *newbuf;
+
+  emit_symtypetab_state_t symstate;
+  memset (&symstate, 0, sizeof (emit_symtypetab_state_t));
+
+  if (!(fp->ctf_flags & LCTF_RDWR))
+    return (ctf_set_errno (fp, ECTF_RDONLY));
+
+  /* Update required?  */
+  if (!(fp->ctf_flags & LCTF_DIRTY))
+    return 0;
+
+  /* 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
+     boundary past the CTF header itself (at relative offset zero).  The flag
+     indicating a new-style function info section (an array of CTF_K_FUNCTION
+     type IDs in the types section) is flipped on.  */
+
+  memset (&hdr, 0, sizeof (hdr));
+  hdr.cth_magic = CTF_MAGIC;
+  hdr.cth_version = CTF_VERSION;
+
+  /* This is a new-format func info section, and the symtab and strtab come out
+     of the dynsym and dynstr these days.  */
+  hdr.cth_flags = (CTF_F_NEWFUNCINFO | CTF_F_DYNSTR);
+
+  if (ctf_symtypetab_sect_sizes (fp, &symstate, &hdr, &objt_size, &func_size,
+				 &objtidx_size, &funcidx_size) < 0)
+    return -1;					/* errno is set for us.  */
+
+  for (nvars = 0, dvd = ctf_list_next (&fp->ctf_dvdefs);
+       dvd != NULL; dvd = ctf_list_next (dvd), nvars++);
+
+  type_size = ctf_type_sect_size (fp);
+
+  /* Compute the size of the CTF buffer we need, sans only the string table,
+     then allocate a new buffer and memcpy the finished header to the start of
+     the buffer.  (We will adjust this later with strtab length info.)  */
+
+  hdr.cth_lbloff = hdr.cth_objtoff = 0;
+  hdr.cth_funcoff = hdr.cth_objtoff + objt_size;
+  hdr.cth_objtidxoff = hdr.cth_funcoff + func_size;
+  hdr.cth_funcidxoff = hdr.cth_objtidxoff + objtidx_size;
+  hdr.cth_varoff = hdr.cth_funcidxoff + funcidx_size;
+  hdr.cth_typeoff = hdr.cth_varoff + (nvars * sizeof (ctf_varent_t));
+  hdr.cth_stroff = hdr.cth_typeoff + type_size;
+  hdr.cth_strlen = 0;
+
+  buf_size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen;
+
+  if ((buf = malloc (buf_size)) == NULL)
+    return (ctf_set_errno (fp, EAGAIN));
+
+  memcpy (buf, &hdr, sizeof (ctf_header_t));
+  t = (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_objtoff;
+
+  hdrp = (ctf_header_t *) buf;
+  if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parname != NULL))
+    ctf_str_add_ref (fp, fp->ctf_parname, &hdrp->cth_parname);
+  if (fp->ctf_cuname != NULL)
+    ctf_str_add_ref (fp, fp->ctf_cuname, &hdrp->cth_cuname);
+
+  if (ctf_emit_symtypetab_sects (fp, &symstate, &t, objt_size, func_size,
+				 objtidx_size, funcidx_size) < 0)
+    goto err;
+
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_varoff);
+
+  /* Work over the variable list, translating everything into ctf_varent_t's and
+     prepping the string table.  */
+
+  dvarents = (ctf_varent_t *) t;
+  for (i = 0, dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL;
+       dvd = ctf_list_next (dvd), i++)
+    {
+      ctf_varent_t *var = &dvarents[i];
+
+      ctf_str_add_ref (fp, dvd->dvd_name, &var->ctv_name);
+      var->ctv_type = (uint32_t) dvd->dvd_type;
+    }
+  assert (i == nvars);
+
+  t += sizeof (ctf_varent_t) * nvars;
+
+  assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_typeoff);
+
+  ctf_emit_type_sect (fp, &t);
+
   assert (t == (unsigned char *) buf + sizeof (ctf_header_t) + hdr.cth_stroff);
 
   /* Construct the final string table and fill out all the string refs with the
@@ -1125,19 +1224,15 @@ ctf_serialize (ctf_dict_t *fp)
 
   return 0;
 
-symerr:
-  ctf_err_warn (fp, 0, err, _("error serializing symtypetabs"));
-  goto err;
 oom:
   free (buf);
-  free (sym_name_order);
   return (ctf_set_errno (fp, EAGAIN));
 err:
   free (buf);
-  free (sym_name_order);
   return -1;					/* errno is set for us.  */
 }
 
+/* File writing.  */
 
 /* Write the compressed CTF data stream to the specified gzFile descriptor.  */
 int
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 05/16] libctf: fix GNU style for do {} while
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (3 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 04/16] libctf: split up ctf_serialize Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 06/16] libctf: eliminate dtd_u, part 1: int/float/slice Nick Alcock
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

It's formatted like this:

do
  {
    ...
  }
while (...);

Not like this:

do
 {
    ...
  } while (...);

or this:

do {
  ...
} while (...);

We used both in various places in libctf.  Fixing it necessitated some
light reindentation.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-archive.c (ctf_archive_next): GNU style fix for do {} while.
	* ctf-dedup.c (ctf_dedup_rhash_type): Likewise.
	(ctf_dedup_rwalk_one_output_mapping): Likewise.
	* ctf-dump.c (ctf_dump_format_type): Likewise.
	* ctf-lookup.c (ctf_symbol_next): Likewise.
	* swap.h (swap_thing): Likewise.
---
 libctf/ctf-archive.c |  3 +-
 libctf/ctf-dedup.c   | 67 +++++++++++++++++++++++---------------------
 libctf/ctf-dump.c    |  3 +-
 libctf/ctf-lookup.c  |  3 +-
 libctf/swap.h        | 24 ++++++++--------
 5 files changed, 54 insertions(+), 46 deletions(-)

diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index 8b8e170241f..e0ceb80fa11 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -1156,7 +1156,8 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
 
       name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
       i->ctn_n++;
-    } while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
+    }
+  while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
 
   if (name)
     *name = name_;
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index ef8507a59f2..9f5ba903ec4 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -589,7 +589,8 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	  goto oom;							\
       if (ctf_dynset_cinsert (citers, hval) < 0)			\
 	goto oom;							\
-    } while (0)
+    }									\
+  while (0)
 
   /* If this is a named struct or union or a forward to one, and this is a child
      traversal, treat this type as if it were a forward -- do not recurse to
@@ -2029,42 +2030,44 @@ ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
      times, which is worse.  */
 
 #define CTF_TYPE_WALK(type, errlabel, errmsg)				\
-  do {									\
-    void *type_id;							\
-    const char *hashval;						\
-    int cited_type_input_num = input_num;				\
+  do									\
+    {									\
+      void *type_id;							\
+      const char *hashval;						\
+      int cited_type_input_num = input_num;				\
 									\
-    if ((fp->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (fp, type))) \
-      cited_type_input_num = parents[input_num];			\
+      if ((fp->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (fp, type))) \
+	cited_type_input_num = parents[input_num];			\
 									\
-    type_id = CTF_DEDUP_GID (output, cited_type_input_num, type);	\
+      type_id = CTF_DEDUP_GID (output, cited_type_input_num, type);	\
 									\
-    if (type == 0)							\
-      {									\
-	ctf_dprintf ("Walking: unimplemented type\n");			\
-	break;								\
-      }									\
+      if (type == 0)							\
+	{								\
+	  ctf_dprintf ("Walking: unimplemented type\n");		\
+	  break;							\
+	}								\
 									\
-    ctf_dprintf ("Looking up ID %i/%lx in type hashes\n",		\
-		 cited_type_input_num, type);				\
-    hashval = ctf_dynhash_lookup (d->cd_type_hashes, type_id);		\
-    if (!ctf_assert (output, hashval))					\
-      {									\
-	whaterr = N_("error looking up ID in type hashes");		\
-	goto errlabel;							\
-      }									\
-    ctf_dprintf ("ID %i/%lx has hash %s\n", cited_type_input_num, type,	\
-		 hashval);						\
+      ctf_dprintf ("Looking up ID %i/%lx in type hashes\n",		\
+		   cited_type_input_num, type);				\
+      hashval = ctf_dynhash_lookup (d->cd_type_hashes, type_id);	\
+      if (!ctf_assert (output, hashval))				\
+	{								\
+	  whaterr = N_("error looking up ID in type hashes");		\
+	  goto errlabel;						\
+	}								\
+      ctf_dprintf ("ID %i/%lx has hash %s\n", cited_type_input_num, type, \
+		   hashval);						\
 									\
-    ret = ctf_dedup_rwalk_output_mapping (output, inputs, ninputs, parents, \
-					  already_visited, hashval,	\
-					  visit_fun, arg, depth);	\
-    if (ret < 0)							\
-      {									\
-	whaterr = errmsg;						\
-	goto errlabel;							\
-      }									\
-  } while (0)
+      ret = ctf_dedup_rwalk_output_mapping (output, inputs, ninputs, parents, \
+					    already_visited, hashval,	\
+					    visit_fun, arg, depth);	\
+      if (ret < 0)							\
+	{								\
+	  whaterr = errmsg;						\
+	  goto errlabel;						\
+	}								\
+    }									\
+  while (0)
 
   switch (ctf_type_kind_unsliced (fp, type))
     {
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 788355d9db1..409626a224b 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -220,7 +220,8 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
 	new_id = ctf_type_reference (fp, id);
       if (new_id != CTF_ERR)
 	str = str_append (str, " -> ");
-    } while (new_id != CTF_ERR);
+    }
+  while (new_id != CTF_ERR);
 
   if (ctf_errno (fp) != ECTF_NOTREF)
     {
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 2e78cf49276..9d1e6d8a4a2 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -723,7 +723,8 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 
 	  *name = ctf_strptr (fp, idx[i->ctn_n]);
 	  sym = tab[i->ctn_n++];
-	} while (sym == -1u || sym == 0);
+	}
+      while (sym == -1u || sym == 0);
     }
   else
     {
diff --git a/libctf/swap.h b/libctf/swap.h
index d7cc9936cea..4d0b48c9e75 100644
--- a/libctf/swap.h
+++ b/libctf/swap.h
@@ -73,18 +73,20 @@ bswap_64 (uint64_t v)
 /* Swap the endianness of something.  */
 
 #define swap_thing(x)							\
-  do {									\
-    _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0		\
-					&& sizeof (x) <= 8),		\
-		    "Invalid size, update endianness code");		\
-    switch (sizeof (x)) {						\
-    case 2: x = bswap_16 (x); break;					\
-    case 4: x = bswap_32 (x); break;					\
-    case 8: x = bswap_64 (x); break;					\
-    case 1: /* Nothing needs doing */					\
-      break;								\
+  do									\
+    {									\
+      _Static_assert (sizeof (x) == 1 || (sizeof (x) % 2 == 0		\
+					  && sizeof (x) <= 8),		\
+		      "Invalid size, update endianness code");		\
+      switch (sizeof (x)) {						\
+      case 2: x = bswap_16 (x); break;					\
+      case 4: x = bswap_32 (x); break;					\
+      case 8: x = bswap_64 (x); break;					\
+      case 1: /* Nothing needs doing */					\
+	break;								\
+      }									\
     }									\
-  } while (0);
+  while (0);
 
 
 #endif /* !defined(_CTF_SWAP_H) */
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 06/16] libctf: eliminate dtd_u, part 1: int/float/slice
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (4 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 05/16] libctf: fix GNU style for do {} while Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 07/16] libctf: eliminate dtd_u, part 2: arrays Nick Alcock
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This series eliminates a lot of special-case code to handle dynamic
types (types added to writable dicts and not yet serialized).

Historically, when such types have variable-length data in their final
CTF representations, libctf has always worked by adding such types to a
special union (ctf_dtdef_t.dtd_u) in the dynamic type definition
structure, then picking the members out of this structure at
serialization time and packing them into their final form.

This has the advantage that the ctf_add_* code doesn't need to know
anything about the final CTF representation, but the significant
disadvantage that all code that looks up types in any way needs two code
paths, one for dynamic types, one for all others.  Historically libctf
"handled" this by not supporting most type lookups on dynamic types at
all until ctf_update was called to do a complete reserialization of the
entire dict (it didn't emit an error, it just emitted wrong results).
Since commit 676c3ecbad6e9c4, which eliminated ctf_update in favour of
the internal-only ctf_serialize function, all the type-lookuup paths
grew an extra branch to handle dynamic types.

We can eliminate this branch again by droppoing the dtd_u stuff and
simply writing out the vlen in (close to) its final form at ctf_add_*
time: type lookup for types using this approach is then identical for
types in writable dicts and types that are in read-only ones, and
serialization is also simplified (we just need to write out the vlen
we already created).

The only complexity lies in type kinds for which multiple
vlen representations are valid depending on properties of the type,
e.g. structures.  But we can start simple, adjusting ints, floats,
and slices to work this way, and leaving everything else as is.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtd_u.dtu_enc>: Remove.
	<dtd_u.dtu_slice>: Likewise.
	<dtd_vlen>: New.
	* ctf-create.c (ctf_add_generic): Perhaps allocate it.  All
	callers adjusted.
	(ctf_dtd_delete): Free it.
	(ctf_add_slice): Use the dtd_vlen, not dtu_enc.
	(ctf_add_encoded): Likewise.  Assert that this must be an int or
	float.
	* ctf-serialize.c (ctf_emit_type_sect): Just copy the dtd_vlen.
	* ctf-dedup.c (ctf_dedup_rhash_type): Use the dtd_vlen, not
	dtu_slice.
	* ctf-types.c (ctf_type_reference): Likewise.
	(ctf_type_encoding): Remove most dynamic-type-specific code: just
	get the vlen from the right place.  Report failure to look up the
	underlying type's encoding.
---
 libctf/ctf-create.c    | 84 ++++++++++++++++++++++++++++--------------
 libctf/ctf-dedup.c     |  2 +-
 libctf/ctf-impl.h      |  3 +-
 libctf/ctf-serialize.c | 19 ++--------
 libctf/ctf-types.c     | 43 ++++++---------------
 5 files changed, 73 insertions(+), 78 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index b2e08623f22..90db7121af6 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -226,6 +226,7 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
   const char *name;
 
   ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
+  free (dtd->dtd_vlen);
 
   switch (kind)
     {
@@ -406,7 +407,7 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
 
 static ctf_id_t
 ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
-		 ctf_dtdef_t **rp)
+		 size_t vlen, ctf_dtdef_t **rp)
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type;
@@ -425,33 +426,42 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
 
   /* Make sure ptrtab always grows to be big enough for all types.  */
   if (ctf_grow_ptrtab (fp) < 0)
-      return CTF_ERR;		/* errno is set for us. */
+      return CTF_ERR;				/* errno is set for us. */
 
-  if ((dtd = malloc (sizeof (ctf_dtdef_t))) == NULL)
+  if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
 
+  if (vlen > 0)
+    {
+      if ((dtd->dtd_vlen = calloc (1, vlen)) == NULL)
+	goto oom;
+    }
+  else
+    dtd->dtd_vlen = NULL;
+
   type = ++fp->ctf_typemax;
   type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD));
 
-  memset (dtd, 0, sizeof (ctf_dtdef_t));
   dtd->dtd_data.ctt_name = ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name);
   dtd->dtd_type = type;
 
   if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')
-    {
-      free (dtd);
-      return (ctf_set_errno (fp, EAGAIN));
-    }
+    goto oom;
 
   if (ctf_dtd_insert (fp, dtd, flag, kind) < 0)
-    {
-      free (dtd);
-      return CTF_ERR;			/* errno is set for us.  */
-    }
+    goto err;					/* errno is set for us.  */
+
   fp->ctf_flags |= LCTF_DIRTY;
 
   *rp = dtd;
   return type;
+
+ oom:
+  ctf_set_errno (fp, EAGAIN);
+ err:
+  free (dtd->dtd_vlen);
+  free (dtd);
+  return CTF_ERR;
 }
 
 /* When encoding integer sizes, we want to convert a byte count in the range
@@ -477,6 +487,7 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type;
+  uint32_t encoding;
 
   if (ep == NULL)
     return (ctf_set_errno (fp, EINVAL));
@@ -484,13 +495,26 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
   if (name == NULL || name[0] == '\0')
     return (ctf_set_errno (fp, ECTF_NONAME));
 
-  if ((type = ctf_add_generic (fp, flag, name, kind, &dtd)) == CTF_ERR)
+  if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
+    return -1;					/* errno is set for us.  */
+
+  if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
+			       &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
   dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, CHAR_BIT)
 				 / CHAR_BIT);
-  dtd->dtd_u.dtu_enc = *ep;
+  switch (kind)
+    {
+    case CTF_K_INTEGER:
+      encoding = CTF_INT_DATA (ep->cte_format, ep->cte_offset, ep->cte_bits);
+      break;
+    case CTF_K_FLOAT:
+      encoding = CTF_FP_DATA (ep->cte_format, ep->cte_offset, ep->cte_bits);
+      break;
+    }
+  memcpy (dtd->dtd_vlen, &encoding, sizeof (encoding));
 
   return type;
 }
@@ -509,7 +533,7 @@ ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
   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)
+  if ((type = ctf_add_generic (fp, flag, NULL, kind, 0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
@@ -539,6 +563,7 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
 	       const ctf_encoding_t *ep)
 {
   ctf_dtdef_t *dtd;
+  ctf_slice_t slice;
   ctf_id_t resolved_ref = ref;
   ctf_id_t type;
   int kind;
@@ -569,15 +594,19 @@ ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
       && (ref != 0))
     return (ctf_set_errno (fp, ECTF_NOTINTFP));
 
-  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE, &dtd)) == CTF_ERR)
+  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
+			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
+  memset (&slice, 0, sizeof (ctf_slice_t));
+
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
   dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, CHAR_BIT)
 				 / CHAR_BIT);
-  dtd->dtd_u.dtu_slice.cts_type = (uint32_t) ref;
-  dtd->dtd_u.dtu_slice.cts_bits = ep->cte_bits;
-  dtd->dtd_u.dtu_slice.cts_offset = ep->cte_offset;
+  slice.cts_type = (uint32_t) ref;
+  slice.cts_bits = ep->cte_bits;
+  slice.cts_offset = ep->cte_offset;
+  memcpy (dtd->dtd_vlen, &slice, sizeof (ctf_slice_t));
 
   return type;
 }
@@ -628,7 +657,8 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
       return (ctf_set_errno (fp, ECTF_INCOMPLETE));
     }
 
-  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY, &dtd)) == CTF_ERR)
+  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
+			       0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
@@ -700,7 +730,7 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
-			       &dtd)) == CTF_ERR)
+			       0, &dtd)) == CTF_ERR)
     {
       free (vdat);
       return CTF_ERR;		   /* errno is set for us.  */
@@ -730,7 +760,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_STRUCT,
-				    &dtd)) == CTF_ERR)
+				    0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
@@ -767,7 +797,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNION,
-				    &dtd)) == CTF_ERR)
+				    0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
@@ -803,7 +833,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM,
-				    &dtd)) == CTF_ERR)
+				    0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
@@ -861,7 +891,7 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type)
     return type;
 
-  if ((type = ctf_add_generic (fp, flag, name, kind, &dtd)) == CTF_ERR)
+  if ((type = ctf_add_generic (fp, flag, name, kind, 0, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
@@ -887,7 +917,7 @@ ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
   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,
+  if ((type = ctf_add_generic (fp, flag, name, CTF_K_TYPEDEF, 0,
 			       &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
@@ -1783,7 +1813,7 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	   manually so as to avoid repeated lookups in ctf_add_member
 	   and to ensure the exact same member offsets as in src_type.  */
 
-	dst_type = ctf_add_generic (dst_fp, flag, name, kind, &dtd);
+	dst_type = ctf_add_generic (dst_fp, flag, name, kind, 0, &dtd);
 	if (dst_type == CTF_ERR)
 	  return CTF_ERR;			/* errno is set for us.  */
 
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 9f5ba903ec4..b8a7d49b9db 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -752,7 +752,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	citer = hval;
 
 	if ((dtd = ctf_dynamic_type (input, type)) != NULL)
-	  slice = &dtd->dtd_u.dtu_slice;
+	  slice = (ctf_slice_t *) dtd->dtd_vlen;
 	else
 	  slice = (ctf_slice_t *) ((uintptr_t) tp + increment);
 
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 5567b4c61f5..742b4b37aff 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -192,13 +192,12 @@ typedef struct ctf_dtdef
   ctf_list_t dtd_list;		/* List forward/back pointers.  */
   ctf_id_t dtd_type;		/* Type identifier for this definition.  */
   ctf_type_t dtd_data;		/* Type node, including name.  */
+  unsigned char *dtd_vlen;	/* Variable-length data for this type.  */
   union
   {
     ctf_list_t dtu_members;	/* struct, union, or enum */
     ctf_arinfo_t dtu_arr;	/* array */
-    ctf_encoding_t dtu_enc;	/* integer or float */
     uint32_t *dtu_argv;		/* function */
-    ctf_slice_t dtu_slice;	/* slice */
   } dtd_u;
 } ctf_dtdef_t;
 
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 1e2c98b473a..f07cb61c42a 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -858,7 +858,6 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
       uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
 
       ctf_array_t cta;
-      uint32_t encoding;
       size_t len;
       ctf_stype_t *copied;
       const char *name;
@@ -879,24 +878,12 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	{
 	case CTF_K_INTEGER:
 	case CTF_K_FLOAT:
-	  if (kind == CTF_K_INTEGER)
-	    {
-	      encoding = CTF_INT_DATA (dtd->dtd_u.dtu_enc.cte_format,
-				       dtd->dtd_u.dtu_enc.cte_offset,
-				       dtd->dtd_u.dtu_enc.cte_bits);
-	    }
-	  else
-	    {
-	      encoding = CTF_FP_DATA (dtd->dtd_u.dtu_enc.cte_format,
-				      dtd->dtd_u.dtu_enc.cte_offset,
-				      dtd->dtd_u.dtu_enc.cte_bits);
-	    }
-	  memcpy (t, &encoding, sizeof (encoding));
-	  t += sizeof (encoding);
+	  memcpy (t, dtd->dtd_vlen, sizeof (uint32_t));
+	  t += sizeof (uint32_t);
 	  break;
 
 	case CTF_K_SLICE:
-	  memcpy (t, &dtd->dtd_u.dtu_slice, sizeof (struct ctf_slice));
+	  memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_slice));
 	  t += sizeof (struct ctf_slice);
 	  break;
 
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 28c5c7aa1e1..ae243817713 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -1168,7 +1168,7 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
 	    sp = (const ctf_slice_t *) ((uintptr_t) tp + increment);
 	  }
 	else
-	  sp = &dtd->dtd_u.dtu_slice;
+	  sp = (const ctf_slice_t *) dtd->dtd_vlen;
 
 	return sp->cts_type;
       }
@@ -1218,52 +1218,30 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
   ctf_dtdef_t *dtd;
   const ctf_type_t *tp;
   ssize_t increment;
+  const unsigned char *vlen;
   uint32_t data;
 
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
     return -1;			/* errno is set for us.  */
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+    vlen = dtd->dtd_vlen;
+  else
     {
-      switch (LCTF_INFO_KIND (fp, tp->ctt_info))
-	{
-	case CTF_K_INTEGER:
-	case CTF_K_FLOAT:
-	  *ep = dtd->dtd_u.dtu_enc;
-	  break;
-	case CTF_K_SLICE:
-	  {
-	    const ctf_slice_t *slice;
-	    ctf_encoding_t underlying_en;
-	    ctf_id_t underlying;
-
-	    slice = &dtd->dtd_u.dtu_slice;
-	    underlying = ctf_type_resolve (fp, slice->cts_type);
-	    data = ctf_type_encoding (fp, underlying, &underlying_en);
-
-	    ep->cte_format = underlying_en.cte_format;
-	    ep->cte_offset = slice->cts_offset;
-	    ep->cte_bits = slice->cts_bits;
-	    break;
-	  }
-	default:
-	  return (ctf_set_errno (ofp, ECTF_NOTINTFP));
-	}
-      return 0;
+      ctf_get_ctt_size (fp, tp, NULL, &increment);
+      vlen = (const unsigned char *) ((uintptr_t) tp + increment);
     }
 
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
-
   switch (LCTF_INFO_KIND (fp, tp->ctt_info))
     {
     case CTF_K_INTEGER:
-      data = *(const uint32_t *) ((uintptr_t) tp + increment);
+      data = *(const uint32_t *) vlen;
       ep->cte_format = CTF_INT_ENCODING (data);
       ep->cte_offset = CTF_INT_OFFSET (data);
       ep->cte_bits = CTF_INT_BITS (data);
       break;
     case CTF_K_FLOAT:
-      data = *(const uint32_t *) ((uintptr_t) tp + increment);
+      data = *(const uint32_t *) vlen;
       ep->cte_format = CTF_FP_ENCODING (data);
       ep->cte_offset = CTF_FP_OFFSET (data);
       ep->cte_bits = CTF_FP_BITS (data);
@@ -1274,9 +1252,10 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
 	ctf_encoding_t underlying_en;
 	ctf_id_t underlying;
 
-	slice = (ctf_slice_t *) ((uintptr_t) tp + increment);
+	slice = (ctf_slice_t *) vlen;
 	underlying = ctf_type_resolve (fp, slice->cts_type);
-	data = ctf_type_encoding (fp, underlying, &underlying_en);
+	if (ctf_type_encoding (fp, underlying, &underlying_en) < 0)
+	  return -1;				/* errno is set for us.  */
 
 	ep->cte_format = underlying_en.cte_format;
 	ep->cte_offset = slice->cts_offset;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 07/16] libctf: eliminate dtd_u, part 2: arrays
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (5 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 06/16] libctf: eliminate dtd_u, part 1: int/float/slice Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 08/16] libctf: eliminate dtd_u, part 3: functions Nick Alcock
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This is even simpler than ints, floats and slices, with the only extra
complication being the need to manually transfer the array parameter in
the rarely-used function ctf_set_array.  (Arrays are unique in libctf in
that they can be modified post facto, not just created and appended to.
I'm not sure why they got this exemption, but it's easy to maintain.)

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtd_u.dtu_arr>: Remove.
	* ctf-create.c (ctf_add_array): Use the dtd_vlen, not dtu_arr.
	(ctf_set_array): Likewise.
	* ctf-serialize.c (ctf_emit_type_sect): Just copy the dtd_vlen.
	* ctf-types.c (ctf_array_info): Just use the vlen.
---
 libctf/ctf-create.c    | 16 +++++++++++++---
 libctf/ctf-impl.h      |  1 -
 libctf/ctf-serialize.c |  8 ++------
 libctf/ctf-types.c     | 10 ++++------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 90db7121af6..bc46cfa6ca8 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -635,6 +635,7 @@ ctf_id_t
 ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
 {
   ctf_dtdef_t *dtd;
+  ctf_array_t cta;
   ctf_id_t type;
   ctf_dict_t *tmp = fp;
 
@@ -658,12 +659,17 @@ ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
     }
 
   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
-			       0, &dtd)) == CTF_ERR)
+			       sizeof (ctf_array_t), &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
+  memset (&cta, 0, sizeof (ctf_array_t));
+
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
   dtd->dtd_data.ctt_size = 0;
-  dtd->dtd_u.dtu_arr = *arp;
+  cta.cta_contents = (uint32_t) arp->ctr_contents;
+  cta.cta_index = (uint32_t) arp->ctr_index;
+  cta.cta_nelems = arp->ctr_nelems;
+  memcpy (dtd->dtd_vlen, &cta, sizeof (ctf_array_t));
 
   return type;
 }
@@ -672,6 +678,7 @@ int
 ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
 {
   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
+  ctf_array_t *vlen;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     return (ctf_set_errno (fp, ECTF_RDONLY));
@@ -680,8 +687,11 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
     return (ctf_set_errno (fp, ECTF_BADID));
 
+  vlen = (ctf_array_t *) dtd->dtd_vlen;
   fp->ctf_flags |= LCTF_DIRTY;
-  dtd->dtd_u.dtu_arr = *arp;
+  vlen->cta_contents = (uint32_t) arp->ctr_contents;
+  vlen->cta_index = (uint32_t) arp->ctr_index;
+  vlen->cta_nelems = arp->ctr_nelems;
 
   return 0;
 }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 742b4b37aff..c1ce50bc3b9 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -196,7 +196,6 @@ typedef struct ctf_dtdef
   union
   {
     ctf_list_t dtu_members;	/* struct, union, or enum */
-    ctf_arinfo_t dtu_arr;	/* array */
     uint32_t *dtu_argv;		/* function */
   } dtd_u;
 } ctf_dtdef_t;
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index f07cb61c42a..d8e78f361f4 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -857,7 +857,6 @@ 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);
 
-      ctf_array_t cta;
       size_t len;
       ctf_stype_t *copied;
       const char *name;
@@ -888,11 +887,8 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	  break;
 
 	case CTF_K_ARRAY:
-	  cta.cta_contents = (uint32_t) dtd->dtd_u.dtu_arr.ctr_contents;
-	  cta.cta_index = (uint32_t) dtd->dtd_u.dtu_arr.ctr_index;
-	  cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems;
-	  memcpy (t, &cta, sizeof (cta));
-	  t += sizeof (cta);
+	  memcpy (t, dtd->dtd_vlen, sizeof (struct ctf_array));
+	  t += sizeof (struct ctf_array);
 	  break;
 
 	case CTF_K_FUNCTION:
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index ae243817713..8c983d5542f 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -1520,14 +1520,12 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
     return (ctf_set_errno (ofp, ECTF_NOTARRAY));
 
   if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+    ap = (const ctf_array_t *) dtd->dtd_vlen;
+  else
     {
-      *arp = dtd->dtd_u.dtu_arr;
-      return 0;
+      ctf_get_ctt_size (fp, tp, NULL, &increment);
+      ap = (const ctf_array_t *) ((uintptr_t) tp + increment);
     }
-
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
-
-  ap = (const ctf_array_t *) ((uintptr_t) tp + increment);
   arp->ctr_contents = ap->cta_contents;
   arp->ctr_index = ap->cta_index;
   arp->ctr_nelems = ap->cta_nelems;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 08/16] libctf: eliminate dtd_u, part 3: functions
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (6 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 07/16] libctf: eliminate dtd_u, part 2: arrays Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd Nick Alcock
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

One more member vanishes from the dtd_u, leaving only the member for
struct/union/enum members.

There's not much to do here, since as of commit afd78bd6f0a30ba5 we use
the same representation (type sizes, etc) in the dtu_argv as we will
use in the final vlen, with one exception: the vlen has alignment
padding, and the dtu_argv did not.  Simplify things by adding suitable
padding in both cases.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtd_u.dtu_argv>: Remove.
	* ctf-create.c (ctf_dtd_delete): No longer free it.
	(ctf_add_function): Use the dtd_vlen, not dtu_argv.  Properly align.
	* ctf-serialize.c (ctf_emit_type_sect): Just copy the dtd_vlen.
	* ctf-types.c (ctf_func_type_info): Just use the vlen.
	(ctf_func_type_args): Likewise.
---
 libctf/ctf-create.c    | 33 ++++++++++++++-------------------
 libctf/ctf-impl.h      |  1 -
 libctf/ctf-serialize.c | 16 +++-------------
 libctf/ctf-types.c     |  4 ++--
 4 files changed, 19 insertions(+), 35 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index bc46cfa6ca8..6acc2428cd7 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -242,9 +242,6 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
 	  free (dmd);
 	}
       break;
-    case CTF_K_FUNCTION:
-      free (dtd->dtd_u.dtu_argv);
-      break;
     case CTF_K_FORWARD:
       name_kind = dtd->dtd_data.ctt_type;
       break;
@@ -703,8 +700,9 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   ctf_dtdef_t *dtd;
   ctf_id_t type;
   uint32_t vlen;
-  uint32_t *vdat = NULL;
+  uint32_t *vdat;
   ctf_dict_t *tmp = fp;
+  size_t initial_vlen;
   size_t i;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
@@ -720,38 +718,35 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
 
   if (ctc->ctc_return != 0
       && ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
-    return CTF_ERR;		/* errno is set for us.  */
+    return CTF_ERR;				/* errno is set for us.  */
 
   if (vlen > CTF_MAX_VLEN)
     return (ctf_set_errno (fp, EOVERFLOW));
 
-  if (vlen != 0 && (vdat = malloc (sizeof (ctf_id_t) * vlen)) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+  /* One word extra allocated for padding for 4-byte alignment if need be.
+     Not reflected in vlen: we don't want to copy anything into it, and
+     it's in addition to (e.g.) the trailing 0 indicating varargs.  */
+
+  initial_vlen = (sizeof (uint32_t) * (vlen + (vlen & 1)));
+  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
+			       initial_vlen, &dtd)) == CTF_ERR)
+    return CTF_ERR;				/* errno is set for us.  */
+
+  vdat = (uint32_t *) dtd->dtd_vlen;
 
   for (i = 0; i < ctc->ctc_argc; i++)
     {
       tmp = fp;
       if (argv[i] != 0 && ctf_lookup_by_id (&tmp, argv[i]) == NULL)
-	{
-	  free (vdat);
-	  return CTF_ERR;	   /* errno is set for us.  */
-	}
+	return CTF_ERR;				/* errno is set for us.  */
       vdat[i] = (uint32_t) argv[i];
     }
 
-  if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
-			       0, &dtd)) == CTF_ERR)
-    {
-      free (vdat);
-      return CTF_ERR;		   /* errno is set for us.  */
-    }
-
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
   dtd->dtd_data.ctt_type = (uint32_t) ctc->ctc_return;
 
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
     vdat[vlen - 1] = 0;		   /* Add trailing zero to indicate varargs.  */
-  dtd->dtd_u.dtu_argv = vdat;
 
   return type;
 }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index c1ce50bc3b9..7a4e418ce2d 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -196,7 +196,6 @@ typedef struct ctf_dtdef
   union
   {
     ctf_list_t dtu_members;	/* struct, union, or enum */
-    uint32_t *dtu_argv;		/* function */
   } dtd_u;
 } ctf_dtdef_t;
 
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index d8e78f361f4..460ae1a510e 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -892,19 +892,9 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	  break;
 
 	case CTF_K_FUNCTION:
-	  {
-	    uint32_t *argv = (uint32_t *) (uintptr_t) t;
-	    uint32_t argc;
-
-	    for (argc = 0; argc < vlen; argc++)
-	      *argv++ = dtd->dtd_u.dtu_argv[argc];
-
-	    if (vlen & 1)
-	      *argv++ = 0;	/* Pad to 4-byte boundary.  */
-
-	    t = (unsigned char *) argv;
-	    break;
-	  }
+	  memcpy (t, dtd->dtd_vlen, sizeof (uint32_t) * (vlen + (vlen & 1)));
+	  t += sizeof (uint32_t) * (vlen + (vlen & 1));
+	  break;
 
 	case CTF_K_STRUCT:
 	case CTF_K_UNION:
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 8c983d5542f..1e1ce8ee529 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -1678,7 +1678,7 @@ ctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip)
   if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
     args = (uint32_t *) ((uintptr_t) tp + increment);
   else
-    args = dtd->dtd_u.dtu_argv;
+    args = (uint32_t *) dtd->dtd_vlen;
 
   if (fip->ctc_argc != 0 && args[fip->ctc_argc - 1] == 0)
     {
@@ -1715,7 +1715,7 @@ ctf_func_type_args (ctf_dict_t *fp, ctf_id_t type, uint32_t argc, ctf_id_t *argv
   if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
     args = (uint32_t *) ((uintptr_t) tp + increment);
   else
-    args = dtd->dtd_u.dtu_argv;
+    args = (uint32_t *) dtd->dtd_vlen;
 
   for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--)
     *argv++ = *args++;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (7 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 08/16] libctf: eliminate dtd_u, part 3: functions Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-15 13:11   ` [PING] " Nick Alcock
  2021-03-06  0:40 ` [PATCH 10/16] libctf: don't lose track of all valid types upon serialization Nick Alcock
                   ` (6 subsequent siblings)
  15 siblings, 1 reply; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This stops problems parallel-installing if a relink of libctf is needed.

ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	PR libctf/27482
	* Makefile.def: Add install-bfd dependencies for install-libctf and
	install-ld; move the install-ld dependency on install-libctf to join
	it.
	* Makefile.in: Regenerated.
---
 Makefile.def | 6 +++++-
 Makefile.in  | 4 +++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/Makefile.def b/Makefile.def
index b45e580da5b..540db0e73c1 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -448,7 +448,6 @@ dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
 dependencies = { module=all-binutils; on=all-libctf; };
 dependencies = { module=all-ld; on=all-libctf; };
-dependencies = { module=install-ld; on=install-libctf; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
@@ -456,6 +455,11 @@ dependencies = { module=install-ld; on=install-libctf; };
 dependencies = { module=install-binutils; on=install-opcodes; };
 dependencies = { module=install-strip-binutils; on=install-strip-opcodes; };
 
+// Likewise for ld, libctf, and bfd.
+dependencies = { module=install-libctf; on=install-bfd; };
+dependencies = { module=install-ld; on=install-bfd; };
+dependencies = { module=install-ld; on=install-libctf; };
+
 // libopcodes depends on libbfd
 dependencies = { module=install-opcodes; on=install-bfd; };
 dependencies = { module=install-strip-opcodes; on=install-strip-bfd; };
diff --git a/Makefile.in b/Makefile.in
index 0a64fc10e5b..ebd137540c1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -52170,9 +52170,11 @@ all-stage3-ld: maybe-all-stage3-libctf
 all-stage4-ld: maybe-all-stage4-libctf
 all-stageprofile-ld: maybe-all-stageprofile-libctf
 all-stagefeedback-ld: maybe-all-stagefeedback-libctf
-install-ld: maybe-install-libctf
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
+install-libctf: maybe-install-bfd
+install-ld: maybe-install-bfd
+install-ld: maybe-install-libctf
 install-opcodes: maybe-install-bfd
 install-strip-opcodes: maybe-install-strip-bfd
 configure-gas: maybe-configure-intl
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 10/16] libctf: don't lose track of all valid types upon serialization
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (8 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 11/16] libctf: do not corrupt strings across ctf_serialize Nick Alcock
                   ` (5 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

One pattern which is rarely done in libctf but which is meant to work is
this:

ctf_create();
ctf_add_*(); // add stuff
ctf_type_*() // look stuff up
ctf_write_*();
ctf_add_*(); // should still work
ctf_type_*() // so should this
ctf_write_*(); // and this

i.e., writing out a dict should not break it and you should be able to
do everything you could do with it before, including writing it out
again.

Unfortunately this has been broken for a while because the field which
indicates the maximum valid type ID was not preserved across
serialization: so type additions after serialization would overwrite
types (obviously disastrous) and type lookups would just fail.

Fix trivial.

libctf/ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-serialize.c (ctf_serialize): Preserve ctf_typemax across
	serialization.
---
 libctf/ctf-serialize.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 460ae1a510e..17f11f67ffb 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -1113,6 +1113,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;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 11/16] libctf: do not corrupt strings across ctf_serialize
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (9 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 10/16] libctf: don't lose track of all valid types upon serialization Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 12/16] libctf: eliminate dtd_u, part 4: enums Nick Alcock
                   ` (4 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

The preceding change revealed a new bug: the string table is sorted for
better compression, so repeated serialization with type (or member)
additions in the middle can move strings around.  But every
serialization flushes the set of refs (the memory locations that are
automatically updated with a final string offset when the strtab is
updated), so if we are not to have string offsets go stale, we must do
all ref additions within the serialization code (which walks the
complete set of types and symbols anyway). Unfortunately, we were adding
one ref in another place: the type name in the dynamic type definitions,
which has a ref added to it by ctf_add_generic.

So adding a type, serializing (via, say, one of the ctf_write
functions), adding another type with a name that sorts earlier, and
serializing again will corrupt the name of the first type because it no
longer had a ref pointing to its dtd entry's name when its string offset
was shifted later in the strtab to mae way for the other type.

To ensure that we don't miss strings, we also maintain a set of *pending
refs* that will be added later (during serialization), and remove
entries from that set when the ref is finally added.  We always use
ctf_str_add_pending outside ctf-serialize.c, ensure that ctf_serialize
adds all strtab offsets as refs (even those in the dtds) on every
serialization, and mandate that no refs are live on entry to
ctf_serialize and that all pending refs are gone before strtab
finalization.  (Of necessity ctf_serialize has to traverse all strtab
offsets in the dtds in order to serialize them, so adding them as refs
at the same time is easy.)

(Note that we still can't erase unused atoms when we roll back, though
we can erase unused refs: members and enums are still not removed by
rollbacks and might reference strings added after the snapshot.)

libctf/ChangeLog
2021-03-03  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-hash.c (ctf_dynset_elements): New.
	* ctf-impl.h (ctf_dynset_elements): Declare it.
	(ctf_str_add_pending): Likewise.
	(ctf_dict_t) <ctf_str_pending_ref>: New, set of refs that must be
	added during serialization.
	* ctf-string.c (ctf_str_create_atoms): Initialize it.
	(CTF_STR_ADD_REF): New flag.
	(CTF_STR_MAKE_PROVISIONAL): Likewise.
	(CTF_STR_PENDING_REF): Likewise.
	(ctf_str_add_ref_internal): Take a flags word rather than int
	params.  Populate, and clear out, ctf_str_pending_ref.
	(ctf_str_add): Adjust accordingly.
	(ctf_str_add_external): Likewise.
	(ctf_str_add_pending): New.
	(ctf_str_remove_ref): Also remove the potential ref if it is a
	pending ref.
	* ctf-serialize.c (ctf_serialize): Prohibit addition of strings
	with ctf_str_add_ref before serialization.  Ensure that the
	ctf_str_pending_ref set is empty before strtab finalization.
	(ctf_emit_type_sect): Add a ref to the ctt_name.
	* ctf-create.c (ctf_add_generic): Add the ctt_name as a pending
	ref.
	* testsuite/libctf-writable/reserialize-strtab-corruption.*: New test.
---
 libctf/ctf-create.c                           |  3 +-
 libctf/ctf-hash.c                             |  6 ++
 libctf/ctf-impl.h                             |  5 +-
 libctf/ctf-serialize.c                        | 24 ++++-
 libctf/ctf-string.c                           | 61 +++++++++++--
 .../reserialize-strtab-corruption.c           | 91 +++++++++++++++++++
 .../reserialize-strtab-corruption.lk          |  5 +
 7 files changed, 183 insertions(+), 12 deletions(-)
 create mode 100644 libctf/testsuite/libctf-writable/reserialize-strtab-corruption.c
 create mode 100644 libctf/testsuite/libctf-writable/reserialize-strtab-corruption.lk

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 6acc2428cd7..ea2c1481b6c 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -439,7 +439,8 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   type = ++fp->ctf_typemax;
   type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD));
 
-  dtd->dtd_data.ctt_name = ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name);
+  dtd->dtd_data.ctt_name = ctf_str_add_pending (fp, name,
+						&dtd->dtd_data.ctt_name);
   dtd->dtd_type = type;
 
   if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')
diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c
index 62f3dde3465..426bd625ffb 100644
--- a/libctf/ctf-hash.c
+++ b/libctf/ctf-hash.c
@@ -672,6 +672,12 @@ ctf_dynset_lookup (ctf_dynset_t *hp, const void *key)
   return NULL;
 }
 
+size_t
+ctf_dynset_elements (ctf_dynset_t *hp)
+{
+  return htab_elements ((struct htab *) hp);
+}
+
 /* TRUE/FALSE return.  */
 int
 ctf_dynset_exists (ctf_dynset_t *hp, const void *key, const void **orig_key)
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 7a4e418ce2d..a319d7f74a2 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -398,7 +398,8 @@ struct ctf_dict
   ctf_names_t ctf_names;	    /* Hash table of remaining type names.  */
   ctf_lookup_t ctf_lookups[5];	    /* Pointers to nametabs for name lookup.  */
   ctf_strs_t ctf_str[2];	    /* Array of string table base and bounds.  */
-  ctf_dynhash_t *ctf_str_atoms;	  /* Hash table of ctf_str_atoms_t.  */
+  ctf_dynhash_t *ctf_str_atoms;	    /* Hash table of ctf_str_atoms_t.  */
+  ctf_dynset_t *ctf_str_pending_ref; /* Locations awaiting ref addition.  */
   uint64_t ctf_str_num_refs;	  /* Number of refs to cts_str_atoms.  */
   uint32_t ctf_str_prov_offset;	  /* Latest provisional offset assigned so far.  */
   unsigned char *ctf_base;	  /* CTF file pointer.  */
@@ -673,6 +674,7 @@ extern int ctf_dynset_insert (ctf_dynset_t *, void *);
 extern void ctf_dynset_remove (ctf_dynset_t *, const void *);
 extern void ctf_dynset_destroy (ctf_dynset_t *);
 extern void *ctf_dynset_lookup (ctf_dynset_t *, const void *);
+extern size_t ctf_dynset_elements (ctf_dynset_t *);
 extern int ctf_dynset_exists (ctf_dynset_t *, const void *key,
 			      const void **orig_key);
 extern int ctf_dynset_next (ctf_dynset_t *, ctf_next_t **, void **key);
@@ -731,6 +733,7 @@ extern int ctf_str_create_atoms (ctf_dict_t *);
 extern void ctf_str_free_atoms (ctf_dict_t *);
 extern uint32_t ctf_str_add (ctf_dict_t *, const char *);
 extern uint32_t ctf_str_add_ref (ctf_dict_t *, const char *, uint32_t *ref);
+extern uint32_t ctf_str_add_pending (ctf_dict_t *, const char *, uint32_t *);
 extern int ctf_str_add_external (ctf_dict_t *, const char *, uint32_t offset);
 extern void ctf_str_remove_ref (ctf_dict_t *, const char *, uint32_t *ref);
 extern void ctf_str_rollback (ctf_dict_t *, ctf_snapshot_id_t);
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 17f11f67ffb..0eff0e197fa 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -870,7 +870,10 @@ 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);
+	}
       t += len;
 
       switch (kind)
@@ -955,6 +958,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 +977,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 +1066,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.  */
@@ -1154,8 +1174,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;
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 91ad2e36db7..9f0e5400141 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -103,7 +103,7 @@ ctf_str_create_atoms (ctf_dict_t *fp)
 {
   fp->ctf_str_atoms = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
 					  free, ctf_str_free_atom);
-  if (fp->ctf_str_atoms == NULL)
+  if (!fp->ctf_str_atoms)
     return -ENOMEM;
 
   if (!fp->ctf_prov_strtab)
@@ -113,6 +113,13 @@ ctf_str_create_atoms (ctf_dict_t *fp)
   if (!fp->ctf_prov_strtab)
     goto oom_prov_strtab;
 
+  if (!fp->ctf_str_pending_ref)
+    fp->ctf_str_pending_ref = ctf_dynset_create (htab_hash_pointer,
+						 htab_eq_pointer,
+						 NULL);
+  if (!fp->ctf_str_pending_ref)
+    goto oom_str_pending_ref;
+
   errno = 0;
   ctf_str_add (fp, "");
   if (errno == ENOMEM)
@@ -123,6 +130,9 @@ ctf_str_create_atoms (ctf_dict_t *fp)
  oom_str_add:
   ctf_dynhash_destroy (fp->ctf_prov_strtab);
   fp->ctf_prov_strtab = NULL;
+ oom_str_pending_ref:
+  ctf_dynset_destroy (fp->ctf_str_pending_ref);
+  fp->ctf_str_pending_ref = NULL;
  oom_prov_strtab:
   ctf_dynhash_destroy (fp->ctf_str_atoms);
   fp->ctf_str_atoms = NULL;
@@ -135,8 +145,13 @@ ctf_str_free_atoms (ctf_dict_t *fp)
 {
   ctf_dynhash_destroy (fp->ctf_prov_strtab);
   ctf_dynhash_destroy (fp->ctf_str_atoms);
+  ctf_dynset_destroy (fp->ctf_str_pending_ref);
 }
 
+#define CTF_STR_ADD_REF 0x1
+#define CTF_STR_MAKE_PROVISIONAL 0x2
+#define CTF_STR_PENDING_REF 0x4
+
 /* Add a string to the atoms table, copying the passed-in string.  Return the
    atom added. Return NULL only when out of memory (and do not touch the
    passed-in string in that case).  Possibly augment the ref list with the
@@ -144,7 +159,7 @@ ctf_str_free_atoms (ctf_dict_t *fp)
    provisional strtab.   */
 static ctf_str_atom_t *
 ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
-			  int add_ref, int make_provisional, uint32_t *ref)
+			  int flags, uint32_t *ref)
 {
   char *newstr = NULL;
   ctf_str_atom_t *atom = NULL;
@@ -152,7 +167,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
 
   atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str);
 
-  if (add_ref)
+  if (flags & CTF_STR_ADD_REF)
     {
       if ((aref = malloc (sizeof (struct ctf_str_atom_ref))) == NULL)
 	return NULL;
@@ -161,8 +176,9 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
 
   if (atom)
     {
-      if (add_ref)
+      if (flags & CTF_STR_ADD_REF)
 	{
+	  ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref);
 	  ctf_list_append (&atom->csa_refs, aref);
 	  fp->ctf_str_num_refs++;
 	}
@@ -182,7 +198,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
   atom->csa_str = newstr;
   atom->csa_snapshot_id = fp->ctf_snapshots;
 
-  if (make_provisional)
+  if (flags & CTF_STR_MAKE_PROVISIONAL)
     {
       atom->csa_offset = fp->ctf_str_prov_offset;
 
@@ -193,8 +209,14 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
       fp->ctf_str_prov_offset += strlen (atom->csa_str) + 1;
     }
 
-  if (add_ref)
+  if (flags & CTF_STR_PENDING_REF)
+    {
+      if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) ref) < 0)
+	goto oom;
+    }
+  else if (flags & CTF_STR_ADD_REF)
     {
+      ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref);
       ctf_list_append (&atom->csa_refs, aref);
       fp->ctf_str_num_refs++;
     }
@@ -222,7 +244,7 @@ ctf_str_add (ctf_dict_t *fp, const char *str)
   if (!str)
     str = "";
 
-  atom = ctf_str_add_ref_internal (fp, str, FALSE, TRUE, 0);
+  atom = ctf_str_add_ref_internal (fp, str, CTF_STR_MAKE_PROVISIONAL, 0);
   if (!atom)
     return 0;
 
@@ -240,7 +262,26 @@ ctf_str_add_ref (ctf_dict_t *fp, const char *str, uint32_t *ref)
   if (!str)
     str = "";
 
-  atom = ctf_str_add_ref_internal (fp, str, TRUE, TRUE, ref);
+  atom = ctf_str_add_ref_internal (fp, str, CTF_STR_ADD_REF
+				   | CTF_STR_MAKE_PROVISIONAL, ref);
+  if (!atom)
+    return 0;
+
+  return atom->csa_offset;
+}
+
+/* Like ctf_str_add_ref(), but notes that this memory location must be added as
+   a ref by a later serialization phase, rather than adding it itself.  */
+uint32_t
+ctf_str_add_pending (ctf_dict_t *fp, const char *str, uint32_t *ref)
+{
+  ctf_str_atom_t *atom;
+
+  if (!str)
+    str = "";
+
+  atom = ctf_str_add_ref_internal (fp, str, CTF_STR_PENDING_REF
+				   | CTF_STR_MAKE_PROVISIONAL, ref);
   if (!atom)
     return 0;
 
@@ -257,7 +298,7 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset)
   if (!str)
     str = "";
 
-  atom = ctf_str_add_ref_internal (fp, str, FALSE, FALSE, 0);
+  atom = ctf_str_add_ref_internal (fp, str, 0, 0);
   if (!atom)
     return 0;
 
@@ -307,6 +348,8 @@ ctf_str_remove_ref (ctf_dict_t *fp, const char *str, uint32_t *ref)
 	  free (aref);
 	}
     }
+
+  ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref);
 }
 
 /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given
diff --git a/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.c b/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.c
new file mode 100644
index 00000000000..1593325da77
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.c
@@ -0,0 +1,91 @@
+/* Make sure serializing a dict (possibly repeatedly) does not corrupt either
+   type lookup or the string content of the dict.  */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (int argc, char *argv[])
+{
+  ctf_dict_t *fp;
+  ctf_id_t zygal, autoschediastic;
+  ctf_snapshot_id_t snap;
+  unsigned char *foo;
+  size_t foo_size;
+  const char *bar;
+  int err;
+  char name[64];
+
+  /* Adding things after serialization should not corrupt names created before
+     serialization.  */
+
+  if ((fp = ctf_create (&err)) == NULL)
+    goto create_err;
+
+  if ((zygal = ctf_add_struct (fp, CTF_ADD_ROOT, "zygal")) == CTF_ERR)
+    goto add_err;
+
+  if ((foo = ctf_write_mem (fp, &foo_size, 4096)) == NULL)
+    goto write_err;
+  free (foo);
+
+  if (ctf_type_name (fp, zygal, name, sizeof (name)) == NULL)
+    fprintf (stderr, "Can't get name of zygal: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else
+    printf ("zygal's name is %s\n", name);
+
+  if ((autoschediastic = ctf_add_enum (fp, CTF_ADD_ROOT, "autoschediastic")) == CTF_ERR)
+    goto add_err;
+
+  if (ctf_type_name (fp, zygal, name, sizeof (name)) == NULL)
+    fprintf (stderr, "Can't get name of zygal: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else
+    printf ("zygal's name is %s\n", name);
+
+  /* Serializing again should not corrupt names either.  */
+  if ((foo = ctf_write_mem (fp, &foo_size, 4096)) == NULL)
+    goto write_err;
+  free (foo);
+
+  if (ctf_type_name (fp, zygal, name, sizeof (name)) == NULL)
+    fprintf (stderr, "Can't get name of zygal: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else
+    printf ("zygal's name is %s\n", name);
+
+  /* Add another new name, roll back, and make sure the strings are
+     uncorrupted.  */
+
+  snap = ctf_snapshot (fp);
+  if (ctf_add_enumerator (fp, autoschediastic, "aichmophobia", 0) < 0)
+    goto add_err;
+
+  if (ctf_rollback (fp, snap) < 0)
+    goto roll_err;
+
+  if (ctf_type_name (fp, zygal, name, sizeof (name)) == NULL)
+    fprintf (stderr, "Can't get name of zygal: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else
+    printf ("zygal's name is %s after first rollback\n", name);
+
+  if (ctf_type_name (fp, autoschediastic, name, sizeof (name)) == NULL)
+    fprintf (stderr, "Can't get name of autoschediastic: %s\n", ctf_errmsg (ctf_errno (fp)));
+  else
+    printf ("autoschediastic's name is %s after first rollback\n", name);
+
+  ctf_dict_close (fp);
+  return 0;
+
+ create_err:
+  fprintf (stderr, "Cannot create: %s\n", ctf_errmsg (err));
+  return 1;
+ add_err:
+  fprintf (stderr, "Cannot add: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ write_err:
+  fprintf (stderr, "Cannot serialize: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+ roll_err:
+  fprintf (stderr, "Cannot roll back: %s\n", ctf_errmsg (ctf_errno (fp)));
+  return 1;
+}
diff --git a/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.lk b/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.lk
new file mode 100644
index 00000000000..58f7a64a331
--- /dev/null
+++ b/libctf/testsuite/libctf-writable/reserialize-strtab-corruption.lk
@@ -0,0 +1,5 @@
+zygal's name is struct zygal
+zygal's name is struct zygal
+zygal's name is struct zygal
+zygal's name is struct zygal after first rollback
+autoschediastic's name is enum autoschediastic after first rollback
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 12/16] libctf: eliminate dtd_u, part 4: enums
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (10 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 11/16] libctf: do not corrupt strings across ctf_serialize Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 13/16] libctf: eliminate dtd_u, part 5: structs / unions Nick Alcock
                   ` (3 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This is the first tricky one, the first complex multi-entry vlen
containing strings.  To handle this in vlen form, we have to handle
pending refs moving around on realloc.

We grow vlen regions using a new ctf_grow_vlen function, and iterate
through the existing enums every time a grow happens, telling the string
machinery the distance between the old and new vlen region and letting
it adjust the pending refs accordingly.  (This avoids traversing all
outstanding refs to find the refs that need adjusting, at the cost of
having to traverse one enum: an obvious major performance win.)

Addition of enums themselves (and also structs/unions later) is a bit
trickier than earlier forms, because the type might be being promoted
from a forward, and forwards have no vlen: so we have to spot that and
create it if needed.

Serialization of enums simplifies down to just telling the string
machinery about the string refs; all the enum type-lookup code loses all
its dynamic member lookup complexity entirely.

A new test is added that iterates over (and gets values of) an enum with
enough members to force a round of vlen growth.

libctf/ChangeLog
2021-03-04  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtd_vlen_alloc>: New.
	(ctf_str_move_pending): Declare.
	* ctf-string.c (ctf_str_add_ref_internal): Fix error return.
	(ctf_str_move_pending): New.
	* ctf-create.c (ctf_grow_vlen): New.
	(ctf_dtd_delete): Zero out the vlen_alloc after free.  Free the
	vlen later: iterate over it and free enum name refs first.
	(ctf_add_generic): Populate dtd_vlen_alloc from vlen.
	(ctf_add_enum): populate the vlen; do it by hand if promoting
	forwards.
	(ctf_add_enumerator): Set up the vlen rather than the dmd.  Expand
	it as needed, repointing string refs via ctf_str_move_pending. Add
	the enumerand names as pending strings.
	* ctf-serialize.c (ctf_copy_emembers): Remove.
	(ctf_emit_type_sect): Copy the vlen into place and ref the
	strings.
	* ctf-types.c (ctf_enum_next): The dynamic portion now uses
	the same code as the non-dynamic.
	(ctf_enum_name): Likewise.
	(ctf_enum_value): Likewise.
	* testsuite/libctf-lookup/enum-many-ctf.c: New test.
	* testsuite/libctf-lookup/enum-many.lk: New test.
---
 libctf/ctf-create.c                           |  94 +++++++++++----
 libctf/ctf-impl.h                             |   3 +
 libctf/ctf-serialize.c                        |  39 +++----
 libctf/ctf-string.c                           |  17 +++
 libctf/ctf-types.c                            | 110 +++++-------------
 .../testsuite/libctf-lookup/enum-many-ctf.c   |  10 ++
 libctf/testsuite/libctf-lookup/enum-many.lk   | 101 ++++++++++++++++
 7 files changed, 252 insertions(+), 122 deletions(-)
 create mode 100644 libctf/testsuite/libctf-lookup/enum-many-ctf.c
 create mode 100644 libctf/testsuite/libctf-lookup/enum-many.lk

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index ea2c1481b6c..3218e3e31ea 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -64,6 +64,30 @@ ctf_grow_ptrtab (ctf_dict_t *fp)
   return 0;
 }
 
+/* Make sure a vlen has enough space: expand it otherwise.  Unlike the ptrtab,
+   which grows quite slowly, the vlen grows in big jumps because it is quite
+   expensive to expand: the caller has to scan the old vlen for string refs
+   first and remove them, then re-add them afterwards.  The initial size is
+   more or less arbitrary.  */
+static int
+ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
+{
+  unsigned char *old = dtd->dtd_vlen;
+
+  if (dtd->dtd_vlen_alloc > vlen)
+    return 0;
+
+  if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen,
+				dtd->dtd_vlen_alloc * 2)) == NULL)
+    {
+      dtd->dtd_vlen = old;
+      return (ctf_set_errno (fp, ENOMEM));
+    }
+  memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
+  dtd->dtd_vlen_alloc *= 2;
+  return 0;
+}
+
 /* To create an empty CTF dict, we just declare a zeroed header and call
    ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new dict r/w and
    initialize the dynamic members.  We start assigning type IDs at 1 because
@@ -222,17 +246,16 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
 {
   ctf_dmdef_t *dmd, *nmd;
   int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+  size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
   int name_kind = kind;
   const char *name;
 
   ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
-  free (dtd->dtd_vlen);
 
   switch (kind)
     {
     case CTF_K_STRUCT:
     case CTF_K_UNION:
-    case CTF_K_ENUM:
       for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
 	   dmd != NULL; dmd = nmd)
 	{
@@ -242,10 +265,22 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
 	  free (dmd);
 	}
       break;
+    case CTF_K_ENUM:
+      {
+	ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+	size_t i;
+
+	for (i = 0; i < vlen; i++)
+	  ctf_str_remove_ref (fp, ctf_strraw (fp, en[i].cte_name),
+			      &en[i].cte_name);
+      }
+      break;
     case CTF_K_FORWARD:
       name_kind = dtd->dtd_data.ctt_type;
       break;
     }
+  free (dtd->dtd_vlen);
+  dtd->dtd_vlen_alloc = 0;
 
   if (dtd->dtd_data.ctt_name
       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL
@@ -402,6 +437,9 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   return 0;
 }
 
+/* Note: vlen is the amount of space *allocated* for the vlen.  It may well not
+   be the amount of space used (yet): the space used is declared in per-kind
+   fashion in the dtd_data's info word.  */
 static ctf_id_t
 ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
 		 size_t vlen, ctf_dtdef_t **rp)
@@ -428,6 +466,7 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
     return (ctf_set_errno (fp, EAGAIN));
 
+  dtd->dtd_vlen_alloc = vlen;
   if (vlen > 0)
     {
       if ((dtd->dtd_vlen = calloc (1, vlen)) == NULL)
@@ -831,6 +870,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
+  size_t initial_vlen = sizeof (ctf_enum_t) * 16;
 
   /* Promote root-visible forwards to enums.  */
   if (name != NULL)
@@ -839,9 +879,17 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM,
-				    0, &dtd)) == CTF_ERR)
+				    initial_vlen, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
+  /* Forwards won't have any vlen yet.  */
+  if (dtd->dtd_vlen_alloc == 0)
+    {
+      if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
+	return (ctf_set_errno (fp, ENOMEM));
+      dtd->dtd_vlen_alloc = initial_vlen;
+    }
+
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
   dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
 
@@ -956,10 +1004,11 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
 		    int value)
 {
   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
-  ctf_dmdef_t *dmd;
+  unsigned char *old_vlen;
+  ctf_enum_t *en;
+  size_t i;
 
   uint32_t kind, vlen, root;
-  char *s;
 
   if (name == NULL)
     return (ctf_set_errno (fp, EINVAL));
@@ -980,29 +1029,32 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   if (vlen == CTF_MAX_VLEN)
     return (ctf_set_errno (fp, ECTF_DTFULL));
 
-  for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-       dmd != NULL; dmd = ctf_list_next (dmd))
+  old_vlen = dtd->dtd_vlen;
+  if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
+    return -1;					/* errno is set for us.  */
+  en = (ctf_enum_t *) dtd->dtd_vlen;
+
+  if (dtd->dtd_vlen != old_vlen)
     {
-      if (strcmp (dmd->dmd_name, name) == 0)
-	return (ctf_set_errno (fp, ECTF_DUPLICATE));
-    }
+      ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen;
 
-  if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
+      /* Remove pending refs in the old vlen region and reapply them.  */
 
-  if ((s = strdup (name)) == NULL)
-    {
-      free (dmd);
-      return (ctf_set_errno (fp, EAGAIN));
+      for (i = 0; i < vlen; i++)
+	ctf_str_move_pending (fp, &en[i].cte_name, move);
     }
 
-  dmd->dmd_name = s;
-  dmd->dmd_type = CTF_ERR;
-  dmd->dmd_offset = 0;
-  dmd->dmd_value = value;
+  for (i = 0; i < vlen; i++)
+    if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+      return (ctf_set_errno (fp, ECTF_DUPLICATE));
+
+  en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
+  en[i].cte_value = value;
+
+  if (en[i].cte_name == 0 && name != NULL && name[0] != '\0')
+    return -1;					/* errno is set for us. */
 
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
-  ctf_list_append (&dtd->dtd_u.dtu_members, dmd);
 
   fp->ctf_flags |= LCTF_DIRTY;
 
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index a319d7f74a2..9a82d953ae8 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stddef.h>
 #include <stdio.h>
 #include <stdint.h>
 #include <limits.h>
@@ -192,6 +193,7 @@ typedef struct ctf_dtdef
   ctf_list_t dtd_list;		/* List forward/back pointers.  */
   ctf_id_t dtd_type;		/* Type identifier for this definition.  */
   ctf_type_t dtd_data;		/* Type node, including name.  */
+  size_t dtd_vlen_alloc;	/* Total vlen space allocated.  */
   unsigned char *dtd_vlen;	/* Variable-length data for this type.  */
   union
   {
@@ -734,6 +736,7 @@ extern void ctf_str_free_atoms (ctf_dict_t *);
 extern uint32_t ctf_str_add (ctf_dict_t *, const char *);
 extern uint32_t ctf_str_add_ref (ctf_dict_t *, const char *, uint32_t *ref);
 extern uint32_t ctf_str_add_pending (ctf_dict_t *, const char *, uint32_t *);
+extern int ctf_str_move_pending (ctf_dict_t *, uint32_t *, ptrdiff_t);
 extern int ctf_str_add_external (ctf_dict_t *, const char *, uint32_t offset);
 extern void ctf_str_remove_ref (ctf_dict_t *, const char *, uint32_t *ref);
 extern void ctf_str_rollback (ctf_dict_t *, ctf_snapshot_id_t);
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 0eff0e197fa..5d94f44b0d0 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -770,26 +770,6 @@ ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t)
   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.  */
 
@@ -860,6 +840,7 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
       size_t len;
       ctf_stype_t *copied;
       const char *name;
+      size_t i;
 
       if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
 	len = sizeof (ctf_stype_t);
@@ -908,8 +889,22 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	  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;
+	  }
 	}
     }
 
diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c
index 9f0e5400141..2e98484f209 100644
--- a/libctf/ctf-string.c
+++ b/libctf/ctf-string.c
@@ -19,6 +19,7 @@
 
 #include <ctf-impl.h>
 #include <string.h>
+#include <assert.h>
 
 /* Convert an encoded CTF string name into a pointer to a C string, using an
   explicit internal strtab rather than the fp-based one.  */
@@ -228,6 +229,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str,
   free (atom);
   free (aref);
   free (newstr);
+  ctf_set_errno (fp, ENOMEM);
   return NULL;
 }
 
@@ -288,6 +290,21 @@ ctf_str_add_pending (ctf_dict_t *fp, const char *str, uint32_t *ref)
   return atom->csa_offset;
 }
 
+/* Note that a pending ref now located at NEW_REF has moved by BYTES bytes.  */
+int
+ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes)
+{
+  if (bytes == 0)
+    return 0;
+
+  if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0)
+    return (ctf_set_errno (fp, ENOMEM));
+
+  ctf_dynset_remove (fp->ctf_str_pending_ref,
+		     (void *) ((signed char *) new_ref - bytes));
+  return 0;
+}
+
 /* Add an external strtab reference at OFFSET.  Returns zero if the addition
    failed, nonzero otherwise.  */
 int
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 1e1ce8ee529..49264ebf5ab 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -318,22 +318,13 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       dtd = ctf_dynamic_type (fp, type);
       i->ctn_iter_fun = (void (*) (void)) ctf_enum_next;
-
-      /* We depend below on the RDWR state indicating whether the DTD-related
-	 fields or the DMD-related fields have been initialized.  */
-
-      assert ((dtd && (fp->ctf_flags & LCTF_RDWR))
-	      || (!dtd && (!(fp->ctf_flags & LCTF_RDWR))));
+      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
 
       if (dtd == NULL)
-	{
-	  i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-
-	  i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
-					      i->ctn_increment);
-	}
+	i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
+					    i->ctn_increment);
       else
-	i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+	i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
 
       *it = i;
     }
@@ -357,27 +348,14 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       return NULL;
     }
 
-  if (!(fp->ctf_flags & LCTF_RDWR))
-    {
-      if (i->ctn_n == 0)
-	goto end_iter;
-
-      name = ctf_strptr (fp, i->u.ctn_en->cte_name);
-      if (val)
-	*val = i->u.ctn_en->cte_value;
-      i->u.ctn_en++;
-      i->ctn_n--;
-    }
-  else
-    {
-      if (i->u.ctn_dmd == NULL)
-	goto end_iter;
+  if (i->ctn_n == 0)
+    goto end_iter;
 
-      name = i->u.ctn_dmd->dmd_name;
-      if (val)
-	*val = i->u.ctn_dmd->dmd_value;
-      i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
-    }
+  name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+  if (val)
+    *val = i->u.ctn_en->cte_value;
+  i->u.ctn_en++;
+  i->ctn_n--;
 
   return name;
 
@@ -1554,35 +1532,24 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
 
   if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
     {
-      (void) ctf_set_errno (ofp, ECTF_NOTENUM);
+      ctf_set_errno (ofp, ECTF_NOTENUM);
       return NULL;
     }
 
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
+  ctf_get_ctt_size (fp, tp, NULL, &increment);
 
   if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    {
-      ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
-
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
-	{
-	  if (ep->cte_value == value)
-	    return (ctf_strptr (fp, ep->cte_name));
-	}
-    }
+    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
   else
-    {
-      ctf_dmdef_t *dmd;
+    ep = (const ctf_enum_t *) dtd->dtd_vlen;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
-	{
-	  if (dmd->dmd_value == value)
-	    return dmd->dmd_name;
-	}
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (ep->cte_value == value)
+	return (ctf_strptr (fp, ep->cte_name));
     }
 
-  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno (ofp, ECTF_NOENUMNAM);
   return NULL;
 }
 
@@ -1590,7 +1557,7 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
    matching name can be found.  Otherwise CTF_ERR is returned.  */
 
 int
-ctf_enum_value (ctf_dict_t * fp, ctf_id_t type, const char *name, int *valp)
+ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
 {
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
@@ -1611,39 +1578,24 @@ ctf_enum_value (ctf_dict_t * fp, ctf_id_t type, const char *name, int *valp)
       return -1;
     }
 
-  (void) ctf_get_ctt_size (fp, tp, NULL, &increment);
-
-  ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
+  ctf_get_ctt_size (fp, tp, NULL, &increment);
 
   if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    {
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
-	{
-	  if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
-	    {
-	      if (valp != NULL)
-		*valp = ep->cte_value;
-	      return 0;
-	    }
-	}
-    }
+    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
   else
-    {
-      ctf_dmdef_t *dmd;
+    ep = (const ctf_enum_t *) dtd->dtd_vlen;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
+  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+    {
+      if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
 	{
-	  if (strcmp (dmd->dmd_name, name) == 0)
-	    {
-	      if (valp != NULL)
-		*valp = dmd->dmd_value;
-	      return 0;
-	    }
+	  if (valp != NULL)
+	    *valp = ep->cte_value;
+	  return 0;
 	}
     }
 
-  (void) ctf_set_errno (ofp, ECTF_NOENUMNAM);
+  ctf_set_errno (ofp, ECTF_NOENUMNAM);
   return -1;
 }
 
diff --git a/libctf/testsuite/libctf-lookup/enum-many-ctf.c b/libctf/testsuite/libctf-lookup/enum-many-ctf.c
new file mode 100644
index 00000000000..f2297d72cdb
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-many-ctf.c
@@ -0,0 +1,10 @@
+/* Looked up item by item. */
+enum e { ENUMSAMPLE_1 = 0, ENUMSAMPLE_2 = 1 };
+
+/* Looked up via both sorts of iterator in turn.  */
+enum ie { IE_0 = -10, IE_1, IE_2, IE_3, IE_4, IE_5, IE_6, IE_7, IE_8, IE_9, IE_A, IE_B, IE_C, IE_D, IE_E, IE_F,
+	  IE_10, IE_11, IE_12, IE_13, IE_14, IE_15, IE_16, IE_17, IE_18, IE_19, IE_1A, IE_1B, IE_1C, IE_1D, IE_1E, IE_1F,
+	  IE_20, IE_21, IE_22, IE_23, IE_24, IE_25, IE_26, IE_27, IE_28, IE_29, IE_2A, IE_2B, IE_2C, IE_2D, IE_2E, IE_2F};
+
+enum e foo;
+enum ie bar;
diff --git a/libctf/testsuite/libctf-lookup/enum-many.lk b/libctf/testsuite/libctf-lookup/enum-many.lk
new file mode 100644
index 00000000000..17eca66aea3
--- /dev/null
+++ b/libctf/testsuite/libctf-lookup/enum-many.lk
@@ -0,0 +1,101 @@
+# source: enum-many-ctf.c
+# lookup: enum.c
+# link: on
+Enum e enumerand ENUMSAMPLE_1 has value 0
+Enum e enumerand ENUMSAMPLE_2 has value 1
+iter test: IE_0 has value -10
+iter test: IE_1 has value -9
+iter test: IE_2 has value -8
+iter test: IE_3 has value -7
+iter test: IE_4 has value -6
+iter test: IE_5 has value -5
+iter test: IE_6 has value -4
+iter test: IE_7 has value -3
+iter test: IE_8 has value -2
+iter test: IE_9 has value -1
+iter test: IE_A has value 0
+iter test: IE_B has value 1
+iter test: IE_C has value 2
+iter test: IE_D has value 3
+iter test: IE_E has value 4
+iter test: IE_F has value 5
+iter test: IE_10 has value 6
+iter test: IE_11 has value 7
+iter test: IE_12 has value 8
+iter test: IE_13 has value 9
+iter test: IE_14 has value 10
+iter test: IE_15 has value 11
+iter test: IE_16 has value 12
+iter test: IE_17 has value 13
+iter test: IE_18 has value 14
+iter test: IE_19 has value 15
+iter test: IE_1A has value 16
+iter test: IE_1B has value 17
+iter test: IE_1C has value 18
+iter test: IE_1D has value 19
+iter test: IE_1E has value 20
+iter test: IE_1F has value 21
+iter test: IE_20 has value 22
+iter test: IE_21 has value 23
+iter test: IE_22 has value 24
+iter test: IE_23 has value 25
+iter test: IE_24 has value 26
+iter test: IE_25 has value 27
+iter test: IE_26 has value 28
+iter test: IE_27 has value 29
+iter test: IE_28 has value 30
+iter test: IE_29 has value 31
+iter test: IE_2A has value 32
+iter test: IE_2B has value 33
+iter test: IE_2C has value 34
+iter test: IE_2D has value 35
+iter test: IE_2E has value 36
+iter test: IE_2F has value 37
+next test: IE_0 has value -10
+next test: IE_1 has value -9
+next test: IE_2 has value -8
+next test: IE_3 has value -7
+next test: IE_4 has value -6
+next test: IE_5 has value -5
+next test: IE_6 has value -4
+next test: IE_7 has value -3
+next test: IE_8 has value -2
+next test: IE_9 has value -1
+next test: IE_A has value 0
+next test: IE_B has value 1
+next test: IE_C has value 2
+next test: IE_D has value 3
+next test: IE_E has value 4
+next test: IE_F has value 5
+next test: IE_10 has value 6
+next test: IE_11 has value 7
+next test: IE_12 has value 8
+next test: IE_13 has value 9
+next test: IE_14 has value 10
+next test: IE_15 has value 11
+next test: IE_16 has value 12
+next test: IE_17 has value 13
+next test: IE_18 has value 14
+next test: IE_19 has value 15
+next test: IE_1A has value 16
+next test: IE_1B has value 17
+next test: IE_1C has value 18
+next test: IE_1D has value 19
+next test: IE_1E has value 20
+next test: IE_1F has value 21
+next test: IE_20 has value 22
+next test: IE_21 has value 23
+next test: IE_22 has value 24
+next test: IE_23 has value 25
+next test: IE_24 has value 26
+next test: IE_25 has value 27
+next test: IE_26 has value 28
+next test: IE_27 has value 29
+next test: IE_28 has value 30
+next test: IE_29 has value 31
+next test: IE_2A has value 32
+next test: IE_2B has value 33
+next test: IE_2C has value 34
+next test: IE_2D has value 35
+next test: IE_2E has value 36
+next test: IE_2F has value 37
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 13/16] libctf: eliminate dtd_u, part 5: structs / unions
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (11 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 12/16] libctf: eliminate dtd_u, part 4: enums Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 14/16] libctf: types: unify code dealing with small-vs-large struct members Nick Alcock
                   ` (2 subsequent siblings)
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

Eliminate the dynamic member storage for structs and unions as we have
for other dynamic types.  This is much like the previous enum
elimination, except that structs and unions are the only types for which
a full-sized ctf_type_t might be needed.  Up to now, this decision has
been made in the individual ctf_add_{struct,union}_sized functions and
duplicated in ctf_add_member_offset.  The vlen machinery lets us
simplify this, always allocating a ctf_lmember_t and setting the
dtd_data's ctt_size to CTF_LSIZE_SENT: we figure out whether this is
really justified and (almost always) repack things down into a
ctf_stype_t at ctf_serialize time.

This allows us to eliminate the dynamic member paths from the iterators and
query functions in ctf-types.c in favour of always using the large-structure
vlen stuff for dynamic types (the diff is ugly but that's just because of the
volume of reindentation this calls for).  This also means the large-structure
vlen stuff gets more heavily tested, which is nice because it was an almost
totally unused code path before now (it only kicked in for structures of size
>4GiB, and how often do you see those?)

The only extra complexity here is ctf_add_type.  Back in the days of the
nondeduplicating linker this was called a ridiculous number of times for
countless identical copies of structures: eschewing the repeated lookups of the
dtd in ctf_add_member_offset and adding the members directly saved an amazing
amount of time.  Now the nondeduplicating linker is gone, this is extreme
overoptimization: we can rip out the direct addition and use ctf_member_next and
ctf_add_member_offset, just like ctf_dedup_emit does.

We augment a ctf_add_type test to try adding a self-referential struct, the only
thing the ctf_add_type part of this change really perturbs.

This completes the elimination of dtd_u.

libctf/ChangeLog
2021-03-04  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_dtdef_t) <dtu_members>: Remove.
	<dtd_u>: Likewise.
	(ctf_dmdef_t): Remove.
	(struct ctf_next) <u.ctn_dmd>: Remove.
	* ctf-create.c (INITIAL_VLEN): New, more-or-less arbitrary initial
	vlen size.
	(ctf_add_enum): Use it.
	(ctf_dtd_delete): Do not free the (removed) dmd; remove string
	refs from the vlen on struct deletion.
	(ctf_add_struct_sized): Populate the vlen: do it by hand if
	promoting forwards.  Always populate the full-size
	lsizehi/lsizelo members.
	(ctf_add_union_sized): Likewise.
	(ctf_add_member_offset): Set up the vlen rather than the dmd.
	Expand it as needed, repointing string refs via
	ctf_str_move_pending. Add the member names as pending strings.
	Always populate the full-size lsizehi/lsizelo members.
	(membadd): Remove, folding back into...
	(ctf_add_type_internal): ... here, adding via an ordinary
	ctf_add_struct_sized and _next iteration rather than doing
	everything by hand.
	* ctf-serialize.c (ctf_copy_smembers): Remove this...
	(ctf_copy_lmembers): ... and this...
	(ctf_emit_type_sect): ... folding into here. Figure out if a
	ctf_stype_t is needed here, not in ctf_add_*_sized.
	(ctf_type_sect_size): Figure out the ctf_stype_t stuff the same
	way here.
	* ctf-types.c (ctf_member_next): Remove the dmd path and always
	use the vlen.  Force large-structure usage for dynamic types.
	(ctf_type_align): Likewise.
	(ctf_member_info): Likewise.
	(ctf_type_rvisit): Likewise.
	* testsuite/libctf-regression/type-add-unnamed-struct-ctf.c: Add a
	self-referential type to this test.
	* testsuite/libctf-regression/type-add-unnamed-struct.c: Adjusted
	accordingly.
	* testsuite/libctf-regression/type-add-unnamed-struct.lk: Likewise.
---
 libctf/ctf-create.c                           | 260 ++++++---------
 libctf/ctf-impl.h                             |  14 -
 libctf/ctf-serialize.c                        | 117 +++----
 libctf/ctf-types.c                            | 298 +++++++-----------
 .../type-add-unnamed-struct-ctf.c             |   1 +
 .../type-add-unnamed-struct.c                 |   2 +-
 .../type-add-unnamed-struct.lk                |   1 +
 7 files changed, 283 insertions(+), 410 deletions(-)

diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 3218e3e31ea..e87b91e928e 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -30,6 +30,12 @@
 #define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
 #endif
 
+/* The initial size of a dynamic type's vlen in members.  Arbitrary: the bigger
+   this is, the less allocation needs to be done for small structure
+   initialization, and the more memory is wasted for small structures during CTF
+   construction.  No effect on generated CTF or ctf_open()ed CTF. */
+#define INITIAL_VLEN 16
+
 /* Make sure the ptrtab has enough space for at least one more type.
 
    We start with 4KiB of ptrtab, enough for a thousand types, then grow it 25%
@@ -244,7 +250,6 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 void
 ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
 {
-  ctf_dmdef_t *dmd, *nmd;
   int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
   size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
   int name_kind = kind;
@@ -256,14 +261,14 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
     {
     case CTF_K_STRUCT:
     case CTF_K_UNION:
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = nmd)
-	{
-	  if (dmd->dmd_name != NULL)
-	      free (dmd->dmd_name);
-	  nmd = ctf_list_next (dmd);
-	  free (dmd);
-	}
+      {
+	ctf_lmember_t *memb = (ctf_lmember_t *) dtd->dtd_vlen;
+	size_t i;
+
+	for (i = 0; i < vlen; i++)
+	  ctf_str_remove_ref (fp, ctf_strraw (fp, memb[i].ctlm_name),
+			      &memb[i].ctlm_name);
+      }
       break;
     case CTF_K_ENUM:
       {
@@ -797,6 +802,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
+  size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN;
 
   /* Promote root-visible forwards to structs.  */
   if (name != NULL)
@@ -805,19 +811,21 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_STRUCT,
-				    0, &dtd)) == CTF_ERR)
+				    initial_vlen, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us.  */
 
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
-
-  if (size > CTF_MAX_SIZE)
+  /* Forwards won't have any vlen yet.  */
+  if (dtd->dtd_vlen_alloc == 0)
     {
-      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
-      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+      if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
+	return (ctf_set_errno (fp, ENOMEM));
+      dtd->dtd_vlen_alloc = initial_vlen;
     }
-  else
-    dtd->dtd_data.ctt_size = (uint32_t) size;
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
+  dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+  dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+  dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
 
   return type;
 }
@@ -834,6 +842,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
+  size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN;
 
   /* Promote root-visible forwards to unions.  */
   if (name != NULL)
@@ -842,19 +851,21 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
     dtd = ctf_dtd_lookup (fp, type);
   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNION,
-				    0, &dtd)) == CTF_ERR)
+				    initial_vlen, &dtd)) == CTF_ERR)
     return CTF_ERR;		/* errno is set for us */
 
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
-
-  if (size > CTF_MAX_SIZE)
+  /* Forwards won't have any vlen yet.  */
+  if (dtd->dtd_vlen_alloc == 0)
     {
-      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
-      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+      if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
+	return (ctf_set_errno (fp, ENOMEM));
+      dtd->dtd_vlen_alloc = initial_vlen;
     }
-  else
-    dtd->dtd_data.ctt_size = (uint32_t) size;
+
+  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
+  dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+  dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
+  dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
 
   return type;
 }
@@ -870,7 +881,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
-  size_t initial_vlen = sizeof (ctf_enum_t) * 16;
+  size_t initial_vlen = sizeof (ctf_enum_t) * INITIAL_VLEN;
 
   /* Promote root-visible forwards to enums.  */
   if (name != NULL)
@@ -1066,12 +1077,13 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 		       ctf_id_t type, unsigned long bit_offset)
 {
   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid);
-  ctf_dmdef_t *dmd;
 
   ssize_t msize, malign, ssize;
   uint32_t kind, vlen, root;
-  char *s = NULL;
+  size_t i;
   int is_incomplete = 0;
+  unsigned char *old_vlen;
+  ctf_lmember_t *memb;
 
   if (!(fp->ctf_flags & LCTF_RDWR))
     return (ctf_set_errno (fp, ECTF_RDONLY));
@@ -1092,14 +1104,26 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   if (vlen == CTF_MAX_VLEN)
     return (ctf_set_errno (fp, ECTF_DTFULL));
 
+  old_vlen = dtd->dtd_vlen;
+  if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
+    return -1;					/* errno is set for us.  */
+  memb = (ctf_lmember_t *) dtd->dtd_vlen;
+
+  if (dtd->dtd_vlen != old_vlen)
+    {
+      ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen;
+
+      /* Remove pending refs in the old vlen region and reapply them.  */
+
+      for (i = 0; i < vlen; i++)
+	ctf_str_move_pending (fp, &memb[i].ctlm_name, move);
+    }
+
   if (name != NULL)
     {
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
-	{
-	  if (dmd->dmd_name != NULL && strcmp (dmd->dmd_name, name) == 0)
-	    return (ctf_set_errno (fp, ECTF_DUPLICATE));
-	}
+      for (i = 0; i < vlen; i++)
+	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
+	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
     }
 
   if ((msize = ctf_type_size (fp, type)) < 0 ||
@@ -1124,18 +1148,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	return -1;		/* errno is set for us.  */
     }
 
-  if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
-    return (ctf_set_errno (fp, EAGAIN));
-
-  if (name != NULL && (s = strdup (name)) == NULL)
-    {
-      free (dmd);
-      return (ctf_set_errno (fp, EAGAIN));
-    }
-
-  dmd->dmd_name = s;
-  dmd->dmd_type = type;
-  dmd->dmd_value = -1;
+  memb[vlen].ctlm_name = ctf_str_add_pending (fp, name, &memb[vlen].ctlm_name);
+  memb[vlen].ctlm_type = type;
+  if (memb[vlen].ctlm_name == 0 && name != NULL && name[0] != '\0')
+    return -1;			/* errno is set for us.  */
 
   if (kind == CTF_K_STRUCT && vlen != 0)
     {
@@ -1143,9 +1159,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	{
 	  /* Natural alignment.  */
 
-	  ctf_dmdef_t *lmd = ctf_list_prev (&dtd->dtd_u.dtu_members);
-	  ctf_id_t ltype = ctf_type_resolve (fp, lmd->dmd_type);
-	  size_t off = lmd->dmd_offset;
+	  ctf_id_t ltype = ctf_type_resolve (fp, memb[vlen - 1].ctlm_type);
+	  size_t off = CTF_LMEM_OFFSET(&memb[vlen - 1]);
 
 	  ctf_encoding_t linfo;
 	  ssize_t lsize;
@@ -1155,10 +1170,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	     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.  */
-	    }
+	    return -1;	/* errno is set for us.  */
 
 	  if (is_incomplete)
 	    {
@@ -1176,14 +1188,15 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 	    off += lsize * CHAR_BIT;
 	  else if (lsize == -1 && ctf_errno (fp) == ECTF_INCOMPLETE)
 	    {
+	      const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name);
+
 	      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
 			    _("ctf_add_member_offset: cannot add member %s of "
 			      "type %lx to struct %lx without specifying "
 			      "explicit offset after member %s of type %lx, "
 			      "which is an incomplete type\n"),
 			    name ? name : _("(unnamed member)"), type, souid,
-			    lmd->dmd_name ? lmd->dmd_name
-			    : _("(unnamed member)"), ltype);
+			    lname ? lname : _("(unnamed member)"), ltype);
 	      return -1;			/* errno is set for us.  */
 	    }
 
@@ -1198,36 +1211,32 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
 
 	  off = roundup (off, CHAR_BIT) / CHAR_BIT;
 	  off = roundup (off, MAX (malign, 1));
-	  dmd->dmd_offset = off * CHAR_BIT;
+	  memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (off * CHAR_BIT);
+	  memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (off * CHAR_BIT);
 	  ssize = off + msize;
 	}
       else
 	{
 	  /* Specified offset in bits.  */
 
-	  dmd->dmd_offset = bit_offset;
+	  memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (bit_offset);
+	  memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (bit_offset);
 	  ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
 	  ssize = MAX (ssize, ((signed) bit_offset / CHAR_BIT) + msize);
 	}
     }
   else
     {
-      dmd->dmd_offset = 0;
+      memb[vlen].ctlm_offsethi = 0;
+      memb[vlen].ctlm_offsetlo = 0;
       ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
       ssize = MAX (ssize, msize);
     }
 
-  if ((size_t) ssize > CTF_MAX_SIZE)
-    {
-      dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-      dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
-      dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize);
-    }
-  else
-    dtd->dtd_data.ctt_size = (uint32_t) ssize;
-
+  dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
+  dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
+  dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize);
   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
-  ctf_list_append (&dtd->dtd_u.dtu_members, dmd);
 
   fp->ctf_flags |= LCTF_DIRTY;
   return 0;
@@ -1411,41 +1420,6 @@ membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset,
   return 0;
 }
 
-static int
-membadd (const char *name, ctf_id_t type, unsigned long offset, void *arg)
-{
-  ctf_bundle_t *ctb = arg;
-  ctf_dmdef_t *dmd;
-  char *s = NULL;
-
-  if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL)
-    return (ctf_set_errno (ctb->ctb_dict, EAGAIN));
-
-  /* Unnamed members in non-dynamic dicts have a name of "", while dynamic dicts
-     use NULL.  Adapt.  */
-
-  if (name[0] == 0)
-    name = NULL;
-
-  if (name != NULL && (s = strdup (name)) == NULL)
-    {
-      free (dmd);
-      return (ctf_set_errno (ctb->ctb_dict, EAGAIN));
-    }
-
-  /* For now, dmd_type is copied as the src_fp's type; it is reset to an
-    equivalent dst_fp type by a final loop in ctf_add_type(), below.  */
-  dmd->dmd_name = s;
-  dmd->dmd_type = type;
-  dmd->dmd_offset = offset;
-  dmd->dmd_value = -1;
-
-  ctf_list_append (&ctb->ctb_dtd->dtd_u.dtu_members, dmd);
-
-  ctb->ctb_dict->ctf_flags |= LCTF_DIRTY;
-  return 0;
-}
-
 /* Record the correspondence between a source and ctf_add_type()-added
    destination type: both types are translated into parent type IDs if need be,
    so they relate to the actual dictionary they are in.  Outside controlled
@@ -1828,11 +1802,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
     case CTF_K_STRUCT:
     case CTF_K_UNION:
       {
-	ctf_dmdef_t *dmd;
-	int errs = 0;
-	size_t size;
-	ssize_t ssize;
-	ctf_dtdef_t *dtd;
+	ctf_next_t *i = NULL;
+	ssize_t offset;
+	const char *membname;
+	ctf_id_t src_membtype;
 
 	/* Technically to match a struct or union we need to check both
 	   ways (src members vs. dst, dst members vs. src) but we make
@@ -1867,67 +1840,44 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
 	    break;
 	  }
 
-	/* Unlike the other cases, copying structs and unions is done
-	   manually so as to avoid repeated lookups in ctf_add_member
-	   and to ensure the exact same member offsets as in src_type.  */
-
-	dst_type = ctf_add_generic (dst_fp, flag, name, kind, 0, &dtd);
+	dst_type = ctf_add_struct_sized (dst_fp, flag, name,
+					 ctf_type_size (src_fp, src_type));
 	if (dst_type == CTF_ERR)
 	  return CTF_ERR;			/* errno is set for us.  */
 
-	dst.ctb_type = dst_type;
-	dst.ctb_dtd = dtd;
-
 	/* Pre-emptively add this struct to the type mapping so that
 	   structures that refer to themselves work.  */
 	ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
 
-	if (ctf_member_iter (src_fp, src_type, membadd, &dst) != 0)
-	  errs++;	       /* Increment errs and fail at bottom of case.  */
-
-	if ((ssize = ctf_type_size (src_fp, src_type)) < 0)
-	  return CTF_ERR;			/* errno is set for us.  */
-
-	size = (size_t) ssize;
-	if (size > CTF_MAX_SIZE)
-	  {
-	    dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-	    dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
-	    dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
-	  }
-	else
-	  dtd->dtd_data.ctt_size = (uint32_t) size;
-
-	dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, vlen);
-
-	/* Make a final pass through the members changing each dmd_type (a
-	   src_fp type) to an equivalent type in dst_fp.  We pass through all
-	   members, leaving any that fail set to CTF_ERR, unless they fail
-	   because they are marking a member of type not representable in this
-	   version of CTF, in which case we just want to silently omit them:
-	   no consumer can do anything with them anyway.  */
-	for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	     dmd != NULL; dmd = ctf_list_next (dmd))
+	while ((offset = ctf_member_next (src_fp, src_type, &i, &membname,
+					  &src_membtype, 0)) >= 0)
 	  {
 	    ctf_dict_t *dst = dst_fp;
-	    ctf_id_t memb_type;
+	    ctf_id_t dst_membtype = ctf_type_mapping (src_fp, src_membtype, &dst);
 
-	    memb_type = ctf_type_mapping (src_fp, dmd->dmd_type, &dst);
-	    if (memb_type == 0)
+	    if (dst_membtype == 0)
 	      {
-		if ((dmd->dmd_type =
-		     ctf_add_type_internal (dst_fp, src_fp, dmd->dmd_type,
-					    proc_tracking_fp)) == CTF_ERR)
+		dst_membtype = ctf_add_type_internal (dst_fp, src_fp,
+						      src_membtype,
+						      proc_tracking_fp);
+		if (dst_membtype == CTF_ERR)
 		  {
 		    if (ctf_errno (dst_fp) != ECTF_NONREPRESENTABLE)
-		      errs++;
+		      {
+			ctf_next_destroy (i);
+			break;
+		      }
 		  }
 	      }
-	    else
-	      dmd->dmd_type = memb_type;
-	  }
 
-	if (errs)
+	    if (ctf_add_member_offset (dst_fp, dst_type, membname,
+				       dst_membtype, offset) < 0)
+	      {
+		ctf_next_destroy (i);
+		break;
+	      }
+	  }
+	if (ctf_errno (src_fp) != ECTF_NEXT_END)
 	  return CTF_ERR;			/* errno is set for us.  */
 	break;
       }
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 9a82d953ae8..87dd03b78fc 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -179,15 +179,6 @@ typedef struct ctf_decl
   int cd_enomem;		     /* Nonzero if OOM during printing.  */
 } ctf_decl_t;
 
-typedef struct ctf_dmdef
-{
-  ctf_list_t dmd_list;		/* List forward/back pointers.  */
-  char *dmd_name;		/* Name of this member.  */
-  ctf_id_t dmd_type;		/* Type of this member (for sou).  */
-  unsigned long dmd_offset;	/* Offset of this member in bits (for sou).  */
-  int dmd_value;		/* Value of this member (for enum).  */
-} ctf_dmdef_t;
-
 typedef struct ctf_dtdef
 {
   ctf_list_t dtd_list;		/* List forward/back pointers.  */
@@ -195,10 +186,6 @@ typedef struct ctf_dtdef
   ctf_type_t dtd_data;		/* Type node, including name.  */
   size_t dtd_vlen_alloc;	/* Total vlen space allocated.  */
   unsigned char *dtd_vlen;	/* Variable-length data for this type.  */
-  union
-  {
-    ctf_list_t dtu_members;	/* struct, union, or enum */
-  } dtd_u;
 } ctf_dtdef_t;
 
 typedef struct ctf_dvdef
@@ -557,7 +544,6 @@ struct ctf_next
   {
     const ctf_member_t *ctn_mp;
     const ctf_lmember_t *ctn_lmp;
-    const ctf_dmdef_t *ctn_dmd;
     const ctf_enum_t *ctn_en;
     const ctf_dvdef_t *ctn_dvd;
     ctf_next_hkv_t *ctn_sorted_hkv;
diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c
index 5d94f44b0d0..0811b7b6efe 100644
--- a/libctf/ctf-serialize.c
+++ b/libctf/ctf-serialize.c
@@ -719,57 +719,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;
-}
-
 /* Iterate through the dynamic type definition list and compute the
    size of the CTF type section.  */
 
@@ -784,8 +733,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 (lsize <= CTF_MAX_SIZE)
+	    type_ctt_size = lsize;
+	}
 
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+      if (type_ctt_size != CTF_LSIZE_SENT)
 	type_size += sizeof (ctf_stype_t);
       else
 	type_size += sizeof (ctf_type_t);
@@ -807,7 +768,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;
@@ -836,13 +797,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;
 
-      if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
+      /* 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 (type_ctt_size != CTF_LSIZE_SENT)
 	len = sizeof (ctf_stype_t);
       else
 	len = sizeof (ctf_type_t);
@@ -855,6 +827,7 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	  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)
@@ -880,12 +853,40 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr)
 	  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:
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index 49264ebf5ab..df7673ecd2e 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -101,24 +101,17 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 
       dtd = ctf_dynamic_type (fp, type);
       i->ctn_iter_fun = (void (*) (void)) ctf_member_next;
-
-      /* We depend below on the RDWR state indicating whether the DTD-related
-	 fields or the DMD-related fields have been initialized.  */
-
-      assert ((dtd && (fp->ctf_flags & LCTF_RDWR))
-	      || (!dtd && (!(fp->ctf_flags & LCTF_RDWR))));
+      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
 
       if (dtd == NULL)
 	{
-	  i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-
 	  if (i->ctn_size < CTF_LSTRUCT_THRESH)
 	    i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment);
 	  else
 	    i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment);
 	}
       else
-	i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
+	i->u.ctn_lmp = (const ctf_lmember_t *) dtd->dtd_vlen;
 
       *it = i;
     }
@@ -141,71 +134,46 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  retry:
   if (!i->ctn_type)
     {
-      if (!(fp->ctf_flags & LCTF_RDWR))
-	{
-	  if (i->ctn_n == 0)
-	    goto end_iter;
-
-	  if (i->ctn_size < CTF_LSTRUCT_THRESH)
-	    {
-	      const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
-
-	      if (name)
-		*name = membname;
-	      if (membtype)
-		*membtype = i->u.ctn_mp->ctm_type;
-	      offset = i->u.ctn_mp->ctm_offset;
-
-	      if (membname[0] == 0
-		  && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
-		      || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
-		i->ctn_type = i->u.ctn_mp->ctm_type;
+      if (i->ctn_n == 0)
+	goto end_iter;
 
-	      i->u.ctn_mp++;
-	    }
-	  else
-	    {
-	      const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
+      /* Dynamic structures in read-write dicts always use lmembers.  */
+      if (i->ctn_size < CTF_LSTRUCT_THRESH
+	  && !(fp->ctf_flags & LCTF_RDWR))
+	{
+	  const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
 
-	      if (name)
-		*name = membname;
-	      if (membtype)
-		*membtype = i->u.ctn_lmp->ctlm_type;
-	      offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
+	  if (name)
+	    *name = membname;
+	  if (membtype)
+	    *membtype = i->u.ctn_mp->ctm_type;
+	  offset = i->u.ctn_mp->ctm_offset;
 
-	      if (membname[0] == 0
-		  && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
-		      || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
-		i->ctn_type = i->u.ctn_lmp->ctlm_type;
+	  if (membname[0] == 0
+	      && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
+	    i->ctn_type = i->u.ctn_mp->ctm_type;
 
-	      i->u.ctn_lmp++;
-	    }
-	  i->ctn_n--;
+	  i->u.ctn_mp++;
 	}
       else
 	{
-	  if (i->u.ctn_dmd == NULL)
-	    goto end_iter;
-	  /* The dmd contains a NULL for unnamed dynamic members.  Don't inflict
-	     this on our callers.  */
+	  const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
+
 	  if (name)
-	    {
-	      if (i->u.ctn_dmd->dmd_name)
-		*name = i->u.ctn_dmd->dmd_name;
-	      else
-		*name = "";
-	    }
+	    *name = membname;
 	  if (membtype)
-	    *membtype = i->u.ctn_dmd->dmd_type;
-	  offset = i->u.ctn_dmd->dmd_offset;
+	    *membtype = i->u.ctn_lmp->ctlm_type;
+	  offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
 
-	  if (i->u.ctn_dmd->dmd_name == NULL
-	      && (ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_UNION))
-	    i->ctn_type = i->u.ctn_dmd->dmd_type;
+	  if (membname[0] == 0
+	      && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
+	    i->ctn_type = i->u.ctn_lmp->ctlm_type;
 
-	  i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd);
+	  i->u.ctn_lmp++;
 	}
+      i->ctn_n--;
 
       /* The callers might want automatic recursive sub-struct traversal.  */
       if (!(flags & CTF_MN_RECURSE))
@@ -996,53 +964,44 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_UNION:
       {
 	size_t align = 0;
+	int dynamic = 0;
 	ctf_dtdef_t *dtd;
 
-	if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-	  {
-	    uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-	    ssize_t size, increment;
-	    const void *vmp;
+	if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+	  dynamic = 1;
 
-	    (void) ctf_get_ctt_size (fp, tp, &size, &increment);
-	    vmp = (unsigned char *) tp + increment;
+	uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+	ssize_t size, increment;
+	const void *vmp;
 
-	    if (kind == CTF_K_STRUCT)
-	      n = MIN (n, 1);	/* Only use first member for structs.  */
+	(void) ctf_get_ctt_size (fp, tp, &size, &increment);
 
-	    if (size < CTF_LSTRUCT_THRESH)
-	      {
-		const ctf_member_t *mp = vmp;
-		for (; n != 0; n--, mp++)
-		  {
-		    ssize_t am = ctf_type_align (ofp, mp->ctm_type);
-		    align = MAX (align, (size_t) am);
-		  }
-	      }
-	    else
+	if (!dynamic)
+	  vmp = (unsigned char *) tp + increment;
+	else
+	  vmp = dtd->dtd_vlen;
+
+	if (kind == CTF_K_STRUCT)
+	  n = MIN (n, 1);	/* Only use first member for structs.  */
+
+	if (size < CTF_LSTRUCT_THRESH && !dynamic)
+	  {
+	    const ctf_member_t *mp = vmp;
+	    for (; n != 0; n--, mp++)
 	      {
-		const ctf_lmember_t *lmp = vmp;
-		for (; n != 0; n--, lmp++)
-		  {
-		    ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
-		    align = MAX (align, (size_t) am);
-		  }
+		ssize_t am = ctf_type_align (ofp, mp->ctm_type);
+		align = MAX (align, (size_t) am);
 	      }
 	  }
 	else
 	  {
-	      ctf_dmdef_t *dmd;
-
-	      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-		   dmd != NULL; dmd = ctf_list_next (dmd))
-		{
-		  ssize_t am = ctf_type_align (ofp, dmd->dmd_type);
-		  align = MAX (align, (size_t) am);
-		  if (kind == CTF_K_STRUCT)
-		    break;
-		}
+	    const ctf_lmember_t *lmp = vmp;
+	    for (; n != 0; n--, lmp++)
+	      {
+		ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
+		align = MAX (align, (size_t) am);
+	      }
 	  }
-
 	return align;
       }
 
@@ -1390,8 +1349,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
   ctf_dtdef_t *dtd;
+  const void *vmp;
   ssize_t size, increment;
   uint32_t kind, n;
+  int dynamic = 0;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1405,73 +1366,54 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
     return (ctf_set_errno (ofp, ECTF_NOTSOU));
 
-  if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
-    {
-      if (size < CTF_LSTRUCT_THRESH)
-	{
-	  const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
-							   increment);
+  if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
+    dynamic = 1;
 
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
-	    {
-	      const char *membname = ctf_strptr (fp, mp->ctm_name);
+  if (!dynamic)
+    vmp = (unsigned char *) tp + increment;
+  else
+    vmp = dtd->dtd_vlen;
 
-	      if (membname[0] == 0
-		  && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
-		      || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
-		  && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
-		return 0;
+  if (size < CTF_LSTRUCT_THRESH && !dynamic)
+    {
+      const ctf_member_t *mp = vmp;
 
-	      if (strcmp (membname, name) == 0)
-		{
-		  mip->ctm_type = mp->ctm_type;
-		  mip->ctm_offset = mp->ctm_offset;
-		  return 0;
-		}
-	    }
-	}
-      else
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
 	{
-	  const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
-							      increment);
+	  const char *membname = ctf_strptr (fp, mp->ctm_name);
 
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
-	    {
-	      const char *membname = ctf_strptr (fp, lmp->ctlm_name);
-
-	      if (membname[0] == 0
-		  && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
-		      || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
-		  && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
-		return 0;
+	  if (membname[0] == 0
+	      && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
+	      && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
+	    return 0;
 
-	      if (strcmp (membname, name) == 0)
-		{
-		  mip->ctm_type = lmp->ctlm_type;
-		  mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
-		  return 0;
-		}
+	  if (strcmp (membname, name) == 0)
+	    {
+	      mip->ctm_type = mp->ctm_type;
+	      mip->ctm_offset = mp->ctm_offset;
+	      return 0;
 	    }
 	}
     }
   else
     {
-      ctf_dmdef_t *dmd;
+      const ctf_lmember_t *lmp = vmp;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
 	{
-	  if (dmd->dmd_name == NULL
-	      && (ctf_type_kind (fp, dmd->dmd_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, dmd->dmd_type) == CTF_K_UNION)
-	      && (ctf_member_info (fp, dmd->dmd_type, name, mip) == 0))
+	  const char *membname = ctf_strptr (fp, lmp->ctlm_name);
+
+	  if (membname[0] == 0
+	      && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
+		  || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
+	      && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
 	    return 0;
 
-	  if (dmd->dmd_name != NULL
-	      && strcmp (dmd->dmd_name, name) == 0)
+	  if (strcmp (membname, name) == 0)
 	    {
-	      mip->ctm_type = dmd->dmd_type;
-	      mip->ctm_offset = dmd->dmd_offset;
+	      mip->ctm_type = lmp->ctlm_type;
+	      mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
 	      return 0;
 	    }
 	}
@@ -1688,8 +1630,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
   ctf_id_t otype = type;
   const ctf_type_t *tp;
   const ctf_dtdef_t *dtd;
+  const void *vmp;
   ssize_t size, increment;
   uint32_t kind, n;
+  int dynamic = 0;
   int rc;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
@@ -1708,48 +1652,38 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
 
   (void) ctf_get_ctt_size (fp, tp, &size, &increment);
 
-  if ((dtd = ctf_dynamic_type (fp, type)) == NULL)
+  if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
+    dynamic = 1;
+
+  if (!dynamic)
+    vmp = (unsigned char *) tp + increment;
+  else
+    vmp = dtd->dtd_vlen;
+
+  if (size < CTF_LSTRUCT_THRESH && !dynamic)
     {
-      if (size < CTF_LSTRUCT_THRESH)
-	{
-	  const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp +
-							   increment);
+      const ctf_member_t *mp = vmp;
 
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
-	    {
-	      if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
-					 func, arg, ctf_strptr (fp,
-								mp->ctm_name),
-					 offset + mp->ctm_offset,
-					 depth + 1)) != 0)
-		return rc;
-	    }
-	}
-      else
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
 	{
-	  const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp +
-							      increment);
-
-	  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
-	    {
-	      if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
-					 func, arg, ctf_strptr (fp,
-								lmp->ctlm_name),
-					 offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
-					 depth + 1)) != 0)
-		return rc;
-	    }
+	  if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
+				     func, arg, ctf_strptr (fp,
+							    mp->ctm_name),
+				     offset + mp->ctm_offset,
+				     depth + 1)) != 0)
+	    return rc;
 	}
     }
   else
     {
-      ctf_dmdef_t *dmd;
+      const ctf_lmember_t *lmp = vmp;
 
-      for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members);
-	   dmd != NULL; dmd = ctf_list_next (dmd))
+      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
 	{
-	  if ((rc = ctf_type_rvisit (fp, dmd->dmd_type, func, arg,
-				     dmd->dmd_name, dmd->dmd_offset,
+	  if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
+				     func, arg, ctf_strptr (fp,
+							    lmp->ctlm_name),
+				     offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
 				     depth + 1)) != 0)
 	    return rc;
 	}
diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c b/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c
index d319aafbac1..a1573a70059 100644
--- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c
+++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c
@@ -12,6 +12,7 @@ struct foo
     struct
     {
       int baz;
+      struct foo *foo;
     };
   };
 };
diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
index 43c3934add4..16ff0948b17 100644
--- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
+++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c
@@ -13,7 +13,7 @@ main (int argc, char *argv[])
   ctf_id_t newtype;
   const char *memb;
   ctf_membinfo_t mi;
-  const char *membs[] = { "bar", "baz", NULL };
+  const char *membs[] = { "bar", "baz", "foo", NULL };
   const char **walk;
   int err;
 
diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk
index caa8934ed2e..b818a2400a1 100644
--- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk
+++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk
@@ -1,3 +1,4 @@
 # source: type-add-unnamed-struct-ctf.c
 Looked up bar, type [0-9a-f]*, offset [0-9a-f]*
 Looked up baz, type [0-9a-f]*, offset [0-9a-f]*
+Looked up foo, type [0-9a-f]*, offset [0-9a-f]*
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 14/16] libctf: types: unify code dealing with small-vs-large struct members
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (12 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 13/16] libctf: eliminate dtd_u, part 5: structs / unions Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 15/16] libctf: a couple of small error-handling fixes Nick Alcock
  2021-03-06  0:40 ` [PATCH 16/16] libctf: support encodings for enums Nick Alcock
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

This completes the job of unifying what was once three separate code
paths full of duplication for every function dealing with querying the
properties of struct and union members.  The dynamic code path was
already removed: this change removes the distinction between small and
large members, by adding a helper that copies out members from the vlen,
expanding small members into large ones as it does so.

This makes it possible to have *more* representations of things like
structure members without needing to change the querying functions at
all.  It also lets us check for buffer overruns more effectively,
verifying that we don't accidentally overrun the end of the vlen in
either the dynamic or static type case.

libctf/ChangeLog
2021-03-04  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-impl.h (ctf_next_t) <ctn_tp>: New.
	<u.ctn_mp>: Remove.
	<u.ctn_lmp>: Remove.
	<u.ctn_vlen>: New.
	* ctf-types.c (ctf_struct_member): New.
	(ctf_member_next): Use it, dropping separate large/small code paths.
	(ctf_type_align): Likewise.
	(ctf_member_info): Likewise.
	(ctf_type_rvisit): Likewise.
---
 libctf/ctf-impl.h  |   4 +-
 libctf/ctf-types.c | 291 +++++++++++++++++++++------------------------
 2 files changed, 138 insertions(+), 157 deletions(-)

diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index 87dd03b78fc..ad4af32e7ee 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -530,6 +530,7 @@ struct ctf_next
   ctf_id_t ctn_type;
   ssize_t ctn_size;
   ssize_t ctn_increment;
+  const ctf_type_t *ctn_tp;
   uint32_t ctn_n;
 
   /* Some iterators contain other iterators, in addition to their other
@@ -542,8 +543,7 @@ struct ctf_next
      members, and the structure, variable and enum members, etc.  */
   union
   {
-    const ctf_member_t *ctn_mp;
-    const ctf_lmember_t *ctn_lmp;
+    unsigned char *ctn_vlen;
     const ctf_enum_t *ctn_en;
     const ctf_dvdef_t *ctn_dvd;
     ctf_next_hkv_t *ctn_sorted_hkv;
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index df7673ecd2e..ed76eca8463 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -35,6 +35,36 @@ ctf_type_ischild (ctf_dict_t * fp, ctf_id_t id)
   return (LCTF_TYPE_ISCHILD (fp, id));
 }
 
+/* Expand a structure element into the passed-in ctf_lmember_t.  */
+
+static int
+ctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp,
+		   unsigned char *vlen, size_t vbytes, size_t n)
+{
+  if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info)))
+    return -1;					/* errno is set for us.  */
+
+  /* Already large.  */
+  if (tp->ctt_size == CTF_LSIZE_SENT)
+    {
+      ctf_lmember_t *lmp = (ctf_lmember_t *) vlen;
+
+      if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes))
+	return -1;				/* errno is set for us.  */
+
+      memcpy (dst, &lmp[n], sizeof (ctf_lmember_t));
+    }
+  else
+    {
+      ctf_member_t *mp = (ctf_member_t *) vlen;
+      dst->ctlm_name = mp[n].ctm_name;
+      dst->ctlm_type = mp[n].ctm_type;
+      dst->ctlm_offsetlo = mp[n].ctm_offset;
+      dst->ctlm_offsethi = 0;
+    }
+  return 0;
+}
+
 /* Iterate over the members of a STRUCT or UNION.  We pass the name, member
    type, and offset of each member to the specified callback function.  */
 
@@ -72,12 +102,14 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   ctf_dict_t *ofp = fp;
   uint32_t kind;
   ssize_t offset;
+  uint32_t max_vlen;
   ctf_next_t *i = *it;
 
   if (!i)
     {
       const ctf_type_t *tp;
       ctf_dtdef_t *dtd;
+      ssize_t size;
       ssize_t increment;
 
       if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
@@ -89,8 +121,9 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
       if ((i = ctf_next_create ()) == NULL)
 	return ctf_set_errno (ofp, ENOMEM);
       i->cu.ctn_fp = ofp;
+      i->ctn_tp = tp;
 
-      (void) ctf_get_ctt_size (fp, tp, &i->ctn_size, &increment);
+      ctf_get_ctt_size (fp, tp, &size, &increment);
       kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
       if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
@@ -99,20 +132,20 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 	  return (ctf_set_errno (ofp, ECTF_NOTSOU));
 	}
 
-      dtd = ctf_dynamic_type (fp, type);
-      i->ctn_iter_fun = (void (*) (void)) ctf_member_next;
-      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-
-      if (dtd == NULL)
+      if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
 	{
-	  if (i->ctn_size < CTF_LSTRUCT_THRESH)
-	    i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment);
-	  else
-	    i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment);
+	  i->u.ctn_vlen = dtd->dtd_vlen;
+	  i->ctn_size = dtd->dtd_vlen_alloc;
 	}
       else
-	i->u.ctn_lmp = (const ctf_lmember_t *) dtd->dtd_vlen;
+	{
+	  unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info);
 
+	  i->u.ctn_vlen = (unsigned char *) tp + increment;
+	  i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);;
+	}
+      i->ctn_iter_fun = (void (*) (void)) ctf_member_next;
+      i->ctn_n = 0;
       *it = i;
     }
 
@@ -126,6 +159,8 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   if ((fp = ctf_get_dict (ofp, type)) == NULL)
     return (ctf_set_errno (ofp, ECTF_NOPARENT));
 
+  max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info);
+
   /* When we hit an unnamed struct/union member, we set ctn_type to indicate
      that we are inside one, then return the unnamed member: on the next call,
      we must skip over top-level member iteration in favour of iteration within
@@ -134,46 +169,29 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
  retry:
   if (!i->ctn_type)
     {
-      if (i->ctn_n == 0)
-	goto end_iter;
-
-      /* Dynamic structures in read-write dicts always use lmembers.  */
-      if (i->ctn_size < CTF_LSTRUCT_THRESH
-	  && !(fp->ctf_flags & LCTF_RDWR))
-	{
-	  const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name);
+      ctf_lmember_t memb;
+      const char *membname;
 
-	  if (name)
-	    *name = membname;
-	  if (membtype)
-	    *membtype = i->u.ctn_mp->ctm_type;
-	  offset = i->u.ctn_mp->ctm_offset;
-
-	  if (membname[0] == 0
-	      && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION))
-	    i->ctn_type = i->u.ctn_mp->ctm_type;
+      if (i->ctn_n == max_vlen)
+	goto end_iter;
 
-	  i->u.ctn_mp++;
-	}
-      else
-	{
-	  const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name);
+      if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size,
+			     i->ctn_n) < 0)
+	return -1;				/* errno is set for us.  */
 
-	  if (name)
-	    *name = membname;
-	  if (membtype)
-	    *membtype = i->u.ctn_lmp->ctlm_type;
-	  offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp);
+      membname = ctf_strptr (fp, memb.ctlm_name);
 
-	  if (membname[0] == 0
-	      && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION))
-	    i->ctn_type = i->u.ctn_lmp->ctlm_type;
+      if (name)
+	*name = membname;
+      if (membtype)
+	*membtype = memb.ctlm_type;
+      offset = (unsigned long) CTF_LMEM_OFFSET (&memb);
 
-	  i->u.ctn_lmp++;
-	}
-      i->ctn_n--;
+      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;
+      i->ctn_n++;
 
       /* The callers might want automatic recursive sub-struct traversal.  */
       if (!(flags & CTF_MN_RECURSE))
@@ -964,43 +982,36 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_UNION:
       {
 	size_t align = 0;
-	int dynamic = 0;
 	ctf_dtdef_t *dtd;
+	unsigned char *vlen;
+	uint32_t i = 0, n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+	ssize_t size, increment, vbytes;
 
-	if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
-	  dynamic = 1;
-
-	uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info);
-	ssize_t size, increment;
-	const void *vmp;
+	ctf_get_ctt_size (fp, tp, &size, &increment);
 
-	(void) ctf_get_ctt_size (fp, tp, &size, &increment);
-
-	if (!dynamic)
-	  vmp = (unsigned char *) tp + increment;
+	if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
+	  {
+	    vlen = dtd->dtd_vlen;
+	    vbytes = dtd->dtd_vlen_alloc;
+	  }
 	else
-	  vmp = dtd->dtd_vlen;
+	  {
+	    vlen = (unsigned char *) tp + increment;
+	    vbytes = LCTF_VBYTES (fp, kind, size, n);
+	  }
 
 	if (kind == CTF_K_STRUCT)
 	  n = MIN (n, 1);	/* Only use first member for structs.  */
 
-	if (size < CTF_LSTRUCT_THRESH && !dynamic)
+	for (; n != 0; n--, i++)
 	  {
-	    const ctf_member_t *mp = vmp;
-	    for (; n != 0; n--, mp++)
-	      {
-		ssize_t am = ctf_type_align (ofp, mp->ctm_type);
-		align = MAX (align, (size_t) am);
-	      }
-	  }
-	else
-	  {
-	    const ctf_lmember_t *lmp = vmp;
-	    for (; n != 0; n--, lmp++)
-	      {
-		ssize_t am = ctf_type_align (ofp, lmp->ctlm_type);
-		align = MAX (align, (size_t) am);
-	      }
+	    ctf_lmember_t memb;
+
+	    if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
+	      return -1;				/* errno is set for us.  */
+
+	    ssize_t am = ctf_type_align (ofp, memb.ctlm_type);
+	    align = MAX (align, (size_t) am);
 	  }
 	return align;
       }
@@ -1349,10 +1360,9 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
   ctf_dtdef_t *dtd;
-  const void *vmp;
-  ssize_t size, increment;
-  uint32_t kind, n;
-  int dynamic = 0;
+  unsigned char *vlen;
+  ssize_t size, increment, vbytes;
+  uint32_t kind, n, i = 0;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
     return -1;			/* errno is set for us.  */
@@ -1360,62 +1370,45 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
     return -1;			/* errno is set for us.  */
 
-  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+  ctf_get_ctt_size (fp, tp, &size, &increment);
   kind = LCTF_INFO_KIND (fp, tp->ctt_info);
 
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
     return (ctf_set_errno (ofp, ECTF_NOTSOU));
 
-  if ((dtd = ctf_dynamic_type (ofp, type)) != NULL)
-    dynamic = 1;
-
-  if (!dynamic)
-    vmp = (unsigned char *) tp + increment;
+  n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+  if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
+    {
+      vlen = dtd->dtd_vlen;
+      vbytes = dtd->dtd_vlen_alloc;
+    }
   else
-    vmp = dtd->dtd_vlen;
+    {
+      vlen = (unsigned char *) tp + increment;
+      vbytes = LCTF_VBYTES (fp, kind, size, n);
+    }
 
-  if (size < CTF_LSTRUCT_THRESH && !dynamic)
+  for (; n != 0; n--, i++)
     {
-      const ctf_member_t *mp = vmp;
+      ctf_lmember_t memb;
+      const char *membname;
 
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
-	{
-	  const char *membname = ctf_strptr (fp, mp->ctm_name);
+      if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
+	return -1;				/* errno is set for us.  */
 
-	  if (membname[0] == 0
-	      && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION)
-	      && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0))
-	    return 0;
+      membname = ctf_strptr (fp, memb.ctlm_name);
 
-	  if (strcmp (membname, name) == 0)
-	    {
-	      mip->ctm_type = mp->ctm_type;
-	      mip->ctm_offset = mp->ctm_offset;
-	      return 0;
-	    }
-	}
-    }
-  else
-    {
-      const ctf_lmember_t *lmp = vmp;
+      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))
+	return 0;
 
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
+      if (strcmp (membname, name) == 0)
 	{
-	  const char *membname = ctf_strptr (fp, lmp->ctlm_name);
-
-	  if (membname[0] == 0
-	      && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT
-		  || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION)
-	      && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0))
-	    return 0;
-
-	  if (strcmp (membname, name) == 0)
-	    {
-	      mip->ctm_type = lmp->ctlm_type;
-	      mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp);
-	      return 0;
-	    }
+	  mip->ctm_type = memb.ctlm_type;
+	  mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (&memb);
+	  return 0;
 	}
     }
 
@@ -1630,10 +1623,9 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
   ctf_id_t otype = type;
   const ctf_type_t *tp;
   const ctf_dtdef_t *dtd;
-  const void *vmp;
-  ssize_t size, increment;
-  uint32_t kind, n;
-  int dynamic = 0;
+  unsigned char *vlen;
+  ssize_t size, increment, vbytes;
+  uint32_t kind, n, i = 0;
   int rc;
 
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
@@ -1650,43 +1642,32 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
     return 0;
 
-  (void) ctf_get_ctt_size (fp, tp, &size, &increment);
+  ctf_get_ctt_size (fp, tp, &size, &increment);
 
+  n = LCTF_INFO_VLEN (fp, tp->ctt_info);
   if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
-    dynamic = 1;
-
-  if (!dynamic)
-    vmp = (unsigned char *) tp + increment;
-  else
-    vmp = dtd->dtd_vlen;
-
-  if (size < CTF_LSTRUCT_THRESH && !dynamic)
     {
-      const ctf_member_t *mp = vmp;
-
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++)
-	{
-	  if ((rc = ctf_type_rvisit (fp, mp->ctm_type,
-				     func, arg, ctf_strptr (fp,
-							    mp->ctm_name),
-				     offset + mp->ctm_offset,
-				     depth + 1)) != 0)
-	    return rc;
-	}
+      vlen = dtd->dtd_vlen;
+      vbytes = dtd->dtd_vlen_alloc;
     }
   else
     {
-      const ctf_lmember_t *lmp = vmp;
+      vlen = (unsigned char *) tp + increment;
+      vbytes = LCTF_VBYTES (fp, kind, size, n);
+    }
 
-      for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++)
-	{
-	  if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type,
-				     func, arg, ctf_strptr (fp,
-							    lmp->ctlm_name),
-				     offset + (unsigned long) CTF_LMEM_OFFSET (lmp),
-				     depth + 1)) != 0)
-	    return rc;
-	}
+  for (; n != 0; n--, i++)
+    {
+      ctf_lmember_t memb;
+
+      if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0)
+	return -1;				/* errno is set for us.  */
+
+      if ((rc = ctf_type_rvisit (fp, memb.ctlm_type,
+				 func, arg, ctf_strptr (fp, memb.ctlm_name),
+				 offset + (unsigned long) CTF_LMEM_OFFSET (&memb),
+				 depth + 1)) != 0)
+	return rc;
     }
 
   return 0;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 15/16] libctf: a couple of small error-handling fixes
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (13 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 14/16] libctf: types: unify code dealing with small-vs-large struct members Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  2021-03-06  0:40 ` [PATCH 16/16] libctf: support encodings for enums Nick Alcock
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

Out-of-memory errors initializing the string atoms table were
disregarded (though they would have caused a segfault very shortly
afterwards).  Errors hashing types during deduplication were only
reported if they happened on the output dict, which is almost never the
case (most errors are going to be on the dict we're working over, which
is going to be one of the inputs).  (The error was detected in both
cases, but the errno was extracted from the wrong dict.)

libctf/ChangeLog
2021-03-04  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-dedup.c (ctf_dedup_rhash_type): Report errors on the input
	dict properly.
	* ctf-open.c (ctf_bufopen_internal): Report errors initializing
	the atoms table.
---
 libctf/ctf-dedup.c | 21 ++++++++++++---------
 libctf/ctf-open.c  |  7 ++++++-
 2 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index b8a7d49b9db..572a68d57ad 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -572,7 +572,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
   char hashbuf[CTF_SHA1_SIZE];
   const char *hval = NULL;
   const char *whaterr;
-  int err;
+  int err = 0;
 
   const char *citer = NULL;
   ctf_dynset_t *citers = NULL;
@@ -697,7 +697,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	if (ctf_type_encoding (input, type, &ep) < 0)
 	  {
 	    whaterr = N_("error getting encoding");
-	    goto err;
+	    goto input_err;
 	  }
 	ctf_dedup_sha1_add (&hash, &ep, sizeof (ctf_encoding_t), "encoding",
 			    depth);
@@ -770,7 +770,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	if (ctf_array_info (input, type, &ar) < 0)
 	  {
 	    whaterr = N_("error getting array info");
-	    goto err;
+	    goto input_err;
 	  }
 
 	if ((hval = ctf_dedup_hash_type (fp, input, inputs, parents, input_num,
@@ -808,7 +808,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	if (ctf_func_type_info (input, type, &fi) < 0)
 	  {
 	    whaterr = N_("error getting func type info");
-	    goto err;
+	    goto input_err;
 	  }
 
 	if ((hval = ctf_dedup_hash_type (fp, input, inputs, parents, input_num,
@@ -828,6 +828,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 
 	if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
 	  {
+	    err = ENOMEM;
 	    whaterr = N_("error doing memory allocation");
 	    goto err;
 	  }
@@ -836,7 +837,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	  {
 	    free (args);
 	    whaterr = N_("error getting func arg type");
-	    goto err;
+	    goto input_err;
 	  }
 	for (j = 0; j < fi.ctc_argc; j++)
 	  {
@@ -871,7 +872,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	if (ctf_errno (input) != ECTF_NEXT_END)
 	  {
 	    whaterr = N_("error doing enum member iteration");
-	    goto err;
+	    goto input_err;
 	  }
 	break;
       }
@@ -916,7 +917,7 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 	if (ctf_errno (input) != ECTF_NEXT_END)
 	  {
 	    whaterr = N_("error doing struct/union member iteration");
-	    goto err;
+	    goto input_err;
 	  }
 	break;
       }
@@ -971,10 +972,12 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
 
  iterr:
   ctf_next_destroy (i);
+ input_err:
+  err = ctf_errno (input);
  err:
   ctf_sha1_fini (&hash, NULL);
-  ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
-			    "kind %i"), ctf_link_input_name (input),
+  ctf_err_warn (fp, 0, err, _("%s (%i): %s: during type hashing for type %lx, "
+			      "kind %i"), ctf_link_input_name (input),
 		input_num, gettext (whaterr), type, kind);
   return NULL;
  oom:
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index c2d9a33555a..8d11134f017 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -1545,7 +1545,12 @@ ctf_bufopen_internal (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect,
      ctf_set_base().  */
 
   ctf_set_version (fp, hp, hp->cth_version);
-  ctf_str_create_atoms (fp);
+  if (ctf_str_create_atoms (fp) < 0)
+    {
+      err = ENOMEM;
+      goto bad;
+    }
+
   fp->ctf_parmax = CTF_MAX_PTYPE;
   memcpy (&fp->ctf_data, ctfsect, sizeof (ctf_sect_t));
 
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 16/16] libctf: support encodings for enums
  2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
                   ` (14 preceding siblings ...)
  2021-03-06  0:40 ` [PATCH 15/16] libctf: a couple of small error-handling fixes Nick Alcock
@ 2021-03-06  0:40 ` Nick Alcock
  15 siblings, 0 replies; 23+ messages in thread
From: Nick Alcock @ 2021-03-06  0:40 UTC (permalink / raw)
  To: binutils

The previous commit started to error-check the lookup of
ctf_type_encoding for the underlying type that is internally done when
carrying out a ctf_type_encoding on a slice.

Unfortunately, enums have no encoding, so this has historically been
returning an error (which is ignored) and then populating the cte_format
with uninitialized data.  Now the error is not ignored, this is
returning an error, which breaks linking of CTF containing bitfields of
enumerated type.

CTF format v3 does not record the actual underlying type of a enum, but
we can mock up something that is not *too* wrong, and that is at any
rate better than uninitialized data.

ld/ChangeLog
2021-03-05  Nick Alcock  <nick.alcock@oracle.com>

	* testsuite/ld-ctf/slice.c: Check slices of enums too.
	* testsuite/ld-ctf/slice.d: Results adjusted.

libctf/ChangeLog
2021-03-05  Nick Alcock  <nick.alcock@oracle.com>

	* ctf-types.c (ctf_type_encoding): Support, after a fashion, for enums.
	* ctf-dump.c (ctf_dump_format_type): Do not report enums' degenerate
	encoding.
---
 ld/testsuite/ld-ctf/slice.c | 3 +++
 ld/testsuite/ld-ctf/slice.d | 4 ++--
 libctf/ctf-dump.c           | 5 ++++-
 libctf/ctf-types.c          | 8 +++++++-
 4 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/ld/testsuite/ld-ctf/slice.c b/ld/testsuite/ld-ctf/slice.c
index 7937bcf796e..fb38852142e 100644
--- a/ld/testsuite/ld-ctf/slice.c
+++ b/ld/testsuite/ld-ctf/slice.c
@@ -1,6 +1,9 @@
+enum foo { FOO_BAR };
+
 struct slices {
   int one : 1;
   int two : 2;
   int six : 6;
   int ten :10;
+  enum foo bar:1;
 } slices; 
diff --git a/ld/testsuite/ld-ctf/slice.d b/ld/testsuite/ld-ctf/slice.d
index d1167828f47..72a7074f9ef 100644
--- a/ld/testsuite/ld-ctf/slice.d
+++ b/ld/testsuite/ld-ctf/slice.d
@@ -15,7 +15,7 @@ Contents of CTF section .ctf:
     Compilation unit name: .*slice.c
 #...
     Data object section:	.* \(0x4 bytes\)
-    Type section:	.* \(0x9c bytes\)
+    Type section:	.* \(0xd0 bytes\)
     String section:	.*
 #...
   Data objects:
@@ -28,5 +28,5 @@ Contents of CTF section .ctf:
         *\[0x1\] two: ID 0x[0-9a-f]*: \(kind 1\) int:2 \[slice 0x1:0x2\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
         *\[0x3\] six: ID 0x[0-9a-f]*: \(kind 1\) int:6 \[slice 0x3:0x6\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
         *\[0x9\] ten: ID 0x[0-9a-f]*: \(kind 1\) int:10 \[slice 0x9:0xa\] \(format 0x1\) \(size 0x2\) \(aligned at 0x2\)
-
+        *\[0x13\] bar: ID 0x[0-9a-f]*: \(kind 8\) enum foo:1 \[slice 0x13:0x1\] \(format 0x1\) \(size 0x1\) \(aligned at 0x1\)
 #...
diff --git a/libctf/ctf-dump.c b/libctf/ctf-dump.c
index 409626a224b..8540212eadd 100644
--- a/libctf/ctf-dump.c
+++ b/libctf/ctf-dump.c
@@ -142,7 +142,10 @@ ctf_dump_format_type (ctf_dict_t *fp, ctf_id_t id, int flag)
       unsliced_kind = ctf_type_kind_unsliced (fp, id);
       kind = ctf_type_kind (fp, id);
 
-      if (ctf_type_encoding (fp, id, &ep) == 0)
+      /* Report encodings of everything with an encoding other than enums:
+	 base-type enums cannot have a nonzero cte_offset or cte_bits value.
+	 (Slices of them can, but they are of kind CTF_K_SLICE.)  */
+      if (unsliced_kind != CTF_K_ENUM && ctf_type_encoding (fp, id, &ep) == 0)
 	{
 	  if ((ssize_t) ep.cte_bits != ctf_type_size (fp, id) * CHAR_BIT
 	      && flag & CTF_FT_BITFIELD)
diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c
index ed76eca8463..9afe06ba112 100644
--- a/libctf/ctf-types.c
+++ b/libctf/ctf-types.c
@@ -1157,7 +1157,7 @@ ctf_type_pointer (ctf_dict_t *fp, ctf_id_t type)
   return (ctf_set_errno (ofp, ECTF_NOTYPE));
 }
 
-/* Return the encoding for the specified INTEGER or FLOAT.  */
+/* Return the encoding for the specified INTEGER, FLOAT, or ENUM.  */
 
 int
 ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
@@ -1194,6 +1194,12 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
       ep->cte_offset = CTF_FP_OFFSET (data);
       ep->cte_bits = CTF_FP_BITS (data);
       break;
+    case CTF_K_ENUM:
+      /* v3 only: we must guess at the underlying integral format.  */
+      ep->cte_format = CTF_INT_SIGNED;
+      ep->cte_offset = 0;
+      ep->cte_bits = 0;
+      break;
     case CTF_K_SLICE:
       {
 	const ctf_slice_t *slice;
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PING] [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-06  0:40 ` [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd Nick Alcock
@ 2021-03-15 13:11   ` Nick Alcock
  2021-03-17 14:23     ` Nick Alcock
  0 siblings, 1 reply; 23+ messages in thread
From: Nick Alcock @ 2021-03-15 13:11 UTC (permalink / raw)
  To: binutils

On 6 Mar 2021, Nick Alcock via Binutils spake thusly:

> This stops problems parallel-installing if a relink of libctf is needed.

OK, this has now been tested by the original reporter and works. This
unblocks this patch series as far as I'm concerned.

This probably needs review from Alan, since it touches ld's dependencies
and even adds one non-ctf-related one that seems to have been missing
beforehand (ld -> bfd).

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PING] [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-15 13:11   ` [PING] " Nick Alcock
@ 2021-03-17 14:23     ` Nick Alcock
  2021-03-17 18:34       ` [PATCH v2 " Nick Alcock
  0 siblings, 1 reply; 23+ messages in thread
From: Nick Alcock @ 2021-03-17 14:23 UTC (permalink / raw)
  To: binutils

On 15 Mar 2021, Nick Alcock via Binutils uttered the following:

> On 6 Mar 2021, Nick Alcock via Binutils spake thusly:
>
>> This stops problems parallel-installing if a relink of libctf is needed.
>
> OK, this has now been tested by the original reporter and works. This
> unblocks this patch series as far as I'm concerned.

.... aaand no sooner did I say that than it was pointed out that
install-strip is distinct from install and needs more rules, so this is
not quite good enough. Will post a v2 soon.

-- 
NULL && (void)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-17 14:23     ` Nick Alcock
@ 2021-03-17 18:34       ` Nick Alcock
  2021-03-18  9:25         ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Nick Alcock @ 2021-03-17 18:34 UTC (permalink / raw)
  To: binutils

This stops problems parallel-installing if a relink of libctf is needed.

Also adds corresponding install-strip dependencies.

ChangeLog
2021-03-02  Nick Alcock  <nick.alcock@oracle.com>

	PR libctf/27482
	* Makefile.def: Add install-bfd dependencies for install-libctf and
	install-ld, and install-strip-bfd dependencies for
	install-strip-libctf and install-strip-ld; move the install-ld
	dependency on install-libctf to join it.
	* Makefile.in: Regenerated.
---
 ChangeLog    | 9 +++++++++
 Makefile.def | 9 ++++++++-
 Makefile.in  | 7 ++++++-
 3 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4cd48fa1dad..1ca90147388 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
+
+	PR libctf/27482
+	* Makefile.def: Add install-bfd dependencies for install-libctf and
+	install-ld, and install-strip-bfd dependencies for
+	install-strip-libctf and install-strip-ld; move the install-ld
+	dependency on install-libctf to join it.
+	* Makefile.in: Regenerated.
+
 2021-02-28  H.J. Lu  <hongjiu.lu@intel.com>
 
 	PR binutils/26766
diff --git a/Makefile.def b/Makefile.def
index b45e580da5b..eb15489390e 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -448,7 +448,6 @@ dependencies = { module=all-binutils; on=all-intl; };
 dependencies = { module=all-binutils; on=all-gas; };
 dependencies = { module=all-binutils; on=all-libctf; };
 dependencies = { module=all-ld; on=all-libctf; };
-dependencies = { module=install-ld; on=install-libctf; };
 
 // We put install-opcodes before install-binutils because the installed
 // binutils might be on PATH, and they might need the shared opcodes
@@ -456,6 +455,14 @@ dependencies = { module=install-ld; on=install-libctf; };
 dependencies = { module=install-binutils; on=install-opcodes; };
 dependencies = { module=install-strip-binutils; on=install-strip-opcodes; };
 
+// Likewise for ld, libctf, and bfd.
+dependencies = { module=install-libctf; on=install-bfd; };
+dependencies = { module=install-ld; on=install-bfd; };
+dependencies = { module=install-ld; on=install-libctf; };
+dependencies = { module=install-strip-libctf; on=install-strip-bfd; };
+dependencies = { module=install-strip-ld; on=install-strip-bfd; };
+dependencies = { module=install-strip-ld; on=install-strip-libctf; };
+
 // libopcodes depends on libbfd
 dependencies = { module=install-opcodes; on=install-bfd; };
 dependencies = { module=install-strip-opcodes; on=install-strip-bfd; };
diff --git a/Makefile.in b/Makefile.in
index 0a64fc10e5b..b5de5ecd7b9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -52170,9 +52170,14 @@ all-stage3-ld: maybe-all-stage3-libctf
 all-stage4-ld: maybe-all-stage4-libctf
 all-stageprofile-ld: maybe-all-stageprofile-libctf
 all-stagefeedback-ld: maybe-all-stagefeedback-libctf
-install-ld: maybe-install-libctf
 install-binutils: maybe-install-opcodes
 install-strip-binutils: maybe-install-strip-opcodes
+install-libctf: maybe-install-bfd
+install-ld: maybe-install-bfd
+install-ld: maybe-install-libctf
+install-strip-libctf: maybe-install-strip-bfd
+install-strip-ld: maybe-install-strip-bfd
+install-strip-ld: maybe-install-strip-libctf
 install-opcodes: maybe-install-bfd
 install-strip-opcodes: maybe-install-strip-bfd
 configure-gas: maybe-configure-intl
-- 
2.30.0.252.gc27e85e57d


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-17 18:34       ` [PATCH v2 " Nick Alcock
@ 2021-03-18  9:25         ` Alan Modra
  2021-03-18 12:30           ` Nick Alcock
  0 siblings, 1 reply; 23+ messages in thread
From: Alan Modra @ 2021-03-18  9:25 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

On Wed, Mar 17, 2021 at 06:34:09PM +0000, Nick Alcock via Binutils wrote:
> This stops problems parallel-installing if a relink of libctf is needed.
> 
> Also adds corresponding install-strip dependencies.
> 
> ChangeLog
> 2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
> 
> 	PR libctf/27482
> 	* Makefile.def: Add install-bfd dependencies for install-libctf and
> 	install-ld, and install-strip-bfd dependencies for
> 	install-strip-libctf and install-strip-ld; move the install-ld
> 	dependency on install-libctf to join it.
> 	* Makefile.in: Regenerated.

OK, thanks.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-18  9:25         ` Alan Modra
@ 2021-03-18 12:30           ` Nick Alcock
  2021-03-19  1:24             ` Alan Modra
  0 siblings, 1 reply; 23+ messages in thread
From: Nick Alcock @ 2021-03-18 12:30 UTC (permalink / raw)
  To: Alan Modra; +Cc: binutils

On 18 Mar 2021, Alan Modra spake thusly:

> On Wed, Mar 17, 2021 at 06:34:09PM +0000, Nick Alcock via Binutils wrote:
>> This stops problems parallel-installing if a relink of libctf is needed.
>> 
>> Also adds corresponding install-strip dependencies.
>> 
>> ChangeLog
>> 2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
>> 
>> 	PR libctf/27482
>> 	* Makefile.def: Add install-bfd dependencies for install-libctf and
>> 	install-ld, and install-strip-bfd dependencies for
>> 	install-strip-libctf and install-strip-ld; move the install-ld
>> 	dependency on install-libctf to join it.
>> 	* Makefile.in: Regenerated.
>
> OK, thanks.

This one probably needs to go into 2.36 too, since that's where the bug
was raised: I assume that's fine.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 09/16] Add install dependencies for ld -> bfd and libctf -> bfd
  2021-03-18 12:30           ` Nick Alcock
@ 2021-03-19  1:24             ` Alan Modra
  0 siblings, 0 replies; 23+ messages in thread
From: Alan Modra @ 2021-03-19  1:24 UTC (permalink / raw)
  To: Nick Alcock; +Cc: binutils

On Thu, Mar 18, 2021 at 12:30:05PM +0000, Nick Alcock wrote:
> On 18 Mar 2021, Alan Modra spake thusly:
> 
> > On Wed, Mar 17, 2021 at 06:34:09PM +0000, Nick Alcock via Binutils wrote:
> >> This stops problems parallel-installing if a relink of libctf is needed.
> >> 
> >> Also adds corresponding install-strip dependencies.
> >> 
> >> ChangeLog
> >> 2021-03-02  Nick Alcock  <nick.alcock@oracle.com>
> >> 
> >> 	PR libctf/27482
> >> 	* Makefile.def: Add install-bfd dependencies for install-libctf and
> >> 	install-ld, and install-strip-bfd dependencies for
> >> 	install-strip-libctf and install-strip-ld; move the install-ld
> >> 	dependency on install-libctf to join it.
> >> 	* Makefile.in: Regenerated.
> >
> > OK, thanks.
> 
> This one probably needs to go into 2.36 too, since that's where the bug
> was raised: I assume that's fine.

Yes, I'd say so.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2021-03-19  1:24 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-06  0:40 [PATCH 00/16] libctf: mostly cleanups and refactoring Nick Alcock
2021-03-06  0:40 ` [PATCH 01/16] libctf: fix some tabdamage and move some code around Nick Alcock
2021-03-06  0:40 ` [PATCH 02/16] libctf: split serialization and file writeout into its own file Nick Alcock
2021-03-06  0:40 ` [PATCH 03/16] libctf: fix comment above ctf_dict_t Nick Alcock
2021-03-06  0:40 ` [PATCH 04/16] libctf: split up ctf_serialize Nick Alcock
2021-03-06  0:40 ` [PATCH 05/16] libctf: fix GNU style for do {} while Nick Alcock
2021-03-06  0:40 ` [PATCH 06/16] libctf: eliminate dtd_u, part 1: int/float/slice Nick Alcock
2021-03-06  0:40 ` [PATCH 07/16] libctf: eliminate dtd_u, part 2: arrays Nick Alcock
2021-03-06  0:40 ` [PATCH 08/16] libctf: eliminate dtd_u, part 3: functions Nick Alcock
2021-03-06  0:40 ` [PATCH 09/16] Add install dependencies for ld -> bfd and libctf -> bfd Nick Alcock
2021-03-15 13:11   ` [PING] " Nick Alcock
2021-03-17 14:23     ` Nick Alcock
2021-03-17 18:34       ` [PATCH v2 " Nick Alcock
2021-03-18  9:25         ` Alan Modra
2021-03-18 12:30           ` Nick Alcock
2021-03-19  1:24             ` Alan Modra
2021-03-06  0:40 ` [PATCH 10/16] libctf: don't lose track of all valid types upon serialization Nick Alcock
2021-03-06  0:40 ` [PATCH 11/16] libctf: do not corrupt strings across ctf_serialize Nick Alcock
2021-03-06  0:40 ` [PATCH 12/16] libctf: eliminate dtd_u, part 4: enums Nick Alcock
2021-03-06  0:40 ` [PATCH 13/16] libctf: eliminate dtd_u, part 5: structs / unions Nick Alcock
2021-03-06  0:40 ` [PATCH 14/16] libctf: types: unify code dealing with small-vs-large struct members Nick Alcock
2021-03-06  0:40 ` [PATCH 15/16] libctf: a couple of small error-handling fixes Nick Alcock
2021-03-06  0:40 ` [PATCH 16/16] libctf: support encodings for enums Nick Alcock

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).