blob: 3f5314ad99544ea6bf735d24fdcd6b1f6b610358 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Standard find_debuginfo callback for libdwfl.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2005-2010, 2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004
Elliott Hughes03333822015-02-18 22:19:45 -08005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08007
Elliott Hughes03333822015-02-18 22:19:45 -08008 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080021 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
Elliott Hughes03333822015-02-18 22:19:45 -080025 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080028
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 open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
38 On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */
39static int
40try_open (const struct stat64 *main_stat,
41 const char *dir, const char *subdir, const char *debuglink,
42 char **debuginfo_file_name)
43{
44 char *fname;
45 if (dir == NULL && subdir == NULL)
46 {
47 fname = strdup (debuglink);
48 if (fname == NULL)
49 return -1;
50 }
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)
54 return -1;
55
56 struct stat64 st;
57 int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
58 if (fd < 0)
59 free (fname);
60 else if (fstat64 (fd, &st) == 0
61 && st.st_ino == main_stat->st_ino
62 && st.st_dev == main_stat->st_dev)
63 {
64 /* This is the main file by another name. Don't look at it again. */
65 close (fd);
66 errno = ENOENT;
67 fd = -1;
68 }
69 else
70 *debuginfo_file_name = fname;
71
72 return fd;
73}
74
75/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC. */
76static inline bool
77check_crc (int fd, GElf_Word debuglink_crc)
78{
79 uint32_t file_crc;
80 return (__libdwfl_crc32_file (fd, &file_crc) == 0
81 && file_crc == debuglink_crc);
82}
83
84static bool
85validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
86{
Elliott Hughes03333822015-02-18 22:19:45 -080087 /* For alt debug files always check the build-id from the Dwarf and alt. */
88 if (mod->dw != NULL)
89 {
90 bool valid = false;
91 const void *build_id;
92 const char *altname;
93 ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
94 &altname,
95 &build_id);
96 if (build_id_len > 0)
97 {
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,
102 false, false);
103 if (error != DWFL_E_NOERROR)
104 __libdwfl_seterrno (error);
105 else
106 {
107 const void *alt_build_id;
108 ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
109 &alt_build_id);
110 if (alt_len > 0 && alt_len == build_id_len
111 && memcmp (build_id, alt_build_id, alt_len) == 0)
112 valid = true;
113 else
114 {
115 /* A mismatch! */
116 elf_end (mod->alt_elf);
117 mod->alt_elf = NULL;
118 close (fd);
119 fd = -1;
120 }
121 }
122 }
123 return valid;
124 }
125
Ben Cheng25b3c042013-11-20 14:45:36 -0800126 /* If we have a build ID, check only that. */
127 if (mod->build_id_len > 0)
128 {
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. */
132
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;
141 else
142 {
143 /* A mismatch! */
144 elf_end (mod->debug.elf);
145 mod->debug.elf = NULL;
146 close (fd);
147 fd = -1;
148 }
149
150 return mod->debug.valid;
151 }
152
153 return !check || check_crc (fd, debuglink_crc);
154}
155
156static int
157find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
158 const char *debuglink_file, GElf_Word debuglink_crc,
159 char **debuginfo_file_name)
160{
161 bool cancheck = debuglink_crc != (GElf_Word) 0;
162
163 const char *file_basename = file_name == NULL ? NULL : basename (file_name);
164 if (debuglink_file == NULL)
165 {
Elliott Hughes03333822015-02-18 22:19:45 -0800166 /* For a alt debug multi file we need a name, for a separate debug
167 name we may be able to fall back on file_basename.debug. */
168 if (file_basename == NULL || mod->dw != NULL)
Ben Cheng25b3c042013-11-20 14:45:36 -0800169 {
170 errno = 0;
171 return -1;
172 }
173
174 size_t len = strlen (file_basename);
175 char *localname = alloca (len + sizeof ".debug");
176 memcpy (localname, file_basename, len);
177 memcpy (&localname[len], ".debug", sizeof ".debug");
178 debuglink_file = localname;
179 cancheck = false;
180 }
181
182 /* Look for a file named DEBUGLINK_FILE in the directories
183 indicated by the debug directory path setting. */
184
185 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
186 char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
187 ?: DEFAULT_DEBUGINFO_PATH);
188
189 /* A leading - or + in the whole path sets whether to check file CRCs. */
190 bool defcheck = true;
191 if (path[0] == '-' || path[0] == '+')
192 {
193 defcheck = path[0] == '+';
194 ++path;
195 }
196
197 /* XXX dev/ino should be cached in struct dwfl_file. */
198 struct stat64 main_stat;
199 if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat)
200 : file_name != NULL ? stat64 (file_name, &main_stat)
201 : -1) < 0))
202 {
203 main_stat.st_dev = 0;
204 main_stat.st_ino = 0;
205 }
206
207 char *file_dirname = (file_basename == file_name ? NULL
208 : strndupa (file_name, file_basename - 1 - file_name));
209 char *p;
210 while ((p = strsep (&path, ":")) != NULL)
211 {
212 /* A leading - or + says whether to check file CRCs for this element. */
213 bool check = defcheck;
214 if (*p == '+' || *p == '-')
215 check = *p++ == '+';
216 check = check && cancheck;
217
Elliott Hughes03333822015-02-18 22:19:45 -0800218 const char *dir, *subdir, *file;
Ben Cheng25b3c042013-11-20 14:45:36 -0800219 switch (p[0])
220 {
221 case '\0':
222 /* An empty entry says to try the main file's directory. */
223 dir = file_dirname;
224 subdir = NULL;
Elliott Hughes03333822015-02-18 22:19:45 -0800225 file = debuglink_file;
Ben Cheng25b3c042013-11-20 14:45:36 -0800226 break;
227 case '/':
228 /* An absolute path says to look there for a subdirectory
Elliott Hughes03333822015-02-18 22:19:45 -0800229 named by the main file's absolute directory. This cannot
230 be applied to a relative file name. For alt debug files
231 it means to look for the basename file in that dir or the
232 .dwz subdir (see below). */
233 if (mod->dw == NULL
234 && (file_dirname == NULL || file_dirname[0] != '/'))
Ben Cheng25b3c042013-11-20 14:45:36 -0800235 continue;
236 dir = p;
Elliott Hughes03333822015-02-18 22:19:45 -0800237 if (mod->dw == NULL)
238 {
239 subdir = file_dirname + 1;
240 file = debuglink_file;
241 }
242 else
243 {
244 subdir = NULL;
245 file = basename (debuglink_file);
246 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800247 break;
248 default:
249 /* A relative path says to try a subdirectory of that name
250 in the main file's directory. */
251 dir = file_dirname;
252 subdir = p;
Elliott Hughes03333822015-02-18 22:19:45 -0800253 file = debuglink_file;
Ben Cheng25b3c042013-11-20 14:45:36 -0800254 break;
255 }
256
257 char *fname = NULL;
Elliott Hughes03333822015-02-18 22:19:45 -0800258 int fd = try_open (&main_stat, dir, subdir, file, &fname);
Ben Cheng25b3c042013-11-20 14:45:36 -0800259 if (fd < 0)
260 switch (errno)
261 {
262 case ENOENT:
263 case ENOTDIR:
Elliott Hughes03333822015-02-18 22:19:45 -0800264 /* If we are looking for the alt file also try the .dwz subdir.
265 But only if this is the empty or absolute path. */
266 if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
267 {
268 fd = try_open (&main_stat, dir, ".dwz",
269 basename (file), &fname);
270 if (fd < 0)
271 {
272 if (errno != ENOENT && errno != ENOTDIR)
273 return -1;
274 else
275 continue;
276 }
277 break;
278 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800279 continue;
280 default:
281 return -1;
282 }
283 if (validate (mod, fd, check, debuglink_crc))
284 {
285 *debuginfo_file_name = fname;
286 return fd;
287 }
288 free (fname);
289 close (fd);
290 }
291
292 /* No dice. */
293 errno = 0;
Ben Cheng25b3c042013-11-20 14:45:36 -0800294 return -1;
295}
296
297int
298dwfl_standard_find_debuginfo (Dwfl_Module *mod,
299 void **userdata __attribute__ ((unused)),
300 const char *modname __attribute__ ((unused)),
301 GElf_Addr base __attribute__ ((unused)),
302 const char *file_name,
303 const char *debuglink_file,
304 GElf_Word debuglink_crc,
305 char **debuginfo_file_name)
306{
307 /* First try by build ID if we have one. If that succeeds or fails
308 other than just by finding nothing, that's all we do. */
309 const unsigned char *bits;
310 GElf_Addr vaddr;
311 if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
312 {
Elliott Hughes03333822015-02-18 22:19:45 -0800313 /* Dropping most arguments means we cannot rely on them in
314 dwfl_build_id_find_debuginfo. But leave it that way since
315 some user code out there also does this, so we'll have to
316 handle it anyway. */
Ben Cheng25b3c042013-11-20 14:45:36 -0800317 int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
318 NULL, NULL, 0,
319 NULL, NULL, 0,
320 debuginfo_file_name);
Elliott Hughes03333822015-02-18 22:19:45 -0800321
322 /* Did the build_id callback find something or report an error?
323 Then we are done. Otherwise fallback on path based search. */
324 if (fd >= 0
325 || (mod->dw == NULL && mod->debug.elf != NULL)
326 || (mod->dw != NULL && mod->alt_elf != NULL)
327 || errno != 0)
Ben Cheng25b3c042013-11-20 14:45:36 -0800328 return fd;
329 }
330
331 /* Failing that, search the path by name. */
332 int fd = find_debuginfo_in_path (mod, file_name,
333 debuglink_file, debuglink_crc,
334 debuginfo_file_name);
335
336 if (fd < 0 && errno == 0)
337 {
338 /* If FILE_NAME is a symlink, the debug file might be associated
339 with the symlink target name instead. */
340
341 char *canon = canonicalize_file_name (file_name);
342 if (canon != NULL && strcmp (file_name, canon))
343 fd = find_debuginfo_in_path (mod, canon,
344 debuglink_file, debuglink_crc,
345 debuginfo_file_name);
346 free (canon);
347 }
348
349 return fd;
350}
351INTDEF (dwfl_standard_find_debuginfo)