1 /* Standard find_debuginfo callback for libdwfl.
2 Copyright (C) 2005-2010, 2014 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 open64 [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 stat64 *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 (open64 (fname, O_RDONLY));
60 else if (fstat64 (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. */
70 *debuginfo_file_name = fname;
75 /* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
77 check_crc (int fd, GElf_Word debuglink_crc)
80 return (__libdwfl_crc32_file (fd, &file_crc) == 0
81 && file_crc == debuglink_crc);
85 validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
87 /* For alt debug files always check the build-id from the Dwarf and alt. */
93 ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
98 /* We need to open an Elf handle on the file so we can check its
99 build ID note for validation. Backdoor the handle into the
100 module data structure since we had to open it early anyway. */
101 Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
103 if (error != DWFL_E_NOERROR)
104 __libdwfl_seterrno (error);
107 const void *alt_build_id;
108 ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
110 if (alt_len > 0 && alt_len == build_id_len
111 && memcmp (build_id, alt_build_id, alt_len) == 0)
116 elf_end (mod->alt_elf);
126 /* If we have a build ID, check only that. */
127 if (mod->build_id_len > 0)
129 /* We need to open an Elf handle on the file so we can check its
130 build ID note for validation. Backdoor the handle into the
131 module data structure since we had to open it early anyway. */
133 mod->debug.valid = false;
134 Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
135 if (error != DWFL_E_NOERROR)
136 __libdwfl_seterrno (error);
137 else if (likely (__libdwfl_find_build_id (mod, false,
138 mod->debug.elf) == 2))
139 /* Also backdoor the gratuitous flag. */
140 mod->debug.valid = true;
144 elf_end (mod->debug.elf);
145 mod->debug.elf = NULL;
150 return mod->debug.valid;
153 return !check || check_crc (fd, debuglink_crc);
157 find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
158 const char *debuglink_file, GElf_Word debuglink_crc,
159 char **debuginfo_file_name)
161 bool cancheck = debuglink_crc != (GElf_Word) 0;
163 const char *file_basename = file_name == NULL ? NULL : basename (file_name);
164 char *localname = NULL;
165 if (debuglink_file == NULL)
167 /* For a alt debug multi file we need a name, for a separate debug
168 name we may be able to fall back on file_basename.debug. */
169 if (file_basename == NULL || mod->dw != NULL)
175 size_t len = strlen (file_basename);
176 localname = malloc (len + sizeof ".debug");
177 if (unlikely (localname == NULL))
179 memcpy (localname, file_basename, len);
180 memcpy (&localname[len], ".debug", sizeof ".debug");
181 debuglink_file = localname;
185 /* Look for a file named DEBUGLINK_FILE in the directories
186 indicated by the debug directory path setting. */
188 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
189 char *localpath = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
190 ?: DEFAULT_DEBUGINFO_PATH);
191 if (unlikely (localpath == NULL))
197 /* A leading - or + in the whole path sets whether to check file CRCs. */
198 bool defcheck = true;
199 char *path = localpath;
200 if (path[0] == '-' || path[0] == '+')
202 defcheck = path[0] == '+';
206 /* XXX dev/ino should be cached in struct dwfl_file. */
207 struct stat64 main_stat;
208 if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat)
209 : file_name != NULL ? stat64 (file_name, &main_stat)
212 main_stat.st_dev = 0;
213 main_stat.st_ino = 0;
216 char *file_dirname = (file_basename == file_name ? NULL
217 : strndup (file_name, file_basename - 1 - file_name));
218 if (file_basename != file_name && file_dirname == NULL)
225 while ((p = strsep (&path, ":")) != NULL)
227 /* A leading - or + says whether to check file CRCs for this element. */
228 bool check = defcheck;
229 if (*p == '+' || *p == '-')
231 check = check && cancheck;
233 const char *dir, *subdir, *file;
237 /* An empty entry says to try the main file's directory. */
240 file = debuglink_file;
243 /* An absolute path says to look there for a subdirectory
244 named by the main file's absolute directory. This cannot
245 be applied to a relative file name. For alt debug files
246 it means to look for the basename file in that dir or the
247 .dwz subdir (see below). */
249 && (file_dirname == NULL || file_dirname[0] != '/'))
254 subdir = file_dirname + 1;
255 file = debuglink_file;
260 file = basename (debuglink_file);
264 /* A relative path says to try a subdirectory of that name
265 in the main file's directory. */
268 file = debuglink_file;
273 int fd = try_open (&main_stat, dir, subdir, file, &fname);
279 /* If we are looking for the alt file also try the .dwz subdir.
280 But only if this is the empty or absolute path. */
281 if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
283 fd = try_open (&main_stat, dir, ".dwz",
284 basename (file), &fname);
287 if (errno != ENOENT && errno != ENOTDIR)
307 if (validate (mod, fd, check, debuglink_crc))
309 *debuginfo_file_name = fname;
322 dwfl_standard_find_debuginfo (Dwfl_Module *mod,
323 void **userdata __attribute__ ((unused)),
324 const char *modname __attribute__ ((unused)),
325 GElf_Addr base __attribute__ ((unused)),
326 const char *file_name,
327 const char *debuglink_file,
328 GElf_Word debuglink_crc,
329 char **debuginfo_file_name)
331 /* First try by build ID if we have one. If that succeeds or fails
332 other than just by finding nothing, that's all we do. */
333 const unsigned char *bits;
335 if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
337 /* Dropping most arguments means we cannot rely on them in
338 dwfl_build_id_find_debuginfo. But leave it that way since
339 some user code out there also does this, so we'll have to
341 int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
344 debuginfo_file_name);
346 /* Did the build_id callback find something or report an error?
347 Then we are done. Otherwise fallback on path based search. */
349 || (mod->dw == NULL && mod->debug.elf != NULL)
350 || (mod->dw != NULL && mod->alt_elf != NULL)
355 /* Failing that, search the path by name. */
356 int fd = find_debuginfo_in_path (mod, file_name,
357 debuglink_file, debuglink_crc,
358 debuginfo_file_name);
360 if (fd < 0 && errno == 0)
362 /* If FILE_NAME is a symlink, the debug file might be associated
363 with the symlink target name instead. */
365 char *canon = canonicalize_file_name (file_name);
366 if (canon != NULL && strcmp (file_name, canon))
367 fd = find_debuginfo_in_path (mod, canon,
368 debuglink_file, debuglink_crc,
369 debuginfo_file_name);
375 INTDEF (dwfl_standard_find_debuginfo)