On Wed, Jul 3, 2024 at 4:38 PM Dmitry V. Levin <ldv@strace.io> wrote:
> On Tue, Jul 02, 2024 at 07:30:58PM +0200, Michal Sekletar wrote:
> [...]
> > +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);
>
> There is a case when realpath() returns a path ending with '/':
> when the path is "/". I'm mentioning this just in case, not sure whether
> sysroot == "/" makes any sense at all, and whether this needs a special
attention.
>
I think that should be fine, //sysroot should be equivalent to /sysroot,
IOW, multiple slashes shouldn't cause any issues.
Michal
>
> --
> ldv
>
>
@@ -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;
@@ -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 \
@@ -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,
@@ -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)
@@ -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);
new file mode 100644
@@ -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
@@ -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
@@ -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,
@@ -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)