1 /* $NetBSD: libdwarf_info.c,v 1.6 2026/05/17 21:40:49 jkoshy Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 John Birrell (jb (at) freebsd.org) 5 * Copyright (c) 2010,2011,2014,2023 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: libdwarf_info.c,v 1.6 2026/05/17 21:40:49 jkoshy Exp $"); 33 ELFTC_VCSID("Id: libdwarf_info.c 4038 2024-03-06 10:17:40Z jkoshy"); 34 35 int 36 _dwarf_info_first_cu(Dwarf_Debug dbg, Dwarf_Error *error) 37 { 38 Dwarf_CU cu; 39 int ret; 40 41 assert(dbg->dbg_cu_current == NULL); 42 cu = STAILQ_FIRST(&dbg->dbg_cu); 43 if (cu != NULL) { 44 dbg->dbg_cu_current = cu; 45 return (DW_DLE_NONE); 46 } 47 48 if (dbg->dbg_info_loaded) 49 return (DW_DLE_NO_ENTRY); 50 51 dbg->dbg_info_off = 0; 52 ret = _dwarf_info_load(dbg, 0, 1, error); 53 if (ret != DW_DLE_NONE) 54 return (ret); 55 56 dbg->dbg_cu_current = STAILQ_FIRST(&dbg->dbg_cu); 57 58 return (DW_DLE_NONE); 59 } 60 61 int 62 _dwarf_info_first_tu(Dwarf_Debug dbg, Dwarf_Error *error) 63 { 64 Dwarf_CU tu; 65 int ret; 66 67 assert(dbg->dbg_tu_current == NULL); 68 tu = STAILQ_FIRST(&dbg->dbg_tu); 69 if (tu != NULL) { 70 dbg->dbg_tu_current = tu; 71 return (DW_DLE_NONE); 72 } 73 74 if (dbg->dbg_types_loaded) 75 return (DW_DLE_NO_ENTRY); 76 77 dbg->dbg_types_off = 0; 78 ret = _dwarf_info_load(dbg, 0, 0, error); 79 if (ret != DW_DLE_NONE) 80 return (ret); 81 82 dbg->dbg_tu_current = STAILQ_FIRST(&dbg->dbg_tu); 83 84 return (DW_DLE_NONE); 85 } 86 87 int 88 _dwarf_info_next_cu(Dwarf_Debug dbg, Dwarf_Error *error) 89 { 90 Dwarf_CU cu; 91 int ret; 92 93 assert(dbg->dbg_cu_current != NULL); 94 cu = STAILQ_NEXT(dbg->dbg_cu_current, cu_next); 95 if (cu != NULL) { 96 dbg->dbg_cu_current = cu; 97 return (DW_DLE_NONE); 98 } 99 100 if (dbg->dbg_info_loaded) { 101 dbg->dbg_cu_current = NULL; 102 return (DW_DLE_NO_ENTRY); 103 } 104 105 ret = _dwarf_info_load(dbg, 0, 1, error); 106 if (ret != DW_DLE_NONE) 107 return (ret); 108 109 dbg->dbg_cu_current = STAILQ_NEXT(dbg->dbg_cu_current, cu_next); 110 111 return (DW_DLE_NONE); 112 } 113 114 int 115 _dwarf_info_next_tu(Dwarf_Debug dbg, Dwarf_Error *error) 116 { 117 Dwarf_CU cu; 118 int ret; 119 120 assert(dbg->dbg_tu_current != NULL); 121 cu = STAILQ_NEXT(dbg->dbg_tu_current, cu_next); 122 if (cu != NULL) { 123 dbg->dbg_tu_current = cu; 124 return (DW_DLE_NONE); 125 } 126 127 if (dbg->dbg_types_loaded) { 128 dbg->dbg_tu_current = NULL; 129 return (DW_DLE_NO_ENTRY); 130 } 131 132 ret = _dwarf_info_load(dbg, 0, 0, error); 133 if (ret != DW_DLE_NONE) 134 return (ret); 135 136 dbg->dbg_tu_current = STAILQ_NEXT(dbg->dbg_tu_current, cu_next); 137 138 return (DW_DLE_NONE); 139 } 140 141 int 142 _dwarf_info_load(Dwarf_Debug dbg, Dwarf_Bool load_all, Dwarf_Bool is_info, 143 Dwarf_Error *error) 144 { 145 Dwarf_CU cu; 146 Dwarf_Section *ds; 147 int dwarf_size, ret; 148 uint64_t length; 149 uint64_t next_offset; 150 uint64_t offset; 151 152 ret = DW_DLE_NONE; 153 154 if (is_info) { 155 if (dbg->dbg_info_loaded) 156 return (ret); 157 offset = dbg->dbg_info_off; 158 ds = dbg->dbg_info_sec; 159 if (ds == NULL) 160 return (DW_DLE_NO_ENTRY); 161 } else { 162 if (dbg->dbg_types_loaded) 163 return (ret); 164 offset = dbg->dbg_types_off; 165 ds = dbg->dbg_types_sec; 166 if (ds == NULL) 167 return (DW_DLE_NO_ENTRY); 168 } 169 170 while (offset < ds->ds_size) { 171 if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) { 172 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 173 return (DW_DLE_MEMORY); 174 } 175 176 cu->cu_dbg = dbg; 177 cu->cu_is_info = is_info; 178 cu->cu_offset = offset; 179 180 length = dbg->read(ds->ds_data, &offset, 4); 181 if (length == 0xffffffff) { 182 length = dbg->read(ds->ds_data, &offset, 8); 183 dwarf_size = 8; 184 } else 185 dwarf_size = 4; 186 cu->cu_dwarf_size = dwarf_size; 187 188 /* 189 * Check if there is enough ELF data for this CU. This assumes 190 * that libelf gives us the entire section in one Elf_Data 191 * object. 192 */ 193 if (length > ds->ds_size - offset) { 194 free(cu); 195 DWARF_SET_ERROR(dbg, error, DW_DLE_CU_LENGTH_ERROR); 196 return (DW_DLE_CU_LENGTH_ERROR); 197 } 198 199 /* Compute the offset to the next compilation unit: */ 200 next_offset = offset + length; 201 if (is_info) 202 dbg->dbg_info_off = next_offset; 203 else 204 dbg->dbg_types_off = next_offset; 205 206 /* Initialise the compilation unit. */ 207 cu->cu_length = length; 208 cu->cu_length_size = (dwarf_size == 4 ? 4 : 12); 209 cu->cu_version = dbg->read(ds->ds_data, &offset, 2); 210 211 /* Verify the DWARF version is supported. */ 212 if (cu->cu_version < 2 || cu->cu_version > 5) { 213 free(cu); 214 DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR); 215 ret = DW_DLE_VERSION_STAMP_ERROR; 216 break; 217 } 218 219 if (cu->cu_version == 5) { 220 /* 221 * DWARF5 has unit_type, abbrev_offset and pointer_size 222 * fields are reordered. 223 */ 224 cu->cu_unit_type = dbg->read(ds->ds_data, &offset, 1); 225 cu->cu_pointer_size = dbg->read(ds->ds_data, &offset, 226 1); 227 cu->cu_abbrev_offset = dbg->read(ds->ds_data, &offset, 228 dwarf_size); 229 } else { 230 /* DWARF4 or lower. */ 231 cu->cu_unit_type = is_info ? DW_UT_compile : DW_UT_type; 232 cu->cu_abbrev_offset = dbg->read(ds->ds_data, &offset, 233 dwarf_size); 234 cu->cu_pointer_size = dbg->read(ds->ds_data, &offset, 235 1); 236 } 237 238 cu->cu_abbrev_offset_cur = cu->cu_abbrev_offset; 239 cu->cu_next_offset = next_offset; 240 241 /* DWARF5 Section 7.5.1.2 defines the dwo_id field. */ 242 if (cu->cu_unit_type == DW_UT_skeleton || 243 cu->cu_unit_type == DW_UT_split_compile) { 244 /* TODO: the ID is implementation defined. */ 245 cu->cu_dwo_id = dbg->read(ds->ds_data, &offset, 8); 246 } 247 248 /* .debug_types extra fields. */ 249 if (!is_info || cu->cu_unit_type == DW_UT_type || 250 cu->cu_unit_type == DW_UT_split_type) { 251 memcpy(cu->cu_type_sig.signature, 252 (char *) ds->ds_data + offset, 8); 253 offset += 8; 254 cu->cu_type_offset = dbg->read(ds->ds_data, &offset, 255 dwarf_size); 256 } 257 258 /* Add the compilation unit to the list. */ 259 if (is_info) 260 STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); 261 else 262 STAILQ_INSERT_TAIL(&dbg->dbg_tu, cu, cu_next); 263 264 cu->cu_1st_offset = offset; 265 266 offset = next_offset; 267 268 if (!load_all) 269 break; 270 } 271 272 if (is_info) { 273 if ((Dwarf_Unsigned) dbg->dbg_info_off >= ds->ds_size) 274 dbg->dbg_info_loaded = 1; 275 } else { 276 if ((Dwarf_Unsigned) dbg->dbg_types_off >= ds->ds_size) 277 dbg->dbg_types_loaded = 1; 278 } 279 280 return (ret); 281 } 282 283 void 284 _dwarf_info_cleanup(Dwarf_Debug dbg) 285 { 286 Dwarf_CU cu, tcu; 287 288 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 289 290 STAILQ_FOREACH_SAFE(cu, &dbg->dbg_cu, cu_next, tcu) { 291 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 292 _dwarf_abbrev_cleanup(cu); 293 if (cu->cu_lineinfo != NULL) { 294 _dwarf_lineno_cleanup(cu->cu_lineinfo); 295 cu->cu_lineinfo = NULL; 296 } 297 free(cu); 298 } 299 300 _dwarf_type_unit_cleanup(dbg); 301 } 302 303 void 304 _dwarf_type_unit_cleanup(Dwarf_Debug dbg) 305 { 306 Dwarf_CU cu, tcu; 307 308 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 309 310 STAILQ_FOREACH_SAFE(cu, &dbg->dbg_tu, cu_next, tcu) { 311 STAILQ_REMOVE(&dbg->dbg_tu, cu, _Dwarf_CU, cu_next); 312 _dwarf_abbrev_cleanup(cu); 313 free(cu); 314 } 315 } 316 317 int 318 _dwarf_info_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 319 { 320 Dwarf_P_Section ds; 321 Dwarf_Rel_Section drs; 322 Dwarf_Unsigned offset; 323 Dwarf_CU cu; 324 int ret; 325 326 assert(dbg != NULL && dbg->write_alloc != NULL); 327 328 if (dbg->dbgp_root_die == NULL) 329 return (DW_DLE_NONE); 330 331 /* Create the single CU for this debugging object. */ 332 if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) { 333 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 334 return (DW_DLE_MEMORY); 335 } 336 cu->cu_dbg = dbg; 337 cu->cu_version = 2; /* DWARF2 */ 338 cu->cu_pointer_size = dbg->dbg_pointer_size; 339 STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); 340 341 /* Create .debug_info section. */ 342 if ((ret = _dwarf_section_init(dbg, &dbg->dbgp_info, ".debug_info", 0, 343 error)) != DW_DLE_NONE) 344 goto gen_fail1; 345 ds = dbg->dbgp_info; 346 347 /* Create relocation section for .debug_init */ 348 if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) != 349 DW_DLE_NONE) 350 goto gen_fail0; 351 352 /* Length placeholder. (We only use 32-bit DWARF format) */ 353 RCHECK(WRITE_VALUE(cu->cu_length, 4)); 354 355 /* Write CU version */ 356 RCHECK(WRITE_VALUE(cu->cu_version, 2)); 357 358 /* 359 * Write abbrev offset. (always 0, we only support single CU) 360 * Also generate a relocation entry for this offset. 361 */ 362 RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, 363 ds->ds_size, 0, cu->cu_abbrev_offset, ".debug_abbrev", error)); 364 365 /* Pointer size. */ 366 RCHECK(WRITE_VALUE(cu->cu_pointer_size, 1)); 367 368 /* Transform the DIE(s) of this CU. */ 369 RCHECK(_dwarf_die_gen(dbg, cu, drs, error)); 370 371 /* Now we can fill in the length of this CU. */ 372 cu->cu_length = ds->ds_size - 4; 373 offset = 0; 374 dbg->write(ds->ds_data, &offset, cu->cu_length, 4); 375 376 /* Inform application the creation of .debug_info ELF section. */ 377 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 378 379 /* 380 * Inform application the creation of relocation section for 381 * .debug_info. 382 */ 383 RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); 384 385 return (DW_DLE_NONE); 386 387 gen_fail: 388 _dwarf_reloc_section_free(dbg, &drs); 389 390 gen_fail0: 391 _dwarf_section_free(dbg, &dbg->dbgp_info); 392 393 gen_fail1: 394 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 395 free(cu); 396 397 return (ret); 398 } 399 400 void 401 _dwarf_info_pro_cleanup(Dwarf_P_Debug dbg) 402 { 403 Dwarf_CU cu; 404 405 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 406 407 cu = STAILQ_FIRST(&dbg->dbg_cu); 408 if (cu != NULL) { 409 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 410 _dwarf_abbrev_cleanup(cu); 411 free(cu); 412 } 413 } 414