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 42e9024..54d3d0a 100644
--- a/libctf/ctf-archive.c
+++ b/libctf/ctf-archive.c
@@ -732,6 +732,113 @@ ctf_archive_iter (const ctf_archive_t *arc, ctf_archive_member_f *func,
return func (arc->ctfi_file, _CTF_SECTION, data);
}
+/* Iterate over all CTF files in an archive, returning each dict in turn as a
+ ctf_file_t, and NULL on error or end of iteration. It is the caller's
+ responsibility to close it. Parent dicts may be skipped. Regardless of
+ whether they are skipped or not, the caller must ctf_import the parent if
+ need be.
+
+ We identify parents by name rather than by flag value: for now, with the
+ linker only emitting parents named _CTF_SECTION, this works well enough. */
+
+ctf_file_t *
+ctf_archive_next (const ctf_archive_t *wrapper, ctf_next_t **it, const char **name,
+ int skip_parent, int *errp)
+{
+ ctf_file_t *f;
+ ctf_next_t *i = *it;
+ struct ctf_archive *arc;
+ struct ctf_archive_modent *modent;
+ const char *nametbl;
+ const char *name_;
+
+ if (!i)
+ {
+ if ((i = ctf_next_create()) == NULL)
+ {
+ if (errp)
+ *errp = ENOMEM;
+ return NULL;
+ }
+ i->cu.ctn_arc = wrapper;
+ i->ctn_iter_fun = (void (*) (void)) ctf_archive_next;
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_archive_next != i->ctn_iter_fun)
+ {
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFUN;
+ return NULL;
+ }
+
+ if (wrapper != i->cu.ctn_arc)
+ {
+ if (errp)
+ *errp = ECTF_NEXT_WRONGFP;
+ return NULL;
+ }
+
+ /* Iteration is made a bit more complex by the need to handle ctf_file_t's
+ transparently wrapped in a single-member archive. These are parents: if
+ skip_parent is on, they are skipped and the iterator terminates
+ immediately. */
+
+ if (!wrapper->ctfi_is_archive && i->ctn_n == 0)
+ {
+ i->ctn_n++;
+ if (!skip_parent)
+ {
+ wrapper->ctfi_file->ctf_refcnt++;
+ return wrapper->ctfi_file;
+ }
+ }
+
+ arc = wrapper->ctfi_archive;
+
+ /* The loop keeps going when skip_parent is on as long as the member we find
+ is the parent (i.e. at most two iterations, but possibly an early return if
+ *all* we have is a parent). */
+
+ const ctf_sect_t *symsect;
+ const ctf_sect_t *strsect;
+
+ do
+ {
+ if ((!wrapper->ctfi_is_archive) || (i->ctn_n >= le64toh (arc->ctfa_nfiles)))
+ {
+ ctf_next_destroy (i);
+ *it = NULL;
+ if (errp)
+ *errp = ECTF_NEXT_END;
+ return NULL;
+ }
+
+ symsect = &wrapper->ctfi_symsect;
+ strsect = &wrapper->ctfi_strsect;
+
+ if (symsect->cts_name == NULL)
+ symsect = NULL;
+ if (strsect->cts_name == NULL)
+ strsect = NULL;
+
+ modent = (ctf_archive_modent_t *) ((char *) arc
+ + sizeof (struct ctf_archive));
+ nametbl = (((const char *) arc) + le64toh (arc->ctfa_names));
+
+ name_ = &nametbl[le64toh (modent[i->ctn_n].name_offset)];
+ i->ctn_n++;
+ } while (skip_parent && strcmp (name_, _CTF_SECTION) == 0);
+
+ if (name)
+ *name = name_;
+
+ f = ctf_arc_open_by_name_internal (arc, symsect, strsect,
+ name_, errp);
+ f->ctf_archive = (ctf_archive_t *) wrapper;
+ return f;
+}
+
#ifdef HAVE_MMAP
/* Map the header in. Only used on new, empty files. */
static void *arc_mmap_header (int fd, size_t headersz)