xref: /freebsd/contrib/elftoolchain/libdwarf/dwarf_die.c (revision 27c43fe1f3795622c5bd4bbfc465a29a800c0799)
1 /*-
2  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
3  * Copyright (c) 2009,2011 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 2073 2011-10-27 03:30:47Z jkoshy $");
31 
32 int
33 dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error)
34 {
35 	Dwarf_Debug dbg;
36 	Dwarf_CU cu;
37 	int ret;
38 
39 	dbg = die != NULL ? die->die_dbg : NULL;
40 
41 	if (die == NULL || ret_die == NULL) {
42 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
43 		return (DW_DLV_ERROR);
44 	}
45 
46 	if (die->die_ab->ab_children == DW_CHILDREN_no)
47 		return (DW_DLV_NO_ENTRY);
48 
49 	dbg = die->die_dbg;
50 	cu = die->die_cu;
51 	ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
52 	    cu->cu_dwarf_size, die->die_next_off, cu->cu_next_offset,
53 	    ret_die, 0, error);
54 
55 	if (ret == DW_DLE_NO_ENTRY) {
56 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
57 		return (DW_DLV_NO_ENTRY);
58 	} else if (ret != DW_DLE_NONE)
59 		return (DW_DLV_ERROR);
60 
61 	return (DW_DLV_OK);
62 }
63 
64 int
65 dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
66     Dwarf_Error *error)
67 {
68 	Dwarf_CU cu;
69 	Dwarf_Attribute at;
70 	uint64_t offset;
71 	int ret, search_sibling;
72 
73 	if (dbg == NULL || ret_die == NULL) {
74 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
75 		return (DW_DLV_ERROR);
76 	}
77 
78 	if ((cu = dbg->dbg_cu_current) == NULL) {
79 		DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
80 		return (DW_DLV_ERROR);
81 	}
82 
83 	/* Application requests the first DIE in this CU. */
84 	if (die == NULL)
85 		return (dwarf_offdie(dbg, cu->cu_1st_offset, ret_die,
86 		    error));
87 
88 	/*
89 	 * If the DIE doesn't have any children, its sibling sits next
90 	 * right to it.
91 	 */
92 	search_sibling = 0;
93 	if (die->die_ab->ab_children == DW_CHILDREN_no)
94 		offset = die->die_next_off;
95 	else {
96 		/*
97 		 * Look for DW_AT_sibling attribute for the offset of
98 		 * its sibling.
99 		 */
100 		if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) {
101 			if (at->at_form != DW_FORM_ref_addr)
102 				offset = at->u[0].u64 + cu->cu_offset;
103 			else
104 				offset = at->u[0].u64;
105 		} else {
106 			offset = die->die_next_off;
107 			search_sibling = 1;
108 		}
109 	}
110 
111 	ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
112 	    cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die,
113 	    search_sibling, error);
114 
115 	if (ret == DW_DLE_NO_ENTRY) {
116 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
117 		return (DW_DLV_NO_ENTRY);
118 	} else if (ret != DW_DLE_NONE)
119 		return (DW_DLV_ERROR);
120 
121 	return (DW_DLV_OK);
122 }
123 
124 static int
125 _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off offset,
126     Dwarf_Die *ret_die, Dwarf_Error *error)
127 {
128 
129 	assert(dbg != NULL && cu != NULL && ret_die != NULL);
130 
131 	return (_dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size,
132 	    offset, cu->cu_next_offset, ret_die, 0, error));
133 }
134 
135 int
136 dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die,
137     Dwarf_Error *error)
138 {
139 	Dwarf_CU cu;
140 	int ret;
141 
142 	if (dbg == NULL || ret_die == NULL) {
143 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
144 		return (DW_DLV_ERROR);
145 	}
146 
147 	/* First search the current CU. */
148 	if (dbg->dbg_cu_current != NULL) {
149 		cu = dbg->dbg_cu_current;
150 		if (offset > cu->cu_offset && offset < cu->cu_next_offset) {
151 			ret = _dwarf_search_die_within_cu(dbg, cu, offset,
152 			    ret_die, error);
153 			if (ret == DW_DLE_NO_ENTRY) {
154 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
155 				return (DW_DLV_NO_ENTRY);
156 			} else if (ret != DW_DLE_NONE)
157 				return (DW_DLV_ERROR);
158 			return (DW_DLV_OK);
159 		}
160 	}
161 
162 	/* Search other CUs. */
163 	ret = _dwarf_info_load(dbg, 1, error);
164 	if (ret != DW_DLE_NONE)
165 		return (DW_DLV_ERROR);
166 
167 	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
168 		if (offset < cu->cu_offset || offset > cu->cu_next_offset)
169 			continue;
170 		ret = _dwarf_search_die_within_cu(dbg, cu, offset,
171 		    ret_die, error);
172 		if (ret == DW_DLE_NO_ENTRY) {
173 			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
174 			return (DW_DLV_NO_ENTRY);
175 		} else if (ret != DW_DLE_NONE)
176 			return (DW_DLV_ERROR);
177 		return (DW_DLV_OK);
178 	}
179 
180 	DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
181 	return (DW_DLV_NO_ENTRY);
182 }
183 
184 int
185 dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error)
186 {
187 	Dwarf_Debug dbg;
188 
189 	dbg = die != NULL ? die->die_dbg : NULL;
190 
191 	if (die == NULL || tag == NULL) {
192 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
193 		return (DW_DLV_ERROR);
194 	}
195 
196 	assert(die->die_ab != NULL);
197 
198 	*tag = (Dwarf_Half) die->die_ab->ab_tag;
199 
200 	return (DW_DLV_OK);
201 }
202 
203 int
204 dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
205 {
206 	Dwarf_Debug dbg;
207 
208 	dbg = die != NULL ? die->die_dbg : NULL;
209 
210 	if (die == NULL || ret_offset == NULL) {
211 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
212 		return (DW_DLV_ERROR);
213 	}
214 
215 	*ret_offset = die->die_offset;
216 
217 	return (DW_DLV_OK);
218 }
219 
220 int
221 dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
222 {
223 	Dwarf_Debug dbg;
224 	Dwarf_CU cu;
225 
226 	dbg = die != NULL ? die->die_dbg : NULL;
227 
228 	if (die == NULL || ret_offset == NULL) {
229 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
230 		return (DW_DLV_ERROR);
231 	}
232 
233 	cu = die->die_cu;
234 	assert(cu != NULL);
235 
236 	*ret_offset = die->die_offset - cu->cu_offset;
237 
238 	return (DW_DLV_OK);
239 }
240 
241 int
242 dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset,
243     Dwarf_Off *cu_length, Dwarf_Error *error)
244 {
245 	Dwarf_Debug dbg;
246 	Dwarf_CU cu;
247 
248 	dbg = die != NULL ? die->die_dbg : NULL;
249 
250 	if (die == NULL || cu_offset == NULL || cu_length == NULL) {
251 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
252 		return (DW_DLV_ERROR);
253 	}
254 
255 	cu = die->die_cu;
256 	assert(cu != NULL);
257 
258 	*cu_offset = cu->cu_offset;
259 	*cu_length = cu->cu_length + cu->cu_length_size;
260 
261 	return (DW_DLV_OK);
262 }
263 
264 int
265 dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error)
266 {
267 	Dwarf_Debug dbg;
268 
269 	dbg = die != NULL ? die->die_dbg : NULL;
270 
271 	if (die == NULL || ret_name == NULL) {
272 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
273 		return (DW_DLV_ERROR);
274 	}
275 
276 	if (die->die_name == NULL) {
277 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
278 		return (DW_DLV_NO_ENTRY);
279 	}
280 
281 	*ret_name = die->die_name;
282 
283 	return (DW_DLV_OK);
284 }
285 
286 int
287 dwarf_die_abbrev_code(Dwarf_Die die)
288 {
289 
290 	assert(die != NULL);
291 
292 	return (die->die_abnum);
293 }
294 
295 int
296 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
297     Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset,
298     Dwarf_Error *error)
299 {
300 	Dwarf_CU cu;
301 
302 	if (dbg == NULL || out_cu_die_offset == NULL) {
303 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
304 		return (DW_DLV_ERROR);
305 	}
306 
307 	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
308 		if (cu->cu_offset == in_cu_header_offset) {
309 			*out_cu_die_offset = cu->cu_1st_offset;
310 			break;
311 		}
312 	}
313 
314 	if (cu == NULL) {
315 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
316 		return (DW_DLV_NO_ENTRY);
317 	}
318 
319 	return (DW_DLV_OK);
320 }
321 
322 int
323 dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size,
324     Dwarf_Error *error)
325 {
326 
327 	if (dbg == NULL || addr_size == NULL) {
328 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
329 		return (DW_DLV_ERROR);
330 	}
331 
332 	*addr_size = dbg->dbg_pointer_size;
333 
334 	return (DW_DLV_OK);
335 }
336