aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/ChangeLog6
-rw-r--r--include/ctf-api.h10
-rw-r--r--libctf/ChangeLog18
-rw-r--r--libctf/ctf-create.c4
-rw-r--r--libctf/ctf-impl.h4
-rw-r--r--libctf/ctf-link.c171
-rw-r--r--libctf/ctf-open.c1
7 files changed, 210 insertions, 4 deletions
diff --git a/include/ChangeLog b/include/ChangeLog
index 0122c1d..ce7c173 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,9 @@
+2019-07-30 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-api.h (ctf_link_add_cu_mapping): New.
+ (ctf_link_memb_name_changer_f): New.
+ (ctf_link_set_memb_name_changer): New.
+
2019-07-13 Nick Alcock <nick.alcock@oracle.com>
* ctf-api.h (ECTF_INTERNAL): New.
diff --git a/include/ctf-api.h b/include/ctf-api.h
index 4130a2e..4ac5fea 100644
--- a/include/ctf-api.h
+++ b/include/ctf-api.h
@@ -421,6 +421,16 @@ extern int ctf_link_shuffle_syms (ctf_file_t *, ctf_link_iter_symbol_f *,
extern unsigned char *ctf_link_write (ctf_file_t *, size_t *size,
size_t threshold);
+/* Specialist linker functions. These functions are not used by ld, but can be
+ used by other prgorams making use of the linker machinery for other purposes
+ to customize its output. */
+extern int ctf_link_add_cu_mapping (ctf_file_t *, const char *from,
+ const char *to);
+typedef char *ctf_link_memb_name_changer_f (ctf_file_t *,
+ const char *, void *);
+extern void ctf_link_set_memb_name_changer
+ (ctf_file_t *, ctf_link_memb_name_changer_f *, void *);
+
extern void ctf_setdebug (int debug);
extern int ctf_getdebug (void);
diff --git a/libctf/ChangeLog b/libctf/ChangeLog
index a5995eb..b272648 100644
--- a/libctf/ChangeLog
+++ b/libctf/ChangeLog
@@ -1,3 +1,21 @@
+2019-07-30 Nick Alcock <nick.alcock@oracle.com>
+
+ * ctf-impl.h (ctf_file_t) <ctf_link_cu_mappping>: New.
+ <ctf_link_memb_name_changer>: Likewise.
+ <ctf_link_memb_name_changer_arg>: Likewise.
+ * ctf-create.c (ctf_update): Update accordingly.
+ * ctf-open.c (ctf_file_close): Likewise.
+ * ctf-link.c (ctf_create_per_cu): Apply the cu mapping.
+ (ctf_link_add_cu_mapping): New.
+ (ctf_link_set_memb_name_changer): Likewise.
+ (ctf_change_parent_name): New.
+ (ctf_name_list_accum_cb_arg_t) <dynames>: New, storage for names
+ allocated by the caller's ctf_link_memb_name_changer.
+ <ndynames>: Likewise.
+ (ctf_accumulate_archive_names): Call the ctf_link_memb_name_changer.
+ (ctf_link_write): Likewise (for _CTF_SECTION only): also call
+ ctf_change_parent_name. Free any resulting names.
+
2019-07-13 Nick Alcock <nick.alcock@oracle.com>
* ctf-link.c (ctf_create_per_cu): New, refactored out of...
diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c
index 90e45f3..19da29c 100644
--- a/libctf/ctf-create.c
+++ b/libctf/ctf-create.c
@@ -473,7 +473,10 @@ ctf_update (ctf_file_t *fp)
nfp->ctf_link_inputs = fp->ctf_link_inputs;
nfp->ctf_link_outputs = fp->ctf_link_outputs;
nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab;
+ nfp->ctf_link_cu_mapping = fp->ctf_link_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_snapshot_lu = fp->ctf_snapshots;
@@ -486,6 +489,7 @@ ctf_update (ctf_file_t *fp)
fp->ctf_link_inputs = NULL;
fp->ctf_link_outputs = NULL;
fp->ctf_syn_ext_strtab = NULL;
+ fp->ctf_link_cu_mapping = NULL;
fp->ctf_link_type_mapping = NULL;
fp->ctf_dvhash = NULL;
diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h
index c522554..554b187 100644
--- a/libctf/ctf-impl.h
+++ b/libctf/ctf-impl.h
@@ -281,6 +281,10 @@ struct ctf_file
ctf_dynhash_t *ctf_link_inputs; /* Inputs to this link. */
ctf_dynhash_t *ctf_link_outputs; /* Additional outputs from this link. */
ctf_dynhash_t *ctf_link_type_mapping; /* Map input types to output types. */
+ ctf_dynhash_t *ctf_link_cu_mapping; /* Map CU names to CTF dict names. */
+ /* Allow the caller to Change the name of link archive members. */
+ ctf_link_memb_name_changer_f *ctf_link_memb_name_changer;
+ void *ctf_link_memb_name_changer_arg; /* Argument for it. */
char *ctf_tmp_typeslice; /* Storage for slicing up type names. */
size_t ctf_tmp_typeslicelen; /* Size of the typeslice. */
void *ctf_specific; /* Data for ctf_get/setspecific(). */
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 8dd81d1..28c2113 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -182,9 +182,26 @@ 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;
- if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, filename)) == 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;
@@ -197,7 +214,7 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
return NULL;
}
- if ((dynname = strdup (filename)) == NULL)
+ if ((dynname = strdup (ctf_name)) == NULL)
goto oom;
if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0)
goto oom;
@@ -215,6 +232,79 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
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;
+}
+
typedef struct ctf_link_in_member_cb_arg
{
ctf_file_t *out_fp;
@@ -266,7 +356,7 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_)
ctf_set_errno (arg->out_fp, 0);
}
- if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->arcname,
+ if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->file_name,
arg->cu_name)) == NULL)
return -1; /* Errno is set for us. */
@@ -347,7 +437,7 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_)
type only present in the child. Try adding to the child, creating if need
be. */
- if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->arcname,
+ if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->file_name,
arg->cu_name)) == NULL)
return -1; /* Errno is set for us. */
@@ -589,6 +679,8 @@ typedef struct ctf_name_list_accum_cb_arg
ctf_file_t *fp;
ctf_file_t **files;
size_t i;
+ char **dynames;
+ size_t ndynames;
} ctf_name_list_accum_cb_arg_t;
/* Accumulate the names and a count of the names in the link output hash,
@@ -622,12 +714,51 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_)
ctf_set_errno (arg->fp, ENOMEM);
return;
}
+
+ /* Allow the caller to get in and modify the name at the last minute. If the
+ caller *does* modify the name, we have to stash away the new name the
+ caller returned so we can free it later on. (The original name is the key
+ of the ctf_link_outputs hash and is freed by the dynhash machinery.) */
+
+ if (fp->ctf_link_memb_name_changer)
+ {
+ char **dynames;
+ char *dyname;
+ void *nc_arg = fp->ctf_link_memb_name_changer_arg;
+
+ dyname = fp->ctf_link_memb_name_changer (fp, name, nc_arg);
+
+ if (dyname != NULL)
+ {
+ if ((dynames = realloc (arg->dynames,
+ sizeof (char *) * ++(arg->ndynames))) == NULL)
+ {
+ (arg->ndynames)--;
+ ctf_set_errno (arg->fp, ENOMEM);
+ return;
+ }
+ arg->dynames = dynames;
+ name = (const char *) dyname;
+ }
+ }
+
arg->names = names;
arg->names[(arg->i) - 1] = (char *) name;
arg->files = files;
arg->files[(arg->i) - 1] = fp;
}
+/* Change the name of the parent CTF section, if the name transformer has got to
+ it. */
+static void
+ctf_change_parent_name (void *key _libctf_unused_, void *value, void *arg)
+{
+ ctf_file_t *fp = (ctf_file_t *) value;
+ const char *name = (const char *) arg;
+
+ ctf_parent_name_set (fp, name);
+}
+
/* Write out a CTF archive (if there are per-CU CTF files) or a CTF file
(otherwise) into a new dynamically-allocated string, and return it.
Members with sizes above THRESHOLD are compressed. */
@@ -636,6 +767,7 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
{
ctf_name_list_accum_cb_arg_t arg;
char **names;
+ char *transformed_name = NULL;
ctf_file_t **files;
FILE *f = NULL;
int err;
@@ -675,7 +807,22 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
}
arg.names = names;
memmove (&(arg.names[1]), arg.names, sizeof (char *) * (arg.i));
+
arg.names[0] = (char *) _CTF_SECTION;
+ if (fp->ctf_link_memb_name_changer)
+ {
+ void *nc_arg = fp->ctf_link_memb_name_changer_arg;
+
+ transformed_name = fp->ctf_link_memb_name_changer (fp, _CTF_SECTION,
+ nc_arg);
+
+ if (transformed_name != NULL)
+ {
+ arg.names[0] = transformed_name;
+ ctf_dynhash_iter (fp->ctf_link_outputs, ctf_change_parent_name,
+ transformed_name);
+ }
+ }
if ((files = realloc (arg.files,
sizeof (struct ctf_file *) * (arg.i + 1))) == NULL)
@@ -736,6 +883,14 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
*size = fsize;
free (arg.names);
free (arg.files);
+ free (transformed_name);
+ if (arg.ndynames)
+ {
+ size_t i;
+ for (i = 0; i < arg.ndynames; i++)
+ free (arg.dynames[i]);
+ free (arg.dynames);
+ }
return buf;
err_no:
@@ -746,6 +901,14 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold)
fclose (f);
free (arg.names);
free (arg.files);
+ free (transformed_name);
+ if (arg.ndynames)
+ {
+ size_t i;
+ for (i = 0; i < arg.ndynames; i++)
+ free (arg.dynames[i]);
+ free (arg.dynames);
+ }
ctf_dprintf ("Cannot write archive in link: %s failure: %s\n", errloc,
ctf_errmsg (ctf_errno (fp)));
return NULL;
diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c
index 600fe8f..2e1913b 100644
--- a/libctf/ctf-open.c
+++ b/libctf/ctf-open.c
@@ -1628,6 +1628,7 @@ ctf_file_close (ctf_file_t *fp)
ctf_dynhash_destroy (fp->ctf_link_inputs);
ctf_dynhash_destroy (fp->ctf_link_outputs);
ctf_dynhash_destroy (fp->ctf_link_type_mapping);
+ ctf_dynhash_destroy (fp->ctf_link_cu_mapping);
ctf_free (fp->ctf_sxlate);
ctf_free (fp->ctf_txlate);