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