We add a new member to Dwfl_Module which remembers all the paths that were attempted when looking for DWARF information. This member is then used with the new __libdw_seterrno_details() if no DWARF information is found with details about every files tried and the reason why they failed.
Possible reasons include the open() call failed (errno is printed), and build ID/CRC validation failed. Signed-off-by: Jonathan Lebon <[email protected]> --- libdwfl/dwfl_build_id_find_elf.c | 21 +++++++ libdwfl/dwfl_module.c | 3 + libdwfl/dwfl_module_getdwarf.c | 10 ++++ libdwfl/find-debuginfo.c | 120 +++++++++++++++++++++++++++++---------- libdwfl/libdwflP.h | 1 + 5 files changed, 124 insertions(+), 31 deletions(-) diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c index 062aad1..338343e 100644 --- a/libdwfl/dwfl_build_id_find_elf.c +++ b/libdwfl/dwfl_build_id_find_elf.c @@ -32,6 +32,23 @@ #include <unistd.h> +static void +append_open_attempt (char **path_list, char *path, int error) +{ + char *new_path_list; + if (*path_list != NULL) + { + if (asprintf (&new_path_list, "%s, %s (errno %d)", + *path_list, path, error) < 0) + return; + free (*path_list); + } + else if (asprintf (&new_path_list, "%s (errno %d)", path, error) < 0) + return; + + *path_list = new_path_list; +} + int internal_function __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, @@ -87,6 +104,10 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, name = NULL; } } + else if (debug) + /* We found nothing, append to the list of failed files. */ + append_open_attempt (&mod->dw_tried_paths, name, errno); + free (name); } diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index 8efcfaa..cb3774f 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -100,6 +100,9 @@ __libdwfl_module_free (Dwfl_Module *mod) if (mod->eh_cfi != NULL) dwarf_cfi_end (mod->eh_cfi); + if (mod->dw_tried_paths != NULL) + free (mod->dw_tried_paths); + free (mod->name); free (mod); } diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index a31898a..c7bc29c 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1316,6 +1316,16 @@ dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias) } __libdwfl_seterrno (mod->dwerr); + + if (mod->dwerr == DWFL_E_NO_DWARF && mod->dw_tried_paths != NULL) + { + /* Provide more details to NO_DWARF error by giving the list of files we + * tried to open. */ + char *details = NULL; + if (asprintf (&details, "tried to open %s", mod->dw_tried_paths) > 0) + __libdwfl_seterrno_details (mod->dwerr, details); + } + return NULL; } INTDEF (dwfl_module_getdwarf) diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c index 3f5314a..80624ff 100644 --- a/libdwfl/find-debuginfo.c +++ b/libdwfl/find-debuginfo.c @@ -33,9 +33,36 @@ #include <sys/stat.h> #include "system.h" +/* Add to the list of attempts a new attempt along with the reason it failed. If + error < 0, then it's a mismatch. Otherwise, it's the errno. */ +static void +append_open_attempt (char **path_list, char *path, int error) +{ + char *reason; + if (error < 0 && asprintf (&reason, "mismatched") < 0) + return; + if (error >= 0 && asprintf (&reason, "errno %d", error) < 0) + return; + + int rc; + char *new_path_list; + if (*path_list != NULL) + rc = asprintf (&new_path_list, "%s, %s (%s)", *path_list, path, reason); + else + rc = asprintf (&new_path_list, "%s (%s)", path, reason); + free (reason); + + if (rc < 0) + return; + + if (*path_list != NULL) + free (*path_list); + *path_list = new_path_list; +} /* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1. - On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */ + *DEBUGINFO_FILE_NAME has the final malloc'd name of the file we are + attempting to open. */ static int try_open (const struct stat64 *main_stat, const char *dir, const char *subdir, const char *debuglink, @@ -55,20 +82,18 @@ try_open (const struct stat64 *main_stat, struct stat64 st; int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY)); - if (fd < 0) - free (fname); - else if (fstat64 (fd, &st) == 0 - && st.st_ino == main_stat->st_ino - && st.st_dev == main_stat->st_dev) + if (fd >= 0 + && fstat64 (fd, &st) == 0 + && st.st_ino == main_stat->st_ino + && st.st_dev == main_stat->st_dev) { /* This is the main file by another name. Don't look at it again. */ close (fd); errno = ENOENT; fd = -1; } - else - *debuginfo_file_name = fname; + *debuginfo_file_name = fname; return fd; } @@ -257,34 +282,61 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name, char *fname = NULL; int fd = try_open (&main_stat, dir, subdir, file, &fname); if (fd < 0) - switch (errno) - { - case ENOENT: - case ENOTDIR: - /* If we are looking for the alt file also try the .dwz subdir. - But only if this is the empty or absolute path. */ - if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/')) - { - fd = try_open (&main_stat, dir, ".dwz", - basename (file), &fname); - if (fd < 0) - { - if (errno != ENOENT && errno != ENOTDIR) - return -1; - else - continue; - } - break; - } - continue; - default: - return -1; - } + { + int error = errno; + + /* Append to the list of failed files. */ + if (fname != NULL) + { + append_open_attempt (&mod->dw_tried_paths, fname, error); + free (fname); + fname = NULL; + } + + switch (error) + { + case ENOENT: + case ENOTDIR: + + /* If we are looking for the alt file also try the .dwz subdir. + But only if this is the empty or absolute path. */ + if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/')) + { + fd = try_open (&main_stat, dir, ".dwz", + basename (file), &fname); + if (fd < 0) + { + error = errno; + + /* Append to the list of failed files. */ + if (fname != NULL) + { + append_open_attempt (&mod->dw_tried_paths, fname, error); + free (fname); + fname = NULL; + } + + if (error != ENOENT && error != ENOTDIR) + return -1; + else + continue; + } + break; + } + continue; + default: + return -1; + } + } if (validate (mod, fd, check, debuglink_crc)) { *debuginfo_file_name = fname; return fd; } + else + // validation failed, they're mismatched files + append_open_attempt (&mod->dw_tried_paths, fname, -1); + free (fname); close (fd); } @@ -304,6 +356,12 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod, GElf_Word debuglink_crc, char **debuginfo_file_name) { + if (mod->dw_tried_paths != NULL) + { + free (mod->dw_tried_paths); + mod->dw_tried_paths = NULL; + } + /* First try by build ID if we have one. If that succeeds or fails other than just by finding nothing, that's all we do. */ const unsigned char *bits; diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 17db534..640f5bb 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -191,6 +191,7 @@ struct Dwfl_Module Dwfl_Error symerr; /* Previous failure to load symbols. */ Dwfl_Error dwerr; /* Previous failure to load DWARF. */ + char *dw_tried_paths; /* Paths that were tried when loading DWARF. */ /* Known CU's in this module. */ struct dwfl_cu *first_cu, **cu; -- 2.1.0
