Commit 9518e10c authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarIan 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0e52f3f9
Loading
Loading
Loading
Loading
+11 −55
Original line number Diff line number Diff line
@@ -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 @@ 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:
+67 −0
Original line number Diff line number Diff line
@@ -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;
}
+4 −0
Original line number Diff line number Diff line
@@ -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 */
+15 −73
Original line number Diff line number Diff line
@@ -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, &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