[PATCH v2 1/3] libdwfl: specify optional sysroot to search for shared libraries and binaries
Michal Sekletar
msekleta@redhat.com
Tue Jul 2 17:30:58 GMT 2024
From: Luke Diamand <ldiamand@roku.com>
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 and binaries.
Signed-off-by: Luke Diamand <ldiamand@roku.com>
Signed-off-by: Michal Sekletar <msekleta@redhat.com>
---
libdw/libdw.map | 5 ++
libdwfl/Makefile.am | 1 +
libdwfl/core-file.c | 2 +-
libdwfl/dwfl_end.c | 1 +
libdwfl/dwfl_segment_report_module.c | 20 ++++++-
libdwfl/dwfl_set_sysroot.c | 80 ++++++++++++++++++++++++++++
libdwfl/libdwfl.h | 6 +++
libdwfl/libdwflP.h | 3 +-
libdwfl/link_map.c | 16 +++++-
9 files changed, 130 insertions(+), 4 deletions(-)
create mode 100644 libdwfl/dwfl_set_sysroot.c
diff --git a/libdw/libdw.map b/libdw/libdw.map
index 3c5ce8dc..552588a9 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -378,3 +378,8 @@ ELFUTILS_0.191 {
global:
dwarf_cu_dwp_section_info;
} ELFUTILS_0.188;
+
+ELFUTILS_0.192 {
+ global:
+ dwfl_set_sysroot;
+} ELFUTILS_0.191;
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 6b26cd51..57c89604 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -67,6 +67,7 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
dwfl_module_return_value_location.c \
dwfl_module_register_names.c \
dwfl_segment_report_module.c \
+ dwfl_set_sysroot.c \
link_map.c core-file.c open.c image-header.c \
dwfl_frame.c frame_unwind.c dwfl_frame_pc.c \
linux-pid-attach.c linux-core-attach.c dwfl_frame_regs.c \
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index 89527d23..3135f884 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -559,7 +559,7 @@ dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
ndx = 0;
do
{
- int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
+ int seg = dwfl_segment_report_module (dwfl, ndx, NULL, executable,
&dwfl_elf_phdr_memory_callback, elf,
core_file_read_eagerly, elf,
elf->maximum_size,
diff --git a/libdwfl/dwfl_end.c b/libdwfl/dwfl_end.c
index a1812407..7b5ac8a1 100644
--- a/libdwfl/dwfl_end.c
+++ b/libdwfl/dwfl_end.c
@@ -48,6 +48,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/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index dc34e0ae..2b050d64 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -288,6 +288,7 @@ read_portion (struct read_state *read_state,
int
dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
+ const char *executable,
Dwfl_Memory_Callback *memory_callback,
void *memory_callback_arg,
Dwfl_Module_Callback *read_eagerly,
@@ -778,7 +779,24 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
name = file_note_name;
name_is_final = true;
bool invalid = false;
- fd = open (name, O_RDONLY);
+
+ /* We were not handed specific executable hence try to look for it in sysroot if
+ it is set. */
+ if (dwfl->sysroot && !executable)
+ {
+ int r;
+ char *n;
+
+ r = asprintf (&n, "%s%s", dwfl->sysroot, name);
+ if (r > 0)
+ {
+ fd = open (n, O_RDONLY);
+ free (n);
+ }
+ }
+ else
+ fd = open (name, O_RDONLY);
+
if (fd >= 0)
{
Dwfl_Error error = __libdw_open_file (&fd, &elf, true, false);
diff --git a/libdwfl/dwfl_set_sysroot.c b/libdwfl/dwfl_set_sysroot.c
new file mode 100644
index 00000000..344d4ae5
--- /dev/null
+++ b/libdwfl/dwfl_set_sysroot.c
@@ -0,0 +1,80 @@
+/* Return one of the sources lines of a CU.
+ Copyright (C) 2024 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include "libdwflP.h"
+#include "libdwP.h"
+
+int
+dwfl_set_sysroot (Dwfl *dwfl, const char *sysroot)
+{
+ if (!sysroot)
+ {
+ free (dwfl->sysroot);
+ dwfl->sysroot = NULL;
+ return 0;
+ }
+
+ char *r, *s;
+ r = realpath (sysroot, NULL);
+ if (!r)
+ return -1;
+
+ int rc;
+ struct stat sb;
+
+ rc = stat (r, &sb);
+ if (rc < 0 || !S_ISDIR (sb.st_mode))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ rc = asprintf (&s, "%s/", r);
+ if (rc < 0)
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ free (dwfl->sysroot);
+ free (r);
+
+ dwfl->sysroot = s;
+ return 0;
+}
+
+INTDEF (dwfl_set_sysroot)
\ No newline at end of file
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 49ad6664..4cbeab55 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -818,6 +818,12 @@ int dwfl_frame_reg (Dwfl_Frame *state, unsigned regno, Dwarf_Word *val)
*/
extern debuginfod_client *dwfl_get_debuginfod_client (Dwfl *dwfl);
+/* Set the sysroot to use when searching for shared libraries and binaries. If not
+ specified, search the system root. Passing NULL clears previously set sysroot. Note
+ that library creates a copy of the sysroot argument. */
+int 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 b3dfea1d..2dc53b81 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -134,6 +134,7 @@ struct Dwfl
int next_segndx;
struct Dwfl_User_Core *user_core;
+ char *sysroot; /* sysroot, or NULL to search standard system paths */
};
#define OFFLINE_REDZONE 0x10000
@@ -697,7 +698,7 @@ struct r_debug_info
/* ...
*/
-extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
+extern int dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, const char *executable,
Dwfl_Memory_Callback *memory_callback,
void *memory_callback_arg,
Dwfl_Module_Callback *read_eagerly,
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index a6c66c78..8ab14862 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -416,7 +416,20 @@ 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
+ char *sysroot_name = NULL;
+ const char *sysroot = dwfl->sysroot;
+
+ /* Don't use the sysroot if the path is already inside it. */
+ bool name_in_sysroot = sysroot && startswith (name, sysroot);
+
+ if (sysroot && !name_in_sysroot)
+ {
+ if (asprintf (&sysroot_name, "%s%s", sysroot, name) < 0)
+ return release_buffer (&memory_closure, &buffer, &buffer_available, -1);
+
+ name = sysroot_name;
+ }
+
int fd = open (name, O_RDONLY);
if (fd >= 0)
{
@@ -502,6 +515,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata,
close (fd);
}
}
+ free(sysroot_name);
}
if (mod != NULL)
--
2.39.3 (Apple Git-146)
More information about the Elfutils-devel
mailing list