xref: /aosp_15_r20/external/elfutils/libdw/dwarf_formref_die.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Look up the DIE in a reference-form attribute.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005-2010, 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 <string.h>
34*7304104dSAndroid Build Coastguard Worker #include "libdwP.h"
35*7304104dSAndroid Build Coastguard Worker #include <dwarf.h>
36*7304104dSAndroid Build Coastguard Worker 
37*7304104dSAndroid Build Coastguard Worker 
38*7304104dSAndroid Build Coastguard Worker Dwarf_Die *
dwarf_formref_die(Dwarf_Attribute * attr,Dwarf_Die * result)39*7304104dSAndroid Build Coastguard Worker dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result)
40*7304104dSAndroid Build Coastguard Worker {
41*7304104dSAndroid Build Coastguard Worker   if (attr == NULL)
42*7304104dSAndroid Build Coastguard Worker     return NULL;
43*7304104dSAndroid Build Coastguard Worker 
44*7304104dSAndroid Build Coastguard Worker   struct Dwarf_CU *cu = attr->cu;
45*7304104dSAndroid Build Coastguard Worker 
46*7304104dSAndroid Build Coastguard Worker   Dwarf_Off offset;
47*7304104dSAndroid Build Coastguard Worker   if (attr->form == DW_FORM_ref_addr || attr->form == DW_FORM_GNU_ref_alt
48*7304104dSAndroid Build Coastguard Worker       || attr->form == DW_FORM_ref_sup4 || attr->form == DW_FORM_ref_sup8)
49*7304104dSAndroid Build Coastguard Worker     {
50*7304104dSAndroid Build Coastguard Worker       /* This has an absolute offset.  */
51*7304104dSAndroid Build Coastguard Worker 
52*7304104dSAndroid Build Coastguard Worker       uint8_t ref_size;
53*7304104dSAndroid Build Coastguard Worker       if (cu->version == 2 && attr->form == DW_FORM_ref_addr)
54*7304104dSAndroid Build Coastguard Worker 	ref_size = cu->address_size;
55*7304104dSAndroid Build Coastguard Worker       else if (attr->form == DW_FORM_ref_sup4)
56*7304104dSAndroid Build Coastguard Worker 	ref_size = 4;
57*7304104dSAndroid Build Coastguard Worker       else if (attr->form == DW_FORM_ref_sup8)
58*7304104dSAndroid Build Coastguard Worker 	ref_size = 8;
59*7304104dSAndroid Build Coastguard Worker       else
60*7304104dSAndroid Build Coastguard Worker 	ref_size = cu->offset_size;
61*7304104dSAndroid Build Coastguard Worker 
62*7304104dSAndroid Build Coastguard Worker       Dwarf *dbg_ret = (attr->form == DW_FORM_GNU_ref_alt
63*7304104dSAndroid Build Coastguard Worker 			? INTUSE(dwarf_getalt) (cu->dbg) : cu->dbg);
64*7304104dSAndroid Build Coastguard Worker 
65*7304104dSAndroid Build Coastguard Worker       if (dbg_ret == NULL)
66*7304104dSAndroid Build Coastguard Worker 	{
67*7304104dSAndroid Build Coastguard Worker 	  __libdw_seterrno (DWARF_E_NO_ALT_DEBUGLINK);
68*7304104dSAndroid Build Coastguard Worker 	  return NULL;
69*7304104dSAndroid Build Coastguard Worker 	}
70*7304104dSAndroid Build Coastguard Worker 
71*7304104dSAndroid Build Coastguard Worker       if (__libdw_read_offset (cu->dbg, dbg_ret, IDX_debug_info, attr->valp,
72*7304104dSAndroid Build Coastguard Worker 			       ref_size, &offset, IDX_debug_info, 0))
73*7304104dSAndroid Build Coastguard Worker 	return NULL;
74*7304104dSAndroid Build Coastguard Worker 
75*7304104dSAndroid Build Coastguard Worker       return INTUSE(dwarf_offdie) (dbg_ret, offset, result);
76*7304104dSAndroid Build Coastguard Worker     }
77*7304104dSAndroid Build Coastguard Worker 
78*7304104dSAndroid Build Coastguard Worker   const unsigned char *datap;
79*7304104dSAndroid Build Coastguard Worker   size_t size;
80*7304104dSAndroid Build Coastguard Worker   if (attr->form == DW_FORM_ref_sig8)
81*7304104dSAndroid Build Coastguard Worker     {
82*7304104dSAndroid Build Coastguard Worker       /* This doesn't have an offset, but instead a value we
83*7304104dSAndroid Build Coastguard Worker 	 have to match in the type unit headers.  */
84*7304104dSAndroid Build Coastguard Worker 
85*7304104dSAndroid Build Coastguard Worker       uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp);
86*7304104dSAndroid Build Coastguard Worker       cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig);
87*7304104dSAndroid Build Coastguard Worker       if (cu == NULL)
88*7304104dSAndroid Build Coastguard Worker 	{
89*7304104dSAndroid Build Coastguard Worker 	  /* Not seen before.  We have to scan through the type units.
90*7304104dSAndroid Build Coastguard Worker 	     Since DWARFv5 these can (also) be found in .debug_info,
91*7304104dSAndroid Build Coastguard Worker 	     so scan that first.  */
92*7304104dSAndroid Build Coastguard Worker 	  bool scan_debug_types = false;
93*7304104dSAndroid Build Coastguard Worker 	  do
94*7304104dSAndroid Build Coastguard Worker 	    {
95*7304104dSAndroid Build Coastguard Worker 	      cu = __libdw_intern_next_unit (attr->cu->dbg, scan_debug_types);
96*7304104dSAndroid Build Coastguard Worker 	      if (cu == NULL)
97*7304104dSAndroid Build Coastguard Worker 		{
98*7304104dSAndroid Build Coastguard Worker 		  if (scan_debug_types == false)
99*7304104dSAndroid Build Coastguard Worker 		    scan_debug_types = true;
100*7304104dSAndroid Build Coastguard Worker 		  else
101*7304104dSAndroid Build Coastguard Worker 		    {
102*7304104dSAndroid Build Coastguard Worker 		      __libdw_seterrno (INTUSE(dwarf_errno) ()
103*7304104dSAndroid Build Coastguard Worker 					?: DWARF_E_INVALID_REFERENCE);
104*7304104dSAndroid Build Coastguard Worker 		      return NULL;
105*7304104dSAndroid Build Coastguard Worker 		    }
106*7304104dSAndroid Build Coastguard Worker 		}
107*7304104dSAndroid Build Coastguard Worker 	    }
108*7304104dSAndroid Build Coastguard Worker 	  while (cu == NULL || cu->unit_id8 != sig);
109*7304104dSAndroid Build Coastguard Worker 	}
110*7304104dSAndroid Build Coastguard Worker 
111*7304104dSAndroid Build Coastguard Worker       int secid = cu_sec_idx (cu);
112*7304104dSAndroid Build Coastguard Worker       datap = cu->dbg->sectiondata[secid]->d_buf;
113*7304104dSAndroid Build Coastguard Worker       size = cu->dbg->sectiondata[secid]->d_size;
114*7304104dSAndroid Build Coastguard Worker       offset = cu->start + cu->subdie_offset;
115*7304104dSAndroid Build Coastguard Worker     }
116*7304104dSAndroid Build Coastguard Worker   else
117*7304104dSAndroid Build Coastguard Worker     {
118*7304104dSAndroid Build Coastguard Worker       /* Other forms produce an offset from the CU.  */
119*7304104dSAndroid Build Coastguard Worker       if (unlikely (__libdw_formref (attr, &offset) != 0))
120*7304104dSAndroid Build Coastguard Worker 	return NULL;
121*7304104dSAndroid Build Coastguard Worker 
122*7304104dSAndroid Build Coastguard Worker       datap = cu->startp;
123*7304104dSAndroid Build Coastguard Worker       size = cu->endp - cu->startp;
124*7304104dSAndroid Build Coastguard Worker     }
125*7304104dSAndroid Build Coastguard Worker 
126*7304104dSAndroid Build Coastguard Worker   if (unlikely (offset >= size))
127*7304104dSAndroid Build Coastguard Worker     {
128*7304104dSAndroid Build Coastguard Worker       __libdw_seterrno (DWARF_E_INVALID_DWARF);
129*7304104dSAndroid Build Coastguard Worker       return NULL;
130*7304104dSAndroid Build Coastguard Worker     }
131*7304104dSAndroid Build Coastguard Worker 
132*7304104dSAndroid Build Coastguard Worker   memset (result, '\0', sizeof (Dwarf_Die));
133*7304104dSAndroid Build Coastguard Worker   result->addr = (char *) datap + offset;
134*7304104dSAndroid Build Coastguard Worker   result->cu = cu;
135*7304104dSAndroid Build Coastguard Worker   return result;
136*7304104dSAndroid Build Coastguard Worker }
137*7304104dSAndroid Build Coastguard Worker INTDEF (dwarf_formref_die)
138