1 /* $OpenBSD: elf.c,v 1.19 2009/10/27 23:59:41 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Michael Shalayeff 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 ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/mman.h> 31 #include <unistd.h> 32 #include <a.out.h> 33 #include <elf_abi.h> 34 #include <errno.h> 35 #include <err.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <ctype.h> 40 #include "elfuncs.h" 41 #include "util.h" 42 43 #if ELFSIZE == 32 44 #define swap_addr swap32 45 #define swap_off swap32 46 #define swap_sword swap32 47 #define swap_word swap32 48 #define swap_sxword swap32 49 #define swap_xword swap32 50 #define swap_half swap16 51 #define swap_quarter swap16 52 #define elf_fix_header elf32_fix_header 53 #define elf_load_shdrs elf32_load_shdrs 54 #define elf_load_phdrs elf32_load_phdrs 55 #define elf_fix_shdrs elf32_fix_shdrs 56 #define elf_fix_phdrs elf32_fix_phdrs 57 #define elf_fix_sym elf32_fix_sym 58 #define elf_size elf32_size 59 #define elf_symloadx elf32_symloadx 60 #define elf_symload elf32_symload 61 #define elf2nlist elf32_2nlist 62 #define elf_shn2type elf32_shn2type 63 #elif ELFSIZE == 64 64 #define swap_addr swap64 65 #define swap_off swap64 66 #ifdef __alpha__ 67 #define swap_sword swap64 68 #define swap_word swap64 69 #else 70 #define swap_sword swap32 71 #define swap_word swap32 72 #endif 73 #define swap_sxword swap64 74 #define swap_xword swap64 75 #define swap_half swap64 76 #define swap_quarter swap16 77 #define elf_fix_header elf64_fix_header 78 #define elf_load_shdrs elf64_load_shdrs 79 #define elf_load_phdrs elf64_load_phdrs 80 #define elf_fix_shdrs elf64_fix_shdrs 81 #define elf_fix_phdrs elf64_fix_phdrs 82 #define elf_fix_sym elf64_fix_sym 83 #define elf_size elf64_size 84 #define elf_symloadx elf64_symloadx 85 #define elf_symload elf64_symload 86 #define elf2nlist elf64_2nlist 87 #define elf_shn2type elf64_shn2type 88 #else 89 #error "Unsupported ELF class" 90 #endif 91 92 #define ELF_SDATA ".sdata" 93 #define ELF_SBSS ".sbss" 94 #define ELF_PLT ".plt" 95 96 #ifndef SHN_MIPS_ACOMMON 97 #define SHN_MIPS_ACOMMON SHN_LOPROC + 0 98 #endif 99 #ifndef SHN_MIPS_TEXT 100 #define SHN_MIPS_TEXT SHN_LOPROC + 1 101 #endif 102 #ifndef SHN_MIPS_DATA 103 #define SHN_MIPS_DATA SHN_LOPROC + 2 104 #endif 105 #ifndef SHN_MIPS_SUNDEFINED 106 #define SHN_MIPS_SUNDEFINED SHN_LOPROC + 4 107 #endif 108 #ifndef SHN_MIPS_SCOMMON 109 #define SHN_MIPS_SCOMMON SHN_LOPROC + 3 110 #endif 111 112 #ifndef STT_PARISC_MILLI 113 #define STT_PARISC_MILLI STT_LOPROC + 0 114 #endif 115 116 int 117 elf_fix_header(Elf_Ehdr *eh) 118 { 119 /* nothing to do */ 120 if (eh->e_ident[EI_DATA] == ELF_TARG_DATA) 121 return (0); 122 123 eh->e_type = swap16(eh->e_type); 124 eh->e_machine = swap16(eh->e_machine); 125 eh->e_version = swap32(eh->e_version); 126 eh->e_entry = swap_addr(eh->e_entry); 127 eh->e_phoff = swap_off(eh->e_phoff); 128 eh->e_shoff = swap_off(eh->e_shoff); 129 eh->e_flags = swap32(eh->e_flags); 130 eh->e_ehsize = swap16(eh->e_ehsize); 131 eh->e_phentsize = swap16(eh->e_phentsize); 132 eh->e_phnum = swap16(eh->e_phnum); 133 eh->e_shentsize = swap16(eh->e_shentsize); 134 eh->e_shnum = swap16(eh->e_shnum); 135 eh->e_shstrndx = swap16(eh->e_shstrndx); 136 137 return (1); 138 } 139 140 Elf_Shdr * 141 elf_load_shdrs(const char *name, FILE *fp, off_t foff, Elf_Ehdr *head) 142 { 143 Elf_Shdr *shdr; 144 145 elf_fix_header(head); 146 147 if ((shdr = calloc(head->e_shentsize, head->e_shnum)) == NULL) { 148 warn("%s: malloc shdr", name); 149 return (NULL); 150 } 151 152 if (fseeko(fp, foff + head->e_shoff, SEEK_SET)) { 153 warn("%s: fseeko", name); 154 free(shdr); 155 return (NULL); 156 } 157 158 if (fread(shdr, head->e_shentsize, head->e_shnum, fp) != head->e_shnum) { 159 warnx("%s: premature EOF", name); 160 free(shdr); 161 return (NULL); 162 } 163 164 elf_fix_shdrs(head, shdr); 165 return (shdr); 166 } 167 168 Elf_Phdr * 169 elf_load_phdrs(const char *name, FILE *fp, off_t foff, Elf_Ehdr *head) 170 { 171 Elf_Phdr *phdr; 172 173 if ((phdr = calloc(head->e_phentsize, head->e_phnum)) == NULL) { 174 warn("%s: malloc phdr", name); 175 return (NULL); 176 } 177 178 if (fseeko(fp, foff + head->e_phoff, SEEK_SET)) { 179 warn("%s: fseeko", name); 180 free(phdr); 181 return (NULL); 182 } 183 184 if (fread(phdr, head->e_phentsize, head->e_phnum, fp) != head->e_phnum) { 185 warnx("%s: premature EOF", name); 186 free(phdr); 187 return (NULL); 188 } 189 190 elf_fix_phdrs(head, phdr); 191 return (phdr); 192 } 193 194 int 195 elf_fix_shdrs(Elf_Ehdr *eh, Elf_Shdr *shdr) 196 { 197 int i; 198 199 /* nothing to do */ 200 if (eh->e_ident[EI_DATA] == ELF_TARG_DATA) 201 return (0); 202 203 for (i = eh->e_shnum; i--; shdr++) { 204 shdr->sh_name = swap32(shdr->sh_name); 205 shdr->sh_type = swap32(shdr->sh_type); 206 shdr->sh_flags = swap_xword(shdr->sh_flags); 207 shdr->sh_addr = swap_addr(shdr->sh_addr); 208 shdr->sh_offset = swap_off(shdr->sh_offset); 209 shdr->sh_size = swap_xword(shdr->sh_size); 210 shdr->sh_link = swap32(shdr->sh_link); 211 shdr->sh_info = swap32(shdr->sh_info); 212 shdr->sh_addralign = swap_xword(shdr->sh_addralign); 213 shdr->sh_entsize = swap_xword(shdr->sh_entsize); 214 } 215 216 return (1); 217 } 218 219 int 220 elf_fix_phdrs(Elf_Ehdr *eh, Elf_Phdr *phdr) 221 { 222 int i; 223 224 /* nothing to do */ 225 if (eh->e_ident[EI_DATA] == ELF_TARG_DATA) 226 return (0); 227 228 for (i = eh->e_phnum; i--; phdr++) { 229 phdr->p_type = swap32(phdr->p_type); 230 phdr->p_flags = swap32(phdr->p_flags); 231 phdr->p_offset = swap_off(phdr->p_offset); 232 phdr->p_vaddr = swap_addr(phdr->p_vaddr); 233 phdr->p_paddr = swap_addr(phdr->p_paddr); 234 phdr->p_filesz = swap_xword(phdr->p_filesz); 235 phdr->p_memsz = swap_xword(phdr->p_memsz); 236 phdr->p_align = swap_xword(phdr->p_align); 237 } 238 239 return (1); 240 } 241 242 int 243 elf_fix_sym(Elf_Ehdr *eh, Elf_Sym *sym) 244 { 245 /* nothing to do */ 246 if (eh->e_ident[EI_DATA] == ELF_TARG_DATA) 247 return (0); 248 249 sym->st_name = swap32(sym->st_name); 250 sym->st_shndx = swap16(sym->st_shndx); 251 sym->st_value = swap_addr(sym->st_value); 252 sym->st_size = swap_xword(sym->st_size); 253 254 return (1); 255 } 256 257 int 258 elf_shn2type(Elf_Ehdr *eh, u_int shn, const char *sn) 259 { 260 switch (shn) { 261 case SHN_MIPS_SUNDEFINED: 262 if (eh->e_machine == EM_MIPS) 263 return (N_UNDF | N_EXT); 264 break; 265 266 case SHN_UNDEF: 267 return (N_UNDF | N_EXT); 268 269 case SHN_ABS: 270 return (N_ABS); 271 272 case SHN_MIPS_ACOMMON: 273 if (eh->e_machine == EM_MIPS) 274 return (N_COMM); 275 break; 276 277 case SHN_MIPS_SCOMMON: 278 if (eh->e_machine == EM_MIPS) 279 return (N_COMM); 280 break; 281 282 case SHN_COMMON: 283 return (N_COMM); 284 285 case SHN_MIPS_TEXT: 286 if (eh->e_machine == EM_MIPS) 287 return (N_TEXT); 288 break; 289 290 case SHN_MIPS_DATA: 291 if (eh->e_machine == EM_MIPS) 292 return (N_DATA); 293 break; 294 295 default: 296 /* beyond 8 a table-driven binsearch shall be used */ 297 if (sn == NULL) 298 return (-1); 299 else if (!strcmp(sn, ELF_TEXT)) 300 return (N_TEXT); 301 else if (!strcmp(sn, ELF_RODATA)) 302 return (N_SIZE); 303 else if (!strcmp(sn, ELF_DATA)) 304 return (N_DATA); 305 else if (!strcmp(sn, ELF_SDATA)) 306 return (N_DATA); 307 else if (!strcmp(sn, ELF_BSS)) 308 return (N_BSS); 309 else if (!strcmp(sn, ELF_SBSS)) 310 return (N_BSS); 311 else if (!strncmp(sn, ELF_GOT, sizeof(ELF_GOT) - 1)) 312 return (N_DATA); 313 else if (!strncmp(sn, ELF_PLT, sizeof(ELF_PLT) - 1)) 314 return (N_DATA); 315 } 316 317 return (-1); 318 } 319 320 /* 321 * Devise nlist's type from Elf_Sym. 322 * XXX this task is done as well in libc and kvm_mkdb. 323 */ 324 int 325 elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr, struct nlist *np) 326 { 327 u_char stt; 328 const char *sn; 329 int type; 330 331 if (sym->st_shndx < eh->e_shnum) 332 sn = shstr + shdr[sym->st_shndx].sh_name; 333 else 334 sn = NULL; 335 #if 0 336 { 337 extern char *stab; 338 printf("%d:%s %d %s\n", sym->st_shndx, sn? sn : "", 339 ELF_ST_TYPE(sym->st_info), stab + sym->st_name); 340 } 341 #endif 342 343 switch (stt = ELF_ST_TYPE(sym->st_info)) { 344 case STT_NOTYPE: 345 case STT_OBJECT: 346 type = elf_shn2type(eh, sym->st_shndx, sn); 347 if (type < 0) { 348 if (sn == NULL) 349 np->n_other = '?'; 350 else 351 np->n_type = stt == STT_NOTYPE? N_COMM : N_DATA; 352 } else { 353 /* a hack for .rodata check (; */ 354 if (type == N_SIZE) { 355 np->n_type = N_DATA; 356 np->n_other = 'r'; 357 } else 358 np->n_type = type; 359 } 360 break; 361 362 case STT_FUNC: 363 type = elf_shn2type(eh, sym->st_shndx, NULL); 364 np->n_type = type < 0? N_TEXT : type; 365 if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 366 np->n_type = N_INDR; 367 np->n_other = 'W'; 368 } else if (sn != NULL && *sn != 0 && 369 strcmp(sn, ELF_INIT) && 370 strcmp(sn, ELF_TEXT) && 371 strcmp(sn, ELF_FINI)) /* XXX GNU compat */ 372 np->n_other = '?'; 373 break; 374 375 case STT_SECTION: 376 type = elf_shn2type(eh, sym->st_shndx, NULL); 377 if (type < 0) 378 np->n_other = '?'; 379 else 380 np->n_type = type; 381 break; 382 383 case STT_FILE: 384 np->n_type = N_FN | N_EXT; 385 break; 386 387 case STT_PARISC_MILLI: 388 if (eh->e_machine == EM_PARISC) 389 np->n_type = N_TEXT; 390 else 391 np->n_other = '?'; 392 break; 393 394 default: 395 np->n_other = '?'; 396 break; 397 } 398 if (np->n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) { 399 np->n_type |= N_EXT; 400 if (np->n_other) 401 np->n_other = toupper(np->n_other); 402 } 403 404 return (0); 405 } 406 407 int 408 elf_size(Elf_Ehdr *head, Elf_Shdr *shdr, 409 u_long *ptext, u_long *pdata, u_long *pbss) 410 { 411 int i; 412 413 *ptext = *pdata = *pbss = 0; 414 415 for (i = 0; i < head->e_shnum; i++) { 416 if (!(shdr[i].sh_flags & SHF_ALLOC)) 417 ; 418 else if (shdr[i].sh_flags & SHF_EXECINSTR || 419 !(shdr[i].sh_flags & SHF_WRITE)) 420 *ptext += shdr[i].sh_size; 421 else if (shdr[i].sh_type == SHT_NOBITS) 422 *pbss += shdr[i].sh_size; 423 else 424 *pdata += shdr[i].sh_size; 425 } 426 427 return (0); 428 } 429 430 int 431 elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, 432 Elf_Shdr *shdr, char *shstr, struct nlist **pnames, 433 struct nlist ***psnames, size_t *pstabsize, int *pnrawnames, 434 const char *strtab, const char *symtab) 435 { 436 long symsize; 437 struct nlist *np; 438 Elf_Sym sbuf; 439 int i; 440 441 for (i = 0; i < eh->e_shnum; i++) { 442 if (!strcmp(shstr + shdr[i].sh_name, strtab)) { 443 *pstabsize = shdr[i].sh_size; 444 if (*pstabsize > SIZE_T_MAX) { 445 warnx("%s: corrupt file", name); 446 return (1); 447 } 448 449 MMAP(stab, *pstabsize, PROT_READ, MAP_PRIVATE|MAP_FILE, 450 fileno(fp), foff + shdr[i].sh_offset); 451 if (stab == MAP_FAILED) 452 return (1); 453 } 454 } 455 for (i = 0; i < eh->e_shnum; i++) { 456 if (!strcmp(shstr + shdr[i].sh_name, symtab)) { 457 symsize = shdr[i].sh_size; 458 if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) { 459 warn("%s: fseeko", name); 460 if (stab) 461 MUNMAP(stab, *pstabsize); 462 return (1); 463 } 464 465 *pnrawnames = symsize / sizeof(sbuf); 466 if ((*pnames = calloc(*pnrawnames, sizeof(*np))) == NULL) { 467 warn("%s: malloc names", name); 468 if (stab) 469 MUNMAP(stab, *pstabsize); 470 return (1); 471 } 472 if ((*psnames = calloc(*pnrawnames, sizeof(np))) == NULL) { 473 warn("%s: malloc snames", name); 474 if (stab) 475 MUNMAP(stab, *pstabsize); 476 free(*pnames); 477 return (1); 478 } 479 480 for (np = *pnames; symsize > 0; symsize -= sizeof(sbuf)) { 481 if (fread(&sbuf, 1, sizeof(sbuf), 482 fp) != sizeof(sbuf)) { 483 warn("%s: read symbol", name); 484 if (stab) 485 MUNMAP(stab, *pstabsize); 486 free(*pnames); 487 free(*psnames); 488 return (1); 489 } 490 491 elf_fix_sym(eh, &sbuf); 492 493 if (!sbuf.st_name || 494 sbuf.st_name > *pstabsize) 495 continue; 496 497 elf2nlist(&sbuf, eh, shdr, shstr, np); 498 np->n_value = sbuf.st_value; 499 np->n_un.n_strx = sbuf.st_name; 500 np++; 501 } 502 *pnrawnames = np - *pnames; 503 } 504 } 505 506 } 507 508 int 509 elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, 510 Elf_Shdr *shdr, struct nlist **pnames, struct nlist ***psnames, 511 size_t *pstabsize, int *pnrawnames) 512 { 513 long shstrsize; 514 char *shstr; 515 516 shstrsize = shdr[eh->e_shstrndx].sh_size; 517 if (shstrsize == 0) { 518 warnx("%s: no name list", name); 519 return (1); 520 } 521 522 if ((shstr = malloc(shstrsize)) == NULL) { 523 warn("%s: malloc shsrt", name); 524 return (1); 525 } 526 527 if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) { 528 warn("%s: fseeko", name); 529 free(shstr); 530 return (1); 531 } 532 533 if (fread(shstr, 1, shstrsize, fp) != shstrsize) { 534 warnx("%s: premature EOF", name); 535 free(shstr); 536 return(1); 537 } 538 539 stab = NULL; 540 *pnames = NULL; *psnames = NULL; 541 elf_symloadx(name, fp, foff, eh, shdr, shstr, pnames, 542 psnames, pstabsize, pnrawnames, ELF_STRTAB, ELF_SYMTAB); 543 if (stab == NULL) { 544 elf_symloadx(name, fp, foff, eh, shdr, shstr, pnames, 545 psnames, pstabsize, pnrawnames, ELF_DYNSTR, ELF_DYNSYM); 546 } 547 548 free(shstr); 549 if (stab == NULL) { 550 warnx("%s: no name list", name); 551 if (*pnames) 552 free(*pnames); 553 if (*psnames) 554 free(*psnames); 555 return (1); 556 } 557 558 return (0); 559 } 560