summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdw/ChangeLog19
-rw-r--r--libdw/Makefile.am4
-rw-r--r--libdw/dwarf_begin_elf.c3
-rw-r--r--libdw/dwarf_end.c10
-rw-r--r--libdw/dwarf_formref_die.c4
-rw-r--r--libdw/dwarf_formstring.c5
-rw-r--r--libdw/dwarf_getalt.c158
-rw-r--r--libdw/dwarf_setalt.c11
-rw-r--r--libdw/libdw.h10
-rw-r--r--libdw/libdwP.h22
-rw-r--r--tests/ChangeLog7
-rw-r--r--tests/allfcts.c5
-rwxr-xr-xtests/run-allfcts-multi.sh16
13 files changed, 258 insertions, 16 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 479dd42b..cb5e61ac 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2018-01-22 Mark Wielaard <[email protected]>
+
+ * 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 <[email protected]>
* dwarf_formsdata.c (dwarf_formsdata):
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 8ee46802..8545b5b4 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -1,6 +1,6 @@
## 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
@@ -31,7 +31,7 @@ include $(top_srcdir)/config/eu.am
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
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 7c3fe103..6834ac53 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -1,5 +1,5 @@
/* 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 <[email protected]>, 2002.
@@ -326,6 +326,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
result->other_byte_order = true;
result->elf = elf;
+ result->alt_fd = -1;
/* Initialize the memory handling. */
result->mem_default_size = mem_default_size;
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 6c6d985a..f6915abf 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -1,5 +1,5 @@
/* 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 <[email protected]>, 2002.
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <assert.h>
#include <string.h>
+#include <unistd.h>
#include "libdwP.h"
#include "cfi.h"
@@ -103,6 +104,13 @@ dwarf_end (Dwarf *dwarf)
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);
}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 7e2b11a2..704816f8 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -1,5 +1,5 @@
/* 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
@@ -53,7 +53,7 @@ dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result)
: 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)
{
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 83abd53d..4eae0ede 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -1,5 +1,5 @@
/* 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 <[email protected]>, 2003.
@@ -48,7 +48,8 @@ dwarf_formstring (Dwarf_Attribute *attrp)
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))
{
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index cc434f03..3e5af151 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -1,5 +1,5 @@
/* 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
@@ -31,12 +31,166 @@
#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)
diff --git a/libdw/dwarf_setalt.c b/libdw/dwarf_setalt.c
index 9bd566ff..9051b8e0 100644
--- a/libdw/dwarf_setalt.c
+++ b/libdw/dwarf_setalt.c
@@ -1,5 +1,5 @@
/* 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
@@ -32,9 +32,18 @@
#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)
diff --git a/libdw/libdw.h b/libdw/libdw.h
index e42c0873..1dcc8153 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -1,5 +1,5 @@
/* 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
@@ -250,7 +250,9 @@ extern Elf *dwarf_getelf (Dwarf *dwarf);
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
@@ -258,7 +260,9 @@ extern Dwarf *dwarf_getalt (Dwarf *main);
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. */
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index fbb8ed08..0681aa15 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1,5 +1,5 @@
/* 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 <[email protected]>, 2002.
@@ -154,6 +154,10 @@ struct Dwarf
/* 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
@@ -760,6 +764,22 @@ int __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
/* 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)
diff --git a/tests/ChangeLog b/tests/ChangeLog
index be203adf..89c531b4 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2018-01-22 Mark Wielaard <[email protected]>
+
+ * 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 <[email protected]>
* elfstrmerge.c (main): Initialize and check symtabshdr instead of
diff --git a/tests/allfcts.c b/tests/allfcts.c
index d3c8d26a..f6373117 100644
--- a/tests/allfcts.c
+++ b/tests/allfcts.c
@@ -51,7 +51,10 @@ setup_alt (Dwarf *main)
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));
diff --git a/tests/run-allfcts-multi.sh b/tests/run-allfcts-multi.sh
index 727b76ee..ef7bb30e 100755
--- a/tests/run-allfcts-multi.sh
+++ b/tests/run-allfcts-multi.sh
@@ -53,4 +53,20 @@ testrun_compare cat allfcts.out <<\EOF
/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