diff options
Diffstat (limited to 'src/libdwfl/find-debuginfo.c')
-rw-r--r-- | src/libdwfl/find-debuginfo.c | 180 |
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; } |