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