From nobody Sun Feb 8 05:28:54 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.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 C7A2C389477 for ; Fri, 30 Jan 2026 23:34:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816087; cv=none; b=pP6ADtyUM/PGZJ/BzyPEnM9c9Y1uxWVwIXOWyZB43P14sPpsLqS/IzU66DL4N9Vhdq+pB08PUd6ZvftwXMlLdzk5b3SrDJNS1F/WYdIrB0Xx78snqR/OkusHnwpXQ7qOZuuaMQY7zV7LCjM91GI/RFvefXmeF9+fDWEAHi5WDWI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816087; c=relaxed/simple; bh=eP+yFNqsM0F+bYwBExXX2CJyNNwIZLp4DSCLVeZFhdU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=kRxxExdy4UuQF+WQSPqM+M4QtPinpiWGhdCfJnd2InyfkBzUaG/uAz9SeXOgNx8a7yb75skEeDhQEV9QGpev/ZEUQJbNIq4ToS47kXBvUHXs7O49e4hUN/rzm66+FOu/hmMDViC5E8G6/6d3xbwFT4UVxjaaQkPBict5+F/NiS0= 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=GROFaqsX; arc=none smtp.client-ip=74.125.82.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="GROFaqsX" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2b795cff830so725525eec.1 for ; Fri, 30 Jan 2026 15:34:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769816085; x=1770420885; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=GQj2Z4SylGf/VCJDURPMv3UALI8c3Pg/YVazRrOkdHk=; b=GROFaqsXJGZKIP2T9r1LGu6Re4bcsRcJ7RnKhyH3Q36HUCS3NwmM5aPYNZz4FmTCXd BsqN1i1jKg1LJOksysINOReRLAKF+u5zhmBEjNJRUOqMvrcf/NKjhgSku/2gaY962lOv /7FwnJYG2QmGNPOGUgKNvHbWl/2UoOSXCZe1CepuOxSx7tMyK+vAILb/8jUGK4oinKp2 ae3IRNm3dFtVwkeSr6bhRiwsCRrdzYMMdPJkD2VrQvVSWugc3GTV9+kuSpMxJvqVUiLL 3hCTTJflzBmoHfR+RpkKhLFON28P2SRrRiJjPmYHkJ3AZKdfuIzDNdGxKaItZEoSUsZx eEyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769816085; x=1770420885; h=cc: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=GQj2Z4SylGf/VCJDURPMv3UALI8c3Pg/YVazRrOkdHk=; b=t2Rehk1BMA7NPokN/tADdHw/ji4254jhNVElblbWzvbxg93iw0YizBaXci1ATJDFGe q4ifcUqSVirAvP8i/gH3LCde6HjdqhtmTNm18OVF4f3LsGdmvbUmyRnc04bzjZ9vXyV+ kslqOdjL72C3+ol9qdLb7//6AUslv3SEvr583LL4ULGTGAayu0UP+QXiCd1oGZeTULf4 5vPtqhO8Op0yGX0hw1zHOPPViMmH9RdpCe1FE1F0mKlex99LW7KHnRhK5AiSy+GHRQEj 8akfTUPfyp1m1eak07p8Pz+dSWuY0h/OaIvwpXRevpm6OslxBN/1YM7sfI4QKJoh0SOS MuTA== X-Forwarded-Encrypted: i=1; AJvYcCVu+BdypthVpoK1qedlKJEAPzqoOzJWU7bIxy6Mrqb7bqqkoHJ81JlGrpfFgqoxfe4vNGgbHitoE5zbO3Q=@vger.kernel.org X-Gm-Message-State: AOJu0YxChidoewTtJ6GWQzRI5UqBVPlGUiyuwtVl4mM4CDdAZ/amaleB c6Ek9jBaFQjFi6rJzPv7irqUvC20/oneLwgB4wNy4vdcD6ypWSjO57IRr3UNDqHnsrnp000Nu4N WEcgf+xMkGg== X-Received: from dybtv10.prod.google.com ([2002:a05:7300:f48a:b0:2b7:9b1b:2ed4]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:7305:b0:2b7:a3a9:9c28 with SMTP id 5a478bee46e88-2b7c88d8c3bmr2541185eec.20.1769816084925; Fri, 30 Jan 2026 15:34:44 -0800 (PST) Date: Fri, 30 Jan 2026 15:34:37 -0800 In-Reply-To: <20260130233439.647447-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: <20260130233439.647447-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.rc1.225.gd81095ad13-goog Message-ID: <20260130233439.647447-2-irogers@google.com> Subject: [PATCH v10 1/3] perf capstone: Support for dlopen-ing libcapstone.so From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , Dmitry Vyukov , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, llvm@lists.linux.dev Cc: Ian Rogers Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" If perf is built with LIBCAPSTONE_DLOPEN=3D1, support dlopen-ing libcapstone.so and then calling the necessary functions by looking them up using dlsym. The types come from capstone.h which means the libcapstone feature check needs to pass, and NO_CAPSTONE=3D1 hasn't been defined. This will cause the definition of HAVE_LIBCAPSTONE_SUPPORT. Earlier versions of this code tried to declare the necessary capstone.h constants and structs, but they weren't stable and caused breakages across libcapstone releases. Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 8 +- tools/perf/tests/make | 2 + tools/perf/util/Build | 2 +- tools/perf/util/capstone.c | 176 +++++++++++++++++++++++++++++-------- tools/perf/util/capstone.h | 33 +++++++ 5 files changed, 179 insertions(+), 42 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 63ca9b2be663..e085d27f698a 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -1078,8 +1078,12 @@ ifndef NO_CAPSTONE $(call feature_check,libcapstone) ifeq ($(feature-libcapstone), 1) CFLAGS +=3D -DHAVE_LIBCAPSTONE_SUPPORT $(LIBCAPSTONE_CFLAGS) - LDFLAGS +=3D $(LICAPSTONE_LDFLAGS) - EXTLIBS +=3D -lcapstone + ifdef LIBCAPSTONE_DLOPEN + CFLAGS +=3D -DLIBCAPSTONE_DLOPEN + else + LDFLAGS +=3D $(LIBCAPSTONE_LDFLAGS) + EXTLIBS +=3D -lcapstone + endif $(call detected,CONFIG_LIBCAPSTONE) else msg :=3D $(warning No libcapstone found, disables disasm engine suppor= t for 'perf script', please install libcapstone-dev/capstone-devel); diff --git a/tools/perf/tests/make b/tools/perf/tests/make index 767ad9e147a8..f15096074d57 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -85,6 +85,7 @@ make_no_libdw :=3D NO_LIBDW=3D1 make_libunwind :=3D LIBUNWIND=3D1 make_no_backtrace :=3D NO_BACKTRACE=3D1 make_no_libcapstone :=3D NO_CAPSTONE=3D1 +make_libcapstone_dlopen :=3D LIBCAPSTONE_DLOPEN=3D1 make_no_libnuma :=3D NO_LIBNUMA=3D1 make_no_libbionic :=3D NO_LIBBIONIC=3D1 make_no_libbpf :=3D NO_LIBBPF=3D1 @@ -159,6 +160,7 @@ run +=3D make_libunwind run +=3D make_no_libdw_dwarf_unwind run +=3D make_no_backtrace run +=3D make_no_libcapstone +run +=3D make_libcapstone_dlopen run +=3D make_no_libnuma run +=3D make_no_libbionic run +=3D make_no_libbpf diff --git a/tools/perf/util/Build b/tools/perf/util/Build index b9925c6902ca..c037b1e99d28 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -11,7 +11,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-$(CONFIG_LIBCAPSTONE) +=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 index 9216916f848f..25cf6e15ec27 100644 --- a/tools/perf/util/capstone.c +++ b/tools/perf/util/capstone.c @@ -11,20 +11,137 @@ #include "print_insn.h" #include "symbol.h" #include "thread.h" +#include #include #include +#include #include =20 -#ifdef HAVE_LIBCAPSTONE_SUPPORT #include + +#ifdef LIBCAPSTONE_DLOPEN +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) +{ +#ifndef LIBCAPSTONE_DLOPEN + 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) +{ +#ifndef LIBCAPSTONE_DLOPEN + 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) +{ +#ifndef LIBCAPSTONE_DLOPEN + 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 +} + +static void perf_cs_free(struct cs_insn *insn, size_t count) +{ +#ifndef LIBCAPSTONE_DLOPEN + 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) +{ +#ifndef LIBCAPSTONE_DLOPEN + 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 +} =20 -#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; + enum cs_arch arch; + enum cs_mode mode; =20 if (machine__is(machine, "x86_64") && is64) { arch =3D CS_ARCH_X86; @@ -45,7 +162,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; } @@ -57,27 +174,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 && @@ -95,7 +210,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, @@ -106,9 +220,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; @@ -118,7 +231,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); @@ -126,20 +239,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; @@ -154,7 +263,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) @@ -195,9 +304,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; @@ -214,13 +321,11 @@ static int find_file_offset(u64 start, u64 len, u64 p= goff, void *arg) } return 0; } -#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; struct dso *dso =3D map__dso(map); @@ -235,7 +340,7 @@ int symbol__disassemble_capstone(const char *filename _= _maybe_unused, const u8 *buf; u64 buf_len; 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; @@ -274,7 +379,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, buf_len, start, buf_len, = &insn); + 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 @@ -313,9 +418,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(code_buf); return count < 0 ? count : 0; @@ -335,16 +440,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); @@ -458,7 +559,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 @@ -467,7 +568,4 @@ int symbol__disassemble_capstone_powerpc(const char *fi= lename __maybe_unused, 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 index 0f030ea034b6..7c0baaa01a73 100644 --- a/tools/perf/util/capstone.h +++ b/tools/perf/util/capstone.h @@ -6,6 +6,7 @@ #include #include #include +#include #include =20 struct annotate_args; @@ -13,6 +14,7 @@ struct machine; struct symbol; struct thread; =20 +#ifdef HAVE_LIBCAPSTONE_SUPPORT 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); @@ -21,4 +23,35 @@ int symbol__disassemble_capstone(const char *filename, s= truct symbol *sym, int symbol__disassemble_capstone_powerpc(const char *filename, struct symb= ol *sym, struct annotate_args *args); =20 +#else /* !HAVE_LIBCAPSTONE_SUPPORT */ +static inline 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) +{ + return -1; +} + +static inline int symbol__disassemble_capstone(const char *filename __mayb= e_unused, + struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ + return -1; +} + +static inline int symbol__disassemble_capstone_powerpc(const char *filenam= e __maybe_unused, + struct symbol *sym __maybe_unused, + struct annotate_args *args __maybe_unused) +{ + return -1; +} + +#endif /* HAVE_LIBCAPSTONE_SUPPORT */ + #endif /* __PERF_CAPSTONE_H */ --=20 2.53.0.rc1.225.gd81095ad13-goog From nobody Sun Feb 8 05:28:54 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.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 8FB1A3876D3 for ; Fri, 30 Jan 2026 23:34:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816089; cv=none; b=bOmOFaV7oW112leDfng1QnQ98ciZbttS50FcFCM3dPCEtNc4Bwvbuj69JsK0EergWT3IMK+UEOkwU8/drOEM7Zte8er/5QCHnw9vnHx8vGm2no4qP1bViPQXkIGai/M6FqSaquDw3SUAkSZQjyIgIZXOcoYCgpSnGlYlbUn6lEk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816089; c=relaxed/simple; bh=PD1Cp56EN64JKlk9iiQd5fQsXh70dciaHqdrY43pM0Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=WIJoA7DzuzwgWSQ7ALKACtVLHH8mI4pR4+PPO3fWeGL1blVmQ8pqDuh6pXbfI7k6yb7aJVCSvYR1cHuK7+isksKxcxvrr/oy8M7LuWRg0JuFHPfWuOvy57KcpYo8Lcye4710MzS/QbZym9T446ZdUaSUXFKe8/4/kAjGdar1sR0= 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=NGHQNj3l; arc=none smtp.client-ip=74.125.82.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="NGHQNj3l" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-1247bb4db53so4365572c88.1 for ; Fri, 30 Jan 2026 15:34:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769816087; x=1770420887; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=h+Zg5DQouSrItplvApzInVUF75CnQHup5ZALsp9Yawo=; b=NGHQNj3losSgK6k3XCEWUjTjD8/pkg/w0CoBpwZiUw6X8S37mgAJVfoMD3znsqD9In 8MOSL2R9Ho2A5oXy3PIdEFgBI+ZixqOfgsmiQO0mgloqbwGv1pZqJWFXKlpbIbm6ZhQS swm0N4GvSIQsMlgMRmhmxjFl0U02Q4B/KnIy+Jvh/f1hlyJnocMpbe++EOLS25EbSGew Pu/MD83RG4IbsghBkSF9j3KJz3JPueUK+fwmDuG9YwiBBLYYHbIVgLgz85OsVeXevLKi oJFeGJCAPEUJr9NH0nPSN6yygn8Vz0drYPctc5Hfyvw1kDLl62p4dq0zp53xdgdjT25H E+nQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769816087; x=1770420887; h=cc: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=h+Zg5DQouSrItplvApzInVUF75CnQHup5ZALsp9Yawo=; b=OkBrj2hbZlx9sf5Cu01FQNSZjPzVBNKkQUmanP243sSqGqIsR7aqYiQLI50EK7v8pf rriEfR8TBEllXVsfovRguM6OGYzmUZbJcvqZ8NND6OXBp9jTs1o1KDnvcQ+63EC9Cw94 34I5lCJXAV7oQZck9BPq7IzjOAHDersgb6SQ5Oa3T4M8nWGQ3YHJ+9pklNEXxZDZ5CRD sO8x7rlBk/t8xwMcHaSNiq5fgkRMmE/CW7sV3VBNQSaV3YNwbIyynY5Qtpu/GPbgCVSV 7a0NbKapAwlBkChKQGi2aC7zu4fzaJ8Iwbp/SWqqdj1newQ9UcdTqfr5pU+DjdVkT5vE rMdw== X-Forwarded-Encrypted: i=1; AJvYcCXCPYiR+nJKdrQa9iUEMzIpE3YMCBl7Ksc4se1Q228trjR3HZFId+Ge9zEa8xudEMmWgD8HrD3pJ0E/WFI=@vger.kernel.org X-Gm-Message-State: AOJu0Yw6TPCJOqW33X2ZH57nUxA4qtk9nBUTINzCxLTYo4xj3/Od0nGv 3DbqIItkMQcIiqztegcWjoRnIjpsfMPifDX6/HgIEd/zFfZWBDIY/3hA3v9ioDfrPiyrO1RVKOm I0RFDM+4xnA== X-Received: from dldnz6.prod.google.com ([2002:a05:701a:ca06:b0:11f:3484:4f15]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:e1f:b0:11e:3e9:3e8c with SMTP id a92af1059eb24-125c101b3demr2608005c88.49.1769816086716; Fri, 30 Jan 2026 15:34:46 -0800 (PST) Date: Fri, 30 Jan 2026 15:34:38 -0800 In-Reply-To: <20260130233439.647447-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: <20260130233439.647447-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.rc1.225.gd81095ad13-goog Message-ID: <20260130233439.647447-3-irogers@google.com> Subject: [PATCH v10 2/3] perf llvm: Support for dlopen-ing libLLVM.so From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , Dmitry Vyukov , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, llvm@lists.linux.dev Cc: Ian Rogers 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 by default don't support its use if HAVE_LIBLLVM_SUPPORT isn't present. Add a new build option LIBLLVM_DYNAMIC=3D1 that builds a separate shared object called libperf-llvm.so containing the LLVM addr2line functionality and support dynamic loading of it. 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 | 273 +++++++++++++++++++++++++---- 6 files changed, 388 insertions(+), 38 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index e085d27f698a..00292aca5e84 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -964,6 +964,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 b6edc8100c8e..525025af1530 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -422,6 +422,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 @@ -989,6 +995,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)' @@ -1090,6 +1106,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)' @@ -1292,7 +1313,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= \ 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 f15096074d57..849eb2a4e3d5 100644 --- a/tools/perf/tests/make +++ b/tools/perf/tests/make @@ -92,6 +92,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 @@ -166,6 +167,7 @@ run +=3D make_no_libbionic 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 c037b1e99d28..eab452ca52ed 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -29,6 +29,7 @@ perf-util-y +=3D find_bit.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 @@ -249,7 +250,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 0d126d233c01..b4c6c15fd2dc 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,18 +8,244 @@ #include "namespaces.h" #include "srcline.h" #include "symbol.h" +#include #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) { @@ -30,14 +257,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); @@ -65,20 +290,16 @@ int llvm__addr2line(const char *dso_name __maybe_unuse= d, u64 addr __maybe_unused free_llvm_inline_frames(inline_frames, num_frames); =20 return num_frames; -#else - return -1; -#endif } =20 -#ifdef HAVE_LIBLLVM_SUPPORT static void init_llvm(void) { static bool init; =20 if (!init) { - LLVMInitializeAllTargetInfos(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllDisassemblers(); + perf_LLVMInitializeAllTargetInfos(); + perf_LLVMInitializeAllTargetMCs(); + perf_LLVMInitializeAllDisassemblers(); init =3D true; } } @@ -111,12 +332,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); @@ -149,15 +368,15 @@ int symbol__disassemble_llvm(const char *filename, st= ruct symbol *sym, if (arch__is_x86(args->arch)) { const char *triplet =3D is_64bit ? "x86_64-pc-linux" : "i686-pc-linux"; =20 - disasm =3D LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, - /*get_op_info=3D*/NULL, symbol_lookup_callback); + disasm =3D perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, + /*get_op_info=3D*/NULL, symbol_lookup_callback); } else { char triplet[64]; =20 scnprintf(triplet, sizeof(triplet), "%s-linux-gnu", args->arch->name); - disasm =3D LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, - /*get_op_info=3D*/NULL, symbol_lookup_callback); + disasm =3D perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=3D*/0, + /*get_op_info=3D*/NULL, symbol_lookup_callback); } =20 if (disasm =3D=3D NULL) @@ -165,8 +384,7 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, =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; @@ -174,7 +392,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>:", @@ -203,9 +421,9 @@ int symbol__disassemble_llvm(const char *filename, stru= ct symbol *sym, * 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 LLVMDisasmInstruction(disasm, (u8 *)(buf + offset), - buf_len - offset, pc, - disasm_buf, sizeof(disasm_buf)); + 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; disasm_len =3D strlen(disasm_buf); @@ -261,13 +479,8 @@ int symbol__disassemble_llvm(const char *filename, str= uct symbol *sym, ret =3D 0; =20 err: - LLVMDisasmDispose(disasm); + perf_LLVMDisasmDispose(disasm); free(code_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.53.0.rc1.225.gd81095ad13-goog From nobody Sun Feb 8 05:28:54 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.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 9D754389DE8 for ; Fri, 30 Jan 2026 23:34:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816091; cv=none; b=HavCKDuhDRv+ovWeOisIw2Iu5qRja6nR12vGnDNErZnEjx4skxTwAmv5eEeGLlbRgP1S+DyBBf3H996EYfhdYBm9XLUEG4SXCqhcoCcwX9fMoukhMV5uCNZtDm85ngvBddWgEI71plw2DQI0+MJvpn6WdNBgLdJkiGNDXUVh4xY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769816091; c=relaxed/simple; bh=f3IwAF4xFUnZiQ0qPUpCQZ3A9awCCpK1Sq8wBjN9MYU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=qToS19zv3TXRAOSTaMKahkS4x7RbO4VpQiJHKAimULYQJCPsA4i0CdzWOZKcPaKyFejU7KgNHlxAXwIs3Yay4OMVjv47vnPuw3w48qVGxwRcdxQV/z0STh0bfXGl+2TrNJCGrzY+Cf/Tjvi8jtog43rT5NNEZB/4a1L8A/kXpCM= 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=BDg1BLd1; arc=none smtp.client-ip=74.125.82.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="BDg1BLd1" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2b74766fae7so3261733eec.0 for ; Fri, 30 Jan 2026 15:34:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769816089; x=1770420889; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=5WXtY1sGpzNmP+KMWAj1QK4gOAMZ7b1jw8oU2SjTVnA=; b=BDg1BLd1C/7iL7/JZuQwnTZ4/y1Plvko0jOxpi/D+pxEqYkOaDVFEzvIIvIGY8bOWy tgweH/zpKwVTpuJSCnvkUn+nnFIAyXzjbu1mK5kVbIZnHSIT6ybFcPk6bbHVft/tM5zZ lIvYfyaU5DR8Iqrpi0PGNEUHbIyMqGRQysYev5i/st9AZeZMLjw3Zeb5ZBiPRW5CU8IP sGrbwzGgpTF8VOyY0FpFcs+X6TC48/MA/CfLrA1YFQ0Ea4/frHScb+VbCPag/7fVKDSG DXXRFRFA6GRUAr2ZNMnu8FV5ZynoIGyOmeoL+8LJIAzkIQ3Q1kGSNEppnSieIUdLa/0G v30g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769816089; x=1770420889; h=cc: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=5WXtY1sGpzNmP+KMWAj1QK4gOAMZ7b1jw8oU2SjTVnA=; b=pmBnX7S7FHpJEMwoZ2H7bXwis4ShIvvM5cY6i0xWo5jqiHxtucvUueG8JGJqkzSo2E XxxWNFwTOGyVi1JIoaiSTICXEAL6sxWaPwu86DzqbMHdwbyyJEBmx6udqRHJpRNM0oOp BR794QINZtO+RQYe40DCXsmxKIUWO76yN/dquvzYTMmjNju3bI/AbA+7K9vNjD5pkg8W wzkaGm3PJFJ2ODilfDKxdrV///WGqAv9Ki+mh+PZpO/I8RELUc+IxuCfUIxDsh2FMGSZ sC1zYd8H2H9xz2uXGEE2t8j1UcXztIrmxbQTAl7bBEeKvl3yhiyYRGKuzeEmc+sXyVAJ M31g== X-Forwarded-Encrypted: i=1; AJvYcCWK21cccivy2DyjwYtG+oHTWBbLcIY9q/Eaw3Hro/9OB6GCNZzV+t4wvzejcgsbZwlTLdpPdJRfS3xVFU4=@vger.kernel.org X-Gm-Message-State: AOJu0Yxv0CwyJZM5RVl6+R9KrGAlUN2eZGPi6EpM4FNPKnTwsIB35MHg Rh/v6DcMitIWn/QfXP4IiQoNurVIa9LQHxAMsiA9aoYhmmNWnSG3MkmobqABrHHBLJL6d+RUO8w fKcZv6y1P8w== X-Received: from dysc40.prod.google.com ([2002:a05:7300:3b28:b0:2b6:b71d:d4f0]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:fb83:b0:2a4:3594:72d7 with SMTP id 5a478bee46e88-2b7c863a245mr2711669eec.6.1769816088831; Fri, 30 Jan 2026 15:34:48 -0800 (PST) Date: Fri, 30 Jan 2026 15:34:39 -0800 In-Reply-To: <20260130233439.647447-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: <20260130233439.647447-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.rc1.225.gd81095ad13-goog Message-ID: <20260130233439.647447-4-irogers@google.com> Subject: [PATCH v10 3/3] perf llvm: Mangle libperf-llvm.so function names From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Adrian Hunter , Nathan Chancellor , Nick Desaulniers , Bill Wendling , Justin Stitt , Charlie Jenkins , "Masami Hiramatsu (Google)" , James Clark , Collin Funk , Dmitry Vyukov , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, llvm@lists.linux.dev Cc: Ian Rogers 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 525025af1530..5b634efbead0 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -996,7 +996,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.53.0.rc1.225.gd81095ad13-goog