aboutsummaryrefslogtreecommitdiff
path: root/libctf/ctf-archive.c
diff options
context:
space:
mode:
Diffstat (limited to 'libctf/ctf-archive.c')
-rw-r--r--libctf/ctf-archive.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/libctf/ctf-archive.c b/libctf/ctf-archive.c
index 4744cb7..c602705 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -1011,6 +1011,113 @@ ctf_arc_lookup_symbol_name (ctf_archive_t *wrapper, const char *symname,
return ctf_arc_lookup_sym_or_name (wrapper, 0, symname, typep, errp);
}
+/* Return all enumeration constants with a given NAME across all dicts in an
+ archive, similar to ctf_lookup_enumerator_next. The DICT is cached, so
+ opening costs are paid only once, but (unlike ctf_arc_lookup_symbol*
+ above) the results of the iterations are not cached. dict and errp are
+ not optional. */
+
+ctf_id_t
+ctf_arc_lookup_enumerator_next (ctf_archive_t *arc, const char *name,
+ ctf_next_t **it, int64_t *enum_value,
+ ctf_dict_t **dict, int *errp)
+{
+ ctf_next_t *i = *it;
+ ctf_id_t type;
+ int opened_this_time = 0;
+ int err;
+
+ /* We have two nested iterators in here: ctn_next tracks archives, while
+ within it ctn_next_inner tracks enumerators within an archive. We
+ keep track of the dict by simply reusing the passed-in arg: if it's
+ changed by the caller, the caller will get an ECTF_WRONGFP error,
+ so this is quite safe and means we don't have to track the arc and fp
+ simultaneously in the ctf_next_t. */
+
+ if (!i)
+ {
+ if ((i = ctf_next_create ()) == NULL)
+ {
+ err = ENOMEM;
+ goto err;
+ }
+ i->ctn_iter_fun = (void (*) (void)) ctf_arc_lookup_enumerator_next;
+ i->cu.ctn_arc = arc;
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_arc_lookup_enumerator_next != i->ctn_iter_fun)
+ {
+ err = ECTF_NEXT_WRONGFUN;
+ goto err;
+ }
+
+ if (arc != i->cu.ctn_arc)
+ {
+ err = ECTF_NEXT_WRONGFP;
+ goto err;
+ }
+
+ /* Prevent any earlier end-of-iteration on this dict from confusing the
+ test below. */
+ if (i->ctn_next != NULL)
+ ctf_set_errno (*dict, 0);
+
+ do
+ {
+ /* At end of one dict, or not started any iterations yet?
+ Traverse to next dict. If we never returned this dict to the
+ caller, close it ourselves: the caller will never see it and cannot
+ do so. */
+
+ if (i->ctn_next == NULL || ctf_errno (*dict) == ECTF_NEXT_END)
+ {
+ if (opened_this_time)
+ {
+ ctf_dict_close (*dict);
+ *dict = NULL;
+ opened_this_time = 0;
+ }
+
+ *dict = ctf_archive_next (arc, &i->ctn_next, NULL, 0, &err);
+ if (!*dict)
+ goto err;
+ opened_this_time = 1;
+ }
+
+ type = ctf_lookup_enumerator_next (*dict, name, &i->ctn_next_inner,
+ enum_value);
+ }
+ while (type == CTF_ERR && ctf_errno (*dict) == ECTF_NEXT_END);
+
+ if (type == CTF_ERR)
+ {
+ err = ctf_errno (*dict);
+ goto err;
+ }
+
+ /* If this dict is being reused from the previous iteration, bump its
+ refcnt: the caller is going to close it and has no idea that we didn't
+ open it this time round. */
+ if (!opened_this_time)
+ ctf_ref (*dict);
+
+ return type;
+
+ err: /* Also ECTF_NEXT_END. */
+ if (opened_this_time)
+ {
+ ctf_dict_close (*dict);
+ *dict = NULL;
+ }
+
+ ctf_next_destroy (i);
+ *it = NULL;
+ if (errp)
+ *errp = err;
+ return CTF_ERR;
+}
+
/* 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