From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794582368; b=A6OIGKEhUETearBJLLnCcpO0Cr4IKmMC66FjtaxlLcmm3qjtzpcmK3etTtjWi7aA9GY7 uWSBMxU6fjULnNiqp4SIZKb41ADCwvJfJdNEWWjOd8lSn/NKgXCPTBSnMG6xX+RBC0u3q XSsNPsZlr7ZFcWygGcTuYligqtbY7rkDTJeu+o1KpqCWSn3pNXpRexUJQL9vxFOQDMbnQ EsN6EZHsxd2U+5jg9QW/3qCAmTomjhHfyehon5+Z2zff6M/76kZqVAbqaNrawV4s3sD0p apJKzAgA8KQ81R+N7K0SC3nzvGcuiLvBoQdmIlMA2N7WixYAZUyW5UyFlgmCqyP4blQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794582368; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:MIME-Version:Content-Transfer-Encoding; bh=W3ZRwmyeoSx2P6LJWkTE9jsMV9ncUeCi/EgPMhmK56w=; b=eyfXntSGBcig+wlBDpXs1oGA2CkuGXh9oMpdrMEwbLg7XtnAyteG8GxjzuqyvxC+4jZu 3jAPqrFSO8sPAwyQWGbyZZbIxlZ+3kQTyg8nFp/kGYrQO0sJwXJz/Vwn5GyiB4YcUormm 0wDoGAenCZgkqtpQJEhDfziZ7sr8v9dDW1AVGievHDZ9UubsPWUks69u08jhvaXkFg7CR 1IvWBmylxhVG9SwTneHIVbmeN8wRizRPQ8YP0RfyDa/eFNP8weGPhFHVaLr0e2zZslMRG l8h/ViF1XCb1/2Gmn4BXpPAoUT8PFMh/G7lUDImmVgN1/e8Xy5fF74P45MQSWUf9Zvg== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=VIoU489R; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C25D7606A33B; Fri, 13 Nov 2026 15:06:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=VIoU489R Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48FB31F000C5; Fri, 13 Nov 2026 15:06:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1794582368; bh=W3ZRwmyeoSx2P6LJWkTE9jsMV9ncUeCi/EgPMhmK56w=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=VIoU489RoF9/sfLJmgAffJ5L/4ou1kZesejZbxoY0kiCOvp+Vf2DFcxNLswu1POzl N/3ZTGD6LubTeSC1qOL6238vRgvOiiKfIbwASOU1ymsRHQgh+EhV9hkubkuqstj0eM yXFnY/nXIz82yj7DnvpZ8+b8GQCqZ//WZUrghW/5xMQckNKKaQDkckfJSrw1hiSRSj M+Y9DIoS/bAB1l+Kzulgdv5Rt3nPjWEPwgcUQlWp0Qr1JVMJYF7vjyYlnsAtOFBY4B Pvw8AWkuAOvzxuUBDq2EQyaqP6Ul1VtS6mAOGdAaCWhTlo9Ba5QehdhKsVM9/ENg2/ g/wVTaCnW3p6A== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , James Clark , Jiri Olsa , Ian Rogers , Adrian Hunter , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo Subject: [PATCH v1 02/12] perf annotate-data: Resolve DW_OP_addrx global variables Date: Fri, 13 Nov 2026 12:05:43 -0300 Message-ID: <20261113150555.1163049-3-acme@kernel.org> X-Mailer: git-send-email 2.56.1 In-Reply-To: <20261113150555.1163049-1-acme@kernel.org> References: <20261113150555.1163049-1-acme@kernel.org> X-Mailing-List: linux-perf-users@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Arnaldo Carvalho de Melo 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 Signed-off-by: Arnaldo Carvalho de Melo --- .../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 +#include + +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