1/* $OpenBSD: elf.c,v 1.39 2021/11/07 08:09:04 semarie 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 115static int elf_fix_header(Elf_Ehdr *); 116static int elf_fix_shdrs(Elf_Ehdr *, Elf_Shdr *); 117static int elf_fix_sym(Elf_Ehdr *, Elf_Sym *); 118static int elf_shn2type(Elf_Ehdr *, u_int _shn, const char *_sn); 119static int elf2nlist(Elf_Sym *, Elf_Ehdr *, Elf_Shdr *, char *_shstr, 120 struct xnlist *_np); 121static 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 126int 127elf_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 150Elf_Shdr * 151elf_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 193int 194elf_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 218int 219elf_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 233int 234elf_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 (!strncmp(sn, ".text.", 6)) 278 return (N_TEXT); 279 else if (!strcmp(sn, ELF_RODATA)) 280 return (N_SIZE); 281 else if (!strcmp(sn, ELF_OPENBSDRANDOMDATA)) 282 return (N_SIZE); 283 else if (!strcmp(sn, ELF_DATA)) 284 return (N_DATA); 285 else if (!strcmp(sn, ELF_SDATA)) 286 return (N_DATA); 287 else if (!strcmp(sn, ELF_TDATA)) 288 return (N_DATA); 289 else if (!strcmp(sn, ELF_BSS)) 290 return (N_BSS); 291 else if (!strcmp(sn, ELF_SBSS)) 292 return (N_BSS); 293 else if (!strcmp(sn, ELF_TBSS)) 294 return (N_BSS); 295 else if (!strncmp(sn, ELF_GOT, sizeof(ELF_GOT) - 1)) 296 return (N_DATA); 297 else if (!strncmp(sn, ELF_PLT, sizeof(ELF_PLT) - 1)) 298 return (N_DATA); 299 } 300 301 return (-1); 302} 303 304/* 305 * Devise xnlist's type from Elf_Sym. 306 * XXX this task is done as well in libc and kvm_mkdb. 307 */ 308int 309elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr, 310 struct xnlist *np) 311{ 312 u_char stt; 313 const char *sn; 314 int type; 315 316 if (sym->st_shndx < eh->e_shnum) 317 sn = shstr + shdr[sym->st_shndx].sh_name; 318 else 319 sn = NULL; 320#if 0 321 { 322 extern char *stab; 323 printf("%d:%s %d %d %s\n", sym->st_shndx, sn? sn : "", 324 ELF_ST_TYPE(sym->st_info), ELF_ST_BIND(sym->st_info), 325 stab + sym->st_name); 326 } 327#endif 328 329 switch (stt = ELF_ST_TYPE(sym->st_info)) { 330 case STT_NOTYPE: 331 case STT_OBJECT: 332 case STT_TLS: 333 type = elf_shn2type(eh, sym->st_shndx, sn); 334 if (type < 0) { 335 if (sn == NULL) 336 np->nl.n_other = '?'; 337 else 338 np->nl.n_type = stt == STT_NOTYPE ? 339 N_COMM : N_DATA; 340 } else { 341 /* a hack for .rodata check (; */ 342 if (type == N_SIZE) { 343 np->nl.n_type = N_DATA; 344 np->nl.n_other = 'r'; 345 } else 346 np->nl.n_type = type; 347 } 348 if (ELF_ST_BIND(sym->st_info) == STB_WEAK) 349 np->nl.n_other = 'W'; 350 break; 351 352 case STT_FUNC: 353 type = elf_shn2type(eh, sym->st_shndx, NULL); 354 np->nl.n_type = type < 0? N_TEXT : type; 355 if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { 356 np->nl.n_other = 'W'; 357 } else if (sn != NULL && *sn != 0 && 358 strcmp(sn, ELF_INIT) && 359 strcmp(sn, ELF_TEXT) && 360 strncmp(sn, ".text.", 6) && 361 strcmp(sn, ELF_FINI)) /* XXX GNU compat */ 362 np->nl.n_other = '?'; 363 break; 364 365 case STT_SECTION: 366 type = elf_shn2type(eh, sym->st_shndx, NULL); 367 if (type < 0) 368 np->nl.n_other = '?'; 369 else 370 np->nl.n_type = type; 371 break; 372 373 case STT_FILE: 374 np->nl.n_type = N_FN | N_EXT; 375 break; 376 377 case STT_PARISC_MILLI: 378 if (eh->e_machine == EM_PARISC) 379 np->nl.n_type = N_TEXT; 380 else 381 np->nl.n_other = '?'; 382 break; 383 384 default: 385 np->nl.n_other = '?'; 386 break; 387 } 388 if (np->nl.n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) { 389 np->nl.n_type |= N_EXT; 390 if (np->nl.n_other) 391 np->nl.n_other = toupper((unsigned char)np->nl.n_other); 392 } 393 394 return (0); 395} 396 397int 398elf_size(Elf_Ehdr *head, Elf_Shdr *shdr, 399 u_long *ptext, u_long *pdata, u_long *pbss) 400{ 401 int i; 402 403 *ptext = *pdata = *pbss = 0; 404 405 for (i = 0; i < head->e_shnum; i++) { 406 if (!(shdr[i].sh_flags & SHF_ALLOC)) 407 ; 408 else if (shdr[i].sh_flags & SHF_EXECINSTR || 409 !(shdr[i].sh_flags & SHF_WRITE)) 410 *ptext += shdr[i].sh_size; 411 else if (shdr[i].sh_type == SHT_NOBITS) 412 *pbss += shdr[i].sh_size; 413 else 414 *pdata += shdr[i].sh_size; 415 } 416 417 return (0); 418} 419 420int 421elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, 422 Elf_Shdr *shdr, char *shstr, long shstrsize, struct xnlist **pnames, 423 struct xnlist ***psnames, size_t *pstabsize, int *pnrawnames, 424 const char *strtab, const char *symtab) 425{ 426 long symsize; 427 struct xnlist *np; 428 Elf_Sym sbuf; 429 int i; 430 431 for (i = 0; i < eh->e_shnum; i++) { 432 if (shdr[i].sh_name >= shstrsize) { 433 warnx("%s: corrupt file", name); 434 return (1); 435 } 436 if (!strcmp(shstr + shdr[i].sh_name, strtab)) { 437 *pstabsize = shdr[i].sh_size; 438 if (*pstabsize > SIZE_MAX) { 439 warnx("%s: corrupt file", name); 440 return (1); 441 } 442 443 MMAP(stab, *pstabsize, PROT_READ, MAP_PRIVATE|MAP_FILE, 444 fileno(fp), foff + shdr[i].sh_offset); 445 if (stab == MAP_FAILED) 446 return (1); 447 } 448 } 449 for (i = 0; i < eh->e_shnum; i++) { 450 if (!strcmp(shstr + shdr[i].sh_name, symtab)) { 451 symsize = shdr[i].sh_size; 452 if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) { 453 warn("%s: fseeko", name); 454 if (stab) 455 MUNMAP(stab, *pstabsize); 456 return (1); 457 } 458 459 *pnrawnames = symsize / sizeof(sbuf); 460 if ((*pnames = calloc(*pnrawnames, sizeof(*np))) == NULL) { 461 warn("%s: malloc names", name); 462 if (stab) 463 MUNMAP(stab, *pstabsize); 464 *pnrawnames = 0; 465 return (1); 466 } 467 if ((*psnames = calloc(*pnrawnames, sizeof(np))) == NULL) { 468 warn("%s: malloc snames", name); 469 if (stab) 470 MUNMAP(stab, *pstabsize); 471 free(*pnames); 472 *pnames = NULL; 473 *pnrawnames = 0; 474 return (1); 475 } 476 477 for (np = *pnames; symsize > 0; symsize -= sizeof(sbuf)) { 478 if (fread(&sbuf, 1, sizeof(sbuf), 479 fp) != sizeof(sbuf)) { 480 warn("%s: read symbol", name); 481 if (stab) 482 MUNMAP(stab, *pstabsize); 483 free(*pnames); 484 free(*psnames); 485 *pnames = NULL; 486 *psnames = NULL; 487 *pnrawnames = 0; 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->nl.n_value = sbuf.st_value; 499 np->nl.n_un.n_strx = sbuf.st_name; 500 np->n_size = sbuf.st_size; 501 np++; 502 } 503 *pnrawnames = np - *pnames; 504 } 505 } 506 return (0); 507} 508 509int 510elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh, 511 Elf_Shdr *shdr, struct xnlist **pnames, struct xnlist ***psnames, 512 size_t *pstabsize, int *pnrawnames) 513{ 514 long shstrsize; 515 char *shstr; 516 517 shstrsize = shdr[eh->e_shstrndx].sh_size; 518 if (shstrsize == 0) { 519 warnx("%s: no name list", name); 520 return (1); 521 } 522 523 if ((shstr = malloc(shstrsize)) == NULL) { 524 warn("%s: malloc shstr", name); 525 return (1); 526 } 527 528 if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) { 529 warn("%s: fseeko", name); 530 free(shstr); 531 return (1); 532 } 533 534 if (fread(shstr, 1, shstrsize, fp) != shstrsize) { 535 warnx("%s: premature EOF", name); 536 free(shstr); 537 return(1); 538 } 539 540 stab = NULL; 541 *pnames = NULL; *psnames = NULL; *pnrawnames = 0; 542 if (!dynamic_only) { 543 elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames, 544 psnames, pstabsize, pnrawnames, ELF_STRTAB, ELF_SYMTAB); 545 } 546 if (stab == NULL) { 547 elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames, 548 psnames, pstabsize, pnrawnames, ELF_DYNSTR, ELF_DYNSYM); 549 } 550 551 free(shstr); 552 if (stab == NULL) { 553 warnx("%s: no name list", name); 554 free(*pnames); 555 free(*psnames); 556 return (1); 557 } 558 559 return (0); 560} 561