gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / libctf / ctf-link.c
index 8dd81d1f124192c335866fd052542fff580bae7f..31179ae13d7c2f349a6997baf79357bd6f8d86b1 100644 (file)
@@ -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;
This page took 0.046344 seconds and 4 git commands to generate.