1 /* $NetBSD: libdwarf_info.c,v 1.5 2024/03/03 17:37:32 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2007 John Birrell (jb@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.5 2024/03/03 17:37:32 christos Exp $"); 33 ELFTC_VCSID("Id: libdwarf_info.c 4013 2023-10-14 22:40:50Z kaiwang27"); 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 DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR); 214 ret = DW_DLE_VERSION_STAMP_ERROR; 215 break; 216 } 217 218 if (cu->cu_version == 5) { 219 /* 220 * DWARF5 has unit_type, abbrev_offset and pointer_size 221 * fields are reordered. 222 */ 223 cu->cu_unit_type = dbg->read(ds->ds_data, &offset, 1); 224 cu->cu_pointer_size = dbg->read(ds->ds_data, &offset, 225 1); 226 cu->cu_abbrev_offset = dbg->read(ds->ds_data, &offset, 227 dwarf_size); 228 } else { 229 /* DWARF4 or lower. */ 230 cu->cu_unit_type = is_info ? DW_UT_compile : DW_UT_type; 231 cu->cu_abbrev_offset = dbg->read(ds->ds_data, &offset, 232 dwarf_size); 233 cu->cu_pointer_size = dbg->read(ds->ds_data, &offset, 234 1); 235 } 236 237 cu->cu_abbrev_offset_cur = cu->cu_abbrev_offset; 238 cu->cu_next_offset = next_offset; 239 240 /* DWARF5 Section 7.5.1.2 defines the dwo_id field. */ 241 if (cu->cu_unit_type == DW_UT_skeleton || 242 cu->cu_unit_type == DW_UT_split_compile) { 243 /* TODO: the ID is implementation defined. */ 244 cu->cu_dwo_id = dbg->read(ds->ds_data, &offset, 8); 245 } 246 247 /* .debug_types extra fields. */ 248 if (!is_info || cu->cu_unit_type == DW_UT_type || 249 cu->cu_unit_type == DW_UT_split_type) { 250 memcpy(cu->cu_type_sig.signature, 251 (char *) ds->ds_data + offset, 8); 252 offset += 8; 253 cu->cu_type_offset = dbg->read(ds->ds_data, &offset, 254 dwarf_size); 255 } 256 257 /* Add the compilation unit to the list. */ 258 if (is_info) 259 STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); 260 else 261 STAILQ_INSERT_TAIL(&dbg->dbg_tu, cu, cu_next); 262 263 cu->cu_1st_offset = offset; 264 265 offset = next_offset; 266 267 if (!load_all) 268 break; 269 } 270 271 if (is_info) { 272 if ((Dwarf_Unsigned) dbg->dbg_info_off >= ds->ds_size) 273 dbg->dbg_info_loaded = 1; 274 } else { 275 if ((Dwarf_Unsigned) dbg->dbg_types_off >= ds->ds_size) 276 dbg->dbg_types_loaded = 1; 277 } 278 279 return (ret); 280 } 281 282 void 283 _dwarf_info_cleanup(Dwarf_Debug dbg) 284 { 285 Dwarf_CU cu, tcu; 286 287 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 288 289 STAILQ_FOREACH_SAFE(cu, &dbg->dbg_cu, cu_next, tcu) { 290 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 291 _dwarf_abbrev_cleanup(cu); 292 if (cu->cu_lineinfo != NULL) { 293 _dwarf_lineno_cleanup(cu->cu_lineinfo); 294 cu->cu_lineinfo = NULL; 295 } 296 free(cu); 297 } 298 299 _dwarf_type_unit_cleanup(dbg); 300 } 301 302 void 303 _dwarf_type_unit_cleanup(Dwarf_Debug dbg) 304 { 305 Dwarf_CU cu, tcu; 306 307 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_READ); 308 309 STAILQ_FOREACH_SAFE(cu, &dbg->dbg_tu, cu_next, tcu) { 310 STAILQ_REMOVE(&dbg->dbg_tu, cu, _Dwarf_CU, cu_next); 311 _dwarf_abbrev_cleanup(cu); 312 free(cu); 313 } 314 } 315 316 int 317 _dwarf_info_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 318 { 319 Dwarf_P_Section ds; 320 Dwarf_Rel_Section drs; 321 Dwarf_Unsigned offset; 322 Dwarf_CU cu; 323 int ret; 324 325 assert(dbg != NULL && dbg->write_alloc != NULL); 326 327 if (dbg->dbgp_root_die == NULL) 328 return (DW_DLE_NONE); 329 330 /* Create the single CU for this debugging object. */ 331 if ((cu = calloc(1, sizeof(struct _Dwarf_CU))) == NULL) { 332 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 333 return (DW_DLE_MEMORY); 334 } 335 cu->cu_dbg = dbg; 336 cu->cu_version = 2; /* DWARF2 */ 337 cu->cu_pointer_size = dbg->dbg_pointer_size; 338 STAILQ_INSERT_TAIL(&dbg->dbg_cu, cu, cu_next); 339 340 /* Create .debug_info section. */ 341 if ((ret = _dwarf_section_init(dbg, &dbg->dbgp_info, ".debug_info", 0, 342 error)) != DW_DLE_NONE) 343 goto gen_fail1; 344 ds = dbg->dbgp_info; 345 346 /* Create relocation section for .debug_init */ 347 if ((ret = _dwarf_reloc_section_init(dbg, &drs, ds, error)) != 348 DW_DLE_NONE) 349 goto gen_fail0; 350 351 /* Length placeholder. (We only use 32-bit DWARF format) */ 352 RCHECK(WRITE_VALUE(cu->cu_length, 4)); 353 354 /* Write CU version */ 355 RCHECK(WRITE_VALUE(cu->cu_version, 2)); 356 357 /* 358 * Write abbrev offset. (always 0, we only support single CU) 359 * Also generate a relocation entry for this offset. 360 */ 361 RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, 362 ds->ds_size, 0, cu->cu_abbrev_offset, ".debug_abbrev", error)); 363 364 /* Pointer size. */ 365 RCHECK(WRITE_VALUE(cu->cu_pointer_size, 1)); 366 367 /* Transform the DIE(s) of this CU. */ 368 RCHECK(_dwarf_die_gen(dbg, cu, drs, error)); 369 370 /* Now we can fill in the length of this CU. */ 371 cu->cu_length = ds->ds_size - 4; 372 offset = 0; 373 dbg->write(ds->ds_data, &offset, cu->cu_length, 4); 374 375 /* Inform application the creation of .debug_info ELF section. */ 376 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 377 378 /* 379 * Inform application the creation of relocation section for 380 * .debug_info. 381 */ 382 RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); 383 384 return (DW_DLE_NONE); 385 386 gen_fail: 387 _dwarf_reloc_section_free(dbg, &drs); 388 389 gen_fail0: 390 _dwarf_section_free(dbg, &dbg->dbgp_info); 391 392 gen_fail1: 393 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 394 free(cu); 395 396 return (ret); 397 } 398 399 void 400 _dwarf_info_pro_cleanup(Dwarf_P_Debug dbg) 401 { 402 Dwarf_CU cu; 403 404 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 405 406 cu = STAILQ_FIRST(&dbg->dbg_cu); 407 if (cu != NULL) { 408 STAILQ_REMOVE(&dbg->dbg_cu, cu, _Dwarf_CU, cu_next); 409 _dwarf_abbrev_cleanup(cu); 410 free(cu); 411 } 412 } 413