Branch data Line data Source code
1 : : /* Retrieves the DWARF descriptor for debugaltlink data. 2 : : Copyright (C) 2014, 2018 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 "libdwP.h" 34 : : #include "libelfP.h" 35 : : #include "libdwelfP.h" 36 : : #include "system.h" 37 : : 38 : : #include <inttypes.h> 39 : : #include <fcntl.h> 40 : : #include <limits.h> 41 : : #include <stdlib.h> 42 : : #include <stdio.h> 43 : : #include <string.h> 44 : : #include <sys/types.h> 45 : : #include <sys/stat.h> 46 : : 47 : : 48 : : char * 49 : : internal_function 50 : 312 : __libdw_filepath (const char *debugdir, const char *dir, const char *file) 51 : : { 52 [ - + ]: 312 : if (file == NULL) 53 : : return NULL; 54 : : 55 [ + + ]: 312 : if (file[0] == '/') 56 : 20 : return strdup (file); 57 : : 58 [ + + + - ]: 292 : if (dir != NULL && dir[0] == '/') 59 : : { 60 : 2 : size_t dirlen = strlen (dir); 61 : 2 : size_t filelen = strlen (file); 62 : 2 : size_t len = dirlen + 1 + filelen + 1; 63 : 2 : char *path = malloc (len); 64 [ + - ]: 2 : if (path != NULL) 65 : : { 66 [ + - ]: 2 : char *c = mempcpy (path, dir, dirlen); 67 [ + - ]: 2 : if (dir[dirlen - 1] != '/') 68 : 2 : *c++ = '/'; 69 : 2 : mempcpy (c, file, filelen + 1); 70 : : } 71 : 2 : return path; 72 : : } 73 : : 74 [ + + ]: 290 : if (debugdir != NULL) 75 : : { 76 : 110 : size_t debugdirlen = strlen (debugdir); 77 [ - + ]: 110 : size_t dirlen = dir != NULL ? strlen (dir) : 0; 78 : 110 : size_t filelen = strlen (file); 79 : 110 : size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1; 80 : 110 : char *path = malloc (len); 81 [ - + ]: 110 : if (path != NULL) 82 : : { 83 [ - + ]: 110 : char *c = mempcpy (path, debugdir, debugdirlen); 84 [ - + ]: 110 : if (dirlen > 0) 85 : : { 86 [ # # ]: 0 : c = mempcpy (c, dir, dirlen); 87 [ # # ]: 0 : if (dir[dirlen - 1] != '/') 88 : 0 : *c++ = '/'; 89 : : } 90 : 110 : mempcpy (c, file, filelen + 1); 91 : 110 : return path; 92 : : } 93 : : } 94 : : 95 : : return NULL; 96 : : } 97 : : 98 : : static void 99 : 242 : find_debug_altlink (Dwarf *dbg) 100 : : { 101 : 242 : const char *altname; 102 : 242 : const void *build_id; 103 : 242 : ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (dbg, 104 : : &altname, 105 : : &build_id); 106 : : 107 : : /* Couldn't even get the debugaltlink. It probably doesn't exist. */ 108 [ + + ]: 242 : if (build_id_len <= 0) 109 : 38 : return; 110 : : 111 : 204 : const uint8_t *id = (const uint8_t *) build_id; 112 : 204 : size_t id_len = build_id_len; 113 : 204 : int fd = -1; 114 : : 115 : : /* We only look in the standard path. And relative to the dbg file. */ 116 : : #define DEBUGINFO_PATH "/usr/lib/debug" 117 : : 118 : : /* We don't handle very short or really large build-ids. We need at 119 : : at least 3 and allow for up to 64 (normally ids are 20 long). */ 120 : : #define MIN_BUILD_ID_BYTES 3 121 : : #define MAX_BUILD_ID_BYTES 64 122 [ + - ]: 204 : if (id_len >= MIN_BUILD_ID_BYTES && id_len <= MAX_BUILD_ID_BYTES) 123 : : { 124 : : /* Note sizeof a string literal includes the trailing zero. */ 125 : 204 : char id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1 126 : : + 2 + 1 + (MAX_BUILD_ID_BYTES - 1) * 2 + sizeof ".debug"]; 127 : 204 : sprintf (&id_path[0], "%s%s", DEBUGINFO_PATH, "/.build-id/"); 128 : 204 : sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1], 129 : 204 : "%02" PRIx8 "/", (uint8_t) id[0]); 130 [ + + ]: 4080 : for (size_t i = 1; i < id_len; ++i) 131 : 3876 : sprintf (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1 132 : 3876 : + 3 + (i - 1) * 2], "%02" PRIx8, (uint8_t) id[i]); 133 : 408 : strcpy (&id_path[sizeof DEBUGINFO_PATH - 1 + sizeof "/.build-id/" - 1 134 : 204 : + 3 + (id_len - 1) * 2], ".debug"); 135 : : 136 [ + - - + ]: 204 : fd = TEMP_FAILURE_RETRY (open (id_path, O_RDONLY)); 137 : : } 138 : : 139 : : /* Fall back on (possible relative) alt file path. */ 140 [ + - ]: 204 : if (fd < 0) 141 : : { 142 : 204 : char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname); 143 [ + + ]: 204 : if (altpath != NULL) 144 : : { 145 [ + + - + ]: 24 : fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY)); 146 : 24 : free (altpath); 147 : : } 148 : : } 149 : : 150 [ + + ]: 204 : if (fd >= 0) 151 : : { 152 : 4 : Dwarf *alt = dwarf_begin (fd, O_RDONLY); 153 [ + - ]: 4 : if (alt != NULL) 154 : : { 155 : 4 : dbg->alt_dwarf = alt; 156 : 4 : dbg->alt_fd = fd; 157 : : } 158 : : else 159 : 0 : close (fd); 160 : : } 161 : : } 162 : : 163 : : /* find_debug_altlink() modifies "dbg->alt_dwarf". 164 : : dwarf_getalt() reads "main->alt_dwarf". 165 : : Mutual exclusion is enforced to prevent a race. */ 166 : : 167 : : Dwarf * 168 : 786 : dwarf_getalt (Dwarf *main) 169 : : { 170 [ - + ]: 786 : if (main == NULL) 171 : : return NULL; 172 : : 173 : 786 : rwlock_wrlock(main->dwarf_lock); 174 : : 175 : : /* Only try once. */ 176 [ + + ]: 786 : if (main->alt_dwarf == (void *) -1) 177 : : { 178 : : rwlock_unlock (main->dwarf_lock); 179 : : return NULL; 180 : : } 181 : : 182 : : /* Assign result before releasing the lock. */ 183 : 490 : Dwarf *result; 184 : : 185 [ + + ]: 490 : if (main->alt_dwarf != NULL) 186 : : { 187 : : result = main->alt_dwarf; 188 : : rwlock_unlock (main->dwarf_lock); 189 : : return result; 190 : : } 191 : : 192 : 242 : find_debug_altlink (main); 193 : : 194 : : /* If we found nothing, make sure we don't try again. */ 195 [ + + ]: 242 : if (main->alt_dwarf == NULL) 196 : : { 197 : 238 : main->alt_dwarf = (void *) -1; 198 : 238 : rwlock_unlock (main->dwarf_lock); 199 : 238 : return NULL; 200 : : } 201 : : 202 : : result = main->alt_dwarf; 203 : : rwlock_unlock (main->dwarf_lock); 204 : : 205 : : return result; 206 : : } 207 : : INTDEF (dwarf_getalt)