diff options
Diffstat (limited to 'libctf/ctf-lookup.c')
-rw-r--r-- | libctf/ctf-lookup.c | 232 |
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. */ |