+/* Return a per-CU output CTF dictionary suitable for the given CU, creating and
+ interning it if need be. */
+
+static ctf_file_t *
+ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
+{
+ ctf_file_t *cu_fp;
+ const char *ctf_name = NULL;
+ char *dynname = NULL;
+
+ /* First, check the mapping table and translate the per-CU name we use
+ accordingly. We check both the input filename and the CU name. Only if
+ neither are set do we fall back to the input filename as the per-CU
+ dictionary name. We prefer the filename because this is easier for likely
+ callers to determine. */
+
+ if (fp->ctf_link_cu_mapping)
+ {
+ if (((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, filename)) == NULL) &&
+ ((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, cuname)) == NULL))
+ ctf_name = filename;
+ }
+
+ if (ctf_name == NULL)
+ ctf_name = filename;
+
+ if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL)
+ {
+ int err;
+
+ if ((cu_fp = ctf_create (&err)) == NULL)
+ {
+ ctf_dprintf ("Cannot create per-CU CTF archive for CU %s from "
+ "input file %s: %s\n", cuname, filename,
+ ctf_errmsg (err));
+ ctf_set_errno (fp, err);
+ return NULL;
+ }
+
+ if ((dynname = strdup (ctf_name)) == NULL)
+ goto oom;
+ if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0)
+ goto oom;
+
+ ctf_import (cu_fp, fp);
+ ctf_cuname_set (cu_fp, cuname);
+ ctf_parent_name_set (cu_fp, _CTF_SECTION);
+ }
+ return cu_fp;
+
+ oom:
+ free (dynname);
+ ctf_file_close (cu_fp);
+ ctf_set_errno (fp, ENOMEM);
+ return NULL;
+}
+
+/* Add a mapping directing that the CU named FROM should have its
+ conflicting/non-duplicate types (depending on link mode) go into a container
+ named TO. Many FROMs can share a TO: in this case, the effect on conflicting
+ types is not yet defined (but in time an auto-renaming algorithm will be
+ added: ugly, but there is really no right thing one can do in this
+ situation).
+
+ We forcibly add a container named TO in every case, even though it may well
+ wind up empty, because clients that use this facility usually expect to find
+ every TO container present, even if empty, and malfunction otherwise. */
+
+int
+ctf_link_add_cu_mapping (ctf_file_t *fp, const char *from, const char *to)
+{
+ int err;
+ char *f, *t;
+
+ if (fp->ctf_link_cu_mapping == NULL)
+ fp->ctf_link_cu_mapping = ctf_dynhash_create (ctf_hash_string,
+ ctf_hash_eq_string, free,
+ free);
+ if (fp->ctf_link_cu_mapping == NULL)
+ return ctf_set_errno (fp, ENOMEM);
+
+ if (fp->ctf_link_outputs == NULL)
+ fp->ctf_link_outputs = ctf_dynhash_create (ctf_hash_string,
+ ctf_hash_eq_string, free,
+ ctf_file_close_thunk);
+
+ if (fp->ctf_link_outputs == NULL)
+ return ctf_set_errno (fp, ENOMEM);
+
+ f = strdup (from);
+ t = strdup (to);
+ if (!f || !t)
+ goto oom;
+
+ if (ctf_create_per_cu (fp, t, t) == NULL)
+ goto oom_noerrno; /* Errno is set for us. */
+
+ err = ctf_dynhash_insert (fp->ctf_link_cu_mapping, f, t);
+ if (err)
+ {
+ ctf_set_errno (fp, err);
+ goto oom_noerrno;
+ }
+
+ return 0;
+
+ oom:
+ ctf_set_errno (fp, errno);
+ oom_noerrno:
+ free (f);
+ free (t);
+ return -1;
+}
+
+/* Set a function which is called to transform the names of archive members.
+ This is useful for applying regular transformations to many names, where
+ ctf_link_add_cu_mapping applies arbitrarily irregular changes to single
+ names. The member name changer is applied at ctf_link_write time, so it
+ cannot conflate multiple CUs into one the way ctf_link_add_cu_mapping can.
+ The changer function accepts a name and should return a new
+ dynamically-allocated name, or NULL if the name should be left unchanged. */
+void
+ctf_link_set_memb_name_changer (ctf_file_t *fp,
+ ctf_link_memb_name_changer_f *changer,
+ void *arg)
+{
+ fp->ctf_link_memb_name_changer = changer;
+ fp->ctf_link_memb_name_changer_arg = arg;
+}
+