1 /* $NetBSD: dwarf_die.c,v 1.2 2014/03/09 16:58:03 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
5 * Copyright (c) 2009,2011 Kai Wang
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include "_libdwarf.h"
31
32 __RCSID("$NetBSD: dwarf_die.c,v 1.2 2014/03/09 16:58:03 christos Exp $");
33 ELFTC_VCSID("Id: dwarf_die.c 2073 2011-10-27 03:30:47Z jkoshy ");
34
35 int
dwarf_child(Dwarf_Die die,Dwarf_Die * ret_die,Dwarf_Error * error)36 dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error)
37 {
38 Dwarf_Debug dbg;
39 Dwarf_CU cu;
40 int ret;
41
42 dbg = die != NULL ? die->die_dbg : NULL;
43
44 if (die == NULL || ret_die == NULL) {
45 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
46 return (DW_DLV_ERROR);
47 }
48
49 if (die->die_ab->ab_children == DW_CHILDREN_no)
50 return (DW_DLV_NO_ENTRY);
51
52 dbg = die->die_dbg;
53 cu = die->die_cu;
54 ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
55 cu->cu_dwarf_size, die->die_next_off, cu->cu_next_offset,
56 ret_die, 0, error);
57
58 if (ret == DW_DLE_NO_ENTRY) {
59 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
60 return (DW_DLV_NO_ENTRY);
61 } else if (ret != DW_DLE_NONE)
62 return (DW_DLV_ERROR);
63
64 return (DW_DLV_OK);
65 }
66
67 int
dwarf_siblingof(Dwarf_Debug dbg,Dwarf_Die die,Dwarf_Die * ret_die,Dwarf_Error * error)68 dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
69 Dwarf_Error *error)
70 {
71 Dwarf_CU cu;
72 Dwarf_Attribute at;
73 uint64_t offset;
74 int ret, search_sibling;
75
76 if (dbg == NULL || ret_die == NULL) {
77 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
78 return (DW_DLV_ERROR);
79 }
80
81 if ((cu = dbg->dbg_cu_current) == NULL) {
82 DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
83 return (DW_DLV_ERROR);
84 }
85
86 /* Application requests the first DIE in this CU. */
87 if (die == NULL)
88 return (dwarf_offdie(dbg, cu->cu_1st_offset, ret_die,
89 error));
90
91 /*
92 * If the DIE doesn't have any children, its sibling sits next
93 * right to it.
94 */
95 search_sibling = 0;
96 if (die->die_ab->ab_children == DW_CHILDREN_no)
97 offset = die->die_next_off;
98 else {
99 /*
100 * Look for DW_AT_sibling attribute for the offset of
101 * its sibling.
102 */
103 if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) {
104 if (at->at_form != DW_FORM_ref_addr)
105 offset = at->u[0].u64 + cu->cu_offset;
106 else
107 offset = at->u[0].u64;
108 } else {
109 offset = die->die_next_off;
110 search_sibling = 1;
111 }
112 }
113
114 ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
115 cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die,
116 search_sibling, error);
117
118 if (ret == DW_DLE_NO_ENTRY) {
119 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
120 return (DW_DLV_NO_ENTRY);
121 } else if (ret != DW_DLE_NONE)
122 return (DW_DLV_ERROR);
123
124 return (DW_DLV_OK);
125 }
126
127 static int
_dwarf_search_die_within_cu(Dwarf_Debug dbg,Dwarf_CU cu,Dwarf_Off offset,Dwarf_Die * ret_die,Dwarf_Error * error)128 _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off offset,
129 Dwarf_Die *ret_die, Dwarf_Error *error)
130 {
131
132 assert(dbg != NULL && cu != NULL && ret_die != NULL);
133
134 return (_dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size,
135 offset, cu->cu_next_offset, ret_die, 0, error));
136 }
137
138 int
dwarf_offdie(Dwarf_Debug dbg,Dwarf_Off offset,Dwarf_Die * ret_die,Dwarf_Error * error)139 dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die,
140 Dwarf_Error *error)
141 {
142 Dwarf_CU cu;
143 int ret;
144
145 if (dbg == NULL || ret_die == NULL) {
146 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
147 return (DW_DLV_ERROR);
148 }
149
150 /* First search the current CU. */
151 if (dbg->dbg_cu_current != NULL) {
152 cu = dbg->dbg_cu_current;
153 if (offset > cu->cu_offset && offset < cu->cu_next_offset) {
154 ret = _dwarf_search_die_within_cu(dbg, cu, offset,
155 ret_die, error);
156 if (ret == DW_DLE_NO_ENTRY) {
157 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
158 return (DW_DLV_NO_ENTRY);
159 } else if (ret != DW_DLE_NONE)
160 return (DW_DLV_ERROR);
161 return (DW_DLV_OK);
162 }
163 }
164
165 /* Search other CUs. */
166 ret = _dwarf_info_load(dbg, 1, error);
167 if (ret != DW_DLE_NONE)
168 return (DW_DLV_ERROR);
169
170 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
171 if (offset < cu->cu_offset || offset > cu->cu_next_offset)
172 continue;
173 ret = _dwarf_search_die_within_cu(dbg, cu, offset,
174 ret_die, error);
175 if (ret == DW_DLE_NO_ENTRY) {
176 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
177 return (DW_DLV_NO_ENTRY);
178 } else if (ret != DW_DLE_NONE)
179 return (DW_DLV_ERROR);
180 return (DW_DLV_OK);
181 }
182
183 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
184 return (DW_DLV_NO_ENTRY);
185 }
186
187 int
dwarf_tag(Dwarf_Die die,Dwarf_Half * tag,Dwarf_Error * error)188 dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error)
189 {
190 Dwarf_Debug dbg;
191
192 dbg = die != NULL ? die->die_dbg : NULL;
193
194 if (die == NULL || tag == NULL) {
195 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
196 return (DW_DLV_ERROR);
197 }
198
199 assert(die->die_ab != NULL);
200
201 *tag = (Dwarf_Half) die->die_ab->ab_tag;
202
203 return (DW_DLV_OK);
204 }
205
206 int
dwarf_dieoffset(Dwarf_Die die,Dwarf_Off * ret_offset,Dwarf_Error * error)207 dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
208 {
209 Dwarf_Debug dbg;
210
211 dbg = die != NULL ? die->die_dbg : NULL;
212
213 if (die == NULL || ret_offset == NULL) {
214 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
215 return (DW_DLV_ERROR);
216 }
217
218 *ret_offset = die->die_offset;
219
220 return (DW_DLV_OK);
221 }
222
223 int
dwarf_die_CU_offset(Dwarf_Die die,Dwarf_Off * ret_offset,Dwarf_Error * error)224 dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
225 {
226 Dwarf_Debug dbg;
227 Dwarf_CU cu;
228
229 dbg = die != NULL ? die->die_dbg : NULL;
230
231 if (die == NULL || ret_offset == NULL) {
232 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
233 return (DW_DLV_ERROR);
234 }
235
236 cu = die->die_cu;
237 assert(cu != NULL);
238
239 *ret_offset = die->die_offset - cu->cu_offset;
240
241 return (DW_DLV_OK);
242 }
243
244 int
dwarf_die_CU_offset_range(Dwarf_Die die,Dwarf_Off * cu_offset,Dwarf_Off * cu_length,Dwarf_Error * error)245 dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset,
246 Dwarf_Off *cu_length, Dwarf_Error *error)
247 {
248 Dwarf_Debug dbg;
249 Dwarf_CU cu;
250
251 dbg = die != NULL ? die->die_dbg : NULL;
252
253 if (die == NULL || cu_offset == NULL || cu_length == NULL) {
254 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
255 return (DW_DLV_ERROR);
256 }
257
258 cu = die->die_cu;
259 assert(cu != NULL);
260
261 *cu_offset = cu->cu_offset;
262 *cu_length = cu->cu_length + cu->cu_length_size;
263
264 return (DW_DLV_OK);
265 }
266
267 int
dwarf_diename(Dwarf_Die die,char ** ret_name,Dwarf_Error * error)268 dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error)
269 {
270 Dwarf_Debug dbg;
271
272 dbg = die != NULL ? die->die_dbg : NULL;
273
274 if (die == NULL || ret_name == NULL) {
275 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
276 return (DW_DLV_ERROR);
277 }
278
279 if (die->die_name == NULL) {
280 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
281 return (DW_DLV_NO_ENTRY);
282 }
283
284 *ret_name = die->die_name;
285
286 return (DW_DLV_OK);
287 }
288
289 int
dwarf_die_abbrev_code(Dwarf_Die die)290 dwarf_die_abbrev_code(Dwarf_Die die)
291 {
292
293 assert(die != NULL);
294
295 return (die->die_abnum);
296 }
297
298 int
dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,Dwarf_Off in_cu_header_offset,Dwarf_Off * out_cu_die_offset,Dwarf_Error * error)299 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
300 Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset,
301 Dwarf_Error *error)
302 {
303 Dwarf_CU cu;
304
305 if (dbg == NULL || out_cu_die_offset == NULL) {
306 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
307 return (DW_DLV_ERROR);
308 }
309
310 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
311 if (cu->cu_offset == in_cu_header_offset) {
312 *out_cu_die_offset = cu->cu_1st_offset;
313 break;
314 }
315 }
316
317 if (cu == NULL) {
318 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
319 return (DW_DLV_NO_ENTRY);
320 }
321
322 return (DW_DLV_OK);
323 }
324
325 int
dwarf_get_address_size(Dwarf_Debug dbg,Dwarf_Half * addr_size,Dwarf_Error * error)326 dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size,
327 Dwarf_Error *error)
328 {
329
330 if (dbg == NULL || addr_size == NULL) {
331 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
332 return (DW_DLV_ERROR);
333 }
334
335 *addr_size = dbg->dbg_pointer_size;
336
337 return (DW_DLV_OK);
338 }
339