blob: 21db91a406a3c384ea113b72abe62fd897c843ca [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Standard find_debuginfo callback for libdwfl.
Roland McGrathbf963472010-02-15 15:16:44 -08002 Copyright (C) 2005-2010 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000028
29#include "libdwflP.h"
30#include <stdio.h>
31#include <fcntl.h>
32#include <unistd.h>
Roland McGrathb9e85182010-06-14 12:45:25 -070033#include <sys/stat.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000034#include "system.h"
35
36
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000037/* 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
Roland McGrathb9e85182010-06-14 12:45:25 -070040try_open (const struct stat64 *main_stat,
41 const char *dir, const char *subdir, const char *debuglink,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000042 char **debuginfo_file_name)
43{
Roland McGrath44865b92007-01-11 05:06:16 +000044 char *fname;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000045 if (dir == NULL && subdir == NULL)
Roland McGrath44865b92007-01-11 05:06:16 +000046 {
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)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000054 return -1;
55
Roland McGrathb9e85182010-06-14 12:45:25 -070056 struct stat64 st;
Roland McGrathd17fac72005-08-23 08:20:21 +000057 int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000058 if (fd < 0)
59 free (fname);
Roland McGrathb9e85182010-06-14 12:45:25 -070060 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 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000069 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;
Ulrich Drepper18618fd2005-07-28 21:29:22 +000080 return (__libdwfl_crc32_file (fd, &file_crc) == 0
81 && file_crc == debuglink_crc);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000082}
83
Roland McGrath59ea7f32007-10-04 08:50:09 +000084static bool
85validate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
86{
87 /* If we have a build ID, check only that. */
88 if (mod->build_id_len > 0)
89 {
90 /* We need to open an Elf handle on the file so we can check its
91 build ID note for validation. Backdoor the handle into the
92 module data structure since we had to open it early anyway. */
Roland McGrathbca43152009-01-05 23:59:32 -080093
94 mod->debug.valid = false;
95 Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
96 if (error != DWFL_E_NOERROR)
97 __libdwfl_seterrno (error);
98 else if (likely (__libdwfl_find_build_id (mod, false,
99 mod->debug.elf) == 2))
Roland McGrathcedd2992010-06-30 01:06:45 -0700100 /* Also backdoor the gratuitous flag. */
101 mod->debug.valid = true;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000102 else
103 {
104 /* A mismatch! */
105 elf_end (mod->debug.elf);
106 mod->debug.elf = NULL;
Roland McGrathbca43152009-01-05 23:59:32 -0800107 close (fd);
108 fd = -1;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000109 }
110
111 return mod->debug.valid;
112 }
113
114 return !check || check_crc (fd, debuglink_crc);
115}
116
117static int
118find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
119 const char *debuglink_file, GElf_Word debuglink_crc,
120 char **debuginfo_file_name)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000121{
Roland McGrathd17fac72005-08-23 08:20:21 +0000122 bool cancheck = debuglink_crc != (GElf_Word) 0;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000123
124 const char *file_basename = file_name == NULL ? NULL : basename (file_name);
125 if (debuglink_file == NULL)
126 {
127 if (file_basename == NULL)
128 {
129 errno = 0;
130 return -1;
131 }
132
133 size_t len = strlen (file_basename);
134 char *localname = alloca (len + sizeof ".debug");
135 memcpy (localname, file_basename, len);
136 memcpy (&localname[len], ".debug", sizeof ".debug");
137 debuglink_file = localname;
138 cancheck = false;
139 }
140
141 /* Look for a file named DEBUGLINK_FILE in the directories
142 indicated by the debug directory path setting. */
143
144 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
145 char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
146 ?: DEFAULT_DEBUGINFO_PATH);
147
148 /* A leading - or + in the whole path sets whether to check file CRCs. */
149 bool defcheck = true;
150 if (path[0] == '-' || path[0] == '+')
151 {
152 defcheck = path[0] == '+';
153 ++path;
154 }
155
Roland McGrathb9e85182010-06-14 12:45:25 -0700156 /* XXX dev/ino should be cached in struct dwfl_file. */
157 struct stat64 main_stat;
158 if (unlikely ((mod->main.fd != -1 ? fstat64 (mod->main.fd, &main_stat)
159 : file_name != NULL ? stat64 (file_name, &main_stat)
160 : -1) < 0))
161 {
162 main_stat.st_dev = 0;
163 main_stat.st_ino = 0;
164 }
165
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000166 char *file_dirname = (file_basename == file_name ? NULL
167 : strndupa (file_name, file_basename - 1 - file_name));
168 char *p;
169 while ((p = strsep (&path, ":")) != NULL)
170 {
171 /* A leading - or + says whether to check file CRCs for this element. */
172 bool check = defcheck;
173 if (*p == '+' || *p == '-')
174 check = *p++ == '+';
175 check = check && cancheck;
176
177 const char *dir, *subdir;
178 switch (p[0])
179 {
180 case '\0':
181 /* An empty entry says to try the main file's directory. */
182 dir = file_dirname;
183 subdir = NULL;
184 break;
185 case '/':
186 /* An absolute path says to look there for a subdirectory
187 named by the main file's absolute directory.
188 This cannot be applied to a relative file name. */
189 if (file_dirname == NULL || file_dirname[0] != '/')
190 continue;
191 dir = p;
192 subdir = file_dirname + 1;
193 break;
194 default:
195 /* A relative path says to try a subdirectory of that name
196 in the main file's directory. */
197 dir = file_dirname;
198 subdir = p;
199 break;
200 }
201
Roland McGrathbf963472010-02-15 15:16:44 -0800202 char *fname = NULL;
Roland McGrathb9e85182010-06-14 12:45:25 -0700203 int fd = try_open (&main_stat, dir, subdir, debuglink_file, &fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000204 if (fd < 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000205 switch (errno)
206 {
207 case ENOENT:
208 case ENOTDIR:
209 continue;
210 default:
211 return -1;
212 }
Roland McGrath59ea7f32007-10-04 08:50:09 +0000213 if (validate (mod, fd, check, debuglink_crc))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214 {
215 *debuginfo_file_name = fname;
216 return fd;
217 }
218 free (fname);
219 close (fd);
220 }
221
222 /* No dice. */
223 errno = 0;
224 return -1;
225}
Roland McGrath59ea7f32007-10-04 08:50:09 +0000226
227int
228dwfl_standard_find_debuginfo (Dwfl_Module *mod,
229 void **userdata __attribute__ ((unused)),
230 const char *modname __attribute__ ((unused)),
231 GElf_Addr base __attribute__ ((unused)),
232 const char *file_name,
233 const char *debuglink_file,
234 GElf_Word debuglink_crc,
235 char **debuginfo_file_name)
236{
237 /* First try by build ID if we have one. If that succeeds or fails
238 other than just by finding nothing, that's all we do. */
239 const unsigned char *bits;
240 GElf_Addr vaddr;
241 if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
242 {
243 int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
244 NULL, NULL, 0,
245 NULL, NULL, 0,
246 debuginfo_file_name);
Roland McGrath82a63362010-06-30 01:18:43 -0700247 if (fd >= 0 || mod->debug.elf != NULL || errno != 0)
Roland McGrath59ea7f32007-10-04 08:50:09 +0000248 return fd;
249 }
250
251 /* Failing that, search the path by name. */
Roland McGrath0fa20e82008-05-07 18:37:14 +0000252 int fd = find_debuginfo_in_path (mod, file_name,
253 debuglink_file, debuglink_crc,
254 debuginfo_file_name);
255
256 if (fd < 0 && errno == 0)
257 {
258 /* If FILE_NAME is a symlink, the debug file might be associated
259 with the symlink target name instead. */
260
261 char *canon = canonicalize_file_name (file_name);
262 if (canon != NULL && strcmp (file_name, canon))
263 fd = find_debuginfo_in_path (mod, canon,
264 debuglink_file, debuglink_crc,
265 debuginfo_file_name);
266 free (canon);
267 }
268
269 return fd;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000270}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000271INTDEF (dwfl_standard_find_debuginfo)