1 /*- 2 * Copyright (c) 2009-2011 Kai Wang 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include "_libdwarf.h" 28 29 ELFTC_VCSID("$Id: libdwarf_arange.c 2070 2011-10-27 03:05:32Z jkoshy $"); 30 31 void 32 _dwarf_arange_cleanup(Dwarf_Debug dbg) 33 { 34 Dwarf_ArangeSet as, tas; 35 Dwarf_Arange ar, tar; 36 37 STAILQ_FOREACH_SAFE(as, &dbg->dbg_aslist, as_next, tas) { 38 STAILQ_FOREACH_SAFE(ar, &as->as_arlist, ar_next, tar) { 39 STAILQ_REMOVE(&as->as_arlist, ar, _Dwarf_Arange, 40 ar_next); 41 free(ar); 42 } 43 STAILQ_REMOVE(&dbg->dbg_aslist, as, _Dwarf_ArangeSet, as_next); 44 free(as); 45 } 46 47 if (dbg->dbg_arange_array) 48 free(dbg->dbg_arange_array); 49 50 dbg->dbg_arange_array = NULL; 51 dbg->dbg_arange_cnt = 0; 52 } 53 54 int 55 _dwarf_arange_init(Dwarf_Debug dbg, Dwarf_Error *error) 56 { 57 Dwarf_CU cu; 58 Dwarf_ArangeSet as; 59 Dwarf_Arange ar; 60 Dwarf_Section *ds; 61 uint64_t offset, dwarf_size, length, addr, range; 62 int i, ret; 63 64 ret = DW_DLE_NONE; 65 66 if ((ds = _dwarf_find_section(dbg, ".debug_aranges")) == NULL) 67 return (DW_DLE_NONE); 68 69 if (!dbg->dbg_info_loaded) { 70 ret = _dwarf_info_load(dbg, 1, error); 71 if (ret != DW_DLE_NONE) 72 return (ret); 73 } 74 75 offset = 0; 76 while (offset < ds->ds_size) { 77 78 if ((as = malloc(sizeof(struct _Dwarf_ArangeSet))) == NULL) { 79 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 80 return (DW_DLE_MEMORY); 81 } 82 STAILQ_INIT(&as->as_arlist); 83 STAILQ_INSERT_TAIL(&dbg->dbg_aslist, as, as_next); 84 85 /* Read in the table header. */ 86 length = dbg->read(ds->ds_data, &offset, 4); 87 if (length == 0xffffffff) { 88 dwarf_size = 8; 89 length = dbg->read(ds->ds_data, &offset, 8); 90 } else 91 dwarf_size = 4; 92 93 as->as_length = length; 94 as->as_version = dbg->read(ds->ds_data, &offset, 2); 95 if (as->as_version != 2) { 96 DWARF_SET_ERROR(dbg, error, DW_DLE_VERSION_STAMP_ERROR); 97 ret = DW_DLE_VERSION_STAMP_ERROR; 98 goto fail_cleanup; 99 } 100 101 as->as_cu_offset = dbg->read(ds->ds_data, &offset, dwarf_size); 102 STAILQ_FOREACH(cu, &dbg->dbg_cu, cu_next) { 103 if (cu->cu_offset == as->as_cu_offset) 104 break; 105 } 106 if (cu == NULL) { 107 DWARF_SET_ERROR(dbg, error, DW_DLE_ARANGE_OFFSET_BAD); 108 ret = DW_DLE_ARANGE_OFFSET_BAD; 109 goto fail_cleanup; 110 } 111 as->as_cu = cu; 112 113 as->as_addrsz = dbg->read(ds->ds_data, &offset, 1); 114 as->as_segsz = dbg->read(ds->ds_data, &offset, 1); 115 116 /* Skip the padding bytes. */ 117 offset = roundup(offset, 2 * as->as_addrsz); 118 119 /* Read in address range descriptors. */ 120 while (offset < ds->ds_size) { 121 addr = dbg->read(ds->ds_data, &offset, as->as_addrsz); 122 range = dbg->read(ds->ds_data, &offset, as->as_addrsz); 123 if (addr == 0 && range == 0) 124 break; 125 if ((ar = calloc(1, sizeof(struct _Dwarf_Arange))) == 126 NULL) { 127 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 128 goto fail_cleanup; 129 } 130 ar->ar_as = as; 131 ar->ar_address = addr; 132 ar->ar_range = range; 133 STAILQ_INSERT_TAIL(&as->as_arlist, ar, ar_next); 134 dbg->dbg_arange_cnt++; 135 } 136 } 137 138 /* Build arange array. */ 139 if (dbg->dbg_arange_cnt > 0) { 140 if ((dbg->dbg_arange_array = malloc(dbg->dbg_arange_cnt * 141 sizeof(struct _Dwarf_Arange))) == NULL) { 142 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 143 ret = DW_DLE_MEMORY; 144 goto fail_cleanup; 145 } 146 147 i = 0; 148 STAILQ_FOREACH(as, &dbg->dbg_aslist, as_next) { 149 STAILQ_FOREACH(ar, &as->as_arlist, ar_next) 150 dbg->dbg_arange_array[i++] = ar; 151 } 152 assert((Dwarf_Unsigned)i == dbg->dbg_arange_cnt); 153 } 154 155 return (DW_DLE_NONE); 156 157 fail_cleanup: 158 159 _dwarf_arange_cleanup(dbg); 160 161 return (ret); 162 } 163 164 int 165 _dwarf_arange_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 166 { 167 Dwarf_P_Section ds; 168 Dwarf_Rel_Section drs; 169 Dwarf_ArangeSet as; 170 Dwarf_Arange ar; 171 uint64_t offset; 172 int ret; 173 174 as = dbg->dbgp_as; 175 assert(as != NULL); 176 if (STAILQ_EMPTY(&as->as_arlist)) 177 return (DW_DLE_NONE); 178 179 as->as_length = 0; 180 as->as_version = 2; 181 as->as_cu_offset = 0; /* We have only one CU. */ 182 as->as_addrsz = dbg->dbg_pointer_size; 183 as->as_segsz = 0; /* XXX */ 184 185 /* Create .debug_arange section. */ 186 if ((ret = _dwarf_section_init(dbg, &ds, ".debug_aranges", 0, error)) != 187 DW_DLE_NONE) 188 goto gen_fail0; 189 190 /* Create relocation section for .debug_aranges */ 191 RCHECK(_dwarf_reloc_section_init(dbg, &drs, ds, error)); 192 193 /* Write section header. */ 194 RCHECK(WRITE_VALUE(as->as_length, 4)); 195 RCHECK(WRITE_VALUE(as->as_version, 2)); 196 RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, dwarf_drt_data_reloc, 4, 197 ds->ds_size, 0, as->as_cu_offset, ".debug_info", error)); 198 RCHECK(WRITE_VALUE(as->as_addrsz, 1)); 199 RCHECK(WRITE_VALUE(as->as_segsz, 1)); 200 201 /* Pad to (2 * address_size) */ 202 offset = roundup(ds->ds_size, 2 * as->as_addrsz); 203 if (offset > ds->ds_size) 204 RCHECK(WRITE_PADDING(0, offset - ds->ds_size)); 205 206 /* Write tuples. */ 207 STAILQ_FOREACH(ar, &as->as_arlist, ar_next) { 208 RCHECK(_dwarf_reloc_entry_add(dbg, drs, ds, 209 dwarf_drt_data_reloc, dbg->dbg_pointer_size, ds->ds_size, 210 ar->ar_symndx, ar->ar_address, NULL, error)); 211 if (ar->ar_esymndx > 0) 212 RCHECK(_dwarf_reloc_entry_add_pair(dbg, drs, ds, 213 dbg->dbg_pointer_size, ds->ds_size, ar->ar_symndx, 214 ar->ar_esymndx, ar->ar_address, ar->ar_eoff, error)); 215 else 216 RCHECK(WRITE_VALUE(ar->ar_range, dbg->dbg_pointer_size)); 217 } 218 RCHECK(WRITE_VALUE(0, dbg->dbg_pointer_size)); 219 RCHECK(WRITE_VALUE(0, dbg->dbg_pointer_size)); 220 221 /* Fill in the length field. */ 222 as->as_length = ds->ds_size - 4; 223 offset = 0; 224 dbg->write(ds->ds_data, &offset, as->as_length, 4); 225 226 /* Inform application the creation of .debug_aranges ELF section. */ 227 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 228 229 /* Finalize relocation section for .debug_aranges */ 230 RCHECK(_dwarf_reloc_section_finalize(dbg, drs, error)); 231 232 return (DW_DLE_NONE); 233 234 gen_fail: 235 _dwarf_reloc_section_free(dbg, &drs); 236 237 gen_fail0: 238 _dwarf_section_free(dbg, &ds); 239 240 return (ret); 241 } 242 243 void 244 _dwarf_arange_pro_cleanup(Dwarf_P_Debug dbg) 245 { 246 Dwarf_ArangeSet as; 247 Dwarf_Arange ar, tar; 248 249 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE); 250 if (dbg->dbgp_as == NULL) 251 return; 252 253 as = dbg->dbgp_as; 254 STAILQ_FOREACH_SAFE(ar, &as->as_arlist, ar_next, tar) { 255 STAILQ_REMOVE(&as->as_arlist, ar, _Dwarf_Arange, ar_next); 256 free(ar); 257 } 258 free(as); 259 dbg->dbgp_as = NULL; 260 } 261