From: Nick Alcock Date: Wed, 17 Feb 2021 15:21:12 +0000 (+0000) Subject: libctf, include: find types of symbols by name X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f4f60336daee74c094474e4da7b88c4a8b75a49e;p=binutils-gdb.git libctf, include: find types of symbols by name The existing ctf_lookup_by_symbol and ctf_arc_lookup_symbol functions suffice to look up the types of symbols if the caller already has a symbol number. But the caller often doesn't have one of those and only knows the name of the symbol: also, in object files, the caller might not have a useful symbol number in any sense (and neither does libctf: the 'symbol number' we use in that case literally starts at 0 for the lexicographically first-sorted symbol in the symtypetab and counts those symbols, so it corresponds to nothing useful). This means that even though object files have a symtypetab (generated by the compiler or by ld -r), the only way we can look up anything in it is to iterate over all symbols in turn with ctf_symbol_next until we find the one we want. This is unhelpful and pointlessly inefficient. So add a pair of functions to look up symbols by name in a dict and in a whole archive: ctf_lookup_by_symbol_name and ctf_arc_lookup_symbol_name. These are identical to the existing functions except that they take symbol names rather than symbol numbers. To avoid insane repetition, we do some refactoring in the process, so that both ctf_lookup_by_symbol and ctf_arc_lookup_symbol turn into thin wrappers around internal functions that do both lookup by symbol index and lookup by name. This massively reduces code duplication because even the existing lookup-by-index stuff wants to use a name sometimes (when looking up in indexed sections), and the new lookup-by-name stuff has to turn it into an index sometimes (when looking up in non-indexed sections): doing it this way lets us share most of that. The actual name->index lookup is done by ctf_lookup_symbol_idx. We do not anticipate this lookup to be as heavily used as ld.so symbol lookup by many orders of magnitude, so using the ELF symbol hashes would probably take more time to read them than is saved by using the hashes, and it adds a lot of complexity. Instead, do a linear search for the symbol name, caching all the name -> index mappings as we go, so that future searches are likely to hit in the cache. To avoid having to repeat this search over and over in a CTF archive when ctf_arc_lookup_symbol_name is used, have cached archive lookups (the sort done by ctf_arc_lookup_symbol* and the ctf_archive_next iterator) pick out the first dict they cache in a given archive and store it in a new ctf_archive field, ctfi_crossdict_cache. This can be used to store cross-dictionary cached state that depends on things like the ELF symbol table rather than the contents of any one dict. ctf_lookup_symbol_idx then caches its name->index mappings in the dictionary named in the crossdict cache, if any, so that ctf_lookup_symbol_idx in other dicts in the same archive benefit from the previous linear search, and the symtab only needs to be scanned at most once. (Note that if you call ctf_lookup_by_symbol_name in one specific dict, and then follow it with a ctf_arc_lookup_symbol_name, the former will not use the crossdict cache because it's only populated by the dict opens in ctf_arc_lookup_symbol_name. This is harmless except for a small one-off waste of memory and time: it's only a cache, after all. We can fix this later by using the archive caching machinery more aggressively.) In ctf-archive, we do similar things, turning ctf_arc_lookup_symbol into a wrapper around a new function that does both index -> ID and name -> ID lookups across all dicts in an archive. We add a new ctfi_symnamedicts cache that maps symbol names to the ctf_dict_t * that it was found in (so that linear searches for symbols don't need to be repeated): but we also *remove* a cache, the ctfi_syms cache that was memoizing the actual ctf_id_t returned from every call to ctf_arc_lookup_symbol. This is pointless: all it saves is one call to ctf_lookup_by_symbol, and that's basically an array lookup and nothing more so isn't worth caching. (Equally, given that symbol -> index mappings are cached by ctf_lookup_by_symbol_name, those calls are nearly free after the first call, so there's no point caching the ctf_id_t in that case either.) We fix up one test that was doing manual symbol lookup to use ctf_arc_lookup_symbol instead, and enhance it to check that the caching layer is not totally broken: we also add a new test to do lookups in a .o file, and another to do lookups in an archive with conflicted types and make sure that sort of multi-dict lookup is actually working. include/ChangeLog 2021-02-17 Nick Alcock * ctf-api.h (ctf_arc_lookup_symbol_name): New. (ctf_lookup_by_symbol_name): Likewise. libctf/ChangeLog 2021-02-17 Nick Alcock * ctf-impl.h (ctf_dict_t) : New. : Likewise. (struct ctf_archive_internal) : New. : New. : Remove. (ctf_lookup_symbol_name): Remove. * ctf-lookup.c (ctf_lookup_symbol_name): Propagate errors from parent properly. Make static. (ctf_lookup_symbol_idx): New, linear search for the symbol name, cached in the crossdict cache's ctf_symhash (if available), or this dict's (otherwise). (ctf_try_lookup_indexed): Allow the symname to be passed in. (ctf_lookup_by_symbol): Turn into a wrapper around... (ctf_lookup_by_sym_or_name): ... this, supporting name lookup too, using ctf_lookup_symbol_idx in non-writable dicts. Special-case name lookup in dynamic dicts without reported symbols, which have no symtab or dynsymidx but where name lookup should still work. (ctf_lookup_by_symbol_name): New, another wrapper. * ctf-archive.c (enosym): Note that this is present in ctfi_symnamedicts too. (ctf_arc_close): Adjust for removal of ctfi_syms. Free the ctfi_symnamedicts. (ctf_arc_flush_caches): Likewise. (ctf_dict_open_cached): Memoize the first cached dict in the crossdict cache. (ctf_arc_lookup_symbol): Turn into a wrapper around... (ctf_arc_lookup_sym_or_name): ... this. No longer cache ctf_id_t lookups: just call ctf_lookup_by_symbol as needed (but still cache the dicts those lookups succeed in). Add lookup-by-name support, with dicts of successful lookups cached in ctfi_symnamedicts. Refactor the caching code a bit. (ctf_arc_lookup_symbol_name): New, another wrapper. * ctf-open.c (ctf_dict_close): Free the ctf_symhash. * libctf.ver (LIBCTF_1.2): New version. Add ctf_lookup_by_symbol_name, ctf_arc_lookup_symbol_name. * testsuite/libctf-lookup/enum-symbol.c (main): Use ctf_arc_lookup_symbol rather than looking up the name ourselves. Fish it out repeatedly, to make sure that symbol caching isn't broken. (symidx_64): Remove. (symidx_32): Remove. * testsuite/libctf-lookup/enum-symbol-obj.lk: Test symbol lookup in an unlinked object file (indexed symtypetab sections only). * testsuite/libctf-writable/symtypetab-nonlinker-writeout.c (try_maybe_reporting): Check symbol types via ctf_lookup_by_symbol_name as well as ctf_symbol_next. * testsuite/libctf-lookup/conflicting-type-syms.*: New test of lookups in a multi-dict archive. --- diff --git a/include/ChangeLog b/include/ChangeLog index a24c920fd67..71f0beb13b0 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2021-02-17 Nick Alcock + + * ctf-api.h (ctf_arc_lookup_symbol_name): New. + (ctf_lookup_by_symbol_name): Likewise. + 2021-02-19 Nelson Chu PR 27158 diff --git a/include/ctf-api.h b/include/ctf-api.h index 6dd43aa365f..ce764dff5e3 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -338,6 +338,9 @@ extern void ctf_arc_close (ctf_archive_t *); extern ctf_dict_t *ctf_arc_lookup_symbol (ctf_archive_t *, unsigned long symidx, ctf_id_t *, int *errp); +extern ctf_dict_t *ctf_arc_lookup_symbol_name (ctf_archive_t *, + const char *name, + ctf_id_t *, int *errp); extern void ctf_arc_flush_caches (ctf_archive_t *); extern ctf_dict_t *ctf_dict_open (const ctf_archive_t *, const char *, int *); @@ -388,6 +391,7 @@ extern int ctf_func_type_args (ctf_dict_t *, ctf_id_t, uint32_t, ctf_id_t *); extern ctf_id_t ctf_lookup_by_name (ctf_dict_t *, const char *); extern ctf_id_t ctf_lookup_by_symbol (ctf_dict_t *, unsigned long); +extern ctf_id_t ctf_lookup_by_symbol_name (ctf_dict_t *, const char *); extern ctf_id_t ctf_symbol_next (ctf_dict_t *, ctf_next_t **, const char **name, int functions); extern ctf_id_t ctf_lookup_variable (ctf_dict_t *, const char *); diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 7a69476b9a9..acf3c4653f7 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,54 @@ +2021-02-17 Nick Alcock + + * ctf-impl.h (ctf_dict_t) : New. + : Likewise. + (struct ctf_archive_internal) : New. + : New. + : Remove. + (ctf_lookup_symbol_name): Remove. + * ctf-lookup.c (ctf_lookup_symbol_name): Propagate errors from + parent properly. Make static. + (ctf_lookup_symbol_idx): New, linear search for the symbol name, + cached in the crossdict cache's ctf_symhash (if available), or + this dict's (otherwise). + (ctf_try_lookup_indexed): Allow the symname to be passed in. + (ctf_lookup_by_symbol): Turn into a wrapper around... + (ctf_lookup_by_sym_or_name): ... this, supporting name lookup too, + using ctf_lookup_symbol_idx in non-writable dicts. Special-case + name lookup in dynamic dicts without reported symbols, which have + no symtab or dynsymidx but where name lookup should still work. + (ctf_lookup_by_symbol_name): New, another wrapper. + * ctf-archive.c (enosym): Note that this is present in + ctfi_symnamedicts too. + (ctf_arc_close): Adjust for removal of ctfi_syms. Free the + ctfi_symnamedicts. + (ctf_arc_flush_caches): Likewise. + (ctf_dict_open_cached): Memoize the first cached dict in the + crossdict cache. + (ctf_arc_lookup_symbol): Turn into a wrapper around... + (ctf_arc_lookup_sym_or_name): ... this. No longer cache + ctf_id_t lookups: just call ctf_lookup_by_symbol as needed (but + still cache the dicts those lookups succeed in). Add + lookup-by-name support, with dicts of successful lookups cached in + ctfi_symnamedicts. Refactor the caching code a bit. + (ctf_arc_lookup_symbol_name): New, another wrapper. + * ctf-open.c (ctf_dict_close): Free the ctf_symhash. + * libctf.ver (LIBCTF_1.2): New version. Add + ctf_lookup_by_symbol_name, ctf_arc_lookup_symbol_name. + * testsuite/libctf-lookup/enum-symbol.c (main): Use + ctf_arc_lookup_symbol rather than looking up the name ourselves. + Fish it out repeatedly, to make sure that symbol caching isn't + broken. + (symidx_64): Remove. + (symidx_32): Remove. + * testsuite/libctf-lookup/enum-symbol-obj.lk: Test symbol lookup + in an unlinked object file (indexed symtypetab sections only). + * testsuite/libctf-writable/symtypetab-nonlinker-writeout.c + (try_maybe_reporting): Check symbol types via + ctf_lookup_by_symbol_name as well as ctf_symbol_next. + * testsuite/libctf-lookup/conflicting-type-syms.*: New test of + lookups in a multi-dict archive. + 2021-02-20 Alan Modra * testsuite/config/default.exp (ld_L_opt): Define. diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c index 193fc4df574..6d9c75c9013 100644 --- a/libctf/ctf-archive.c +++ b/libctf/ctf-archive.c @@ -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 diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 0a508ebd174..a6e1da58930 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -382,6 +382,8 @@ struct ctf_dict ctf_sect_t ctf_symtab; /* Symbol table from object file. */ ctf_sect_t ctf_strtab; /* String table from object file. */ int ctf_symsect_little_endian; /* Endianness of the ctf_symtab. */ + ctf_dynhash_t *ctf_symhash; /* (partial) hash, symsect name -> idx. */ + size_t ctf_symhash_latest; /* Amount of symsect scanned so far. */ ctf_dynhash_t *ctf_prov_strtab; /* Maps provisional-strtab offsets to names. */ ctf_dynhash_t *ctf_syn_ext_strtab; /* Maps ext-strtab offsets to names. */ @@ -508,8 +510,9 @@ struct ctf_archive_internal ctf_dict_t *ctfi_dict; struct ctf_archive *ctfi_archive; ctf_dynhash_t *ctfi_dicts; /* Dicts we have opened and cached. */ + ctf_dict_t *ctfi_crossdict_cache; /* Cross-dict caching. */ ctf_dict_t **ctfi_symdicts; /* Array of index -> ctf_dict_t *. */ - ctf_id_t *ctfi_syms; /* Array of index -> ctf_id_t. */ + ctf_dynhash_t *ctfi_symnamedicts; /* Hash of name -> ctf_dict_t *. */ ctf_sect_t ctfi_symsect; int ctfi_symsect_little_endian; /* -1 for unknown / do not set. */ ctf_sect_t ctfi_strsect; @@ -784,7 +787,6 @@ extern ctf_link_sym_t *ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *ds const Elf32_Sym *src, uint32_t symidx); extern ctf_link_sym_t *ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src, uint32_t symidx); -extern const char *ctf_lookup_symbol_name (ctf_dict_t *fp, unsigned long symidx); /* Variables, all underscore-prepended. */ diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c index 72f6a2a24c7..6e17e5f4c54 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. */ diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 67d9f84c361..c2d9a33555a 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1737,6 +1737,7 @@ ctf_dict_close (ctf_dict_t *fp) } ctf_dynhash_destroy (fp->ctf_dvhash); + ctf_dynhash_destroy (fp->ctf_symhash); free (fp->ctf_funcidx_sxlate); free (fp->ctf_objtidx_sxlate); ctf_dynhash_destroy (fp->ctf_objthash); diff --git a/libctf/libctf.ver b/libctf/libctf.ver index 2137c5b810f..8c362f3c39e 100644 --- a/libctf/libctf.ver +++ b/libctf/libctf.ver @@ -196,3 +196,9 @@ LIBCTF_1.1 { ctf_symsect_endianness; ctf_arc_symsect_endianness; } LIBCTF_1.0; + +LIBCTF_1.2 { + global: + ctf_lookup_by_symbol_name; + ctf_arc_lookup_symbol_name; +} LIBCTF_1.1; diff --git a/libctf/testsuite/libctf-lookup/conflicting-type-syms-a.c b/libctf/testsuite/libctf-lookup/conflicting-type-syms-a.c new file mode 100644 index 00000000000..65414877114 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/conflicting-type-syms-a.c @@ -0,0 +1,5 @@ +typedef long a_t; +typedef long b_t; + +a_t *a; +b_t ignore2; diff --git a/libctf/testsuite/libctf-lookup/conflicting-type-syms-b.c b/libctf/testsuite/libctf-lookup/conflicting-type-syms-b.c new file mode 100644 index 00000000000..e458021efb1 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/conflicting-type-syms-b.c @@ -0,0 +1,5 @@ +typedef long a_t; +typedef long b_t; + +a_t b; +b_t ignore1; diff --git a/libctf/testsuite/libctf-lookup/conflicting-type-syms.c b/libctf/testsuite/libctf-lookup/conflicting-type-syms.c new file mode 100644 index 00000000000..ffe6983e250 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/conflicting-type-syms.c @@ -0,0 +1,99 @@ +#include "config.h" +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + ctf_archive_t *ctf; + ctf_dict_t *a_fp, *ignore1_fp, *b_fp, *ignore2_fp, *tmp_fp; + int err; + ctf_id_t a, b, ignore1, ignore2, tmp; + char *foo; + ctf_next_t *i = NULL; + const char *name; + int val; + + if (argc != 2) + { + fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]); + exit(1); + } + + if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL) + goto open_err; + + /* Fish out each symbol in turn: also try to fish out a nonexistent one. */ + + if ((a_fp = ctf_arc_lookup_symbol_name (ctf, "a", &a, &err)) == NULL) + goto sym_err; + printf ("Type of a is %s\n", foo = ctf_type_aname (a_fp, a)); + + if ((b_fp = ctf_arc_lookup_symbol_name (ctf, "b", &b, &err)) == NULL) + goto sym_err; + printf ("Type of b is %s\n", foo = ctf_type_aname (b_fp, b)); + + if ((ignore1_fp = ctf_arc_lookup_symbol_name (ctf, "ignore1", &ignore1, &err)) == NULL) + goto sym_err; + printf ("Type of ignore1 is %s\n", foo = ctf_type_aname (ignore1_fp, ignore1)); + + if ((ignore2_fp = ctf_arc_lookup_symbol_name (ctf, "ignore2", &ignore2, &err)) == NULL) + goto sym_err; + printf ("Type of ignore2 is %s\n", foo = ctf_type_aname (ignore2_fp, ignore1)); + + /* Try a call in just-get-the-dict mode and make sure it doesn't fail. */ + if ((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "ignore2", NULL, &err)) == NULL) + goto sym_err; + ctf_dict_close (tmp_fp); + + /* Make sure failures fail. */ + if ((ctf_arc_lookup_symbol_name (ctf, "nonexistent", NULL, &err) != NULL) + || err != ECTF_NOTYPEDAT) + goto nosym_err; + + /* Fish them out again to check the caching layer. */ + if (((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "a", &tmp, &err)) != a_fp) + || (tmp != a)) + goto sym_cache_err; + ctf_dict_close (tmp_fp); + + if (((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "b", &tmp, &err)) != b_fp) + || (tmp != b)) + goto sym_cache_err; + ctf_dict_close (tmp_fp); + + if (((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "ignore1", &tmp, &err)) != ignore1_fp) + || (tmp != ignore1)) + goto sym_cache_err; + ctf_dict_close (tmp_fp); + + if (((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "ignore2", &tmp, &err)) != ignore2_fp) + || (tmp != ignore2)) + goto sym_cache_err; + ctf_dict_close (tmp_fp); + + ctf_dict_close (a_fp); + ctf_dict_close (b_fp); + ctf_dict_close (ignore1_fp); + ctf_dict_close (ignore2_fp); + ctf_close (ctf); + + return 0; + + open_err: + fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err)); + return 1; + sym_err: + fprintf (stderr, "%s: Symbol lookup error: %s\n", argv[0], ctf_errmsg (err)); + return 1; + nosym_err: + fprintf (stderr, "%s: Nonexistent symbol lookup unexpected error: %s\n", argv[0], + ctf_errmsg (err)); + return 1; + sym_cache_err: + fprintf (stderr, "%s: Symbol re-lookup error (caching bug): %s\n", argv[0], + ctf_errmsg (err)); + return 1; +} diff --git a/libctf/testsuite/libctf-lookup/conflicting-type-syms.lk b/libctf/testsuite/libctf-lookup/conflicting-type-syms.lk new file mode 100644 index 00000000000..09b41dfd623 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/conflicting-type-syms.lk @@ -0,0 +1,7 @@ +# lookup: conflicting-type-syms.c +# source: conflicting-type-syms-a.c +# source: conflicting-type-syms-b.c +Type of a is a_t \* +Type of b is a_t +Type of ignore1 is b_t +Type of ignore2 is b_t diff --git a/libctf/testsuite/libctf-lookup/enum-symbol-obj.lk b/libctf/testsuite/libctf-lookup/enum-symbol-obj.lk new file mode 100644 index 00000000000..548d67b70c6 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/enum-symbol-obj.lk @@ -0,0 +1,5 @@ +# lookup: enum-symbol.c +# source: enum-symbol-ctf.c +red1 has value 0 +green1 has value 1 +blue1 has value 2 diff --git a/libctf/testsuite/libctf-lookup/enum-symbol.c b/libctf/testsuite/libctf-lookup/enum-symbol.c index 4f63b61b803..c67478fe780 100644 --- a/libctf/testsuite/libctf-lookup/enum-symbol.c +++ b/libctf/testsuite/libctf-lookup/enum-symbol.c @@ -1,71 +1,19 @@ #include "config.h" -#include -#include #include -#include #include #include #include -ssize_t symidx_64 (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name) -{ - const char *strs = (const char *) strsect->cts_data; - size_t i; - Elf64_Sym *sym = (Elf64_Sym *) s->cts_data; - for (i = 0; i < s->cts_size / s->cts_entsize; i++, sym++) - { - Elf64_Word nameoff = sym->st_name; -#ifdef WORDS_BIGENDIAN - if (little_endian) - swap_thing (nameoff); -#else - if (!little_endian) - swap_thing (nameoff); -#endif - if (strcmp (strs + nameoff, name) == 0) - return i; - } - return -1; -} - -ssize_t symidx_32 (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name) -{ - const char *strs = (const char *) strsect->cts_data; - size_t i; - Elf32_Sym *sym = (Elf32_Sym *) s->cts_data; - for (i = 0; i < s->cts_size / s->cts_entsize; i++, sym++) - { - Elf32_Word nameoff = sym->st_name; -#ifdef WORDS_BIGENDIAN - if (little_endian) - swap_thing (nameoff); -#else - if (!little_endian) - swap_thing (nameoff); -#endif - if (strcmp (strs + nameoff, name) == 0) - return i; - } - return -1; -} - int main (int argc, char *argv[]) { - ctf_dict_t *fp; - bfd *abfd; ctf_archive_t *ctf; - ctf_sect_t symsect; - ctf_sect_t strsect; - ssize_t symidx; + ctf_dict_t *fp, *tmp_fp; int err; - ctf_id_t type; + ctf_id_t type, tmp; ctf_next_t *i = NULL; const char *name; int val; - int little_endian; - - ssize_t (*get_sym) (ctf_sect_t *s, ctf_sect_t *strsect, int little_endian, const char *name); if (argc != 2) { @@ -73,53 +21,12 @@ main (int argc, char *argv[]) exit(1); } - /* Figure out the endianness of the symtab(s). */ - if ((abfd = bfd_openr (argv[1], NULL)) == NULL - || !bfd_check_format (abfd, bfd_object)) - goto bfd_open_err; - little_endian = bfd_little_endian (abfd); - bfd_close_all_done (abfd); - if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL) goto open_err; - if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL) - goto open_err; - - symsect = ctf_getsymsect (fp); - strsect = ctf_getstrsect (fp); - if (symsect.cts_data == NULL - || strsect.cts_data == NULL) - { - fprintf (stderr, "%s: no symtab or strtab\n", argv[0]); - return 1; - } - - ctf_dict_close (fp); - - if (symsect.cts_entsize != sizeof (Elf64_Sym) && - symsect.cts_entsize != sizeof (Elf32_Sym)) - { - fprintf (stderr, "%s: unknown symsize: %lx\n", argv[0], - symsect.cts_size); - return 1; - } - - switch (symsect.cts_entsize) - { - case sizeof (Elf64_Sym): get_sym = symidx_64; break; - case sizeof (Elf32_Sym): get_sym = symidx_32; break; - } - - if ((symidx = get_sym (&symsect, &strsect, little_endian, "primary1")) < 0) - { - fprintf (stderr, "%s: symbol not found: primary1\n", argv[0]); - return 1; - } - - /* Fish it out, then fish out all its enumerand/value pairs. */ + /* Fish out the enumerator, then fish out all its enumerand/value pairs. */ - if ((fp = ctf_arc_lookup_symbol (ctf, symidx, &type, &err)) == NULL) + if ((fp = ctf_arc_lookup_symbol_name (ctf, "primary1", &type, &err)) == NULL) goto sym_err; while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL) @@ -129,21 +36,27 @@ main (int argc, char *argv[]) if (ctf_errno (fp) != ECTF_NEXT_END) goto nerr; + /* Fish it out again to check the caching layer. */ + if (((tmp_fp = ctf_arc_lookup_symbol_name (ctf, "primary1", &tmp, &err)) != fp) + || (tmp != type)) + goto sym_cache_err; + + ctf_dict_close (tmp_fp); ctf_dict_close (fp); ctf_close (ctf); return 0; - bfd_open_err: - fprintf (stderr, "%s: cannot open: %s\n", argv[0], bfd_errmsg (bfd_get_error ())); - return 1; - open_err: fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err)); return 1; sym_err: fprintf (stderr, "%s: Symbol lookup error: %s\n", argv[0], ctf_errmsg (err)); return 1; + sym_cache_err: + fprintf (stderr, "%s: Symbol re-lookup error (caching bug): %s\n", argv[0], + ctf_errmsg (err)); + return 1; err: fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp))); return 1; diff --git a/libctf/testsuite/libctf-writable/symtypetab-nonlinker-writeout.c b/libctf/testsuite/libctf-writable/symtypetab-nonlinker-writeout.c index d339963d264..98144de6391 100644 --- a/libctf/testsuite/libctf-writable/symtypetab-nonlinker-writeout.c +++ b/libctf/testsuite/libctf-writable/symtypetab-nonlinker-writeout.c @@ -98,6 +98,21 @@ try_maybe_reporting (int report) if (ctf_errno (fp) != ECTF_NEXT_END) goto iter_err; + /* Look up all the symbols by name and make sure that works. */ + + if (ctf_lookup_by_symbol_name (fp, "data_a") != base2) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "data_b") != base3) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "data_c") != base) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_a") != func2) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_b") != func3) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_c") != func) + goto lookup_syms_err; + /* Possibly report some but not all of the symbols, as if we are a linker (no real program would do this without using the ctf_link APIs, but it's not *prohibited*, just useless, and if they do we don't want things to @@ -121,6 +136,21 @@ try_maybe_reporting (int report) if (report_sym (fp, &sym, "func_c", 4, 2) < 0 || report_sym (fp, &sym, "func_a", 5, 2) < 0) goto report_err; + + /* Look up all the symbols by name now we have reported symbols. */ + + if (ctf_lookup_by_symbol_name (fp, "data_a") != base2) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "data_b") != base3) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "data_c") != base) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_a") != func2) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_b") != func3) + goto lookup_syms_err; + if (ctf_lookup_by_symbol_name (fp, "func_c") != func) + goto lookup_syms_err; } /* Write out, to memory. */ @@ -203,6 +233,10 @@ try_maybe_reporting (int report) expected_overshoot_err: fprintf (stderr, "Too many symbols in post-writeout comparison\n"); exit (1); + lookup_syms_err: + fprintf (stderr, "Explicit lookup of symbols by name failed: %s\n", + ctf_errmsg (ctf_errno (fp))); + exit (1); expected_compar_err: fprintf (stderr, "Non-dynamic iteration comparison failure: %s " "(type %lx): expected %s (type %lx)\n", symname, symtype,