1/* Find an ELF file for a module from its build ID. 2 Copyright (C) 2007-2010, 2014, 2015 Red Hat, Inc. 3 This file is part of elfutils. 4 5 This file is free software; you can redistribute it and/or modify 6 it under the terms of either 7 8 * the GNU Lesser General Public License as published by the Free 9 Software Foundation; either version 3 of the License, or (at 10 your option) any later version 11 12 or 13 14 * the GNU General Public License as published by the Free 15 Software Foundation; either version 2 of the License, or (at 16 your option) any later version 17 18 or both in parallel, as here. 19 20 elfutils is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of 22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 General Public License for more details. 24 25 You should have received copies of the GNU General Public License and 26 the GNU Lesser General Public License along with this program. If 27 not, see <http://www.gnu.org/licenses/>. */ 28 29#include "libdwflP.h" 30#include <inttypes.h> 31#include <fcntl.h> 32#include <unistd.h> 33 34 35int 36internal_function 37__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, 38 const size_t id_len, const uint8_t *id) 39{ 40 /* We don't handle very short or really large build-ids. We need at 41 at least 3 and allow for up to 64 (normally ids are 20 long). */ 42#define MIN_BUILD_ID_BYTES 3 43#define MAX_BUILD_ID_BYTES 64 44 if (id_len < MIN_BUILD_ID_BYTES || id_len > MAX_BUILD_ID_BYTES) 45 { 46 __libdwfl_seterrno (DWFL_E_WRONG_ID_ELF); 47 return -1; 48 } 49 50 /* Search debuginfo_path directories' .build-id/ subdirectories. */ 51 52 char id_name[sizeof "/.build-id/" + 1 + MAX_BUILD_ID_BYTES * 2 53 + sizeof ".debug" - 1]; 54 strcpy (id_name, "/.build-id/"); 55 int n = snprintf (&id_name[sizeof "/.build-id/" - 1], 56 4, "%02" PRIx8 "/", (uint8_t) id[0]); 57 assert (n == 3); 58 for (size_t i = 1; i < id_len; ++i) 59 { 60 n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2], 61 3, "%02" PRIx8, (uint8_t) id[i]); 62 assert (n == 2); 63 } 64 if (debug) 65 strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2], 66 ".debug"); 67 68 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; 69 char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) 70 ?: DEFAULT_DEBUGINFO_PATH); 71 if (path == NULL) 72 return -1; 73 74 int fd = -1; 75 char *dir; 76 char *paths = path; 77 while (fd < 0 && (dir = strsep (&paths, ":")) != NULL) 78 { 79 if (dir[0] == '+' || dir[0] == '-') 80 ++dir; 81 82 /* Only absolute directory names are useful to us. */ 83 if (dir[0] != '/') 84 continue; 85 86 size_t dirlen = strlen (dir); 87 char *name = malloc (dirlen + sizeof id_name); 88 if (unlikely (name == NULL)) 89 break; 90 memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name); 91 92 fd = TEMP_FAILURE_RETRY (open (name, O_RDONLY)); 93 if (fd >= 0) 94 { 95 if (*file_name != NULL) 96 free (*file_name); 97 *file_name = canonicalize_file_name (name); 98 if (*file_name == NULL) 99 { 100 *file_name = name; 101 name = NULL; 102 } 103 } 104 free (name); 105 } 106 107 free (path); 108 109 /* If we simply found nothing, clear errno. If we had some other error 110 with the file, report that. Possibly this should treat other errors 111 like ENOENT too. But ignoring all errors could mask some that should 112 be reported. */ 113 if (fd < 0 && errno == ENOENT) 114 errno = 0; 115 116 return fd; 117} 118 119int 120internal_function 121__libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name) 122{ 123 /* If *FILE_NAME was primed into the module, leave it there 124 as the fallback when we have nothing to offer. */ 125 errno = 0; 126 if (mod->build_id_len <= 0) 127 return -1; 128 129 const size_t id_len = mod->build_id_len; 130 const uint8_t *id = mod->build_id_bits; 131 132 return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id); 133} 134 135int 136dwfl_build_id_find_elf (Dwfl_Module *mod, 137 void **userdata __attribute__ ((unused)), 138 const char *modname __attribute__ ((unused)), 139 Dwarf_Addr base __attribute__ ((unused)), 140 char **file_name, Elf **elfp) 141{ 142 *elfp = NULL; 143 if (mod->is_executable 144 && mod->dwfl->user_core != NULL 145 && mod->dwfl->user_core->executable_for_core != NULL) 146 { 147 /* When dwfl_core_file_report was called with a non-NULL executable file 148 name this callback will replace the Dwfl_Module main.name with the 149 recorded executable file when MOD was identified as main executable 150 (which then triggers opening and reporting of the executable). */ 151 const char *executable = mod->dwfl->user_core->executable_for_core; 152 int fd = open (executable, O_RDONLY); 153 if (fd >= 0) 154 { 155 *file_name = strdup (executable); 156 if (*file_name != NULL) 157 return fd; 158 else 159 close (fd); 160 } 161 } 162 int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name); 163 if (fd >= 0) 164 { 165 Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false); 166 if (error != DWFL_E_NOERROR) 167 __libdwfl_seterrno (error); 168 else if (__libdwfl_find_build_id (mod, false, *elfp) == 2) 169 { 170 /* This is a backdoor signal to short-circuit the ID refresh. */ 171 mod->main.valid = true; 172 return fd; 173 } 174 else 175 { 176 /* This file does not contain the ID it should! */ 177 elf_end (*elfp); 178 *elfp = NULL; 179 close (fd); 180 fd = -1; 181 } 182 free (*file_name); 183 *file_name = NULL; 184 } 185 else if (errno == 0 && mod->build_id_len > 0) 186 /* Setting this with no file yet loaded is a marker that 187 the build ID is authoritative even if we also know a 188 putative *FILE_NAME. */ 189 mod->main.valid = true; 190 191 return fd; 192} 193INTDEF (dwfl_build_id_find_elf) 194