]> Git Repo - binutils.git/blobdiff - libctf/ctf-lookup.c
Automatic date update in version.in
[binutils.git] / libctf / ctf-lookup.c
index 72f6a2a24c7062b961186d052fadac5309c9543b..26b3f8863c0136a8bcd963a39cb503a4ffa980b3 100644 (file)
@@ -1,5 +1,5 @@
 /* Symbol, variable and name lookup.
-   Copyright (C) 2019-2021 Free Software Foundation, Inc.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
 
    This file is part of libctf.
 
@@ -111,10 +111,14 @@ isqualifier (const char *s, size_t len)
   };
 
   int h = s[len - 1] + (int) len - 105;
-  const struct qual *qp = &qhash[h];
+  const struct qual *qp;
 
-  return (h >= 0 && (size_t) h < sizeof (qhash) / sizeof (qhash[0])
-         && (size_t) len == qp->q_len &&
+  if (h < 0 || (size_t) h >= sizeof (qhash) / sizeof (qhash[0]))
+    return 0;
+
+  qp = &qhash[h];
+
+  return ((size_t) len == qp->q_len &&
          strncmp (qp->q_name, s, qp->q_len) == 0);
 }
 
@@ -172,7 +176,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
          int in_child = 0;
 
          ntype = CTF_ERR;
-         if (child && idx <= child->ctf_pptrtab_len)
+         if (child && idx < child->ctf_pptrtab_len)
            {
              ntype = child->ctf_pptrtab[idx];
              if (ntype)
@@ -202,7 +206,7 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
              idx = LCTF_TYPE_TO_INDEX (fp, ntype);
 
              ntype = CTF_ERR;
-             if (child && idx <= child->ctf_pptrtab_len)
+             if (child && idx < child->ctf_pptrtab_len)
                {
                  ntype = child->ctf_pptrtab[idx];
                  if (ntype)
@@ -459,7 +463,7 @@ ctf_symidx_sort (ctf_dict_t *fp, uint32_t *idx, size_t *nidx,
 /* Given a symbol index, return the name of that symbol from the table provided
    by ctf_link_shuffle_syms, or failing that from the secondary string table, or
    the null string.  */
-const char *
+static const char *
 ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
 {
   const ctf_sect_t *sp = &fp->ctf_symtab;
@@ -512,7 +516,13 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
 
  try_parent:
   if (fp->ctf_parent)
-    return ctf_lookup_symbol_name (fp->ctf_parent, symidx);
+    {
+      const char *ret;
+      ret = ctf_lookup_symbol_name (fp->ctf_parent, symidx);
+      if (ret == NULL)
+       ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+      return ret;
+    }
   else
     {
       ctf_set_errno (fp, err);
@@ -520,6 +530,116 @@ ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx)
     }
 }
 
+/* Given a symbol name, return the index of that symbol, or -1 on error or if
+   not found.  */
+static unsigned long
+ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
+{
+  const ctf_sect_t *sp = &fp->ctf_symtab;
+  ctf_link_sym_t sym;
+  void *known_idx;
+  int err;
+  ctf_dict_t *cache = fp;
+
+  if (fp->ctf_dynsyms)
+    {
+      err = EINVAL;
+
+      ctf_link_sym_t *symp;
+
+      if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
+       goto try_parent;
+
+      return symp->st_symidx;
+    }
+
+  err = ECTF_NOSYMTAB;
+  if (sp->cts_data == NULL)
+    goto try_parent;
+
+  /* First, try a hash lookup to see if we have already spotted this symbol
+     during a past iteration: create the hash first if need be.  The lifespan
+     of the strings is equal to the lifespan of the cts_data, so we don't
+     need to strdup them.  If this dict was opened as part of an archive,
+     and this archive has designed a crossdict_cache to cache results that
+     are the same across all dicts in an archive, use it.  */
+
+  if (fp->ctf_archive && fp->ctf_archive->ctfi_crossdict_cache)
+    cache = fp->ctf_archive->ctfi_crossdict_cache;
+
+  if (!cache->ctf_symhash)
+    if ((cache->ctf_symhash = ctf_dynhash_create (ctf_hash_string,
+                                                 ctf_hash_eq_string,
+                                                 NULL, NULL)) == NULL)
+      goto oom;
+
+  if (ctf_dynhash_lookup_kv (cache->ctf_symhash, symname, NULL, &known_idx))
+    return (unsigned long) (uintptr_t) known_idx;
+
+  /* Hash lookup unsuccessful: linear search, populating the hashtab for later
+     lookups as we go.  */
+
+  for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize;
+       cache->ctf_symhash_latest++)
+    {
+      switch (sp->cts_entsize)
+       {
+       case sizeof (Elf64_Sym):
+         {
+           Elf64_Sym *symp = (Elf64_Sym *) sp->cts_data;
+           ctf_elf64_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
+                                  cache->ctf_symhash_latest);
+           if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
+                                       NULL, NULL))
+             if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
+                                      (const void *) (uintptr_t)
+                                      cache->ctf_symhash_latest) < 0)
+               goto oom;
+           if (strcmp (sym.st_name, symname) == 0)
+             return cache->ctf_symhash_latest++;
+         }
+         break;
+       case sizeof (Elf32_Sym):
+         {
+           Elf32_Sym *symp = (Elf32_Sym *) sp->cts_data;
+           ctf_elf32_to_link_sym (fp, &sym, &symp[cache->ctf_symhash_latest],
+                                  cache->ctf_symhash_latest);
+           if (!ctf_dynhash_lookup_kv (cache->ctf_symhash, sym.st_name,
+                                       NULL, NULL))
+             if (ctf_dynhash_cinsert (cache->ctf_symhash, sym.st_name,
+                                      (const void *) (uintptr_t)
+                                      cache->ctf_symhash_latest) < 0)
+               goto oom;
+           if (strcmp (sym.st_name, symname) == 0)
+             return cache->ctf_symhash_latest++;
+         }
+         break;
+       default:
+         ctf_set_errno (fp, ECTF_SYMTAB);
+         return (unsigned long) -1;
+       }
+    }
+
+  /* Searched everything, still not found.  */
+
+  return (unsigned long) -1;
+
+ try_parent:
+  if (fp->ctf_parent)
+    return ctf_lookup_symbol_idx (fp->ctf_parent, symname);
+  else
+    {
+      ctf_set_errno (fp, err);
+      return (unsigned long) -1;
+    }
+oom:
+  ctf_set_errno (fp, ENOMEM);
+  ctf_err_warn (fp, 0, ENOMEM, _("cannot allocate memory for symbol "
+                                "lookup hashtab"));
+  return (unsigned long) -1;
+
+}
+
 /* Iterate over all symbols with types: if FUNC, function symbols, otherwise,
    data symbols.  The name argument is not optional.  The return order is
    arbitrary, though is likely to be in symbol index or name order.  You can
@@ -607,7 +727,8 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
 
          *name = ctf_strptr (fp, idx[i->ctn_n]);
          sym = tab[i->ctn_n++];
-       } while (sym == -1u || sym == 0);
+       }
+      while (sym == -1u || sym == 0);
     }
   else
     {
@@ -664,20 +785,24 @@ ctf_lookup_idx_name (const void *key_, const void *idx_)
   return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, key->clik_names[*idx])));
 }
 
-/* Given a symbol number, look up that symbol in the function or object
-   index table (which must exist).  Return 0 if not found there (or pad).  */
+/* Given a symbol name or (failing that) number, look up that symbol in the
+   function or object index table (which must exist).  Return 0 if not found
+   there (or pad).  */
 
 static ctf_id_t
-ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, int is_function)
+ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
+                       const char *symname, int is_function)
 {
-  const char *symname = ctf_lookup_symbol_name (fp, symidx);
   struct ctf_header *hp = fp->ctf_header;
   uint32_t *symtypetab;
   uint32_t *names;
   uint32_t *sxlate;
   size_t nidx;
 
-  ctf_dprintf ("Looking up type of object with symtab idx %lx (%s) in "
+  if (symname == NULL)
+    symname = ctf_lookup_symbol_name (fp, symidx);
+
+  ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in "
               "indexed symtypetab\n", symidx, symname);
 
   if (symname[0] == '\0')
@@ -745,13 +870,15 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx, int is_function)
   return symtypetab[*idx];
 }
 
-/* Given a symbol table index, return the type of the function or data object
-   described by the corresponding entry in the symbol table.  We can only return
-   symbols in read-only dicts and in dicts for which ctf_link_shuffle_syms has
-   been called to assign symbol indexes to symbol names.  */
+/* Given a symbol name or (if NULL) symbol index, return the type of the
+   function or data object described by the corresponding entry in the symbol
+   table.  We can only return symbols in read-only dicts and in dicts for which
+   ctf_link_shuffle_syms has been called to assign symbol indexes to symbol
+   names.  */
 
-ctf_id_t
-ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
+static ctf_id_t
+ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
+                          const char *symname)
 {
   const ctf_sect_t *sp = &fp->ctf_symtab;
   ctf_id_t type = 0;
@@ -762,38 +889,62 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
     {
       const ctf_link_sym_t *sym;
 
-      ctf_dprintf ("Looking up type of object with symtab idx %lx in "
-                  "writable dict symtypetab\n", symidx);
+      if (symname)
+       ctf_dprintf ("Looking up type of object with symname %s in "
+                    "writable dict symtypetab\n", symname);
+      else
+       ctf_dprintf ("Looking up type of object with symtab idx %lx in "
+                    "writable dict symtypetab\n", symidx);
 
       /* The dict must be dynamic.  */
       if (!ctf_assert (fp, fp->ctf_flags & LCTF_RDWR))
        return CTF_ERR;
 
-      err = EINVAL;
-      if (symidx > fp->ctf_dynsymmax)
-       goto try_parent;
+      /* No name? Need to look it up.  */
+      if (!symname)
+       {
+         err = EINVAL;
+         if (symidx > fp->ctf_dynsymmax)
+           goto try_parent;
 
-      sym = fp->ctf_dynsymidx[symidx];
-      err = ECTF_NOTYPEDAT;
-      if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
-       goto try_parent;
+         sym = fp->ctf_dynsymidx[symidx];
+         err = ECTF_NOTYPEDAT;
+         if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
+           goto try_parent;
 
-      if (!ctf_assert (fp, !sym->st_nameidx_set))
-       return CTF_ERR;
+         if (!ctf_assert (fp, !sym->st_nameidx_set))
+           return CTF_ERR;
+         symname = sym->st_name;
+     }
 
       if (fp->ctf_objthash == NULL
          || ((type = (ctf_id_t) (uintptr_t)
-              ctf_dynhash_lookup (fp->ctf_objthash, sym->st_name)) == 0))
+              ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
        {
          if (fp->ctf_funchash == NULL
              || ((type = (ctf_id_t) (uintptr_t)
-                  ctf_dynhash_lookup (fp->ctf_funchash, sym->st_name)) == 0))
+                  ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
            goto try_parent;
        }
 
       return type;
     }
 
+  /* Lookup by name in a dynamic dict: just do it directly.  */
+  if (symname && fp->ctf_flags & LCTF_RDWR)
+    {
+      if (fp->ctf_objthash == NULL
+         || ((type = (ctf_id_t) (uintptr_t)
+              ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
+       {
+         if (fp->ctf_funchash == NULL
+             || ((type = (ctf_id_t) (uintptr_t)
+                  ctf_dynhash_lookup (fp->ctf_funchash, symname)) == 0))
+           goto try_parent;
+       }
+      return type;
+    }
+
   err = ECTF_NOSYMTAB;
   if (sp->cts_data == NULL)
     goto try_parent;
@@ -801,17 +952,17 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
   /* This covers both out-of-range lookups and a dynamic dict which hasn't been
      shuffled yet.  */
   err = EINVAL;
-  if (symidx >= fp->ctf_nsyms)
+  if (symname == NULL && symidx >= fp->ctf_nsyms)
     goto try_parent;
 
   if (fp->ctf_objtidx_names)
     {
-      if ((type = ctf_try_lookup_indexed (fp, symidx, 0)) == CTF_ERR)
+      if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR)
        return CTF_ERR;                         /* errno is set for us.  */
     }
   if (type == 0 && fp->ctf_funcidx_names)
     {
-      if ((type = ctf_try_lookup_indexed (fp, symidx, 1)) == CTF_ERR)
+      if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
        return CTF_ERR;                         /* errno is set for us.  */
     }
   if (type != 0)
@@ -825,6 +976,10 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
 
   ctf_dprintf ("Looking up object type %lx in 1:1 dict symtypetab\n", symidx);
 
+  if (symname != NULL)
+    if ((symidx = ctf_lookup_symbol_idx (fp, symname)) == (unsigned long) -1)
+      goto try_parent;
+
   if (fp->ctf_sxlate[symidx] == -1u)
     goto try_parent;
 
@@ -836,11 +991,33 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
   return type;
  try_parent:
   if (fp->ctf_parent)
-    return ctf_lookup_by_symbol (fp->ctf_parent, symidx);
+    {
+      ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
+                                               symname);
+      if (ret == CTF_ERR)
+       ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
+      return ret;
+    }
   else
     return (ctf_set_errno (fp, err));
 }
 
+/* Given a symbol table index, return the type of the function or data object
+   described by the corresponding entry in the symbol table.  */
+ctf_id_t
+ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
+{
+  return ctf_lookup_by_sym_or_name (fp, symidx, NULL);
+}
+
+/* Given a symbol name, return the type of the function or data object described
+   by the corresponding entry in the symbol table.  */
+ctf_id_t
+ctf_lookup_by_symbol_name (ctf_dict_t *fp, const char *symname)
+{
+  return ctf_lookup_by_sym_or_name (fp, 0, symname);
+}
+
 /* Given a symbol table index, return the info for the function described
    by the corresponding entry in the symbol table, which may be a function
    symbol or may be a data symbol that happens to be a function pointer.  */
This page took 0.034492 seconds and 4 git commands to generate.