xref: /netbsd-src/external/bsd/elftoolchain/dist/libdwarf/dwarf_die.c (revision 5ac3bc719ce6e70593039505b491894133237d12)
1 /*	$NetBSD: dwarf_die.c,v 1.5 2024/03/03 17:37:30 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
5  * Copyright (c) 2009,2011,2014 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.5 2024/03/03 17:37:30 christos Exp $");
33 ELFTC_VCSID("Id: dwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27");
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_Section *ds;
40 	Dwarf_CU cu;
41 	int ret;
42 
43 	dbg = die != NULL ? die->die_dbg : NULL;
44 
45 	if (die == NULL || ret_die == NULL) {
46 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
47 		return (DW_DLV_ERROR);
48 	}
49 
50 	if (die->die_ab->ab_children == DW_CHILDREN_no)
51 		return (DW_DLV_NO_ENTRY);
52 
53 	dbg = die->die_dbg;
54 	cu = die->die_cu;
55 	ds = cu->cu_is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec;
56 	ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size,
57 	    die->die_next_off, cu->cu_next_offset, ret_die, 0, error);
58 
59 	if (ret == DW_DLE_NO_ENTRY) {
60 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
61 		return (DW_DLV_NO_ENTRY);
62 	} else if (ret != DW_DLE_NONE)
63 		return (DW_DLV_ERROR);
64 
65 	return (DW_DLV_OK);
66 }
67 
68 int
dwarf_siblingof_b(Dwarf_Debug dbg,Dwarf_Die die,Dwarf_Die * ret_die,Dwarf_Bool is_info,Dwarf_Error * error)69 dwarf_siblingof_b(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
70     Dwarf_Bool is_info, Dwarf_Error *error)
71 {
72 	Dwarf_CU cu;
73 	Dwarf_Attribute at;
74 	Dwarf_Section *ds;
75 	uint64_t offset;
76 	int ret, search_sibling;
77 
78 	if (dbg == NULL || ret_die == NULL) {
79 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
80 		return (DW_DLV_ERROR);
81 	}
82 
83 	ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec;
84 	cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current;
85 
86 	if (cu == NULL) {
87 		DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
88 		return (DW_DLV_ERROR);
89 	}
90 
91 	/* Application requests the first DIE in this CU. */
92 	if (die == NULL)
93 		return (dwarf_offdie_b(dbg, cu->cu_1st_offset, is_info,
94 		    ret_die, error));
95 
96 	/*
97 	 * Check if the `is_info' flag matches the debug section the
98 	 * DIE belongs to.
99 	 */
100 	if (is_info != die->die_cu->cu_is_info) {
101 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
102 		return (DW_DLV_ERROR);
103 	}
104 
105 	/*
106 	 * If the DIE doesn't have any children, its sibling sits next
107 	 * right to it.
108 	 */
109 	search_sibling = 0;
110 	if (die->die_ab->ab_children == DW_CHILDREN_no)
111 		offset = die->die_next_off;
112 	else {
113 		/*
114 		 * Look for DW_AT_sibling attribute for the offset of
115 		 * its sibling.
116 		 */
117 		if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) {
118 			if (at->at_form != DW_FORM_ref_addr)
119 				offset = at->u[0].u64 + cu->cu_offset;
120 			else
121 				offset = at->u[0].u64;
122 		} else {
123 			offset = die->die_next_off;
124 			search_sibling = 1;
125 		}
126 	}
127 
128 	ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size, offset,
129 	    cu->cu_next_offset, ret_die, search_sibling, error);
130 
131 	if (ret == DW_DLE_NO_ENTRY) {
132 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
133 		return (DW_DLV_NO_ENTRY);
134 	} else if (ret != DW_DLE_NONE)
135 		return (DW_DLV_ERROR);
136 
137 	return (DW_DLV_OK);
138 }
139 
140 
141 int
dwarf_siblingof(Dwarf_Debug dbg,Dwarf_Die die,Dwarf_Die * ret_die,Dwarf_Error * error)142 dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
143     Dwarf_Error *error)
144 {
145 
146 	return (dwarf_siblingof_b(dbg, die, ret_die, 1, error));
147 }
148 
149 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)150 _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_Section *s, Dwarf_CU cu,
151     Dwarf_Off offset, Dwarf_Die *ret_die, Dwarf_Error *error)
152 {
153 
154 	assert(dbg != NULL && cu != NULL && ret_die != NULL);
155 
156 	return (_dwarf_die_parse(dbg, s, cu, cu->cu_dwarf_size,
157 	    offset, cu->cu_next_offset, ret_die, 0, error));
158 }
159 
160 int
dwarf_offdie_b(Dwarf_Debug dbg,Dwarf_Off offset,Dwarf_Bool is_info,Dwarf_Die * ret_die,Dwarf_Error * error)161 dwarf_offdie_b(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Bool is_info,
162     Dwarf_Die *ret_die, Dwarf_Error *error)
163 {
164 	Dwarf_Section *ds;
165 	Dwarf_CU cu;
166 	int ret;
167 
168 	if (dbg == NULL || ret_die == NULL) {
169 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
170 		return (DW_DLV_ERROR);
171 	}
172 
173 	ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec;
174 	cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current;
175 
176 	/* First search the current CU. */
177 	if (cu != NULL) {
178 		if (offset > cu->cu_offset && offset < cu->cu_next_offset) {
179 			ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset,
180 			    ret_die, error);
181 			if (ret == DW_DLE_NO_ENTRY) {
182 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
183 				return (DW_DLV_NO_ENTRY);
184 			} else if (ret != DW_DLE_NONE)
185 				return (DW_DLV_ERROR);
186 			return (DW_DLV_OK);
187 		}
188 	}
189 
190 	/* Search other CUs. */
191 	ret = _dwarf_info_load(dbg, 1, is_info, error);
192 	if (ret != DW_DLE_NONE)
193 		return (DW_DLV_ERROR);
194 
195 	if (is_info) {
196 		STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
197 			if (offset < cu->cu_offset ||
198 			    offset > cu->cu_next_offset)
199 				continue;
200 			ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset,
201 			    ret_die, error);
202 			if (ret == DW_DLE_NO_ENTRY) {
203 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
204 				return (DW_DLV_NO_ENTRY);
205 			} else if (ret != DW_DLE_NONE)
206 				return (DW_DLV_ERROR);
207 			return (DW_DLV_OK);
208 		}
209 	} else {
210 		STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) {
211 			if (offset < cu->cu_offset ||
212 			    offset > cu->cu_next_offset)
213 				continue;
214 			ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset,
215 			    ret_die, error);
216 			if (ret == DW_DLE_NO_ENTRY) {
217 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
218 				return (DW_DLV_NO_ENTRY);
219 			} else if (ret != DW_DLE_NONE)
220 				return (DW_DLV_ERROR);
221 			return (DW_DLV_OK);
222 		}
223 	}
224 
225 	DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
226 	return (DW_DLV_NO_ENTRY);
227 }
228 
229 int
dwarf_offdie(Dwarf_Debug dbg,Dwarf_Off offset,Dwarf_Die * ret_die,Dwarf_Error * error)230 dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die,
231     Dwarf_Error *error)
232 {
233 
234 	return (dwarf_offdie_b(dbg, offset, 1, ret_die, error));
235 }
236 
237 int
dwarf_tag(Dwarf_Die die,Dwarf_Half * tag,Dwarf_Error * error)238 dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error)
239 {
240 	Dwarf_Debug dbg;
241 
242 	dbg = die != NULL ? die->die_dbg : NULL;
243 
244 	if (die == NULL || tag == NULL) {
245 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
246 		return (DW_DLV_ERROR);
247 	}
248 
249 	assert(die->die_ab != NULL);
250 
251 	*tag = (Dwarf_Half) die->die_ab->ab_tag;
252 
253 	return (DW_DLV_OK);
254 }
255 
256 int
dwarf_dieoffset(Dwarf_Die die,Dwarf_Off * ret_offset,Dwarf_Error * error)257 dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
258 {
259 	Dwarf_Debug dbg;
260 
261 	dbg = die != NULL ? die->die_dbg : NULL;
262 
263 	if (die == NULL || ret_offset == NULL) {
264 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
265 		return (DW_DLV_ERROR);
266 	}
267 
268 	*ret_offset = die->die_offset;
269 
270 	return (DW_DLV_OK);
271 }
272 
273 int
dwarf_die_CU_offset(Dwarf_Die die,Dwarf_Off * ret_offset,Dwarf_Error * error)274 dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
275 {
276 	Dwarf_Debug dbg;
277 	Dwarf_CU cu;
278 
279 	dbg = die != NULL ? die->die_dbg : NULL;
280 
281 	if (die == NULL || ret_offset == NULL) {
282 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
283 		return (DW_DLV_ERROR);
284 	}
285 
286 	cu = die->die_cu;
287 	assert(cu != NULL);
288 
289 	*ret_offset = die->die_offset - cu->cu_offset;
290 
291 	return (DW_DLV_OK);
292 }
293 
294 int
dwarf_die_CU_offset_range(Dwarf_Die die,Dwarf_Off * cu_offset,Dwarf_Off * cu_length,Dwarf_Error * error)295 dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset,
296     Dwarf_Off *cu_length, Dwarf_Error *error)
297 {
298 	Dwarf_Debug dbg;
299 	Dwarf_CU cu;
300 
301 	dbg = die != NULL ? die->die_dbg : NULL;
302 
303 	if (die == NULL || cu_offset == NULL || cu_length == NULL) {
304 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
305 		return (DW_DLV_ERROR);
306 	}
307 
308 	cu = die->die_cu;
309 	assert(cu != NULL);
310 
311 	*cu_offset = cu->cu_offset;
312 	*cu_length = cu->cu_length + cu->cu_length_size;
313 
314 	return (DW_DLV_OK);
315 }
316 
317 int
dwarf_diename(Dwarf_Die die,char ** ret_name,Dwarf_Error * error)318 dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error)
319 {
320 	Dwarf_Debug dbg;
321 
322 	dbg = die != NULL ? die->die_dbg : NULL;
323 
324 	if (die == NULL || ret_name == NULL) {
325 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
326 		return (DW_DLV_ERROR);
327 	}
328 
329 	if (die->die_name == NULL) {
330 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
331 		return (DW_DLV_NO_ENTRY);
332 	}
333 
334 	*ret_name = die->die_name;
335 
336 	return (DW_DLV_OK);
337 }
338 
339 int
dwarf_die_abbrev_code(Dwarf_Die die)340 dwarf_die_abbrev_code(Dwarf_Die die)
341 {
342 
343 	assert(die != NULL);
344 
345 	return (die->die_abnum);
346 }
347 
348 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)349 dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg,
350     Dwarf_Off in_cu_header_offset, Dwarf_Bool is_info,
351     Dwarf_Off *out_cu_die_offset, Dwarf_Error *error)
352 {
353 	Dwarf_CU cu;
354 
355 	if (dbg == NULL || out_cu_die_offset == NULL) {
356 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
357 		return (DW_DLV_ERROR);
358 	}
359 
360 	if (is_info) {
361 		STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
362 			if (cu->cu_offset == in_cu_header_offset) {
363 				*out_cu_die_offset = cu->cu_1st_offset;
364 				break;
365 			}
366 		}
367 	} else {
368 		STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) {
369 			if (cu->cu_offset == in_cu_header_offset) {
370 				*out_cu_die_offset = cu->cu_1st_offset;
371 				break;
372 			}
373 		}
374 	}
375 
376 	if (cu == NULL) {
377 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
378 		return (DW_DLV_NO_ENTRY);
379 	}
380 
381 	return (DW_DLV_OK);
382 }
383 
384 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)385 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
386     Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset,
387     Dwarf_Error *error)
388 {
389 
390 	return (dwarf_get_cu_die_offset_given_cu_header_offset_b(dbg,
391 	    in_cu_header_offset, 1, out_cu_die_offset, error));
392 }
393 
394 int
dwarf_get_address_size(Dwarf_Debug dbg,Dwarf_Half * addr_size,Dwarf_Error * error)395 dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size,
396     Dwarf_Error *error)
397 {
398 
399 	if (dbg == NULL || addr_size == NULL) {
400 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
401 		return (DW_DLV_ERROR);
402 	}
403 
404 	*addr_size = dbg->dbg_pointer_size;
405 
406 	return (DW_DLV_OK);
407 }
408 
409 Dwarf_Bool
dwarf_get_die_infotypes_flag(Dwarf_Die die)410 dwarf_get_die_infotypes_flag(Dwarf_Die die)
411 {
412 
413 	assert(die != NULL);
414 
415 	return (die->die_cu->cu_is_info);
416 }
417