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