X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=libctf%2Fctf-link.c;h=31179ae13d7c2f349a6997baf79357bd6f8d86b1;hb=7a77f1ac2c6f899faa39e8c0b42d4284d586c44e;hp=8dd81d1f124192c335866fd052542fff580bae7f;hpb=eabb7154df3e97e9d808a8673953cc1ce708f3d4;p=deliverable%2Fbinutils-gdb.git diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index 8dd81d1f12..31179ae13d 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -1,5 +1,5 @@ /* CTF linking. - Copyright (C) 2019 Free Software Foundation, Inc. + Copyright (C) 2019-2020 Free Software Foundation, Inc. This file is part of libctf. @@ -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; @@ -258,15 +348,20 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_) err = ctf_errno (arg->out_fp); if (err != ECTF_CONFLICT) { - ctf_dprintf ("Cannot link type %lx from archive member %s, input file %s " - "into output link: %s\n", type, arg->arcname, arg->file_name, - ctf_errmsg (err)); - return -1; + if (err != ECTF_NONREPRESENTABLE) + ctf_dprintf ("Cannot link type %lx from archive member %s, input file %s " + "into output link: %s\n", type, arg->arcname, arg->file_name, + ctf_errmsg (err)); + /* We must ignore this problem or we end up losing future types, then + trying to link the variables in, then exploding. Better to link as + much as possible. XXX when we add a proper link warning + infrastructure, we should report the error here! */ + return 0; } 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. */ @@ -274,6 +369,11 @@ ctf_link_one_type (ctf_id_t type, int isroot _libctf_unused_, void *arg_) return 0; err = ctf_errno (per_cu_out_fp); + if (err != ECTF_NONREPRESENTABLE) + ctf_dprintf ("Cannot link type %lx from CTF archive member %s, input file %s " + "into output per-CU CTF archive member %s: %s: skipped\n", type, + arg->arcname, arg->file_name, arg->arcname, + ctf_errmsg (err)); if (err == ECTF_CONFLICT) /* Conflicts are possible at this stage only if a non-ld user has combined multiple TUs into a single output dictionary. Even in this case we do not @@ -347,7 +447,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. */ @@ -539,7 +639,7 @@ ctf_link_intern_extern_string (void *key _libctf_unused_, void *value, ctf_link_out_string_cb_arg_t *arg = (ctf_link_out_string_cb_arg_t *) arg_; fp->ctf_flags |= LCTF_DIRTY; - if (ctf_str_add_external (fp, arg->str, arg->offset) == NULL) + if (!ctf_str_add_external (fp, arg->str, arg->offset)) arg->err = ENOMEM; } @@ -562,7 +662,7 @@ ctf_link_add_strtab (ctf_file_t *fp, ctf_link_strtab_string_f *add_string, ctf_link_out_string_cb_arg_t iter_arg = { str, offset, 0 }; fp->ctf_flags |= LCTF_DIRTY; - if (ctf_str_add_external (fp, str, offset) == NULL) + if (!ctf_str_add_external (fp, str, offset)) err = ENOMEM; ctf_dynhash_iter (fp->ctf_link_outputs, ctf_link_intern_extern_string, @@ -589,10 +689,11 @@ 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, - and run ctf_update() on them to generate them. */ +/* Accumulate the names and a count of the names in the link output hash. */ static void ctf_accumulate_archive_names (void *key, void *value, void *arg_) { @@ -601,13 +702,6 @@ ctf_accumulate_archive_names (void *key, void *value, void *arg_) char **names; ctf_file_t **files; ctf_name_list_accum_cb_arg_t *arg = (ctf_name_list_accum_cb_arg_t *) arg_; - int err; - - if ((err = ctf_update (fp)) < 0) - { - ctf_set_errno (arg->fp, ctf_errno (fp)); - return; - } if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL) { @@ -622,12 +716,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 +769,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; @@ -646,12 +780,6 @@ ctf_link_write (ctf_file_t *fp, size_t *size, size_t threshold) memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t)); arg.fp = fp; - if (ctf_update (fp) < 0) - { - errloc = "CTF file construction"; - goto err; - } - if (fp->ctf_link_outputs) { ctf_dynhash_iter (fp->ctf_link_outputs, ctf_accumulate_archive_names, &arg); @@ -675,7 +803,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 +879,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 +897,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;