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 : #include <unistd.h>
44 :
45 : void
46 50 : try_split_file (Dwarf_CU *cu, const char *dwo_path)
47 : {
48 50 : int split_fd = open (dwo_path, O_RDONLY);
49 50 : if (split_fd != -1)
50 : {
51 49 : Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ);
52 49 : if (split_dwarf != NULL)
53 : {
54 49 : Dwarf_CU *split = NULL;
55 99 : while (dwarf_get_units (split_dwarf, split, &split,
56 : NULL, NULL, NULL, NULL) == 0)
57 : {
58 49 : if (split->unit_type == DW_UT_split_compile
59 49 : && cu->unit_id8 == split->unit_id8)
60 : {
61 48 : if (tsearch (split->dbg, &cu->dbg->split_tree,
62 : __libdw_finddbg_cb) == NULL)
63 : {
64 : /* Something went wrong. Don't link. */
65 0 : __libdw_seterrno (DWARF_E_NOMEM);
66 0 : break;
67 : }
68 :
69 : /* Link skeleton and split compile units. */
70 48 : __libdw_link_skel_split (cu, split);
71 :
72 : /* We have everything we need from this ELF
73 : file. And we are going to close the fd to
74 : not run out of file descriptors. */
75 48 : elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
76 48 : break;
77 : }
78 : }
79 49 : if (cu->split == (Dwarf_CU *) -1)
80 1 : dwarf_end (split_dwarf);
81 : }
82 : /* Always close, because we don't want to run out of file
83 : descriptors. See also the elf_fcntl ELF_C_FDDONE call
84 : above. */
85 49 : close (split_fd);
86 : }
87 50 : }
88 :
89 : Dwarf_CU *
90 : internal_function
91 310 : __libdw_find_split_unit (Dwarf_CU *cu)
92 : {
93 : /* Only try once. */
94 310 : if (cu->split != (Dwarf_CU *) -1)
95 : return cu->split;
96 :
97 : /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
98 : The split unit will be the first in the dwo file and should have the
99 : same id as the skeleton. */
100 49 : if (cu->unit_type == DW_UT_skeleton)
101 : {
102 98 : Dwarf_Die cudie = CUDIE (cu);
103 : Dwarf_Attribute dwo_name;
104 : /* It is fine if dwo_dir doesn't exists, but then dwo_name needs
105 : to be an absolute path. */
106 49 : if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
107 26 : || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL)
108 : {
109 : /* First try the dwo file name in the same directory
110 : as we found the skeleton file. */
111 49 : const char *dwo_file = dwarf_formstring (&dwo_name);
112 49 : const char *debugdir = cu->dbg->debugdir;
113 49 : char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
114 49 : if (dwo_path != NULL)
115 : {
116 49 : try_split_file (cu, dwo_path);
117 49 : free (dwo_path);
118 : }
119 :
120 49 : if (cu->split == (Dwarf_CU *) -1)
121 : {
122 : /* Try compdir plus dwo_name. */
123 : Dwarf_Attribute compdir;
124 1 : dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
125 1 : const char *dwo_dir = dwarf_formstring (&compdir);
126 1 : if (dwo_dir != NULL)
127 : {
128 1 : dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
129 1 : if (dwo_path != NULL)
130 : {
131 1 : try_split_file (cu, dwo_path);
132 1 : free (dwo_path);
133 : }
134 : }
135 : }
136 : /* XXX If still not found we could try stripping dirs from the
137 : comp_dir and adding them from the comp_dir, assuming
138 : someone moved a whole build tree around. */
139 : }
140 : }
141 :
142 : /* If we found nothing, make sure we don't try again. */
143 49 : if (cu->split == (Dwarf_CU *) -1)
144 1 : cu->split = NULL;
145 :
146 49 : return cu->split;
147 : }
|