xref: /aosp_15_r20/external/elfutils/libdw/libdw_find_split_unit.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Find the split (or skeleton) unit for a given unit.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2018 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker 
5*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker    it under the terms of either
7*7304104dSAndroid Build Coastguard Worker 
8*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker        your option) any later version
11*7304104dSAndroid Build Coastguard Worker 
12*7304104dSAndroid Build Coastguard Worker    or
13*7304104dSAndroid Build Coastguard Worker 
14*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker        your option) any later version
17*7304104dSAndroid Build Coastguard Worker 
18*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker 
20*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker 
25*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
27*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
28*7304104dSAndroid Build Coastguard Worker 
29*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
30*7304104dSAndroid Build Coastguard Worker # include <config.h>
31*7304104dSAndroid Build Coastguard Worker #endif
32*7304104dSAndroid Build Coastguard Worker 
33*7304104dSAndroid Build Coastguard Worker #include "libdwP.h"
34*7304104dSAndroid Build Coastguard Worker #include "libelfP.h"
35*7304104dSAndroid Build Coastguard Worker 
36*7304104dSAndroid Build Coastguard Worker #include <limits.h>
37*7304104dSAndroid Build Coastguard Worker #include <search.h>
38*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
39*7304104dSAndroid Build Coastguard Worker #include <string.h>
40*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
41*7304104dSAndroid Build Coastguard Worker #include <sys/stat.h>
42*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
43*7304104dSAndroid Build Coastguard Worker 
44*7304104dSAndroid Build Coastguard Worker static void
try_split_file(Dwarf_CU * cu,const char * dwo_path)45*7304104dSAndroid Build Coastguard Worker try_split_file (Dwarf_CU *cu, const char *dwo_path)
46*7304104dSAndroid Build Coastguard Worker {
47*7304104dSAndroid Build Coastguard Worker   int split_fd = open (dwo_path, O_RDONLY);
48*7304104dSAndroid Build Coastguard Worker   if (split_fd != -1)
49*7304104dSAndroid Build Coastguard Worker     {
50*7304104dSAndroid Build Coastguard Worker       Dwarf *split_dwarf = dwarf_begin (split_fd, DWARF_C_READ);
51*7304104dSAndroid Build Coastguard Worker       if (split_dwarf != NULL)
52*7304104dSAndroid Build Coastguard Worker 	{
53*7304104dSAndroid Build Coastguard Worker 	  Dwarf_CU *split = NULL;
54*7304104dSAndroid Build Coastguard Worker 	  while (INTUSE(dwarf_get_units) (split_dwarf, split, &split,
55*7304104dSAndroid Build Coastguard Worker 					  NULL, NULL, NULL, NULL) == 0)
56*7304104dSAndroid Build Coastguard Worker 	    {
57*7304104dSAndroid Build Coastguard Worker 	      if (split->unit_type == DW_UT_split_compile
58*7304104dSAndroid Build Coastguard Worker 		  && cu->unit_id8 == split->unit_id8)
59*7304104dSAndroid Build Coastguard Worker 		{
60*7304104dSAndroid Build Coastguard Worker 		  if (tsearch (split->dbg, &cu->dbg->split_tree,
61*7304104dSAndroid Build Coastguard Worker 			       __libdw_finddbg_cb) == NULL)
62*7304104dSAndroid Build Coastguard Worker 		    {
63*7304104dSAndroid Build Coastguard Worker 		      /* Something went wrong.  Don't link.  */
64*7304104dSAndroid Build Coastguard Worker 		      __libdw_seterrno (DWARF_E_NOMEM);
65*7304104dSAndroid Build Coastguard Worker 		      break;
66*7304104dSAndroid Build Coastguard Worker 		    }
67*7304104dSAndroid Build Coastguard Worker 
68*7304104dSAndroid Build Coastguard Worker 		  /* Link skeleton and split compile units.  */
69*7304104dSAndroid Build Coastguard Worker 		  __libdw_link_skel_split (cu, split);
70*7304104dSAndroid Build Coastguard Worker 
71*7304104dSAndroid Build Coastguard Worker 		  /* We have everything we need from this ELF
72*7304104dSAndroid Build Coastguard Worker 		     file.  And we are going to close the fd to
73*7304104dSAndroid Build Coastguard Worker 		     not run out of file descriptors.  */
74*7304104dSAndroid Build Coastguard Worker 		  elf_cntl (split_dwarf->elf, ELF_C_FDDONE);
75*7304104dSAndroid Build Coastguard Worker 		  break;
76*7304104dSAndroid Build Coastguard Worker 		}
77*7304104dSAndroid Build Coastguard Worker 	    }
78*7304104dSAndroid Build Coastguard Worker 	  if (cu->split == (Dwarf_CU *) -1)
79*7304104dSAndroid Build Coastguard Worker 	    dwarf_end (split_dwarf);
80*7304104dSAndroid Build Coastguard Worker 	}
81*7304104dSAndroid Build Coastguard Worker       /* Always close, because we don't want to run out of file
82*7304104dSAndroid Build Coastguard Worker 	 descriptors.  See also the elf_fcntl ELF_C_FDDONE call
83*7304104dSAndroid Build Coastguard Worker 	 above.  */
84*7304104dSAndroid Build Coastguard Worker       close (split_fd);
85*7304104dSAndroid Build Coastguard Worker     }
86*7304104dSAndroid Build Coastguard Worker }
87*7304104dSAndroid Build Coastguard Worker 
88*7304104dSAndroid Build Coastguard Worker static void
try_dwp_file(Dwarf_CU * cu)89*7304104dSAndroid Build Coastguard Worker try_dwp_file (Dwarf_CU *cu)
90*7304104dSAndroid Build Coastguard Worker {
91*7304104dSAndroid Build Coastguard Worker   if (cu->dbg->dwp_dwarf == NULL)
92*7304104dSAndroid Build Coastguard Worker     {
93*7304104dSAndroid Build Coastguard Worker       if (cu->dbg->elfpath != NULL)
94*7304104dSAndroid Build Coastguard Worker 	{
95*7304104dSAndroid Build Coastguard Worker 	  /* The DWARF 5 standard says "the package file is typically placed in
96*7304104dSAndroid Build Coastguard Worker 	     the same directory as the application, and is given the same name
97*7304104dSAndroid Build Coastguard Worker 	     with a '.dwp' extension".  */
98*7304104dSAndroid Build Coastguard Worker 	  size_t elfpath_len = strlen (cu->dbg->elfpath);
99*7304104dSAndroid Build Coastguard Worker 	  char *dwp_path = malloc (elfpath_len + 5);
100*7304104dSAndroid Build Coastguard Worker 	  if (dwp_path == NULL)
101*7304104dSAndroid Build Coastguard Worker 	    {
102*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (DWARF_E_NOMEM);
103*7304104dSAndroid Build Coastguard Worker 	      return;
104*7304104dSAndroid Build Coastguard Worker 	    }
105*7304104dSAndroid Build Coastguard Worker 	  memcpy (dwp_path, cu->dbg->elfpath, elfpath_len);
106*7304104dSAndroid Build Coastguard Worker 	  strcpy (dwp_path + elfpath_len, ".dwp");
107*7304104dSAndroid Build Coastguard Worker 	  int dwp_fd = open (dwp_path, O_RDONLY);
108*7304104dSAndroid Build Coastguard Worker 	  free (dwp_path);
109*7304104dSAndroid Build Coastguard Worker 	  if (dwp_fd != -1)
110*7304104dSAndroid Build Coastguard Worker 	    {
111*7304104dSAndroid Build Coastguard Worker 	      Dwarf *dwp_dwarf = dwarf_begin (dwp_fd, DWARF_C_READ);
112*7304104dSAndroid Build Coastguard Worker 	      /* There's no way to know whether we got the correct file until
113*7304104dSAndroid Build Coastguard Worker 		 we look up the unit, but it should at least be a dwp file.  */
114*7304104dSAndroid Build Coastguard Worker 	      if (dwp_dwarf != NULL
115*7304104dSAndroid Build Coastguard Worker 		  && (dwp_dwarf->sectiondata[IDX_debug_cu_index] != NULL
116*7304104dSAndroid Build Coastguard Worker 		      || dwp_dwarf->sectiondata[IDX_debug_tu_index] != NULL))
117*7304104dSAndroid Build Coastguard Worker 		{
118*7304104dSAndroid Build Coastguard Worker 		  cu->dbg->dwp_dwarf = dwp_dwarf;
119*7304104dSAndroid Build Coastguard Worker 		  cu->dbg->dwp_fd = dwp_fd;
120*7304104dSAndroid Build Coastguard Worker 		}
121*7304104dSAndroid Build Coastguard Worker 	      else
122*7304104dSAndroid Build Coastguard Worker 		close (dwp_fd);
123*7304104dSAndroid Build Coastguard Worker 	    }
124*7304104dSAndroid Build Coastguard Worker 	}
125*7304104dSAndroid Build Coastguard Worker       if (cu->dbg->dwp_dwarf == NULL)
126*7304104dSAndroid Build Coastguard Worker 	cu->dbg->dwp_dwarf = (Dwarf *) -1;
127*7304104dSAndroid Build Coastguard Worker     }
128*7304104dSAndroid Build Coastguard Worker 
129*7304104dSAndroid Build Coastguard Worker   if (cu->dbg->dwp_dwarf != (Dwarf *) -1)
130*7304104dSAndroid Build Coastguard Worker     {
131*7304104dSAndroid Build Coastguard Worker       Dwarf_CU *split = __libdw_dwp_findcu_id (cu->dbg->dwp_dwarf,
132*7304104dSAndroid Build Coastguard Worker 					       cu->unit_id8);
133*7304104dSAndroid Build Coastguard Worker       if (split != NULL)
134*7304104dSAndroid Build Coastguard Worker 	{
135*7304104dSAndroid Build Coastguard Worker 	  if (tsearch (split->dbg, &cu->dbg->split_tree,
136*7304104dSAndroid Build Coastguard Worker 		       __libdw_finddbg_cb) == NULL)
137*7304104dSAndroid Build Coastguard Worker 	    {
138*7304104dSAndroid Build Coastguard Worker 	      /* Something went wrong.  Don't link.  */
139*7304104dSAndroid Build Coastguard Worker 	      __libdw_seterrno (DWARF_E_NOMEM);
140*7304104dSAndroid Build Coastguard Worker 	      return;
141*7304104dSAndroid Build Coastguard Worker 	    }
142*7304104dSAndroid Build Coastguard Worker 
143*7304104dSAndroid Build Coastguard Worker 	  /* Link skeleton and split compile units.  */
144*7304104dSAndroid Build Coastguard Worker 	  __libdw_link_skel_split (cu, split);
145*7304104dSAndroid Build Coastguard Worker 	}
146*7304104dSAndroid Build Coastguard Worker     }
147*7304104dSAndroid Build Coastguard Worker }
148*7304104dSAndroid Build Coastguard Worker 
149*7304104dSAndroid Build Coastguard Worker Dwarf_CU *
150*7304104dSAndroid Build Coastguard Worker internal_function
__libdw_find_split_unit(Dwarf_CU * cu)151*7304104dSAndroid Build Coastguard Worker __libdw_find_split_unit (Dwarf_CU *cu)
152*7304104dSAndroid Build Coastguard Worker {
153*7304104dSAndroid Build Coastguard Worker   /* Only try once.  */
154*7304104dSAndroid Build Coastguard Worker   if (cu->split != (Dwarf_CU *) -1)
155*7304104dSAndroid Build Coastguard Worker     return cu->split;
156*7304104dSAndroid Build Coastguard Worker 
157*7304104dSAndroid Build Coastguard Worker   /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
158*7304104dSAndroid Build Coastguard Worker      The split unit will be the first in the dwo file and should have the
159*7304104dSAndroid Build Coastguard Worker      same id as the skeleton.  */
160*7304104dSAndroid Build Coastguard Worker   if (cu->unit_type == DW_UT_skeleton)
161*7304104dSAndroid Build Coastguard Worker     {
162*7304104dSAndroid Build Coastguard Worker       /* First, try the dwp file.  */
163*7304104dSAndroid Build Coastguard Worker       try_dwp_file (cu);
164*7304104dSAndroid Build Coastguard Worker 
165*7304104dSAndroid Build Coastguard Worker       Dwarf_Die cudie = CUDIE (cu);
166*7304104dSAndroid Build Coastguard Worker       Dwarf_Attribute dwo_name;
167*7304104dSAndroid Build Coastguard Worker       /* Try a dwo file.  It is fine if dwo_dir doesn't exist, but then
168*7304104dSAndroid Build Coastguard Worker 	 dwo_name needs to be an absolute path.  */
169*7304104dSAndroid Build Coastguard Worker       if (cu->split == (Dwarf_CU *) -1
170*7304104dSAndroid Build Coastguard Worker 	  && (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
171*7304104dSAndroid Build Coastguard Worker 	      || dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL))
172*7304104dSAndroid Build Coastguard Worker 	{
173*7304104dSAndroid Build Coastguard Worker 	  /* Try the dwo file name in the same directory
174*7304104dSAndroid Build Coastguard Worker 	     as we found the skeleton file.  */
175*7304104dSAndroid Build Coastguard Worker 	  const char *dwo_file = dwarf_formstring (&dwo_name);
176*7304104dSAndroid Build Coastguard Worker 	  const char *debugdir = cu->dbg->debugdir;
177*7304104dSAndroid Build Coastguard Worker 	  char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
178*7304104dSAndroid Build Coastguard Worker 	  if (dwo_path != NULL)
179*7304104dSAndroid Build Coastguard Worker 	    {
180*7304104dSAndroid Build Coastguard Worker 	      try_split_file (cu, dwo_path);
181*7304104dSAndroid Build Coastguard Worker 	      free (dwo_path);
182*7304104dSAndroid Build Coastguard Worker 	    }
183*7304104dSAndroid Build Coastguard Worker 
184*7304104dSAndroid Build Coastguard Worker 	  if (cu->split == (Dwarf_CU *) -1)
185*7304104dSAndroid Build Coastguard Worker 	    {
186*7304104dSAndroid Build Coastguard Worker 	      /* Try compdir plus dwo_name.  */
187*7304104dSAndroid Build Coastguard Worker 	      Dwarf_Attribute compdir;
188*7304104dSAndroid Build Coastguard Worker 	      dwarf_attr (&cudie, DW_AT_comp_dir, &compdir);
189*7304104dSAndroid Build Coastguard Worker 	      const char *dwo_dir = dwarf_formstring (&compdir);
190*7304104dSAndroid Build Coastguard Worker 	      if (dwo_dir != NULL)
191*7304104dSAndroid Build Coastguard Worker 		{
192*7304104dSAndroid Build Coastguard Worker 		  dwo_path = __libdw_filepath (debugdir, dwo_dir, dwo_file);
193*7304104dSAndroid Build Coastguard Worker 		  if (dwo_path != NULL)
194*7304104dSAndroid Build Coastguard Worker 		    {
195*7304104dSAndroid Build Coastguard Worker 		      try_split_file (cu, dwo_path);
196*7304104dSAndroid Build Coastguard Worker 		      free (dwo_path);
197*7304104dSAndroid Build Coastguard Worker 		    }
198*7304104dSAndroid Build Coastguard Worker 		}
199*7304104dSAndroid Build Coastguard Worker 	    }
200*7304104dSAndroid Build Coastguard Worker 	  /* XXX If still not found we could try stripping dirs from the
201*7304104dSAndroid Build Coastguard Worker 	     comp_dir and adding them from the comp_dir, assuming
202*7304104dSAndroid Build Coastguard Worker 	     someone moved a whole build tree around.  */
203*7304104dSAndroid Build Coastguard Worker 	}
204*7304104dSAndroid Build Coastguard Worker     }
205*7304104dSAndroid Build Coastguard Worker 
206*7304104dSAndroid Build Coastguard Worker   /* If we found nothing, make sure we don't try again.  */
207*7304104dSAndroid Build Coastguard Worker   if (cu->split == (Dwarf_CU *) -1)
208*7304104dSAndroid Build Coastguard Worker     cu->split = NULL;
209*7304104dSAndroid Build Coastguard Worker 
210*7304104dSAndroid Build Coastguard Worker   return cu->split;
211*7304104dSAndroid Build Coastguard Worker }
212