Home | History | Annotate | Line # | Download | only in libdwarf
      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 (at) 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
     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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    340 dwarf_die_abbrev_code(Dwarf_Die die)
    341 {
    342 
    343 	assert(die != NULL);
    344 
    345 	return (die->die_abnum);
    346 }
    347 
    348 int
    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
    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
    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
    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