From: Nick Alcock Date: Thu, 24 Apr 2025 17:00:32 +0000 (+0100) Subject: libctf, types: ctf_type_kind_{iter,next} et al X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a632f3ed33636101e0cef0485abe52255841b5c7;p=thirdparty%2Fbinutils-gdb.git libctf, types: ctf_type_kind_{iter,next} et al These new functions let you iterate over types by kind, letting you get all variables, all enums, all datasecs, etc. (This is amenable to future optimization, and some is expected shortly.) We also add new iternal functions ctf_type_kind_{forwarded_,unsliced_,}tp which are like the corresponding non-_tp functions except that they take a ctf_type_t rather than a type ID: doing this allows the deduplicator to use these nearly-public functions more. The public ctf_type_kind* functions are reimplemented in terms of these. This machinery is the principal place where the magic encoding of forwards is encoded. --- diff --git a/include/ctf-api.h b/include/ctf-api.h index ac8965fef06..079c4cf8784 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -310,8 +310,6 @@ _CTF_ERRORS typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset, int depth, void *arg); -typedef int ctf_type_f (ctf_id_t type, void *arg); -typedef int ctf_type_all_f (ctf_id_t type, int flag, void *arg); void *arg); typedef int ctf_member_f (ctf_dict_t *, const char *name, ctf_id_t membtype, size_t offset, int bit_width, void *arg); @@ -321,6 +319,9 @@ typedef int ctf_variable_f (ctf_dict_t *, const char *name, ctf_id_t type, void *arg); typedef int ctf_datasec_var_f (ctf_dict_t *fp, ctf_id_t type, size_t offset, size_t datasec_size, void *arg); +typedef int ctf_type_f (ctf_dict_t *, ctf_id_t type, void *arg); +typedef int ctf_type_all_f (ctf_dict_t *, ctf_id_t type, int flag, void *arg); +typedef int ctf_type_kind_f (ctf_dict_t *, ctf_id_t type, int kind, void *arg); typedef int ctf_archive_member_f (ctf_dict_t *fp, const char *name, void *arg); typedef int ctf_archive_raw_member_f (const char *name, const void *content, size_t len, void *arg); @@ -793,8 +794,10 @@ extern ctf_id_t ctf_arc_lookup_enumerator_next (ctf_archive_t *, const char *nam extern int ctf_type_iter (ctf_dict_t *, ctf_type_f *, void *); extern int ctf_type_iter_all (ctf_dict_t *, ctf_type_all_f *, void *); +extern int ctf_type_kind_iter (ctf_dict_t *, int kind, ctf_type_kind_f *, void *); extern ctf_id_t ctf_type_next (ctf_dict_t *, ctf_next_t **, int *flag, int want_hidden); +extern ctf_id_t ctf_type_kind_next (ctf_dict_t *, ctf_next_t **, int kind); extern int ctf_variable_iter (ctf_dict_t *, ctf_variable_f *, void *); extern ctf_id_t ctf_variable_next (ctf_dict_t *, ctf_next_t **, diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 49f677b0d65..f0422c05970 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -811,6 +811,9 @@ extern char *ctf_str_append_noerr (char *, const char *); extern ctf_id_t ctf_type_resolve_unsliced (ctf_dict_t *, ctf_id_t); extern ctf_id_t ctf_type_resolve_nonrepresentable (ctf_dict_t *, ctf_id_t, int allow_zero); extern int ctf_type_kind_unsliced (ctf_dict_t *, ctf_id_t); +extern int ctf_type_kind_unsliced_tp (ctf_dict_t *, const ctf_type_t *); +extern int ctf_type_kind_tp (ctf_dict_t *, const ctf_type_t *); +extern int ctf_type_kind_forwarded_tp (ctf_dict_t *, const ctf_type_t *); extern ssize_t ctf_type_align_natural (ctf_dict_t *fp, ctf_id_t prev_type, ctf_id_t type, ssize_t bit_offset); extern ctf_var_secinfo_t *ctf_datasec_entry (ctf_dict_t *, ctf_id_t, diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 94ecdbeadf6..bb2d652248c 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -489,8 +489,8 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, return NULL; } -/* Iterate over every root (user-visible) type in the given CTF dict. - We pass the type ID of each type to the specified callback function. +/* Iterate over every root (user-visible) type in the given CTF dict. We pass + the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children @@ -505,7 +505,7 @@ ctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg) while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR) { int rc; - if ((rc = func (type, arg)) != 0) + if ((rc = func (fp, type, arg)) != 0) { ctf_next_destroy (i); return rc; @@ -517,12 +517,12 @@ ctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg) return 0; } -/* Iterate over every type in the given CTF dict, user-visible or not. - We pass the type ID of each type to the specified callback function. +/* Iterate over every type in the given CTF dict, user-visible or not. We pass + the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children - of a single parent. */ + of a single parent. */ int ctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg) @@ -534,7 +534,42 @@ ctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg) while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR) { int rc; - if ((rc = func (type, flag, arg)) != 0) + if ((rc = func (fp, type, flag, arg)) != 0) + { + ctf_next_destroy (i); + return rc; + } + } + if (ctf_errno (fp) != ECTF_NEXT_END) + return -1; /* errno is set for us. */ + + return 0; +} + +/* Iterate over every type of the given kind in the given CTF dict. + We pass the type ID of each type to the specified callback function. + + Types returned may be prefixed (but this is normally invisible): you can also + specifically traverse prefixed types by asking for CTF_K_BIG or CTF_K_HIDDEN. + In this case, the kind of the type returned will be different (the kind + prefixed). Using CTF_K_BIG may have unexpected results if types have been + added to this dict since it was opened, since types are only 'unbiggened' + upon being written out. + + Does not traverse parent types: you have to do that explicitly. This is by + design, to avoid traversing them more than once if traversing many children + of a single parent. */ + +int +ctf_type_kind_iter (ctf_dict_t *fp, int kind, ctf_type_kind_f *func, void *arg) +{ + ctf_next_t *i = NULL; + ctf_id_t type; + + while ((type = ctf_type_kind_next (fp, &i, kind)) != CTF_ERR) + { + int rc; + if ((rc = func (fp, type, kind, arg)) != 0) { ctf_next_destroy (i); return rc; @@ -565,7 +600,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden) return ctf_set_typed_errno (fp, ENOMEM); i->cu.ctn_fp = fp; - i->ctn_type = 1; + i->i.ctn_idx = 1; i->ctn_iter_fun = (void (*) (void)) ctf_type_next; *it = i; } @@ -576,19 +611,78 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden) if (fp != i->cu.ctn_fp) return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); - while (i->ctn_type <= fp->ctf_typemax) + while (i->i.ctn_idx <= fp->ctf_typemax) { - const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type); + const ctf_type_t *tp; + + if (i->i.ctn_idx > fp->ctf_stypes) + tp = ctf_dtd_lookup (fp, ctf_index_to_type (fp, i->i.ctn_idx))->dtd_data; + else + tp = fp->ctf_txlate[i->i.ctn_idx]; if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info))) { - i->ctn_type++; + i->i.ctn_idx++; continue; } if (flag) *flag = LCTF_INFO_ISROOT (fp, tp->ctt_info); - return ctf_index_to_type (fp, i->ctn_type++); + return ctf_index_to_type (fp, i->i.ctn_idx++); + } + ctf_next_destroy (i); + *it = NULL; + return ctf_set_typed_errno (fp, ECTF_NEXT_END); +} + +/* UPTODO optimize this */ + +/* Iterate over every type of a given kind in the given CTF dict, returning each + type ID in turn. Returns CTF_ERR on end of iteration or error. you can also + specifically traverse prefixed types by asking for CTF_K_BIG or CTF_K_HIDDEN. + In this case, the kind of the type returned will be different (the kind + prefixed). Using CTF_K_BIG may have unexpected results if types have been + added to this dict since it was opened, since types are only 'unbiggened' + upon being written out. + + Does not traverse parent types: you have to do that explicitly. This is by + design, to avoid traversing them more than once if traversing many children + of a single parent. */ + +ctf_id_t +ctf_type_kind_next (ctf_dict_t *fp, ctf_next_t **it, int kind) +{ + ctf_next_t *i = *it; + + if (!i) + { + if ((i = ctf_next_create ()) == NULL) + return ctf_set_typed_errno (fp, ENOMEM); + + i->cu.ctn_fp = fp; + i->i.ctn_idx = 1; + i->ctn_iter_fun = (void (*) (void)) ctf_type_kind_next; + *it = i; + } + + if ((void (*) (void)) ctf_type_kind_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)); + + while (i->i.ctn_idx <= fp->ctf_typemax) + { + ctf_id_t type = ctf_index_to_type (fp, i->i.ctn_idx); + + if (ctf_type_kind (i->cu.ctn_fp, type) != kind) + { + i->i.ctn_idx++; + continue; + } + + i->i.ctn_idx++; + return type; } ctf_next_destroy (i); *it = NULL; @@ -1339,17 +1433,84 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type) } } -/* Return the kind (CTF_K_* constant) for the specified type ID. */ +/* Return the kind (CTF_K_* constant) for the specified type pointer. + Internal use only. + + Pretend that all forwards are of type CTF_K_FORWARD, for ease of + use and compatibility. */ + +int +ctf_type_kind_unsliced_tp (ctf_dict_t *fp, const ctf_type_t *tp) +{ + if (LCTF_KIND (fp, tp) == CTF_K_ENUM + && LCTF_VLEN (fp, tp) == 0) + return CTF_K_FORWARD; + + return (LCTF_KIND (fp, tp)); +} + +/* Return the kind (CTF_K_* constant) for the specified type pointer. + Slices are considered to be of the same kind as the type sliced. */ + +int +ctf_type_kind_tp (ctf_dict_t *fp, const ctf_type_t *tp) +{ + int kind; + + if ((kind = ctf_type_kind_unsliced_tp (fp, tp)) < 0) + return -1; /* errno is set for us. */ + + if (kind == CTF_K_SLICE) + { + const ctf_slice_t *sp; + ssize_t increment; + + ctf_get_ctt_size (fp, tp, NULL, &increment); + sp = (const ctf_slice_t *) tp + increment; + + kind = ctf_type_kind_unsliced (fp, sp->cts_type); + } + + return kind; +} + +/* Return the kind of this type pointer, except, for forwards, return the kind + of thing this is a forward to. */ +int +ctf_type_kind_forwarded_tp (ctf_dict_t *fp, const ctf_type_t *tp) +{ + int kind; + + if ((kind = ctf_type_kind_tp (fp, tp)) < 0) + return -1; /* errno is set for us. */ + + /* Covers forwards to enums, too. */ + if (kind != CTF_K_FORWARD) + return kind; + + while (LCTF_IS_PREFIXED_INFO (tp->ctt_info)) + tp++; + + if (CTF_INFO_KFLAG (tp->ctt_info)) + return CTF_K_UNION; + else + return CTF_K_STRUCT; +} + +/* Return the kind (CTF_K_* constant) for the specified type ID. + + Pretend that all forwards are of type CTF_K_FORWARD, for ease of + use and compatibility. */ int ctf_type_kind_unsliced (ctf_dict_t *fp, ctf_id_t type) { const ctf_type_t *tp; - if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) + if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL) return -1; /* errno is set for us. */ - return (LCTF_INFO_KIND (fp, tp->ctt_info)); + return (ctf_type_kind_unsliced_tp (fp, tp)); } /* Return the kind (CTF_K_* constant) for the specified type ID. @@ -1366,7 +1527,7 @@ ctf_type_kind (ctf_dict_t *fp, ctf_id_t type) if (kind == CTF_K_SLICE) { if ((type = ctf_type_reference (fp, type)) == CTF_ERR) - return -1; + return -1; /* errno is set for us. */ kind = ctf_type_kind_unsliced (fp, type); } @@ -1378,19 +1539,17 @@ ctf_type_kind (ctf_dict_t *fp, ctf_id_t type) int ctf_type_kind_forwarded (ctf_dict_t *fp, ctf_id_t type) { - int kind; - const ctf_type_t *tp; + int ret; + ctf_dict_t *ofp = fp; + const ctf_type_t *tp, *suffix; - if ((kind = ctf_type_kind (fp, type)) < 0) + if ((tp = ctf_lookup_by_id (&fp, type, &suffix)) == NULL) return -1; /* errno is set for us. */ - if (kind != CTF_K_FORWARD) - return kind; + if ((ret = ctf_type_kind_forwarded_tp (fp, tp)) < 0) + return (ctf_set_errno (ofp, ctf_errno (fp))); - if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) - return -1; /* errno is set for us. */ - - return tp->ctt_type; + return ret; } /* If the type is one that directly references another type (such as POINTER), diff --git a/libctf/libctf.ver b/libctf/libctf.ver index 421bf40945b..605faa3e0e6 100644 --- a/libctf/libctf.ver +++ b/libctf/libctf.ver @@ -102,6 +102,8 @@ LIBCTF_2.0 { ctf_type_iter; ctf_type_next; ctf_type_iter_all; + ctf_type_kind_iter; + ctf_type_kind_next; ctf_variable_iter; ctf_variable_next; ctf_datasec_iter;