When searching the list of modules in a core file, if the core was generated on a different system to the current one, we need to look in a sysroot for the various shared objects.
For example, we might be looking at a core file from an ARM system using elfutils running on an x86 host. This change adds a new function, dwfl_set_sysroot(), which then gets used when searching for libraries. Signed-off-by: Luke Diamand <ldiam...@roku.com> --- libdw/libdw.map | 7 ++++++- libdwfl/dwfl_end.c | 1 + libdwfl/libdwfl.h | 5 +++++ libdwfl/libdwflP.h | 1 + libdwfl/link_map.c | 26 ++++++++++++++++++++++++-- 5 files changed, 37 insertions(+), 3 deletions(-) diff --git a/libdw/libdw.map b/libdw/libdw.map index 55482d58..43a9de2e 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -360,4 +360,9 @@ ELFUTILS_0.173 { ELFUTILS_0.175 { global: dwelf_elf_begin; -} ELFUTILS_0.173; \ No newline at end of file +} ELFUTILS_0.173; + +ELFUTILS_0.176 { + global: + dwfl_set_sysroot; +} ELFUTILS_0.175; diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c index 74ee9e07..345d9947 100644 --- a/libdwfl/dwfl_end.c +++ b/libdwfl/dwfl_end.c @@ -45,6 +45,7 @@ dwfl_end (Dwfl *dwfl) free (dwfl->lookup_addr); free (dwfl->lookup_module); free (dwfl->lookup_segndx); + free (dwfl->sysroot); Dwfl_Module *next = dwfl->modulelist; while (next != NULL) diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index a0c1d357..c11e2f24 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -807,6 +807,11 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) __nonnull_attribute__ (1, 2); +/* Set the sysroot to use when searching for shared libraries. If not + specified, search in the system root. */ +void dwfl_set_sysroot (Dwfl *dwfl, const char *sysroot) + __nonnull_attribute__ (1); + #ifdef __cplusplus } #endif diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 941a8b66..db16ab57 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -138,6 +138,7 @@ struct Dwfl int lookup_tail_ndx; struct Dwfl_User_Core *user_core; + char *sysroot; /* sysroot, or NULL to search standard system paths */ }; #define OFFLINE_REDZONE 0x10000 diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 29307c74..cf18c0a2 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -34,6 +34,7 @@ #include <byteswap.h> #include <endian.h> #include <fcntl.h> +#include <stdlib.h> /* This element is always provided and always has a constant value. This makes it an easy thing to scan for to discern the format. */ @@ -388,8 +389,21 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, if (name != NULL) { /* This code is mostly inlined dwfl_report_elf. */ - // XXX hook for sysroot - int fd = open (name, O_RDONLY); + char *path_name; + int rc; + const char *sysroot = dwfl->sysroot; + + /* don't look in the sysroot if the path is already inside the sysroot */ + bool name_in_sysroot = sysroot && (strncmp(name, sysroot, strlen(sysroot)) == 0); + + if (!name_in_sysroot && sysroot) + rc = asprintf(&path_name, "%s/%s", sysroot, name); + else + rc = asprintf(&path_name, "%s", name); + if (unlikely(rc == -1)) + return release_buffer(-1); + + int fd = open (path_name, O_RDONLY); if (fd >= 0) { Elf *elf; @@ -471,6 +485,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, close (fd); } } + free(path_name); } if (mod != NULL) @@ -1037,3 +1052,10 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, &integrated_memory_callback, &mcb, r_debug_info); } INTDEF (dwfl_link_map_report) + +void +dwfl_set_sysroot (Dwfl *dwfl, const char *sysroot) +{ + dwfl->sysroot = realpath(sysroot, NULL); +} +INTDEF (dwfl_set_sysroot) -- 2.20.1