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