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 : :
36 : : #include <limits.h>
37 : : #include <search.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 : 54 : try_split_file (Dwarf_CU *cu, const char *dwo_path)
46 : : {
47 : 54 : int split_fd = open (dwo_path, O_RDONLY);
48 [ + + ]: 54 : if (split_fd != -1)
49 : : {
50 : 53 : Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ);
51 [ + - ]: 53 : if (split_dwarf != NULL)
52 : : {
53 : 53 : Dwarf_CU *split = NULL;
54 : 53 : while (INTUSE(dwarf_get_units) (split_dwarf, split, &split,
55 [ + + ]: 54 : NULL, NULL, NULL, NULL) == 0)
56 : : {
57 [ + - ]: 53 : if (split->unit_type == DW_UT_split_compile
58 [ + + ]: 53 : && cu->unit_id8 == split->unit_id8)
59 : : {
60 [ - + ]: 52 : if (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 : 52 : __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 : 52 : elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
75 : 52 : break;
76 : : }
77 : : }
78 [ + + ]: 53 : if (cu->split == (Dwarf_CU *) -1)
79 : 1 : 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 : 53 : close (split_fd);
85 : : }
86 : 54 : }
87 : :
88 : : static void
89 : 86 : try_dwp_file (Dwarf_CU *cu)
90 : : {
91 [ + + ]: 86 : if (cu->dbg->dwp_dwarf == NULL)
92 : : {
93 [ + - ]: 44 : 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 : 44 : size_t elfpath_len = strlen (cu->dbg->elfpath);
99 : 44 : char *dwp_path = malloc (elfpath_len + 5);
100 [ - + ]: 44 : if (dwp_path == NULL)
101 : : {
102 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
103 : 0 : return;
104 : : }
105 : 44 : memcpy (dwp_path, cu->dbg->elfpath, elfpath_len);
106 : 44 : strcpy (dwp_path + elfpath_len, ".dwp");
107 : 44 : int dwp_fd = open (dwp_path, O_RDONLY);
108 : 44 : free (dwp_path);
109 [ + + ]: 44 : if (dwp_fd != -1)
110 : : {
111 : 11 : 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 [ + - ]: 11 : if (dwp_dwarf != NULL
115 [ - + ]: 11 : && (dwp_dwarf->sectiondata[IDX_debug_cu_index] != NULL
116 [ # # ]: 0 : || dwp_dwarf->sectiondata[IDX_debug_tu_index] != NULL))
117 : : {
118 : 11 : cu->dbg->dwp_dwarf = dwp_dwarf;
119 : 11 : cu->dbg->dwp_fd = dwp_fd;
120 : : }
121 : : else
122 : 0 : close (dwp_fd);
123 : : }
124 : : }
125 [ + + ]: 44 : if (cu->dbg->dwp_dwarf == NULL)
126 : 33 : cu->dbg->dwp_dwarf = (Dwarf *) -1;
127 : : }
128 : :
129 [ + + ]: 86 : if (cu->dbg->dwp_dwarf != (Dwarf *) -1)
130 : : {
131 : 33 : Dwarf_CU *split = __libdw_dwp_findcu_id (cu->dbg->dwp_dwarf,
132 : : cu->unit_id8);
133 [ + - ]: 33 : if (split != NULL)
134 : : {
135 [ - + ]: 33 : if (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 : 33 : __libdw_link_skel_split (cu, split);
145 : : }
146 : : }
147 : : }
148 : :
149 : : Dwarf_CU *
150 : : internal_function
151 : 527 : __libdw_find_split_unit (Dwarf_CU *cu)
152 : : {
153 : : /* Only try once. */
154 [ + + ]: 527 : if (cu->split != (Dwarf_CU *) -1)
155 : : return cu->split;
156 : :
157 : : /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
158 : : The split unit will be the first in the dwo file and should have the
159 : : same id as the skeleton. */
160 [ + - ]: 86 : if (cu->unit_type == DW_UT_skeleton)
161 : : {
162 : : /* First, try the dwp file. */
163 : 86 : try_dwp_file (cu);
164 : :
165 [ + + ]: 86 : Dwarf_Die cudie = CUDIE (cu);
166 : 86 : Dwarf_Attribute dwo_name;
167 : : /* Try a dwo file. It is fine if dwo_dir doesn't exist, but then
168 : : dwo_name needs to be an absolute path. */
169 [ + + ]: 86 : if (cu->split == (Dwarf_CU *) -1
170 [ + + ]: 53 : && (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
171 [ + - ]: 28 : || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL))
172 : : {
173 : : /* Try the dwo file name in the same directory
174 : : as we found the skeleton file. */
175 : 53 : const char *dwo_file = dwarf_formstring (&dwo_name);
176 : 53 : const char *debugdir = cu->dbg->debugdir;
177 : 53 : char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
178 [ + - ]: 53 : if (dwo_path != NULL)
179 : : {
180 : 53 : try_split_file (cu, dwo_path);
181 : 53 : free (dwo_path);
182 : : }
183 : :
184 [ + + ]: 53 : if (cu->split == (Dwarf_CU *) -1)
185 : : {
186 : : /* Try compdir plus dwo_name. */
187 : 1 : Dwarf_Attribute compdir;
188 : 1 : dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
189 : 1 : const char *dwo_dir = dwarf_formstring (&compdir);
190 [ + - ]: 1 : if (dwo_dir != NULL)
191 : : {
192 : 1 : dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
193 [ + - ]: 1 : if (dwo_path != NULL)
194 : : {
195 : 1 : try_split_file (cu, dwo_path);
196 : 1 : free (dwo_path);
197 : : }
198 : : }
199 : : }
200 : : /* XXX If still not found we could try stripping dirs from the
201 : : comp_dir and adding them from the comp_dir, assuming
202 : : someone moved a whole build tree around. */
203 : : }
204 : : }
205 : :
206 : : /* If we found nothing, make sure we don't try again. */
207 [ + + ]: 86 : if (cu->split == (Dwarf_CU *) -1)
208 : 1 : cu->split = NULL;
209 : :
210 : 86 : return cu->split;
211 : : }
|