perf symbols: Save DSO loading errno to better report errors
Before, when some problem happened while trying to load the kernel symtab, 'perf top' would show: ┌─Warning:───────────────────────────┐ │The vmlinux file can't be used. │ │Kernel samples will not be resolved.│ │ │ │ │ │Press any key... │ └────────────────────────────────────┘ Now, it reports: # perf top --vmlinux /dev/null ┌─Warning:───────────────────────────────────────────┐ │The /tmp/passwd file can't be used: Invalid ELF file│ │Kernel samples will not be resolved. │ │ │ │ │ │Press any key... │ └────────────────────────────────────────────────────┘ This is possible because we now register the reason for not being able to load the symtab in the dso->load_errno member, and provide a dso__strerror_load() routine to format this error into a strerror like string with a short reason for the error while loading. That can be just forwarding the dso__strerror_load() call to strerror_r(), or, for a separate errno range providing a custom message. Reported-by: Ingo Molnar <mingo@kernel.org> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Borislav Petkov <bp@suse.de> Cc: David Ahern <dsahern@gmail.com> Cc: Don Zickus <dzickus@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-u5rb5uq63xqhkfb8uv2lxd5u@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
17e44dc46f
commit
18425f13a0
@ -757,8 +757,10 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
||||
al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
|
||||
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
|
||||
if (symbol_conf.vmlinux_name) {
|
||||
ui__warning("The %s file can't be used.\n%s",
|
||||
symbol_conf.vmlinux_name, msg);
|
||||
char serr[256];
|
||||
dso__strerror_load(al.map->dso, serr, sizeof(serr));
|
||||
ui__warning("The %s file can't be used: %s\n%s",
|
||||
symbol_conf.vmlinux_name, serr, msg);
|
||||
} else {
|
||||
ui__warning("A vmlinux file was not found.\n%s",
|
||||
msg);
|
||||
|
@ -1137,3 +1137,36 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine)
|
||||
|
||||
return dso__type_fd(fd);
|
||||
}
|
||||
|
||||
int dso__strerror_load(struct dso *dso, char *buf, size_t buflen)
|
||||
{
|
||||
int idx, errnum = dso->load_errno;
|
||||
/*
|
||||
* This must have a same ordering as the enum dso_load_errno.
|
||||
*/
|
||||
static const char *dso_load__error_str[] = {
|
||||
"Internal tools/perf/ library error",
|
||||
"Invalid ELF file",
|
||||
"Can not read build id",
|
||||
"Mismatching build id",
|
||||
"Decompression failure",
|
||||
};
|
||||
|
||||
BUG_ON(buflen == 0);
|
||||
|
||||
if (errnum >= 0) {
|
||||
const char *err = strerror_r(errnum, buf, buflen);
|
||||
|
||||
if (err != buf)
|
||||
scnprintf(buf, buflen, "%s", err);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errnum < __DSO_LOAD_ERRNO__START || errnum >= __DSO_LOAD_ERRNO__END)
|
||||
return -1;
|
||||
|
||||
idx = errnum - __DSO_LOAD_ERRNO__START;
|
||||
scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -60,6 +60,31 @@ enum dso_type {
|
||||
DSO__TYPE_X32BIT,
|
||||
};
|
||||
|
||||
enum dso_load_errno {
|
||||
DSO_LOAD_ERRNO__SUCCESS = 0,
|
||||
|
||||
/*
|
||||
* Choose an arbitrary negative big number not to clash with standard
|
||||
* errno since SUS requires the errno has distinct positive values.
|
||||
* See 'Issue 6' in the link below.
|
||||
*
|
||||
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
|
||||
*/
|
||||
__DSO_LOAD_ERRNO__START = -10000,
|
||||
|
||||
DSO_LOAD_ERRNO__INTERNAL_ERROR = __DSO_LOAD_ERRNO__START,
|
||||
|
||||
/* for symsrc__init() */
|
||||
DSO_LOAD_ERRNO__INVALID_ELF,
|
||||
DSO_LOAD_ERRNO__CANNOT_READ_BUILDID,
|
||||
DSO_LOAD_ERRNO__MISMATCHING_BUILDID,
|
||||
|
||||
/* for decompress_kmodule */
|
||||
DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE,
|
||||
|
||||
__DSO_LOAD_ERRNO__END,
|
||||
};
|
||||
|
||||
#define DSO__SWAP(dso, type, val) \
|
||||
({ \
|
||||
type ____r = val; \
|
||||
@ -113,6 +138,7 @@ struct dso {
|
||||
enum dso_swap_type needs_swap;
|
||||
enum dso_binary_type symtab_type;
|
||||
enum dso_binary_type binary_type;
|
||||
enum dso_load_errno load_errno;
|
||||
u8 adjust_symbols:1;
|
||||
u8 has_build_id:1;
|
||||
u8 has_srcline:1;
|
||||
@ -294,4 +320,6 @@ void dso__free_a2l(struct dso *dso);
|
||||
|
||||
enum dso_type dso__type(struct dso *dso, struct machine *machine);
|
||||
|
||||
int dso__strerror_load(struct dso *dso, char *buf, size_t buflen);
|
||||
|
||||
#endif /* __PERF_DSO */
|
||||
|
@ -595,10 +595,13 @@ static int decompress_kmodule(struct dso *dso, const char *name,
|
||||
return -1;
|
||||
|
||||
fd = mkstemp(tmpbuf);
|
||||
if (fd < 0)
|
||||
if (fd < 0) {
|
||||
dso->load_errno = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!decompress_to_file(m.ext, name, fd)) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__DECOMPRESSION_FAILURE;
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
@ -635,38 +638,50 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
|
||||
Elf *elf;
|
||||
int fd;
|
||||
|
||||
if (dso__needs_decompress(dso))
|
||||
if (dso__needs_decompress(dso)) {
|
||||
fd = decompress_kmodule(dso, name, type);
|
||||
else
|
||||
fd = open(name, O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
} else {
|
||||
fd = open(name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
dso->load_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
|
||||
if (elf == NULL) {
|
||||
pr_debug("%s: cannot read %s ELF file.\n", __func__, name);
|
||||
dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
if (gelf_getehdr(elf, &ehdr) == NULL) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__INVALID_ELF;
|
||||
pr_debug("%s: cannot get elf header.\n", __func__);
|
||||
goto out_elf_end;
|
||||
}
|
||||
|
||||
if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
|
||||
if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__INTERNAL_ERROR;
|
||||
goto out_elf_end;
|
||||
}
|
||||
|
||||
/* Always reject images with a mismatched build-id: */
|
||||
if (dso->has_build_id) {
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
|
||||
if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0)
|
||||
if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__CANNOT_READ_BUILDID;
|
||||
goto out_elf_end;
|
||||
}
|
||||
|
||||
if (!dso__build_id_equal(dso, build_id))
|
||||
if (!dso__build_id_equal(dso, build_id)) {
|
||||
dso->load_errno = DSO_LOAD_ERRNO__MISMATCHING_BUILDID;
|
||||
goto out_elf_end;
|
||||
}
|
||||
}
|
||||
|
||||
ss->is_64_bit = (gelf_getclass(elf) == ELFCLASS64);
|
||||
|
||||
@ -701,8 +716,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
|
||||
}
|
||||
|
||||
ss->name = strdup(name);
|
||||
if (!ss->name)
|
||||
if (!ss->name) {
|
||||
dso->load_errno = errno;
|
||||
goto out_elf_end;
|
||||
}
|
||||
|
||||
ss->elf = elf;
|
||||
ss->fd = fd;
|
||||
|
@ -246,13 +246,12 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
|
||||
const char *name,
|
||||
int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
|
||||
enum dso_binary_type type)
|
||||
{
|
||||
int fd = open(name, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
goto out_errno;
|
||||
|
||||
ss->name = strdup(name);
|
||||
if (!ss->name)
|
||||
@ -264,6 +263,8 @@ int symsrc__init(struct symsrc *ss, struct dso *dso __maybe_unused,
|
||||
return 0;
|
||||
out_close:
|
||||
close(fd);
|
||||
out_errno:
|
||||
dso->load_errno = errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user