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 $");
33ELFTC_VCSID("Id: dwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27");
34
35int
36dwarf_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
68int
69dwarf_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
141int
142dwarf_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
149static int
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
160int
161dwarf_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
229int
230dwarf_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
237int
238dwarf_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
256int
257dwarf_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
273int
274dwarf_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
294int
295dwarf_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
317int
318dwarf_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
339int
340dwarf_die_abbrev_code(Dwarf_Die die)
341{
342
343	assert(die != NULL);
344
345	return (die->die_abnum);
346}
347
348int
349dwarf_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
384int
385dwarf_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
394int
395dwarf_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
409Dwarf_Bool
410dwarf_get_die_infotypes_flag(Dwarf_Die die)
411{
412
413	assert(die != NULL);
414
415	return (die->die_cu->cu_is_info);
416}
417