1 /* Standard find_debuginfo callback for libdwfl. 2 Copyright (C) 2005-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 <stdio.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <sys/stat.h> 38 #include "system.h" 39 40 41 /* Try to open [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1. 42 On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */ 43 static int 44 try_open (const struct stat *main_stat, 45 const char *dir, const char *subdir, const char *debuglink, 46 char **debuginfo_file_name) 47 { 48 char *fname; 49 if (dir == NULL && subdir == NULL) 50 { 51 fname = strdup (debuglink); 52 if (unlikely (fname == NULL)) 53 return -1; 54 } 55 else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink) 56 : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink) 57 : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0) 58 return -1; 59 60 struct stat st; 61 int fd = TEMP_FAILURE_RETRY (open (fname, O_RDONLY)); 62 if (fd < 0) 63 free (fname); 64 else if (fstat (fd, &st) == 0 65 && st.st_ino == main_stat->st_ino 66 && st.st_dev == main_stat->st_dev) 67 { 68 /* This is the main file by another name. Don't look at it again. */ 69 free (fname); 70 close (fd); 71 errno = ENOENT; 72 fd = -1; 73 } 74 else 75 *debuginfo_file_name = fname; 76 77 return fd; 78 } 79 80 /* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */ 81 static inline bool 82 check_crc (int fd, GElf_Word debuglink_crc) 83 { 84 uint32_t file_crc; 85 return (__libdwfl_crc32_file (fd, &file_crc) == 0 86 && file_crc == debuglink_crc); 87 } 88 89 static bool 90 validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc) 91 { 92 /* For alt debug files always check the build-id from the Dwarf and alt. */ 93 if (mod->dw != NULL) 94 { 95 bool valid = false; 96 const void *build_id; 97 const char *altname; 98 ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, 99 &altname, 100 &build_id); 101 if (build_id_len > 0) 102 { 103 /* We need to open an Elf handle on the file so we can check its 104 build ID note for validation. Backdoor the handle into the 105 module data structure since we had to open it early anyway. */ 106 Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf, 107 false, false); 108 if (error != DWFL_E_NOERROR) 109 __libdwfl_seterrno (error); 110 else 111 { 112 const void *alt_build_id; 113 ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf, 114 &alt_build_id); 115 if (alt_len > 0 && alt_len == build_id_len 116 && memcmp (build_id, alt_build_id, alt_len) == 0) 117 valid = true; 118 else 119 { 120 /* A mismatch! */ 121 elf_end (mod->alt_elf); 122 mod->alt_elf = NULL; 123 close (fd); 124 fd = -1; 125 } 126 } 127 } 128 return valid; 129 } 130 131 /* If we have a build ID, check only that. */ 132 if (mod->build_id_len > 0) 133 { 134 /* We need to open an Elf handle on the file so we can check its 135 build ID note for validation. Backdoor the handle into the 136 module data structure since we had to open it early anyway. */ 137 138 mod->debug.valid = false; 139 Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false); 140 if (error != DWFL_E_NOERROR) 141 __libdwfl_seterrno (error); 142 else if (likely (__libdwfl_find_build_id (mod, false, 143 mod->debug.elf) == 2)) 144 /* Also backdoor the gratuitous flag. */ 145 mod->debug.valid = true; 146 else 147 { 148 /* A mismatch! */ 149 elf_end (mod->debug.elf); 150 mod->debug.elf = NULL; 151 close (fd); 152 fd = -1; 153 } 154 155 return mod->debug.valid; 156 } 157 158 return !check || check_crc (fd, debuglink_crc); 159 } 160 161 static int 162 find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name, 163 const char *debuglink_file, GElf_Word debuglink_crc, 164 char **debuginfo_file_name) 165 { 166 bool cancheck = debuglink_crc != (GElf_Word) 0; 167 168 const char *file_basename = file_name == NULL ? NULL : basename (file_name); 169 char *localname = NULL; 170 171 /* We invent a debuglink .debug name if NULL, but then want to try the 172 basename too. */ 173 bool debuglink_null = debuglink_file == NULL; 174 if (debuglink_null) 175 { 176 /* For a alt debug multi file we need a name, for a separate debug 177 name we may be able to fall back on file_basename.debug. */ 178 if (file_basename == NULL || mod->dw != NULL) 179 { 180 errno = 0; 181 return -1; 182 } 183 184 size_t len = strlen (file_basename); 185 localname = malloc (len + sizeof ".debug"); 186 if (unlikely (localname == NULL)) 187 return -1; 188 memcpy (localname, file_basename, len); 189 memcpy (&localname[len], ".debug", sizeof ".debug"); 190 debuglink_file = localname; 191 cancheck = false; 192 } 193 194 /* Look for a file named DEBUGLINK_FILE in the directories 195 indicated by the debug directory path setting. */ 196 197 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; 198 char *localpath = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) 199 ?: DEFAULT_DEBUGINFO_PATH); 200 if (unlikely (localpath == NULL)) 201 { 202 free (localname); 203 return -1; 204 } 205 206 /* A leading - or + in the whole path sets whether to check file CRCs. */ 207 bool defcheck = true; 208 char *path = localpath; 209 if (path[0] == '-' || path[0] == '+') 210 { 211 defcheck = path[0] == '+'; 212 ++path; 213 } 214 215 /* XXX dev/ino should be cached in struct dwfl_file. */ 216 struct stat main_stat; 217 if (unlikely ((mod->main.fd != -1 ? fstat (mod->main.fd, &main_stat) 218 : file_name != NULL ? stat (file_name, &main_stat) 219 : -1) < 0)) 220 { 221 main_stat.st_dev = 0; 222 main_stat.st_ino = 0; 223 } 224 225 char *file_dirname = (file_basename == file_name ? NULL 226 : strndup (file_name, file_basename - 1 - file_name)); 227 if (file_basename != file_name && file_dirname == NULL) 228 { 229 free (localpath); 230 free (localname); 231 return -1; 232 } 233 char *p; 234 while ((p = strsep (&path, ":")) != NULL) 235 { 236 /* A leading - or + says whether to check file CRCs for this element. */ 237 bool check = defcheck; 238 if (*p == '+' || *p == '-') 239 check = *p++ == '+'; 240 check = check && cancheck; 241 242 /* Try the basename too, if we made up the debuglink name and this 243 is not the main directory. */ 244 bool try_file_basename; 245 246 const char *dir, *subdir, *file; 247 switch (p[0]) 248 { 249 case '\0': 250 /* An empty entry says to try the main file's directory. */ 251 dir = file_dirname; 252 subdir = NULL; 253 file = debuglink_file; 254 try_file_basename = false; 255 break; 256 case '/': 257 /* An absolute path says to look there for a subdirectory 258 named by the main file's absolute directory. This cannot 259 be applied to a relative file name. For alt debug files 260 it means to look for the basename file in that dir or the 261 .dwz subdir (see below). */ 262 if (mod->dw == NULL 263 && (file_dirname == NULL || file_dirname[0] != '/')) 264 continue; 265 dir = p; 266 if (mod->dw == NULL) 267 { 268 subdir = file_dirname; 269 /* We want to explore all sub-subdirs. Chop off one slash 270 at a time. */ 271 explore_dir: 272 subdir = strchr (subdir, '/'); 273 if (subdir != NULL) 274 subdir = subdir + 1; 275 if (subdir && *subdir == 0) 276 continue; 277 file = debuglink_file; 278 } 279 else 280 { 281 subdir = NULL; 282 file = basename (debuglink_file); 283 } 284 try_file_basename = debuglink_null; 285 break; 286 default: 287 /* A relative path says to try a subdirectory of that name 288 in the main file's directory. */ 289 dir = file_dirname; 290 subdir = p; 291 file = debuglink_file; 292 try_file_basename = debuglink_null; 293 break; 294 } 295 296 char *fname = NULL; 297 int fd = try_open (&main_stat, dir, subdir, file, &fname); 298 if (fd < 0 && try_file_basename) 299 fd = try_open (&main_stat, dir, subdir, file_basename, &fname); 300 if (fd < 0) 301 switch (errno) 302 { 303 case ENOENT: 304 case ENOTDIR: 305 /* If we are looking for the alt file also try the .dwz subdir. 306 But only if this is the empty or absolute path. */ 307 if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/')) 308 { 309 fd = try_open (&main_stat, dir, ".dwz", 310 basename (file), &fname); 311 if (fd < 0) 312 { 313 if (errno != ENOENT && errno != ENOTDIR) 314 goto fail_free; 315 else 316 continue; 317 } 318 break; 319 } 320 /* If possible try again with a sub-subdir. */ 321 if (mod->dw == NULL && subdir) 322 goto explore_dir; 323 continue; 324 default: 325 goto fail_free; 326 } 327 if (validate (mod, fd, check, debuglink_crc)) 328 { 329 free (localpath); 330 free (localname); 331 free (file_dirname); 332 *debuginfo_file_name = fname; 333 return fd; 334 } 335 free (fname); 336 close (fd); 337 } 338 339 /* No dice. */ 340 errno = 0; 341 fail_free: 342 free (localpath); 343 free (localname); 344 free (file_dirname); 345 return -1; 346 } 347 348 int 349 dwfl_standard_find_debuginfo (Dwfl_Module *mod, 350 void **userdata __attribute__ ((unused)), 351 const char *modname __attribute__ ((unused)), 352 GElf_Addr base __attribute__ ((unused)), 353 const char *file_name, 354 const char *debuglink_file, 355 GElf_Word debuglink_crc, 356 char **debuginfo_file_name) 357 { 358 /* First try by build ID if we have one. If that succeeds or fails 359 other than just by finding nothing, that's all we do. */ 360 const unsigned char *bits; 361 GElf_Addr vaddr; 362 if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0) 363 { 364 /* Dropping most arguments means we cannot rely on them in 365 dwfl_build_id_find_debuginfo. But leave it that way since 366 some user code out there also does this, so we'll have to 367 handle it anyway. */ 368 int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod, 369 NULL, NULL, 0, 370 NULL, NULL, 0, 371 debuginfo_file_name); 372 373 /* Did the build_id callback find something or report an error? 374 Then we are done. Otherwise fallback on path based search. */ 375 if (fd >= 0 376 || (mod->dw == NULL && mod->debug.elf != NULL) 377 || (mod->dw != NULL && mod->alt_elf != NULL) 378 || errno != 0) 379 return fd; 380 } 381 382 /* Failing that, search the path by name. */ 383 int fd = find_debuginfo_in_path (mod, file_name, 384 debuglink_file, debuglink_crc, 385 debuginfo_file_name); 386 387 if (fd < 0 && errno == 0 && file_name != NULL) 388 { 389 /* If FILE_NAME is a symlink, the debug file might be associated 390 with the symlink target name instead. */ 391 392 char *canon = realpath (file_name, NULL); 393 if (canon != NULL && strcmp (file_name, canon)) 394 fd = find_debuginfo_in_path (mod, canon, 395 debuglink_file, debuglink_crc, 396 debuginfo_file_name); 397 free (canon); 398 } 399 400 return fd; 401 } 402 INTDEF (dwfl_standard_find_debuginfo) 403