From: Luke Diamand <ldiam...@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 <ldiam...@roku.com>
Signed-off-by: Michal Sekletar <msekl...@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)

Reply via email to