aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-lookup.c
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2023-12-19 16:58:19 +0000
committerNick Alcock <nick.alcock@oracle.com>2024-04-19 16:14:46 +0100
commit8a60c93096326ef818dd72d0a44bd575a04cc55a (patch)
tree60c2d3df1bbfee0ad98cbb73bca635825ef8b9b6 /libctf/ctf-lookup.c
parent2ba5ec13b20a927666096dd7d6df22b845dcd475 (diff)
downloadbinutils-8a60c93096326ef818dd72d0a44bd575a04cc55a.zip
binutils-8a60c93096326ef818dd72d0a44bd575a04cc55a.tar.gz
binutils-8a60c93096326ef818dd72d0a44bd575a04cc55a.tar.bz2
libctf: support addition of types to dicts read via ctf_open()
libctf has long declared deserialized dictionaries (out of files or ELF sections or memory buffers or whatever) to be read-only: back in the furthest prehistory this was not the case, in that you could add a few sorts of type to such dicts, but attempting to do so often caused horrible memory corruption, so I banned the lot. But it turns out real consumers want it (notably DTrace, which synthesises pointers to types that don't have them and adds them to the ctf_open()ed dicts if it needs them). Let's bring it back again, but without the memory corruption and without the massive code duplication required in days of yore to distinguish between static and dynamic types: the representation of both types has been identical for a few years, with the only difference being that types as a whole are stored in a big buffer for types read in via ctf_open and per-type hashtables for newly-added types. So we discard the internally-visible concept of "readonly dictionaries" in favour of declaring the *range of types* that were already present when the dict was read in to be read-only: you can't modify them (say, by adding members to them if they're structs, or calling ctf_set_array on them), but you can add more types and point to them. (The API remains the same, with calls sometimes returning ECTF_RDONLY, but now they do so less often.) This is a fairly invasive change, mostly because code written since the ban was introduced didn't take the possibility of a static/dynamic split into account. Some of these irregularities were hard to define as anything but bugs. Notably: - The symbol handling was assuming that symbols only needed to be looked for in dynamic hashtabs or static linker-laid-out indexed/ nonindexed layouts, but now we want to check both in case people added more symbols to a dict they opened. - The code that handles type additions wasn't checking to see if types with the same name existed *at all* (so you could do ctf_add_typedef (fp, "foo", bar) repeatedly without error). This seems reasonable for types you just added, but we probably *do* want to ban addition of types with names that override names we already used in the ctf_open()ed portion, since that would probably corrupt existing type relationships. (Doing things this way also avoids causing new errors for any existing code that was doing this sort of thing.) - ctf_lookup_variable entirely failed to work for variables just added by ctf_add_variable: you had to write the dict out and read it back in again before they appeared. - The symbol handling remembered what symbols you looked up but didn't remember their types, so you could look up an object symbol and then find it popping up when you asked for function symbols, which seems less than ideal. Since we had to rejig things enough to be able to distinguish function and object symbols internally anyway (in order to give suitable errors if you try to add a symbol with a name that already existed in the ctf_open()ed dict), this bug suddenly became more visible and was easily fixed. We do not (yet) support writing out dicts that have been previously read in via ctf_open() or other deserializer (you can look things up in them, but not write them out a second time). This never worked, so there is no incompatibility; if it is needed at a later date, the serializer is a little bit closer to having it work now (the only table we don't deal with is the types table, and that's because the upcoming CTFv4 changes are likely to make major changes to the way that table is represented internally, so adding more code that depends on its current form seems like a bad idea). There is a new testcase that tests much of this, in particular that modification of existing types is still banned and that you can add new ones and chase them without error. libctf/ * ctf-impl.h (struct ctf_dict.ctf_symhash): Split into... (ctf_dict.ctf_symhash_func): ... this and... (ctf_dict.ctf_symhash_objt): ... this. (ctf_dict.ctf_stypes): New, counts static types. (LCTF_INDEX_TO_TYPEPTR): Use it instead of CTF_RDWR. (LCTF_RDWR): Deleted. (LCTF_DIRTY): Renumbered. (LCTF_LINKING): Likewise. (ctf_lookup_variable_here): New. (ctf_lookup_by_sym_or_name): Likewise. (ctf_symbol_next_static): Likewise. (ctf_add_variable_forced): Likewise. (ctf_add_funcobjt_sym_forced): Likewise. (ctf_simple_open_internal): Adjust. (ctf_bufopen_internal): Likewise. * ctf-create.c (ctf_grow_ptrtab): Adjust a lot to start with. (ctf_create): Migrate a bunch of initializations into bufopen. Force recreation of name tables. Do not forcibly override the model, let ctf_bufopen do it. (ctf_static_type): New. (ctf_update): Drop LCTF_RDWR check. (ctf_dynamic_type): Likewise. (ctf_add_function): Likewise. (ctf_add_type_internal): Likewise. (ctf_rollback): Check ctf_stypes, not LCTF_RDWR. (ctf_set_array): Likewise. (ctf_add_struct_sized): Likewise. (ctf_add_union_sized): Likewise. (ctf_add_enum): Likewise. (ctf_add_enumerator): Likewise (only on the target dict). (ctf_add_member_offset): Likewise. (ctf_add_generic): Drop LCTF_RDWR check. Ban addition of types with colliding names. (ctf_add_forward): Note safety under the new rules. (ctf_add_variable): Split all but the existence check into... (ctf_add_variable_forced): ... this new function. (ctf_add_funcobjt_sym): Likewise... (ctf_add_funcobjt_sym_forced): ... for this new function. * ctf-link.c (ctf_link_add_linker_symbol): Ban calling on dicts with any stypes. (ctf_link_add_strtab): Likewise. (ctf_link_shuffle_syms): Likewise. (ctf_link_intern_extern_string): Note pre-existing prohibition. * ctf-lookup.c (ctf_lookup_by_id): Drop LCTF_RDWR check. (ctf_lookup_variable): Split out looking in a dict but not its parent into... (ctf_lookup_variable_here): ... this new function. (ctf_lookup_symbol_idx): Track whether looking up a function or object: cache them separately. (ctf_symbol_next): Split out looking in non-dynamic symtypetab entries to... (ctf_symbol_next_static): ... this new function. Don't get confused by the simultaneous presence of static and dynamic symtypetab entries. (ctf_try_lookup_indexed): Don't waste time looking up symbols by index before there can be any idea how symbols are numbered. (ctf_lookup_by_sym_or_name): Distinguish between function and data object lookups. Drop LCTF_RDWR. (ctf_lookup_by_symbol): Adjust. (ctf_lookup_by_symbol_name): Likewise. * ctf-open.c (init_types): Rename to... (init_static_types): ... this. Drop LCTF_RDWR. Populate ctf_stypes. (ctf_simple_open): Drop writable arg. (ctf_simple_open_internal): Likewise. (ctf_bufopen): Likewise. (ctf_bufopen_internal): Populate fields only used for writable dicts. Drop LCTF_RDWR. (ctf_dict_close): Cater for symhash cache split. * ctf-serialize.c (ctf_serialize): Use ctf_stypes, not LCTF_RDWR. * ctf-types.c (ctf_variable_next): Drop LCTF_RDWR. * testsuite/libctf-lookup/add-to-opened*: New test.
Diffstat (limited to 'libctf/ctf-lookup.c')
-rw-r--r--libctf/ctf-lookup.c349
1 files changed, 222 insertions, 127 deletions
diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c
index b5d2637..1fcbebe 100644
--- a/libctf/ctf-lookup.c
+++ b/libctf/ctf-lookup.c
@@ -329,7 +329,7 @@ ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
const ctf_type_t *
ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
{
- ctf_dict_t *fp = *fpp; /* Caller passes in starting CTF dict. */
+ ctf_dict_t *fp = *fpp;
ctf_id_t idx;
if ((fp = ctf_get_dict (fp, type)) == NULL)
@@ -338,27 +338,10 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type)
return NULL;
}
- /* If this dict is writable, check for a dynamic type. */
-
- if (fp->ctf_flags & LCTF_RDWR)
- {
- ctf_dtdef_t *dtd;
-
- if ((dtd = ctf_dynamic_type (fp, type)) != NULL)
- {
- *fpp = fp;
- return &dtd->dtd_data;
- }
- (void) ctf_set_errno (*fpp, ECTF_BADID);
- return NULL;
- }
-
- /* Check for a type in the static portion. */
-
idx = LCTF_TYPE_TO_INDEX (fp, type);
if (idx > 0 && (unsigned long) idx <= fp->ctf_typemax)
{
- *fpp = fp; /* Function returns ending CTF dict. */
+ *fpp = fp; /* Possibly the parent CTF dict. */
return (LCTF_INDEX_TO_TYPEPTR (fp, idx));
}
@@ -384,34 +367,50 @@ ctf_lookup_var (const void *key_, const void *lookup_)
return (strcmp (key->clik_name, ctf_strptr (key->clik_fp, lookup->ctv_name)));
}
-/* Given a variable name, return the type of the variable with that name. */
+/* Given a variable name, return the type of the variable with that name.
+ Look only in this dict, not in the parent. */
ctf_id_t
-ctf_lookup_variable (ctf_dict_t *fp, const char *name)
+ctf_lookup_variable_here (ctf_dict_t *fp, const char *name)
{
+ ctf_dvdef_t *dvd = ctf_dvd_lookup (fp, name);
ctf_varent_t *ent;
ctf_lookup_idx_key_t key = { fp, name, NULL };
+ if (dvd != NULL)
+ return dvd->dvd_type;
+
/* This array is sorted, so we can bsearch for it. */
ent = bsearch (&key, fp->ctf_vars, fp->ctf_nvars, sizeof (ctf_varent_t),
ctf_lookup_var);
if (ent == NULL)
- {
- if (fp->ctf_parent != NULL)
- {
- ctf_id_t ptype;
+ return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
+
+ return ent->ctv_type;
+}
- if ((ptype = ctf_lookup_variable (fp->ctf_parent, name)) != CTF_ERR)
- return ptype;
- return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
- }
+/* As above, but look in the parent too. */
- return (ctf_set_typed_errno (fp, ECTF_NOTYPEDAT));
+ctf_id_t
+ctf_lookup_variable (ctf_dict_t *fp, const char *name)
+{
+ ctf_id_t type;
+
+ if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR)
+ {
+ if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL)
+ {
+ if ((type = ctf_lookup_variable_here (fp->ctf_parent, name)) != CTF_ERR)
+ return type;
+ return (ctf_set_typed_errno (fp, ctf_errno (fp->ctf_parent)));
+ }
+
+ return -1; /* errno is set for us. */
}
- return ent->ctv_type;
+ return type;
}
typedef struct ctf_symidx_sort_arg_cb
@@ -535,9 +534,11 @@ 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. */
+ not found. If is_function is >= 0, return only function or data object
+ symbols, respectively. */
static unsigned long
-ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
+ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname, int try_parent,
+ int is_function)
{
const ctf_sect_t *sp = &fp->ctf_symtab;
ctf_link_sym_t sym;
@@ -551,7 +552,9 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
ctf_link_sym_t *symp;
- if ((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
+ if (((symp = ctf_dynhash_lookup (fp->ctf_dynsyms, symname)) == NULL)
+ || (symp->st_type != STT_OBJECT && is_function == 0)
+ || (symp->st_type != STT_FUNC && is_function == 1))
goto try_parent;
return symp->st_symidx;
@@ -562,22 +565,33 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
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
+ 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 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)
+ if (!cache->ctf_symhash_func)
+ if ((cache->ctf_symhash_func = ctf_dynhash_create (ctf_hash_string,
+ ctf_hash_eq_string,
+ NULL, NULL)) == NULL)
+ goto oom;
+
+ if (!cache->ctf_symhash_objt)
+ if ((cache->ctf_symhash_objt = 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))
+ if (is_function != 0 &&
+ ctf_dynhash_lookup_kv (cache->ctf_symhash_func, symname, NULL, &known_idx))
+ return (unsigned long) (uintptr_t) known_idx;
+
+ if (is_function != 1 &&
+ ctf_dynhash_lookup_kv (cache->ctf_symhash_objt, symname, NULL, &known_idx))
return (unsigned long) (uintptr_t) known_idx;
/* Hash lookup unsuccessful: linear search, populating the hashtab for later
@@ -586,21 +600,16 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
for (; cache->ctf_symhash_latest < sp->cts_size / sp->cts_entsize;
cache->ctf_symhash_latest++)
{
+ ctf_dynhash_t *h;
+
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):
@@ -608,20 +617,28 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
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;
}
- break;
default:
ctf_set_errno (fp, ECTF_SYMTAB);
return (unsigned long) -1;
}
+
+ if (sym.st_type == STT_FUNC)
+ h = cache->ctf_symhash_func;
+ else if (sym.st_type == STT_OBJECT)
+ h = cache->ctf_symhash_objt;
+ else
+ continue; /* Not of interest. */
+
+ if (!ctf_dynhash_lookup_kv (h, sym.st_name,
+ NULL, NULL))
+ if (ctf_dynhash_cinsert (h, 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++;
}
/* Searched everything, still not found. */
@@ -629,11 +646,12 @@ ctf_lookup_symbol_idx (ctf_dict_t *fp, const char *symname)
return (unsigned long) -1;
try_parent:
- if (fp->ctf_parent)
+ if (fp->ctf_parent && try_parent)
{
unsigned long psym;
- if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname))
+ if ((psym = ctf_lookup_symbol_idx (fp->ctf_parent, symname, try_parent,
+ is_function))
!= (unsigned long) -1)
return psym;
@@ -653,12 +671,17 @@ oom:
}
-/* 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
- change the value of 'functions' in the middle of iteration over non-dynamic
- dicts, but doing so on dynamic dicts will fail. (This is probably not very
- useful, but there is no reason to prohibit it.) */
+ctf_id_t
+ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name,
+ int functions);
+
+/* 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.
+ Changing the value of 'functions' in the middle of iteration has
+ unpredictable effects (probably skipping symbols, etc) and is not
+ recommended. Adding symbols while iteration is underway may also lead
+ to other symbols being skipped. */
ctf_id_t
ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
@@ -685,24 +708,24 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
if (fp != i->cu.ctn_fp)
return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
- /* We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
+ /* Check the dynamic set of names first, to allow previously-written names
+ to be replaced with dynamic ones (there is still no way to remove them,
+ though).
+
+ We intentionally use raw access, not ctf_lookup_by_symbol, to avoid
incurring additional sorting cost for unsorted symtypetabs coming from the
compiler, to allow ctf_symbol_next to work in the absence of a symtab, and
finally because it's easier to work out what the name of each symbol is if
we do that. */
- if (fp->ctf_flags & LCTF_RDWR)
- {
- ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
- void *dyn_name = NULL, *dyn_value = NULL;
-
- if (!dynh)
- {
- ctf_next_destroy (i);
- return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
- }
+ ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
+ void *dyn_name = NULL, *dyn_value = NULL;
+ size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0;
+ if (i->ctn_n < dyn_els)
+ {
err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value);
+
/* This covers errors and also end-of-iteration. */
if (err != 0)
{
@@ -713,9 +736,50 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
*name = dyn_name;
sym = (ctf_id_t) (uintptr_t) dyn_value;
+ i->ctn_n++;
+
+ return sym;
}
- else if ((!functions && fp->ctf_objtidx_names) ||
- (functions && fp->ctf_funcidx_names))
+
+ return ctf_symbol_next_static (fp, it, name, functions);
+}
+
+/* ctf_symbol_next, but only for static symbols. Mostly an internal
+ implementation detail of ctf_symbol_next, but also used to simplify
+ serialization. */
+ctf_id_t
+ctf_symbol_next_static (ctf_dict_t *fp, ctf_next_t **it, const char **name,
+ int functions)
+{
+ ctf_id_t sym = CTF_ERR;
+ ctf_next_t *i = *it;
+ ctf_dynhash_t *dynh = functions ? fp->ctf_funchash : fp->ctf_objthash;
+ size_t dyn_els = dynh ? ctf_dynhash_elements (dynh) : 0;
+
+ /* Only relevant for direct internal-to-library calls, not via
+ ctf_symbol_next (but important then). */
+
+ if (!i)
+ {
+ if ((i = ctf_next_create ()) == NULL)
+ return ctf_set_typed_errno (fp, ENOMEM);
+
+ i->cu.ctn_fp = fp;
+ i->ctn_iter_fun = (void (*) (void)) ctf_symbol_next;
+ i->ctn_n = dyn_els;
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_symbol_next != i->ctn_iter_fun)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
+
+ if (fp != i->cu.ctn_fp)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
+
+ /* TODO-v4: Indexed after non-indexed portions? */
+
+ if ((!functions && fp->ctf_objtidx_names) ||
+ (functions && fp->ctf_funcidx_names))
{
ctf_header_t *hp = fp->ctf_header;
uint32_t *idx = functions ? fp->ctf_funcidx_names : fp->ctf_objtidx_names;
@@ -735,48 +799,51 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
do
{
- if (i->ctn_n >= len)
+ if (i->ctn_n - dyn_els >= len)
goto end;
- *name = ctf_strptr (fp, idx[i->ctn_n]);
- sym = tab[i->ctn_n++];
+ *name = ctf_strptr (fp, idx[i->ctn_n - dyn_els]);
+ sym = tab[i->ctn_n - dyn_els];
+ i->ctn_n++;
}
while (sym == -1u || sym == 0);
}
else
{
- /* Skip over pads in ctf_xslate, padding for typeless symbols in the
+ /* Skip over pads in ctf_sxlate, padding for typeless symbols in the
symtypetab itself, and symbols in the wrong table. */
- for (; i->ctn_n < fp->ctf_nsyms; i->ctn_n++)
+ for (; i->ctn_n - dyn_els < fp->ctf_nsyms; i->ctn_n++)
{
ctf_header_t *hp = fp->ctf_header;
+ size_t n = i->ctn_n - dyn_els;
- if (fp->ctf_sxlate[i->ctn_n] == -1u)
+ if (fp->ctf_sxlate[n] == -1u)
continue;
- sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[i->ctn_n]);
+ sym = *(uint32_t *) ((uintptr_t) fp->ctf_buf + fp->ctf_sxlate[n]);
if (sym == 0)
continue;
if (functions)
{
- if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_funcoff
- && fp->ctf_sxlate[i->ctn_n] < hp->cth_objtidxoff)
+ if (fp->ctf_sxlate[n] >= hp->cth_funcoff
+ && fp->ctf_sxlate[n] < hp->cth_objtidxoff)
break;
}
else
{
- if (fp->ctf_sxlate[i->ctn_n] >= hp->cth_objtoff
- && fp->ctf_sxlate[i->ctn_n] < hp->cth_funcoff)
+ if (fp->ctf_sxlate[n] >= hp->cth_objtoff
+ && fp->ctf_sxlate[n] < hp->cth_funcoff)
break;
}
}
- if (i->ctn_n >= fp->ctf_nsyms)
+ if (i->ctn_n - dyn_els >= fp->ctf_nsyms)
goto end;
- *name = ctf_lookup_symbol_name (fp, i->ctn_n++);
+ *name = ctf_lookup_symbol_name (fp, i->ctn_n - dyn_els);
+ i->ctn_n++;
}
return sym;
@@ -815,6 +882,13 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
if (symname == NULL)
symname = ctf_lookup_symbol_name (fp, symidx);
+ /* Dynamic dict with no static portion: just return. */
+ if (!hp)
+ {
+ ctf_dprintf ("%s not found in idx: dict is dynamic\n", symname);
+ return 0;
+ }
+
ctf_dprintf ("Looking up type of object with symtab idx %lx or name %s in "
"indexed symtypetab\n", symidx, symname);
@@ -887,17 +961,27 @@ ctf_try_lookup_indexed (ctf_dict_t *fp, unsigned long symidx,
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. */
+ names.
-static ctf_id_t
+ If try_parent is false, do not check the parent dict too.
+
+ If is_function is > -1, only look for data objects or functions in
+ particular. */
+
+ctf_id_t
ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
- const char *symname)
+ const char *symname, int try_parent,
+ int is_function)
{
const ctf_sect_t *sp = &fp->ctf_symtab;
ctf_id_t type = 0;
int err = 0;
- /* Shuffled dynsymidx present? Use that. */
+ /* Shuffled dynsymidx present? Use that. For now, the dynsymidx and
+ shuffled-symbol lookup only support dynamically-added symbols, because
+ this interface is meant for use by linkers, and linkers are only going
+ to report symbols against newly-created, freshly-ctf_link'ed dicts: so
+ there will be no static component in any case. */
if (fp->ctf_dynsymidx)
{
const ctf_link_sym_t *sym;
@@ -909,10 +993,6 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
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;
-
/* No name? Need to look it up. */
if (!symname)
{
@@ -922,7 +1002,9 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
sym = fp->ctf_dynsymidx[symidx];
err = ECTF_NOTYPEDAT;
- if (!sym || (sym->st_shndx != STT_OBJECT && sym->st_shndx != STT_FUNC))
+ if (!sym || (sym->st_type != STT_OBJECT && sym->st_type != STT_FUNC)
+ || (sym->st_type != STT_OBJECT && is_function == 0)
+ || (sym->st_type != STT_FUNC && is_function == 1))
goto try_parent;
if (!ctf_assert (fp, !sym->st_nameidx_set))
@@ -931,49 +1013,55 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
}
if (fp->ctf_objthash == NULL
- || ((type = (ctf_id_t) (uintptr_t)
- ctf_dynhash_lookup (fp->ctf_objthash, symname)) == 0))
+ || is_function == 1
+ || (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))
+ || is_function == 0
+ || (type = (ctf_id_t) (uintptr_t)
+ 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)
+ /* Dict not shuffled: look for a dynamic sym first, and look it up
+ directly. */
+ if (symname)
{
- 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;
+ if (fp->ctf_objthash != NULL
+ && is_function != 1
+ && ((type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_objthash, symname)) != 0))
+ return type;
+
+ if (fp->ctf_funchash != NULL
+ && is_function != 0
+ && ((type = (ctf_id_t) (uintptr_t)
+ ctf_dynhash_lookup (fp->ctf_funchash, symname)) != 0))
+ return type;
}
err = ECTF_NOSYMTAB;
if (sp->cts_data == NULL)
goto try_parent;
- /* This covers both out-of-range lookups and a dynamic dict which hasn't been
- shuffled yet. */
+ /* This covers both out-of-range lookups by index and a dynamic dict which
+ hasn't been shuffled yet. */
err = EINVAL;
if (symname == NULL && symidx >= fp->ctf_nsyms)
goto try_parent;
- if (fp->ctf_objtidx_names)
+ /* Try an indexed lookup. */
+
+ if (fp->ctf_objtidx_names && is_function != 1)
{
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 == 0 && fp->ctf_funcidx_names && is_function != 0)
{
if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
@@ -981,6 +1069,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
if (type != 0)
return type;
+ /* Indexed but no symbol found -> not present, try the parent. */
err = ECTF_NOTYPEDAT;
if (fp->ctf_objtidx_names && fp->ctf_funcidx_names)
goto try_parent;
@@ -990,7 +1079,8 @@ ctf_lookup_by_sym_or_name (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)
+ if ((symidx = ctf_lookup_symbol_idx (fp, symname, try_parent, is_function))
+ == (unsigned long) -1)
goto try_parent;
if (fp->ctf_sxlate[symidx] == -1u)
@@ -1002,11 +1092,16 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
goto try_parent;
return type;
+
try_parent:
+ if (!try_parent)
+ return ctf_set_errno (fp, err);
+
if (fp->ctf_parent)
{
ctf_id_t ret = ctf_lookup_by_sym_or_name (fp->ctf_parent, symidx,
- symname);
+ symname, try_parent,
+ is_function);
if (ret == CTF_ERR)
ctf_set_errno (fp, ctf_errno (fp->ctf_parent));
return ret;
@@ -1020,7 +1115,7 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
ctf_id_t
ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
{
- return ctf_lookup_by_sym_or_name (fp, symidx, NULL);
+ return ctf_lookup_by_sym_or_name (fp, symidx, NULL, 1, -1);
}
/* Given a symbol name, return the type of the function or data object described
@@ -1028,7 +1123,7 @@ ctf_lookup_by_symbol (ctf_dict_t *fp, unsigned long symidx)
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);
+ return ctf_lookup_by_sym_or_name (fp, 0, symname, 1, -1);
}
/* Given a symbol table index, return the info for the function described