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