mmo.c leak in mmo_make_section
[binutils-gdb.git] / libctf / ctf-dedup.c
index b58b815b84d38203a94394f9abf7accf58cb08e2..dcde3e88c6f150485fb9fce646b423bdaed30122 100644 (file)
@@ -1,5 +1,5 @@
 /* CTF type deduplication.
-   Copyright (C) 2019 Free Software Foundation, Inc.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
 
    This file is part of libctf.
 
@@ -55,7 +55,7 @@
    *global type ID* or 'GID', a pair of an array offset and a ctf_id_t.  Since
    both are already 32 bits or less or can easily be constrained to that range,
    we can pack them both into a single 64-bit hash word for easy lookups, which
-   would be much more annoying to do with a ctf_file_t * and a ctf_id_t.  (On
+   would be much more annoying to do with a ctf_dict_t * and a ctf_id_t.  (On
    32-bit platforms, we must do that anyway, since pointers, and thus hash keys
    and values, are only 32 bits wide).  We track which inputs are parents of
    which other inputs so that we can correctly recognize that types we have
     approach, but with a smaller key, this is all we can do.  */
 
 static void *
-id_to_packed_id (ctf_file_t *fp, int input_num, ctf_id_t type)
+id_to_packed_id (ctf_dict_t *fp, int input_num, ctf_id_t type)
 {
   const void *lookup;
   ctf_type_id_key_t *dynkey = NULL;
   ctf_type_id_key_t key = { input_num, type };
 
-  if (!ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_file_t,
+  if (!ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_dict_t,
                              &key, &lookup, NULL))
     {
       if ((dynkey = malloc (sizeof (ctf_type_id_key_t))) == NULL)
        goto oom;
       memcpy (dynkey, &key, sizeof (ctf_type_id_key_t));
 
-      if (ctf_dynhash_insert (fp->ctf_dedup.cd_id_to_file_t, dynkey, NULL) < 0)
+      if (ctf_dynhash_insert (fp->ctf_dedup.cd_id_to_dict_t, dynkey, NULL) < 0)
        goto oom;
 
-      ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_file_t,
+      ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_dict_t,
                             dynkey, &lookup, NULL);
     }
   /* We use a raw assert() here because there isn't really a way to get any sort
@@ -352,7 +352,7 @@ make_set_element (ctf_dynhash_t *set, const void *key)
   if ((element = ctf_dynhash_lookup (set, key)) == NULL)
     {
       if ((element = ctf_dynset_create (htab_hash_string,
-                                       ctf_dynset_eq_string,
+                                       htab_eq_string,
                                        NULL)) == NULL)
        return NULL;
 
@@ -368,7 +368,7 @@ make_set_element (ctf_dynhash_t *set, const void *key)
 
 /* Initialize the dedup atoms table.  */
 int
-ctf_dedup_atoms_init (ctf_file_t *fp)
+ctf_dedup_atoms_init (ctf_dict_t *fp)
 {
   if (fp->ctf_dedup_atoms)
     return 0;
@@ -376,7 +376,7 @@ ctf_dedup_atoms_init (ctf_file_t *fp)
   if (!fp->ctf_dedup_atoms_alloc)
     {
       if ((fp->ctf_dedup_atoms_alloc
-          = ctf_dynset_create (htab_hash_string, ctf_dynset_eq_string,
+          = ctf_dynset_create (htab_hash_string, htab_eq_string,
                                free)) == NULL)
        return ctf_set_errno (fp, ENOMEM);
     }
@@ -387,7 +387,7 @@ ctf_dedup_atoms_init (ctf_file_t *fp)
 /* Intern things in the dedup atoms table.  */
 
 static const char *
-intern (ctf_file_t *fp, char *atom)
+intern (ctf_dict_t *fp, char *atom)
 {
   const void *foo;
 
@@ -414,7 +414,7 @@ intern (ctf_file_t *fp, char *atom)
    while allowing for the four C namespaces (normal, struct, union, enum).
    Return a new dynamically-allocated string.  */
 static const char *
-ctf_decorate_type_name (ctf_file_t *fp, const char *name, int kind)
+ctf_decorate_type_name (ctf_dict_t *fp, const char *name, int kind)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   const char *ret;
@@ -484,13 +484,13 @@ ctf_dedup_sha1_add (ctf_sha1_t *sha1, const void *buf, size_t len,
 }
 
 static const char *
-ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
-                    ctf_file_t **inputs, uint32_t *parents,
+ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
+                    ctf_dict_t **inputs, uint32_t *parents,
                     int input_num, ctf_id_t type, int flags,
                     unsigned long depth,
-                    int (*populate_fun) (ctf_file_t *fp,
-                                         ctf_file_t *input,
-                                         ctf_file_t **inputs,
+                    int (*populate_fun) (ctf_dict_t *fp,
+                                         ctf_dict_t *input,
+                                         ctf_dict_t **inputs,
                                          int input_num,
                                          ctf_id_t type,
                                          void *id,
@@ -519,7 +519,7 @@ ctf_dedup_is_stub (const char *name, int kind, int fwdkind, int flags)
    Only called for forwards or forwardable types with names, when the link mode
    is CTF_LINK_SHARE_DUPLICATED.  */
 static int
-ctf_dedup_record_origin (ctf_file_t *fp, int input_num, const char *decorated,
+ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
                         void *id)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
@@ -551,14 +551,14 @@ ctf_dedup_record_origin (ctf_file_t *fp, int input_num, const char *decorated,
    calls, recursively).  */
 
 static const char *
-ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
+ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
                      uint32_t *parents, int input_num, ctf_id_t type,
                      void *type_id, const ctf_type_t *tp, const char *name,
                      const char *decorated, int kind, int flags,
                      unsigned long depth,
-                     int (*populate_fun) (ctf_file_t *fp,
-                                          ctf_file_t *input,
-                                          ctf_file_t **inputs,
+                     int (*populate_fun) (ctf_dict_t *fp,
+                                          ctf_dict_t *input,
+                                          ctf_dict_t **inputs,
                                           int input_num,
                                           ctf_id_t type,
                                           void *id,
@@ -572,7 +572,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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;
@@ -584,12 +584,13 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
       whaterr = N_("error updating citers");                           \
       if (!citers)                                                     \
        if ((citers = ctf_dynset_create (htab_hash_string,              \
-                                         ctf_dynset_eq_string,         \
-                                         NULL)) == NULL)               \
+                                        htab_eq_string,                \
+                                        NULL)) == NULL)                \
          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
@@ -638,6 +639,27 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
        && ctf_dedup_record_origin (fp, input_num, decorated, type_id) < 0)
       return NULL;                             /* errno is set for us.  */
 
+#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
+  ctf_dprintf ("%lu: hashing thing with ID %i/%lx (kind %i): %s.\n",
+              depth, input_num, type, kind, name ? name : "");
+#endif
+
+  /* Some type kinds don't have names: the API provides no way to set the name,
+     so the type the deduplicator outputs will be nameless even if the input
+     somehow has a name, and the name should not be mixed into the hash.  */
+
+  switch (kind)
+    {
+    case CTF_K_POINTER:
+    case CTF_K_ARRAY:
+    case CTF_K_FUNCTION:
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+    case CTF_K_SLICE:
+      name = NULL;
+    }
+
   /* Mix in invariant stuff, transforming the type kind if needed.  Note that
      the vlen is *not* hashed in: the actual variable-length info is hashed in
      instead, piecewise.  The vlen is not part of the type, only the
@@ -647,11 +669,6 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
      *other types in the same TU* with the same name: so two types can easily
      have distinct nonroot flags, yet be exactly the same type.*/
 
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
-  ctf_dprintf ("%lu: hashing thing with ID %i/%lx (kind %i): %s.\n",
-              depth, input_num, type, kind, name ? name : "");
-#endif
-
   ctf_sha1_init (&hash);
   if (name)
     ctf_dedup_sha1_add (&hash, name, strlen (name) + 1, "name", depth);
@@ -680,7 +697,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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);
@@ -735,7 +752,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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);
 
@@ -753,7 +770,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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,
@@ -791,7 +808,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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,
@@ -811,6 +828,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
 
        if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
          {
+           err = ENOMEM;
            whaterr = N_("error doing memory allocation");
            goto err;
          }
@@ -819,7 +837,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
          {
            free (args);
            whaterr = N_("error getting func arg type");
-           goto err;
+           goto input_err;
          }
        for (j = 0; j < fi.ctc_argc; j++)
          {
@@ -854,7 +872,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
        if (ctf_errno (input) != ECTF_NEXT_END)
          {
            whaterr = N_("error doing enum member iteration");
-           goto err;
+           goto input_err;
          }
        break;
       }
@@ -871,8 +889,8 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
        ctf_dedup_sha1_add (&hash, &size, sizeof (ssize_t), "struct size",
                            depth);
 
-       while ((offset = ctf_member_next (input, type, &i, &mname,
-                                         &membtype)) >= 0)
+       while ((offset = ctf_member_next (input, type, &i, &mname, &membtype,
+                                         0)) >= 0)
          {
            if (mname == NULL)
              mname = "";
@@ -899,7 +917,7 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
        if (ctf_errno (input) != ECTF_NEXT_END)
          {
            whaterr = N_("error doing struct/union member iteration");
-           goto err;
+           goto input_err;
          }
        break;
       }
@@ -954,10 +972,12 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_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:
@@ -990,13 +1010,13 @@ ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
    Returns a hash value (an atom), or NULL on error.  */
 
 static const char *
-ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
-                    ctf_file_t **inputs, uint32_t *parents,
+ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
+                    ctf_dict_t **inputs, uint32_t *parents,
                     int input_num, ctf_id_t type, int flags,
                     unsigned long depth,
-                    int (*populate_fun) (ctf_file_t *fp,
-                                         ctf_file_t *input,
-                                         ctf_file_t **inputs,
+                    int (*populate_fun) (ctf_dict_t *fp,
+                                         ctf_dict_t *input,
+                                         ctf_dict_t **inputs,
                                          int input_num,
                                          ctf_id_t type,
                                          void *id,
@@ -1044,10 +1064,6 @@ ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
   if (tp->ctt_name == 0 || !name || name[0] == '\0')
     name = NULL;
 
-  /* Treat the unknown kind just like the unimplemented type.  */
-  if (kind == CTF_K_UNKNOWN)
-    return "00000000000000000000";
-
   /* Decorate the name appropriately for the namespace it appears in: forwards
      appear in the namespace of their referent.  */
 
@@ -1139,8 +1155,8 @@ ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
    cd_output_first_tu mapping.  */
 
 static int
-ctf_dedup_populate_mappings (ctf_file_t *fp, ctf_file_t *input _libctf_unused_,
-                            ctf_file_t **inputs _libctf_unused_,
+ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
+                            ctf_dict_t **inputs _libctf_unused_,
                             int input_num _libctf_unused_,
                             ctf_id_t type _libctf_unused_, void *id,
                             const char *decorated_name,
@@ -1212,7 +1228,7 @@ ctf_dedup_populate_mappings (ctf_file_t *fp, ctf_file_t *input _libctf_unused_,
 
       while ((err = ctf_dynset_cnext (type_ids, &i, &one_id)) == 0)
        {
-         ctf_file_t *foo = inputs[CTF_DEDUP_GID_TO_INPUT (one_id)];
+         ctf_dict_t *foo = inputs[CTF_DEDUP_GID_TO_INPUT (one_id)];
          ctf_id_t bar = CTF_DEDUP_GID_TO_TYPE (one_id);
          if (ctf_type_kind_unsliced (foo, bar) != orig_kind)
            {
@@ -1285,7 +1301,7 @@ ctf_dedup_populate_mappings (ctf_file_t *fp, ctf_file_t *input _libctf_unused_,
    ctf_dedup_maybe_synthesize_forward.)  */
 
 static int
-ctf_dedup_mark_conflicting_hash (ctf_file_t *fp, const char *hval)
+ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   ctf_next_t *i = NULL;
@@ -1331,7 +1347,7 @@ ctf_dedup_mark_conflicting_hash (ctf_file_t *fp, const char *hval)
 
 /* Look up a type kind from the output mapping, given a type hash value.  */
 static int
-ctf_dedup_hash_kind (ctf_file_t *fp, ctf_file_t **inputs, const char *hash)
+ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   void *id;
@@ -1363,8 +1379,8 @@ ctf_dedup_hash_kind (ctf_file_t *fp, ctf_file_t **inputs, const char *hash)
 /* Used to keep a count of types: i.e. distinct type hash values.  */
 typedef struct ctf_dedup_type_counter
 {
-  ctf_file_t *fp;
-  ctf_file_t **inputs;
+  ctf_dict_t *fp;
+  ctf_dict_t **inputs;
   int num_non_forwards;
 } ctf_dedup_type_counter_t;
 
@@ -1401,7 +1417,7 @@ ctf_dedup_count_types (void *key_, void *value _libctf_unused_, void *arg_)
 /* Detect name ambiguity and mark ambiguous names as conflicting, other than the
    most common.  */
 static int
-ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
+ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   ctf_next_t *i = NULL;
@@ -1486,12 +1502,17 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
             the most-popular type on insertion, and we want conflicting structs
             et al to have all forwards left intact, so the user is notified
             that this type is conflicting.  TODO: improve this in future by
-            setting such forwards non-root-visible.)  */
+            setting such forwards non-root-visible.)
+
+            If multiple distinct types are "most common", pick the one that
+            appears first on the link line, and within that, the one with the
+            lowest type ID.  (See sort_output_mapping.)  */
 
          const void *key;
          const void *count;
          const char *hval;
          long max_hcount = -1;
+         void *max_gid = NULL;
          const char *max_hval = NULL;
 
          if (ctf_dynhash_elements (name_counts) <= 1)
@@ -1501,10 +1522,24 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
          while ((err = ctf_dynhash_cnext (name_counts, &j, &key, &count)) == 0)
            {
              hval = (const char *) key;
+
              if ((long int) (uintptr_t) count > max_hcount)
                {
                  max_hcount = (long int) (uintptr_t) count;
                  max_hval = hval;
+                 max_gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+               }
+             else if ((long int) (uintptr_t) count == max_hcount)
+               {
+                 void *gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+
+                 if (CTF_DEDUP_GID_TO_INPUT(gid) < CTF_DEDUP_GID_TO_INPUT(max_gid)
+                     || (CTF_DEDUP_GID_TO_INPUT(gid) == CTF_DEDUP_GID_TO_INPUT(max_gid)
+                         && CTF_DEDUP_GID_TO_TYPE(gid) < CTF_DEDUP_GID_TO_TYPE(max_gid)))
+                   {
+                     max_hval = hval;
+                     max_gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+                   }
                }
            }
          if (err != ECTF_NEXT_END)
@@ -1560,7 +1595,7 @@ ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
 /* Initialize the deduplication machinery.  */
 
 static int
-ctf_dedup_init (ctf_file_t *fp)
+ctf_dedup_init (ctf_dict_t *fp)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   size_t i;
@@ -1569,7 +1604,7 @@ ctf_dedup_init (ctf_file_t *fp)
       goto oom;
 
 #if IDS_NEED_ALLOCATION
-  if ((d->cd_id_to_file_t = ctf_dynhash_create (ctf_hash_type_id_key,
+  if ((d->cd_id_to_dict_t = ctf_dynhash_create (ctf_hash_type_id_key,
                                                ctf_hash_eq_type_id_key,
                                                free, NULL)) == NULL)
     goto oom;
@@ -1626,6 +1661,12 @@ ctf_dedup_init (ctf_file_t *fp)
     goto oom;
 #endif
 
+  if ((d->cd_input_nums
+       = ctf_dynhash_create (ctf_hash_integer,
+                            ctf_hash_eq_integer,
+                            NULL, NULL)) == NULL)
+    goto oom;
+
   if ((d->cd_emission_struct_members
        = ctf_dynhash_create (ctf_hash_integer,
                             ctf_hash_eq_integer,
@@ -1634,7 +1675,7 @@ ctf_dedup_init (ctf_file_t *fp)
 
   if ((d->cd_conflicting_types
        = ctf_dynset_create (htab_hash_string,
-                           ctf_dynset_eq_string, NULL)) == NULL)
+                           htab_eq_string, NULL)) == NULL)
     goto oom;
 
   return 0;
@@ -1645,15 +1686,17 @@ ctf_dedup_init (ctf_file_t *fp)
   return ctf_set_errno (fp, ENOMEM);
 }
 
+/* No ctf_dedup calls are allowed after this call other than starting a new
+   deduplication via ctf_dedup (not even ctf_dedup_type_mapping lookups).  */
 void
-ctf_dedup_fini (ctf_file_t *fp, ctf_file_t **outputs, uint32_t noutputs)
+ctf_dedup_fini (ctf_dict_t *fp, ctf_dict_t **outputs, uint32_t noutputs)
 {
   ctf_dedup_t *d = &fp->ctf_dedup;
   size_t i;
 
   /* ctf_dedup_atoms is kept across links.  */
 #if IDS_NEED_ALLOCATION
-  ctf_dynhash_destroy (d->cd_id_to_file_t);
+  ctf_dynhash_destroy (d->cd_id_to_dict_t);
 #endif
   for (i = 0; i < 4; i++)
     ctf_dynhash_destroy (d->cd_decorated_names[i]);
@@ -1666,6 +1709,7 @@ ctf_dedup_fini (ctf_file_t *fp, ctf_file_t **outputs, uint32_t noutputs)
 #ifdef ENABLE_LIBCTF_HASH_DEBUGGING
   ctf_dynhash_destroy (d->cd_output_mapping_guard);
 #endif
+  ctf_dynhash_destroy (d->cd_input_nums);
   ctf_dynhash_destroy (d->cd_emission_struct_members);
   ctf_dynset_destroy (d->cd_conflicting_types);
 
@@ -1677,7 +1721,7 @@ ctf_dedup_fini (ctf_file_t *fp, ctf_file_t **outputs, uint32_t noutputs)
          ctf_dedup_t *od = &outputs[i]->ctf_dedup;
          ctf_dynhash_destroy (od->cd_output_emission_hashes);
          ctf_dynhash_destroy (od->cd_output_emission_conflicted_forwards);
-         ctf_file_close (od->cd_output);
+         ctf_dict_close (od->cd_output);
        }
     }
   memset (d, 0, sizeof (ctf_dedup_t));
@@ -1686,16 +1730,16 @@ ctf_dedup_fini (ctf_file_t *fp, ctf_file_t **outputs, uint32_t noutputs)
 /* Return 1 if this type is cited by multiple input dictionaries.  */
 
 static int
-ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
                                const char *hval)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
   ctf_dynset_t *type_ids;
   ctf_next_t *i = NULL;
   void *id;
-  ctf_file_t *found = NULL, *relative_found = NULL;
+  ctf_dict_t *found = NULL, *relative_found = NULL;
   const char *type_id;
-  ctf_file_t *input_fp;
+  ctf_dict_t *input_fp;
   ctf_id_t input_id;
   const char *name;
   const char *decorated;
@@ -1714,7 +1758,7 @@ ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
 
   while ((err = ctf_dynset_next (type_ids, &i, &id)) == 0)
     {
-      ctf_file_t *fp = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
+      ctf_dict_t *fp = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
 
       if (fp == found || fp == relative_found)
        continue;
@@ -1760,7 +1804,7 @@ ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
   name = ctf_type_name_raw (input_fp, input_id);
 
   if ((fwdkind == CTF_K_STRUCT || fwdkind == CTF_K_UNION)
-      && name && name[0] != '\0')
+      && name[0] != '\0')
     {
       const void *origin;
 
@@ -1781,7 +1825,7 @@ ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
    types.  Only used if the link mode is CTF_LINK_SHARE_DUPLICATED.  */
 
 static int
-ctf_dedup_conflictify_unshared (ctf_file_t *output, ctf_file_t **inputs)
+ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
   ctf_next_t *i = NULL;
@@ -1789,7 +1833,7 @@ ctf_dedup_conflictify_unshared (ctf_file_t *output, ctf_file_t **inputs)
   const void *k;
   ctf_dynset_t *to_mark = NULL;
 
-  if ((to_mark = ctf_dynset_create (htab_hash_string, ctf_dynset_eq_string,
+  if ((to_mark = ctf_dynset_create (htab_hash_string, htab_eq_string,
                                    NULL)) == NULL)
     goto err_no;
 
@@ -1853,19 +1897,29 @@ ctf_dedup_conflictify_unshared (ctf_file_t *output, ctf_file_t **inputs)
    ctf_dedup_emit afterwards to do that.  */
 
 int
-ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
+ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
           uint32_t *parents, int cu_mapped)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
   size_t i;
   ctf_next_t *it = NULL;
 
-  for (i = 0; i < ninputs; i++)
-    ctf_dprintf ("Input %i: %s\n", (int) i, ctf_link_input_name (inputs[i]));
-
   if (ctf_dedup_init (output) < 0)
     return -1;                                         /* errno is set for us.  */
 
+  for (i = 0; i < ninputs; i++)
+    {
+      ctf_dprintf ("Input %i: %s\n", (int) i, ctf_link_input_name (inputs[i]));
+      if (ctf_dynhash_insert (d->cd_input_nums, inputs[i],
+                             (void *) (uintptr_t) i) < 0)
+       {
+         ctf_set_errno (output, errno);
+         ctf_err_warn (output, 0, errno, _("ctf_dedup: cannot initialize: %s\n"),
+                       ctf_errmsg (errno));
+         goto err;
+       }
+    }
+
   /* Some flags do not apply when CU-mapping: this is not a duplicated link,
      because there is only one output and we really don't want to end up marking
      all nonconflicting but appears-only-once types as conflicting (which in the
@@ -1889,15 +1943,17 @@ ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
 
       while ((id = ctf_type_next (inputs[i], &it, NULL, 1)) != CTF_ERR)
        {
-         ctf_dedup_hash_type (output, inputs[i], inputs, parents,
-                              i, id, 0, 0, ctf_dedup_populate_mappings);
+         if (ctf_dedup_hash_type (output, inputs[i], inputs,
+                                  parents, i, id, 0, 0,
+                                  ctf_dedup_populate_mappings) == NULL)
+           goto err;                           /* errno is set for us.  */
        }
       if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
        {
          ctf_set_errno (output, ctf_errno (inputs[i]));
          ctf_err_warn (output, 0, 0, _("iteration failure "
                                        "computing type hashes"));
-         return -1;
+         goto err;
        }
     }
 
@@ -1908,7 +1964,7 @@ ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
 
   ctf_dprintf ("Detecting type name ambiguity\n");
   if (ctf_dedup_detect_name_ambiguity (output, inputs) < 0)
-    return -1;                                 /* errno is set for us.  */
+      goto err;                                        /* errno is set for us.  */
 
   /* If the link mode is CTF_LINK_SHARE_DUPLICATED, we change any unconflicting
      types whose output mapping references only one input dict into a
@@ -1918,23 +1974,27 @@ ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
     {
       ctf_dprintf ("Conflictifying unshared types\n");
       if (ctf_dedup_conflictify_unshared (output, inputs) < 0)
-       return -1;                              /* errno is set for us.  */
+       goto err;                               /* errno is set for us.  */
     }
   return 0;
+
+ err:
+  ctf_dedup_fini (output, NULL, 0);
+  return -1;
 }
 
 static int
-ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
                                uint32_t ninputs, uint32_t *parents,
                                ctf_dynset_t *already_visited,
                                const char *hval,
                                int (*visit_fun) (const char *hval,
-                                                 ctf_file_t *output,
-                                                 ctf_file_t **inputs,
+                                                 ctf_dict_t *output,
+                                                 ctf_dict_t **inputs,
                                                  uint32_t ninputs,
                                                  uint32_t *parents,
                                                  int already_visited,
-                                                 ctf_file_t *input,
+                                                 ctf_dict_t *input,
                                                  ctf_id_t type,
                                                  void *id,
                                                  int depth,
@@ -1944,19 +2004,19 @@ ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
 /* Like ctf_dedup_rwalk_output_mapping (which see), only takes a single target
    type and visits it.  */
 static int
-ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
-                                   ctf_file_t **inputs, uint32_t ninputs,
+ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
+                                   ctf_dict_t **inputs, uint32_t ninputs,
                                    uint32_t *parents,
                                    ctf_dynset_t *already_visited,
                                    int visited, void *type_id,
                                    const char *hval,
                                    int (*visit_fun) (const char *hval,
-                                                     ctf_file_t *output,
-                                                     ctf_file_t **inputs,
+                                                     ctf_dict_t *output,
+                                                     ctf_dict_t **inputs,
                                                      uint32_t ninputs,
                                                      uint32_t *parents,
                                                      int already_visited,
-                                                     ctf_file_t *input,
+                                                     ctf_dict_t *input,
                                                      ctf_id_t type,
                                                      void *id,
                                                      int depth,
@@ -1964,7 +2024,7 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
                                    void *arg, unsigned long depth)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
-  ctf_file_t *fp;
+  ctf_dict_t *fp;
   int input_num;
   ctf_id_t type;
   int ret;
@@ -1988,48 +2048,48 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_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))
     {
     case CTF_K_UNKNOWN:
-      /* Just skip things of unknown kind.  */
-      return 0;
     case CTF_K_FORWARD:
     case CTF_K_INTEGER:
     case CTF_K_FLOAT:
@@ -2128,17 +2188,17 @@ ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
    once, but are not recursed through repeatedly: ALREADY_VISITED tracks whether
    types have already been visited.  */
 static int
-ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
                                uint32_t ninputs, uint32_t *parents,
                                ctf_dynset_t *already_visited,
                                const char *hval,
                                int (*visit_fun) (const char *hval,
-                                                 ctf_file_t *output,
-                                                 ctf_file_t **inputs,
+                                                 ctf_dict_t *output,
+                                                 ctf_dict_t **inputs,
                                                  uint32_t ninputs,
                                                  uint32_t *parents,
                                                  int already_visited,
-                                                 ctf_file_t *input,
+                                                 ctf_dict_t *input,
                                                  ctf_id_t type,
                                                  void *id,
                                                  int depth,
@@ -2222,7 +2282,7 @@ ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
 
 typedef struct ctf_sort_om_cb_arg
 {
-  ctf_file_t **inputs;
+  ctf_dict_t **inputs;
   uint32_t ninputs;
   ctf_dedup_t *d;
 } ctf_sort_om_cb_arg_t;
@@ -2241,8 +2301,8 @@ sort_output_mapping (const ctf_next_hkv_t *one, const ctf_next_hkv_t *two,
   void *one_gid, *two_gid;
   uint32_t one_ninput;
   uint32_t two_ninput;
-  ctf_file_t *one_fp;
-  ctf_file_t *two_fp;
+  ctf_dict_t *one_fp;
+  ctf_dict_t *two_fp;
   ctf_id_t one_type;
   ctf_id_t two_type;
 
@@ -2288,15 +2348,15 @@ sort_output_mapping (const ctf_next_hkv_t *one, const ctf_next_hkv_t *two,
 
 /* The public entry point to ctf_dedup_rwalk_output_mapping, above.  */
 static int
-ctf_dedup_walk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
                               uint32_t ninputs, uint32_t *parents,
                               int (*visit_fun) (const char *hval,
-                                                ctf_file_t *output,
-                                                ctf_file_t **inputs,
+                                                ctf_dict_t *output,
+                                                ctf_dict_t **inputs,
                                                 uint32_t ninputs,
                                                 uint32_t *parents,
                                                 int already_visited,
-                                                ctf_file_t *input,
+                                                ctf_dict_t *input,
                                                 ctf_id_t type,
                                                 void *id,
                                                 int depth,
@@ -2310,7 +2370,7 @@ ctf_dedup_walk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
   void *k;
 
   if ((already_visited = ctf_dynset_create (htab_hash_string,
-                                           ctf_dynset_eq_string,
+                                           htab_eq_string,
                                            NULL)) == NULL)
     return ctf_set_errno (output, ENOMEM);
 
@@ -2351,28 +2411,27 @@ ctf_dedup_walk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
    conflicted per-TU type ID in INPUT with hash HVAL.  Return its CTF ID, or 0
    if none was needed.  */
 static ctf_id_t
-ctf_dedup_maybe_synthesize_forward (ctf_file_t *output, ctf_file_t *target,
-                                   ctf_file_t *input, ctf_id_t id,
+ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
+                                   ctf_dict_t *input, ctf_id_t id,
                                    const char *hval)
 {
   ctf_dedup_t *od = &output->ctf_dedup;
   ctf_dedup_t *td = &target->ctf_dedup;
   int kind;
   int fwdkind;
-  const char *name;
+  const char *name = ctf_type_name_raw (input, id);
   const char *decorated;
   void *v;
   ctf_id_t emitted_forward;
 
   if (!ctf_dynset_exists (od->cd_conflicting_types, hval, NULL)
       || target->ctf_flags & LCTF_CHILD
-      || !ctf_type_name_raw (input, id)
+      || name[0] == '\0'
       || (((kind = ctf_type_kind_unsliced (input, id)) != CTF_K_STRUCT
           && kind != CTF_K_UNION && kind != CTF_K_FORWARD)))
     return 0;
 
   fwdkind = ctf_type_kind_forwarded (input, id);
-  name = ctf_type_name_raw (input, id);
 
   ctf_dprintf ("Using synthetic forward for conflicted struct/union with "
               "hval %s\n", hval);
@@ -2430,14 +2489,14 @@ ctf_dedup_maybe_synthesize_forward (ctf_file_t *output, ctf_file_t *target,
    make usability a bit better.  */
 
 static ctf_id_t
-ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
-                       ctf_file_t **inputs, uint32_t ninputs,
-                       uint32_t *parents, ctf_file_t *input, int input_num,
+ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
+                       ctf_dict_t **inputs, uint32_t ninputs,
+                       uint32_t *parents, ctf_dict_t *input, int input_num,
                        ctf_id_t id)
 {
   ctf_dedup_t *od = &output->ctf_dedup;
   ctf_dedup_t *td = &target->ctf_dedup;
-  ctf_file_t *err_fp = input;
+  ctf_dict_t *err_fp = input;
   const char *hval;
   void *target_id;
   ctf_id_t emitted_forward;
@@ -2535,7 +2594,7 @@ ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
    have already been emitted.  (This type itself may also have been emitted.)
 
    If the ARG is 1, this is a CU-mapped deduplication round mapping many
-   ctf_file_t's into precisely one: conflicting types should be marked
+   ctf_dict_t's into precisely one: conflicting types should be marked
    non-root-visible.  If the ARG is 0, conflicting types go into per-CU
    dictionaries stored in the input's ctf_dedup.cd_output: otherwise, everything
    is emitted directly into the output.  No struct/union members are emitted.
@@ -2546,16 +2605,16 @@ ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
    data object section, backtrace section etc).  */
 
 static int
-ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
                     uint32_t ninputs, uint32_t *parents, int already_visited,
-                    ctf_file_t *input, ctf_id_t type, void *id, int depth,
+                    ctf_dict_t *input, ctf_id_t type, void *id, int depth,
                     void *arg)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
   int kind = ctf_type_kind_unsliced (input, type);
   const char *name;
-  ctf_file_t *target = output;
-  ctf_file_t *real_input;
+  ctf_dict_t *target = output;
+  ctf_dict_t *real_input;
   const ctf_type_t *tp;
   int input_num = CTF_DEDUP_GID_TO_INPUT (id);
   int output_num = (uint32_t) -1;              /* 'shared' */
@@ -2612,6 +2671,8 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
          ctf_parent_name_set (target, _CTF_SECTION);
 
          input->ctf_dedup.cd_output = target;
+         input->ctf_link_in_out = target;
+         target->ctf_link_in_out = input;
        }
       output_num = input_num;
     }
@@ -2656,9 +2717,11 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
   switch (kind)
     {
     case CTF_K_UNKNOWN:
-      /* These are types that CTF cannot encode, marked as such by the compile.
-        We intentionally do not re-emit these.  */
-      new_type = 0;
+      /* These are types that CTF cannot encode, marked as such by the
+        compiler.  */
+      errtype = _("unknown type");
+      if ((new_type = ctf_add_unknown (target, isroot, name)) == CTF_ERR)
+       goto err_target;
       break;
     case CTF_K_FORWARD:
       /* This will do nothing if the type to which this forwards already exists,
@@ -2844,7 +2907,10 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
                     id, out_id);
        /* Record the need to emit the members of this structure later.  */
        if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
-         goto err_target;
+         {
+           ctf_set_errno (target, errno);
+           goto err_target;
+         }
        break;
       }
     default:
@@ -2896,14 +2962,14 @@ ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
    point.  */
 
 static int
-ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
                               uint32_t ninputs, uint32_t *parents)
 {
   ctf_dedup_t *d = &output->ctf_dedup;
   ctf_next_t *i = NULL;
   void *input_id, *target_id;
   int err;
-  ctf_file_t *err_fp, *input_fp;
+  ctf_dict_t *err_fp, *input_fp;
   int input_num;
   ctf_id_t err_type;
 
@@ -2911,7 +2977,7 @@ ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
                                  &input_id, &target_id)) == 0)
     {
       ctf_next_t *j = NULL;
-      ctf_file_t *target;
+      ctf_dict_t *target;
       uint32_t target_num;
       ctf_id_t input_type, target_type;
       ssize_t offset;
@@ -2940,7 +3006,7 @@ ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
       target_type = CTF_DEDUP_GID_TO_TYPE (target_id);
 
       while ((offset = ctf_member_next (input_fp, input_type, &j, &name,
-                                       &membtype)) >= 0)
+                                       &membtype, 0)) >= 0)
        {
          err_fp = target;
          err_type = target_type;
@@ -2988,100 +3054,6 @@ ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
   return ctf_set_errno (output, err);
 }
 
-/* Populate the type mapping used by the types in one FP (which must be an input
-   dict containing a non-null cd_output resulting from a ctf_dedup_emit_type
-   walk).  */
-static int
-ctf_dedup_populate_type_mapping (ctf_file_t *shared, ctf_file_t *fp,
-                                ctf_file_t **inputs)
-{
-  ctf_dedup_t *d = &shared->ctf_dedup;
-  ctf_file_t *output = fp->ctf_dedup.cd_output;
-  const void *k, *v;
-  ctf_next_t *i = NULL;
-  int err;
-
-  /* The shared dict (the output) stores its types in the fp itself, not in a
-     separate cd_output dict.  */
-  if (shared == fp)
-    output = fp;
-
-  /* There may be no types to emit at all, or all the types in this TU may be
-     shared.  */
-  if (!output || !output->ctf_dedup.cd_output_emission_hashes)
-    return 0;
-
-  while ((err = ctf_dynhash_cnext (output->ctf_dedup.cd_output_emission_hashes,
-                                 &i, &k, &v)) == 0)
-    {
-      const char *hval = (const char *) k;
-      ctf_id_t id_out = (ctf_id_t) (uintptr_t) v;
-      ctf_next_t *j = NULL;
-      ctf_dynset_t *type_ids;
-      const void *id;
-
-      type_ids = ctf_dynhash_lookup (d->cd_output_mapping, hval);
-      if (!ctf_assert (shared, type_ids))
-       return -1;
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
-      ctf_dprintf ("Traversing emission hash: hval %s\n", hval);
-#endif
-
-      while ((err = ctf_dynset_cnext (type_ids, &j, &id)) == 0)
-       {
-         ctf_file_t *input = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
-         ctf_id_t id_in = CTF_DEDUP_GID_TO_TYPE (id);
-
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
-         ctf_dprintf ("Adding mapping from %i/%lx to %lx\n",
-                      CTF_DEDUP_GID_TO_INPUT (id), id_in, id_out);
-#endif
-         ctf_add_type_mapping (input, id_in, output, id_out);
-       }
-      if (err != ECTF_NEXT_END)
-       {
-         ctf_next_destroy (i);
-         goto err;
-       }
-    }
-  if (err != ECTF_NEXT_END)
-    goto err;
-
-  return 0;
-
- err:
-  ctf_err_warn (shared, 0, err, _("iteration error populating the type mapping"));
-  return ctf_set_errno (shared, err);
-}
-
-/* Populate the type mapping machinery used by the rest of the linker,
-   by ctf_add_type, etc.  */
-static int
-ctf_dedup_populate_type_mappings (ctf_file_t *output, ctf_file_t **inputs,
-                                 uint32_t ninputs)
-{
-  size_t i;
-
-  if (ctf_dedup_populate_type_mapping (output, output, inputs) < 0)
-    {
-      ctf_err_warn (output, 0, 0, _("cannot populate type mappings for shared "
-                                   "CTF dict"));
-      return -1;                               /* errno is set for us.  */
-    }
-
-  for (i = 0; i < ninputs; i++)
-    {
-      if (ctf_dedup_populate_type_mapping (output, inputs[i], inputs) < 0)
-       {
-         ctf_err_warn (output, 0, ctf_errno (inputs[i]),
-                       _("cannot populate type mappings for per-CU CTF dict"));
-         return ctf_set_errno (output, ctf_errno (inputs[i]));
-       }
-    }
-
-  return 0;
-}
-
 /* Emit deduplicated types into the outputs.  The shared type repository is
    OUTPUT, on which the ctf_dedup function must have already been called.  The
    PARENTS array contains the INPUTS index of the parent dict for every child
@@ -3094,13 +3066,13 @@ ctf_dedup_populate_type_mappings (ctf_file_t *output, ctf_file_t **inputs,
    If CU_MAPPED is set, this is a first pass for a link with a non-empty CU
    mapping: only one output will result.  */
 
-ctf_file_t **
-ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
+ctf_dict_t **
+ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
                uint32_t *parents, uint32_t *noutputs, int cu_mapped)
 {
   size_t num_outputs = 1;              /* Always at least one output: us.  */
-  ctf_file_t **outputs;
-  ctf_file_t **walk;
+  ctf_dict_t **outputs;
+  ctf_dict_t **walk;
   size_t i;
 
   ctf_dprintf ("Triggering emission.\n");
@@ -3112,9 +3084,6 @@ ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
   if (ctf_dedup_emit_struct_members (output, inputs, ninputs, parents) < 0)
     return NULL;                               /* errno is set for us.  */
 
-  if (ctf_dedup_populate_type_mappings (output, inputs, ninputs) < 0)
-    return NULL;                               /* errno is set for us.  */
-
   for (i = 0; i < ninputs; i++)
     {
       if (inputs[i]->ctf_dedup.cd_output)
@@ -3124,7 +3093,7 @@ ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
   if (!ctf_assert (output, !cu_mapped || (cu_mapped && num_outputs == 1)))
     return NULL;
 
-  if ((outputs = calloc (num_outputs, sizeof (ctf_file_t *))) == NULL)
+  if ((outputs = calloc (num_outputs, sizeof (ctf_dict_t *))) == NULL)
     {
       ctf_err_warn (output, 0, ENOMEM,
                    _("out of memory allocating link outputs array"));
@@ -3148,6 +3117,76 @@ ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
        }
     }
 
-  ctf_dedup_fini (output, outputs, num_outputs);
   return outputs;
 }
+
+/* Determine what type SRC_FP / SRC_TYPE was emitted as in the FP, which
+   must be the shared dict or have it as a parent: return 0 if none.  The SRC_FP
+   must be a past input to ctf_dedup.  */
+
+ctf_id_t
+ctf_dedup_type_mapping (ctf_dict_t *fp, ctf_dict_t *src_fp, ctf_id_t src_type)
+{
+  ctf_dict_t *output = NULL;
+  ctf_dedup_t *d;
+  int input_num;
+  void *num_ptr;
+  void *type_ptr;
+  int found;
+  const char *hval;
+
+  /* It is an error (an internal error in the caller, in ctf-link.c) to call
+     this with an FP that is not a per-CU output or shared output dict, or with
+     a SRC_FP that was not passed to ctf_dedup as an input; it is an internal
+     error in ctf-dedup for the type passed not to have been hashed, though if
+     the src_fp is a child dict and the type is not a child type, it will have
+     been hashed under the GID corresponding to the parent.  */
+
+  if (fp->ctf_dedup.cd_type_hashes != NULL)
+    output = fp;
+  else if (fp->ctf_parent && fp->ctf_parent->ctf_dedup.cd_type_hashes != NULL)
+    output = fp->ctf_parent;
+  else
+    {
+      ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_err_warn (fp, 0, ECTF_INTERNAL,
+                   _("dict %p passed to ctf_dedup_type_mapping is not a "
+                     "deduplicated output"), (void *) fp);
+      return CTF_ERR;
+    }
+
+  if (src_fp->ctf_parent && ctf_type_isparent (src_fp, src_type))
+    src_fp = src_fp->ctf_parent;
+
+  d = &output->ctf_dedup;
+
+  found = ctf_dynhash_lookup_kv (d->cd_input_nums, src_fp, NULL, &num_ptr);
+  if (!ctf_assert (output, found != 0))
+    return CTF_ERR;                            /* errno is set for us.  */
+  input_num = (uintptr_t) num_ptr;
+
+  hval = ctf_dynhash_lookup (d->cd_type_hashes,
+                            CTF_DEDUP_GID (output, input_num, src_type));
+
+  if (!ctf_assert (output, hval != NULL))
+    return CTF_ERR;                            /* errno is set for us.  */
+
+  /* The emission hashes may be unset if this dict was created after
+     deduplication to house variables or other things that would conflict if
+     stored in the shared dict.  */
+  if (fp->ctf_dedup.cd_output_emission_hashes)
+    if (ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_output_emission_hashes, hval,
+                              NULL, &type_ptr))
+      return (ctf_id_t) (uintptr_t) type_ptr;
+
+  if (fp->ctf_parent)
+    {
+      ctf_dict_t *pfp = fp->ctf_parent;
+      if (pfp->ctf_dedup.cd_output_emission_hashes)
+       if (ctf_dynhash_lookup_kv (pfp->ctf_dedup.cd_output_emission_hashes,
+                                  hval, NULL, &type_ptr))
+         return (ctf_id_t) (uintptr_t) type_ptr;
+    }
+
+  return 0;
+}