Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 1 | /* Find an ELF file for a module from its build ID. |
Roland McGrath | ed431dd | 2010-05-06 00:52:51 -0700 | [diff] [blame] | 2 | Copyright (C) 2007-2010 Red Hat, Inc. |
Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 3 | This file is part of elfutils. |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 4 | |
Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 5 | This file is free software; you can redistribute it and/or modify |
| 6 | it under the terms of either |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 7 | |
Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 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 |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 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 | |
Mark Wielaard | de2ed97 | 2012-06-05 17:15:16 +0200 | [diff] [blame] | 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/>. */ |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 28 | |
| 29 | #include "libdwflP.h" |
| 30 | #include <inttypes.h> |
| 31 | #include <fcntl.h> |
| 32 | #include <unistd.h> |
| 33 | |
| 34 | |
| 35 | int |
| 36 | internal_function |
| 37 | __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name) |
| 38 | { |
Roland McGrath | 059c83e | 2008-02-21 06:19:39 +0000 | [diff] [blame] | 39 | /* If *FILE_NAME was primed into the module, leave it there |
| 40 | as the fallback when we have nothing to offer. */ |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 41 | errno = 0; |
| 42 | if (mod->build_id_len <= 0) |
| 43 | return -1; |
| 44 | |
| 45 | const size_t id_len = mod->build_id_len; |
| 46 | const uint8_t *id = mod->build_id_bits; |
| 47 | |
| 48 | /* Search debuginfo_path directories' .build-id/ subdirectories. */ |
| 49 | |
| 50 | char id_name[sizeof "/.build-id/" + 1 + id_len * 2 + sizeof ".debug" - 1]; |
| 51 | strcpy (id_name, "/.build-id/"); |
| 52 | int n = snprintf (&id_name[sizeof "/.build-id/" - 1], |
| 53 | 4, "%02" PRIx8 "/", (uint8_t) id[0]); |
| 54 | assert (n == 3); |
| 55 | for (size_t i = 1; i < id_len; ++i) |
| 56 | { |
| 57 | n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2], |
| 58 | 3, "%02" PRIx8, (uint8_t) id[i]); |
| 59 | assert (n == 2); |
| 60 | } |
| 61 | if (debug) |
| 62 | strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2], |
| 63 | ".debug"); |
| 64 | |
| 65 | const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; |
| 66 | char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL) |
| 67 | ?: DEFAULT_DEBUGINFO_PATH); |
| 68 | |
| 69 | int fd = -1; |
| 70 | char *dir; |
| 71 | while (fd < 0 && (dir = strsep (&path, ":")) != NULL) |
| 72 | { |
| 73 | if (dir[0] == '+' || dir[0] == '-') |
| 74 | ++dir; |
| 75 | |
| 76 | /* Only absolute directory names are useful to us. */ |
| 77 | if (dir[0] != '/') |
| 78 | continue; |
| 79 | |
| 80 | size_t dirlen = strlen (dir); |
| 81 | char *name = malloc (dirlen + sizeof id_name); |
| 82 | if (unlikely (name == NULL)) |
| 83 | break; |
| 84 | memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name); |
| 85 | |
| 86 | fd = TEMP_FAILURE_RETRY (open64 (name, O_RDONLY)); |
| 87 | if (fd >= 0) |
| 88 | { |
| 89 | if (*file_name != NULL) |
| 90 | free (*file_name); |
| 91 | *file_name = canonicalize_file_name (name); |
| 92 | if (*file_name == NULL) |
| 93 | { |
| 94 | *file_name = name; |
| 95 | name = NULL; |
| 96 | } |
| 97 | } |
| 98 | free (name); |
| 99 | } |
| 100 | |
Roland McGrath | 1d8bb25 | 2008-08-07 08:39:41 +0000 | [diff] [blame] | 101 | /* If we simply found nothing, clear errno. If we had some other error |
| 102 | with the file, report that. Possibly this should treat other errors |
| 103 | like ENOENT too. But ignoring all errors could mask some that should |
| 104 | be reported. */ |
| 105 | if (fd < 0 && errno == ENOENT) |
| 106 | errno = 0; |
| 107 | |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 108 | return fd; |
| 109 | } |
| 110 | |
| 111 | int |
| 112 | dwfl_build_id_find_elf (Dwfl_Module *mod, |
| 113 | void **userdata __attribute__ ((unused)), |
| 114 | const char *modname __attribute__ ((unused)), |
| 115 | Dwarf_Addr base __attribute__ ((unused)), |
| 116 | char **file_name, Elf **elfp) |
| 117 | { |
| 118 | *elfp = NULL; |
| 119 | int fd = __libdwfl_open_by_build_id (mod, false, file_name); |
| 120 | if (fd >= 0) |
| 121 | { |
Roland McGrath | bca4315 | 2009-01-05 23:59:32 -0800 | [diff] [blame] | 122 | Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false); |
| 123 | if (error != DWFL_E_NOERROR) |
| 124 | __libdwfl_seterrno (error); |
| 125 | else if (__libdwfl_find_build_id (mod, false, *elfp) == 2) |
| 126 | { |
| 127 | /* This is a backdoor signal to short-circuit the ID refresh. */ |
| 128 | mod->main.valid = true; |
| 129 | return fd; |
| 130 | } |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 131 | else |
| 132 | { |
| 133 | /* This file does not contain the ID it should! */ |
| 134 | elf_end (*elfp); |
| 135 | *elfp = NULL; |
| 136 | close (fd); |
| 137 | fd = -1; |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 138 | } |
Roland McGrath | bca4315 | 2009-01-05 23:59:32 -0800 | [diff] [blame] | 139 | free (*file_name); |
| 140 | *file_name = NULL; |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 141 | } |
Roland McGrath | ed431dd | 2010-05-06 00:52:51 -0700 | [diff] [blame] | 142 | else if (errno == 0 && mod->build_id_len > 0) |
| 143 | /* Setting this with no file yet loaded is a marker that |
| 144 | the build ID is authoritative even if we also know a |
| 145 | putative *FILE_NAME. */ |
| 146 | mod->main.valid = true; |
| 147 | |
Roland McGrath | 59ea7f3 | 2007-10-04 08:50:09 +0000 | [diff] [blame] | 148 | return fd; |
| 149 | } |
| 150 | INTDEF (dwfl_build_id_find_elf) |