From: Nick Alcock Date: Thu, 24 Apr 2025 13:58:50 +0000 (+0100) Subject: libctf: CTFv4: type opening X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ad13b7d44f7af14e2f41f8b63549737e0612453f;p=thirdparty%2Fbinutils-gdb.git libctf: CTFv4: type opening The majority of this commit rejigs the core type table opening code for CTFv4: there are a few ancillary bits it drags in, indicated below. The internal definition of a child dict (that may not have type or string lookups performed in it until ctf_open time) used to be 'has a cth_parent_name', but since BTF doesn't have one of those at all, we add an additional check: a dict the first byte of whose strtab is not 0 must be a child. (If *either* is true, this is a child dict, which allows for the possibility of CTF dicts with non-deduplicated strtabs -- thus with leading \0's -- to exist in future.) The initial sweep through the type table in init_static_types (to size the name-table lookup hashes) also now checks for various types which indicate that this must be a CTF dict, in addition to being adjusted to cater for new CTFv4 representations of things like forwards. (At this early stage, we cannot rely on the functions in ctf-type.c to abstract over this for us.) We make some new hashtables for new namespace-like things: datasecs and type and decl tags. The main name-population loop in init_static_types_names_internal takes prefixes into account, looking for the name on the suffix type (where the name is always found). LSTRUCT handling is removed (they no longer exist); ENUM64s, enum forwards, VARs, datasecs, and type and decl tags get their names suitably populated. Some buggy code which tried to populate the name tables for cvr-quals (which are nameless) was dropped. We add an extra pass which traverses all datasecs and keeps track of which datasec each var is instantiated in (if any) in a new ctf_var_datasecs hash table. (This uses a number of type-querying functions which don't yet exist: they'll be added in the upcoming commits.) We handle the type 0 == void case by pointing the first element of ctf_txlate at a type read in named "void" (making type 0 an alias to it), or, if one doesn't exist, creating a new one (outside the type table and dtd arrays), and pointing type 0 at that. Since it is numbered 0 and not in the type table or dtd arrays, it will never be written out at serialization time, but since it is *present*, libctf consumers who expect the void type to have an integral definition rather than being a magic number will get what they expect. --- diff --git a/include/ctf-api.h b/include/ctf-api.h index 5ca8e76231f..a771de234f9 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -541,9 +541,10 @@ extern ctf_id_t ctf_lookup_by_symbol_name (ctf_dict_t *, const char *); extern ctf_id_t ctf_symbol_next (ctf_dict_t *, ctf_next_t **, const char **name, int functions); -/* Look up a type by name: some simple C type parsing is done, but this is by no - means comprehensive. Structures, unions and enums need "struct ", "union " - or "enum " on the front, as usual in C. */ +/* Look up a type or variable by name: some simple C type parsing is done, but + this is by no means comprehensive. Structures, unions and enums need "struct + ", "union " or "enum " on the front, as usual in C. Some prefixes not seen + in C exist as well: datasecs use "datasec ". */ extern ctf_id_t ctf_lookup_by_name (ctf_dict_t *, const char *); diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 3262c4e6790..f58df00fb01 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -106,14 +106,21 @@ ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen) ctf_dict_t * ctf_create (int *errp) { - static const ctf_header_t hdr = { .cth_preamble = { CTF_MAGIC, CTF_VERSION, 0 } }; + static ctf_header_t hdr = + { + .btf.bth_preamble = { CTF_BTF_MAGIC, CTF_BTF_VERSION, 0 }, + .btf.bth_hdr_len = sizeof (ctf_btf_header_t), + }; ctf_dynhash_t *structs = NULL, *unions = NULL, *enums = NULL, *names = NULL; + ctf_dynhash_t *datasecs = NULL, *tags = NULL; ctf_sect_t cts; ctf_dict_t *fp; libctf_init_debug(); + hdr.cth_preamble.ctp_magic_version = (CTFv4_MAGIC << 16) | CTF_VERSION; + structs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, NULL, NULL); unions = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, @@ -122,7 +129,11 @@ ctf_create (int *errp) NULL, NULL); names = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, NULL, NULL); - if (!structs || !unions || !enums || !names) + datasecs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, NULL); + tags = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, + NULL, (ctf_hash_free_fun) ctf_dynset_destroy); + if (!structs || !unions || !enums || !names || !datasecs || !tags) { ctf_set_open_errno (errp, EAGAIN); goto err; @@ -142,10 +153,14 @@ ctf_create (int *errp) ctf_dynhash_destroy (fp->ctf_unions); ctf_dynhash_destroy (fp->ctf_enums); ctf_dynhash_destroy (fp->ctf_names); + ctf_dynhash_destroy (fp->ctf_datasecs); + ctf_dynhash_destroy (fp->ctf_tags); fp->ctf_structs = structs; fp->ctf_unions = unions; fp->ctf_enums = enums; fp->ctf_names = names; + fp->ctf_datasecs = datasecs; + fp->ctf_tags = tags; fp->ctf_dtoldid = 0; fp->ctf_snapshot_lu = 0; @@ -166,6 +181,8 @@ ctf_create (int *errp) ctf_dynhash_destroy (unions); ctf_dynhash_destroy (enums); ctf_dynhash_destroy (names); + ctf_dynhash_destroy (datasecs); + ctf_dynhash_destroy (tags); return NULL; } diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c index 89f2c1472ee..7cde73f7816 100644 --- a/libctf/ctf-hash.c +++ b/libctf/ctf-hash.c @@ -779,6 +779,12 @@ ctf_dynset_destroy (ctf_dynset_t *hp) htab_delete ((struct htab *) hp); } +void +ctf_dynset_destroy_arg (ctf_dynset_t *hp, void *unused _libctf_unused_) +{ + ctf_dynset_destroy (hp); +} + void * ctf_dynset_lookup (ctf_dynset_t *hp, const void *key) { diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index a7ce6c80df0..5bbfdf68d7d 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -385,9 +385,12 @@ struct ctf_dict ctf_dynhash_t *ctf_structs; /* Hash table of struct types. */ ctf_dynhash_t *ctf_unions; /* Hash table of union types. */ ctf_dynhash_t *ctf_enums; /* Hash table of enum types. */ + ctf_dynhash_t *ctf_datasecs; /* Hash table of datasecs. */ + ctf_dynhash_t *ctf_tags; /* Hash table of dynsets of type/decl tags. */ ctf_dynhash_t *ctf_names; /* Hash table of remaining types, plus enumeration constants. */ - ctf_lookup_t ctf_lookups[5]; /* Pointers to nametabs for name lookup. */ + ctf_lookup_t ctf_lookups[6]; /* Pointers to nametabs for name lookup. */ + ctf_dynhash_t *ctf_var_datasecs; /* Variable -> datasec mappings. */ ctf_strs_t ctf_str[2]; /* Array of string table base and bounds. */ ctf_strs_writable_t *ctf_dynstrtab; /* Dynamically allocated string table, if any. */ ctf_dynhash_t *ctf_str_atoms; /* Hash table of ctf_str_atoms_t. */ @@ -412,6 +415,8 @@ struct ctf_dict uint32_t *ctf_pptrtab; /* Parent types pointed to by child dicts. */ size_t ctf_pptrtab_len; /* Num types storable in pptrtab currently. */ uint32_t ctf_pptrtab_typemax; /* Max child type when pptrtab last updated. */ + ctf_type_t *ctf_void_type; /* void type, if dynamically constructed. (More + space allocated, due to vlen.) */ ctf_dynset_t *ctf_conflicting_enums; /* Tracks enum constants that conflict. */ uint32_t *ctf_funcidx_names; /* Name of each function symbol in symtypetab (if indexed). */ @@ -707,6 +712,7 @@ extern int ctf_dynset_insert (ctf_dynset_t *, void *); extern void ctf_dynset_remove (ctf_dynset_t *, const void *); extern size_t ctf_dynset_elements (const ctf_dynset_t *); extern void ctf_dynset_destroy (ctf_dynset_t *); +extern void ctf_dynset_destroy_arg (ctf_dynset_t *, void *unused); extern void *ctf_dynset_lookup (ctf_dynset_t *, const void *); extern int ctf_dynset_exists (ctf_dynset_t *, const void *key, const void **orig_key); diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 8ba65b9bae9..78bc8bb5bfb 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -560,7 +560,7 @@ ctf_set_base (ctf_dict_t *fp, const ctf_header_t *hp, unsigned char *base) } static int -init_static_types_names (ctf_dict_t *fp, ctf_header_t *cth); +init_static_types_names (ctf_dict_t *fp, ctf_header_t *cth, int is_btf); /* Populate statically-defined types (those loaded from a saved buffer). @@ -591,50 +591,105 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) fp->ctf_provtypemax = (uint32_t) -1; /* We determine whether the dict is a child or a parent based on the value of - cth_parname. */ + cth_parent_name: for BTF this is not enough, because there is no + cth_parent_name: instead, we can check the first byte of the strtab, which + is always 0 for parents and never 0 for children. */ - int child = cth->cth_parname != 0; + int child = (cth->cth_parent_name != 0 + || (fp->ctf_str[CTF_STRTAB_0].cts_len > 0 + && fp->ctf_str[CTF_STRTAB_0].cts_strs[0] != 0)); if (fp->ctf_version < CTF_VERSION_4) { +#if 0 int err; + if ((err = upgrade_types (fp, cth)) != 0) return err; /* Upgrade failed. */ +#endif + ctf_err_warn (NULL, 0, ECTF_INTERNAL, "Implementation of backward-compatible CTF reading still underway\n"); + return ECTF_INTERNAL; } - tbuf = (ctf_type_t *) (fp->ctf_buf + cth->cth_typeoff); - tend = (ctf_type_t *) (fp->ctf_buf + cth->cth_stroff); + tbuf = (ctf_type_t *) (fp->ctf_buf + cth->btf.bth_type_off); + tend = (ctf_type_t *) ((uintptr_t) tbuf + cth->btf.bth_type_len); - /* We make two passes through the entire type section, and one third pass - through part of it: but only the first is guaranteed to happen at this - stage. The second and third passes require working string lookup, so in - child dicts can only happen at ctf_import time. + /* We make two passes through the entire type section, and more passes through + parts of it: but only the first is guaranteed to happen at this stage. The + later passes require working string lookup, so in child dicts can only + happen at ctf_import time. + + For prefixed kinds, we are interested in the thing we are prefixing: + that is the true type. In this first pass, we count the number of each type and type-like identifier (like enumerators) and the total number of types. */ for (tp = tbuf; tp < tend; typemax++) { - unsigned short kind = LCTF_INFO_KIND (fp, tp->ctt_info); - unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); + unsigned short kind = LCTF_INFO_UNPREFIXED_KIND (fp, tp->ctt_info); + size_t vlen = LCTF_VLEN (fp, tp); + int nonroot = 0; ssize_t size, increment, vbytes; + const ctf_type_t *suffix = tp; (void) ctf_get_ctt_size (fp, tp, &size, &increment); - vbytes = LCTF_VBYTES (fp, kind, size, vlen); + + /* Go to the first unprefixed type, incrementing all prefixed types' + popcounts along the way. If we find a CTF_K_CONFLICTING, stop: these + counts are used to increment identifier hashtab sizes, and conflicting + types do not appear in identifier hashtabs. */ + + while (LCTF_IS_PREFIXED_KIND (kind)) + { + if (is_btf) + return ECTF_CORRUPT; + + pop[suffix->ctt_type]++; + + if (kind == CTF_K_CONFLICTING) + { + nonroot = 1; + break; + } + + suffix++; + if (suffix >= tend) + return ECTF_CORRUPT; + + kind = LCTF_INFO_UNPREFIXED_KIND (fp, suffix->ctt_info); + } + + if (is_btf && kind > CTF_BTF_K_MAX) + return ECTF_CORRUPT; + + vbytes = LCTF_VBYTES (fp, suffix, size); if (vbytes < 0) return ECTF_CORRUPT; - /* For forward declarations, ctt_type is the CTF_K_* kind for the tag, - so bump that population count too. */ - if (kind == CTF_K_FORWARD) - pop[tp->ctt_type]++; + if (!nonroot) + { + /* For forward declarations, the kflag indicates what type to use, so bump + that population count too. For enums, vlen 0 indicates a forward, so + bump the forward population count. */ + if (kind == CTF_K_FORWARD) + { + if (CTF_INFO_KFLAG (suffix->ctt_info)) + pop[CTF_K_UNION]++; + else + pop[CTF_K_STRUCT]++; + } + else if (kind == CTF_K_ENUM && vlen == 0) + pop[CTF_K_FORWARD]++; - tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes); - pop[kind]++; + if (kind == CTF_K_ENUM || kind == CTF_K_ENUM64) + pop_enumerators += vlen; + + pop[kind]++; + } - if (kind == CTF_K_ENUM) - pop_enumerators += vlen; + tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes); } if (child) @@ -666,11 +721,24 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) NULL, NULL, NULL)) == NULL) return ENOMEM; + if ((fp->ctf_datasecs + = ctf_dynhash_create_sized (pop[CTF_K_DATASEC], ctf_hash_string, + ctf_hash_eq_string, + NULL, NULL, NULL)) == NULL) + return ENOMEM; + + if ((fp->ctf_tags + = ctf_dynhash_create_sized (pop[CTF_K_DECL_TAG] + pop [CTF_K_TYPE_TAG], + ctf_hash_string, ctf_hash_eq_string, + NULL, (ctf_hash_free_arg_fun) ctf_dynset_destroy_arg, + NULL)) == NULL) + return ENOMEM; + if ((fp->ctf_names = ctf_dynhash_create_sized (pop[CTF_K_UNKNOWN] + pop[CTF_K_INTEGER] + pop[CTF_K_FLOAT] + - pop[CTF_K_FUNCTION] + + pop[CTF_K_FUNC_LINKAGE] + pop[CTF_K_TYPEDEF] + pop_enumerators, ctf_hash_string, @@ -678,6 +746,11 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) NULL, NULL, NULL)) == NULL) return ENOMEM; + if ((fp->ctf_var_datasecs + = ctf_dynhash_create (htab_hash_pointer, htab_eq_pointer, NULL, NULL)) + == NULL) + return ENOMEM; + if ((fp->ctf_conflicting_enums = ctf_dynset_create (htab_hash_string, htab_eq_string, NULL)) == NULL) return ENOMEM; @@ -698,9 +771,7 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL) return ENOMEM; /* Memory allocation failed. */ - /* UPTODO: BTF is like v4 here: no string lookups in children, which blocks - almost all operations until after ctf_import. */ - if (child && cth->cth_parent_strlen != 0) + if (child || cth->cth_parent_strlen != 0) { fp->ctf_flags |= LCTF_NO_STR; return 0; @@ -708,17 +779,17 @@ init_static_types (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) ctf_dprintf ("%u types initialized (other than names)\n", fp->ctf_typemax); - return init_static_types_names (fp, cth); + return init_static_types_names (fp, cth, is_btf); } static int -init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, +init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, int is_btf, ctf_dynset_t *all_enums); /* A wrapper to simplify memory allocation. */ static int -init_static_types_names (ctf_dict_t *fp, ctf_header_t *cth) +init_static_types_names (ctf_dict_t *fp, ctf_header_t *cth, int is_btf) { ctf_dynset_t *all_enums; int err; @@ -727,41 +798,43 @@ init_static_types_names (ctf_dict_t *fp, ctf_header_t *cth) NULL)) == NULL) return ENOMEM; - err = init_static_types_names_internal (fp, cth, all_enums); + err = init_static_types_names_internal (fp, cth, is_btf, all_enums); ctf_dynset_destroy (all_enums); return err; } -/* Initialize the parts of the CTF dict whose initialization depends on name - lookup. This happens at open time except for child dicts, when (for CTFv4+ - dicts) it happens at ctf_import time instead, because before then the strtab - is truncated at the start. +static int +init_void (ctf_dict_t *fp); + +/* Initialize the parts of the CTF dict whose initialization depends on name or + type lookup. This happens at open time except for child dicts, when (for + CTFv4+ dicts) it happens at ctf_import time instead, because before then the + strtab and type tables are truncated at the start. As a function largely called at open time, this function does not reliably - set the ctf_errno, but instead *returns* the error code. */ + set the ctf_errno, but instead returns a positive error code. */ static int -init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, +init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, int is_btf, ctf_dynset_t *all_enums) { - const ctf_type_t *tbuf; - const ctf_type_t *tend; + ctf_type_t *tbuf, *tend, *tp; + ctf_type_t **xp; - const ctf_type_t *tp; uint32_t id; - uint32_t *xp; - - unsigned long typemax = fp->ctf_typemax; + ctf_id_t type; ctf_next_t *i = NULL; void *k; int err; - int child = cth->cth_parname != 0; - int nlstructs = 0, nlunions = 0; + /* See init_static_types. */ + int child = (cth->cth_parent_name != 0 + || (fp->ctf_str[CTF_STRTAB_0].cts_len > 0 + && fp->ctf_str[CTF_STRTAB_0].cts_strs[0] != 0)); - tbuf = (ctf_type_t *) (fp->ctf_buf + cth->cth_typeoff); - tend = (ctf_type_t *) (fp->ctf_buf + cth->cth_stroff); + tbuf = (ctf_type_t *) (fp->ctf_buf + cth->btf.bth_type_off); + tend = (ctf_type_t *) ((uintptr_t) tbuf + cth->btf.bth_type_len); assert (!(fp->ctf_flags & LCTF_NO_STR)); @@ -770,30 +843,34 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, /* In this second pass through the types, we fill in each entry of the type and pointer tables and add names to the appropriate hashes. - (Not all names are added in this pass, only type names. See below.) + (Not all names are added in this pass, only type names. See below.) */ - Reset ctf_typemax and bump it as we go, but keep it one higher than normal, - so that the type being read in is considered a valid type and it is at - least barely possible to run simple lookups on it: but higher types are - not, since their names are not yet known. (It is kept at its standard - value before this function is called so that at least some type-related - operations work. */ - - for (id = 1, fp->ctf_typemax = 1, tp = tbuf; tp < tend; xp++, id++, fp->ctf_typemax++) + for (id = 1, tp = tbuf; tp < tend; xp++, id++) { - unsigned short kind = LCTF_INFO_KIND (fp, tp->ctt_info); + unsigned short kind = LCTF_KIND (fp, tp); unsigned short isroot = LCTF_INFO_ISROOT (fp, tp->ctt_info); - unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); + size_t vlen = LCTF_VLEN (fp, tp); ssize_t size, increment, vbytes; - + const ctf_type_t *suffix = tp; const char *name; + /* Prefixed type: pull off the prefixes (for most purposes). (We already + know the prefixes cannot overflow.) */ + + while (LCTF_IS_PREFIXED_INFO (suffix->ctt_info)) + { + if (is_btf) + return ECTF_CORRUPT; + + suffix++; + } + (void) ctf_get_ctt_size (fp, tp, &size, &increment); - name = ctf_strptr (fp, tp->ctt_name); - /* Cannot fail: shielded by call in loop above. */ - vbytes = LCTF_VBYTES (fp, kind, size, vlen); + name = ctf_strptr (fp, suffix->ctt_name); + /* Cannot fail: shielded by call in init_static_types. */ + vbytes = LCTF_VBYTES (fp, suffix, size); - *xp = (uint32_t) ((uintptr_t) tp - (uintptr_t) fp->ctf_buf); + *xp = tp; switch (kind) { @@ -817,7 +894,10 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, type as long as the new type is zero-offset and has a bit-width wider than the existing one, since the native type must necessarily have a bit-width at least as wide as any - bitfield based on it. */ + bitfield based on it. + + BTF floats are more or less useless, having no encoding: + the ctf_type_encoding check here suffices to replace them. */ if (((existing = ctf_dynhash_lookup_type (fp->ctf_names, name)) == 0) || ctf_type_encoding (fp, existing, &existing_en) != 0 @@ -828,40 +908,62 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, { err = ctf_dynhash_insert_type (fp, fp->ctf_names, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; } break; } + case CTF_K_BTF_FLOAT: + { + ctf_id_t existing; + + if (!isroot) + break; + + /* Don't allow a float to be overwritten by a BTF float. */ + + if (((existing = ctf_dynhash_lookup_type (fp->ctf_names, name)) == 0) + && ctf_type_kind (fp, existing) == CTF_K_FLOAT) + break; + + err = ctf_dynhash_insert_type (fp, fp->ctf_names, + ctf_index_to_type (fp, id), + suffix->ctt_name); + if (err != 0) + return err * -1; + break; + } + /* These kinds have no name, so do not need interning into any hashtables. */ case CTF_K_ARRAY: case CTF_K_SLICE: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + case CTF_K_FUNCTION: break; - case CTF_K_FUNCTION: + case CTF_K_FUNC_LINKAGE: if (!isroot) break; err = ctf_dynhash_insert_type (fp, fp->ctf_names, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; break; case CTF_K_STRUCT: - if (size >= CTF_LSTRUCT_THRESH) - nlstructs++; - if (!isroot) break; err = ctf_dynhash_insert_type (fp, fp->ctf_structs, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; @@ -869,38 +971,45 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, break; case CTF_K_UNION: - if (size >= CTF_LSTRUCT_THRESH) - nlunions++; - if (!isroot) break; err = ctf_dynhash_insert_type (fp, fp->ctf_unions, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; break; case CTF_K_ENUM: + case CTF_K_ENUM64: { if (!isroot) break; + /* Only insert forward types if the type is not already present. */ + if (vlen == 0 + && ctf_dynhash_lookup_type (ctf_name_table (fp, kind), + name) != 0) + break; + err = ctf_dynhash_insert_type (fp, fp->ctf_enums, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; - /* Remember all enums for later rescanning. */ + /* Remember all non-forward enums for later rescanning. */ - err = ctf_dynset_insert (all_enums, (void *) (ptrdiff_t) - ctf_index_to_type (fp, id)); - if (err != 0) - return err * -1; + if (vlen != 0) + { + err = ctf_dynset_insert (all_enums, (void *) (ptrdiff_t) + ctf_index_to_type (fp, id)); + if (err != 0) + return err * -1; + } break; } @@ -910,14 +1019,56 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, err = ctf_dynhash_insert_type (fp, fp->ctf_names, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; break; + case CTF_K_VAR: + if (!isroot) + break; + + err = ctf_dynhash_insert_type (fp, fp->ctf_names, + ctf_index_to_type (fp, id), + suffix->ctt_name); + if (err != 0) + return err * -1; + break; + + case CTF_K_DATASEC: + if (!isroot) + break; + + err = ctf_dynhash_insert_type (fp, fp->ctf_datasecs, + ctf_index_to_type (fp, id), + suffix->ctt_name); + if (err != 0) + return err * -1; + + break; + + case CTF_K_DECL_TAG: + case CTF_K_TYPE_TAG: + { + const char *str; + + if ((str = ctf_strptr_validate (fp, suffix->ctt_name)) == NULL) + return ctf_errno (fp); + + if (!isroot) + break; + + if (ctf_insert_type_decl_tag (fp, id, name, kind) < 0) + return ctf_errno (fp); + + break; + } + case CTF_K_FORWARD: { - ctf_dynhash_t *h = ctf_name_table (fp, tp->ctt_type); + int kflag = CTF_INFO_KFLAG (tp->ctt_info); + ctf_dynhash_t *h = ctf_name_table (fp, kflag == 1 + ? CTF_K_UNION : CTF_K_STRUCT); if (!isroot) break; @@ -927,7 +1078,7 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, if (ctf_dynhash_lookup_type (h, name) == 0) { err = ctf_dynhash_insert_type (fp, h, ctf_index_to_type (fp, id), - tp->ctt_name); + suffix->ctt_name); if (err != 0) return err * -1; } @@ -939,22 +1090,12 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, store the index of the pointer type in fp->ctf_ptrtab[ index of referenced type ]. */ - if (ctf_type_ischild (fp, tp->ctt_type) == child - && ctf_type_to_index (fp, tp->ctt_type) <= fp->ctf_typemax) - fp->ctf_ptrtab[ctf_type_to_index (fp, tp->ctt_type)] = id; - /*FALLTHRU*/ - - case CTF_K_VOLATILE: - case CTF_K_CONST: - case CTF_K_RESTRICT: - if (!isroot) - break; + if (ctf_type_ischild (fp, suffix->ctt_type) == child + && ctf_type_to_index (fp, suffix->ctt_type) <= fp->ctf_typemax) + fp->ctf_ptrtab[ctf_type_to_index (fp, suffix->ctt_type)] = id; - err = ctf_dynhash_insert_type (fp, fp->ctf_names, - ctf_index_to_type (fp, id), 0); - if (err != 0) - return err * -1; break; + default: ctf_err_warn (fp, 0, ECTF_CORRUPT, _("init_static_types(): unhandled CTF kind: %x"), kind); @@ -962,10 +1103,12 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, } tp = (ctf_type_t *) ((uintptr_t) tp + increment + vbytes); } - fp->ctf_typemax--; - assert (fp->ctf_typemax == typemax); + assert (fp->ctf_typemax == id - 1); - ctf_dprintf ("%u total types processed\n", fp->ctf_typemax); + ctf_dprintf ("%u total types processed\n", id - 1); + + if ((err = init_void (fp) < 0)) + return err; /* In the third pass, we traverse the enums we spotted earlier and track all the enumeration constants to aid in future detection of duplicates. @@ -974,6 +1117,9 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, enum appears with a constant FOO, then later a type named FOO appears, too late to spot the conflict by checking the enum's constants. */ + ctf_dprintf ("Extracting enumeration constants from %zu enums\n", + ctf_dynset_elements (all_enums)); + while ((err = ctf_dynset_next (all_enums, &i, &k)) == 0) { ctf_id_t enum_id = (uintptr_t) k; @@ -998,20 +1144,94 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth, if (err != ECTF_NEXT_END) return err; + /* In the final pass, we traverse all datasecs and remember the variables in + each, so we can rapidly map from variable back to datasec. */ + + ctf_dprintf ("Getting variable datasec membership\n"); + + while ((type = ctf_type_kind_next (fp, &i, CTF_K_DATASEC)) != CTF_ERR) + { + ctf_next_t *i_sec = NULL; + ctf_id_t var_type; + + while ((var_type = ctf_datasec_var_next (fp, type, &i_sec, NULL, NULL)) + != CTF_ERR) + { + err = ctf_dynhash_insert (fp->ctf_var_datasecs, + (void *) (ptrdiff_t) var_type, + (void *) (ptrdiff_t) type); + if (err != 0) + return err * -1; + } + if (ctf_errno (fp) != ECTF_NEXT_END) + { + ctf_next_destroy (i); + return ctf_errno (fp); + } + } + if (ctf_errno (fp) != ECTF_NEXT_END) + return ctf_errno (fp); + ctf_dprintf ("%zu enum names hashed\n", ctf_dynhash_elements (fp->ctf_enums)); ctf_dprintf ("%zu conflicting enumerators identified\n", ctf_dynset_elements (fp->ctf_conflicting_enums)); - ctf_dprintf ("%zu struct names hashed (%d long)\n", - ctf_dynhash_elements (fp->ctf_structs), nlstructs); - ctf_dprintf ("%zu union names hashed (%d long)\n", - ctf_dynhash_elements (fp->ctf_unions), nlunions); + ctf_dprintf ("%zu struct names hashed\n", + ctf_dynhash_elements (fp->ctf_structs)); + ctf_dprintf ("%zu union names hashed\n", + ctf_dynhash_elements (fp->ctf_unions)); ctf_dprintf ("%zu base type names and identifiers hashed\n", ctf_dynhash_elements (fp->ctf_names)); return 0; } +/* Prepare the void type. If present, index 0 is pointed at it: otherwise, we + make one in the ctf_void_type member and point index 0 at that. Because this + is index 0, it is not written out by serialization (which always starts at + index 1): because it is type 0, it is the type expected by BTF consumers: + because it is a real, queryable type, CTF consumers will get a proper type + back that they can query the properties of. + + As an initialization function, this returns a positive error code, or + zero. */ + +static int +init_void (ctf_dict_t *fp) +{ + ctf_id_t void_type; + ctf_type_t *void_tp; + + void_type = ctf_dynhash_lookup_type (ctf_name_table (fp, CTF_K_INTEGER), "void"); + + if (void_type == 0) + { + uint32_t *vlen; + + if ((void_tp = calloc (1, sizeof (ctf_type_t) + sizeof (uint32_t))) == NULL) + return ENOMEM; + vlen = (uint32_t *) (void_tp + 1); + + void_tp->ctt_name = ctf_str_add (fp, "void"); + void_tp->ctt_info = CTF_TYPE_INFO (CTF_K_INTEGER, 0, 0); + void_tp->ctt_size = 4; /* (bytes) */ + *vlen = CTF_INT_DATA (CTF_INT_SIGNED, 0, 0); + + fp->ctf_void_type = void_tp; + } + else + { + ctf_dict_t *tmp = fp; + + void_tp = (ctf_type_t *) ctf_lookup_by_id (&tmp, void_type, NULL); + assert (void_tp != NULL); + } + + fp->ctf_txlate[0] = void_tp; + + return 0; +} + /* Endianness-flipping routines. We flip everything, mindlessly, even 1-byte entities, so that future @@ -1371,12 +1591,15 @@ void ctf_set_ctl_hashes (ctf_dict_t *fp) fp->ctf_lookups[2].ctl_prefix = "enum"; fp->ctf_lookups[2].ctl_len = strlen (fp->ctf_lookups[2].ctl_prefix); fp->ctf_lookups[2].ctl_hash = fp->ctf_enums; - fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; + fp->ctf_lookups[3].ctl_prefix = "datasec"; fp->ctf_lookups[3].ctl_len = strlen (fp->ctf_lookups[3].ctl_prefix); - fp->ctf_lookups[3].ctl_hash = fp->ctf_names; - fp->ctf_lookups[4].ctl_prefix = NULL; - fp->ctf_lookups[4].ctl_len = 0; - fp->ctf_lookups[4].ctl_hash = NULL; + fp->ctf_lookups[3].ctl_hash = fp->ctf_datasecs; + fp->ctf_lookups[4].ctl_prefix = _CTF_NULLSTR; + fp->ctf_lookups[4].ctl_len = strlen (fp->ctf_lookups[4].ctl_prefix); + fp->ctf_lookups[4].ctl_hash = fp->ctf_names; + fp->ctf_lookups[5].ctl_prefix = NULL; + fp->ctf_lookups[5].ctl_len = 0; + fp->ctf_lookups[5].ctl_hash = NULL; } /* Open a CTF file, mocking up a suitable ctf_sect. */ @@ -2149,6 +2372,8 @@ ctf_dict_close (ctf_dict_t *fp) ctf_dynhash_destroy (fp->ctf_structs); ctf_dynhash_destroy (fp->ctf_unions); ctf_dynhash_destroy (fp->ctf_enums); + ctf_dynhash_destroy (fp->ctf_datasecs); + ctf_dynhash_destroy (fp->ctf_tags); ctf_dynhash_destroy (fp->ctf_names); for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd) @@ -2157,6 +2382,7 @@ ctf_dict_close (ctf_dict_t *fp) ctf_dvd_delete (fp, dvd); } ctf_dynhash_destroy (fp->ctf_dvhash); + ctf_dynhash_destroy (fp->ctf_var_datasecs); ctf_dynhash_destroy (fp->ctf_symhash_func); ctf_dynhash_destroy (fp->ctf_symhash_objt); @@ -2217,6 +2443,7 @@ ctf_dict_close (ctf_dict_t *fp) free (err); } + free (fp->ctf_void_type); free (fp->ctf_sxlate); free (fp->ctf_txlate); free (fp->ctf_ptrtab); @@ -2439,7 +2666,8 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed) fp->ctf_flags |= LCTF_CHILD; fp->ctf_flags &= ~LCTF_NO_STR; - if (no_strings && (err = init_static_types_names (fp, fp->ctf_header)) < 0) + if (no_strings && (err = init_static_types_names (fp, fp->ctf_header, + fp->ctf_opened_btf) < 0)) { /* Undo everything other than cache flushing. */