]> Git Repo - binutils.git/blobdiff - libctf/ctf-link.c
Automatic date update in version.in
[binutils.git] / libctf / ctf-link.c
index 5471fccd0f7eb814b834562ad6dd9649e0964cc6..902b4408cd66197059cda7a91193317f6502b970 100644 (file)
@@ -1,5 +1,5 @@
 /* CTF linking.
-   Copyright (C) 2019-2021 Free Software Foundation, Inc.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
 
    This file is part of libctf.
 
@@ -72,7 +72,7 @@ ctf_unnamed_cuname (ctf_dict_t *fp)
    never gets explicitly freed in the ctf_link_input.  */
 typedef struct ctf_link_input
 {
-  const char *clin_filename;
+  char *clin_filename;
   ctf_archive_t *clin_arc;
   ctf_dict_t *clin_fp;
   int n;
@@ -84,6 +84,7 @@ 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);
 }
 
@@ -93,27 +94,54 @@ static int
 ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
                           ctf_dict_t *fp_input, const char *name)
 {
-  ctf_link_input_t *input = NULL;
-  char *dupname = NULL;
+  int existing = 0;
+  ctf_link_input_t *input;
+  char *filename, *keyname;
 
-  if ((input = calloc (1, sizeof (ctf_link_input_t))) == NULL)
-    goto oom;
+  /* 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 ((dupname = strdup (name)) == NULL)
+  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 = dupname;
+  input->clin_filename = filename;
   input->n = ctf_dynhash_elements (fp->ctf_link_inputs);
 
-  if (ctf_dynhash_insert (fp->ctf_link_inputs, dupname, input) < 0)
-    goto oom;
+  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;
- oom:
+
+ oom3:
+  free (keyname);
+ oom2:
   free (input);
-  free (dupname);
+ oom1:
+  free (filename);
+ oom:
   return ctf_set_errno (fp, ENOMEM);
 }
 
@@ -133,6 +161,10 @@ ctf_link_add_ctf_internal (ctf_dict_t *fp, ctf_archive_t *ctf,
     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.  */
 
@@ -189,20 +221,96 @@ ctf_link_add_ctf (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name)
   return ctf_link_add (fp, ctf, name, NULL, 0);
 }
 
-/* Return a per-CU output CTF dictionary suitable for the given CU, creating and
-   interning it if need be.  */
+/* 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);
+  ctf_set_errno (fp, ECTF_NEEDSBFD);
+  return -1;
+#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);
+      ctf_set_errno (fp, err);
+      return -1;
+    }
+
+  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.  */
 
-_libctf_nonnull_((1,2))
 static ctf_dict_t *
-ctf_create_per_cu (ctf_dict_t *fp, const char *cu_name)
+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;
 
-  /* First, check the mapping table and translate the per-CU name we use
+  /* 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,
@@ -213,7 +321,12 @@ ctf_create_per_cu (ctf_dict_t *fp, const char *cu_name)
   if (ctf_name == NULL)
     ctf_name = cu_name;
 
-  if ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL)
+  /* 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 ((cu_fp = ctf_dynhash_lookup (fp->ctf_link_outputs, ctf_name)) == NULL
+      || cu_fp->ctf_link_in_out != fp)
     {
       int err;
 
@@ -225,14 +338,19 @@ ctf_create_per_cu (ctf_dict_t *fp, const char *cu_name)
          return NULL;
        }
 
-      if ((dynname = strdup (ctf_name)) == NULL)
-       goto oom;
-      if (ctf_dynhash_insert (fp->ctf_link_outputs, dynname, cu_fp) < 0)
+      ctf_import_unref (cu_fp, fp);
+
+      if ((dynname = ctf_new_per_cu_name (fp, ctf_name)) == NULL)
        goto oom;
 
-      ctf_import_unref (cu_fp, fp);
       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;
 
@@ -258,6 +376,10 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
   char *f = NULL, *t = NULL;
   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,
@@ -309,7 +431,10 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)
        }
     }
   else
-    free (t);
+    {
+      free (t);
+      t = NULL;
+    }
 
   if (ctf_dynhash_insert (one_out, f, NULL) < 0)
     {
@@ -435,7 +560,7 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
       return 0;
     }
 
-  if ((per_cu_out_fp = ctf_create_per_cu (fp, ctf_unnamed_cuname (in_fp))) == NULL)
+  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.  */
@@ -461,52 +586,6 @@ ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name,
   return 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);
-  ctf_set_errno (fp, ECTF_NEEDSBFD);
-  return -1;
-#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);
-      ctf_set_errno (fp, err);
-      return -1;
-    }
-
-  if ((count = ctf_archive_count (input->clin_arc)) == 0)
-    ctf_arc_close (input->clin_arc);
-
-  return (ssize_t) count;
-}
-
 typedef struct link_sort_inputs_cb_arg
 {
   int is_cu_mapped;
@@ -807,7 +886,12 @@ ctf_link_deduplicating_close_inputs (ctf_dict_t *fp, ctf_dynhash_t *cu_names,
   return 0;
 }
 
-/* Do a deduplicating link of all variables in the inputs.  */
+/* 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)
@@ -820,6 +904,8 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
       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)
@@ -830,6 +916,34 @@ ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs,
        }
       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;
 }
@@ -917,7 +1031,7 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input,
          continue;
        }
 
-      if ((per_cu_out_fp = ctf_create_per_cu (fp, ctf_unnamed_cuname (input))) == NULL)
+      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.  */
@@ -1222,6 +1336,31 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp)
   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"));
+      ctf_set_errno (fp, err);
+      return -1;
+    }
+  return 0;
+}
+
 /* Do a deduplicating link using the ctf-dedup machinery.  */
 static void
 ctf_link_deduplicating (ctf_dict_t *fp)
@@ -1285,7 +1424,7 @@ ctf_link_deduplicating (ctf_dict_t *fp)
          continue;
        }
 
-      if ((dynname = strdup (ctf_cuname (outputs[i]))) == NULL)
+      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)
@@ -1339,20 +1478,15 @@ ctf_link_deduplicating (ctf_dict_t *fp)
   return;
 
  err_clean_outputs:
-  for (i = 1; i < noutputs; i++)
-    {
-      ctf_dynhash_remove (fp->ctf_link_outputs, ctf_cuname (outputs[i]));
-      ctf_dict_close (outputs[i]);
-    }
+  ctf_link_empty_outputs (fp);
   goto err;
 }
 
 /* Merge types and variable sections in all dicts added to the link together.
-   All the added dicts are closed.  */
+   The result of any previous link is discarded.  */
 int
 ctf_link (ctf_dict_t *fp, int flags)
 {
-  ctf_next_t *i = NULL;
   int err;
 
   fp->ctf_link_flags = flags;
@@ -1360,7 +1494,9 @@ ctf_link (ctf_dict_t *fp, int flags)
   if (fp->ctf_link_inputs == NULL)
     return 0;                                  /* Nothing to do. */
 
-  if (fp->ctf_link_outputs == NULL)
+  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)
@@ -1376,13 +1512,14 @@ ctf_link (ctf_dict_t *fp, int flags)
   fp->ctf_flags |= LCTF_LINKING;
   if (fp->ctf_link_out_cu_mapping && (flags & CTF_LINK_EMPTY_CU_MAPPINGS))
     {
-      void *v;
+      ctf_next_t *i = NULL;
+      void *k;
 
-      while ((err = ctf_dynhash_next (fp->ctf_link_out_cu_mapping, &i, &v,
+      while ((err = ctf_dynhash_next (fp->ctf_link_out_cu_mapping, &i, &k,
                                      NULL)) == 0)
        {
-         const char *to = (const char *) v;
-         if (ctf_create_per_cu (fp, to) == NULL)
+         const char *to = (const char *) k;
+         if (ctf_create_per_cu (fp, NULL, to) == NULL)
            {
              fp->ctf_flags &= ~LCTF_LINKING;
              ctf_next_destroy (i);
This page took 0.037906 seconds and 4 git commands to generate.