]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - libctf/ctf-archive.c
libctf, include: find types of symbols by name
[thirdparty/binutils-gdb.git] / libctf / ctf-archive.c
index 193fc4df5749e090d418079a3aa8b902bcda2c5a..6d9c75c9013248dd6a3ff3957c8f81e87a078505 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