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