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@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 $"); 33ELFTC_VCSID("Id: dwarf_die.c 3039 2014-05-18 15:10:56Z kaiwang27"); 34 35int 36dwarf_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 68int 69dwarf_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 141int 142dwarf_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 149static 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 160int 161dwarf_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 229int 230dwarf_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 237int 238dwarf_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 256int 257dwarf_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 273int 274dwarf_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 294int 295dwarf_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 317int 318dwarf_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 339int 340dwarf_die_abbrev_code(Dwarf_Die die) 341{ 342 343 assert(die != NULL); 344 345 return (die->die_abnum); 346} 347 348int 349dwarf_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 384int 385dwarf_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 394int 395dwarf_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 409Dwarf_Bool 410dwarf_get_die_infotypes_flag(Dwarf_Die die) 411{ 412 413 assert(die != NULL); 414 415 return (die->die_cu->cu_is_info); 416} 417