|  | /* CTF linking. | 
|  | Copyright (C) 2019-2024 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 <string.h> | 
|  |  | 
|  | #if defined (PIC) | 
|  | #pragma weak ctf_open | 
|  | #endif | 
|  |  | 
|  | /* CTF linking consists of adding CTF archives full of content to be merged into | 
|  | this one to the current file (which must be writable) by calling | 
|  | ctf_link_add_ctf.  Once this is done, a call to ctf_link will merge the type | 
|  | tables together, generating new CTF files as needed, with this one as a | 
|  | parent, to contain types from the inputs which conflict.  ctf_link_add_strtab | 
|  | takes a callback which provides string/offset pairs to be added to the | 
|  | external symbol table and deduplicated from all CTF string tables in the | 
|  | output link; ctf_link_shuffle_syms takes a callback which provides symtab | 
|  | entries in ascending order, and shuffles the function and data sections to | 
|  | match; and ctf_link_write emits a CTF file (if there are no conflicts | 
|  | requiring per-compilation-unit sub-CTF files) or CTF archives (otherwise) and | 
|  | returns it, suitable for addition in the .ctf section of the output.  */ | 
|  |  | 
|  | /* Return the name of the compilation unit this CTF dict or its parent applies | 
|  | to, or a non-null string otherwise: prefer the parent.  Used in debugging | 
|  | output.  Sometimes used for outputs too.  */ | 
|  | const char * | 
|  | ctf_link_input_name (ctf_dict_t *fp) | 
|  | { | 
|  | if (fp->ctf_parent && fp->ctf_parent->ctf_cuname) | 
|  | return fp->ctf_parent->ctf_cuname; | 
|  | else if (fp->ctf_cuname) | 
|  | return fp->ctf_cuname; | 
|  | else | 
|  | return "(unnamed)"; | 
|  | } | 
|  |  | 
|  | /* Return the cuname of a dict, or the string "unnamed-CU" if none.  */ | 
|  |  | 
|  | static const char * | 
|  | ctf_unnamed_cuname (ctf_dict_t *fp) | 
|  | { | 
|  | const char *cuname = ctf_cuname (fp); | 
|  |  | 
|  | if (!cuname) | 
|  | cuname = "unnamed-CU"; | 
|  |  | 
|  | return cuname; | 
|  | } | 
|  |  | 
|  | /* The linker inputs look like this.  clin_fp is used for short-circuited | 
|  | CU-mapped links that can entirely avoid the first link phase in some | 
|  | situations in favour of just passing on the contained ctf_dict_t: it is | 
|  | always the sole ctf_dict_t inside the corresponding clin_arc.  If set, it | 
|  | gets assigned directly to the final link inputs and freed from there, so it | 
|  | never gets explicitly freed in the ctf_link_input.  */ | 
|  | typedef struct ctf_link_input | 
|  | { | 
|  | char *clin_filename; | 
|  | ctf_archive_t *clin_arc; | 
|  | ctf_dict_t *clin_fp; | 
|  | int n; | 
|  | } ctf_link_input_t; | 
|  |  | 
|  | static void | 
|  | ctf_link_input_close (void *input) | 
|  | { | 
|  | ctf_link_input_t *i = (ctf_link_input_t *) input; | 
|  | if (i->clin_arc) | 
|  | ctf_arc_close (i->clin_arc); | 
|  | free (i->clin_filename); | 
|  | free (i); | 
|  | } | 
|  |  | 
|  | /* Like ctf_link_add_ctf, below, but with no error-checking, so it can be called | 
|  | in the middle of an ongoing link.  */ | 
|  | static int | 
|  | ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf, | 
|  | ctf_dict_t *fp_input, const char *name) | 
|  | { | 
|  | int existing = 0; | 
|  | ctf_link_input_t *input; | 
|  | char *filename, *keyname; | 
|  |  | 
|  | /* Existing: return it, or (if a different dict with the same name | 
|  | is already there) make up a new unique name.  Always use the actual name | 
|  | for the filename, because that needs to be ctf_open()ed.  */ | 
|  |  | 
|  | if ((input = ctf_dynhash_lookup (fp->ctf_link_inputs, name)) != NULL) | 
|  | { | 
|  | if ((fp_input != NULL && (input->clin_fp == fp_input)) | 
|  | || (ctf != NULL && (input->clin_arc == ctf))) | 
|  | return 0; | 
|  | existing = 1; | 
|  | } | 
|  |  | 
|  | if ((filename = strdup (name)) == NULL) | 
|  | goto oom; | 
|  |  | 
|  | if ((input = calloc (1, sizeof (ctf_link_input_t))) == NULL) | 
|  | goto oom1; | 
|  |  | 
|  | input->clin_arc = ctf; | 
|  | input->clin_fp = fp_input; | 
|  | input->clin_filename = filename; | 
|  | input->n = ctf_dynhash_elements (fp->ctf_link_inputs); | 
|  |  | 
|  | if (existing) | 
|  | { | 
|  | if (asprintf (&keyname, "%s#%li", name, (long int) | 
|  | ctf_dynhash_elements (fp->ctf_link_inputs)) < 0) | 
|  | goto oom2; | 
|  | } | 
|  | else if ((keyname = strdup (name)) == NULL) | 
|  | goto oom2; | 
|  |  | 
|  | if (ctf_dynhash_insert (fp->ctf_link_inputs, keyname, input) < 0) | 
|  | goto oom3; | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | oom3: | 
|  | free (keyname); | 
|  | oom2: | 
|  | free (input); | 
|  | oom1: | 
|  | free (filename); | 
|  | oom: | 
|  | return ctf_set_errno (fp, ENOMEM); | 
|  | } | 
|  |  | 
|  | /* Add a file, memory buffer, or unopened file (by name) to a link. | 
|  |  | 
|  | You can call this with: | 
|  |  | 
|  | CTF and NAME: link the passed ctf_archive_t, with the given NAME. | 
|  | NAME alone: open NAME as a CTF file when needed. | 
|  | BUF and NAME: open the BUF (of length N) as CTF, with the given NAME.  (Not | 
|  | yet implemented.) | 
|  |  | 
|  | Passed in CTF args are owned by the dictionary and will be freed by it. | 
|  | The BUF arg is *not* owned by the dictionary, and the user should not free | 
|  | its referent until the link is done. | 
|  |  | 
|  | The order of calls to this function influences the order of types in the | 
|  | final link output, but otherwise is not important. | 
|  |  | 
|  | Repeated additions of the same NAME have no effect; repeated additions of | 
|  | different dicts with the same NAME add all the dicts with unique NAMEs | 
|  | derived from NAME. | 
|  |  | 
|  | Private for now, but may in time become public once support for BUF is | 
|  | implemented.  */ | 
|  |  | 
|  | static int | 
|  | ctf_link_add (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name, | 
|  | void *buf _libctf_unused_, size_t n _libctf_unused_) | 
|  | { | 
|  | if (buf) | 
|  | return (ctf_set_errno (fp, ECTF_NOTYET)); | 
|  |  | 
|  | if (!((ctf && name && !buf) | 
|  | || (name && !buf && !ctf) | 
|  | || (buf && name && !ctf))) | 
|  | return (ctf_set_errno (fp, EINVAL)); | 
|  |  | 
|  | /* We can only lazily open files if libctf.so is in use rather than | 
|  | libctf-nobfd.so.  This is a little tricky: in shared libraries, we can use | 
|  | a weak symbol so that -lctf -lctf-nobfd works, but in static libraries we | 
|  | must distinguish between the two libraries explicitly.  */ | 
|  |  | 
|  | #if defined (PIC) | 
|  | if (!buf && !ctf && name && !ctf_open) | 
|  | return (ctf_set_errno (fp, ECTF_NEEDSBFD)); | 
|  | #elif NOBFD | 
|  | if (!buf && !ctf && name) | 
|  | return (ctf_set_errno (fp, ECTF_NEEDSBFD)); | 
|  | #endif | 
|  |  | 
|  | if (fp->ctf_link_outputs) | 
|  | return (ctf_set_errno (fp, ECTF_LINKADDEDLATE)); | 
|  | if (fp->ctf_link_inputs == NULL) | 
|  | fp->ctf_link_inputs = ctf_dynhash_create (ctf_hash_string, | 
|  | ctf_hash_eq_string, free, | 
|  | ctf_link_input_close); | 
|  |  | 
|  | if (fp->ctf_link_inputs == NULL) | 
|  | return (ctf_set_errno (fp, ENOMEM)); | 
|  |  | 
|  | return ctf_link_add_ctf_internal (fp, ctf, NULL, name); | 
|  | } | 
|  |  | 
|  | /* Add an opened CTF archive or unopened file (by name) to a link. | 
|  | If CTF is NULL and NAME is non-null, an unopened file is meant: | 
|  | otherwise, the specified archive is assumed to have the given NAME. | 
|  |  | 
|  | Passed in CTF args are owned by the dictionary and will be freed by it. | 
|  |  | 
|  | The order of calls to this function influences the order of types in the | 
|  | final link output, but otherwise is not important.  */ | 
|  |  | 
|  | int | 
|  | 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); | 
|  | return ctf_set_errno (fp, ECTF_NEEDSBFD); | 
|  | #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); | 
|  | return ctf_set_errno (fp, err); | 
|  | } | 
|  |  | 
|  | if ((count = ctf_archive_count (input->clin_arc)) == 0) | 
|  | ctf_arc_close (input->clin_arc); | 
|  |  | 
|  | return (ssize_t) count; | 
|  | } | 
|  |  | 
|  | /* Find a non-clashing unique name for a per-CU output dict, to prevent distinct | 
|  | members corresponding to inputs with identical cunames from overwriting each | 
|  | other.  The name should be something like NAME.  */ | 
|  |  | 
|  | static char * | 
|  | ctf_new_per_cu_name (ctf_dict_t *fp, const char *name) | 
|  | { | 
|  | char *dynname; | 
|  | long int i = 0; | 
|  |  | 
|  | if ((dynname = strdup (name)) == NULL) | 
|  | return NULL; | 
|  |  | 
|  | while ((ctf_dynhash_lookup (fp->ctf_link_outputs, dynname)) != NULL) | 
|  | { | 
|  | free (dynname); | 
|  | if (asprintf (&dynname, "%s#%li", name, i++) < 0) | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return dynname; | 
|  | } | 
|  |  | 
|  | /* Return a per-CU output CTF dictionary suitable for the given INPUT or CU, | 
|  | creating and interning it if need be.  */ | 
|  |  | 
|  | static ctf_dict_t * | 
|  | ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name) | 
|  | { | 
|  | ctf_dict_t *cu_fp; | 
|  | const char *ctf_name = NULL; | 
|  | char *dynname = NULL; | 
|  |  | 
|  | /* Already has a per-CU mapping?  Just return it.  */ | 
|  |  | 
|  | if (input && input->ctf_link_in_out) | 
|  | return input->ctf_link_in_out; | 
|  |  | 
|  | /* Check the mapping table and translate the per-CU name we use | 
|  | accordingly.  */ | 
|  |  | 
|  | if (cu_name == NULL) | 
|  | cu_name = ctf_unnamed_cuname (input); | 
|  |  | 
|  | if (fp->ctf_link_in_cu_mapping) | 
|  | { | 
|  | if ((ctf_name = ctf_dynhash_lookup (fp->ctf_link_in_cu_mapping, | 
|  | cu_name)) == NULL) | 
|  | ctf_name = cu_name; | 
|  | } | 
|  |  | 
|  | if (ctf_name == NULL) | 
|  | ctf_name = cu_name; | 
|  |  | 
|  | /* Look up the per-CU dict.  If we don't know of one, or it is for a different input | 
|  | CU which just happens to have the same name, create a new one.  If we are creating | 
|  | a dict with no input specified, anything will do.  */ | 
|  |  | 
|  | if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL | 
|  | || (input && cu_fp->ctf_link_in_out != fp)) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | if ((cu_fp = ctf_create (&err)) == NULL) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive for " | 
|  | "input CU %s"), cu_name); | 
|  | ctf_set_errno (fp, err); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ctf_import_unref (cu_fp, fp); | 
|  |  | 
|  | if ((dynname = ctf_new_per_cu_name (fp, ctf_name)) == NULL) | 
|  | goto oom; | 
|  |  | 
|  | ctf_cuname_set (cu_fp, cu_name); | 
|  |  | 
|  | ctf_parent_name_set (cu_fp, _CTF_SECTION); | 
|  | cu_fp->ctf_link_in_out = fp; | 
|  | fp->ctf_link_in_out = cu_fp; | 
|  |  | 
|  | if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0) | 
|  | goto oom; | 
|  | } | 
|  | return cu_fp; | 
|  |  | 
|  | oom: | 
|  | free (dynname); | 
|  | ctf_dict_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 dict | 
|  | named TO.  Many FROMs can share a TO, but adding the same FROM with | 
|  | a different TO will replace the old mapping. | 
|  |  | 
|  | We forcibly add a dict 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 dict present, even if empty, and malfunction otherwise.  */ | 
|  |  | 
|  | int | 
|  | ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to) | 
|  | { | 
|  | int err; | 
|  | char *f = NULL, *t = NULL, *existing; | 
|  | ctf_dynhash_t *one_out; | 
|  |  | 
|  | /* Mappings cannot be set up if per-CU output dicts already exist.  */ | 
|  | if (fp->ctf_link_outputs && ctf_dynhash_elements (fp->ctf_link_outputs) != 0) | 
|  | return (ctf_set_errno (fp, ECTF_LINKADDEDLATE)); | 
|  |  | 
|  | if (fp->ctf_link_in_cu_mapping == NULL) | 
|  | fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string, | 
|  | ctf_hash_eq_string, free, | 
|  | free); | 
|  | if (fp->ctf_link_in_cu_mapping == NULL) | 
|  | goto oom; | 
|  |  | 
|  | if (fp->ctf_link_out_cu_mapping == NULL) | 
|  | fp->ctf_link_out_cu_mapping = ctf_dynhash_create (ctf_hash_string, | 
|  | ctf_hash_eq_string, free, | 
|  | (ctf_hash_free_fun) | 
|  | ctf_dynhash_destroy); | 
|  | if (fp->ctf_link_out_cu_mapping == NULL) | 
|  | goto oom; | 
|  |  | 
|  | /* If this FROM already exists, remove the mapping from both the FROM->TO | 
|  | and the TO->FROM lists: the user wants to change it.  */ | 
|  |  | 
|  | if ((existing = ctf_dynhash_lookup (fp->ctf_link_in_cu_mapping, from)) != NULL) | 
|  | { | 
|  | one_out = ctf_dynhash_lookup (fp->ctf_link_out_cu_mapping, existing); | 
|  | if (!ctf_assert (fp, one_out)) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | ctf_dynhash_remove (one_out, from); | 
|  | ctf_dynhash_remove (fp->ctf_link_in_cu_mapping, from); | 
|  | } | 
|  |  | 
|  | f = strdup (from); | 
|  | t = strdup (to); | 
|  | if (!f || !t) | 
|  | goto oom; | 
|  |  | 
|  | /* Track both in a list from FROM to TO and in a list from TO to a list of | 
|  | FROM.  The former is used to create TUs with the mapped-to name at need: | 
|  | the latter is used in deduplicating links to pull in all input CUs | 
|  | corresponding to a single output CU.  */ | 
|  |  | 
|  | if ((err = ctf_dynhash_insert (fp->ctf_link_in_cu_mapping, f, t)) < 0) | 
|  | { | 
|  | ctf_set_errno (fp, err); | 
|  | goto oom_noerrno; | 
|  | } | 
|  |  | 
|  | /* f and t are now owned by the in_cu_mapping: reallocate them.  */ | 
|  | f = strdup (from); | 
|  | t = strdup (to); | 
|  | if (!f || !t) | 
|  | goto oom; | 
|  |  | 
|  | if ((one_out = ctf_dynhash_lookup (fp->ctf_link_out_cu_mapping, t)) == NULL) | 
|  | { | 
|  | if ((one_out = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, | 
|  | free, NULL)) == NULL) | 
|  | goto oom; | 
|  | if ((err = ctf_dynhash_insert (fp->ctf_link_out_cu_mapping, | 
|  | t, one_out)) < 0) | 
|  | { | 
|  | ctf_dynhash_destroy (one_out); | 
|  | ctf_set_errno (fp, err); | 
|  | goto oom_noerrno; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | free (t); | 
|  | t = NULL; | 
|  | } | 
|  |  | 
|  | if (ctf_dynhash_insert (one_out, f, NULL) < 0) | 
|  | { | 
|  | 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_dict_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; | 
|  | } | 
|  |  | 
|  | /* Set a function which is used to filter out unwanted variables from the link.  */ | 
|  | int | 
|  | ctf_link_set_variable_filter (ctf_dict_t *fp, ctf_link_variable_filter_f *filter, | 
|  | void *arg) | 
|  | { | 
|  | fp->ctf_link_variable_filter = filter; | 
|  | fp->ctf_link_variable_filter_arg = arg; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Check if we can safely add a variable with the given type to this dict.  */ | 
|  |  | 
|  | static int | 
|  | check_variable (const char *name, ctf_dict_t *fp, ctf_id_t type, | 
|  | ctf_dvdef_t **out_dvd) | 
|  | { | 
|  | ctf_dvdef_t *dvd; | 
|  |  | 
|  | dvd = ctf_dynhash_lookup (fp->ctf_dvhash, name); | 
|  | *out_dvd = dvd; | 
|  | if (!dvd) | 
|  | return 1; | 
|  |  | 
|  | if (dvd->dvd_type != type) | 
|  | { | 
|  | /* Variable here.  Wrong type: cannot add.  Just skip it, because there is | 
|  | no way to express this in CTF.  Don't even warn: this case is too | 
|  | common.  (This might be the parent, in which case we'll try adding in | 
|  | the child first, and only then give up.)  */ | 
|  | ctf_dprintf ("Inexpressible duplicate variable %s skipped.\n", name); | 
|  | } | 
|  |  | 
|  | return 0;				      /* Already exists.  */ | 
|  | } | 
|  |  | 
|  | /* Link one variable named NAME of type TYPE found in IN_FP into FP.  */ | 
|  |  | 
|  | static int | 
|  | ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name, | 
|  | ctf_id_t type, int cu_mapped) | 
|  | { | 
|  | ctf_dict_t *per_cu_out_fp; | 
|  | ctf_id_t dst_type = 0; | 
|  | ctf_dvdef_t *dvd; | 
|  |  | 
|  | /* See if this variable is filtered out.  */ | 
|  |  | 
|  | if (fp->ctf_link_variable_filter) | 
|  | { | 
|  | void *farg = fp->ctf_link_variable_filter_arg; | 
|  | if (fp->ctf_link_variable_filter (in_fp, name, type, farg)) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* If this type is mapped to a type in the parent dict, we want to try to add | 
|  | to that first: if it reports a duplicate, or if the type is in a child | 
|  | already, add straight to the child.  */ | 
|  |  | 
|  | if ((dst_type = ctf_dedup_type_mapping (fp, in_fp, type)) == CTF_ERR) | 
|  | return -1;					/* errno is set for us.  */ | 
|  |  | 
|  | if (dst_type != 0) | 
|  | { | 
|  | if (!ctf_assert (fp, ctf_type_isparent (fp, dst_type))) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | if (check_variable (name, fp, dst_type, &dvd)) | 
|  | { | 
|  | /* No variable here: we can add it.  */ | 
|  | if (ctf_add_variable (fp, name, dst_type) < 0) | 
|  | return -1; 				/* errno is set for us.  */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Already present?  Nothing to do.  */ | 
|  | if (dvd && dvd->dvd_type == dst_type) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Can't add to the parent due to a name clash, or because it references a | 
|  | type only present in the child.  Try adding to the child, creating if need | 
|  | be.  If we can't do that, skip it.  Don't add to a child if we're doing a | 
|  | CU-mapped link, since that has only one output.  */ | 
|  |  | 
|  | if (cu_mapped) | 
|  | { | 
|  | ctf_dprintf ("Variable %s in input file %s depends on a type %lx hidden " | 
|  | "due to conflicts: skipped.\n", name, | 
|  | ctf_unnamed_cuname (in_fp), type); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if ((per_cu_out_fp = ctf_create_per_cu (fp, in_fp, NULL)) == NULL) | 
|  | return -1;					/* errno is set for us.  */ | 
|  |  | 
|  | /* If the type was not found, check for it in the child too.  */ | 
|  | if (dst_type == 0) | 
|  | { | 
|  | if ((dst_type = ctf_dedup_type_mapping (per_cu_out_fp, | 
|  | in_fp, type)) == CTF_ERR) | 
|  | return -1;				/* errno is set for us.   */ | 
|  |  | 
|  | if (dst_type == 0) | 
|  | { | 
|  | ctf_err_warn (fp, 1, 0, _("type %lx for variable %s in input file %s " | 
|  | "not found: skipped"), type, name, | 
|  | ctf_unnamed_cuname (in_fp)); | 
|  | /* Do not terminate the link: just skip the variable.  */ | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (check_variable (name, per_cu_out_fp, dst_type, &dvd)) | 
|  | if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0) | 
|  | return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp))); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | typedef struct link_sort_inputs_cb_arg | 
|  | { | 
|  | int is_cu_mapped; | 
|  | ctf_dict_t *fp; | 
|  | } link_sort_inputs_cb_arg_t; | 
|  |  | 
|  | /* Sort the inputs by N (the link order).  For CU-mapped links, this is a | 
|  | mapping of input to output name, not a mapping of input name to input | 
|  | ctf_link_input_t: compensate accordingly.  */ | 
|  | static int | 
|  | ctf_link_sort_inputs (const ctf_next_hkv_t *one, const ctf_next_hkv_t *two, | 
|  | void *arg) | 
|  | { | 
|  | ctf_link_input_t *input_1; | 
|  | ctf_link_input_t *input_2; | 
|  | link_sort_inputs_cb_arg_t *cu_mapped = (link_sort_inputs_cb_arg_t *) arg; | 
|  |  | 
|  | if (!cu_mapped || !cu_mapped->is_cu_mapped) | 
|  | { | 
|  | input_1 = (ctf_link_input_t *) one->hkv_value; | 
|  | input_2 = (ctf_link_input_t *) two->hkv_value; | 
|  | } | 
|  | else | 
|  | { | 
|  | const char *name_1 = (const char *) one->hkv_key; | 
|  | const char *name_2 = (const char *) two->hkv_key; | 
|  |  | 
|  | input_1 = ctf_dynhash_lookup (cu_mapped->fp->ctf_link_inputs, name_1); | 
|  | input_2 = ctf_dynhash_lookup (cu_mapped->fp->ctf_link_inputs, name_2); | 
|  |  | 
|  | /* There is no guarantee that CU-mappings actually have corresponding | 
|  | inputs: the relative ordering in that case is unimportant.  */ | 
|  | if (!input_1) | 
|  | return -1; | 
|  | if (!input_2) | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (input_1->n < input_2->n) | 
|  | return -1; | 
|  | else if (input_1->n > input_2->n) | 
|  | return 1; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Count the number of input dicts in the ctf_link_inputs, or that subset of the | 
|  | ctf_link_inputs given by CU_NAMES if set.  Return the number of input dicts, | 
|  | and optionally the name and ctf_link_input_t of the single input archive if | 
|  | only one exists (no matter how many dicts it contains).  */ | 
|  | static ssize_t | 
|  | ctf_link_deduplicating_count_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names, | 
|  | ctf_link_input_t **only_one_input) | 
|  | { | 
|  | ctf_dynhash_t *inputs = fp->ctf_link_inputs; | 
|  | ctf_next_t *i = NULL; | 
|  | void *name, *input; | 
|  | ctf_link_input_t *one_input = NULL; | 
|  | const char *one_name = NULL; | 
|  | ssize_t count = 0, narcs = 0; | 
|  | int err; | 
|  |  | 
|  | if (cu_names) | 
|  | inputs = cu_names; | 
|  |  | 
|  | while ((err = ctf_dynhash_next (inputs, &i, &name, &input)) == 0) | 
|  | { | 
|  | ssize_t one_count; | 
|  |  | 
|  | one_name = (const char *) name; | 
|  | /* If we are processing CU names, get the real input.  */ | 
|  | if (cu_names) | 
|  | one_input = ctf_dynhash_lookup (fp->ctf_link_inputs, one_name); | 
|  | else | 
|  | one_input = (ctf_link_input_t *) input; | 
|  |  | 
|  | if (!one_input) | 
|  | continue; | 
|  |  | 
|  | one_count = ctf_link_lazy_open (fp, one_input); | 
|  |  | 
|  | if (one_count < 0) | 
|  | { | 
|  | ctf_next_destroy (i); | 
|  | return -1;				/* errno is set for us.  */ | 
|  | } | 
|  |  | 
|  | count += one_count; | 
|  | narcs++; | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("iteration error counting deduplicating " | 
|  | "CTF link inputs")); | 
|  | return ctf_set_errno (fp, err); | 
|  | } | 
|  |  | 
|  | if (!count) | 
|  | return 0; | 
|  |  | 
|  | if (narcs == 1) | 
|  | { | 
|  | if (only_one_input) | 
|  | *only_one_input = one_input; | 
|  | } | 
|  | else if (only_one_input) | 
|  | *only_one_input = NULL; | 
|  |  | 
|  | return count; | 
|  | } | 
|  |  | 
|  | /* Allocate and populate an inputs array big enough for a given set of inputs: | 
|  | either a specific set of CU names (those from that set found in the | 
|  | ctf_link_inputs), or the entire ctf_link_inputs (if cu_names is not set). | 
|  | The number of inputs (from ctf_link_deduplicating_count_inputs, above) is | 
|  | passed in NINPUTS: an array of uint32_t containing parent pointers | 
|  | (corresponding to those members of the inputs that have parents) is allocated | 
|  | and returned in PARENTS. | 
|  |  | 
|  | The inputs are *archives*, not files: the archive can have multiple members | 
|  | if it is the result of a previous incremental link.  We want to add every one | 
|  | in turn, including the shared parent.  (The dedup machinery knows that a type | 
|  | used by a single dictionary and its parent should not be shared in | 
|  | CTF_LINK_SHARE_DUPLICATED mode.) | 
|  |  | 
|  | If no inputs exist that correspond to these CUs, return NULL with the errno | 
|  | set to ECTF_NOCTFDATA.  */ | 
|  | static ctf_dict_t ** | 
|  | ctf_link_deduplicating_open_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names, | 
|  | ssize_t ninputs, uint32_t **parents) | 
|  | { | 
|  | ctf_dynhash_t *inputs = fp->ctf_link_inputs; | 
|  | ctf_next_t *i = NULL; | 
|  | void *name, *input; | 
|  | link_sort_inputs_cb_arg_t sort_arg; | 
|  | ctf_dict_t **dedup_inputs = NULL; | 
|  | ctf_dict_t **walk; | 
|  | uint32_t *parents_ = NULL; | 
|  | int err; | 
|  |  | 
|  | if (cu_names) | 
|  | inputs = cu_names; | 
|  |  | 
|  | if ((dedup_inputs = calloc (ninputs, sizeof (ctf_dict_t *))) == NULL) | 
|  | goto oom; | 
|  |  | 
|  | if ((parents_ = calloc (ninputs, sizeof (uint32_t))) == NULL) | 
|  | goto oom; | 
|  |  | 
|  | walk = dedup_inputs; | 
|  |  | 
|  | /* Counting done: push every input into the array, in the order they were | 
|  | passed to ctf_link_add_ctf (and ultimately ld).  */ | 
|  |  | 
|  | sort_arg.is_cu_mapped = (cu_names != NULL); | 
|  | sort_arg.fp = fp; | 
|  |  | 
|  | while ((err = ctf_dynhash_next_sorted (inputs, &i, &name, &input, | 
|  | ctf_link_sort_inputs, &sort_arg)) == 0) | 
|  | { | 
|  | const char *one_name = (const char *) name; | 
|  | ctf_link_input_t *one_input; | 
|  | ctf_dict_t *one_fp; | 
|  | ctf_dict_t *parent_fp = NULL; | 
|  | uint32_t parent_i; | 
|  | ctf_next_t *j = NULL; | 
|  |  | 
|  | /* If we are processing CU names, get the real input.  All the inputs | 
|  | will have been opened, if they contained any CTF at all.  */ | 
|  | if (cu_names) | 
|  | one_input = ctf_dynhash_lookup (fp->ctf_link_inputs, one_name); | 
|  | else | 
|  | one_input = (ctf_link_input_t *) input; | 
|  |  | 
|  | if (!one_input || (!one_input->clin_arc && !one_input->clin_fp)) | 
|  | continue; | 
|  |  | 
|  | /* Short-circuit: if clin_fp is set, just use it.   */ | 
|  | if (one_input->clin_fp) | 
|  | { | 
|  | parents_[walk - dedup_inputs] = walk - dedup_inputs; | 
|  | *walk = one_input->clin_fp; | 
|  | walk++; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* Get and insert the parent archive (if any), if this archive has | 
|  | multiple members.  We assume, as elsewhere, that the parent is named | 
|  | _CTF_SECTION.  */ | 
|  |  | 
|  | if ((parent_fp = ctf_dict_open (one_input->clin_arc, _CTF_SECTION, | 
|  | &err)) == NULL) | 
|  | { | 
|  | if (err != ECTF_NOMEMBNAM) | 
|  | { | 
|  | ctf_next_destroy (i); | 
|  | ctf_set_errno (fp, err); | 
|  | goto err; | 
|  | } | 
|  | } | 
|  | else | 
|  | { | 
|  | *walk = parent_fp; | 
|  | parent_i = walk - dedup_inputs; | 
|  | walk++; | 
|  | } | 
|  |  | 
|  | /* We disregard the input archive name: either it is the parent (which we | 
|  | already have), or we want to put everything into one TU sharing the | 
|  | cuname anyway (if this is a CU-mapped link), or this is the final phase | 
|  | of a relink with CU-mapping off (i.e. ld -r) in which case the cuname | 
|  | is correctly set regardless.  */ | 
|  | while ((one_fp = ctf_archive_next (one_input->clin_arc, &j, NULL, | 
|  | 1, &err)) != NULL) | 
|  | { | 
|  | if (one_fp->ctf_flags & LCTF_CHILD) | 
|  | { | 
|  | /* The contents of the parents array for elements not | 
|  | corresponding to children is undefined.  If there is no parent | 
|  | (itself a sign of a likely linker bug or corrupt input), we set | 
|  | it to itself.  */ | 
|  |  | 
|  | ctf_import (one_fp, parent_fp); | 
|  | if (parent_fp) | 
|  | parents_[walk - dedup_inputs] = parent_i; | 
|  | else | 
|  | parents_[walk - dedup_inputs] = walk - dedup_inputs; | 
|  | } | 
|  | *walk = one_fp; | 
|  | walk++; | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_next_destroy (i); | 
|  | goto iterr; | 
|  | } | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | goto iterr; | 
|  |  | 
|  | *parents = parents_; | 
|  |  | 
|  | return dedup_inputs; | 
|  |  | 
|  | oom: | 
|  | err = ENOMEM; | 
|  |  | 
|  | iterr: | 
|  | ctf_set_errno (fp, err); | 
|  |  | 
|  | err: | 
|  | free (dedup_inputs); | 
|  | free (parents_); | 
|  | ctf_err_warn (fp, 0, 0, _("error in deduplicating CTF link " | 
|  | "input allocation")); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | /* Close INPUTS that have already been linked, first the passed array, and then | 
|  | that subset of the ctf_link_inputs archives they came from cited by the | 
|  | CU_NAMES.  If CU_NAMES is not specified, close all the ctf_link_inputs in one | 
|  | go, leaving it empty.  */ | 
|  | static int | 
|  | ctf_link_deduplicating_close_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names, | 
|  | ctf_dict_t **inputs, ssize_t ninputs) | 
|  | { | 
|  | ctf_next_t *it = NULL; | 
|  | void *name; | 
|  | int err; | 
|  | ssize_t i; | 
|  |  | 
|  | /* This is the inverse of ctf_link_deduplicating_open_inputs: so first, close | 
|  | all the individual input dicts, opened by the archive iterator.  */ | 
|  | for (i = 0; i < ninputs; i++) | 
|  | ctf_dict_close (inputs[i]); | 
|  |  | 
|  | /* Now close the archives they are part of.  */ | 
|  | if (cu_names) | 
|  | { | 
|  | while ((err = ctf_dynhash_next (cu_names, &it, &name, NULL)) == 0) | 
|  | { | 
|  | /* Remove the input from the linker inputs, if it exists, which also | 
|  | closes it.  */ | 
|  |  | 
|  | ctf_dynhash_remove (fp->ctf_link_inputs, (const char *) name); | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("iteration error in deduplicating link " | 
|  | "input freeing")); | 
|  | ctf_set_errno (fp, err); | 
|  | } | 
|  | } | 
|  | else | 
|  | ctf_dynhash_empty (fp->ctf_link_inputs); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Do a deduplicating link of all variables in the inputs. | 
|  |  | 
|  | Also, if we are not omitting the variable section, integrate all symbols from | 
|  | the symtypetabs into the variable section too.  (Duplication with the | 
|  | symtypetab section in the output will be eliminated at serialization time.)  */ | 
|  |  | 
|  | static int | 
|  | ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs, | 
|  | size_t ninputs, int cu_mapped) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < ninputs; i++) | 
|  | { | 
|  | ctf_next_t *it = NULL; | 
|  | ctf_id_t type; | 
|  | const char *name; | 
|  |  | 
|  | /* First the variables on the inputs.  */ | 
|  |  | 
|  | while ((type = ctf_variable_next (inputs[i], &it, &name)) != CTF_ERR) | 
|  | { | 
|  | if (ctf_link_one_variable (fp, inputs[i], name, type, cu_mapped) < 0) | 
|  | { | 
|  | ctf_next_destroy (it); | 
|  | return -1;			/* errno is set for us.  */ | 
|  | } | 
|  | } | 
|  | if (ctf_errno (inputs[i]) != ECTF_NEXT_END) | 
|  | return ctf_set_errno (fp, ctf_errno (inputs[i])); | 
|  |  | 
|  | /* Next the symbols.  We integrate data symbols even though the compiler | 
|  | is currently doing the same, to allow the compiler to stop in | 
|  | future.  */ | 
|  |  | 
|  | while ((type = ctf_symbol_next (inputs[i], &it, &name, 0)) != CTF_ERR) | 
|  | { | 
|  | if (ctf_link_one_variable (fp, inputs[i], name, type, 1) < 0) | 
|  | { | 
|  | ctf_next_destroy (it); | 
|  | return -1;			/* errno is set for us.  */ | 
|  | } | 
|  | } | 
|  | if (ctf_errno (inputs[i]) != ECTF_NEXT_END) | 
|  | return ctf_set_errno (fp, ctf_errno (inputs[i])); | 
|  |  | 
|  | /* Finally the function symbols.  */ | 
|  |  | 
|  | while ((type = ctf_symbol_next (inputs[i], &it, &name, 1)) != CTF_ERR) | 
|  | { | 
|  | if (ctf_link_one_variable (fp, inputs[i], name, type, 1) < 0) | 
|  | { | 
|  | ctf_next_destroy (it); | 
|  | return -1;			/* errno is set for us.  */ | 
|  | } | 
|  | } | 
|  | if (ctf_errno (inputs[i]) != ECTF_NEXT_END) | 
|  | return ctf_set_errno (fp, ctf_errno (inputs[i])); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Check for symbol conflicts during linking.  Three possibilities: already | 
|  | exists, conflicting, or nonexistent.  We don't have a dvd structure we can | 
|  | use as a flag like check_variable does, so we use a tristate return | 
|  | value instead: -1: conflicting; 1: nonexistent: 0: already exists.  */ | 
|  |  | 
|  | static int | 
|  | check_sym (ctf_dict_t *fp, const char *name, ctf_id_t type, int functions) | 
|  | { | 
|  | ctf_dynhash_t *thishash = functions ? fp->ctf_funchash : fp->ctf_objthash; | 
|  | ctf_dynhash_t *thathash = functions ? fp->ctf_objthash : fp->ctf_funchash; | 
|  | void *value; | 
|  |  | 
|  | /* Wrong type (function when object is wanted, etc).  */ | 
|  | if (ctf_dynhash_lookup_kv (thathash, name, NULL, NULL)) | 
|  | return -1; | 
|  |  | 
|  | /* Not present at all yet.  */ | 
|  | if (!ctf_dynhash_lookup_kv (thishash, name, NULL, &value)) | 
|  | return 1; | 
|  |  | 
|  | /* Already present.  */ | 
|  | if ((ctf_id_t) (uintptr_t) value == type) | 
|  | return 0; | 
|  |  | 
|  | /* Wrong type.  */ | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* Do a deduplicating link of one symtypetab (function info or data object) in | 
|  | one input dict.  */ | 
|  |  | 
|  | static int | 
|  | ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input, | 
|  | int cu_mapped, int functions) | 
|  | { | 
|  | ctf_next_t *it = NULL; | 
|  | const char *name; | 
|  | ctf_id_t type; | 
|  |  | 
|  | while ((type = ctf_symbol_next (input, &it, &name, functions)) != CTF_ERR) | 
|  | { | 
|  | ctf_id_t dst_type; | 
|  | ctf_dict_t *per_cu_out_fp; | 
|  | int sym; | 
|  |  | 
|  | /* Look in the parent first.  */ | 
|  |  | 
|  | if ((dst_type = ctf_dedup_type_mapping (fp, input, type)) == CTF_ERR) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | if (dst_type != 0) | 
|  | { | 
|  | if (!ctf_assert (fp, ctf_type_isparent (fp, dst_type))) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | sym = check_sym (fp, name, dst_type, functions); | 
|  |  | 
|  | /* Already present: next symbol.  */ | 
|  | if (sym == 0) | 
|  | continue; | 
|  | /* Not present: add it.  */ | 
|  | else if (sym > 0) | 
|  | { | 
|  | if (ctf_add_funcobjt_sym (fp, functions, | 
|  | name, dst_type) < 0) | 
|  | return -1; 			/* errno is set for us.  */ | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Can't add to the parent due to a name clash (most unlikely), or because | 
|  | it references a type only present in the child.  Try adding to the | 
|  | child, creating if need be.  If we can't do that, skip it.  Don't add | 
|  | to a child if we're doing a CU-mapped link, since that has only one | 
|  | output.  */ | 
|  | if (cu_mapped) | 
|  | { | 
|  | ctf_dprintf ("Symbol %s in input file %s depends on a type %lx " | 
|  | "hidden due to conflicts: skipped.\n", name, | 
|  | ctf_unnamed_cuname (input), type); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if ((per_cu_out_fp = ctf_create_per_cu (fp, input, NULL)) == NULL) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | /* If the type was not found, check for it in the child too.  */ | 
|  | if (dst_type == 0) | 
|  | { | 
|  | if ((dst_type = ctf_dedup_type_mapping (per_cu_out_fp, | 
|  | input, type)) == CTF_ERR) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | if (dst_type == 0) | 
|  | { | 
|  | ctf_err_warn (fp, 1, 0, | 
|  | _("type %lx for symbol %s in input file %s " | 
|  | "not found: skipped"), type, name, | 
|  | ctf_unnamed_cuname (input)); | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | sym = check_sym (per_cu_out_fp, name, dst_type, functions); | 
|  |  | 
|  | /* Already present: next symbol.  */ | 
|  | if (sym == 0) | 
|  | continue; | 
|  | /* Not present: add it.  */ | 
|  | else if (sym > 0) | 
|  | { | 
|  | if (ctf_add_funcobjt_sym (per_cu_out_fp, functions, | 
|  | name, dst_type) < 0) | 
|  | return -1;				/* errno is set for us.  */ | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Perhaps this should be an assertion failure.  */ | 
|  | ctf_err_warn (fp, 0, ECTF_DUPLICATE, | 
|  | _("symbol %s in input file %s found conflicting " | 
|  | "even when trying in per-CU dict."), name, | 
|  | ctf_unnamed_cuname (input)); | 
|  | return (ctf_set_errno (fp, ECTF_DUPLICATE)); | 
|  | } | 
|  | } | 
|  | if (ctf_errno (input) != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_set_errno (fp, ctf_errno (input)); | 
|  | ctf_err_warn (fp, 0, ctf_errno (input), | 
|  | functions ? _("iterating over function symbols") : | 
|  | _("iterating over data symbols")); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Do a deduplicating link of the function info and data objects | 
|  | in the inputs.  */ | 
|  | static int | 
|  | ctf_link_deduplicating_syms (ctf_dict_t *fp, ctf_dict_t **inputs, | 
|  | size_t ninputs, int cu_mapped) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < ninputs; i++) | 
|  | { | 
|  | if (ctf_link_deduplicating_one_symtypetab (fp, inputs[i], | 
|  | cu_mapped, 0) < 0) | 
|  | return -1;				/* errno is set for us.  */ | 
|  |  | 
|  | if (ctf_link_deduplicating_one_symtypetab (fp, inputs[i], | 
|  | cu_mapped, 1) < 0) | 
|  | return -1;				/* errno is set for us.  */ | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Do the per-CU part of a deduplicating link.  */ | 
|  | static int | 
|  | ctf_link_deduplicating_per_cu (ctf_dict_t *fp) | 
|  | { | 
|  | ctf_next_t *i = NULL; | 
|  | int err; | 
|  | void *out_cu; | 
|  | void *in_cus; | 
|  |  | 
|  | /* Links with a per-CU mapping in force get a first pass of deduplication, | 
|  | dedupping the inputs for a given CU mapping into the output for that | 
|  | mapping.  The outputs from this process get fed back into the final pass | 
|  | that is carried out even for non-CU links.  */ | 
|  |  | 
|  | while ((err = ctf_dynhash_next (fp->ctf_link_out_cu_mapping, &i, &out_cu, | 
|  | &in_cus)) == 0) | 
|  | { | 
|  | const char *out_name = (const char *) out_cu; | 
|  | ctf_dynhash_t *in = (ctf_dynhash_t *) in_cus; | 
|  | ctf_dict_t *out = NULL; | 
|  | ctf_dict_t **inputs; | 
|  | ctf_dict_t **outputs; | 
|  | ctf_archive_t *in_arc; | 
|  | ssize_t ninputs; | 
|  | ctf_link_input_t *only_input; | 
|  | uint32_t noutputs; | 
|  | uint32_t *parents; | 
|  |  | 
|  | if ((ninputs = ctf_link_deduplicating_count_inputs (fp, in, | 
|  | &only_input)) == -1) | 
|  | goto err_open_inputs; | 
|  |  | 
|  | /* CU mapping with no inputs?  Skip.  */ | 
|  | if (ninputs == 0) | 
|  | continue; | 
|  |  | 
|  | if (labs ((long int) ninputs) > 0xfffffffe) | 
|  | { | 
|  | ctf_err_warn (fp, 0, EFBIG, _("too many inputs in deduplicating " | 
|  | "link: %li"), (long int) ninputs); | 
|  | ctf_set_errno (fp, EFBIG); | 
|  | goto err_open_inputs; | 
|  | } | 
|  |  | 
|  | /* Short-circuit: a cu-mapped link with only one input archive with | 
|  | unconflicting contents is a do-nothing, and we can just leave the input | 
|  | in place: we do have to change the cuname, though, so we unwrap it, | 
|  | change the cuname, then stuff it back in the linker input again, via | 
|  | the clin_fp short-circuit member.  ctf_link_deduplicating_open_inputs | 
|  | will spot this member and jam it straight into the next link phase, | 
|  | ignoring the corresponding archive.  */ | 
|  | if (only_input && ninputs == 1) | 
|  | { | 
|  | ctf_next_t *ai = NULL; | 
|  | int err; | 
|  |  | 
|  | /* We can abuse an archive iterator to get the only member cheaply, no | 
|  | matter what its name.  */ | 
|  | only_input->clin_fp = ctf_archive_next (only_input->clin_arc, | 
|  | &ai, NULL, 0, &err); | 
|  | if (!only_input->clin_fp) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("cannot open archive %s in " | 
|  | "CU-mapped CTF link"), | 
|  | only_input->clin_filename); | 
|  | ctf_set_errno (fp, err); | 
|  | goto err_open_inputs; | 
|  | } | 
|  | ctf_next_destroy (ai); | 
|  |  | 
|  | if (strcmp (only_input->clin_filename, out_name) != 0) | 
|  | { | 
|  | /* Renaming. We need to add a new input, then null out the | 
|  | clin_arc and clin_fp of the old one to stop it being | 
|  | auto-closed on removal.  The new input needs its cuname changed | 
|  | to out_name, which is doable only because the cuname is a | 
|  | dynamic property which can be changed even in readonly | 
|  | dicts. */ | 
|  |  | 
|  | ctf_cuname_set (only_input->clin_fp, out_name); | 
|  | if (ctf_link_add_ctf_internal (fp, only_input->clin_arc, | 
|  | only_input->clin_fp, | 
|  | out_name) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("cannot add intermediate files " | 
|  | "to link")); | 
|  | goto err_open_inputs; | 
|  | } | 
|  | only_input->clin_arc = NULL; | 
|  | only_input->clin_fp = NULL; | 
|  | ctf_dynhash_remove (fp->ctf_link_inputs, | 
|  | only_input->clin_filename); | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | /* This is a real CU many-to-one mapping: we must dedup the inputs into | 
|  | a new output to be used in the final link phase.  */ | 
|  |  | 
|  | if ((inputs = ctf_link_deduplicating_open_inputs (fp, in, ninputs, | 
|  | &parents)) == NULL) | 
|  | { | 
|  | ctf_next_destroy (i); | 
|  | goto err_inputs; | 
|  | } | 
|  |  | 
|  | if ((out = ctf_create (&err)) == NULL) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("cannot create per-CU CTF archive " | 
|  | "for %s"), | 
|  | out_name); | 
|  | ctf_set_errno (fp, err); | 
|  | goto err_inputs; | 
|  | } | 
|  |  | 
|  | /* Share the atoms table to reduce memory usage.  */ | 
|  | out->ctf_dedup_atoms = fp->ctf_dedup_atoms_alloc; | 
|  |  | 
|  | /* No ctf_imports at this stage: this per-CU dictionary has no parents. | 
|  | Parent/child deduplication happens in the link's final pass.  However, | 
|  | the cuname *is* important, as it is propagated into the final | 
|  | dictionary.  */ | 
|  | ctf_cuname_set (out, out_name); | 
|  |  | 
|  | if (ctf_dedup (out, inputs, ninputs, parents, 1) < 0) | 
|  | { | 
|  | ctf_set_errno (fp, ctf_errno (out)); | 
|  | ctf_err_warn (fp, 0, 0, _("CU-mapped deduplication failed for %s"), | 
|  | out_name); | 
|  | goto err_inputs; | 
|  | } | 
|  |  | 
|  | if ((outputs = ctf_dedup_emit (out, inputs, ninputs, parents, | 
|  | &noutputs, 1)) == NULL) | 
|  | { | 
|  | ctf_set_errno (fp, ctf_errno (out)); | 
|  | ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link type emission " | 
|  | "failed for %s"), out_name); | 
|  | goto err_inputs; | 
|  | } | 
|  | if (!ctf_assert (fp, noutputs == 1)) | 
|  | { | 
|  | size_t j; | 
|  | for (j = 1; j < noutputs; j++) | 
|  | ctf_dict_close (outputs[j]); | 
|  | goto err_inputs_outputs; | 
|  | } | 
|  |  | 
|  | if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION) | 
|  | && ctf_link_deduplicating_variables (out, inputs, ninputs, 1) < 0) | 
|  | { | 
|  | ctf_set_errno (fp, ctf_errno (out)); | 
|  | ctf_err_warn (fp, 0, 0, _("CU-mapped deduplicating link variable " | 
|  | "emission failed for %s"), out_name); | 
|  | goto err_inputs_outputs; | 
|  | } | 
|  |  | 
|  | ctf_dedup_fini (out, outputs, noutputs); | 
|  |  | 
|  | /* For now, we omit symbol section linking for CU-mapped links, until it | 
|  | is clear how to unify the symbol table across such links.  (Perhaps we | 
|  | should emit an unconditionally indexed symtab, like the compiler | 
|  | does.)  */ | 
|  |  | 
|  | if (ctf_link_deduplicating_close_inputs (fp, in, inputs, ninputs) < 0) | 
|  | { | 
|  | free (inputs); | 
|  | free (parents); | 
|  | goto err_outputs; | 
|  | } | 
|  | free (inputs); | 
|  | free (parents); | 
|  |  | 
|  | /* Splice any errors or warnings created during this link back into the | 
|  | dict that the caller knows about.  */ | 
|  | ctf_list_splice (&fp->ctf_errs_warnings, &outputs[0]->ctf_errs_warnings); | 
|  |  | 
|  | /* This output now becomes an input to the next link phase, with a name | 
|  | equal to the CU name.  We have to wrap it in an archive wrapper | 
|  | first.  */ | 
|  |  | 
|  | if ((in_arc = ctf_new_archive_internal (0, 0, NULL, outputs[0], NULL, | 
|  | NULL, &err)) == NULL) | 
|  | { | 
|  | ctf_set_errno (fp, err); | 
|  | goto err_outputs; | 
|  | } | 
|  |  | 
|  | if (ctf_link_add_ctf_internal (fp, in_arc, NULL, | 
|  | ctf_cuname (outputs[0])) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("cannot add intermediate files to link")); | 
|  | goto err_outputs; | 
|  | } | 
|  |  | 
|  | ctf_dict_close (out); | 
|  | free (outputs); | 
|  | continue; | 
|  |  | 
|  | err_inputs_outputs: | 
|  | ctf_list_splice (&fp->ctf_errs_warnings, &outputs[0]->ctf_errs_warnings); | 
|  | ctf_dict_close (outputs[0]); | 
|  | free (outputs); | 
|  | err_inputs: | 
|  | ctf_link_deduplicating_close_inputs (fp, in, inputs, ninputs); | 
|  | ctf_dict_close (out); | 
|  | free (inputs); | 
|  | free (parents); | 
|  | err_open_inputs: | 
|  | ctf_next_destroy (i); | 
|  | return -1; | 
|  |  | 
|  | err_outputs: | 
|  | ctf_list_splice (&fp->ctf_errs_warnings, &outputs[0]->ctf_errs_warnings); | 
|  | ctf_dict_close (outputs[0]); | 
|  | free (outputs); | 
|  | ctf_next_destroy (i); | 
|  | return -1;				/* Errno is set for us.  */ | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("iteration error in CU-mapped deduplicating " | 
|  | "link")); | 
|  | return ctf_set_errno (fp, err); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Empty all the ctf_link_outputs.  */ | 
|  | static int | 
|  | ctf_link_empty_outputs (ctf_dict_t *fp) | 
|  | { | 
|  | ctf_next_t *i = NULL; | 
|  | void *v; | 
|  | int err; | 
|  |  | 
|  | ctf_dynhash_empty (fp->ctf_link_outputs); | 
|  |  | 
|  | while ((err = ctf_dynhash_next (fp->ctf_link_inputs, &i, NULL, &v)) == 0) | 
|  | { | 
|  | ctf_dict_t *in = (ctf_dict_t *) v; | 
|  | in->ctf_link_in_out = NULL; | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | fp->ctf_flags &= ~LCTF_LINKING; | 
|  | ctf_err_warn (fp, 1, err, _("iteration error removing old outputs")); | 
|  | return ctf_set_errno (fp, err); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Do a deduplicating link using the ctf-dedup machinery.  */ | 
|  | static void | 
|  | ctf_link_deduplicating (ctf_dict_t *fp) | 
|  | { | 
|  | size_t i; | 
|  | ctf_dict_t **inputs, **outputs = NULL; | 
|  | ssize_t ninputs; | 
|  | uint32_t noutputs; | 
|  | uint32_t *parents; | 
|  |  | 
|  | if (ctf_dedup_atoms_init (fp) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("allocating CTF dedup atoms table")); | 
|  | return;					/* Errno is set for us.  */ | 
|  | } | 
|  |  | 
|  | if (fp->ctf_link_out_cu_mapping | 
|  | && (ctf_link_deduplicating_per_cu (fp) < 0)) | 
|  | return;					/* Errno is set for us.  */ | 
|  |  | 
|  | if ((ninputs = ctf_link_deduplicating_count_inputs (fp, NULL, NULL)) < 0) | 
|  | return;					/* Errno is set for us.  */ | 
|  |  | 
|  | if ((inputs = ctf_link_deduplicating_open_inputs (fp, NULL, ninputs, | 
|  | &parents)) == NULL) | 
|  | return;					/* Errno is set for us.  */ | 
|  |  | 
|  | if (ninputs == 1 && ctf_cuname (inputs[0]) != NULL) | 
|  | ctf_cuname_set (fp, ctf_cuname (inputs[0])); | 
|  |  | 
|  | if (ctf_dedup (fp, inputs, ninputs, parents, 0) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("deduplication failed for %s"), | 
|  | ctf_link_input_name (fp)); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if ((outputs = ctf_dedup_emit (fp, inputs, ninputs, parents, &noutputs, | 
|  | 0)) == NULL) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("deduplicating link type emission failed " | 
|  | "for %s"), ctf_link_input_name (fp)); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if (!ctf_assert (fp, outputs[0] == fp)) | 
|  | { | 
|  | for (i = 1; i < noutputs; i++) | 
|  | ctf_dict_close (outputs[i]); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < noutputs; i++) | 
|  | { | 
|  | char *dynname; | 
|  |  | 
|  | /* We already have access to this one.  Close the duplicate.  */ | 
|  | if (i == 0) | 
|  | { | 
|  | ctf_dict_close (outputs[0]); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if ((dynname = ctf_new_per_cu_name (fp, ctf_cuname (outputs[i]))) == NULL) | 
|  | goto oom_one_output; | 
|  |  | 
|  | if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, outputs[i]) < 0) | 
|  | goto oom_one_output; | 
|  |  | 
|  | continue; | 
|  |  | 
|  | oom_one_output: | 
|  | ctf_set_errno (fp, ENOMEM); | 
|  | ctf_err_warn (fp, 0, 0, _("out of memory allocating link outputs")); | 
|  | free (dynname); | 
|  |  | 
|  | for (; i < noutputs; i++) | 
|  | ctf_dict_close (outputs[i]); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if (!(fp->ctf_link_flags & CTF_LINK_OMIT_VARIABLES_SECTION) | 
|  | && ctf_link_deduplicating_variables (fp, inputs, ninputs, 0) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("deduplicating link variable emission failed for " | 
|  | "%s"), ctf_link_input_name (fp)); | 
|  | goto err_clean_outputs; | 
|  | } | 
|  |  | 
|  | if (ctf_link_deduplicating_syms (fp, inputs, ninputs, 0) < 0) | 
|  | { | 
|  | ctf_err_warn (fp, 0, 0, _("deduplicating link symbol emission failed for " | 
|  | "%s"), ctf_link_input_name (fp)); | 
|  | goto err_clean_outputs; | 
|  | } | 
|  |  | 
|  | ctf_dedup_fini (fp, outputs, noutputs); | 
|  |  | 
|  | /* Now close all the inputs, including per-CU intermediates.  */ | 
|  |  | 
|  | if (ctf_link_deduplicating_close_inputs (fp, NULL, inputs, ninputs) < 0) | 
|  | return;					/* errno is set for us.  */ | 
|  |  | 
|  | ninputs = 0;					/* Prevent double-close.  */ | 
|  | ctf_set_errno (fp, 0); | 
|  |  | 
|  | /* Fall through.  */ | 
|  |  | 
|  | err: | 
|  | for (i = 0; i < (size_t) ninputs; i++) | 
|  | ctf_dict_close (inputs[i]); | 
|  | free (inputs); | 
|  | free (parents); | 
|  | free (outputs); | 
|  | return; | 
|  |  | 
|  | err_clean_outputs: | 
|  | ctf_link_empty_outputs (fp); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | /* Merge types and variable sections in all dicts added to the link together. | 
|  | The result of any previous link is discarded.  */ | 
|  | int | 
|  | ctf_link (ctf_dict_t *fp, int flags) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | fp->ctf_link_flags = flags; | 
|  |  | 
|  | if (fp->ctf_link_inputs == NULL) | 
|  | return 0;					/* Nothing to do. */ | 
|  |  | 
|  | if (fp->ctf_link_outputs != NULL) | 
|  | ctf_link_empty_outputs (fp); | 
|  | else | 
|  | fp->ctf_link_outputs = ctf_dynhash_create (ctf_hash_string, | 
|  | ctf_hash_eq_string, free, | 
|  | (ctf_hash_free_fun) | 
|  | ctf_dict_close); | 
|  |  | 
|  | if (fp->ctf_link_outputs == NULL) | 
|  | return ctf_set_errno (fp, ENOMEM); | 
|  |  | 
|  | fp->ctf_flags |= LCTF_LINKING; | 
|  | ctf_link_deduplicating (fp); | 
|  | fp->ctf_flags &= ~LCTF_LINKING; | 
|  |  | 
|  | if ((ctf_errno (fp) != 0) && (ctf_errno (fp) != ECTF_NOCTFDATA)) | 
|  | return -1; | 
|  |  | 
|  | /* Create empty CUs if requested.  We do not currently claim that multiple | 
|  | links in succession with CTF_LINK_EMPTY_CU_MAPPINGS set in some calls and | 
|  | not set in others will do anything especially sensible.  */ | 
|  |  | 
|  | if (fp->ctf_link_out_cu_mapping && (flags & CTF_LINK_EMPTY_CU_MAPPINGS)) | 
|  | { | 
|  | ctf_next_t *i = NULL; | 
|  | void *k; | 
|  |  | 
|  | while ((err = ctf_dynhash_next (fp->ctf_link_out_cu_mapping, &i, &k, | 
|  | NULL)) == 0) | 
|  | { | 
|  | const char *to = (const char *) k; | 
|  | if (ctf_create_per_cu (fp, NULL, to) == NULL) | 
|  | { | 
|  | fp->ctf_flags &= ~LCTF_LINKING; | 
|  | ctf_next_destroy (i); | 
|  | return -1;			/* Errno is set for us.  */ | 
|  | } | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | fp->ctf_flags &= ~LCTF_LINKING; | 
|  | ctf_err_warn (fp, 1, err, _("iteration error creating empty CUs")); | 
|  | return ctf_set_errno (fp, err); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | typedef struct ctf_link_out_string_cb_arg | 
|  | { | 
|  | const char *str; | 
|  | uint32_t offset; | 
|  | int err; | 
|  | } ctf_link_out_string_cb_arg_t; | 
|  |  | 
|  | /* Intern a string in the string table of an output per-CU CTF file.  */ | 
|  | static void | 
|  | ctf_link_intern_extern_string (void *key _libctf_unused_, void *value, | 
|  | void *arg_) | 
|  | { | 
|  | ctf_dict_t *fp = (ctf_dict_t *) 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)) | 
|  | arg->err = ENOMEM; | 
|  | } | 
|  |  | 
|  | /* Repeatedly call ADD_STRING to acquire strings from the external string table, | 
|  | adding them to the atoms table for this CU and all subsidiary CUs. | 
|  |  | 
|  | If ctf_link is also called, it must be called first if you want the new CTF | 
|  | files ctf_link can create to get their strings dedupped against the ELF | 
|  | strtab properly.  */ | 
|  | int | 
|  | ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string, | 
|  | void *arg) | 
|  | { | 
|  | const char *str; | 
|  | uint32_t offset; | 
|  | int err = 0; | 
|  |  | 
|  | while ((str = add_string (&offset, arg)) != NULL) | 
|  | { | 
|  | 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)) | 
|  | err = ENOMEM; | 
|  |  | 
|  | ctf_dynhash_iter (fp->ctf_link_outputs, ctf_link_intern_extern_string, | 
|  | &iter_arg); | 
|  | if (iter_arg.err) | 
|  | err = iter_arg.err; | 
|  | } | 
|  |  | 
|  | if (err) | 
|  | ctf_set_errno (fp, err); | 
|  |  | 
|  | return -err; | 
|  | } | 
|  |  | 
|  | /* Inform the ctf-link machinery of a new symbol in the target symbol table | 
|  | (which must be some symtab that is not usually stripped, and which | 
|  | is in agreement with ctf_bfdopen_ctfsect).  May be called either before or | 
|  | after ctf_link_add_strtab.  */ | 
|  | int | 
|  | ctf_link_add_linker_symbol (ctf_dict_t *fp, ctf_link_sym_t *sym) | 
|  | { | 
|  | ctf_in_flight_dynsym_t *cid; | 
|  |  | 
|  | /* Cheat a little: if there is already an ENOMEM error code recorded against | 
|  | this dict, we shouldn't even try to add symbols because there will be no | 
|  | memory to do so: probably we failed to add some previous symbol.  This | 
|  | makes out-of-memory exits 'sticky' across calls to this function, so the | 
|  | caller doesn't need to worry about error conditions.  */ | 
|  |  | 
|  | if (ctf_errno (fp) == ENOMEM) | 
|  | return -ENOMEM;				/* errno is set for us.  */ | 
|  |  | 
|  | if (ctf_symtab_skippable (sym)) | 
|  | return 0; | 
|  |  | 
|  | if (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC) | 
|  | return 0; | 
|  |  | 
|  | /* Add the symbol to the in-flight list.  */ | 
|  |  | 
|  | if ((cid = malloc (sizeof (ctf_in_flight_dynsym_t))) == NULL) | 
|  | goto oom; | 
|  |  | 
|  | cid->cid_sym = *sym; | 
|  | ctf_list_append (&fp->ctf_in_flight_dynsyms, cid); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | oom: | 
|  | ctf_dynhash_destroy (fp->ctf_dynsyms); | 
|  | fp->ctf_dynsyms = NULL; | 
|  | ctf_set_errno (fp, ENOMEM); | 
|  | return -ENOMEM; | 
|  | } | 
|  |  | 
|  | /* Impose an ordering on symbols.  The ordering takes effect immediately, but | 
|  | since the ordering info does not include type IDs, lookups may return nothing | 
|  | until such IDs are added by calls to ctf_add_*_sym.  Must be called after | 
|  | ctf_link_add_strtab and ctf_link_add_linker_symbol.  */ | 
|  | int | 
|  | ctf_link_shuffle_syms (ctf_dict_t *fp) | 
|  | { | 
|  | ctf_in_flight_dynsym_t *did, *nid; | 
|  | ctf_next_t *i = NULL; | 
|  | int err = ENOMEM; | 
|  | void *name_, *sym_; | 
|  |  | 
|  | if (!fp->ctf_dynsyms) | 
|  | { | 
|  | fp->ctf_dynsyms = ctf_dynhash_create (ctf_hash_string, | 
|  | ctf_hash_eq_string, | 
|  | NULL, free); | 
|  | if (!fp->ctf_dynsyms) | 
|  | { | 
|  | ctf_set_errno (fp, ENOMEM); | 
|  | return -ENOMEM; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Add all the symbols, excluding only those we already know are prohibited | 
|  | from appearing in symtypetabs.  */ | 
|  |  | 
|  | for (did = ctf_list_next (&fp->ctf_in_flight_dynsyms); did != NULL; did = nid) | 
|  | { | 
|  | ctf_link_sym_t *new_sym; | 
|  |  | 
|  | nid = ctf_list_next (did); | 
|  | ctf_list_delete (&fp->ctf_in_flight_dynsyms, did); | 
|  |  | 
|  | /* We might get a name or an external strtab offset.  The strtab offset is | 
|  | guaranteed resolvable at this point, so turn it into a string.  */ | 
|  |  | 
|  | if (did->cid_sym.st_name == NULL) | 
|  | { | 
|  | uint32_t off = CTF_SET_STID (did->cid_sym.st_nameidx, CTF_STRTAB_1); | 
|  |  | 
|  | did->cid_sym.st_name = ctf_strraw (fp, off); | 
|  | did->cid_sym.st_nameidx_set = 0; | 
|  | if (!ctf_assert (fp, did->cid_sym.st_name != NULL)) | 
|  | return -ECTF_INTERNAL;		/* errno is set for us.  */ | 
|  | } | 
|  |  | 
|  | /* The symbol might have turned out to be nameless, so we have to recheck | 
|  | for skippability here.  */ | 
|  | if (!ctf_symtab_skippable (&did->cid_sym)) | 
|  | { | 
|  | ctf_dprintf ("symbol from linker: %s (%x)\n", did->cid_sym.st_name, | 
|  | did->cid_sym.st_symidx); | 
|  |  | 
|  | if ((new_sym = malloc (sizeof (ctf_link_sym_t))) == NULL) | 
|  | goto local_oom; | 
|  |  | 
|  | memcpy (new_sym, &did->cid_sym, sizeof (ctf_link_sym_t)); | 
|  | if (ctf_dynhash_cinsert (fp->ctf_dynsyms, new_sym->st_name, new_sym) < 0) | 
|  | goto local_oom; | 
|  |  | 
|  | if (fp->ctf_dynsymmax < new_sym->st_symidx) | 
|  | fp->ctf_dynsymmax = new_sym->st_symidx; | 
|  | } | 
|  |  | 
|  | free (did); | 
|  | continue; | 
|  |  | 
|  | local_oom: | 
|  | free (did); | 
|  | free (new_sym); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | /* If no symbols are reported, unwind what we have done and return.  This | 
|  | makes it a bit easier for the serializer to tell that no symbols have been | 
|  | reported and that it should look elsewhere for reported symbols.  */ | 
|  | if (!ctf_dynhash_elements (fp->ctf_dynsyms)) | 
|  | { | 
|  | ctf_dprintf ("No symbols: not a final link.\n"); | 
|  | ctf_dynhash_destroy (fp->ctf_dynsyms); | 
|  | fp->ctf_dynsyms = NULL; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Construct a mapping from shndx to the symbol info.  */ | 
|  | free (fp->ctf_dynsymidx); | 
|  | if ((fp->ctf_dynsymidx = calloc (fp->ctf_dynsymmax + 1, | 
|  | sizeof (ctf_link_sym_t *))) == NULL) | 
|  | goto err; | 
|  |  | 
|  | while ((err = ctf_dynhash_next (fp->ctf_dynsyms, &i, &name_, &sym_)) == 0) | 
|  | { | 
|  | const char *name = (const char *) name; | 
|  | ctf_link_sym_t *symp = (ctf_link_sym_t *) sym_; | 
|  |  | 
|  | if (!ctf_assert (fp, symp->st_symidx <= fp->ctf_dynsymmax)) | 
|  | { | 
|  | ctf_next_destroy (i); | 
|  | err = ctf_errno (fp); | 
|  | goto err; | 
|  | } | 
|  | fp->ctf_dynsymidx[symp->st_symidx] = symp; | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | { | 
|  | ctf_err_warn (fp, 0, err, _("error iterating over shuffled symbols")); | 
|  | goto err; | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | err: | 
|  | /* Leave the in-flight symbols around: they'll be freed at | 
|  | dict close time regardless.  */ | 
|  | ctf_dynhash_destroy (fp->ctf_dynsyms); | 
|  | fp->ctf_dynsyms = NULL; | 
|  | free (fp->ctf_dynsymidx); | 
|  | fp->ctf_dynsymidx = NULL; | 
|  | fp->ctf_dynsymmax = 0; | 
|  | ctf_set_errno (fp, err); | 
|  | return -err; | 
|  | } | 
|  |  | 
|  | typedef struct ctf_name_list_accum_cb_arg | 
|  | { | 
|  | char **names; | 
|  | ctf_dict_t *fp; | 
|  | ctf_dict_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.  */ | 
|  | static void | 
|  | ctf_accumulate_archive_names (void *key, void *value, void *arg_) | 
|  | { | 
|  | const char *name = (const char *) key; | 
|  | ctf_dict_t *fp = (ctf_dict_t *) value; | 
|  | char **names; | 
|  | ctf_dict_t **files; | 
|  | ctf_name_list_accum_cb_arg_t *arg = (ctf_name_list_accum_cb_arg_t *) arg_; | 
|  |  | 
|  | if ((names = realloc (arg->names, sizeof (char *) * ++(arg->i))) == NULL) | 
|  | { | 
|  | (arg->i)--; | 
|  | ctf_set_errno (arg->fp, ENOMEM); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if ((files = realloc (arg->files, sizeof (ctf_dict_t *) * arg->i)) == NULL) | 
|  | { | 
|  | (arg->i)--; | 
|  | 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_dict_t *fp = (ctf_dict_t *) value; | 
|  | const char *name = (const char *) arg; | 
|  |  | 
|  | ctf_parent_name_set (fp, name); | 
|  | } | 
|  |  | 
|  | /* Warn if we may suffer information loss because the CTF input files are too | 
|  | old.  Usually we provide complete backward compatibility, but compiler | 
|  | changes etc which never hit a release may have a flag in the header that | 
|  | simply prevents those changes from being used.  */ | 
|  | static void | 
|  | ctf_link_warn_outdated_inputs (ctf_dict_t *fp) | 
|  | { | 
|  | ctf_next_t *i = NULL; | 
|  | void *name_; | 
|  | void *input_; | 
|  | int err; | 
|  |  | 
|  | while ((err = ctf_dynhash_next (fp->ctf_link_inputs, &i, &name_, &input_)) == 0) | 
|  | { | 
|  | const char *name = (const char *) name_; | 
|  | ctf_link_input_t *input = (ctf_link_input_t *) input_; | 
|  | ctf_next_t *j = NULL; | 
|  | ctf_dict_t *ifp; | 
|  | int err; | 
|  |  | 
|  | /* We only care about CTF archives by this point: lazy-opened archives | 
|  | have always been opened by this point, and short-circuited entries have | 
|  | a matching corresponding archive member. Entries with NULL clin_arc can | 
|  | exist, and constitute old entries renamed via a name changer: the | 
|  | renamed entries exist elsewhere in the list, so we can just skip | 
|  | those.  */ | 
|  |  | 
|  | if (!input->clin_arc) | 
|  | continue; | 
|  |  | 
|  | /* All entries in the archive will necessarily contain the same | 
|  | CTF_F_NEWFUNCINFO flag, so we only need to check the first. We don't | 
|  | even need to do that if we can't open it for any reason at all: the | 
|  | link will fail later on regardless, since an input can't be opened. */ | 
|  |  | 
|  | ifp = ctf_archive_next (input->clin_arc, &j, NULL, 0, &err); | 
|  | if (!ifp) | 
|  | continue; | 
|  | ctf_next_destroy (j); | 
|  |  | 
|  | if (!(ifp->ctf_header->cth_flags & CTF_F_NEWFUNCINFO) | 
|  | && (ifp->ctf_header->cth_varoff - ifp->ctf_header->cth_funcoff) > 0) | 
|  | ctf_err_warn (fp, 1, 0, _("linker input %s has CTF func info but uses " | 
|  | "an old, unreleased func info format: " | 
|  | "this func info section will be dropped."), | 
|  | name); | 
|  | } | 
|  | if (err != ECTF_NEXT_END) | 
|  | ctf_err_warn (fp, 0, err, _("error checking for outdated inputs")); | 
|  | } | 
|  |  | 
|  | /* 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.  */ | 
|  | unsigned char * | 
|  | ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold) | 
|  | { | 
|  | ctf_name_list_accum_cb_arg_t arg; | 
|  | char **names; | 
|  | char *transformed_name = NULL; | 
|  | ctf_dict_t **files; | 
|  | FILE *f = NULL; | 
|  | size_t i; | 
|  | int err; | 
|  | long fsize; | 
|  | const char *errloc; | 
|  | unsigned char *buf = NULL; | 
|  |  | 
|  | memset (&arg, 0, sizeof (ctf_name_list_accum_cb_arg_t)); | 
|  | arg.fp = fp; | 
|  | fp->ctf_flags |= LCTF_LINKING; | 
|  |  | 
|  | ctf_link_warn_outdated_inputs (fp); | 
|  |  | 
|  | if (fp->ctf_link_outputs) | 
|  | { | 
|  | ctf_dynhash_iter (fp->ctf_link_outputs, ctf_accumulate_archive_names, &arg); | 
|  | if (ctf_errno (fp) < 0) | 
|  | { | 
|  | errloc = "hash creation"; | 
|  | goto err; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* No extra outputs? Just write a simple ctf_dict_t.  */ | 
|  | if (arg.i == 0) | 
|  | { | 
|  | unsigned char *ret = ctf_write_mem (fp, size, threshold); | 
|  | fp->ctf_flags &= ~LCTF_LINKING; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* Writing an archive.  Stick ourselves (the shared repository, parent of all | 
|  | other archives) on the front of it with the default name.  */ | 
|  | if ((names = realloc (arg.names, sizeof (char *) * (arg.i + 1))) == NULL) | 
|  | { | 
|  | errloc = "name reallocation"; | 
|  | goto err_no; | 
|  | } | 
|  | 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); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Propagate the link flags to all the dicts in this link.  */ | 
|  | for (i = 0; i < arg.i; i++) | 
|  | { | 
|  | arg.files[i]->ctf_link_flags = fp->ctf_link_flags; | 
|  | arg.files[i]->ctf_flags |= LCTF_LINKING; | 
|  | } | 
|  |  | 
|  | if ((files = realloc (arg.files, | 
|  | sizeof (struct ctf_dict *) * (arg.i + 1))) == NULL) | 
|  | { | 
|  | errloc = "ctf_dict reallocation"; | 
|  | goto err_no; | 
|  | } | 
|  | arg.files = files; | 
|  | memmove (&(arg.files[1]), arg.files, sizeof (ctf_dict_t *) * (arg.i)); | 
|  | arg.files[0] = fp; | 
|  |  | 
|  | if ((f = tmpfile ()) == NULL) | 
|  | { | 
|  | errloc = "tempfile creation"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | if ((err = ctf_arc_write_fd (fileno (f), arg.files, arg.i + 1, | 
|  | (const char **) arg.names, | 
|  | threshold)) < 0) | 
|  | { | 
|  | errloc = "archive writing"; | 
|  | ctf_set_errno (fp, err); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if (fseek (f, 0, SEEK_END) < 0) | 
|  | { | 
|  | errloc = "seeking to end"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | if ((fsize = ftell (f)) < 0) | 
|  | { | 
|  | errloc = "filesize determination"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | if (fseek (f, 0, SEEK_SET) < 0) | 
|  | { | 
|  | errloc = "filepos resetting"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | if ((buf = malloc (fsize)) == NULL) | 
|  | { | 
|  | errloc = "CTF archive buffer allocation"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | while (!feof (f) && fread (buf, fsize, 1, f) == 0) | 
|  | if (ferror (f)) | 
|  | { | 
|  | errloc = "reading archive from temporary file"; | 
|  | goto err_no; | 
|  | } | 
|  |  | 
|  | *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); | 
|  | } | 
|  | fclose (f); | 
|  | return buf; | 
|  |  | 
|  | err_no: | 
|  | ctf_set_errno (fp, errno); | 
|  |  | 
|  | /* Turn off the is-linking flag on all the dicts in this link.  */ | 
|  | for (i = 0; i < arg.i; i++) | 
|  | arg.files[i]->ctf_flags &= ~LCTF_LINKING; | 
|  | err: | 
|  | free (buf); | 
|  | if (f) | 
|  | 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_err_warn (fp, 0, 0, _("cannot write archive in link: %s failure"), | 
|  | errloc); | 
|  | return NULL; | 
|  | } |