* [PATCH dwarves v2 0/2] dwarf_loader: Fix --lang_exclude on merged CUs
@ 2026-10-10 0:52 Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 1/2] dwarf_loader: Take the merged CU language from a CU that is kept Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 2/2] dwarf_loader: Load types that kept CUs use from excluded CUs Alan Derk
0 siblings, 2 replies; 3+ messages in thread
From: Alan Derk @ 2026-10-10 0:52 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Alan Maguire; +Cc: dwarves, bpf, rust-for-linux
Two fixes for --lang_exclude when CUs are merged, as for LTO objects.
Patch 1 takes the merged CU's language from a CU that is kept, so that
excluding the language of the first CU no longer drops the whole
object. With LTO, this is what makes BTF generation fail for kernel
modules that mix Rust and C.
Patch 2 fixes a second bug from the same commit, which I found while
testing userspace LTO objects after sending v1. With clang LTO, a type
such as int is emitted once and shared through DW_FORM_ref_addr, so
skipping the excluded CUs left references into them dangling: pahole
crashed printing such members, and -J encoded them as void. Patch 2
loads the types that kept CUs use from the excluded CUs. Output without
--lang_exclude does not change, and neither does the BTF of the LTO
kernels I tested.
Patch 1 exposes this bug in one more link order. For a C++ object
linked before a C one, pahole used to drop the C types without any
error; with patch 1 alone it keeps them, and then crashes printing them,
or encodes them as void with -J. Please apply the two together.
As far as I know, patch 1 removes the last thing that keeps the kernel's
RUST option off when LTO and BTF are both on. Once these fixes are in a
release, I'd like to propose relaxing that dependency to something like:
depends on !DEBUG_INFO_BTF || (PAHOLE_HAS_LANG_EXCLUDE && (!LTO || PAHOLE_VERSION >= 133))
assuming they land in 1.33. The kernel tests in patch 1 ran with
"&& !LTO" dropped from that line, hence the Cc to rust-for-linux.
Changes in v2:
- Add patch 2.
- Patch 1 is unchanged; its note about the Kconfig follow-up moved here.
v1: https://lore.kernel.org/all/20261009201032.40105-1-linux@alanderk.com/
Alan Derk (2):
dwarf_loader: Take the merged CU language from a CU that is kept
dwarf_loader: Load types that kept CUs use from excluded CUs
dwarf_loader.c | 129 +++++++++++++++++++++++++++-----
tests/lang_exclude_lto_refs.sh | 76 +++++++++++++++++++
tests/lang_exclude_merged_cu.sh | 67 +++++++++++++++++
3 files changed, 253 insertions(+), 19 deletions(-)
create mode 100755 tests/lang_exclude_lto_refs.sh
create mode 100755 tests/lang_exclude_merged_cu.sh
base-commit: 1e342ac44979748bcf5bb37f84ea055e7f4d7184
--
2.55.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH dwarves v2 1/2] dwarf_loader: Take the merged CU language from a CU that is kept
2026-10-10 0:52 [PATCH dwarves v2 0/2] dwarf_loader: Fix --lang_exclude on merged CUs Alan Derk
@ 2026-10-10 0:52 ` Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 2/2] dwarf_loader: Load types that kept CUs use from excluded CUs Alan Derk
1 sibling, 0 replies; 3+ messages in thread
From: Alan Derk @ 2026-10-10 0:52 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Alan Maguire; +Cc: dwarves, bpf, rust-for-linux
When the CUs of an object are merged, as for clang LTO objects, the
merged CU takes the language of the first CU. Since commit
b98565e7b17ec24d ("dwarf_loader: Honour --lang_exclude when merging LTO
built CUs") the DIEs of excluded CUs are skipped while merging, but
pahole_stealer() then applies the same filter to the merged CU. If the
first CU is in an excluded language, the whole merged CU is dropped,
including the CUs that were kept, and with -J pahole writes no BTF and
still exits 0.
Kernel modules mixing Rust and C hit this in clang LTO builds with
CONFIG_DEBUG_INFO_BTF_MODULES: kbuild passes --lang_exclude=rust, and
the Rust CU comes first in the linked module even when the Rust object
is listed last, as the C objects are bitcode compiled at link time.
scripts/gen-btf.sh then fails, here for a Rust sample module:
FAILED: load BTF from samples/rust/rust_minimal.ko.BTF.1: No such file or directory
This is what is left of the problem behind kernel commit 5daa0c35a1f0
("rust: Disallow BTF generation with Rust + LTO"), which keeps RUST off
when LTO and BTF are both on. With pahole 1.32 a ThinLTO vmlinux with
Rust built in gets clean BTF, but its Rust modules fail as above, so
that restriction can't be relaxed yet. Distributions with LTO kernels,
such as CachyOS's default kernel, keep BTF for sched_ext and BPF tools
and go without Rust; out-of-tree modules that build their own Rust
objects there hit this today.
Take the merged CU's language from the first CU the filter keeps, and
its producer too, as producer_clang also steers how the merged DIEs are
processed. Run the filter before checking for DIEs, as the unmerged
path does, so that a first CU without DIEs, such as an assembler CU,
still counts and the output without --lang_exclude does not change. If
every CU is filtered out, the merged CU keeps the first CU's language
and is dropped as before.
Before, with a C++ object linked before a C one:
$ pahole -V --btf_features=force_cu_merging --lang_exclude=c++14 merged.o
Filtering CU first.cpp written in c++14.
Filtering CU written in c++14.
After:
$ pahole -V --btf_features=force_cu_merging --lang_exclude=c++14 merged.o
Filtering CU first.cpp written in c++14.
struct c_only {
int b; /* 0 4 */
...
Add tests/lang_exclude_merged_cu.sh for this.
Tested with clang 21 builds of 7.2.9 with RUST enabled: x86_64 with
ThinLTO (DWARF 4 and 5), full LTO and distributed ThinLTO, and arm64
and riscv64 with ThinLTO. The Rust sample modules get BTF and load with
MODULE_ALLOW_BTF_MISMATCH=n, and the BTF of vmlinux and of the C
modules does not change.
Fixes: b98565e7b17ec24d ("dwarf_loader: Honour --lang_exclude when merging LTO built CUs")
Assisted-by: LLM
Signed-off-by: Alan Derk <linux@alanderk.com>
---
Part of the dwarf_loader.c diff is re-indentation; git show -w is easier
to read.
dwarf_loader.c | 34 +++++++++++------
tests/lang_exclude_merged_cu.sh | 67 +++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+), 12 deletions(-)
create mode 100755 tests/lang_exclude_merged_cu.sh
diff --git a/dwarf_loader.c b/dwarf_loader.c
index 01049e9..fbed36e 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -5329,6 +5329,7 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
struct dwarf_cu *dcu = NULL;
Dwarf_Off off = 0, noff;
struct cu *cu = NULL;
+ bool kept_cu = false;
size_t cuhl;
while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, &pointer_size,
@@ -5441,23 +5442,32 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
cus__add(cus, cu);
}
- Dwarf_Die child;
- if (dwarf_child(cu_die, &child) == 0) {
- bool filtered = false;
+ bool filtered = false;
- if (conf->early_cu_filter) {
- struct cu unmerged_cu = {
- .name = attr_string(cu_die, DW_AT_name, conf),
- .language = attr_numeric(cu_die, DW_AT_language),
- };
+ if (conf->early_cu_filter) {
+ struct cu unmerged_cu = {
+ .name = attr_string(cu_die, DW_AT_name, conf),
+ .language = attr_numeric(cu_die, DW_AT_language),
+ };
- filtered = conf->early_cu_filter(&unmerged_cu) == NULL;
- }
+ filtered = conf->early_cu_filter(&unmerged_cu) == NULL;
+ }
- if (!filtered && die__process_unit(&child, cu, conf, 0) != 0)
- goto out_abort;
+ /*
+ * pahole filters the merged CU by language again, so it must
+ * not keep the language of a CU filtered out here.
+ */
+ if (!filtered && !kept_cu) {
+ cu->language = attr_numeric(cu_die, DW_AT_language);
+ cu->producer_clang = attr_producer_clang(cu_die);
+ kept_cu = true;
}
+ Dwarf_Die child;
+ if (!filtered && dwarf_child(cu_die, &child) == 0 &&
+ die__process_unit(&child, cu, conf, 0) != 0)
+ goto out_abort;
+
off = noff;
}
diff --git a/tests/lang_exclude_merged_cu.sh b/tests/lang_exclude_merged_cu.sh
new file mode 100755
index 0000000..507c6ac
--- /dev/null
+++ b/tests/lang_exclude_merged_cu.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Test --lang_exclude when CUs are merged, as for LTO objects: excluding the
+# language of the first CU must not drop the CUs that follow it.
+
+. "$(dirname "$0")/test_lib.sh"
+outdir=$(make_tmpdir)
+
+trap cleanup EXIT
+
+title_log "Language filtering of merged CUs."
+
+CC=${CC:-gcc}
+CXX=${CXX:-g++}
+LD=${LD:-ld}
+for tool in "$CC" "$CXX" "$LD"; do
+ if ! command -v "${tool%% *}" > /dev/null 2>&1; then
+ info_log "skip: $tool not available"
+ test_skip
+ fi
+done
+
+cat > "$outdir/first.cpp" << 'EOF'
+struct cpp_only {
+ int a;
+};
+
+struct cpp_only cpp_var;
+EOF
+
+cat > "$outdir/second.c" << 'EOF'
+struct c_only {
+ int b;
+};
+
+struct c_only c_var;
+EOF
+
+obj="$outdir/merged.o"
+
+if ! $CXX -g -c -o "$outdir/first.o" "$outdir/first.cpp" 2>/dev/null ||
+ ! $CC -g -c -o "$outdir/second.o" "$outdir/second.c" 2>/dev/null ||
+ ! $LD -r -o "$obj" "$outdir/first.o" "$outdir/second.o" 2>/dev/null; then
+ error_log "FAIL: compilation failed"
+ test_fail
+fi
+
+output=$(pahole --btf_features=force_cu_merging -F dwarf "$obj" 2>/dev/null)
+if ! echo "$output" | grep -q "struct cpp_only" ||
+ ! echo "$output" | grep -q "struct c_only"; then
+ error_log "FAIL: merged CU lacks types without --lang_exclude"
+ test_fail
+fi
+
+output=$(pahole --btf_features=force_cu_merging -F dwarf \
+ --lang_exclude=c++,c++03,c++11,c++14 "$obj" 2>/dev/null)
+if echo "$output" | grep -q "struct cpp_only"; then
+ error_log "FAIL: --lang_exclude=c++ kept the C++ CU"
+ test_fail
+fi
+if ! echo "$output" | grep -q "struct c_only"; then
+ error_log "FAIL: --lang_exclude=c++ dropped the C CU merged after it"
+ test_fail
+fi
+
+test_pass
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH dwarves v2 2/2] dwarf_loader: Load types that kept CUs use from excluded CUs
2026-10-10 0:52 [PATCH dwarves v2 0/2] dwarf_loader: Fix --lang_exclude on merged CUs Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 1/2] dwarf_loader: Take the merged CU language from a CU that is kept Alan Derk
@ 2026-10-10 0:52 ` Alan Derk
1 sibling, 0 replies; 3+ messages in thread
From: Alan Derk @ 2026-10-10 0:52 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Alan Maguire; +Cc: dwarves, bpf, rust-for-linux
With clang LTO, LLVM emits a type such as int once, in the first CU
that uses it, and other CUs refer to it with DW_FORM_ref_addr. Since
commit b98565e7b17ec24d ("dwarf_loader: Honour --lang_exclude when
merging LTO built CUs") the DIEs of the CUs that --lang_exclude filters
out are skipped when merging, so a kept CU that uses a type from one of
them is left with a dangling reference. Members that use such a type
end up typed void: pahole crashes printing them, and -J encodes them
with type_id 0 and exits 0.
$ head zero.c first.cpp second.c
==> zero.c <==
char zero_c;
==> first.cpp <==
int cpp_int;
==> second.c <==
struct c_only { int b; } c_var;
$ clang -flto -g -c zero.c second.c; clang++ -flto -g -c first.cpp
$ clang -flto -fuse-ld=lld -shared -o three.so zero.o first.o second.o
$ pahole --lang_exclude=c++14 three.so
namespace__recode_dwarf_types: couldn't find 0x57 type for 0x8a (member)!
struct c_only {
<ERROR(__class__fprintf:1838): 0 not found!>
Segmentation fault
Remember the offsets of the CUs that the filter skips, and when a type
lookup misses an offset in one of them, load that DIE if it is a type.
The types it refers to are looked up when it is recoded, so they are
loaded too. As this adds types while recoding, cu__recode_dwarf_types()
now repeats its passes until no new tags show up.
After:
$ pahole --lang_exclude=c++14 three.so
struct c_only {
int b; /* 0 4 */
...
Only types are loaded. References to functions and variables in
excluded CUs, such as the abstract origin of a function inlined across
CUs or the function that a C++ using declaration names, still print
"couldn't find", as loading them would add functions in the excluded
language to the output. A nested C++ type that a kept CU refers to
directly is loaded as a top-level type.
Without --lang_exclude, or when no kept CU refers to an excluded one,
nothing is loaded and the output does not change.
Add tests/lang_exclude_lto_refs.sh for this.
Tested with clang 21 full LTO and ThinLTO builds of a C++/C program
in both link orders. Only base types (int, char, long) were loaded, and
apart from the order of the types the output matches that of the other
link order: text and BTF with C++ excluded, text with C excluded. Two
C++ objects built with -std=c++11 and -std=c++17 that include <cstdio>
give the same text with c++11 excluded in either order; there the C
library types they share, such as FILE, are loaded too. ASan reports no
errors on these apart from a leak with -J that predates this series.
gcc 16 LTO, Rust+C ThinLTO and Debian debuginfo processed by dwz load
nothing and do not change, and neither does the BTF of 7.2.9 x86_64 and
arm64 ThinLTO kernels with Rust enabled.
Fixes: b98565e7b17ec24d ("dwarf_loader: Honour --lang_exclude when merging LTO built CUs")
Assisted-by: LLM
Signed-off-by: Alan Derk <linux@alanderk.com>
---
dwarf_loader.c | 95 +++++++++++++++++++++++++++++++---
tests/lang_exclude_lto_refs.sh | 76 +++++++++++++++++++++++++++
2 files changed, 164 insertions(+), 7 deletions(-)
create mode 100755 tests/lang_exclude_lto_refs.sh
diff --git a/dwarf_loader.c b/dwarf_loader.c
index fbed36e..10ab37a 100644
--- a/dwarf_loader.c
+++ b/dwarf_loader.c
@@ -169,6 +169,11 @@ struct alt_pu {
bool hit; /* referenced by main CUs? */
};
+struct excluded_cu {
+ Dwarf_Off start;
+ Dwarf_Off end;
+};
+
struct dwarf_cu {
struct hlist_head *hash_tags; /* tags (functions, etc.) keyed by DWARF offset */
struct hlist_head *hash_types; /* types keyed by DWARF offset */
@@ -183,6 +188,10 @@ struct dwarf_cu {
uint32_t nr_alt_pus;
uint32_t allocated_alt_pus;
bool processing_alt; /* true while processing alt-file DIEs */
+ struct excluded_cu *excluded_cus; /* skipped by early_cu_filter when merging */
+ uint32_t nr_excluded_cus;
+ Dwarf *dw;
+ struct conf_load *conf;
};
static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
@@ -215,6 +224,8 @@ static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu)
dcu->alt_pus = NULL;
dcu->nr_alt_pus = 0;
dcu->allocated_alt_pus = 0;
+ dcu->excluded_cus = NULL;
+ dcu->nr_excluded_cus = 0;
/*
* processing_alt is per-merged-CU state, not thread-safe.
* The merged-CU path (cus__merge_and_process_cu) is
@@ -249,6 +260,7 @@ static void dwarf_cu__delete(struct cu *cu)
zfree(&dcu->imported_units);
zfree(&dcu->alt_pus);
+ zfree(&dcu->excluded_cus);
if (dcu->alt) {
cu__free(cu, dcu->alt->hash_tags);
cu__free(cu, dcu->alt->hash_types);
@@ -475,6 +487,8 @@ static struct dwarf_tag *__dwarf_cu__find_tag_by_ref(const struct dwarf_cu *cu,
dtag->from_types_section.field, \
dtag->from_alt.field)
+static struct dwarf_tag *dwarf_cu__load_excluded_type(struct dwarf_cu *dcu, Dwarf_Off ref);
+
/* Same as __dwarf_cu__find_tag_by_ref but for type lookups (hash_types). */
static struct dwarf_tag *__dwarf_cu__find_type_by_ref(struct dwarf_cu *dcu,
const Dwarf_Off ref,
@@ -497,6 +511,8 @@ static struct dwarf_tag *__dwarf_cu__find_type_by_ref(struct dwarf_cu *dcu,
struct dwarf_tag *dtag = hashtags__find(dcu->hash_types, ref);
+ if (dtag == NULL)
+ dtag = dwarf_cu__load_excluded_type(dcu, ref);
if (dtag)
dcu->last_type_lookup = dtag;
@@ -3693,6 +3709,62 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *co
return 0;
}
+static int dwarf_cu__add_excluded_cu(struct dwarf_cu *dcu, Dwarf_Off start, Dwarf_Off end)
+{
+ struct excluded_cu *cus = realloc(dcu->excluded_cus,
+ (dcu->nr_excluded_cus + 1) * sizeof(*cus));
+
+ if (cus == NULL)
+ return -ENOMEM;
+
+ cus[dcu->nr_excluded_cus++] = (struct excluded_cu){ .start = start, .end = end };
+ dcu->excluded_cus = cus;
+ return 0;
+}
+
+static bool dwarf_cu__in_excluded_cu(const struct dwarf_cu *dcu, Dwarf_Off offset)
+{
+ for (uint32_t i = 0; i < dcu->nr_excluded_cus; i++)
+ if (offset >= dcu->excluded_cus[i].start && offset < dcu->excluded_cus[i].end)
+ return true;
+ return false;
+}
+
+/*
+ * With LTO, LLVM emits a type such as int once, in the first CU that uses it,
+ * and other CUs refer to it with DW_FORM_ref_addr. So the CUs kept when merging
+ * can refer to types in CUs that early_cu_filter excluded. Load those types
+ * when they are looked up, and nothing else from the excluded CUs.
+ */
+static struct dwarf_tag *dwarf_cu__load_excluded_type(struct dwarf_cu *dcu, Dwarf_Off ref)
+{
+ struct tag *tag, die_tag = {};
+ uint32_t id = 0;
+ Dwarf_Die die;
+
+ if (!dwarf_cu__in_excluded_cu(dcu, ref) || dwarf_offdie(dcu->dw, ref, &die) == NULL)
+ return NULL;
+
+ /*
+ * A using declaration can name a function, and processing a function
+ * adds its parameters to the CU's tables, so check the tag first.
+ */
+ die_tag.tag = dwarf_tag(&die);
+ if (!tag__is_tag_type(&die_tag))
+ return NULL;
+
+ tag = die__process_tag(&die, dcu->cu, 1, dcu->conf);
+ if (tag == NULL || tag == &unsupported_tag)
+ return NULL;
+
+ /* As in die__process_unit(). */
+ if (tag->tag != DW_TAG_unspecified_type)
+ cu__add_tag(dcu->cu, tag, &id);
+ cu__hash(dcu->cu, tag);
+ tag__dwarf(tag)->small_id = id;
+ return tag__dwarf(tag);
+}
+
static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu);
static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu)
@@ -4497,10 +4569,10 @@ static int cu__resolve_func_ret_types_optimized(struct cu *cu, struct conf_load
static int cu__recode_dwarf_types_table(struct cu *cu,
struct ptr_table *pt,
- uint32_t i)
+ uint32_t *i)
{
- for (; i < pt->nr_entries; ++i) {
- struct tag *tag = pt->entries[i];
+ for (; *i < pt->nr_entries; ++*i) {
+ struct tag *tag = pt->entries[*i];
if (tag != NULL) /* void, see cu__new */
if (tag__recode_dwarf_type(tag, cu))
@@ -4512,10 +4584,15 @@ static int cu__recode_dwarf_types_table(struct cu *cu,
static int cu__recode_dwarf_types(struct cu *cu)
{
- if (cu__recode_dwarf_types_table(cu, &cu->types_table, 1) ||
- cu__recode_dwarf_types_table(cu, &cu->tags_table, 0) ||
- cu__recode_dwarf_types_table(cu, &cu->functions_table, 0))
- return -1;
+ uint32_t types = 1, tags = 0, functions = 0;
+
+ /* Recoding can add tags, see dwarf_cu__load_excluded_type(). */
+ do {
+ if (cu__recode_dwarf_types_table(cu, &cu->types_table, &types) ||
+ cu__recode_dwarf_types_table(cu, &cu->tags_table, &tags) ||
+ cu__recode_dwarf_types_table(cu, &cu->functions_table, &functions))
+ return -1;
+ } while (types < cu->types_table.nr_entries || tags < cu->tags_table.nr_entries);
return 0;
}
@@ -5366,6 +5443,8 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
dcu->cu = cu;
dcu->type_unit = type_dcu;
+ dcu->dw = dw;
+ dcu->conf = conf;
cu->priv = dcu;
cu->dfops = &dwarf__ops;
@@ -5451,6 +5530,8 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf,
};
filtered = conf->early_cu_filter(&unmerged_cu) == NULL;
+ if (filtered && dwarf_cu__add_excluded_cu(dcu, off, noff))
+ goto out_abort;
}
/*
diff --git a/tests/lang_exclude_lto_refs.sh b/tests/lang_exclude_lto_refs.sh
new file mode 100755
index 0000000..56bcb7b
--- /dev/null
+++ b/tests/lang_exclude_lto_refs.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Test --lang_exclude on clang LTO objects, where a kept CU refers to a type
+# in an excluded CU: LLVM emits int once, in the first CU that uses it.
+
+. "$(dirname "$0")/test_lib.sh"
+outdir=$(make_tmpdir)
+
+trap cleanup EXIT
+
+title_log "Language filtering of LTO CUs that refer to excluded CUs."
+
+for tool in clang clang++ ld.lld; do
+ if ! command -v $tool > /dev/null 2>&1; then
+ info_log "skip: $tool not available"
+ test_skip
+ fi
+done
+
+echo 'char zero_c;' > "$outdir/zero.c"
+
+cat > "$outdir/first.cpp" << 'EOF'
+struct cpp_only {
+ int a;
+};
+
+struct cpp_only cpp_var;
+EOF
+
+cat > "$outdir/second.c" << 'EOF'
+struct c_only {
+ int b;
+};
+
+struct c_only c_var;
+EOF
+
+obj="$outdir/lto.so"
+
+if ! clang -flto -g -c -o "$outdir/zero.o" "$outdir/zero.c" 2>/dev/null ||
+ ! clang++ -flto -g -c -o "$outdir/first.o" "$outdir/first.cpp" 2>/dev/null ||
+ ! clang -flto -g -c -o "$outdir/second.o" "$outdir/second.c" 2>/dev/null ||
+ ! clang -flto -fuse-ld=lld -shared -o "$obj" "$outdir/zero.o" \
+ "$outdir/first.o" "$outdir/second.o" 2>/dev/null; then
+ error_log "FAIL: compilation failed"
+ test_fail
+fi
+
+lang_exclude=c++,c++03,c++11,c++14
+btf="$outdir/lto.btf"
+
+check()
+{
+ if [ $1 -ne 0 ]; then
+ error_log "FAIL: $2: pahole failed"
+ test_fail
+ fi
+ if echo "$3" | grep -q "struct cpp_only"; then
+ error_log "FAIL: $2: --lang_exclude=c++ kept the C++ CU"
+ test_fail
+ fi
+ if ! echo "$3" | grep -Eq "^[[:space:]]+int[[:space:]]+b;"; then
+ error_log "FAIL: $2: c_only.b lost its type, int from the C++ CU"
+ test_fail
+ fi
+}
+
+output=$(pahole -F dwarf --lang_exclude=$lang_exclude "$obj" 2>/dev/null)
+check $? "DWARF" "$output"
+
+pahole -J --btf_encode_detached="$btf" --lang_exclude=$lang_exclude "$obj" > /dev/null 2>&1
+output=$(pahole -F btf "$btf" 2>/dev/null)
+check $? "BTF" "$output"
+
+test_pass
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-10 0:52 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-10 0:52 [PATCH dwarves v2 0/2] dwarf_loader: Fix --lang_exclude on merged CUs Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 1/2] dwarf_loader: Take the merged CU language from a CU that is kept Alan Derk
2026-10-10 0:52 ` [PATCH dwarves v2 2/2] dwarf_loader: Load types that kept CUs use from excluded CUs Alan Derk
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox