aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'libctf/ctf-lookup.c')
-rw-r--r--libctf/ctf-lookup.c232
1 files changed, 202 insertions, 30 deletions
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index 72f6a2a..6e17e5f 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -459,7 +459,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 +512,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 +526,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
@@ -664,20 +780,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 +865,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 +884,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 +947,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 +971,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 +986,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. */