mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-19 19:43:34 -04:00
libdwfl: Move dwz alt multi file searching to find_debuginfo callback.
Don't hard code the Dwarf dwz alt multi file search but allow the user to override it through the standard Dwfl_Callbacks. Also move ownership completely to the user of dwarf_setalt by removing free_alt from Dwarf and adding alt, fd and elf fields to Dwfl_Module. Add a relative .dwz file test case. Signed-off-by: Mark Wielaard <mjw@redhat.com>
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
2014-05-01 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* libdwP.h (struct Dwarf): Remove free_alt.
|
||||
* dwarf_end.c (dwarf_end): Don't check free_alt, don't end alt_dwarf.
|
||||
* dwarf_setalt.c (dwarf_setalt): Don't check or set free_alt.
|
||||
|
||||
2014-04-30 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* libdw.map (ELFUTILS_0.159): Add dwelf_elf_gnu_build_id.
|
||||
|
||||
+1
-5
@@ -1,5 +1,5 @@
|
||||
/* Release debugging handling context.
|
||||
Copyright (C) 2002-2011 Red Hat, Inc.
|
||||
Copyright (C) 2002-2011, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
|
||||
|
||||
@@ -111,10 +111,6 @@ dwarf_end (dwarf)
|
||||
if (dwarf->free_elf)
|
||||
elf_end (dwarf->elf);
|
||||
|
||||
/* Free the alternative Dwarf descriptor if necessary. */
|
||||
if (dwarf->free_alt)
|
||||
INTUSE (dwarf_end) (dwarf->alt_dwarf);
|
||||
|
||||
/* Free the context descriptor. */
|
||||
free (dwarf);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,6 @@
|
||||
void
|
||||
dwarf_setalt (Dwarf *main, Dwarf *alt)
|
||||
{
|
||||
if (main->free_alt)
|
||||
INTUSE (dwarf_end) (main->alt_dwarf);
|
||||
main->free_alt = false;
|
||||
main->alt_dwarf = alt;
|
||||
}
|
||||
INTDEF (dwarf_setalt)
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/* Internal definitions for libdwarf.
|
||||
Copyright (C) 2002-2011, 2013 Red Hat, Inc.
|
||||
Copyright (C) 2002-2011, 2013, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
|
||||
|
||||
@@ -147,9 +147,6 @@ struct Dwarf
|
||||
/* If true, we allocated the ELF descriptor ourselves. */
|
||||
bool free_elf;
|
||||
|
||||
/* If true, we allocated the Dwarf descriptor for alt_dwarf ourselves. */
|
||||
bool free_alt;
|
||||
|
||||
/* Information for traversing the .debug_pubnames section. This is
|
||||
an array and separately allocated with malloc. */
|
||||
struct pubnames_s
|
||||
|
||||
@@ -1,3 +1,36 @@
|
||||
2014-05-01 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* libdwflP.h (struct Dwfl_Module): Add alt, alt_fd and alt_elf fields.
|
||||
(__libdwfl_open_mod_by_build_id): Renamed __libdwfl_open_by_build_id.
|
||||
(__libdwfl_open_by_build_id): New declaration that takes an explicit
|
||||
build-id.
|
||||
* dwfl_build_id_find_debuginfo.c (dwfl_build_id_find_debuginfo): If
|
||||
we already have the Dwarf then look for the alt dwz multi file by
|
||||
build-id.
|
||||
* dwfl_build_id_find_elf.c (__libdwfl_open_by_build_id): Add the
|
||||
build-id we are looking for as argument.
|
||||
(__libdwfl_open_mod_by_build_id): New function, calls
|
||||
__libdwfl_open_by_build_id.
|
||||
(dwfl_build_id_find_elf): Call __libdwfl_open_mod_by_build_id.
|
||||
* dwfl_module.c (__libdwfl_module_free): Release alt, alt_elf and
|
||||
close alt_fd if necessary.
|
||||
* dwfl_module_getdwarf.c (__check_build_id): Removed.
|
||||
(try_debugaltlink): Removed.
|
||||
(open_debugaltlink): Removed.
|
||||
(open_elf_file): First half of open_elf that just opens the elf
|
||||
file but doesn't setup the load address.
|
||||
(open_elf): Call open_elf_file.
|
||||
(find_debug_altlink): New function.
|
||||
(load_dw): Remove loading of dwz multifile.
|
||||
(find_dw): Call find_debug_altlink.
|
||||
* find-debuginfo.c (validate): Handle alt debug case using
|
||||
dwelf_dwarf_gnu_debugaltlink and mod->alt_elf.
|
||||
(find_debuginfo_in_path): Handle alt debug files possibly in .dwz
|
||||
subdirs.
|
||||
* linux-kernel-modules.c (try_kernel_name): Use fakemod.debug.name
|
||||
to store name to find by dwfl_standard_find_debuginfo instead of
|
||||
allocating an extra variable on stack.
|
||||
|
||||
2014-04-30 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* dwfl_module_build_id.c (__libdwfl_find_elf_build_id): Moved to
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Find the debuginfo file for a module from its build ID.
|
||||
Copyright (C) 2007, 2009 Red Hat, Inc.
|
||||
Copyright (C) 2007, 2009, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
@@ -41,10 +41,61 @@ dwfl_build_id_find_debuginfo (Dwfl_Module *mod,
|
||||
char **debuginfo_file_name)
|
||||
{
|
||||
int fd = -1;
|
||||
|
||||
/* Are we looking for a separate debug file for the main file or for
|
||||
an alternate (dwz multi) debug file? Alternatively we could check
|
||||
whether the dwbias == -1. */
|
||||
if (mod->dw != NULL)
|
||||
{
|
||||
const void *build_id;
|
||||
const char *altname;
|
||||
ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
|
||||
&altname,
|
||||
&build_id);
|
||||
if (build_id_len > 0)
|
||||
fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name,
|
||||
build_id_len, build_id);
|
||||
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* We need to open an Elf handle on the file so we can check its
|
||||
build ID note for validation. Backdoor the handle into the
|
||||
module data structure since we had to open it early anyway. */
|
||||
Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
|
||||
true, false);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
__libdwfl_seterrno (error);
|
||||
else
|
||||
{
|
||||
const void *alt_build_id;
|
||||
ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
|
||||
&alt_build_id);
|
||||
if (alt_len > 0 && alt_len == build_id_len
|
||||
&& memcmp (build_id, alt_build_id, alt_len) == 0)
|
||||
return fd;
|
||||
else
|
||||
{
|
||||
/* A mismatch! */
|
||||
elf_end (mod->alt_elf);
|
||||
mod->alt_elf = NULL;
|
||||
close (fd);
|
||||
fd = -1;
|
||||
}
|
||||
free (*debuginfo_file_name);
|
||||
*debuginfo_file_name = NULL;
|
||||
errno = 0;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* We don't even have the Dwarf yet and it isn't in the main file.
|
||||
Try to find separate debug file now using the module build id. */
|
||||
const unsigned char *bits;
|
||||
GElf_Addr vaddr;
|
||||
|
||||
if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
|
||||
fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name);
|
||||
fd = __libdwfl_open_mod_by_build_id (mod, true, debuginfo_file_name);
|
||||
if (fd >= 0)
|
||||
{
|
||||
/* We need to open an Elf handle on the file so we can check its
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Find an ELF file for a module from its build ID.
|
||||
Copyright (C) 2007-2010 Red Hat, Inc.
|
||||
Copyright (C) 2007-2010, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
@@ -34,17 +34,9 @@
|
||||
|
||||
int
|
||||
internal_function
|
||||
__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
|
||||
__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name,
|
||||
const size_t id_len, const uint8_t *id)
|
||||
{
|
||||
/* If *FILE_NAME was primed into the module, leave it there
|
||||
as the fallback when we have nothing to offer. */
|
||||
errno = 0;
|
||||
if (mod->build_id_len <= 0)
|
||||
return -1;
|
||||
|
||||
const size_t id_len = mod->build_id_len;
|
||||
const uint8_t *id = mod->build_id_bits;
|
||||
|
||||
/* Search debuginfo_path directories' .build-id/ subdirectories. */
|
||||
|
||||
char id_name[sizeof "/.build-id/" + 1 + id_len * 2 + sizeof ".debug" - 1];
|
||||
@@ -108,6 +100,22 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
internal_function
|
||||
__libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
|
||||
{
|
||||
/* If *FILE_NAME was primed into the module, leave it there
|
||||
as the fallback when we have nothing to offer. */
|
||||
errno = 0;
|
||||
if (mod->build_id_len <= 0)
|
||||
return -1;
|
||||
|
||||
const size_t id_len = mod->build_id_len;
|
||||
const uint8_t *id = mod->build_id_bits;
|
||||
|
||||
return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id);
|
||||
}
|
||||
|
||||
int
|
||||
dwfl_build_id_find_elf (Dwfl_Module *mod,
|
||||
void **userdata __attribute__ ((unused)),
|
||||
@@ -133,7 +141,7 @@ dwfl_build_id_find_elf (Dwfl_Module *mod,
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
int fd = __libdwfl_open_by_build_id (mod, false, file_name);
|
||||
int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name);
|
||||
if (fd >= 0)
|
||||
{
|
||||
Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false);
|
||||
|
||||
+12
-2
@@ -1,5 +1,5 @@
|
||||
/* Maintenance of module list in libdwfl.
|
||||
Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc.
|
||||
Copyright (C) 2005, 2006, 2007, 2008, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
@@ -71,7 +71,17 @@ __libdwfl_module_free (Dwfl_Module *mod)
|
||||
}
|
||||
|
||||
if (mod->dw != NULL)
|
||||
INTUSE(dwarf_end) (mod->dw);
|
||||
{
|
||||
INTUSE(dwarf_end) (mod->dw);
|
||||
if (mod->alt != NULL)
|
||||
{
|
||||
INTUSE(dwarf_end) (mod->alt);
|
||||
if (mod->alt_elf != NULL)
|
||||
elf_end (mod->alt_elf);
|
||||
if (mod->alt_fd != -1)
|
||||
close (mod->alt_fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (mod->ebl != NULL)
|
||||
ebl_closebackend (mod->ebl);
|
||||
|
||||
+93
-115
@@ -34,99 +34,10 @@
|
||||
#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
|
||||
#include "../libelf/libelfP.h"
|
||||
|
||||
#ifdef ENABLE_DWZ
|
||||
internal_function int
|
||||
__check_build_id (Dwarf *dw, const uint8_t *build_id, const size_t id_len)
|
||||
{
|
||||
if (dw == NULL)
|
||||
return -1;
|
||||
|
||||
Elf *elf = dw->elf;
|
||||
const void *elf_build_id;
|
||||
ssize_t elf_id_len = INTUSE(dwelf_elf_gnu_build_id) (elf, &elf_build_id);
|
||||
if (elf_id_len < 0)
|
||||
return -1;
|
||||
|
||||
return (id_len == (size_t) elf_id_len
|
||||
&& memcmp (build_id, elf_build_id, id_len) == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Try to open an debug alt link by name, checking build_id.
|
||||
Marks free_alt on success, return NULL on failure. */
|
||||
static Dwarf *
|
||||
try_debugaltlink (Dwarf *result, const char *try_name,
|
||||
const uint8_t *build_id, const size_t id_len)
|
||||
{
|
||||
int fd = open (try_name, O_RDONLY);
|
||||
if (fd > 0)
|
||||
{
|
||||
Dwarf *alt_dwarf = INTUSE (dwarf_begin) (fd, DWARF_C_READ);
|
||||
if (alt_dwarf != NULL)
|
||||
{
|
||||
Elf *elf = alt_dwarf->elf;
|
||||
if (__check_build_id (alt_dwarf, build_id, id_len) == 0
|
||||
&& elf_cntl (elf, ELF_C_FDREAD) == 0)
|
||||
{
|
||||
close (fd);
|
||||
INTUSE (dwarf_setalt) (result, alt_dwarf);
|
||||
result->free_alt = true;
|
||||
return result;
|
||||
}
|
||||
INTUSE (dwarf_end) (result->alt_dwarf);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For dwz multifile support, ignore if it looks wrong. */
|
||||
static Dwarf *
|
||||
open_debugaltlink (Dwarf *result, const char *alt_name,
|
||||
const uint8_t *build_id, const size_t id_len)
|
||||
{
|
||||
/* First try the name itself, it is either an absolute path or
|
||||
a relative one. Sadly we don't know relative from where at
|
||||
this point. */
|
||||
if (try_debugaltlink (result, alt_name, build_id, id_len) != NULL)
|
||||
return result;
|
||||
|
||||
/* Lets try based on the build-id. This is somewhat distro specific,
|
||||
we are following the Fedora implementation described at
|
||||
https://fedoraproject.org/wiki/Releases/FeatureBuildId#Find_files_by_build_ID
|
||||
*/
|
||||
#define DEBUG_PREFIX "/usr/lib/debug/.build-id/"
|
||||
#define PREFIX_LEN sizeof (DEBUG_PREFIX)
|
||||
char id_name[PREFIX_LEN + 1 + id_len * 2 + sizeof ".debug" - 1];
|
||||
strcpy (id_name, DEBUG_PREFIX);
|
||||
int n = snprintf (&id_name[PREFIX_LEN - 1],
|
||||
4, "%02" PRIx8 "/", (uint8_t) build_id[0]);
|
||||
assert (n == 3);
|
||||
for (size_t i = 1; i < id_len; ++i)
|
||||
{
|
||||
n = snprintf (&id_name[PREFIX_LEN - 1 + 3 + (i - 1) * 2],
|
||||
3, "%02" PRIx8, (uint8_t) build_id[i]);
|
||||
assert (n == 2);
|
||||
}
|
||||
strcpy (&id_name[PREFIX_LEN - 1 + 3 + (id_len - 1) * 2],
|
||||
".debug");
|
||||
|
||||
if (try_debugaltlink (result, id_name, build_id, id_len))
|
||||
return result;
|
||||
|
||||
/* Everything failed, mark this Dwarf as not having an alternate,
|
||||
but don't fail the load. The user may want to set it by hand
|
||||
before usage. */
|
||||
result->alt_dwarf = NULL;
|
||||
return result;
|
||||
}
|
||||
#endif /* ENABLE_DWZ */
|
||||
|
||||
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
|
||||
When we return success, FILE->elf and FILE->vaddr are set up. */
|
||||
static inline Dwfl_Error
|
||||
open_elf (Dwfl_Module *mod, struct dwfl_file *file)
|
||||
open_elf_file (Elf **elf, int *fd, char **name)
|
||||
{
|
||||
if (file->elf == NULL)
|
||||
if (*elf == NULL)
|
||||
{
|
||||
/* CBFAIL uses errno if it's set, so clear it first in case we don't
|
||||
set it with an open failure below. */
|
||||
@@ -134,25 +45,36 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
|
||||
|
||||
/* If there was a pre-primed file name left that the callback left
|
||||
behind, try to open that file name. */
|
||||
if (file->fd < 0 && file->name != NULL)
|
||||
file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY));
|
||||
if (*fd < 0 && *name != NULL)
|
||||
*fd = TEMP_FAILURE_RETRY (open64 (*name, O_RDONLY));
|
||||
|
||||
if (file->fd < 0)
|
||||
if (*fd < 0)
|
||||
return CBFAIL;
|
||||
|
||||
Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
return error;
|
||||
return __libdw_open_file (fd, elf, true, false);
|
||||
}
|
||||
else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
|
||||
else if (unlikely (elf_kind (*elf) != ELF_K_ELF))
|
||||
{
|
||||
elf_end (file->elf);
|
||||
file->elf = NULL;
|
||||
close (file->fd);
|
||||
file->fd = -1;
|
||||
elf_end (*elf);
|
||||
*elf = NULL;
|
||||
close (*fd);
|
||||
*fd = -1;
|
||||
return DWFL_E_BADELF;
|
||||
}
|
||||
|
||||
/* Elf file already open and looks fine. */
|
||||
return DWFL_E_NOERROR;
|
||||
}
|
||||
|
||||
/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
|
||||
When we return success, FILE->elf and FILE->vaddr are set up. */
|
||||
static inline Dwfl_Error
|
||||
open_elf (Dwfl_Module *mod, struct dwfl_file *file)
|
||||
{
|
||||
Dwfl_Error error = open_elf_file (&file->elf, &file->fd, &file->name);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
return error;
|
||||
|
||||
GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
|
||||
if (ehdr == NULL)
|
||||
{
|
||||
@@ -586,6 +508,57 @@ find_debuginfo (Dwfl_Module *mod)
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DWZ
|
||||
/* Try to find the alternative debug link for the given DWARF and set
|
||||
it if found. Only called when mod->dw is already setup but still
|
||||
might need an alternative (dwz multi) debug file. filename is either
|
||||
the main or debug name from which the Dwarf was created. */
|
||||
static void
|
||||
find_debug_altlink (Dwfl_Module *mod, const char *filename)
|
||||
{
|
||||
assert (mod->dw != NULL);
|
||||
|
||||
const char *altname;
|
||||
const void *build_id;
|
||||
ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
|
||||
&altname,
|
||||
&build_id);
|
||||
|
||||
if (build_id_len > 0)
|
||||
{
|
||||
/* We could store altfile in the module, but don't really need it. */
|
||||
char *altfile = NULL;
|
||||
mod->alt_fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
|
||||
filename,
|
||||
altname,
|
||||
0,
|
||||
&altfile);
|
||||
|
||||
/* The (internal) callbacks might just set mod->alt_elf directly
|
||||
because they open the Elf anyway for sanity checking.
|
||||
Otherwise open either the given file name or use the fd
|
||||
returned. */
|
||||
Dwfl_Error error = open_elf_file (&mod->alt_elf, &mod->alt_fd,
|
||||
&altfile);
|
||||
if (error == DWFL_E_NOERROR)
|
||||
{
|
||||
mod->alt = INTUSE(dwarf_begin_elf) (mod->alt_elf,
|
||||
DWARF_C_READ, NULL);
|
||||
if (mod->alt == NULL)
|
||||
{
|
||||
elf_end (mod->alt_elf);
|
||||
mod->alt_elf = NULL;
|
||||
close (mod->alt_fd);
|
||||
mod->alt_fd = -1;
|
||||
}
|
||||
else
|
||||
dwarf_setalt (mod->dw, mod->alt);
|
||||
}
|
||||
|
||||
free (altfile); /* See above, we don't really need it. */
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_DWZ */
|
||||
|
||||
/* Try to find a symbol table in FILE.
|
||||
Returns DWFL_E_NOERROR if a proper one is found.
|
||||
@@ -1209,19 +1182,6 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
|
||||
return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DWZ
|
||||
/* For dwz multifile support, ignore if it looks wrong. */
|
||||
{
|
||||
const void *build_id;
|
||||
const char *alt_name;
|
||||
size_t id_len = INTUSE (dwelf_dwarf_gnu_debugaltlink) (mod->dw,
|
||||
&alt_name,
|
||||
&build_id);
|
||||
if (id_len > 0)
|
||||
open_debugaltlink (mod->dw, alt_name, build_id, id_len);
|
||||
}
|
||||
#endif /* ENABLE_DWZ */
|
||||
|
||||
/* Until we have iterated through all CU's, we might do lazy lookups. */
|
||||
mod->lazycu = 1;
|
||||
|
||||
@@ -1248,6 +1208,13 @@ find_dw (Dwfl_Module *mod)
|
||||
case DWFL_E_NOERROR:
|
||||
mod->debug.elf = mod->main.elf;
|
||||
mod->debug.address_sync = mod->main.address_sync;
|
||||
|
||||
#ifdef ENABLE_DWZ
|
||||
/* The Dwarf might need an alt debug file, find that now after
|
||||
everything about the debug file has been setup (the
|
||||
find_debuginfo callback might need it). */
|
||||
find_debug_altlink (mod, mod->main.name);
|
||||
#endif /* ENABLE_DWZ */
|
||||
return;
|
||||
|
||||
case DWFL_E_NO_DWARF:
|
||||
@@ -1263,6 +1230,17 @@ find_dw (Dwfl_Module *mod)
|
||||
{
|
||||
case DWFL_E_NOERROR:
|
||||
mod->dwerr = load_dw (mod, &mod->debug);
|
||||
if (mod->dwerr == DWFL_E_NOERROR)
|
||||
{
|
||||
#ifdef ENABLE_DWZ
|
||||
/* The Dwarf might need an alt debug file, find that now after
|
||||
everything about the debug file has been setup (the
|
||||
find_debuginfo callback might need it). */
|
||||
find_debug_altlink (mod, mod->debug.name);
|
||||
#endif /* ENABLE_DWZ */
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DWFL_E_CB: /* The find_debuginfo hook failed. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Standard find_debuginfo callback for libdwfl.
|
||||
Copyright (C) 2005-2010 Red Hat, Inc.
|
||||
Copyright (C) 2005-2010, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
@@ -84,6 +84,45 @@ check_crc (int fd, GElf_Word debuglink_crc)
|
||||
static bool
|
||||
validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
|
||||
{
|
||||
/* For alt debug files always check the build-id from the Dwarf and alt. */
|
||||
if (mod->dw != NULL)
|
||||
{
|
||||
bool valid = false;
|
||||
const void *build_id;
|
||||
const char *altname;
|
||||
ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
|
||||
&altname,
|
||||
&build_id);
|
||||
if (build_id_len > 0)
|
||||
{
|
||||
/* We need to open an Elf handle on the file so we can check its
|
||||
build ID note for validation. Backdoor the handle into the
|
||||
module data structure since we had to open it early anyway. */
|
||||
Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
|
||||
false, false);
|
||||
if (error != DWFL_E_NOERROR)
|
||||
__libdwfl_seterrno (error);
|
||||
else
|
||||
{
|
||||
const void *alt_build_id;
|
||||
ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
|
||||
&alt_build_id);
|
||||
if (alt_len > 0 && alt_len == build_id_len
|
||||
&& memcmp (build_id, alt_build_id, alt_len) == 0)
|
||||
valid = true;
|
||||
else
|
||||
{
|
||||
/* A mismatch! */
|
||||
elf_end (mod->alt_elf);
|
||||
mod->alt_elf = NULL;
|
||||
close (fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/* If we have a build ID, check only that. */
|
||||
if (mod->build_id_len > 0)
|
||||
{
|
||||
@@ -124,7 +163,9 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
|
||||
const char *file_basename = file_name == NULL ? NULL : basename (file_name);
|
||||
if (debuglink_file == NULL)
|
||||
{
|
||||
if (file_basename == NULL)
|
||||
/* For a alt debug multi file we need a name, for a separate debug
|
||||
name we may be able to fall back on file_basename.debug. */
|
||||
if (file_basename == NULL || mod->dw != NULL)
|
||||
{
|
||||
errno = 0;
|
||||
return -1;
|
||||
@@ -174,38 +215,67 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
|
||||
check = *p++ == '+';
|
||||
check = check && cancheck;
|
||||
|
||||
const char *dir, *subdir;
|
||||
const char *dir, *subdir, *file;
|
||||
switch (p[0])
|
||||
{
|
||||
case '\0':
|
||||
/* An empty entry says to try the main file's directory. */
|
||||
dir = file_dirname;
|
||||
subdir = NULL;
|
||||
file = debuglink_file;
|
||||
break;
|
||||
case '/':
|
||||
/* An absolute path says to look there for a subdirectory
|
||||
named by the main file's absolute directory.
|
||||
This cannot be applied to a relative file name. */
|
||||
if (file_dirname == NULL || file_dirname[0] != '/')
|
||||
named by the main file's absolute directory. This cannot
|
||||
be applied to a relative file name. For alt debug files
|
||||
it means to look for the basename file in that dir or the
|
||||
.dwz subdir (see below). */
|
||||
if (mod->dw == NULL
|
||||
&& (file_dirname == NULL || file_dirname[0] != '/'))
|
||||
continue;
|
||||
dir = p;
|
||||
subdir = file_dirname + 1;
|
||||
if (mod->dw == NULL)
|
||||
{
|
||||
subdir = file_dirname + 1;
|
||||
file = debuglink_file;
|
||||
}
|
||||
else
|
||||
{
|
||||
subdir = NULL;
|
||||
file = basename (debuglink_file);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* A relative path says to try a subdirectory of that name
|
||||
in the main file's directory. */
|
||||
dir = file_dirname;
|
||||
subdir = p;
|
||||
file = debuglink_file;
|
||||
break;
|
||||
}
|
||||
|
||||
char *fname = NULL;
|
||||
int fd = try_open (&main_stat, dir, subdir, debuglink_file, &fname);
|
||||
int fd = try_open (&main_stat, dir, subdir, file, &fname);
|
||||
if (fd < 0)
|
||||
switch (errno)
|
||||
{
|
||||
case ENOENT:
|
||||
case ENOTDIR:
|
||||
/* If we are looking for the alt file also try the .dwz subdir.
|
||||
But only if this is the empty or absolute path. */
|
||||
if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
|
||||
{
|
||||
fd = try_open (&main_stat, dir, ".dwz",
|
||||
basename (file), &fname);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno != ENOENT && errno != ENOTDIR)
|
||||
return -1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
return -1;
|
||||
@@ -240,11 +310,21 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod,
|
||||
GElf_Addr vaddr;
|
||||
if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
|
||||
{
|
||||
/* Dropping most arguments means we cannot rely on them in
|
||||
dwfl_build_id_find_debuginfo. But leave it that way since
|
||||
some user code out there also does this, so we'll have to
|
||||
handle it anyway. */
|
||||
int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
|
||||
NULL, NULL, 0,
|
||||
NULL, NULL, 0,
|
||||
debuginfo_file_name);
|
||||
if (fd >= 0 || mod->debug.elf != NULL || errno != 0)
|
||||
|
||||
/* Did the build_id callback find something or report an error?
|
||||
Then we are done. Otherwise fallback on path based search. */
|
||||
if (fd >= 0
|
||||
|| (mod->dw == NULL && mod->debug.elf != NULL)
|
||||
|| (mod->dw != NULL && mod->alt_elf != NULL)
|
||||
|| errno != 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
||||
+9
-1
@@ -182,6 +182,9 @@ struct Dwfl_Module
|
||||
Elf_Data *aux_symxndxdata; /* Data in the extended auxiliary table. */
|
||||
|
||||
Dwarf *dw; /* libdw handle for its debugging info. */
|
||||
Dwarf *alt; /* Dwarf used for dwarf_setalt, or NULL. */
|
||||
int alt_fd; /* descriptor, only valid when alt != NULL. */
|
||||
Elf *alt_elf; /* Elf for alt Dwarf. */
|
||||
|
||||
Dwfl_Error symerr; /* Previous failure to load symbols. */
|
||||
Dwfl_Error dwerr; /* Previous failure to load DWARF. */
|
||||
@@ -518,8 +521,13 @@ extern int __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
|
||||
internal_function;
|
||||
|
||||
/* Open a main or debuginfo file by its build ID, returns the fd. */
|
||||
extern int __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug,
|
||||
char **file_name) internal_function;
|
||||
|
||||
/* Same, but takes an explicit build_id, can also be used for alt debug. */
|
||||
extern int __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug,
|
||||
char **file_name) internal_function;
|
||||
char **file_name, const size_t id_len,
|
||||
const uint8_t *id) internal_function;
|
||||
|
||||
extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len)
|
||||
attribute_hidden;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Standard libdwfl callbacks for debugging the running Linux kernel.
|
||||
Copyright (C) 2005-2011, 2013 Red Hat, Inc.
|
||||
Copyright (C) 2005-2011, 2013, 2014 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
@@ -88,23 +88,22 @@ try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
char *debugfname = NULL;
|
||||
Dwfl_Module fakemod = { .dwfl = dwfl };
|
||||
/* First try the file's unadorned basename as DEBUGLINK_FILE,
|
||||
to look for "vmlinux" files. */
|
||||
fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
|
||||
*fname, basename (*fname), 0,
|
||||
&debugfname);
|
||||
&fakemod.debug.name);
|
||||
if (fd < 0 && try_debug)
|
||||
/* Next, let the call use the default of basename + ".debug",
|
||||
to look for "vmlinux.debug" files. */
|
||||
fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
|
||||
*fname, NULL, 0,
|
||||
&debugfname);
|
||||
if (debugfname != NULL)
|
||||
&fakemod.debug.name);
|
||||
if (fakemod.debug.name != NULL)
|
||||
{
|
||||
free (*fname);
|
||||
*fname = debugfname;
|
||||
*fname = fakemod.debug.name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
2014-05-01 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* readelf.c (find_no_debuginfo): Call dwfl_standard_find_debuginfo
|
||||
if looking for alternate debug file.
|
||||
|
||||
2014-04-11 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* Makefile.am (AM_CPPFLAGS): Add -I libdwelf.
|
||||
|
||||
+24
-10
@@ -693,18 +693,32 @@ process_dwflmod (Dwfl_Module *dwflmod,
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
/* Stub libdwfl callback, only the ELF handle already open is ever used. */
|
||||
/* Stub libdwfl callback, only the ELF handle already open is ever used.
|
||||
Only used for finding the alternate debug file if the Dwarf comes from
|
||||
the main file. We are not interested in separate debuginfo. */
|
||||
static int
|
||||
find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
|
||||
void **userdata __attribute__ ((unused)),
|
||||
const char *modname __attribute__ ((unused)),
|
||||
Dwarf_Addr base __attribute__ ((unused)),
|
||||
const char *file_name __attribute__ ((unused)),
|
||||
const char *debuglink_file __attribute__ ((unused)),
|
||||
GElf_Word debuglink_crc __attribute__ ((unused)),
|
||||
char **debuginfo_file_name __attribute__ ((unused)))
|
||||
find_no_debuginfo (Dwfl_Module *mod,
|
||||
void **userdata,
|
||||
const char *modname,
|
||||
Dwarf_Addr base,
|
||||
const char *file_name,
|
||||
const char *debuglink_file,
|
||||
GElf_Word debuglink_crc,
|
||||
char **debuginfo_file_name)
|
||||
{
|
||||
return -1;
|
||||
Dwarf_Addr dwbias;
|
||||
dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
|
||||
|
||||
/* We are only interested if the Dwarf has been setup on the main
|
||||
elf file but is only missing the alternate debug link. If dwbias
|
||||
hasn't even been setup, this is searching for separate debuginfo
|
||||
for the main elf. We don't care in that case. */
|
||||
if (dwbias == (Dwarf_Addr) -1)
|
||||
return -1;
|
||||
|
||||
return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
|
||||
file_name, debuglink_file,
|
||||
debuglink_crc, debuginfo_file_name);
|
||||
}
|
||||
|
||||
/* Process one input file. */
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
2014-05-01 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* run-readelf-dwz-multi.sh: Add tests with alt debug files in .dwz
|
||||
subdir.
|
||||
|
||||
2014-04-30 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* buildid.c, buildid.sh, testfile42_noshdrs.bz2: New files.
|
||||
|
||||
@@ -136,6 +136,69 @@ DWARF section [28] '.debug_info' at offset 0x1078:
|
||||
type (ref_udata) [ 2b]
|
||||
EOF
|
||||
|
||||
# Same as above, but find alt debug file in a .dwz subdir.
|
||||
mkdir .dwz
|
||||
mv testfile_multi.dwz .dwz
|
||||
testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info testfile_multi_main <<\EOF
|
||||
|
||||
DWARF section [28] '.debug_info' at offset 0x1078:
|
||||
[Offset]
|
||||
Compilation unit at offset 0:
|
||||
Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
|
||||
[ b] compile_unit
|
||||
producer (strp) "GNU C 4.7.0 20120507 (Red Hat 4.7.0-5) -mtune=generic -march=x86-64 -g"
|
||||
language (data1) C89 (1)
|
||||
name (strp) "main.c"
|
||||
comp_dir (GNU_strp_alt) "/home/mark/src/tests/dwz"
|
||||
low_pc (addr) 0x00000000004006ac <main>
|
||||
high_pc (udata) 44 (0x00000000004006d8)
|
||||
stmt_list (sec_offset) 0
|
||||
[ 26] imported_unit
|
||||
import (GNU_ref_alt) [ b]
|
||||
[ 2b] pointer_type
|
||||
byte_size (data1) 8
|
||||
type (GNU_ref_alt) [ 53]
|
||||
[ 31] subprogram
|
||||
external (flag_present)
|
||||
name (strp) "main"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 3
|
||||
prototyped (flag_present)
|
||||
type (GNU_ref_alt) [ 3e]
|
||||
low_pc (addr) 0x00000000004006ac <main>
|
||||
high_pc (udata) 44 (0x00000000004006d8)
|
||||
frame_base (exprloc)
|
||||
[ 0] call_frame_cfa
|
||||
GNU_all_tail_call_sites (flag_present)
|
||||
sibling (ref_udata) [ 6e]
|
||||
[ 48] formal_parameter
|
||||
name (strp) "argc"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 3
|
||||
type (GNU_ref_alt) [ 3e]
|
||||
location (exprloc)
|
||||
[ 0] fbreg -36
|
||||
[ 56] formal_parameter
|
||||
name (strp) "argv"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 3
|
||||
type (ref_udata) [ 6e]
|
||||
location (exprloc)
|
||||
[ 0] fbreg -48
|
||||
[ 61] variable
|
||||
name (string) "b"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 5
|
||||
type (GNU_ref_alt) [ 5a]
|
||||
location (exprloc)
|
||||
[ 0] fbreg -32
|
||||
[ 6e] pointer_type
|
||||
byte_size (data1) 8
|
||||
type (ref_udata) [ 2b]
|
||||
EOF
|
||||
mv .dwz/testfile_multi.dwz .
|
||||
rmdir .dwz
|
||||
|
||||
testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info libtestfile_multi_shared.so <<\EOF
|
||||
|
||||
DWARF section [25] '.debug_info' at offset 0x106c:
|
||||
@@ -173,6 +236,48 @@ DWARF section [25] '.debug_info' at offset 0x106c:
|
||||
[ 0] fbreg -24
|
||||
EOF
|
||||
|
||||
# Same as above, but find alt debug file in a .dwz subdir.
|
||||
mkdir .dwz
|
||||
mv testfile_multi.dwz .dwz
|
||||
testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info libtestfile_multi_shared.so <<\EOF
|
||||
|
||||
DWARF section [25] '.debug_info' at offset 0x106c:
|
||||
[Offset]
|
||||
Compilation unit at offset 0:
|
||||
Version: 4, Abbreviation section offset: 0, Address size: 8, Offset size: 4
|
||||
[ b] compile_unit
|
||||
producer (strp) "GNU C 4.7.0 20120507 (Red Hat 4.7.0-5) -fpreprocessed -mtune=generic -march=x86-64 -g -fPIC"
|
||||
language (data1) C89 (1)
|
||||
name (strp) "shared.c"
|
||||
comp_dir (GNU_strp_alt) "/home/mark/src/tests/dwz"
|
||||
low_pc (addr) +0x0000000000000670 <call_foo>
|
||||
high_pc (udata) 23 (+0x0000000000000687)
|
||||
stmt_list (sec_offset) 0
|
||||
[ 26] imported_unit
|
||||
import (GNU_ref_alt) [ b]
|
||||
[ 2b] subprogram
|
||||
external (flag_present)
|
||||
name (strp) "call_foo"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 3
|
||||
prototyped (flag_present)
|
||||
type (GNU_ref_alt) [ 3e]
|
||||
low_pc (addr) +0x0000000000000670 <call_foo>
|
||||
high_pc (udata) 23 (+0x0000000000000687)
|
||||
frame_base (exprloc)
|
||||
[ 0] call_frame_cfa
|
||||
GNU_all_call_sites (flag_present)
|
||||
[ 41] formal_parameter
|
||||
name (string) "fb"
|
||||
decl_file (data1) 1
|
||||
decl_line (data1) 3
|
||||
type (GNU_ref_alt) [ 76]
|
||||
location (exprloc)
|
||||
[ 0] fbreg -24
|
||||
EOF
|
||||
mv .dwz/testfile_multi.dwz .
|
||||
rmdir .dwz
|
||||
|
||||
testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info testfile-dwzstr <<\EOF
|
||||
|
||||
DWARF section [28] '.debug_info' at offset 0x1088:
|
||||
|
||||
Reference in New Issue
Block a user