From: Arnaldo Carvalho de Melo <acme@kernel.org>
To: Namhyung Kim <namhyung@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>,
Thomas Gleixner <tglx@linutronix.de>,
James Clark <james.clark@linaro.org>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
Clark Williams <williams@redhat.com>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
Arnaldo Carvalho de Melo <acme@redhat.com>
Subject: [PATCH v2 02/11] perf annotate-data: Resolve DW_OP_addrx global variables
Date: Fri, 13 Nov 2026 17:08:40 -0300 [thread overview]
Message-ID: <20261113200850.2803460-3-acme@kernel.org> (raw)
In-Reply-To: <20261113200850.2803460-1-acme@kernel.org>
From: Arnaldo Carvalho de Melo <acme@redhat.com>
clang emits DW_AT_location with DW_OP_addrx for global variables in
DWARF 5, gcc emits DW_OP_addr. The address index was not resolved, so
those variables were not found by address; the by-name fallback also
missed the ones in .bss past the file backed end of the last segment.
Resolve the index with dwarf_getlocation_attr() + dwarf_formaddr() and
use the resulting address in the by-address lookup and in the global
variable cache. Add a test that compiles the workload with clang
-gdwarf-5 and checks that the global is annotated.
Fixes: d60469d7c0e5c4e8 ("perf dwarf-aux: Add die_find_variable_by_addr()")
Fixes: d7b60803a790b716 ("perf dwarf-aux: Add die_collect_global_vars()")
Cc: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
.../tests/shell/data_type_profiling_clang.sh | 108 ++++++++++++++++++
tools/perf/util/dwarf-aux.c | 42 ++++++-
2 files changed, 145 insertions(+), 5 deletions(-)
create mode 100755 tools/perf/tests/shell/data_type_profiling_clang.sh
diff --git a/tools/perf/tests/shell/data_type_profiling_clang.sh b/tools/perf/tests/shell/data_type_profiling_clang.sh
new file mode 100755
index 0000000000000000..8e425952d4742a2c
--- /dev/null
+++ b/tools/perf/tests/shell/data_type_profiling_clang.sh
@@ -0,0 +1,108 @@
+#!/bin/bash
+# perf data type profiling tests with clang DWARF 5
+# SPDX-License-Identifier: GPL-2.0
+
+set -e
+
+# clang describes the location of globals with DW_OP_addrx where gcc
+# uses DW_OP_addr, so the workload has to be built here to get that
+# encoding.
+
+command -v clang > /dev/null || exit 2
+
+perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
+perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
+prog=$(mktemp /tmp/__perf_test.clang.XXXXX)
+src="${prog}.c"
+
+cleanup()
+{
+ rm -f "$perfdata" "$perfout" "$prog" "$src"
+ trap - EXIT TERM INT
+}
+
+trap_cleanup()
+{
+ echo "Unexpected signal in ${FUNCNAME[1]}"
+ cleanup
+ exit 1
+}
+trap trap_cleanup EXIT TERM INT
+
+# No point in recording if the PMU cannot do memory events.
+if perf mem record -o /dev/null -- true 2>&1 | \
+ grep -q "failed: no PMU supports the memory events"; then
+ cleanup
+ exit 2
+fi
+if ! perf mem record -o /dev/null -- true 2>/dev/null; then
+ echo "Skip: cannot record memory events on this PMU"
+ cleanup
+ exit 2
+fi
+
+cat > "$src" <<'EOF'
+#include <signal.h>
+#include <unistd.h>
+
+struct conn {
+ int saddr;
+ int daddr;
+ long bytes;
+};
+
+static volatile struct conn conn;
+static volatile sig_atomic_t done;
+
+static void stop(int sig)
+{
+ done = 1;
+}
+
+int main(void)
+{
+ unsigned long sum = 0;
+ int i = 0;
+
+ signal(SIGALRM, stop);
+ alarm(1);
+
+ while (!done) {
+ conn.saddr = i;
+ conn.daddr = i + 1;
+ sum += conn.bytes;
+ i++;
+ }
+ return sum != 0;
+}
+EOF
+
+# -fPIE keeps the accesses PC-relative on x86_64, the operand form the
+# data type resolver handles.
+if ! clang -O0 -gdwarf-5 -fPIE -pie -o "$prog" "$src"; then
+ echo "Skip: cannot build the workload with clang"
+ cleanup
+ exit 2
+fi
+
+if ! perf mem record -o "$perfdata" -- "$prog" > /dev/null 2>&1; then
+ echo "FAIL: perf mem record"
+ cleanup
+ exit 1
+fi
+
+if ! perf annotate --code-with-type -i "$perfdata" --stdio \
+ --percent-limit 1 > "$perfout" 2>/dev/null; then
+ echo "FAIL: perf annotate"
+ cleanup
+ exit 1
+fi
+
+if ! grep -q "# data-type: struct conn" "$perfout"; then
+ echo "FAIL: struct conn not resolved, DW_OP_addrx not handled?"
+ cleanup
+ exit 1
+fi
+
+echo "DW_OP_addrx global resolved"
+cleanup
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index 48a11c95a67686e4..5db7458f01116a4e 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -14,6 +14,11 @@
#include "strbuf.h"
#include "string2.h"
+/* DWARF 5 address index, libdw's dwarf_getlocations() returns it unresolved */
+#ifndef DW_OP_addrx
+#define DW_OP_addrx 0xa1
+#endif
+
/**
* cu_find_realpath - Find the realpath of the target file
* @cu_die: A DIE(dwarf information entry) of CU(compilation Unit)
@@ -1629,6 +1634,31 @@ Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg,
return result;
}
+/*
+ * Get the absolute address of a location expression that consists of a
+ * single address, either DW_OP_addr or DW_OP_addrx. libdw leaves the
+ * DWARF 5 address index unresolved, it has to be looked up in .debug_addr.
+ */
+static bool die_get_location_addr(Dwarf_Attribute *attr, Dwarf_Op *ops,
+ Dwarf_Addr *addr)
+{
+ if (ops->atom == DW_OP_addr) {
+ *addr = ops->number;
+ return true;
+ }
+
+ if (ops->atom == DW_OP_addrx) {
+ Dwarf_Attribute addr_attr;
+
+ if (dwarf_getlocation_attr(attr, ops, &addr_attr) != 0)
+ return false;
+
+ return dwarf_formaddr(&addr_attr, addr) == 0;
+ }
+
+ return false;
+}
+
/* Only checks direct child DIEs in the given scope */
static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg)
{
@@ -1647,11 +1677,13 @@ static int __die_find_var_addr_cb(Dwarf_Die *die_mem, void *arg)
return DIE_FIND_CB_SIBLING;
while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
- if (ops->atom != DW_OP_addr)
+ Dwarf_Addr addr;
+
+ if (!die_get_location_addr(&attr, ops, &addr))
continue;
if (check_allowed_ops(ops, nops) &&
- match_var_offset(die_mem, data, data->addr, ops->number,
+ match_var_offset(die_mem, data, data->addr, addr,
/*is_pointer=*/false))
return DIE_FIND_CB_END;
}
@@ -1777,7 +1809,7 @@ static int __die_collect_global_vars_cb(Dwarf_Die *die_mem, void *arg)
Dwarf_Die type_die;
int tag = dwarf_tag(die_mem);
Dwarf_Attribute attr;
- Dwarf_Addr base, start, end;
+ Dwarf_Addr base, start, end, addr;
Dwarf_Op *ops;
size_t nops;
struct die_var_type *vt;
@@ -1792,7 +1824,7 @@ static int __die_collect_global_vars_cb(Dwarf_Die *die_mem, void *arg)
if (dwarf_getlocations(&attr, 0, &base, &start, &end, &ops, &nops) <= 0)
return DIE_FIND_CB_SIBLING;
- if (ops->atom != DW_OP_addr)
+ if (!die_get_location_addr(&attr, ops, &addr))
return DIE_FIND_CB_SIBLING;
if (!check_allowed_ops(ops, nops))
@@ -1808,7 +1840,7 @@ static int __die_collect_global_vars_cb(Dwarf_Die *die_mem, void *arg)
vt->die_off = dwarf_dieoffset(&type_die);
vt->die_tag = dwarf_tag(&type_die);
vt->from_alt = !die_same_file(die_mem, &type_die);
- vt->addr = ops->number;
+ vt->addr = addr;
vt->end = 0;
vt->has_range = false;
vt->reg = -1;
--
2.56.0
next prev parent reply other threads:[~2026-11-13 20:09 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 20:08 [PATCH v2 0/11] perf coverage: A harness for perf, and the fixes it found Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 01/11] perf scripts: Add a coverage harness for perf Arnaldo Carvalho de Melo
2026-11-13 20:08 ` Arnaldo Carvalho de Melo [this message]
2026-11-13 20:08 ` [PATCH v2 03/11] perf tests: Exercise the flexible array member path Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 04/11] perf annotate-data: Count flexible array accesses for the whole struct Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 05/11] perf tests: Exercise data type resolution from a register Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 06/11] perf annotate: Print the stats after the annotations Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 07/11] perf tests: Silence the libbfd probe in build-test Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 08/11] perf build: Record the display-only features in FEATURE-DUMP Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 09/11] perf tests: Fix the Intel PT virtual LBR check Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 10/11] perf test: Drop samples without an IP in the dlfilter test Arnaldo Carvalho de Melo
2026-11-13 20:08 ` [PATCH v2 11/11] perf test: Skip the LBR inline unwinding check when unsupported 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=20261113200850.2803460-3-acme@kernel.org \
--to=acme@kernel.org \
--cc=acme@redhat.com \
--cc=adrian.hunter@intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mingo@kernel.org \
--cc=namhyung@kernel.org \
--cc=tglx@linutronix.de \
--cc=williams@redhat.com \
/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