1 /* Standard find_debuginfo callback for libdwfl.
2 Copyright (C) 2005-2010, 2014, 2015 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
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. */
40 try_open (const struct stat *main_stat,
41 const char *dir, const char *subdir, const char *debuglink,
42 char **debuginfo_file_name)
45 if (dir == NULL && subdir == NULL)
47 fname = strdup (debuglink);
48 if (unlikely (fname == NULL))
51 else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
52 : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
53 : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
57 int fd = TEMP_FAILURE_RETRY (open (fname, O_RDONLY));
60 else if (fstat (fd, &st) == 0
61 && st.st_ino == main_stat->st_ino
62 && st.st_dev == main_stat->st_dev)
64 /* This is the main file by another name. Don't look at it again. */
71 *debuginfo_file_name = fname;
76 /* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
78 check_crc (int fd, GElf_Word debuglink_crc)
81 return (__libdwfl_crc32_file (fd, &file_crc) == 0
82 && file_crc == debuglink_crc);
86 validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
88 /* For alt debug files always check the build-id from the Dwarf and alt. */
94 ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
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 Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
104 if (error != DWFL_E_NOERROR)
105 __libdwfl_seterrno (error);
108 const void *alt_build_id;
109 ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
111 if (alt_len > 0 && alt_len == build_id_len
112 && memcmp (build_id, alt_build_id, alt_len) == 0)
117 elf_end (mod->alt_elf);
127 /* If we have a build ID, check only that. */
128 if (mod->build_id_len > 0)
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. */
134 mod->debug.valid = false;
135 Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
136 if (error != DWFL_E_NOERROR)
137 __libdwfl_seterrno (error);
138 else if (likely (__libdwfl_find_build_id (mod, false,
139 mod->debug.elf) == 2))
140 /* Also backdoor the gratuitous flag. */
141 mod->debug.valid = true;
145 elf_end (mod->debug.elf);
146 mod->debug.elf = NULL;
151 return mod->debug.valid;
154 return !check || check_crc (fd, debuglink_crc);
158 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)
162 bool cancheck = debuglink_crc != (GElf_Word) 0;
164 const char *file_basename = file_name == NULL ? NULL : basename (file_name);
165 char *localname = NULL;
166 if (debuglink_file == NULL)
168 /* For a alt debug multi file we need a name, for a separate debug
169 name we may be able to fall back on file_basename.debug. */
170 if (file_basename == NULL || mod->dw != NULL)
176 size_t len = strlen (file_basename);
177 localname = malloc (len + sizeof ".debug");
178 if (unlikely (localname == NULL))
180 memcpy (localname, file_basename, len);
181 memcpy (&localname[len], ".debug", sizeof ".debug");
182 debuglink_file = localname;
186 /* Look for a file named DEBUGLINK_FILE in the directories
187 indicated by the debug directory path setting. */
189 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
190 char *localpath = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
191 ?: DEFAULT_DEBUGINFO_PATH);
192 if (unlikely (localpath == NULL))
198 /* A leading - or + in the whole path sets whether to check file CRCs. */
199 bool defcheck = true;
200 char *path = localpath;
201 if (path[0] == '-' || path[0] == '+')
203 defcheck = path[0] == '+';
207 /* XXX dev/ino should be cached in struct dwfl_file. */
208 struct stat main_stat;
209 if (unlikely ((mod->main.fd != -1 ? fstat (mod->main.fd, &main_stat)
210 : file_name != NULL ? stat (file_name, &main_stat)
213 main_stat.st_dev = 0;
214 main_stat.st_ino = 0;
217 char *file_dirname = (file_basename == file_name ? NULL
218 : strndup (file_name, file_basename - 1 - file_name));
219 if (file_basename != file_name && file_dirname == NULL)
226 while ((p = strsep (&path, ":")) != NULL)
228 /* A leading - or + says whether to check file CRCs for this element. */
229 bool check = defcheck;
230 if (*p == '+' || *p == '-')
232 check = check && cancheck;
234 const char *dir, *subdir, *file;
238 /* An empty entry says to try the main file's directory. */
241 file = debuglink_file;
244 /* An absolute path says to look there for a subdirectory
245 named by the main file's absolute directory. This cannot
246 be applied to a relative file name. For alt debug files
247 it means to look for the basename file in that dir or the
248 .dwz subdir (see below). */
250 && (file_dirname == NULL || file_dirname[0] != '/'))
255 subdir = file_dirname;
256 /* We want to explore all sub-subdirs. Chop off one slash
259 subdir = strchr (subdir, '/');
262 if (subdir && *subdir == 0)
264 file = debuglink_file;
269 file = basename (debuglink_file);
273 /* A relative path says to try a subdirectory of that name
274 in the main file's directory. */
277 file = debuglink_file;
282 int fd = try_open (&main_stat, dir, subdir, file, &fname);
288 /* If we are looking for the alt file also try the .dwz subdir.
289 But only if this is the empty or absolute path. */
290 if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
292 fd = try_open (&main_stat, dir, ".dwz",
293 basename (file), &fname);
296 if (errno != ENOENT && errno != ENOTDIR)
303 /* If possible try again with a sub-subdir. */
304 if (mod->dw == NULL && subdir)
310 if (validate (mod, fd, check, debuglink_crc))
315 *debuginfo_file_name = fname;
332 dwfl_standard_find_debuginfo (Dwfl_Module *mod,
333 void **userdata __attribute__ ((unused)),
334 const char *modname __attribute__ ((unused)),
335 GElf_Addr base __attribute__ ((unused)),
336 const char *file_name,
337 const char *debuglink_file,
338 GElf_Word debuglink_crc,
339 char **debuginfo_file_name)
341 /* First try by build ID if we have one. If that succeeds or fails
342 other than just by finding nothing, that's all we do. */
343 const unsigned char *bits;
345 if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
347 /* Dropping most arguments means we cannot rely on them in
348 dwfl_build_id_find_debuginfo. But leave it that way since
349 some user code out there also does this, so we'll have to
351 int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
354 debuginfo_file_name);
356 /* Did the build_id callback find something or report an error?
357 Then we are done. Otherwise fallback on path based search. */
359 || (mod->dw == NULL && mod->debug.elf != NULL)
360 || (mod->dw != NULL && mod->alt_elf != NULL)
365 /* Failing that, search the path by name. */
366 int fd = find_debuginfo_in_path (mod, file_name,
367 debuglink_file, debuglink_crc,
368 debuginfo_file_name);
370 if (fd < 0 && errno == 0 && file_name != NULL)
372 /* If FILE_NAME is a symlink, the debug file might be associated
373 with the symlink target name instead. */
375 char *canon = canonicalize_file_name (file_name);
376 if (canon != NULL && strcmp (file_name, canon))
377 fd = find_debuginfo_in_path (mod, canon,
378 debuglink_file, debuglink_crc,
379 debuginfo_file_name);
385 INTDEF (dwfl_standard_find_debuginfo)