AArch64: Add gdbserver MTE support
[deliverable/binutils-gdb.git] / libctf / ctf-archive.c
index 193fc4df5749e090d418079a3aa8b902bcda2c5a..e0ceb80fa11fa1899c5c3e091192e3cf8f114a30 100644 (file)
@@ -46,8 +46,8 @@ static int arc_mmap_writeout (int fd, void *header, size_t headersz,
 static int arc_mmap_unmap (void *header, size_t headersz, const char **errmsg);
 static void ctf_arc_import_parent (const ctf_archive_t *arc, ctf_dict_t *fp);
 
-/* Flag to indicate "symbol not present" in
-   ctf_archive_internal.ctfi_symdicts.  Never initialized.  */
+/* Flag to indicate "symbol not present" in ctf_archive_internal.ctfi_symdicts
+   and ctfi_symnamedicts.  Never initialized.  */
 static ctf_dict_t enosym;
 
 /* Write out a CTF archive to the start of the file referenced by the passed-in
@@ -529,8 +529,8 @@ ctf_arc_close (ctf_archive_t *arc)
     }
   else
     ctf_dict_close (arc->ctfi_dict);
-  free (arc->ctfi_syms);
   free (arc->ctfi_symdicts);
+  free (arc->ctfi_symnamedicts);
   ctf_dynhash_destroy (arc->ctfi_dicts);
   if (arc->ctfi_free_symsect)
     free ((void *) arc->ctfi_symsect.cts_data);
@@ -645,8 +645,9 @@ ctf_cached_dict_close (void *fp)
   ctf_dict_close ((ctf_dict_t *) fp);
 }
 
-/* Return the ctf_dict_t with the given name and cache it in the
-   archive's ctfi_dicts.  */
+/* Return the ctf_dict_t with the given name and cache it in the archive's
+   ctfi_dicts.  If this is the first cached dict, designate it the
+   crossdict_cache.  */
 static ctf_dict_t *
 ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
 {
@@ -678,6 +679,9 @@ ctf_dict_open_cached (ctf_archive_t *arc, const char *name, int *errp)
     goto oom;
   fp->ctf_refcnt++;
 
+  if (arc->ctfi_crossdict_cache == NULL)
+    arc->ctfi_crossdict_cache = fp;
+
   return fp;
 
  oom:
@@ -693,11 +697,12 @@ void
 ctf_arc_flush_caches (ctf_archive_t *wrapper)
 {
   free (wrapper->ctfi_symdicts);
-  free (wrapper->ctfi_syms);
+  free (wrapper->ctfi_symnamedicts);
   ctf_dynhash_destroy (wrapper->ctfi_dicts);
   wrapper->ctfi_symdicts = NULL;
-  wrapper->ctfi_syms = NULL;
+  wrapper->ctfi_symnamedicts = NULL;
   wrapper->ctfi_dicts = NULL;
+  wrapper->ctfi_crossdict_cache = NULL;
 }
 
 /* Return the ctf_dict_t at the given ctfa_ctfs-relative offset, or NULL if
@@ -778,31 +783,46 @@ ctf_archive_count (const ctf_archive_t *wrapper)
   return wrapper->ctfi_archive->ctfa_ndicts;
 }
 
-/* Look up a symbol in an archive.  Return the dict in the archive that the
-   symbol is found in, and (optionally) the ctf_id_t of the symbol in that dict
-   (so you don't have to look it up yourself).  The dict and mapping are both
-   cached, so repeated lookups are nearly free.
+/* Look up a symbol in an archive by name or index (if the name is set, a lookup
+   by name is done).  Return the dict in the archive that the symbol is found
+   in, and (optionally) the ctf_id_t of the symbol in that dict (so you don't
+   have to look it up yourself).  The dict is cached, so repeated lookups are
+   nearly free.
 
    As usual, you should ctf_dict_close() the returned dict once you are done
    with it.
 
    Returns NULL on error, and an error in errp (if set).  */
 
-ctf_dict_t *
-ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
-                      ctf_id_t *typep, int *errp)
+static ctf_dict_t *
+ctf_arc_lookup_sym_or_name (ctf_archive_t *wrapper, unsigned long symidx,
+                           const char *symname, ctf_id_t *typep, int *errp)
 {
   ctf_dict_t *fp;
+  void *fpkey;
   ctf_id_t type;
 
   /* The usual non-archive-transparent-wrapper special case.  */
   if (!wrapper->ctfi_is_archive)
     {
-      if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
+      if (!symname)
        {
-         if (errp)
-           *errp = ctf_errno (wrapper->ctfi_dict);
-         return NULL;
+         if ((type = ctf_lookup_by_symbol (wrapper->ctfi_dict, symidx)) == CTF_ERR)
+           {
+             if (errp)
+               *errp = ctf_errno (wrapper->ctfi_dict);
+             return NULL;
+           }
+       }
+      else
+       {
+         if ((type = ctf_lookup_by_symbol_name (wrapper->ctfi_dict,
+                                                symname)) == CTF_ERR)
+           {
+             if (errp)
+               *errp = ctf_errno (wrapper->ctfi_dict);
+             return NULL;
+           }
        }
       if (typep)
        *typep = type;
@@ -820,27 +840,28 @@ ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
       return NULL;
     }
 
-  /* Make enough space for all possible symbols, if not already done.
-     We cache both the ctf_id_t and the originating dictionary of all symbols.
-     The dict links are weak, to the dictionaries cached in ctfi_dicts: their
-     refcnts are *not* bumped.  */
+  /* Make enough space for all possible symbol indexes, if not already done.  We
+     cache the originating dictionary of all symbols.  The dict links are weak,
+     to the dictionaries cached in ctfi_dicts: their refcnts are *not* bumped.
+     We also cache similar mappings for symbol names: these are ordinary
+     dynhashes, with weak links to dicts.  */
 
-  if (!wrapper->ctfi_syms)
+  if (!wrapper->ctfi_symdicts)
     {
-      if ((wrapper->ctfi_syms = calloc (wrapper->ctfi_symsect.cts_size
-                                       / wrapper->ctfi_symsect.cts_entsize,
-                                       sizeof (ctf_id_t))) == NULL)
+      if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
+                                           / wrapper->ctfi_symsect.cts_entsize,
+                                           sizeof (ctf_dict_t *))) == NULL)
        {
          if (errp)
            *errp = ENOMEM;
          return NULL;
        }
     }
-  if (!wrapper->ctfi_symdicts)
+  if (!wrapper->ctfi_symnamedicts)
     {
-      if ((wrapper->ctfi_symdicts = calloc (wrapper->ctfi_symsect.cts_size
-                                           / wrapper->ctfi_symsect.cts_entsize,
-                                           sizeof (ctf_dict_t *))) == NULL)
+      if ((wrapper->ctfi_symnamedicts = ctf_dynhash_create (ctf_hash_string,
+                                                           ctf_hash_eq_string,
+                                                           free, NULL)) == NULL)
        {
          if (errp)
            *errp = ENOMEM;
@@ -848,22 +869,38 @@ ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
        }
     }
 
-  /* Perhaps it's cached.  */
-  if (wrapper->ctfi_symdicts[symidx] != NULL)
+  /* Perhaps the dict in which we found a previous lookup is cached.  If it's
+     supposed to be cached but we don't find it, pretend it was always not
+     found: this should never happen, but shouldn't be allowed to cause trouble
+     if it does.  */
+
+  if ((symname && ctf_dynhash_lookup_kv (wrapper->ctfi_symnamedicts,
+                                        symname, NULL, &fpkey))
+      || (!symname && wrapper->ctfi_symdicts[symidx] != NULL))
     {
-      if (wrapper->ctfi_symdicts[symidx] == &enosym)
+      if (symname)
+       fp = (ctf_dict_t *) fpkey;
+      else
+       fp = wrapper->ctfi_symdicts[symidx];
+
+      if (fp == &enosym)
+       goto no_sym;
+
+      if (symname)
        {
-         if (errp)
-           *errp = ECTF_NOTYPEDAT;
-         if (typep)
-           *typep = CTF_ERR;
-         return NULL;
+         if ((type = ctf_lookup_by_symbol_name (fp, symname)) == CTF_ERR)
+           goto cache_no_sym;
+       }
+      else
+       {
+         if ((type = ctf_lookup_by_symbol (fp, symidx)) == CTF_ERR)
+           goto cache_no_sym;
        }
 
       if (typep)
-       *typep = wrapper->ctfi_syms[symidx];
-      wrapper->ctfi_symdicts[symidx]->ctf_refcnt++;
-      return wrapper->ctfi_symdicts[symidx];
+       *typep = type;
+      fp->ctf_refcnt++;
+      return fp;
     }
 
   /* Not cached: find it and cache it.  We must track open errors ourselves even
@@ -882,16 +919,36 @@ ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
 
   while ((fp = ctf_archive_next (wrapper, &i, &name, 0, local_errp)) != NULL)
     {
-      if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
+      if (!symname)
        {
-         wrapper->ctfi_syms[symidx] = type;
-         wrapper->ctfi_symdicts[symidx] = fp;
-         ctf_next_destroy (i);
+         if ((type = ctf_lookup_by_symbol (fp, symidx)) != CTF_ERR)
+           wrapper->ctfi_symdicts[symidx] = fp;
+       }
+      else
+       {
+         if ((type = ctf_lookup_by_symbol_name (fp, symname)) != CTF_ERR)
+           {
+             char *tmp;
+             /* No error checking, as above.  */
+             if ((tmp = strdup (symname)) != NULL)
+               ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, fp);
+           }
+       }
 
+      if (type != CTF_ERR)
+       {
          if (typep)
            *typep = type;
+         ctf_next_destroy (i);
          return fp;
        }
+      if (ctf_errno (fp) != ECTF_NOTYPEDAT)
+       {
+         if (errp)
+           *errp = ctf_errno (fp);
+         ctf_next_destroy (i);
+         return NULL;                          /* errno is set for us.  */
+       }
       ctf_dict_close (fp);
     }
   if (*local_errp != ECTF_NEXT_END)
@@ -899,11 +956,25 @@ ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
       ctf_next_destroy (i);
       return NULL;
     }
+
   /* Don't leak end-of-iteration to the caller.  */
   *local_errp = 0;
 
-  wrapper->ctfi_symdicts[symidx] = &enosym;
+ cache_no_sym:
+  if (!symname)
+    wrapper->ctfi_symdicts[symidx] = &enosym;
+  else
+    {
+      char *tmp;
 
+      /* No error checking: if caching fails, there is only a slight performance
+        impact.  */
+      if ((tmp = strdup (symname)) != NULL)
+       if (ctf_dynhash_insert (wrapper->ctfi_symnamedicts, tmp, &enosym) < 0)
+         free (tmp);
+    }
+
+ no_sym:
   if (errp)
     *errp = ECTF_NOTYPEDAT;
   if (typep)
@@ -911,6 +982,23 @@ ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
   return NULL;
 }
 
+/* The public API for looking up a symbol by index.  */
+ctf_dict_t *
+ctf_arc_lookup_symbol (ctf_archive_t *wrapper, unsigned long symidx,
+                      ctf_id_t *typep, int *errp)
+{
+  return ctf_arc_lookup_sym_or_name (wrapper, symidx, NULL, typep, errp);
+}
+
+/* The public API for looking up a symbol by name. */
+
+ctf_dict_t *
+ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
+                           ctf_id_t *typep, int *errp)
+{
+  return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
+}
+
 /* Raw iteration over all CTF files in an archive.  We pass the raw data for all
    CTF files in turn to the specified callback function.  */
 static int
@@ -955,70 +1043,32 @@ ctf_archive_raw_iter (const ctf_archive_t *arc,
   return -EINVAL;                       /* Not supported. */
 }
 
-/* Iterate over all CTF files in an archive.  We pass all CTF files in turn to
-   the specified callback function.  */
-static int
-ctf_archive_iter_internal (const ctf_archive_t *wrapper,
-                          const struct ctf_archive *arc,
-                          const ctf_sect_t *symsect,
-                          const ctf_sect_t *strsect,
-                          ctf_archive_member_f *func, void *data)
+/* Iterate over all CTF files in an archive: public entry point.  We pass all
+   CTF files in turn to the specified callback function.  */
+int
+ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
+                 void *data)
 {
-  int rc;
-  size_t i;
-  ctf_dict_t *f;
-  struct ctf_archive_modent *modent;
-  const char *nametbl;
-
-  modent = (ctf_archive_modent_t *) ((char *) arc
-                                    + sizeof (struct ctf_archive));
-  nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
+  ctf_next_t *i = NULL;
+  ctf_dict_t *fp;
+  const char *name;
+  int err;
 
-  for (i = 0; i < le64toh (arc->ctfa_ndicts); i++)
+  while ((fp = ctf_archive_next (arc, &i, &name, 0, &err)) != NULL)
     {
-      const char *name;
-
-      name = &nametbl[le64toh (modent[i].name_offset)];
-      if ((f = ctf_dict_open_internal (arc, symsect, strsect,
-                                      name,
-                                      wrapper->ctfi_symsect_little_endian,
-                                      &rc)) == NULL)
-       return rc;
+      int rc;
 
-      f->ctf_archive = (ctf_archive_t *) wrapper;
-      ctf_arc_import_parent (wrapper, f);
-      if ((rc = func (f, name, data)) != 0)
+      if ((rc = func (fp, name, data)) != 0)
        {
-         ctf_dict_close (f);
+         ctf_dict_close (fp);
+         ctf_next_destroy (i);
          return rc;
        }
-
-      ctf_dict_close (f);
+      ctf_dict_close (fp);
     }
   return 0;
 }
 
-/* Iterate over all CTF files in an archive: public entry point.  We pass all
-   CTF files in turn to the specified callback function.  */
-int
-ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
-                 void *data)
-{
-  const ctf_sect_t *symsect = &arc->ctfi_symsect;
-  const ctf_sect_t *strsect = &arc->ctfi_strsect;
-
-  if (symsect->cts_name == NULL)
-    symsect = NULL;
-  if (strsect->cts_name == NULL)
-    strsect = NULL;
-
-  if (arc->ctfi_is_archive)
-    return ctf_archive_iter_internal (arc, arc->ctfi_archive, symsect, strsect,
-                                     func, data);
-
-  return func (arc->ctfi_dict, _CTF_SECTION, data);
-}
-
 /* Iterate over all CTF files in an archive, returning each dict in turn as a
    ctf_dict_t, and NULL on error or end of iteration.  It is the caller's
    responsibility to close it.  Parent dicts may be skipped.
@@ -1077,6 +1127,8 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
       if (!skip_parent)
        {
          wrapper->ctfi_dict->ctf_refcnt++;
+         if (name)
+           *name = _CTF_SECTION;
          return wrapper->ctfi_dict;
        }
     }
@@ -1104,7 +1156,8 @@ ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **na
 
       name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
       i->ctn_n++;
-    } while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
+    }
+  while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
 
   if (name)
     *name = name_;
This page took 0.027747 seconds and 4 git commands to generate.