From: Nick Alcock Date: Thu, 24 Apr 2025 12:50:38 +0000 (+0100) Subject: libctf: adapt core dictops for v4 and prefix types X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6a4a485c7b080373aa0e9989a12652007d23d57e;p=thirdparty%2Fbinutils-gdb.git libctf: adapt core dictops for v4 and prefix types The heart of libctf's reading code is the ctf_dictops_t and the functions it provides for reading various things no matter what the CTF version in use: these are called via LCTF_*() macros that translate into calls into the dictops. The introduction of prefix types in v4 requires changes here: in particular, we want the ability to get the type kind of whatever ctf_type_t we are looking at (the 'unprefixed' kind), as well as the ability to get the type kind taking prefixes into account: and more generally we want the ability to both look at a given prefix and look at the type as a whole. So several ctf_dictops_t entries are added for this (ctfo_get_prefixed_kind, ctfo_get_prefixed_vlen). This means API changes (no callers yet adjusted, it'll happen as we go), because the existing macros were mostly called with e.g. a ctt_info value and returned a type kind, while now we need to be called with the actual ctf_type_t itself, so we can possibly walk beyond it to find the real type record. ctfo_get_vbytes needs adjusting for this. We also add names to most of the ctf_type_t parameters, because suddenly we can have up to three of them: one relating to the first entry in the type record (which may be a prefix, usually called 'prefix'), one relating to the true type record (which may be a suffix, so usually called 'suffix'), and one possibly relating to some intermediate record if we have multiple prefixes (usually called 'tp'). There is one horrible special case in here: the vlen of the new CTF_K_FUNC_LINKAGE kind (equivalent to BTF_KIND_FUNC) is always zero: it reuses the vlen field to encode the linkage (!). BTF is rife with ugly hacks like this. --- diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 4b9518b5438..6a6ed8eda7a 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -133,11 +133,13 @@ typedef struct ctf_lookup typedef struct ctf_dictops { uint32_t (*ctfo_get_kind) (uint32_t); + uint32_t (*ctfo_get_prefixed_kind) (const ctf_type_t *tp); uint32_t (*ctfo_get_root) (uint32_t); uint32_t (*ctfo_get_vlen) (uint32_t); - ssize_t (*ctfo_get_ctt_size) (const ctf_dict_t *, const ctf_type_t *, + uint32_t (*ctfo_get_prefixed_vlen) (const ctf_type_t *tp); + ssize_t (*ctfo_get_ctt_size) (const ctf_dict_t *, const ctf_type_t *tp, ssize_t *, ssize_t *); - ssize_t (*ctfo_get_vbytes) (ctf_dict_t *, unsigned short, ssize_t, size_t); + ssize_t (*ctfo_get_vbytes) (ctf_dict_t *, const ctf_type_t *, ssize_t); } ctf_dictops_t; typedef struct ctf_list @@ -593,11 +595,24 @@ extern ctf_id_t ctf_index_to_type (const ctf_dict_t *, uint32_t); &(ctf_dtd_lookup (fp, ctf_index_to_type (fp, i))->dtd_data) : \ (ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)])) -#define LCTF_INFO_KIND(fp, info) ((fp)->ctf_dictops->ctfo_get_kind(info)) +/* The non *INFO variants of these macros acquire the relevant info from the + suffixed type, if the type is prefixed. (Internally to libctf, all types + that may ever take a prefix are prefixed until they are written out, so that + nothing special needs to be done to handle them should their size later + expand past the limit where prefixing is needed.) */ + +#define LCTF_INFO_UNPREFIXED_KIND(fp, info) ((fp)->ctf_dictops->ctfo_get_kind(info)) +#define LCTF_KIND(fp, tp) ((fp)->ctf_dictops->ctfo_get_prefixed_kind(tp)) #define LCTF_INFO_ISROOT(fp, info) ((fp)->ctf_dictops->ctfo_get_root(info)) -#define LCTF_INFO_VLEN(fp, info) ((fp)->ctf_dictops->ctfo_get_vlen(info)) -#define LCTF_VBYTES(fp, kind, size, vlen) \ - ((fp)->ctf_dictops->ctfo_get_vbytes(fp, kind, size, vlen)) +#define LCTF_VLEN(fp, tp) ((fp)->ctf_dictops->ctfo_get_prefixed_vlen(tp)) +#define LCTF_INFO_UNPREFIXED_VLEN(fp, info) ((fp)->ctf_dictops->ctfo_get_vlen(info)) +#define LCTF_VBYTES(fp, tp, size) \ + ((fp)->ctf_dictops->ctfo_get_vbytes (fp, tp, size)) + +#define LCTF_IS_PREFIXED_KIND(kind) (kind == CTF_K_BIG || kind == CTF_K_CONFLICTING) +#define LCTF_IS_PREFIXED_INFO(info) \ + ((CTF_INFO_KIND ((info)) == CTF_K_BIG) \ + || (CTF_INFO_KIND ((info)) == CTF_K_CONFLICTING)) #define LCTF_CHILD 0x0001 /* CTF dict is a child. */ #define LCTF_LINKING 0x0002 /* CTF link is underway: respect ctf_link_flags. */ @@ -807,6 +822,9 @@ extern ctf_link_sym_t *ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *ds extern ctf_link_sym_t *ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst, const Elf64_Sym *src, uint32_t symidx); +ssize_t get_ctt_size_v2_unconverted (const ctf_dict_t *, const ctf_type_t *, + ssize_t *sizep, ssize_t *incrementp); + /* Variables, all underscore-prepended. */ extern const char _CTF_SECTION[]; /* name of CTF ELF section */ diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index fb8a752ca53..b17dae6bdbd 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -43,10 +43,16 @@ get_kind_v1 (uint32_t info) return (CTF_V1_INFO_KIND (info)); } +static uint32_t +get_prefixed_kind_v1 (const ctf_type_t *tp) +{ + return (CTF_V1_INFO_KIND (tp->ctt_info)); +} + static uint32_t get_root_v1 (uint32_t info) { - return (CTF_V1_INFO_ISROOT (info)); + return !!(CTF_V1_INFO_ISROOT (info)); } static uint32_t @@ -55,16 +61,28 @@ get_vlen_v1 (uint32_t info) return (CTF_V1_INFO_VLEN (info)); } +static uint32_t +get_prefixed_vlen_v1 (const ctf_type_t *tp) +{ + return (CTF_V1_INFO_VLEN (tp->ctt_info)); +} + static uint32_t get_kind_v2 (uint32_t info) { return (CTF_V2_INFO_KIND (info)); } +static uint32_t +get_prefixed_kind_v2 (const ctf_type_t *tp) +{ + return (CTF_V2_INFO_KIND (tp->ctt_info)); +} + static uint32_t get_root_v2 (uint32_t info) { - return (CTF_V2_INFO_ISROOT (info)); + return !!(CTF_V2_INFO_ISROOT (info)); } static uint32_t @@ -73,12 +91,72 @@ get_vlen_v2 (uint32_t info) return (CTF_V2_INFO_VLEN (info)); } +static uint32_t +get_prefixed_vlen_v2 (const ctf_type_t *tp) +{ + return (CTF_V2_INFO_VLEN (tp->ctt_info)); +} + +static uint32_t +get_kind_v4 (uint32_t info) +{ + return (CTF_INFO_KIND (info)); +} + +static uint32_t +get_prefixed_kind_v4 (const ctf_type_t *tp) +{ + /* Resolve away as many prefixes as exist. */ + + while (LCTF_IS_PREFIXED_INFO (tp->ctt_info)) + tp++; + + return CTF_INFO_KIND (tp->ctt_info); +} + +static uint32_t +get_root_v4 (uint32_t info) +{ + return (CTF_INFO_KIND (info) != CTF_K_CONFLICTING); +} + +static uint32_t +get_vlen_v4 (uint32_t info) +{ + return (CTF_INFO_VLEN (info)); +} + +static uint32_t +get_prefixed_vlen_v4 (const ctf_type_t *tp) +{ + const ctf_type_t *suffix; + + /* Resolve away non-BIG prefixes (which have no affect on vlen). */ + + while (LCTF_IS_PREFIXED_INFO (tp->ctt_info) + && CTF_INFO_KIND (tp->ctt_info) != CTF_K_BIG) + tp++; + + if (!LCTF_IS_PREFIXED_INFO (tp->ctt_info)) + return (CTF_INFO_VLEN (tp->ctt_info)); + + suffix = tp + 1; + + /* Special case: CTF_K_FUNC_LINKAGE reuses the vlen field for the linkage: its + vlen is always zero. */ + if (CTF_INFO_KIND (suffix->ctt_info) == CTF_K_FUNC_LINKAGE) + return 0; + + /* CTF_K_BIG. */ + return (CTF_INFO_VLEN (tp->ctt_info) << 16 | CTF_INFO_VLEN (suffix->ctt_info)); +} + static inline ssize_t -get_ctt_size_common (const ctf_dict_t *fp _libctf_unused_, - const ctf_type_t *tp _libctf_unused_, - ssize_t *sizep, ssize_t *incrementp, size_t lsize, - size_t csize, size_t ctf_type_size, - size_t ctf_stype_size, size_t ctf_lsize_sent) +get_ctt_size_old (const ctf_dict_t *fp _libctf_unused_, + const ctf_type_t *tp _libctf_unused_, + ssize_t *sizep, ssize_t *incrementp, size_t lsize, + size_t csize, size_t ctf_type_size, + size_t ctf_stype_size, size_t ctf_lsize_sent) { ssize_t size, increment; @@ -107,56 +185,91 @@ get_ctt_size_v1 (const ctf_dict_t *fp, const ctf_type_t *tp, { ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp; - return (get_ctt_size_common (fp, tp, sizep, incrementp, - CTF_TYPE_LSIZE (t1p), t1p->ctt_size, - sizeof (ctf_type_v1_t), sizeof (ctf_stype_v1_t), - CTF_LSIZE_SENT_V1)); + return (get_ctt_size_old (fp, tp, sizep, incrementp, + CTF_V3_TYPE_LSIZE (t1p), t1p->ctt_size, + sizeof (ctf_type_v1_t), sizeof (ctf_stype_v1_t), + CTF_LSIZE_SENT_V1)); } /* Return the size that a v1 will be once it is converted to v2. */ -static ssize_t +ssize_t get_ctt_size_v2_unconverted (const ctf_dict_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp) { ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp; - return (get_ctt_size_common (fp, tp, sizep, incrementp, - CTF_TYPE_LSIZE (t1p), t1p->ctt_size, - sizeof (ctf_type_t), sizeof (ctf_stype_t), - CTF_LSIZE_SENT)); + return (get_ctt_size_old (fp, tp, sizep, incrementp, + CTF_V3_TYPE_LSIZE (t1p), t1p->ctt_size, + sizeof (ctf_type_v2_t), sizeof (ctf_stype_v2_t), + CTF_LSIZE_SENT)); } static ssize_t get_ctt_size_v2 (const ctf_dict_t *fp, const ctf_type_t *tp, ssize_t *sizep, ssize_t *incrementp) { - return (get_ctt_size_common (fp, tp, sizep, incrementp, - CTF_TYPE_LSIZE (tp), tp->ctt_size, - sizeof (ctf_type_t), sizeof (ctf_stype_t), - CTF_LSIZE_SENT)); + ctf_type_v2_t *t2p = (ctf_type_v2_t *) tp; + + return (get_ctt_size_old (fp, tp, sizep, incrementp, + CTF_V3_TYPE_LSIZE (t2p), t2p->ctt_size, + sizeof (ctf_type_v2_t), sizeof (ctf_stype_v2_t), + CTF_LSIZE_SENT)); +} + +static ssize_t +get_ctt_size_v4 (const ctf_dict_t *fp _libctf_unused_, const ctf_type_t *tp, + ssize_t *sizep, ssize_t *incrementp) +{ + ssize_t size = 0; + + /* Figure out how many prefixes there are, and adjust the size appropriately + if we pass a BIG. */ + + if (incrementp) + *incrementp = 0; + + while (LCTF_IS_PREFIXED_INFO (tp->ctt_info)) + { + if (CTF_INFO_KIND (tp->ctt_info) == CTF_K_BIG) + size = ((ssize_t) tp->ctt_size) << 32; + + if (incrementp) + *incrementp += sizeof (ctf_type_t); + + tp++; + } + + if (incrementp) + *incrementp += sizeof (ctf_type_t); + + size |= tp->ctt_size; + + if (sizep) + *sizep = size; + + return size; } static ssize_t -get_vbytes_common (ctf_dict_t *fp, unsigned short kind, - ssize_t size _libctf_unused_, size_t vlen) +get_vbytes_old (ctf_dict_t *fp, unsigned short kind, size_t vlen) { switch (kind) { - case CTF_K_INTEGER: - case CTF_K_FLOAT: + case CTF_V3_K_INTEGER: + case CTF_V3_K_FLOAT: return (sizeof (uint32_t)); - case CTF_K_SLICE: + case CTF_V3_K_SLICE: return (sizeof (ctf_slice_t)); - case CTF_K_ENUM: + case CTF_V3_K_ENUM: return (sizeof (ctf_enum_t) * vlen); - case CTF_K_FORWARD: - case CTF_K_UNKNOWN: - case CTF_K_POINTER: - case CTF_K_TYPEDEF: - case CTF_K_VOLATILE: - case CTF_K_CONST: - case CTF_K_RESTRICT: + case CTF_V3_K_FORWARD: + case CTF_V3_K_UNKNOWN: + case CTF_V3_K_POINTER: + case CTF_V3_K_TYPEDEF: + case CTF_V3_K_VOLATILE: + case CTF_V3_K_CONST: + case CTF_V3_K_RESTRICT: return 0; default: ctf_set_errno (fp, ECTF_CORRUPT); @@ -166,57 +279,124 @@ get_vbytes_common (ctf_dict_t *fp, unsigned short kind, } static ssize_t -get_vbytes_v1 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen) +get_vbytes_v1 (ctf_dict_t *fp, const ctf_type_t *tp, ssize_t size) { + unsigned short kind = CTF_V1_INFO_KIND (tp->ctt_info); + size_t vlen = CTF_V1_INFO_VLEN (tp->ctt_info); + switch (kind) { - case CTF_K_ARRAY: + case CTF_V3_K_ARRAY: return (sizeof (ctf_array_v1_t)); - case CTF_K_FUNCTION: + case CTF_V3_K_FUNCTION: return (sizeof (unsigned short) * (vlen + (vlen & 1))); - case CTF_K_STRUCT: - case CTF_K_UNION: + case CTF_V3_K_STRUCT: + case CTF_V3_K_UNION: if (size < CTF_LSTRUCT_THRESH_V1) return (sizeof (ctf_member_v1_t) * vlen); else return (sizeof (ctf_lmember_v1_t) * vlen); } - return (get_vbytes_common (fp, kind, size, vlen)); + return (get_vbytes_old (fp, kind, vlen)); } static ssize_t -get_vbytes_v2 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen) +get_vbytes_v2 (ctf_dict_t *fp, const ctf_type_t *tp, ssize_t size) { + unsigned short kind = CTF_V2_INFO_KIND (tp->ctt_info); + size_t vlen = CTF_V2_INFO_VLEN (tp->ctt_info); + switch (kind) { - case CTF_K_ARRAY: + case CTF_V3_K_ARRAY: return (sizeof (ctf_array_t)); - case CTF_K_FUNCTION: + case CTF_V3_K_FUNCTION: return (sizeof (uint32_t) * (vlen + (vlen & 1))); - case CTF_K_STRUCT: - case CTF_K_UNION: + case CTF_V3_K_STRUCT: + case CTF_V3_K_UNION: if (size < CTF_LSTRUCT_THRESH) - return (sizeof (ctf_member_t) * vlen); + return (sizeof (ctf_member_v2_t) * vlen); else - return (sizeof (ctf_lmember_t) * vlen); + return (sizeof (ctf_lmember_v2_t) * vlen); } - return (get_vbytes_common (fp, kind, size, vlen)); + return (get_vbytes_old (fp, kind, vlen)); +} + +static ssize_t +get_vbytes_v4 (ctf_dict_t *fp, const ctf_type_t *tp, + ssize_t size _libctf_unused_) +{ + unsigned short kind = LCTF_KIND (fp, tp); + ssize_t vlen = LCTF_VLEN (fp, tp); + + switch (kind) + { + case CTF_K_INTEGER: + case CTF_K_FLOAT: + return (sizeof (uint32_t)); + case CTF_K_SLICE: + return (sizeof (ctf_slice_t)); + case CTF_K_ENUM: + return (sizeof (ctf_enum_t) * vlen); + case CTF_K_ENUM64: + return (sizeof (ctf_enum64_t) * vlen); + case CTF_K_ARRAY: + return (sizeof (ctf_array_t)); + case CTF_K_STRUCT: + case CTF_K_UNION: + return (sizeof (ctf_member_t) * vlen); + case CTF_K_FUNCTION: + return (sizeof (ctf_param_t) * vlen); + case CTF_K_VAR: + return (sizeof (ctf_linkage_t)); + case CTF_K_DATASEC: + return (sizeof (ctf_var_secinfo_t) * vlen); + case CTF_K_DECL_TAG: + return (sizeof (ctf_decl_tag_t)); + case CTF_K_TYPE_TAG: + case CTF_K_FORWARD: + case CTF_K_UNKNOWN: + case CTF_K_POINTER: + case CTF_K_TYPEDEF: + case CTF_K_VOLATILE: + case CTF_K_CONST: + case CTF_K_RESTRICT: + case CTF_K_FUNC_LINKAGE: + case CTF_K_BTF_FLOAT: + return 0; + /* These should have been resolved away by LCTF_KIND. + If this somehow didn't work, fail. */ + case CTF_K_BIG: + case CTF_K_CONFLICTING: + ctf_set_errno (fp, ECTF_INTERNAL); + ctf_err_warn (fp, 0, 0, _("internal error: prefixed kind seen in get_vbytes_v4: %x"), kind); + return -1; + default: + ctf_set_errno (fp, ECTF_CORRUPT); + ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind); + return -1; + } } static const ctf_dictops_t ctf_dictops[] = { - {NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL}, /* CTF_VERSION_1 */ - {get_kind_v1, get_root_v1, get_vlen_v1, get_ctt_size_v1, get_vbytes_v1}, + {get_kind_v1, get_prefixed_kind_v1, get_root_v1, get_vlen_v1, + get_prefixed_vlen_v1, get_ctt_size_v1, get_vbytes_v1}, /* CTF_VERSION_1_UPGRADED_3 */ - {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, + {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2, + get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, /* CTF_VERSION_2 */ - {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, + {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2, + get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, /* CTF_VERSION_3, identical to 2: only new type kinds */ - {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, - /* UPTODO: CTF_VERSION_4, identical to 3 at present (but not for long) */ - {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, + {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2, + get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2}, + /* CTF_VERSION_4, always BTF-compatible. */ + {get_kind_v4, get_prefixed_kind_v4, get_root_v4, get_vlen_v4, + get_prefixed_vlen_v4, get_ctt_size_v4, get_vbytes_v4}, }; /* Initialize the symtab translation table as appropriate for its indexing