mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 14:41:22 -05:00
perf dso: Move read_symbol() from llvm/capstone to dso
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>
This commit is contained in:
committed by
Arnaldo Carvalho de Melo
parent
0e52f3f9f1
commit
9518e10c2b
@@ -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 = ¬es->src->source;
|
||||
|
||||
/* Discard all lines and fallback to objdump */
|
||||
@@ -359,7 +315,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
|
||||
if (free_count > 0)
|
||||
cs_free(insn, free_count);
|
||||
}
|
||||
free(buf);
|
||||
free(code_buf);
|
||||
return count < 0 ? count : 0;
|
||||
|
||||
err:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 @@ 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;
|
||||
@@ -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, ¬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 = 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
|
||||
|
||||
Reference in New Issue
Block a user