packaging: update homepage url
[platform/upstream/elfutils.git] / libdwfl / find-debuginfo.c
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 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   if (dir == NULL && subdir == NULL)
46     {
47       fname = strdup (debuglink);
48       if (unlikely (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 stat st;
57   int fd = TEMP_FAILURE_RETRY (open (fname, O_RDONLY));
58   if (fd < 0)
59     free (fname);
60   else if (fstat (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       free (fname);
66       close (fd);
67       errno = ENOENT;
68       fd = -1;
69     }
70   else
71     *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   return (__libdwfl_crc32_file (fd, &file_crc) == 0
82           && file_crc == debuglink_crc);
83 }
84
85 static bool
86 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   if (mod->dw != NULL)
90     {
91       bool valid = false;
92       const void *build_id;
93       const char *altname;
94       ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
95                                                                    &altname,
96                                                                    &build_id);
97       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           Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
103                                                 false, false);
104           if (error != DWFL_E_NOERROR)
105             __libdwfl_seterrno (error);
106           else
107             {
108               const void *alt_build_id;
109               ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
110                                                                 &alt_build_id);
111               if (alt_len > 0 && alt_len == build_id_len
112                   && memcmp (build_id, alt_build_id, alt_len) == 0)
113                 valid = true;
114               else
115                 {
116                   /* A mismatch!  */
117                   elf_end (mod->alt_elf);
118                   mod->alt_elf = NULL;
119                   close (fd);
120                   fd = -1;
121                 }
122             }
123         }
124       return valid;
125     }
126
127   /* If we have a build ID, check only that.  */
128   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       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;
142       else
143         {
144           /* A mismatch!  */
145           elf_end (mod->debug.elf);
146           mod->debug.elf = NULL;
147           close (fd);
148           fd = -1;
149         }
150
151       return mod->debug.valid;
152     }
153
154   return !check || check_crc (fd, debuglink_crc);
155 }
156
157 static int
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)
161 {
162   bool cancheck = debuglink_crc != (GElf_Word) 0;
163
164   const char *file_basename = file_name == NULL ? NULL : basename (file_name);
165   char *localname = NULL;
166   if (debuglink_file == NULL)
167     {
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)
171         {
172           errno = 0;
173           return -1;
174         }
175
176       size_t len = strlen (file_basename);
177       localname = malloc (len + sizeof ".debug");
178       if (unlikely (localname == NULL))
179         return -1;
180       memcpy (localname, file_basename, len);
181       memcpy (&localname[len], ".debug", sizeof ".debug");
182       debuglink_file = localname;
183       cancheck = false;
184     }
185
186   /* Look for a file named DEBUGLINK_FILE in the directories
187      indicated by the debug directory path setting.  */
188
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))
193     {
194       free (localname);
195       return -1;
196     }
197
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] == '+')
202     {
203       defcheck = path[0] == '+';
204       ++path;
205     }
206
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)
211                  : -1) < 0))
212     {
213       main_stat.st_dev = 0;
214       main_stat.st_ino = 0;
215     }
216
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)
220     {
221       free (localpath);
222       free (localname);
223       return -1;
224     }
225   char *p;
226   while ((p = strsep (&path, ":")) != NULL)
227     {
228       /* A leading - or + says whether to check file CRCs for this element.  */
229       bool check = defcheck;
230       if (*p == '+' || *p == '-')
231         check = *p++ == '+';
232       check = check && cancheck;
233
234       const char *dir, *subdir, *file;
235       switch (p[0])
236         {
237         case '\0':
238           /* An empty entry says to try the main file's directory.  */
239           dir = file_dirname;
240           subdir = NULL;
241           file = debuglink_file;
242           break;
243         case '/':
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).  */
249           if (mod->dw == NULL
250               && (file_dirname == NULL || file_dirname[0] != '/'))
251             continue;
252           dir = p;
253           if (mod->dw == NULL)
254             {
255               subdir = file_dirname;
256               /* We want to explore all sub-subdirs.  Chop off one slash
257                  at a time.  */
258             explore_dir:
259               subdir = strchr (subdir, '/');
260               if (subdir != NULL)
261                 subdir = subdir + 1;
262               if (subdir && *subdir == 0)
263                 continue;
264               file = debuglink_file;
265             }
266           else
267             {
268               subdir = NULL;
269               file = basename (debuglink_file);
270             }
271           break;
272         default:
273           /* A relative path says to try a subdirectory of that name
274              in the main file's directory.  */
275           dir = file_dirname;
276           subdir = p;
277           file = debuglink_file;
278           break;
279         }
280
281       char *fname = NULL;
282       int fd = try_open (&main_stat, dir, subdir, file, &fname);
283       if (fd < 0)
284         switch (errno)
285           {
286           case ENOENT:
287           case ENOTDIR:
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] == '/'))
291               {
292                 fd = try_open (&main_stat, dir, ".dwz",
293                                basename (file), &fname);
294                 if (fd < 0)
295                   {
296                     if (errno != ENOENT && errno != ENOTDIR)
297                       goto fail_free;
298                     else
299                       continue;
300                   }
301                 break;
302               }
303             /* If possible try again with a sub-subdir.  */
304             if (mod->dw == NULL && subdir)
305               goto explore_dir;
306             continue;
307           default:
308             goto fail_free;
309           }
310       if (validate (mod, fd, check, debuglink_crc))
311         {
312           free (localpath);
313           free (localname);
314           free (file_dirname);
315           *debuginfo_file_name = fname;
316           return fd;
317         }
318       free (fname);
319       close (fd);
320     }
321
322   /* No dice.  */
323   errno = 0;
324 fail_free:
325   free (localpath);
326   free (localname);
327   free (file_dirname);
328   return -1;
329 }
330
331 int
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)
340 {
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;
344   GElf_Addr vaddr;
345   if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
346     {
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
350          handle it anyway.  */
351       int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
352                                                      NULL, NULL, 0,
353                                                      NULL, NULL, 0,
354                                                      debuginfo_file_name);
355
356       /* Did the build_id callback find something or report an error?
357          Then we are done.  Otherwise fallback on path based search.  */
358       if (fd >= 0
359           || (mod->dw == NULL && mod->debug.elf != NULL)
360           || (mod->dw != NULL && mod->alt_elf != NULL)
361           || errno != 0)
362         return fd;
363     }
364
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);
369
370   if (fd < 0 && errno == 0 && file_name != NULL)
371     {
372       /* If FILE_NAME is a symlink, the debug file might be associated
373          with the symlink target name instead.  */
374
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);
380       free (canon);
381     }
382
383   return fd;
384 }
385 INTDEF (dwfl_standard_find_debuginfo)