1 /*- 2 * Copyright (c) 2007 John Birrell (jb@freebsd.org) 3 * Copyright (c) 2009,2011 Kai Wang 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include "_libdwarf.h" 29 30 ELFTC_VCSID("$Id: dwarf_die.c 2073 2011-10-27 03:30:47Z jkoshy $"); 31 32 int 33 dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error) 34 { 35 Dwarf_Debug dbg; 36 Dwarf_CU cu; 37 int ret; 38 39 dbg = die != NULL ? die->die_dbg : NULL; 40 41 if (die == NULL || ret_die == NULL) { 42 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 43 return (DW_DLV_ERROR); 44 } 45 46 if (die->die_ab->ab_children == DW_CHILDREN_no) 47 return (DW_DLV_NO_ENTRY); 48 49 dbg = die->die_dbg; 50 cu = die->die_cu; 51 ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu, 52 cu->cu_dwarf_size, die->die_next_off, cu->cu_next_offset, 53 ret_die, 0, error); 54 55 if (ret == DW_DLE_NO_ENTRY) { 56 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 57 return (DW_DLV_NO_ENTRY); 58 } else if (ret != DW_DLE_NONE) 59 return (DW_DLV_ERROR); 60 61 return (DW_DLV_OK); 62 } 63 64 int 65 dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, 66 Dwarf_Error *error) 67 { 68 Dwarf_CU cu; 69 Dwarf_Attribute at; 70 uint64_t offset; 71 int ret, search_sibling; 72 73 if (dbg == NULL || ret_die == NULL) { 74 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 75 return (DW_DLV_ERROR); 76 } 77 78 if ((cu = dbg->dbg_cu_current) == NULL) { 79 DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); 80 return (DW_DLV_ERROR); 81 } 82 83 /* Application requests the first DIE in this CU. */ 84 if (die == NULL) 85 return (dwarf_offdie(dbg, cu->cu_1st_offset, ret_die, 86 error)); 87 88 /* 89 * If the DIE doesn't have any children, its sibling sits next 90 * right to it. 91 */ 92 search_sibling = 0; 93 if (die->die_ab->ab_children == DW_CHILDREN_no) 94 offset = die->die_next_off; 95 else { 96 /* 97 * Look for DW_AT_sibling attribute for the offset of 98 * its sibling. 99 */ 100 if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) { 101 if (at->at_form != DW_FORM_ref_addr) 102 offset = at->u[0].u64 + cu->cu_offset; 103 else 104 offset = at->u[0].u64; 105 } else { 106 offset = die->die_next_off; 107 search_sibling = 1; 108 } 109 } 110 111 ret = _dwarf_die_parse(die->die_dbg, dbg->dbg_info_sec, cu, 112 cu->cu_dwarf_size, offset, cu->cu_next_offset, ret_die, 113 search_sibling, error); 114 115 if (ret == DW_DLE_NO_ENTRY) { 116 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 117 return (DW_DLV_NO_ENTRY); 118 } else if (ret != DW_DLE_NONE) 119 return (DW_DLV_ERROR); 120 121 return (DW_DLV_OK); 122 } 123 124 static int 125 _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Off offset, 126 Dwarf_Die *ret_die, Dwarf_Error *error) 127 { 128 129 assert(dbg != NULL && cu != NULL && ret_die != NULL); 130 131 return (_dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size, 132 offset, cu->cu_next_offset, ret_die, 0, error)); 133 } 134 135 int 136 dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die, 137 Dwarf_Error *error) 138 { 139 Dwarf_CU cu; 140 int ret; 141 142 if (dbg == NULL || ret_die == NULL) { 143 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 144 return (DW_DLV_ERROR); 145 } 146 147 /* First search the current CU. */ 148 if (dbg->dbg_cu_current != NULL) { 149 cu = dbg->dbg_cu_current; 150 if (offset > cu->cu_offset && offset < cu->cu_next_offset) { 151 ret = _dwarf_search_die_within_cu(dbg, cu, offset, 152 ret_die, error); 153 if (ret == DW_DLE_NO_ENTRY) { 154 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 155 return (DW_DLV_NO_ENTRY); 156 } else if (ret != DW_DLE_NONE) 157 return (DW_DLV_ERROR); 158 return (DW_DLV_OK); 159 } 160 } 161 162 /* Search other CUs. */ 163 ret = _dwarf_info_load(dbg, 1, error); 164 if (ret != DW_DLE_NONE) 165 return (DW_DLV_ERROR); 166 167 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 168 if (offset < cu->cu_offset || offset > cu->cu_next_offset) 169 continue; 170 ret = _dwarf_search_die_within_cu(dbg, cu, offset, 171 ret_die, error); 172 if (ret == DW_DLE_NO_ENTRY) { 173 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 174 return (DW_DLV_NO_ENTRY); 175 } else if (ret != DW_DLE_NONE) 176 return (DW_DLV_ERROR); 177 return (DW_DLV_OK); 178 } 179 180 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 181 return (DW_DLV_NO_ENTRY); 182 } 183 184 int 185 dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error) 186 { 187 Dwarf_Debug dbg; 188 189 dbg = die != NULL ? die->die_dbg : NULL; 190 191 if (die == NULL || tag == NULL) { 192 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 193 return (DW_DLV_ERROR); 194 } 195 196 assert(die->die_ab != NULL); 197 198 *tag = (Dwarf_Half) die->die_ab->ab_tag; 199 200 return (DW_DLV_OK); 201 } 202 203 int 204 dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) 205 { 206 Dwarf_Debug dbg; 207 208 dbg = die != NULL ? die->die_dbg : NULL; 209 210 if (die == NULL || ret_offset == NULL) { 211 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 212 return (DW_DLV_ERROR); 213 } 214 215 *ret_offset = die->die_offset; 216 217 return (DW_DLV_OK); 218 } 219 220 int 221 dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) 222 { 223 Dwarf_Debug dbg; 224 Dwarf_CU cu; 225 226 dbg = die != NULL ? die->die_dbg : NULL; 227 228 if (die == NULL || ret_offset == NULL) { 229 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 230 return (DW_DLV_ERROR); 231 } 232 233 cu = die->die_cu; 234 assert(cu != NULL); 235 236 *ret_offset = die->die_offset - cu->cu_offset; 237 238 return (DW_DLV_OK); 239 } 240 241 int 242 dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset, 243 Dwarf_Off *cu_length, Dwarf_Error *error) 244 { 245 Dwarf_Debug dbg; 246 Dwarf_CU cu; 247 248 dbg = die != NULL ? die->die_dbg : NULL; 249 250 if (die == NULL || cu_offset == NULL || cu_length == NULL) { 251 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 252 return (DW_DLV_ERROR); 253 } 254 255 cu = die->die_cu; 256 assert(cu != NULL); 257 258 *cu_offset = cu->cu_offset; 259 *cu_length = cu->cu_length + cu->cu_length_size; 260 261 return (DW_DLV_OK); 262 } 263 264 int 265 dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error) 266 { 267 Dwarf_Debug dbg; 268 269 dbg = die != NULL ? die->die_dbg : NULL; 270 271 if (die == NULL || ret_name == NULL) { 272 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 273 return (DW_DLV_ERROR); 274 } 275 276 if (die->die_name == NULL) { 277 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 278 return (DW_DLV_NO_ENTRY); 279 } 280 281 *ret_name = die->die_name; 282 283 return (DW_DLV_OK); 284 } 285 286 int 287 dwarf_die_abbrev_code(Dwarf_Die die) 288 { 289 290 assert(die != NULL); 291 292 return (die->die_abnum); 293 } 294 295 int 296 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, 297 Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset, 298 Dwarf_Error *error) 299 { 300 Dwarf_CU cu; 301 302 if (dbg == NULL || out_cu_die_offset == NULL) { 303 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 304 return (DW_DLV_ERROR); 305 } 306 307 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 308 if (cu->cu_offset == in_cu_header_offset) { 309 *out_cu_die_offset = cu->cu_1st_offset; 310 break; 311 } 312 } 313 314 if (cu == NULL) { 315 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 316 return (DW_DLV_NO_ENTRY); 317 } 318 319 return (DW_DLV_OK); 320 } 321 322 int 323 dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size, 324 Dwarf_Error *error) 325 { 326 327 if (dbg == NULL || addr_size == NULL) { 328 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 329 return (DW_DLV_ERROR); 330 } 331 332 *addr_size = dbg->dbg_pointer_size; 333 334 return (DW_DLV_OK); 335 } 336