* [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO
@ 2025-04-17 23:07 Ian Rogers
2025-04-17 23:07 ` [PATCH v4 01/19] perf build: Remove libtracefs configuration Ian Rogers
` (19 more replies)
0 siblings, 20 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
Linking against libcapstone and libLLVM can be a significant increase
in dependencies and file size if building statically. For something
like `perf record` the disassembler and addr2line functionality won't
be used. Support dynamically loading these libraries using dlopen and
then calling the appropriate functions found using dlsym.
BUILD_NONDISTRO is used to build perf against the license incompatible
libbfd and libiberty libraries. As this has been opt-in for nearly 2
years, commit dd317df07207 ("perf build: Make binutil libraries opt
in"), remove the code to simplify the code base.
The patch series:
1) does some initial clean up;
2) moves the capstone and LLVM code to their own C files,
3) simplifies a little the capstone code;
4) adds perf_ variants of the functions that will either directly call
the function or use dlsym to discover it;
5) adds BPF JIT disassembly support to LLVM and capstone disassembly;
6) removes the BUILD_NONDISTRO code, reduces scope and removes what's possible;
7) adds fallback to srcline's addr2line so that llvm_addr2line is
tried first and then the forked command tried next, moving the code
for forking out of the main srcline.c file in the process.
The addr2line LLVM functionality is written in C++. To avoid linking
against libLLVM for this, a new LIBLLVM_DYNAMIC option is added where
the C++ code with the libLLVM dependency will be built into a
libperf-llvm.so and that dlsym-ed and called against. Ideally LLVM
would extend their C API to avoid this.
The libbfd BPF disassembly supported source lines, this wasn't ported
to the capstone and LLVM disassembly.
v4: Rebase and addition of a patch removing an unused struct variable.
v3: Add srcline addr2line fallback trying LLVM first then forking a
process. This came up in conversation with Steinar Gunderson
<sesse@google.com>.
Tweak the cover letter message to try to address Andi Kleen's
<ak@linux.intel.com> feedback that the series doesn't really
achieve anything.
v2: Add mangling of the function names in libperf-llvm.so to avoid
potential infinite recursion. Add BPF JIT disassembly support to
LLVM and capstone. Add/rebase the BUILD_NONDISTRO cleanup onto the
series from:
https://lore.kernel.org/lkml/20250111202851.1075338-1-irogers@google.com/
Some other minor additional clean up.
Ian Rogers (19):
perf build: Remove libtracefs configuration
perf map: Constify objdump offset/address conversion APIs
perf capstone: Move capstone functionality into its own file
perf llvm: Move llvm functionality into its own file
perf capstone: Remove open_capstone_handle
perf capstone: Support for dlopen-ing libcapstone.so
perf llvm: Support for dlopen-ing libLLVM.so
perf llvm: Mangle libperf-llvm.so function names
perf dso: Move read_symbol from llvm/capstone to dso
perf dso: Support BPF programs in dso__read_symbol
perf llvm: Disassemble cleanup
perf dso: Clean up read_symbol error handling
perf build: Remove libbfd support
perf build: Remove libiberty support
perf build: Remove unused defines
perf disasm: Remove disasm_bpf
perf disasm: Make ins__scnprintf and ins__is_nop static
perf srcline: Fallback between addr2line implementations
perf disasm: Remove unused evsel from annotate_args
tools/perf/Documentation/perf-check.txt | 1 -
tools/perf/Makefile.config | 90 +--
tools/perf/Makefile.perf | 35 +-
tools/perf/builtin-check.c | 1 -
tools/perf/builtin-script.c | 2 -
tools/perf/tests/Build | 1 -
tools/perf/tests/builtin-test.c | 1 -
tools/perf/tests/make | 4 +-
tools/perf/tests/pe-file-parsing.c | 101 ----
tools/perf/tests/tests.h | 1 -
tools/perf/util/Build | 6 +-
tools/perf/util/addr2line.c | 439 ++++++++++++++
tools/perf/util/addr2line.h | 20 +
tools/perf/util/annotate.c | 1 -
tools/perf/util/annotate.h | 1 -
tools/perf/util/capstone.c | 682 +++++++++++++++++++++
tools/perf/util/capstone.h | 24 +
tools/perf/util/config.c | 2 +-
tools/perf/util/demangle-cxx.cpp | 22 +-
tools/perf/util/disasm.c | 628 +------------------
tools/perf/util/disasm.h | 6 +-
tools/perf/util/disasm_bpf.c | 195 ------
tools/perf/util/disasm_bpf.h | 12 -
tools/perf/util/dso.c | 98 +++
tools/perf/util/dso.h | 4 +
tools/perf/util/llvm-c-helpers.cpp | 120 +++-
tools/perf/util/llvm-c-helpers.h | 24 +-
tools/perf/util/llvm.c | 484 +++++++++++++++
tools/perf/util/llvm.h | 21 +
tools/perf/util/map.c | 19 +-
tools/perf/util/map.h | 6 +-
tools/perf/util/print_insn.c | 117 +---
tools/perf/util/srcline.c | 772 +-----------------------
tools/perf/util/srcline.h | 7 +-
tools/perf/util/symbol-elf.c | 95 ---
tools/perf/util/symbol.c | 135 -----
tools/perf/util/symbol.h | 4 -
37 files changed, 2020 insertions(+), 2161 deletions(-)
delete mode 100644 tools/perf/tests/pe-file-parsing.c
create mode 100644 tools/perf/util/addr2line.c
create mode 100644 tools/perf/util/addr2line.h
create mode 100644 tools/perf/util/capstone.c
create mode 100644 tools/perf/util/capstone.h
delete mode 100644 tools/perf/util/disasm_bpf.c
delete mode 100644 tools/perf/util/disasm_bpf.h
create mode 100644 tools/perf/util/llvm.c
create mode 100644 tools/perf/util/llvm.h
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply [flat|nested] 28+ messages in thread
* [PATCH v4 01/19] perf build: Remove libtracefs configuration
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 02/19] perf map: Constify objdump offset/address conversion APIs Ian Rogers
` (18 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
libtracefs isn't used by perf but not having it installed causes build
warnings. Given the library isn't used, there is no need for the
configuration or warnings so remove.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 14 --------------
1 file changed, 14 deletions(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 9f08a6e96b35..f31b240cd23e 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -1176,20 +1176,6 @@ ifneq ($(NO_LIBTRACEEVENT),1)
else
$(error ERROR: libtraceevent is missing. Please install libtraceevent-dev/libtraceevent-devel and/or set LIBTRACEEVENT_DIR or build with NO_LIBTRACEEVENT=1)
endif
-
- ifeq ($(feature-libtracefs), 1)
- CFLAGS += $(shell $(PKG_CONFIG) --cflags libtracefs)
- LDFLAGS += $(shell $(PKG_CONFIG) --libs-only-L libtracefs)
- EXTLIBS += $(shell $(PKG_CONFIG) --libs-only-l libtracefs)
- LIBTRACEFS_VERSION := $(shell $(PKG_CONFIG) --modversion libtracefs).0.0
- LIBTRACEFS_VERSION_1 := $(word 1, $(subst ., ,$(LIBTRACEFS_VERSION)))
- LIBTRACEFS_VERSION_2 := $(word 2, $(subst ., ,$(LIBTRACEFS_VERSION)))
- LIBTRACEFS_VERSION_3 := $(word 3, $(subst ., ,$(LIBTRACEFS_VERSION)))
- LIBTRACEFS_VERSION_CPP := $(shell expr $(LIBTRACEFS_VERSION_1) \* 255 \* 255 + $(LIBTRACEFS_VERSION_2) \* 255 + $(LIBTRACEFS_VERSION_3))
- CFLAGS += -DLIBTRACEFS_VERSION=$(LIBTRACEFS_VERSION_CPP)
- else
- $(warning libtracefs is missing. Please install libtracefs-dev/libtracefs-devel)
- endif
endif
# Among the variables below, these:
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 02/19] perf map: Constify objdump offset/address conversion APIs
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
2025-04-17 23:07 ` [PATCH v4 01/19] perf build: Remove libtracefs configuration Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 03/19] perf capstone: Move capstone functionality into its own file Ian Rogers
` (17 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 d729438b7d65..a22a423792d7 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -514,6 +514,8 @@ void srccode_state_free(struct srccode_state *state)
state->line = 0;
}
+static const struct kmap *__map__const_kmap(const struct map *map);
+
/**
* map__rip_2objdump - convert symbol start address to objdump address.
* @map: memory map
@@ -525,9 +527,9 @@ void srccode_state_free(struct srccode_state *state)
*
* Return: Address suitable for passing to "objdump --start-address="
*/
-u64 map__rip_2objdump(struct map *map, u64 rip)
+u64 map__rip_2objdump(const struct map *map, u64 rip)
{
- struct kmap *kmap = __map__kmap(map);
+ const struct kmap *kmap = __map__const_kmap(map);
const struct dso *dso = map__dso(map);
/*
@@ -570,7 +572,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 = map__dso(map);
@@ -587,7 +589,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
}
/* 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 = map__dso(map);
@@ -619,6 +621,15 @@ struct kmap *__map__kmap(struct map *map)
return (struct kmap *)(&RC_CHK_ACCESS(map)[1]);
}
+static const struct kmap *__map__const_kmap(const struct map *map)
+{
+ const struct dso *dso = 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 = __map__kmap(map);
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 4262f5a143be..768501eec70e 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)
}
/* rip/ip <-> addr suitable for passing to `objdump --start-address=` */
-u64 map__rip_2objdump(struct map *map, u64 rip);
+u64 map__rip_2objdump(const struct map *map, u64 rip);
/* objdump address -> memory address */
-u64 map__objdump_2mem(struct map *map, u64 ip);
+u64 map__objdump_2mem(const struct map *map, u64 ip);
/* objdump address -> rip */
-u64 map__objdump_2rip(struct map *map, u64 ip);
+u64 map__objdump_2rip(const struct map *map, u64 ip);
struct symbol;
struct thread;
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 03/19] perf capstone: Move capstone functionality into its own file
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
2025-04-17 23:07 ` [PATCH v4 01/19] perf build: Remove libtracefs configuration Ian Rogers
2025-04-17 23:07 ` [PATCH v4 02/19] perf map: Constify objdump offset/address conversion APIs Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 04/19] perf llvm: Move llvm " Ian Rogers
` (16 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 9b16df881af8..9ae89349947a 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1222,7 +1222,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 = fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->is64bit,
(uint8_t *)inbuf, inlen, ip, lenp,
@@ -1231,7 +1230,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));
}
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 946bce6628f3..1300b42cd748 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -8,6 +8,7 @@ perf-util-y += block-info.o
perf-util-y += block-range.o
perf-util-y += build-id.o
perf-util-y += cacheline.o
+perf-util-y += capstone.o
perf-util-y += config.o
perf-util-y += copyfile.o
perf-util-y += ctype.o
diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
new file mode 100644
index 000000000000..c0a6d94ebc18
--- /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 <fcntl.h>
+#include <string.h>
+
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+#include <capstone/capstone.h>
+#endif
+
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+static 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 = CS_ARCH_X86;
+ mode = CS_MODE_64;
+ } else if (machine__normalized_is(machine, "x86")) {
+ arch = CS_ARCH_X86;
+ mode = CS_MODE_32;
+ } else if (machine__normalized_is(machine, "arm64")) {
+ arch = CS_ARCH_ARM64;
+ mode = CS_MODE_ARM;
+ } else if (machine__normalized_is(machine, "arm")) {
+ arch = CS_ARCH_ARM;
+ mode = CS_MODE_ARM + CS_MODE_V8;
+ } else if (machine__normalized_is(machine, "s390")) {
+ arch = CS_ARCH_SYSZ;
+ mode = CS_MODE_BIG_ENDIAN;
+ } else {
+ return -1;
+ }
+
+ if (cs_open(arch, mode, cs_handle) != 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 *insn,
+ int print_opts, FILE *fp)
+{
+ struct addr_location al;
+ size_t printed = 0;
+
+ if (insn->detail && insn->detail->x86.op_count == 1) {
+ cs_x86_op *op = &insn->detail->x86.operands[0];
+
+ addr_location__init(&al);
+ if (op->type == X86_OP_IMM &&
+ thread__find_symbol(thread, cpumode, op->imm, &al)) {
+ printed += fprintf(fp, "%s ", insn[0].mnemonic);
+ printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
+ if (print_opts & PRINT_INSN_IMM_HEX)
+ printed += fprintf(fp, " [%#" PRIx64 "]", op->imm);
+ addr_location__exit(&al);
+ return printed;
+ }
+ addr_location__exit(&al);
+ }
+
+ printed += 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 = capstone_init(machine, &cs_handle, is64bit, true);
+ if (ret < 0)
+ return ret;
+
+ count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
+ if (count > 0) {
+ if (machine__normalized_is(machine, "x86"))
+ printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
+ else
+ printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
+ if (lenp)
+ *lenp = insn->size;
+ cs_free(insn, count);
+ } else {
+ printed = -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 = args->options;
+ cs_mode mode = 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) != 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 = args->ms.map;
+ struct symbol *sym;
+
+ /* TODO: support more architectures */
+ if (!arch__is(args->arch, "x86"))
+ return;
+
+ if (insn->detail == NULL)
+ return;
+
+ for (i = 0; i < insn->detail->x86.op_count; i++) {
+ cs_x86_op *op = &insn->detail->x86.operands[i];
+ u64 orig_addr;
+
+ if (op->type != X86_OP_MEM)
+ continue;
+
+ /* only print RIP-based global symbols for now */
+ if (op->mem.base != X86_REG_RIP)
+ continue;
+
+ /* get the target address */
+ orig_addr = addr + insn->size + op->mem.disp;
+ addr = 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 = maps__find(map__kmaps(map), addr);
+ if (map == NULL)
+ continue;
+ }
+
+ /* convert it to map-relative address for search */
+ addr = map__map_ip(map, addr);
+
+ sym = map__find_symbol(map, addr);
+ if (sym == NULL)
+ continue;
+
+ if (addr == 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 = arg;
+
+ if (start <= data->ip && data->ip < start + len) {
+ data->offset = 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 = map__dso(map);
+ struct nscookie nsc;
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 end = map__rip_2objdump(map, sym->end);
+ int fd, count;
+ u8 *buf = NULL;
+ struct find_file_offset_data data = {
+ .ip = start,
+ };
+
+ *is_64bit = false;
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ return NULL;
+
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
+ is_64bit) == 0)
+ goto err;
+
+ *len = end - start;
+ buf = malloc(*len);
+ if (buf == NULL)
+ goto err;
+
+ count = pread(fd, buf, *len, data.offset);
+ close(fd);
+ fd = -1;
+
+ if ((u64)count != *len)
+ goto err;
+
+ return buf;
+
+err:
+ if (fd >= 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 = symbol__annotation(sym);
+ struct map *map = args->ms.map;
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 len;
+ u64 offset;
+ int i, count, free_count;
+ bool is_64bit = false;
+ bool needs_cs_close = false;
+ u8 *buf = NULL;
+ csh handle;
+ cs_insn *insn = NULL;
+ char disasm_buf[512];
+ struct disasm_line *dl;
+
+ if (args->options->objdump_path)
+ return -1;
+
+ buf = read_symbol(filename, map, sym, &len, &is_64bit);
+ if (buf == NULL)
+ return -1;
+
+ /* add the function address and name */
+ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
+ start, sym->name);
+
+ args->offset = -1;
+ args->line = disasm_buf;
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms.sym = sym;
+
+ dl = disasm_line__new(args);
+ if (dl == 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 = true;
+
+ free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
+ for (i = 0, offset = 0; i < count; i++) {
+ int printed;
+
+ printed = 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 = offset;
+ args->line = disasm_buf;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ offset += insn[i].size;
+ }
+
+ /* It failed in the middle: probably due to unknown instructions */
+ if (offset != len) {
+ struct list_head *list = ¬es->src->source;
+
+ /* Discard all lines and fallback to objdump */
+ while (!list_empty(list)) {
+ dl = list_first_entry(list, struct disasm_line, al.node);
+
+ list_del_init(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ count = -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 = -1;
+ goto out;
+#else
+ return -1;
+#endif
+}
+
+int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
+ struct symbol *sym __maybe_unused,
+ struct annotate_args *args __maybe_unused)
+{
+#ifdef HAVE_LIBCAPSTONE_SUPPORT
+ struct annotation *notes = symbol__annotation(sym);
+ struct map *map = args->ms.map;
+ struct dso *dso = map__dso(map);
+ struct nscookie nsc;
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 end = map__rip_2objdump(map, sym->end);
+ u64 len = end - start;
+ u64 offset;
+ int i, fd, count;
+ bool is_64bit = false;
+ bool needs_cs_close = false;
+ u8 *buf = NULL;
+ struct find_file_offset_data data = {
+ .ip = start,
+ };
+ csh handle;
+ char disasm_buf[512];
+ struct disasm_line *dl;
+ u32 *line;
+ bool disassembler_style = false;
+
+ if (args->options->objdump_path)
+ return -1;
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ return -1;
+
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
+ &is_64bit) == 0)
+ goto err;
+
+ if (!args->options->disassembler_style ||
+ !strcmp(args->options->disassembler_style, "att"))
+ disassembler_style = true;
+
+ if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0)
+ goto err;
+
+ needs_cs_close = true;
+
+ buf = malloc(len);
+ if (buf == NULL)
+ goto err;
+
+ count = pread(fd, buf, len, data.offset);
+ close(fd);
+ fd = -1;
+
+ if ((u64)count != len)
+ goto err;
+
+ line = (u32 *)buf;
+
+ /* add the function address and name */
+ scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
+ start, sym->name);
+
+ args->offset = -1;
+ args->line = disasm_buf;
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms.sym = sym;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ /*
+ * TODO: enable disassm for powerpc
+ * count = 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 = len/4;
+
+ for (i = 0, offset = 0; i < count; i++) {
+ args->offset = offset;
+ sprintf(args->line, "%x", line[i]);
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ break;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ offset += 4;
+ }
+
+ /* It failed in the middle */
+ if (offset != len) {
+ struct list_head *list = ¬es->src->source;
+
+ /* Discard all lines and fallback to objdump */
+ while (!list_empty(list)) {
+ dl = list_first_entry(list, struct disasm_line, al.node);
+
+ list_del_init(&dl->al.node);
+ disasm_line__free(dl);
+ }
+ count = -1;
+ }
+
+out:
+ if (needs_cs_close)
+ cs_close(&handle);
+ free(buf);
+ return count < 0 ? count : 0;
+
+err:
+ if (fd >= 0)
+ close(fd);
+ count = -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 <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/types.h>
+
+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 symbol *sym,
+ struct annotate_args *args);
+
+#endif /* __PERF_CAPSTONE_H */
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 8f0eb56c6fc6..85401fc04b2e 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"
@@ -1330,39 +1331,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
return 0;
}
-#ifdef HAVE_LIBCAPSTONE_SUPPORT
-#include <capstone/capstone.h>
-
-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 = args->options;
- cs_mode mode = 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) != 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;
@@ -1428,322 +1397,6 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym,
}
#endif
-#if !defined(HAVE_LIBCAPSTONE_SUPPORT) || !defined(HAVE_LIBLLVM_SUPPORT)
-static void symbol__disassembler_missing(const char *disassembler, const char *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 = args->ms.map;
- struct symbol *sym;
-
- /* TODO: support more architectures */
- if (!arch__is(args->arch, "x86"))
- return;
-
- if (insn->detail == NULL)
- return;
-
- for (i = 0; i < insn->detail->x86.op_count; i++) {
- cs_x86_op *op = &insn->detail->x86.operands[i];
- u64 orig_addr;
-
- if (op->type != X86_OP_MEM)
- continue;
-
- /* only print RIP-based global symbols for now */
- if (op->mem.base != X86_REG_RIP)
- continue;
-
- /* get the target address */
- orig_addr = addr + insn->size + op->mem.disp;
- addr = 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 = maps__find(map__kmaps(map), addr);
- if (map == NULL)
- continue;
- }
-
- /* convert it to map-relative address for search */
- addr = map__map_ip(map, addr);
-
- sym = map__find_symbol(map, addr);
- if (sym == NULL)
- continue;
-
- if (addr == 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 symbol *sym,
- struct annotate_args *args)
-{
- struct annotation *notes = symbol__annotation(sym);
- struct map *map = args->ms.map;
- struct dso *dso = map__dso(map);
- struct nscookie nsc;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
- u64 len = end - start;
- u64 offset;
- int i, fd, count;
- bool is_64bit = false;
- bool needs_cs_close = false;
- u8 *buf = NULL;
- struct find_file_offset_data data = {
- .ip = start,
- };
- csh handle;
- char disasm_buf[512];
- struct disasm_line *dl;
- u32 *line;
- bool disassembler_style = false;
-
- if (args->options->objdump_path)
- return -1;
-
- nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
- fd = open(filename, O_RDONLY);
- nsinfo__mountns_exit(&nsc);
- if (fd < 0)
- return -1;
-
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
- &is_64bit) == 0)
- goto err;
-
- if (!args->options->disassembler_style ||
- !strcmp(args->options->disassembler_style, "att"))
- disassembler_style = true;
-
- if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0)
- goto err;
-
- needs_cs_close = true;
-
- buf = malloc(len);
- if (buf == NULL)
- goto err;
-
- count = pread(fd, buf, len, data.offset);
- close(fd);
- fd = -1;
-
- if ((u64)count != len)
- goto err;
-
- line = (u32 *)buf;
-
- /* add the function address and name */
- scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
-
- args->offset = -1;
- args->line = disasm_buf;
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
-
- dl = disasm_line__new(args);
- if (dl == NULL)
- goto err;
-
- annotation_line__add(&dl->al, ¬es->src->source);
-
- /*
- * TODO: enable disassm for powerpc
- * count = 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 = len/4;
-
- for (i = 0, offset = 0; i < count; i++) {
- args->offset = offset;
- sprintf(args->line, "%x", line[i]);
-
- dl = disasm_line__new(args);
- if (dl == NULL)
- break;
-
- annotation_line__add(&dl->al, ¬es->src->source);
-
- offset += 4;
- }
-
- /* It failed in the middle */
- if (offset != len) {
- struct list_head *list = ¬es->src->source;
-
- /* Discard all lines and fallback to objdump */
- while (!list_empty(list)) {
- dl = list_first_entry(list, struct disasm_line, al.node);
-
- list_del_init(&dl->al.node);
- disasm_line__free(dl);
- }
- count = -1;
- }
-
-out:
- if (needs_cs_close)
- cs_close(&handle);
- free(buf);
- return count < 0 ? count : 0;
-
-err:
- if (fd >= 0)
- close(fd);
- count = -1;
- goto out;
-}
-
-static int symbol__disassemble_capstone(char *filename, struct symbol *sym,
- struct annotate_args *args)
-{
- struct annotation *notes = symbol__annotation(sym);
- struct map *map = args->ms.map;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 len;
- u64 offset;
- int i, count, free_count;
- bool is_64bit = false;
- bool needs_cs_close = false;
- u8 *buf = NULL;
- csh handle;
- cs_insn *insn = NULL;
- char disasm_buf[512];
- struct disasm_line *dl;
-
- if (args->options->objdump_path)
- return -1;
-
- buf = read_symbol(filename, map, sym, &len, &is_64bit);
- if (buf == NULL)
- return -1;
-
- /* add the function address and name */
- scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:",
- start, sym->name);
-
- args->offset = -1;
- args->line = disasm_buf;
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
-
- dl = disasm_line__new(args);
- if (dl == 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 = true;
-
- free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
- for (i = 0, offset = 0; i < count; i++) {
- int printed;
-
- printed = 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 = offset;
- args->line = disasm_buf;
-
- dl = disasm_line__new(args);
- if (dl == NULL)
- goto err;
-
- annotation_line__add(&dl->al, ¬es->src->source);
-
- offset += insn[i].size;
- }
-
- /* It failed in the middle: probably due to unknown instructions */
- if (offset != len) {
- struct list_head *list = ¬es->src->source;
-
- /* Discard all lines and fallback to objdump */
- while (!list_empty(list)) {
- dl = list_first_entry(list, struct disasm_line, al.node);
-
- list_del_init(&dl->al.node);
- disasm_line__free(dl);
- }
- count = -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 = -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 symbol *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)
{
@@ -2011,10 +1664,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 *sym,
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 <inttypes.h>
#include <string.h>
#include <stdbool.h>
+#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 *sample, FILE *fp)
return printed;
}
-#ifdef HAVE_LIBCAPSTONE_SUPPORT
-#include <capstone/capstone.h>
-
-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 = CS_ARCH_X86;
- mode = CS_MODE_64;
- } else if (machine__normalized_is(machine, "x86")) {
- arch = CS_ARCH_X86;
- mode = CS_MODE_32;
- } else if (machine__normalized_is(machine, "arm64")) {
- arch = CS_ARCH_ARM64;
- mode = CS_MODE_ARM;
- } else if (machine__normalized_is(machine, "arm")) {
- arch = CS_ARCH_ARM;
- mode = CS_MODE_ARM + CS_MODE_V8;
- } else if (machine__normalized_is(machine, "s390")) {
- arch = CS_ARCH_SYSZ;
- mode = CS_MODE_BIG_ENDIAN;
- } else {
- return -1;
- }
-
- if (cs_open(arch, mode, cs_handle) != 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 *insn,
- int print_opts, FILE *fp)
-{
- struct addr_location al;
- size_t printed = 0;
-
- if (insn->detail && insn->detail->x86.op_count == 1) {
- cs_x86_op *op = &insn->detail->x86.operands[0];
-
- addr_location__init(&al);
- if (op->type == X86_OP_IMM &&
- thread__find_symbol(thread, cpumode, op->imm, &al)) {
- printed += fprintf(fp, "%s ", insn[0].mnemonic);
- printed += symbol__fprintf_symname_offs(al.sym, &al, fp);
- if (print_opts & PRINT_INSN_IMM_HEX)
- printed += fprintf(fp, " [%#" PRIx64 "]", op->imm);
- addr_location__exit(&al);
- return printed;
- }
- addr_location__exit(&al);
- }
-
- printed += 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 = al->map ? map__dso(al->map) : NULL;
@@ -123,32 +46,8 @@ ssize_t fprintf_insn_asm(struct machine *machine, struct 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 = capstone_init(machine, &cs_handle, is64bit, true);
- if (ret < 0)
- return ret;
-
- count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
- if (count > 0) {
- if (machine__normalized_is(machine, "x86"))
- printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
- else
- printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
- if (lenp)
- *lenp = insn->size;
- cs_free(insn, count);
- } else {
- printed = -1;
- }
-
- cs_close(&cs_handle);
- return printed;
+ return capstone__fprintf_insn_asm(machine, thread, cpumode, is64bit, code, code_size,
+ ip, lenp, print_opts, fp);
}
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 *sample, struct thread *threa
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
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 04/19] perf llvm: Move llvm functionality into its own file
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (2 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 03/19] perf capstone: Move capstone functionality into its own file Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 05/19] perf capstone: Remove open_capstone_handle Ian Rogers
` (15 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 disassembl 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 <irogers@google.com>
---
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 1300b42cd748..caea11286fc9 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -26,6 +26,7 @@ perf-util-y += evswitch.o
perf-util-y += find_bit.o
perf-util-y += get_current_dir_name.o
perf-util-y += levenshtein.o
+perf-util-y += llvm.o
perf-util-y += mmap.o
perf-util-y += memswap.o
perf-util-y += parse-events.o
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 85401fc04b2e..73343ae5fc96 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, size_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 annotate_args *args);
-static char *expand_tabs(char *line, char **storage, size_t *storage_len);
static __attribute__((constructor)) void symbol__init_regexpr(void)
{
@@ -1331,72 +1331,6 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil
return 0;
}
-#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 = arg;
-
- if (start <= data->ip && data->ip < start + len) {
- data->offset = 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 = map__dso(map);
- struct nscookie nsc;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
- int fd, count;
- u8 *buf = NULL;
- struct find_file_offset_data data = {
- .ip = start,
- };
-
- *is_64bit = false;
-
- nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
- fd = open(filename, O_RDONLY);
- nsinfo__mountns_exit(&nsc);
- if (fd < 0)
- return NULL;
-
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
- is_64bit) == 0)
- goto err;
-
- *len = end - start;
- buf = malloc(*len);
- if (buf == NULL)
- goto err;
-
- count = pread(fd, buf, *len, data.offset);
- close(fd);
- fd = -1;
-
- if ((u64)count != *len)
- goto err;
-
- return buf;
-
-err:
- if (fd >= 0)
- close(fd);
- free(buf);
- return NULL;
-}
-#endif
-
static int symbol__disassemble_raw(char *filename, struct symbol *sym,
struct annotate_args *args)
{
@@ -1483,202 +1417,12 @@ static int symbol__disassemble_raw(char *filename, struct symbol *sym,
goto out;
}
-#ifdef HAVE_LIBLLVM_SUPPORT
-#include <llvm-c/Disassembler.h>
-#include <llvm-c/Target.h>
-#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, because
- * it puts quotation marks around what we return), but we use this as a hint
- * 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 = disinfo;
-
- if (*ref_type == LLVMDisassembler_ReferenceType_In_Branch)
- storage->branch_addr = value;
- else if (*ref_type == LLVMDisassembler_ReferenceType_In_PCrel_Load)
- storage->pcrel_load_addr = value;
- *ref_type = LLVMDisassembler_ReferenceType_InOut_None;
- return NULL;
-}
-
-static int symbol__disassemble_llvm(char *filename, struct symbol *sym,
- struct annotate_args *args)
-{
- struct annotation *notes = symbol__annotation(sym);
- struct map *map = args->ms.map;
- struct dso *dso = map__dso(map);
- u64 start = 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 = NULL;
- struct symbol_lookup_storage storage;
- char *line_storage = NULL;
- size_t line_storage_len = 0;
- int ret = -1;
-
- if (args->options->objdump_path)
- return -1;
-
- LLVMInitializeAllTargetInfos();
- LLVMInitializeAllTargetMCs();
- LLVMInitializeAllDisassemblers();
-
- buf = read_symbol(filename, map, sym, &len, &is_64bit);
- if (buf == 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 = LLVMCreateDisasm(triplet, &storage, 0, NULL,
- symbol_lookup_callback);
- if (disasm == 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 = -1;
- args->line = disasm_buf;
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
-
- dl = disasm_line__new(args);
- if (dl == NULL)
- goto err;
-
- annotation_line__add(&dl->al, ¬es->src->source);
-
- pc = start;
- for (u64 offset = 0; offset < len; ) {
- unsigned int ins_len;
-
- storage.branch_addr = 0;
- storage.pcrel_load_addr = 0;
-
- ins_len = LLVMDisasmInstruction(disasm, buf + offset,
- len - offset, pc,
- disasm_buf, sizeof(disasm_buf));
- if (ins_len == 0)
- goto err;
- disasm_len = strlen(disasm_buf);
-
- if (storage.branch_addr != 0) {
- char *name = llvm_name_for_code(dso, filename,
- storage.branch_addr);
- if (name != NULL) {
- disasm_len += scnprintf(disasm_buf + disasm_len,
- sizeof(disasm_buf) -
- disasm_len,
- " <%s>", name);
- free(name);
- }
- }
- if (storage.pcrel_load_addr != 0) {
- char *name = llvm_name_for_data(dso, filename,
- storage.pcrel_load_addr);
- disasm_len += scnprintf(disasm_buf + disasm_len,
- sizeof(disasm_buf) - disasm_len,
- " # %#"PRIx64,
- storage.pcrel_load_addr);
- if (name) {
- disasm_len += scnprintf(disasm_buf + disasm_len,
- sizeof(disasm_buf) -
- disasm_len,
- " <%s>", name);
- free(name);
- }
- }
-
- args->offset = offset;
- args->line = expand_tabs(disasm_buf, &line_storage,
- &line_storage_len);
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
-
- llvm_addr2line(filename, pc, &args->fileloc,
- (unsigned int *)&args->line_nr, false, NULL);
-
- dl = disasm_line__new(args);
- if (dl == NULL)
- goto err;
-
- annotation_line__add(&dl->al, ¬es->src->source);
-
- free(args->fileloc);
- pc += ins_len;
- offset += ins_len;
- }
-
- ret = 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 *sym,
- 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,
int symbol__disassemble(struct symbol *sym, struct annotate_args *args);
+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 <fcntl.h>
+#include <unistd.h>
+#include <linux/zalloc.h>
+
+#ifdef HAVE_LIBLLVM_SUPPORT
+#include "llvm-c-helpers.h"
+#include <llvm-c/Disassembler.h>
+#include <llvm-c/Target.h>
+#endif
+
+#ifdef HAVE_LIBLLVM_SUPPORT
+static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames,
+ int num_frames)
+{
+ if (inline_frames != NULL) {
+ for (int i = 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 = NULL;
+ int num_frames = llvm_addr2line(dso_name, addr, file, line,
+ node && unwind_inlines, &inline_frames);
+
+ if (num_frames == 0 || !inline_frames) {
+ /* Error, or we didn't want inlines. */
+ return num_frames;
+ }
+
+ for (int i = 0; i < num_frames; ++i) {
+ struct symbol *inline_sym =
+ new_inline_sym(dso, sym, inline_frames[i].funcname);
+ char *srcline = NULL;
+
+ if (inline_frames[i].filename) {
+ srcline =
+ srcline_from_fileline(inline_frames[i].filename,
+ inline_frames[i].line);
+ }
+ if (inline_list__append(inline_sym, srcline, node) != 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 = arg;
+
+ if (start <= data->ip && data->ip < start + len) {
+ data->offset = 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 = map__dso(map);
+ struct nscookie nsc;
+ u64 start = map__rip_2objdump(map, sym->start);
+ u64 end = map__rip_2objdump(map, sym->end);
+ int fd, count;
+ u8 *buf = NULL;
+ struct find_file_offset_data data = {
+ .ip = start,
+ };
+
+ *is_64bit = false;
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ return NULL;
+
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
+ is_64bit) == 0)
+ goto err;
+
+ *len = end - start;
+ buf = malloc(*len);
+ if (buf == NULL)
+ goto err;
+
+ count = pread(fd, buf, *len, data.offset);
+ close(fd);
+ fd = -1;
+
+ if ((u64)count != *len)
+ goto err;
+
+ return buf;
+
+err:
+ if (fd >= 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, because
+ * it puts quotation marks around what we return), but we use this as a hint
+ * 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 = disinfo;
+
+ if (*ref_type == LLVMDisassembler_ReferenceType_In_Branch)
+ storage->branch_addr = value;
+ else if (*ref_type == LLVMDisassembler_ReferenceType_In_PCrel_Load)
+ storage->pcrel_load_addr = value;
+ *ref_type = 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 = symbol__annotation(sym);
+ struct map *map = args->ms.map;
+ struct dso *dso = map__dso(map);
+ u64 start = 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 = NULL;
+ struct symbol_lookup_storage storage;
+ char *line_storage = NULL;
+ size_t line_storage_len = 0;
+ int ret = -1;
+
+ if (args->options->objdump_path)
+ return -1;
+
+ LLVMInitializeAllTargetInfos();
+ LLVMInitializeAllTargetMCs();
+ LLVMInitializeAllDisassemblers();
+
+ buf = read_symbol(filename, map, sym, &len, &is_64bit);
+ if (buf == 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 = LLVMCreateDisasm(triplet, &storage, 0, NULL,
+ symbol_lookup_callback);
+ if (disasm == 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 = -1;
+ args->line = disasm_buf;
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms.sym = sym;
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ pc = start;
+ for (u64 offset = 0; offset < len; ) {
+ unsigned int ins_len;
+
+ storage.branch_addr = 0;
+ storage.pcrel_load_addr = 0;
+
+ ins_len = LLVMDisasmInstruction(disasm, buf + offset,
+ len - offset, pc,
+ disasm_buf, sizeof(disasm_buf));
+ if (ins_len == 0)
+ goto err;
+ disasm_len = strlen(disasm_buf);
+
+ if (storage.branch_addr != 0) {
+ char *name = llvm_name_for_code(dso, filename,
+ storage.branch_addr);
+ if (name != NULL) {
+ disasm_len += scnprintf(disasm_buf + disasm_len,
+ sizeof(disasm_buf) -
+ disasm_len,
+ " <%s>", name);
+ free(name);
+ }
+ }
+ if (storage.pcrel_load_addr != 0) {
+ char *name = llvm_name_for_data(dso, filename,
+ storage.pcrel_load_addr);
+ disasm_len += scnprintf(disasm_buf + disasm_len,
+ sizeof(disasm_buf) - disasm_len,
+ " # %#"PRIx64,
+ storage.pcrel_load_addr);
+ if (name) {
+ disasm_len += scnprintf(disasm_buf + disasm_len,
+ sizeof(disasm_buf) -
+ disasm_len,
+ " <%s>", name);
+ free(name);
+ }
+ }
+
+ args->offset = offset;
+ args->line = expand_tabs(disasm_buf, &line_storage,
+ &line_storage_len);
+ args->line_nr = 0;
+ args->fileloc = NULL;
+ args->ms.sym = sym;
+
+ llvm_addr2line(filename, pc, &args->fileloc,
+ (unsigned int *)&args->line_nr, false, NULL);
+
+ dl = disasm_line__new(args);
+ if (dl == NULL)
+ goto err;
+
+ annotation_line__add(&dl->al, ¬es->src->source);
+
+ free(args->fileloc);
+ pc += ins_len;
+ offset += ins_len;
+ }
+
+ ret = 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 <stdbool.h>
+#include <linux/types.h>
+
+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 f32d0d4f4bc9..26fd55455efd 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;
}
-static int inline_list__append(struct symbol *symbol, char *srcline,
- struct inline_node *node)
+int inline_list__append(struct symbol *symbol, char *srcline, struct inline_node *node)
{
struct inline_list *ilist;
@@ -77,7 +74,7 @@ static const char *gnu_basename(const char *path)
return base ? base + 1 : path;
}
-static char *srcline_from_fileline(const char *file, unsigned int line)
+char *srcline_from_fileline(const char *file, unsigned int line)
{
char *srcline;
@@ -93,9 +90,9 @@ static char *srcline_from_fileline(const char *file, unsigned int line)
return srcline;
}
-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 = NULL;
@@ -135,58 +132,20 @@ static struct symbol *new_inline_sym(struct dso *dso,
#define MAX_INLINE_NEST 1024
#ifdef HAVE_LIBLLVM_SUPPORT
-
-static void free_llvm_inline_frames(struct llvm_a2l_frame *inline_frames,
- int num_frames)
-{
- if (inline_frames != NULL) {
- for (int i = 0; i < num_frames; ++i) {
- zfree(&inline_frames[i].filename);
- zfree(&inline_frames[i].funcname);
- }
- zfree(&inline_frames);
- }
-}
+#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)
+ bool unwind_inlines, struct inline_node *node,
+ struct symbol *sym)
{
- struct llvm_a2l_frame *inline_frames = NULL;
- int num_frames = llvm_addr2line(dso_name, addr, file, line,
- node && unwind_inlines, &inline_frames);
-
- if (num_frames == 0 || !inline_frames) {
- /* Error, or we didn't want inlines. */
- return num_frames;
- }
-
- for (int i = 0; i < num_frames; ++i) {
- struct symbol *inline_sym =
- new_inline_sym(dso, sym, inline_frames[i].funcname);
- char *srcline = NULL;
-
- if (inline_frames[i].filename) {
- srcline =
- srcline_from_fileline(inline_frames[i].filename,
- inline_frames[i].line);
- }
- if (inline_list__append(inline_sym, srcline, node) != 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, node, sym);
}
-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)
/*
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_cached *tree, u64 addr);
/* delete all nodes within the tree of inline_node s */
void inlines__tree_delete(struct rb_root_cached *tree);
+int inline_list__append(struct symbol *symbol, char *srcline, struct inline_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 */
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 05/19] perf capstone: Remove open_capstone_handle
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (3 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 04/19] perf llvm: Move llvm " Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so Ian Rogers
` (14 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 c0a6d94ebc18..c9845e4d8781 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 *machine __maybe_unused,
#endif
}
-#ifdef HAVE_LIBCAPSTONE_SUPPORT
-static int open_capstone_handle(struct annotate_args *args, bool is_64bit, csh *handle)
-{
- struct annotation_options *opt = args->options;
- cs_mode mode = 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) != 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 = NULL;
char disasm_buf[512];
struct disasm_line *dl;
+ bool disassembler_style = false;
if (args->options->objdump_path)
return -1;
@@ -333,7 +307,11 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
annotation_line__add(&dl->al, ¬es->src->source);
- if (open_capstone_handle(args, is_64bit, &handle) < 0)
+ if (!args->options->disassembler_style ||
+ !strcmp(args->options->disassembler_style, "att"))
+ disassembler_style = true;
+
+ if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0)
goto err;
needs_cs_close = true;
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (4 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 05/19] perf capstone: Remove open_capstone_handle Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-06-26 23:19 ` Namhyung Kim
2025-04-17 23:07 ` [PATCH v4 07/19] perf llvm: Support for dlopen-ing libLLVM.so Ian Rogers
` (13 subsequent siblings)
19 siblings, 1 reply; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 c9845e4d8781..8d65c7a55a8b 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 <dlfcn.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <string.h>
#ifdef HAVE_LIBCAPSTONE_SUPPORT
#include <capstone/capstone.h>
+#else
+typedef size_t csh;
+enum cs_arch {
+ CS_ARCH_ARM = 0,
+ CS_ARCH_ARM64 = 1,
+ CS_ARCH_X86 = 3,
+ CS_ARCH_SYSZ = 6,
+};
+enum cs_mode {
+ CS_MODE_ARM = 0,
+ CS_MODE_32 = 1 << 2,
+ CS_MODE_64 = 1 << 3,
+ CS_MODE_V8 = 1 << 6,
+ CS_MODE_BIG_ENDIAN = 1 << 31,
+};
+enum cs_opt_type {
+ CS_OPT_SYNTAX = 1,
+ CS_OPT_DETAIL = 2,
+};
+enum cs_opt_value {
+ CS_OPT_SYNTAX_ATT = 2,
+ CS_OPT_ON = 3,
+};
+enum cs_err {
+ CS_ERR_OK = 0,
+ CS_ERR_HANDLE = 3,
+};
+enum x86_op_type {
+ X86_OP_IMM = 2,
+ X86_OP_MEM = 3,
+};
+enum x86_reg {
+ X86_REG_RIP = 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 = true;
+ dll_handle = 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 *handle);
+
+ if (!fn_init) {
+ fn = dlsym(perf_cs_dll_handle(), "cs_open");
+ if (!fn)
+ pr_debug("dlsym failed for cs_open\n");
+ fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_option");
+ if (!fn)
+ pr_debug("dlsym failed for cs_option\n");
+ fn_init = 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_size,
+ uint64_t address, size_t count, struct cs_insn **insn);
+
+ if (!fn_init) {
+ fn = dlsym(perf_cs_dll_handle(), "cs_disasm");
+ if (!fn)
+ pr_debug("dlsym failed for cs_disasm\n");
+ fn_init = 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)
+{
#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 = dlsym(perf_cs_dll_handle(), "cs_free");
+ if (!fn)
+ pr_debug("dlsym failed for cs_free\n");
+ fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_close");
+ if (!fn)
+ pr_debug("dlsym failed for cs_close\n");
+ fn_init = true;
+ }
+ if (!fn)
+ return CS_ERR_HANDLE;
+ return fn(handle);
+#endif
+}
+
static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
bool disassembler_style)
{
- cs_arch arch;
- cs_mode mode;
+ enum cs_arch arch;
+ enum cs_mode mode;
if (machine__is(machine, "x86_64") && is64) {
arch = CS_ARCH_X86;
@@ -44,7 +274,7 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
return -1;
}
- if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
+ if (perf_cs_open(arch, mode, cs_handle) != 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);
}
return 0;
}
-#endif
-#ifdef HAVE_LIBCAPSTONE_SUPPORT
-static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
+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 = 0;
if (insn->detail && insn->detail->x86.op_count == 1) {
- cs_x86_op *op = &insn->detail->x86.operands[0];
+ struct cs_x86_op *op = &insn->detail->x86.operands[0];
addr_location__init(&al);
if (op->type == X86_OP_IMM &&
@@ -94,7 +322,6 @@ static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
printed += 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,
@@ -105,9 +332,8 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __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 *machine __maybe_unused,
if (ret < 0)
return ret;
- count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
+ count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
if (count > 0) {
if (machine__normalized_is(machine, "x86"))
printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
@@ -125,20 +351,16 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
if (lenp)
*lenp = insn->size;
- cs_free(insn, count);
+ perf_cs_free(insn, count);
} else {
printed = -1;
}
- cs_close(&cs_handle);
+ perf_cs_close(&cs_handle);
return printed;
-#else
- return -1;
-#endif
}
-#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;
for (i = 0; i < insn->detail->x86.op_count; i++) {
- cs_x86_op *op = &insn->detail->x86.operands[i];
+ struct cs_x86_op *op = &insn->detail->x86.operands[i];
u64 orig_addr;
if (op->type != X86_OP_MEM)
@@ -194,9 +416,7 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
break;
}
}
-#endif
-#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 pgoff, void *arg)
}
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)
@@ -262,13 +480,11 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym,
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 = symbol__annotation(sym);
struct map *map = args->ms.map;
u64 start = map__rip_2objdump(map, sym->start);
@@ -279,7 +495,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
bool needs_cs_close = false;
u8 *buf = NULL;
csh handle;
- cs_insn *insn = NULL;
+ struct cs_insn *insn = NULL;
char disasm_buf[512];
struct disasm_line *dl;
bool disassembler_style = false;
@@ -316,7 +532,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
needs_cs_close = true;
- free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
+ free_count = count = perf_cs_disasm(handle, buf, len, start, len, &insn);
for (i = 0, offset = 0; i < count; i++) {
int printed;
@@ -355,9 +571,9 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
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 = -1;
goto out;
-#else
- return -1;
-#endif
}
int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
struct symbol *sym __maybe_unused,
struct annotate_args *args __maybe_unused)
{
-#ifdef HAVE_LIBCAPSTONE_SUPPORT
struct annotation *notes = symbol__annotation(sym);
struct map *map = args->ms.map;
struct dso *dso = map__dso(map);
@@ -499,7 +711,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
out:
if (needs_cs_close)
- cs_close(&handle);
+ perf_cs_close(&handle);
free(buf);
return count < 0 ? count : 0;
@@ -508,7 +720,4 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
close(fd);
count = -1;
goto out;
-#else
- return -1;
-#endif
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 07/19] perf llvm: Support for dlopen-ing libLLVM.so
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (5 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 08/19] perf llvm: Mangle libperf-llvm.so function names Ian Rogers
` (12 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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=1
Signed-off-by: Ian Rogers <irogers@google.com>
---
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 f31b240cd23e..d6d8c6b970e3 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -968,6 +968,19 @@ ifndef NO_LIBLLVM
NO_LIBLLVM := 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 detected)
+ endif
+ CFLAGS += -DHAVE_LIBLLVM_DYNAMIC
+ CFLAGS += $(shell $(LLVM_CONFIG) --cflags)
+ CXXFLAGS += -DHAVE_LIBLLVM_DYNAMIC
+ CXXFLAGS += $(shell $(LLVM_CONFIG) --cxxflags)
+endif
ifndef NO_DEMANGLE
$(call feature_check,cxa-demangle)
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 979d4691221a..6833dda27ffb 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -424,6 +424,12 @@ ifndef NO_JVMTI
PROGRAMS += $(OUTPUT)$(LIBJVMTI)
endif
+LIBPERF_LLVM = libperf-llvm.so
+
+ifdef LIBLLVM_DYNAMIC
+PROGRAMS += $(OUTPUT)$(LIBPERF_LLVM)
+endif
+
DLFILTERS := dlfilter-test-api-v0.so dlfilter-test-api-v2.so dlfilter-show-cycles.so
DLFILTERS := $(patsubst %,$(OUTPUT)dlfilters/%,$(DLFILTERS))
@@ -996,6 +1002,16 @@ $(LIBSYMBOL)-clean:
$(call QUIET_CLEAN, libsymbol)
$(Q)$(RM) -r -- $(LIBSYMBOL_OUTPUT)
+ifdef LIBLLVM_DYNAMIC
+LIBPERF_LLVM_CXXFLAGS := $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXFLAGS)) -DHAVE_LIBLLVM_SUPPORT
+LIBPERF_LLVM_LIBS = -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)'
@@ -1097,6 +1113,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)'
@@ -1278,7 +1299,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-vdso32 \
- 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 0ee94caf9ec1..44d76eacce49 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -93,6 +93,7 @@ make_libbpf_dynamic := LIBBPF_DYNAMIC=1
make_no_libbpf_DEBUG := NO_LIBBPF=1 DEBUG=1
make_no_libcrypto := NO_LIBCRYPTO=1
make_no_libllvm := NO_LIBLLVM=1
+make_libllvm_dynamic := NO_LIBLLVM=1 LIBLLVM_DYNAMIC=1
make_with_babeltrace:= LIBBABELTRACE=1
make_with_coresight := CORESIGHT=1
make_no_sdt := NO_SDT=1
@@ -162,6 +163,7 @@ run += make_no_libbpf
run += make_no_libbpf_DEBUG
run += make_no_libcrypto
run += make_no_libllvm
+run += make_libllvm_dynamic
run += make_no_sdt
run += make_no_syscall_tbl
run += make_with_babeltrace
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index caea11286fc9..861e8ed4ac49 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -27,6 +27,7 @@ perf-util-y += find_bit.o
perf-util-y += get_current_dir_name.o
perf-util-y += levenshtein.o
perf-util-y += llvm.o
+perf-util-y += llvm-c-helpers.o
perf-util-y += mmap.o
perf-util-y += memswap.o
perf-util-y += parse-events.o
@@ -240,7 +241,6 @@ perf-util-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
perf-util-y += demangle-ocaml.o
perf-util-y += demangle-java.o
perf-util-y += demangle-rust.o
-perf-util-$(CONFIG_LIBLLVM) += llvm-c-helpers.o
ifdef CONFIG_JITDUMP
perf-util-$(CONFIG_LIBELF) += jitdump.o
diff --git a/tools/perf/util/llvm-c-helpers.cpp b/tools/perf/util/llvm-c-helpers.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 <= 15 */
#include <llvm/DebugInfo/Symbolize/Symbolize.h>
#include <llvm/Support/TargetSelect.h>
#pragma GCC diagnostic pop
+#endif
+#if !defined(HAVE_LIBLLVM_SUPPORT) || defined(HAVE_LIBLLVM_DYNAMIC)
+#include <dlfcn.h>
+#endif
#include <inttypes.h>
#include <stdio.h>
#include <sys/types.h>
#include <linux/compiler.h>
extern "C" {
+#include "debug.h"
#include <linux/zalloc.h>
}
#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);
+#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 = true;
+ dll_handle = dlopen("libperf-llvm.so", RTLD_LAZY);
+ if (!dll_handle)
+ pr_debug("dlopen failed for libperf-llvm.so\n");
+ }
+ return dll_handle;
+}
+#endif
/*
* Allocate a static LLVMSymbolizer, which will live to the end of the program.
* Unlike the bfd paths, LLVMSymbolizer has its own cache, so we do not need
* to store anything in the dso struct.
*/
+#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
static LLVMSymbolizer *get_symbolizer()
{
static LLVMSymbolizer *instance = nullptr;
@@ -49,8 +74,10 @@ static LLVMSymbolizer *get_symbolizer()
}
return instance;
}
+#endif
/* 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 = line_info.Line;
return 1;
}
+#endif
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_unused,
+ 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 = get_symbolizer();
object::SectionedAddress sectioned_addr = {
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 = perf_llvm_c_helpers_dll_handle();
+
+ if (!handle)
+ return 0;
+
+ fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_addr2line"));
+ if (!fn)
+ pr_debug("dlsym failed for llvm_addr2line\n");
+ fn_init = true;
+ }
+ if (!fn)
+ return 0;
+ return fn(dso_name, addr, file, line, unwind_inlines, inline_frames);
+#else
+ return 0;
+#endif
}
+#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 char *sym_name,
return strdup(sym_name);
}
}
+#endif
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_name __maybe_unused,
+ u64 addr __maybe_unused)
{
+#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
LLVMSymbolizer *symbolizer = get_symbolizer();
object::SectionedAddress sectioned_addr = {
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 = perf_llvm_c_helpers_dll_handle();
+
+ if (!handle)
+ return NULL;
+
+ fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_name_for_code"));
+ if (!fn)
+ pr_debug("dlsym failed for llvm_name_for_code\n");
+ fn_init = true;
+ }
+ if (!fn)
+ return NULL;
+ return fn(dso, dso_name, addr);
+#else
+ return 0;
+#endif
}
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_name __maybe_unused,
+ u64 addr __maybe_unused)
{
+#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
LLVMSymbolizer *symbolizer = get_symbolizer();
object::SectionedAddress sectioned_addr = {
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 = perf_llvm_c_helpers_dll_handle();
+
+ if (!handle)
+ return NULL;
+
+ fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_name_for_data"));
+ if (!fn)
+ pr_debug("dlsym failed for llvm_name_for_data\n");
+ fn_init = 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 <dlfcn.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <unistd.h>
#include <linux/zalloc.h>
-#ifdef HAVE_LIBLLVM_SUPPORT
-#include "llvm-c-helpers.h"
+#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
#include <llvm-c/Disassembler.h>
#include <llvm-c/Target.h>
+#else
+typedef void *LLVMDisasmContextRef;
+typedef int (*LLVMOpInfoCallback)(void *dis_info, uint64_t pc, uint64_t offset,
+ 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[] = {
+ "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 = true;
+ dll_handle = 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 = 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 as a symbol. */
+ static bool done_init;
+
+ if (done_init)
+ return;
+
+ for (size_t i = 0; i < ARRAY_SIZE(llvm_targets); i++) {
+ void (*fn)(void) = perf_llvm_dll_fun("LLVMInitialize%sTargetInfo",
+ llvm_targets[i]);
+
+ if (!fn)
+ continue;
+ fn();
+ }
+ done_init = 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 = 0; i < ARRAY_SIZE(llvm_targets); i++) {
+ void (*fn)(void) = perf_llvm_dll_fun("LLVMInitialize%sTargetMC",
+ llvm_targets[i]);
+
+ if (!fn)
+ continue;
+ fn();
+ }
+ done_init = 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 = 0; i < ARRAY_SIZE(llvm_targets); i++) {
+ void (*fn)(void) = perf_llvm_dll_fun("LLVMInitialize%sDisassembler",
+ llvm_targets[i]);
+
+ if (!fn)
+ continue;
+ fn();
+ }
+ done_init = 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, symbol_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 = dlsym(perf_llvm_dll_handle(), "LLVMCreateDisasm");
+ if (!fn)
+ pr_debug("dlsym failed for LLVMCreateDisasm\n");
+ fn_init = 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 = dlsym(perf_llvm_dll_handle(), "LLVMSetDisasmOptions");
+ if (!fn)
+ pr_debug("dlsym failed for LLVMSetDisasmOptions\n");
+ fn_init = true;
+ }
+ if (!fn)
+ return 0;
+ return fn(context, options);
+#endif
+}
+
+static size_t perf_LLVMDisasmInstruction(LLVMDisasmContextRef context, uint8_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 = dlsym(perf_llvm_dll_handle(), "LLVMDisasmInstruction");
+ if (!fn)
+ pr_debug("dlsym failed for LLVMDisasmInstruction\n");
+ fn_init = 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 = dlsym(perf_llvm_dll_handle(), "LLVMDisasmDispose");
+ if (!fn)
+ pr_debug("dlsym failed for LLVMDisasmDispose\n");
+ fn_init = true;
+ }
+ if (!fn)
+ return;
+ fn(context);
#endif
+}
+
-#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_frame *inline_frames,
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 = NULL;
int num_frames = 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);
return num_frames;
-#else
- return -1;
-#endif
}
void dso__free_a2l_llvm(struct dso *dso __maybe_unused)
@@ -75,7 +297,6 @@ void dso__free_a2l_llvm(struct dso *dso __maybe_unused)
}
-#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, struct symbol *sym,
free(buf);
return NULL;
}
-#endif
/*
* 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, struct 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 = 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 = symbol__annotation(sym);
struct map *map = args->ms.map;
struct dso *dso = map__dso(map);
@@ -197,9 +414,9 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
if (args->options->objdump_path)
return -1;
- LLVMInitializeAllTargetInfos();
- LLVMInitializeAllTargetMCs();
- LLVMInitializeAllDisassemblers();
+ perf_LLVMInitializeAllTargetInfos();
+ perf_LLVMInitializeAllTargetMCs();
+ perf_LLVMInitializeAllDisassemblers();
buf = read_symbol(filename, map, sym, &len, &is_64bit);
if (buf == NULL)
@@ -215,15 +432,14 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
args->arch->name);
}
- disasm = LLVMCreateDisasm(triplet, &storage, 0, NULL,
- symbol_lookup_callback);
+ disasm = perf_LLVMCreateDisasm(triplet, &storage, 0, NULL,
+ symbol_lookup_callback);
if (disasm == NULL)
goto err;
if (args->options->disassembler_style &&
!strcmp(args->options->disassembler_style, "intel"))
- LLVMSetDisasmOptions(disasm,
- LLVMDisassembler_Option_AsmPrinterVariant);
+ perf_LLVMSetDisasmOptions(disasm, LLVMDisassembler_Option_AsmPrinterVariant);
/*
* This needs to be set after AsmPrinterVariant, due to a bug in LLVM;
@@ -231,7 +447,7 @@ int symbol__disassemble_llvm(const char *filename, struct 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);
/* 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, struct symbol *sym,
storage.branch_addr = 0;
storage.pcrel_load_addr = 0;
- ins_len = LLVMDisasmInstruction(disasm, buf + offset,
- len - offset, pc,
- disasm_buf, sizeof(disasm_buf));
+ ins_len = perf_LLVMDisasmInstruction(disasm, buf + offset,
+ len - offset, pc,
+ disasm_buf, sizeof(disasm_buf));
if (ins_len == 0)
goto err;
disasm_len = strlen(disasm_buf);
@@ -314,13 +530,8 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
ret = 0;
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
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 08/19] perf llvm: Mangle libperf-llvm.so function names
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (6 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 07/19] perf llvm: Support for dlopen-ing libLLVM.so Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 09/19] perf dso: Move read_symbol from llvm/capstone to dso Ian Rogers
` (11 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 6833dda27ffb..fc65537d5821 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -1003,7 +1003,8 @@ $(LIBSYMBOL)-clean:
$(Q)$(RM) -r -- $(LIBSYMBOL_OUTPUT)
ifdef LIBLLVM_DYNAMIC
-LIBPERF_LLVM_CXXFLAGS := $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXFLAGS)) -DHAVE_LIBLLVM_SUPPORT
+LIBPERF_LLVM_CXXFLAGS := $(call filter-out,-DHAVE_LIBLLVM_DYNAMIC,$(CXXFLAGS))
+LIBPERF_LLVM_CXXFLAGS += -DHAVE_LIBLLVM_SUPPORT -DBUILDING_PERF_LLVMSO
LIBPERF_LLVM_LIBS = -L$(shell $(LLVM_CONFIG) --libdir) $(LIBLLVM) -lstdc++
$(OUTPUT)$(LIBPERF_LLVM): util/llvm-c-helpers.cpp
diff --git a/tools/perf/util/llvm-c-helpers.cpp b/tools/perf/util/llvm-c-helpers.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
extern "C"
-int llvm_addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_unused,
- 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_unused,
+ u64 addr __maybe_unused,
+ 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 = get_symbolizer();
@@ -177,7 +179,8 @@ int llvm_addr2line(const char *dso_name __maybe_unused, u64 addr __maybe_unused,
if (!handle)
return 0;
- fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_addr2line"));
+ fn = reinterpret_cast<decltype(fn)>(
+ dlsym(handle, MANGLE_PERF_LLVM_API_STR(llvm_addr2line)));
if (!fn)
pr_debug("dlsym failed for llvm_addr2line\n");
fn_init = true;
@@ -215,8 +218,9 @@ make_symbol_relative_string(struct dso *dso, const char *sym_name,
#endif
extern "C"
-char *llvm_name_for_code(struct dso *dso __maybe_unused, const char *dso_name __maybe_unused,
- u64 addr __maybe_unused)
+char *MANGLE_PERF_LLVM_API(llvm_name_for_code)(struct dso *dso __maybe_unused,
+ const char *dso_name __maybe_unused,
+ u64 addr __maybe_unused)
{
#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
LLVMSymbolizer *symbolizer = get_symbolizer();
@@ -242,7 +246,8 @@ char *llvm_name_for_code(struct dso *dso __maybe_unused, const char *dso_name __
if (!handle)
return NULL;
- fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_name_for_code"));
+ fn = reinterpret_cast<decltype(fn)>(
+ 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 = true;
@@ -256,8 +261,9 @@ char *llvm_name_for_code(struct dso *dso __maybe_unused, const char *dso_name __
}
extern "C"
-char *llvm_name_for_data(struct dso *dso __maybe_unused, const char *dso_name __maybe_unused,
- u64 addr __maybe_unused)
+char *MANGLE_PERF_LLVM_API(llvm_name_for_data)(struct dso *dso __maybe_unused,
+ const char *dso_name __maybe_unused,
+ u64 addr __maybe_unused)
{
#if defined(HAVE_LIBLLVM_SUPPORT) && !defined(HAVE_LIBLLVM_DYNAMIC)
LLVMSymbolizer *symbolizer = get_symbolizer();
@@ -283,7 +289,8 @@ char *llvm_name_for_data(struct dso *dso __maybe_unused, const char *dso_name __
if (!handle)
return NULL;
- fn = reinterpret_cast<decltype(fn)>(dlsym(handle, "llvm_name_for_data"));
+ fn = reinterpret_cast<decltype(fn)>(
+ 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 = true;
diff --git a/tools/perf/util/llvm-c-helpers.h b/tools/perf/util/llvm-c-helpers.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
+/* 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;
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);
/*
* 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);
#ifdef __cplusplus
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 09/19] perf dso: Move read_symbol from llvm/capstone to dso
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (7 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 08/19] perf llvm: Mangle libperf-llvm.so function names Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 10/19] perf dso: Support BPF programs in dso__read_symbol Ian Rogers
` (10 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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 8d65c7a55a8b..f103988184c8 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 pgoff, void *arg)
return 0;
}
-static u8 *
-read_symbol(const char *filename, struct map *map, struct symbol *sym,
- u64 *len, bool *is_64bit)
-{
- struct dso *dso = map__dso(map);
- struct nscookie nsc;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
- int fd, count;
- u8 *buf = NULL;
- struct find_file_offset_data data = {
- .ip = start,
- };
-
- *is_64bit = false;
-
- nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
- fd = open(filename, O_RDONLY);
- nsinfo__mountns_exit(&nsc);
- if (fd < 0)
- return NULL;
-
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
- is_64bit) == 0)
- goto err;
-
- *len = end - start;
- buf = malloc(*len);
- if (buf == NULL)
- goto err;
-
- count = pread(fd, buf, *len, data.offset);
- close(fd);
- fd = -1;
-
- if ((u64)count != *len)
- goto err;
-
- return buf;
-
-err:
- if (fd >= 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 = symbol__annotation(sym);
struct map *map = args->ms.map;
+ struct dso *dso = map__dso(map);
u64 start = map__rip_2objdump(map, sym->start);
- u64 len;
u64 offset;
int i, count, free_count;
bool is_64bit = false;
bool needs_cs_close = false;
- u8 *buf = NULL;
+ /* Malloc-ed buffer containing instructions read from disk. */
+ u8 *code_buf = NULL;
+ /* Pointer to code to be disassembled. */
+ const u8 *buf;
+ u64 buf_len;
csh handle;
struct cs_insn *insn = 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;
- buf = read_symbol(filename, map, sym, &len, &is_64bit);
+ buf = dso__read_symbol(dso, filename, map, sym,
+ &code_buf, &buf_len, &is_64bit);
if (buf == NULL)
return -1;
@@ -532,7 +490,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
needs_cs_close = true;
- free_count = count = perf_cs_disasm(handle, buf, len, start, len, &insn);
+ free_count = count = perf_cs_disasm(handle, buf, buf_len, start, buf_len, &insn);
for (i = 0, offset = 0; i < count; i++) {
int printed;
@@ -556,7 +514,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
}
/* It failed in the middle: probably due to unknown instructions */
- if (offset != len) {
+ if (offset != buf_len) {
struct list_head *list = ¬es->src->source;
/* 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;
err:
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 8619b6eea62d..9b1e3fb3b2b9 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1776,3 +1776,70 @@ bool is_perf_pid_map_name(const char *dso_name)
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 = arg;
+
+ if (start <= data->ip && data->ip < start + len) {
+ data->offset = 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 = map__rip_2objdump(map, sym->start);
+ u64 end = map__rip_2objdump(map, sym->end);
+ int fd, count;
+ u8 *buf = NULL;
+ size_t len;
+ struct find_file_offset_data data = {
+ .ip = start,
+ };
+
+ *out_buf = NULL;
+ *out_buf_len = 0;
+ *is_64bit = false;
+
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(symfs_filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ return NULL;
+
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, is_64bit) == 0)
+ goto err;
+
+ len = end - start;
+ buf = malloc(len);
+ if (buf == NULL)
+ goto err;
+
+ count = pread(fd, buf, len, data.offset);
+ close(fd);
+ fd = -1;
+
+ if ((u64)count != len)
+ goto err;
+
+ *out_buf = buf;
+ *out_buf_len = len;
+ return buf;
+
+err:
+ if (fd >= 0)
+ close(fd);
+ free(buf);
+ return NULL;
+}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index c87564471f9b..6230eea7a93a 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -896,4 +896,8 @@ u64 dso__findnew_global_type(struct dso *dso, u64 addr, u64 offset);
bool perf_pid_map_tid(const char *dso_name, int *tid);
bool is_perf_pid_map_name(const char *dso_name);
+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. */
}
-
-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 = arg;
-
- if (start <= data->ip && data->ip < start + len) {
- data->offset = 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 = map__dso(map);
- struct nscookie nsc;
- u64 start = map__rip_2objdump(map, sym->start);
- u64 end = map__rip_2objdump(map, sym->end);
- int fd, count;
- u8 *buf = NULL;
- struct find_file_offset_data data = {
- .ip = start,
- };
-
- *is_64bit = false;
-
- nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
- fd = open(filename, O_RDONLY);
- nsinfo__mountns_exit(&nsc);
- if (fd < 0)
- return NULL;
-
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data,
- is_64bit) == 0)
- goto err;
-
- *len = end - start;
- buf = malloc(*len);
- if (buf == NULL)
- goto err;
-
- count = pread(fd, buf, *len, data.offset);
- close(fd);
- fd = -1;
-
- if ((u64)count != *len)
- goto err;
-
- return buf;
-
-err:
- if (fd >= 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, because
@@ -397,8 +332,11 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
struct map *map = args->ms.map;
struct dso *dso = map__dso(map);
u64 start = map__rip_2objdump(map, sym->start);
- u8 *buf;
- u64 len;
+ /* Malloc-ed buffer containing instructions read from disk. */
+ u8 *code_buf = 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, struct symbol *sym,
perf_LLVMInitializeAllTargetMCs();
perf_LLVMInitializeAllDisassemblers();
- buf = read_symbol(filename, map, sym, &len, &is_64bit);
+ buf = dso__read_symbol(dso, filename, map, sym,
+ &code_buf, &buf_len, &is_64bit);
if (buf == NULL)
return -1;
@@ -466,14 +405,18 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
annotation_line__add(&dl->al, ¬es->src->source);
pc = start;
- for (u64 offset = 0; offset < len; ) {
+ for (u64 offset = 0; offset < buf_len; ) {
unsigned int ins_len;
storage.branch_addr = 0;
storage.pcrel_load_addr = 0;
- ins_len = 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 = perf_LLVMDisasmInstruction(disasm, (u8 *)(buf + offset),
+ buf_len - offset, pc,
disasm_buf, sizeof(disasm_buf));
if (ins_len == 0)
goto err;
@@ -531,7 +474,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
err:
perf_LLVMDisasmDispose(disasm);
- free(buf);
+ free(code_buf);
free(line_storage);
return ret;
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 10/19] perf dso: Support BPF programs in dso__read_symbol
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (8 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 09/19] perf dso: Move read_symbol from llvm/capstone to dso Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 11/19] perf llvm: Disassemble cleanup Ian Rogers
` (9 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
Set the buffer to the code in the BPF linear info. This enables BPF
JIT code disassembly by LLVM and capstone. Move the disassmble_bpf
calls to disassemble_objdump so that they are only called after
falling back to the objdump option.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/disasm.c | 12 +++---
tools/perf/util/dso.c | 85 +++++++++++++++++++++++++---------------
2 files changed, 60 insertions(+), 37 deletions(-)
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 73343ae5fc96..175d9d3b5c97 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -1501,6 +1501,12 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
struct child_process objdump_process;
int err;
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
+ return symbol__disassemble_bpf(sym, args);
+
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE)
+ return symbol__disassemble_bpf_image(sym, args);
+
err = asprintf(&command,
"%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64
@@ -1635,11 +1641,7 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), sym, sym->name);
- if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
- return symbol__disassemble_bpf(sym, args);
- } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) {
- return symbol__disassemble_bpf_image(sym, args);
- } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) {
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__NOT_FOUND) {
return SYMBOL_ANNOTATE_ERRNO__COULDNT_DETERMINE_FILE_TYPE;
} else if (dso__is_kcore(dso)) {
kce.addr = map__rip_2objdump(map, sym->start);
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 9b1e3fb3b2b9..d08e2a1f49c1 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1798,48 +1798,69 @@ 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 = map__rip_2objdump(map, sym->start);
u64 end = map__rip_2objdump(map, sym->end);
- int fd, count;
- u8 *buf = NULL;
- size_t len;
- struct find_file_offset_data data = {
- .ip = start,
- };
+ const u8 *buf;
+ size_t len = end - start;
*out_buf = NULL;
*out_buf_len = 0;
*is_64bit = false;
- nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
- fd = open(symfs_filename, O_RDONLY);
- nsinfo__mountns_exit(&nsc);
- if (fd < 0)
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) {
+ pr_debug("No BPF image disassembly support\n");
return NULL;
+ } else if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
+#ifdef HAVE_LIBBPF_SUPPORT
+ struct bpf_prog_info_node *info_node;
+ struct perf_bpil *info_linear;
+
+ *is_64bit = sizeof(void *) == sizeof(u64);
+ info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
+ dso__bpf_prog(dso)->id);
+ if (!info_node) {
+ errno = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
+ return NULL;
+ }
+ info_linear = info_node->info_linear;
+ buf = (const u8 *)(uintptr_t)(info_linear->info.jited_prog_insns);
+ assert(len <= info_linear->info.jited_prog_len);
+#else
+ pr_debug("No BPF program disassembly support\n");
+ return NULL;
+#endif
+ } else {
+ struct nscookie nsc;
+ int fd;
+ ssize_t count;
+ struct find_file_offset_data data = {
+ .ip = start,
+ };
+ u8 *code_buf = NULL;
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, is_64bit) == 0)
- goto err;
-
- len = end - start;
- buf = malloc(len);
- if (buf == NULL)
- goto err;
-
- count = pread(fd, buf, len, data.offset);
- close(fd);
- fd = -1;
-
- if ((u64)count != len)
- goto err;
+ nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
+ fd = open(symfs_filename, O_RDONLY);
+ nsinfo__mountns_exit(&nsc);
+ if (fd < 0)
+ return NULL;
- *out_buf = buf;
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, is_64bit) == 0) {
+ close(fd);
+ return NULL;
+ }
+ buf = code_buf = malloc(len);
+ if (buf == NULL) {
+ close(fd);
+ return NULL;
+ }
+ count = pread(fd, code_buf, len, data.offset);
+ close(fd);
+ if ((u64)count != len) {
+ free(code_buf);
+ return NULL;
+ }
+ *out_buf = code_buf;
+ }
*out_buf_len = len;
return buf;
-
-err:
- if (fd >= 0)
- close(fd);
- free(buf);
- return NULL;
}
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 11/19] perf llvm: Disassemble cleanup
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (9 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 10/19] perf dso: Support BPF programs in dso__read_symbol Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 12/19] perf dso: Clean up read_symbol error handling Ian Rogers
` (8 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
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(LLVMDisasmContextRef context)
#endif
}
+static void init_llvm(void)
+{
+ static bool init;
+
+ if (!init) {
+ perf_LLVMInitializeAllTargetInfos();
+ perf_LLVMInitializeAllTargetMCs();
+ perf_LLVMInitializeAllDisassemblers();
+ init = true;
+ }
+}
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, struct 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, struct symbol *sym,
if (args->options->objdump_path)
return -1;
- perf_LLVMInitializeAllTargetInfos();
- perf_LLVMInitializeAllTargetMCs();
- perf_LLVMInitializeAllDisassemblers();
-
buf = dso__read_symbol(dso, filename, map, sym,
&code_buf, &buf_len, &is_64bit);
if (buf == NULL)
return -1;
+ 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 = is_64bit ? "x86_64-pc-linux" : "i686-pc-linux";
+
+ disasm = perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=*/0,
+ /*get_op_info=*/NULL, symbol_lookup_callback);
} else {
+ char triplet[64];
+
scnprintf(triplet, sizeof(triplet), "%s-linux-gnu",
args->arch->name);
+ disasm = perf_LLVMCreateDisasm(triplet, &storage, /*tag_type=*/0,
+ /*get_op_info=*/NULL, symbol_lookup_callback);
}
-
- disasm = perf_LLVMCreateDisasm(triplet, &storage, 0, NULL,
- symbol_lookup_callback);
if (disasm == NULL)
goto err;
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 12/19] perf dso: Clean up read_symbol error handling
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (10 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 11/19] perf llvm: Disassemble cleanup Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 13/19] perf build: Remove libbfd support Ian Rogers
` (7 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 <irogers@google.com>
---
tools/perf/util/capstone.c | 3 ++-
tools/perf/util/dso.c | 14 ++++++++++++--
tools/perf/util/llvm.c | 3 ++-
3 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c
index f103988184c8..032548828925 100644
--- a/tools/perf/util/capstone.c
+++ b/tools/perf/util/capstone.c
@@ -12,6 +12,7 @@
#include "symbol.h"
#include "thread.h"
#include <dlfcn.h>
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <string.h>
@@ -463,7 +464,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
buf = dso__read_symbol(dso, filename, map, sym,
&code_buf, &buf_len, &is_64bit);
if (buf == NULL)
- return -1;
+ return errno;
/* 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 d08e2a1f49c1..243fc33cc449 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1809,6 +1809,7 @@ const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename,
if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE) {
pr_debug("No BPF image disassembly support\n");
+ errno = EOPNOTSUPP;
return NULL;
} else if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO) {
#ifdef HAVE_LIBBPF_SUPPORT
@@ -1827,6 +1828,7 @@ const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename,
assert(len <= info_linear->info.jited_prog_len);
#else
pr_debug("No BPF program disassembly support\n");
+ errno = EOPNOTSUPP;
return NULL;
#endif
} else {
@@ -1837,26 +1839,34 @@ const u8 *dso__read_symbol(struct dso *dso, const char *symfs_filename,
.ip = start,
};
u8 *code_buf = NULL;
+ int saved_errno;
nsinfo__mountns_enter(dso__nsinfo(dso), &nsc);
fd = open(symfs_filename, O_RDONLY);
+ saved_errno = errno;
nsinfo__mountns_exit(&nsc);
- if (fd < 0)
+ if (fd < 0) {
+ errno = saved_errno;
return NULL;
+ }
- if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, is_64bit) == 0) {
+ if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, is_64bit) <= 0) {
close(fd);
+ errno = ENOENT;
return NULL;
}
buf = code_buf = malloc(len);
if (buf == NULL) {
close(fd);
+ errno = ENOMEM;
return NULL;
}
count = pread(fd, code_buf, len, data.offset);
+ saved_errno = errno;
close(fd);
if ((u64)count != len) {
free(code_buf);
+ errno = saved_errno;
return NULL;
}
*out_buf = code_buf;
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 <dlfcn.h>
+#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <unistd.h>
@@ -365,7 +366,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
buf = dso__read_symbol(dso, filename, map, sym,
&code_buf, &buf_len, &is_64bit);
if (buf == NULL)
- return -1;
+ return errno;
init_llvm();
if (arch__is(args->arch, "x86")) {
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 13/19] perf build: Remove libbfd support
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (11 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 12/19] perf dso: Clean up read_symbol error handling Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 14/19] perf build: Remove libiberty support Ian Rogers
` (6 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
libbfd is license incompatible with perf and building requires the
BUILD_NONDISTRO=1 build flag. Remove the code to simplify the code
base.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Documentation/perf-check.txt | 1 -
tools/perf/Makefile.config | 38 +---
tools/perf/builtin-check.c | 1 -
tools/perf/tests/Build | 1 -
tools/perf/tests/builtin-test.c | 1 -
tools/perf/tests/pe-file-parsing.c | 101 ----------
tools/perf/tests/tests.h | 1 -
tools/perf/util/demangle-cxx.cpp | 13 +-
tools/perf/util/disasm_bpf.c | 166 ----------------
tools/perf/util/srcline.c | 243 +-----------------------
tools/perf/util/symbol-elf.c | 86 +--------
tools/perf/util/symbol.c | 135 -------------
tools/perf/util/symbol.h | 4 -
13 files changed, 7 insertions(+), 784 deletions(-)
delete mode 100644 tools/perf/tests/pe-file-parsing.c
diff --git a/tools/perf/Documentation/perf-check.txt b/tools/perf/Documentation/perf-check.txt
index a764a4629220..f6ec81ad87b2 100644
--- a/tools/perf/Documentation/perf-check.txt
+++ b/tools/perf/Documentation/perf-check.txt
@@ -51,7 +51,6 @@ feature::
dwarf_getlocations / HAVE_LIBDW_SUPPORT
dwarf-unwind / HAVE_DWARF_UNWIND_SUPPORT
auxtrace / HAVE_AUXTRACE_SUPPORT
- libbfd / HAVE_LIBBFD_SUPPORT
libcapstone / HAVE_LIBCAPSTONE_SUPPORT
libcrypto / HAVE_LIBCRYPTO_SUPPORT
libdw-dwarf-unwind / HAVE_LIBDW_SUPPORT
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index d6d8c6b970e3..870451929771 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -916,42 +916,6 @@ ifneq ($(NO_JEVENTS),1)
endif
endif
-ifdef BUILD_NONDISTRO
- ifeq ($(feature-libbfd), 1)
- EXTLIBS += -lbfd -lopcodes
- else
- # we are on a system that requires -liberty and (maybe) -lz
- # to link against -lbfd; test each case individually here
-
- # call all detections now so we get correct
- # status in VF output
- $(call feature_check,libbfd-liberty)
- $(call feature_check,libbfd-liberty-z)
-
- ifeq ($(feature-libbfd-liberty), 1)
- EXTLIBS += -lbfd -lopcodes -liberty
- FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -ldl
- FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -ldl
- else
- ifeq ($(feature-libbfd-liberty-z), 1)
- EXTLIBS += -lbfd -lopcodes -liberty -lz
- FEATURE_CHECK_LDFLAGS-disassembler-four-args += -liberty -lz -ldl
- FEATURE_CHECK_LDFLAGS-disassembler-init-styled += -liberty -lz -ldl
- endif
- endif
- $(call feature_check,disassembler-four-args)
- $(call feature_check,disassembler-init-styled)
- endif
-
- CFLAGS += -DHAVE_LIBBFD_SUPPORT
- CXXFLAGS += -DHAVE_LIBBFD_SUPPORT
- ifeq ($(feature-libbfd-buildid), 1)
- CFLAGS += -DHAVE_LIBBFD_BUILDID_SUPPORT
- else
- $(warning Old version of libbfd/binutils things like PE executable profiling will not be available)
- endif
-endif
-
ifndef NO_LIBLLVM
$(call feature_check,llvm-perf)
ifeq ($(feature-llvm-perf), 1)
@@ -1336,6 +1300,6 @@ endif
# re-generate FEATURE-DUMP as we may have called feature_check, found out
# extra libraries to add to LDFLAGS of some other test and then redo those
-# tests, see the block about libbfd, disassembler-four-args, for instance.
+# tests, see the block about disassembler-four-args, for instance.
$(shell rm -f $(FEATURE_DUMP_FILENAME))
$(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
diff --git a/tools/perf/builtin-check.c b/tools/perf/builtin-check.c
index 9a509cb3bb9a..6724dc45b609 100644
--- a/tools/perf/builtin-check.c
+++ b/tools/perf/builtin-check.c
@@ -42,7 +42,6 @@ struct feature_status supported_features[] = {
FEATURE_STATUS("dwarf_getlocations", HAVE_LIBDW_SUPPORT),
FEATURE_STATUS("dwarf-unwind", HAVE_DWARF_UNWIND_SUPPORT),
FEATURE_STATUS("auxtrace", HAVE_AUXTRACE_SUPPORT),
- FEATURE_STATUS_TIP("libbfd", HAVE_LIBBFD_SUPPORT, "Deprecated, license incompatibility, use BUILD_NONDISTRO=1 and install binutils-dev[el]"),
FEATURE_STATUS("libcapstone", HAVE_LIBCAPSTONE_SUPPORT),
FEATURE_STATUS("libcrypto", HAVE_LIBCRYPTO_SUPPORT),
FEATURE_STATUS("libdw-dwarf-unwind", HAVE_LIBDW_SUPPORT),
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 934f32090553..1ded1776aebc 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -58,7 +58,6 @@ perf-test-y += demangle-java-test.o
perf-test-y += demangle-ocaml-test.o
perf-test-y += pfm.o
perf-test-y += parse-metric.o
-perf-test-y += pe-file-parsing.o
perf-test-y += expand-cgroup.o
perf-test-y += perf-time-to-tsc.o
perf-test-y += dlfilter-test.o
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 14d30a5053be..e77bf446e821 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -127,7 +127,6 @@ static struct test_suite *generic_tests[] = {
&suite__demangle_java,
&suite__demangle_ocaml,
&suite__parse_metric,
- &suite__pe_file_parsing,
&suite__expand_cgroup_events,
&suite__perf_time_to_tsc,
&suite__dlfilter,
diff --git a/tools/perf/tests/pe-file-parsing.c b/tools/perf/tests/pe-file-parsing.c
deleted file mode 100644
index fff58b220c07..000000000000
--- a/tools/perf/tests/pe-file-parsing.c
+++ /dev/null
@@ -1,101 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <stdbool.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <subcmd/exec-cmd.h>
-
-#include "debug.h"
-#include "util/build-id.h"
-#include "util/symbol.h"
-#include "util/dso.h"
-
-#include "tests.h"
-
-#ifdef HAVE_LIBBFD_SUPPORT
-
-static int run_dir(const char *d)
-{
- char filename[PATH_MAX];
- char debugfile[PATH_MAX];
- struct build_id bid;
- char debuglink[PATH_MAX];
- char expect_build_id[] = {
- 0x5a, 0x0f, 0xd8, 0x82, 0xb5, 0x30, 0x84, 0x22,
- 0x4b, 0xa4, 0x7b, 0x62, 0x4c, 0x55, 0xa4, 0x69,
- };
- char expect_debuglink[PATH_MAX] = "pe-file.exe.debug";
- struct dso *dso;
- struct symbol *sym;
- int ret;
- size_t idx;
-
- scnprintf(filename, PATH_MAX, "%s/pe-file.exe", d);
- ret = filename__read_build_id(filename, &bid);
- TEST_ASSERT_VAL("Failed to read build_id",
- ret == sizeof(expect_build_id));
- TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id,
- sizeof(expect_build_id)));
-
- ret = filename__read_debuglink(filename, debuglink, PATH_MAX);
- TEST_ASSERT_VAL("Failed to read debuglink", ret == 0);
- TEST_ASSERT_VAL("Wrong debuglink",
- !strcmp(debuglink, expect_debuglink));
-
- scnprintf(debugfile, PATH_MAX, "%s/%s", d, debuglink);
- ret = filename__read_build_id(debugfile, &bid);
- TEST_ASSERT_VAL("Failed to read debug file build_id",
- ret == sizeof(expect_build_id));
- TEST_ASSERT_VAL("Wrong build_id", !memcmp(bid.data, expect_build_id,
- sizeof(expect_build_id)));
-
- dso = dso__new(filename);
- TEST_ASSERT_VAL("Failed to get dso", dso);
-
- ret = dso__load_bfd_symbols(dso, debugfile);
- TEST_ASSERT_VAL("Failed to load symbols", ret == 0);
-
- dso__sort_by_name(dso);
- sym = dso__find_symbol_by_name(dso, "main", &idx);
- TEST_ASSERT_VAL("Failed to find main", sym);
- dso__delete(dso);
-
- return TEST_OK;
-}
-
-static int test__pe_file_parsing(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
-{
- struct stat st;
- char path_dir[PATH_MAX];
-
- /* First try development tree tests. */
- if (!lstat("./tests", &st))
- return run_dir("./tests");
-
- /* Then installed path. */
- snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
-
- if (!lstat(path_dir, &st))
- return run_dir(path_dir);
-
- return TEST_SKIP;
-}
-
-#else
-
-static int test__pe_file_parsing(struct test_suite *test __maybe_unused,
- int subtest __maybe_unused)
-{
- return TEST_SKIP;
-}
-
-#endif
-
-DEFINE_SUITE("PE file support", pe_file_parsing);
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 8aea344536b8..751c8489059a 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -159,7 +159,6 @@ DECLARE_SUITE(demangle_java);
DECLARE_SUITE(demangle_ocaml);
DECLARE_SUITE(pfm);
DECLARE_SUITE(parse_metric);
-DECLARE_SUITE(pe_file_parsing);
DECLARE_SUITE(expand_cgroup_events);
DECLARE_SUITE(perf_time_to_tsc);
DECLARE_SUITE(dlfilter);
diff --git a/tools/perf/util/demangle-cxx.cpp b/tools/perf/util/demangle-cxx.cpp
index 85b706641837..bd657eb37efc 100644
--- a/tools/perf/util/demangle-cxx.cpp
+++ b/tools/perf/util/demangle-cxx.cpp
@@ -4,16 +4,11 @@
#include <string.h>
#include <linux/compiler.h>
-#ifdef HAVE_LIBBFD_SUPPORT
-#define PACKAGE 'perf'
-#include <bfd.h>
-#endif
-
#ifdef HAVE_CXA_DEMANGLE_SUPPORT
#include <cxxabi.h>
#endif
-#if defined(HAVE_LIBBFD_SUPPORT) || defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#if 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 */
@@ -29,11 +24,7 @@ extern "C"
char *cxx_demangle_sym(const char *str, bool params __maybe_unused,
bool modifiers __maybe_unused)
{
-#ifdef HAVE_LIBBFD_SUPPORT
- int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
-
- return bfd_demangle(NULL, str, flags);
-#elif defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#if defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
return cplus_demangle(str, flags);
diff --git a/tools/perf/util/disasm_bpf.c b/tools/perf/util/disasm_bpf.c
index 1fee71c79b62..a891a0b909a7 100644
--- a/tools/perf/util/disasm_bpf.c
+++ b/tools/perf/util/disasm_bpf.c
@@ -6,176 +6,10 @@
#include <linux/zalloc.h>
#include <string.h>
-#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
-#define PACKAGE "perf"
-#include <bfd.h>
-#include <bpf/bpf.h>
-#include <bpf/btf.h>
-#include <bpf/libbpf.h>
-#include <dis-asm.h>
-#include <errno.h>
-#include <linux/btf.h>
-#include <tools/dis-asm-compat.h>
-
-#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 = symbol__annotation(sym);
- struct bpf_prog_linfo *prog_linfo = NULL;
- struct bpf_prog_info_node *info_node;
- int len = sym->end - sym->start;
- disassembler_ftype disassemble;
- struct map *map = args->ms.map;
- struct perf_bpil *info_linear;
- struct disassemble_info info;
- struct dso *dso = map__dso(map);
- int pc = 0, count, sub_id;
- struct btf *btf = NULL;
- char tpath[PATH_MAX];
- size_t buf_size;
- int nr_skip = 0;
- char *buf;
- bfd *bfdf;
- int ret;
- FILE *s;
-
- if (dso__binary_type(dso) != 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 = bfd_openr(tpath, NULL);
- if (bfdf == NULL)
- abort();
-
- if (!bfd_check_format(bfdf, bfd_object))
- abort();
-
- s = open_memstream(&buf, &buf_size);
- if (!s) {
- ret = errno;
- goto out;
- }
- init_disassemble_info_compat(&info, s,
- (fprintf_ftype) fprintf,
- fprintf_styled);
- info.arch = bfd_get_arch(bfdf);
- info.mach = bfd_get_mach(bfdf);
-
- info_node = perf_env__find_bpf_prog_info(dso__bpf_prog(dso)->env,
- dso__bpf_prog(dso)->id);
- if (!info_node) {
- ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF;
- goto out;
- }
- info_linear = info_node->info_linear;
- sub_id = dso__bpf_prog(dso)->sub_id;
-
- info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
- info.buffer_length = info_linear->info.jited_prog_len;
-
- if (info_linear->info.nr_line_info)
- prog_linfo = bpf_prog_linfo__new(&info_linear->info);
-
- if (info_linear->info.btf_id) {
- struct btf_node *node;
-
- node = perf_env__find_btf(dso__bpf_prog(dso)->env,
- info_linear->info.btf_id);
- if (node)
- btf = btf__new((__u8 *)(node->data),
- node->data_size);
- }
-
- disassemble_init_for_target(&info);
-
-#ifdef DISASM_FOUR_ARGS_SIGNATURE
- disassemble = disassembler(info.arch,
- bfd_big_endian(bfdf),
- info.mach,
- bfdf);
-#else
- disassemble = disassembler(bfdf);
-#endif
- if (disassemble == NULL)
- abort();
-
- fflush(s);
- do {
- const struct bpf_line_info *linfo = NULL;
- struct disasm_line *dl;
- size_t prev_buf_size;
- const char *srcline;
- u64 addr;
-
- addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id];
- count = disassemble(pc, &info);
-
- if (prog_linfo)
- linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
- addr, sub_id,
- nr_skip);
-
- if (linfo && btf) {
- srcline = btf__name_by_offset(btf, linfo->line_off);
- nr_skip++;
- } else
- srcline = NULL;
-
- fprintf(s, "\n");
- prev_buf_size = buf_size;
- fflush(s);
-
- if (!annotate_opts.hide_src_code && srcline) {
- args->offset = -1;
- args->line = strdup(srcline);
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
- dl = disasm_line__new(args);
- if (dl) {
- annotation_line__add(&dl->al,
- ¬es->src->source);
- }
- }
-
- args->offset = pc;
- args->line = buf + prev_buf_size;
- args->line_nr = 0;
- args->fileloc = NULL;
- args->ms.sym = sym;
- dl = disasm_line__new(args);
- if (dl)
- annotation_line__add(&dl->al, ¬es->src->source);
-
- pc += count;
- } while (count > 0 && pc < len);
-
- ret = 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 annotate_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)
{
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 26fd55455efd..797e78826508 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -146,247 +146,8 @@ 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 <bfd.h>
-
-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 = 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 = FALSE;
-
- if ((bfd_get_file_flags(abfd) & HAS_SYMS) == 0)
- return bfd_error(bfd_get_filename(abfd));
-
- storage = bfd_get_symtab_upper_bound(abfd);
- if (storage == 0L) {
- storage = bfd_get_dynamic_symtab_upper_bound(abfd);
- dynamic = TRUE;
- }
- if (storage < 0L)
- return bfd_error(bfd_get_filename(abfd));
-
- syms = malloc(storage);
- if (dynamic)
- symcount = bfd_canonicalize_dynamic_symtab(abfd, syms);
- else
- symcount = bfd_canonicalize_symtab(abfd, syms);
-
- if (symcount < 0) {
- free(syms);
- return bfd_error(bfd_get_filename(abfd));
- }
-
- a2l->syms = syms;
- return 0;
-}
-
-static void find_address_in_section(bfd *abfd, asection *section, void *data)
-{
- bfd_vma pc, vma;
- bfd_size_type size;
- struct a2l_data *a2l = data;
- flagword flags;
-
- if (a2l->found)
- return;
-
-#ifdef bfd_get_section_flags
- flags = bfd_get_section_flags(abfd, section);
-#else
- flags = bfd_section_flags(section);
-#endif
- if ((flags & SEC_ALLOC) == 0)
- return;
-
- pc = a2l->addr;
-#ifdef bfd_get_section_vma
- vma = bfd_get_section_vma(abfd, section);
-#else
- vma = bfd_section_vma(section);
-#endif
-#ifdef bfd_get_section_size
- size = bfd_get_section_size(section);
-#else
- size = bfd_section_size(section);
-#endif
-
- if (pc < vma || pc >= vma + size)
- return;
-
- a2l->found = bfd_find_nearest_line(abfd, section, a2l->syms, pc - vma,
- &a2l->filename, &a2l->funcname,
- &a2l->line);
-
- if (a2l->filename && !strlen(a2l->filename))
- a2l->filename = NULL;
-}
-
-static struct a2l_data *addr2line_init(const char *path)
-{
- bfd *abfd;
- struct a2l_data *a2l = NULL;
-
- abfd = bfd_openr(path, NULL);
- if (abfd == NULL)
- return NULL;
-
- if (!bfd_check_format(abfd, bfd_object))
- goto out;
-
- a2l = zalloc(sizeof(*a2l));
- if (a2l == NULL)
- goto out;
-
- a2l->abfd = abfd;
- a2l->input = strdup(path);
- if (a2l->input == 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 = dso__a2l(dso);
- struct symbol *inline_sym = new_inline_sym(dso, sym, a2l->funcname);
- char *srcline = NULL;
-
- if (a2l->filename)
- srcline = srcline_from_fileline(a2l->filename, a2l->line);
-
- return inline_list__append(inline_sym, srcline, node);
-}
-
-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 = 0;
- struct a2l_data *a2l = dso__a2l(dso);
-
- if (!a2l) {
- a2l = addr2line_init(dso_name);
- dso__set_a2l(dso, a2l);
- }
-
- if (a2l == NULL) {
- if (!symbol_conf.disable_add2line_warn)
- pr_warning("addr2line_init failed for %s\n", dso_name);
- return 0;
- }
-
- a2l->addr = addr;
- a2l->found = false;
-
- bfd_map_over_sections(a2l->abfd, find_address_in_section, a2l);
-
- if (!a2l->found)
- return 0;
-
- if (unwind_inlines) {
- int cnt = 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 = NULL;
-
- if (node != NULL) {
- if (inline_list__append_dso_a2l(dso, node, sym))
- return 0;
- // found at least one inline frame
- ret = 1;
- }
- }
- }
-
- if (file) {
- *file = a2l->filename ? strdup(a2l->filename) : NULL;
- ret = *file ? 1 : 0;
- }
-
- if (line)
- *line = a2l->line;
-
- return ret;
-}
-
-void dso__free_a2l(struct dso *dso)
-{
- struct a2l_data *a2l = dso__a2l(dso);
-
- if (!a2l)
- return;
-
- addr2line_cleanup(a2l);
-
- dso__set_a2l(dso, NULL);
-}
-
-#else /* HAVE_LIBBFD_SUPPORT */
+#else /* HAVE_LIBLLVM_SUPPORT */
static int filename_split(char *filename, unsigned int *line_nr)
{
@@ -805,7 +566,7 @@ void dso__free_a2l(struct dso *dso)
dso__set_a2l(dso, NULL);
}
-#endif /* HAVE_LIBBFD_SUPPORT */
+#endif /* HAVE_LIBLLVM_SUPPORT */
static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
struct dso *dso, struct symbol *sym)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index fbf6d0f73af9..856819bbba59 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -28,12 +28,7 @@
#include <symbol/kallsyms.h>
#include <internal/lib.h>
-#ifdef HAVE_LIBBFD_SUPPORT
-#define PACKAGE 'perf'
-#include <bfd.h>
-#endif
-
-#if defined(HAVE_LIBBFD_SUPPORT) || defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#if 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 */
@@ -292,11 +287,7 @@ static bool want_demangle(bool is_kernel_sym)
char *cxx_demangle_sym(const char *str __maybe_unused, bool params __maybe_unused,
bool modifiers __maybe_unused)
{
-#ifdef HAVE_LIBBFD_SUPPORT
- int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
-
- return bfd_demangle(NULL, str, flags);
-#elif defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#if defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
return cplus_demangle(str, flags);
@@ -936,37 +927,6 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size)
return err;
}
-#ifdef HAVE_LIBBFD_BUILDID_SUPPORT
-
-static int read_build_id(const char *filename, struct build_id *bid)
-{
- size_t size = sizeof(bid->data);
- int err = -1;
- bfd *abfd;
-
- abfd = 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;
- }
-
- 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 = bid->size = 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)
{
size_t size = sizeof(bid->data);
@@ -997,8 +957,6 @@ static int read_build_id(const char *filename, struct build_id *bid)
return err;
}
-#endif // HAVE_LIBBFD_BUILDID_SUPPORT
-
int filename__read_build_id(const char *filename, struct build_id *bid)
{
struct kmod_path m = { .name = NULL, };
@@ -1082,44 +1040,6 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid)
return err;
}
-#ifdef HAVE_LIBBFD_SUPPORT
-
-int filename__read_debuglink(const char *filename, char *debuglink,
- size_t size)
-{
- int err = -1;
- asection *section;
- bfd *abfd;
-
- abfd = 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 = 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 = 0;
-
-out_close:
- bfd_close(abfd);
- return err;
-}
-
-#else
-
int filename__read_debuglink(const char *filename, char *debuglink,
size_t size)
{
@@ -1172,8 +1092,6 @@ int filename__read_debuglink(const char *filename, char *debuglink,
return err;
}
-#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 11540219481b..dacddfa2cab2 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -1575,137 +1575,6 @@ static int dso__load_perf_map(const char *map_path, struct dso *dso)
return -1;
}
-#ifdef HAVE_LIBBFD_SUPPORT
-#define PACKAGE 'perf'
-#include <bfd.h>
-
-static int bfd_symbols__cmpvalue(const void *a, const void *b)
-{
- const asymbol *as = *(const asymbol **)a, *bs = *(const asymbol **)b;
-
- if (bfd_asymbol_value(as) != 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 = -1;
- long symbols_size, symbols_count, i;
- asection *section;
- asymbol **symbols, *sym;
- struct symbol *symbol;
- bfd *abfd;
- u64 start, len;
-
- abfd = 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) == bfd_target_elf_flavour)
- goto out_close;
-
- symbols_size = bfd_get_symtab_upper_bound(abfd);
- if (symbols_size == 0) {
- bfd_close(abfd);
- return 0;
- }
-
- if (symbols_size < 0)
- goto out_close;
-
- symbols = malloc(symbols_size);
- if (!symbols)
- goto out_close;
-
- symbols_count = bfd_canonicalize_symtab(abfd, symbols);
- if (symbols_count < 0)
- goto out_free;
-
- section = bfd_get_section_by_name(abfd, ".text");
- if (section) {
- for (i = 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 = (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 = 0; i < symbols_count; ++i) {
- sym = symbols[i];
- section = bfd_asymbol_section(sym);
- if (bfd2elf_binding(sym) < 0)
- continue;
-
- while (i + 1 < symbols_count &&
- bfd_asymbol_section(symbols[i + 1]) == section &&
- bfd2elf_binding(symbols[i + 1]) < 0)
- i++;
-
- if (i + 1 < symbols_count &&
- bfd_asymbol_section(symbols[i + 1]) == section)
- len = symbols[i + 1]->value - sym->value;
- else
- len = section->size - sym->value;
-
- start = bfd_asymbol_value(sym) - dso__text_offset(dso);
- symbol = 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 = 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)
{
@@ -1908,10 +1777,6 @@ int dso__load(struct dso *dso, struct map *map)
}
}
-#ifdef HAVE_LIBBFD_SUPPORT
- if (is_reg)
- bfdrc = dso__load_bfd_symbols(dso, name);
-#endif
if (is_reg && bfdrc < 0)
sirc = symsrc__init(ss, dso, name, symtab_type);
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 3fb5d146d9b1..508fd559a8a1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -174,10 +174,6 @@ int symbol__config_symfs(const struct option *opt __maybe_unused,
struct symsrc;
-#ifdef HAVE_LIBBFD_SUPPORT
-int dso__load_bfd_symbols(struct dso *dso, const char *debugfile);
-#endif
-
int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss,
struct symsrc *runtime_ss, int kmodule);
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss);
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 14/19] perf build: Remove libiberty support
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (12 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 13/19] perf build: Remove libbfd support Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 15/19] perf build: Remove unused defines Ian Rogers
` (5 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
libiberty is license incompatible with perf and building requires the
BUILD_NONDISTRO=1 build flag. libiberty is used for
HAVE_CPLUS_DEMANGLE_SUPPORT. Remove the code to simplify the code base
as it can't be distributed. Remove the BUILD_NONDISTRO build flag and
test as they no longer enable/disable support.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 12 ------------
tools/perf/Makefile.perf | 11 ++++-------
tools/perf/tests/make | 2 --
tools/perf/util/demangle-cxx.cpp | 13 +------------
tools/perf/util/symbol-elf.c | 13 -------------
5 files changed, 5 insertions(+), 46 deletions(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 870451929771..3ed047ffb4f5 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -954,18 +954,6 @@ ifndef NO_DEMANGLE
CXXFLAGS += -DHAVE_CXA_DEMANGLE_SUPPORT
$(call detected,CONFIG_CXX_DEMANGLE)
endif
- ifdef BUILD_NONDISTRO
- ifeq ($(filter -liberty,$(EXTLIBS)),)
- $(call feature_check,cplus-demangle)
- ifeq ($(feature-cplus-demangle), 1)
- EXTLIBS += -liberty
- endif
- endif
- ifneq ($(filter -liberty,$(EXTLIBS)),)
- CFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
- CXXFLAGS += -DHAVE_CPLUS_DEMANGLE_SUPPORT
- endif
- endif
endif
ifndef NO_LZMA
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index fc65537d5821..58982d8d1014 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -123,9 +123,6 @@ include ../scripts/utilities.mak
#
# Set BUILD_BPF_SKEL to 0 to override BUILD_BPF_SKEL and not build BPF skeletons
#
-# Define BUILD_NONDISTRO to enable building an linking against libbfd and
-# libiberty distribution license incompatible libraries.
-#
# Define EXTRA_TESTS to enable building extra tests useful mainly to perf
# developers, such as:
# x86 instruction decoder - new instructions test
@@ -298,10 +295,10 @@ LIBSYMBOL_DIR = $(srctree)/tools/lib/symbol/
LIBPERF_DIR = $(srctree)/tools/lib/perf/
DOC_DIR = $(srctree)/tools/perf/Documentation/
-# Set FEATURE_TESTS to 'all' so all possible feature checkers are executed.
-# Without this setting the output feature dump file misses some features, for
-# example, liberty. Select all checkers so we won't get an incomplete feature
-# dump file.
+# Set FEATURE_TESTS to 'all' so all possible feature checkers are
+# executed. Without this setting the output feature dump file misses
+# some features. Select all checkers so we won't get an incomplete
+# feature dump file.
ifeq ($(config),1)
ifdef MAKECMDGOALS
ifeq ($(filter feature-dump,$(MAKECMDGOALS)),feature-dump)
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 44d76eacce49..4a1ed20bff7e 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -68,7 +68,6 @@ python_perf_so := $(shell $(MAKE) python_perf_target|grep "Target is:"|awk '{pri
make_clean_all := clean all
make_python_perf_so := $(python_perf_so)
make_debug := DEBUG=1
-make_nondistro := BUILD_NONDISTRO=1
make_extra_tests := EXTRA_TESTS=1
make_jevents_all := JEVENTS_ARCH=all
make_no_bpf_skel := BUILD_BPF_SKEL=0
@@ -139,7 +138,6 @@ MAKE_F := $(MAKE) -f $(MK)
endif
run += make_python_perf_so
run += make_debug
-run += make_nondistro
run += make_extra_tests
run += make_jevents_all
run += make_no_bpf_skel
diff --git a/tools/perf/util/demangle-cxx.cpp b/tools/perf/util/demangle-cxx.cpp
index bd657eb37efc..36801ea327a6 100644
--- a/tools/perf/util/demangle-cxx.cpp
+++ b/tools/perf/util/demangle-cxx.cpp
@@ -8,13 +8,6 @@
#include <cxxabi.h>
#endif
-#if 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
-
/*
* Demangle C++ function signature
*
@@ -24,11 +17,7 @@ extern "C"
char *cxx_demangle_sym(const char *str, bool params __maybe_unused,
bool modifiers __maybe_unused)
{
-#if defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
- int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
-
- return cplus_demangle(str, flags);
-#elif defined(HAVE_CXA_DEMANGLE_SUPPORT)
+#if defined(HAVE_CXA_DEMANGLE_SUPPORT)
char *output;
int status;
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 856819bbba59..6e0cf3d2aec5 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -28,13 +28,6 @@
#include <symbol/kallsyms.h>
#include <internal/lib.h>
-#if 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
@@ -287,13 +280,7 @@ static bool want_demangle(bool is_kernel_sym)
char *cxx_demangle_sym(const char *str __maybe_unused, bool params __maybe_unused,
bool modifiers __maybe_unused)
{
-#if defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
- int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
-
- return cplus_demangle(str, flags);
-#else
return NULL;
-#endif
}
#endif /* !HAVE_CXA_DEMANGLE_SUPPORT */
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 15/19] perf build: Remove unused defines
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (13 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 14/19] perf build: Remove libiberty support Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 16/19] perf disasm: Remove disasm_bpf Ian Rogers
` (4 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
DISASM_FOUR_ARGS_SIGNATURE and DISASM_INIT_STYLED were used with
libbfd support. Remove now that libbfd support is removed.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 3ed047ffb4f5..bb4d31b1e1df 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -320,9 +320,6 @@ FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
FEATURE_CHECK_LDFLAGS-libaio = -lrt
-FEATURE_CHECK_LDFLAGS-disassembler-four-args = -lbfd -lopcodes -ldl
-FEATURE_CHECK_LDFLAGS-disassembler-init-styled = -lbfd -lopcodes -ldl
-
CORE_CFLAGS += -fno-omit-frame-pointer
CORE_CFLAGS += -Wall
CORE_CFLAGS += -Wextra
@@ -349,7 +346,7 @@ endif
ifeq ($(FEATURES_DUMP),)
# We will display at the end of this Makefile.config, using $(call feature_display_entries)
-# As we may retry some feature detection here, see the disassembler-four-args case, for instance
+# As we may retry some feature detection here.
FEATURE_DISPLAY_DEFERRED := 1
include $(srctree)/tools/build/Makefile.feature
else
@@ -1006,14 +1003,6 @@ ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif
-ifeq ($(feature-disassembler-four-args), 1)
- CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
-endif
-
-ifeq ($(feature-disassembler-init-styled), 1)
- CFLAGS += -DDISASM_INIT_STYLED
-endif
-
ifeq (${IS_64_BIT}, 1)
ifndef NO_PERF_READ_VDSO32
$(call feature_check,compile-32)
@@ -1288,6 +1277,6 @@ endif
# re-generate FEATURE-DUMP as we may have called feature_check, found out
# extra libraries to add to LDFLAGS of some other test and then redo those
-# tests, see the block about disassembler-four-args, for instance.
+# tests.
$(shell rm -f $(FEATURE_DUMP_FILENAME))
$(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 16/19] perf disasm: Remove disasm_bpf
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (14 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 15/19] perf build: Remove unused defines Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 17/19] perf disasm: Make ins__scnprintf and ins__is_nop static Ian Rogers
` (3 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
BPF disassembly was handled in here by libbfd. The LLVM and capstone
disassemblers now support BPF JIT disassembly. As libbfd support was
removed the functions here no longer did anything remove them and
associated error values.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/util/Build | 1 -
tools/perf/util/annotate.h | 1 -
tools/perf/util/disasm.c | 12 +++---------
tools/perf/util/disasm_bpf.c | 29 -----------------------------
tools/perf/util/disasm_bpf.h | 12 ------------
5 files changed, 3 insertions(+), 52 deletions(-)
delete mode 100644 tools/perf/util/disasm_bpf.c
delete mode 100644 tools/perf/util/disasm_bpf.h
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 861e8ed4ac49..cc22cc8a5aac 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -14,7 +14,6 @@ perf-util-y += copyfile.o
perf-util-y += ctype.o
perf-util-y += db-export.o
perf-util-y += disasm.o
-perf-util-y += disasm_bpf.o
perf-util-y += env.o
perf-util-y += event.o
perf-util-y += evlist.o
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index bbb89b32f398..8b14a90a3a0c 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -446,7 +446,6 @@ enum symbol_disassemble_errno {
__SYMBOL_ANNOTATE_ERRNO__START = -10000,
SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX = __SYMBOL_ANNOTATE_ERRNO__START,
- SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF,
SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING,
SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP,
SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE,
diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c
index 175d9d3b5c97..683eb6aa7b53 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -17,7 +17,6 @@
#include "capstone.h"
#include "debug.h"
#include "disasm.h"
-#include "disasm_bpf.h"
#include "dso.h"
#include "dwarf-regs.h"
#include "env.h"
@@ -1231,9 +1230,6 @@ int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, s
" --vmlinux vmlinux\n", build_id_msg ?: "");
}
break;
- case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF:
- scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation");
- break;
case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP:
scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions.");
break;
@@ -1501,11 +1497,9 @@ static int symbol__disassemble_objdump(const char *filename, struct symbol *sym,
struct child_process objdump_process;
int err;
- if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO)
- return symbol__disassemble_bpf(sym, args);
-
- if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE)
- return symbol__disassemble_bpf_image(sym, args);
+ if (dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_PROG_INFO ||
+ dso__binary_type(dso) == DSO_BINARY_TYPE__BPF_IMAGE)
+ return -1;
err = asprintf(&command,
"%s %s%s --start-address=0x%016" PRIx64
diff --git a/tools/perf/util/disasm_bpf.c b/tools/perf/util/disasm_bpf.c
deleted file mode 100644
index a891a0b909a7..000000000000
--- a/tools/perf/util/disasm_bpf.c
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include "util/annotate.h"
-#include "util/disasm_bpf.h"
-#include "util/symbol.h"
-#include <linux/zalloc.h>
-#include <string.h>
-
-int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, struct annotate_args *args __maybe_unused)
-{
- return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
-}
-
-int symbol__disassemble_bpf_image(struct symbol *sym, struct annotate_args *args)
-{
- struct annotation *notes = symbol__annotation(sym);
- struct disasm_line *dl;
-
- args->offset = -1;
- args->line = strdup("to be implemented");
- args->line_nr = 0;
- args->fileloc = NULL;
- dl = 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 */
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 17/19] perf disasm: Make ins__scnprintf and ins__is_nop static
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (15 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 16/19] perf disasm: Remove disasm_bpf Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 18/19] perf srcline: Fallback between addr2line implementations Ian Rogers
` (2 subsequent siblings)
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
Reduce the scope of ins__scnprintf and ins__is_nop that aren't used
outside of disasm.c.
Signed-off-by: Ian Rogers <irogers@google.com>
---
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 683eb6aa7b53..72e7f1312fb4 100644
--- a/tools/perf/util/disasm.c
+++ b/tools/perf/util/disasm.c
@@ -246,8 +246,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);
}
-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);
@@ -824,7 +824,7 @@ static struct ins_ops ret_ops = {
.scnprintf = ins__raw_scnprintf,
};
-bool ins__is_nop(const struct ins *ins)
+static bool ins__is_nop(const struct ins *ins)
{
return ins->ops == &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);
struct ins_ops *ins__find(struct arch *arch, const char *name, struct disasm_line *dl);
-int ins__scnprintf(struct ins *ins, char *bf, size_t size,
- struct ins_operands *ops, int max_ins_name);
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);
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 18/19] perf srcline: Fallback between addr2line implementations
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (16 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 17/19] perf disasm: Make ins__scnprintf and ins__is_nop static Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 19/19] perf disasm: Remove unused evsel from annotate_args Ian Rogers
2025-04-18 21:29 ` [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Arnaldo Carvalho de Melo
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
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 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 <irogers@google.com>
---
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 | 482 ++----------------------------------
tools/perf/util/srcline.h | 1 -
8 files changed, 484 insertions(+), 469 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 cc22cc8a5aac..197c40543c6d 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
perf-util-y += arm64-frame-pointer-unwind-support.o
+perf-util-y += addr2line.o
perf-util-y += addr_location.o
perf-util-y += annotate.o
perf-util-y += block-info.o
diff --git a/tools/perf/util/addr2line.c b/tools/perf/util/addr2line.c
new file mode 100644
index 000000000000..2f6445c183aa
--- /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 <api/io.h>
+#include <linux/zalloc.h>
+#include <subcmd/run-command.h>
+
+#include <inttypes.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_INLINE_NEST 1024
+
+/* If addr2line doesn't return data for 1 second then timeout. */
+int addr2line_timeout_ms = 1 * 1000;
+
+static int filename_split(char *filename, unsigned int *line_nr)
+{
+ char *sep;
+
+ sep = strchr(filename, '\n');
+ if (sep)
+ *sep = '\0';
+
+ if (!strcmp(filename, "??:0"))
+ return 0;
+
+ sep = strchr(filename, ':');
+ if (sep) {
+ *sep++ = '\0';
+ *line_nr = 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 != -1) {
+ kill(a2l->pid, SIGKILL);
+ finish_command(a2l); /* ignore result, we don't care */
+ a2l->pid = -1;
+ close(a2l->in);
+ close(a2l->out);
+ }
+
+ free(a2l);
+}
+
+static struct child_process *addr2line_subprocess_init(const char *addr2line_path,
+ const char *binary_path)
+{
+ const char *argv[] = {
+ addr2line_path ?: "addr2line",
+ "-e", binary_path,
+ "-a", "-i", "-f", NULL
+ };
+ struct child_process *a2l = zalloc(sizeof(*a2l));
+ int start_command_status = 0;
+
+ if (a2l == NULL) {
+ pr_err("Failed to allocate memory for addr2line");
+ return NULL;
+ }
+
+ a2l->pid = -1;
+ a2l->in = -1;
+ a2l->out = -1;
+ a2l->no_stderr = 1;
+
+ a2l->argv = argv;
+ start_command_status = start_command(a2l);
+ a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */
+
+ if (start_command_status != 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) != 2)
+ return BROKEN;
+
+ io__init(&io, a2l->out, buf, sizeof(buf));
+ ch = io__get_char(&io);
+ if (ch == ',') {
+ style = LLVM;
+ cached = true;
+ lines = 1;
+ pr_debug("Detected LLVM addr2line style\n");
+ } else if (ch == '0') {
+ style = GNU_BINUTILS;
+ cached = true;
+ lines = 3;
+ pr_debug("Detected binutils addr2line style\n");
+ } else {
+ if (!symbol_conf.disable_add2line_warn) {
+ char *output = 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 = io__get_char(&io);
+ if (ch <= 0)
+ break;
+ if (ch == '\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 ==> error
+ * 0 ==> sentinel (or other ill-formed) record read
+ * 1 ==> a genuine record read
+ */
+ char *line = NULL;
+ size_t line_len = 0;
+ unsigned int dummy_line_nr = 0;
+ int ret = -1;
+
+ if (function != NULL)
+ zfree(function);
+
+ if (filename != NULL)
+ zfree(filename);
+
+ if (line_nr != NULL)
+ *line_nr = 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_debug("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line);
+ if (style == LLVM && line_len == 2 && line[0] == ',') {
+ /* Found the llvm-addr2line sentinel character. */
+ zfree(&line);
+ return 0;
+ } else if (style == GNU_BINUTILS && (!first || addr != 0)) {
+ int zero_count = 0, non_zero_count = 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 >= 2 || line[0] != '0' || line[1] != 'x') {
+ for (size_t i = 2; i < line_len; i++) {
+ if (line[i] == '0')
+ zero_count++;
+ else if (line[i] != '\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 = io__get_char(io);
+ } while (ch > 0 && ch != '\n');
+ do {
+ ch = io__get_char(io);
+ } while (ch > 0 && ch != '\n');
+ return 0;
+ }
+ }
+ }
+ /* Read the second function name line (if inline data then this is the first line). */
+ if (first && (io__getline(io, &line, &line_len) < 0 || !line_len))
+ goto error;
+
+ pr_debug("%s %s: addr2line read line: %s", __func__, dso_name, line);
+ if (function != NULL)
+ *function = strdup(strim(line));
+
+ zfree(&line);
+ line_len = 0;
+
+ /* Read the third filename and line number line. */
+ if (io__getline(io, &line, &line_len) < 0 || !line_len)
+ goto error;
+
+ pr_debug("%s %s: addr2line filename:number : %s", __func__, dso_name, line);
+ if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 &&
+ style == GNU_BINUTILS) {
+ ret = 0;
+ goto error;
+ }
+
+ if (filename != NULL)
+ *filename = strdup(line);
+
+ zfree(&line);
+ line_len = 0;
+
+ return 1;
+
+error:
+ free(line);
+ if (function != NULL)
+ zfree(function);
+ if (filename != 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 = new_inline_sym(dso, sym, function);
+
+ return inline_list__append(inline_sym, srcline_from_fileline(filename, line_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 = dso__a2l(dso);
+ char *record_function = NULL;
+ char *record_filename = NULL;
+ unsigned int record_line_nr = 0;
+ int record_status = -1;
+ int ret = 0;
+ size_t inline_count = 0;
+ int len;
+ char buf[128];
+ ssize_t written;
+ struct io io = { .eof = 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 = dso__a2l(dso);
+ }
+
+ if (a2l == NULL) {
+ if (!symbol_conf.disable_add2line_warn)
+ pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name);
+ goto out;
+ }
+ a2l_style = addr2line_configure(a2l, dso_name);
+ if (a2l_style == 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 = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr);
+ written = len > 0 ? write(a2l->in, buf, len) : -1;
+ if (written != 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 = addr2line_timeout_ms;
+ switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/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=*/1, /*first=*/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 = strdup(record_filename);
+ ret = 1;
+ }
+ if (line_nr)
+ *line_nr = record_line_nr;
+
+ if (unwind_inlines) {
+ if (node && inline_list__append_record(dso, node, sym,
+ record_function,
+ record_filename,
+ record_line_nr)) {
+ ret = 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 = read_addr2line_record(&io,
+ a2l_style,
+ dso_name,
+ /*addr=*/1,
+ /*first=*/false,
+ &record_function,
+ &record_filename,
+ &record_line_nr)) == 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 = 0;
+ goto out;
+ }
+ ret = 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 = 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 <linux/types.h>
+
+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_unused, u64 addr __maybe_unused
return num_frames;
}
-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, because
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);
-
-void dso__free_a2l_llvm(struct dso *dso);
-
int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
struct annotate_args *args);
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index 797e78826508..a5d8e994d9ea 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -1,30 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
-#include <inttypes.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <linux/compiler.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/zalloc.h>
-
-#include <api/io.h>
-
-#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 "llvm.h"
#include "symbol.h"
-#include "subcmd/run-command.h"
-/* If addr2line doesn't return data for 1 second then timeout. */
-int addr2line_timeout_ms = 1 * 1000;
+#include <inttypes.h>
+#include <string.h>
+
bool srcline_full_filename;
char *srcline__unknown = (char *)"??:0";
@@ -129,445 +113,22 @@ struct symbol *new_inline_sym(struct dso *dso,
return inline_sym;
}
-#define MAX_INLINE_NEST 1024
-
-#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, node, sym);
-}
-
-void dso__free_a2l(struct dso *dso)
-{
- dso__free_a2l_llvm(dso);
-}
-
-#else /* HAVE_LIBLLVM_SUPPORT */
-
-static int filename_split(char *filename, unsigned int *line_nr)
-{
- char *sep;
-
- sep = strchr(filename, '\n');
- if (sep)
- *sep = '\0';
-
- if (!strcmp(filename, "??:0"))
- return 0;
-
- sep = strchr(filename, ':');
- if (sep) {
- *sep++ = '\0';
- *line_nr = 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)
+ char **file, unsigned int *line_nr,
+ struct dso *dso,
+ bool unwind_inlines,
+ struct inline_node *node,
+ struct symbol *sym)
{
- if (a2l->pid != -1) {
- kill(a2l->pid, SIGKILL);
- finish_command(a2l); /* ignore result, we don't care */
- a2l->pid = -1;
- close(a2l->in);
- close(a2l->out);
- }
+ int ret;
- free(a2l);
-}
+ ret = llvm__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym);
+ if (ret > 0)
+ return ret;
-static struct child_process *addr2line_subprocess_init(const char *addr2line_path,
- const char *binary_path)
-{
- const char *argv[] = {
- addr2line_path ?: "addr2line",
- "-e", binary_path,
- "-a", "-i", "-f", NULL
- };
- struct child_process *a2l = zalloc(sizeof(*a2l));
- int start_command_status = 0;
-
- if (a2l == NULL) {
- pr_err("Failed to allocate memory for addr2line");
- return NULL;
- }
-
- a2l->pid = -1;
- a2l->in = -1;
- a2l->out = -1;
- a2l->no_stderr = 1;
-
- a2l->argv = argv;
- start_command_status = start_command(a2l);
- a2l->argv = NULL; /* it's not used after start_command; avoid dangling pointers */
-
- if (start_command_status != 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) != 2)
- return BROKEN;
-
- io__init(&io, a2l->out, buf, sizeof(buf));
- ch = io__get_char(&io);
- if (ch == ',') {
- style = LLVM;
- cached = true;
- lines = 1;
- pr_debug("Detected LLVM addr2line style\n");
- } else if (ch == '0') {
- style = GNU_BINUTILS;
- cached = true;
- lines = 3;
- pr_debug("Detected binutils addr2line style\n");
- } else {
- if (!symbol_conf.disable_add2line_warn) {
- char *output = 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 = io__get_char(&io);
- if (ch <= 0)
- break;
- if (ch == '\n')
- lines--;
- }
- /* Ignore SIGPIPE in the event addr2line exits. */
- signal(SIGPIPE, SIG_IGN);
- }
- return style;
+ return cmd__addr2line(dso_name, addr, file, line_nr, dso, unwind_inlines, node, sym);
}
-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 ==> error
- * 0 ==> sentinel (or other ill-formed) record read
- * 1 ==> a genuine record read
- */
- char *line = NULL;
- size_t line_len = 0;
- unsigned int dummy_line_nr = 0;
- int ret = -1;
-
- if (function != NULL)
- zfree(function);
-
- if (filename != NULL)
- zfree(filename);
-
- if (line_nr != NULL)
- *line_nr = 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_debug("%s %s: addr2line read address for sentinel: %s", __func__, dso_name, line);
- if (style == LLVM && line_len == 2 && line[0] == ',') {
- /* Found the llvm-addr2line sentinel character. */
- zfree(&line);
- return 0;
- } else if (style == GNU_BINUTILS && (!first || addr != 0)) {
- int zero_count = 0, non_zero_count = 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 >= 2 || line[0] != '0' || line[1] != 'x') {
- for (size_t i = 2; i < line_len; i++) {
- if (line[i] == '0')
- zero_count++;
- else if (line[i] != '\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 = io__get_char(io);
- } while (ch > 0 && ch != '\n');
- do {
- ch = io__get_char(io);
- } while (ch > 0 && ch != '\n');
- return 0;
- }
- }
- }
- /* Read the second function name line (if inline data then this is the first line). */
- if (first && (io__getline(io, &line, &line_len) < 0 || !line_len))
- goto error;
-
- pr_debug("%s %s: addr2line read line: %s", __func__, dso_name, line);
- if (function != NULL)
- *function = strdup(strim(line));
-
- zfree(&line);
- line_len = 0;
-
- /* Read the third filename and line number line. */
- if (io__getline(io, &line, &line_len) < 0 || !line_len)
- goto error;
-
- pr_debug("%s %s: addr2line filename:number : %s", __func__, dso_name, line);
- if (filename_split(line, line_nr == NULL ? &dummy_line_nr : line_nr) == 0 &&
- style == GNU_BINUTILS) {
- ret = 0;
- goto error;
- }
-
- if (filename != NULL)
- *filename = strdup(line);
-
- zfree(&line);
- line_len = 0;
-
- return 1;
-
-error:
- free(line);
- if (function != NULL)
- zfree(function);
- if (filename != 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 = new_inline_sym(dso, sym, function);
-
- return inline_list__append(inline_sym, srcline_from_fileline(filename, line_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 = dso__a2l(dso);
- char *record_function = NULL;
- char *record_filename = NULL;
- unsigned int record_line_nr = 0;
- int record_status = -1;
- int ret = 0;
- size_t inline_count = 0;
- int len;
- char buf[128];
- ssize_t written;
- struct io io = { .eof = 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 = dso__a2l(dso);
- }
-
- if (a2l == NULL) {
- if (!symbol_conf.disable_add2line_warn)
- pr_warning("%s %s: addr2line_subprocess_init failed\n", __func__, dso_name);
- goto out;
- }
- a2l_style = addr2line_configure(a2l, dso_name);
- if (a2l_style == 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 = snprintf(buf, sizeof(buf), "%016"PRIx64"\n,\n", addr);
- written = len > 0 ? write(a2l->in, buf, len) : -1;
- if (written != 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 = addr2line_timeout_ms;
- switch (read_addr2line_record(&io, a2l_style, dso_name, addr, /*first=*/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=*/1, /*first=*/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 = strdup(record_filename);
- ret = 1;
- }
- if (line_nr)
- *line_nr = record_line_nr;
-
- if (unwind_inlines) {
- if (node && inline_list__append_record(dso, node, sym,
- record_function,
- record_filename,
- record_line_nr)) {
- ret = 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 = read_addr2line_record(&io,
- a2l_style,
- dso_name,
- /*addr=*/1,
- /*first=*/false,
- &record_function,
- &record_filename,
- &record_line_nr)) == 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 = 0;
- goto out;
- }
- ret = 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 = dso__a2l(dso);
-
- if (!a2l)
- return;
-
- addr2line_subprocess_cleanup(a2l);
-
- dso__set_a2l(dso, NULL);
-}
-
-#endif /* HAVE_LIBLLVM_SUPPORT */
-
static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
struct dso *dso, struct symbol *sym)
{
@@ -582,7 +143,9 @@ static struct inline_node *addr2inlines(const char *dso_name, u64 addr,
INIT_LIST_HEAD(&node->val);
node->addr = addr;
- addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym);
+ addr2line(dso_name, addr, /*file=*/NULL, /*line_nr=*/NULL, dso,
+ /*unwind_inlines=*/true, node, sym);
+
return node;
}
@@ -609,7 +172,7 @@ char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
goto out_err;
if (!addr2line(dso_name, addr, &file, &line, dso,
- unwind_inlines, NULL, sym))
+ unwind_inlines, /*node=*/NULL, sym))
goto out_err;
srcline = srcline_from_fileline(file, line);
@@ -655,7 +218,8 @@ char *get_srcline_split(struct dso *dso, u64 addr, unsigned *line)
if (dso_name == NULL)
goto out_err;
- if (!addr2line(dso_name, addr, &file, line, dso, true, NULL, NULL))
+ if (!addr2line(dso_name, addr, &file, line, dso, /*unwind_inlines=*/true,
+ /*node=*/NULL, /*sym=*/NULL))
goto out_err;
dso__set_a2l_fails(dso, 0);
diff --git a/tools/perf/util/srcline.h b/tools/perf/util/srcline.h
index 80c20169e250..ce03b90dea1d 100644
--- a/tools/perf/util/srcline.h
+++ b/tools/perf/util/srcline.h
@@ -9,7 +9,6 @@
struct dso;
struct symbol;
-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);
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [PATCH v4 19/19] perf disasm: Remove unused evsel from annotate_args
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (17 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 18/19] perf srcline: Fallback between addr2line implementations Ian Rogers
@ 2025-04-17 23:07 ` Ian Rogers
2025-04-18 21:29 ` [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Arnaldo Carvalho de Melo
19 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-04-17 23:07 UTC (permalink / raw)
To: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Ian Rogers, Adrian Hunter, Kan Liang, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Aditya Gupta,
Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
Set in symbol__annotate but never used.
Signed-off-by: Ian Rogers <irogers@google.com>
---
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 264a212b47df..a2a2849a5b79 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -1013,7 +1013,6 @@ int symbol__annotate(struct map_symbol *ms, struct evsel *evsel,
struct symbol *sym = ms->sym;
struct annotation *notes = symbol__annotation(sym);
struct annotate_args args = {
- .evsel = evsel,
.options = &annotate_opts,
};
struct arch *arch = 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;
--
2.49.0.805.g082f7c87e0-goog
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
` (18 preceding siblings ...)
2025-04-17 23:07 ` [PATCH v4 19/19] perf disasm: Remove unused evsel from annotate_args Ian Rogers
@ 2025-04-18 21:29 ` Arnaldo Carvalho de Melo
2025-04-19 4:22 ` Ian Rogers
19 siblings, 1 reply; 28+ messages in thread
From: Arnaldo Carvalho de Melo @ 2025-04-18 21:29 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
On Thu, Apr 17, 2025 at 04:07:21PM -0700, Ian Rogers wrote:
> Linking against libcapstone and libLLVM can be a significant increase
> in dependencies and file size if building statically. For something
> like `perf record` the disassembler and addr2line functionality won't
> be used. Support dynamically loading these libraries using dlopen and
> then calling the appropriate functions found using dlsym.
>
> BUILD_NONDISTRO is used to build perf against the license incompatible
> libbfd and libiberty libraries. As this has been opt-in for nearly 2
> years, commit dd317df07207 ("perf build: Make binutil libraries opt
> in"), remove the code to simplify the code base.
>
> The patch series:
> 1) does some initial clean up;
> 2) moves the capstone and LLVM code to their own C files,
> 3) simplifies a little the capstone code;
> 4) adds perf_ variants of the functions that will either directly call
> the function or use dlsym to discover it;
> 5) adds BPF JIT disassembly support to LLVM and capstone disassembly;
> 6) removes the BUILD_NONDISTRO code, reduces scope and removes what's possible;
> 7) adds fallback to srcline's addr2line so that llvm_addr2line is
> tried first and then the forked command tried next, moving the code
> for forking out of the main srcline.c file in the process.
>
> The addr2line LLVM functionality is written in C++. To avoid linking
> against libLLVM for this, a new LIBLLVM_DYNAMIC option is added where
> the C++ code with the libLLVM dependency will be built into a
> libperf-llvm.so and that dlsym-ed and called against. Ideally LLVM
> would extend their C API to avoid this.
>
> The libbfd BPF disassembly supported source lines, this wasn't ported
> to the capstone and LLVM disassembly.
Doing the build tests I noticed, so far:
29 58.92 opensuse:15.4 : FAIL gcc version 7.5.0 (SUSE Linux)
<SNIP>
+ make NO_LIBTRACEEVENT=1 ARCH= CROSS_COMPILE= EXTRA_CFLAGS= NO_LIBBPF=1 -C tools/perf O=/tmp/build/perf
make: Entering directory '/git/perf-6.15.0-rc2/tools/perf'
BUILD: Doing 'make -j32' parallel build
Warning: Skipped check-headers due to missing ../../include
Makefile.config:560: No elfutils/debuginfod.h found, no debuginfo server support, please install libdebuginfod-dev/elfutils-debuginfod-client-devel or equivalent
Makefile.config:687: Warning: Disabled BPF skeletons as libbpf is required
Makefile.config:1039: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev
update-alternatives: error: no alternatives for java
update-alternatives: error: no alternatives for java
Makefile.config:1100: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel
Makefile.config:1113: libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev
Auto-detecting system features:
... libdw: [ on ]
... glibc: [ on ]
... libelf: [ on ]
... libnuma: [ on ]
... numa_num_possible_cpus: [ on ]
... libperl: [ on ]
... libpython: [ on ]
... libcrypto: [ on ]
... libcapstone: [ on ]
... llvm-perf: [ on ]
... zlib: [ on ]
... lzma: [ on ]
... get_cpuid: [ on ]
... bpf: [ on ]
... libaio: [ on ]
... libzstd: [ on ]
PERF_VERSION = 6.15.rc2.gfbcac9367d45
GEN /tmp/build/perf/common-cmds.h
GEN /tmp/build/perf/arch/arm64/include/generated/asm/sysreg-defs.h
GEN perf-archive
GEN perf-iostat
CC /tmp/build/perf/dlfilters/dlfilter-test-api-v0.o
CC /tmp/build/perf/dlfilters/dlfilter-test-api-v2.o
CC /tmp/build/perf/dlfilters/dlfilter-show-cycles.o
INSTALL /tmp/build/perf/libapi/include/api/cpu.h
INSTALL /tmp/build/perf/libapi/include/api/debug.h
INSTALL /tmp/build/perf/libapi/include/api/io.h
MKDIR /tmp/build/perf/libapi/fd/
INSTALL /tmp/build/perf/libapi/include/api/io_dir.h
CC /tmp/build/perf/libapi/cpu.o
MKDIR /tmp/build/perf/libapi/fs/
INSTALL /tmp/build/perf/libapi/include/api/fd/array.h
CC /tmp/build/perf/libapi/debug.o
MKDIR /tmp/build/perf/libapi/fs/
MKDIR /tmp/build/perf/libapi/fs/
CC /tmp/build/perf/libapi/fd/array.o
INSTALL /tmp/build/perf/libapi/include/api/fs/tracing_path.h
CC /tmp/build/perf/libapi/str_error_r.o
INSTALL /tmp/build/perf/libapi/include/api/fs/fs.h
CC /tmp/build/perf/libapi/fs/tracing_path.o
CC /tmp/build/perf/libapi/fs/fs.o
CC /tmp/build/perf/libapi/fs/cgroup.o
INSTALL libapi_headers
INSTALL /tmp/build/perf/libperf/include/perf/bpf_perf.h
INSTALL /tmp/build/perf/libperf/include/perf/core.h
INSTALL /tmp/build/perf/libperf/include/perf/cpumap.h
INSTALL /tmp/build/perf/libperf/include/perf/threadmap.h
CC /tmp/build/perf/libperf/core.o
CC /tmp/build/perf/libperf/cpumap.o
CC /tmp/build/perf/libperf/threadmap.o
INSTALL /tmp/build/perf/libperf/include/perf/evlist.h
CC /tmp/build/perf/libperf/evlist.o
CC /tmp/build/perf/libperf/evsel.o
CC /tmp/build/perf/libperf/mmap.o
CC /tmp/build/perf/libperf/zalloc.o
INSTALL /tmp/build/perf/libsubcmd/include/subcmd/exec-cmd.h
INSTALL /tmp/build/perf/libperf/include/perf/evsel.h
CC /tmp/build/perf/libperf/xyarray.o
CC /tmp/build/perf/libperf/lib.o
INSTALL /tmp/build/perf/libsubcmd/include/subcmd/help.h
INSTALL /tmp/build/perf/libsubcmd/include/subcmd/pager.h
LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v0.so
INSTALL /tmp/build/perf/libsubcmd/include/subcmd/parse-options.h
LD /tmp/build/perf/libapi/fd/libapi-in.o
INSTALL /tmp/build/perf/libsubcmd/include/subcmd/run-command.h
INSTALL libsubcmd_headers
LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v2.so
INSTALL /tmp/build/perf/libperf/include/perf/event.h
INSTALL /tmp/build/perf/libsymbol/include/symbol/kallsyms.h
CC /tmp/build/perf/libsymbol/kallsyms.o
INSTALL /tmp/build/perf/libperf/include/perf/mmap.h
INSTALL /tmp/build/perf/libperf/include/internal/cpumap.h
INSTALL /tmp/build/perf/libperf/include/internal/evlist.h
INSTALL /tmp/build/perf/libperf/include/internal/evsel.h
INSTALL /tmp/build/perf/libperf/include/internal/rc_check.h
INSTALL /tmp/build/perf/libperf/include/internal/mmap.h
INSTALL /tmp/build/perf/libperf/include/internal/threadmap.h
INSTALL /tmp/build/perf/libperf/include/internal/lib.h
INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h
LINK /tmp/build/perf/dlfilters/dlfilter-show-cycles.so
LD /tmp/build/perf/libapi/fs/libapi-in.o
evlist.c:28:6: error: no previous prototype for 'perf_evlist__init' [-Werror=missing-prototypes]
void perf_evlist__init(struct perf_evlist *evlist)
^~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__init':
evlist.c:30:24: error: dereferencing pointer to incomplete type 'struct perf_evlist'
INIT_LIST_HEAD(&evlist->entries);
^~
evlist.c:33:2: error: implicit declaration of function 'perf_evlist__reset_id_hash'; did you mean 'perf_evlist__set_maps'? [-Werror=implicit-function-declaration]
perf_evlist__reset_id_hash(evlist);
^~~~~~~~~~~~~~~~~~~~~~~~~~
perf_evlist__set_maps
evlist.c:33:2: error: nested extern declaration of 'perf_evlist__reset_id_hash' [-Werror=nested-externs]
evlist.c: In function 'perf_evlist__purge':
evlist.c:157:2: error: implicit declaration of function 'perf_evlist__for_each_entry_safe'; did you mean 'hlist_for_each_entry_safe'? [-Werror=implicit-function-declaration]
perf_evlist__for_each_entry_safe(evlist, n, pos) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
hlist_for_each_entry_safe
evlist.c:157:2: error: nested extern declaration of 'perf_evlist__for_each_entry_safe' [-Werror=nested-externs]
evlist.c:157:51: error: expected ';' before '{' token
perf_evlist__for_each_entry_safe(evlist, n, pos) {
^
evlist.c: At top level:
evlist.c:165:6: error: no previous prototype for 'perf_evlist__exit' [-Werror=missing-prototypes]
void perf_evlist__exit(struct perf_evlist *evlist)
^~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__open':
evlist.c:217:2: error: implicit declaration of function 'perf_evlist__for_each_entry'; did you mean 'perf_evlist__for_each_evsel'? [-Werror=implicit-function-declaration]
perf_evlist__for_each_entry(evlist, evsel) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~
perf_evlist__for_each_evsel
evlist.c:217:2: error: nested extern declaration of 'perf_evlist__for_each_entry' [-Werror=nested-externs]
evlist.c:217:45: error: expected ';' before '{' token
perf_evlist__for_each_entry(evlist, evsel) {
^
evlist.c:225:1: error: label 'out_err' defined but not used [-Werror=unused-label]
out_err:
^~~~~~~
INSTALL libperf_headers
evlist.c: In function 'perf_evlist__close':
evlist.c:234:2: error: implicit declaration of function 'perf_evlist__for_each_entry_reverse'; did you mean 'list_for_each_entry_reverse'? [-Werror=implicit-function-declaration]
perf_evlist__for_each_entry_reverse(evlist, evsel)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
list_for_each_entry_reverse
evlist.c:234:2: error: nested extern declaration of 'perf_evlist__for_each_entry_reverse' [-Werror=nested-externs]
evlist.c:235:3: error: expected ';' before 'perf_evsel__close'
perf_evsel__close(evsel);
^~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__enable':
evlist.c:243:3: error: expected ';' before 'perf_evsel__enable'
perf_evsel__enable(evsel);
^~~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__disable':
evlist.c:251:3: error: expected ';' before 'perf_evsel__disable'
perf_evsel__disable(evsel);
^~~~~~~~~~~~~~~~~~~
evlist.c: At top level:
evlist.c:254:5: error: no previous prototype for 'perf_evlist__read_format' [-Werror=missing-prototypes]
u64 perf_evlist__read_format(struct perf_evlist *evlist)
^~~~~~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__read_format':
evlist.c:256:29: error: implicit declaration of function 'perf_evlist__first'; did you mean 'perf_evlist__init'? [-Werror=implicit-function-declaration]
struct perf_evsel *first = perf_evlist__first(evlist);
^~~~~~~~~~~~~~~~~~
perf_evlist__init
evlist.c:256:29: error: nested extern declaration of 'perf_evlist__first' [-Werror=nested-externs]
evlist.c:256:29: error: initialization makes pointer from integer without a cast [-Werror=int-conversion]
INSTALL libsymbol_headers
evlist.c: In function 'perf_evlist__id_hash':
evlist.c:272:26: error: 'PERF_EVLIST__HLIST_BITS' undeclared (first use in this function); did you mean 'PERF_SAMPLE_ID__HLIST_BITS'?
hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
^~~~~~~~~~~~~~~~~~~~~~~
PERF_SAMPLE_ID__HLIST_BITS
evlist.c:272:26: note: each undeclared identifier is reported only once for each function it appears in
evlist.c:267:6: error: variable 'hash' set but not used [-Werror=unused-but-set-variable]
int hash;
^~~~
evlist.c: At top level:
evlist.c:276:6: error: no previous prototype for 'perf_evlist__reset_id_hash' [-Werror=missing-prototypes]
void perf_evlist__reset_id_hash(struct perf_evlist *evlist)
^~~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c:276:6: error: conflicting types for 'perf_evlist__reset_id_hash' [-Werror]
evlist.c:33:2: note: previous implicit declaration of 'perf_evlist__reset_id_hash' was here
perf_evlist__reset_id_hash(evlist);
^~~~~~~~~~~~~~~~~~~~~~~~~~
LD /tmp/build/perf/libapi/libapi-in.o
evlist.c: In function 'perf_evlist__reset_id_hash':
evlist.c:280:18: error: 'PERF_EVLIST__HLIST_SIZE' undeclared (first use in this function); did you mean 'PERF_SAMPLE_ID__HLIST_SIZE'?
for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
^~~~~~~~~~~~~~~~~~~~~~~
PERF_SAMPLE_ID__HLIST_SIZE
evlist.c: At top level:
evlist.c:284:6: error: no previous prototype for 'perf_evlist__id_add' [-Werror=missing-prototypes]
void perf_evlist__id_add(struct perf_evlist *evlist,
^~~~~~~~~~~~~~~~~~~
evlist.c:295:5: error: no previous prototype for 'perf_evlist__id_add_fd' [-Werror=missing-prototypes]
int perf_evlist__id_add_fd(struct perf_evlist *evlist,
^~~~~~~~~~~~~~~~~~~~~~
evlist.c:339:5: error: no previous prototype for 'perf_evlist__alloc_pollfd' [-Werror=missing-prototypes]
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
^~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__alloc_pollfd':
evlist.c:346:45: error: expected ';' before '{' token
perf_evlist__for_each_entry(evlist, evsel) {
^
evlist.c:343:6: error: unused variable 'nfds' [-Werror=unused-variable]
int nfds = 0;
^~~~
evlist.c:342:6: error: unused variable 'nr_threads' [-Werror=unused-variable]
int nr_threads = perf_thread_map__nr(evlist->threads);
^~~~~~~~~~
evlist.c:341:6: error: unused variable 'nr_cpus' [-Werror=unused-variable]
int nr_cpus = perf_cpu_map__nr(evlist->all_cpus);
^~~~~~~
evlist.c: At top level:
evlist.c:360:5: error: no previous prototype for 'perf_evlist__add_pollfd' [-Werror=missing-prototypes]
int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd,
^~~~~~~~~~~~~~~~~~~~~~~
evlist.c:469:51: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'mmap_per_evsel':
evlist.c:477:45: error: expected ';' before '{' token
perf_evlist__for_each_entry(evlist, evsel) {
^
evlist.c:475:6: error: unused variable 'revent' [-Werror=unused-variable]
int revent;
^~~~~~
evlist.c:473:18: error: unused variable 'evlist_cpu' [-Werror=unused-variable]
struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->all_cpus, cpu_idx);
^~~~~~~~~~
evlist.c:560:1: error: no return statement in function returning non-void [-Werror=return-type]
}
^
evlist.c:469:73: error: unused parameter 'ops' [-Werror=unused-parameter]
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~
evlist.c:470:13: error: unused parameter 'idx' [-Werror=unused-parameter]
int idx, struct perf_mmap_param *mp, int cpu_idx,
^~~
evlist.c:470:42: error: unused parameter 'mp' [-Werror=unused-parameter]
int idx, struct perf_mmap_param *mp, int cpu_idx,
^~
evlist.c:471:13: error: unused parameter 'thread' [-Werror=unused-parameter]
int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
^~~~~~
evlist.c:471:26: error: unused parameter '_output' [-Werror=unused-parameter]
int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
^~~~~~~
evlist.c:471:40: error: unused parameter '_output_overwrite' [-Werror=unused-parameter]
int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
^~~~~~~~~~~~~~~~~
evlist.c:471:64: error: unused parameter 'nr_mmaps' [-Werror=unused-parameter]
int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
^~~~~~~~
evlist.c: At top level:
evlist.c:563:52: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'mmap_per_thread':
evlist.c:579:30: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (mmap_per_evsel(evlist, ops, idx, mp, 0, thread, &output,
^~~
evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~
evlist.c:589:30: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (mmap_per_evsel(evlist, ops, idx, mp, cpu, 0, &output,
^~~
evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~
evlist.c: At top level:
evlist.c:605:49: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'mmap_per_cpu':
evlist.c:620:31: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
^~~
evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~
evlist.c: At top level:
evlist.c:653:13: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~~~~~~~
evlist.c:652:5: error: no previous prototype for 'perf_evlist__mmap_ops' [-Werror=missing-prototypes]
int perf_evlist__mmap_ops(struct perf_evlist *evlist,
^~~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__mmap_ops':
evlist.c:659:18: error: dereferencing pointer to incomplete type 'struct perf_evlist_mmap_ops'
if (!ops || !ops->get || !ops->mmap)
^~
evlist.c:666:45: error: expected ';' before '{' token
perf_evlist__for_each_entry(evlist, evsel) {
^
evlist.c:677:34: error: passing argument 2 of 'mmap_per_thread' from incompatible pointer type [-Werror=incompatible-pointer-types]
return mmap_per_thread(evlist, ops, mp);
^~~
evlist.c:563:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~~~~
evlist.c:679:30: error: passing argument 2 of 'mmap_per_cpu' from incompatible pointer type [-Werror=incompatible-pointer-types]
return mmap_per_cpu(evlist, ops, mp);
^~~
evlist.c:605:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
^~~~~~~~~~~~
evlist.c: In function 'perf_evlist__mmap':
evlist.c:685:9: error: variable 'ops' has initializer but incomplete type
struct perf_evlist_mmap_ops ops = {
^~~~~~~~~~~~~~~~~~~~
evlist.c:686:4: error: 'struct perf_evlist_mmap_ops' has no member named 'get'
.get = perf_evlist__mmap_cb_get,
^~~
evlist.c:686:11: error: excess elements in struct initializer [-Werror]
.get = perf_evlist__mmap_cb_get,
^~~~~~~~~~~~~~~~~~~~~~~~
evlist.c:686:11: note: (near initialization for 'ops')
evlist.c:687:4: error: 'struct perf_evlist_mmap_ops' has no member named 'mmap'
.mmap = perf_evlist__mmap_cb_mmap,
^~~~
evlist.c:687:11: error: excess elements in struct initializer [-Werror]
.mmap = perf_evlist__mmap_cb_mmap,
^~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c:687:11: note: (near initialization for 'ops')
evlist.c:685:30: error: storage size of 'ops' isn't known
struct perf_evlist_mmap_ops ops = {
^~~
evlist.c:685:30: error: unused variable 'ops' [-Werror=unused-variable]
evlist.c: At top level:
evlist.c:723:6: error: no previous prototype for '__perf_evlist__set_leader' [-Werror=missing-prototypes]
void __perf_evlist__set_leader(struct list_head *list, struct perf_evsel *leader)
^~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c: In function '__perf_evlist__set_leader':
evlist.c:728:2: error: implicit declaration of function '__perf_evlist__for_each_entry'; did you mean 'perf_evlist__for_each_evsel'? [-Werror=implicit-function-declaration]
__perf_evlist__for_each_entry(list, evsel) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
perf_evlist__for_each_evsel
evlist.c:728:2: error: nested extern declaration of '__perf_evlist__for_each_entry' [-Werror=nested-externs]
evlist.c:728:45: error: expected ';' before '{' token
__perf_evlist__for_each_entry(list, evsel) {
^
evlist.c:726:6: error: unused variable 'n' [-Werror=unused-variable]
int n = 0;
^
evlist.c:723:75: error: unused parameter 'leader' [-Werror=unused-parameter]
void __perf_evlist__set_leader(struct list_head *list, struct perf_evsel *leader)
^~~~~~
evlist.c: At top level:
evlist.c:762:6: error: no previous prototype for 'perf_evlist__go_system_wide' [-Werror=missing-prototypes]
void perf_evlist__go_system_wide(struct perf_evlist *evlist, struct perf_evsel *evsel)
^~~~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c: In function 'perf_evlist__filter_pollfd':
evlist.c:386:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
evlist.c: In function 'perf_evlist__poll':
evlist.c:391:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
evlist.c: In function 'perf_evlist__mmap':
evlist.c:693:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
evlist.c: In function 'perf_evlist__next_mmap':
evlist.c:721:1: error: control reaches end of non-void function [-Werror=return-type]
}
^
At top level:
evlist.c:459:13: error: 'perf_evlist__set_mmap_first' defined but not used [-Werror=unused-function]
static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map,
^~~~~~~~~~~~~~~~~~~~~~~~~~~
evlist.c:420:13: error: 'perf_evsel__set_sid_idx' defined but not used [-Werror=unused-function]
static void perf_evsel__set_sid_idx(struct perf_evsel *evsel, int idx, int cpu, int thread)
^~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make[4]: *** [/git/perf-6.15.0-rc2/tools/build/Makefile.build:85: /tmp/build/perf/libperf/evlist.o] Error 1
make[4]: *** Waiting for unfinished jobs....
AR /tmp/build/perf/libapi/libapi.a
CC /tmp/build/perf/libsubcmd/exec-cmd.o
CC /tmp/build/perf/libsubcmd/help.o
CC /tmp/build/perf/libsubcmd/pager.o
CC /tmp/build/perf/libsubcmd/run-command.o
CC /tmp/build/perf/libsubcmd/parse-options.o
CC /tmp/build/perf/libsubcmd/sigchain.o
CC /tmp/build/perf/libsubcmd/subcmd-config.o
LD /tmp/build/perf/libsymbol/libsymbol-in.o
AR /tmp/build/perf/libsymbol/libsymbol.a
make[3]: *** [Makefile:103: /tmp/build/perf/libperf/libperf-in.o] Error 2
make[2]: *** [Makefile.perf:976: /tmp/build/perf/libperf/libperf.a] Error 2
make[2]: *** Waiting for unfinished jobs....
LD /tmp/build/perf/libsubcmd/libsubcmd-in.o
AR /tmp/build/perf/libsubcmd/libsubcmd.a
make[1]: *** [Makefile.perf:287: sub-make] Error 2
make: *** [Makefile:76: all] Error 2
make: Leaving directory '/git/perf-6.15.0-rc2/tools/perf'
+ exit 1
toolsbuilder@number:~/git/linux-tools-container-builds$
23 18.51 fedora:38 : FAIL gcc version 13.2.1 20240316 (Red Hat 13.2.1-7) (GCC)
<SNIP>
evsel.c:23:6: error: no previous prototype for 'perf_evsel__init' [-Werror=missing-prototypes]
23 | void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
| ^~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__init':
evsel.c:26:30: error: invalid use of undefined type 'struct perf_evsel'
26 | INIT_LIST_HEAD(&evsel->node);
| ^~
evsel.c:27:30: error: invalid use of undefined type 'struct perf_evsel'
27 | INIT_LIST_HEAD(&evsel->per_stream_periods);
| ^~
evsel.c:28:14: error: invalid use of undefined type 'struct perf_evsel'
28 | evsel->attr = *attr;
| ^~
evsel.c:28:23: error: invalid use of undefined type 'struct perf_event_attr'
28 | evsel->attr = *attr;
| ^
evsel.c:29:14: error: invalid use of undefined type 'struct perf_evsel'
29 | evsel->idx = idx;
| ^~
evsel.c:30:14: error: invalid use of undefined type 'struct perf_evsel'
30 | evsel->leader = evsel;
| ^~
evsel.c: In function 'perf_evsel__new':
evsel.c:35:49: error: invalid application of 'sizeof' to incomplete type 'struct perf_evsel'
35 | struct perf_evsel *evsel = zalloc(sizeof(*evsel));
| ^
evsel.c: At top level:
evsel.c:54:5: error: no previous prototype for 'perf_evsel__alloc_fd' [-Werror=missing-prototypes]
54 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
| ^~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__alloc_fd':
evsel.c:56:14: error: invalid use of undefined type 'struct perf_evsel'
56 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
| ^~
evsel.c:58:18: error: invalid use of undefined type 'struct perf_evsel'
58 | if (evsel->fd) {
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:63:43: note: in expansion of macro 'FD'
63 | int *fd = FD(evsel, idx, thread);
| ^~
evsel.c:71:21: error: invalid use of undefined type 'struct perf_evsel'
71 | return evsel->fd != NULL ? 0 : -ENOMEM;
| ^~
evsel.c: In function 'perf_evsel__alloc_mmap':
evsel.c:76:14: error: invalid use of undefined type 'struct perf_evsel'
76 | evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
| ^~
evsel.c:78:21: error: invalid use of undefined type 'struct perf_evsel'
78 | return evsel->mmap != NULL ? 0 : -ENOMEM;
| ^~
evsel.c: In function 'get_group_fd':
evsel.c:91:42: error: invalid use of undefined type 'struct perf_evsel'
91 | struct perf_evsel *leader = evsel->leader;
| ^~
evsel.c:103:20: error: invalid use of undefined type 'struct perf_evsel'
103 | if (!leader->fd)
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:106:14: note: in expansion of macro 'FD'
106 | fd = FD(leader, cpu_map_idx, thread);
| ^~
evsel.c: In function 'perf_evsel__open':
evsel.c:145:18: error: invalid use of undefined type 'struct perf_evsel'
145 | if (evsel->fd == NULL &&
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:153:36: note: in expansion of macro 'FD'
153 | evsel_fd = FD(evsel, idx, thread);
| ^~
evsel.c:163:56: error: invalid use of undefined type 'struct perf_evsel'
163 | fd = sys_perf_event_open(&evsel->attr,
| ^~
evsel.c: In function 'perf_evsel__close_fd_cpu':
evsel.c:186:55: error: invalid use of undefined type 'struct perf_evsel'
186 | for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:187:27: note: in expansion of macro 'FD'
187 | int *fd = FD(evsel, cpu_map_idx, thread);
| ^~
evsel.c: At top level:
evsel.c:196:6: error: no previous prototype for 'perf_evsel__close_fd' [-Werror=missing-prototypes]
196 | void perf_evsel__close_fd(struct perf_evsel *evsel)
| ^~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__close_fd':
evsel.c:198:53: error: invalid use of undefined type 'struct perf_evsel'
198 | for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
| ^~
evsel.c: At top level:
evsel.c:202:6: error: no previous prototype for 'perf_evsel__free_fd' [-Werror=missing-prototypes]
202 | void perf_evsel__free_fd(struct perf_evsel *evsel)
| ^~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__free_fd':
evsel.c:204:30: error: invalid use of undefined type 'struct perf_evsel'
204 | xyarray__delete(evsel->fd);
| ^~
evsel.c:205:14: error: invalid use of undefined type 'struct perf_evsel'
205 | evsel->fd = NULL;
| ^~
evsel.c: In function 'perf_evsel__close':
evsel.c:210:18: error: invalid use of undefined type 'struct perf_evsel'
210 | if (evsel->fd == NULL)
| ^~
evsel.c: In function 'perf_evsel__close_cpu':
evsel.c:219:18: error: invalid use of undefined type 'struct perf_evsel'
219 | if (evsel->fd == NULL)
| ^~
evsel.c: In function 'perf_evsel__munmap':
evsel.c:229:18: error: invalid use of undefined type 'struct perf_evsel'
229 | if (evsel->fd == NULL || evsel->mmap == NULL)
| ^~
evsel.c:229:39: error: invalid use of undefined type 'struct perf_evsel'
229 | if (evsel->fd == NULL || evsel->mmap == NULL)
| ^~
evsel.c:232:49: error: invalid use of undefined type 'struct perf_evsel'
232 | for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
| ^~
evsel.c:233:63: error: invalid use of undefined type 'struct perf_evsel'
233 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:234:35: note: in expansion of macro 'FD'
234 | int *fd = FD(evsel, idx, thread);
| ^~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:239:43: note: in expansion of macro 'MMAP'
239 | perf_mmap__munmap(MMAP(evsel, idx, thread));
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:239:43: note: in expansion of macro 'MMAP'
239 | perf_mmap__munmap(MMAP(evsel, idx, thread));
| ^~~~
evsel.c:243:30: error: invalid use of undefined type 'struct perf_evsel'
243 | xyarray__delete(evsel->mmap);
| ^~
evsel.c:244:14: error: invalid use of undefined type 'struct perf_evsel'
244 | evsel->mmap = NULL;
| ^~
evsel.c: In function 'perf_evsel__mmap':
evsel.c:255:18: error: invalid use of undefined type 'struct perf_evsel'
255 | if (evsel->fd == NULL || evsel->mmap)
| ^~
evsel.c:255:39: error: invalid use of undefined type 'struct perf_evsel'
255 | if (evsel->fd == NULL || evsel->mmap)
| ^~
evsel.c:258:63: error: invalid use of undefined type 'struct perf_evsel'
258 | if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
| ^~
evsel.c:258:90: error: invalid use of undefined type 'struct perf_evsel'
258 | if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
| ^~
evsel.c:261:49: error: invalid use of undefined type 'struct perf_evsel'
261 | for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
| ^~
evsel.c:262:63: error: invalid use of undefined type 'struct perf_evsel'
262 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
| ^~
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:263:35: note: in expansion of macro 'FD'
263 | int *fd = FD(evsel, idx, thread);
| ^~
evsel.c:265:70: error: invalid use of undefined type 'struct perf_evsel'
265 | struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
| ^~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:270:31: note: in expansion of macro 'MMAP'
270 | map = MMAP(evsel, idx, thread);
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:270:31: note: in expansion of macro 'MMAP'
270 | map = MMAP(evsel, idx, thread);
| ^~~~
evsel.c: In function 'perf_evsel__mmap_base':
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:286:19: note: in expansion of macro 'FD'
286 | int *fd = FD(evsel, cpu_map_idx, thread);
| ^~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:288:38: note: in expansion of macro 'MMAP'
288 | if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:288:38: note: in expansion of macro 'MMAP'
288 | if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
| ^~~~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:291:16: note: in expansion of macro 'MMAP'
291 | return MMAP(evsel, cpu_map_idx, thread)->base;
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:291:16: note: in expansion of macro 'MMAP'
291 | return MMAP(evsel, cpu_map_idx, thread)->base;
| ^~~~
evsel.c: At top level:
evsel.c:294:5: error: no previous prototype for 'perf_evsel__read_size' [-Werror=missing-prototypes]
294 | int perf_evsel__read_size(struct perf_evsel *evsel)
| ^~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__read_size':
evsel.c:296:32: error: invalid use of undefined type 'struct perf_evsel'
296 | u64 read_format = evsel->attr.read_format;
| ^~
evsel.c:301:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
301 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:301:27: note: each undeclared identifier is reported only once for each function it appears in
evsel.c:304:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
304 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:307:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
307 | if (read_format & PERF_FORMAT_ID)
| ^~~~~~~~~~~~~~
evsel.c:310:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
310 | if (read_format & PERF_FORMAT_LOST)
| ^~~~~~~~~~~~~~~~
evsel.c:313:27: error: 'PERF_FORMAT_GROUP' undeclared (first use in this function)
313 | if (read_format & PERF_FORMAT_GROUP) {
| ^~~~~~~~~~~~~~~~~
evsel.c:314:27: error: invalid use of undefined type 'struct perf_evsel'
314 | nr = evsel->nr_members;
| ^~
evsel.c: In function 'perf_evsel__read_group':
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:327:19: note: in expansion of macro 'FD'
327 | int *fd = FD(evsel, cpu_map_idx, thread);
| ^~
evsel.c:328:32: error: invalid use of undefined type 'struct perf_evsel'
328 | u64 read_format = evsel->attr.read_format;
| ^~
evsel.c:348:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
348 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:350:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
350 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:355:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
355 | if (read_format & PERF_FORMAT_ID)
| ^~~~~~~~~~~~~~
evsel.c:357:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
357 | if (read_format & PERF_FORMAT_LOST)
| ^~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__adjust_values':
evsel.c:371:32: error: invalid use of undefined type 'struct perf_evsel'
371 | u64 read_format = evsel->attr.read_format;
| ^~
evsel.c:376:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
376 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CC /tmp/build/perf/libsubcmd/subcmd-config.o
evsel.c:379:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
379 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CC /tmp/build/perf/libbpf/staticobjs/libbpf.o
evsel.c:382:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
382 | if (read_format & PERF_FORMAT_ID)
| ^~~~~~~~~~~~~~
evsel.c:385:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
385 | if (read_format & PERF_FORMAT_LOST)
| ^~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__read':
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:393:19: note: in expansion of macro 'FD'
393 | int *fd = FD(evsel, cpu_map_idx, thread);
| ^~
evsel.c:394:32: error: invalid use of undefined type 'struct perf_evsel'
394 | u64 read_format = evsel->attr.read_format;
| ^~
evsel.c:402:27: error: 'PERF_FORMAT_GROUP' undeclared (first use in this function)
402 | if (read_format & PERF_FORMAT_GROUP)
| ^~~~~~~~~~~~~~~~~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:405:13: note: in expansion of macro 'MMAP'
405 | if (MMAP(evsel, cpu_map_idx, thread) &&
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:405:13: note: in expansion of macro 'MMAP'
405 | if (MMAP(evsel, cpu_map_idx, thread) &&
| ^~~~
evsel.c:406:30: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
406 | !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
| ^~~~~~~~~~~~~~
evsel.c:406:47: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
406 | !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
| ^~~~~~~~~~~~~~~~
evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:407:35: note: in expansion of macro 'MMAP'
407 | !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
| ^~~~
evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
| ^~
evsel.c:407:35: note: in expansion of macro 'MMAP'
407 | !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
| ^~~~
evsel.c: In function 'perf_evsel__ioctl':
evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
| ^~
evsel.c:420:19: note: in expansion of macro 'FD'
420 | int *fd = FD(evsel, cpu_map_idx, thread);
| ^~
evsel.c: In function 'perf_evsel__run_ioctl':
evsel.c:434:55: error: invalid use of undefined type 'struct perf_evsel'
434 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
| ^~
INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h
evsel.c: In function 'perf_evsel__enable_cpu':
evsel.c:446:45: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
446 | return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
| ^~~~~~~~~~~~~~~~~~~~~
In file included from evsel.c:6:
evsel.c: In function 'perf_evsel__enable_thread':
evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
| ^~
/tmp/build/perf/libperf/include/perf/cpumap.h:89:51: note: in definition of macro 'perf_cpu_map__for_each_cpu'
89 | for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \
| ^~~~
evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
| ^~
/tmp/build/perf/libperf/include/perf/cpumap.h:90:39: note: in definition of macro 'perf_cpu_map__for_each_cpu'
90 | (idx) < perf_cpu_map__nr(cpus); \
| ^~~~
evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
| ^~
/tmp/build/perf/libperf/include/perf/cpumap.h:91:49: note: in definition of macro 'perf_cpu_map__for_each_cpu'
91 | (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx))
| ^~~~
evsel.c:456:48: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
456 | err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
| ^~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__enable':
evsel.c:469:45: error: invalid use of undefined type 'struct perf_evsel'
469 | for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
| ^~
evsel.c:470:52: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
470 | err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
| ^~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__disable_cpu':
evsel.c:476:45: error: 'PERF_EVENT_IOC_DISABLE' undeclared (first use in this function)
476 | return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
| ^~~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__disable':
evsel.c:484:45: error: invalid use of undefined type 'struct perf_evsel'
484 | for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
| ^~
evsel.c:485:52: error: 'PERF_EVENT_IOC_DISABLE' undeclared (first use in this function)
485 | err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
| ^~~~~~~~~~~~~~~~~~~~~~
evsel.c: At top level:
evsel.c:489:5: error: no previous prototype for 'perf_evsel__apply_filter' [-Werror=missing-prototypes]
489 | int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
| ^~~~~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__apply_filter':
evsel.c:493:47: error: invalid use of undefined type 'struct perf_evsel'
493 | for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
| ^~
evsel.c:495:38: error: 'PERF_EVENT_IOC_SET_FILTER' undeclared (first use in this function)
495 | PERF_EVENT_IOC_SET_FILTER,
| ^~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__cpus':
evsel.c:502:21: error: invalid use of undefined type 'struct perf_evsel'
502 | return evsel->cpus;
| ^~
evsel.c: In function 'perf_evsel__threads':
evsel.c:507:21: error: invalid use of undefined type 'struct perf_evsel'
507 | return evsel->threads;
| ^~
evsel.c: In function 'perf_evsel__attr':
evsel.c:512:22: error: invalid use of undefined type 'struct perf_evsel'
512 | return &evsel->attr;
| ^~
evsel.c: At top level:
evsel.c:515:5: error: no previous prototype for 'perf_evsel__alloc_id' [-Werror=missing-prototypes]
515 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
| ^~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__alloc_id':
evsel.c:520:14: error: invalid use of undefined type 'struct perf_evsel'
520 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
| ^~
evsel.c:520:65: error: invalid application of 'sizeof' to incomplete type 'struct perf_sample_id'
520 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
| ^~~~~~
evsel.c:521:18: error: invalid use of undefined type 'struct perf_evsel'
521 | if (evsel->sample_id == NULL)
| ^~
evsel.c:524:14: error: invalid use of undefined type 'struct perf_evsel'
524 | evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
| ^~
evsel.c:525:18: error: invalid use of undefined type 'struct perf_evsel'
525 | if (evsel->id == NULL) {
| ^~
evsel.c:526:38: error: invalid use of undefined type 'struct perf_evsel'
526 | xyarray__delete(evsel->sample_id);
| ^~
evsel.c:527:22: error: invalid use of undefined type 'struct perf_evsel'
527 | evsel->sample_id = NULL;
| ^~
evsel.c: At top level:
evsel.c:534:6: error: no previous prototype for 'perf_evsel__free_id' [-Werror=missing-prototypes]
534 | void perf_evsel__free_id(struct perf_evsel *evsel)
| ^~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__free_id':
evsel.c:538:30: error: invalid use of undefined type 'struct perf_evsel'
538 | xyarray__delete(evsel->sample_id);
| ^~
evsel.c:539:14: error: invalid use of undefined type 'struct perf_evsel'
539 | evsel->sample_id = NULL;
| ^~
In file included from evsel.c:11:
evsel.c:540:21: error: invalid use of undefined type 'struct perf_evsel'
540 | zfree(&evsel->id);
| ^~
/git/perf-6.15.0-rc2/tools/include/linux/zalloc.h:10:38: note: in definition of macro 'zfree'
10 | #define zfree(ptr) __zfree((void **)(ptr))
| ^~~
evsel.c:541:14: error: invalid use of undefined type 'struct perf_evsel'
541 | evsel->ids = 0;
| ^~
evsel.c:543:9: error: implicit declaration of function 'perf_evsel_for_each_per_thread_period_safe' [-Werror=implicit-function-declaration]
543 | perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:543:9: error: nested extern declaration of 'perf_evsel_for_each_per_thread_period_safe' [-Werror=nested-externs]
evsel.c:543:66: error: expected ';' before '{' token
543 | perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
| ^~
| ;
evsel.c: At top level:
evsel.c:549:6: error: no previous prototype for 'perf_evsel__attr_has_per_thread_sample_period' [-Werror=missing-prototypes]
549 | bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_evsel__attr_has_per_thread_sample_period':
evsel.c:551:22: error: invalid use of undefined type 'struct perf_evsel'
551 | return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
| ^~
evsel.c:551:43: error: 'PERF_SAMPLE_READ' undeclared (first use in this function)
551 | return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
| ^~~~~~~~~~~~~~~~
evsel.c:552:23: error: invalid use of undefined type 'struct perf_evsel'
552 | (evsel->attr.sample_type & PERF_SAMPLE_TID) &&
| ^~
evsel.c:552:44: error: 'PERF_SAMPLE_TID' undeclared (first use in this function); did you mean 'PERF_SAMPLE_MAX_SIZE'?
552 | (evsel->attr.sample_type & PERF_SAMPLE_TID) &&
| ^~~~~~~~~~~~~~~
| PERF_SAMPLE_MAX_SIZE
evsel.c:553:22: error: invalid use of undefined type 'struct perf_evsel'
553 | evsel->attr.inherit;
| ^~
evsel.c: At top level:
evsel.c:556:48: error: 'struct perf_sample_id' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
556 | u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
| ^~~~~~~~~~~~~~
evsel.c:556:6: error: no previous prototype for 'perf_sample_id__get_period_storage' [-Werror=missing-prototypes]
556 | u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c: In function 'perf_sample_id__get_period_storage':
evsel.c:563:28: error: invalid use of undefined type 'struct perf_sample_id'
563 | return &sid->period;
| ^~
evsel.c:565:29: error: 'PERF_SAMPLE_ID__HLIST_BITS' undeclared (first use in this function)
565 | hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~
evsel.c:566:20: error: invalid use of undefined type 'struct perf_sample_id'
566 | head = &sid->periods[hash];
| ^~
In file included from /git/perf-6.15.0-rc2/tools/include/linux/kernel.h:14,
from /git/perf-6.15.0-rc2/tools/include/linux/list.h:7,
from evsel.c:9:
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:33: error: invalid use of undefined type 'struct perf_sample_id_period'
14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
| ^~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:54: error: initialization of 'const int *' from incompatible pointer type 'struct hlist_node *' [-Werror=incompatible-pointer-types]
14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
| ^
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/sys/mman.h:25,
from evsel.c:20:
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:15:35: error: invalid use of undefined type 'struct perf_sample_id_period'
15 | (type *)((char *)__mptr - offsetof(type, member)); })
| ^~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:728:42: error: invalid use of undefined type 'struct perf_sample_id_period'
728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
| ^~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:715:19: note: in definition of macro 'hlist_entry_safe'
715 | ({ typeof(ptr) ____ptr = (ptr); \
| ^~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:728:42: error: invalid use of undefined type 'struct perf_sample_id_period'
728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
| ^~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:715:35: note: in definition of macro 'hlist_entry_safe'
715 | ({ typeof(ptr) ____ptr = (ptr); \
| ^~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:33: error: invalid use of undefined type 'struct perf_sample_id_period'
14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
| ^~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:54: error: initialization of 'const int *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion]
14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
| ^
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/container_of.h:15:35: error: invalid use of undefined type 'struct perf_sample_id_period'
15 | (type *)((char *)__mptr - offsetof(type, member)); })
| ^~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
| ^~~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
| ^~~~~~~~~~~
/git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
| ^~~~~~~~~~~~~~~~
evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
568 | hlist_for_each_entry(res, head, hnode)
| ^~~~~~~~~~~~~~~~~~~~
evsel.c:569:24: error: invalid use of undefined type 'struct perf_sample_id_period'
569 | if (res->tid == tid)
| ^~
evsel.c:570:36: error: invalid use of undefined type 'struct perf_sample_id_period'
570 | return &res->period;
| ^~
evsel.c:572:16: error: invalid use of undefined type 'struct perf_sample_id'
572 | if (sid->evsel == NULL)
| ^~
evsel.c:575:29: error: invalid application of 'sizeof' to incomplete type 'struct perf_sample_id_period'
575 | res = zalloc(sizeof(struct perf_sample_id_period));
| ^~~~~~
evsel.c:579:28: error: invalid use of undefined type 'struct perf_sample_id_period'
579 | INIT_LIST_HEAD(&res->node);
| ^~
evsel.c:580:12: error: invalid use of undefined type 'struct perf_sample_id_period'
580 | res->tid = tid;
| ^~
evsel.c:582:27: error: invalid use of undefined type 'struct perf_sample_id_period'
582 | list_add_tail(&res->node, &sid->evsel->per_stream_periods);
| ^~
evsel.c:582:39: error: invalid use of undefined type 'struct perf_sample_id'
582 | list_add_tail(&res->node, &sid->evsel->per_stream_periods);
| ^~
evsel.c:583:28: error: invalid use of undefined type 'struct perf_sample_id_period'
583 | hlist_add_head(&res->hnode, &sid->periods[hash]);
| ^~
evsel.c:583:41: error: invalid use of undefined type 'struct perf_sample_id'
583 | hlist_add_head(&res->hnode, &sid->periods[hash]);
| ^~
evsel.c:585:20: error: invalid use of undefined type 'struct perf_sample_id_period'
585 | return &res->period;
| ^~
evsel.c:560:13: error: variable 'hash' set but not used [-Werror=unused-but-set-variable]
560 | int hash;
| ^~~~
evsel.c: In function 'perf_evsel__alloc_fd':
evsel.c:72:1: error: control reaches end of non-void function [-Werror=return-type]
72 | }
| ^
evsel.c: In function 'perf_evsel__mmap_base':
evsel.c:292:1: error: control reaches end of non-void function [-Werror=return-type]
292 | }
| ^
evsel.c: In function 'perf_evsel__enable_cpu':
evsel.c:447:1: error: control reaches end of non-void function [-Werror=return-type]
447 | }
| ^
evsel.c: In function 'perf_evsel__disable_cpu':
evsel.c:477:1: error: control reaches end of non-void function [-Werror=return-type]
477 | }
| ^
evsel.c: In function 'perf_evsel__cpus':
evsel.c:503:1: error: control reaches end of non-void function [-Werror=return-type]
503 | }
| ^
evsel.c: In function 'perf_evsel__threads':
evsel.c:508:1: error: control reaches end of non-void function [-Werror=return-type]
508 | }
| ^
evsel.c: In function 'perf_evsel__attr':
evsel.c:513:1: error: control reaches end of non-void function [-Werror=return-type]
513 | }
| ^
evsel.c: In function 'perf_evsel__attr_has_per_thread_sample_period':
evsel.c:554:1: error: control reaches end of non-void function [-Werror=return-type]
554 | }
| ^
evsel.c: In function 'perf_sample_id__get_period_storage':
evsel.c:586:1: error: control reaches end of non-void function [-Werror=return-type]
586 | }
| ^
cc1: all warnings being treated as errors
make[4]: *** [/git/perf-6.15.0-rc2/tools/build/Makefile.build:85: /tmp/build/perf/libperf/evsel.o] Error 1
make[4]: *** Waiting for unfinished jobs....
LD /tmp/build/perf/jvmti/jvmti-in.o
CC /tmp/build/perf/libbpf/staticobjs/bpf.o
INSTALL libperf_headers
CC /tmp/build/perf/libbpf/staticobjs/nlattr.o
LD /tmp/build/perf/libapi/libapi-in.o
AR /tmp/build/perf/libapi/libapi.a
CC /tmp/build/perf/libbpf/staticobjs/libbpf_errno.o
CC /tmp/build/perf/libbpf/staticobjs/btf.o
CC /tmp/build/perf/libbpf/staticobjs/str_error.o
CC /tmp/build/perf/libbpf/staticobjs/netlink.o
CC /tmp/build/perf/libbpf/staticobjs/bpf_prog_linfo.o
CC /tmp/build/perf/libbpf/staticobjs/libbpf_probes.o
CC /tmp/build/perf/libbpf/staticobjs/btf_dump.o
CC /tmp/build/perf/libbpf/staticobjs/ringbuf.o
CC /tmp/build/perf/libbpf/staticobjs/hashmap.o
CC /tmp/build/perf/libbpf/staticobjs/strset.o
CC /tmp/build/perf/libbpf/staticobjs/linker.o
CC /tmp/build/perf/libbpf/staticobjs/gen_loader.o
CC /tmp/build/perf/libbpf/staticobjs/usdt.o
CC /tmp/build/perf/libbpf/staticobjs/relo_core.o
CC /tmp/build/perf/libbpf/staticobjs/zip.o
CC /tmp/build/perf/libbpf/staticobjs/elf.o
CC /tmp/build/perf/libbpf/staticobjs/btf_iter.o
CC /tmp/build/perf/libbpf/staticobjs/features.o
CC /tmp/build/perf/libbpf/staticobjs/btf_relocate.o
make[3]: *** [Makefile:103: /tmp/build/perf/libperf/libperf-in.o] Error 2
make[2]: *** [Makefile.perf:976: /tmp/build/perf/libperf/libperf.a] Error 2
make[2]: *** Waiting for unfinished jobs....
LD /tmp/build/perf/libsubcmd/libsubcmd-in.o
AR /tmp/build/perf/libsubcmd/libsubcmd.a
LD /tmp/build/perf/libbpf/staticobjs/libbpf-in.o
LINK /tmp/build/perf/libbpf/libbpf.a
Auto-detecting system features:
... clang-bpf-co-re: [ on ]
... llvm: [ on ]
... libcap: [ on ]
... libbfd: [ on ]
MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf
MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/
MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/hashmap.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/relo_core.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_internal.h
GEN /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/bpf_helper_defs.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/btf.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_legacy.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_common.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helpers.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_tracing.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_core_read.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_endian.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_version.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/skel_internal.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/usdt.bpf.h
INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helper_defs.h
INSTALL libbpf_headers
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/nlattr.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_errno.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/str_error.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/netlink.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_probes.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/hashmap.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_dump.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ringbuf.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/strset.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/linker.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/gen_loader.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/zip.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/usdt.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/relo_core.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_relocate.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/elf.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/features.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_iter.o
LD /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf-in.o
LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/libbpf.a
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/main.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/common.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/json_writer.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/gen.o
CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/btf.o
LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/bpftool
make[1]: *** [Makefile.perf:287: sub-make] Error 2
make: *** [Makefile:76: all] Error 2
make: Leaving directory '/git/perf-6.15.0-rc2/tools/perf'
+ exit 1
toolsbuilder@number:~/git/linux-tools-container-builds$
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO
2025-04-18 21:29 ` [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Arnaldo Carvalho de Melo
@ 2025-04-19 4:22 ` Ian Rogers
[not found] ` <CA+JHD93NCu5VeP9b+DzMm0f0YHwJLRFJeHNtWogx6wKFrHi8Yw@mail.gmail.com>
0 siblings, 1 reply; 28+ messages in thread
From: Ian Rogers @ 2025-04-19 4:22 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, Ingo Molnar, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Adrian Hunter, Kan Liang,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins, Changbin Du,
Masami Hiramatsu (Google), James Clark, Kajol Jain, Athira Rajeev,
Li Huafei, Dmitry Vyukov, Andi Kleen, Chaitanya S Prakash,
linux-kernel, linux-perf-users, llvm, Song Liu, bpf
On Fri, Apr 18, 2025 at 2:29 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Thu, Apr 17, 2025 at 04:07:21PM -0700, Ian Rogers wrote:
> > Linking against libcapstone and libLLVM can be a significant increase
> > in dependencies and file size if building statically. For something
> > like `perf record` the disassembler and addr2line functionality won't
> > be used. Support dynamically loading these libraries using dlopen and
> > then calling the appropriate functions found using dlsym.
> >
> > BUILD_NONDISTRO is used to build perf against the license incompatible
> > libbfd and libiberty libraries. As this has been opt-in for nearly 2
> > years, commit dd317df07207 ("perf build: Make binutil libraries opt
> > in"), remove the code to simplify the code base.
> >
> > The patch series:
> > 1) does some initial clean up;
> > 2) moves the capstone and LLVM code to their own C files,
> > 3) simplifies a little the capstone code;
> > 4) adds perf_ variants of the functions that will either directly call
> > the function or use dlsym to discover it;
> > 5) adds BPF JIT disassembly support to LLVM and capstone disassembly;
> > 6) removes the BUILD_NONDISTRO code, reduces scope and removes what's possible;
> > 7) adds fallback to srcline's addr2line so that llvm_addr2line is
> > tried first and then the forked command tried next, moving the code
> > for forking out of the main srcline.c file in the process.
> >
> > The addr2line LLVM functionality is written in C++. To avoid linking
> > against libLLVM for this, a new LIBLLVM_DYNAMIC option is added where
> > the C++ code with the libLLVM dependency will be built into a
> > libperf-llvm.so and that dlsym-ed and called against. Ideally LLVM
> > would extend their C API to avoid this.
> >
> > The libbfd BPF disassembly supported source lines, this wasn't ported
> > to the capstone and LLVM disassembly.
>
> Doing the build tests I noticed, so far:
>
> 29 58.92 opensuse:15.4 : FAIL gcc version 7.5.0 (SUSE Linux)
> <SNIP>
> + make NO_LIBTRACEEVENT=1 ARCH= CROSS_COMPILE= EXTRA_CFLAGS= NO_LIBBPF=1 -C tools/perf O=/tmp/build/perf
> make: Entering directory '/git/perf-6.15.0-rc2/tools/perf'
> BUILD: Doing 'make -j32' parallel build
> Warning: Skipped check-headers due to missing ../../include
> Makefile.config:560: No elfutils/debuginfod.h found, no debuginfo server support, please install libdebuginfod-dev/elfutils-debuginfod-client-devel or equivalent
> Makefile.config:687: Warning: Disabled BPF skeletons as libbpf is required
> Makefile.config:1039: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev
> update-alternatives: error: no alternatives for java
> update-alternatives: error: no alternatives for java
> Makefile.config:1100: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel
> Makefile.config:1113: libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev
>
> Auto-detecting system features:
> ... libdw: [ on ]
> ... glibc: [ on ]
> ... libelf: [ on ]
> ... libnuma: [ on ]
> ... numa_num_possible_cpus: [ on ]
> ... libperl: [ on ]
> ... libpython: [ on ]
> ... libcrypto: [ on ]
> ... libcapstone: [ on ]
> ... llvm-perf: [ on ]
> ... zlib: [ on ]
> ... lzma: [ on ]
> ... get_cpuid: [ on ]
> ... bpf: [ on ]
> ... libaio: [ on ]
> ... libzstd: [ on ]
>
> PERF_VERSION = 6.15.rc2.gfbcac9367d45
> GEN /tmp/build/perf/common-cmds.h
> GEN /tmp/build/perf/arch/arm64/include/generated/asm/sysreg-defs.h
> GEN perf-archive
> GEN perf-iostat
> CC /tmp/build/perf/dlfilters/dlfilter-test-api-v0.o
> CC /tmp/build/perf/dlfilters/dlfilter-test-api-v2.o
> CC /tmp/build/perf/dlfilters/dlfilter-show-cycles.o
> INSTALL /tmp/build/perf/libapi/include/api/cpu.h
> INSTALL /tmp/build/perf/libapi/include/api/debug.h
> INSTALL /tmp/build/perf/libapi/include/api/io.h
> MKDIR /tmp/build/perf/libapi/fd/
> INSTALL /tmp/build/perf/libapi/include/api/io_dir.h
> CC /tmp/build/perf/libapi/cpu.o
> MKDIR /tmp/build/perf/libapi/fs/
> INSTALL /tmp/build/perf/libapi/include/api/fd/array.h
> CC /tmp/build/perf/libapi/debug.o
> MKDIR /tmp/build/perf/libapi/fs/
> MKDIR /tmp/build/perf/libapi/fs/
> CC /tmp/build/perf/libapi/fd/array.o
> INSTALL /tmp/build/perf/libapi/include/api/fs/tracing_path.h
> CC /tmp/build/perf/libapi/str_error_r.o
> INSTALL /tmp/build/perf/libapi/include/api/fs/fs.h
> CC /tmp/build/perf/libapi/fs/tracing_path.o
> CC /tmp/build/perf/libapi/fs/fs.o
> CC /tmp/build/perf/libapi/fs/cgroup.o
> INSTALL libapi_headers
> INSTALL /tmp/build/perf/libperf/include/perf/bpf_perf.h
> INSTALL /tmp/build/perf/libperf/include/perf/core.h
> INSTALL /tmp/build/perf/libperf/include/perf/cpumap.h
> INSTALL /tmp/build/perf/libperf/include/perf/threadmap.h
> CC /tmp/build/perf/libperf/core.o
> CC /tmp/build/perf/libperf/cpumap.o
> CC /tmp/build/perf/libperf/threadmap.o
> INSTALL /tmp/build/perf/libperf/include/perf/evlist.h
> CC /tmp/build/perf/libperf/evlist.o
> CC /tmp/build/perf/libperf/evsel.o
> CC /tmp/build/perf/libperf/mmap.o
> CC /tmp/build/perf/libperf/zalloc.o
> INSTALL /tmp/build/perf/libsubcmd/include/subcmd/exec-cmd.h
> INSTALL /tmp/build/perf/libperf/include/perf/evsel.h
> CC /tmp/build/perf/libperf/xyarray.o
> CC /tmp/build/perf/libperf/lib.o
> INSTALL /tmp/build/perf/libsubcmd/include/subcmd/help.h
> INSTALL /tmp/build/perf/libsubcmd/include/subcmd/pager.h
> LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v0.so
> INSTALL /tmp/build/perf/libsubcmd/include/subcmd/parse-options.h
> LD /tmp/build/perf/libapi/fd/libapi-in.o
> INSTALL /tmp/build/perf/libsubcmd/include/subcmd/run-command.h
> INSTALL libsubcmd_headers
> LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v2.so
> INSTALL /tmp/build/perf/libperf/include/perf/event.h
> INSTALL /tmp/build/perf/libsymbol/include/symbol/kallsyms.h
> CC /tmp/build/perf/libsymbol/kallsyms.o
> INSTALL /tmp/build/perf/libperf/include/perf/mmap.h
> INSTALL /tmp/build/perf/libperf/include/internal/cpumap.h
> INSTALL /tmp/build/perf/libperf/include/internal/evlist.h
> INSTALL /tmp/build/perf/libperf/include/internal/evsel.h
> INSTALL /tmp/build/perf/libperf/include/internal/rc_check.h
> INSTALL /tmp/build/perf/libperf/include/internal/mmap.h
> INSTALL /tmp/build/perf/libperf/include/internal/threadmap.h
> INSTALL /tmp/build/perf/libperf/include/internal/lib.h
> INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h
> LINK /tmp/build/perf/dlfilters/dlfilter-show-cycles.so
> LD /tmp/build/perf/libapi/fs/libapi-in.o
> evlist.c:28:6: error: no previous prototype for 'perf_evlist__init' [-Werror=missing-prototypes]
> void perf_evlist__init(struct perf_evlist *evlist)
> ^~~~~~~~~~~~~~~~~
Hmm.. but on line 8 of tools/lib/perf/evlist.c is:
#include <internal/evlist.h>
is there a libperf installed somewhere? I thought we were just
statically linking currently. I'm not sure what I can do to resolve
this, it seems like a set up issue.
Thanks,
Ian
> evlist.c: In function 'perf_evlist__init':
> evlist.c:30:24: error: dereferencing pointer to incomplete type 'struct perf_evlist'
> INIT_LIST_HEAD(&evlist->entries);
> ^~
> evlist.c:33:2: error: implicit declaration of function 'perf_evlist__reset_id_hash'; did you mean 'perf_evlist__set_maps'? [-Werror=implicit-function-declaration]
> perf_evlist__reset_id_hash(evlist);
> ^~~~~~~~~~~~~~~~~~~~~~~~~~
> perf_evlist__set_maps
> evlist.c:33:2: error: nested extern declaration of 'perf_evlist__reset_id_hash' [-Werror=nested-externs]
> evlist.c: In function 'perf_evlist__purge':
> evlist.c:157:2: error: implicit declaration of function 'perf_evlist__for_each_entry_safe'; did you mean 'hlist_for_each_entry_safe'? [-Werror=implicit-function-declaration]
> perf_evlist__for_each_entry_safe(evlist, n, pos) {
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> hlist_for_each_entry_safe
> evlist.c:157:2: error: nested extern declaration of 'perf_evlist__for_each_entry_safe' [-Werror=nested-externs]
> evlist.c:157:51: error: expected ';' before '{' token
> perf_evlist__for_each_entry_safe(evlist, n, pos) {
> ^
> evlist.c: At top level:
> evlist.c:165:6: error: no previous prototype for 'perf_evlist__exit' [-Werror=missing-prototypes]
> void perf_evlist__exit(struct perf_evlist *evlist)
> ^~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__open':
> evlist.c:217:2: error: implicit declaration of function 'perf_evlist__for_each_entry'; did you mean 'perf_evlist__for_each_evsel'? [-Werror=implicit-function-declaration]
> perf_evlist__for_each_entry(evlist, evsel) {
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~
> perf_evlist__for_each_evsel
> evlist.c:217:2: error: nested extern declaration of 'perf_evlist__for_each_entry' [-Werror=nested-externs]
> evlist.c:217:45: error: expected ';' before '{' token
> perf_evlist__for_each_entry(evlist, evsel) {
> ^
> evlist.c:225:1: error: label 'out_err' defined but not used [-Werror=unused-label]
> out_err:
> ^~~~~~~
> INSTALL libperf_headers
> evlist.c: In function 'perf_evlist__close':
> evlist.c:234:2: error: implicit declaration of function 'perf_evlist__for_each_entry_reverse'; did you mean 'list_for_each_entry_reverse'? [-Werror=implicit-function-declaration]
> perf_evlist__for_each_entry_reverse(evlist, evsel)
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> list_for_each_entry_reverse
> evlist.c:234:2: error: nested extern declaration of 'perf_evlist__for_each_entry_reverse' [-Werror=nested-externs]
> evlist.c:235:3: error: expected ';' before 'perf_evsel__close'
> perf_evsel__close(evsel);
> ^~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__enable':
> evlist.c:243:3: error: expected ';' before 'perf_evsel__enable'
> perf_evsel__enable(evsel);
> ^~~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__disable':
> evlist.c:251:3: error: expected ';' before 'perf_evsel__disable'
> perf_evsel__disable(evsel);
> ^~~~~~~~~~~~~~~~~~~
> evlist.c: At top level:
> evlist.c:254:5: error: no previous prototype for 'perf_evlist__read_format' [-Werror=missing-prototypes]
> u64 perf_evlist__read_format(struct perf_evlist *evlist)
> ^~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__read_format':
> evlist.c:256:29: error: implicit declaration of function 'perf_evlist__first'; did you mean 'perf_evlist__init'? [-Werror=implicit-function-declaration]
> struct perf_evsel *first = perf_evlist__first(evlist);
> ^~~~~~~~~~~~~~~~~~
> perf_evlist__init
> evlist.c:256:29: error: nested extern declaration of 'perf_evlist__first' [-Werror=nested-externs]
> evlist.c:256:29: error: initialization makes pointer from integer without a cast [-Werror=int-conversion]
> INSTALL libsymbol_headers
> evlist.c: In function 'perf_evlist__id_hash':
> evlist.c:272:26: error: 'PERF_EVLIST__HLIST_BITS' undeclared (first use in this function); did you mean 'PERF_SAMPLE_ID__HLIST_BITS'?
> hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS);
> ^~~~~~~~~~~~~~~~~~~~~~~
> PERF_SAMPLE_ID__HLIST_BITS
> evlist.c:272:26: note: each undeclared identifier is reported only once for each function it appears in
> evlist.c:267:6: error: variable 'hash' set but not used [-Werror=unused-but-set-variable]
> int hash;
> ^~~~
> evlist.c: At top level:
> evlist.c:276:6: error: no previous prototype for 'perf_evlist__reset_id_hash' [-Werror=missing-prototypes]
> void perf_evlist__reset_id_hash(struct perf_evlist *evlist)
> ^~~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c:276:6: error: conflicting types for 'perf_evlist__reset_id_hash' [-Werror]
> evlist.c:33:2: note: previous implicit declaration of 'perf_evlist__reset_id_hash' was here
> perf_evlist__reset_id_hash(evlist);
> ^~~~~~~~~~~~~~~~~~~~~~~~~~
> LD /tmp/build/perf/libapi/libapi-in.o
> evlist.c: In function 'perf_evlist__reset_id_hash':
> evlist.c:280:18: error: 'PERF_EVLIST__HLIST_SIZE' undeclared (first use in this function); did you mean 'PERF_SAMPLE_ID__HLIST_SIZE'?
> for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i)
> ^~~~~~~~~~~~~~~~~~~~~~~
> PERF_SAMPLE_ID__HLIST_SIZE
> evlist.c: At top level:
> evlist.c:284:6: error: no previous prototype for 'perf_evlist__id_add' [-Werror=missing-prototypes]
> void perf_evlist__id_add(struct perf_evlist *evlist,
> ^~~~~~~~~~~~~~~~~~~
> evlist.c:295:5: error: no previous prototype for 'perf_evlist__id_add_fd' [-Werror=missing-prototypes]
> int perf_evlist__id_add_fd(struct perf_evlist *evlist,
> ^~~~~~~~~~~~~~~~~~~~~~
> evlist.c:339:5: error: no previous prototype for 'perf_evlist__alloc_pollfd' [-Werror=missing-prototypes]
> int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
> ^~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__alloc_pollfd':
> evlist.c:346:45: error: expected ';' before '{' token
> perf_evlist__for_each_entry(evlist, evsel) {
> ^
> evlist.c:343:6: error: unused variable 'nfds' [-Werror=unused-variable]
> int nfds = 0;
> ^~~~
> evlist.c:342:6: error: unused variable 'nr_threads' [-Werror=unused-variable]
> int nr_threads = perf_thread_map__nr(evlist->threads);
> ^~~~~~~~~~
> evlist.c:341:6: error: unused variable 'nr_cpus' [-Werror=unused-variable]
> int nr_cpus = perf_cpu_map__nr(evlist->all_cpus);
> ^~~~~~~
> evlist.c: At top level:
> evlist.c:360:5: error: no previous prototype for 'perf_evlist__add_pollfd' [-Werror=missing-prototypes]
> int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd,
> ^~~~~~~~~~~~~~~~~~~~~~~
> evlist.c:469:51: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'mmap_per_evsel':
> evlist.c:477:45: error: expected ';' before '{' token
> perf_evlist__for_each_entry(evlist, evsel) {
> ^
> evlist.c:475:6: error: unused variable 'revent' [-Werror=unused-variable]
> int revent;
> ^~~~~~
> evlist.c:473:18: error: unused variable 'evlist_cpu' [-Werror=unused-variable]
> struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->all_cpus, cpu_idx);
> ^~~~~~~~~~
> evlist.c:560:1: error: no return statement in function returning non-void [-Werror=return-type]
> }
> ^
> evlist.c:469:73: error: unused parameter 'ops' [-Werror=unused-parameter]
> mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~
> evlist.c:470:13: error: unused parameter 'idx' [-Werror=unused-parameter]
> int idx, struct perf_mmap_param *mp, int cpu_idx,
> ^~~
> evlist.c:470:42: error: unused parameter 'mp' [-Werror=unused-parameter]
> int idx, struct perf_mmap_param *mp, int cpu_idx,
> ^~
> evlist.c:471:13: error: unused parameter 'thread' [-Werror=unused-parameter]
> int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
> ^~~~~~
> evlist.c:471:26: error: unused parameter '_output' [-Werror=unused-parameter]
> int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
> ^~~~~~~
> evlist.c:471:40: error: unused parameter '_output_overwrite' [-Werror=unused-parameter]
> int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
> ^~~~~~~~~~~~~~~~~
> evlist.c:471:64: error: unused parameter 'nr_mmaps' [-Werror=unused-parameter]
> int thread, int *_output, int *_output_overwrite, int *nr_mmaps)
> ^~~~~~~~
> evlist.c: At top level:
> evlist.c:563:52: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'mmap_per_thread':
> evlist.c:579:30: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
> if (mmap_per_evsel(evlist, ops, idx, mp, 0, thread, &output,
> ^~~
> evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
> mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~
> evlist.c:589:30: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
> if (mmap_per_evsel(evlist, ops, idx, mp, cpu, 0, &output,
> ^~~
> evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
> mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~
> evlist.c: At top level:
> evlist.c:605:49: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'mmap_per_cpu':
> evlist.c:620:31: error: passing argument 2 of 'mmap_per_evsel' from incompatible pointer type [-Werror=incompatible-pointer-types]
> if (mmap_per_evsel(evlist, ops, cpu, mp, cpu,
> ^~~
> evlist.c:469:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
> mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~
> evlist.c: At top level:
> evlist.c:653:13: error: 'struct perf_evlist_mmap_ops' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~~~~~~~
> evlist.c:652:5: error: no previous prototype for 'perf_evlist__mmap_ops' [-Werror=missing-prototypes]
> int perf_evlist__mmap_ops(struct perf_evlist *evlist,
> ^~~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__mmap_ops':
> evlist.c:659:18: error: dereferencing pointer to incomplete type 'struct perf_evlist_mmap_ops'
> if (!ops || !ops->get || !ops->mmap)
> ^~
> evlist.c:666:45: error: expected ';' before '{' token
> perf_evlist__for_each_entry(evlist, evsel) {
> ^
> evlist.c:677:34: error: passing argument 2 of 'mmap_per_thread' from incompatible pointer type [-Werror=incompatible-pointer-types]
> return mmap_per_thread(evlist, ops, mp);
> ^~~
> evlist.c:563:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
> mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~~~~
> evlist.c:679:30: error: passing argument 2 of 'mmap_per_cpu' from incompatible pointer type [-Werror=incompatible-pointer-types]
> return mmap_per_cpu(evlist, ops, mp);
> ^~~
> evlist.c:605:1: note: expected 'struct perf_evlist_mmap_ops *' but argument is of type 'struct perf_evlist_mmap_ops *'
> mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops,
> ^~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__mmap':
> evlist.c:685:9: error: variable 'ops' has initializer but incomplete type
> struct perf_evlist_mmap_ops ops = {
> ^~~~~~~~~~~~~~~~~~~~
> evlist.c:686:4: error: 'struct perf_evlist_mmap_ops' has no member named 'get'
> .get = perf_evlist__mmap_cb_get,
> ^~~
> evlist.c:686:11: error: excess elements in struct initializer [-Werror]
> .get = perf_evlist__mmap_cb_get,
> ^~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c:686:11: note: (near initialization for 'ops')
> evlist.c:687:4: error: 'struct perf_evlist_mmap_ops' has no member named 'mmap'
> .mmap = perf_evlist__mmap_cb_mmap,
> ^~~~
> evlist.c:687:11: error: excess elements in struct initializer [-Werror]
> .mmap = perf_evlist__mmap_cb_mmap,
> ^~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c:687:11: note: (near initialization for 'ops')
> evlist.c:685:30: error: storage size of 'ops' isn't known
> struct perf_evlist_mmap_ops ops = {
> ^~~
> evlist.c:685:30: error: unused variable 'ops' [-Werror=unused-variable]
> evlist.c: At top level:
> evlist.c:723:6: error: no previous prototype for '__perf_evlist__set_leader' [-Werror=missing-prototypes]
> void __perf_evlist__set_leader(struct list_head *list, struct perf_evsel *leader)
> ^~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c: In function '__perf_evlist__set_leader':
> evlist.c:728:2: error: implicit declaration of function '__perf_evlist__for_each_entry'; did you mean 'perf_evlist__for_each_evsel'? [-Werror=implicit-function-declaration]
> __perf_evlist__for_each_entry(list, evsel) {
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> perf_evlist__for_each_evsel
> evlist.c:728:2: error: nested extern declaration of '__perf_evlist__for_each_entry' [-Werror=nested-externs]
> evlist.c:728:45: error: expected ';' before '{' token
> __perf_evlist__for_each_entry(list, evsel) {
> ^
> evlist.c:726:6: error: unused variable 'n' [-Werror=unused-variable]
> int n = 0;
> ^
> evlist.c:723:75: error: unused parameter 'leader' [-Werror=unused-parameter]
> void __perf_evlist__set_leader(struct list_head *list, struct perf_evsel *leader)
> ^~~~~~
> evlist.c: At top level:
> evlist.c:762:6: error: no previous prototype for 'perf_evlist__go_system_wide' [-Werror=missing-prototypes]
> void perf_evlist__go_system_wide(struct perf_evlist *evlist, struct perf_evsel *evsel)
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c: In function 'perf_evlist__filter_pollfd':
> evlist.c:386:1: error: control reaches end of non-void function [-Werror=return-type]
> }
> ^
> evlist.c: In function 'perf_evlist__poll':
> evlist.c:391:1: error: control reaches end of non-void function [-Werror=return-type]
> }
> ^
> evlist.c: In function 'perf_evlist__mmap':
> evlist.c:693:1: error: control reaches end of non-void function [-Werror=return-type]
> }
> ^
> evlist.c: In function 'perf_evlist__next_mmap':
> evlist.c:721:1: error: control reaches end of non-void function [-Werror=return-type]
> }
> ^
> At top level:
> evlist.c:459:13: error: 'perf_evlist__set_mmap_first' defined but not used [-Werror=unused-function]
> static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map,
> ^~~~~~~~~~~~~~~~~~~~~~~~~~~
> evlist.c:420:13: error: 'perf_evsel__set_sid_idx' defined but not used [-Werror=unused-function]
> static void perf_evsel__set_sid_idx(struct perf_evsel *evsel, int idx, int cpu, int thread)
> ^~~~~~~~~~~~~~~~~~~~~~~
> cc1: all warnings being treated as errors
> make[4]: *** [/git/perf-6.15.0-rc2/tools/build/Makefile.build:85: /tmp/build/perf/libperf/evlist.o] Error 1
> make[4]: *** Waiting for unfinished jobs....
> AR /tmp/build/perf/libapi/libapi.a
> CC /tmp/build/perf/libsubcmd/exec-cmd.o
> CC /tmp/build/perf/libsubcmd/help.o
> CC /tmp/build/perf/libsubcmd/pager.o
> CC /tmp/build/perf/libsubcmd/run-command.o
> CC /tmp/build/perf/libsubcmd/parse-options.o
> CC /tmp/build/perf/libsubcmd/sigchain.o
> CC /tmp/build/perf/libsubcmd/subcmd-config.o
> LD /tmp/build/perf/libsymbol/libsymbol-in.o
> AR /tmp/build/perf/libsymbol/libsymbol.a
> make[3]: *** [Makefile:103: /tmp/build/perf/libperf/libperf-in.o] Error 2
> make[2]: *** [Makefile.perf:976: /tmp/build/perf/libperf/libperf.a] Error 2
> make[2]: *** Waiting for unfinished jobs....
> LD /tmp/build/perf/libsubcmd/libsubcmd-in.o
> AR /tmp/build/perf/libsubcmd/libsubcmd.a
> make[1]: *** [Makefile.perf:287: sub-make] Error 2
> make: *** [Makefile:76: all] Error 2
> make: Leaving directory '/git/perf-6.15.0-rc2/tools/perf'
> + exit 1
> toolsbuilder@number:~/git/linux-tools-container-builds$
>
>
> 23 18.51 fedora:38 : FAIL gcc version 13.2.1 20240316 (Red Hat 13.2.1-7) (GCC)
> <SNIP>
> evsel.c:23:6: error: no previous prototype for 'perf_evsel__init' [-Werror=missing-prototypes]
> 23 | void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr,
> | ^~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__init':
> evsel.c:26:30: error: invalid use of undefined type 'struct perf_evsel'
> 26 | INIT_LIST_HEAD(&evsel->node);
> | ^~
> evsel.c:27:30: error: invalid use of undefined type 'struct perf_evsel'
> 27 | INIT_LIST_HEAD(&evsel->per_stream_periods);
> | ^~
> evsel.c:28:14: error: invalid use of undefined type 'struct perf_evsel'
> 28 | evsel->attr = *attr;
> | ^~
> evsel.c:28:23: error: invalid use of undefined type 'struct perf_event_attr'
> 28 | evsel->attr = *attr;
> | ^
> evsel.c:29:14: error: invalid use of undefined type 'struct perf_evsel'
> 29 | evsel->idx = idx;
> | ^~
> evsel.c:30:14: error: invalid use of undefined type 'struct perf_evsel'
> 30 | evsel->leader = evsel;
> | ^~
> evsel.c: In function 'perf_evsel__new':
> evsel.c:35:49: error: invalid application of 'sizeof' to incomplete type 'struct perf_evsel'
> 35 | struct perf_evsel *evsel = zalloc(sizeof(*evsel));
> | ^
> evsel.c: At top level:
> evsel.c:54:5: error: no previous prototype for 'perf_evsel__alloc_fd' [-Werror=missing-prototypes]
> 54 | int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
> | ^~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__alloc_fd':
> evsel.c:56:14: error: invalid use of undefined type 'struct perf_evsel'
> 56 | evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int));
> | ^~
> evsel.c:58:18: error: invalid use of undefined type 'struct perf_evsel'
> 58 | if (evsel->fd) {
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:63:43: note: in expansion of macro 'FD'
> 63 | int *fd = FD(evsel, idx, thread);
> | ^~
> evsel.c:71:21: error: invalid use of undefined type 'struct perf_evsel'
> 71 | return evsel->fd != NULL ? 0 : -ENOMEM;
> | ^~
> evsel.c: In function 'perf_evsel__alloc_mmap':
> evsel.c:76:14: error: invalid use of undefined type 'struct perf_evsel'
> 76 | evsel->mmap = xyarray__new(ncpus, nthreads, sizeof(struct perf_mmap));
> | ^~
> evsel.c:78:21: error: invalid use of undefined type 'struct perf_evsel'
> 78 | return evsel->mmap != NULL ? 0 : -ENOMEM;
> | ^~
> evsel.c: In function 'get_group_fd':
> evsel.c:91:42: error: invalid use of undefined type 'struct perf_evsel'
> 91 | struct perf_evsel *leader = evsel->leader;
> | ^~
> evsel.c:103:20: error: invalid use of undefined type 'struct perf_evsel'
> 103 | if (!leader->fd)
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:106:14: note: in expansion of macro 'FD'
> 106 | fd = FD(leader, cpu_map_idx, thread);
> | ^~
> evsel.c: In function 'perf_evsel__open':
> evsel.c:145:18: error: invalid use of undefined type 'struct perf_evsel'
> 145 | if (evsel->fd == NULL &&
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:153:36: note: in expansion of macro 'FD'
> 153 | evsel_fd = FD(evsel, idx, thread);
> | ^~
> evsel.c:163:56: error: invalid use of undefined type 'struct perf_evsel'
> 163 | fd = sys_perf_event_open(&evsel->attr,
> | ^~
> evsel.c: In function 'perf_evsel__close_fd_cpu':
> evsel.c:186:55: error: invalid use of undefined type 'struct perf_evsel'
> 186 | for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) {
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:187:27: note: in expansion of macro 'FD'
> 187 | int *fd = FD(evsel, cpu_map_idx, thread);
> | ^~
> evsel.c: At top level:
> evsel.c:196:6: error: no previous prototype for 'perf_evsel__close_fd' [-Werror=missing-prototypes]
> 196 | void perf_evsel__close_fd(struct perf_evsel *evsel)
> | ^~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__close_fd':
> evsel.c:198:53: error: invalid use of undefined type 'struct perf_evsel'
> 198 | for (int idx = 0; idx < xyarray__max_x(evsel->fd); idx++)
> | ^~
> evsel.c: At top level:
> evsel.c:202:6: error: no previous prototype for 'perf_evsel__free_fd' [-Werror=missing-prototypes]
> 202 | void perf_evsel__free_fd(struct perf_evsel *evsel)
> | ^~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__free_fd':
> evsel.c:204:30: error: invalid use of undefined type 'struct perf_evsel'
> 204 | xyarray__delete(evsel->fd);
> | ^~
> evsel.c:205:14: error: invalid use of undefined type 'struct perf_evsel'
> 205 | evsel->fd = NULL;
> | ^~
> evsel.c: In function 'perf_evsel__close':
> evsel.c:210:18: error: invalid use of undefined type 'struct perf_evsel'
> 210 | if (evsel->fd == NULL)
> | ^~
> evsel.c: In function 'perf_evsel__close_cpu':
> evsel.c:219:18: error: invalid use of undefined type 'struct perf_evsel'
> 219 | if (evsel->fd == NULL)
> | ^~
> evsel.c: In function 'perf_evsel__munmap':
> evsel.c:229:18: error: invalid use of undefined type 'struct perf_evsel'
> 229 | if (evsel->fd == NULL || evsel->mmap == NULL)
> | ^~
> evsel.c:229:39: error: invalid use of undefined type 'struct perf_evsel'
> 229 | if (evsel->fd == NULL || evsel->mmap == NULL)
> | ^~
> evsel.c:232:49: error: invalid use of undefined type 'struct perf_evsel'
> 232 | for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
> | ^~
> evsel.c:233:63: error: invalid use of undefined type 'struct perf_evsel'
> 233 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:234:35: note: in expansion of macro 'FD'
> 234 | int *fd = FD(evsel, idx, thread);
> | ^~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:239:43: note: in expansion of macro 'MMAP'
> 239 | perf_mmap__munmap(MMAP(evsel, idx, thread));
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:239:43: note: in expansion of macro 'MMAP'
> 239 | perf_mmap__munmap(MMAP(evsel, idx, thread));
> | ^~~~
> evsel.c:243:30: error: invalid use of undefined type 'struct perf_evsel'
> 243 | xyarray__delete(evsel->mmap);
> | ^~
> evsel.c:244:14: error: invalid use of undefined type 'struct perf_evsel'
> 244 | evsel->mmap = NULL;
> | ^~
> evsel.c: In function 'perf_evsel__mmap':
> evsel.c:255:18: error: invalid use of undefined type 'struct perf_evsel'
> 255 | if (evsel->fd == NULL || evsel->mmap)
> | ^~
> evsel.c:255:39: error: invalid use of undefined type 'struct perf_evsel'
> 255 | if (evsel->fd == NULL || evsel->mmap)
> | ^~
> evsel.c:258:63: error: invalid use of undefined type 'struct perf_evsel'
> 258 | if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
> | ^~
> evsel.c:258:90: error: invalid use of undefined type 'struct perf_evsel'
> 258 | if (perf_evsel__alloc_mmap(evsel, xyarray__max_x(evsel->fd), xyarray__max_y(evsel->fd)) < 0)
> | ^~
> evsel.c:261:49: error: invalid use of undefined type 'struct perf_evsel'
> 261 | for (idx = 0; idx < xyarray__max_x(evsel->fd); idx++) {
> | ^~
> evsel.c:262:63: error: invalid use of undefined type 'struct perf_evsel'
> 262 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
> | ^~
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:263:35: note: in expansion of macro 'FD'
> 263 | int *fd = FD(evsel, idx, thread);
> | ^~
> evsel.c:265:70: error: invalid use of undefined type 'struct perf_evsel'
> 265 | struct perf_cpu cpu = perf_cpu_map__cpu(evsel->cpus, idx);
> | ^~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:270:31: note: in expansion of macro 'MMAP'
> 270 | map = MMAP(evsel, idx, thread);
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:270:31: note: in expansion of macro 'MMAP'
> 270 | map = MMAP(evsel, idx, thread);
> | ^~~~
> evsel.c: In function 'perf_evsel__mmap_base':
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:286:19: note: in expansion of macro 'FD'
> 286 | int *fd = FD(evsel, cpu_map_idx, thread);
> | ^~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:288:38: note: in expansion of macro 'MMAP'
> 288 | if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:288:38: note: in expansion of macro 'MMAP'
> 288 | if (fd == NULL || *fd < 0 || MMAP(evsel, cpu_map_idx, thread) == NULL)
> | ^~~~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:291:16: note: in expansion of macro 'MMAP'
> 291 | return MMAP(evsel, cpu_map_idx, thread)->base;
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:291:16: note: in expansion of macro 'MMAP'
> 291 | return MMAP(evsel, cpu_map_idx, thread)->base;
> | ^~~~
> evsel.c: At top level:
> evsel.c:294:5: error: no previous prototype for 'perf_evsel__read_size' [-Werror=missing-prototypes]
> 294 | int perf_evsel__read_size(struct perf_evsel *evsel)
> | ^~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__read_size':
> evsel.c:296:32: error: invalid use of undefined type 'struct perf_evsel'
> 296 | u64 read_format = evsel->attr.read_format;
> | ^~
> evsel.c:301:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
> 301 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:301:27: note: each undeclared identifier is reported only once for each function it appears in
> evsel.c:304:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
> 304 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:307:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
> 307 | if (read_format & PERF_FORMAT_ID)
> | ^~~~~~~~~~~~~~
> evsel.c:310:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
> 310 | if (read_format & PERF_FORMAT_LOST)
> | ^~~~~~~~~~~~~~~~
> evsel.c:313:27: error: 'PERF_FORMAT_GROUP' undeclared (first use in this function)
> 313 | if (read_format & PERF_FORMAT_GROUP) {
> | ^~~~~~~~~~~~~~~~~
> evsel.c:314:27: error: invalid use of undefined type 'struct perf_evsel'
> 314 | nr = evsel->nr_members;
> | ^~
> evsel.c: In function 'perf_evsel__read_group':
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:327:19: note: in expansion of macro 'FD'
> 327 | int *fd = FD(evsel, cpu_map_idx, thread);
> | ^~
> evsel.c:328:32: error: invalid use of undefined type 'struct perf_evsel'
> 328 | u64 read_format = evsel->attr.read_format;
> | ^~
> evsel.c:348:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
> 348 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:350:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
> 350 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:355:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
> 355 | if (read_format & PERF_FORMAT_ID)
> | ^~~~~~~~~~~~~~
> evsel.c:357:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
> 357 | if (read_format & PERF_FORMAT_LOST)
> | ^~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__adjust_values':
> evsel.c:371:32: error: invalid use of undefined type 'struct perf_evsel'
> 371 | u64 read_format = evsel->attr.read_format;
> | ^~
> evsel.c:376:27: error: 'PERF_FORMAT_TOTAL_TIME_ENABLED' undeclared (first use in this function)
> 376 | if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> CC /tmp/build/perf/libsubcmd/subcmd-config.o
> evsel.c:379:27: error: 'PERF_FORMAT_TOTAL_TIME_RUNNING' undeclared (first use in this function)
> 379 | if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> CC /tmp/build/perf/libbpf/staticobjs/libbpf.o
> evsel.c:382:27: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
> 382 | if (read_format & PERF_FORMAT_ID)
> | ^~~~~~~~~~~~~~
> evsel.c:385:27: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
> 385 | if (read_format & PERF_FORMAT_LOST)
> | ^~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__read':
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:393:19: note: in expansion of macro 'FD'
> 393 | int *fd = FD(evsel, cpu_map_idx, thread);
> | ^~
> evsel.c:394:32: error: invalid use of undefined type 'struct perf_evsel'
> 394 | u64 read_format = evsel->attr.read_format;
> | ^~
> evsel.c:402:27: error: 'PERF_FORMAT_GROUP' undeclared (first use in this function)
> 402 | if (read_format & PERF_FORMAT_GROUP)
> | ^~~~~~~~~~~~~~~~~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:405:13: note: in expansion of macro 'MMAP'
> 405 | if (MMAP(evsel, cpu_map_idx, thread) &&
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:405:13: note: in expansion of macro 'MMAP'
> 405 | if (MMAP(evsel, cpu_map_idx, thread) &&
> | ^~~~
> evsel.c:406:30: error: 'PERF_FORMAT_ID' undeclared (first use in this function)
> 406 | !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
> | ^~~~~~~~~~~~~~
> evsel.c:406:47: error: 'PERF_FORMAT_LOST' undeclared (first use in this function)
> 406 | !(read_format & (PERF_FORMAT_ID | PERF_FORMAT_LOST)) &&
> | ^~~~~~~~~~~~~~~~
> evsel.c:51:16: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:407:35: note: in expansion of macro 'MMAP'
> 407 | !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
> | ^~~~
> evsel.c:51:68: error: invalid use of undefined type 'struct perf_evsel'
> 51 | (_evsel->mmap ? ((struct perf_mmap *) xyarray__entry(_evsel->mmap, _cpu_map_idx, _thread)) \
> | ^~
> evsel.c:407:35: note: in expansion of macro 'MMAP'
> 407 | !perf_mmap__read_self(MMAP(evsel, cpu_map_idx, thread), count))
> | ^~~~
> evsel.c: In function 'perf_evsel__ioctl':
> evsel.c:49:38: error: invalid use of undefined type 'struct perf_evsel'
> 49 | ((int *)xyarray__entry(_evsel->fd, _cpu_map_idx, _thread))
> | ^~
> evsel.c:420:19: note: in expansion of macro 'FD'
> 420 | int *fd = FD(evsel, cpu_map_idx, thread);
> | ^~
> evsel.c: In function 'perf_evsel__run_ioctl':
> evsel.c:434:55: error: invalid use of undefined type 'struct perf_evsel'
> 434 | for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) {
> | ^~
> INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h
> evsel.c: In function 'perf_evsel__enable_cpu':
> evsel.c:446:45: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
> 446 | return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, cpu_map_idx);
> | ^~~~~~~~~~~~~~~~~~~~~
> In file included from evsel.c:6:
> evsel.c: In function 'perf_evsel__enable_thread':
> evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
> 455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
> | ^~
> /tmp/build/perf/libperf/include/perf/cpumap.h:89:51: note: in definition of macro 'perf_cpu_map__for_each_cpu'
> 89 | for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \
> | ^~~~
> evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
> 455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
> | ^~
> /tmp/build/perf/libperf/include/perf/cpumap.h:90:39: note: in definition of macro 'perf_cpu_map__for_each_cpu'
> 90 | (idx) < perf_cpu_map__nr(cpus); \
> | ^~~~
> evsel.c:455:51: error: invalid use of undefined type 'struct perf_evsel'
> 455 | perf_cpu_map__for_each_cpu(cpu, idx, evsel->cpus) {
> | ^~
> /tmp/build/perf/libperf/include/perf/cpumap.h:91:49: note: in definition of macro 'perf_cpu_map__for_each_cpu'
> 91 | (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx))
> | ^~~~
> evsel.c:456:48: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
> 456 | err = perf_evsel__ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, idx, thread);
> | ^~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__enable':
> evsel.c:469:45: error: invalid use of undefined type 'struct perf_evsel'
> 469 | for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
> | ^~
> evsel.c:470:52: error: 'PERF_EVENT_IOC_ENABLE' undeclared (first use in this function)
> 470 | err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, NULL, i);
> | ^~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__disable_cpu':
> evsel.c:476:45: error: 'PERF_EVENT_IOC_DISABLE' undeclared (first use in this function)
> 476 | return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, cpu_map_idx);
> | ^~~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__disable':
> evsel.c:484:45: error: invalid use of undefined type 'struct perf_evsel'
> 484 | for (i = 0; i < xyarray__max_x(evsel->fd) && !err; i++)
> | ^~
> evsel.c:485:52: error: 'PERF_EVENT_IOC_DISABLE' undeclared (first use in this function)
> 485 | err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, NULL, i);
> | ^~~~~~~~~~~~~~~~~~~~~~
> evsel.c: At top level:
> evsel.c:489:5: error: no previous prototype for 'perf_evsel__apply_filter' [-Werror=missing-prototypes]
> 489 | int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter)
> | ^~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__apply_filter':
> evsel.c:493:47: error: invalid use of undefined type 'struct perf_evsel'
> 493 | for (i = 0; i < perf_cpu_map__nr(evsel->cpus) && !err; i++)
> | ^~
> evsel.c:495:38: error: 'PERF_EVENT_IOC_SET_FILTER' undeclared (first use in this function)
> 495 | PERF_EVENT_IOC_SET_FILTER,
> | ^~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__cpus':
> evsel.c:502:21: error: invalid use of undefined type 'struct perf_evsel'
> 502 | return evsel->cpus;
> | ^~
> evsel.c: In function 'perf_evsel__threads':
> evsel.c:507:21: error: invalid use of undefined type 'struct perf_evsel'
> 507 | return evsel->threads;
> | ^~
> evsel.c: In function 'perf_evsel__attr':
> evsel.c:512:22: error: invalid use of undefined type 'struct perf_evsel'
> 512 | return &evsel->attr;
> | ^~
> evsel.c: At top level:
> evsel.c:515:5: error: no previous prototype for 'perf_evsel__alloc_id' [-Werror=missing-prototypes]
> 515 | int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
> | ^~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__alloc_id':
> evsel.c:520:14: error: invalid use of undefined type 'struct perf_evsel'
> 520 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
> | ^~
> evsel.c:520:65: error: invalid application of 'sizeof' to incomplete type 'struct perf_sample_id'
> 520 | evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id));
> | ^~~~~~
> evsel.c:521:18: error: invalid use of undefined type 'struct perf_evsel'
> 521 | if (evsel->sample_id == NULL)
> | ^~
> evsel.c:524:14: error: invalid use of undefined type 'struct perf_evsel'
> 524 | evsel->id = zalloc(ncpus * nthreads * sizeof(u64));
> | ^~
> evsel.c:525:18: error: invalid use of undefined type 'struct perf_evsel'
> 525 | if (evsel->id == NULL) {
> | ^~
> evsel.c:526:38: error: invalid use of undefined type 'struct perf_evsel'
> 526 | xyarray__delete(evsel->sample_id);
> | ^~
> evsel.c:527:22: error: invalid use of undefined type 'struct perf_evsel'
> 527 | evsel->sample_id = NULL;
> | ^~
> evsel.c: At top level:
> evsel.c:534:6: error: no previous prototype for 'perf_evsel__free_id' [-Werror=missing-prototypes]
> 534 | void perf_evsel__free_id(struct perf_evsel *evsel)
> | ^~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__free_id':
> evsel.c:538:30: error: invalid use of undefined type 'struct perf_evsel'
> 538 | xyarray__delete(evsel->sample_id);
> | ^~
> evsel.c:539:14: error: invalid use of undefined type 'struct perf_evsel'
> 539 | evsel->sample_id = NULL;
> | ^~
> In file included from evsel.c:11:
> evsel.c:540:21: error: invalid use of undefined type 'struct perf_evsel'
> 540 | zfree(&evsel->id);
> | ^~
> /git/perf-6.15.0-rc2/tools/include/linux/zalloc.h:10:38: note: in definition of macro 'zfree'
> 10 | #define zfree(ptr) __zfree((void **)(ptr))
> | ^~~
> evsel.c:541:14: error: invalid use of undefined type 'struct perf_evsel'
> 541 | evsel->ids = 0;
> | ^~
> evsel.c:543:9: error: implicit declaration of function 'perf_evsel_for_each_per_thread_period_safe' [-Werror=implicit-function-declaration]
> 543 | perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:543:9: error: nested extern declaration of 'perf_evsel_for_each_per_thread_period_safe' [-Werror=nested-externs]
> evsel.c:543:66: error: expected ';' before '{' token
> 543 | perf_evsel_for_each_per_thread_period_safe(evsel, n, pos) {
> | ^~
> | ;
> evsel.c: At top level:
> evsel.c:549:6: error: no previous prototype for 'perf_evsel__attr_has_per_thread_sample_period' [-Werror=missing-prototypes]
> 549 | bool perf_evsel__attr_has_per_thread_sample_period(struct perf_evsel *evsel)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_evsel__attr_has_per_thread_sample_period':
> evsel.c:551:22: error: invalid use of undefined type 'struct perf_evsel'
> 551 | return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
> | ^~
> evsel.c:551:43: error: 'PERF_SAMPLE_READ' undeclared (first use in this function)
> 551 | return (evsel->attr.sample_type & PERF_SAMPLE_READ) &&
> | ^~~~~~~~~~~~~~~~
> evsel.c:552:23: error: invalid use of undefined type 'struct perf_evsel'
> 552 | (evsel->attr.sample_type & PERF_SAMPLE_TID) &&
> | ^~
> evsel.c:552:44: error: 'PERF_SAMPLE_TID' undeclared (first use in this function); did you mean 'PERF_SAMPLE_MAX_SIZE'?
> 552 | (evsel->attr.sample_type & PERF_SAMPLE_TID) &&
> | ^~~~~~~~~~~~~~~
> | PERF_SAMPLE_MAX_SIZE
> evsel.c:553:22: error: invalid use of undefined type 'struct perf_evsel'
> 553 | evsel->attr.inherit;
> | ^~
> evsel.c: At top level:
> evsel.c:556:48: error: 'struct perf_sample_id' declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> 556 | u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
> | ^~~~~~~~~~~~~~
> evsel.c:556:6: error: no previous prototype for 'perf_sample_id__get_period_storage' [-Werror=missing-prototypes]
> 556 | u64 *perf_sample_id__get_period_storage(struct perf_sample_id *sid, u32 tid, bool per_thread)
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c: In function 'perf_sample_id__get_period_storage':
> evsel.c:563:28: error: invalid use of undefined type 'struct perf_sample_id'
> 563 | return &sid->period;
> | ^~
> evsel.c:565:29: error: 'PERF_SAMPLE_ID__HLIST_BITS' undeclared (first use in this function)
> 565 | hash = hash_32(tid, PERF_SAMPLE_ID__HLIST_BITS);
> | ^~~~~~~~~~~~~~~~~~~~~~~~~~
> evsel.c:566:20: error: invalid use of undefined type 'struct perf_sample_id'
> 566 | head = &sid->periods[hash];
> | ^~
> In file included from /git/perf-6.15.0-rc2/tools/include/linux/kernel.h:14,
> from /git/perf-6.15.0-rc2/tools/include/linux/list.h:7,
> from evsel.c:9:
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:33: error: invalid use of undefined type 'struct perf_sample_id_period'
> 14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
> | ^~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
> 726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:54: error: initialization of 'const int *' from incompatible pointer type 'struct hlist_node *' [-Werror=incompatible-pointer-types]
> 14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
> | ^
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
> 726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> In file included from /usr/include/sys/mman.h:25,
> from evsel.c:20:
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:15:35: error: invalid use of undefined type 'struct perf_sample_id_period'
> 15 | (type *)((char *)__mptr - offsetof(type, member)); })
> | ^~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:726:20: note: in expansion of macro 'hlist_entry_safe'
> 726 | for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:728:42: error: invalid use of undefined type 'struct perf_sample_id_period'
> 728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
> | ^~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:715:19: note: in definition of macro 'hlist_entry_safe'
> 715 | ({ typeof(ptr) ____ptr = (ptr); \
> | ^~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:728:42: error: invalid use of undefined type 'struct perf_sample_id_period'
> 728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
> | ^~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:715:35: note: in definition of macro 'hlist_entry_safe'
> 715 | ({ typeof(ptr) ____ptr = (ptr); \
> | ^~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:33: error: invalid use of undefined type 'struct perf_sample_id_period'
> 14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
> | ^~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
> 728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:14:54: error: initialization of 'const int *' from 'int' makes pointer from integer without a cast [-Werror=int-conversion]
> 14 | const typeof(((type *)0)->member) * __mptr = (ptr); \
> | ^
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
> 728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/container_of.h:15:35: error: invalid use of undefined type 'struct perf_sample_id_period'
> 15 | (type *)((char *)__mptr - offsetof(type, member)); })
> | ^~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:705:40: note: in expansion of macro 'container_of'
> 705 | #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
> | ^~~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:716:22: note: in expansion of macro 'hlist_entry'
> 716 | ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
> | ^~~~~~~~~~~
> /git/perf-6.15.0-rc2/tools/include/linux/list.h:728:20: note: in expansion of macro 'hlist_entry_safe'
> 728 | pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
> | ^~~~~~~~~~~~~~~~
> evsel.c:568:9: note: in expansion of macro 'hlist_for_each_entry'
> 568 | hlist_for_each_entry(res, head, hnode)
> | ^~~~~~~~~~~~~~~~~~~~
> evsel.c:569:24: error: invalid use of undefined type 'struct perf_sample_id_period'
> 569 | if (res->tid == tid)
> | ^~
> evsel.c:570:36: error: invalid use of undefined type 'struct perf_sample_id_period'
> 570 | return &res->period;
> | ^~
> evsel.c:572:16: error: invalid use of undefined type 'struct perf_sample_id'
> 572 | if (sid->evsel == NULL)
> | ^~
> evsel.c:575:29: error: invalid application of 'sizeof' to incomplete type 'struct perf_sample_id_period'
> 575 | res = zalloc(sizeof(struct perf_sample_id_period));
> | ^~~~~~
> evsel.c:579:28: error: invalid use of undefined type 'struct perf_sample_id_period'
> 579 | INIT_LIST_HEAD(&res->node);
> | ^~
> evsel.c:580:12: error: invalid use of undefined type 'struct perf_sample_id_period'
> 580 | res->tid = tid;
> | ^~
> evsel.c:582:27: error: invalid use of undefined type 'struct perf_sample_id_period'
> 582 | list_add_tail(&res->node, &sid->evsel->per_stream_periods);
> | ^~
> evsel.c:582:39: error: invalid use of undefined type 'struct perf_sample_id'
> 582 | list_add_tail(&res->node, &sid->evsel->per_stream_periods);
> | ^~
> evsel.c:583:28: error: invalid use of undefined type 'struct perf_sample_id_period'
> 583 | hlist_add_head(&res->hnode, &sid->periods[hash]);
> | ^~
> evsel.c:583:41: error: invalid use of undefined type 'struct perf_sample_id'
> 583 | hlist_add_head(&res->hnode, &sid->periods[hash]);
> | ^~
> evsel.c:585:20: error: invalid use of undefined type 'struct perf_sample_id_period'
> 585 | return &res->period;
> | ^~
> evsel.c:560:13: error: variable 'hash' set but not used [-Werror=unused-but-set-variable]
> 560 | int hash;
> | ^~~~
> evsel.c: In function 'perf_evsel__alloc_fd':
> evsel.c:72:1: error: control reaches end of non-void function [-Werror=return-type]
> 72 | }
> | ^
> evsel.c: In function 'perf_evsel__mmap_base':
> evsel.c:292:1: error: control reaches end of non-void function [-Werror=return-type]
> 292 | }
> | ^
> evsel.c: In function 'perf_evsel__enable_cpu':
> evsel.c:447:1: error: control reaches end of non-void function [-Werror=return-type]
> 447 | }
> | ^
> evsel.c: In function 'perf_evsel__disable_cpu':
> evsel.c:477:1: error: control reaches end of non-void function [-Werror=return-type]
> 477 | }
> | ^
> evsel.c: In function 'perf_evsel__cpus':
> evsel.c:503:1: error: control reaches end of non-void function [-Werror=return-type]
> 503 | }
> | ^
> evsel.c: In function 'perf_evsel__threads':
> evsel.c:508:1: error: control reaches end of non-void function [-Werror=return-type]
> 508 | }
> | ^
> evsel.c: In function 'perf_evsel__attr':
> evsel.c:513:1: error: control reaches end of non-void function [-Werror=return-type]
> 513 | }
> | ^
> evsel.c: In function 'perf_evsel__attr_has_per_thread_sample_period':
> evsel.c:554:1: error: control reaches end of non-void function [-Werror=return-type]
> 554 | }
> | ^
> evsel.c: In function 'perf_sample_id__get_period_storage':
> evsel.c:586:1: error: control reaches end of non-void function [-Werror=return-type]
> 586 | }
> | ^
> cc1: all warnings being treated as errors
> make[4]: *** [/git/perf-6.15.0-rc2/tools/build/Makefile.build:85: /tmp/build/perf/libperf/evsel.o] Error 1
> make[4]: *** Waiting for unfinished jobs....
> LD /tmp/build/perf/jvmti/jvmti-in.o
> CC /tmp/build/perf/libbpf/staticobjs/bpf.o
> INSTALL libperf_headers
> CC /tmp/build/perf/libbpf/staticobjs/nlattr.o
> LD /tmp/build/perf/libapi/libapi-in.o
> AR /tmp/build/perf/libapi/libapi.a
> CC /tmp/build/perf/libbpf/staticobjs/libbpf_errno.o
> CC /tmp/build/perf/libbpf/staticobjs/btf.o
> CC /tmp/build/perf/libbpf/staticobjs/str_error.o
> CC /tmp/build/perf/libbpf/staticobjs/netlink.o
> CC /tmp/build/perf/libbpf/staticobjs/bpf_prog_linfo.o
> CC /tmp/build/perf/libbpf/staticobjs/libbpf_probes.o
> CC /tmp/build/perf/libbpf/staticobjs/btf_dump.o
> CC /tmp/build/perf/libbpf/staticobjs/ringbuf.o
> CC /tmp/build/perf/libbpf/staticobjs/hashmap.o
> CC /tmp/build/perf/libbpf/staticobjs/strset.o
> CC /tmp/build/perf/libbpf/staticobjs/linker.o
> CC /tmp/build/perf/libbpf/staticobjs/gen_loader.o
> CC /tmp/build/perf/libbpf/staticobjs/usdt.o
> CC /tmp/build/perf/libbpf/staticobjs/relo_core.o
> CC /tmp/build/perf/libbpf/staticobjs/zip.o
> CC /tmp/build/perf/libbpf/staticobjs/elf.o
> CC /tmp/build/perf/libbpf/staticobjs/btf_iter.o
> CC /tmp/build/perf/libbpf/staticobjs/features.o
> CC /tmp/build/perf/libbpf/staticobjs/btf_relocate.o
> make[3]: *** [Makefile:103: /tmp/build/perf/libperf/libperf-in.o] Error 2
> make[2]: *** [Makefile.perf:976: /tmp/build/perf/libperf/libperf.a] Error 2
> make[2]: *** Waiting for unfinished jobs....
> LD /tmp/build/perf/libsubcmd/libsubcmd-in.o
> AR /tmp/build/perf/libsubcmd/libsubcmd.a
> LD /tmp/build/perf/libbpf/staticobjs/libbpf-in.o
> LINK /tmp/build/perf/libbpf/libbpf.a
>
> Auto-detecting system features:
> ... clang-bpf-co-re: [ on ]
> ... llvm: [ on ]
> ... libcap: [ on ]
> ... libbfd: [ on ]
>
> MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf
> MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/
> MKDIR /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/hashmap.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/relo_core.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_internal.h
> GEN /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/bpf_helper_defs.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/btf.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_legacy.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_common.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helpers.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_tracing.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_core_read.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_endian.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/libbpf_version.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/skel_internal.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/usdt.bpf.h
> INSTALL /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/include/bpf/bpf_helper_defs.h
> INSTALL libbpf_headers
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/nlattr.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_errno.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/str_error.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/netlink.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/bpf_prog_linfo.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf_probes.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/hashmap.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_dump.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/ringbuf.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/strset.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/linker.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/gen_loader.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/zip.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/usdt.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/relo_core.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_relocate.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/elf.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/features.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/btf_iter.o
> LD /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/staticobjs/libbpf-in.o
> LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/libbpf/libbpf.a
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/main.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/common.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/json_writer.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/gen.o
> CC /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/btf.o
> LINK /tmp/build/perf/util/bpf_skel/.tmp/bootstrap/bpftool
> make[1]: *** [Makefile.perf:287: sub-make] Error 2
> make: *** [Makefile:76: all] Error 2
> make: Leaving directory '/git/perf-6.15.0-rc2/tools/perf'
> + exit 1
> toolsbuilder@number:~/git/linux-tools-container-builds$
>
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO
[not found] ` <CA+JHD93NCu5VeP9b+DzMm0f0YHwJLRFJeHNtWogx6wKFrHi8Yw@mail.gmail.com>
@ 2025-05-27 20:45 ` Ian Rogers
0 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-05-27 20:45 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Arnaldo Carvalho de Melo, Peter Zijlstra, Ingo Molnar,
Namhyung Kim, Mark Rutland, Alexander Shishkin, Jiri Olsa,
Adrian Hunter, Kan Liang, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Aditya Gupta, Steinar H. Gunderson,
Charlie Jenkins, Changbin Du, Masami Hiramatsu (Google),
James Clark, Kajol Jain, Athira Rajeev, Li Huafei, Dmitry Vyukov,
Andi Kleen, Chaitanya S Prakash, Linux Kernel Mailing List,
linux-perf-users, clang-built-linux, Song Liu, bpf
On Sat, Apr 19, 2025 at 3:31 AM Arnaldo Carvalho de Melo
<arnaldo.melo@gmail.com> wrote:
>
>
>
> On Sat, Apr 19, 2025, 1:23 AM Ian Rogers <irogers@google.com> wrote:
>>
>> On Fri, Apr 18, 2025 at 2:29 PM Arnaldo Carvalho de Melo
>> <acme@kernel.org> wrote:
>> >
>> > On Thu, Apr 17, 2025 at 04:07:21PM -0700, Ian Rogers wrote:
>> > > Linking against libcapstone and libLLVM can be a significant increase
>> > > in dependencies and file size if building statically. For something
>> > > like `perf record` the disassembler and addr2line functionality won't
>> > > be used. Support dynamically loading these libraries using dlopen and
>> > > then calling the appropriate functions found using dlsym.
>> > >
>> > > BUILD_NONDISTRO is used to build perf against the license incompatible
>> > > libbfd and libiberty libraries. As this has been opt-in for nearly 2
>> > > years, commit dd317df07207 ("perf build: Make binutil libraries opt
>> > > in"), remove the code to simplify the code base.
>> > >
>> > > The patch series:
>> > > 1) does some initial clean up;
>> > > 2) moves the capstone and LLVM code to their own C files,
>> > > 3) simplifies a little the capstone code;
>> > > 4) adds perf_ variants of the functions that will either directly call
>> > > the function or use dlsym to discover it;
>> > > 5) adds BPF JIT disassembly support to LLVM and capstone disassembly;
>> > > 6) removes the BUILD_NONDISTRO code, reduces scope and removes what's possible;
>> > > 7) adds fallback to srcline's addr2line so that llvm_addr2line is
>> > > tried first and then the forked command tried next, moving the code
>> > > for forking out of the main srcline.c file in the process.
>> > >
>> > > The addr2line LLVM functionality is written in C++. To avoid linking
>> > > against libLLVM for this, a new LIBLLVM_DYNAMIC option is added where
>> > > the C++ code with the libLLVM dependency will be built into a
>> > > libperf-llvm.so and that dlsym-ed and called against. Ideally LLVM
>> > > would extend their C API to avoid this.
>> > >
>> > > The libbfd BPF disassembly supported source lines, this wasn't ported
>> > > to the capstone and LLVM disassembly.
>> >
>> > Doing the build tests I noticed, so far:
>> >
>> > 29 58.92 opensuse:15.4 : FAIL gcc version 7.5.0 (SUSE Linux)
>> > <SNIP>
>> > + make NO_LIBTRACEEVENT=1 ARCH= CROSS_COMPILE= EXTRA_CFLAGS= NO_LIBBPF=1 -C tools/perf O=/tmp/build/perf
>> > make: Entering directory '/git/perf-6.15.0-rc2/tools/perf'
>> > BUILD: Doing 'make -j32' parallel build
>> > Warning: Skipped check-headers due to missing ../../include
>> > Makefile.config:560: No elfutils/debuginfod.h found, no debuginfo server support, please install libdebuginfod-dev/elfutils-debuginfod-client-devel or equivalent
>> > Makefile.config:687: Warning: Disabled BPF skeletons as libbpf is required
>> > Makefile.config:1039: No libbabeltrace found, disables 'perf data' CTF format support, please install libbabeltrace-dev[el]/libbabeltrace-ctf-dev
>> > update-alternatives: error: no alternatives for java
>> > update-alternatives: error: no alternatives for java
>> > Makefile.config:1100: No openjdk development package found, please install JDK package, e.g. openjdk-8-jdk, java-1.8.0-openjdk-devel
>> > Makefile.config:1113: libpfm4 not found, disables libpfm4 support. Please install libpfm4-dev
>> >
>> > Auto-detecting system features:
>> > ... libdw: [ on ]
>> > ... glibc: [ on ]
>> > ... libelf: [ on ]
>> > ... libnuma: [ on ]
>> > ... numa_num_possible_cpus: [ on ]
>> > ... libperl: [ on ]
>> > ... libpython: [ on ]
>> > ... libcrypto: [ on ]
>> > ... libcapstone: [ on ]
>> > ... llvm-perf: [ on ]
>> > ... zlib: [ on ]
>> > ... lzma: [ on ]
>> > ... get_cpuid: [ on ]
>> > ... bpf: [ on ]
>> > ... libaio: [ on ]
>> > ... libzstd: [ on ]
>> >
>> > PERF_VERSION = 6.15.rc2.gfbcac9367d45
>> > GEN /tmp/build/perf/common-cmds.h
>> > GEN /tmp/build/perf/arch/arm64/include/generated/asm/sysreg-defs.h
>> > GEN perf-archive
>> > GEN perf-iostat
>> > CC /tmp/build/perf/dlfilters/dlfilter-test-api-v0.o
>> > CC /tmp/build/perf/dlfilters/dlfilter-test-api-v2.o
>> > CC /tmp/build/perf/dlfilters/dlfilter-show-cycles.o
>> > INSTALL /tmp/build/perf/libapi/include/api/cpu.h
>> > INSTALL /tmp/build/perf/libapi/include/api/debug.h
>> > INSTALL /tmp/build/perf/libapi/include/api/io.h
>> > MKDIR /tmp/build/perf/libapi/fd/
>> > INSTALL /tmp/build/perf/libapi/include/api/io_dir.h
>> > CC /tmp/build/perf/libapi/cpu.o
>> > MKDIR /tmp/build/perf/libapi/fs/
>> > INSTALL /tmp/build/perf/libapi/include/api/fd/array.h
>> > CC /tmp/build/perf/libapi/debug.o
>> > MKDIR /tmp/build/perf/libapi/fs/
>> > MKDIR /tmp/build/perf/libapi/fs/
>> > CC /tmp/build/perf/libapi/fd/array.o
>> > INSTALL /tmp/build/perf/libapi/include/api/fs/tracing_path.h
>> > CC /tmp/build/perf/libapi/str_error_r.o
>> > INSTALL /tmp/build/perf/libapi/include/api/fs/fs.h
>> > CC /tmp/build/perf/libapi/fs/tracing_path.o
>> > CC /tmp/build/perf/libapi/fs/fs.o
>> > CC /tmp/build/perf/libapi/fs/cgroup.o
>> > INSTALL libapi_headers
>> > INSTALL /tmp/build/perf/libperf/include/perf/bpf_perf.h
>> > INSTALL /tmp/build/perf/libperf/include/perf/core.h
>> > INSTALL /tmp/build/perf/libperf/include/perf/cpumap.h
>> > INSTALL /tmp/build/perf/libperf/include/perf/threadmap.h
>> > CC /tmp/build/perf/libperf/core.o
>> > CC /tmp/build/perf/libperf/cpumap.o
>> > CC /tmp/build/perf/libperf/threadmap.o
>> > INSTALL /tmp/build/perf/libperf/include/perf/evlist.h
>> > CC /tmp/build/perf/libperf/evlist.o
>> > CC /tmp/build/perf/libperf/evsel.o
>> > CC /tmp/build/perf/libperf/mmap.o
>> > CC /tmp/build/perf/libperf/zalloc.o
>> > INSTALL /tmp/build/perf/libsubcmd/include/subcmd/exec-cmd.h
>> > INSTALL /tmp/build/perf/libperf/include/perf/evsel.h
>> > CC /tmp/build/perf/libperf/xyarray.o
>> > CC /tmp/build/perf/libperf/lib.o
>> > INSTALL /tmp/build/perf/libsubcmd/include/subcmd/help.h
>> > INSTALL /tmp/build/perf/libsubcmd/include/subcmd/pager.h
>> > LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v0.so
>> > INSTALL /tmp/build/perf/libsubcmd/include/subcmd/parse-options.h
>> > LD /tmp/build/perf/libapi/fd/libapi-in.o
>> > INSTALL /tmp/build/perf/libsubcmd/include/subcmd/run-command.h
>> > INSTALL libsubcmd_headers
>> > LINK /tmp/build/perf/dlfilters/dlfilter-test-api-v2.so
>> > INSTALL /tmp/build/perf/libperf/include/perf/event.h
>> > INSTALL /tmp/build/perf/libsymbol/include/symbol/kallsyms.h
>> > CC /tmp/build/perf/libsymbol/kallsyms.o
>> > INSTALL /tmp/build/perf/libperf/include/perf/mmap.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/cpumap.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/evlist.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/evsel.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/rc_check.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/mmap.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/threadmap.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/lib.h
>> > INSTALL /tmp/build/perf/libperf/include/internal/xyarray.h
>> > LINK /tmp/build/perf/dlfilters/dlfilter-show-cycles.so
>> > LD /tmp/build/perf/libapi/fs/libapi-in.o
>> > evlist.c:28:6: error: no previous prototype for 'perf_evlist__init' [-Werror=missing-prototypes]
>> > void perf_evlist__init(struct perf_evlist *evlist)
>> > ^~~~~~~~~~~~~~~~~
>>
>> Hmm.. but on line 8 of tools/lib/perf/evlist.c is:
>> #include <internal/evlist.h>
>> is there a libperf installed somewhere? I thought we were just
>> statically linking currently. I'm not sure what I can do to resolve
>> this, it seems like a set up issue.
>
>
> I'll investigate and report back.
Ping. Thanks,
Ian
> - Arnaldo
>
>>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-04-17 23:07 ` [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so Ian Rogers
@ 2025-06-26 23:19 ` Namhyung Kim
2025-06-27 4:53 ` Ian Rogers
0 siblings, 1 reply; 28+ messages in thread
From: Namhyung Kim @ 2025-06-26 23:19 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Nathan Chancellor, Nick Desaulniers, Bill Wendling,
Justin Stitt, Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins,
Changbin Du, Masami Hiramatsu (Google), James Clark, Kajol Jain,
Athira Rajeev, Li Huafei, Dmitry Vyukov, Andi Kleen,
Chaitanya S Prakash, linux-kernel, linux-perf-users, llvm,
Song Liu, bpf
On Thu, Apr 17, 2025 at 04:07:27PM -0700, Ian Rogers wrote:
> 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.
I still think it's simpler to require capstone headers at build time and
add LIBCAPSTONE_DYNAMIC=1 or something to support dlopen.
Thanks,
Namhyung
>
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
> 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 c9845e4d8781..8d65c7a55a8b 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 <dlfcn.h>
> #include <fcntl.h>
> +#include <inttypes.h>
> #include <string.h>
>
> #ifdef HAVE_LIBCAPSTONE_SUPPORT
> #include <capstone/capstone.h>
> +#else
> +typedef size_t csh;
> +enum cs_arch {
> + CS_ARCH_ARM = 0,
> + CS_ARCH_ARM64 = 1,
> + CS_ARCH_X86 = 3,
> + CS_ARCH_SYSZ = 6,
> +};
> +enum cs_mode {
> + CS_MODE_ARM = 0,
> + CS_MODE_32 = 1 << 2,
> + CS_MODE_64 = 1 << 3,
> + CS_MODE_V8 = 1 << 6,
> + CS_MODE_BIG_ENDIAN = 1 << 31,
> +};
> +enum cs_opt_type {
> + CS_OPT_SYNTAX = 1,
> + CS_OPT_DETAIL = 2,
> +};
> +enum cs_opt_value {
> + CS_OPT_SYNTAX_ATT = 2,
> + CS_OPT_ON = 3,
> +};
> +enum cs_err {
> + CS_ERR_OK = 0,
> + CS_ERR_HANDLE = 3,
> +};
> +enum x86_op_type {
> + X86_OP_IMM = 2,
> + X86_OP_MEM = 3,
> +};
> +enum x86_reg {
> + X86_REG_RIP = 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 = true;
> + dll_handle = 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 *handle);
> +
> + if (!fn_init) {
> + fn = dlsym(perf_cs_dll_handle(), "cs_open");
> + if (!fn)
> + pr_debug("dlsym failed for cs_open\n");
> + fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_option");
> + if (!fn)
> + pr_debug("dlsym failed for cs_option\n");
> + fn_init = 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_size,
> + uint64_t address, size_t count, struct cs_insn **insn);
> +
> + if (!fn_init) {
> + fn = dlsym(perf_cs_dll_handle(), "cs_disasm");
> + if (!fn)
> + pr_debug("dlsym failed for cs_disasm\n");
> + fn_init = 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)
> +{
> #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 = dlsym(perf_cs_dll_handle(), "cs_free");
> + if (!fn)
> + pr_debug("dlsym failed for cs_free\n");
> + fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_close");
> + if (!fn)
> + pr_debug("dlsym failed for cs_close\n");
> + fn_init = true;
> + }
> + if (!fn)
> + return CS_ERR_HANDLE;
> + return fn(handle);
> +#endif
> +}
> +
> static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
> bool disassembler_style)
> {
> - cs_arch arch;
> - cs_mode mode;
> + enum cs_arch arch;
> + enum cs_mode mode;
>
> if (machine__is(machine, "x86_64") && is64) {
> arch = CS_ARCH_X86;
> @@ -44,7 +274,7 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
> return -1;
> }
>
> - if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
> + if (perf_cs_open(arch, mode, cs_handle) != 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);
> }
>
> return 0;
> }
> -#endif
>
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> -static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
> +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 = 0;
>
> if (insn->detail && insn->detail->x86.op_count == 1) {
> - cs_x86_op *op = &insn->detail->x86.operands[0];
> + struct cs_x86_op *op = &insn->detail->x86.operands[0];
>
> addr_location__init(&al);
> if (op->type == X86_OP_IMM &&
> @@ -94,7 +322,6 @@ static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
> printed += 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,
> @@ -105,9 +332,8 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __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 *machine __maybe_unused,
> if (ret < 0)
> return ret;
>
> - count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
> + count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
> if (count > 0) {
> if (machine__normalized_is(machine, "x86"))
> printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
> @@ -125,20 +351,16 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
> printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
> if (lenp)
> *lenp = insn->size;
> - cs_free(insn, count);
> + perf_cs_free(insn, count);
> } else {
> printed = -1;
> }
>
> - cs_close(&cs_handle);
> + perf_cs_close(&cs_handle);
> return printed;
> -#else
> - return -1;
> -#endif
> }
>
> -#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;
>
> for (i = 0; i < insn->detail->x86.op_count; i++) {
> - cs_x86_op *op = &insn->detail->x86.operands[i];
> + struct cs_x86_op *op = &insn->detail->x86.operands[i];
> u64 orig_addr;
>
> if (op->type != X86_OP_MEM)
> @@ -194,9 +416,7 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
> break;
> }
> }
> -#endif
>
> -#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 pgoff, void *arg)
> }
> 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)
> @@ -262,13 +480,11 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym,
> 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 = symbol__annotation(sym);
> struct map *map = args->ms.map;
> u64 start = map__rip_2objdump(map, sym->start);
> @@ -279,7 +495,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
> bool needs_cs_close = false;
> u8 *buf = NULL;
> csh handle;
> - cs_insn *insn = NULL;
> + struct cs_insn *insn = NULL;
> char disasm_buf[512];
> struct disasm_line *dl;
> bool disassembler_style = false;
> @@ -316,7 +532,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>
> needs_cs_close = true;
>
> - free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
> + free_count = count = perf_cs_disasm(handle, buf, len, start, len, &insn);
> for (i = 0, offset = 0; i < count; i++) {
> int printed;
>
> @@ -355,9 +571,9 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>
> 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 = -1;
> goto out;
> -#else
> - return -1;
> -#endif
> }
>
> int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
> struct symbol *sym __maybe_unused,
> struct annotate_args *args __maybe_unused)
> {
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> struct annotation *notes = symbol__annotation(sym);
> struct map *map = args->ms.map;
> struct dso *dso = map__dso(map);
> @@ -499,7 +711,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
>
> out:
> if (needs_cs_close)
> - cs_close(&handle);
> + perf_cs_close(&handle);
> free(buf);
> return count < 0 ? count : 0;
>
> @@ -508,7 +720,4 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
> close(fd);
> count = -1;
> goto out;
> -#else
> - return -1;
> -#endif
> }
> --
> 2.49.0.805.g082f7c87e0-goog
>
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-06-26 23:19 ` Namhyung Kim
@ 2025-06-27 4:53 ` Ian Rogers
2025-06-27 16:44 ` Ian Rogers
0 siblings, 1 reply; 28+ messages in thread
From: Ian Rogers @ 2025-06-27 4:53 UTC (permalink / raw)
To: Namhyung Kim
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Nathan Chancellor, Nick Desaulniers, Bill Wendling,
Justin Stitt, Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins,
Changbin Du, Masami Hiramatsu (Google), James Clark, Kajol Jain,
Athira Rajeev, Li Huafei, Dmitry Vyukov, Andi Kleen,
Chaitanya S Prakash, linux-kernel, linux-perf-users, llvm,
Song Liu, bpf
On Thu, Jun 26, 2025 at 4:19 PM Namhyung Kim <namhyung@kernel.org> wrote:
>
> On Thu, Apr 17, 2025 at 04:07:27PM -0700, Ian Rogers wrote:
> > 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.
>
> I still think it's simpler to require capstone headers at build time and
> add LIBCAPSTONE_DYNAMIC=1 or something to support dlopen.
I agree, having a header file avoids the need to declare the header
file values. This is simpler. Can we make the build require
libcapstone and libLLVM in the same way that libtraceevent is
required? That is you have to explicitly build with NO_LIBTRACEEVENT=1
to get a no libtraceevent build to succeed. If we don't do this then
having LIBCAPSTONE_DYNAMIC will most likely be an unused option and
not worth carrying in the code base, I think that's sad. If we require
the libraries I don't like the idea of people arguing, "why do I need
to install libcapstone and libLLVM just to get the kernel/perf to
build now?" The non-simple, but still not very complex, approach taken
here was taken as a compromise to get the best result (a perf that
gets faster, BPF support, .. when libraries are available without
explicitly depending on them) while trying not to offend kernel
developers who are often trying to build on minimal systems.
Thanks,
Ian
> Thanks,
> Namhyung
>
> >
> > Signed-off-by: Ian Rogers <irogers@google.com>
> > ---
> > 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 c9845e4d8781..8d65c7a55a8b 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 <dlfcn.h>
> > #include <fcntl.h>
> > +#include <inttypes.h>
> > #include <string.h>
> >
> > #ifdef HAVE_LIBCAPSTONE_SUPPORT
> > #include <capstone/capstone.h>
> > +#else
> > +typedef size_t csh;
> > +enum cs_arch {
> > + CS_ARCH_ARM = 0,
> > + CS_ARCH_ARM64 = 1,
> > + CS_ARCH_X86 = 3,
> > + CS_ARCH_SYSZ = 6,
> > +};
> > +enum cs_mode {
> > + CS_MODE_ARM = 0,
> > + CS_MODE_32 = 1 << 2,
> > + CS_MODE_64 = 1 << 3,
> > + CS_MODE_V8 = 1 << 6,
> > + CS_MODE_BIG_ENDIAN = 1 << 31,
> > +};
> > +enum cs_opt_type {
> > + CS_OPT_SYNTAX = 1,
> > + CS_OPT_DETAIL = 2,
> > +};
> > +enum cs_opt_value {
> > + CS_OPT_SYNTAX_ATT = 2,
> > + CS_OPT_ON = 3,
> > +};
> > +enum cs_err {
> > + CS_ERR_OK = 0,
> > + CS_ERR_HANDLE = 3,
> > +};
> > +enum x86_op_type {
> > + X86_OP_IMM = 2,
> > + X86_OP_MEM = 3,
> > +};
> > +enum x86_reg {
> > + X86_REG_RIP = 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 = true;
> > + dll_handle = 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 *handle);
> > +
> > + if (!fn_init) {
> > + fn = dlsym(perf_cs_dll_handle(), "cs_open");
> > + if (!fn)
> > + pr_debug("dlsym failed for cs_open\n");
> > + fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_option");
> > + if (!fn)
> > + pr_debug("dlsym failed for cs_option\n");
> > + fn_init = 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_size,
> > + uint64_t address, size_t count, struct cs_insn **insn);
> > +
> > + if (!fn_init) {
> > + fn = dlsym(perf_cs_dll_handle(), "cs_disasm");
> > + if (!fn)
> > + pr_debug("dlsym failed for cs_disasm\n");
> > + fn_init = 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)
> > +{
> > #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 = dlsym(perf_cs_dll_handle(), "cs_free");
> > + if (!fn)
> > + pr_debug("dlsym failed for cs_free\n");
> > + fn_init = 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 = dlsym(perf_cs_dll_handle(), "cs_close");
> > + if (!fn)
> > + pr_debug("dlsym failed for cs_close\n");
> > + fn_init = true;
> > + }
> > + if (!fn)
> > + return CS_ERR_HANDLE;
> > + return fn(handle);
> > +#endif
> > +}
> > +
> > static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
> > bool disassembler_style)
> > {
> > - cs_arch arch;
> > - cs_mode mode;
> > + enum cs_arch arch;
> > + enum cs_mode mode;
> >
> > if (machine__is(machine, "x86_64") && is64) {
> > arch = CS_ARCH_X86;
> > @@ -44,7 +274,7 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
> > return -1;
> > }
> >
> > - if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
> > + if (perf_cs_open(arch, mode, cs_handle) != 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);
> > }
> >
> > return 0;
> > }
> > -#endif
> >
> > -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> > -static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
> > +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 = 0;
> >
> > if (insn->detail && insn->detail->x86.op_count == 1) {
> > - cs_x86_op *op = &insn->detail->x86.operands[0];
> > + struct cs_x86_op *op = &insn->detail->x86.operands[0];
> >
> > addr_location__init(&al);
> > if (op->type == X86_OP_IMM &&
> > @@ -94,7 +322,6 @@ static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
> > printed += 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,
> > @@ -105,9 +332,8 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __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 *machine __maybe_unused,
> > if (ret < 0)
> > return ret;
> >
> > - count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
> > + count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
> > if (count > 0) {
> > if (machine__normalized_is(machine, "x86"))
> > printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
> > @@ -125,20 +351,16 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
> > printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
> > if (lenp)
> > *lenp = insn->size;
> > - cs_free(insn, count);
> > + perf_cs_free(insn, count);
> > } else {
> > printed = -1;
> > }
> >
> > - cs_close(&cs_handle);
> > + perf_cs_close(&cs_handle);
> > return printed;
> > -#else
> > - return -1;
> > -#endif
> > }
> >
> > -#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;
> >
> > for (i = 0; i < insn->detail->x86.op_count; i++) {
> > - cs_x86_op *op = &insn->detail->x86.operands[i];
> > + struct cs_x86_op *op = &insn->detail->x86.operands[i];
> > u64 orig_addr;
> >
> > if (op->type != X86_OP_MEM)
> > @@ -194,9 +416,7 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
> > break;
> > }
> > }
> > -#endif
> >
> > -#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 pgoff, void *arg)
> > }
> > 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)
> > @@ -262,13 +480,11 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym,
> > 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 = symbol__annotation(sym);
> > struct map *map = args->ms.map;
> > u64 start = map__rip_2objdump(map, sym->start);
> > @@ -279,7 +495,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
> > bool needs_cs_close = false;
> > u8 *buf = NULL;
> > csh handle;
> > - cs_insn *insn = NULL;
> > + struct cs_insn *insn = NULL;
> > char disasm_buf[512];
> > struct disasm_line *dl;
> > bool disassembler_style = false;
> > @@ -316,7 +532,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
> >
> > needs_cs_close = true;
> >
> > - free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
> > + free_count = count = perf_cs_disasm(handle, buf, len, start, len, &insn);
> > for (i = 0, offset = 0; i < count; i++) {
> > int printed;
> >
> > @@ -355,9 +571,9 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
> >
> > 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 = -1;
> > goto out;
> > -#else
> > - return -1;
> > -#endif
> > }
> >
> > int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
> > struct symbol *sym __maybe_unused,
> > struct annotate_args *args __maybe_unused)
> > {
> > -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> > struct annotation *notes = symbol__annotation(sym);
> > struct map *map = args->ms.map;
> > struct dso *dso = map__dso(map);
> > @@ -499,7 +711,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
> >
> > out:
> > if (needs_cs_close)
> > - cs_close(&handle);
> > + perf_cs_close(&handle);
> > free(buf);
> > return count < 0 ? count : 0;
> >
> > @@ -508,7 +720,4 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
> > close(fd);
> > count = -1;
> > goto out;
> > -#else
> > - return -1;
> > -#endif
> > }
> > --
> > 2.49.0.805.g082f7c87e0-goog
> >
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-06-27 4:53 ` Ian Rogers
@ 2025-06-27 16:44 ` Ian Rogers
2025-06-27 19:26 ` Namhyung Kim
0 siblings, 1 reply; 28+ messages in thread
From: Ian Rogers @ 2025-06-27 16:44 UTC (permalink / raw)
To: Namhyung Kim
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Nathan Chancellor, Nick Desaulniers, Bill Wendling,
Justin Stitt, Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins,
Changbin Du, Masami Hiramatsu (Google), James Clark, Kajol Jain,
Athira Rajeev, Li Huafei, Dmitry Vyukov, Andi Kleen,
Chaitanya S Prakash, linux-kernel, linux-perf-users, llvm,
Song Liu, bpf
On Thu, Jun 26, 2025 at 9:53 PM Ian Rogers <irogers@google.com> wrote:
>
> On Thu, Jun 26, 2025 at 4:19 PM Namhyung Kim <namhyung@kernel.org> wrote:
> >
> > On Thu, Apr 17, 2025 at 04:07:27PM -0700, Ian Rogers wrote:
> > > 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.
> >
> > I still think it's simpler to require capstone headers at build time and
> > add LIBCAPSTONE_DYNAMIC=1 or something to support dlopen.
>
> I agree, having a header file avoids the need to declare the header
> file values. This is simpler. Can we make the build require
> libcapstone and libLLVM in the same way that libtraceevent is
> required? That is you have to explicitly build with NO_LIBTRACEEVENT=1
> to get a no libtraceevent build to succeed. If we don't do this then
> having LIBCAPSTONE_DYNAMIC will most likely be an unused option and
> not worth carrying in the code base, I think that's sad. If we require
> the libraries I don't like the idea of people arguing, "why do I need
> to install libcapstone and libLLVM just to get the kernel/perf to
> build now?" The non-simple, but still not very complex, approach taken
> here was taken as a compromise to get the best result (a perf that
> gets faster, BPF support, .. when libraries are available without
> explicitly depending on them) while trying not to offend kernel
> developers who are often trying to build on minimal systems.
Fwiw, a situation that I think is analogous (and was playing on my
mind while writing the code) is that we don't require python to build
perf and carry around empty-pmu-events.c:
https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/pmu-events/empty-pmu-events.c?h=perf-tools-next
It would be simpler (in the code base and in general) to require
everyone building perf to have python.
Having python on a system seems less of a stretch than requiring
libcapstone and libLLVM.
If we keep the existing build approach, optional capstone and libLLVM
by detecting it as a feature, then just linking against the libraries
is natural. Someone would need to know they care about optionality and
enable LIBCAPSTONE_DYNAMIC=1. An average build where the libraries
weren't present would lose the libcapstone and libLLVM support. We
could warn about this situation but some people are upset about build
warnings, and if we do warn we could be pushing people into just
linking against libcapstone and libLLVM which seems like we'll fall
foul of the, "perf has too many library dependencies," complaint. We
could warn about linking against libraries when there is a _DYNAMIC
alternative like this available, but again people don't like build
warnings and they could legitimately want to link against libcapstone
or libLLVM.
Anyway, that's why I ended up with the code in this state, to best try
to play off all the different compromises and complaints that have
been dealt with in the past.
Thanks,
Ian
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-06-27 16:44 ` Ian Rogers
@ 2025-06-27 19:26 ` Namhyung Kim
2025-06-27 23:11 ` Ian Rogers
0 siblings, 1 reply; 28+ messages in thread
From: Namhyung Kim @ 2025-06-27 19:26 UTC (permalink / raw)
To: Ian Rogers
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Nathan Chancellor, Nick Desaulniers, Bill Wendling,
Justin Stitt, Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins,
Changbin Du, Masami Hiramatsu (Google), James Clark, Kajol Jain,
Athira Rajeev, Li Huafei, Dmitry Vyukov, Andi Kleen,
Chaitanya S Prakash, linux-kernel, linux-perf-users, llvm,
Song Liu, bpf
On Fri, Jun 27, 2025 at 09:44:02AM -0700, Ian Rogers wrote:
> On Thu, Jun 26, 2025 at 9:53 PM Ian Rogers <irogers@google.com> wrote:
> >
> > On Thu, Jun 26, 2025 at 4:19 PM Namhyung Kim <namhyung@kernel.org> wrote:
> > >
> > > On Thu, Apr 17, 2025 at 04:07:27PM -0700, Ian Rogers wrote:
> > > > 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.
> > >
> > > I still think it's simpler to require capstone headers at build time and
> > > add LIBCAPSTONE_DYNAMIC=1 or something to support dlopen.
> >
> > I agree, having a header file avoids the need to declare the header
> > file values. This is simpler. Can we make the build require
> > libcapstone and libLLVM in the same way that libtraceevent is
> > required? That is you have to explicitly build with NO_LIBTRACEEVENT=1
> > to get a no libtraceevent build to succeed. If we don't do this then
> > having LIBCAPSTONE_DYNAMIC will most likely be an unused option and
> > not worth carrying in the code base, I think that's sad. If we require
> > the libraries I don't like the idea of people arguing, "why do I need
> > to install libcapstone and libLLVM just to get the kernel/perf to
> > build now?" The non-simple, but still not very complex, approach taken
> > here was taken as a compromise to get the best result (a perf that
> > gets faster, BPF support, .. when libraries are available without
> > explicitly depending on them) while trying not to offend kernel
> > developers who are often trying to build on minimal systems.
>
> Fwiw, a situation that I think is analogous (and was playing on my
> mind while writing the code) is that we don't require python to build
> perf and carry around empty-pmu-events.c:
> https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/pmu-events/empty-pmu-events.c?h=perf-tools-next
> It would be simpler (in the code base and in general) to require
> everyone building perf to have python.
> Having python on a system seems less of a stretch than requiring
> libcapstone and libLLVM.
>
> If we keep the existing build approach, optional capstone and libLLVM
> by detecting it as a feature, then just linking against the libraries
> is natural. Someone would need to know they care about optionality and
> enable LIBCAPSTONE_DYNAMIC=1. An average build where the libraries
> weren't present would lose the libcapstone and libLLVM support. We
> could warn about this situation but some people are upset about build
> warnings, and if we do warn we could be pushing people into just
> linking against libcapstone and libLLVM which seems like we'll fall
> foul of the, "perf has too many library dependencies," complaint. We
> could warn about linking against libraries when there is a _DYNAMIC
> alternative like this available, but again people don't like build
> warnings and they could legitimately want to link against libcapstone
> or libLLVM.
>
> Anyway, that's why I ended up with the code in this state, to best try
> to play off all the different compromises and complaints that have
> been dealt with in the past.
I can see your point. Adding new build flags is likely to be unused and
forgotten.
But I also think is that this dlopen support is mostly useful to distro
package managers who want to support more flexible environment and
regular dynamic linking is preferred to local builds over dlopen. Then
adding a note to a pull request and contacting them directly (if needed)
might work?
Thanks,
Namhyung
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so
2025-06-27 19:26 ` Namhyung Kim
@ 2025-06-27 23:11 ` Ian Rogers
0 siblings, 0 replies; 28+ messages in thread
From: Ian Rogers @ 2025-06-27 23:11 UTC (permalink / raw)
To: Namhyung Kim
Cc: Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo,
Mark Rutland, Alexander Shishkin, Jiri Olsa, Adrian Hunter,
Kan Liang, Nathan Chancellor, Nick Desaulniers, Bill Wendling,
Justin Stitt, Aditya Gupta, Steinar H. Gunderson, Charlie Jenkins,
Changbin Du, Masami Hiramatsu (Google), James Clark, Kajol Jain,
Athira Rajeev, Li Huafei, Dmitry Vyukov, Andi Kleen,
Chaitanya S Prakash, linux-kernel, linux-perf-users, llvm,
Song Liu, bpf
On Fri, Jun 27, 2025 at 12:26 PM Namhyung Kim <namhyung@kernel.org> wrote:
>
> On Fri, Jun 27, 2025 at 09:44:02AM -0700, Ian Rogers wrote:
> > On Thu, Jun 26, 2025 at 9:53 PM Ian Rogers <irogers@google.com> wrote:
> > >
> > > On Thu, Jun 26, 2025 at 4:19 PM Namhyung Kim <namhyung@kernel.org> wrote:
> > > >
> > > > On Thu, Apr 17, 2025 at 04:07:27PM -0700, Ian Rogers wrote:
> > > > > 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.
> > > >
> > > > I still think it's simpler to require capstone headers at build time and
> > > > add LIBCAPSTONE_DYNAMIC=1 or something to support dlopen.
> > >
> > > I agree, having a header file avoids the need to declare the header
> > > file values. This is simpler. Can we make the build require
> > > libcapstone and libLLVM in the same way that libtraceevent is
> > > required? That is you have to explicitly build with NO_LIBTRACEEVENT=1
> > > to get a no libtraceevent build to succeed. If we don't do this then
> > > having LIBCAPSTONE_DYNAMIC will most likely be an unused option and
> > > not worth carrying in the code base, I think that's sad. If we require
> > > the libraries I don't like the idea of people arguing, "why do I need
> > > to install libcapstone and libLLVM just to get the kernel/perf to
> > > build now?" The non-simple, but still not very complex, approach taken
> > > here was taken as a compromise to get the best result (a perf that
> > > gets faster, BPF support, .. when libraries are available without
> > > explicitly depending on them) while trying not to offend kernel
> > > developers who are often trying to build on minimal systems.
> >
> > Fwiw, a situation that I think is analogous (and was playing on my
> > mind while writing the code) is that we don't require python to build
> > perf and carry around empty-pmu-events.c:
> > https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/pmu-events/empty-pmu-events.c?h=perf-tools-next
> > It would be simpler (in the code base and in general) to require
> > everyone building perf to have python.
> > Having python on a system seems less of a stretch than requiring
> > libcapstone and libLLVM.
> >
> > If we keep the existing build approach, optional capstone and libLLVM
> > by detecting it as a feature, then just linking against the libraries
> > is natural. Someone would need to know they care about optionality and
> > enable LIBCAPSTONE_DYNAMIC=1. An average build where the libraries
> > weren't present would lose the libcapstone and libLLVM support. We
> > could warn about this situation but some people are upset about build
> > warnings, and if we do warn we could be pushing people into just
> > linking against libcapstone and libLLVM which seems like we'll fall
> > foul of the, "perf has too many library dependencies," complaint. We
> > could warn about linking against libraries when there is a _DYNAMIC
> > alternative like this available, but again people don't like build
> > warnings and they could legitimately want to link against libcapstone
> > or libLLVM.
> >
> > Anyway, that's why I ended up with the code in this state, to best try
> > to play off all the different compromises and complaints that have
> > been dealt with in the past.
>
> I can see your point. Adding new build flags is likely to be unused and
> forgotten.
There's also more code to support the neither linked or nor dlopened approach.
> But I also think is that this dlopen support is mostly useful to distro
> package managers who want to support more flexible environment and
> regular dynamic linking is preferred to local builds over dlopen. Then
> adding a note to a pull request and contacting them directly (if needed)
> might work?
If you want to run with this then I don't mind.
Thanks,
Ian
> Thanks,
> Namhyung
>
^ permalink raw reply [flat|nested] 28+ messages in thread
end of thread, other threads:[~2025-06-27 23:11 UTC | newest]
Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-17 23:07 [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Ian Rogers
2025-04-17 23:07 ` [PATCH v4 01/19] perf build: Remove libtracefs configuration Ian Rogers
2025-04-17 23:07 ` [PATCH v4 02/19] perf map: Constify objdump offset/address conversion APIs Ian Rogers
2025-04-17 23:07 ` [PATCH v4 03/19] perf capstone: Move capstone functionality into its own file Ian Rogers
2025-04-17 23:07 ` [PATCH v4 04/19] perf llvm: Move llvm " Ian Rogers
2025-04-17 23:07 ` [PATCH v4 05/19] perf capstone: Remove open_capstone_handle Ian Rogers
2025-04-17 23:07 ` [PATCH v4 06/19] perf capstone: Support for dlopen-ing libcapstone.so Ian Rogers
2025-06-26 23:19 ` Namhyung Kim
2025-06-27 4:53 ` Ian Rogers
2025-06-27 16:44 ` Ian Rogers
2025-06-27 19:26 ` Namhyung Kim
2025-06-27 23:11 ` Ian Rogers
2025-04-17 23:07 ` [PATCH v4 07/19] perf llvm: Support for dlopen-ing libLLVM.so Ian Rogers
2025-04-17 23:07 ` [PATCH v4 08/19] perf llvm: Mangle libperf-llvm.so function names Ian Rogers
2025-04-17 23:07 ` [PATCH v4 09/19] perf dso: Move read_symbol from llvm/capstone to dso Ian Rogers
2025-04-17 23:07 ` [PATCH v4 10/19] perf dso: Support BPF programs in dso__read_symbol Ian Rogers
2025-04-17 23:07 ` [PATCH v4 11/19] perf llvm: Disassemble cleanup Ian Rogers
2025-04-17 23:07 ` [PATCH v4 12/19] perf dso: Clean up read_symbol error handling Ian Rogers
2025-04-17 23:07 ` [PATCH v4 13/19] perf build: Remove libbfd support Ian Rogers
2025-04-17 23:07 ` [PATCH v4 14/19] perf build: Remove libiberty support Ian Rogers
2025-04-17 23:07 ` [PATCH v4 15/19] perf build: Remove unused defines Ian Rogers
2025-04-17 23:07 ` [PATCH v4 16/19] perf disasm: Remove disasm_bpf Ian Rogers
2025-04-17 23:07 ` [PATCH v4 17/19] perf disasm: Make ins__scnprintf and ins__is_nop static Ian Rogers
2025-04-17 23:07 ` [PATCH v4 18/19] perf srcline: Fallback between addr2line implementations Ian Rogers
2025-04-17 23:07 ` [PATCH v4 19/19] perf disasm: Remove unused evsel from annotate_args Ian Rogers
2025-04-18 21:29 ` [PATCH v4 00/19] Support dynamic opening of capstone/llvm remove BUILD_NONDISTRO Arnaldo Carvalho de Melo
2025-04-19 4:22 ` Ian Rogers
[not found] ` <CA+JHD93NCu5VeP9b+DzMm0f0YHwJLRFJeHNtWogx6wKFrHi8Yw@mail.gmail.com>
2025-05-27 20:45 ` Ian Rogers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).