From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Alan Maguire <alan.maguire@oracle.com>
Cc: Jiri Olsa <jolsa@kernel.org>,
Clark Williams <williams@redhat.com>,
dwarves@vger.kernel.org, bpf@vger.kernel.org,
Andrii Nakryiko <andrii@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH 29/31] btf_encoder: Fix multi-dimensional array encoding
Date: Wed, 29 Jul 2026 16:07:29 -0300 [thread overview]
Message-ID: <20260729190733.72876-30-acme@kernel.org> (raw)
In-Reply-To: <20260729190733.72876-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Before this fix, DW_TAG_array_type with more than one dimension was
encoded as a single BTF_KIND_ARRAY using array_type__nelems() which
returns the FLAT total element count. For int a[3][4] that produced:
ARRAY(type=int, nelems=12) ← wrong, flat count
BTF encodes each dimension as a separate chained BTF_KIND_ARRAY:
inner: ARRAY(type=int, nelems=4)
outer: ARRAY(type=inner, nelems=3)
The encoder now loops from innermost to outermost dimension, emitting
one BTF_KIND_ARRAY per dimension, matching the BTF format used by
bpftool and the kernel verifier.
Because one DWARF type now maps to D BTF types (one per dimension),
the simple linear formula type_id_off + core_id no longer gives the
correct BTF id for any type that appears after a multi-dimensional
array. A pre-scan pass (btf_encoder__precompute_btf_ids) runs before
the encoding loop and fills btf_id_map[] with the correct expected BTF
id for every DWARF core_id, accounting for:
- NULL holes in types_table (type_id_null_adj)
- Skipped types (DW_TAG_unspecified_type → encode_tag returns 0)
- Extra BTF slots consumed by multi-dim arrays
btf_encoder__tag_type() consults the map first so that cross-references
from struct members, pointers, and typedefs resolve to the right BTF id
even before the referenced type has been encoded. The map is
authoritative whenever it covers a given id — a 0-sentinel entry
correctly resolves to BTF void rather than falling through to the
linear formula.
Audited: DW_TAG_unspecified_type is the sole return-0 path in
encode_tag; all callees (add_base_type, add_ref_type, add_struct_type,
add_enum_type, add_func_proto, add_array) return >= 1 or negative.
The drift check is updated to compare the actual returned BTF id against
the pre-computed map entry rather than the old linear formula.
Before: pahole -F btf showed int a[3][4] as int a[4][3] or int a[12]
After: int a[2][3][4] encodes as three chained BTF_KIND_ARRAY nodes
and round-trips correctly to int a[2][3][4]
And these all match:
⬢ [acme@toolbx pahole]$ pahole -F btf -C lru_gen_folio vmlinux.btf
struct lru_gen_folio {
long unsigned int max_seq; /* 0 8 */
long unsigned int min_seq[2]; /* 8 16 */
long unsigned int timestamps[4]; /* 24 32 */
struct list_head folios[4][2][5]; /* 56 640 */
/* --- cacheline 10 boundary (640 bytes) was 56 bytes ago --- */
long int nr_pages[4][2][5]; /* 696 320 */
/* --- cacheline 15 boundary (960 bytes) was 56 bytes ago --- */
long unsigned int avg_refaulted[2][4]; /* 1016 64 */
/* --- cacheline 16 boundary (1024 bytes) was 56 bytes ago --- */
long unsigned int avg_total[2][4]; /* 1080 64 */
/* --- cacheline 17 boundary (1088 bytes) was 56 bytes ago --- */
long unsigned int protected[1][2][4]; /* 1144 64 */
/* --- cacheline 18 boundary (1152 bytes) was 56 bytes ago --- */
atomic_long_t evicted[1][2][4]; /* 1208 64 */
/* --- cacheline 19 boundary (1216 bytes) was 56 bytes ago --- */
atomic_long_t refaulted[1][2][4]; /* 1272 64 */
/* --- cacheline 20 boundary (1280 bytes) was 56 bytes ago --- */
bool enabled; /* 1336 1 */
u8 gen; /* 1337 1 */
u8 seg; /* 1338 1 */
/* XXX 5 bytes hole, try to pack */
/* --- cacheline 21 boundary (1344 bytes) --- */
struct hlist_nulls_node list; /* 1344 16 */
/* size: 1360, cachelines: 22, members: 14 */
/* sum members: 1355, holes: 1, sum holes: 5 */
/* last cacheline: 16 bytes */
};
⬢ [acme@toolbx pahole]$ pahole -F dwarf -C lru_gen_folio vmlinux
struct lru_gen_folio {
long unsigned int max_seq; /* 0 8 */
long unsigned int min_seq[2]; /* 8 16 */
long unsigned int timestamps[4]; /* 24 32 */
struct list_head folios[4][2][5]; /* 56 640 */
/* --- cacheline 10 boundary (640 bytes) was 56 bytes ago --- */
long int nr_pages[4][2][5]; /* 696 320 */
/* --- cacheline 15 boundary (960 bytes) was 56 bytes ago --- */
long unsigned int avg_refaulted[2][4]; /* 1016 64 */
/* --- cacheline 16 boundary (1024 bytes) was 56 bytes ago --- */
long unsigned int avg_total[2][4]; /* 1080 64 */
/* --- cacheline 17 boundary (1088 bytes) was 56 bytes ago --- */
long unsigned int protected[1][2][4]; /* 1144 64 */
/* --- cacheline 18 boundary (1152 bytes) was 56 bytes ago --- */
atomic_long_t evicted[1][2][4]; /* 1208 64 */
/* --- cacheline 19 boundary (1216 bytes) was 56 bytes ago --- */
atomic_long_t refaulted[1][2][4]; /* 1272 64 */
/* --- cacheline 20 boundary (1280 bytes) was 56 bytes ago --- */
bool enabled; /* 1336 1 */
u8 gen; /* 1337 1 */
u8 seg; /* 1338 1 */
/* XXX 5 bytes hole, try to pack */
/* --- cacheline 21 boundary (1344 bytes) --- */
struct hlist_nulls_node list; /* 1344 16 */
/* size: 1360, cachelines: 22, members: 14 */
/* sum members: 1355, holes: 1, sum holes: 5 */
/* last cacheline: 16 bytes */
};
⬢ [acme@toolbx pahole]$
And:
⬢ [acme@toolbx pahole]$ bpftool btf dump file vmlinux.btf format c | grep lru_gen_folio -A20
struct lru_gen_folio {
long unsigned int max_seq;
long unsigned int min_seq[2];
long unsigned int timestamps[4];
struct list_head folios[4][2][5];
long int nr_pages[4][2][5];
long unsigned int avg_refaulted[2][4];
long unsigned int avg_total[2][4];
long unsigned int protected[1][2][4];
atomic_long_t evicted[1][2][4];
atomic_long_t refaulted[1][2][4];
bool enabled;
u8 gen;
u8 seg;
struct hlist_nulls_node list;
};
⬢ [acme@toolbx pahole]$ bpftool btf dump file vmlinux.btf format raw | grep lru_gen_folio -A20
[867] STRUCT 'lru_gen_folio' size=1360 vlen=14
'max_seq' type_id=1 bits_offset=0
'min_seq' type_id=4 bits_offset=64
'timestamps' type_id=721 bits_offset=192
'folios' type_id=870 bits_offset=448
'nr_pages' type_id=873 bits_offset=5568
'avg_refaulted' type_id=874 bits_offset=8128
'avg_total' type_id=874 bits_offset=8640
'protected' type_id=875 bits_offset=9152
'evicted' type_id=878 bits_offset=9664
'refaulted' type_id=878 bits_offset=10176
'enabled' type_id=71 bits_offset=10688
'gen' type_id=29 bits_offset=10696
'seg' type_id=29 bits_offset=10704
'list' type_id=695 bits_offset=10752
[868] ARRAY '(anon)' type_id=97 index_type_id=21 nr_elems=5
[869] ARRAY '(anon)' type_id=868 index_type_id=21 nr_elems=2
[870] ARRAY '(anon)' type_id=869 index_type_id=21 nr_elems=4
[871] ARRAY '(anon)' type_id=44 index_type_id=21 nr_elems=5
[872] ARRAY '(anon)' type_id=871 index_type_id=21 nr_elems=2
[873] ARRAY '(anon)' type_id=872 index_type_id=21 nr_elems=4
Fixes: 68645f7facc2eb69 ("btf: Add BTF support")
Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
btf_encoder.c | 299 +++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 260 insertions(+), 39 deletions(-)
diff --git a/btf_encoder.c b/btf_encoder.c
index c7ebaec4829d121a..20d8317a909f775f 100644
--- a/btf_encoder.c
+++ b/btf_encoder.c
@@ -152,6 +152,27 @@ struct btf_encoder {
encode_attributes,
true_signature;
uint32_t array_index_id;
+ uint32_t *type_id_null_adj;
+ /*
+ * Maps DWARF core_id → actual BTF type id. Populated by
+ * btf_encoder__precompute_btf_ids() before encoding begins.
+ *
+ * Entry value 0 means "skipped" (e.g. DW_TAG_unspecified_type);
+ * this is safe as a sentinel because BTF type id 0 is void and
+ * the first real type id is always >= 1.
+ *
+ * tag__nr_btf_ids() is the single source of truth for how many
+ * BTF ids each DWARF tag consumes; both precompute and encode
+ * use it so the mapping stays consistent.
+ */
+ uint32_t *btf_id_map;
+ uint32_t btf_id_map_sz;
+ /*
+ * Final extra/skipped counts from btf_encoder__precompute_btf_ids(),
+ * used to compute the fallback array_index_id when "int" is absent.
+ */
+ uint32_t btf_id_extra;
+ uint32_t btf_id_skipped;
struct elf_secinfo *secinfo;
size_t seccnt;
int encode_vars;
@@ -742,7 +763,15 @@ static int32_t btf_encoder__tag_type(struct btf_encoder *encoder, uint32_t tag_t
if (tag_type == 0)
return 0;
- return encoder->type_id_off + tag_type;
+ /* Map is authoritative when it covers this id: entry 0 means
+ * skipped (DW_TAG_unspecified_type, dwz-pruned) → void. */
+ if (encoder->btf_id_map && tag_type < encoder->btf_id_map_sz)
+ return encoder->btf_id_map[tag_type];
+
+ /* Fallback for map-absent CUs (nr == 0) or out-of-range ids */
+ uint32_t adj = encoder->type_id_null_adj ? encoder->type_id_null_adj[tag_type] : 0;
+
+ return encoder->type_id_off + tag_type - adj;
}
static int btf__tag_bpf_arena_ptr(struct btf *btf, int ptr_id)
@@ -1812,20 +1841,6 @@ static void dump_invalid_symbol(const char *msg, const char *sym,
fprintf(stderr, "PAHOLE: Error: Use '--btf_encode_force' to ignore such symbols and force emit the btf.\n");
}
-static int tag__check_id_drift(struct btf_encoder *encoder, const struct tag *tag,
- uint32_t core_id, uint32_t btf_type_id)
-{
- if (btf_type_id != (core_id + encoder->type_id_off)) {
- fprintf(stderr,
- "%s: %s id drift, core_id: %u, btf_type_id: %u, type_id_off: %u\n",
- __func__, dwarf_tag_name(tag->tag),
- core_id, btf_type_id, encoder->type_id_off);
- return -1;
- }
-
- return 0;
-}
-
static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct tag *tag)
{
struct type *type = tag__type(tag);
@@ -1858,18 +1873,6 @@ static int32_t btf_encoder__add_struct_type(struct btf_encoder *encoder, struct
return type_id;
}
-static uint32_t array_type__nelems(struct tag *tag)
-{
- int i;
- uint32_t nelem = 1;
- struct array_type *array = tag__array_type(tag);
-
- for (i = array->dimensions - 1; i >= 0; --i)
- nelem *= array->nr_entries[i];
-
- return nelem;
-}
-
static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct tag *tag,
struct conf_load *conf_load)
{
@@ -1891,7 +1894,28 @@ static int32_t btf_encoder__add_enum_type(struct btf_encoder *encoder, struct ta
return type_id;
}
+/*
+ * How many BTF type IDs will encoding this tag consume?
+ * 0 — skipped (DW_TAG_unspecified_type)
+ * 1 — the common case
+ * D — multi-dimensional arrays (one BTF_KIND_ARRAY per dimension)
+ *
+ * Both btf_encoder__precompute_btf_ids() and btf_encoder__encode_tag()
+ * must agree on this; keeping the logic in one place prevents drift.
+ */
+static int tag__nr_btf_ids(const struct tag *tag)
+{
+ if (tag->tag == DW_TAG_unspecified_type)
+ return 0;
+ if (tag->tag == DW_TAG_array_type) {
+ int dims = tag__array_type(tag)->dimensions;
+ return dims < 1 ? 1 : dims;
+ }
+ return 1;
+}
+
static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
+ const struct cu *cu __maybe_unused,
struct conf_load *conf_load)
{
/* single out type 0 as it represents special type "void" */
@@ -1899,6 +1923,11 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
struct base_type *bt;
const char *name;
+ /*
+ * Any case that returns 0 (skip) must have a matching entry in
+ * tag__nr_btf_ids(); the precompute map depends on agreement.
+ * The drift check will catch mismatches at runtime.
+ */
switch (tag->tag) {
case DW_TAG_base_type:
bt = tag__base_type(tag);
@@ -1927,10 +1956,35 @@ static int btf_encoder__encode_tag(struct btf_encoder *encoder, struct tag *tag,
return btf_encoder__add_ref_type(encoder, BTF_KIND_FWD, 0, name, tag->tag == DW_TAG_union_type);
else
return btf_encoder__add_struct_type(encoder, tag);
- case DW_TAG_array_type:
- /* TODO: Encode one dimension at a time. */
+ case DW_TAG_array_type: {
+ /*
+ * BTF represents each array dimension as a separate chained
+ * BTF_KIND_ARRAY node. Emit from innermost to outermost so
+ * that each outer node can reference the one just emitted.
+ * For int a[3][4] (dimensions=2, nr_entries=[3,4]):
+ * i=1: ARRAY(type=int, nelems=4) → id_inner
+ * i=0: ARRAY(type=id_inner, nelems=3) → returned id
+ */
+ struct array_type *at = tag__array_type(tag);
+ int32_t id = ref_type_id;
+ int i;
+
encoder->need_index_type = true;
- return btf_encoder__add_array(encoder, ref_type_id, encoder->array_index_id, array_type__nelems(tag));
+ /*
+ * Malformed DWARF may produce 0 dimensions; emit one
+ * BTF_KIND_ARRAY with 0 elements rather than returning the
+ * bare element type (which would trigger an ID drift error).
+ */
+ if (at->dimensions == 0) {
+ return btf_encoder__add_array(encoder, id, encoder->array_index_id, 0);
+ }
+ for (i = at->dimensions - 1; i >= 0; --i) {
+ id = btf_encoder__add_array(encoder, id, encoder->array_index_id, at->nr_entries[i]);
+ if (id < 0)
+ return id;
+ }
+ return id;
+ }
case DW_TAG_enumeration_type:
return btf_encoder__add_enum_type(encoder, tag, conf_load);
case DW_TAG_subroutine_type:
@@ -2985,10 +3039,80 @@ static bool ftype__has_uncertain_arg_loc(struct cu *cu, struct ftype *ftype)
return false;
}
+/*
+ * Pre-compute the actual BTF type id for every DWARF core_id.
+ *
+ * The linear formula type_id_off + core_id - null_adj holds only for a
+ * strict 1-to-1 DWARF→BTF mapping. Two things break it:
+ *
+ * • Skipped types (DW_TAG_unspecified_type → encode_tag returns 0): each
+ * skipped entry shifts all subsequent BTF ids down by 1.
+ *
+ * • Multi-dimensional arrays: one BTF_KIND_ARRAY is emitted per dimension,
+ * so a D-dimensional array occupies D consecutive BTF ids. The "name" of
+ * the type (the outermost array) lands at base + D - 1, and each inner
+ * array consumed an extra slot, shifting all later ids up.
+ *
+ * By scanning the types table once before encoding we can fill btf_id_map[]
+ * with the correct expected id for every core_id. btf_encoder__tag_type()
+ * then reads the map so that any type reference (struct member, pointer base,
+ * typedef chain, …) resolves to the right BTF id even when the referenced
+ * type hasn't been encoded yet.
+ *
+ * Assumes every non-skipped tag appends exactly nr_ids fresh BTF types;
+ * no in-CU dedup occurs (dedup is a separate libbpf btf__dedup() pass).
+ */
+static int btf_encoder__precompute_btf_ids(struct btf_encoder *encoder, struct cu *cu)
+{
+ uint32_t nr = cu->types_table.nr_entries;
+ uint32_t cid, extra = 0, skipped = 0;
+
+ if (!nr)
+ return 0;
+
+ encoder->btf_id_map = calloc(nr, sizeof(*encoder->btf_id_map));
+ if (!encoder->btf_id_map) {
+ fprintf(stderr, "btf_encoder: out of memory for btf_id_map (%u entries)\n", nr);
+ return -ENOMEM;
+ }
+ encoder->btf_id_map_sz = nr;
+
+ /* Mirror cu__for_each_type: valid core_ids are 1 .. nr-1 */
+ for (cid = 1; cid < nr; cid++) {
+ struct tag *t = cu->types_table.entries[cid];
+ uint32_t adj, base;
+ int nr_ids;
+
+ if (!t)
+ continue;
+
+ nr_ids = tag__nr_btf_ids(t);
+ if (nr_ids == 0) {
+ skipped++;
+ continue;
+ }
+
+ adj = encoder->type_id_null_adj ? encoder->type_id_null_adj[cid] : 0;
+ base = encoder->type_id_off + cid - adj - skipped + extra;
+
+ /*
+ * Multi-dim arrays consume nr_ids consecutive BTF slots;
+ * the outermost (the type other entries reference) is the
+ * last one emitted: base + nr_ids - 1.
+ */
+ encoder->btf_id_map[cid] = base + (nr_ids - 1);
+ extra += nr_ids - 1;
+ }
+
+ encoder->btf_id_extra = extra;
+ encoder->btf_id_skipped = skipped;
+ return 0;
+}
+
int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct conf_load *conf_load)
{
struct llvm_annotation *annot;
- int btf_type_id, tag_type_id, skipped_types = 0;
+ int btf_type_id, tag_type_id;
struct elf_functions *funcs;
uint32_t core_id;
struct function *fn;
@@ -3005,6 +3129,50 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
encoder->type_id_off = btf__type_cnt(encoder->btf) - 1;
+ /*
+ * NULL holes in types_table occur only with dwz alternate debug
+ * files: dwarf_cu__prune_unreferenced_alt_pus() NULLs entries for
+ * imported partial unit types not referenced by this CU. This
+ * does not happen in the common kernel BTF case.
+ *
+ * Build a prefix-sum so btf_encoder__tag_type() can translate
+ * types_table indices (small_ids) to dense BTF type IDs.
+ */
+ encoder->type_id_null_adj = NULL;
+ if (cu->types_table.nr_entries > 0) {
+ uint32_t nr = cu->types_table.nr_entries;
+ uint32_t *adj = calloc(nr + 1, sizeof(*adj));
+
+ if (adj) {
+ uint32_t nulls = 0;
+
+ for (uint32_t i = 1; i < nr; i++) {
+ if (cu->types_table.entries[i] == NULL)
+ nulls++;
+ adj[i] = nulls;
+ }
+ adj[nr] = nulls;
+ if (nulls > 0)
+ encoder->type_id_null_adj = adj;
+ else
+ free(adj);
+ } else {
+ /* Without the adjustment table, NULL holes would cause
+ * wrong BTF type IDs — fail rather than silently corrupt */
+ for (uint32_t i = 1; i < nr; i++) {
+ if (cu->types_table.entries[i] == NULL) {
+ fprintf(stderr, "btf_encoder: out of memory for type_id_null_adj (%u entries)\n", nr);
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+ }
+ }
+
+ err = btf_encoder__precompute_btf_ids(encoder, cu);
+ if (err)
+ goto out;
+
if (!encoder->has_index_type) {
/* cu__find_base_type_by_name() takes "type_id_t *id" */
type_id_t id;
@@ -3012,24 +3180,58 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
encoder->has_index_type = true;
encoder->array_index_id = btf_encoder__tag_type(encoder, id);
} else {
+ uint32_t nr = cu->types_table.nr_entries;
+ uint32_t adj = encoder->type_id_null_adj ? encoder->type_id_null_adj[nr] : 0;
+
encoder->has_index_type = false;
- encoder->array_index_id = encoder->type_id_off + cu->types_table.nr_entries;
+ /*
+ * Point past all encoded CU types. Must account for
+ * NULL holes (adj), skipped DW_TAG_unspecified_type
+ * entries, and extra BTF slots from multi-dim arrays.
+ */
+ encoder->array_index_id = encoder->type_id_off + nr - adj
+ - encoder->btf_id_skipped
+ + encoder->btf_id_extra;
}
}
cu__for_each_type(cu, core_id, pos) {
- btf_type_id = btf_encoder__encode_tag(encoder, pos, conf_load);
+ btf_type_id = btf_encoder__encode_tag(encoder, pos, cu, conf_load);
- if (btf_type_id == 0) {
- ++skipped_types;
+ if (btf_type_id == 0)
continue;
- }
- if (btf_type_id < 0 ||
- tag__check_id_drift(encoder, pos, core_id, btf_type_id + skipped_types)) {
+ /* Verify actual BTF id matches the pre-computed map entry. */
+ if (btf_type_id < 0) {
+ fprintf(stderr,
+ "%s: error encoding %s (core_id %u): %d\n",
+ __func__, dwarf_tag_name(pos->tag), core_id,
+ btf_type_id);
err = -1;
goto out;
}
+ if (encoder->btf_id_map && core_id < encoder->btf_id_map_sz) {
+ uint32_t expected = encoder->btf_id_map[core_id];
+
+ /* Inverse check: precompute expected skip but encode emitted */
+ if (!expected) {
+ fprintf(stderr,
+ "%s: %s unexpected emit, core_id: %u, btf_type_id: %u "
+ "(precompute predicted skip)\n",
+ __func__, dwarf_tag_name(pos->tag), core_id,
+ (uint32_t)btf_type_id);
+ err = -1;
+ goto out;
+ }
+ if ((uint32_t)btf_type_id != expected) {
+ fprintf(stderr,
+ "%s: %s id drift, core_id: %u, expected: %u, got: %u\n",
+ __func__, dwarf_tag_name(pos->tag), core_id,
+ expected, (uint32_t)btf_type_id);
+ err = -1;
+ goto out;
+ }
+ }
}
if (encoder->need_index_type && !encoder->has_index_type) {
@@ -3060,7 +3262,15 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
continue;
}
- btf_type_id = encoder->type_id_off + core_id;
+ if (!encoder->btf_id_map ||
+ core_id >= encoder->btf_id_map_sz ||
+ !encoder->btf_id_map[core_id]) {
+ if (encoder->verbose)
+ fprintf(stderr, "BTF: skipping annotations on unmapped %s (core_id %u)\n",
+ tag_name, core_id);
+ continue;
+ }
+ btf_type_id = (int)encoder->btf_id_map[core_id];
ns = tag__namespace(pos);
list_for_each_entry(annot, &ns->annots, node) {
tag_type_id = btf_encoder__add_decl_tag(encoder, annot->value, btf_type_id, annot->component_idx);
@@ -3122,6 +3332,17 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
if (!err)
err = LSK__DELETE;
out:
+ /*
+ * Safe to free here: btf_encoder__save_func() stores
+ * already-translated BTF type IDs, so the deferred
+ * btf_encoder__add_saved_funcs() path never calls
+ * btf_encoder__tag_type() after this point.
+ */
+ zfree(&encoder->type_id_null_adj);
+ zfree(&encoder->btf_id_map);
+ encoder->btf_id_map_sz = 0;
+ encoder->btf_id_extra = 0;
+ encoder->btf_id_skipped = 0;
encoder->cu = NULL;
return err;
}
--
2.55.0
next prev parent reply other threads:[~2026-07-29 19:08 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-29 19:07 [PATCHES 00/31] pahole: Bug fixes and small improvements Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 01/31] cmake: Update minimum required version from 3.5 to 3.10 Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 02/31] Fix -Wsign-compare warnings across the codebase Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 03/31] btf_encoder: Fix interior pointer free and missing NULL check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 04/31] dwarves: Fix missing list head initialization in type__clone_members Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 05/31] pahole: Fix instance memory leak on early returns in prototype__stdio_fprintf_value Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 06/31] ctf_loader, libctf: Fix error path resource leaks Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 07/31] dwarves: Don't search for holes before member byte sizes are cached Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 08/31] dwarf_loader: Allocate type_dcu via dwarf_cu__new to fix dangling stack pointer Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 09/31] dwarf_loader: Fix annotation failure leaks in variable and typedef creation Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 10/31] btf_encoder: Use btf_encoder__tag_type() for all type ID computations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 11/31] pahole: Fix --errno typo that decrements instead of negating Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 12/31] dwarves: Fix heap buffer overflow in languages__parse realloc Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 13/31] btf_encoder: Fix early cleanup crashes in btf_encoder__new/delete Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 14/31] btf_encoder, libctf: Add elf_strptr NULL checks and fix kfunc bounds Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 15/31] dwarf_loader: Fix --fixup_silly_bitfields condition check Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 16/31] dwarf_loader: Skip libdw__lock when elfutils is built thread-safe Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 17/31] dwarf_loader: Fix data race in tag__init() decl_file string cache Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 18/31] pahole: Fix parse_btf_features("all") being a silent no-op Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 19/31] dwarves: Fix variable shadowing in __cus__find_struct_by_name() Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 20/31] dutil: Add exec_objcopy() shell-injection-safe helper Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 21/31] btf_encoder: Fall back to objcopy when llvm-objcopy is not available Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 22/31] dwarf_loader, btf_loader: Replace stale FIXME/XXX comments with explanations Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 23/31] pahole: Skip inline expansions during BTF encoding Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 24/31] pahole: Use fseek for seekable files in --prettify and --seek_bytes Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 25/31] pahole: Guard pipe_seek() against negative offsets Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 26/31] gobuffer: Remove 5 dead functions found via coverage analysis Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 27/31] dwarves: Remove 6 " Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 28/31] pfunct, dwarves_fprintf: Mark file-local functions as static Arnaldo Carvalho de Melo
2026-07-29 19:07 ` Arnaldo Carvalho de Melo [this message]
2026-07-29 19:07 ` [PATCH 30/31] btf_loader: Fix multi-dimensional array loading Arnaldo Carvalho de Melo
2026-07-29 19:07 ` [PATCH 31/31] btfdiff: Remove --flat_arrays now that pahole encodes multi dim arrays in BTF Arnaldo Carvalho de Melo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260729190733.72876-30-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=dwarves@vger.kernel.org \
--cc=jolsa@kernel.org \
--cc=williams@redhat.com \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox