diff options
| -rw-r--r-- | libdw/ChangeLog | 19 | ||||
| -rw-r--r-- | libdw/Makefile.am | 4 | ||||
| -rw-r--r-- | libdw/dwarf_begin_elf.c | 3 | ||||
| -rw-r--r-- | libdw/dwarf_end.c | 10 | ||||
| -rw-r--r-- | libdw/dwarf_formref_die.c | 4 | ||||
| -rw-r--r-- | libdw/dwarf_formstring.c | 5 | ||||
| -rw-r--r-- | libdw/dwarf_getalt.c | 158 | ||||
| -rw-r--r-- | libdw/dwarf_setalt.c | 11 | ||||
| -rw-r--r-- | libdw/libdw.h | 10 | ||||
| -rw-r--r-- | libdw/libdwP.h | 22 | ||||
| -rw-r--r-- | tests/ChangeLog | 7 | ||||
| -rw-r--r-- | tests/allfcts.c | 5 | ||||
| -rwxr-xr-x | tests/run-allfcts-multi.sh | 16 |
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 |
