]> www.infradead.org Git - users/hch/misc.git/commitdiff
perf dso: Move read_symbol() from llvm/capstone to dso
authorIan Rogers <irogers@google.com>
Sun, 5 Oct 2025 21:22:04 +0000 (14:22 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 6 Oct 2025 19:35:25 +0000 (16:35 -0300)
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>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alexghiti@rivosinc.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Bill Wendling <morbo@google.com>
Cc: Charlie Jenkins <charlie@rivosinc.com>
Cc: Collin Funk <collin.funk1@gmail.com>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Eric Biggers <ebiggers@kernel.org>
Cc: Haibo Xu <haibo1.xu@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Li Huafei <lihuafei1@huawei.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <song@kernel.org>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/capstone.c
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/llvm.c

index 01e47d5c8e3ea9dcab66ab2b520fe2704947276a..c23df911e91c1dc7851470093b1f7f1ad0cb1a68 100644 (file)
@@ -215,55 +215,6 @@ static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg)
 }
 #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)
@@ -271,13 +222,17 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
 #ifdef HAVE_LIBCAPSTONE_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);
-       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;
        cs_insn *insn = NULL;
        char disasm_buf[512];
@@ -287,7 +242,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;
 
@@ -316,7 +272,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 = cs_disasm(handle, buf, buf_len, start, buf_len, &insn);
        for (i = 0, offset = 0; i < count; i++) {
                int printed;
 
@@ -340,7 +296,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 = &notes->src->source;
 
                /* Discard all lines and fallback to objdump */
@@ -359,7 +315,7 @@ out:
                if (free_count > 0)
                        cs_free(insn, free_count);
        }
-       free(buf);
+       free(code_buf);
        return count < 0 ? count : 0;
 
 err:
index 282e3af85d5aaf0ad9cdc3439c4787df0a6d1124..87d075942de685e5f876f1c0de545269d9ac0116 100644 (file)
@@ -1798,3 +1798,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;
+}
index fd8e95de77f78dfcb5afc5858ba0597e0ef89082..f8ccb9816b89c3878f66ca9de698570824518152 100644 (file)
@@ -924,4 +924,8 @@ static inline struct debuginfo *dso__debuginfo(struct dso *dso)
        return debuginfo__new(dso__long_name(dso));
 }
 
+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 */
index b71649d616e3aae9ed19012b0191a0dd691173d7..ec41d0f27000f7ced867da5788cbedde48c6d145 100644 (file)
@@ -87,71 +87,6 @@ static void init_llvm(void)
        }
 }
 
-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
@@ -160,7 +95,6 @@ err:
  * 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;
@@ -191,8 +125,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 disasm_buf[2048];
@@ -207,7 +144,8 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
        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;
 
@@ -259,14 +197,18 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
        annotation_line__add(&dl->al, &notes->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 = 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 = LLVMDisasmInstruction(disasm, (u8 *)(buf + offset),
+                                               buf_len - offset, pc,
                                                disasm_buf, sizeof(disasm_buf));
                if (ins_len == 0)
                        goto err;
@@ -324,7 +266,7 @@ int symbol__disassemble_llvm(const char *filename, struct symbol *sym,
 
 err:
        LLVMDisasmDispose(disasm);
-       free(buf);
+       free(code_buf);
        free(line_storage);
        return ret;
 #else // HAVE_LIBLLVM_SUPPORT