+2018-01-22 Mark Wielaard <mark@klomp.org>
+
+ * Makefile.am (AM_CPPFLAGS): Add -I libdwelf.
+ * dwarf_begin_elf.c (dwarf_begin_elf): Initialize Dwarf alt_fd to -1.
+ * dwarf_end.c (dwarf_end): Call dwarf_end and close on the alt_dwarf
+ and alt_fd if we allocated them.
+ * dwarf_fromref_die.c (dwarf_formref_die): Call dwarf_getalt.
+ * dwarf_formstring.c (dwarf_formstring): Likewise.
+ * dwarf_getalt.c (__libdw_filepath): New internal function.
+ (find_debug_altlink): New static function.
+ (dwarf_getalt): Check Dwarf alt_dwarf and call find_debug_altlink.
+ Cache result.
+ * dwarf_setalt.c (dwarf_setalt): Clean up Dwarf alt_dwarf and alt_fd
+ if we allocated.
+ * libdw.h (dwarf_getalt): Extend documentation.
+ (dwarf_setalt): Likewise.
+ * libdwP.h (struct Dwarf): Add alt_fd field.
+ (filepath): Declare new internal function.
+
2018-01-14 Petr Machata <pmachata@gmail.com>
* dwarf_formsdata.c (dwarf_formsdata):
## Process this file with automake to create Makefile.in
##
-## Copyright (C) 2002-2010, 2012, 2014, 2016 Red Hat, Inc.
+## Copyright (C) 2002-2010, 2012, 2014, 2016, 2018 Red Hat, Inc.
## This file is part of elfutils.
##
## This file is free software; you can redistribute it and/or modify
if BUILD_STATIC
AM_CFLAGS += $(fpic_CFLAGS)
endif
-AM_CPPFLAGS += -I$(srcdir)/../libelf
+AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf
VERSION = 1
lib_LIBRARIES = libdw.a
/* Create descriptor from ELF descriptor for processing file.
- Copyright (C) 2002-2011, 2014, 2015 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2014, 2015, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
result->other_byte_order = true;
result->elf = elf;
+ result->alt_fd = -1;
/* Initialize the memory handling. */
result->mem_default_size = mem_default_size;
/* Release debugging handling context.
- Copyright (C) 2002-2011, 2014 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
#include <stdlib.h>
#include <assert.h>
#include <string.h>
+#include <unistd.h>
#include "libdwP.h"
#include "cfi.h"
free (dwarf->fake_loc_cu);
}
+ /* Did we find and allocate the alt Dwarf ourselves? */
+ if (dwarf->alt_fd != -1)
+ {
+ INTUSE(dwarf_end) (dwarf->alt_dwarf);
+ close (dwarf->alt_fd);
+ }
+
/* Free the context descriptor. */
free (dwarf);
}
/* Look up the DIE in a reference-form attribute.
- Copyright (C) 2005-2010 Red Hat, Inc.
+ Copyright (C) 2005-2010, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
: cu->offset_size);
Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt
- ? cu->dbg->alt_dwarf : cu->dbg);
+ ? INTUSE(dwarf_getalt) (cu->dbg) : cu->dbg);
if (dbg_ret == NULL)
{
/* Return string associated with given attribute.
- Copyright (C) 2003-2010, 2013 Red Hat, Inc.
+ Copyright (C) 2003-2010, 2013, 2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
return (const char *) attrp->valp;
Dwarf *dbg = attrp->cu->dbg;
- Dwarf *dbg_ret = attrp->form == DW_FORM_GNU_strp_alt ? dbg->alt_dwarf : dbg;
+ Dwarf *dbg_ret = (attrp->form == DW_FORM_GNU_strp_alt
+ ? INTUSE(dwarf_getalt) (dbg) : dbg);
if (unlikely (dbg_ret == NULL))
{
/* Retrieves the DWARF descriptor for debugaltlink data.
- Copyright (C) 2014 Red Hat, Inc.
+ Copyright (C) 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
#endif
#include "libdwP.h"
+#include "libelfP.h"
+#include "libdwelfP.h"
+#include "system.h"
+
+#include <inttypes.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+char *
+internal_function
+__libdw_filepath (int fd, const char *dir, const char *file)
+{
+ if (file == NULL)
+ return NULL;
+
+ if (file[0] == '/')
+ return strdup (file);
+
+ if (dir != NULL && dir[0] == '/')
+ {
+ size_t dirlen = strlen (dir);
+ size_t filelen = strlen (file);
+ size_t len = dirlen + 1 + filelen + 1;
+ char *path = malloc (len);
+ if (path != NULL)
+ {
+ char *c = mempcpy (path, dir, dirlen);
+ if (dir[dirlen - 1] != '/')
+ *c++ = '/';
+ mempcpy (c, file, filelen + 1);
+ }
+ return path;
+ }
+
+ if (fd >= 0)
+ {
+ /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25. */
+ char devfdpath[25];
+ sprintf (devfdpath, "/proc/self/fd/%u", fd);
+ char *fdpath = realpath (devfdpath, NULL);
+ char *path = NULL;
+ char *fddir;
+ if (fdpath != NULL && fdpath[0] == '/'
+ && (fddir = strrchr (fdpath, '/')) != NULL)
+ {
+ *++fddir = '\0';
+ size_t fdpathlen = strlen (fdpath);
+ size_t dirlen = dir != NULL ? strlen (dir) : 0;
+ size_t filelen = strlen (file);
+ size_t len = fdpathlen + 1 + dirlen + 1 + filelen + 1;
+ path = malloc (len);
+ if (path != NULL)
+ {
+ char *c = mempcpy (path, fdpath, fdpathlen);
+ if (dirlen > 0)
+ {
+ c = mempcpy (c, dir, dirlen);
+ if (dir[dirlen - 1] != '/')
+ *c++ = '/';
+ }
+ mempcpy (c, file, filelen + 1);
+ }
+ }
+ free (fdpath);
+ return path;
+ }
+
+ return NULL;
+}
+
+static void
+find_debug_altlink (Dwarf *dbg)
+{
+ const char *altname;
+ const void *build_id;
+ ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg,
+ &altname,
+ &build_id);
+
+ /* Couldn't even get the debugaltlink. It probably doesn't exist. */
+ if (build_id_len <= 0)
+ return;
+
+ const uint8_t *id = (const uint8_t *) build_id;
+ size_t id_len = build_id_len;
+ int fd = -1;
+
+ /* We only look in the standard path. And relative to the dbg file. */
+#define DEBUGINFO_PATH "/usr/lib/debug"
+
+ /* We don't handle very short or really large build-ids. We need at
+ at least 3 and allow for up to 64 (normally ids are 20 long). */
+#define MIN_BUILD_ID_BYTES 3
+#define MAX_BUILD_ID_BYTES 64
+ if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES)
+ {
+ /* Note sizeof a string literal includes the trailing zero. */
+ char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 2 + 1 + (MAX_BUILD_ID_BYTES - 2) * 2 + sizeof ".debug"];
+ sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/");
+ sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1],
+ "%02" PRIx8 "/", (uint8_t) id[0]);
+ for (size_t i = 1; i < id_len; ++i)
+ sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]);
+ strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1
+ + 3 + (id_len - 1) * 2], ".debug");
+
+ fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY));
+ }
+
+ /* Fall back on (possible relative) alt file path. */
+ if (fd < 0)
+ {
+ char *altpath = __libdw_filepath (dbg->elf->fildes, NULL, altname);
+ if (altpath != NULL)
+ {
+ fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
+ free (altpath);
+ }
+ }
+
+ if (fd >= 0)
+ {
+ Dwarf *alt = dwarf_begin (fd, O_RDONLY);
+ if (alt != NULL)
+ {
+ dbg->alt_dwarf = alt;
+ dbg->alt_fd = fd;
+ }
+ else
+ close (fd);
+ }
+}
Dwarf *
dwarf_getalt (Dwarf *main)
{
- if (main == NULL)
+ /* Only try once. */
+ if (main == NULL || main->alt_dwarf == (void *) -1)
return NULL;
+
+ if (main->alt_dwarf != NULL)
+ return main->alt_dwarf;
+
+ find_debug_altlink (main);
+
+ /* If we found nothing, make sure we don't try again. */
+ if (main->alt_dwarf == NULL)
+ {
+ main->alt_dwarf = (void *) -1;
+ return NULL;
+ }
+
return main->alt_dwarf;
}
INTDEF (dwarf_getalt)
/* Provides the data referenced by the .gnu_debugaltlink section.
- Copyright (C) 2014 Red Hat, Inc.
+ Copyright (C) 2014, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
#include "libdwP.h"
+#include <unistd.h>
+
void
dwarf_setalt (Dwarf *main, Dwarf *alt)
{
+ if (main->alt_fd != -1)
+ {
+ INTUSE(dwarf_end) (main->alt_dwarf);
+ close (main->alt_fd);
+ main->alt_fd = -1;
+ }
+
main->alt_dwarf = alt;
}
INTDEF (dwarf_setalt)
/* Interfaces for libdw.
- Copyright (C) 2002-2010, 2013, 2014, 2016 Red Hat, Inc.
+ Copyright (C) 2002-2010, 2013, 2014, 2016, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
extern Dwarf *dwarf_cu_getdwarf (Dwarf_CU *cu);
/* Retrieves the DWARF descriptor for debugaltlink data. Returns NULL
- if no alternate debug data has been supplied. */
+ if no alternate debug data has been supplied yet. libdw will try
+ to set the alt file on first use of an alt FORM if not yet explicitly
+ provided by dwarf_setalt. */
extern Dwarf *dwarf_getalt (Dwarf *main);
/* Provides the data referenced by the .gnu_debugaltlink section. The
same build ID). It is the responsibility of the caller to ensure
that the data referenced by ALT stays valid while it is used by
MAIN, until dwarf_setalt is called on MAIN with a different
- descriptor, or dwarf_end. */
+ descriptor, or dwarf_end. Must be called before inspecting DIEs
+ that might have alt FORMs. Otherwise libdw will try to set the
+ alt file itself on first use. */
extern void dwarf_setalt (Dwarf *main, Dwarf *alt);
/* Release debugging handling context. */
/* Internal definitions for libdwarf.
- Copyright (C) 2002-2011, 2013-2017 Red Hat, Inc.
+ Copyright (C) 2002-2011, 2013-2018 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
/* If true, we allocated the ELF descriptor ourselves. */
bool free_elf;
+ /* If >= 0, we allocated the alt_dwarf ourselves and must end it and
+ close this file descriptor. */
+ int alt_fd;
+
/* Information for traversing the .debug_pubnames section. This is
an array and separately allocated with malloc. */
struct pubnames_s
/* Load and return value of DW_AT_comp_dir from CUDIE. */
const char *__libdw_getcompdir (Dwarf_Die *cudie);
+/* Given a file descriptor, dir and file returns a full path. If the
+ file is absolute (starts with a /) a copy of file is returned. If
+ the file isn't absolute, but dir is absolute, then a path that is
+ the concatenation of dir and file is returned. If neither file,
+ nor dir is absolute, the path will be constructed using dir (if not
+ NULL) and file relative to the path of the given file descriptor
+ (if valid).
+
+ The file descriptor may be -1 and the dir may be NULL (in which
+ case they aren't used). If file is NULL, or no full path can be
+ constructed NULL is returned.
+
+ The caller is responsible for freeing the result if not NULL. */
+char * filepath (int fd, const char *dir, const char *file)
+ internal_function;
+
/* Aliases to avoid PLTs. */
INTDECL (dwarf_aggregate_size)
+2018-01-22 Mark Wielaard <mark@klomp.org>
+
+ * allfcts.c (setup_alt): Print warning when alt file couldn't be
+ found.
+ * run-allfcts-multi.sh: Add testcase where alt file is in a subdir
+ where it cannot be found by allfcts itself (but it can by libdw).
+
2018-01-25 Mark Wielaard <mark@klomp.org>
* elfstrmerge.c (main): Initialize and check symtabshdr instead of
errx (1, "dwelf_dwarf_gnu_debugaltlink: %s", dwarf_errmsg (-1));
int fd = open (alt_name, O_RDONLY);
if (fd < 0)
- err (1, "open (%s)", alt_name);
+ {
+ printf ("Warning: no alt file found.\n");
+ return NULL;
+ }
Dwarf *dbg_alt = dwarf_begin (fd, DWARF_C_READ);
if (dbg_alt == NULL)
errx (1, "dwarf_begin (%s): %s", alt_name, dwarf_errmsg (-1));
/tmp/test-offset-loop.c:7:main
EOF
+# allfcts has a too simple mechanism for setting the alt file.
+# check that if we don't set it, things still work (because libdw will
+# find the alt file for us).
+mkdir subdir
+mv test-offset-loop test-offset-loop.alt subdir/
+testrun ${abs_builddir}/allfcts subdir/test-offset-loop > allfcts.out
+testrun_compare cat allfcts.out <<\EOF
+Warning: no alt file found.
+/tmp/test-offset-loop.c:6:get_errno
+/tmp/test-offset-loop.c:5:is_error
+/tmp/test-offset-loop.c:4:padding
+/tmp/test-offset-loop.c:7:main
+EOF
+
+rm -rf subdir
+
exit 0