Line data Source code
1 : /* Standard find_debuginfo callback for libdwfl.
2 : Copyright (C) 2005-2010, 2014, 2015, 2019 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 0 : try_open (const struct stat *main_stat,
45 : const char *dir, const char *subdir, const char *debuglink,
46 : char **debuginfo_file_name)
47 : {
48 0 : char *fname;
49 0 : if (dir == NULL && subdir == NULL)
50 : {
51 0 : fname = strdup (debuglink);
52 0 : if (unlikely (fname == NULL))
53 0 : return -1;
54 : }
55 0 : else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
56 0 : : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
57 0 : : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
58 0 : return -1;
59 :
60 0 : struct stat st;
61 0 : int fd = TEMP_FAILURE_RETRY (open (fname, O_RDONLY));
62 0 : if (fd < 0)
63 0 : free (fname);
64 0 : else if (fstat (fd, &st) == 0
65 0 : && st.st_ino == main_stat->st_ino
66 0 : && st.st_dev == main_stat->st_dev)
67 : {
68 : /* This is the main file by another name. Don't look at it again. */
69 0 : free (fname);
70 0 : close (fd);
71 0 : errno = ENOENT;
72 0 : fd = -1;
73 : }
74 : else
75 0 : *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 1 : uint32_t file_crc;
85 1 : return (__libdwfl_crc32_file (fd, &file_crc) == 0
86 1 : && file_crc == debuglink_crc);
87 : }
88 :
89 : static bool
90 39 : 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 39 : if (mod->dw != NULL)
94 : {
95 9 : bool valid = false;
96 9 : const void *build_id;
97 9 : const char *altname;
98 9 : ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
99 : &altname,
100 : &build_id);
101 9 : 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 9 : Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
107 : false, false);
108 9 : if (error != DWFL_E_NOERROR)
109 0 : __libdwfl_seterrno (error);
110 : else
111 : {
112 9 : const void *alt_build_id;
113 9 : ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
114 : &alt_build_id);
115 9 : if (alt_len > 0 && alt_len == build_id_len
116 9 : && memcmp (build_id, alt_build_id, alt_len) == 0)
117 : valid = true;
118 : else
119 : {
120 : /* A mismatch! */
121 0 : elf_end (mod->alt_elf);
122 0 : mod->alt_elf = NULL;
123 0 : close (fd);
124 0 : fd = -1;
125 : }
126 : }
127 : }
128 9 : return valid;
129 : }
130 :
131 : /* If we have a build ID, check only that. */
132 30 : 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 29 : mod->debug.valid = false;
139 29 : Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
140 29 : if (error != DWFL_E_NOERROR)
141 0 : __libdwfl_seterrno (error);
142 29 : else if (likely (__libdwfl_find_build_id (mod, false,
143 : mod->debug.elf) == 2))
144 : /* Also backdoor the gratuitous flag. */
145 29 : mod->debug.valid = true;
146 : else
147 : {
148 : /* A mismatch! */
149 0 : elf_end (mod->debug.elf);
150 0 : mod->debug.elf = NULL;
151 0 : close (fd);
152 0 : fd = -1;
153 : }
154 :
155 29 : return mod->debug.valid;
156 : }
157 :
158 3 : return !check || check_crc (fd, debuglink_crc);
159 : }
160 :
161 : static int
162 145 : 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 145 : bool cancheck = debuglink_crc != (GElf_Word) 0;
167 :
168 145 : const char *file_basename = file_name == NULL ? NULL : basename (file_name);
169 145 : char *localname = NULL;
170 :
171 : /* We invent a debuglink .debug name if NULL, but then want to try the
172 : basename too. */
173 145 : bool debuglink_null = debuglink_file == NULL;
174 145 : 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 96 : if (file_basename == NULL || mod->dw != NULL)
179 : {
180 22 : errno = 0;
181 22 : return -1;
182 : }
183 :
184 74 : size_t len = strlen (file_basename);
185 74 : localname = malloc (len + sizeof ".debug");
186 74 : if (unlikely (localname == NULL))
187 : return -1;
188 74 : memcpy (localname, file_basename, len);
189 74 : memcpy (&localname[len], ".debug", sizeof ".debug");
190 74 : debuglink_file = localname;
191 74 : 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 123 : const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
198 123 : char *localpath = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
199 : ?: DEFAULT_DEBUGINFO_PATH);
200 123 : if (unlikely (localpath == NULL))
201 : {
202 0 : free (localname);
203 0 : return -1;
204 : }
205 :
206 : /* A leading - or + in the whole path sets whether to check file CRCs. */
207 123 : bool defcheck = true;
208 123 : char *path = localpath;
209 123 : if (path[0] == '-' || path[0] == '+')
210 : {
211 0 : defcheck = path[0] == '+';
212 0 : ++path;
213 : }
214 :
215 : /* XXX dev/ino should be cached in struct dwfl_file. */
216 123 : struct stat main_stat;
217 123 : 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 0 : main_stat.st_dev = 0;
222 0 : main_stat.st_ino = 0;
223 : }
224 :
225 246 : char *file_dirname = (file_basename == file_name ? NULL
226 123 : : strndup (file_name, file_basename - 1 - file_name));
227 123 : if (file_basename != file_name && file_dirname == NULL)
228 : {
229 0 : free (localpath);
230 0 : free (localname);
231 0 : return -1;
232 : }
233 : char *p;
234 375 : while ((p = strsep (&path, ":")) != NULL)
235 : {
236 : /* A leading - or + says whether to check file CRCs for this element. */
237 291 : bool check = defcheck;
238 291 : if (*p == '+' || *p == '-')
239 0 : check = *p++ == '+';
240 291 : 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 291 : bool try_file_basename;
245 :
246 291 : const char *dir, *subdir, *file;
247 291 : 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 85 : 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 85 : if (mod->dw == NULL
263 81 : && (file_dirname == NULL || file_dirname[0] != '/'))
264 252 : continue;
265 49 : dir = p;
266 49 : 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 338 : explore_dir:
272 338 : subdir = strchr (subdir, '/');
273 338 : if (subdir != NULL)
274 214 : subdir = subdir + 1;
275 338 : if (subdir && *subdir == 0)
276 : continue;
277 : file = debuglink_file;
278 : }
279 : else
280 : {
281 4 : subdir = NULL;
282 4 : file = basename (debuglink_file);
283 : }
284 : try_file_basename = debuglink_null;
285 : break;
286 84 : default:
287 : /* A relative path says to try a subdirectory of that name
288 : in the main file's directory. */
289 84 : dir = file_dirname;
290 84 : subdir = p;
291 84 : file = debuglink_file;
292 84 : try_file_basename = debuglink_null;
293 84 : break;
294 : }
295 :
296 548 : char *fname = NULL;
297 548 : int fd = try_open (&main_stat, dir, subdir, file, &fname);
298 548 : if (fd < 0 && try_file_basename)
299 372 : fd = try_open (&main_stat, dir, subdir, file_basename, &fname);
300 548 : if (fd < 0)
301 511 : switch (errno)
302 : {
303 511 : 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 511 : if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
308 : {
309 10 : fd = try_open (&main_stat, dir, ".dwz",
310 10 : basename (file), &fname);
311 10 : if (fd < 0)
312 : {
313 8 : if (errno != ENOENT && errno != ENOTDIR)
314 0 : goto fail_free;
315 : else
316 : continue;
317 : }
318 : break;
319 : }
320 : /* If possible try again with a sub-subdir. */
321 501 : if (mod->dw == NULL && subdir)
322 : goto explore_dir;
323 : continue;
324 : default:
325 : goto fail_free;
326 : }
327 39 : if (validate (mod, fd, check, debuglink_crc))
328 : {
329 39 : free (localpath);
330 39 : free (localname);
331 39 : free (file_dirname);
332 39 : *debuginfo_file_name = fname;
333 39 : return fd;
334 : }
335 0 : free (fname);
336 0 : close (fd);
337 : }
338 :
339 : /* No dice. */
340 84 : errno = 0;
341 84 : fail_free:
342 84 : free (localpath);
343 84 : free (localname);
344 84 : free (file_dirname);
345 84 : return -1;
346 : }
347 :
348 : int
349 115 : 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 115 : const unsigned char *bits;
361 115 : GElf_Addr vaddr;
362 115 : int bits_len;
363 115 : if ((bits_len = INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr)) > 0)
364 : {
365 : /* Dropping most arguments means we cannot rely on them in
366 : dwfl_build_id_find_debuginfo. But leave it that way since
367 : some user code out there also does this, so we'll have to
368 : handle it anyway. */
369 104 : int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
370 : NULL, NULL, 0,
371 : NULL, NULL, 0,
372 : debuginfo_file_name);
373 :
374 : /* Did the build_id callback find something or report an error?
375 : Then we are done. Otherwise fallback on path based search. */
376 104 : if (fd >= 0
377 95 : || (mod->dw == NULL && mod->debug.elf != NULL)
378 95 : || (mod->dw != NULL && mod->alt_elf != NULL)
379 95 : || errno != 0)
380 : return fd;
381 : }
382 :
383 : /* Failing that, search the path by name. */
384 106 : int fd = find_debuginfo_in_path (mod, file_name,
385 : debuglink_file, debuglink_crc,
386 : debuginfo_file_name);
387 :
388 106 : if (fd < 0 && errno == 0 && file_name != NULL)
389 : {
390 : /* If FILE_NAME is a symlink, the debug file might be associated
391 : with the symlink target name instead. */
392 :
393 47 : char *canon = realpath (file_name, NULL);
394 47 : if (canon != NULL && strcmp (file_name, canon))
395 39 : fd = find_debuginfo_in_path (mod, canon,
396 : debuglink_file, debuglink_crc,
397 : debuginfo_file_name);
398 47 : free (canon);
399 : }
400 :
401 106 : if (fd < 0 && bits_len > 0)
402 57 : fd = __libdwfl_debuginfod_find_debuginfo (mod->dwfl, bits, bits_len);
403 :
404 : return fd;
405 : }
406 : INTDEF (dwfl_standard_find_debuginfo)
|