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