1 /*- 2 * Copyright (c) 2007 John Birrell (jb@freebsd.org) 3 * Copyright (c) 2009-2011 Kai Wang 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include "_libdwarf.h" 29 30 ELFTC_VCSID("$Id: libdwarf_abbrev.c 3420 2016-02-27 02:14:05Z emaste $"); 31 32 int 33 _dwarf_abbrev_add(Dwarf_CU cu, uint64_t entry, uint64_t tag, uint8_t children, 34 uint64_t aboff, Dwarf_Abbrev *abp, Dwarf_Error *error) 35 { 36 Dwarf_Abbrev ab; 37 Dwarf_Debug dbg; 38 39 dbg = cu != NULL ? cu->cu_dbg : NULL; 40 41 if ((ab = malloc(sizeof(struct _Dwarf_Abbrev))) == NULL) { 42 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 43 return (DW_DLE_MEMORY); 44 } 45 46 /* Initialise the abbrev structure. */ 47 ab->ab_entry = entry; 48 ab->ab_tag = tag; 49 ab->ab_children = children; 50 ab->ab_offset = aboff; 51 ab->ab_length = 0; /* fill in later. */ 52 ab->ab_atnum = 0; /* fill in later. */ 53 54 /* Initialise the list of attribute definitions. */ 55 STAILQ_INIT(&ab->ab_attrdef); 56 57 /* Add the abbrev to the hash table of the compilation unit. */ 58 if (cu != NULL) 59 HASH_ADD(ab_hh, cu->cu_abbrev_hash, ab_entry, 60 sizeof(ab->ab_entry), ab); 61 62 *abp = ab; 63 return (DW_DLE_NONE); 64 } 65 66 int 67 _dwarf_attrdef_add(Dwarf_Debug dbg, Dwarf_Abbrev ab, uint64_t attr, 68 uint64_t form, uint64_t adoff, Dwarf_AttrDef *adp, Dwarf_Error *error) 69 { 70 Dwarf_AttrDef ad; 71 72 if (ab == NULL) { 73 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 74 return (DW_DLE_ARGUMENT); 75 } 76 77 if ((ad = malloc(sizeof(struct _Dwarf_AttrDef))) == NULL) { 78 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 79 return (DW_DLE_MEMORY); 80 } 81 82 /* Initialise the attribute definition structure. */ 83 ad->ad_attrib = attr; 84 ad->ad_form = form; 85 ad->ad_offset = adoff; 86 87 /* Add the attribute definition to the list in the abbrev. */ 88 STAILQ_INSERT_TAIL(&ab->ab_attrdef, ad, ad_next); 89 90 /* Increase number of attribute counter. */ 91 ab->ab_atnum++; 92 93 if (adp != NULL) 94 *adp = ad; 95 96 return (DW_DLE_NONE); 97 } 98 99 int 100 _dwarf_abbrev_parse(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Unsigned *offset, 101 Dwarf_Abbrev *abp, Dwarf_Error *error) 102 { 103 Dwarf_Section *ds; 104 uint64_t attr; 105 uint64_t entry; 106 uint64_t form; 107 uint64_t aboff; 108 uint64_t adoff; 109 uint64_t tag; 110 uint8_t children; 111 int ret; 112 113 assert(abp != NULL); 114 115 ds = _dwarf_find_section(dbg, ".debug_abbrev"); 116 if (ds == NULL || *offset >= ds->ds_size) 117 return (DW_DLE_NO_ENTRY); 118 119 aboff = *offset; 120 121 entry = _dwarf_read_uleb128(ds->ds_data, offset); 122 if (entry == 0) { 123 /* Last entry. */ 124 ret = _dwarf_abbrev_add(cu, entry, 0, 0, aboff, abp, 125 error); 126 if (ret == DW_DLE_NONE) { 127 (*abp)->ab_length = 1; 128 return (ret); 129 } else 130 return (ret); 131 } 132 tag = _dwarf_read_uleb128(ds->ds_data, offset); 133 children = dbg->read(ds->ds_data, offset, 1); 134 if ((ret = _dwarf_abbrev_add(cu, entry, tag, children, aboff, 135 abp, error)) != DW_DLE_NONE) 136 return (ret); 137 138 /* Parse attribute definitions. */ 139 do { 140 adoff = *offset; 141 attr = _dwarf_read_uleb128(ds->ds_data, offset); 142 form = _dwarf_read_uleb128(ds->ds_data, offset); 143 if (attr != 0) 144 if ((ret = _dwarf_attrdef_add(dbg, *abp, attr, 145 form, adoff, NULL, error)) != DW_DLE_NONE) 146 return (ret); 147 } while (attr != 0); 148 149 (*abp)->ab_length = *offset - aboff; 150 151 return (ret); 152 } 153 154 int 155 _dwarf_abbrev_find(Dwarf_CU cu, uint64_t entry, Dwarf_Abbrev *abp, 156 Dwarf_Error *error) 157 { 158 Dwarf_Abbrev ab; 159 Dwarf_Section *ds; 160 Dwarf_Unsigned offset; 161 int ret; 162 163 if (entry == 0) 164 return (DW_DLE_NO_ENTRY); 165 166 /* Check if the desired abbrev entry is already in the hash table. */ 167 HASH_FIND(ab_hh, cu->cu_abbrev_hash, &entry, sizeof(entry), ab); 168 if (ab != NULL) { 169 *abp = ab; 170 return (DW_DLE_NONE); 171 } 172 173 if (cu->cu_abbrev_loaded) { 174 return (DW_DLE_NO_ENTRY); 175 } 176 177 /* Load and search the abbrev table. */ 178 ds = _dwarf_find_section(cu->cu_dbg, ".debug_abbrev"); 179 if (ds == NULL) 180 return (DW_DLE_NO_ENTRY); 181 182 offset = cu->cu_abbrev_offset_cur; 183 while (offset < ds->ds_size) { 184 ret = _dwarf_abbrev_parse(cu->cu_dbg, cu, &offset, &ab, error); 185 if (ret != DW_DLE_NONE) 186 return (ret); 187 if (ab->ab_entry == entry) { 188 cu->cu_abbrev_offset_cur = offset; 189 *abp = ab; 190 return (DW_DLE_NONE); 191 } 192 if (ab->ab_entry == 0) { 193 cu->cu_abbrev_offset_cur = offset; 194 cu->cu_abbrev_loaded = 1; 195 break; 196 } 197 } 198 199 return (DW_DLE_NO_ENTRY); 200 } 201 202 void 203 _dwarf_abbrev_cleanup(Dwarf_CU cu) 204 { 205 Dwarf_Abbrev ab, tab; 206 Dwarf_AttrDef ad, tad; 207 208 assert(cu != NULL); 209 210 HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) { 211 HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab); 212 STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) { 213 STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef, 214 ad_next); 215 free(ad); 216 } 217 free(ab); 218 } 219 } 220 221 int 222 _dwarf_abbrev_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 223 { 224 Dwarf_CU cu; 225 Dwarf_Abbrev ab; 226 Dwarf_AttrDef ad; 227 Dwarf_P_Section ds; 228 int ret; 229 230 cu = STAILQ_FIRST(&dbg->dbg_cu); 231 if (cu == NULL) 232 return (DW_DLE_NONE); 233 234 /* Create .debug_abbrev section. */ 235 if ((ret = _dwarf_section_init(dbg, &ds, ".debug_abbrev", 0, error)) != 236 DW_DLE_NONE) 237 return (ret); 238 239 for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) { 240 RCHECK(WRITE_ULEB128(ab->ab_entry)); 241 RCHECK(WRITE_ULEB128(ab->ab_tag)); 242 RCHECK(WRITE_VALUE(ab->ab_children, 1)); 243 STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) { 244 RCHECK(WRITE_ULEB128(ad->ad_attrib)); 245 RCHECK(WRITE_ULEB128(ad->ad_form)); 246 } 247 /* Signal end of attribute spec list. */ 248 RCHECK(WRITE_ULEB128(0)); 249 RCHECK(WRITE_ULEB128(0)); 250 } 251 /* End of abbreviation for this CU. */ 252 RCHECK(WRITE_ULEB128(0)); 253 254 /* Notify the creation of .debug_abbrev ELF section. */ 255 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 256 257 return (DW_DLE_NONE); 258 259 gen_fail: 260 261 _dwarf_section_free(dbg, &ds); 262 263 return (ret); 264 } 265