xref: /freebsd/contrib/elftoolchain/libdwarf/dwarf_die.c (revision 1201c6fd2725b43972488766a6f3754f4e71b065)
12de3b87aSKai Wang /*-
22de3b87aSKai Wang  * Copyright (c) 2007 John Birrell (jb@freebsd.org)
32de3b87aSKai Wang  * Copyright (c) 2009,2011 Kai Wang
42de3b87aSKai Wang  * All rights reserved.
52de3b87aSKai Wang  *
62de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
72de3b87aSKai Wang  * modification, are permitted provided that the following conditions
82de3b87aSKai Wang  * are met:
92de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
102de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
112de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
122de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
132de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
142de3b87aSKai Wang  *
152de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252de3b87aSKai Wang  * SUCH DAMAGE.
262de3b87aSKai Wang  */
272de3b87aSKai Wang 
282de3b87aSKai Wang #include "_libdwarf.h"
292de3b87aSKai Wang 
302de3b87aSKai Wang ELFTC_VCSID("$Id: dwarf_die.c 2073 2011-10-27 03:30:47Z jkoshy $");
312de3b87aSKai Wang 
322de3b87aSKai Wang int
332de3b87aSKai Wang dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error)
342de3b87aSKai Wang {
352de3b87aSKai Wang 	Dwarf_Debug dbg;
362de3b87aSKai Wang 	Dwarf_CU cu;
372de3b87aSKai Wang 	int ret;
382de3b87aSKai Wang 
392de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
402de3b87aSKai Wang 
412de3b87aSKai Wang 	if (die == NULL || ret_die == NULL) {
422de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
432de3b87aSKai Wang 		return (DW_DLV_ERROR);
442de3b87aSKai Wang 	}
452de3b87aSKai Wang 
462de3b87aSKai Wang 	if (die->die_ab->ab_children == DW_CHILDREN_no)
47*1201c6fdSKai Wang 		return (DW_DLV_NO_ENTRY);
482de3b87aSKai Wang 
492de3b87aSKai Wang 	dbg = die->die_dbg;
502de3b87aSKai Wang 	cu = die->die_cu;
512de3b87aSKai Wang 	ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
522de3b87aSKai Wang 	    cu->cu_dwarf_size, die->die_next_off, cu->cu_next_offset,
532de3b87aSKai Wang 	    ret_die, 0, error);
542de3b87aSKai Wang 
552de3b87aSKai Wang 	if (ret == DW_DLE_NO_ENTRY) {
562de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
572de3b87aSKai Wang 		return (DW_DLV_NO_ENTRY);
582de3b87aSKai Wang 	} else if (ret != DW_DLE_NONE)
592de3b87aSKai Wang 		return (DW_DLV_ERROR);
602de3b87aSKai Wang 
612de3b87aSKai Wang 	return (DW_DLV_OK);
622de3b87aSKai Wang }
632de3b87aSKai Wang 
642de3b87aSKai Wang int
652de3b87aSKai Wang dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die,
662de3b87aSKai Wang     Dwarf_Error *error)
672de3b87aSKai Wang {
682de3b87aSKai Wang 	Dwarf_CU cu;
692de3b87aSKai Wang 	Dwarf_Attribute at;
702de3b87aSKai Wang 	uint64_t offset;
712de3b87aSKai Wang 	int ret, search_sibling;
722de3b87aSKai Wang 
732de3b87aSKai Wang 	if (dbg == NULL || ret_die == NULL) {
742de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
752de3b87aSKai Wang 		return (DW_DLV_ERROR);
762de3b87aSKai Wang 	}
772de3b87aSKai Wang 
782de3b87aSKai Wang 	if ((cu = dbg->dbg_cu_current) == NULL) {
792de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT);
802de3b87aSKai Wang 		return (DW_DLV_ERROR);
812de3b87aSKai Wang 	}
822de3b87aSKai Wang 
832de3b87aSKai Wang 	/* Application requests the first DIE in this CU. */
842de3b87aSKai Wang 	if (die == NULL)
852de3b87aSKai Wang 		return (dwarf_offdie(dbg, cu->cu_1st_offset, ret_die,
862de3b87aSKai Wang 		    error));
872de3b87aSKai Wang 
882de3b87aSKai Wang 	/*
892de3b87aSKai Wang 	 * If the DIE doesn't have any children, its sibling sits next
902de3b87aSKai Wang 	 * right to it.
912de3b87aSKai Wang 	 */
922de3b87aSKai Wang 	search_sibling = 0;
932de3b87aSKai Wang 	if (die->die_ab->ab_children == DW_CHILDREN_no)
942de3b87aSKai Wang 		offset = die->die_next_off;
952de3b87aSKai Wang 	else {
962de3b87aSKai Wang 		/*
972de3b87aSKai Wang 		 * Look for DW_AT_sibling attribute for the offset of
982de3b87aSKai Wang 		 * its sibling.
992de3b87aSKai Wang 		 */
1002de3b87aSKai Wang 		if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) {
1012de3b87aSKai Wang 			if (at->at_form != DW_FORM_ref_addr)
1022de3b87aSKai Wang 				offset = at->u[0].u64 + cu->cu_offset;
1032de3b87aSKai Wang 			else
1042de3b87aSKai Wang 				offset = at->u[0].u64;
1052de3b87aSKai Wang 		} else {
1062de3b87aSKai Wang 			offset = die->die_next_off;
1072de3b87aSKai Wang 			search_sibling = 1;
1082de3b87aSKai Wang 		}
1092de3b87aSKai Wang 	}
1102de3b87aSKai Wang 
1112de3b87aSKai Wang 	ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu,
1122de3b87aSKai Wang 	    cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die,
1132de3b87aSKai Wang 	    search_sibling, error);
1142de3b87aSKai Wang 
1152de3b87aSKai Wang 	if (ret == DW_DLE_NO_ENTRY) {
1162de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
1172de3b87aSKai Wang 		return (DW_DLV_NO_ENTRY);
1182de3b87aSKai Wang 	} else if (ret != DW_DLE_NONE)
1192de3b87aSKai Wang 		return (DW_DLV_ERROR);
1202de3b87aSKai Wang 
1212de3b87aSKai Wang 	return (DW_DLV_OK);
1222de3b87aSKai Wang }
1232de3b87aSKai Wang 
1242de3b87aSKai Wang static int
1252de3b87aSKai Wang _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off offset,
1262de3b87aSKai Wang     Dwarf_Die *ret_die, Dwarf_Error *error)
1272de3b87aSKai Wang {
1282de3b87aSKai Wang 
1292de3b87aSKai Wang 	assert(dbg != NULL && cu != NULL && ret_die != NULL);
1302de3b87aSKai Wang 
1312de3b87aSKai Wang 	return (_dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size,
1322de3b87aSKai Wang 	    offset, cu->cu_next_offset, ret_die, 0, error));
1332de3b87aSKai Wang }
1342de3b87aSKai Wang 
1352de3b87aSKai Wang int
1362de3b87aSKai Wang dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die,
1372de3b87aSKai Wang     Dwarf_Error *error)
1382de3b87aSKai Wang {
1392de3b87aSKai Wang 	Dwarf_CU cu;
1402de3b87aSKai Wang 	int ret;
1412de3b87aSKai Wang 
1422de3b87aSKai Wang 	if (dbg == NULL || ret_die == NULL) {
1432de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1442de3b87aSKai Wang 		return (DW_DLV_ERROR);
1452de3b87aSKai Wang 	}
1462de3b87aSKai Wang 
1472de3b87aSKai Wang 	/* First search the current CU. */
1482de3b87aSKai Wang 	if (dbg->dbg_cu_current != NULL) {
1492de3b87aSKai Wang 		cu = dbg->dbg_cu_current;
1502de3b87aSKai Wang 		if (offset > cu->cu_offset && offset < cu->cu_next_offset) {
1512de3b87aSKai Wang 			ret = _dwarf_search_die_within_cu(dbg, cu, offset,
1522de3b87aSKai Wang 			    ret_die, error);
1532de3b87aSKai Wang 			if (ret == DW_DLE_NO_ENTRY) {
1542de3b87aSKai Wang 				DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
1552de3b87aSKai Wang 				return (DW_DLV_NO_ENTRY);
1562de3b87aSKai Wang 			} else if (ret != DW_DLE_NONE)
1572de3b87aSKai Wang 				return (DW_DLV_ERROR);
1582de3b87aSKai Wang 			return (DW_DLV_OK);
1592de3b87aSKai Wang 		}
1602de3b87aSKai Wang 	}
1612de3b87aSKai Wang 
1622de3b87aSKai Wang 	/* Search other CUs. */
1632de3b87aSKai Wang 	ret = _dwarf_info_load(dbg, 1, error);
1642de3b87aSKai Wang 	if (ret != DW_DLE_NONE)
1652de3b87aSKai Wang 		return (DW_DLV_ERROR);
1662de3b87aSKai Wang 
1672de3b87aSKai Wang 	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
1682de3b87aSKai Wang 		if (offset < cu->cu_offset || offset > cu->cu_next_offset)
1692de3b87aSKai Wang 			continue;
1702de3b87aSKai Wang 		ret = _dwarf_search_die_within_cu(dbg, cu, offset,
1712de3b87aSKai Wang 		    ret_die, error);
1722de3b87aSKai Wang 		if (ret == DW_DLE_NO_ENTRY) {
1732de3b87aSKai Wang 			DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
1742de3b87aSKai Wang 			return (DW_DLV_NO_ENTRY);
1752de3b87aSKai Wang 		} else if (ret != DW_DLE_NONE)
1762de3b87aSKai Wang 			return (DW_DLV_ERROR);
1772de3b87aSKai Wang 		return (DW_DLV_OK);
1782de3b87aSKai Wang 	}
1792de3b87aSKai Wang 
1802de3b87aSKai Wang 	DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
1812de3b87aSKai Wang 	return (DW_DLV_NO_ENTRY);
1822de3b87aSKai Wang }
1832de3b87aSKai Wang 
1842de3b87aSKai Wang int
1852de3b87aSKai Wang dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error)
1862de3b87aSKai Wang {
1872de3b87aSKai Wang 	Dwarf_Debug dbg;
1882de3b87aSKai Wang 
1892de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
1902de3b87aSKai Wang 
1912de3b87aSKai Wang 	if (die == NULL || tag == NULL) {
1922de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
1932de3b87aSKai Wang 		return (DW_DLV_ERROR);
1942de3b87aSKai Wang 	}
1952de3b87aSKai Wang 
1962de3b87aSKai Wang 	assert(die->die_ab != NULL);
1972de3b87aSKai Wang 
1982de3b87aSKai Wang 	*tag = (Dwarf_Half) die->die_ab->ab_tag;
1992de3b87aSKai Wang 
2002de3b87aSKai Wang 	return (DW_DLV_OK);
2012de3b87aSKai Wang }
2022de3b87aSKai Wang 
2032de3b87aSKai Wang int
2042de3b87aSKai Wang dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
2052de3b87aSKai Wang {
2062de3b87aSKai Wang 	Dwarf_Debug dbg;
2072de3b87aSKai Wang 
2082de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
2092de3b87aSKai Wang 
2102de3b87aSKai Wang 	if (die == NULL || ret_offset == NULL) {
2112de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2122de3b87aSKai Wang 		return (DW_DLV_ERROR);
2132de3b87aSKai Wang 	}
2142de3b87aSKai Wang 
2152de3b87aSKai Wang 	*ret_offset = die->die_offset;
2162de3b87aSKai Wang 
2172de3b87aSKai Wang 	return (DW_DLV_OK);
2182de3b87aSKai Wang }
2192de3b87aSKai Wang 
2202de3b87aSKai Wang int
2212de3b87aSKai Wang dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error)
2222de3b87aSKai Wang {
2232de3b87aSKai Wang 	Dwarf_Debug dbg;
2242de3b87aSKai Wang 	Dwarf_CU cu;
2252de3b87aSKai Wang 
2262de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
2272de3b87aSKai Wang 
2282de3b87aSKai Wang 	if (die == NULL || ret_offset == NULL) {
2292de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2302de3b87aSKai Wang 		return (DW_DLV_ERROR);
2312de3b87aSKai Wang 	}
2322de3b87aSKai Wang 
2332de3b87aSKai Wang 	cu = die->die_cu;
2342de3b87aSKai Wang 	assert(cu != NULL);
2352de3b87aSKai Wang 
2362de3b87aSKai Wang 	*ret_offset = die->die_offset - cu->cu_offset;
2372de3b87aSKai Wang 
2382de3b87aSKai Wang 	return (DW_DLV_OK);
2392de3b87aSKai Wang }
2402de3b87aSKai Wang 
2412de3b87aSKai Wang int
2422de3b87aSKai Wang dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset,
2432de3b87aSKai Wang     Dwarf_Off *cu_length, Dwarf_Error *error)
2442de3b87aSKai Wang {
2452de3b87aSKai Wang 	Dwarf_Debug dbg;
2462de3b87aSKai Wang 	Dwarf_CU cu;
2472de3b87aSKai Wang 
2482de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
2492de3b87aSKai Wang 
2502de3b87aSKai Wang 	if (die == NULL || cu_offset == NULL || cu_length == NULL) {
2512de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2522de3b87aSKai Wang 		return (DW_DLV_ERROR);
2532de3b87aSKai Wang 	}
2542de3b87aSKai Wang 
2552de3b87aSKai Wang 	cu = die->die_cu;
2562de3b87aSKai Wang 	assert(cu != NULL);
2572de3b87aSKai Wang 
2582de3b87aSKai Wang 	*cu_offset = cu->cu_offset;
2592de3b87aSKai Wang 	*cu_length = cu->cu_length + cu->cu_length_size;
2602de3b87aSKai Wang 
2612de3b87aSKai Wang 	return (DW_DLV_OK);
2622de3b87aSKai Wang }
2632de3b87aSKai Wang 
2642de3b87aSKai Wang int
2652de3b87aSKai Wang dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error)
2662de3b87aSKai Wang {
2672de3b87aSKai Wang 	Dwarf_Debug dbg;
2682de3b87aSKai Wang 
2692de3b87aSKai Wang 	dbg = die != NULL ? die->die_dbg : NULL;
2702de3b87aSKai Wang 
2712de3b87aSKai Wang 	if (die == NULL || ret_name == NULL) {
2722de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
2732de3b87aSKai Wang 		return (DW_DLV_ERROR);
2742de3b87aSKai Wang 	}
2752de3b87aSKai Wang 
2762de3b87aSKai Wang 	if (die->die_name == NULL) {
2772de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
2782de3b87aSKai Wang 		return (DW_DLV_NO_ENTRY);
2792de3b87aSKai Wang 	}
2802de3b87aSKai Wang 
2812de3b87aSKai Wang 	*ret_name = die->die_name;
2822de3b87aSKai Wang 
2832de3b87aSKai Wang 	return (DW_DLV_OK);
2842de3b87aSKai Wang }
2852de3b87aSKai Wang 
2862de3b87aSKai Wang int
2872de3b87aSKai Wang dwarf_die_abbrev_code(Dwarf_Die die)
2882de3b87aSKai Wang {
2892de3b87aSKai Wang 
2902de3b87aSKai Wang 	assert(die != NULL);
2912de3b87aSKai Wang 
2922de3b87aSKai Wang 	return (die->die_abnum);
2932de3b87aSKai Wang }
2942de3b87aSKai Wang 
2952de3b87aSKai Wang int
2962de3b87aSKai Wang dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg,
2972de3b87aSKai Wang     Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset,
2982de3b87aSKai Wang     Dwarf_Error *error)
2992de3b87aSKai Wang {
3002de3b87aSKai Wang 	Dwarf_CU cu;
3012de3b87aSKai Wang 
3022de3b87aSKai Wang 	if (dbg == NULL || out_cu_die_offset == NULL) {
3032de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
3042de3b87aSKai Wang 		return (DW_DLV_ERROR);
3052de3b87aSKai Wang 	}
3062de3b87aSKai Wang 
3072de3b87aSKai Wang 	STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) {
3082de3b87aSKai Wang 		if (cu->cu_offset == in_cu_header_offset) {
3092de3b87aSKai Wang 			*out_cu_die_offset = cu->cu_1st_offset;
3102de3b87aSKai Wang 			break;
3112de3b87aSKai Wang 		}
3122de3b87aSKai Wang 	}
3132de3b87aSKai Wang 
3142de3b87aSKai Wang 	if (cu == NULL) {
3152de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
3162de3b87aSKai Wang 		return (DW_DLV_NO_ENTRY);
3172de3b87aSKai Wang 	}
3182de3b87aSKai Wang 
3192de3b87aSKai Wang 	return (DW_DLV_OK);
3202de3b87aSKai Wang }
3212de3b87aSKai Wang 
3222de3b87aSKai Wang int
3232de3b87aSKai Wang dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size,
3242de3b87aSKai Wang     Dwarf_Error *error)
3252de3b87aSKai Wang {
3262de3b87aSKai Wang 
3272de3b87aSKai Wang 	if (dbg == NULL || addr_size == NULL) {
3282de3b87aSKai Wang 		DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
3292de3b87aSKai Wang 		return (DW_DLV_ERROR);
3302de3b87aSKai Wang 	}
3312de3b87aSKai Wang 
3322de3b87aSKai Wang 	*addr_size = dbg->dbg_pointer_size;
3332de3b87aSKai Wang 
3342de3b87aSKai Wang 	return (DW_DLV_OK);
3352de3b87aSKai Wang }
336