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 #ifdef HAVE_CONFIG_H 30 # include <config.h> 31 #endif 32 33 #include "libdwflP.h" 34 #include <inttypes.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include "system.h" 38 39 40 int 41 internal_function 42 __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name, 43 const size_t id_len, const uint8_t *id) 44 { 45 /* We don't handle very short or really large build-ids. We need at 46 at least 3 and allow for up to 64 (normally ids are 20 long). */ 47 #define MIN_BUILD_ID_BYTES 3 48 #define MAX_BUILD_ID_BYTES 64 49 if (id_len < MIN_BUILD_ID_BYTES || id_len > MAX_BUILD_ID_BYTES) 50 { 51 __libdwfl_seterrno (DWFL_E_WRONG_ID_ELF); 52 return -1; 53 } 54 55 /* Search debuginfo_path directories' .build-id/ subdirectories. */ 56 57 char id_name[sizeof "/.build-id/" + 1 + MAX_BUILD_ID_BYTES * 2 58 + sizeof ".debug" - 1]; 59 strcpy (id_name, "/.build-id/"); 60 int n = snprintf (&id_name[sizeof "/.build-id/" - 1], 61 4, "%02" PRIx8 "/", (uint8_t) id[0]); 62 assert (n == 3); 63 for (size_t i = 1; i < id_len; ++i) 64 { 65 n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2], 66 3, "%02" PRIx8, (uint8_t) id[i]); 67 assert (n == 2); 68 } 69 if (debug) 70 strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2], 71 ".debug"); 72 73 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; 74 char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) 75 ?: DEFAULT_DEBUGINFO_PATH); 76 if (path == NULL) 77 return -1; 78 79 int fd = -1; 80 char *dir; 81 char *paths = path; 82 while (fd < 0 && (dir = strsep (&paths, ":")) != NULL) 83 { 84 if (dir[0] == '+' || dir[0] == '-') 85 ++dir; 86 87 /* Only absolute directory names are useful to us. */ 88 if (dir[0] != '/') 89 continue; 90 91 size_t dirlen = strlen (dir); 92 char *name = malloc (dirlen + sizeof id_name); 93 if (unlikely (name == NULL)) 94 break; 95 memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name); 96 97 fd = TEMP_FAILURE_RETRY (open (name, O_RDONLY)); 98 if (fd >= 0) 99 { 100 if (*file_name != NULL) 101 free (*file_name); 102 *file_name = realpath (name, NULL); 103 if (*file_name == NULL) 104 { 105 *file_name = name; 106 name = NULL; 107 } 108 } 109 free (name); 110 } 111 112 free (path); 113 114 /* If we simply found nothing, clear errno. If we had some other error 115 with the file, report that. Possibly this should treat other errors 116 like ENOENT too. But ignoring all errors could mask some that should 117 be reported. */ 118 if (fd < 0 && errno == ENOENT) 119 errno = 0; 120 121 return fd; 122 } 123 124 int 125 internal_function 126 __libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name) 127 { 128 /* If *FILE_NAME was primed into the module, leave it there 129 as the fallback when we have nothing to offer. */ 130 errno = 0; 131 if (mod->build_id_len <= 0) 132 return -1; 133 134 const size_t id_len = mod->build_id_len; 135 const uint8_t *id = mod->build_id_bits; 136 137 return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id); 138 } 139 140 int 141 dwfl_build_id_find_elf (Dwfl_Module *mod, 142 void **userdata __attribute__ ((unused)), 143 const char *modname __attribute__ ((unused)), 144 Dwarf_Addr base __attribute__ ((unused)), 145 char **file_name, Elf **elfp) 146 { 147 *elfp = NULL; 148 if (mod->is_executable 149 && mod->dwfl->user_core != NULL 150 && mod->dwfl->user_core->executable_for_core != NULL) 151 { 152 /* When dwfl_core_file_report was called with a non-NULL executable file 153 name this callback will replace the Dwfl_Module main.name with the 154 recorded executable file when MOD was identified as main executable 155 (which then triggers opening and reporting of the executable). */ 156 const char *executable = mod->dwfl->user_core->executable_for_core; 157 int fd = open (executable, O_RDONLY); 158 if (fd >= 0) 159 { 160 *file_name = strdup (executable); 161 if (*file_name != NULL) 162 return fd; 163 else 164 close (fd); 165 } 166 } 167 int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name); 168 if (fd >= 0) 169 { 170 Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false); 171 if (error != DWFL_E_NOERROR) 172 __libdwfl_seterrno (error); 173 else if (__libdwfl_find_build_id (mod, false, *elfp) == 2) 174 { 175 /* This is a backdoor signal to short-circuit the ID refresh. */ 176 mod->main.valid = true; 177 return fd; 178 } 179 else 180 { 181 /* This file does not contain the ID it should! */ 182 elf_end (*elfp); 183 *elfp = NULL; 184 close (fd); 185 fd = -1; 186 } 187 free (*file_name); 188 *file_name = NULL; 189 } 190 else if (errno == 0 && mod->build_id_len > 0) 191 /* Setting this with no file yet loaded is a marker that 192 the build ID is authoritative even if we also know a 193 putative *FILE_NAME. */ 194 mod->main.valid = true; 195 196 return fd; 197 } 198 INTDEF (dwfl_build_id_find_elf) 199