From: Nick Alcock Date: Fri, 25 Apr 2025 16:59:31 +0000 (+0100) Subject: libctf: open, types: ctf_import for BTF X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=908a7e71671ea2ecafed060866d9fd6a665a79a2;p=thirdparty%2Fbinutils-gdb.git libctf: open, types: ctf_import for BTF ctf_import needs a bunch of fixes to work with pure BTF dicts -- and, for that matter, importing newly-created parent dicts that have never been written out, which may have a bunch of nonprovisional types (if types were added to it before any imports were done) or may not (if at least one ctf_import into it was done before any types were added). So we adjust things so that the values that are checked against are the nonprovisional-types values: the header revisions actually changed the name of cth_parent_typemax to cth_parent_ntypes to make this clearer, so catch up with that. In the parent, we have to use ctf_idmax, not ctf_typemax. One thing we must prohibit is that you cannot add a bunch of types to a child and then import a parent into it: the type IDs will all be wrong and the string offsets more so. This was partly prohibited: prohibit it entirely (excepting only that the not-actually-written-out void type we might add to new BTF dicts does not influence this check). Since BTF children don't have a cth_parent_ntypes or a cth_parent_strlen, we cannot check this stuff, but just set them and hope. --- diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 6cf525b9659..b58c0c4030c 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -2641,20 +2641,30 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed) number of types. (Provisional types excepted: they go at the top of the type ID space, and will not overlap any child types.) */ - if (pfp->ctf_idmax != fp->ctf_header->cth_parent_typemax) + if (pfp->ctf_idmax != fp->ctf_header->cth_parent_ntypes) { - if (fp->ctf_header->cth_parent_typemax != 0) + if (fp->ctf_header->cth_parent_ntypes != 0) { ctf_err_warn (fp, 0, ECTF_WRONGPARENT, _("ctf_import: incorrect parent dict: %u types expected, %u found"), - fp->ctf_header->cth_parent_typemax, pfp->ctf_idmax); + fp->ctf_header->cth_parent_ntypes, pfp->ctf_idmax); return (ctf_set_errno (fp, ECTF_WRONGPARENT)); } - else if (fp->ctf_header->cth_parent_typemax == 0) + else if (fp->ctf_opened_btf) + { + /* A pure BTF dict does not track the number of types in the parent: + just update and hope. */ + + fp->ctf_header->cth_parent_ntypes = pfp->ctf_idmax; + } + else if (fp->ctf_header->cth_parent_ntypes == 0) { /* If we are importing into a parent dict, the child dict had better be empty. Set its starting type ID, which need not be zero: the - parent can already have types. */ + parent can already have types. We assign typemax rather than + idmax because when this is a new dict we want the types to count + up from the number of types currently in the parent, not the number + in the parent when it was opened. */ if (fp->ctf_typemax != 0) { @@ -2663,17 +2673,23 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed) fp->ctf_typemax); return (ctf_set_errno (fp, EINVAL)); } - fp->ctf_header->cth_parent_typemax = pfp->ctf_typemax; + fp->ctf_header->cth_parent_ntypes = pfp->ctf_typemax; } } - /* We might in time be able to lift this restriction, but it is unlikely to be - something anyone would want to do, so let's not bother for now. */ + /* No importing dicts with provisional strings in (except for the void one + added to all new dicts). We might in time be able to lift this + restriction, but it is unlikely to be something anyone would want to do, so + let's not bother for now. If we have a system-created void type, it might + have instantiated a new string. */ - if (ctf_dynhash_elements (fp->ctf_prov_strtab) != 0) + if ((fp->ctf_void_type == NULL + && ctf_dynhash_elements (fp->ctf_prov_strtab) != 0) + || (fp->ctf_void_type != NULL + && ctf_dynhash_elements (fp->ctf_prov_strtab) > 1)) { ctf_err_warn (fp, 0, EINVAL, - _("ctf_import: child dict already has %zi bytes of strings, cannot import"), + _("ctf_import: child dict already has %zi strings, cannot import"), ctf_dynhash_elements (fp->ctf_prov_strtab)); return (ctf_set_errno (fp, EINVAL)); } @@ -2694,8 +2710,16 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed) fp->ctf_parent_unreffed = unreffed; fp->ctf_parent = pfp; + /* BTF dicts don't have any parent strlen in the header, but we need to know + it to dereference strings. */ + + if (fp->ctf_opened_btf) + fp->ctf_header->cth_parent_strlen = pfp->ctf_str[CTF_STRTAB_0].cts_len; + /* If this is a dict that hasn't previously allowed string lookups, - we can allow them now, and finish initialization. */ + we can allow them now, and finish initialization. (This requires us to + figure out whether the buffer contains pure BTF or not: we can do that by + checking the CTF-specific magic number in the header we read in.) */ fp->ctf_flags |= LCTF_CHILD; fp->ctf_flags &= ~LCTF_NO_STR; diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 4ff32c2f847..19d63bf6172 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -40,7 +40,7 @@ ctf_type_isparent (const ctf_dict_t *fp, ctf_id_t id) have been added. Simple range check. */ if (!fp->ctf_parent) - return (fp->ctf_header->cth_parent_typemax >= id); + return (fp->ctf_header->cth_parent_ntypes >= id); /* Types in the parent's idmax range (which encompasses its stypes range) are in the parent. */ @@ -76,16 +76,16 @@ ctf_type_to_index_internal (const ctf_dict_t *fp, ctf_id_t type) { uint32_t idx = type; - assert (((fp->ctf_flags & LCTF_CHILD) && (type > fp->ctf_header->cth_parent_typemax)) || + assert (((fp->ctf_flags & LCTF_CHILD) && (type > fp->ctf_header->cth_parent_ntypes)) || (!(fp->ctf_flags & LCTF_CHILD))); if (fp->ctf_flags & LCTF_CHILD) { /* Non-dynamic type in parent: no index permitted. */ - assert (type > fp->ctf_header->cth_parent_typemax); + assert (type > fp->ctf_header->cth_parent_ntypes); - idx -= fp->ctf_header->cth_parent_typemax; + idx -= fp->ctf_header->cth_parent_ntypes; } if (idx <= fp->ctf_stypes) @@ -130,7 +130,7 @@ ctf_id_t ctf_index_to_type (const ctf_dict_t *fp, uint32_t idx) { if (fp->ctf_flags & LCTF_CHILD) - return idx + fp->ctf_header->cth_parent_typemax; + return idx + fp->ctf_header->cth_parent_ntypes; if (idx <= (fp->ctf_typemax - fp->ctf_nprovtypes)) return idx;