]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwfl: specify optional sysroot to search for shared libraries and binaries
authorLuke Diamand <ldiamand@roku.com>
Tue, 2 Jul 2024 17:30:58 +0000 (19:30 +0200)
committerAaron Merey <amerey@redhat.com>
Thu, 4 Jul 2024 22:41:19 +0000 (18:41 -0400)
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
libdwfl/Makefile.am
libdwfl/core-file.c
libdwfl/dwfl_end.c
libdwfl/dwfl_segment_report_module.c
libdwfl/dwfl_set_sysroot.c [new file with mode: 0644]
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libdwfl/link_map.c

index 3c5ce8dc7c956fb7f3f956f920063d0b6a3609a8..552588a94c0c1a1f2fd5b973553c784026e6de14 100644 (file)
@@ -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;
index 6b26cd515af28d3a72e19e51fad47a459dcd5484..57c89604cd07fd9cfbbfca7a02c6ea132aa80290 100644 (file)
@@ -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 \
index 89527d233e17326c8ca32fff3dfa9d0af3ca336f..3135f884256e01d1cc5d90b4e20a1c58c39e106b 100644 (file)
@@ -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,
index a18124077751452565a9e0b3e8c080479e64c2b4..7b5ac8a1fdeb4b4acc8892b5d5340377440f62bd 100644 (file)
@@ -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)
index dc34e0aefdf9bdd89eb5a1f889d5057430e960b0..32f44af85c89429fd566d8af87204e2dfdc0c83d 100644 (file)
@@ -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 (file)
index 0000000..ffb0e79
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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 <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)
index 49ad6664899ea884348213520d40217159c867a5..4cbeab5597261236858750bdb9fd7b0817e22e95 100644 (file)
@@ -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
index b3dfea1d1b9aa4114c5ad58b01be261572221013..d27bfdc2dd6ac592446d00af09cf50b352c8436f 100644 (file)
@@ -134,6 +134,8 @@ 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
@@ -698,6 +700,7 @@ struct r_debug_info
 /* ...
  */
 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,
index a6c66c789643372d31076db30dc251923e6b1128..8ab14862ca2488fe2b5ba25b3fe6b6b583d93f80 100644 (file)
@@ -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)