1 /* $NetBSD: libdwarf_elf_init.c,v 1.6 2024/03/03 17:37:32 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2009,2023 Kai Wang 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "_libdwarf.h" 30 31 __RCSID("$NetBSD: libdwarf_elf_init.c,v 1.6 2024/03/03 17:37:32 christos Exp $"); 32 ELFTC_VCSID("Id: libdwarf_elf_init.c 4016 2023-10-15 05:39:46Z kaiwang27"); 33 34 static const char *debug_name[] = { 35 ".debug_abbrev", 36 ".debug_aranges", 37 ".debug_frame", 38 ".debug_info", 39 ".debug_types", 40 ".debug_line", 41 ".debug_pubnames", 42 ".eh_frame", 43 ".debug_macinfo", 44 ".debug_str", 45 ".debug_line_str", 46 ".debug_loc", 47 ".debug_pubtypes", 48 ".debug_ranges", 49 ".debug_static_func", 50 ".debug_static_vars", 51 ".debug_typenames", 52 ".debug_weaknames", 53 NULL 54 }; 55 56 static void 57 _dwarf_elf_apply_rel_reloc(Dwarf_Debug dbg, void *buf, uint64_t bufsize, 58 Elf_Data *rel_data, Elf_Data *symtab_data, int endian) 59 { 60 Dwarf_Unsigned type; 61 GElf_Rel rel; 62 GElf_Sym sym; 63 size_t symndx; 64 uint64_t offset; 65 uint64_t addend; 66 int size, j; 67 68 j = 0; 69 while (gelf_getrel(rel_data, j++, &rel) != NULL) { 70 symndx = GELF_R_SYM(rel.r_info); 71 type = GELF_R_TYPE(rel.r_info); 72 73 if (gelf_getsym(symtab_data, symndx, &sym) == NULL) 74 continue; 75 76 size = _dwarf_get_reloc_size(dbg, type); 77 if (size == 0) 78 continue; /* Unknown or non-absolute relocation. */ 79 80 offset = rel.r_offset; 81 if (offset + size >= bufsize) 82 continue; 83 84 if (endian == ELFDATA2MSB) 85 addend = _dwarf_read_msb(buf, &offset, size); 86 else 87 addend = _dwarf_read_lsb(buf, &offset, size); 88 89 offset = rel.r_offset; 90 if (endian == ELFDATA2MSB) 91 _dwarf_write_msb(buf, &offset, sym.st_value + addend, 92 size); 93 else 94 _dwarf_write_lsb(buf, &offset, sym.st_value + addend, 95 size); 96 } 97 } 98 99 static void 100 _dwarf_elf_apply_rela_reloc(Dwarf_Debug dbg, void *buf, uint64_t bufsize, 101 Elf_Data *rel_data, Elf_Data *symtab_data, int endian) 102 { 103 Dwarf_Unsigned type; 104 GElf_Rela rela; 105 GElf_Sym sym; 106 size_t symndx; 107 uint64_t offset; 108 int size, j; 109 110 j = 0; 111 while (gelf_getrela(rel_data, j++, &rela) != NULL) { 112 symndx = GELF_R_SYM(rela.r_info); 113 type = GELF_R_TYPE(rela.r_info); 114 115 if (gelf_getsym(symtab_data, symndx, &sym) == NULL) 116 continue; 117 118 offset = rela.r_offset; 119 size = _dwarf_get_reloc_size(dbg, type); 120 if (size == 0) 121 continue; /* Unknown or non-absolute relocation. */ 122 if (offset + size >= bufsize) 123 continue; 124 125 if (endian == ELFDATA2MSB) 126 _dwarf_write_msb(buf, &offset, 127 sym.st_value + rela.r_addend, size); 128 else 129 _dwarf_write_lsb(buf, &offset, 130 sym.st_value + rela.r_addend, size); 131 } 132 } 133 134 static int 135 _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx, 136 size_t symtab, Elf_Data *symtab_data, Dwarf_Error *error) 137 { 138 GElf_Ehdr eh; 139 GElf_Shdr sh; 140 Elf_Scn *scn; 141 Elf_Data *rel; 142 int elferr; 143 144 if (symtab == 0 || symtab_data == NULL) 145 return (DW_DLE_NONE); 146 147 if (gelf_getehdr(elf, &eh) == NULL) { 148 DWARF_SET_ELF_ERROR(dbg, error); 149 return (DW_DLE_ELF); 150 } 151 152 scn = NULL; 153 (void) elf_errno(); 154 while ((scn = elf_nextscn(elf, scn)) != NULL) { 155 if (gelf_getshdr(scn, &sh) == NULL) { 156 DWARF_SET_ELF_ERROR(dbg, error); 157 return (DW_DLE_ELF); 158 } 159 160 if ((sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) || 161 sh.sh_size == 0) 162 continue; 163 164 if (sh.sh_info == shndx && sh.sh_link == symtab) { 165 if ((rel = elf_getdata(scn, NULL)) == NULL) { 166 elferr = elf_errno(); 167 if (elferr != 0) { 168 _DWARF_SET_ERROR(NULL, error, 169 DW_DLE_ELF, elferr); 170 return (DW_DLE_ELF); 171 } else 172 return (DW_DLE_NONE); 173 } 174 175 ed->ed_alloc = malloc(ed->ed_data->d_size); 176 if (ed->ed_alloc == NULL) { 177 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 178 return (DW_DLE_MEMORY); 179 } 180 memcpy(ed->ed_alloc, ed->ed_data->d_buf, 181 ed->ed_data->d_size); 182 if (sh.sh_type == SHT_REL) 183 _dwarf_elf_apply_rel_reloc(dbg, 184 ed->ed_alloc, ed->ed_data->d_size, 185 rel, symtab_data, eh.e_ident[EI_DATA]); 186 else 187 _dwarf_elf_apply_rela_reloc(dbg, 188 ed->ed_alloc, ed->ed_data->d_size, 189 rel, symtab_data, eh.e_ident[EI_DATA]); 190 191 return (DW_DLE_NONE); 192 } 193 } 194 elferr = elf_errno(); 195 if (elferr != 0) { 196 DWARF_SET_ELF_ERROR(dbg, error); 197 return (DW_DLE_ELF); 198 } 199 200 return (DW_DLE_NONE); 201 } 202 203 int 204 _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) 205 { 206 Dwarf_Obj_Access_Interface *iface; 207 Dwarf_Elf_Object *e; 208 const char *name; 209 GElf_Shdr sh; 210 Elf_Scn *scn; 211 Elf_Data *symtab_data; 212 size_t symtab_ndx; 213 int elferr, i, j, n, ret; 214 215 ret = DW_DLE_NONE; 216 217 if ((iface = calloc(1, sizeof(*iface))) == NULL) { 218 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 219 return (DW_DLE_MEMORY); 220 } 221 222 if ((e = calloc(1, sizeof(*e))) == NULL) { 223 free(iface); 224 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 225 return (DW_DLE_MEMORY); 226 } 227 228 e->eo_elf = elf; 229 e->eo_methods.get_section_info = _dwarf_elf_get_section_info; 230 e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order; 231 e->eo_methods.get_length_size = _dwarf_elf_get_length_size; 232 e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size; 233 e->eo_methods.get_section_count = _dwarf_elf_get_section_count; 234 e->eo_methods.load_section = _dwarf_elf_load_section; 235 236 iface->object = e; 237 iface->methods = &e->eo_methods; 238 239 dbg->dbg_iface = iface; 240 241 if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) { 242 DWARF_SET_ELF_ERROR(dbg, error); 243 ret = DW_DLE_ELF; 244 goto fail_cleanup; 245 } 246 247 dbg->dbg_machine = e->eo_ehdr.e_machine; 248 249 if (!elf_getshstrndx(elf, &e->eo_strndx)) { 250 DWARF_SET_ELF_ERROR(dbg, error); 251 ret = DW_DLE_ELF; 252 goto fail_cleanup; 253 } 254 255 n = 0; 256 symtab_ndx = 0; 257 symtab_data = NULL; 258 scn = NULL; 259 (void) elf_errno(); 260 while ((scn = elf_nextscn(elf, scn)) != NULL) { 261 if (gelf_getshdr(scn, &sh) == NULL) { 262 DWARF_SET_ELF_ERROR(dbg, error); 263 ret = DW_DLE_ELF; 264 goto fail_cleanup; 265 } 266 267 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == 268 NULL) { 269 DWARF_SET_ELF_ERROR(dbg, error); 270 ret = DW_DLE_ELF; 271 goto fail_cleanup; 272 } 273 274 if (!strcmp(name, ".symtab")) { 275 symtab_ndx = elf_ndxscn(scn); 276 if ((symtab_data = elf_getdata(scn, NULL)) == NULL) { 277 elferr = elf_errno(); 278 if (elferr != 0) { 279 _DWARF_SET_ERROR(NULL, error, 280 DW_DLE_ELF, elferr); 281 ret = DW_DLE_ELF; 282 goto fail_cleanup; 283 } 284 } 285 continue; 286 } 287 288 for (i = 0; debug_name[i] != NULL; i++) { 289 if (!strcmp(name, debug_name[i])) 290 n++; 291 } 292 } 293 elferr = elf_errno(); 294 if (elferr != 0) { 295 DWARF_SET_ELF_ERROR(dbg, error); 296 return (DW_DLE_ELF); 297 } 298 299 e->eo_seccnt = n; 300 301 if (n == 0) 302 return (DW_DLE_NONE); 303 304 if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL || 305 (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) { 306 DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY); 307 ret = DW_DLE_MEMORY; 308 goto fail_cleanup; 309 } 310 311 scn = NULL; 312 j = 0; 313 while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) { 314 if (gelf_getshdr(scn, &sh) == NULL) { 315 DWARF_SET_ELF_ERROR(dbg, error); 316 ret = DW_DLE_ELF; 317 goto fail_cleanup; 318 } 319 320 memcpy(&e->eo_shdr[j], &sh, sizeof(sh)); 321 322 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == 323 NULL) { 324 DWARF_SET_ELF_ERROR(dbg, error); 325 ret = DW_DLE_ELF; 326 goto fail_cleanup; 327 } 328 329 for (i = 0; debug_name[i] != NULL; i++) { 330 if (strcmp(name, debug_name[i])) 331 continue; 332 333 (void) elf_errno(); 334 if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) == 335 NULL) { 336 elferr = elf_errno(); 337 if (elferr != 0) { 338 _DWARF_SET_ERROR(dbg, error, 339 DW_DLE_ELF, elferr); 340 ret = DW_DLE_ELF; 341 goto fail_cleanup; 342 } 343 } 344 345 if (_libdwarf.applyreloc) { 346 if (_dwarf_elf_relocate(dbg, elf, 347 &e->eo_data[j], elf_ndxscn(scn), symtab_ndx, 348 symtab_data, error) != DW_DLE_NONE) 349 goto fail_cleanup; 350 } 351 352 j++; 353 } 354 } 355 356 assert(j == n); 357 358 return (DW_DLE_NONE); 359 360 fail_cleanup: 361 362 _dwarf_elf_deinit(dbg); 363 364 return (ret); 365 } 366 367 void 368 _dwarf_elf_deinit(Dwarf_Debug dbg) 369 { 370 Dwarf_Obj_Access_Interface *iface; 371 Dwarf_Elf_Object *e; 372 int i; 373 374 iface = dbg->dbg_iface; 375 assert(iface != NULL); 376 377 e = iface->object; 378 assert(e != NULL); 379 380 if (e->eo_data) { 381 for (i = 0; (Dwarf_Unsigned) i < e->eo_seccnt; i++) { 382 if (e->eo_data[i].ed_alloc) 383 free(e->eo_data[i].ed_alloc); 384 } 385 free(e->eo_data); 386 } 387 if (e->eo_shdr) 388 free(e->eo_shdr); 389 390 free(e); 391 free(iface); 392 393 dbg->dbg_iface = NULL; 394 } 395