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