Branch data Line data Source code
1 : : /* Find the split (or skeleton) unit for a given unit.
2 : : Copyright (C) 2018 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 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include "libdwP.h"
34 : : #include "libelfP.h"
35 : : #include "libdwelfP.h"
36 : : #include "eu-search.h"
37 : :
38 : : #include <limits.h>
39 : : #include <stdlib.h>
40 : : #include <string.h>
41 : : #include <sys/types.h>
42 : : #include <sys/stat.h>
43 : : #include <fcntl.h>
44 : :
45 : : static void
46 : 112 : try_split_file (Dwarf_CU *cu, const char *dwo_path)
47 : : {
48 : 112 : int split_fd = open (dwo_path, O_RDONLY);
49 [ + + ]: 112 : if (split_fd != -1)
50 : : {
51 : 110 : Dwarf *split_dwarf = INTUSE(dwarf_begin_type) (split_fd, DWARF_C_READ,
52 : : DWARF_T_DWO);
53 [ + - ]: 110 : if (split_dwarf != NULL)
54 : : {
55 : 110 : Dwarf_CU *split = NULL;
56 : 110 : while (INTUSE(dwarf_get_units) (split_dwarf, split, &split,
57 [ + + ]: 112 : NULL, NULL, NULL, NULL) == 0)
58 : : {
59 [ + - ]: 110 : if (split->unit_type == DW_UT_split_compile
60 [ + + ]: 110 : && cu->unit_id8 == split->unit_id8)
61 : : {
62 [ - + ]: 108 : if (eu_tsearch (split->dbg, &cu->dbg->split_tree,
63 : : __libdw_finddbg_cb) == NULL)
64 : : {
65 : : /* Something went wrong. Don't link. */
66 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
67 : 0 : break;
68 : : }
69 : :
70 : : /* Link skeleton and split compile units. */
71 : 108 : __libdw_link_skel_split (cu, split);
72 : :
73 : : /* We have everything we need from this ELF
74 : : file. And we are going to close the fd to
75 : : not run out of file descriptors. */
76 : 108 : elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
77 : 108 : break;
78 : : }
79 : : }
80 [ + + ]: 110 : if (cu->split == (Dwarf_CU *) -1)
81 : 2 : INTUSE (dwarf_end) (split_dwarf);
82 : : }
83 : : /* Always close, because we don't want to run out of file
84 : : descriptors. See also the elf_fcntl ELF_C_FDDONE call
85 : : above. */
86 : 110 : close (split_fd);
87 : : }
88 : 112 : }
89 : :
90 : : static void
91 : 198 : try_dwp_file (Dwarf_CU *cu)
92 : : {
93 [ + + ]: 198 : if (cu->dbg->dwp_dwarf == NULL)
94 : : {
95 : 98 : uint8_t is_dwp;
96 : 98 : const char *filename;
97 : 98 : const uint8_t *dwp_id;
98 : 98 : int dwp_fd = -1;
99 : :
100 : 98 : ssize_t idlen = INTUSE(dwelf_dwarf_debug_dwp) (cu->dbg, NULL, &is_dwp,
101 : : &filename, &dwp_id);
102 [ + - + + : 98 : if (idlen >= 0 && filename != NULL && is_dwp == 0 && *filename != '\0')
+ - + - ]
103 : : {
104 : : /* XXX we need to set standards where/how to find id based
105 : : dwp files, including debuginfod support. For now only use
106 : : the file path. */
107 : 2 : char *path = __libdw_filepath (cu->dbg->debugdir, NULL, filename);
108 [ + - ]: 2 : if (path != NULL)
109 : : {
110 [ - + - - ]: 2 : dwp_fd = TEMP_FAILURE_RETRY (open (path, O_RDONLY));
111 : 2 : free (path);
112 : : }
113 : : }
114 : :
115 [ - + + - ]: 98 : if (dwp_fd == -1 && cu->dbg->elfpath != NULL)
116 : : {
117 : : /* The DWARF 5 standard says "the package file is typically placed in
118 : : the same directory as the application, and is given the same name
119 : : with a '.dwp' extension". */
120 : 96 : size_t elfpath_len = strlen (cu->dbg->elfpath);
121 : 96 : char *dwp_path = malloc (elfpath_len + 5);
122 [ - + ]: 96 : if (dwp_path == NULL)
123 : : {
124 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
125 : 0 : return;
126 : : }
127 : 96 : memcpy (dwp_path, cu->dbg->elfpath, elfpath_len);
128 : 96 : strcpy (dwp_path + elfpath_len, ".dwp");
129 [ + + - + ]: 96 : dwp_fd = TEMP_FAILURE_RETRY (open (dwp_path, O_RDONLY));
130 : 96 : free (dwp_path);
131 : : }
132 : :
133 [ + + ]: 96 : if (dwp_fd != -1)
134 : : {
135 : 28 : Dwarf *dwp_dwarf = INTUSE(dwarf_begin_type) (dwp_fd, DWARF_C_READ,
136 : : DWARF_T_DWO);
137 : : /* There's no way to know whether we got the correct file until
138 : : we look up the unit, but it should at least be a dwp file. */
139 [ + - ]: 28 : if (dwp_dwarf != NULL
140 [ - + ]: 28 : && (dwp_dwarf->sectiondata[IDX_debug_cu_index] != NULL
141 [ # # ]: 0 : || dwp_dwarf->sectiondata[IDX_debug_tu_index] != NULL))
142 : : {
143 : 28 : cu->dbg->dwp_dwarf = dwp_dwarf;
144 : 28 : cu->dbg->dwp_fd = dwp_fd;
145 : : }
146 : : else
147 : 0 : close (dwp_fd);
148 : : }
149 [ + + ]: 98 : if (cu->dbg->dwp_dwarf == NULL)
150 : 70 : cu->dbg->dwp_dwarf = (Dwarf *) -1;
151 : : }
152 : :
153 [ + + ]: 198 : if (cu->dbg->dwp_dwarf != (Dwarf *) -1)
154 : : {
155 : 88 : Dwarf_CU *split = __libdw_dwp_findcu_id (cu->dbg->dwp_dwarf,
156 : : cu->unit_id8);
157 [ + - ]: 88 : if (split != NULL)
158 : : {
159 [ - + ]: 88 : if (eu_tsearch (split->dbg, &cu->dbg->split_tree,
160 : : __libdw_finddbg_cb) == NULL)
161 : : {
162 : : /* Something went wrong. Don't link. */
163 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
164 : 0 : return;
165 : : }
166 : :
167 : : /* Link skeleton and split compile units. */
168 : 88 : __libdw_link_skel_split (cu, split);
169 : : }
170 : : }
171 : : }
172 : :
173 : : Dwarf_CU *
174 : : internal_function
175 : 1108 : __libdw_find_split_unit (Dwarf_CU *cu)
176 : : {
177 : : /* Set result before releasing the lock. */
178 : 1108 : Dwarf_CU *result;
179 : :
180 : 1108 : rwlock_wrlock(cu->split_lock);
181 : :
182 : : /* Only try once. */
183 [ + + ]: 1108 : if (cu->split != (Dwarf_CU *) -1)
184 : : {
185 : 1108 : result = cu->split;
186 : : rwlock_unlock(cu->split_lock);
187 : : return result;
188 : : }
189 : :
190 : : /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
191 : : The split unit will be the first in the dwo file and should have the
192 : : same id as the skeleton. */
193 [ + - ]: 198 : if (cu->unit_type == DW_UT_skeleton)
194 : : {
195 : : /* First, try the dwp file. */
196 : 198 : try_dwp_file (cu);
197 : :
198 : 198 : Dwarf_Die cudie = CUDIE (cu);
199 : 198 : Dwarf_Attribute dwo_name;
200 : : /* Try a dwo file. It is fine if dwo_dir doesn't exist, but then
201 : : dwo_name needs to be an absolute path. */
202 [ + + ]: 198 : if (cu->split == (Dwarf_CU *) -1
203 [ + + ]: 110 : && (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
204 [ + - ]: 56 : || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL))
205 : : {
206 : : /* Try the dwo file name in the same directory
207 : : as we found the skeleton file. */
208 : 110 : const char *dwo_file = dwarf_formstring (&dwo_name);
209 : 110 : const char *debugdir = cu->dbg->debugdir;
210 : 110 : char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
211 [ + - ]: 110 : if (dwo_path != NULL)
212 : : {
213 : 110 : try_split_file (cu, dwo_path);
214 : 110 : free (dwo_path);
215 : : }
216 : :
217 [ + + ]: 110 : if (cu->split == (Dwarf_CU *) -1)
218 : : {
219 : : /* Try compdir plus dwo_name. */
220 : 2 : Dwarf_Attribute compdir;
221 : 2 : dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
222 : 2 : const char *dwo_dir = dwarf_formstring (&compdir);
223 [ + - ]: 2 : if (dwo_dir != NULL)
224 : : {
225 : 2 : dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
226 [ + - ]: 2 : if (dwo_path != NULL)
227 : : {
228 : 2 : try_split_file (cu, dwo_path);
229 : 2 : free (dwo_path);
230 : : }
231 : : }
232 : : }
233 : : /* XXX If still not found we could try stripping dirs from the
234 : : comp_dir and adding them from the comp_dir, assuming
235 : : someone moved a whole build tree around. */
236 : : }
237 : : }
238 : :
239 : : /* If we found nothing, make sure we don't try again. */
240 [ + + ]: 198 : if (cu->split == (Dwarf_CU *) -1)
241 : 2 : cu->split = NULL;
242 : :
243 : 198 : result = cu->split;
244 : 198 : rwlock_unlock(cu->split_lock);
245 : 198 : return result;
246 : : }
|