blob: 9272c1fdc1e6df4b291fe0ed3d5953e4b361dc2d [file] [log] [blame]
Roland McGrath59ea7f32007-10-04 08:50:09 +00001/* Find an ELF file for a module from its build ID.
Roland McGrathed431dd2010-05-06 00:52:51 -07002 Copyright (C) 2007-2010 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Roland McGrath59ea7f32007-10-04 08:50:09 +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
Roland McGrath59ea7f32007-10-04 08:50:09 +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
Roland McGrath59ea7f32007-10-04 08:50:09 +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/>. */
Roland McGrath59ea7f32007-10-04 08:50:09 +000028
29#include "libdwflP.h"
30#include <inttypes.h>
31#include <fcntl.h>
32#include <unistd.h>
33
34
35int
36internal_function
37__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
38{
Roland McGrath059c83e2008-02-21 06:19:39 +000039 /* If *FILE_NAME was primed into the module, leave it there
40 as the fallback when we have nothing to offer. */
Roland McGrath59ea7f32007-10-04 08:50:09 +000041 errno = 0;
42 if (mod->build_id_len <= 0)
43 return -1;
44
45 const size_t id_len = mod->build_id_len;
46 const uint8_t *id = mod->build_id_bits;
47
48 /* Search debuginfo_path directories' .build-id/ subdirectories. */
49
50 char id_name[sizeof "/.build-id/" + 1 + id_len * 2 + sizeof ".debug" - 1];
51 strcpy (id_name, "/.build-id/");
52 int n = snprintf (&id_name[sizeof "/.build-id/" - 1],
53 4, "%02" PRIx8 "/", (uint8_t) id[0]);
54 assert (n == 3);
55 for (size_t i = 1; i < id_len; ++i)
56 {
57 n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2],
58 3, "%02" PRIx8, (uint8_t) id[i]);
59 assert (n == 2);
60 }
61 if (debug)
62 strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2],
63 ".debug");
64
65 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
66 char *path = strdupa ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
67 ?: DEFAULT_DEBUGINFO_PATH);
68
69 int fd = -1;
70 char *dir;
71 while (fd < 0 && (dir = strsep (&path, ":")) != NULL)
72 {
73 if (dir[0] == '+' || dir[0] == '-')
74 ++dir;
75
76 /* Only absolute directory names are useful to us. */
77 if (dir[0] != '/')
78 continue;
79
80 size_t dirlen = strlen (dir);
81 char *name = malloc (dirlen + sizeof id_name);
82 if (unlikely (name == NULL))
83 break;
84 memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name);
85
86 fd = TEMP_FAILURE_RETRY (open64 (name, O_RDONLY));
87 if (fd >= 0)
88 {
89 if (*file_name != NULL)
90 free (*file_name);
91 *file_name = canonicalize_file_name (name);
92 if (*file_name == NULL)
93 {
94 *file_name = name;
95 name = NULL;
96 }
97 }
98 free (name);
99 }
100
Roland McGrath1d8bb252008-08-07 08:39:41 +0000101 /* If we simply found nothing, clear errno. If we had some other error
102 with the file, report that. Possibly this should treat other errors
103 like ENOENT too. But ignoring all errors could mask some that should
104 be reported. */
105 if (fd < 0 && errno == ENOENT)
106 errno = 0;
107
Roland McGrath59ea7f32007-10-04 08:50:09 +0000108 return fd;
109}
110
111int
112dwfl_build_id_find_elf (Dwfl_Module *mod,
113 void **userdata __attribute__ ((unused)),
114 const char *modname __attribute__ ((unused)),
115 Dwarf_Addr base __attribute__ ((unused)),
116 char **file_name, Elf **elfp)
117{
118 *elfp = NULL;
119 int fd = __libdwfl_open_by_build_id (mod, false, file_name);
120 if (fd >= 0)
121 {
Roland McGrathbca43152009-01-05 23:59:32 -0800122 Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false);
123 if (error != DWFL_E_NOERROR)
124 __libdwfl_seterrno (error);
125 else if (__libdwfl_find_build_id (mod, false, *elfp) == 2)
126 {
127 /* This is a backdoor signal to short-circuit the ID refresh. */
128 mod->main.valid = true;
129 return fd;
130 }
Roland McGrath59ea7f32007-10-04 08:50:09 +0000131 else
132 {
133 /* This file does not contain the ID it should! */
134 elf_end (*elfp);
135 *elfp = NULL;
136 close (fd);
137 fd = -1;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000138 }
Roland McGrathbca43152009-01-05 23:59:32 -0800139 free (*file_name);
140 *file_name = NULL;
Roland McGrath59ea7f32007-10-04 08:50:09 +0000141 }
Roland McGrathed431dd2010-05-06 00:52:51 -0700142 else if (errno == 0 && mod->build_id_len > 0)
143 /* Setting this with no file yet loaded is a marker that
144 the build ID is authoritative even if we also know a
145 putative *FILE_NAME. */
146 mod->main.valid = true;
147
Roland McGrath59ea7f32007-10-04 08:50:09 +0000148 return fd;
149}
150INTDEF (dwfl_build_id_find_elf)