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