1 /*- 2 * Copyright (c) 2007 John Birrell (jb@freebsd.org) 3 * Copyright (c) 2009,2011,2014 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 3039 2014-05-18 15:10:56Z kaiwang27 $"); 31 32 int 33 dwarf_child(Dwarf_Die die, Dwarf_Die *ret_die, Dwarf_Error *error) 34 { 35 Dwarf_Debug dbg; 36 Dwarf_Section *ds; 37 Dwarf_CU cu; 38 int ret; 39 40 dbg = die != NULL ? die->die_dbg : NULL; 41 42 if (die == NULL || ret_die == NULL) { 43 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 44 return (DW_DLV_ERROR); 45 } 46 47 if (die->die_ab->ab_children == DW_CHILDREN_no) 48 return (DW_DLV_NO_ENTRY); 49 50 dbg = die->die_dbg; 51 cu = die->die_cu; 52 ds = cu->cu_is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; 53 ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size, 54 die->die_next_off, cu->cu_next_offset, ret_die, 0, error); 55 56 if (ret == DW_DLE_NO_ENTRY) { 57 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 58 return (DW_DLV_NO_ENTRY); 59 } else if (ret != DW_DLE_NONE) 60 return (DW_DLV_ERROR); 61 62 return (DW_DLV_OK); 63 } 64 65 int 66 dwarf_siblingof_b(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, 67 Dwarf_Bool is_info, Dwarf_Error *error) 68 { 69 Dwarf_CU cu; 70 Dwarf_Attribute at; 71 Dwarf_Section *ds; 72 uint64_t offset; 73 int ret, search_sibling; 74 75 if (dbg == NULL || ret_die == NULL) { 76 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 77 return (DW_DLV_ERROR); 78 } 79 80 ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; 81 cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current; 82 83 if (cu == NULL) { 84 DWARF_SET_ERROR(dbg, error, DW_DLE_DIE_NO_CU_CONTEXT); 85 return (DW_DLV_ERROR); 86 } 87 88 /* Application requests the first DIE in this CU. */ 89 if (die == NULL) 90 return (dwarf_offdie_b(dbg, cu->cu_1st_offset, is_info, 91 ret_die, error)); 92 93 /* 94 * Check if the `is_info' flag matches the debug section the 95 * DIE belongs to. 96 */ 97 if (is_info != die->die_cu->cu_is_info) { 98 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 99 return (DW_DLV_ERROR); 100 } 101 102 /* 103 * If the DIE doesn't have any children, its sibling sits next 104 * right to it. 105 */ 106 search_sibling = 0; 107 if (die->die_ab->ab_children == DW_CHILDREN_no) 108 offset = die->die_next_off; 109 else { 110 /* 111 * Look for DW_AT_sibling attribute for the offset of 112 * its sibling. 113 */ 114 if ((at = _dwarf_attr_find(die, DW_AT_sibling)) != NULL) { 115 if (at->at_form != DW_FORM_ref_addr) 116 offset = at->u[0].u64 + cu->cu_offset; 117 else 118 offset = at->u[0].u64; 119 } else { 120 offset = die->die_next_off; 121 search_sibling = 1; 122 } 123 } 124 125 ret = _dwarf_die_parse(die->die_dbg, ds, cu, cu->cu_dwarf_size, offset, 126 cu->cu_next_offset, ret_die, search_sibling, error); 127 128 if (ret == DW_DLE_NO_ENTRY) { 129 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 130 return (DW_DLV_NO_ENTRY); 131 } else if (ret != DW_DLE_NONE) 132 return (DW_DLV_ERROR); 133 134 return (DW_DLV_OK); 135 } 136 137 138 int 139 dwarf_siblingof(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Die *ret_die, 140 Dwarf_Error *error) 141 { 142 143 return (dwarf_siblingof_b(dbg, die, ret_die, 1, error)); 144 } 145 146 static int 147 _dwarf_search_die_within_cu(Dwarf_Debug dbg, Dwarf_Section *s, Dwarf_CU cu, 148 Dwarf_Off offset, Dwarf_Die *ret_die, Dwarf_Error *error) 149 { 150 151 assert(dbg != NULL && cu != NULL && ret_die != NULL); 152 153 return (_dwarf_die_parse(dbg, s, cu, cu->cu_dwarf_size, 154 offset, cu->cu_next_offset, ret_die, 0, error)); 155 } 156 157 int 158 dwarf_offdie_b(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Bool is_info, 159 Dwarf_Die *ret_die, Dwarf_Error *error) 160 { 161 Dwarf_Section *ds; 162 Dwarf_CU cu; 163 int ret; 164 165 if (dbg == NULL || ret_die == NULL) { 166 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 167 return (DW_DLV_ERROR); 168 } 169 170 ds = is_info ? dbg->dbg_info_sec : dbg->dbg_types_sec; 171 cu = is_info ? dbg->dbg_cu_current : dbg->dbg_tu_current; 172 173 /* First search the current CU. */ 174 if (cu != NULL) { 175 if (offset > cu->cu_offset && offset < cu->cu_next_offset) { 176 ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, 177 ret_die, error); 178 if (ret == DW_DLE_NO_ENTRY) { 179 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 180 return (DW_DLV_NO_ENTRY); 181 } else if (ret != DW_DLE_NONE) 182 return (DW_DLV_ERROR); 183 return (DW_DLV_OK); 184 } 185 } 186 187 /* Search other CUs. */ 188 ret = _dwarf_info_load(dbg, 1, is_info, error); 189 if (ret != DW_DLE_NONE) 190 return (DW_DLV_ERROR); 191 192 if (is_info) { 193 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 194 if (offset < cu->cu_offset || 195 offset > cu->cu_next_offset) 196 continue; 197 ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, 198 ret_die, error); 199 if (ret == DW_DLE_NO_ENTRY) { 200 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 201 return (DW_DLV_NO_ENTRY); 202 } else if (ret != DW_DLE_NONE) 203 return (DW_DLV_ERROR); 204 return (DW_DLV_OK); 205 } 206 } else { 207 STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) { 208 if (offset < cu->cu_offset || 209 offset > cu->cu_next_offset) 210 continue; 211 ret = _dwarf_search_die_within_cu(dbg, ds, cu, offset, 212 ret_die, error); 213 if (ret == DW_DLE_NO_ENTRY) { 214 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 215 return (DW_DLV_NO_ENTRY); 216 } else if (ret != DW_DLE_NONE) 217 return (DW_DLV_ERROR); 218 return (DW_DLV_OK); 219 } 220 } 221 222 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 223 return (DW_DLV_NO_ENTRY); 224 } 225 226 int 227 dwarf_offdie(Dwarf_Debug dbg, Dwarf_Off offset, Dwarf_Die *ret_die, 228 Dwarf_Error *error) 229 { 230 231 return (dwarf_offdie_b(dbg, offset, 1, ret_die, error)); 232 } 233 234 int 235 dwarf_tag(Dwarf_Die die, Dwarf_Half *tag, Dwarf_Error *error) 236 { 237 Dwarf_Debug dbg; 238 239 dbg = die != NULL ? die->die_dbg : NULL; 240 241 if (die == NULL || tag == NULL) { 242 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 243 return (DW_DLV_ERROR); 244 } 245 246 assert(die->die_ab != NULL); 247 248 *tag = (Dwarf_Half) die->die_ab->ab_tag; 249 250 return (DW_DLV_OK); 251 } 252 253 int 254 dwarf_dieoffset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) 255 { 256 Dwarf_Debug dbg; 257 258 dbg = die != NULL ? die->die_dbg : NULL; 259 260 if (die == NULL || ret_offset == NULL) { 261 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 262 return (DW_DLV_ERROR); 263 } 264 265 *ret_offset = die->die_offset; 266 267 return (DW_DLV_OK); 268 } 269 270 int 271 dwarf_die_CU_offset(Dwarf_Die die, Dwarf_Off *ret_offset, Dwarf_Error *error) 272 { 273 Dwarf_Debug dbg; 274 Dwarf_CU cu; 275 276 dbg = die != NULL ? die->die_dbg : NULL; 277 278 if (die == NULL || ret_offset == NULL) { 279 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 280 return (DW_DLV_ERROR); 281 } 282 283 cu = die->die_cu; 284 assert(cu != NULL); 285 286 *ret_offset = die->die_offset - cu->cu_offset; 287 288 return (DW_DLV_OK); 289 } 290 291 int 292 dwarf_die_CU_offset_range(Dwarf_Die die, Dwarf_Off *cu_offset, 293 Dwarf_Off *cu_length, Dwarf_Error *error) 294 { 295 Dwarf_Debug dbg; 296 Dwarf_CU cu; 297 298 dbg = die != NULL ? die->die_dbg : NULL; 299 300 if (die == NULL || cu_offset == NULL || cu_length == NULL) { 301 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 302 return (DW_DLV_ERROR); 303 } 304 305 cu = die->die_cu; 306 assert(cu != NULL); 307 308 *cu_offset = cu->cu_offset; 309 *cu_length = cu->cu_length + cu->cu_length_size; 310 311 return (DW_DLV_OK); 312 } 313 314 int 315 dwarf_diename(Dwarf_Die die, char **ret_name, Dwarf_Error *error) 316 { 317 Dwarf_Debug dbg; 318 319 dbg = die != NULL ? die->die_dbg : NULL; 320 321 if (die == NULL || ret_name == NULL) { 322 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 323 return (DW_DLV_ERROR); 324 } 325 326 if (die->die_name == NULL) { 327 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 328 return (DW_DLV_NO_ENTRY); 329 } 330 331 *ret_name = die->die_name; 332 333 return (DW_DLV_OK); 334 } 335 336 int 337 dwarf_die_abbrev_code(Dwarf_Die die) 338 { 339 340 assert(die != NULL); 341 342 return (die->die_abnum); 343 } 344 345 int 346 dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg, 347 Dwarf_Off in_cu_header_offset, Dwarf_Bool is_info, 348 Dwarf_Off *out_cu_die_offset, Dwarf_Error *error) 349 { 350 Dwarf_CU cu; 351 352 if (dbg == NULL || out_cu_die_offset == NULL) { 353 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 354 return (DW_DLV_ERROR); 355 } 356 357 if (is_info) { 358 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 359 if (cu->cu_offset == in_cu_header_offset) { 360 *out_cu_die_offset = cu->cu_1st_offset; 361 break; 362 } 363 } 364 } else { 365 STAILQ_FOREACH(cu, &dbg->dbg_tu, cu_next) { 366 if (cu->cu_offset == in_cu_header_offset) { 367 *out_cu_die_offset = cu->cu_1st_offset; 368 break; 369 } 370 } 371 } 372 373 if (cu == NULL) { 374 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY); 375 return (DW_DLV_NO_ENTRY); 376 } 377 378 return (DW_DLV_OK); 379 } 380 381 int 382 dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, 383 Dwarf_Off in_cu_header_offset, Dwarf_Off *out_cu_die_offset, 384 Dwarf_Error *error) 385 { 386 387 return (dwarf_get_cu_die_offset_given_cu_header_offset_b(dbg, 388 in_cu_header_offset, 1, out_cu_die_offset, error)); 389 } 390 391 int 392 dwarf_get_address_size(Dwarf_Debug dbg, Dwarf_Half *addr_size, 393 Dwarf_Error *error) 394 { 395 396 if (dbg == NULL || addr_size == NULL) { 397 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 398 return (DW_DLV_ERROR); 399 } 400 401 *addr_size = dbg->dbg_pointer_size; 402 403 return (DW_DLV_OK); 404 } 405 406 Dwarf_Bool 407 dwarf_get_die_infotypes_flag(Dwarf_Die die) 408 { 409 410 assert(die != NULL); 411 412 return (die->die_cu->cu_is_info); 413 } 414