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