perf symbols: Save DSO loading errno to better report errors
tip-bot for Arnaldo Carvalho de Melo
merge botCommit-ID: 18425f13a0890ac1e88a64276771c1ae10030b4a Gitweb: http://git.kernel.org/tip/18425f13a0890ac1e88a64276771c1ae10030b4a Author: Arnaldo Carvalho de Melo <[email protected]> AuthorDate: Tue, 24 Mar 2015 11:49:02 -0300 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Tue, 24 Mar 2015 12:08:43 -0300
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 <[email protected]>
Acked-by Jiri Olsa <[email protected]>
Cc Adrian Hunter <[email protected]>
Cc Borislav Petkov <[email protected]>
Cc David Ahern <[email protected]>
Cc Don Zickus <[email protected]>
Cc Frederic Weisbecker <[email protected]>
Cc Namhyung Kim <[email protected]>
Cc Stephane Eranian <[email protected]>
Signed-off-by Arnaldo Carvalho de Melo <[email protected]>
--- tools/perf/builtin-top.c | 6 ++++-- tools/perf/util/dso.c | 33 +++++++++++++++++++++++++++++++++ tools/perf/util/dso.h | 28 ++++++++++++++++++++++++++++ tools/perf/util/symbol-elf.c | 37 +++++++++++++++++++++++++++---------- tools/perf/util/symbol-minimal.c | 7 ++++--- 5 files changed, 96 insertions(+), 15 deletions(-)
tools/perf/builtin-top.c +4 -2
@@ -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);
tools/perf/util/dso.c +33 -0
@@ -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 ; +}
tools/perf/util/dso.h +28 -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 */
tools/perf/util/symbol-elf.c +27 -10
@@ -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,37 +638,49 @@ 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 +if (fd <0 ) +return -1 ; + }else { fd =open (name,O_RDONLY ); - -if (fd <0 ) -return -1 ; +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;
tools/perf/util/symbol-minimal.c +4 -3
@@ -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 ; }