1 /* $NetBSD: libdwarf_elf_init.c,v 1.4 2016/03/07 14:32:02 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 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.4 2016/03/07 14:32:02 hannken Exp $"); 32 ELFTC_VCSID("Id: libdwarf_elf_init.c 3161 2015-02-15 21:43:36Z emaste "); 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_loc", 46 ".debug_pubtypes", 47 ".debug_ranges", 48 ".debug_static_func", 49 ".debug_static_vars", 50 ".debug_typenames", 51 ".debug_weaknames", 52 NULL 53 }; 54 55 static void 56 _dwarf_elf_write_reloc(Dwarf_Debug dbg, Elf_Data *symtab_data, int endian, 57 void *buf, uint64_t offset, GElf_Xword r_info, GElf_Sxword r_addend, 58 int is_rel) 59 { 60 GElf_Sym sym; 61 int size; 62 63 if (gelf_getsym(symtab_data, GELF_R_SYM(r_info), &sym) == NULL) 64 return; 65 if ((size = _dwarf_get_reloc_size(dbg, GELF_R_TYPE(r_info))) == 0) 66 return; /* Unknown or non-absolute relocation. */ 67 if (is_rel) { 68 uint64_t roffset = offset; 69 70 if (endian == ELFDATA2MSB) 71 r_addend = _dwarf_read_msb(buf, &roffset, size); 72 else 73 r_addend = _dwarf_read_lsb(buf, &roffset, size); 74 } 75 if (endian == ELFDATA2MSB) 76 _dwarf_write_msb(buf, &offset, sym.st_value + r_addend, size); 77 else 78 _dwarf_write_lsb(buf, &offset, sym.st_value + r_addend, size); 79 } 80 81 static void 82 _dwarf_elf_apply_rel_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data, 83 Elf_Data *symtab_data, int endian) 84 { 85 GElf_Rel rel; 86 int j; 87 88 j = 0; 89 while (gelf_getrel(rel_data, j++, &rel) != NULL) 90 _dwarf_elf_write_reloc(dbg, symtab_data, endian, buf, 91 rel.r_offset, rel.r_info, 0, 1); 92 } 93 94 static void 95 _dwarf_elf_apply_rela_reloc(Dwarf_Debug dbg, void *buf, Elf_Data *rel_data, 96 Elf_Data *symtab_data, int endian) 97 { 98 GElf_Rela rela; 99 int j; 100 101 j = 0; 102 while (gelf_getrela(rel_data, j++, &rela) != NULL) 103 _dwarf_elf_write_reloc(dbg, symtab_data, endian, buf, 104 rela.r_offset, rela.r_info, rela.r_addend, 0); 105 } 106 107 static int 108 _dwarf_elf_relocate(Dwarf_Debug dbg, Elf *elf, Dwarf_Elf_Data *ed, size_t shndx, 109 size_t symtab, Elf_Data *symtab_data, Dwarf_Error *error) 110 { 111 GElf_Ehdr eh; 112 GElf_Shdr sh; 113 Elf_Scn *scn; 114 Elf_Data *rel; 115 int elferr; 116 117 if (symtab == 0 || symtab_data == NULL) 118 return (DW_DLE_NONE); 119 120 if (gelf_getehdr(elf, &eh) == NULL) { 121 DWARF_SET_ELF_ERROR(dbg, error); 122 return (DW_DLE_ELF); 123 } 124 125 scn = NULL; 126 (void) elf_errno(); 127 while ((scn = elf_nextscn(elf, scn)) != NULL) { 128 if (gelf_getshdr(scn, &sh) == NULL) { 129 DWARF_SET_ELF_ERROR(dbg, error); 130 return (DW_DLE_ELF); 131 } 132 133 if ((sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA) || 134 sh.sh_size == 0) 135 continue; 136 137 if (sh.sh_info == shndx && sh.sh_link == symtab) { 138 if ((rel = elf_getdata(scn, NULL)) == NULL) { 139 elferr = elf_errno(); 140 if (elferr != 0) { 141 _DWARF_SET_ERROR(NULL, error, 142 DW_DLE_ELF, elferr); 143 return (DW_DLE_ELF); 144 } else 145 return (DW_DLE_NONE); 146 } 147 148 ed->ed_alloc = malloc(ed->ed_data->d_size); 149 if (ed->ed_alloc == NULL) { 150 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 151 return (DW_DLE_MEMORY); 152 } 153 memcpy(ed->ed_alloc, ed->ed_data->d_buf, 154 ed->ed_data->d_size); 155 if (sh.sh_type == SHT_REL) 156 _dwarf_elf_apply_rel_reloc(dbg, ed->ed_alloc, 157 rel, symtab_data, eh.e_ident[EI_DATA]); 158 else 159 _dwarf_elf_apply_rela_reloc(dbg, ed->ed_alloc, 160 rel, symtab_data, eh.e_ident[EI_DATA]); 161 162 return (DW_DLE_NONE); 163 } 164 } 165 elferr = elf_errno(); 166 if (elferr != 0) { 167 DWARF_SET_ELF_ERROR(dbg, error); 168 return (DW_DLE_ELF); 169 } 170 171 return (DW_DLE_NONE); 172 } 173 174 int 175 _dwarf_elf_init(Dwarf_Debug dbg, Elf *elf, Dwarf_Error *error) 176 { 177 Dwarf_Obj_Access_Interface *iface; 178 Dwarf_Elf_Object *e; 179 const char *name; 180 GElf_Shdr sh; 181 Elf_Scn *scn; 182 Elf_Data *symtab_data; 183 size_t symtab_ndx; 184 int elferr, i, j, n, ret; 185 186 ret = DW_DLE_NONE; 187 188 if ((iface = calloc(1, sizeof(*iface))) == NULL) { 189 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 190 return (DW_DLE_MEMORY); 191 } 192 193 if ((e = calloc(1, sizeof(*e))) == NULL) { 194 free(iface); 195 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY); 196 return (DW_DLE_MEMORY); 197 } 198 199 e->eo_elf = elf; 200 e->eo_methods.get_section_info = _dwarf_elf_get_section_info; 201 e->eo_methods.get_byte_order = _dwarf_elf_get_byte_order; 202 e->eo_methods.get_length_size = _dwarf_elf_get_length_size; 203 e->eo_methods.get_pointer_size = _dwarf_elf_get_pointer_size; 204 e->eo_methods.get_section_count = _dwarf_elf_get_section_count; 205 e->eo_methods.load_section = _dwarf_elf_load_section; 206 207 iface->object = e; 208 iface->methods = &e->eo_methods; 209 210 dbg->dbg_iface = iface; 211 212 if (gelf_getehdr(elf, &e->eo_ehdr) == NULL) { 213 DWARF_SET_ELF_ERROR(dbg, error); 214 ret = DW_DLE_ELF; 215 goto fail_cleanup; 216 } 217 218 dbg->dbg_machine = e->eo_ehdr.e_machine; 219 220 if (!elf_getshstrndx(elf, &e->eo_strndx)) { 221 DWARF_SET_ELF_ERROR(dbg, error); 222 ret = DW_DLE_ELF; 223 goto fail_cleanup; 224 } 225 226 n = 0; 227 symtab_ndx = 0; 228 symtab_data = NULL; 229 scn = NULL; 230 (void) elf_errno(); 231 while ((scn = elf_nextscn(elf, scn)) != NULL) { 232 if (gelf_getshdr(scn, &sh) == NULL) { 233 DWARF_SET_ELF_ERROR(dbg, error); 234 ret = DW_DLE_ELF; 235 goto fail_cleanup; 236 } 237 238 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == 239 NULL) { 240 DWARF_SET_ELF_ERROR(dbg, error); 241 ret = DW_DLE_ELF; 242 goto fail_cleanup; 243 } 244 245 if (!strcmp(name, ".symtab")) { 246 symtab_ndx = elf_ndxscn(scn); 247 if ((symtab_data = elf_getdata(scn, NULL)) == NULL) { 248 elferr = elf_errno(); 249 if (elferr != 0) { 250 _DWARF_SET_ERROR(NULL, error, 251 DW_DLE_ELF, elferr); 252 ret = DW_DLE_ELF; 253 goto fail_cleanup; 254 } 255 } 256 continue; 257 } 258 259 for (i = 0; debug_name[i] != NULL; i++) { 260 if (!strcmp(name, debug_name[i])) 261 n++; 262 } 263 } 264 elferr = elf_errno(); 265 if (elferr != 0) { 266 DWARF_SET_ELF_ERROR(dbg, error); 267 return (DW_DLE_ELF); 268 } 269 270 e->eo_seccnt = n; 271 272 if (n == 0) 273 return (DW_DLE_NONE); 274 275 if ((e->eo_data = calloc(n, sizeof(Dwarf_Elf_Data))) == NULL || 276 (e->eo_shdr = calloc(n, sizeof(GElf_Shdr))) == NULL) { 277 DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY); 278 ret = DW_DLE_MEMORY; 279 goto fail_cleanup; 280 } 281 282 scn = NULL; 283 j = 0; 284 while ((scn = elf_nextscn(elf, scn)) != NULL && j < n) { 285 if (gelf_getshdr(scn, &sh) == NULL) { 286 DWARF_SET_ELF_ERROR(dbg, error); 287 ret = DW_DLE_ELF; 288 goto fail_cleanup; 289 } 290 291 memcpy(&e->eo_shdr[j], &sh, sizeof(sh)); 292 293 if ((name = elf_strptr(elf, e->eo_strndx, sh.sh_name)) == 294 NULL) { 295 DWARF_SET_ELF_ERROR(dbg, error); 296 ret = DW_DLE_ELF; 297 goto fail_cleanup; 298 } 299 300 for (i = 0; debug_name[i] != NULL; i++) { 301 if (strcmp(name, debug_name[i])) 302 continue; 303 304 (void) elf_errno(); 305 if ((e->eo_data[j].ed_data = elf_getdata(scn, NULL)) == 306 NULL) { 307 elferr = elf_errno(); 308 if (elferr != 0) { 309 _DWARF_SET_ERROR(dbg, error, 310 DW_DLE_ELF, elferr); 311 ret = DW_DLE_ELF; 312 goto fail_cleanup; 313 } 314 } 315 316 if (_libdwarf.applyreloc) { 317 if (_dwarf_elf_relocate(dbg, elf, 318 &e->eo_data[j], elf_ndxscn(scn), symtab_ndx, 319 symtab_data, error) != DW_DLE_NONE) 320 goto fail_cleanup; 321 } 322 323 j++; 324 } 325 } 326 327 assert(j == n); 328 329 return (DW_DLE_NONE); 330 331 fail_cleanup: 332 333 _dwarf_elf_deinit(dbg); 334 335 return (ret); 336 } 337 338 void 339 _dwarf_elf_deinit(Dwarf_Debug dbg) 340 { 341 Dwarf_Obj_Access_Interface *iface; 342 Dwarf_Elf_Object *e; 343 int i; 344 345 iface = dbg->dbg_iface; 346 assert(iface != NULL); 347 348 e = iface->object; 349 assert(e != NULL); 350 351 if (e->eo_data) { 352 for (i = 0; (Dwarf_Unsigned) i < e->eo_seccnt; i++) { 353 if (e->eo_data[i].ed_alloc) 354 free(e->eo_data[i].ed_alloc); 355 } 356 free(e->eo_data); 357 } 358 if (e->eo_shdr) 359 free(e->eo_shdr); 360 361 free(e); 362 free(iface); 363 364 dbg->dbg_iface = NULL; 365 } 366