diff options
-rw-r--r-- | include/ChangeLog | 5 | ||||
-rw-r--r-- | include/ctf-api.h | 7 | ||||
-rw-r--r-- | libctf/ChangeLog | 22 | ||||
-rw-r--r-- | libctf/ctf-dedup.c | 6 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 12 | ||||
-rw-r--r-- | libctf/ctf-lookup.c | 2 | ||||
-rw-r--r-- | libctf/ctf-types.c | 227 | ||||
-rw-r--r-- | libctf/ctf-util.c | 5 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/struct-iteration-ctf.c | 28 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/struct-iteration.c | 92 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/struct-iteration.lk | 24 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/struct-lookup.c | 60 | ||||
-rw-r--r-- | libctf/testsuite/libctf-lookup/struct-lookup.lk | 4 |
13 files changed, 392 insertions, 102 deletions
diff --git a/include/ChangeLog b/include/ChangeLog index 1b56987..ab2aa33 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,5 +1,10 @@ 2021-01-05 Nick Alcock <nick.alcock@oracle.com> + * ctf-api.h (CTF_MN_RECURSE): New. + (ctf_member_next): Add flags argument. + +2021-01-05 Nick Alcock <nick.alcock@oracle.com> + * ctf-api.h (ECTF_INCOMPLETE): New. (ECTF_NERR): Adjust. diff --git a/include/ctf-api.h b/include/ctf-api.h index b3cfd39..5cf3257 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -264,6 +264,10 @@ _CTF_ERRORS #define CTF_ADD_NONROOT 0 /* Type only visible in nested scope. */ #define CTF_ADD_ROOT 1 /* Type visible at top-level scope. */ +/* Flags for ctf_member_next. */ + +#define CTF_MN_RECURSE 0x1 /* Recurse into unnamed members. */ + /* These typedefs are used to define the signature for callback functions that can be used with the iteration and visit functions below. There is also a family of iteration functions that do not require callbacks. */ @@ -411,7 +415,8 @@ extern int ctf_label_info (ctf_dict_t *, const char *, ctf_lblinfo_t *); extern int ctf_member_count (ctf_dict_t *, ctf_id_t); extern int ctf_member_iter (ctf_dict_t *, ctf_id_t, ctf_member_f *, void *); extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **, - const char **name, ctf_id_t *membtype); + const char **name, ctf_id_t *membtype, + int flags); extern int ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *); extern const char *ctf_enum_next (ctf_dict_t *, ctf_id_t, ctf_next_t **, int *); diff --git a/libctf/ChangeLog b/libctf/ChangeLog index db75fd5..57507c4 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,27 @@ 2021-01-05 Nick Alcock <nick.alcock@oracle.com> + * ctf-impl.h (struct ctf_next) <u.ctn_next>: Move to... + <ctn_next>: ... here. + * ctf-util.c (ctf_next_destroy): Unconditionally destroy it. + * ctf-lookup.c (ctf_symbol_next): Adjust accordingly. + * ctf-types.c (ctf_member_iter): Reimplement in terms of... + (ctf_member_next): ... this. Support recursive unnamed member + iteration (off by default). + (ctf_member_info): Look up members in unnamed sub-structs. + * ctf-dedup.c (ctf_dedup_rhash_type): Adjust ctf_member_next call. + (ctf_dedup_emit_struct_members): Likewise. + * testsuite/libctf-lookup/struct-iteration-ctf.c: Test empty unnamed + members, and a normal member after the end. + * testsuite/libctf-lookup/struct-iteration.c: Verify that + ctf_member_count is consistent with the number of successful returns + from a non-recursive ctf_member_next. + * testsuite/libctf-lookup/struct-iteration-*: New, test iteration + over struct members. + * testsuite/libctf-lookup/struct-lookup.c: New test. + * testsuite/libctf-lookup/struct-lookup.lk: New test. + +2021-01-05 Nick Alcock <nick.alcock@oracle.com> + * ctf-link.c (ctf_link_warn_outdated_inputs): New. (ctf_link_write): Call it. diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c index fd72a60..da88ae371 100644 --- a/libctf/ctf-dedup.c +++ b/libctf/ctf-dedup.c @@ -887,8 +887,8 @@ ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs, ctf_dedup_sha1_add (&hash, &size, sizeof (ssize_t), "struct size", depth); - while ((offset = ctf_member_next (input, type, &i, &mname, - &membtype)) >= 0) + while ((offset = ctf_member_next (input, type, &i, &mname, &membtype, + 0)) >= 0) { if (mname == NULL) mname = ""; @@ -2956,7 +2956,7 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs, target_type = CTF_DEDUP_GID_TO_TYPE (target_id); while ((offset = ctf_member_next (input_fp, input_type, &j, &name, - &membtype)) >= 0) + &membtype, 0)) >= 0) { err_fp = target; err_type = target_type; diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index b19ae69..8a173c1 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -532,13 +532,15 @@ struct ctf_next ssize_t ctn_size; ssize_t ctn_increment; uint32_t ctn_n; + + /* Some iterators contain other iterators, in addition to their other + state. */ + ctf_next_t *ctn_next; + /* We can save space on this side of things by noting that a dictionary is either dynamic or not, as a whole, and a given iterator can only iterate over one kind of thing at once: so we can overlap the DTD and non-DTD - members, and the structure, variable and enum members, etc. - - Some of the _next iterators actually thunk down to another _next iterator - themselves, so one of the options in here is a _next iterator! */ + members, and the structure, variable and enum members, etc. */ union { const ctf_member_t *ctn_mp; @@ -546,10 +548,10 @@ struct ctf_next const ctf_dmdef_t *ctn_dmd; const ctf_enum_t *ctn_en; const ctf_dvdef_t *ctn_dvd; - ctf_next_t *ctn_next; ctf_next_hkv_t *ctn_sorted_hkv; void **ctn_hash_slot; } u; + /* This union is of various sorts of dict we can iterate over: currently dictionaries and archives, dynhashes, and dynsets. */ union diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c index 869c3843..0d6ef3c 100644 --- a/libctf/ctf-lookup.c +++ b/libctf/ctf-lookup.c @@ -442,7 +442,7 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name, return (ctf_set_errno (fp, ECTF_NEXT_END)); } - err = ctf_dynhash_next (dynh, &i->u.ctn_next, &dyn_name, &dyn_value); + err = ctf_dynhash_next (dynh, &i->ctn_next, &dyn_name, &dyn_value); /* This covers errors and also end-of-iteration. */ if (err != 0) { diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index a3d824b..6275be0 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -41,76 +41,33 @@ ctf_type_ischild (ctf_dict_t * fp, ctf_id_t id) int ctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) { - ctf_dict_t *ofp = fp; - const ctf_type_t *tp; - ctf_dtdef_t *dtd; - ssize_t size, increment; - uint32_t kind, n; + ctf_next_t *i = NULL; + ssize_t offset; + const char *name; + ctf_id_t membtype; int rc; - if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) - return -1; /* errno is set for us. */ - - if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) - return -1; /* errno is set for us. */ - - (void) ctf_get_ctt_size (fp, tp, &size, &increment); - kind = LCTF_INFO_KIND (fp, tp->ctt_info); - - if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) - return (ctf_set_errno (ofp, ECTF_NOTSOU)); - - if ((dtd = ctf_dynamic_type (fp, type)) == NULL) + while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) { - if (size < CTF_LSTRUCT_THRESH) - { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); - - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) - { - const char *name = ctf_strptr (fp, mp->ctm_name); - if ((rc = func (name, mp->ctm_type, mp->ctm_offset, arg)) != 0) - return rc; - } - } - else - { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); - - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) - { - const char *name = ctf_strptr (fp, lmp->ctlm_name); - if ((rc = func (name, lmp->ctlm_type, - (unsigned long) CTF_LMEM_OFFSET (lmp), arg)) != 0) - return rc; - } - } - } - else - { - ctf_dmdef_t *dmd; - - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) + if ((rc = func (name, membtype, offset, arg)) != 0) { - if ((rc = func (dmd->dmd_name, dmd->dmd_type, - dmd->dmd_offset, arg)) != 0) - return rc; + ctf_next_destroy (i); + return rc; } } + if (ctf_errno (fp) != ECTF_NEXT_END) + return -1; /* errno is set for us. */ return 0; } /* Iterate over the members of a STRUCT or UNION, returning each member's offset and optionally name and member type in turn. On end-of-iteration, - returns -1. */ + returns -1. If FLAGS is CTF_MN_RECURSE, recurse into unnamed members. */ ssize_t ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, - const char **name, ctf_id_t *membtype) + const char **name, ctf_id_t *membtype, int flags) { ctf_dict_t *ofp = fp; uint32_t kind; @@ -121,6 +78,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, { const ctf_type_t *tp; ctf_dtdef_t *dtd; + ssize_t increment; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) return -1; /* errno is set for us. */ @@ -132,8 +90,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, return ctf_set_errno (ofp, ENOMEM); i->cu.ctn_fp = ofp; - (void) ctf_get_ctt_size (fp, tp, &i->ctn_size, - &i->ctn_increment); + (void) ctf_get_ctt_size (fp, tp, &i->ctn_size, &increment); kind = LCTF_INFO_KIND (fp, tp->ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) @@ -156,11 +113,9 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); if (i->ctn_size < CTF_LSTRUCT_THRESH) - i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + - i->ctn_increment); + i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment); else - i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - i->ctn_increment); + i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment); } else i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members); @@ -178,41 +133,112 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, if ((fp = ctf_get_dict (ofp, type)) == NULL) return (ctf_set_errno (ofp, ECTF_NOPARENT)); - if (!(fp->ctf_flags & LCTF_RDWR)) - { - if (i->ctn_n == 0) - goto end_iter; + /* When we hit an unnamed struct/union member, we set ctn_type to indicate + that we are inside one, then return the unnamed member: on the next call, + we must skip over top-level member iteration in favour of iteration within + the sub-struct until it later turns out that that iteration has ended. */ - if (i->ctn_size < CTF_LSTRUCT_THRESH) + retry: + if (!i->ctn_type) + { + if (!(fp->ctf_flags & LCTF_RDWR)) { - if (name) - *name = ctf_strptr (fp, i->u.ctn_mp->ctm_name); - if (membtype) - *membtype = i->u.ctn_mp->ctm_type; - offset = i->u.ctn_mp->ctm_offset; - i->u.ctn_mp++; + if (i->ctn_n == 0) + goto end_iter; + + if (i->ctn_size < CTF_LSTRUCT_THRESH) + { + const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name); + + if (name) + *name = membname; + if (membtype) + *membtype = i->u.ctn_mp->ctm_type; + offset = i->u.ctn_mp->ctm_offset; + + if (membname[0] == 0 + && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION)) + i->ctn_type = i->u.ctn_mp->ctm_type; + + i->u.ctn_mp++; + } + else + { + const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name); + + if (name) + *name = membname; + if (membtype) + *membtype = i->u.ctn_lmp->ctlm_type; + offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp); + + if (membname[0] == 0 + && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION)) + i->ctn_type = i->u.ctn_lmp->ctlm_type; + + i->u.ctn_lmp++; + } + i->ctn_n--; } else { + if (i->u.ctn_dmd == NULL) + goto end_iter; + /* The dmd contains a NULL for unnamed dynamic members. Don't inflict + this on our callers. */ if (name) - *name = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name); + { + if (i->u.ctn_dmd->dmd_name) + *name = i->u.ctn_dmd->dmd_name; + else + *name = ""; + } if (membtype) - *membtype = i->u.ctn_lmp->ctlm_type; - offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp); - i->u.ctn_lmp++; + *membtype = i->u.ctn_dmd->dmd_type; + offset = i->u.ctn_dmd->dmd_offset; + + if (i->u.ctn_dmd->dmd_name == NULL + && (ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_STRUCT + || ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_UNION)) + i->ctn_type = i->u.ctn_dmd->dmd_type; + + i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd); } - i->ctn_n--; + + /* The callers might want automatic recursive sub-struct traversal. */ + if (!(flags & CTF_MN_RECURSE)) + i->ctn_type = 0; + + /* Sub-struct traversal starting? Take note of the offset of this member, + for later boosting of sub-struct members' offsets. */ + if (i->ctn_type) + i->ctn_increment = offset; } + /* Traversing a sub-struct? Just return it, with the offset adjusted. */ else { - if (i->u.ctn_dmd == NULL) - goto end_iter; - if (name) - *name = i->u.ctn_dmd->dmd_name; - if (membtype) - *membtype = i->u.ctn_dmd->dmd_type; - offset = i->u.ctn_dmd->dmd_offset; - i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd); + ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name, + membtype, flags); + + if (ret >= 0) + return ret + i->ctn_increment; + + if (ctf_errno (fp) != ECTF_NEXT_END) + { + ctf_next_destroy (i); + *it = NULL; + i->ctn_type = 0; + return ret; /* errno is set for us. */ + } + + if (!ctf_assert (fp, (i->ctn_next == NULL))) + return -1; /* errno is set for us. */ + + i->ctn_type = 0; + /* This sub-struct has ended: on to the next real member. */ + goto retry; } return offset; @@ -1377,7 +1403,7 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype, } /* Return the number of members in a STRUCT or UNION, or the number of - enumerators in an ENUM. */ + enumerators in an ENUM. The count does not include unnamed sub-members. */ int ctf_member_count (ctf_dict_t *fp, ctf_id_t type) @@ -1433,7 +1459,15 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) { - if (strcmp (ctf_strptr (fp, mp->ctm_name), name) == 0) + const char *membname = ctf_strptr (fp, mp->ctm_name); + + if (membname[0] == 0 + && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION) + && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0)) + return 0; + + if (strcmp (membname, name) == 0) { mip->ctm_type = mp->ctm_type; mip->ctm_offset = mp->ctm_offset; @@ -1448,7 +1482,15 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) { - if (strcmp (ctf_strptr (fp, lmp->ctlm_name), name) == 0) + const char *membname = ctf_strptr (fp, lmp->ctlm_name); + + if (membname[0] == 0 + && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION) + && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0)) + return 0; + + if (strcmp (membname, name) == 0) { mip->ctm_type = lmp->ctlm_type; mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp); @@ -1464,7 +1506,14 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next (dmd)) { - if (strcmp (dmd->dmd_name, name) == 0) + if (dmd->dmd_name == NULL + && (ctf_type_kind (fp, dmd->dmd_type) == CTF_K_STRUCT + || ctf_type_kind (fp, dmd->dmd_type) == CTF_K_UNION) + && (ctf_member_info (fp, dmd->dmd_type, name, mip) == 0)) + return 0; + + if (dmd->dmd_name != NULL + && strcmp (dmd->dmd_name, name) == 0) { mip->ctm_type = dmd->dmd_type; mip->ctm_offset = dmd->dmd_offset; diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c index 879ebbf..4f126ba 100644 --- a/libctf/ctf-util.c +++ b/libctf/ctf-util.c @@ -283,9 +283,8 @@ ctf_next_destroy (ctf_next_t *i) if (i->ctn_iter_fun == (void (*) (void)) ctf_dynhash_next_sorted) free (i->u.ctn_sorted_hkv); - if (i->ctn_iter_fun == (void (*) (void)) ctf_symbol_next - && i->cu.ctn_fp->ctf_flags & LCTF_RDWR) - ctf_next_destroy (i->u.ctn_next); + if (i->ctn_next) + ctf_next_destroy (i->ctn_next); free (i); } diff --git a/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c new file mode 100644 index 0000000..7df67ad --- /dev/null +++ b/libctf/testsuite/libctf-lookup/struct-iteration-ctf.c @@ -0,0 +1,28 @@ +#include <unistd.h> + +struct foo_t +{ + int foo; + size_t bar; + const char *baz; + struct foo_t *self; + union + { + double should_not_appear; + char *nor_should_this; + } named; + struct + { + long unnamed_sub_member; + union + { + double one_more_level; + long yes_really_one_more; + }; + }; + struct {}; /* Empty ones */ + union {}; + int after_the_end; +}; + +struct foo_t used; diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.c b/libctf/testsuite/libctf-lookup/struct-iteration.c new file mode 100644 index 0000000..0375060 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/struct-iteration.c @@ -0,0 +1,92 @@ +#include <ctf-api.h> +#include <stdio.h> +#include <stdlib.h> + +static int +print_struct (const char *name, ctf_id_t membtype, unsigned long offset, + void *fp_) +{ + ctf_dict_t *fp = (ctf_dict_t *) fp_; + char *type_name = ctf_type_aname (fp, membtype); + + printf ("iter test: %s, offset %lx, has type %lx/%s\n", + name, offset, membtype, type_name); + free (type_name); + + return 0; +} + +int +main (int argc, char *argv[]) +{ + ctf_dict_t *fp; + ctf_archive_t *ctf; + ctf_id_t type; + ctf_next_t *i = NULL; + const char *name; + ctf_id_t membtype; + ssize_t offset; + ssize_t icount = 0; + int err; + + 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; + if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL) + goto open_err; + + /* Iterate over the structure members with each iterator type in turn. */ + + if ((type = ctf_lookup_by_name (fp, "struct foo_t") ) == CTF_ERR) + goto err; + + if (ctf_member_iter (fp, type, print_struct, fp) < 0) + goto ierr; + + while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, + CTF_MN_RECURSE)) >= 0) + { + char *type_name = ctf_type_aname (fp, membtype); + + printf ("next test: %s, offset %lx, has type %lx/%s\n", + name, offset, membtype, type_name); + free (type_name); + } + if (ctf_errno (fp) != ECTF_NEXT_END) + goto nerr; + + /* Now make sure the count of members does not include any recursive + members. */ + while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) + icount++; + + if (ctf_errno (fp) != ECTF_NEXT_END) + goto nerr; + + if (icount != ctf_member_count (fp, type)) + printf ("member counts differ: %li by direct iteration, " + "%li by ctf_member_count\n", icount, ctf_member_count (fp, type)); + + ctf_dict_close (fp); + ctf_close (ctf); + + return 0; + + open_err: + fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err)); + return 1; + err: + fprintf (stderr, "Lookup failed: %s\n", ctf_errmsg (ctf_errno (fp))); + return 1; + ierr: + fprintf (stderr, "_iter iteration failed: %s\n", ctf_errmsg (ctf_errno (fp))); + return 1; + nerr: + fprintf (stderr, "_next iteration failed: %s\n", ctf_errmsg (ctf_errno (fp))); + return 1; +} diff --git a/libctf/testsuite/libctf-lookup/struct-iteration.lk b/libctf/testsuite/libctf-lookup/struct-iteration.lk new file mode 100644 index 0000000..fd64454 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/struct-iteration.lk @@ -0,0 +1,24 @@ +# source: struct-iteration-ctf.c +# link: on +iter test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int +iter test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t +iter test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \* +iter test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \* +iter test: named, offset [0-9a-f]*, has type [0-9a-f]*/union +iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct +iter test: , offset [0-9a-f]*, has type [0-9a-f]*/struct +iter test: , offset [0-9a-f]*, has type [0-9a-f]*/union +iter test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int +next test: foo, offset [0-9a-f]*, has type [0-9a-f]*/int +next test: bar, offset [0-9a-f]*, has type [0-9a-f]*/size_t +next test: baz, offset [0-9a-f]*, has type [0-9a-f]*/const char \* +next test: self, offset [0-9a-f]*, has type [0-9a-f]*/struct foo_t \* +next test: named, offset [0-9a-f]*, has type [0-9a-f]*/union +next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct +next test: unnamed_sub_member, offset [0-9a-f]*, has type [0-9a-f]*/long int +next test: , offset [0-9a-f]*, has type [0-9a-f]*/union +next test: one_more_level, offset [0-9a-f]*, has type [0-9a-f]*/double +next test: yes_really_one_more, offset [0-9a-f]*, has type [0-9a-f]*/long int +next test: , offset [0-9a-f]*, has type [0-9a-f]*/struct +next test: , offset [0-9a-f]*, has type [0-9a-f]*/union +next test: after_the_end, offset [0-9a-f]*, has type [0-9a-f]*/int diff --git a/libctf/testsuite/libctf-lookup/struct-lookup.c b/libctf/testsuite/libctf-lookup/struct-lookup.c new file mode 100644 index 0000000..9b95317 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/struct-lookup.c @@ -0,0 +1,60 @@ +#include <ctf-api.h> +#include <stdio.h> +#include <stdlib.h> + +int +main (int argc, char *argv[]) +{ + ctf_dict_t *fp; + ctf_archive_t *ctf; + ctf_id_t type; + char *type_name; + ctf_membinfo_t mi; + int err; + + 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; + if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL) + goto open_err; + + /* Dig out some strucutre members by name. */ + + if ((type = ctf_lookup_by_name (fp, "struct foo_t") ) == CTF_ERR) + goto err; + + if (ctf_member_info (fp, type, "baz", &mi) < 0) + goto err; + + type_name = ctf_type_aname (fp, mi.ctm_type); + printf ("baz is of type %s, at offset %lx\n", type_name, mi.ctm_offset); + free (type_name); + + if (ctf_member_info (fp, type, "one_more_level", &mi) < 0) + goto err; + + type_name = ctf_type_aname (fp, mi.ctm_type); + printf ("one_more_level is of type %s, at offset %lx\n", type_name, mi.ctm_offset); + free (type_name); + + if (ctf_member_info (fp, type, "should_not_appear", &mi) >= 0 + || ctf_errno (fp) != ECTF_NOMEMBNAM) + fprintf (stderr, "should_not_appear appeared.\n"); + + ctf_dict_close (fp); + ctf_close (ctf); + + return 0; + + open_err: + fprintf (stderr, "%s: cannot open: %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-lookup/struct-lookup.lk b/libctf/testsuite/libctf-lookup/struct-lookup.lk new file mode 100644 index 0000000..b848823 --- /dev/null +++ b/libctf/testsuite/libctf-lookup/struct-lookup.lk @@ -0,0 +1,4 @@ +# source: struct-iteration-ctf.c +# link: on +baz is of type const char \*, at offset [0-9a-z]* +one_more_level is of type double, at offset [0-9a-z]* |