summaryrefslogtreecommitdiffstats
path: root/src/libdwfl/find-debuginfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libdwfl/find-debuginfo.c')
-rw-r--r--src/libdwfl/find-debuginfo.c180
1 files changed, 108 insertions, 72 deletions
diff --git a/src/libdwfl/find-debuginfo.c b/src/libdwfl/find-debuginfo.c
index 12cfe636..3f5314ad 100644
--- a/src/libdwfl/find-debuginfo.c
+++ b/src/libdwfl/find-debuginfo.c
@@ -1,51 +1,30 @@
/* Standard find_debuginfo callback for libdwfl.
- Copyright (C) 2005-2010 Red Hat, Inc.
- This file is part of Red Hat elfutils.
+ Copyright (C) 2005-2010, 2014 Red Hat, Inc.
+ This file is part of elfutils.
- Red Hat elfutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by the
- Free Software Foundation; version 2 of the License.
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of either
- Red Hat elfutils is distributed in the hope that it will be useful, but
+ * 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 a copy of the GNU General Public License along
- with Red Hat elfutils; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
-
- In addition, as a special exception, Red Hat, Inc. gives You the
- additional right to link the code of Red Hat elfutils with code licensed
- under any Open Source Initiative certified open source license
- (http://www.opensource.org/licenses/index.php) which requires the
- distribution of source code with any binary distribution and to
- distribute linked combinations of the two. Non-GPL Code permitted under
- this exception must only link to the code of Red Hat elfutils through
- those well defined interfaces identified in the file named EXCEPTION
- found in the source code files (the "Approved Interfaces"). The files
- of Non-GPL Code may instantiate templates or use macros or inline
- functions from the Approved Interfaces without causing the resulting
- work to be covered by the GNU General Public License. Only Red Hat,
- Inc. may make changes or additions to the list of Approved Interfaces.
- Red Hat's grant of this exception is conditioned upon your not adding
- any new exceptions. If you wish to add a new Approved Interface or
- exception, please contact Red Hat. You must obey the GNU General Public
- License in all respects for all of the Red Hat elfutils code and other
- code used in conjunction with Red Hat elfutils except the Non-GPL Code
- covered by this exception. If you modify this file, you may extend this
- exception to your version of the file, but you are not obligated to do
- so. If you do not wish to provide this exception without modification,
- you must delete this exception statement from your version and license
- this file solely under the GPL without exception.
-
- Red Hat elfutils is an included package of the Open Invention Network.
- An included package of the Open Invention Network is a package for which
- Open Invention Network licensees cross-license their patents. No patent
- license is granted, either expressly or impliedly, by designation as an
- included package. Should you wish to participate in the Open Invention
- Network licensing program, please visit www.openinventionnetwork.com
- <http://www.openinventionnetwork.com>. */
+ 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/>. */
#include "libdwflP.h"
#include <stdio.h>
@@ -105,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)
{
@@ -145,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;
@@ -163,13 +183,8 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
indicated by the debug directory path setting. */
const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
-#if defined(__BIONIC__) || defined(__APPLE__)
- char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
- ?: DEFAULT_DEBUGINFO_PATH);
-#else
char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
?: DEFAULT_DEBUGINFO_PATH);
-#endif
/* A leading - or + in the whole path sets whether to check file CRCs. */
bool defcheck = true;
@@ -189,14 +204,8 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
main_stat.st_ino = 0;
}
-#if defined(__BIONIC__) || defined(__APPLE__)
- char *file_dirname = (file_basename == file_name ? NULL
- : strndup (file_name, file_basename - 1 - file_name));
-#else
char *file_dirname = (file_basename == file_name ? NULL
: strndupa (file_name, file_basename - 1 - file_name));
-#endif
-
char *p;
while ((p = strsep (&path, ":")) != NULL)
{
@@ -206,53 +215,74 @@ 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:
-#if defined(__BIONIC__) || defined(__APPLE__)
- free(path);
- free(file_dirname);
-#endif
return -1;
}
if (validate (mod, fd, check, debuglink_crc))
{
*debuginfo_file_name = fname;
-#if defined(__BIONIC__) || defined(__APPLE__)
- free(path);
- free(file_dirname);
-#endif
return fd;
}
free (fname);
@@ -261,10 +291,6 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
/* No dice. */
errno = 0;
-#if defined(__BIONIC__) || defined(__APPLE__)
- free(path);
- free(file_dirname);
-#endif
return -1;
}
@@ -284,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;
}