From nobody Thu Oct 2 02:12:27 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