1 /* $NetBSD: libdwarf_abbrev.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) 2009-2011 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_abbrev.c,v 1.6 2026/05/17 21:40:49 jkoshy Exp $"); 33 ELFTC_VCSID("Id: libdwarf_abbrev.c 4049 2024-07-20 07:38:17Z jkoshy"); 34 35 static int 36 _dwarf_abbrev_allocate(Dwarf_Debug dbg, Dwarf_Abbrev *abp, 37 Dwarf_Error *error) 38 { 39 Dwarf_Abbrev ab; 40 41 if ((ab = calloc(1, sizeof(struct _Dwarf_Abbrev))) == NULL) { 42 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 43 return (DW_DLE_MEMORY); 44 } 45 46 /* Initialise the list of attribute definitions. */ 47 STAILQ_INIT(&ab->ab_attrdef); 48 49 *abp = ab; 50 51 return (DW_DLE_NONE); 52 } 53 54 static void 55 _dwarf_abbrev_release(Dwarf_Abbrev ab) { 56 Dwarf_AttrDef ad, tad; 57 58 STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) { 59 STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef, 60 ad_next); 61 free(ad); 62 } 63 64 free(ab); 65 } 66 67 int 68 _dwarf_abbrev_add(Dwarf_CU cu, uint64_t entry, uint64_t tag, uint8_t children, 69 uint64_t aboff, Dwarf_Abbrev *abp, Dwarf_Error *error) 70 { 71 Dwarf_Abbrev ab; 72 Dwarf_Debug dbg; 73 int ret; 74 75 dbg = cu != NULL ? cu->cu_dbg : NULL; 76 77 if ((ret = _dwarf_abbrev_allocate(dbg, &ab, error)) != DW_DLE_NONE) 78 return (ret); 79 80 /* Initialise the abbrev structure. */ 81 ab->ab_entry = entry; 82 ab->ab_tag = tag; 83 ab->ab_children = children; 84 ab->ab_offset = aboff; 85 ab->ab_length = 0; /* fill in later. */ 86 ab->ab_atnum = 0; /* fill in later. */ 87 88 /* Add the abbrev to the hash table of the compilation unit. */ 89 if (cu != NULL) 90 HASH_ADD(ab_hh, cu->cu_abbrev_hash, ab_entry, 91 sizeof(ab->ab_entry), ab); 92 93 *abp = ab; 94 return (DW_DLE_NONE); 95 } 96 97 int 98 _dwarf_attrdef_add(Dwarf_Debug dbg, Dwarf_Abbrev ab, uint64_t attr, 99 uint64_t form, int64_t ic, uint64_t adoff, Dwarf_AttrDef *adp, 100 Dwarf_Error *error) 101 { 102 Dwarf_AttrDef ad; 103 104 if (ab == NULL) { 105 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT); 106 return (DW_DLE_ARGUMENT); 107 } 108 109 if ((ad = malloc(sizeof(struct _Dwarf_AttrDef))) == NULL) { 110 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 111 return (DW_DLE_MEMORY); 112 } 113 114 /* Initialise the attribute definition structure. */ 115 ad->ad_attrib = attr; 116 ad->ad_form = form; 117 ad->ad_const = ic; 118 ad->ad_offset = adoff; 119 120 /* Add the attribute definition to the list in the abbrev. */ 121 STAILQ_INSERT_TAIL(&ab->ab_attrdef, ad, ad_next); 122 123 /* Increase number of attribute counter. */ 124 ab->ab_atnum++; 125 126 if (adp != NULL) 127 *adp = ad; 128 129 return (DW_DLE_NONE); 130 } 131 132 int 133 _dwarf_abbrev_parse(Dwarf_Debug dbg, Dwarf_CU cu, Dwarf_Unsigned *offset, 134 Dwarf_Abbrev *abp, Dwarf_Error *error) 135 { 136 Dwarf_Section *ds; 137 uint64_t attr; 138 uint64_t entry; 139 uint64_t form; 140 uint64_t aboff; 141 uint64_t adoff; 142 uint64_t tag; 143 int64_t ic; 144 uint8_t children; 145 int ret; 146 147 assert(abp != NULL); 148 149 ds = _dwarf_find_section(dbg, ".debug_abbrev"); 150 if (ds == NULL || *offset >= ds->ds_size) 151 return (DW_DLE_NO_ENTRY); 152 153 aboff = *offset; 154 155 entry = _dwarf_read_uleb128(ds->ds_data, offset); 156 if (entry == 0) { 157 /* Last entry. */ 158 ret = _dwarf_abbrev_add(cu, entry, 0, 0, aboff, abp, 159 error); 160 if (ret != DW_DLE_NONE) 161 goto error; 162 163 (*abp)->ab_length = 1; 164 return (ret); 165 } 166 tag = _dwarf_read_uleb128(ds->ds_data, offset); 167 children = dbg->read(ds->ds_data, offset, 1); 168 if ((ret = _dwarf_abbrev_add(cu, entry, tag, children, aboff, 169 abp, error)) != DW_DLE_NONE) 170 goto error; 171 172 /* Parse attribute definitions. */ 173 do { 174 adoff = *offset; 175 attr = _dwarf_read_uleb128(ds->ds_data, offset); 176 form = _dwarf_read_uleb128(ds->ds_data, offset); 177 ic = 0; 178 if (form == DW_FORM_implicit_const) { 179 /* 180 * DWARF5 7.5.3: atrribute definition with the form 181 * DW_FORM_implicit_const contains a third part, a 182 * signed LEB128 value indicating a constant value. 183 * No value is needed to store in the .debug_info 184 * as a result. 185 */ 186 ic = _dwarf_read_sleb128(ds->ds_data, offset); 187 } 188 if (attr != 0) { 189 if ((ret = _dwarf_attrdef_add(dbg, *abp, attr, 190 form, ic, adoff, NULL, error)) != DW_DLE_NONE) 191 goto error; 192 } 193 } while (attr != 0); 194 195 (*abp)->ab_length = *offset - aboff; 196 197 return (ret); 198 199 error: 200 _dwarf_abbrev_release(*abp); 201 202 return (ret); 203 } 204 205 int 206 _dwarf_abbrev_find(Dwarf_CU cu, uint64_t entry, Dwarf_Abbrev *abp, 207 Dwarf_Error *error) 208 { 209 Dwarf_Abbrev ab; 210 Dwarf_Section *ds; 211 Dwarf_Unsigned offset; 212 int ret; 213 214 if (entry == 0) 215 return (DW_DLE_NO_ENTRY); 216 217 /* Check if the desired abbrev entry is already in the hash table. */ 218 HASH_FIND(ab_hh, cu->cu_abbrev_hash, &entry, sizeof(entry), ab); 219 if (ab != NULL) { 220 *abp = ab; 221 return (DW_DLE_NONE); 222 } 223 224 if (cu->cu_abbrev_loaded) { 225 return (DW_DLE_NO_ENTRY); 226 } 227 228 /* Load and search the abbrev table. */ 229 ds = _dwarf_find_section(cu->cu_dbg, ".debug_abbrev"); 230 if (ds == NULL) 231 return (DW_DLE_NO_ENTRY); 232 233 offset = cu->cu_abbrev_offset_cur; 234 while (offset < ds->ds_size) { 235 ret = _dwarf_abbrev_parse(cu->cu_dbg, cu, &offset, &ab, error); 236 if (ret != DW_DLE_NONE) 237 return (ret); 238 if (ab->ab_entry == entry) { 239 cu->cu_abbrev_offset_cur = offset; 240 *abp = ab; 241 return (DW_DLE_NONE); 242 } 243 if (ab->ab_entry == 0) { 244 cu->cu_abbrev_offset_cur = offset; 245 cu->cu_abbrev_loaded = 1; 246 break; 247 } 248 } 249 250 return (DW_DLE_NO_ENTRY); 251 } 252 253 void 254 _dwarf_abbrev_cleanup(Dwarf_CU cu) 255 { 256 Dwarf_Abbrev ab, tab; 257 258 assert(cu != NULL); 259 260 HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) { 261 HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab); 262 _dwarf_abbrev_release(ab); 263 } 264 } 265 266 int 267 _dwarf_abbrev_gen(Dwarf_P_Debug dbg, Dwarf_Error *error) 268 { 269 Dwarf_CU cu; 270 Dwarf_Abbrev ab; 271 Dwarf_AttrDef ad; 272 Dwarf_P_Section ds; 273 int ret; 274 275 cu = STAILQ_FIRST(&dbg->dbg_cu); 276 if (cu == NULL) 277 return (DW_DLE_NONE); 278 279 /* Create .debug_abbrev section. */ 280 if ((ret = _dwarf_section_init(dbg, &ds, ".debug_abbrev", 0, error)) != 281 DW_DLE_NONE) 282 return (ret); 283 284 for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) { 285 RCHECK(WRITE_ULEB128(ab->ab_entry)); 286 RCHECK(WRITE_ULEB128(ab->ab_tag)); 287 RCHECK(WRITE_VALUE(ab->ab_children, 1)); 288 STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) { 289 RCHECK(WRITE_ULEB128(ad->ad_attrib)); 290 RCHECK(WRITE_ULEB128(ad->ad_form)); 291 } 292 /* Signal end of attribute spec list. */ 293 RCHECK(WRITE_ULEB128(0)); 294 RCHECK(WRITE_ULEB128(0)); 295 } 296 /* End of abbreviation for this CU. */ 297 RCHECK(WRITE_ULEB128(0)); 298 299 /* Notify the creation of .debug_abbrev ELF section. */ 300 RCHECK(_dwarf_section_callback(dbg, ds, SHT_PROGBITS, 0, 0, 0, error)); 301 302 return (DW_DLE_NONE); 303 304 gen_fail: 305 306 _dwarf_section_free(dbg, &ds); 307 308 return (ret); 309 } 310