From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E750E24678E for ; Mon, 29 Sep 2025 19:08:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172910; cv=none; b=qMwmNFB20uiCZnwN4ABvZVLcIOP2IDW0w5yXbNIFoN3Tal5PhWPH66OfzZ4ISOU+d5TXh+jSsltDc5EYt01A+DN+Zl+86jkY12ypKztkeTxrApK2zPY7JZo9TdjJS4MR4qxr+dTL21Y7yM/ZquQgSvpmsG3lRSSBpKZIjxFZm0s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172910; c=relaxed/simple; bh=jts437rB1GIJacBrxxx4epa/L3BnkDASSEk1qV6a9yg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=kUfYoTPeI4LmxvKyCLNzqnEz9FZwcv8In1zhOzbTDoCfPdPmko9FDP7c3Wabg9PJyrWByNxadB2qZmE/JXOcOdOLvEPBjfBq4Lc6fLNUQ1dgE46KYnTV/4P9RTppncT0iksK4US3RbnM2HVO/YhOZH7kvUGdJHnWQQZfoSFQMk4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=3OUGFkW5; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="3OUGFkW5" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2681623f927so47996925ad.0 for ; Mon, 29 Sep 2025 12:08:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172908; x=1759777708; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=cCPSZa95CLjIX1ekaMXSBPwEqC8hhuYwGZNsoeQYOdI=; b=3OUGFkW507sLNe0htroiKFxKbJl9huWN8KXqz/TxarIf1pyl30HMcf7jVTrBdGn1pR 8AeqCGvJfaZVz17LrzcCi6dOoyz4XV5w/aHXTToAYjheflhL+ID510+QABES6ARXMm7x Vrzffe1Wlx5/2m8Xav/c64EoL580fAGPwUjA0RSqNe99lo8YkcWrjKt6qpRAztleoYl2 ZIHmTIYwRSESxnBaZ3+a3H6krSAsig18WG1FtbG7D7e23ZpQIeN3MI+gORr8u2iYo54h FVQCkNZ1UimfpI4170pAUzTPv1cLObVA3EH02ecZfSLXMe+vIHZjyImRmUhUPnGneaTS As7A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172908; x=1759777708; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=cCPSZa95CLjIX1ekaMXSBPwEqC8hhuYwGZNsoeQYOdI=; b=KI7SZilLeX9zklHSYsK9ZhBu5skYmMxp4JHfNNbZmzZv/No1shbur94kqwsZfPSo+G fA7kw2IlOvvxQXyOVF5DW8LD/J5TbW1Z2V3b6JJRbv1XxYm5pHfIS5Aw/4lwGHOf6Ko+ l+PxGOiHQ3vJQrCHYlaTaVGkdmyZlCtzwacRn7FVLejhxuv4JjsbRwti+e+U2Pq40P1J mK+e65ux1dQLR4rRge9hbo9lQ2+uWGJgsHqH7xgrvKtN4gj5YgHgLhz9eDjdewxy2PHX qgekNWiewM/e20wsIRyoJRSAdFx7eYMstsQaYmYtbSLrPOCjeVnvuaeXUeV2abnFrRJ3 Of7A== X-Forwarded-Encrypted: i=1; AJvYcCXPAvhO2Ecb8TYLKSornTgSto0GPUPxe+npz3jWivuFwg8som6njk7LhGAFGKIDe64w9qUlO2YTPlduflI=@vger.kernel.org X-Gm-Message-State: AOJu0Yyd9SI8yfJUBsJaNQiXhDUqzWllWWG3qrFV8EB4OR1BpINACMR6 CoS1NF5SFsYSf4vZxNxBLAVRelVt4Lm3Hf5N7l59Fm6mE/U0qDZGF3Cy9MDb5cIzUatOGocADK5 Nmndtu5aRHg== X-Google-Smtp-Source: AGHT+IHRqf99uJlVCyIDD61PqSw9guLbG8f2axDFVLPxmfvJQ46Ggtr9CTWOji6+cSZrHK7d8OcAI0/g0sj4 X-Received: from pjbfh12.prod.google.com ([2002:a17:90b:34c:b0:32f:46d:993b]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:ecca:b0:269:8d16:42d1 with SMTP id d9443c01a7336-27ed4aac32cmr171706855ad.50.1759172908198; Mon, 29 Sep 2025 12:08:28 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:51 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-2-irogers@google.com> Subject: [PATCH v6 01/15] perf map: Constify objdump offset/address conversion APIs From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Make the map argument const as the conversion act won't modify the map and this allows other callers to use a const struct map. Signed-off-by: Ian Rogers --- tools/perf/util/map.c | 19 +++++++++++++++---- tools/perf/util/map.h | 6 +++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index b46c68c24d1c..41cdddc987ee 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -513,6 +513,8 @@ void srccode_state_free(struct srccode_state *state) state->line =3D 0; } =20 +static const struct kmap *__map__const_kmap(const struct map *map); + /** * map__rip_2objdump - convert symbol start address to objdump address. * @map: memory map @@ -524,9 +526,9 @@ void srccode_state_free(struct srccode_state *state) * * Return: Address suitable for passing to "objdump --start-address=3D" */ -u64 map__rip_2objdump(struct map *map, u64 rip) +u64 map__rip_2objdump(const struct map *map, u64 rip) { - struct kmap *kmap =3D __map__kmap(map); + const struct kmap *kmap =3D __map__const_kmap(map); const struct dso *dso =3D map__dso(map); =20 /* @@ -569,7 +571,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip) * * Return: Memory address. */ -u64 map__objdump_2mem(struct map *map, u64 ip) +u64 map__objdump_2mem(const struct map *map, u64 ip) { const struct dso *dso =3D map__dso(map); =20 @@ -586,7 +588,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip) } =20 /* convert objdump address to relative address. (To be removed) */ -u64 map__objdump_2rip(struct map *map, u64 ip) +u64 map__objdump_2rip(const struct map *map, u64 ip) { const struct dso *dso =3D map__dso(map); =20 @@ -618,6 +620,15 @@ struct kmap *__map__kmap(struct map *map) return (struct kmap *)(&RC_CHK_ACCESS(map)[1]); } =20 +static const struct kmap *__map__const_kmap(const struct map *map) +{ + const struct dso *dso =3D map__dso(map); + + if (!dso || !dso__kernel(dso)) + return NULL; + return (struct kmap *)(&RC_CHK_ACCESS(map)[1]); +} + struct kmap *map__kmap(struct map *map) { struct kmap *kmap =3D __map__kmap(map); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 9cadf533a561..979b3e11b9bc 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -133,13 +133,13 @@ static inline u64 map__unmap_ip(const struct map *map= , u64 ip_or_rip) } =20 /* rip/ip <-> addr suitable for passing to `objdump --start-address=3D` */ -u64 map__rip_2objdump(struct map *map, u64 rip); +u64 map__rip_2objdump(const struct map *map, u64 rip); =20 /* objdump address -> memory address */ -u64 map__objdump_2mem(struct map *map, u64 ip); +u64 map__objdump_2mem(const struct map *map, u64 ip); =20 /* objdump address -> rip */ -u64 map__objdump_2rip(struct map *map, u64 ip); +u64 map__objdump_2rip(const struct map *map, u64 ip); =20 struct symbol; struct thread; --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E85F32494F8 for ; Mon, 29 Sep 2025 19:08:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172917; cv=none; b=A2uVYZlrw8pVfdz75/EO3GoXMsdjAcJ44xj/mxkuXMsXcmKJs3UH/+8uezWC157Nr4noqvRi3+aoOr5d/uQRUbL7gzj2iFHSuZFg7aQn75+Vw1vXVpsTTkWLYdxAQ/2s/cTSHd/KXIf3VCF0Ra3/HMvdNFX4EcZy67NN5x7Drpg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172917; c=relaxed/simple; bh=AH10k0VfIWS3Uo+GJRjr4K7nLh0LoWG8LK3IT0DYoLc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=geY+1pkYZoI5FMtjoDpvX9akSoaT1NxPWQZnvqWMteUwWfygflrFH7Sw82QXfs+STxnDTF8Et2cnf00Z9fjRYIroXBG0wMBMxkzSVu4ZpGW4bDEEbmt5OzRwwNlDNkEekg25OPOTzrPjApBYftG3phhXUPlKqU+FZ55HeX2HtKg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Nt0ooWFK; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Nt0ooWFK" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-33826e101ecso1390710a91.1 for ; Mon, 29 Sep 2025 12:08:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172914; x=1759777714; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=MqGyR28f1tm+gvVGPtWeEGEaRPSoyJeZAHGoxJSzkRI=; b=Nt0ooWFKZZ/AglWHXX+heBh0TcBpIqLypIl+XV8I7pYdb3g053f0GvH3rmFMHbZZMF MMesi5DOyQ2dilr/XWASrFj99TqlDDKU/3lFJoHkNasU5DrGT43nZe0hfvAWM/BAYhWB 9jpRTwZrXw0og6+metyV7EGUtCRMpMYHUMdvvExlvdKMcxx/bacffoMu+fuGi3ygRQC/ 4FJGqIEnFg3p+lxEZHv8O+JzkoUBwJ5z2feqkUbOBbId3nOUo2RPsHcCGgYmEOdRwq5r 57wS3kYcguQtcs6mdPbbvugCIjm/0Eobue0E72GZcdOEkqsH5uhzcF+64Sxj15a7WHuV gagg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172914; x=1759777714; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=MqGyR28f1tm+gvVGPtWeEGEaRPSoyJeZAHGoxJSzkRI=; b=So67BPkVwfSrXeCRCwZiUS3irp4KN0uO1xF3EUn8qt/R7YixzNYrY7FPmhlhoupE1q 7oVleWmDd1iL5elilMVwO5pOfGJc+fxn41Hxk6RbAquIn/kh5lY1JhXDYOoMtFX4KInB DNeAwSZvQfWxitW7oOShfWvVCmJYmQ0JJMnjOBHDiL2MtAWMGEsBDUYDJVM/bHHAPvO2 3IovXRWYco4GVM1khFgsWjNIit7+kFtHTvwh6HwcZmVRm3l01Qk5CHwLCsQTGCZ3AVs7 3i0XeHgIuHV53W44zAGgwOkkYJlfpKcg9if9PunLQeYL/JwaBvy4qKM6dMqR8NnO/o8G JknQ== X-Forwarded-Encrypted: i=1; AJvYcCWPMV8VrZrfRznBZEgH8ygH0xZ5ObCCowkcbo9w+BqwoRxscUa0h6NhQHaFJo1GIj3+2zTEedMso48q1ek=@vger.kernel.org X-Gm-Message-State: AOJu0YzJOfngO0gHM/Fh8Amp0yGM8dsRWFF32y2hjwvpJ/1T98wtWfzS tyBObMMZ5oMcDeM94JvYTID5kK8T479VOZEsMbuAU5tuMmz3tBJWEFwGeYTu13Rp/LhatP58/A+ Y6VaTqQw4Vw== X-Google-Smtp-Source: AGHT+IG7ZICS04WxKh5JePvtc+PmCuMFWnNdbaGpZEx0vtV6SySpH3GRjr83YxtMrTey6uBz0OZ1MPVuUUcd X-Received: from pjbnm6.prod.google.com ([2002:a17:90b:19c6:b0:330:5945:699e]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:3846:b0:327:53f0:6368 with SMTP id 98e67ed59e1d1-3383abe25aemr1686317a91.2.1759172914105; Mon, 29 Sep 2025 12:08:34 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:52 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-3-irogers@google.com> Subject: [PATCH v6 02/15] perf capstone: Move capstone functionality into its own file From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Capstone disassembly support was split between disasm.c and print_insn.c. Move support out of these files into capstone.[ch] and remove include capstone/capstone.h from those files. As disassembly routines can fail, make failure the only option without HAVE_LIBCAPSTONE_SUPPORT. For simplicity's sake, duplicate the read_symbol utility function. The intent with moving capstone support into a single file is that dynamic support, using dlopen for libcapstone, can be added in later patches. This can potentially always succeed or fail, so relying on ifdefs isn't sufficient. Using dlopen is a useful option to minimize the perf tools dependencies and potentially size. Signed-off-by: Ian Rogers --- tools/perf/builtin-script.c | 2 - tools/perf/util/Build | 1 + tools/perf/util/capstone.c | 536 +++++++++++++++++++++++++++++++++++ tools/perf/util/capstone.h | 24 ++ tools/perf/util/disasm.c | 356 +---------------------- tools/perf/util/print_insn.c | 117 +------- 6 files changed, 569 insertions(+), 467 deletions(-) create mode 100644 tools/perf/util/capstone.c create mode 100644 tools/perf/util/capstone.h diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index d9fbdcf72f25..818a6490dab4 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1224,7 +1224,6 @@ static int any_dump_insn(struct evsel *evsel __maybe_= unused, u8 *inbuf, int inlen, int *lenp, FILE *fp) { -#ifdef HAVE_LIBCAPSTONE_SUPPORT if (PRINT_FIELD(BRSTACKDISASM)) { int printed =3D fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->i= s64bit, (uint8_t *)inbuf, inlen, ip, lenp, @@ -1233,7 +1232,6 @@ static int any_dump_insn(struct evsel *evsel __maybe_= unused, if (printed > 0) return printed; } -#endif return fprintf(fp, "%s", dump_insn(x, ip, inbuf, inlen, lenp)); } =20 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 4959e7a990e4..4e8414b7c283 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -8,6 +8,7 @@ perf-util-y +=3D block-info.o perf-util-y +=3D block-range.o perf-util-y +=3D build-id.o perf-util-y +=3D cacheline.o +perf-util-y +=3D capstone.o perf-util-y +=3D config.o perf-util-y +=3D copyfile.o perf-util-y +=3D ctype.o diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c new file mode 100644 index 000000000000..dd58e574aa52 --- /dev/null +++ b/tools/perf/util/capstone.c @@ -0,0 +1,536 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "capstone.h" +#include "annotate.h" +#include "addr_location.h" +#include "debug.h" +#include "disasm.h" +#include "dso.h" +#include "machine.h" +#include "map.h" +#include "namespaces.h" +#include "print_insn.h" +#include "symbol.h" +#include "thread.h" +#include +#include + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +#include +#endif + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +static int capstone_init(struct machine *machine, csh *cs_handle, bool is6= 4, + bool disassembler_style) +{ + cs_arch arch; + cs_mode mode; + + if (machine__is(machine, "x86_64") && is64) { + arch =3D CS_ARCH_X86; + mode =3D CS_MODE_64; + } else if (machine__normalized_is(machine, "x86")) { + arch =3D CS_ARCH_X86; + mode =3D CS_MODE_32; + } else if (machine__normalized_is(machine, "arm64")) { + arch =3D CS_ARCH_ARM64; + mode =3D CS_MODE_ARM; + } else if (machine__normalized_is(machine, "arm")) { + arch =3D CS_ARCH_ARM; + mode =3D CS_MODE_ARM + CS_MODE_V8; + } else if (machine__normalized_is(machine, "s390")) { + arch =3D CS_ARCH_SYSZ; + mode =3D CS_MODE_BIG_ENDIAN; + } else { + return -1; + } + + if (cs_open(arch, mode, cs_handle) !=3D CS_ERR_OK) { + pr_warning_once("cs_open failed\n"); + return -1; + } + + if (machine__normalized_is(machine, "x86")) { + /* + * In case of using capstone_init while symbol__disassemble + * setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts + * is set via annotation args + */ + if (disassembler_style) + cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + /* + * Resolving address operands to symbols is implemented + * on x86 by investigating instruction details. + */ + cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); + } + + return 0; +} +#endif + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *i= nsn, + int print_opts, FILE *fp) +{ + struct addr_location al; + size_t printed =3D 0; + + if (insn->detail && insn->detail->x86.op_count =3D=3D 1) { + cs_x86_op *op =3D &insn->detail->x86.operands[0]; + + addr_location__init(&al); + if (op->type =3D=3D X86_OP_IMM && + thread__find_symbol(thread, cpumode, op->imm, &al)) { + printed +=3D fprintf(fp, "%s ", insn[0].mnemonic); + printed +=3D symbol__fprintf_symname_offs(al.sym, &al, fp); + if (print_opts & PRINT_INSN_IMM_HEX) + printed +=3D fprintf(fp, " [%#" PRIx64 "]", op->imm); + addr_location__exit(&al); + return printed; + } + addr_location__exit(&al); + } + + printed +=3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); + return printed; +} +#endif + + +ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused, + struct thread *thread __maybe_unused, + u8 cpumode __maybe_unused, bool is64bit __maybe_unused, + const uint8_t *code __maybe_unused, + size_t code_size __maybe_unused, + uint64_t ip __maybe_unused, int *lenp __maybe_unused, + int print_opts __maybe_unused, FILE *fp __maybe_unused) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + size_t printed; + cs_insn *insn; + csh cs_handle; + size_t count; + int ret; + + /* TODO: Try to initiate capstone only once but need a proper place. */ + ret =3D capstone_init(machine, &cs_handle, is64bit, true); + if (ret < 0) + return ret; + + count =3D cs_disasm(cs_handle, code, code_size, ip, 1, &insn); + if (count > 0) { + if (machine__normalized_is(machine, "x86")) + printed =3D print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); + else + printed =3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); + if (lenp) + *lenp =3D insn->size; + cs_free(insn, count); + } else { + printed =3D -1; + } + + cs_close(&cs_handle); + return printed; +#else + return -1; +#endif +} + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +static int open_capstone_handle(struct annotate_args *args, bool is_64bit,= csh *handle) +{ + struct annotation_options *opt =3D args->options; + cs_mode mode =3D is_64bit ? CS_MODE_64 : CS_MODE_32; + + /* TODO: support more architectures */ + if (!arch__is(args->arch, "x86")) + return -1; + + if (cs_open(CS_ARCH_X86, mode, handle) !=3D CS_ERR_OK) + return -1; + + if (!opt->disassembler_style || + !strcmp(opt->disassembler_style, "att")) + cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + + /* + * Resolving address operands to symbols is implemented + * on x86 by investigating instruction details. + */ + cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); + + return 0; +} +#endif + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, + struct annotate_args *args, u64 addr) +{ + int i; + struct map *map =3D args->ms.map; + struct symbol *sym; + + /* TODO: support more architectures */ + if (!arch__is(args->arch, "x86")) + return; + + if (insn->detail =3D=3D NULL) + return; + + for (i =3D 0; i < insn->detail->x86.op_count; i++) { + cs_x86_op *op =3D &insn->detail->x86.operands[i]; + u64 orig_addr; + + if (op->type !=3D X86_OP_MEM) + continue; + + /* only print RIP-based global symbols for now */ + if (op->mem.base !=3D X86_REG_RIP) + continue; + + /* get the target address */ + orig_addr =3D addr + insn->size + op->mem.disp; + addr =3D map__objdump_2mem(map, orig_addr); + + if (dso__kernel(map__dso(map))) { + /* + * The kernel maps can be split into sections, let's + * find the map first and the search the symbol. + */ + map =3D maps__find(map__kmaps(map), addr); + if (map =3D=3D NULL) + continue; + } + + /* convert it to map-relative address for search */ + addr =3D map__map_ip(map, addr); + + sym =3D map__find_symbol(map, addr); + if (sym =3D=3D NULL) + continue; + + if (addr =3D=3D sym->start) { + scnprintf(buf, len, "\t# %"PRIx64" <%s>", + orig_addr, sym->name); + } else { + scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", + orig_addr, sym->name, addr - sym->start); + } + break; + } +} +#endif + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +struct find_file_offset_data { + u64 ip; + u64 offset; +}; + +/* This will be called for each PHDR in an ELF binary */ +static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) +{ + struct find_file_offset_data *data =3D arg; + + if (start <=3D data->ip && data->ip < start + len) { + data->offset =3D pgoff + data->ip - start; + return 1; + } + return 0; +} +#endif + +#ifdef HAVE_LIBCAPSTONE_SUPPORT +static u8 * +read_symbol(const char *filename, struct map *map, struct symbol *sym, + u64 *len, bool *is_64bit) +{ + struct dso *dso =3D map__dso(map); + struct nscookie nsc; + u64 start =3D map__rip_2objdump(map, sym->start); + u64 end =3D map__rip_2objdump(map, sym->end); + int fd, count; + u8 *buf =3D NULL; + struct find_file_offset_data data =3D { + .ip =3D start, + }; + + *is_64bit =3D false; + + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); + fd =3D open(filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return NULL; + + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, + is_64bit) =3D=3D 0) + goto err; + + *len =3D end - start; + buf =3D malloc(*len); + if (buf =3D=3D NULL) + goto err; + + count =3D pread(fd, buf, *len, data.offset); + close(fd); + fd =3D -1; + + if ((u64)count !=3D *len) + goto err; + + return buf; + +err: + if (fd >=3D 0) + close(fd); + free(buf); + return NULL; +} +#endif + +int symbol__disassemble_capstone(const char *filename __maybe_unused, + struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + struct annotation *notes =3D symbol__annotation(sym); + struct map *map =3D args->ms.map; + u64 start =3D map__rip_2objdump(map, sym->start); + u64 len; + u64 offset; + int i, count, free_count; + bool is_64bit =3D false; + bool needs_cs_close =3D false; + u8 *buf =3D NULL; + csh handle; + cs_insn *insn =3D NULL; + char disasm_buf[512]; + struct disasm_line *dl; + + if (args->options->objdump_path) + return -1; + + buf =3D read_symbol(filename, map, sym, &len, &is_64bit); + if (buf =3D=3D NULL) + return -1; + + /* add the function address and name */ + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", + start, sym->name); + + args->offset =3D -1; + args->line =3D disasm_buf; + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + if (open_capstone_handle(args, is_64bit, &handle) < 0) + goto err; + + needs_cs_close =3D true; + + free_count =3D count =3D cs_disasm(handle, buf, len, start, len, &insn); + for (i =3D 0, offset =3D 0; i < count; i++) { + int printed; + + printed =3D scnprintf(disasm_buf, sizeof(disasm_buf), + " %-7s %s", + insn[i].mnemonic, insn[i].op_str); + print_capstone_detail(&insn[i], disasm_buf + printed, + sizeof(disasm_buf) - printed, args, + start + offset); + + args->offset =3D offset; + args->line =3D disasm_buf; + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + offset +=3D insn[i].size; + } + + /* It failed in the middle: probably due to unknown instructions */ + if (offset !=3D len) { + struct list_head *list =3D ¬es->src->source; + + /* Discard all lines and fallback to objdump */ + while (!list_empty(list)) { + dl =3D list_first_entry(list, struct disasm_line, al.node); + + list_del_init(&dl->al.node); + disasm_line__free(dl); + } + count =3D -1; + } + +out: + if (needs_cs_close) { + cs_close(&handle); + if (free_count > 0) + cs_free(insn, free_count); + } + free(buf); + return count < 0 ? count : 0; + +err: + if (needs_cs_close) { + struct disasm_line *tmp; + + /* + * It probably failed in the middle of the above loop. + * Release any resources it might add. + */ + list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { + list_del(&dl->al.node); + disasm_line__free(dl); + } + } + count =3D -1; + goto out; +#else + return -1; +#endif +} + +int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unus= ed, + struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + struct annotation *notes =3D symbol__annotation(sym); + struct map *map =3D args->ms.map; + struct dso *dso =3D map__dso(map); + struct nscookie nsc; + u64 start =3D map__rip_2objdump(map, sym->start); + u64 end =3D map__rip_2objdump(map, sym->end); + u64 len =3D end - start; + u64 offset; + int i, fd, count; + bool is_64bit =3D false; + bool needs_cs_close =3D false; + u8 *buf =3D NULL; + struct find_file_offset_data data =3D { + .ip =3D start, + }; + csh handle; + char disasm_buf[512]; + struct disasm_line *dl; + u32 *line; + bool disassembler_style =3D false; + + if (args->options->objdump_path) + return -1; + + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); + fd =3D open(filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return -1; + + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, + &is_64bit) =3D=3D 0) + goto err; + + if (!args->options->disassembler_style || + !strcmp(args->options->disassembler_style, "att")) + disassembler_style =3D true; + + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disass= embler_style) < 0) + goto err; + + needs_cs_close =3D true; + + buf =3D malloc(len); + if (buf =3D=3D NULL) + goto err; + + count =3D pread(fd, buf, len, data.offset); + close(fd); + fd =3D -1; + + if ((u64)count !=3D len) + goto err; + + line =3D (u32 *)buf; + + /* add the function address and name */ + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", + start, sym->name); + + args->offset =3D -1; + args->line =3D disasm_buf; + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + /* + * TODO: enable disassm for powerpc + * count =3D cs_disasm(handle, buf, len, start, len, &insn); + * + * For now, only binary code is saved in disassembled line + * to be used in "type" and "typeoff" sort keys. Each raw code + * is 32 bit instruction. So use "len/4" to get the number of + * entries. + */ + count =3D len/4; + + for (i =3D 0, offset =3D 0; i < count; i++) { + args->offset =3D offset; + sprintf(args->line, "%x", line[i]); + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + break; + + annotation_line__add(&dl->al, ¬es->src->source); + + offset +=3D 4; + } + + /* It failed in the middle */ + if (offset !=3D len) { + struct list_head *list =3D ¬es->src->source; + + /* Discard all lines and fallback to objdump */ + while (!list_empty(list)) { + dl =3D list_first_entry(list, struct disasm_line, al.node); + + list_del_init(&dl->al.node); + disasm_line__free(dl); + } + count =3D -1; + } + +out: + if (needs_cs_close) + cs_close(&handle); + free(buf); + return count < 0 ? count : 0; + +err: + if (fd >=3D 0) + close(fd); + count =3D -1; + goto out; +#else + return -1; +#endif +} diff --git a/tools/perf/util/capstone.h b/tools/perf/util/capstone.h new file mode 100644 index 000000000000..0f030ea034b6 --- /dev/null +++ b/tools/perf/util/capstone.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_CAPSTONE_H +#define __PERF_CAPSTONE_H + +#include +#include +#include +#include +#include + +struct annotate_args; +struct machine; +struct symbol; +struct thread; + +ssize_t capstone__fprintf_insn_asm(struct machine *machine, struct thread = *thread, u8 cpumode, + bool is64bit, const uint8_t *code, size_t code_size, + uint64_t ip, int *lenp, int print_opts, FILE *fp); +int symbol__disassemble_capstone(const char *filename, struct symbol *sym, + struct annotate_args *args); +int symbol__disassemble_capstone_powerpc(const char *filename, struct symb= ol *sym, + struct annotate_args *args); + +#endif /* __PERF_CAPSTONE_H */ diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index e257bd918c89..28529fda8a87 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -14,6 +14,7 @@ #include "annotate.h" #include "annotate-data.h" #include "build-id.h" +#include "capstone.h" #include "debug.h" #include "disasm.h" #include "disasm_bpf.h" @@ -1333,39 +1334,7 @@ static int dso__disassemble_filename(struct dso *dso= , char *filename, size_t fil return 0; } =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT -#include - -int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool= disassembler_style); - -static int open_capstone_handle(struct annotate_args *args, bool is_64bit, - csh *handle) -{ - struct annotation_options *opt =3D args->options; - cs_mode mode =3D is_64bit ? CS_MODE_64 : CS_MODE_32; - - /* TODO: support more architectures */ - if (!arch__is(args->arch, "x86")) - return -1; - - if (cs_open(CS_ARCH_X86, mode, handle) !=3D CS_ERR_OK) - return -1; - - if (!opt->disassembler_style || - !strcmp(opt->disassembler_style, "att")) - cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); - - /* - * Resolving address operands to symbols is implemented - * on x86 by investigating instruction details. - */ - cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); - - return 0; -} -#endif - -#if defined(HAVE_LIBCAPSTONE_SUPPORT) || defined(HAVE_LIBLLVM_SUPPORT) +#if defined(HAVE_LIBLLVM_SUPPORT) struct find_file_offset_data { u64 ip; u64 offset; @@ -1431,322 +1400,6 @@ read_symbol(const char *filename, struct map *map, = struct symbol *sym, } #endif =20 -#if !defined(HAVE_LIBCAPSTONE_SUPPORT) || !defined(HAVE_LIBLLVM_SUPPORT) -static void symbol__disassembler_missing(const char *disassembler, const c= har *filename, - struct symbol *sym) -{ - pr_debug("The %s disassembler isn't linked in for %s in %s\n", - disassembler, sym->name, filename); -} -#endif - -#ifdef HAVE_LIBCAPSTONE_SUPPORT -static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, - struct annotate_args *args, u64 addr) -{ - int i; - struct map *map =3D args->ms.map; - struct symbol *sym; - - /* TODO: support more architectures */ - if (!arch__is(args->arch, "x86")) - return; - - if (insn->detail =3D=3D NULL) - return; - - for (i =3D 0; i < insn->detail->x86.op_count; i++) { - cs_x86_op *op =3D &insn->detail->x86.operands[i]; - u64 orig_addr; - - if (op->type !=3D X86_OP_MEM) - continue; - - /* only print RIP-based global symbols for now */ - if (op->mem.base !=3D X86_REG_RIP) - continue; - - /* get the target address */ - orig_addr =3D addr + insn->size + op->mem.disp; - addr =3D map__objdump_2mem(map, orig_addr); - - if (dso__kernel(map__dso(map))) { - /* - * The kernel maps can be splitted into sections, - * let's find the map first and the search the symbol. - */ - map =3D maps__find(map__kmaps(map), addr); - if (map =3D=3D NULL) - continue; - } - - /* convert it to map-relative address for search */ - addr =3D map__map_ip(map, addr); - - sym =3D map__find_symbol(map, addr); - if (sym =3D=3D NULL) - continue; - - if (addr =3D=3D sym->start) { - scnprintf(buf, len, "\t# %"PRIx64" <%s>", - orig_addr, sym->name); - } else { - scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", - orig_addr, sym->name, addr - sym->start); - } - break; - } -} - -static int symbol__disassemble_capstone_powerpc(char *filename, struct sym= bol *sym, - struct annotate_args *args) -{ - struct annotation *notes =3D symbol__annotation(sym); - struct map *map =3D args->ms.map; - struct dso *dso =3D map__dso(map); - struct nscookie nsc; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 end =3D map__rip_2objdump(map, sym->end); - u64 len =3D end - start; - u64 offset; - int i, fd, count; - bool is_64bit =3D false; - bool needs_cs_close =3D false; - u8 *buf =3D NULL; - struct find_file_offset_data data =3D { - .ip =3D start, - }; - csh handle; - char disasm_buf[512]; - struct disasm_line *dl; - u32 *line; - bool disassembler_style =3D false; - - if (args->options->objdump_path) - return -1; - - nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - fd =3D open(filename, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fd < 0) - return -1; - - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, - &is_64bit) =3D=3D 0) - goto err; - - if (!args->options->disassembler_style || - !strcmp(args->options->disassembler_style, "att")) - disassembler_style =3D true; - - if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disass= embler_style) < 0) - goto err; - - needs_cs_close =3D true; - - buf =3D malloc(len); - if (buf =3D=3D NULL) - goto err; - - count =3D pread(fd, buf, len, data.offset); - close(fd); - fd =3D -1; - - if ((u64)count !=3D len) - goto err; - - line =3D (u32 *)buf; - - /* add the function address and name */ - scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", - start, sym->name); - - args->offset =3D -1; - args->line =3D disasm_buf; - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - goto err; - - annotation_line__add(&dl->al, ¬es->src->source); - - /* - * TODO: enable disassm for powerpc - * count =3D cs_disasm(handle, buf, len, start, len, &insn); - * - * For now, only binary code is saved in disassembled line - * to be used in "type" and "typeoff" sort keys. Each raw code - * is 32 bit instruction. So use "len/4" to get the number of - * entries. - */ - count =3D len/4; - - for (i =3D 0, offset =3D 0; i < count; i++) { - args->offset =3D offset; - sprintf(args->line, "%x", line[i]); - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - break; - - annotation_line__add(&dl->al, ¬es->src->source); - - offset +=3D 4; - } - - /* It failed in the middle */ - if (offset !=3D len) { - struct list_head *list =3D ¬es->src->source; - - /* Discard all lines and fallback to objdump */ - while (!list_empty(list)) { - dl =3D list_first_entry(list, struct disasm_line, al.node); - - list_del_init(&dl->al.node); - disasm_line__free(dl); - } - count =3D -1; - } - -out: - if (needs_cs_close) - cs_close(&handle); - free(buf); - return count < 0 ? count : 0; - -err: - if (fd >=3D 0) - close(fd); - count =3D -1; - goto out; -} - -static int symbol__disassemble_capstone(char *filename, struct symbol *sym, - struct annotate_args *args) -{ - struct annotation *notes =3D symbol__annotation(sym); - struct map *map =3D args->ms.map; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 len; - u64 offset; - int i, count, free_count; - bool is_64bit =3D false; - bool needs_cs_close =3D false; - u8 *buf =3D NULL; - csh handle; - cs_insn *insn =3D NULL; - char disasm_buf[512]; - struct disasm_line *dl; - - if (args->options->objdump_path) - return -1; - - buf =3D read_symbol(filename, map, sym, &len, &is_64bit); - if (buf =3D=3D NULL) - return -1; - - /* add the function address and name */ - scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", - start, sym->name); - - args->offset =3D -1; - args->line =3D disasm_buf; - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - goto err; - - annotation_line__add(&dl->al, ¬es->src->source); - - if (open_capstone_handle(args, is_64bit, &handle) < 0) - goto err; - - needs_cs_close =3D true; - - free_count =3D count =3D cs_disasm(handle, buf, len, start, len, &insn); - for (i =3D 0, offset =3D 0; i < count; i++) { - int printed; - - printed =3D scnprintf(disasm_buf, sizeof(disasm_buf), - " %-7s %s", - insn[i].mnemonic, insn[i].op_str); - print_capstone_detail(&insn[i], disasm_buf + printed, - sizeof(disasm_buf) - printed, args, - start + offset); - - args->offset =3D offset; - args->line =3D disasm_buf; - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - goto err; - - annotation_line__add(&dl->al, ¬es->src->source); - - offset +=3D insn[i].size; - } - - /* It failed in the middle: probably due to unknown instructions */ - if (offset !=3D len) { - struct list_head *list =3D ¬es->src->source; - - /* Discard all lines and fallback to objdump */ - while (!list_empty(list)) { - dl =3D list_first_entry(list, struct disasm_line, al.node); - - list_del_init(&dl->al.node); - disasm_line__free(dl); - } - count =3D -1; - } - -out: - if (needs_cs_close) { - cs_close(&handle); - if (free_count > 0) - cs_free(insn, free_count); - } - free(buf); - return count < 0 ? count : 0; - -err: - if (needs_cs_close) { - struct disasm_line *tmp; - - /* - * It probably failed in the middle of the above loop. - * Release any resources it might add. - */ - list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { - list_del(&dl->al.node); - disasm_line__free(dl); - } - } - count =3D -1; - goto out; -} -#else // HAVE_LIBCAPSTONE_SUPPORT -static int symbol__disassemble_capstone(char *filename, struct symbol *sym, - struct annotate_args *args __maybe_unused) -{ - symbol__disassembler_missing("capstone", filename, sym); - return -1; -} - -static int symbol__disassemble_capstone_powerpc(char *filename, struct sym= bol *sym, - struct annotate_args *args __maybe_unused) -{ - symbol__disassembler_missing("capstone powerpc", filename, sym); - return -1; -} -#endif // HAVE_LIBCAPSTONE_SUPPORT - static int symbol__disassemble_raw(char *filename, struct symbol *sym, struct annotate_args *args) { @@ -2014,10 +1667,11 @@ static int symbol__disassemble_llvm(char *filename,= struct symbol *sym, return ret; } #else // HAVE_LIBLLVM_SUPPORT -static int symbol__disassemble_llvm(char *filename, struct symbol *sym, +static int symbol__disassemble_llvm(const char *filename, struct symbol *s= ym, struct annotate_args *args __maybe_unused) { - symbol__disassembler_missing("LLVM", filename, sym); + pr_debug("The LLVM disassembler isn't linked in for %s in %s\n", + sym->name, filename); return -1; } #endif // HAVE_LIBLLVM_SUPPORT diff --git a/tools/perf/util/print_insn.c b/tools/perf/util/print_insn.c index a33a7726422d..02e6fbb8ca04 100644 --- a/tools/perf/util/print_insn.c +++ b/tools/perf/util/print_insn.c @@ -7,6 +7,7 @@ #include #include #include +#include "capstone.h" #include "debug.h" #include "sample.h" #include "symbol.h" @@ -29,84 +30,6 @@ size_t sample__fprintf_insn_raw(struct perf_sample *samp= le, FILE *fp) return printed; } =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT -#include - -int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool= disassembler_style); - -int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool= disassembler_style) -{ - cs_arch arch; - cs_mode mode; - - if (machine__is(machine, "x86_64") && is64) { - arch =3D CS_ARCH_X86; - mode =3D CS_MODE_64; - } else if (machine__normalized_is(machine, "x86")) { - arch =3D CS_ARCH_X86; - mode =3D CS_MODE_32; - } else if (machine__normalized_is(machine, "arm64")) { - arch =3D CS_ARCH_ARM64; - mode =3D CS_MODE_ARM; - } else if (machine__normalized_is(machine, "arm")) { - arch =3D CS_ARCH_ARM; - mode =3D CS_MODE_ARM + CS_MODE_V8; - } else if (machine__normalized_is(machine, "s390")) { - arch =3D CS_ARCH_SYSZ; - mode =3D CS_MODE_BIG_ENDIAN; - } else { - return -1; - } - - if (cs_open(arch, mode, cs_handle) !=3D CS_ERR_OK) { - pr_warning_once("cs_open failed\n"); - return -1; - } - - if (machine__normalized_is(machine, "x86")) { - /* - * In case of using capstone_init while symbol__disassemble - * setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts - * is set via annotation args - */ - if (disassembler_style) - cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); - /* - * Resolving address operands to symbols is implemented - * on x86 by investigating instruction details. - */ - cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); - } - - return 0; -} - -static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *i= nsn, - int print_opts, FILE *fp) -{ - struct addr_location al; - size_t printed =3D 0; - - if (insn->detail && insn->detail->x86.op_count =3D=3D 1) { - cs_x86_op *op =3D &insn->detail->x86.operands[0]; - - addr_location__init(&al); - if (op->type =3D=3D X86_OP_IMM && - thread__find_symbol(thread, cpumode, op->imm, &al)) { - printed +=3D fprintf(fp, "%s ", insn[0].mnemonic); - printed +=3D symbol__fprintf_symname_offs(al.sym, &al, fp); - if (print_opts & PRINT_INSN_IMM_HEX) - printed +=3D fprintf(fp, " [%#" PRIx64 "]", op->imm); - addr_location__exit(&al); - return printed; - } - addr_location__exit(&al); - } - - printed +=3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); - return printed; -} - static bool is64bitip(struct machine *machine, struct addr_location *al) { const struct dso *dso =3D al->map ? map__dso(al->map) : NULL; @@ -123,32 +46,8 @@ ssize_t fprintf_insn_asm(struct machine *machine, struc= t thread *thread, u8 cpum bool is64bit, const uint8_t *code, size_t code_size, uint64_t ip, int *lenp, int print_opts, FILE *fp) { - size_t printed; - cs_insn *insn; - csh cs_handle; - size_t count; - int ret; - - /* TODO: Try to initiate capstone only once but need a proper place. */ - ret =3D capstone_init(machine, &cs_handle, is64bit, true); - if (ret < 0) - return ret; - - count =3D cs_disasm(cs_handle, code, code_size, ip, 1, &insn); - if (count > 0) { - if (machine__normalized_is(machine, "x86")) - printed =3D print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); - else - printed =3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); - if (lenp) - *lenp =3D insn->size; - cs_free(insn, count); - } else { - printed =3D -1; - } - - cs_close(&cs_handle); - return printed; + return capstone__fprintf_insn_asm(machine, thread, cpumode, is64bit, code= , code_size, + ip, lenp, print_opts, fp); } =20 size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread = *thread, @@ -166,13 +65,3 @@ size_t sample__fprintf_insn_asm(struct perf_sample *sam= ple, struct thread *threa =20 return printed; } -#else -size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused, - struct thread *thread __maybe_unused, - struct machine *machine __maybe_unused, - FILE *fp __maybe_unused, - struct addr_location *al __maybe_unused) -{ - return 0; -} -#endif --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 267D024BBF4 for ; Mon, 29 Sep 2025 19:08:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172923; cv=none; b=IXnp3EWBrsPADCwHLgQpabSRIlQiG7Wi4bibj/h9RpktJb6DriLxmVqZB20JLUx6/4PlKzm7h5w8MbUsm7P7JXf/xEaUnGOw/rkedddPsLHM7BMpuwo1wZ4cwBhg4eT435/HDxheEmyA78BcF7DvPo4+Mf1GF6I/4p+YEXFDckM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172923; c=relaxed/simple; bh=9Wrfyz5d4Vw6n3hBwMPQ3SckVlcXXhGNHCI7GT1AsHc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=cEBecDYx6AyIQvU1LERs7CTBuH/ugRxGeEbUlscCTMTZRWs/ZVhuu5MtnXyoosDbij8GEOfQCabpa8HHj03ypdsMAGMI2RW4E6imNIIthuG4oJDAMTGO6Y5lpsaSS/g6MqUE6+sREoiOltvBvh52JkMpmsct4uc2s/Jn7FvRdx0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=I1God0kR; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="I1God0kR" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-78427dae77eso1594556b3a.3 for ; Mon, 29 Sep 2025 12:08:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172920; x=1759777720; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=VJZStBwsSZT1l6u8zguk7Oi4jMmsanbdrpaigNdeIgk=; b=I1God0kRpF11UkuPZ2ZyHm+X2A7T4sT1QrtDfEZIrfN6i5qelti2zch6Bsr+d1L0Ux cqdKuD/CNcGx0apHdENfkbzwZyPJxibyIUR1eX5q4l/k1tU5qqpPyPN2e0rGYD4kOXdy 06UDaICvRIlyUecfR/78Al++813YRQhZPcO2BKeMmHG4p4DyRuGdMj4db+nsdcUBY3o9 lVlMr9NkhDblK0u5TF7BYFTgoTPFR0Fop6589N7lWhib5NM/F89c1v9puwP72rJrHyfo bj1zG4gJocReSJ51/h9A0YoqNm4j7NyDMqGGqynphtZliN0fJe92r3srPM2LaTgElgxk X3hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172920; x=1759777720; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VJZStBwsSZT1l6u8zguk7Oi4jMmsanbdrpaigNdeIgk=; b=UqBfZppFIvTu1hWa6mbXqxrKkPwuIsSYJ5sSxuMrVEsHUj/qrwLnx6pMWIY2lQriZv YESN36i0jaxiuK9nzGWektzJ6w9vud64QEOuApvdke81rCj2Ikr4NWqiSMCGhRfCF6CO vUHD9yNaJGQMgCsaKHwaNW0PgHGFpfGzB40s+PyYpOIOUc+Bx7PbTZ8wGAIepHic5yza pUFQ2uvXzuwYcpWfKBOyY6O/XJMbWSlRrhKlwkJlBEdF3QWeypXBhStWPOxFZ5uaCmaf I48LyC0JFVuMobuk7mga7Y2wisM313BKuivBz3pf5LAjLw7akTEfJTlZCdS05jh95sLZ k8jQ== X-Forwarded-Encrypted: i=1; AJvYcCXiJyTe09YQVdZMUE6A2hHB7uX2yN3Kk+TKzM/ITa4HPfzUZa4g5IrwmZOSFmi66CXt9QS4nskmSnVg1f4=@vger.kernel.org X-Gm-Message-State: AOJu0Yzumg6rPojunLug1EF2doXvzr1/40fDyLnoWBSFqze5OZeNagDw jDRbDYw+agVzpfhMVepva2uGIZTkblXerJ54qhTLyatH4MTHY02NmPOWhvSom0z4QKgeIYGwV3L U9rYoB5tSuQ== X-Google-Smtp-Source: AGHT+IFtP31ZrJyqD+SczI12Kvova/WSRQTjgN30JT5s4DKXA7INEO8X+M0x2XKSG84NE5l1ytSPIA6a0UyB X-Received: from pge3.prod.google.com ([2002:a05:6a02:2d03:b0:b55:6d2d:41f7]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:6d85:b0:2e6:b58a:dde9 with SMTP id adf61e73a8af0-2e7d7362837mr22659513637.40.1759172919762; Mon, 29 Sep 2025 12:08:39 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:53 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-4-irogers@google.com> Subject: [PATCH v6 03/15] perf llvm: Move llvm functionality into its own file From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" LLVM disassembly support was in disasm.c and addr2line support in srcline.c. Move support out of these files into llvm.[ch] and remove LLVM includes from those files. As disassembly routines can fail, make failure the only option without HAVE_LIBLLVM_SUPPORT. For simplicity's sake, duplicate the read_symbol utility function. The intent with moving LLVM support into a single file is that dynamic support, using dlopen for libllvm, can be added in later patches. This can potentially always succeed or fail, so relying on ifdefs isn't sufficient. Using dlopen is a useful option to minimize the perf tools dependencies and potentially size. Signed-off-by: Ian Rogers --- tools/perf/util/Build | 1 + tools/perf/util/disasm.c | 260 +----------------------------- tools/perf/util/disasm.h | 2 + tools/perf/util/llvm.c | 326 ++++++++++++++++++++++++++++++++++++++ tools/perf/util/llvm.h | 24 +++ tools/perf/util/srcline.c | 65 ++------ tools/perf/util/srcline.h | 6 + 7 files changed, 373 insertions(+), 311 deletions(-) create mode 100644 tools/perf/util/llvm.c create mode 100644 tools/perf/util/llvm.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 4e8414b7c283..63160c4a517e 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -26,6 +26,7 @@ perf-util-y +=3D evswitch.o perf-util-y +=3D find_bit.o perf-util-y +=3D get_current_dir_name.o perf-util-y +=3D levenshtein.o +perf-util-y +=3D llvm.o perf-util-y +=3D mmap.o perf-util-y +=3D memswap.o perf-util-y +=3D parse-events.o diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 28529fda8a87..fa6accd8d873 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -22,6 +22,7 @@ #include "dwarf-regs.h" #include "env.h" #include "evsel.h" +#include "llvm.h" #include "map.h" #include "maps.h" #include "namespaces.h" @@ -50,7 +51,6 @@ static int call__scnprintf(struct ins *ins, char *bf, siz= e_t size, static void ins__sort(struct arch *arch); static int disasm_line__parse(char *line, const char **namep, char **rawp); static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annot= ate_args *args); -static char *expand_tabs(char *line, char **storage, size_t *storage_len); =20 static __attribute__((constructor)) void symbol__init_regexpr(void) { @@ -1334,72 +1334,6 @@ static int dso__disassemble_filename(struct dso *dso= , char *filename, size_t fil return 0; } =20 -#if defined(HAVE_LIBLLVM_SUPPORT) -struct find_file_offset_data { - u64 ip; - u64 offset; -}; - -/* This will be called for each PHDR in an ELF binary */ -static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) -{ - struct find_file_offset_data *data =3D arg; - - if (start <=3D data->ip && data->ip < start + len) { - data->offset =3D pgoff + data->ip - start; - return 1; - } - return 0; -} - -static u8 * -read_symbol(const char *filename, struct map *map, struct symbol *sym, - u64 *len, bool *is_64bit) -{ - struct dso *dso =3D map__dso(map); - struct nscookie nsc; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 end =3D map__rip_2objdump(map, sym->end); - int fd, count; - u8 *buf =3D NULL; - struct find_file_offset_data data =3D { - .ip =3D start, - }; - - *is_64bit =3D false; - - nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - fd =3D open(filename, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fd < 0) - return NULL; - - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, - is_64bit) =3D=3D 0) - goto err; - - *len =3D end - start; - buf =3D malloc(*len); - if (buf =3D=3D NULL) - goto err; - - count =3D pread(fd, buf, *len, data.offset); - close(fd); - fd =3D -1; - - if ((u64)count !=3D *len) - goto err; - - return buf; - -err: - if (fd >=3D 0) - close(fd); - free(buf); - return NULL; -} -#endif - static int symbol__disassemble_raw(char *filename, struct symbol *sym, struct annotate_args *args) { @@ -1486,202 +1420,12 @@ static int symbol__disassemble_raw(char *filename,= struct symbol *sym, goto out; } =20 -#ifdef HAVE_LIBLLVM_SUPPORT -#include -#include -#include "util/llvm-c-helpers.h" - -struct symbol_lookup_storage { - u64 branch_addr; - u64 pcrel_load_addr; -}; - -/* - * Whenever LLVM wants to resolve an address into a symbol, it calls this - * callback. We don't ever actually _return_ anything (in particular, beca= use - * it puts quotation marks around what we return), but we use this as a hi= nt - * that there is a branch or PC-relative address in the expression that we - * should add some textual annotation for after the instruction. The caller - * will use this information to add the actual annotation. - */ -static const char * -symbol_lookup_callback(void *disinfo, uint64_t value, - uint64_t *ref_type, - uint64_t address __maybe_unused, - const char **ref __maybe_unused) -{ - struct symbol_lookup_storage *storage =3D disinfo; - - if (*ref_type =3D=3D LLVMDisassembler_ReferenceType_In_Branch) - storage->branch_addr =3D value; - else if (*ref_type =3D=3D LLVMDisassembler_ReferenceType_In_PCrel_Load) - storage->pcrel_load_addr =3D value; - *ref_type =3D LLVMDisassembler_ReferenceType_InOut_None; - return NULL; -} - -static int symbol__disassemble_llvm(char *filename, struct symbol *sym, - struct annotate_args *args) -{ - struct annotation *notes =3D symbol__annotation(sym); - struct map *map =3D args->ms.map; - struct dso *dso =3D map__dso(map); - u64 start =3D map__rip_2objdump(map, sym->start); - u8 *buf; - u64 len; - u64 pc; - bool is_64bit; - char triplet[64]; - char disasm_buf[2048]; - size_t disasm_len; - struct disasm_line *dl; - LLVMDisasmContextRef disasm =3D NULL; - struct symbol_lookup_storage storage; - char *line_storage =3D NULL; - size_t line_storage_len =3D 0; - int ret =3D -1; - - if (args->options->objdump_path) - return -1; - - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllDisassemblers(); - - buf =3D read_symbol(filename, map, sym, &len, &is_64bit); - if (buf =3D=3D NULL) - return -1; - - if (arch__is(args->arch, "x86")) { - if (is_64bit) - scnprintf(triplet, sizeof(triplet), "x86_64-pc-linux"); - else - scnprintf(triplet, sizeof(triplet), "i686-pc-linux"); - } else { - scnprintf(triplet, sizeof(triplet), "%s-linux-gnu", - args->arch->name); - } - - disasm =3D LLVMCreateDisasm(triplet, &storage, 0, NULL, - symbol_lookup_callback); - if (disasm =3D=3D NULL) - goto err; - - if (args->options->disassembler_style && - !strcmp(args->options->disassembler_style, "intel")) - LLVMSetDisasmOptions(disasm, - LLVMDisassembler_Option_AsmPrinterVariant); - - /* - * This needs to be set after AsmPrinterVariant, due to a bug in LLVM; - * setting AsmPrinterVariant makes a new instruction printer, making it - * forget about the PrintImmHex flag (which is applied before if both - * are given to the same call). - */ - LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_PrintImmHex); - - /* add the function address and name */ - scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", - start, sym->name); - - args->offset =3D -1; - args->line =3D disasm_buf; - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - goto err; - - annotation_line__add(&dl->al, ¬es->src->source); - - pc =3D start; - for (u64 offset =3D 0; offset < len; ) { - unsigned int ins_len; - - storage.branch_addr =3D 0; - storage.pcrel_load_addr =3D 0; - - ins_len =3D LLVMDisasmInstruction(disasm, buf + offset, - len - offset, pc, - disasm_buf, sizeof(disasm_buf)); - if (ins_len =3D=3D 0) - goto err; - disasm_len =3D strlen(disasm_buf); - - if (storage.branch_addr !=3D 0) { - char *name =3D llvm_name_for_code(dso, filename, - storage.branch_addr); - if (name !=3D NULL) { - disasm_len +=3D scnprintf(disasm_buf + disasm_len, - sizeof(disasm_buf) - - disasm_len, - " <%s>", name); - free(name); - } - } - if (storage.pcrel_load_addr !=3D 0) { - char *name =3D llvm_name_for_data(dso, filename, - storage.pcrel_load_addr); - disasm_len +=3D scnprintf(disasm_buf + disasm_len, - sizeof(disasm_buf) - disasm_len, - " # %#"PRIx64, - storage.pcrel_load_addr); - if (name) { - disasm_len +=3D scnprintf(disasm_buf + disasm_len, - sizeof(disasm_buf) - - disasm_len, - " <%s>", name); - free(name); - } - } - - args->offset =3D offset; - args->line =3D expand_tabs(disasm_buf, &line_storage, - &line_storage_len); - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - - llvm_addr2line(filename, pc, &args->fileloc, - (unsigned int *)&args->line_nr, false, NULL); - - dl =3D disasm_line__new(args); - if (dl =3D=3D NULL) - goto err; - - annotation_line__add(&dl->al, ¬es->src->source); - - free(args->fileloc); - pc +=3D ins_len; - offset +=3D ins_len; - } - - ret =3D 0; - -err: - LLVMDisasmDispose(disasm); - free(buf); - free(line_storage); - return ret; -} -#else // HAVE_LIBLLVM_SUPPORT -static int symbol__disassemble_llvm(const char *filename, struct symbol *s= ym, - struct annotate_args *args __maybe_unused) -{ - pr_debug("The LLVM disassembler isn't linked in for %s in %s\n", - sym->name, filename); - return -1; -} -#endif // HAVE_LIBLLVM_SUPPORT - /* * Possibly create a new version of line with tabs expanded. Returns the * existing or new line, storage is updated if a new line is allocated. If * allocation fails then NULL is returned. */ -static char *expand_tabs(char *line, char **storage, size_t *storage_len) +char *expand_tabs(char *line, char **storage, size_t *storage_len) { size_t i, src, dst, len, new_storage_len, num_tabs; char *new_line; diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h index c135db2416b5..2cb4e1a6bd30 100644 --- a/tools/perf/util/disasm.h +++ b/tools/perf/util/disasm.h @@ -128,4 +128,6 @@ int disasm_line__scnprintf(struct disasm_line *dl, char= *bf, size_t size, =20 int symbol__disassemble(struct symbol *sym, struct annotate_args *args); =20 +char *expand_tabs(char *line, char **storage, size_t *storage_len); + #endif /* __PERF_UTIL_DISASM_H */ diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c new file mode 100644 index 000000000000..ddc737194692 --- /dev/null +++ b/tools/perf/util/llvm.c @@ -0,0 +1,326 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "llvm.h" +#include "annotate.h" +#include "debug.h" +#include "dso.h" +#include "map.h" +#include "namespaces.h" +#include "srcline.h" +#include "symbol.h" +#include +#include +#include + +#ifdef HAVE_LIBLLVM_SUPPORT +#include "llvm-c-helpers.h" +#include +#include +#endif + +#ifdef HAVE_LIBLLVM_SUPPORT +static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames, + int num_frames) +{ + if (inline_frames !=3D NULL) { + for (int i =3D 0; i < num_frames; ++i) { + zfree(&inline_frames[i].filename); + zfree(&inline_frames[i].funcname); + } + zfree(&inline_frames); + } +} +#endif + +int llvm__addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_= unused, + char **file __maybe_unused, unsigned int *line __maybe_unused, + struct dso *dso __maybe_unused, bool unwind_inlines __maybe_unused, + struct inline_node *node __maybe_unused, struct symbol *sym __maybe= _unused) +{ +#ifdef HAVE_LIBLLVM_SUPPORT + struct llvm_a2l_frame *inline_frames =3D NULL; + int num_frames =3D llvm_addr2line(dso_name, addr, file, line, + node && unwind_inlines, &inline_frames); + + if (num_frames =3D=3D 0 || !inline_frames) { + /* Error, or we didn't want inlines. */ + return num_frames; + } + + for (int i =3D 0; i < num_frames; ++i) { + struct symbol *inline_sym =3D + new_inline_sym(dso, sym, inline_frames[i].funcname); + char *srcline =3D NULL; + + if (inline_frames[i].filename) { + srcline =3D + srcline_from_fileline(inline_frames[i].filename, + inline_frames[i].line); + } + if (inline_list__append(inline_sym, srcline, node) !=3D 0) { + free_llvm_inline_frames(inline_frames, num_frames); + return 0; + } + } + free_llvm_inline_frames(inline_frames, num_frames); + + return num_frames; +#else + return -1; +#endif +} + +void dso__free_a2l_llvm(struct dso *dso __maybe_unused) +{ + /* Nothing to free. */ +} + + +#if defined(HAVE_LIBLLVM_SUPPORT) +struct find_file_offset_data { + u64 ip; + u64 offset; +}; + +/* This will be called for each PHDR in an ELF binary */ +static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) +{ + struct find_file_offset_data *data =3D arg; + + if (start <=3D data->ip && data->ip < start + len) { + data->offset =3D pgoff + data->ip - start; + return 1; + } + return 0; +} + +static u8 * +read_symbol(const char *filename, struct map *map, struct symbol *sym, + u64 *len, bool *is_64bit) +{ + struct dso *dso =3D map__dso(map); + struct nscookie nsc; + u64 start =3D map__rip_2objdump(map, sym->start); + u64 end =3D map__rip_2objdump(map, sym->end); + int fd, count; + u8 *buf =3D NULL; + struct find_file_offset_data data =3D { + .ip =3D start, + }; + + *is_64bit =3D false; + + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); + fd =3D open(filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return NULL; + + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, + is_64bit) =3D=3D 0) + goto err; + + *len =3D end - start; + buf =3D malloc(*len); + if (buf =3D=3D NULL) + goto err; + + count =3D pread(fd, buf, *len, data.offset); + close(fd); + fd =3D -1; + + if ((u64)count !=3D *len) + goto err; + + return buf; + +err: + if (fd >=3D 0) + close(fd); + free(buf); + return NULL; +} +#endif + +/* + * Whenever LLVM wants to resolve an address into a symbol, it calls this + * callback. We don't ever actually _return_ anything (in particular, beca= use + * it puts quotation marks around what we return), but we use this as a hi= nt + * that there is a branch or PC-relative address in the expression that we + * should add some textual annotation for after the instruction. The caller + * will use this information to add the actual annotation. + */ +#ifdef HAVE_LIBLLVM_SUPPORT +struct symbol_lookup_storage { + u64 branch_addr; + u64 pcrel_load_addr; +}; + +static const char * +symbol_lookup_callback(void *disinfo, uint64_t value, + uint64_t *ref_type, + uint64_t address __maybe_unused, + const char **ref __maybe_unused) +{ + struct symbol_lookup_storage *storage =3D disinfo; + + if (*ref_type =3D=3D LLVMDisassembler_ReferenceType_In_Branch) + storage->branch_addr =3D value; + else if (*ref_type =3D=3D LLVMDisassembler_ReferenceType_In_PCrel_Load) + storage->pcrel_load_addr =3D value; + *ref_type =3D LLVMDisassembler_ReferenceType_InOut_None; + return NULL; +} +#endif + +int symbol__disassemble_llvm(const char *filename, struct symbol *sym, + struct annotate_args *args __maybe_unused) +{ +#ifdef HAVE_LIBLLVM_SUPPORT + struct annotation *notes =3D symbol__annotation(sym); + struct map *map =3D args->ms.map; + struct dso *dso =3D map__dso(map); + u64 start =3D map__rip_2objdump(map, sym->start); + u8 *buf; + u64 len; + u64 pc; + bool is_64bit; + char triplet[64]; + char disasm_buf[2048]; + size_t disasm_len; + struct disasm_line *dl; + LLVMDisasmContextRef disasm =3D NULL; + struct symbol_lookup_storage storage; + char *line_storage =3D NULL; + size_t line_storage_len =3D 0; + int ret =3D -1; + + if (args->options->objdump_path) + return -1; + + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + buf =3D read_symbol(filename, map, sym, &len, &is_64bit); + if (buf =3D=3D NULL) + return -1; + + if (arch__is(args->arch, "x86")) { + if (is_64bit) + scnprintf(triplet, sizeof(triplet), "x86_64-pc-linux"); + else + scnprintf(triplet, sizeof(triplet), "i686-pc-linux"); + } else { + scnprintf(triplet, sizeof(triplet), "%s-linux-gnu", + args->arch->name); + } + + disasm =3D LLVMCreateDisasm(triplet, &storage, 0, NULL, + symbol_lookup_callback); + if (disasm =3D=3D NULL) + goto err; + + if (args->options->disassembler_style && + !strcmp(args->options->disassembler_style, "intel")) + LLVMSetDisasmOptions(disasm, + LLVMDisassembler_Option_AsmPrinterVariant); + + /* + * This needs to be set after AsmPrinterVariant, due to a bug in LLVM; + * setting AsmPrinterVariant makes a new instruction printer, making it + * forget about the PrintImmHex flag (which is applied before if both + * are given to the same call). + */ + LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_PrintImmHex); + + /* add the function address and name */ + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", + start, sym->name); + + args->offset =3D -1; + args->line =3D disasm_buf; + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + pc =3D start; + for (u64 offset =3D 0; offset < len; ) { + unsigned int ins_len; + + storage.branch_addr =3D 0; + storage.pcrel_load_addr =3D 0; + + ins_len =3D LLVMDisasmInstruction(disasm, buf + offset, + len - offset, pc, + disasm_buf, sizeof(disasm_buf)); + if (ins_len =3D=3D 0) + goto err; + disasm_len =3D strlen(disasm_buf); + + if (storage.branch_addr !=3D 0) { + char *name =3D llvm_name_for_code(dso, filename, + storage.branch_addr); + if (name !=3D NULL) { + disasm_len +=3D scnprintf(disasm_buf + disasm_len, + sizeof(disasm_buf) - + disasm_len, + " <%s>", name); + free(name); + } + } + if (storage.pcrel_load_addr !=3D 0) { + char *name =3D llvm_name_for_data(dso, filename, + storage.pcrel_load_addr); + disasm_len +=3D scnprintf(disasm_buf + disasm_len, + sizeof(disasm_buf) - disasm_len, + " # %#"PRIx64, + storage.pcrel_load_addr); + if (name) { + disasm_len +=3D scnprintf(disasm_buf + disasm_len, + sizeof(disasm_buf) - + disasm_len, + " <%s>", name); + free(name); + } + } + + args->offset =3D offset; + args->line =3D expand_tabs(disasm_buf, &line_storage, + &line_storage_len); + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + + llvm_addr2line(filename, pc, &args->fileloc, + (unsigned int *)&args->line_nr, false, NULL); + + dl =3D disasm_line__new(args); + if (dl =3D=3D NULL) + goto err; + + annotation_line__add(&dl->al, ¬es->src->source); + + free(args->fileloc); + pc +=3D ins_len; + offset +=3D ins_len; + } + + ret =3D 0; + +err: + LLVMDisasmDispose(disasm); + free(buf); + free(line_storage); + return ret; +#else // HAVE_LIBLLVM_SUPPORT + pr_debug("The LLVM disassembler isn't linked in for %s in %s\n", + sym->name, filename); + return -1; +#endif +} diff --git a/tools/perf/util/llvm.h b/tools/perf/util/llvm.h new file mode 100644 index 000000000000..8aa19bb6b068 --- /dev/null +++ b/tools/perf/util/llvm.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_LLVM_H +#define __PERF_LLVM_H + +#include +#include + +struct annotate_args; +struct dso; +struct inline_node; +struct symbol; + +int llvm__addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line, struct dso *dso, + bool unwind_inlines, struct inline_node *node, + struct symbol *sym); + + +void dso__free_a2l_llvm(struct dso *dso); + +int symbol__disassemble_llvm(const char *filename, struct symbol *sym, + struct annotate_args *args); + +#endif /* __PERF_LLVM_H */ diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 3e3449e35dd4..45e138ff3e52 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -17,9 +17,7 @@ #include "util/debug.h" #include "util/callchain.h" #include "util/symbol_conf.h" -#ifdef HAVE_LIBLLVM_SUPPORT -#include "util/llvm-c-helpers.h" -#endif +#include "llvm.h" #include "srcline.h" #include "string2.h" #include "symbol.h" @@ -49,8 +47,7 @@ static const char *srcline_dso_name(struct dso *dso) return dso_name; } =20 -static int inline_list__append(struct symbol *symbol, char *srcline, - struct inline_node *node) +int inline_list__append(struct symbol *symbol, char *srcline, struct inlin= e_node *node) { struct inline_list *ilist; =20 @@ -77,7 +74,7 @@ static const char *gnu_basename(const char *path) return base ? base + 1 : path; } =20 -static char *srcline_from_fileline(const char *file, unsigned int line) +char *srcline_from_fileline(const char *file, unsigned int line) { char *srcline; =20 @@ -93,9 +90,9 @@ static char *srcline_from_fileline(const char *file, unsi= gned int line) return srcline; } =20 -static struct symbol *new_inline_sym(struct dso *dso, - struct symbol *base_sym, - const char *funcname) +struct symbol *new_inline_sym(struct dso *dso, + struct symbol *base_sym, + const char *funcname) { struct symbol *inline_sym; char *demangled =3D NULL; @@ -135,58 +132,20 @@ static struct symbol *new_inline_sym(struct dso *dso, #define MAX_INLINE_NEST 1024 =20 #ifdef HAVE_LIBLLVM_SUPPORT - -static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames, - int num_frames) -{ - if (inline_frames !=3D NULL) { - for (int i =3D 0; i < num_frames; ++i) { - zfree(&inline_frames[i].filename); - zfree(&inline_frames[i].funcname); - } - zfree(&inline_frames); - } -} +#include "llvm.h" =20 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line, struct dso *dso, - bool unwind_inlines, struct inline_node *node, - struct symbol *sym) + bool unwind_inlines, struct inline_node *node, + struct symbol *sym) { - struct llvm_a2l_frame *inline_frames =3D NULL; - int num_frames =3D llvm_addr2line(dso_name, addr, file, line, - node && unwind_inlines, &inline_frames); - - if (num_frames =3D=3D 0 || !inline_frames) { - /* Error, or we didn't want inlines. */ - return num_frames; - } - - for (int i =3D 0; i < num_frames; ++i) { - struct symbol *inline_sym =3D - new_inline_sym(dso, sym, inline_frames[i].funcname); - char *srcline =3D NULL; - - if (inline_frames[i].filename) { - srcline =3D - srcline_from_fileline(inline_frames[i].filename, - inline_frames[i].line); - } - if (inline_list__append(inline_sym, srcline, node) !=3D 0) { - free_llvm_inline_frames(inline_frames, num_frames); - return 0; - } - } - free_llvm_inline_frames(inline_frames, num_frames); - - return num_frames; + return llvm__addr2line(dso_name, addr, file, line, dso, unwind_inlines, n= ode, sym); } =20 -void dso__free_a2l(struct dso *dso __maybe_unused) +void dso__free_a2l(struct dso *dso) { - /* Nothing to free. */ + dso__free_a2l_llvm(dso); } - #elif defined(HAVE_LIBBFD_SUPPORT) =20 /* diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h index 75010d39ea28..80c20169e250 100644 --- a/tools/perf/util/srcline.h +++ b/tools/perf/util/srcline.h @@ -55,4 +55,10 @@ struct inline_node *inlines__tree_find(struct rb_root_ca= ched *tree, u64 addr); /* delete all nodes within the tree of inline_node s */ void inlines__tree_delete(struct rb_root_cached *tree); =20 +int inline_list__append(struct symbol *symbol, char *srcline, struct inlin= e_node *node); +char *srcline_from_fileline(const char *file, unsigned int line); +struct symbol *new_inline_sym(struct dso *dso, + struct symbol *base_sym, + const char *funcname); + #endif /* PERF_SRCLINE_H */ --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5B38824BCE8 for ; Mon, 29 Sep 2025 19:08:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172926; cv=none; b=UyTc81E1Tk5RLkDJwZ4Jtd/vTGepZq2MCyfM9AhupkKOQhS7U5TpbyQd5KKJ3339uBNkbawAcXOLEeA10I1ZYruh9XjdJAlwvkRJOsZQVM6F2d6Wv7pNLmdd7QBXzPJg+t1VMhaSCe2t7XSKO7f7CdfmSrsl9tk40jFq7BuSyxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172926; c=relaxed/simple; bh=sG7GXj9dZWPgoweAiBVtaxLXGry2kM2zSMgSFDKWukw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=pH7kELT8K7orrNDxeVuXPiAT7YHQnIevw0pda8np+XF/Z77P7NR7kqMfnDIyMn57H3MM2NCW74ySX+3gisgf9iKp6S9FXxHxJdMaX4tdtxWZ+OBDlR98cpHdJXB15CfpW7MW7paocI0uYjmE0XpxsTBL+AIHeVWj3rAaGdiD/hc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=B4WogKpa; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="B4WogKpa" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-268149e1c28so46207165ad.1 for ; Mon, 29 Sep 2025 12:08:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172922; x=1759777722; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=J33L4M07H2Lw9WZtW+pVpjZvTY7fnFzmKJOxPiOQosU=; b=B4WogKpat9iZZopgka7/ZjDwfii4Rbl/mCp6pnEwIIES0OMRUjlslWRomgwMvft5CW Pu1GTmG1Kdh9WA2VMayrGOc89g2c3V8zG2w73XS3Bp1y9Fok9nNRaCV8nf5F16x84R9z u9sRhzu57rXzmdsQfDaBzz4Gj0+Asv+MjkmvLUYr8viS+KtqWm+Y+4E+x94nuP7PPL5e Gv7OIY1ZQlS2NCTKllXnVm1KWxpTFeAct8AGePRv1retaNzpq+HA3WKUrMJGkaApDMRK lRtIvW/iTNZ8H+FVMcsY5DRSGuPqgqD5GlOg7IrBxasPzoqiBxRP7e3NBr/KW+Jq3xJv 8OCA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172922; x=1759777722; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=J33L4M07H2Lw9WZtW+pVpjZvTY7fnFzmKJOxPiOQosU=; b=Yvuomn0HGGE5oVsLi29BnL4Xsu+6FbMek09Jvdg/3WWYX/yIp8A6eGWJRVxbxYSCkG 9wKMW03BGv8tvLbVLEfi4YmmnmZjkAVx8vO5XfhnkrvIhguSvNOMWuR1aQw1Yp5fEuKD pXFq96U26IhDGiJhuDCx/s9/UVa9V0cfcsJfU9NnG/03gSJUym5oZq1ke/lXSqQGnf8T 9D7yVRSIlRcvT5LSONfUoiQHANP6k16PIPfIhnX4hqUdm/alRN/v5wvTmI06mxHfpR3F GyQ5FhimCy4RXnlfwKiIY3gMNMBCBII23iAta50suxtcX3n+ZzSAgohhDmlnc0pEabNF e0WQ== X-Forwarded-Encrypted: i=1; AJvYcCWhIwPRNgfnIrZ0ya4r4HQfEmPzr/2e5GQv3hn99bONZm2kL/Xvqtdp3vE8H7ax5kJrb+xoiUUAvbGBw0s=@vger.kernel.org X-Gm-Message-State: AOJu0YxRJe+A3kocVTKT+7Vv6kApuYAL81YKNich2Pw8+hZbDDQtbKxR 2Nss305+aSRVpSCC94ZF+J4yaGdWJfnj6rjG/Oo1DJJx1QnG++Jd1gFcb/Q9akUTKZ6gkkAAu1N E+woE7HUJjg== X-Google-Smtp-Source: AGHT+IEQjzs/CagmcVqOtXMdd616zkKpRk3siJg1YZORZiilUy81aMWHjOhgnzp447Lgxr4TMVOxzst/qaPz X-Received: from pgbcz14.prod.google.com ([2002:a05:6a02:230e:b0:b55:1827:9212]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:2c0d:b0:275:27ab:f6c4 with SMTP id d9443c01a7336-27ed4a315b5mr204239165ad.33.1759172921696; Mon, 29 Sep 2025 12:08:41 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:54 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-5-irogers@google.com> Subject: [PATCH v6 04/15] perf libbfd: Move libbfd functionality to its own file From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move symbolization and srcline libbfd dependencies to a separate libbfd.c. This mirrors moving llvm and capstone code. While this code is deprecated as it is part of BUILD_NONDISTRO license incompatible code, moving the code to its own file minimizes disruption in the main files. disasm_bpf.c is moved to libbfd.c also except for symbol__disassemble_bpf_image which is currently more of a placeholder function rather than something that provides disassembly support. demangle-cxx.cpp code isn't migrated as it is very limited. Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 1 + tools/perf/util/Build | 2 +- tools/perf/util/disasm.c | 19 +- tools/perf/util/disasm_bpf.c | 195 ------------ tools/perf/util/disasm_bpf.h | 12 - tools/perf/util/libbfd.c | 600 +++++++++++++++++++++++++++++++++++ tools/perf/util/libbfd.h | 83 +++++ tools/perf/util/srcline.c | 232 +------------- tools/perf/util/srcline.h | 2 + tools/perf/util/symbol-elf.c | 100 +----- tools/perf/util/symbol.c | 131 -------- 11 files changed, 718 insertions(+), 659 deletions(-) delete mode 100644 tools/perf/util/disasm_bpf.c delete mode 100644 tools/perf/util/disasm_bpf.h create mode 100644 tools/perf/util/libbfd.c create mode 100644 tools/perf/util/libbfd.h diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 7bc2341295c3..1907d1c70b68 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -947,6 +947,7 @@ ifdef BUILD_NONDISTRO =20 CFLAGS +=3D -DHAVE_LIBBFD_SUPPORT CXXFLAGS +=3D -DHAVE_LIBBFD_SUPPORT + $(call detected,CONFIG_LIBBFD) =20 $(call feature_check,libbfd-buildid) =20 diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 63160c4a517e..bb2023a3d0c9 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -14,7 +14,6 @@ perf-util-y +=3D copyfile.o perf-util-y +=3D ctype.o perf-util-y +=3D db-export.o perf-util-y +=3D disasm.o -perf-util-y +=3D disasm_bpf.o perf-util-y +=3D env.o perf-util-y +=3D event.o perf-util-y +=3D evlist.o @@ -26,6 +25,7 @@ perf-util-y +=3D evswitch.o perf-util-y +=3D find_bit.o perf-util-y +=3D get_current_dir_name.o perf-util-y +=3D levenshtein.o +perf-util-$(CONFIG_LIBBFD) +=3D libbfd.o perf-util-y +=3D llvm.o perf-util-y +=3D mmap.o perf-util-y +=3D memswap.o diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index fa6accd8d873..a1240543c89c 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -17,11 +17,11 @@ #include "capstone.h" #include "debug.h" #include "disasm.h" -#include "disasm_bpf.h" #include "dso.h" #include "dwarf-regs.h" #include "env.h" #include "evsel.h" +#include "libbfd.h" #include "llvm.h" #include "map.h" #include "maps.h" @@ -1480,6 +1480,23 @@ char *expand_tabs(char *line, char **storage, size_t= *storage_len) return new_line; } =20 +static int symbol__disassemble_bpf_image(struct symbol *sym, struct annota= te_args *args) +{ + struct annotation *notes =3D symbol__annotation(sym); + struct disasm_line *dl; + + args->offset =3D -1; + args->line =3D strdup("to be implemented"); + args->line_nr =3D 0; + args->fileloc =3D NULL; + dl =3D disasm_line__new(args); + if (dl) + annotation_line__add(&dl->al, ¬es->src->source); + + zfree(&args->line); + return 0; +} + static int symbol__disassemble_objdump(const char *filename, struct symbol= *sym, struct annotate_args *args) { diff --git a/tools/perf/util/disasm_bpf.c b/tools/perf/util/disasm_bpf.c deleted file mode 100644 index 1fee71c79b62..000000000000 --- a/tools/perf/util/disasm_bpf.c +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include "util/annotate.h" -#include "util/disasm_bpf.h" -#include "util/symbol.h" -#include -#include - -#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) -#define PACKAGE "perf" -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util/bpf-event.h" -#include "util/bpf-utils.h" -#include "util/debug.h" -#include "util/dso.h" -#include "util/map.h" -#include "util/env.h" -#include "util/util.h" - -int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args) -{ - struct annotation *notes =3D symbol__annotation(sym); - struct bpf_prog_linfo *prog_linfo =3D NULL; - struct bpf_prog_info_node *info_node; - int len =3D sym->end - sym->start; - disassembler_ftype disassemble; - struct map *map =3D args->ms.map; - struct perf_bpil *info_linear; - struct disassemble_info info; - struct dso *dso =3D map__dso(map); - int pc =3D 0, count, sub_id; - struct btf *btf =3D NULL; - char tpath[PATH_MAX]; - size_t buf_size; - int nr_skip =3D 0; - char *buf; - bfd *bfdf; - int ret; - FILE *s; - - if (dso__binary_type(dso) !=3D DSO_BINARY_TYPE__BPF_PROG_INFO) - return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; - - pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func= __, - sym->name, sym->start, sym->end - sym->start); - - memset(tpath, 0, sizeof(tpath)); - perf_exe(tpath, sizeof(tpath)); - - bfdf =3D bfd_openr(tpath, NULL); - if (bfdf =3D=3D NULL) - abort(); - - if (!bfd_check_format(bfdf, bfd_object)) - abort(); - - s =3D open_memstream(&buf, &buf_size); - if (!s) { - ret =3D errno; - goto out; - } - init_disassemble_info_compat(&info, s, - (fprintf_ftype) fprintf, - fprintf_styled); - info.arch =3D bfd_get_arch(bfdf); - info.mach =3D bfd_get_mach(bfdf); - - info_node =3D perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env, - dso__bpf_prog(dso)->id); - if (!info_node) { - ret =3D SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; - goto out; - } - info_linear =3D info_node->info_linear; - sub_id =3D dso__bpf_prog(dso)->sub_id; - - info.buffer =3D (void *)(uintptr_t)(info_linear->info.jited_prog_insns); - info.buffer_length =3D info_linear->info.jited_prog_len; - - if (info_linear->info.nr_line_info) - prog_linfo =3D bpf_prog_linfo__new(&info_linear->info); - - if (info_linear->info.btf_id) { - struct btf_node *node; - - node =3D perf_env__find_btf(dso__bpf_prog(dso)->env, - info_linear->info.btf_id); - if (node) - btf =3D btf__new((__u8 *)(node->data), - node->data_size); - } - - disassemble_init_for_target(&info); - -#ifdef DISASM_FOUR_ARGS_SIGNATURE - disassemble =3D disassembler(info.arch, - bfd_big_endian(bfdf), - info.mach, - bfdf); -#else - disassemble =3D disassembler(bfdf); -#endif - if (disassemble =3D=3D NULL) - abort(); - - fflush(s); - do { - const struct bpf_line_info *linfo =3D NULL; - struct disasm_line *dl; - size_t prev_buf_size; - const char *srcline; - u64 addr; - - addr =3D pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id= ]; - count =3D disassemble(pc, &info); - - if (prog_linfo) - linfo =3D bpf_prog_linfo__lfind_addr_func(prog_linfo, - addr, sub_id, - nr_skip); - - if (linfo && btf) { - srcline =3D btf__name_by_offset(btf, linfo->line_off); - nr_skip++; - } else - srcline =3D NULL; - - fprintf(s, "\n"); - prev_buf_size =3D buf_size; - fflush(s); - - if (!annotate_opts.hide_src_code && srcline) { - args->offset =3D -1; - args->line =3D strdup(srcline); - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - dl =3D disasm_line__new(args); - if (dl) { - annotation_line__add(&dl->al, - ¬es->src->source); - } - } - - args->offset =3D pc; - args->line =3D buf + prev_buf_size; - args->line_nr =3D 0; - args->fileloc =3D NULL; - args->ms.sym =3D sym; - dl =3D disasm_line__new(args); - if (dl) - annotation_line__add(&dl->al, ¬es->src->source); - - pc +=3D count; - } while (count > 0 && pc < len); - - ret =3D 0; -out: - free(prog_linfo); - btf__free(btf); - fclose(s); - bfd_close(bfdf); - return ret; -} -#else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) -int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, struct anno= tate_args *args __maybe_unused) -{ - return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; -} -#endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) - -int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args= *args) -{ - struct annotation *notes =3D symbol__annotation(sym); - struct disasm_line *dl; - - args->offset =3D -1; - args->line =3D strdup("to be implemented"); - args->line_nr =3D 0; - args->fileloc =3D NULL; - dl =3D disasm_line__new(args); - if (dl) - annotation_line__add(&dl->al, ¬es->src->source); - - zfree(&args->line); - return 0; -} diff --git a/tools/perf/util/disasm_bpf.h b/tools/perf/util/disasm_bpf.h deleted file mode 100644 index 2ecb19545388..000000000000 --- a/tools/perf/util/disasm_bpf.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#ifndef __PERF_DISASM_BPF_H -#define __PERF_DISASM_BPF_H - -struct symbol; -struct annotate_args; - -int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args= ); -int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args= *args); - -#endif /* __PERF_DISASM_BPF_H */ diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c new file mode 100644 index 000000000000..09a0eeb78a1a --- /dev/null +++ b/tools/perf/util/libbfd.c @@ -0,0 +1,600 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libbfd.h" +#include "annotate.h" +#include "bpf-event.h" +#include "bpf-utils.h" +#include "debug.h" +#include "dso.h" +#include "env.h" +#include "map.h" +#include "srcline.h" +#include "symbol.h" +#include "symbol_conf.h" +#include "util.h" +#include +#ifdef HAVE_LIBBPF_SUPPORT +#include +#include +#endif +#include +#include +#include +#define PACKAGE "perf" +#include + +/* + * Implement addr2line using libbfd. + */ +struct a2l_data { + const char *input; + u64 addr; + + bool found; + const char *filename; + const char *funcname; + unsigned int line; + + bfd *abfd; + asymbol **syms; +}; + +static int bfd_error(const char *string) +{ + const char *errmsg; + + errmsg =3D bfd_errmsg(bfd_get_error()); + fflush(stdout); + + if (string) + pr_debug("%s: %s\n", string, errmsg); + else + pr_debug("%s\n", errmsg); + + return -1; +} + +static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) +{ + long storage; + long symcount; + asymbol **syms; + bfd_boolean dynamic =3D FALSE; + + if ((bfd_get_file_flags(abfd) & HAS_SYMS) =3D=3D 0) + return bfd_error(bfd_get_filename(abfd)); + + storage =3D bfd_get_symtab_upper_bound(abfd); + if (storage =3D=3D 0L) { + storage =3D bfd_get_dynamic_symtab_upper_bound(abfd); + dynamic =3D TRUE; + } + if (storage < 0L) + return bfd_error(bfd_get_filename(abfd)); + + syms =3D malloc(storage); + if (dynamic) + symcount =3D bfd_canonicalize_dynamic_symtab(abfd, syms); + else + symcount =3D bfd_canonicalize_symtab(abfd, syms); + + if (symcount < 0) { + free(syms); + return bfd_error(bfd_get_filename(abfd)); + } + + a2l->syms =3D syms; + return 0; +} + +static void find_address_in_section(bfd *abfd, asection *section, void *da= ta) +{ + bfd_vma pc, vma; + bfd_size_type size; + struct a2l_data *a2l =3D data; + flagword flags; + + if (a2l->found) + return; + +#ifdef bfd_get_section_flags + flags =3D bfd_get_section_flags(abfd, section); +#else + flags =3D bfd_section_flags(section); +#endif + if ((flags & SEC_ALLOC) =3D=3D 0) + return; + + pc =3D a2l->addr; +#ifdef bfd_get_section_vma + vma =3D bfd_get_section_vma(abfd, section); +#else + vma =3D bfd_section_vma(section); +#endif +#ifdef bfd_get_section_size + size =3D bfd_get_section_size(section); +#else + size =3D bfd_section_size(section); +#endif + + if (pc < vma || pc >=3D vma + size) + return; + + a2l->found =3D bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma, + &a2l->filename, &a2l->funcname, + &a2l->line); + + if (a2l->filename && !strlen(a2l->filename)) + a2l->filename =3D NULL; +} + +static struct a2l_data *addr2line_init(const char *path) +{ + bfd *abfd; + struct a2l_data *a2l =3D NULL; + + abfd =3D bfd_openr(path, NULL); + if (abfd =3D=3D NULL) + return NULL; + + if (!bfd_check_format(abfd, bfd_object)) + goto out; + + a2l =3D zalloc(sizeof(*a2l)); + if (a2l =3D=3D NULL) + goto out; + + a2l->abfd =3D abfd; + a2l->input =3D strdup(path); + if (a2l->input =3D=3D NULL) + goto out; + + if (slurp_symtab(abfd, a2l)) + goto out; + + return a2l; + +out: + if (a2l) { + zfree((char **)&a2l->input); + free(a2l); + } + bfd_close(abfd); + return NULL; +} + +static void addr2line_cleanup(struct a2l_data *a2l) +{ + if (a2l->abfd) + bfd_close(a2l->abfd); + zfree((char **)&a2l->input); + zfree(&a2l->syms); + free(a2l); +} + +static int inline_list__append_dso_a2l(struct dso *dso, + struct inline_node *node, + struct symbol *sym) +{ + struct a2l_data *a2l =3D dso__a2l(dso); + struct symbol *inline_sym =3D new_inline_sym(dso, sym, a2l->funcname); + char *srcline =3D NULL; + + if (a2l->filename) + srcline =3D srcline_from_fileline(a2l->filename, a2l->line); + + return inline_list__append(inline_sym, srcline, node); +} + +int libbfd__addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line, struct dso *dso, + bool unwind_inlines, struct inline_node *node, + struct symbol *sym) +{ + int ret =3D 0; + struct a2l_data *a2l =3D dso__a2l(dso); + + if (!a2l) { + a2l =3D addr2line_init(dso_name); + dso__set_a2l(dso, a2l); + } + + if (a2l =3D=3D NULL) { + if (!symbol_conf.disable_add2line_warn) + pr_warning("addr2line_init failed for %s\n", dso_name); + return 0; + } + + a2l->addr =3D addr; + a2l->found =3D false; + + bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); + + if (!a2l->found) + return 0; + + if (unwind_inlines) { + int cnt =3D 0; + + if (node && inline_list__append_dso_a2l(dso, node, sym)) + return 0; + + while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, + &a2l->funcname, &a2l->line) && + cnt++ < MAX_INLINE_NEST) { + + if (a2l->filename && !strlen(a2l->filename)) + a2l->filename =3D NULL; + + if (node !=3D NULL) { + if (inline_list__append_dso_a2l(dso, node, sym)) + return 0; + // found at least one inline frame + ret =3D 1; + } + } + } + + if (file) { + *file =3D a2l->filename ? strdup(a2l->filename) : NULL; + ret =3D *file ? 1 : 0; + } + + if (line) + *line =3D a2l->line; + + return ret; +} + +void dso__free_a2l_libbfd(struct dso *dso) +{ + struct a2l_data *a2l =3D dso__a2l(dso); + + if (!a2l) + return; + + addr2line_cleanup(a2l); + + dso__set_a2l(dso, NULL); +} + +static int bfd_symbols__cmpvalue(const void *a, const void *b) +{ + const asymbol *as =3D *(const asymbol **)a, *bs =3D *(const asymbol **)b; + + if (bfd_asymbol_value(as) !=3D bfd_asymbol_value(bs)) + return bfd_asymbol_value(as) - bfd_asymbol_value(bs); + + return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; +} + +static int bfd2elf_binding(asymbol *symbol) +{ + if (symbol->flags & BSF_WEAK) + return STB_WEAK; + if (symbol->flags & BSF_GLOBAL) + return STB_GLOBAL; + if (symbol->flags & BSF_LOCAL) + return STB_LOCAL; + return -1; +} + +int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) +{ + int err =3D -1; + long symbols_size, symbols_count, i; + asection *section; + asymbol **symbols, *sym; + struct symbol *symbol; + bfd *abfd; + u64 start, len; + + abfd =3D bfd_openr(debugfile, NULL); + if (!abfd) + return -1; + + if (!bfd_check_format(abfd, bfd_object)) { + pr_debug2("%s: cannot read %s bfd file.\n", __func__, + dso__long_name(dso)); + goto out_close; + } + + if (bfd_get_flavour(abfd) =3D=3D bfd_target_elf_flavour) + goto out_close; + + symbols_size =3D bfd_get_symtab_upper_bound(abfd); + if (symbols_size =3D=3D 0) { + bfd_close(abfd); + return 0; + } + + if (symbols_size < 0) + goto out_close; + + symbols =3D malloc(symbols_size); + if (!symbols) + goto out_close; + + symbols_count =3D bfd_canonicalize_symtab(abfd, symbols); + if (symbols_count < 0) + goto out_free; + + section =3D bfd_get_section_by_name(abfd, ".text"); + if (section) { + for (i =3D 0; i < symbols_count; ++i) { + if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || + !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) + break; + } + if (i < symbols_count) { + /* PE symbols can only have 4 bytes, so use .text high bits */ + u64 text_offset =3D (section->vma - (u32)section->vma) + + (u32)bfd_asymbol_value(symbols[i]); + dso__set_text_offset(dso, text_offset); + dso__set_text_end(dso, (section->vma - text_offset) + section->size); + } else { + dso__set_text_offset(dso, section->vma - section->filepos); + dso__set_text_end(dso, section->filepos + section->size); + } + } + + qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); + +#ifdef bfd_get_section +#define bfd_asymbol_section bfd_get_section +#endif + for (i =3D 0; i < symbols_count; ++i) { + sym =3D symbols[i]; + section =3D bfd_asymbol_section(sym); + if (bfd2elf_binding(sym) < 0) + continue; + + while (i + 1 < symbols_count && + bfd_asymbol_section(symbols[i + 1]) =3D=3D section && + bfd2elf_binding(symbols[i + 1]) < 0) + i++; + + if (i + 1 < symbols_count && + bfd_asymbol_section(symbols[i + 1]) =3D=3D section) + len =3D symbols[i + 1]->value - sym->value; + else + len =3D section->size - sym->value; + + start =3D bfd_asymbol_value(sym) - dso__text_offset(dso); + symbol =3D symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, + bfd_asymbol_name(sym)); + if (!symbol) + goto out_free; + + symbols__insert(dso__symbols(dso), symbol); + } +#ifdef bfd_get_section +#undef bfd_asymbol_section +#endif + + symbols__fixup_end(dso__symbols(dso), false); + symbols__fixup_duplicate(dso__symbols(dso)); + dso__set_adjust_symbols(dso, true); + + err =3D 0; +out_free: + free(symbols); +out_close: + bfd_close(abfd); + return err; +} + +int libbfd__read_build_id(const char *filename, struct build_id *bid, bool= block) +{ + size_t size =3D sizeof(bid->data); + int err =3D -1, fd; + bfd *abfd; + + fd =3D open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK)); + if (fd < 0) + return -1; + + abfd =3D bfd_fdopenr(filename, /*target=3D*/NULL, fd); + if (!abfd) + return -1; + + if (!bfd_check_format(abfd, bfd_object)) { + pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); + goto out_close; + } + + if (!abfd->build_id || abfd->build_id->size > size) + goto out_close; + + memcpy(bid->data, abfd->build_id->data, abfd->build_id->size); + memset(bid->data + abfd->build_id->size, 0, size - abfd->build_id->size); + err =3D bid->size =3D abfd->build_id->size; + +out_close: + bfd_close(abfd); + return err; +} + +int libbfd_filename__read_debuglink(const char *filename, char *debuglink, + size_t size) +{ + int err =3D -1; + asection *section; + bfd *abfd; + + abfd =3D bfd_openr(filename, NULL); + if (!abfd) + return -1; + + if (!bfd_check_format(abfd, bfd_object)) { + pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); + goto out_close; + } + + section =3D bfd_get_section_by_name(abfd, ".gnu_debuglink"); + if (!section) + goto out_close; + + if (section->size > size) + goto out_close; + + if (!bfd_get_section_contents(abfd, section, debuglink, 0, + section->size)) + goto out_close; + + err =3D 0; + +out_close: + bfd_close(abfd); + return err; +} + +int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ +#ifdef HAVE_LIBBPF_SUPPORT + struct annotation *notes =3D symbol__annotation(sym); + struct bpf_prog_linfo *prog_linfo =3D NULL; + struct bpf_prog_info_node *info_node; + int len =3D sym->end - sym->start; + disassembler_ftype disassemble; + struct map *map =3D args->ms.map; + struct perf_bpil *info_linear; + struct disassemble_info info; + struct dso *dso =3D map__dso(map); + int pc =3D 0, count, sub_id; + struct btf *btf =3D NULL; + char tpath[PATH_MAX]; + size_t buf_size; + int nr_skip =3D 0; + char *buf; + bfd *bfdf; + int ret; + FILE *s; + + if (dso__binary_type(dso) !=3D DSO_BINARY_TYPE__BPF_PROG_INFO) + return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; + + pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func= __, + sym->name, sym->start, sym->end - sym->start); + + memset(tpath, 0, sizeof(tpath)); + perf_exe(tpath, sizeof(tpath)); + + bfdf =3D bfd_openr(tpath, NULL); + if (bfdf =3D=3D NULL) + abort(); + + if (!bfd_check_format(bfdf, bfd_object)) + abort(); + + s =3D open_memstream(&buf, &buf_size); + if (!s) { + ret =3D errno; + goto out; + } + init_disassemble_info_compat(&info, s, + (fprintf_ftype) fprintf, + fprintf_styled); + info.arch =3D bfd_get_arch(bfdf); + info.mach =3D bfd_get_mach(bfdf); + + info_node =3D perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env, + dso__bpf_prog(dso)->id); + if (!info_node) { + ret =3D SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; + goto out; + } + info_linear =3D info_node->info_linear; + sub_id =3D dso__bpf_prog(dso)->sub_id; + + info.buffer =3D (void *)(uintptr_t)(info_linear->info.jited_prog_insns); + info.buffer_length =3D info_linear->info.jited_prog_len; + + if (info_linear->info.nr_line_info) + prog_linfo =3D bpf_prog_linfo__new(&info_linear->info); + + if (info_linear->info.btf_id) { + struct btf_node *node; + + node =3D perf_env__find_btf(dso__bpf_prog(dso)->env, + info_linear->info.btf_id); + if (node) + btf =3D btf__new((__u8 *)(node->data), + node->data_size); + } + + disassemble_init_for_target(&info); + +#ifdef DISASM_FOUR_ARGS_SIGNATURE + disassemble =3D disassembler(info.arch, + bfd_big_endian(bfdf), + info.mach, + bfdf); +#else + disassemble =3D disassembler(bfdf); +#endif + if (disassemble =3D=3D NULL) + abort(); + + fflush(s); + do { + const struct bpf_line_info *linfo =3D NULL; + struct disasm_line *dl; + size_t prev_buf_size; + const char *srcline; + u64 addr; + + addr =3D pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id= ]; + count =3D disassemble(pc, &info); + + if (prog_linfo) + linfo =3D bpf_prog_linfo__lfind_addr_func(prog_linfo, + addr, sub_id, + nr_skip); + + if (linfo && btf) { + srcline =3D btf__name_by_offset(btf, linfo->line_off); + nr_skip++; + } else + srcline =3D NULL; + + fprintf(s, "\n"); + prev_buf_size =3D buf_size; + fflush(s); + + if (!annotate_opts.hide_src_code && srcline) { + args->offset =3D -1; + args->line =3D strdup(srcline); + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + dl =3D disasm_line__new(args); + if (dl) { + annotation_line__add(&dl->al, + ¬es->src->source); + } + } + + args->offset =3D pc; + args->line =3D buf + prev_buf_size; + args->line_nr =3D 0; + args->fileloc =3D NULL; + args->ms.sym =3D sym; + dl =3D disasm_line__new(args); + if (dl) + annotation_line__add(&dl->al, ¬es->src->source); + + pc +=3D count; + } while (count > 0 && pc < len); + + ret =3D 0; +out: + free(prog_linfo); + btf__free(btf); + fclose(s); + bfd_close(bfdf); + return ret; +#else + return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; +#endif +} diff --git a/tools/perf/util/libbfd.h b/tools/perf/util/libbfd.h new file mode 100644 index 000000000000..7441e95f8ec0 --- /dev/null +++ b/tools/perf/util/libbfd.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_LIBBFD_H +#define __PERF_LIBBFD_H + +#include +#include +#include +#include + +struct annotate_args; +struct build_id; +struct dso; +struct inline_node; +struct symbol; + +#ifdef HAVE_LIBBFD_SUPPORT +int libbfd__addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line, struct dso *dso, + bool unwind_inlines, struct inline_node *node, + struct symbol *sym); + + +void dso__free_a2l_libbfd(struct dso *dso); + +int symbol__disassemble_libbfd(const char *filename, struct symbol *sym, + struct annotate_args *args); + +int libbfd__read_build_id(const char *filename, struct build_id *bid, bool= block); + +int libbfd_filename__read_debuglink(const char *filename, char *debuglink,= size_t size); + +int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args= ); + +#else // !defined(HAVE_LIBBFD_SUPPORT) +#include "annotate.h" + +static inline int libbfd__addr2line(const char *dso_name __always_unused, + u64 addr __always_unused, + char **file __always_unused, + unsigned int *line __always_unused, + struct dso *dso __always_unused, + bool unwind_inlines __always_unused, + struct inline_node *node __always_unused, + struct symbol *sym __always_unused) +{ + return -1; +} + + +static inline void dso__free_a2l_libbfd(struct dso *dso __always_unused) +{ +} + +static inline int symbol__disassemble_libbfd(const char *filename __always= _unused, + struct symbol *sym __always_unused, + struct annotate_args *args __always_unused) +{ + return -1; +} + +static inline int libbfd__read_build_id(const char *filename __always_unus= ed, + struct build_id *bid __always_unused, + bool block __always_unused) +{ + return -1; +} + +static inline int libbfd_filename__read_debuglink(const char *filename __a= lways_unused, + char *debuglink __always_unused, + size_t size __always_unused) +{ + return -1; +} + +static inline int symbol__disassemble_bpf(struct symbol *sym __always_unus= ed, + struct annotate_args *args __always_unused) +{ + return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; +} + +#endif // defined(HAVE_LIBBFD_SUPPORT) + +#endif /* __PERF_LIBBFD_H */ diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 45e138ff3e52..23b942d4729e 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -129,8 +129,6 @@ struct symbol *new_inline_sym(struct dso *dso, return inline_sym; } =20 -#define MAX_INLINE_NEST 1024 - #ifdef HAVE_LIBLLVM_SUPPORT #include "llvm.h" =20 @@ -147,243 +145,19 @@ void dso__free_a2l(struct dso *dso) dso__free_a2l_llvm(dso); } #elif defined(HAVE_LIBBFD_SUPPORT) - -/* - * Implement addr2line using libbfd. - */ -#define PACKAGE "perf" -#include - -struct a2l_data { - const char *input; - u64 addr; - - bool found; - const char *filename; - const char *funcname; - unsigned line; - - bfd *abfd; - asymbol **syms; -}; - -static int bfd_error(const char *string) -{ - const char *errmsg; - - errmsg =3D bfd_errmsg(bfd_get_error()); - fflush(stdout); - - if (string) - pr_debug("%s: %s\n", string, errmsg); - else - pr_debug("%s\n", errmsg); - - return -1; -} - -static int slurp_symtab(bfd *abfd, struct a2l_data *a2l) -{ - long storage; - long symcount; - asymbol **syms; - bfd_boolean dynamic =3D FALSE; - - if ((bfd_get_file_flags(abfd) & HAS_SYMS) =3D=3D 0) - return bfd_error(bfd_get_filename(abfd)); - - storage =3D bfd_get_symtab_upper_bound(abfd); - if (storage =3D=3D 0L) { - storage =3D bfd_get_dynamic_symtab_upper_bound(abfd); - dynamic =3D TRUE; - } - if (storage < 0L) - return bfd_error(bfd_get_filename(abfd)); - - syms =3D malloc(storage); - if (dynamic) - symcount =3D bfd_canonicalize_dynamic_symtab(abfd, syms); - else - symcount =3D bfd_canonicalize_symtab(abfd, syms); - - if (symcount < 0) { - free(syms); - return bfd_error(bfd_get_filename(abfd)); - } - - a2l->syms =3D syms; - return 0; -} - -static void find_address_in_section(bfd *abfd, asection *section, void *da= ta) -{ - bfd_vma pc, vma; - bfd_size_type size; - struct a2l_data *a2l =3D data; - flagword flags; - - if (a2l->found) - return; - -#ifdef bfd_get_section_flags - flags =3D bfd_get_section_flags(abfd, section); -#else - flags =3D bfd_section_flags(section); -#endif - if ((flags & SEC_ALLOC) =3D=3D 0) - return; - - pc =3D a2l->addr; -#ifdef bfd_get_section_vma - vma =3D bfd_get_section_vma(abfd, section); -#else - vma =3D bfd_section_vma(section); -#endif -#ifdef bfd_get_section_size - size =3D bfd_get_section_size(section); -#else - size =3D bfd_section_size(section); -#endif - - if (pc < vma || pc >=3D vma + size) - return; - - a2l->found =3D bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma, - &a2l->filename, &a2l->funcname, - &a2l->line); - - if (a2l->filename && !strlen(a2l->filename)) - a2l->filename =3D NULL; -} - -static struct a2l_data *addr2line_init(const char *path) -{ - bfd *abfd; - struct a2l_data *a2l =3D NULL; - - abfd =3D bfd_openr(path, NULL); - if (abfd =3D=3D NULL) - return NULL; - - if (!bfd_check_format(abfd, bfd_object)) - goto out; - - a2l =3D zalloc(sizeof(*a2l)); - if (a2l =3D=3D NULL) - goto out; - - a2l->abfd =3D abfd; - a2l->input =3D strdup(path); - if (a2l->input =3D=3D NULL) - goto out; - - if (slurp_symtab(abfd, a2l)) - goto out; - - return a2l; - -out: - if (a2l) { - zfree((char **)&a2l->input); - free(a2l); - } - bfd_close(abfd); - return NULL; -} - -static void addr2line_cleanup(struct a2l_data *a2l) -{ - if (a2l->abfd) - bfd_close(a2l->abfd); - zfree((char **)&a2l->input); - zfree(&a2l->syms); - free(a2l); -} - -static int inline_list__append_dso_a2l(struct dso *dso, - struct inline_node *node, - struct symbol *sym) -{ - struct a2l_data *a2l =3D dso__a2l(dso); - struct symbol *inline_sym =3D new_inline_sym(dso, sym, a2l->funcname); - char *srcline =3D NULL; - - if (a2l->filename) - srcline =3D srcline_from_fileline(a2l->filename, a2l->line); - - return inline_list__append(inline_sym, srcline, node); -} +#include "libbfd.h" =20 static int addr2line(const char *dso_name, u64 addr, char **file, unsigned int *line, struct dso *dso, bool unwind_inlines, struct inline_node *node, struct symbol *sym) { - int ret =3D 0; - struct a2l_data *a2l =3D dso__a2l(dso); - - if (!a2l) { - a2l =3D addr2line_init(dso_name); - dso__set_a2l(dso, a2l); - } - - if (a2l =3D=3D NULL) { - if (!symbol_conf.disable_add2line_warn) - pr_warning("addr2line_init failed for %s\n", dso_name); - return 0; - } - - a2l->addr =3D addr; - a2l->found =3D false; - - bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l); - - if (!a2l->found) - return 0; - - if (unwind_inlines) { - int cnt =3D 0; - - if (node && inline_list__append_dso_a2l(dso, node, sym)) - return 0; - - while (bfd_find_inliner_info(a2l->abfd, &a2l->filename, - &a2l->funcname, &a2l->line) && - cnt++ < MAX_INLINE_NEST) { - - if (a2l->filename && !strlen(a2l->filename)) - a2l->filename =3D NULL; - - if (node !=3D NULL) { - if (inline_list__append_dso_a2l(dso, node, sym)) - return 0; - // found at least one inline frame - ret =3D 1; - } - } - } - - if (file) { - *file =3D a2l->filename ? strdup(a2l->filename) : NULL; - ret =3D *file ? 1 : 0; - } - - if (line) - *line =3D a2l->line; - - return ret; + return libbfd__addr2line(dso_name, addr, file, line, dso, unwind_inlines,= node, sym); } =20 void dso__free_a2l(struct dso *dso) { - struct a2l_data *a2l =3D dso__a2l(dso); - - if (!a2l) - return; - - addr2line_cleanup(a2l); - - dso__set_a2l(dso, NULL); + dso__free_a2l_libbfd(dso); } =20 #else /* HAVE_LIBBFD_SUPPORT */ diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h index 80c20169e250..6e66ddbcc879 100644 --- a/tools/perf/util/srcline.h +++ b/tools/perf/util/srcline.h @@ -29,6 +29,8 @@ void srcline__tree_delete(struct rb_root_cached *tree); extern char *srcline__unknown; #define SRCLINE_UNKNOWN srcline__unknown =20 +#define MAX_INLINE_NEST 1024 + struct inline_list { struct symbol *symbol; char *srcline; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 1346fd180653..9e820599bab3 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -9,6 +9,7 @@ =20 #include "compress.h" #include "dso.h" +#include "libbfd.h" #include "map.h" #include "maps.h" #include "symbol.h" @@ -24,18 +25,6 @@ #include #include =20 -#ifdef HAVE_LIBBFD_SUPPORT -#define PACKAGE 'perf' -#include -#endif - -#if defined(HAVE_LIBBFD_SUPPORT) || defined(HAVE_CPLUS_DEMANGLE_SUPPORT) -#ifndef DMGL_PARAMS -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#endif -#endif - #ifndef EM_AARCH64 #define EM_AARCH64 183 /* ARM 64 bit */ #endif @@ -871,47 +860,16 @@ static int elf_read_build_id(Elf *elf, void *bf, size= _t size) return err; } =20 -#ifdef HAVE_LIBBFD_BUILDID_SUPPORT - -static int read_build_id(const char *filename, struct build_id *bid, bool = block) -{ - size_t size =3D sizeof(bid->data); - int err =3D -1, fd; - bfd *abfd; - - fd =3D open(filename, block ? O_RDONLY : (O_RDONLY | O_NONBLOCK)); - if (fd < 0) - return -1; - - abfd =3D bfd_fdopenr(filename, /*target=3D*/NULL, fd); - if (!abfd) - return -1; - - if (!bfd_check_format(abfd, bfd_object)) { - pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); - goto out_close; - } - - if (!abfd->build_id || abfd->build_id->size > size) - goto out_close; - - memcpy(bid->data, abfd->build_id->data, abfd->build_id->size); - memset(bid->data + abfd->build_id->size, 0, size - abfd->build_id->size); - err =3D bid->size =3D abfd->build_id->size; - -out_close: - bfd_close(abfd); - return err; -} - -#else // HAVE_LIBBFD_BUILDID_SUPPORT - static int read_build_id(const char *filename, struct build_id *bid, bool = block) { size_t size =3D sizeof(bid->data); - int fd, err =3D -1; + int fd, err; Elf *elf; =20 + err =3D libbfd__read_build_id(filename, bid, block); + if (err >=3D 0) + goto out; + if (size < BUILD_ID_SIZE) goto out; =20 @@ -936,8 +894,6 @@ static int read_build_id(const char *filename, struct b= uild_id *bid, bool block) return err; } =20 -#endif // HAVE_LIBBFD_BUILDID_SUPPORT - int filename__read_build_id(const char *filename, struct build_id *bid, bo= ol block) { struct kmod_path m =3D { .name =3D NULL, }; @@ -1022,44 +978,6 @@ int sysfs__read_build_id(const char *filename, struct= build_id *bid) return err; } =20 -#ifdef HAVE_LIBBFD_SUPPORT - -int filename__read_debuglink(const char *filename, char *debuglink, - size_t size) -{ - int err =3D -1; - asection *section; - bfd *abfd; - - abfd =3D bfd_openr(filename, NULL); - if (!abfd) - return -1; - - if (!bfd_check_format(abfd, bfd_object)) { - pr_debug2("%s: cannot read %s bfd file.\n", __func__, filename); - goto out_close; - } - - section =3D bfd_get_section_by_name(abfd, ".gnu_debuglink"); - if (!section) - goto out_close; - - if (section->size > size) - goto out_close; - - if (!bfd_get_section_contents(abfd, section, debuglink, 0, - section->size)) - goto out_close; - - err =3D 0; - -out_close: - bfd_close(abfd); - return err; -} - -#else - int filename__read_debuglink(const char *filename, char *debuglink, size_t size) { @@ -1071,6 +989,10 @@ int filename__read_debuglink(const char *filename, ch= ar *debuglink, Elf_Scn *sec; Elf_Kind ek; =20 + err =3D libbfd_filename__read_debuglink(filename, debuglink, size); + if (err >=3D 0) + goto out; + fd =3D open(filename, O_RDONLY); if (fd < 0) goto out; @@ -1112,8 +1034,6 @@ int filename__read_debuglink(const char *filename, ch= ar *debuglink, return err; } =20 -#endif - bool symsrc__possibly_runtime(struct symsrc *ss) { return ss->dynsym || ss->opdsec; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3d04382687d1..cc26b7bf302b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1589,137 +1589,6 @@ static int dso__load_perf_map(const char *map_path,= struct dso *dso) return -1; } =20 -#ifdef HAVE_LIBBFD_SUPPORT -#define PACKAGE 'perf' -#include - -static int bfd_symbols__cmpvalue(const void *a, const void *b) -{ - const asymbol *as =3D *(const asymbol **)a, *bs =3D *(const asymbol **)b; - - if (bfd_asymbol_value(as) !=3D bfd_asymbol_value(bs)) - return bfd_asymbol_value(as) - bfd_asymbol_value(bs); - - return bfd_asymbol_name(as)[0] - bfd_asymbol_name(bs)[0]; -} - -static int bfd2elf_binding(asymbol *symbol) -{ - if (symbol->flags & BSF_WEAK) - return STB_WEAK; - if (symbol->flags & BSF_GLOBAL) - return STB_GLOBAL; - if (symbol->flags & BSF_LOCAL) - return STB_LOCAL; - return -1; -} - -int dso__load_bfd_symbols(struct dso *dso, const char *debugfile) -{ - int err =3D -1; - long symbols_size, symbols_count, i; - asection *section; - asymbol **symbols, *sym; - struct symbol *symbol; - bfd *abfd; - u64 start, len; - - abfd =3D bfd_openr(debugfile, NULL); - if (!abfd) - return -1; - - if (!bfd_check_format(abfd, bfd_object)) { - pr_debug2("%s: cannot read %s bfd file.\n", __func__, - dso__long_name(dso)); - goto out_close; - } - - if (bfd_get_flavour(abfd) =3D=3D bfd_target_elf_flavour) - goto out_close; - - symbols_size =3D bfd_get_symtab_upper_bound(abfd); - if (symbols_size =3D=3D 0) { - bfd_close(abfd); - return 0; - } - - if (symbols_size < 0) - goto out_close; - - symbols =3D malloc(symbols_size); - if (!symbols) - goto out_close; - - symbols_count =3D bfd_canonicalize_symtab(abfd, symbols); - if (symbols_count < 0) - goto out_free; - - section =3D bfd_get_section_by_name(abfd, ".text"); - if (section) { - for (i =3D 0; i < symbols_count; ++i) { - if (!strcmp(bfd_asymbol_name(symbols[i]), "__ImageBase") || - !strcmp(bfd_asymbol_name(symbols[i]), "__image_base__")) - break; - } - if (i < symbols_count) { - /* PE symbols can only have 4 bytes, so use .text high bits */ - u64 text_offset =3D (section->vma - (u32)section->vma) - + (u32)bfd_asymbol_value(symbols[i]); - dso__set_text_offset(dso, text_offset); - dso__set_text_end(dso, (section->vma - text_offset) + section->size); - } else { - dso__set_text_offset(dso, section->vma - section->filepos); - dso__set_text_end(dso, section->filepos + section->size); - } - } - - qsort(symbols, symbols_count, sizeof(asymbol *), bfd_symbols__cmpvalue); - -#ifdef bfd_get_section -#define bfd_asymbol_section bfd_get_section -#endif - for (i =3D 0; i < symbols_count; ++i) { - sym =3D symbols[i]; - section =3D bfd_asymbol_section(sym); - if (bfd2elf_binding(sym) < 0) - continue; - - while (i + 1 < symbols_count && - bfd_asymbol_section(symbols[i + 1]) =3D=3D section && - bfd2elf_binding(symbols[i + 1]) < 0) - i++; - - if (i + 1 < symbols_count && - bfd_asymbol_section(symbols[i + 1]) =3D=3D section) - len =3D symbols[i + 1]->value - sym->value; - else - len =3D section->size - sym->value; - - start =3D bfd_asymbol_value(sym) - dso__text_offset(dso); - symbol =3D symbol__new(start, len, bfd2elf_binding(sym), STT_FUNC, - bfd_asymbol_name(sym)); - if (!symbol) - goto out_free; - - symbols__insert(dso__symbols(dso), symbol); - } -#ifdef bfd_get_section -#undef bfd_asymbol_section -#endif - - symbols__fixup_end(dso__symbols(dso), false); - symbols__fixup_duplicate(dso__symbols(dso)); - dso__set_adjust_symbols(dso, true); - - err =3D 0; -out_free: - free(symbols); -out_close: - bfd_close(abfd); - return err; -} -#endif - static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod, enum dso_binary_type type) { --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5EA39254855 for ; Mon, 29 Sep 2025 19:08:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172930; cv=none; b=D+jXLZL7wFcIql7mAvcBuKtUIIi45XEQpTsrS1d/rB6SJdej6+e9hgWKTFtQxFYnRRfv/+jjbRE+ux/0nr/vo6yrGhSpWm6BZyGi/kq6EX05oYU+EdkByU2VHd0b3u7w4l5LEn23x3nt7j6DjoyLIzPfohZA8IfajdZAsVBG8bU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172930; c=relaxed/simple; bh=UcoUgqD5Q/SkkemokbzVJ+iRz4obkkfuwAK0b461Crs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=m0lu9+1fEM/9tHIsziWmf747CnFulHkayNPNc1soERigcrrcsWPxDys6uvVchXngUMkeT8g6Eqlqd+UXza6YGGAZ6tgwNbotWSacoreqyfhZZ+zHvRpCJE4oPoJq6m0NuQG/BOsI/UDMDakNkGNImu4ckVDSt5q4MYYHMg+hIR4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=p3w6i+ft; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="p3w6i+ft" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-32edda89a37so4615106a91.1 for ; Mon, 29 Sep 2025 12:08:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172928; x=1759777728; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=dDZ0M0yiFaINDqNMQn65gDjbecQUNUjlpaqlu/RqK2I=; b=p3w6i+ftPrDkUqxxcped1KiUy9YHWkk+yPMGN5b+uZlBMZcr6LAVpGwXKlnFojDiqo tEndCHyYQPvyNR0jy+MgSmipXXYxn/2pTKrfQPzsGjqoZJgtdWMqmH5Dlcxe7zElYQi2 A1jXbssINrQhswDJLeeuYsZ17s7/M16+NDwLKUr9YlnKfieUV6l02AlfnoJm5t4WUBRK ye3wCdDpL+itCOd1C3H7X5Jwep0HJkUw4mvUApLEgrojPvV+R6XHAbzJXLSnGcshwY3S nhhVt7LEStJIH3RyM72XubnJm4XzCJxsBbU01Cn9xDYQstFirgXlOEe6AGVnsn1PMZTZ v1ZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172928; x=1759777728; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=dDZ0M0yiFaINDqNMQn65gDjbecQUNUjlpaqlu/RqK2I=; b=u9pFxx5/Jf06YT1b1intcCTMbhR+kcD7MC43KUNdNG7V9RNAFRBBQseRAoIszXgWnt S8tPmRKgTxP6KVR71EjAj4/Q2A1otTXD/iCgNmACo0MvzlznUrVKbEqSGGg8Yix4IwNR UOhcqUb2KX8/aZt6Ljvhyjheohyd1z/Qj4D3rfQxnQT+qdtydEw03qkOweLPeXZN6fkp CMr7n2oH7IrHUjK8UMJMfskGVMcFwkWabOu4xUlSGI/eW6KE+embolnKqjYiX0b/Jzaq wKctSSzg8OMm82ZoDB6O+tlQRgk/RqYfeG/CNdEiZmyxh6G8ERq0jbx/6R/JgQBsYpGD 0Z4g== X-Forwarded-Encrypted: i=1; AJvYcCUFyqL7noAnvT5yOb4c4oRDrJnKmiRrnvOVJLp88jLdXIcs6sSYr3U9+UMGxQwoJdpbzT09rZsS/siKC28=@vger.kernel.org X-Gm-Message-State: AOJu0YzIRDoCxYWTE/KGTx1NGbycuRH2yNOQX2gyWWR+H6nb1hrrWpmd o1mmSOpVTlG/ZLGmg+CuZv6564bz6DidDEUpd4r4baofukHQgjHqxandA4IsUB9NmeVE9uFGbzn vafQv4P1Q9g== X-Google-Smtp-Source: AGHT+IG/L8wfV8J+ckgrkT+kb7TWIc9uNlSseJshUzk1fQYWWvGgp/ovT6W4Pa0aDHCOn4arQ2uxbLWCwwft X-Received: from pjber8.prod.google.com ([2002:a17:90a:f6c8:b0:32b:6136:95b9]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:e7d0:b0:338:2c90:1540 with SMTP id 98e67ed59e1d1-3382c90186cmr5122050a91.20.1759172926884; Mon, 29 Sep 2025 12:08:46 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:55 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-6-irogers@google.com> Subject: [PATCH v6 05/15] perf capstone: Remove open_capstone_handle From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" open_capstone_handle is similar to capstone_init and used only by symbol__disassemble_capstone. symbol__disassemble_capstone_powerpc already uses capstone_init, transition symbol__disassemble_capstone and eliminate open_capstone_handle. Signed-off-by: Ian Rogers --- tools/perf/util/capstone.c | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index dd58e574aa52..01e47d5c8e3e 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -137,33 +137,6 @@ ssize_t capstone__fprintf_insn_asm(struct machine *mac= hine __maybe_unused, #endif } =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT -static int open_capstone_handle(struct annotate_args *args, bool is_64bit,= csh *handle) -{ - struct annotation_options *opt =3D args->options; - cs_mode mode =3D is_64bit ? CS_MODE_64 : CS_MODE_32; - - /* TODO: support more architectures */ - if (!arch__is(args->arch, "x86")) - return -1; - - if (cs_open(CS_ARCH_X86, mode, handle) !=3D CS_ERR_OK) - return -1; - - if (!opt->disassembler_style || - !strcmp(opt->disassembler_style, "att")) - cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); - - /* - * Resolving address operands to symbols is implemented - * on x86 by investigating instruction details. - */ - cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); - - return 0; -} -#endif - #ifdef HAVE_LIBCAPSTONE_SUPPORT static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, struct annotate_args *args, u64 addr) @@ -309,6 +282,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, cs_insn *insn =3D NULL; char disasm_buf[512]; struct disasm_line *dl; + bool disassembler_style =3D false; =20 if (args->options->objdump_path) return -1; @@ -333,7 +307,11 @@ int symbol__disassemble_capstone(const char *filename = __maybe_unused, =20 annotation_line__add(&dl->al, ¬es->src->source); =20 - if (open_capstone_handle(args, is_64bit, &handle) < 0) + if (!args->options->disassembler_style || + !strcmp(args->options->disassembler_style, "att")) + disassembler_style =3D true; + + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disass= embler_style) < 0) goto err; =20 needs_cs_close =3D true; --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-yw1-f201.google.com (mail-yw1-f201.google.com [209.85.128.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BE70D25FA0F for ; Mon, 29 Sep 2025 19:08:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172936; cv=none; b=GN2M4mCGUWrZS6wXIDQqQ4jmzix2wmEiDg7EaU+z3qqax+a0cSTBcW46XbbSVwOfNkY6pWn+ywv6Bf3uMnaqVjlABW3tMsayrk7SUZsgk4AK+czBNyzFxEs5Rq+Buw6sljowtGCfzrjrVj2ARDbzDsASbGrs41zYnD3s9J6D/Kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172936; c=relaxed/simple; bh=AVPvmJinkN+ChIjcvn7Zq0BPV9zVIYeBJdwRHwdUEpE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=BJdzxJjHiHoFRGg05h/7v4Wg++/vC6/ZtU4hyPlr/jxxXgUc3PBzynMvAZsG8mubzYqGngng15Gzs+4WlPsJPVf7+GrtLJlu8h+UYmtuhDV21tSyXkic6QJxyfR1egj4Bb9Mi72LoqnuCGnrCxjrPipNjXif17x69ZRkyv0T5Tk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=i2eoPiNt; arc=none smtp.client-ip=209.85.128.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="i2eoPiNt" Received: by mail-yw1-f201.google.com with SMTP id 00721157ae682-71d60163d68so74223537b3.0 for ; Mon, 29 Sep 2025 12:08:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172933; x=1759777733; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=BI3nOwntd4sZSGIX2BG+Rf556tM7S0t0SeXjHRWsGnc=; b=i2eoPiNtaqiGihrBWfx4IjhX9zVUoJ3GsAc1R44nLFUwa12Ed2fxLSzSMVN1TAbBHx THCxb38FrDXTxpRcY0A5h2qZlRsBprS9IntQoaF2P7drNPvtNvCqkUEajUGN+5H2cbIo 5/zZ6XyCKUNi4URI7uMOARHjSEF8N2cPYft3fjhJbVUFeVO61KVuIqeJTKtHrxH82L5r Z81P+QpWN511trNUZn20GqXs7Q/9psIc+mAC/jsm9/iQV+xke51tS3gp1HF0K0If/z9U W4LMdWXUHWxOGXxCZAWnpyFc++N+Clne0l40kxqW2QadIRxVXlCfi4ihfngS2l4S2tcs xvxg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172933; x=1759777733; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=BI3nOwntd4sZSGIX2BG+Rf556tM7S0t0SeXjHRWsGnc=; b=I5tFGOc5P1CD2E8yZfoUw1krpfdGccZmVMnslZBK69QVoiTwAoq5dYV2RSbTmmirnx EHVdPvHJ9+0p+wAj/Ogjc9BUGxljK7neJ8wE2L6eOvQzDGkXCmwKbE6LtSgAbowjGL+B 5JxLRqOhMF1zx+jYwuyuluh5V4LS/O+eZSgdiK3KgvaFAbVRXbTLmhzohagTaJp/YhID BtkrbU5+OSojtTr+wyKLjH9LZVkEjz1ubUK3RXMT9QVQlNeme+o4xCPky4AV2i+YQN0o ZhNemc72bMWQXe/dfgd9Tu6KG+DTEk+1wpWI3QNFTbs/2RrIu+B1swmnGqd2JF13Ka1f QwIA== X-Forwarded-Encrypted: i=1; AJvYcCXO6wRZ7Hztd6frKXiuBkhKHcTpjY3UwkIk4XZEo0k/EgO615YJbw6h6fGianDIvvXtPPbLilDLiMdnda4=@vger.kernel.org X-Gm-Message-State: AOJu0YzzZauIpsdCiBYlVduxtdqTcAHCJX7HcuezulX+qKggBLa4gJfp PRFdnMNplXfTRsAhIqGPlDVMa+NBnjgD3q1hDKmZWVsaG+tBKYlhpR9yAQk7IXHJtv5/m2S8529 QWIBqoyBbiw== X-Google-Smtp-Source: AGHT+IEZEQST18hSDEs9VdJT5pI7Rj9LvHne7IRGt9VFqU0+6AdUDCmPRkVWUYq7ucbBJPFv4W+PzzAHAnV4 X-Received: from ywbbg10.prod.google.com ([2002:a05:690c:30a:b0:726:20d5:53]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:690c:a7d2:b0:71b:fa04:d16e with SMTP id 00721157ae682-763fa716424mr164008727b3.16.1759172932666; Mon, 29 Sep 2025 12:08:52 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:56 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-7-irogers@google.com> Subject: [PATCH v6 06/15] perf capstone: Support for dlopen-ing libcapstone.so From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If perf wasn't built against libcapstone, no HAVE_LIBCAPSTONE_SUPPORT, support dlopen-ing libcapstone.so and then calling the necessary functions by looking them up using dlsym. Reverse engineer the types in the API using pahole, adding only what's used in the perf code or necessary for the sake of struct size and alignment. Signed-off-by: Ian Rogers --- tools/perf/util/capstone.c | 287 ++++++++++++++++++++++++++++++++----- 1 file changed, 248 insertions(+), 39 deletions(-) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index 01e47d5c8e3e..fa9aa9cde68d 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -11,19 +11,249 @@ #include "print_insn.h" #include "symbol.h" #include "thread.h" +#include #include +#include #include =20 #ifdef HAVE_LIBCAPSTONE_SUPPORT #include +#else +typedef size_t csh; +enum cs_arch { + CS_ARCH_ARM =3D 0, + CS_ARCH_ARM64 =3D 1, + CS_ARCH_X86 =3D 3, + CS_ARCH_SYSZ =3D 6, +}; +enum cs_mode { + CS_MODE_ARM =3D 0, + CS_MODE_32 =3D 1 << 2, + CS_MODE_64 =3D 1 << 3, + CS_MODE_V8 =3D 1 << 6, + CS_MODE_BIG_ENDIAN =3D 1 << 31, +}; +enum cs_opt_type { + CS_OPT_SYNTAX =3D 1, + CS_OPT_DETAIL =3D 2, +}; +enum cs_opt_value { + CS_OPT_SYNTAX_ATT =3D 2, + CS_OPT_ON =3D 3, +}; +enum cs_err { + CS_ERR_OK =3D 0, + CS_ERR_HANDLE =3D 3, +}; +enum x86_op_type { + X86_OP_IMM =3D 2, + X86_OP_MEM =3D 3, +}; +enum x86_reg { + X86_REG_RIP =3D 41, +}; +typedef int32_t x86_avx_bcast; +struct x86_op_mem { + enum x86_reg segment; + enum x86_reg base; + enum x86_reg index; + int scale; + int64_t disp; +}; + +struct cs_x86_op { + enum x86_op_type type; + union { + enum x86_reg reg; + int64_t imm; + struct x86_op_mem mem; + }; + uint8_t size; + uint8_t access; + x86_avx_bcast avx_bcast; + bool avx_zero_opmask; +}; +struct cs_x86_encoding { + uint8_t modrm_offset; + uint8_t disp_offset; + uint8_t disp_size; + uint8_t imm_offset; + uint8_t imm_size; +}; +typedef int32_t x86_xop_cc; +typedef int32_t x86_sse_cc; +typedef int32_t x86_avx_cc; +typedef int32_t x86_avx_rm; +struct cs_x86 { + uint8_t prefix[4]; + uint8_t opcode[4]; + uint8_t rex; + uint8_t addr_size; + uint8_t modrm; + uint8_t sib; + int64_t disp; + enum x86_reg sib_index; + int8_t sib_scale; + enum x86_reg sib_base; + x86_xop_cc xop_cc; + x86_sse_cc sse_cc; + x86_avx_cc avx_cc; + bool avx_sae; + x86_avx_rm avx_rm; + union { + uint64_t eflags; + uint64_t fpu_flags; + }; + uint8_t op_count; + struct cs_x86_op operands[8]; + struct cs_x86_encoding encoding; +}; +struct cs_detail { + uint16_t regs_read[12]; + uint8_t regs_read_count; + uint16_t regs_write[20]; + uint8_t regs_write_count; + uint8_t groups[8]; + uint8_t groups_count; + + union { + struct cs_x86 x86; + }; +}; +struct cs_insn { + unsigned int id; + uint64_t address; + uint16_t size; + uint8_t bytes[16]; + char mnemonic[32]; + char op_str[160]; + struct cs_detail *detail; +}; +#endif + +#ifndef HAVE_LIBCAPSTONE_SUPPORT +static void *perf_cs_dll_handle(void) +{ + static bool dll_handle_init; + static void *dll_handle; + + if (!dll_handle_init) { + dll_handle_init =3D true; + dll_handle =3D dlopen("libcapstone.so", RTLD_LAZY); + if (!dll_handle) + pr_debug("dlopen failed for libcapstone.so\n"); + } + return dll_handle; +} +#endif + +static enum cs_err perf_cs_open(enum cs_arch arch, enum cs_mode mode, csh = *handle) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + return cs_open(arch, mode, handle); +#else + static bool fn_init; + static enum cs_err (*fn)(enum cs_arch arch, enum cs_mode mode, csh *handl= e); + + if (!fn_init) { + fn =3D dlsym(perf_cs_dll_handle(), "cs_open"); + if (!fn) + pr_debug("dlsym failed for cs_open\n"); + fn_init =3D true; + } + if (!fn) + return CS_ERR_HANDLE; + return fn(arch, mode, handle); +#endif +} + +static enum cs_err perf_cs_option(csh handle, enum cs_opt_type type, size_= t value) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + return cs_option(handle, type, value); +#else + static bool fn_init; + static enum cs_err (*fn)(csh handle, enum cs_opt_type type, size_t value); + + if (!fn_init) { + fn =3D dlsym(perf_cs_dll_handle(), "cs_option"); + if (!fn) + pr_debug("dlsym failed for cs_option\n"); + fn_init =3D true; + } + if (!fn) + return CS_ERR_HANDLE; + return fn(handle, type, value); +#endif +} + +static size_t perf_cs_disasm(csh handle, const uint8_t *code, size_t code_= size, + uint64_t address, size_t count, struct cs_insn **insn) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + return cs_disasm(handle, code, code_size, address, count, insn); +#else + static bool fn_init; + static enum cs_err (*fn)(csh handle, const uint8_t *code, size_t code_siz= e, + uint64_t address, size_t count, struct cs_insn **insn); + + if (!fn_init) { + fn =3D dlsym(perf_cs_dll_handle(), "cs_disasm"); + if (!fn) + pr_debug("dlsym failed for cs_disasm\n"); + fn_init =3D true; + } + if (!fn) + return CS_ERR_HANDLE; + return fn(handle, code, code_size, address, count, insn); #endif +} =20 +static void perf_cs_free(struct cs_insn *insn, size_t count) +{ #ifdef HAVE_LIBCAPSTONE_SUPPORT + cs_free(insn, count); +#else + static bool fn_init; + static void (*fn)(struct cs_insn *insn, size_t count); + + if (!fn_init) { + fn =3D dlsym(perf_cs_dll_handle(), "cs_free"); + if (!fn) + pr_debug("dlsym failed for cs_free\n"); + fn_init =3D true; + } + if (!fn) + return; + fn(insn, count); +#endif +} + +static enum cs_err perf_cs_close(csh *handle) +{ +#ifdef HAVE_LIBCAPSTONE_SUPPORT + return cs_close(handle); +#else + static bool fn_init; + static enum cs_err (*fn)(csh *handle); + + if (!fn_init) { + fn =3D dlsym(perf_cs_dll_handle(), "cs_close"); + if (!fn) + pr_debug("dlsym failed for cs_close\n"); + fn_init =3D true; + } + if (!fn) + return CS_ERR_HANDLE; + return fn(handle); +#endif +} + static int capstone_init(struct machine *machine, csh *cs_handle, bool is6= 4, bool disassembler_style) { - cs_arch arch; - cs_mode mode; + enum cs_arch arch; + enum cs_mode mode; =20 if (machine__is(machine, "x86_64") && is64) { arch =3D CS_ARCH_X86; @@ -44,7 +274,7 @@ static int capstone_init(struct machine *machine, csh *c= s_handle, bool is64, return -1; } =20 - if (cs_open(arch, mode, cs_handle) !=3D CS_ERR_OK) { + if (perf_cs_open(arch, mode, cs_handle) !=3D CS_ERR_OK) { pr_warning_once("cs_open failed\n"); return -1; } @@ -56,27 +286,25 @@ static int capstone_init(struct machine *machine, csh = *cs_handle, bool is64, * is set via annotation args */ if (disassembler_style) - cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); + perf_cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); /* * Resolving address operands to symbols is implemented * on x86 by investigating instruction details. */ - cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); + perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); } =20 return 0; } -#endif =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT -static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *i= nsn, +static size_t print_insn_x86(struct thread *thread, u8 cpumode, struct cs_= insn *insn, int print_opts, FILE *fp) { struct addr_location al; size_t printed =3D 0; =20 if (insn->detail && insn->detail->x86.op_count =3D=3D 1) { - cs_x86_op *op =3D &insn->detail->x86.operands[0]; + struct cs_x86_op *op =3D &insn->detail->x86.operands[0]; =20 addr_location__init(&al); if (op->type =3D=3D X86_OP_IMM && @@ -94,7 +322,6 @@ static size_t print_insn_x86(struct thread *thread, u8 c= pumode, cs_insn *insn, printed +=3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); return printed; } -#endif =20 =20 ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused, @@ -105,9 +332,8 @@ ssize_t capstone__fprintf_insn_asm(struct machine *mach= ine __maybe_unused, uint64_t ip __maybe_unused, int *lenp __maybe_unused, int print_opts __maybe_unused, FILE *fp __maybe_unused) { -#ifdef HAVE_LIBCAPSTONE_SUPPORT size_t printed; - cs_insn *insn; + struct cs_insn *insn; csh cs_handle; size_t count; int ret; @@ -117,7 +343,7 @@ ssize_t capstone__fprintf_insn_asm(struct machine *mach= ine __maybe_unused, if (ret < 0) return ret; =20 - count =3D cs_disasm(cs_handle, code, code_size, ip, 1, &insn); + count =3D perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn); if (count > 0) { if (machine__normalized_is(machine, "x86")) printed =3D print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); @@ -125,20 +351,16 @@ ssize_t capstone__fprintf_insn_asm(struct machine *ma= chine __maybe_unused, printed =3D fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); if (lenp) *lenp =3D insn->size; - cs_free(insn, count); + perf_cs_free(insn, count); } else { printed =3D -1; } =20 - cs_close(&cs_handle); + perf_cs_close(&cs_handle); return printed; -#else - return -1; -#endif } =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT -static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, +static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t = len, struct annotate_args *args, u64 addr) { int i; @@ -153,7 +375,7 @@ static void print_capstone_detail(cs_insn *insn, char *= buf, size_t len, return; =20 for (i =3D 0; i < insn->detail->x86.op_count; i++) { - cs_x86_op *op =3D &insn->detail->x86.operands[i]; + struct cs_x86_op *op =3D &insn->detail->x86.operands[i]; u64 orig_addr; =20 if (op->type !=3D X86_OP_MEM) @@ -194,9 +416,7 @@ static void print_capstone_detail(cs_insn *insn, char *= buf, size_t len, break; } } -#endif =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT struct find_file_offset_data { u64 ip; u64 offset; @@ -213,9 +433,7 @@ static int find_file_offset(u64 start, u64 len, u64 pgo= ff, void *arg) } return 0; } -#endif =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT static u8 * read_symbol(const char *filename, struct map *map, struct symbol *sym, u64 *len, bool *is_64bit) @@ -262,13 +480,11 @@ read_symbol(const char *filename, struct map *map, st= ruct symbol *sym, free(buf); return NULL; } -#endif =20 int symbol__disassemble_capstone(const char *filename __maybe_unused, struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused) { -#ifdef HAVE_LIBCAPSTONE_SUPPORT struct annotation *notes =3D symbol__annotation(sym); struct map *map =3D args->ms.map; u64 start =3D map__rip_2objdump(map, sym->start); @@ -279,7 +495,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, bool needs_cs_close =3D false; u8 *buf =3D NULL; csh handle; - cs_insn *insn =3D NULL; + struct cs_insn *insn =3D NULL; char disasm_buf[512]; struct disasm_line *dl; bool disassembler_style =3D false; @@ -316,7 +532,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, =20 needs_cs_close =3D true; =20 - free_count =3D count =3D cs_disasm(handle, buf, len, start, len, &insn); + free_count =3D count =3D perf_cs_disasm(handle, buf, len, start, len, &in= sn); for (i =3D 0, offset =3D 0; i < count; i++) { int printed; =20 @@ -355,9 +571,9 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, =20 out: if (needs_cs_close) { - cs_close(&handle); + perf_cs_close(&handle); if (free_count > 0) - cs_free(insn, free_count); + perf_cs_free(insn, free_count); } free(buf); return count < 0 ? count : 0; @@ -377,16 +593,12 @@ int symbol__disassemble_capstone(const char *filename= __maybe_unused, } count =3D -1; goto out; -#else - return -1; -#endif } =20 int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unus= ed, struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused) { -#ifdef HAVE_LIBCAPSTONE_SUPPORT struct annotation *notes =3D symbol__annotation(sym); struct map *map =3D args->ms.map; struct dso *dso =3D map__dso(map); @@ -499,7 +711,7 @@ int symbol__disassemble_capstone_powerpc(const char *fi= lename __maybe_unused, =20 out: if (needs_cs_close) - cs_close(&handle); + perf_cs_close(&handle); free(buf); return count < 0 ? count : 0; =20 @@ -508,7 +720,4 @@ int symbol__disassemble_capstone_powerpc(const char *fi= lename __maybe_unused, close(fd); count =3D -1; goto out; -#else - return -1; -#endif } --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E0188263C69 for ; Mon, 29 Sep 2025 19:08:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172941; cv=none; b=CSQ+Ec8Zi2zFdnC1MSlD8nb7kN7RTKkxM0KXdcXaaruwV0p46PmiOVWYTAYmcE9qNnMPmNqY5VmqasLMVoyTfM/EGFBmMtaIlQhFNGKhy21iovnMML6nTkSkmCR8W6U9JJZ6LYMHnVYCeIB06omTV0eAl1S6WcwjK/2EjuL99Qc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172941; c=relaxed/simple; bh=yTH20s8951joK535fHaC9v5lBDumKagO6fIaIaUfYoo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=TZuy/aGCZpqSDDAH8XeYFku9dimTDkKCrUsnCFlfdRzU4yV6qvw22XTliP3mPG1soEKl4EEdWOObBzyJbpyn3K5plJWAIzs8xuGfJtf6YBkxIxLjzq7Lu0BMzCA9OqxvNfZRundTXX0rsd0hDb5IjfJWZkvcfZGurmALFmLgSOI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qAk1fQKm; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qAk1fQKm" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-32df881dce2so5244709a91.2 for ; Mon, 29 Sep 2025 12:08:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172938; x=1759777738; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=JwSHsxQoyjJ+Jio9kzarHPG8pCq3muSNxEdDXDWx/xE=; b=qAk1fQKmAh7jniUcbrjxwbe5MQh8Vw3ND/bEOAcVYK4LJtL925wbtxcfGTBRNzPuYM mY7AkDnZH4+22IeJJt3/m9m8f3ZzEv2nTbBZXQofhMHd8Kx3nbPi2gxGVt0C63qukc/t D4QWIb3PdS4uHLFCXdSgTBU9O0EgfaNqmZYI+EBtmR6jCY5fjpb3AaRMo5i6zH215JUE 1DGqBxsNEpzUO5T/0MvhShs7HjjUOsG6vKtGeEzId5lBPfhcVKoscnYWHBda4HW4rty6 EoRUAXEFQWnuuc0TkXCTOfHrBbls8UX7JZFz7wzKkSX0wexEwwvA29TjxgtvpZRmxikf Hs9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172938; x=1759777738; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=JwSHsxQoyjJ+Jio9kzarHPG8pCq3muSNxEdDXDWx/xE=; b=t4sZRprGH3G6QeavPYo0qsGS4i49CkfPVb/k7c1G3SxqVzaf3M2hy45m+35PU2gieZ 9R+i5GM3QmjxIUNsgAPpX+8nI9AX3PWWLaFY8FEBhwUHl89c4YsCox27ju4A1PMkLf19 ZPmALvyDm32sbXQcaGAIoH+USiTDsH0YbzOx9RZYvJ1wHL95yL0aRAgTWLBFP6pf9dil 4mqO7ldkkP+NkswJtods5ux7q77gqhXpJlHhdwFh2TBIZqclGt8pBxQ2Os1X6v8znnWe m3F+Knscy5pEFil696vR7YOi2mrxVuXw4O4J/UAY6NlsymkpKCbAZOFndCU4miUlnoTv ZWKA== X-Forwarded-Encrypted: i=1; AJvYcCUlb5lvsdboLos/+cdgDxEjACtt8gt+bIUZSd9fG1Pdu7VwTqUwQosf0IkSdCSo5/DcAL10syB5eN/S+rs=@vger.kernel.org X-Gm-Message-State: AOJu0Yxvs5vWArdnsUHhWKtQYo3DTZkTmCtPPkOtgRVw12u5tFYGwmD5 Tf82BoiHcDXe7PNXx972mReFxKgu/5CAUD8HqRqmmeJl8Sce2xSBl4FggE8yoUCAygn/QFaMy0S L9qfcFFicPw== X-Google-Smtp-Source: AGHT+IEmEqexTWK/0EWAhQwHCmFiLfkzudXJz/ez7WQ8Pg7t1Jo7Z+TtkMFjLye0pIwkV3QWI2BtoqGQhhcF X-Received: from pjtx10.prod.google.com ([2002:a17:90a:ca0a:b0:330:b9e9:7acc]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:e7c1:b0:32e:7340:a7f7 with SMTP id 98e67ed59e1d1-3342a272c3cmr16774914a91.2.1759172937990; Mon, 29 Sep 2025 12:08:57 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:57 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-8-irogers@google.com> Subject: [PATCH v6 07/15] perf llvm: Support for dlopen-ing libLLVM.so From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If perf wasn't built against libLLVM, no HAVE_LIBLLVM_SUPPORT, support dlopen-ing libLLVM.so and then calling the necessary functions by looking them up using dlsym. As the C++ code in llvm-c-helpers used for addr2line is problematic to call using dlsym, build that C++ code against libLLVM.so as a separate shared object, and support dynamic loading of it. This build option is enabled with LIBLLVM_DYNAMIC=3D1 Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 13 ++ tools/perf/Makefile.perf | 23 ++- tools/perf/tests/make | 2 + tools/perf/util/Build | 2 +- tools/perf/util/llvm-c-helpers.cpp | 113 +++++++++++- tools/perf/util/llvm.c | 271 +++++++++++++++++++++++++---- 6 files changed, 386 insertions(+), 38 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 1907d1c70b68..57d7e5b29198 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -974,6 +974,19 @@ ifndef NO_LIBLLVM NO_LIBLLVM :=3D 1 endif endif +ifdef LIBLLVM_DYNAMIC + ifndef NO_LIBLLVM + $(error LIBLLVM_DYNAMIC should be used with NO_LIBLLVM) + endif + $(call feature_check,llvm-perf) + ifneq ($(feature-llvm-perf), 1) + $(warning LIBLLVM_DYNAMIC requires libLLVM.so which wasn't feature det= ected) + endif + CFLAGS +=3D -DHAVE_LIBLLVM_DYNAMIC + CFLAGS +=3D $(shell $(LLVM_CONFIG) --cflags) + CXXFLAGS +=3D -DHAVE_LIBLLVM_DYNAMIC + CXXFLAGS +=3D $(shell $(LLVM_CONFIG) --cxxflags) +endif =20 ifndef NO_DEMANGLE $(call feature_check,cxa-demangle) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index e2150acc2c13..bfa4ad7ea89d 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -423,6 +423,12 @@ ifndef NO_JVMTI PROGRAMS +=3D $(OUTPUT)$(LIBJVMTI) endif =20 +LIBPERF_LLVM =3D libperf-llvm.so + +ifdef LIBLLVM_DYNAMIC +PROGRAMS +=3D $(OUTPUT)$(LIBPERF_LLVM) +endif + DLFILTERS :=3D dlfilter-test-api-v0.so dlfilter-test-api-v2.so dlfilter-sh= ow-cycles.so DLFILTERS :=3D $(patsubst %,$(OUTPUT)dlfilters/%,$(DLFILTERS)) =20 @@ -995,6 +1001,16 @@ $(LIBSYMBOL)-clean: $(call QUIET_CLEAN, libsymbol) $(Q)$(RM) -r -- $(LIBSYMBOL_OUTPUT) =20 +ifdef LIBLLVM_DYNAMIC +LIBPERF_LLVM_CXXFLAGS :=3D $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXF= LAGS)) -DHAVE_LIBLLVM_SUPPORT +LIBPERF_LLVM_LIBS =3D -L$(shell $(LLVM_CONFIG) --libdir) $(LIBLLVM) -lstdc= ++ + +$(OUTPUT)$(LIBPERF_LLVM): util/llvm-c-helpers.cpp + $(QUIET_LINK)$(CXX) $(LIBPERF_LLVM_CXXFLAGS) $(LIBPERF_LLVM_LIBS) -shared= -o $@ $< + +$(OUTPUT)perf: $(OUTPUT)$(LIBPERF_LLVM) +endif + help: @echo 'Perf make targets:' @echo ' doc - make *all* documentation (see below)' @@ -1096,6 +1112,11 @@ ifndef NO_JVMTI $(call QUIET_INSTALL, $(LIBJVMTI)) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \ $(INSTALL) $(OUTPUT)$(LIBJVMTI) '$(DESTDIR_SQ)$(libdir_SQ)'; +endif +ifdef LIBLLVM_DYNAMIC + $(call QUIET_INSTALL, $(LIBPERF_LLVM)) \ + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(libdir_SQ)'; \ + $(INSTALL) $(OUTPUT)$(LIBPERF_LLVM) '$(DESTDIR_SQ)$(libdir_SQ)'; endif $(call QUIET_INSTALL, libexec) \ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' @@ -1281,7 +1302,7 @@ clean:: $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-= clean $(LIBSYMBOL)-clean $( -name '\.*.cmd' -delete -o -name '\.*.d' -delete -o -name '*.shellcheck_= log' -delete $(Q)$(RM) $(OUTPUT).config-detected $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso= 32 \ - perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI).so + perf-read-vdsox32 $(OUTPUT)$(LIBJVMTI) $(OUTPUT)$(LIBPERF_LLVM) $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo= \ $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE \ $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \ diff --git a/tools/perf/tests/make b/tools/perf/tests/make index c574a678c28a..301cda63a27f 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -93,6 +93,7 @@ make_no_libbpf :=3D NO_LIBBPF=3D1 make_libbpf_dynamic :=3D LIBBPF_DYNAMIC=3D1 make_no_libbpf_DEBUG :=3D NO_LIBBPF=3D1 DEBUG=3D1 make_no_libllvm :=3D NO_LIBLLVM=3D1 +make_libllvm_dynamic :=3D NO_LIBLLVM=3D1 LIBLLVM_DYNAMIC=3D1 make_with_babeltrace:=3D LIBBABELTRACE=3D1 make_with_coresight :=3D CORESIGHT=3D1 make_no_sdt :=3D NO_SDT=3D1 @@ -162,6 +163,7 @@ run +=3D make_no_auxtrace run +=3D make_no_libbpf run +=3D make_no_libbpf_DEBUG run +=3D make_no_libllvm +run +=3D make_libllvm_dynamic run +=3D make_no_sdt run +=3D make_no_syscall_tbl run +=3D make_with_babeltrace diff --git a/tools/perf/util/Build b/tools/perf/util/Build index bb2023a3d0c9..98d0a673fb53 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -27,6 +27,7 @@ perf-util-y +=3D get_current_dir_name.o perf-util-y +=3D levenshtein.o perf-util-$(CONFIG_LIBBFD) +=3D libbfd.o perf-util-y +=3D llvm.o +perf-util-y +=3D llvm-c-helpers.o perf-util-y +=3D mmap.o perf-util-y +=3D memswap.o perf-util-y +=3D parse-events.o @@ -248,7 +249,6 @@ perf-util-$(CONFIG_CXX_DEMANGLE) +=3D demangle-cxx.o perf-util-y +=3D demangle-ocaml.o perf-util-y +=3D demangle-java.o perf-util-y +=3D demangle-rust-v0.o -perf-util-$(CONFIG_LIBLLVM) +=3D llvm-c-helpers.o =20 CFLAGS_demangle-rust-v0.o +=3D -Wno-shadow -Wno-declaration-after-statemen= t \ -Wno-switch-default -Wno-switch-enum -Wno-missing-field-initializers diff --git a/tools/perf/util/llvm-c-helpers.cpp b/tools/perf/util/llvm-c-he= lpers.cpp index 004081bd12c9..5a6f76e6b705 100644 --- a/tools/perf/util/llvm-c-helpers.cpp +++ b/tools/perf/util/llvm-c-helpers.cpp @@ -5,17 +5,23 @@ * macros (e.g. noinline) that conflict with compiler builtins used * by LLVM. */ +#ifdef HAVE_LIBLLVM_SUPPORT #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" /* Needed for LLVM <= =3D 15 */ #include #include #pragma GCC diagnostic pop +#endif =20 +#if !defined(HAVE_LIBLLVM_SUPPORT) || defined(HAVE_LIBLLVM_DYNAMIC) +#include +#endif #include #include #include #include extern "C" { +#include "debug.h" #include } #include "llvm-c-helpers.h" @@ -23,14 +29,33 @@ extern "C" { extern "C" char *dso__demangle_sym(struct dso *dso, int kmodule, const char *elf_name= ); =20 +#ifdef HAVE_LIBLLVM_SUPPORT using namespace llvm; using llvm::symbolize::LLVMSymbolizer; +#endif + +#if !defined(HAVE_LIBLLVM_SUPPORT) && defined(HAVE_LIBLLVM_DYNAMIC) +static void *perf_llvm_c_helpers_dll_handle(void) +{ + static bool dll_handle_init; + static void *dll_handle; + + if (!dll_handle_init) { + dll_handle_init =3D true; + dll_handle =3D dlopen("libperf-llvm.so", RTLD_LAZY); + if (!dll_handle) + pr_debug("dlopen failed for libperf-llvm.so\n"); + } + return dll_handle; +} +#endif =20 /* * Allocate a static LLVMSymbolizer, which will live to the end of the pro= gram. * Unlike the bfd paths, LLVMSymbolizer has its own cache, so we do not ne= ed * to store anything in the dso struct. */ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) static LLVMSymbolizer *get_symbolizer() { static LLVMSymbolizer *instance =3D nullptr; @@ -49,8 +74,10 @@ static LLVMSymbolizer *get_symbolizer() } return instance; } +#endif =20 /* Returns 0 on error, 1 on success. */ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) static int extract_file_and_line(const DILineInfo &line_info, char **file, unsigned int *line) { @@ -69,13 +96,15 @@ static int extract_file_and_line(const DILineInfo &line= _info, char **file, *line =3D line_info.Line; return 1; } +#endif =20 extern "C" -int llvm_addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line, - bool unwind_inlines, - llvm_a2l_frame **inline_frames) +int llvm_addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_u= nused, + char **file __maybe_unused, unsigned int *line __maybe_unused, + bool unwind_inlines __maybe_unused, + llvm_a2l_frame **inline_frames __maybe_unused) { +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); object::SectionedAddress sectioned_addr =3D { addr, @@ -135,8 +164,33 @@ int llvm_addr2line(const char *dso_name, u64 addr, return 0; return extract_file_and_line(*res_or_err, file, line); } +#elif defined(HAVE_LIBLLVM_DYNAMIC) + static bool fn_init; + static int (*fn)(const char *dso_name, u64 addr, + char **file, unsigned int *line, + bool unwind_inlines, + llvm_a2l_frame **inline_frames); + + if (!fn_init) { + void * handle =3D perf_llvm_c_helpers_dll_handle(); + + if (!handle) + return 0; + + fn =3D reinterpret_cast(dlsym(handle, "llvm_addr2line")); + if (!fn) + pr_debug("dlsym failed for llvm_addr2line\n"); + fn_init =3D true; + } + if (!fn) + return 0; + return fn(dso_name, addr, file, line, unwind_inlines, inline_frames); +#else + return 0; +#endif } =20 +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) static char * make_symbol_relative_string(struct dso *dso, const char *sym_name, u64 addr, u64 base_addr) @@ -158,10 +212,13 @@ make_symbol_relative_string(struct dso *dso, const ch= ar *sym_name, return strdup(sym_name); } } +#endif =20 extern "C" -char *llvm_name_for_code(struct dso *dso, const char *dso_name, u64 addr) +char *llvm_name_for_code(struct dso *dso __maybe_unused, const char *dso_n= ame __maybe_unused, + u64 addr __maybe_unused) { +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); object::SectionedAddress sectioned_addr =3D { addr, @@ -175,11 +232,34 @@ char *llvm_name_for_code(struct dso *dso, const char = *dso_name, u64 addr) return make_symbol_relative_string( dso, res_or_err->FunctionName.c_str(), addr, res_or_err->StartAddress ? *res_or_err->StartAddress : 0); +#elif defined(HAVE_LIBLLVM_DYNAMIC) + static bool fn_init; + static char *(*fn)(struct dso *dso, const char *dso_name, u64 addr); + + if (!fn_init) { + void * handle =3D perf_llvm_c_helpers_dll_handle(); + + if (!handle) + return NULL; + + fn =3D reinterpret_cast(dlsym(handle, "llvm_name_for_code"= )); + if (!fn) + pr_debug("dlsym failed for llvm_name_for_code\n"); + fn_init =3D true; + } + if (!fn) + return NULL; + return fn(dso, dso_name, addr); +#else + return 0; +#endif } =20 extern "C" -char *llvm_name_for_data(struct dso *dso, const char *dso_name, u64 addr) +char *llvm_name_for_data(struct dso *dso __maybe_unused, const char *dso_n= ame __maybe_unused, + u64 addr __maybe_unused) { +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); object::SectionedAddress sectioned_addr =3D { addr, @@ -193,4 +273,25 @@ char *llvm_name_for_data(struct dso *dso, const char *= dso_name, u64 addr) return make_symbol_relative_string( dso, res_or_err->Name.c_str(), addr, res_or_err->Start); +#elif defined(HAVE_LIBLLVM_DYNAMIC) + static bool fn_init; + static char *(*fn)(struct dso *dso, const char *dso_name, u64 addr); + + if (!fn_init) { + void * handle =3D perf_llvm_c_helpers_dll_handle(); + + if (!handle) + return NULL; + + fn =3D reinterpret_cast(dlsym(handle, "llvm_name_for_data"= )); + if (!fn) + pr_debug("dlsym failed for llvm_name_for_data\n"); + fn_init =3D true; + } + if (!fn) + return NULL; + return fn(dso, dso_name, addr); +#else + return 0; +#endif } diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index ddc737194692..f6a8943b7c9d 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "llvm.h" +#include "llvm-c-helpers.h" #include "annotate.h" #include "debug.h" #include "dso.h" @@ -7,17 +8,243 @@ #include "namespaces.h" #include "srcline.h" #include "symbol.h" +#include #include +#include #include #include =20 -#ifdef HAVE_LIBLLVM_SUPPORT -#include "llvm-c-helpers.h" +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) #include #include +#else +typedef void *LLVMDisasmContextRef; +typedef int (*LLVMOpInfoCallback)(void *dis_info, uint64_t pc, uint64_t of= fset, + uint64_t op_size, uint64_t inst_size, + int tag_type, void *tag_buf); +typedef const char *(*LLVMSymbolLookupCallback)(void *dis_info, + uint64_t reference_value, + uint64_t *reference_type, + uint64_t reference_pc, + const char **reference_name); +#define LLVMDisassembler_ReferenceType_InOut_None 0 +#define LLVMDisassembler_ReferenceType_In_Branch 1 +#define LLVMDisassembler_ReferenceType_In_PCrel_Load 2 +#define LLVMDisassembler_Option_PrintImmHex 2 +#define LLVMDisassembler_Option_AsmPrinterVariant 4 +const char *llvm_targets[] =3D { + "AMDGPU", + "ARM", + "AVR", + "BPF", + "Hexagon", + "Lanai", + "LoongArch", + "Mips", + "MSP430", + "NVPTX", + "PowerPC", + "RISCV", + "Sparc", + "SystemZ", + "VE", + "WebAssembly", + "X86", + "XCore", + "M68k", + "Xtensa", +}; +#endif + +#if !defined(HAVE_LIBLLVM_SUPPORT) || defined(HAVE_LIBLLVM_DYNAMIC) +static void *perf_llvm_dll_handle(void) +{ + static bool dll_handle_init; + static void *dll_handle; + + if (!dll_handle_init) { + dll_handle_init =3D true; + dll_handle =3D dlopen("libLLVM.so", RTLD_LAZY); + if (!dll_handle) + pr_debug("dlopen failed for libLLVM.so\n"); + } + return dll_handle; +} +#endif + +#if !defined(HAVE_LIBLLVM_SUPPORT) || defined(HAVE_LIBLLVM_DYNAMIC) +static void *perf_llvm_dll_fun(const char *fmt, const char *target) +{ + char buf[128]; + void *fn; + + snprintf(buf, sizeof(buf), fmt, target); + fn =3D dlsym(perf_llvm_dll_handle(), buf); + if (!fn) + pr_debug("dlsym failed for %s\n", buf); + + return fn; +} +#endif + +static void perf_LLVMInitializeAllTargetInfos(void) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + LLVMInitializeAllTargetInfos(); +#else + /* LLVMInitializeAllTargetInfos is a header file function not available a= s a symbol. */ + static bool done_init; + + if (done_init) + return; + + for (size_t i =3D 0; i < ARRAY_SIZE(llvm_targets); i++) { + void (*fn)(void) =3D perf_llvm_dll_fun("LLVMInitialize%sTargetInfo", + llvm_targets[i]); + + if (!fn) + continue; + fn(); + } + done_init =3D true; +#endif +} + +static void perf_LLVMInitializeAllTargetMCs(void) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + LLVMInitializeAllTargetMCs(); +#else + /* LLVMInitializeAllTargetMCs is a header file function not available as = a symbol. */ + static bool done_init; + + if (done_init) + return; + + for (size_t i =3D 0; i < ARRAY_SIZE(llvm_targets); i++) { + void (*fn)(void) =3D perf_llvm_dll_fun("LLVMInitialize%sTargetMC", + llvm_targets[i]); + + if (!fn) + continue; + fn(); + } + done_init =3D true; +#endif +} + +static void perf_LLVMInitializeAllDisassemblers(void) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + LLVMInitializeAllDisassemblers(); +#else + /* LLVMInitializeAllDisassemblers is a header file function not available= as a symbol. */ + static bool done_init; + + if (done_init) + return; + + for (size_t i =3D 0; i < ARRAY_SIZE(llvm_targets); i++) { + void (*fn)(void) =3D perf_llvm_dll_fun("LLVMInitialize%sDisassembler", + llvm_targets[i]); + + if (!fn) + continue; + fn(); + } + done_init =3D true; +#endif +} + +static LLVMDisasmContextRef perf_LLVMCreateDisasm(const char *triple_name,= void *dis_info, + int tag_type, LLVMOpInfoCallback get_op_info, + LLVMSymbolLookupCallback symbol_lookup) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + return LLVMCreateDisasm(triple_name, dis_info, tag_type, get_op_info, sym= bol_lookup); +#else + static bool fn_init; + static LLVMDisasmContextRef (*fn)(const char *triple_name, void *dis_info, + int tag_type, LLVMOpInfoCallback get_op_info, + LLVMSymbolLookupCallback symbol_lookup); + + if (!fn_init) { + fn =3D dlsym(perf_llvm_dll_handle(), "LLVMCreateDisasm"); + if (!fn) + pr_debug("dlsym failed for LLVMCreateDisasm\n"); + fn_init =3D true; + } + if (!fn) + return NULL; + return fn(triple_name, dis_info, tag_type, get_op_info, symbol_lookup); +#endif +} + +static int perf_LLVMSetDisasmOptions(LLVMDisasmContextRef context, uint64_= t options) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + return LLVMSetDisasmOptions(context, options); +#else + static bool fn_init; + static int (*fn)(LLVMDisasmContextRef context, uint64_t options); + + if (!fn_init) { + fn =3D dlsym(perf_llvm_dll_handle(), "LLVMSetDisasmOptions"); + if (!fn) + pr_debug("dlsym failed for LLVMSetDisasmOptions\n"); + fn_init =3D true; + } + if (!fn) + return 0; + return fn(context, options); +#endif +} + +static size_t perf_LLVMDisasmInstruction(LLVMDisasmContextRef context, uin= t8_t *bytes, + uint64_t bytes_size, uint64_t pc, + char *out_string, size_t out_string_size) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + return LLVMDisasmInstruction(context, bytes, bytes_size, pc, out_string, = out_string_size); +#else + static bool fn_init; + static int (*fn)(LLVMDisasmContextRef context, uint8_t *bytes, + uint64_t bytes_size, uint64_t pc, + char *out_string, size_t out_string_size); + + if (!fn_init) { + fn =3D dlsym(perf_llvm_dll_handle(), "LLVMDisasmInstruction"); + if (!fn) + pr_debug("dlsym failed for LLVMDisasmInstruction\n"); + fn_init =3D true; + } + if (!fn) + return 0; + return fn(context, bytes, bytes_size, pc, out_string, out_string_size); +#endif +} + +static void perf_LLVMDisasmDispose(LLVMDisasmContextRef context) +{ +#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) + LLVMDisasmDispose(context); +#else + static bool fn_init; + static int (*fn)(LLVMDisasmContextRef context); + + if (!fn_init) { + fn =3D dlsym(perf_llvm_dll_handle(), "LLVMDisasmDispose"); + if (!fn) + pr_debug("dlsym failed for LLVMDisasmDispose\n"); + fn_init =3D true; + } + if (!fn) + return; + fn(context); #endif +} + =20 -#ifdef HAVE_LIBLLVM_SUPPORT static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames, int num_frames) { @@ -29,14 +256,12 @@ static void free_llvm_inline_frames(struct llvm_a2l_fr= ame *inline_frames, zfree(&inline_frames); } } -#endif =20 int llvm__addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_= unused, char **file __maybe_unused, unsigned int *line __maybe_unused, struct dso *dso __maybe_unused, bool unwind_inlines __maybe_unused, struct inline_node *node __maybe_unused, struct symbol *sym __maybe= _unused) { -#ifdef HAVE_LIBLLVM_SUPPORT struct llvm_a2l_frame *inline_frames =3D NULL; int num_frames =3D llvm_addr2line(dso_name, addr, file, line, node && unwind_inlines, &inline_frames); @@ -64,9 +289,6 @@ int llvm__addr2line(const char *dso_name __maybe_unused,= u64 addr __maybe_unused free_llvm_inline_frames(inline_frames, num_frames); =20 return num_frames; -#else - return -1; -#endif } =20 void dso__free_a2l_llvm(struct dso *dso __maybe_unused) @@ -75,7 +297,6 @@ void dso__free_a2l_llvm(struct dso *dso __maybe_unused) } =20 =20 -#if defined(HAVE_LIBLLVM_SUPPORT) struct find_file_offset_data { u64 ip; u64 offset; @@ -139,7 +360,6 @@ read_symbol(const char *filename, struct map *map, stru= ct symbol *sym, free(buf); return NULL; } -#endif =20 /* * Whenever LLVM wants to resolve an address into a symbol, it calls this @@ -149,7 +369,6 @@ read_symbol(const char *filename, struct map *map, stru= ct symbol *sym, * should add some textual annotation for after the instruction. The caller * will use this information to add the actual annotation. */ -#ifdef HAVE_LIBLLVM_SUPPORT struct symbol_lookup_storage { u64 branch_addr; u64 pcrel_load_addr; @@ -170,12 +389,10 @@ symbol_lookup_callback(void *disinfo, uint64_t value, *ref_type =3D LLVMDisassembler_ReferenceType_InOut_None; return NULL; } -#endif =20 int symbol__disassemble_llvm(const char *filename, struct symbol *sym, struct annotate_args *args __maybe_unused) { -#ifdef HAVE_LIBLLVM_SUPPORT struct annotation *notes =3D symbol__annotation(sym); struct map *map =3D args->ms.map; struct dso *dso =3D map__dso(map); @@ -197,9 +414,9 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, if (args->options->objdump_path) return -1; =20 - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllDisassemblers(); + perf_LLVMInitializeAllTargetInfos(); + perf_LLVMInitializeAllTargetMCs(); + perf_LLVMInitializeAllDisassemblers(); =20 buf =3D read_symbol(filename, map, sym, &len, &is_64bit); if (buf =3D=3D NULL) @@ -215,15 +432,14 @@ int symbol__disassemble_llvm(const char *filename, st= ruct symbol *sym, args->arch->name); } =20 - disasm =3D LLVMCreateDisasm(triplet, &storage, 0, NULL, - symbol_lookup_callback); + disasm =3D perf_LLVMCreateDisasm(triplet, &storage, 0, NULL, + symbol_lookup_callback); if (disasm =3D=3D NULL) goto err; =20 if (args->options->disassembler_style && !strcmp(args->options->disassembler_style, "intel")) - LLVMSetDisasmOptions(disasm, - LLVMDisassembler_Option_AsmPrinterVariant); + perf_LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_AsmPrinterVari= ant); =20 /* * This needs to be set after AsmPrinterVariant, due to a bug in LLVM; @@ -231,7 +447,7 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, * forget about the PrintImmHex flag (which is applied before if both * are given to the same call). */ - LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_PrintImmHex); + perf_LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_PrintImmHex); =20 /* add the function address and name */ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", @@ -256,9 +472,9 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, storage.branch_addr =3D 0; storage.pcrel_load_addr =3D 0; =20 - ins_len =3D LLVMDisasmInstruction(disasm, buf + offset, - len - offset, pc, - disasm_buf, sizeof(disasm_buf)); + ins_len =3D perf_LLVMDisasmInstruction(disasm, buf + offset, + len - offset, pc, + disasm_buf, sizeof(disasm_buf)); if (ins_len =3D=3D 0) goto err; disasm_len =3D strlen(disasm_buf); @@ -314,13 +530,8 @@ int symbol__disassemble_llvm(const char *filename, str= uct symbol *sym, ret =3D 0; =20 err: - LLVMDisasmDispose(disasm); + perf_LLVMDisasmDispose(disasm); free(buf); free(line_storage); return ret; -#else // HAVE_LIBLLVM_SUPPORT - pr_debug("The LLVM disassembler isn't linked in for %s in %s\n", - sym->name, filename); - return -1; -#endif } --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 075B825FA0F for ; Mon, 29 Sep 2025 19:09:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172946; cv=none; b=UcOZFuBZjzGVGHHA/YsSZhnk8a/R5s9+fYX3NtWeyor2ddrn2C1zhBZ6MUWuA4WBO+jq+U7d1uZhuC9/B+PAJbtFqJ+K8SMZSosydJw8nML0Cr+1Mj3fwCH0HIl76vJqKdAfpf4KIkxaNchIH44kJEkpa5PDzlFLFhUmttlnq2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172946; c=relaxed/simple; bh=hJbJqmcYDzzeEA5UaB+mfOUCf7O3rGSrP2WQctdACw8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=MW4d3tF6hecQIMztK+F7h+mqJZsMqa8tPYGtPPP863OGWBqyH7Lwclzibt5d04lgujeGmGw+kWnQm2R4lbQ3jD5QzRNaopEUzJA06F6BAVfU/J2tXnT89WU9byucGGuvdHJZhf/ZQ813OzIE9Ljqxh/dpLi3cH1lgohT/4H3MN0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fi9Lb9Gf; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fi9Lb9Gf" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-33428befc5bso4858618a91.0 for ; Mon, 29 Sep 2025 12:09:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172943; x=1759777743; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=Nw0N4/Uod+NlE7NHfTmmC6QBsSLW7zYvlfoB2ZS28CE=; b=fi9Lb9GfwZk65c74Zc4FIajpNIQPbjuNm1jdQzChBhzX740BJhSTERd4e3OzeKnoRN mix4UNMf1mnZgSHhW5qHpuQ5Lg9Hjd2MYSeATIWVSUkp/XUfUGqDFz1dX24xBekQJLpX TiSuppb8JB4rnQLpHk5TpybFkP5/0P2YAHY6kBwNydUNm79/uWANehRyajJqo9i/g4Ao 8TLegIV3U2BhqIADcpQbbrTdwc4tJYVoc7upzZuMWstEFUfUNCFy3e3+QS222ySHQ+tR GFTbhdqmeUalb8jYZ2W41xJjysDl2+KwV1t4io2EDwNSZy3JDxCmaAh/RA5RN16V6gMV Ftnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172943; x=1759777743; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Nw0N4/Uod+NlE7NHfTmmC6QBsSLW7zYvlfoB2ZS28CE=; b=IZSpmFQ+3Iod90cRFFMBs4XV3GKiL9yzB0B+QohKpJaYFmsSqQkRbujAQ6w11PyOGd C/nSBTaBB0zrNvMk5jLG1ViUK6dVD8rEF0qGWDUc89mlxZELZht9899j6EPoymZrNSg2 j/xv2m453eYt8d5Ew+wiKytI3pdzdgpJ3vD72y8STcgWD41TTWv9z0x/Yw548hI1yCWE JKoMgDjmt3YzE/UMtVHAsCSrPRGROkNU65yYmLZFHd9zD/oeF5T+4hdCQn3V4aTEqNR2 E376Ob0UijwseTxW3YdmK00ERf/97M6RxBqAHoit2kyLm0jXJxgPiVZOzIi10j9ZLXcp eOAw== X-Forwarded-Encrypted: i=1; AJvYcCWCvcVBLDz7gXW4jatAtaIbNPavAqv6Ty+txLZ1UqjB5bG0Zrdj6XLygzdDFA3ORMSp4u2/8A1yaU9NTi4=@vger.kernel.org X-Gm-Message-State: AOJu0YyZA/YZtKCAWJyAYHrJQM3QETXsYr0K5A9LRTgRt3x5kzlJlaIC iOvNWFA7c4kfHlN722daghWn2FMfJSe/Ym7eVlvmu/DiSgeEM9WXo+DkZPM68qPO5moq9YiC0nu uuPPugtv8UA== X-Google-Smtp-Source: AGHT+IGZO8H4JLpFgt1/0MVyoB9Uqa4UugryjMaoOCLJw8jlXl8/35ep01Y5UvG/XDtrEKHxSP6ttmMCTZDF X-Received: from pjbbx13.prod.google.com ([2002:a17:90a:f48d:b0:332:7fae:e138]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4d82:b0:332:afb1:d050 with SMTP id 98e67ed59e1d1-3342a28c02amr19221287a91.14.1759172943374; Mon, 29 Sep 2025 12:09:03 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:58 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-9-irogers@google.com> Subject: [PATCH v6 08/15] perf llvm: Mangle libperf-llvm.so function names From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For a function like llvm_addr2line having the libperf-llvm.so exported symbol named llvm_addr2line meant that the perf llvm_addr2line could sometimes erroneously be returned. This led to infinite recursion and eventual stack overflow. To avoid this conflict add a new BUILDING_PERF_LLVMSO when libperf-llvm.so is being built and use it to alter the behavior of MANGLE_PERF_LLVM_API, a macro that prefixes the name when libperf-llvm.so is being built. The prefixed named avoids the name collision. Signed-off-by: Ian Rogers --- tools/perf/Makefile.perf | 3 ++- tools/perf/util/llvm-c-helpers.cpp | 29 ++++++++++++++++++----------- tools/perf/util/llvm-c-helpers.h | 24 ++++++++++++++++-------- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index bfa4ad7ea89d..116c935c06f7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -1002,7 +1002,8 @@ $(LIBSYMBOL)-clean: $(Q)$(RM) -r -- $(LIBSYMBOL_OUTPUT) =20 ifdef LIBLLVM_DYNAMIC -LIBPERF_LLVM_CXXFLAGS :=3D $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXF= LAGS)) -DHAVE_LIBLLVM_SUPPORT +LIBPERF_LLVM_CXXFLAGS :=3D $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXF= LAGS)) +LIBPERF_LLVM_CXXFLAGS +=3D -DHAVE_LIBLLVM_SUPPORT -DBUILDING_PERF_LLVMSO LIBPERF_LLVM_LIBS =3D -L$(shell $(LLVM_CONFIG) --libdir) $(LIBLLVM) -lstdc= ++ =20 $(OUTPUT)$(LIBPERF_LLVM): util/llvm-c-helpers.cpp diff --git a/tools/perf/util/llvm-c-helpers.cpp b/tools/perf/util/llvm-c-he= lpers.cpp index 5a6f76e6b705..8cea380be5c2 100644 --- a/tools/perf/util/llvm-c-helpers.cpp +++ b/tools/perf/util/llvm-c-helpers.cpp @@ -99,10 +99,12 @@ static int extract_file_and_line(const DILineInfo &line= _info, char **file, #endif =20 extern "C" -int llvm_addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_u= nused, - char **file __maybe_unused, unsigned int *line __maybe_unused, - bool unwind_inlines __maybe_unused, - llvm_a2l_frame **inline_frames __maybe_unused) +int MANGLE_PERF_LLVM_API(llvm_addr2line)(const char *dso_name __maybe_unus= ed, + u64 addr __maybe_unused, + char **file __maybe_unused, + unsigned int *line __maybe_unused, + bool unwind_inlines __maybe_unuse= d, + llvm_a2l_frame **inline_frames __= maybe_unused) { #if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); @@ -177,7 +179,8 @@ int llvm_addr2line(const char *dso_name __maybe_unused,= u64 addr __maybe_unused, if (!handle) return 0; =20 - fn =3D reinterpret_cast(dlsym(handle, "llvm_addr2line")); + fn =3D reinterpret_cast( + dlsym(handle, MANGLE_PERF_LLVM_API_STR(llvm_addr2line))); if (!fn) pr_debug("dlsym failed for llvm_addr2line\n"); fn_init =3D true; @@ -215,8 +218,9 @@ make_symbol_relative_string(struct dso *dso, const char= *sym_name, #endif =20 extern "C" -char *llvm_name_for_code(struct dso *dso __maybe_unused, const char *dso_n= ame __maybe_unused, - u64 addr __maybe_unused) +char *MANGLE_PERF_LLVM_API(llvm_name_for_code)(struct dso *dso __maybe_unu= sed, + const char *dso_name __maybe_unused, + u64 addr __maybe_unused) { #if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); @@ -242,7 +246,8 @@ char *llvm_name_for_code(struct dso *dso __maybe_unused= , const char *dso_name __ if (!handle) return NULL; =20 - fn =3D reinterpret_cast(dlsym(handle, "llvm_name_for_code"= )); + fn =3D reinterpret_cast( + dlsym(handle, MANGLE_PERF_LLVM_API_STR(llvm_name_for_code))); if (!fn) pr_debug("dlsym failed for llvm_name_for_code\n"); fn_init =3D true; @@ -256,8 +261,9 @@ char *llvm_name_for_code(struct dso *dso __maybe_unused= , const char *dso_name __ } =20 extern "C" -char *llvm_name_for_data(struct dso *dso __maybe_unused, const char *dso_n= ame __maybe_unused, - u64 addr __maybe_unused) +char *MANGLE_PERF_LLVM_API(llvm_name_for_data)(struct dso *dso __maybe_unu= sed, + const char *dso_name __maybe_unused, + u64 addr __maybe_unused) { #if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC) LLVMSymbolizer *symbolizer =3D get_symbolizer(); @@ -283,7 +289,8 @@ char *llvm_name_for_data(struct dso *dso __maybe_unused= , const char *dso_name __ if (!handle) return NULL; =20 - fn =3D reinterpret_cast(dlsym(handle, "llvm_name_for_data"= )); + fn =3D reinterpret_cast( + dlsym(handle, MANGLE_PERF_LLVM_API_STR(llvm_name_for_data))); if (!fn) pr_debug("dlsym failed for llvm_name_for_data\n"); fn_init =3D true; diff --git a/tools/perf/util/llvm-c-helpers.h b/tools/perf/util/llvm-c-help= ers.h index d2b99637a28a..cfcfd540cdae 100644 --- a/tools/perf/util/llvm-c-helpers.h +++ b/tools/perf/util/llvm-c-helpers.h @@ -13,6 +13,14 @@ extern "C" { #endif =20 +/* Support name mangling so that libperf_llvm.so's names don't match those= in perf. */ +#ifdef BUILDING_PERF_LLVMSO +#define MANGLE_PERF_LLVM_API(x) PERF_LLVM_SO_ ## x +#else +#define MANGLE_PERF_LLVM_API(x) x +#endif +#define MANGLE_PERF_LLVM_API_STR(x) "PERF_LLVM_SO_" #x + struct dso; =20 struct llvm_a2l_frame { @@ -37,12 +45,12 @@ struct llvm_a2l_frame { * a newly allocated array with that length. The caller is then responsible * for freeing both the strings and the array itself. */ -int llvm_addr2line(const char* dso_name, - u64 addr, - char** file, - unsigned int* line, - bool unwind_inlines, - struct llvm_a2l_frame** inline_frames); +int MANGLE_PERF_LLVM_API(llvm_addr2line)(const char *dso_name, + u64 addr, + char **file, + unsigned int *line, + bool unwind_inlines, + struct llvm_a2l_frame **inline_frames); =20 /* * Simple symbolizers for addresses; will convert something like @@ -50,8 +58,8 @@ int llvm_addr2line(const char* dso_name, * * The returned value must be freed by the caller, with free(). */ -char *llvm_name_for_code(struct dso *dso, const char *dso_name, u64 addr); -char *llvm_name_for_data(struct dso *dso, const char *dso_name, u64 addr); +char *MANGLE_PERF_LLVM_API(llvm_name_for_code)(struct dso *dso, const char= *dso_name, u64 addr); +char *MANGLE_PERF_LLVM_API(llvm_name_for_data)(struct dso *dso, const char= *dso_name, u64 addr); =20 #ifdef __cplusplus } --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6CE8B26B75B for ; Mon, 29 Sep 2025 19:09:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172948; cv=none; b=UWu8eCM4b9WnUeWaKXWgmLDJ3A0XS+29X34zM0ggwPtCryp7TifV3YKU4DaUWOlaWjs+PQagZg3sjjcuvMX34U5FpLfGQcESRkp7Cuv1MPOtWoS5sKfyZgEn62WkdTg6yEuejOhWw+milupjDTx+6ic0X64OSgFIrMLObPKrV1I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172948; c=relaxed/simple; bh=fKtsBVVZrwXhvs4xGsoMfIzV+lzZRRuS+hR0a0WuWTk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=RVNTJMnwqnONlLCmA1SAX3xSUfXZ8KA8IbisXmQKTJ4rS9gZYm629GfWYvSAn1r4TJKFk5asFN2N2rUr5MU2XlyL9Ik1HECl9ith9Naao7ZglnC2Njn5UTjE5D+cV58B/QBgTgJ3pz3mNFq7zSja4y4j9nYvt17ZeGkhy1aKe+M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=oI5bcAOC; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="oI5bcAOC" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-b55735710f0so6661873a12.2 for ; Mon, 29 Sep 2025 12:09:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172946; x=1759777746; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=23me5LsIGKvV3LZyzJtrbgmlsoLLJrcCc9Uj9IrIdaM=; b=oI5bcAOCWrWLUR4g/PFZHe5ngdBWn7yx7vA8j2m7KQgNsUPZKYXCyoRHMlYCVMhqqA Dzb4UApNLUO14i2qQp5XlkVMv7L1NQUwZF8cqx+gGVbBcwSPsx2bIleiCencS7NOdTRt hLUU6r3GGaCKL5D/htWY9UC6qYLrE60VIlTi6FPLDeYM5PbT03rs7gyNOwSycYrrHhzx +jienYr6PevnL2zFoebZZSBcyFERet4jL0yKatUvnmSoUas88XG88Y6eNg9GnMGwtiai 7lLELqivkbNGkXlY1/2Vzdv/6wD563jxbO0ESj3WpTJuJYGQBU7WQFFn8ES/kBT/F1PE tZ4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172946; x=1759777746; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=23me5LsIGKvV3LZyzJtrbgmlsoLLJrcCc9Uj9IrIdaM=; b=QvbxVmRphVjbNY5m/4e1af039/c/BK+vQap+7Pxrr0CQAmCLV7gdZ3r1p3eGJnE52l JqQIqOUQKJqKAgA2C6kuvUMUiklaaqLZ044rn0UtWvL0/kERUFJWrrMV27hSzHcca3wT 49fM+CmUgsQ/RTEg/Q5DgUDxYXI0sZXRjlqEYtZKy26mMZfwjXNLtOtSM+Aa1YE6QyFi zmVYWcDiYyJBKYrqjkU4QBTOErR+LdPgmb9ErOYa+rAcY+2GOnoQw4kL63O94Mz3+iH2 DsxPxDYwq07+hKikdMQZ9dgGddBWomwEwN9Qs7FXFo6npEzPDKRTEsCMcp9gI4BUHi4P V9Yg== X-Forwarded-Encrypted: i=1; AJvYcCV1aBmBqDr1XN9ou8Jg+ShzakgDKyzNPw7vo5QuxWzv4M/kiRqUhvb4yWEghybxH3h0TDE4YrSTs+O0ZUU=@vger.kernel.org X-Gm-Message-State: AOJu0YxylyBPXPyV1iHU7TDv6I7J4wYhvm0xViErC+fcNb0wmlj1QIl9 qSEeGuV7lJUmn2zm5Pac395PUnBpw3A9xe8nLc7zNx8BjCp2Sg3OjuJ8aeIAC0v3Y7ak8OVzSgd cjseVshzF0w== X-Google-Smtp-Source: AGHT+IEGJkvupWf4rQtKx0upUagq28uTpq7hSM4UAUkHSWoRUnkpLsZoBBntb8d18v7zVQzjqen0T6+nL+7f X-Received: from pgbdp9.prod.google.com ([2002:a05:6a02:f09:b0:b54:fe27:c3e4]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:6d98:b0:248:86a1:a253 with SMTP id adf61e73a8af0-2e7c750079amr21765837637.15.1759172945527; Mon, 29 Sep 2025 12:09:05 -0700 (PDT) Date: Mon, 29 Sep 2025 12:07:59 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-10-irogers@google.com> Subject: [PATCH v6 09/15] perf dso: Move read_symbol from llvm/capstone to dso From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move the read_symbol function to dso.h, make the return type const and add a mutable out_buf out parameter. In future changes this will allow a code pointer to be returned without necessary allocating memory. Signed-off-by: Ian Rogers --- tools/perf/util/capstone.c | 64 +++++----------------------- tools/perf/util/dso.c | 67 +++++++++++++++++++++++++++++ tools/perf/util/dso.h | 4 ++ tools/perf/util/llvm.c | 87 +++++++------------------------------- 4 files changed, 97 insertions(+), 125 deletions(-) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index fa9aa9cde68d..5aeae261f7ee 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -434,66 +434,23 @@ static int find_file_offset(u64 start, u64 len, u64 p= goff, void *arg) return 0; } =20 -static u8 * -read_symbol(const char *filename, struct map *map, struct symbol *sym, - u64 *len, bool *is_64bit) -{ - struct dso *dso =3D map__dso(map); - struct nscookie nsc; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 end =3D map__rip_2objdump(map, sym->end); - int fd, count; - u8 *buf =3D NULL; - struct find_file_offset_data data =3D { - .ip =3D start, - }; - - *is_64bit =3D false; - - nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - fd =3D open(filename, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fd < 0) - return NULL; - - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, - is_64bit) =3D=3D 0) - goto err; - - *len =3D end - start; - buf =3D malloc(*len); - if (buf =3D=3D NULL) - goto err; - - count =3D pread(fd, buf, *len, data.offset); - close(fd); - fd =3D -1; - - if ((u64)count !=3D *len) - goto err; - - return buf; - -err: - if (fd >=3D 0) - close(fd); - free(buf); - return NULL; -} - int symbol__disassemble_capstone(const char *filename __maybe_unused, struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused) { struct annotation *notes =3D symbol__annotation(sym); struct map *map =3D args->ms.map; + struct dso *dso =3D map__dso(map); u64 start =3D map__rip_2objdump(map, sym->start); - u64 len; u64 offset; int i, count, free_count; bool is_64bit =3D false; bool needs_cs_close =3D false; - u8 *buf =3D NULL; + /* Malloc-ed buffer containing instructions read from disk. */ + u8 *code_buf =3D NULL; + /* Pointer to code to be disassembled. */ + const u8 *buf; + u64 buf_len; csh handle; struct cs_insn *insn =3D NULL; char disasm_buf[512]; @@ -503,7 +460,8 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, if (args->options->objdump_path) return -1; =20 - buf =3D read_symbol(filename, map, sym, &len, &is_64bit); + buf =3D dso__read_symbol(dso, filename, map, sym, + &code_buf, &buf_len, &is_64bit); if (buf =3D=3D NULL) return -1; =20 @@ -532,7 +490,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, =20 needs_cs_close =3D true; =20 - free_count =3D count =3D perf_cs_disasm(handle, buf, len, start, len, &in= sn); + free_count =3D count =3D perf_cs_disasm(handle, buf, buf_len, start, buf_= len, &insn); for (i =3D 0, offset =3D 0; i < count; i++) { int printed; =20 @@ -556,7 +514,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, } =20 /* It failed in the middle: probably due to unknown instructions */ - if (offset !=3D len) { + if (offset !=3D buf_len) { struct list_head *list =3D ¬es->src->source; =20 /* Discard all lines and fallback to objdump */ @@ -575,7 +533,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, if (free_count > 0) perf_cs_free(insn, free_count); } - free(buf); + free(code_buf); return count < 0 ? count : 0; =20 err: diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 282e3af85d5a..87d075942de6 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1798,3 +1798,70 @@ bool is_perf_pid_map_name(const char *dso_name) =20 return perf_pid_map_tid(dso_name, &tid); } + +struct find_file_offset_data { + u64 ip; + u64 offset; +}; + +/* This will be called for each PHDR in an ELF binary */ +static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) +{ + struct find_file_offset_data *data =3D arg; + + if (start <=3D data->ip && data->ip < start + len) { + data->offset =3D pgoff + data->ip - start; + return 1; + } + return 0; +} + +const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename, + const struct map *map, const struct symbol *sym, + u8 **out_buf, u64 *out_buf_len, bool *is_64bit) +{ + struct nscookie nsc; + u64 start =3D map__rip_2objdump(map, sym->start); + u64 end =3D map__rip_2objdump(map, sym->end); + int fd, count; + u8 *buf =3D NULL; + size_t len; + struct find_file_offset_data data =3D { + .ip =3D start, + }; + + *out_buf =3D NULL; + *out_buf_len =3D 0; + *is_64bit =3D false; + + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); + fd =3D open(symfs_filename, O_RDONLY); + nsinfo__mountns_exit(&nsc); + if (fd < 0) + return NULL; + + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, is_64bit= ) =3D=3D 0) + goto err; + + len =3D end - start; + buf =3D malloc(len); + if (buf =3D=3D NULL) + goto err; + + count =3D pread(fd, buf, len, data.offset); + close(fd); + fd =3D -1; + + if ((u64)count !=3D len) + goto err; + + *out_buf =3D buf; + *out_buf_len =3D len; + return buf; + +err: + if (fd >=3D 0) + close(fd); + free(buf); + return NULL; +} diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index fd8e95de77f7..f8ccb9816b89 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -924,4 +924,8 @@ static inline struct debuginfo *dso__debuginfo(struct d= so *dso) return debuginfo__new(dso__long_name(dso)); } =20 +const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename, + const struct map *map, const struct symbol *sym, + u8 **out_buf, u64 *out_buf_len, bool *is_64bit); + #endif /* __PERF_DSO */ diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index f6a8943b7c9d..a0774373f0d6 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -296,71 +296,6 @@ void dso__free_a2l_llvm(struct dso *dso __maybe_unused) /* Nothing to free. */ } =20 - -struct find_file_offset_data { - u64 ip; - u64 offset; -}; - -/* This will be called for each PHDR in an ELF binary */ -static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) -{ - struct find_file_offset_data *data =3D arg; - - if (start <=3D data->ip && data->ip < start + len) { - data->offset =3D pgoff + data->ip - start; - return 1; - } - return 0; -} - -static u8 * -read_symbol(const char *filename, struct map *map, struct symbol *sym, - u64 *len, bool *is_64bit) -{ - struct dso *dso =3D map__dso(map); - struct nscookie nsc; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 end =3D map__rip_2objdump(map, sym->end); - int fd, count; - u8 *buf =3D NULL; - struct find_file_offset_data data =3D { - .ip =3D start, - }; - - *is_64bit =3D false; - - nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); - fd =3D open(filename, O_RDONLY); - nsinfo__mountns_exit(&nsc); - if (fd < 0) - return NULL; - - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, - is_64bit) =3D=3D 0) - goto err; - - *len =3D end - start; - buf =3D malloc(*len); - if (buf =3D=3D NULL) - goto err; - - count =3D pread(fd, buf, *len, data.offset); - close(fd); - fd =3D -1; - - if ((u64)count !=3D *len) - goto err; - - return buf; - -err: - if (fd >=3D 0) - close(fd); - free(buf); - return NULL; -} - /* * Whenever LLVM wants to resolve an address into a symbol, it calls this * callback. We don't ever actually _return_ anything (in particular, beca= use @@ -397,8 +332,11 @@ int symbol__disassemble_llvm(const char *filename, str= uct symbol *sym, struct map *map =3D args->ms.map; struct dso *dso =3D map__dso(map); u64 start =3D map__rip_2objdump(map, sym->start); - u8 *buf; - u64 len; + /* Malloc-ed buffer containing instructions read from disk. */ + u8 *code_buf =3D NULL; + /* Pointer to code to be disassembled. */ + const u8 *buf; + u64 buf_len; u64 pc; bool is_64bit; char triplet[64]; @@ -418,7 +356,8 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, perf_LLVMInitializeAllTargetMCs(); perf_LLVMInitializeAllDisassemblers(); =20 - buf =3D read_symbol(filename, map, sym, &len, &is_64bit); + buf =3D dso__read_symbol(dso, filename, map, sym, + &code_buf, &buf_len, &is_64bit); if (buf =3D=3D NULL) return -1; =20 @@ -466,14 +405,18 @@ int symbol__disassemble_llvm(const char *filename, st= ruct symbol *sym, annotation_line__add(&dl->al, ¬es->src->source); =20 pc =3D start; - for (u64 offset =3D 0; offset < len; ) { + for (u64 offset =3D 0; offset < buf_len; ) { unsigned int ins_len; =20 storage.branch_addr =3D 0; storage.pcrel_load_addr =3D 0; =20 - ins_len =3D perf_LLVMDisasmInstruction(disasm, buf + offset, - len - offset, pc, + /* + * LLVM's API has the code be disassembled as non-const, cast + * here as we may be disassembling from mapped read-only memory. + */ + ins_len =3D perf_LLVMDisasmInstruction(disasm, (u8 *)(buf + offset), + buf_len - offset, pc, disasm_buf, sizeof(disasm_buf)); if (ins_len =3D=3D 0) goto err; @@ -531,7 +474,7 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, =20 err: perf_LLVMDisasmDispose(disasm); - free(buf); + free(code_buf); free(line_storage); return ret; } --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E947217736 for ; Mon, 29 Sep 2025 19:09:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172950; cv=none; b=nttp0DK2QRSefJSy2cy3jsGdIXHJFYZD+2GgpQBVMHB629wcBiyMUhguaquoXvJPlTEmk0yhAuIPrcpS3q5YMTXVc7quX2ilFqNjTlHROCYqJ/+/3jLM8FG5riLAWfzqGODvchp7w5c/B4GoQQwvxNRNJs+o0uHP5dwsBxr1wwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172950; c=relaxed/simple; bh=612MmCdeynDCJhM2xzf4ABRBj4OerTlGO2/5DPdcThw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=UApWkxwJrAsc2pyYaonF8w8eozbq526gJEvxvh0/WSRtXCkqvLnwOwPwJiIdvaAYFePtxUgv4T5OEEEGe+9Z43qnNQuEJ6gTYcpz0tw4TNlaAAQw74SJYJVoGmPxuskhKbe41clwJsn1sMLNAq6/C7J+U/IT2Ir0l71QIz0nShk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SMrVe3cf; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SMrVe3cf" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b5533921eb2so3496015a12.0 for ; Mon, 29 Sep 2025 12:09:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172947; x=1759777747; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=T80LtbzuTq5QEV4YhukVhePJHtqZ6mXSdjQ51H1sVJk=; b=SMrVe3cfGPN5Sz2eC7qO0QXM1/jaCRSOZpO7E85PNWH4sDY2wJWuiFYFXGUhBNSMMX bkKHYnT3P2cnlh209NWzmnHcwLURoQFCAYg76Qok8D0Oe77EuHMd+HZJ5IO1KYJ7Mv/y l6SMGnkt222nca+N/mvEpCvLpi1vrFIATVB0XfDxZeCj9AfbaaVOjYj6A7EBZBQY5p+n TLLIxiM729qtF6YyqzYDPf1YL3SbOPcWMwwDLUBJXtcTTLxz1SQ7pTwuWhIobOKZEcDn 4PJ7mt6rLlfoP641Sb96y3t/Wy70HgZLWPego6mT3qIMx1mIWvmu7vz07uJE++Cnsn1H J3Kw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172947; x=1759777747; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=T80LtbzuTq5QEV4YhukVhePJHtqZ6mXSdjQ51H1sVJk=; b=shqMk/altqJWpFX+lKU3yGGf4xfV3d19XVJ19tkD9qE44s73NplPmVbLvTro3TpBUA x95q021fd3YBxampZLMCb3LpWXfRQpv4StWFVoYL30Co9v/vHbBeEpayH7l1Y0tgKzQZ 4hsIfn2hTJc3uHiBWAUh4QeHH1VqzMDtFpDPw64H5jH0cmM2AvXuu13Uh/dTvggjwFBu bI7Hq/nEoUa1adn8bZJDxMGG+/EloXsEbGJdnS5RufjV7iNSrfe4kLBu+E3YnqoZkyZF CP0ZzFcqrPikVhl0vsysxlBKaCvL3r0xedVc4ZM90xZtfVROOMundEHA2DaYt/wgcJbV KzRw== X-Forwarded-Encrypted: i=1; AJvYcCVuevtKGP6k9/88kDX5GrqHEEPFIqk6uhy6bGiTCpfTc3UnEqtqUOJDG4XiO/g9dUvMJr+kro3fGTW3fEM=@vger.kernel.org X-Gm-Message-State: AOJu0YwRG7lLXZJsk8+QZBXTvo9dvN8XJPHhOHBv1YLi72cad+3WxAw+ zRgqOJ+1ToLn1FIkJAVvfbvL05WF1wsoNuBb4Drh1Y3LcIlZpaxEZRF3JQN3jgmfAKyTD+bc+xh yK4/dGVLycA== X-Google-Smtp-Source: AGHT+IEvvky+/EgLWwl3K8Zs/55gu/czFI/PdGTNrcAlGJ4vN8lSEIzR8QJ/i33rJKHm2HVt07K26itw31Jq X-Received: from pgdf9.prod.google.com ([2002:a05:6a02:5149:b0:b52:19fd:897f]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:244c:b0:27e:ec72:f67 with SMTP id d9443c01a7336-27eec7211f2mr148076835ad.6.1759172947312; Mon, 29 Sep 2025 12:09:07 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:00 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-11-irogers@google.com> Subject: [PATCH v6 10/15] perf dso: Support BPF programs in dso__read_symbol From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Set the buffer to the code in the BPF linear info. This enables BPF JIT code disassembly by LLVM and capstone. Move the common but minimal disassmble_bpf_image call to disassemble_objdump so that it is only called after falling back to the objdump option. Similarly move the disassmble_bpf function to disassemble_objdump and rename to disassmble_bpf_libbfd to make it clearer that this support relies on libbfd. Signed-off-by: Ian Rogers --- tools/perf/util/disasm.c | 12 +++-- tools/perf/util/dso.c | 100 ++++++++++++++++++++++++++------------- tools/perf/util/libbfd.c | 4 +- tools/perf/util/libbfd.h | 6 +-- 4 files changed, 80 insertions(+), 42 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index a1240543c89c..e64902e520ab 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1521,6 +1521,12 @@ static int symbol__disassemble_objdump(const char *f= ilename, struct symbol *sym, struct child_process objdump_process; int err; =20 + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) + return symbol__disassemble_bpf_libbfd(sym, args); + + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_IMAGE) + return symbol__disassemble_bpf_image(sym, args); + err =3D asprintf(&command, "%s %s%s --start-address=3D0x%016" PRIx64 " --stop-address=3D0x%016" PRIx64 @@ -1655,11 +1661,7 @@ int symbol__disassemble(struct symbol *sym, struct a= nnotate_args *args) =20 pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), = sym, sym->name); =20 - if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) { - return symbol__disassemble_bpf(sym, args); - } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_IMAGE) { - return symbol__disassemble_bpf_image(sym, args); - } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__NOT_FOUND) { + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__NOT_FOUND) { return SYMBOL_ANNOTATE_ERRNO__COULDNT_DETERMINE_FILE_TYPE; } else if (dso__is_kcore(dso)) { kce.addr =3D map__rip_2objdump(map, sym->start); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 87d075942de6..0aed5c8691bd 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1816,23 +1816,17 @@ static int find_file_offset(u64 start, u64 len, u64= pgoff, void *arg) return 0; } =20 -const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename, - const struct map *map, const struct symbol *sym, - u8 **out_buf, u64 *out_buf_len, bool *is_64bit) +static const u8 *__dso__read_symbol(struct dso *dso, const char *symfs_fil= ename, + u64 start, size_t len, + u8 **out_buf, u64 *out_buf_len, bool *is_64bit) { struct nscookie nsc; - u64 start =3D map__rip_2objdump(map, sym->start); - u64 end =3D map__rip_2objdump(map, sym->end); - int fd, count; - u8 *buf =3D NULL; - size_t len; + int fd; + ssize_t count; struct find_file_offset_data data =3D { .ip =3D start, }; - - *out_buf =3D NULL; - *out_buf_len =3D 0; - *is_64bit =3D false; + u8 *code_buf =3D NULL; =20 nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); fd =3D open(symfs_filename, O_RDONLY); @@ -1840,28 +1834,70 @@ const u8 *dso__read_symbol(struct dso *dso, const c= har *symfs_filename, if (fd < 0) return NULL; =20 - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, is_64bit= ) =3D=3D 0) - goto err; - - len =3D end - start; - buf =3D malloc(len); - if (buf =3D=3D NULL) - goto err; - - count =3D pread(fd, buf, len, data.offset); + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, is_64bit= ) =3D=3D 0) { + close(fd); + return NULL; + } + code_buf =3D malloc(len); + if (code_buf =3D=3D NULL) { + close(fd); + return NULL; + } + count =3D pread(fd, code_buf, len, data.offset); close(fd); - fd =3D -1; + if ((u64)count !=3D len) { + free(code_buf); + return NULL; + } + *out_buf =3D code_buf; + *out_buf_len =3D len; + return code_buf; +} =20 - if ((u64)count !=3D len) - goto err; +/* + * Read a symbol into memory for disassembly by a library like capstone of + * libLLVM. If memory is allocated out_buf holds it. + */ +const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename, + const struct map *map, const struct symbol *sym, + u8 **out_buf, u64 *out_buf_len, bool *is_64bit) +{ + u64 start =3D map__rip_2objdump(map, sym->start); + u64 end =3D map__rip_2objdump(map, sym->end); + size_t len =3D end - start; =20 - *out_buf =3D buf; - *out_buf_len =3D len; - return buf; + *out_buf =3D NULL; + *out_buf_len =3D 0; + *is_64bit =3D false; =20 -err: - if (fd >=3D 0) - close(fd); - free(buf); - return NULL; + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_IMAGE) { + /* + * Note, there is fallback BPF image disassembly in the objdump + * version but it currently does nothing. + */ + return NULL; + } + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) { +#ifdef HAVE_LIBBPF_SUPPORT + struct bpf_prog_info_node *info_node; + struct perf_bpil *info_linear; + + *is_64bit =3D sizeof(void *) =3D=3D sizeof(u64); + info_node =3D perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env, + dso__bpf_prog(dso)->id); + if (!info_node) { + errno =3D SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; + return NULL; + } + info_linear =3D info_node->info_linear; + assert(len <=3D info_linear->info.jited_prog_len); + *out_buf_len =3D len; + return (const u8 *)(uintptr_t)(info_linear->info.jited_prog_insns); +#else + pr_debug("No BPF program disassembly support\n"); + return NULL; +#endif + } + return __dso__read_symbol(dso, symfs_filename, start, len, + out_buf, out_buf_len, is_64bit); } diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c index 09a0eeb78a1a..01147fbf73b3 100644 --- a/tools/perf/util/libbfd.c +++ b/tools/perf/util/libbfd.c @@ -448,8 +448,8 @@ int libbfd_filename__read_debuglink(const char *filenam= e, char *debuglink, return err; } =20 -int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, - struct annotate_args *args __maybe_unused) +int symbol__disassemble_bpf_libbfd(struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) { #ifdef HAVE_LIBBPF_SUPPORT struct annotation *notes =3D symbol__annotation(sym); diff --git a/tools/perf/util/libbfd.h b/tools/perf/util/libbfd.h index 7441e95f8ec0..e300f171d1bd 100644 --- a/tools/perf/util/libbfd.h +++ b/tools/perf/util/libbfd.h @@ -29,7 +29,7 @@ int libbfd__read_build_id(const char *filename, struct bu= ild_id *bid, bool block =20 int libbfd_filename__read_debuglink(const char *filename, char *debuglink,= size_t size); =20 -int symbol__disassemble_bpf(struct symbol *sym, struct annotate_args *args= ); +int symbol__disassemble_bpf_libbfd(struct symbol *sym, struct annotate_arg= s *args); =20 #else // !defined(HAVE_LIBBFD_SUPPORT) #include "annotate.h" @@ -72,8 +72,8 @@ static inline int libbfd_filename__read_debuglink(const c= har *filename __always_ return -1; } =20 -static inline int symbol__disassemble_bpf(struct symbol *sym __always_unus= ed, - struct annotate_args *args __always_unused) +static inline int symbol__disassemble_bpf_libbfd(struct symbol *sym __alwa= ys_unused, + struct annotate_args *args __always_unused) { return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; } --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B87227F198 for ; Mon, 29 Sep 2025 19:09:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172954; cv=none; b=GWi1ag9Xycpznu0fXplfoj/0GCyJ7INGniXqzI2Yx6PxK0V7DFrAID3FEySXYArv93jn1I5e2dhTRUE449A5MQv2oqqWpj5dqCenkvRF5F4qWCYC8Xpp34Dshn4JyE5ju8XuvDLQPmH3fIJH6Mmqrm4m9+k8/oMPkhBK2+f0IIk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172954; c=relaxed/simple; bh=PDbyASb6oi0nl45LtWvyo0kRcHkCyKYVr1dxxwhi2G4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=ZyUxyNinfyx8ks0KqepTmkiDZx62hXri7+lAO/e7ttuYGDIDVRhnn3TSyCmcmvcUAsYbktr5tdRM/IfNtvZA9hbktaBD2ynQsOCdzjdxsXEop61kevDZPH/BaqFUU+8a8qagjm051RG4Ofp6WwBHdY68j7zprYaF1vJ1F1iCAAI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=LDwfccL7; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="LDwfccL7" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-335276a711cso4447837a91.2 for ; Mon, 29 Sep 2025 12:09:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172952; x=1759777752; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=CLBs8A19UY4qrfPktznrRiT2oVtJL0cBY+Wi6IC10nw=; b=LDwfccL7uRQgfpCEQZZPD+6l7KV4Xtx9XfOYA/jsGBZe14VB7obvt+zM/snu6FkAoh pxIwVnd5u3VXGRj8hq1Gvh3BF3P9Oa1RRaBlcipiArqaCFlP2ZCHC6xs/8GF+NT86xOI +aHuHfSf33+AE+T6kNkxOFH1iF25HZ82B8oxQUhkA0acbj1PufWvpFY4Bu7Hfy7tmaGB Ftcg3X3/7YF6aoVmPzqGcxWOKzNFmeK6NZkFYPNLCm+PPfZ8kkjvTw8L2glDQ/n+mt/6 aPEiPNm28p9cMLFQa3CvrpZGYW0NYNZcVersnOSVocEqmq3eG1pv1fx8yWxSBDW954KD XTNA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172952; x=1759777752; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=CLBs8A19UY4qrfPktznrRiT2oVtJL0cBY+Wi6IC10nw=; b=pj9h9U+L481+PJm5yPC0eFcImqF2dj0OQNrej9qnVaK8ZTb7z5udcHZCnVxl81K+BU Qrp+xONtX7sbYD8ciXalV10LfQQFLgvRI5SkVXh8JS9iaJ01oLs70bBxzc/hzCqi76G0 cNyM3Q3amEX3mvNT0UoPQUZQP9Ju6JNOtn8m/uLUbPynMCzzaySbzJWEZihJpD43XKRF pOv4DHK734Y+DoT8ZKe3pdYqGWLHbC/iVxyt8LulreLVh0Uk/MMzRBerrNucfNbEoKds Ify0mbJzJhl/BiZwdewfQ7H0+IFjKvTEI2ViRR+H31US8oB+wpPRM7X6sN3H3o3G9QWh Ojvg== X-Forwarded-Encrypted: i=1; AJvYcCUcGN2ZHS3+S2cDOYUPVGVWjpCesVe2Sq5dISsIpXYG1rxnSBD3wIuXGu6C2EKMstihcPoI98mucjkYXtQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxS9C9pNPEtQzpOov2sD3or6o3sQvbtDzZ2/mE/oEXP/W27Opku elQ8+TKk15EhjLrRxbMhGyJt5NgWrsVy3v+K6NCTRtf9mmlAmzi5KbgU03lurw3w5JzbQR8e90u mn9jd0OGdtQ== X-Google-Smtp-Source: AGHT+IEAC9a1XEUOGGyjwkk2VhXg5eHtNB/otbVrKPS7fT7pgJKU6BcOUwXrzCMoVf6kg30mhKL3QelUZQIH X-Received: from pjbsf12.prod.google.com ([2002:a17:90b:51cc:b0:334:1935:56cc]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:1f8c:b0:330:797a:f4ea with SMTP id 98e67ed59e1d1-3342a2e73d7mr21521918a91.29.1759172952591; Mon, 29 Sep 2025 12:09:12 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:01 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-12-irogers@google.com> Subject: [PATCH v6 11/15] perf llvm: Disassemble cleanup From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move the 3 LLVM initialization routines to be called in a single init_llvm function that has its own bool to avoid repeated initialization. Reduce the scope of triplet and avoid copying strings for x86. Signed-off-by: Ian Rogers --- tools/perf/util/llvm.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index a0774373f0d6..a28f130c8951 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -244,6 +244,17 @@ static void perf_LLVMDisasmDispose(LLVMDisasmContextRe= f context) #endif } =20 +static void init_llvm(void) +{ + static bool init; + + if (!init) { + perf_LLVMInitializeAllTargetInfos(); + perf_LLVMInitializeAllTargetMCs(); + perf_LLVMInitializeAllDisassemblers(); + init =3D true; + } +} =20 static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames, int num_frames) @@ -339,7 +350,6 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, u64 buf_len; u64 pc; bool is_64bit; - char triplet[64]; char disasm_buf[2048]; size_t disasm_len; struct disasm_line *dl; @@ -352,27 +362,25 @@ int symbol__disassemble_llvm(const char *filename, st= ruct symbol *sym, if (args->options->objdump_path) return -1; =20 - perf_LLVMInitializeAllTargetInfos(); - perf_LLVMInitializeAllTargetMCs(); - perf_LLVMInitializeAllDisassemblers(); - buf =3D dso__read_symbol(dso, filename, map, sym, &code_buf, &buf_len, &is_64bit); if (buf =3D=3D NULL) return -1; =20 + init_llvm(); if (arch__is(args->arch, "x86")) { - if (is_64bit) - scnprintf(triplet, sizeof(triplet), "x86_64-pc-linux"); - else - scnprintf(triplet, sizeof(triplet), "i686-pc-linux"); + const char *triplet =3D is_64bit ? "x86_64-pc-linux" : "i686-pc-linux"; + + disasm =3D perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, + /*get_op_info=3D*/NULL, symbol_lookup_callback); } else { + char triplet[64]; + scnprintf(triplet, sizeof(triplet), "%s-linux-gnu", args->arch->name); + disasm =3D perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, + /*get_op_info=3D*/NULL, symbol_lookup_callback); } - - disasm =3D perf_LLVMCreateDisasm(triplet, &storage, 0, NULL, - symbol_lookup_callback); if (disasm =3D=3D NULL) goto err; =20 --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 03ADF295DB8 for ; Mon, 29 Sep 2025 19:09:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172960; cv=none; b=C2Ai6RWCXUqbkJ7oANeFL3645jHaYyPhrqFsjvUia0usrv3mccklj4jYYxhVbeHLLC4/2z+xBdGiNdMGxMYIVRrTP3IBdNubJ1U/dCQKDgp5XkNpXy+kpyZc6uG+HlBIhuznxvdYFlwNfgLbLVuro/euFhVuqd6uNW0vJOMLSGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172960; c=relaxed/simple; bh=3x6uHsyrBbNmgRCRMDBpOpkaIRMxB51Rh5aACDVUbqQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=Rc8yhfUZ5az+5HU9r3ISAQqtsSGwSP9JKcxlDyJRpJnQ9Mkey7DD/AKoGSMS82GHq/tTEUEfIqrqG93aoG8imnthapbkMDUKv2Kri2nMmwLSIt+PuFpALCjsuVuVx4io/tFi7mtgJC2SvoKKF7QVMZLXVXL6HX/S4QaKA70L+qU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qdnnRnic; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qdnnRnic" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-77f68c697d3so3522261b3a.1 for ; Mon, 29 Sep 2025 12:09:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172955; x=1759777755; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=3VdaBDHiSOtBGNqPCgDdEXCvLGYer8aP4O1DydDNh98=; b=qdnnRnic2peqJ5xGdkkmPK78qprcwpK+0tf9KckOr2j7TP5w6mb6wiHvWu3tzLmmX2 Z0h95lC1oX41VTEUIcswf9BZJ+qJ9OFbTkVQ0rRO7WSTUw8OQTPjkYcGpvX2iRCcBFhw pn2iB5z5xJJGe+3qenwwqCwefOVOUP7KyrA9ZYTexiB4qhBZM2tWTix7TWn984njINrS QKaIxdA/iYZxuDFTuLgT6rglQOkd1V0G7AiXAr/HzLaAG78D2ivwALM3HGl9Tw4i+Me3 AQrChhFDoOVtuvFaG3rVDTNWEgMC9+yNwU7BFj7uVqdLaPphaiToEeG3sCtvGVaoxIY4 Lf2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172955; x=1759777755; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=3VdaBDHiSOtBGNqPCgDdEXCvLGYer8aP4O1DydDNh98=; b=e2vRspQ3Hyf+4IbHAvFvwr9JVADwbc27sBgU4acJ4p67UhpUJkurxB1udxIDQnJwBB wQag9YUlAqhNIlZkYlu/6hBereuU7+u8Nk2mZvX1v3fy4v8CPjypXKBOentYTIwEMMOe 8JygngzscqNs4dIz4+MvfpHp4/RKwYp0cxd0dAb2vtNoqurFQS0pVLB6I/CQpYhPyz0x vmUi3Kt+BZyBS4HHMWplSl6uCeFm/k+s+Hs3+ekMzjbKQ3ewluD4cCNnHHqisBKnzQnW zg6z+QH0cSFlRXsbhXceY5mblr3XRyMe87Jdx4a2/DrRydVg5xytIq8+dkL1K062lf4M 9puw== X-Forwarded-Encrypted: i=1; AJvYcCWmUnGVfjQjFS7SarOuSWKQkgZFDPluhOtnWfmIxHf3zUDMfqvrGnFHydfPcooGe10zSY3r3dmj8Br2VwY=@vger.kernel.org X-Gm-Message-State: AOJu0Ywn3aE3K0oa8HUXTw/RsxUZi1ZAtMqQmoioTtJDFV7jgR8fpbhH c0scrEac9Z3S745arR/+zS5cdy3KcrNh1nT+KIUFBnLPz0YVit74fUjN1j+VDg9Eo04N0CWQvW4 RzysuizLAlg== X-Google-Smtp-Source: AGHT+IFGhoOWjQgkF0L/NciS7Xfc7ntjSvsp7meQoiLbtTvTPGEmfOtvs2UKevw6zAF7rh0zR61UX/7++OhU X-Received: from pgng22.prod.google.com ([2002:a63:3756:0:b0:b56:3de0:d767]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:12cb:b0:2d9:b2ee:7855 with SMTP id adf61e73a8af0-2e7d7c04d2dmr19511013637.51.1759172954887; Mon, 29 Sep 2025 12:09:14 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:02 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-13-irogers@google.com> Subject: [PATCH v6 12/15] perf dso: Clean up read_symbol error handling From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Ensure errno is set and return to caller for error handling. Unusually for perf the value isn't negated as expected by symbol__strerror_disassemble. Signed-off-by: Ian Rogers --- tools/perf/util/capstone.c | 3 ++- tools/perf/util/dso.c | 15 ++++++++++++--- tools/perf/util/llvm.c | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c index 5aeae261f7ee..88e270237443 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -12,6 +12,7 @@ #include "symbol.h" #include "thread.h" #include +#include #include #include #include @@ -463,7 +464,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, buf =3D dso__read_symbol(dso, filename, map, sym, &code_buf, &buf_len, &is_64bit); if (buf =3D=3D NULL) - return -1; + return errno; =20 /* add the function address and name */ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 0aed5c8691bd..344e689567ee 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -1827,26 +1827,33 @@ static const u8 *__dso__read_symbol(struct dso *dso= , const char *symfs_filename, .ip =3D start, }; u8 *code_buf =3D NULL; + int saved_errno; =20 nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); fd =3D open(symfs_filename, O_RDONLY); + saved_errno =3D errno; nsinfo__mountns_exit(&nsc); - if (fd < 0) + if (fd < 0) { + errno =3D saved_errno; return NULL; - - if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, is_64bit= ) =3D=3D 0) { + } + if (file__read_maps(fd, /*exe=3D*/true, find_file_offset, &data, is_64bit= ) <=3D 0) { close(fd); + errno =3D ENOENT; return NULL; } code_buf =3D malloc(len); if (code_buf =3D=3D NULL) { close(fd); + errno =3D ENOMEM; return NULL; } count =3D pread(fd, code_buf, len, data.offset); + saved_errno =3D errno; close(fd); if ((u64)count !=3D len) { free(code_buf); + errno =3D saved_errno; return NULL; } *out_buf =3D code_buf; @@ -1875,6 +1882,7 @@ const u8 *dso__read_symbol(struct dso *dso, const cha= r *symfs_filename, * Note, there is fallback BPF image disassembly in the objdump * version but it currently does nothing. */ + errno =3D EOPNOTSUPP; return NULL; } if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) { @@ -1895,6 +1903,7 @@ const u8 *dso__read_symbol(struct dso *dso, const cha= r *symfs_filename, return (const u8 *)(uintptr_t)(info_linear->info.jited_prog_insns); #else pr_debug("No BPF program disassembly support\n"); + errno =3D EOPNOTSUPP; return NULL; #endif } diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index a28f130c8951..1607364ee736 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -9,6 +9,7 @@ #include "srcline.h" #include "symbol.h" #include +#include #include #include #include @@ -365,7 +366,7 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, buf =3D dso__read_symbol(dso, filename, map, sym, &code_buf, &buf_len, &is_64bit); if (buf =3D=3D NULL) - return -1; + return errno; =20 init_llvm(); if (arch__is(args->arch, "x86")) { --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96ED9288C96 for ; Mon, 29 Sep 2025 19:09:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172959; cv=none; b=Zcq4sBGmcFZOykzQRtDkd1XUsaPFpbxES2pGJ0v0Mll7kI8wpl8abRgR9bmTrejZ6puE0AvjTtaOFhju82G3yQ2uBjzIZ/g5n6FbckWr5O7wD8tT3J5fx5aQZdKHDVUISNM5aj1hWOG6oyvDb9iLVc7y79P4913+LKaAgSoyceY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172959; c=relaxed/simple; bh=QAMXMzzdI9MdutH7eQN4wd9SUdKYuTS3iFPzHIudd8c=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=hrkA6iM47mJPlPx3KEFSYA0gSmOcw8DO17pM1XiX1pTuc/cZGlapsN35ZRYZxMXQyYd+eQhoohPftLFhJAcJDPqafKTDrP4ZRemfxG90VaH2RiZ1A2wNZOR5bhMzdrb+lAZmKNcS1cq5hwGDID0fjiVgjJwWsZeHUz45fNjV488= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=jJ4QBprE; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="jJ4QBprE" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-28c58e009d1so16380385ad.3 for ; Mon, 29 Sep 2025 12:09:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172956; x=1759777756; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=rdcK/lBU6rEBVQg0qeNeqiUObE1KDszjje3klwu/MCM=; b=jJ4QBprEh0GjwKLc355Pi1mY26EcEmTi7iCE4S00B6KaqGD5baYxXDwtc3AlPpkDVl vhrcV+InhA5v847pZKpVfvITBifN/MlDGr45BrM57H4RI3ZI7l8y6bhFrgXcI2yTrQTw 59f2waLEANfJhi3Ze+xc8kMDy56U4D11MBobrRgm8KmDNPATx+7/T1RJ9jmOw9bk+Mlb p4G7ui5gq8o2CcZFWCpjsh1Zq+K5RUALYZ6NhtvbnmUk7KPeSzzE7kG5ZVqkhhRAEd9P KCjICOUJ3UutStHz3uxtH8o+d9wULCnKEpx6I37onzYNGyMP9SuXoSRa8ivC0huoi0dQ aB8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172956; x=1759777756; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=rdcK/lBU6rEBVQg0qeNeqiUObE1KDszjje3klwu/MCM=; b=KI2pVIXDWth6IvyojE3scGXAhJL+58dPzZC6Td9p7LsfaTaKJ0f4Gv6dwdBf4E/MD1 AfLVCVChRTRUiAO2iYep0FS9VZlNCnQjrcGF6yY6mOIHCTswaOgRJEgpf/u1ef4ED1IV Cf+8qTgOjjGs65n6Ric7AEsLzNmX/l2dh+RedzsiNgpD47YnVu5Pur5DOdP7M5Mo47rY EvfhqUu5moOcoS2YSxmoS2xdbM3K9/ivf4iFjEfg1MXVPnAb7R6ju1UA8rvCOC3gcebF iteWNeIqFrcFOKTrSIIE2PTnHX0Blz8/6ApXhGO2A4JaPaRT+XWQ7ZH5xoIp0OaPhNRI 5HrA== X-Forwarded-Encrypted: i=1; AJvYcCVmhHXVfgcDIQC0pO1xG9WKqC0Y3Nm7myp8qm5wrLXN6CnINL7bDnVEHjqsR/LIawz87Oq60rg0o8+A8Pg=@vger.kernel.org X-Gm-Message-State: AOJu0YyTIXufh02i2ew71YqaHskRXAXNN3wq7xCxw6cCB+PvHvHZjko4 b/7PH3tqcFplhZlWBnZngfgZ5ZYZAmNWjjjFMQCXiZRPma8WoeYTRBdofjXFUei9VGfJwOvagnu QohsoAudweA== X-Google-Smtp-Source: AGHT+IEJX47iOtVtrshwBHm4+RSHE5OXtXWHjA4rxRxxI9/ipxBIUfnBsBl2AQARp8ZA4p+cWOFp5/eQGOfA X-Received: from plko4.prod.google.com ([2002:a17:902:6b04:b0:234:c104:43f1]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:ea0a:b0:24b:62ef:9d38 with SMTP id d9443c01a7336-27ed49d2948mr197295705ad.19.1759172956552; Mon, 29 Sep 2025 12:09:16 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:03 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-14-irogers@google.com> Subject: [PATCH v6 13/15] perf disasm: Make ins__scnprintf and ins__is_nop static From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Reduce the scope of ins__scnprintf and ins__is_nop that aren't used outside of disasm.c. Signed-off-by: Ian Rogers --- tools/perf/util/disasm.c | 6 +++--- tools/perf/util/disasm.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index e64902e520ab..50b9433f3f8e 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -247,8 +247,8 @@ static int ins__raw_scnprintf(struct ins *ins, char *bf= , size_t size, return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); } =20 -int ins__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name) +static int ins__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, int max_ins_name) { if (ins->ops->scnprintf) return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); @@ -828,7 +828,7 @@ static struct ins_ops ret_ops =3D { .scnprintf =3D ins__raw_scnprintf, }; =20 -bool ins__is_nop(const struct ins *ins) +static bool ins__is_nop(const struct ins *ins) { return ins->ops =3D=3D &nop_ops; } diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h index 2cb4e1a6bd30..09c86f540f7f 100644 --- a/tools/perf/util/disasm.h +++ b/tools/perf/util/disasm.h @@ -110,13 +110,10 @@ struct arch *arch__find(const char *name); bool arch__is(struct arch *arch, const char *name); =20 struct ins_ops *ins__find(struct arch *arch, const char *name, struct disa= sm_line *dl); -int ins__scnprintf(struct ins *ins, char *bf, size_t size, - struct ins_operands *ops, int max_ins_name); =20 bool ins__is_call(const struct ins *ins); bool ins__is_jump(const struct ins *ins); bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); -bool ins__is_nop(const struct ins *ins); bool ins__is_ret(const struct ins *ins); bool ins__is_lock(const struct ins *ins); =20 --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9B16229C343 for ; Mon, 29 Sep 2025 19:09:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172965; cv=none; b=Ua+w6pJIWzOw9mGHj4nN61D++ih7UaQgVh4FsqpWeoMdk9+VgaRzLIbhGLJOsU9kiuVpRaf/A2KdYpG97c7tbDZ39hn/2zJM/5BMgWpreSDGnWLLtQE1f5oFTbE2QVLPUFkMflKhYhUvD5eQ/cYdtE+e/9ZUc8vpbLSQSdx+yDg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172965; c=relaxed/simple; bh=1iLYUYb8ouvZnn/UKIENKYunRTLk9SlEBZxwfkYQBNQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=lBXDRxAGHrvVEfS9tV0FExtrjBBiLSt+N9f9GxGEDKeEF7jUrxCNg8PcoZQ8HUiPZ+x3g3bN911gYWLb5w+Tt5ziSmHtCfnQUn95JFIDIEjEBdMrTp5wYcrF/qm9UdtmKIJBsYtIUyG49G3AQKVqdjteLsV0lnQEUWNEKiK/xAA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=0KemWLKi; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="0KemWLKi" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-334b0876195so5077260a91.1 for ; Mon, 29 Sep 2025 12:09:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172962; x=1759777762; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=mk8LHZnikQ82ewf8h3KEcwFqyB8K5toDN0BOHpgdtJs=; b=0KemWLKi0hPuQBG/NPKjY38Kb97RgcZvHdfad0x6wLRCTkfhgJVsci+x37+iT4vB6D k0hx25opDeUbPx2e2tHU+PzxkEvwaCFNWQktSC7l9EfNL7kzEKBoT9aDstnLlQyJdqIO WK/Rtu4K4xA+TW533kbawGpY5SpLzOTNU0JO0L5roFTkdVKi3tc7T53dA+OQYMigXB8X beHlN9qbImGSOXcR5ohU23oSyfTbwyDfWiCkv8KLjQ6eJJNOfpixIKdo9B+kTS0mI1nR 1e467HDJxneB/D77CKAKXkJdCH1EXbDOl+fgLEmS6r1uGJgHeAXf4dPySWg0qefylgGB yjLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172962; x=1759777762; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=mk8LHZnikQ82ewf8h3KEcwFqyB8K5toDN0BOHpgdtJs=; b=ABSydZD4wfKHSycFkKNwCygVSLuaWTwWswRqF6wZ3EYFBLw86P1Tt6ua94pPr0EyLc ZtqQ0wvMoPfbV8oKKTvcHm8REFQSBeWg/ONa5hEAYrrcR6j46N/dbBlgae9uW+KBNo/j t9zTWfaDvw1U7I37JpkOXye4s0tEF5b0+/XCcw5kEVot/pwbM78tlwsOEl/kpi616UFg IyhnWw55Sha4aNROxnXPn7eKXBi2Zuy4wa7k7Ihxr8KzXYGriaPyYlsVaeuGLBWH7131 AT4TpmcZxkqsxWhM7qM1oIat2MQdTKPOfZGlhKTHXESPLQmiy6Q96rki3M/k9rUncZH9 24kg== X-Forwarded-Encrypted: i=1; AJvYcCUEeDUsdfSdc5vwDLelCK3hywhjk3kYvN1ILJBysBCtB6X2D34+HRklTjxQqziBgzAObv1qCp+OH4mH5qU=@vger.kernel.org X-Gm-Message-State: AOJu0Yyn0YirhUrcdw3et2jDloMlcpsxQlEcRJw3ZLeiLA/RP9Wmtwen Pfvg88B4Kj57hrSuHp/4jPSuxggsy2ymqwzXpwKoxtVZEKZJhUhFjMOl10KQ7JNRSDLmlEIdbPF gx6dl4xVGNQ== X-Google-Smtp-Source: AGHT+IFJsPmVvCx4+OEHNEgB278DZ/E7yNqKaqoP/lPuYE5QqWPfRjE57/jvUw93LiCw7cWJPDB3rHYUkAZ3 X-Received: from pjbcx11.prod.google.com ([2002:a17:90a:fd8b:b0:327:c20a:364]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:384e:b0:332:6356:86b6 with SMTP id 98e67ed59e1d1-3342a28ab34mr18926159a91.9.1759172961933; Mon, 29 Sep 2025 12:09:21 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:04 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-15-irogers@google.com> Subject: [PATCH v6 14/15] perf srcline: Fallback between addr2line implementations From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Factor the addr2line function implementation into separate source files (addr2line.[ch]) and rename the addr2line function cmd__addr2line. In srcline replace the ifdef-ed addr2line implementations with one that first tries the llvm__addr2line implementation, then the deprecated libbfd__addr2line function and on failure uses cmd__addr2line. If HAVE_LIBLLVM_SUPPORT is enabled the llvm__addr2line will execute against the libLLVM.so it is linked against. If HAVE_LIBLLVM_DYNAMIC is enabled then libperf-llvm.so (that links against libLLVM.so) will be dlopened. If the dlopen succeeds then the behavior should match HAVE_LIBLLVM_SUPPORT. On failure cmd__addr2line is used. The dlopen is only tried once. If HAVE_LIBLLVM_DYNAMIC isn't enabled then llvm__addr2line immediately fails and cmd__addr2line is used. Clean up the dso__free_a2l logic, which is only needed in the non-LLVM version and moved to addr2line.c. Signed-off-by: Ian Rogers --- tools/perf/util/Build | 1 + tools/perf/util/addr2line.c | 439 ++++++++++++++++++++++++++++++++ tools/perf/util/addr2line.h | 20 ++ tools/perf/util/config.c | 2 +- tools/perf/util/llvm.c | 5 - tools/perf/util/llvm.h | 3 - tools/perf/util/srcline.c | 495 ++---------------------------------- tools/perf/util/srcline.h | 1 - 8 files changed, 485 insertions(+), 481 deletions(-) create mode 100644 tools/perf/util/addr2line.c create mode 100644 tools/perf/util/addr2line.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 98d0a673fb53..684556986e64 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -2,6 +2,7 @@ include $(srctree)/tools/scripts/Makefile.include include $(srctree)/tools/scripts/utilities.mak =20 perf-util-y +=3D arm64-frame-pointer-unwind-support.o +perf-util-y +=3D addr2line.o perf-util-y +=3D addr_location.o perf-util-y +=3D annotate.o perf-util-y +=3D block-info.o diff --git a/tools/perf/util/addr2line.c b/tools/perf/util/addr2line.c new file mode 100644 index 000000000000..f2d94a3272d7 --- /dev/null +++ b/tools/perf/util/addr2line.c @@ -0,0 +1,439 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "addr2line.h" +#include "debug.h" +#include "dso.h" +#include "string2.h" +#include "srcline.h" +#include "symbol.h" +#include "symbol_conf.h" + +#include +#include +#include + +#include +#include +#include +#include + +#define MAX_INLINE_NEST 1024 + +/* If addr2line doesn't return data for 1 second then timeout. */ +int addr2line_timeout_ms =3D 1 * 1000; + +static int filename_split(char *filename, unsigned int *line_nr) +{ + char *sep; + + sep =3D strchr(filename, '\n'); + if (sep) + *sep =3D '\0'; + + if (!strcmp(filename, "??:0")) + return 0; + + sep =3D strchr(filename, ':'); + if (sep) { + *sep++ =3D '\0'; + *line_nr =3D strtoul(sep, NULL, 0); + return 1; + } + pr_debug("addr2line missing ':' in filename split\n"); + return 0; +} + +static void addr2line_subprocess_cleanup(struct child_process *a2l) +{ + if (a2l->pid !=3D -1) { + kill(a2l->pid, SIGKILL); + finish_command(a2l); /* ignore result, we don't care */ + a2l->pid =3D -1; + close(a2l->in); + close(a2l->out); + } + + free(a2l); +} + +static struct child_process *addr2line_subprocess_init(const char *addr2li= ne_path, + const char *binary_path) +{ + const char *argv[] =3D { + addr2line_path ?: "addr2line", + "-e", binary_path, + "-a", "-i", "-f", NULL + }; + struct child_process *a2l =3D zalloc(sizeof(*a2l)); + int start_command_status =3D 0; + + if (a2l =3D=3D NULL) { + pr_err("Failed to allocate memory for addr2line"); + return NULL; + } + + a2l->pid =3D -1; + a2l->in =3D -1; + a2l->out =3D -1; + a2l->no_stderr =3D 1; + + a2l->argv =3D argv; + start_command_status =3D start_command(a2l); + a2l->argv =3D NULL; /* it's not used after start_command; avoid dangling = pointers */ + + if (start_command_status !=3D 0) { + pr_warning("could not start addr2line (%s) for %s: start_command return = code %d\n", + addr2line_path, binary_path, start_command_status); + addr2line_subprocess_cleanup(a2l); + return NULL; + } + + return a2l; +} + +enum a2l_style { + BROKEN, + GNU_BINUTILS, + LLVM, +}; + +static enum a2l_style addr2line_configure(struct child_process *a2l, const= char *dso_name) +{ + static bool cached; + static enum a2l_style style; + + if (!cached) { + char buf[128]; + struct io io; + int ch; + int lines; + + if (write(a2l->in, ",\n", 2) !=3D 2) + return BROKEN; + + io__init(&io, a2l->out, buf, sizeof(buf)); + ch =3D io__get_char(&io); + if (ch =3D=3D ',') { + style =3D LLVM; + cached =3D true; + lines =3D 1; + pr_debug3("Detected LLVM addr2line style\n"); + } else if (ch =3D=3D '0') { + style =3D GNU_BINUTILS; + cached =3D true; + lines =3D 3; + pr_debug3("Detected binutils addr2line style\n"); + } else { + if (!symbol_conf.disable_add2line_warn) { + char *output =3D NULL; + size_t output_len; + + io__getline(&io, &output, &output_len); + pr_warning("%s %s: addr2line configuration failed\n", + __func__, dso_name); + pr_warning("\t%c%s", ch, output); + } + pr_debug("Unknown/broken addr2line style\n"); + return BROKEN; + } + while (lines) { + ch =3D io__get_char(&io); + if (ch <=3D 0) + break; + if (ch =3D=3D '\n') + lines--; + } + /* Ignore SIGPIPE in the event addr2line exits. */ + signal(SIGPIPE, SIG_IGN); + } + return style; +} + +static int read_addr2line_record(struct io *io, + enum a2l_style style, + const char *dso_name, + u64 addr, + bool first, + char **function, + char **filename, + unsigned int *line_nr) +{ + /* + * Returns: + * -1 =3D=3D> error + * 0 =3D=3D> sentinel (or other ill-formed) record read + * 1 =3D=3D> a genuine record read + */ + char *line =3D NULL; + size_t line_len =3D 0; + unsigned int dummy_line_nr =3D 0; + int ret =3D -1; + + if (function !=3D NULL) + zfree(function); + + if (filename !=3D NULL) + zfree(filename); + + if (line_nr !=3D NULL) + *line_nr =3D 0; + + /* + * Read the first line. Without an error this will be: + * - for the first line an address like 0x1234, + * - the binutils sentinel 0x0000000000000000, + * - the llvm-addr2line the sentinel ',' character, + * - the function name line for an inlined function. + */ + if (io__getline(io, &line, &line_len) < 0 || !line_len) + goto error; + + pr_debug3("%s %s: addr2line read address for sentinel: %s", __func__, dso= _name, line); + if (style =3D=3D LLVM && line_len =3D=3D 2 && line[0] =3D=3D ',') { + /* Found the llvm-addr2line sentinel character. */ + zfree(&line); + return 0; + } else if (style =3D=3D GNU_BINUTILS && (!first || addr !=3D 0)) { + int zero_count =3D 0, non_zero_count =3D 0; + /* + * Check for binutils sentinel ignoring it for the case the + * requested address is 0. + */ + + /* A given address should always start 0x. */ + if (line_len >=3D 2 || line[0] !=3D '0' || line[1] !=3D 'x') { + for (size_t i =3D 2; i < line_len; i++) { + if (line[i] =3D=3D '0') + zero_count++; + else if (line[i] !=3D '\n') + non_zero_count++; + } + if (!non_zero_count) { + int ch; + + if (first && !zero_count) { + /* Line was erroneous just '0x'. */ + goto error; + } + /* + * Line was 0x0..0, the sentinel for binutils. Remove + * the function and filename lines. + */ + zfree(&line); + do { + ch =3D io__get_char(io); + } while (ch > 0 && ch !=3D '\n'); + do { + ch =3D io__get_char(io); + } while (ch > 0 && ch !=3D '\n'); + return 0; + } + } + } + /* Read the second function name line (if inline data then this is the fi= rst line). */ + if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) + goto error; + + pr_debug3("%s %s: addr2line read line: %s", __func__, dso_name, line); + if (function !=3D NULL) + *function =3D strdup(strim(line)); + + zfree(&line); + line_len =3D 0; + + /* Read the third filename and line number line. */ + if (io__getline(io, &line, &line_len) < 0 || !line_len) + goto error; + + pr_debug3("%s %s: addr2line filename:number : %s", __func__, dso_name, li= ne); + if (filename_split(line, line_nr =3D=3D NULL ? &dummy_line_nr : line_nr) = =3D=3D 0 && + style =3D=3D GNU_BINUTILS) { + ret =3D 0; + goto error; + } + + if (filename !=3D NULL) + *filename =3D strdup(line); + + zfree(&line); + line_len =3D 0; + + return 1; + +error: + free(line); + if (function !=3D NULL) + zfree(function); + if (filename !=3D NULL) + zfree(filename); + return ret; +} + +static int inline_list__append_record(struct dso *dso, + struct inline_node *node, + struct symbol *sym, + const char *function, + const char *filename, + unsigned int line_nr) +{ + struct symbol *inline_sym =3D new_inline_sym(dso, sym, function); + + return inline_list__append(inline_sym, srcline_from_fileline(filename, li= ne_nr), node); +} + +int cmd__addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line_nr, + struct dso *dso, + bool unwind_inlines, + struct inline_node *node, + struct symbol *sym __maybe_unused) +{ + struct child_process *a2l =3D dso__a2l(dso); + char *record_function =3D NULL; + char *record_filename =3D NULL; + unsigned int record_line_nr =3D 0; + int record_status =3D -1; + int ret =3D 0; + size_t inline_count =3D 0; + int len; + char buf[128]; + ssize_t written; + struct io io =3D { .eof =3D false }; + enum a2l_style a2l_style; + + if (!a2l) { + if (!filename__has_section(dso_name, ".debug_line")) + goto out; + + dso__set_a2l(dso, + addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name)); + a2l =3D dso__a2l(dso); + } + + if (a2l =3D=3D NULL) { + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_n= ame); + goto out; + } + a2l_style =3D addr2line_configure(a2l, dso_name); + if (a2l_style =3D=3D BROKEN) + goto out; + + /* + * Send our request and then *deliberately* send something that can't be + * interpreted as a valid address to ask addr2line about (namely, + * ","). This causes addr2line to first write out the answer to our + * request, in an unbounded/unknown number of records, and then to write + * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," + * for llvm-addr2line, so that we can detect when it has finished giving + * us anything useful. + */ + len =3D snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); + written =3D len > 0 ? write(a2l->in, buf, len) : -1; + if (written !=3D len) { + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not send request\n", __func__, dso_name); + goto out; + } + io__init(&io, a2l->out, buf, sizeof(buf)); + io.timeout_ms =3D addr2line_timeout_ms; + switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=3D*= /true, + &record_function, &record_filename, &record_line_nr)) { + case -1: + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not read first record\n", __func__, dso_name); + goto out; + case 0: + /* + * The first record was invalid, so return failure, but first + * read another record, since we sent a sentinel ',' for the + * sake of detected the last inlined function. Treat this as the + * first of a record as the ',' generates a new start with GNU + * binutils, also force a non-zero address as we're no longer + * reading that record. + */ + switch (read_addr2line_record(&io, a2l_style, dso_name, + /*addr=3D*/1, /*first=3D*/true, + NULL, NULL, NULL)) { + case -1: + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: could not read sentinel record\n", + __func__, dso_name); + break; + case 0: + /* The sentinel as expected. */ + break; + default: + if (!symbol_conf.disable_add2line_warn) + pr_warning("%s %s: unexpected record instead of sentinel", + __func__, dso_name); + break; + } + goto out; + default: + /* First record as expected. */ + break; + } + + if (file) { + *file =3D strdup(record_filename); + ret =3D 1; + } + if (line_nr) + *line_nr =3D record_line_nr; + + if (unwind_inlines) { + if (node && inline_list__append_record(dso, node, sym, + record_function, + record_filename, + record_line_nr)) { + ret =3D 0; + goto out; + } + } + + /* + * We have to read the records even if we don't care about the inline + * info. This isn't the first record and force the address to non-zero + * as we're reading records beyond the first. + */ + while ((record_status =3D read_addr2line_record(&io, + a2l_style, + dso_name, + /*addr=3D*/1, + /*first=3D*/false, + &record_function, + &record_filename, + &record_line_nr)) =3D=3D 1) { + if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { + if (inline_list__append_record(dso, node, sym, + record_function, + record_filename, + record_line_nr)) { + ret =3D 0; + goto out; + } + ret =3D 1; /* found at least one inline frame */ + } + } + +out: + free(record_function); + free(record_filename); + if (io.eof) { + dso__set_a2l(dso, NULL); + addr2line_subprocess_cleanup(a2l); + } + return ret; +} + +void dso__free_a2l(struct dso *dso) +{ + struct child_process *a2l =3D dso__a2l(dso); + + if (!a2l) + return; + + addr2line_subprocess_cleanup(a2l); + + dso__set_a2l(dso, NULL); +} diff --git a/tools/perf/util/addr2line.h b/tools/perf/util/addr2line.h new file mode 100644 index 000000000000..d35a47ba8dab --- /dev/null +++ b/tools/perf/util/addr2line.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_ADDR2LINE_H +#define __PERF_ADDR2LINE_H + +#include + +struct dso; +struct inline_node; +struct symbol; + +extern int addr2line_timeout_ms; + +int cmd__addr2line(const char *dso_name, u64 addr, + char **file, unsigned int *line_nr, + struct dso *dso, + bool unwind_inlines, + struct inline_node *node, + struct symbol *sym); + +#endif /* __PERF_ADDR2LINE_H */ diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index ae72b66b6ded..6f914620c6ff 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -19,7 +19,7 @@ #include "util/hist.h" /* perf_hist_config */ #include "util/stat.h" /* perf_stat__set_big_num */ #include "util/evsel.h" /* evsel__hw_names, evsel__use_bpf_counters */ -#include "util/srcline.h" /* addr2line_timeout_ms */ +#include "util/addr2line.h" /* addr2line_timeout_ms */ #include "build-id.h" #include "debug.h" #include "config.h" diff --git a/tools/perf/util/llvm.c b/tools/perf/util/llvm.c index 1607364ee736..cacb510c6814 100644 --- a/tools/perf/util/llvm.c +++ b/tools/perf/util/llvm.c @@ -303,11 +303,6 @@ int llvm__addr2line(const char *dso_name __maybe_unuse= d, u64 addr __maybe_unused return num_frames; } =20 -void dso__free_a2l_llvm(struct dso *dso __maybe_unused) -{ - /* Nothing to free. */ -} - /* * Whenever LLVM wants to resolve an address into a symbol, it calls this * callback. We don't ever actually _return_ anything (in particular, beca= use diff --git a/tools/perf/util/llvm.h b/tools/perf/util/llvm.h index 8aa19bb6b068..57f6bafb24bb 100644 --- a/tools/perf/util/llvm.h +++ b/tools/perf/util/llvm.h @@ -15,9 +15,6 @@ int llvm__addr2line(const char *dso_name, u64 addr, bool unwind_inlines, struct inline_node *node, struct symbol *sym); =20 - -void dso__free_a2l_llvm(struct dso *dso); - int symbol__disassemble_llvm(const char *filename, struct symbol *sym, struct annotate_args *args); =20 diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c index 23b942d4729e..27c0966611ab 100644 --- a/tools/perf/util/srcline.c +++ b/tools/perf/util/srcline.c @@ -1,30 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "util/dso.h" -#include "util/debug.h" -#include "util/callchain.h" -#include "util/symbol_conf.h" -#include "llvm.h" #include "srcline.h" -#include "string2.h" +#include "addr2line.h" +#include "dso.h" +#include "callchain.h" +#include "libbfd.h" +#include "llvm.h" #include "symbol.h" -#include "subcmd/run-command.h" =20 -/* If addr2line doesn't return data for 1 second then timeout. */ -int addr2line_timeout_ms =3D 1 * 1000; +#include +#include + bool srcline_full_filename; =20 char *srcline__unknown =3D (char *)"??:0"; @@ -129,458 +114,23 @@ struct symbol *new_inline_sym(struct dso *dso, return inline_sym; } =20 -#ifdef HAVE_LIBLLVM_SUPPORT -#include "llvm.h" - -static int addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line, struct dso *dso, - bool unwind_inlines, struct inline_node *node, - struct symbol *sym) -{ - return llvm__addr2line(dso_name, addr, file, line, dso, unwind_inlines, n= ode, sym); -} - -void dso__free_a2l(struct dso *dso) -{ - dso__free_a2l_llvm(dso); -} -#elif defined(HAVE_LIBBFD_SUPPORT) -#include "libbfd.h" - -static int addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line, struct dso *dso, - bool unwind_inlines, struct inline_node *node, +static int addr2line(const char *dso_name, u64 addr, char **file, unsigned= int *line_nr, + struct dso *dso, bool unwind_inlines, struct inline_node *node, struct symbol *sym) { - return libbfd__addr2line(dso_name, addr, file, line, dso, unwind_inlines,= node, sym); -} - -void dso__free_a2l(struct dso *dso) -{ - dso__free_a2l_libbfd(dso); -} - -#else /* HAVE_LIBBFD_SUPPORT */ - -static int filename_split(char *filename, unsigned int *line_nr) -{ - char *sep; - - sep =3D strchr(filename, '\n'); - if (sep) - *sep =3D '\0'; - - if (!strcmp(filename, "??:0")) - return 0; - - sep =3D strchr(filename, ':'); - if (sep) { - *sep++ =3D '\0'; - *line_nr =3D strtoul(sep, NULL, 0); - return 1; - } - pr_debug("addr2line missing ':' in filename split\n"); - return 0; -} - -static void addr2line_subprocess_cleanup(struct child_process *a2l) -{ - if (a2l->pid !=3D -1) { - kill(a2l->pid, SIGKILL); - finish_command(a2l); /* ignore result, we don't care */ - a2l->pid =3D -1; - close(a2l->in); - close(a2l->out); - } - - free(a2l); -} - -static struct child_process *addr2line_subprocess_init(const char *addr2li= ne_path, - const char *binary_path) -{ - const char *argv[] =3D { - addr2line_path ?: "addr2line", - "-e", binary_path, - "-a", "-i", "-f", NULL - }; - struct child_process *a2l =3D zalloc(sizeof(*a2l)); - int start_command_status =3D 0; - - if (a2l =3D=3D NULL) { - pr_err("Failed to allocate memory for addr2line"); - return NULL; - } - - a2l->pid =3D -1; - a2l->in =3D -1; - a2l->out =3D -1; - a2l->no_stderr =3D 1; - - a2l->argv =3D argv; - start_command_status =3D start_command(a2l); - a2l->argv =3D NULL; /* it's not used after start_command; avoid dangling = pointers */ - - if (start_command_status !=3D 0) { - pr_warning("could not start addr2line (%s) for %s: start_command return = code %d\n", - addr2line_path, binary_path, start_command_status); - addr2line_subprocess_cleanup(a2l); - return NULL; - } - - return a2l; -} - -enum a2l_style { - BROKEN, - GNU_BINUTILS, - LLVM, -}; - -static enum a2l_style addr2line_configure(struct child_process *a2l, const= char *dso_name) -{ - static bool cached; - static enum a2l_style style; - - if (!cached) { - char buf[128]; - struct io io; - int ch; - int lines; - - if (write(a2l->in, ",\n", 2) !=3D 2) - return BROKEN; - - io__init(&io, a2l->out, buf, sizeof(buf)); - ch =3D io__get_char(&io); - if (ch =3D=3D ',') { - style =3D LLVM; - cached =3D true; - lines =3D 1; - pr_debug3("Detected LLVM addr2line style\n"); - } else if (ch =3D=3D '0') { - style =3D GNU_BINUTILS; - cached =3D true; - lines =3D 3; - pr_debug3("Detected binutils addr2line style\n"); - } else { - if (!symbol_conf.disable_add2line_warn) { - char *output =3D NULL; - size_t output_len; - - io__getline(&io, &output, &output_len); - pr_warning("%s %s: addr2line configuration failed\n", - __func__, dso_name); - pr_warning("\t%c%s", ch, output); - } - pr_debug("Unknown/broken addr2line style\n"); - return BROKEN; - } - while (lines) { - ch =3D io__get_char(&io); - if (ch <=3D 0) - break; - if (ch =3D=3D '\n') - lines--; - } - /* Ignore SIGPIPE in the event addr2line exits. */ - signal(SIGPIPE, SIG_IGN); - } - return style; -} - -static int read_addr2line_record(struct io *io, - enum a2l_style style, - const char *dso_name, - u64 addr, - bool first, - char **function, - char **filename, - unsigned int *line_nr) -{ - /* - * Returns: - * -1 =3D=3D> error - * 0 =3D=3D> sentinel (or other ill-formed) record read - * 1 =3D=3D> a genuine record read - */ - char *line =3D NULL; - size_t line_len =3D 0; - unsigned int dummy_line_nr =3D 0; - int ret =3D -1; - - if (function !=3D NULL) - zfree(function); - - if (filename !=3D NULL) - zfree(filename); - - if (line_nr !=3D NULL) - *line_nr =3D 0; - - /* - * Read the first line. Without an error this will be: - * - for the first line an address like 0x1234, - * - the binutils sentinel 0x0000000000000000, - * - the llvm-addr2line the sentinel ',' character, - * - the function name line for an inlined function. - */ - if (io__getline(io, &line, &line_len) < 0 || !line_len) - goto error; - - pr_debug3("%s %s: addr2line read address for sentinel: %s", __func__, dso= _name, line); - if (style =3D=3D LLVM && line_len =3D=3D 2 && line[0] =3D=3D ',') { - /* Found the llvm-addr2line sentinel character. */ - zfree(&line); - return 0; - } else if (style =3D=3D GNU_BINUTILS && (!first || addr !=3D 0)) { - int zero_count =3D 0, non_zero_count =3D 0; - /* - * Check for binutils sentinel ignoring it for the case the - * requested address is 0. - */ - - /* A given address should always start 0x. */ - if (line_len >=3D 2 || line[0] !=3D '0' || line[1] !=3D 'x') { - for (size_t i =3D 2; i < line_len; i++) { - if (line[i] =3D=3D '0') - zero_count++; - else if (line[i] !=3D '\n') - non_zero_count++; - } - if (!non_zero_count) { - int ch; - - if (first && !zero_count) { - /* Line was erroneous just '0x'. */ - goto error; - } - /* - * Line was 0x0..0, the sentinel for binutils. Remove - * the function and filename lines. - */ - zfree(&line); - do { - ch =3D io__get_char(io); - } while (ch > 0 && ch !=3D '\n'); - do { - ch =3D io__get_char(io); - } while (ch > 0 && ch !=3D '\n'); - return 0; - } - } - } - /* Read the second function name line (if inline data then this is the fi= rst line). */ - if (first && (io__getline(io, &line, &line_len) < 0 || !line_len)) - goto error; - - pr_debug3("%s %s: addr2line read line: %s", __func__, dso_name, line); - if (function !=3D NULL) - *function =3D strdup(strim(line)); - - zfree(&line); - line_len =3D 0; - - /* Read the third filename and line number line. */ - if (io__getline(io, &line, &line_len) < 0 || !line_len) - goto error; - - pr_debug3("%s %s: addr2line filename:number : %s", __func__, dso_name, li= ne); - if (filename_split(line, line_nr =3D=3D NULL ? &dummy_line_nr : line_nr) = =3D=3D 0 && - style =3D=3D GNU_BINUTILS) { - ret =3D 0; - goto error; - } - - if (filename !=3D NULL) - *filename =3D strdup(line); - - zfree(&line); - line_len =3D 0; - - return 1; - -error: - free(line); - if (function !=3D NULL) - zfree(function); - if (filename !=3D NULL) - zfree(filename); - return ret; -} - -static int inline_list__append_record(struct dso *dso, - struct inline_node *node, - struct symbol *sym, - const char *function, - const char *filename, - unsigned int line_nr) -{ - struct symbol *inline_sym =3D new_inline_sym(dso, sym, function); - - return inline_list__append(inline_sym, srcline_from_fileline(filename, li= ne_nr), node); -} - -static int addr2line(const char *dso_name, u64 addr, - char **file, unsigned int *line_nr, - struct dso *dso, - bool unwind_inlines, - struct inline_node *node, - struct symbol *sym __maybe_unused) -{ - struct child_process *a2l =3D dso__a2l(dso); - char *record_function =3D NULL; - char *record_filename =3D NULL; - unsigned int record_line_nr =3D 0; - int record_status =3D -1; - int ret =3D 0; - size_t inline_count =3D 0; - int len; - char buf[128]; - ssize_t written; - struct io io =3D { .eof =3D false }; - enum a2l_style a2l_style; - - if (!a2l) { - if (!filename__has_section(dso_name, ".debug_line")) - goto out; - - dso__set_a2l(dso, - addr2line_subprocess_init(symbol_conf.addr2line_path, dso_name)); - a2l =3D dso__a2l(dso); - } - - if (a2l =3D=3D NULL) { - if (!symbol_conf.disable_add2line_warn) - pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_n= ame); - goto out; - } - a2l_style =3D addr2line_configure(a2l, dso_name); - if (a2l_style =3D=3D BROKEN) - goto out; - - /* - * Send our request and then *deliberately* send something that can't be - * interpreted as a valid address to ask addr2line about (namely, - * ","). This causes addr2line to first write out the answer to our - * request, in an unbounded/unknown number of records, and then to write - * out the lines "0x0...0", "??" and "??:0", for GNU binutils, or "," - * for llvm-addr2line, so that we can detect when it has finished giving - * us anything useful. - */ - len =3D snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr); - written =3D len > 0 ? write(a2l->in, buf, len) : -1; - if (written !=3D len) { - if (!symbol_conf.disable_add2line_warn) - pr_warning("%s %s: could not send request\n", __func__, dso_name); - goto out; - } - io__init(&io, a2l->out, buf, sizeof(buf)); - io.timeout_ms =3D addr2line_timeout_ms; - switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=3D*= /true, - &record_function, &record_filename, &record_line_nr)) { - case -1: - if (!symbol_conf.disable_add2line_warn) - pr_warning("%s %s: could not read first record\n", __func__, dso_name); - goto out; - case 0: - /* - * The first record was invalid, so return failure, but first - * read another record, since we sent a sentinel ',' for the - * sake of detected the last inlined function. Treat this as the - * first of a record as the ',' generates a new start with GNU - * binutils, also force a non-zero address as we're no longer - * reading that record. - */ - switch (read_addr2line_record(&io, a2l_style, dso_name, - /*addr=3D*/1, /*first=3D*/true, - NULL, NULL, NULL)) { - case -1: - if (!symbol_conf.disable_add2line_warn) - pr_warning("%s %s: could not read sentinel record\n", - __func__, dso_name); - break; - case 0: - /* The sentinel as expected. */ - break; - default: - if (!symbol_conf.disable_add2line_warn) - pr_warning("%s %s: unexpected record instead of sentinel", - __func__, dso_name); - break; - } - goto out; - default: - /* First record as expected. */ - break; - } - - if (file) { - *file =3D strdup(record_filename); - ret =3D 1; - } - if (line_nr) - *line_nr =3D record_line_nr; - - if (unwind_inlines) { - if (node && inline_list__append_record(dso, node, sym, - record_function, - record_filename, - record_line_nr)) { - ret =3D 0; - goto out; - } - } - - /* - * We have to read the records even if we don't care about the inline - * info. This isn't the first record and force the address to non-zero - * as we're reading records beyond the first. - */ - while ((record_status =3D read_addr2line_record(&io, - a2l_style, - dso_name, - /*addr=3D*/1, - /*first=3D*/false, - &record_function, - &record_filename, - &record_line_nr)) =3D=3D 1) { - if (unwind_inlines && node && inline_count++ < MAX_INLINE_NEST) { - if (inline_list__append_record(dso, node, sym, - record_function, - record_filename, - record_line_nr)) { - ret =3D 0; - goto out; - } - ret =3D 1; /* found at least one inline frame */ - } - } - -out: - free(record_function); - free(record_filename); - if (io.eof) { - dso__set_a2l(dso, NULL); - addr2line_subprocess_cleanup(a2l); - } - return ret; -} - -void dso__free_a2l(struct dso *dso) -{ - struct child_process *a2l =3D dso__a2l(dso); + int ret; =20 - if (!a2l) - return; + ret =3D llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inline= s, node, sym); + if (ret > 0) + return ret; =20 - addr2line_subprocess_cleanup(a2l); + ret =3D libbfd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inli= nes, node, sym); + if (ret > 0) + return ret; =20 - dso__set_a2l(dso, NULL); + return cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines,= node, sym); } =20 -#endif /* HAVE_LIBBFD_SUPPORT */ - static struct inline_node *addr2inlines(const char *dso_name, u64 addr, struct dso *dso, struct symbol *sym) { @@ -595,7 +145,9 @@ static struct inline_node *addr2inlines(const char *dso= _name, u64 addr, INIT_LIST_HEAD(&node->val); node->addr =3D addr; =20 - addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); + addr2line(dso_name, addr, /*file=3D*/NULL, /*line_nr=3D*/NULL, dso, + /*unwind_inlines=3D*/true, node, sym); + return node; } =20 @@ -622,7 +174,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct s= ymbol *sym, goto out_err; =20 if (!addr2line(dso_name, addr, &file, &line, dso, - unwind_inlines, NULL, sym)) + unwind_inlines, /*node=3D*/NULL, sym)) goto out_err; =20 srcline =3D srcline_from_fileline(file, line); @@ -668,7 +220,8 @@ char *get_srcline_split(struct dso *dso, u64 addr, unsi= gned *line) if (dso_name =3D=3D NULL) goto out_err; =20 - if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL)) + if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=3D*/tru= e, + /*node=3D*/NULL, /*sym=3D*/NULL)) goto out_err; =20 dso__set_a2l_fails(dso, 0); diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h index 6e66ddbcc879..c36f573cd339 100644 --- a/tools/perf/util/srcline.h +++ b/tools/perf/util/srcline.h @@ -9,7 +9,6 @@ struct dso; struct symbol; =20 -extern int addr2line_timeout_ms; extern bool srcline_full_filename; char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym, bool show_sym, bool show_addr, u64 ip); --=20 2.51.0.570.gb178f27e6d-goog From nobody Thu Oct 2 00:49:22 2025 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5BFE42BCF45 for ; Mon, 29 Sep 2025 19:09:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172966; cv=none; b=kDpvwJjTmaJ/FTAUoozY6n5bbhTAJne348BzL+dyHlNT/uDmjaMkbbpZmeUePLWWWOWOJy0pqhPF62ZcP3kd6jfadxh+1KBzD8/4+ODXJNTRbAh8xVY1VkTFnD9IL2ElXL32a5iQTwO4n3SAGcfHIgvlOMadcsBSEMO52YZwq0Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1759172966; c=relaxed/simple; bh=AdUfJ3+HbRhbK7PtlXvfEfALYxdhT7u77r7aSN4uwZk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=J13YBJZriCfO96nhCUCDB084qud11lmmNyl+JU6ymlFfEgnYATHjZNsiSE0JLd3QUfKTDJKR+qy8OCy6Onag3TZc+6Bixv1y42LUbukKW45euoglXSqi2ZOwne6MFvMEYCoeJt+APdECfN+WPW1wGR+4NAyNj2a8Oaoc5fBFx/M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=L9yQeoMo; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="L9yQeoMo" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-28d1747f23bso6456075ad.3 for ; Mon, 29 Sep 2025 12:09:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1759172964; x=1759777764; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=4971M/0zABDO+i83fcQEQWVemuah1MT0Et0WsfrEZzk=; b=L9yQeoMoPkXg5d5lT2D7Ra4n++RDy2SE9MSuD1eTVbKyNZt8WSLkEloIFCzXNqO3cf wgo7N6WOlI3EbhXo5y3QghXVKhaL+Zvz8smMzTX6PYl9BbIVf1GEj4T9C4wjsBNEy4Q1 KlOwLH5/fBorFi9cSI8qqlETXPIa4jpkZ8BNK0uEtWK6NZAVH6EQ+bKbkY9YGqEsyc6E BLs/sdBbGMY+DbRGhMRogroFvjoCF9NtRqAFJi8SLM2GPrX1fIc/hJ4vsLdpOiDW5Wft CCZEQXne39KFIdsPDNuxX8Nvhvcr9ivaFvj2gSVR3Mwpc54sE3l3Kzq5pqKdVIvy3Gzj r7NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1759172964; x=1759777764; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=4971M/0zABDO+i83fcQEQWVemuah1MT0Et0WsfrEZzk=; b=odKJYnKt5ImKVDrK5J/bVDD2WE6hYftGi1POM7+BTGSokw0fGDG3Wlr+vTUPrICS8r pHe5CDSIEHPC8319zDPinAy7IpNErsr0Jc0qbDQZQCnFrBpH74Bip0/NX3G2m8JTxlhw 6ChYkXDLc0KROlalEmY7MebESlu+OxyKqfk+7C+/ldSytqSf74FJAx5soNZX43JL6n2+ ETwp7SUClIV3YOdFUBP11TTXh0FxbOYVjNInSCyVa0fxyrARfAmyLlUjmtrDT4i3Ne7l fxeQwDBJUTc9eoxNQvavVGkpzM5KiLofz+1v3F8R7nGEH9FjQZ+knb9QP2cRo9JsA2m9 Klrw== X-Forwarded-Encrypted: i=1; AJvYcCWgdtM3Wcc24C3g1dvO65QOBSp0dntgNQ+mSv516e3KGPYmSLHRUk/zct2z42To4cr9TiQHHbwHW29XUug=@vger.kernel.org X-Gm-Message-State: AOJu0YxoXylZJkQ5Vz3NjGQtppXVy+d+UzlhocGNfSFrQELaRDar5+by 96i6Vz7SgUnv90QjA0HtHHGGpw/Su5ggbOLbpnsLVnt71jvGF6H0jAu9oBygSapgDicxi9inWZh wDGjmvfY9CQ== X-Google-Smtp-Source: AGHT+IGSCDVx0cLNNfPAO34F5NCMZLpRD91/a9vLPfmnYqOXMggPFusn25YIXzpM5IEFpb7ikaAU0IUITXOR X-Received: from pgar25.prod.google.com ([2002:a05:6a02:2e99:b0:b58:4e62:6f3d]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:acf:b0:274:5030:2906 with SMTP id d9443c01a7336-27ed4ab8df8mr196816435ad.46.1759172963586; Mon, 29 Sep 2025 12:09:23 -0700 (PDT) Date: Mon, 29 Sep 2025 12:08:05 -0700 In-Reply-To: <20250929190805.201446-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250929190805.201446-1-irogers@google.com> X-Mailer: git-send-email 2.51.0.570.gb178f27e6d-goog Message-ID: <20250929190805.201446-16-irogers@google.com> Subject: [PATCH v6 15/15] perf disasm: Remove unused evsel from annotate_args From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , Eric Biggers , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , "Dr. David Alan Gilbert" , Li Huafei , Athira Rajeev , Stephen Brennan , Dmitry Vyukov , Alexandre Ghiti , Haibo Xu , Andi Kleen , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, bpf@vger.kernel.org, llvm@lists.linux.dev, Song Liu Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Set in symbol__annotate but never used. Signed-off-by: Ian Rogers --- tools/perf/util/annotate.c | 1 - tools/perf/util/disasm.h | 1 - 2 files changed, 2 deletions(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index c9b220d9f924..a2e34f149a07 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1015,7 +1015,6 @@ int symbol__annotate(struct map_symbol *ms, struct ev= sel *evsel, struct symbol *sym =3D ms->sym; struct annotation *notes =3D symbol__annotation(sym); struct annotate_args args =3D { - .evsel =3D evsel, .options =3D &annotate_opts, }; struct arch *arch =3D NULL; diff --git a/tools/perf/util/disasm.h b/tools/perf/util/disasm.h index 09c86f540f7f..d2cb555e4a3b 100644 --- a/tools/perf/util/disasm.h +++ b/tools/perf/util/disasm.h @@ -98,7 +98,6 @@ struct ins_ops { struct annotate_args { struct arch *arch; struct map_symbol ms; - struct evsel *evsel; struct annotation_options *options; s64 offset; char *line; --=20 2.51.0.570.gb178f27e6d-goog