1#include <assert.h>2#include <errno.h>3#include <limits.h>4#include <stdio.h>5#include <stdlib.h>6#include <string.h>78#include <scc/mach.h>9#include <scc/elf.h>1011#include <scc/elf/elftypes.h>12#include <scc/elf/elfhdr.h>13#include <scc/elf/elfphdr.h>14#include <scc/elf/elfshdr.h>15#include <scc/elf/elfent.h>16#include <scc/elf/elfrel.h>1718#include "../libmach.h"19#include "fun.h"2021struct elfunpack {22 void (*hdr)(int, unsigned char *, Elfhdr *);23 void (*phdr)(int, unsigned char *, Elfphdr *);24 void (*sec)(int, unsigned char *, Elfsec *);25 void (*sym)(int, unsigned char *, Elfsym *);26 void (*rel)(int, unsigned char *, Elfrel *);27 void (*rela)(int, unsigned char *, Elfrel *);2829 int hdrsiz;30 int phdrsiz;31 int shentsiz;32 int symsiz;33 int relsiz;34 int relasiz;35};3637struct elfunpack unpack64;38struct elfunpack unpack32;3940static void41unpack_hdr64(int order, unsigned char *buf, Elfhdr *hdr)42{43 Elf64_Ehdr ehdr;44 int n;4546 n = unpack(order,47 buf,48 "'16sslqqqlssssss",49 ehdr.e_ident,50 &ehdr.e_type,51 &ehdr.e_machine,52 &ehdr.e_version,53 &ehdr.e_entry,54 &ehdr.e_phoff,55 &ehdr.e_shoff,56 &ehdr.e_flags,57 &ehdr.e_ehsize,58 &ehdr.e_phentsize,59 &ehdr.e_phnum,60 &ehdr.e_shentsize,61 &ehdr.e_shnum,62 &ehdr.e_shstrndx);6364 assert(n == ELFH64SZ);6566 memcpy(hdr->ident, ehdr.e_ident, EI_NIDENT);67 hdr->type = ehdr.e_type;68 hdr->machine = ehdr.e_machine;69 hdr->version = ehdr.e_version;70 hdr->entry = ehdr.e_entry;71 hdr->phoff = ehdr.e_phoff;72 hdr->shoff = ehdr.e_shoff;73 hdr->flags = ehdr.e_flags;74 hdr->ehsize = ehdr.e_ehsize;75 hdr->phentsize = ehdr.e_phentsize;76 hdr->phnum = ehdr.e_phnum;77 hdr->shentsize = ehdr.e_shentsize;78 hdr->shnum = ehdr.e_shnum;79 hdr->shstrndx = ehdr.e_shstrndx;80}8182static void83unpack_hdr32(int order, unsigned char *buf, Elfhdr *hdr)84{85 Elf32_Ehdr ehdr;86 int n;8788 n = unpack(order,89 buf,90 "'16sslllllssssss",91 ehdr.e_ident,92 &ehdr.e_type,93 &ehdr.e_machine,94 &ehdr.e_version,95 &ehdr.e_entry,96 &ehdr.e_phoff,97 &ehdr.e_shoff,98 &ehdr.e_flags,99 &ehdr.e_ehsize,100 &ehdr.e_phentsize,101 &ehdr.e_phnum,102 &ehdr.e_shentsize,103 &ehdr.e_shnum,104 &ehdr.e_shstrndx);105106 assert(n == ELFH32SZ);107108 memcpy(hdr->ident, ehdr.e_ident, EI_NIDENT);109 hdr->type = ehdr.e_type;110 hdr->machine = ehdr.e_machine;111 hdr->version = ehdr.e_version;112 hdr->entry = ehdr.e_entry;113 hdr->phoff = ehdr.e_phoff;114 hdr->shoff = ehdr.e_shoff;115 hdr->flags = ehdr.e_flags;116 hdr->ehsize = ehdr.e_ehsize;117 hdr->phentsize = ehdr.e_phentsize;118 hdr->phnum = ehdr.e_phnum;119 hdr->shentsize = ehdr.e_shentsize;120 hdr->shnum = ehdr.e_shnum;121 hdr->shstrndx = ehdr.e_shstrndx;122}123124static void125unpack_phdr64(int order, unsigned char *buf, Elfphdr *hdr)126{127 int n;128 Elf64_Phdr phdr;129130 n = unpack(order,131 buf,132 "llqqqqqq",133 &phdr.p_type,134 &phdr.p_flags,135 &phdr.p_offset,136 &phdr.p_vaddr,137 &phdr.p_paddr,138 &phdr.p_filesz,139 &phdr.p_memsz,140 &phdr.p_align);141142 assert(n == ELFP64SZ);143144 hdr->type = phdr.p_type;145 hdr->flags = phdr.p_flags;146 hdr->offset = phdr.p_offset;147 hdr->vaddr = phdr.p_vaddr;148 hdr->paddr = phdr.p_paddr;149 hdr->filesz = phdr.p_filesz;150 hdr->memsz = phdr.p_memsz;151 hdr->align = phdr.p_align;152}153154static void155unpack_phdr32(int order, unsigned char *buf, Elfphdr *hdr)156{157 int n;158 Elf32_Phdr phdr;159160 n = unpack(order,161 buf,162 "llllllll",163 &phdr.p_type,164 &phdr.p_offset,165 &phdr.p_vaddr,166 &phdr.p_paddr,167 &phdr.p_filesz,168 &phdr.p_memsz,169 &phdr.p_flags,170 &phdr.p_align);171172 assert(n == ELFP32SZ);173174 hdr->type = phdr.p_type;175 hdr->flags = phdr.p_flags;176 hdr->offset = phdr.p_offset;177 hdr->vaddr = phdr.p_vaddr;178 hdr->paddr = phdr.p_paddr;179 hdr->filesz = phdr.p_filesz;180 hdr->memsz = phdr.p_memsz;181 hdr->align = phdr.p_align;182}183184static void185unpack_shdr64(int order, unsigned char *buf, Elfsec *sec)186{187 int n;188 Elf64_Shdr shdr;189190 n = unpack(order,191 buf,192 "llqqqqllqq",193 &shdr.sh_name,194 &shdr.sh_type,195 &shdr.sh_flags,196 &shdr.sh_addr,197 &shdr.sh_offset,198 &shdr.sh_size,199 &shdr.sh_link,200 &shdr.sh_info,201 &shdr.sh_addralign,202 &shdr.sh_entsize);203204 assert(n == ELFS64SZ);205206 sec->sh_name = shdr.sh_name;207 sec->type = shdr.sh_type;208 sec->flags = shdr.sh_flags;209 sec->addr = shdr.sh_addr;210 sec->offset = shdr.sh_offset;211 sec->size = shdr.sh_size;212 sec->link = shdr.sh_link;213 sec->info = shdr.sh_info;214 sec->addralign = shdr.sh_addralign;215 sec->entsize = shdr.sh_entsize;216}217218static void219unpack_shdr32(int order, unsigned char *buf, Elfsec *sec)220{221 int n;222 Elf32_Shdr shdr;223224 n = unpack(order,225 buf,226 "llllllllll",227 &shdr.sh_name,228 &shdr.sh_type,229 &shdr.sh_flags,230 &shdr.sh_addr,231 &shdr.sh_offset,232 &shdr.sh_size,233 &shdr.sh_link,234 &shdr.sh_info,235 &shdr.sh_addralign,236 &shdr.sh_entsize);237238 assert(n == ELFS32SZ);239240 sec->sh_name = shdr.sh_name;241 sec->type = shdr.sh_type;242 sec->flags = shdr.sh_flags;243 sec->addr = shdr.sh_addr;244 sec->offset = shdr.sh_offset;245 sec->size = shdr.sh_size;246 sec->link = shdr.sh_link;247 sec->info = shdr.sh_info;248 sec->addralign = shdr.sh_addralign;249 sec->entsize = shdr.sh_entsize;250}251252static void253unpack_sym64(int order, unsigned char *buf, Elfsym *sym)254{255 int n;256 Elf64_Sym ent;257258 n = unpack(order,259 buf,260 "lccsqq",261 &ent.st_name,262 &ent.st_info,263 &ent.st_other,264 &ent.st_shndx,265 &ent.st_value,266 &ent.st_size);267268 assert(n == ELFE64SZ);269270 sym->st_name = ent.st_name;271 sym->info = ent.st_info;272 sym->other = ent.st_other;273 sym->shndx = ent.st_shndx;274 sym->value = ent.st_value;275 sym->size = ent.st_size;276}277278static void279unpack_sym32(int order, unsigned char *buf, Elfsym *sym)280{281 int n;282 Elf32_Sym ent;283284 n = unpack(order,285 buf,286 "lllccs",287 &ent.st_name,288 &ent.st_value,289 &ent.st_size,290 &ent.st_info,291 &ent.st_other,292 &ent.st_shndx);293294 assert(n == ELFE32SZ);295296 sym->st_name = ent.st_name;297 sym->info = ent.st_info;298 sym->other = ent.st_other;299 sym->shndx = ent.st_shndx;300 sym->value = ent.st_value;301 sym->size = ent.st_size;302}303304static void305unpack_rel64(int order, unsigned char *buf, Elfrel *rp)306{307 int n;308 Elf64_Rel r;309310 n = unpack(order,311 buf,312 "qq",313 &r.r_offset,314 &r.r_info);315316 assert(n == ELFR64SZ);317318 rp->off = r.r_offset;319 rp->info = r.r_info;320 rp->addend = 0;321}322323static void324unpack_rel32(int order, unsigned char *buf, Elfrel *rp)325{326 int n;327 Elf32_Rel r;328329 n = unpack(order,330 buf,331 "ll",332 &r.r_offset,333 &r.r_info);334335 assert(n == ELFR32SZ);336337 rp->off = r.r_offset;338 rp->info = r.r_info;339 rp->addend = 0;340}341342static void343unpack_rela64(int order, unsigned char *buf, Elfrel *rp)344{345 int n;346 Elf64_Rela r;347348 n = unpack(order,349 buf,350 "qqq",351 &r.r_offset,352 &r.r_info,353 &r.r_addend);354355 assert(n == ELFRA64SZ);356357 rp->off = r.r_offset;358 rp->info = r.r_info;359 rp->addend = r.r_addend;360}361362static void363unpack_rela32(int order, unsigned char *buf, Elfrel *rp)364{365 int n;366 Elf32_Rela r;367368 n = unpack(order,369 buf,370 "lll",371 &r.r_offset,372 &r.r_info,373 &r.r_addend);374375 assert(n == ELFRA32SZ);376377 rp->off = r.r_offset;378 rp->info = r.r_info;379 rp->addend = r.r_addend;380}381382static int383readhdr(Obj *obj, FILE *fp)384{385 Elf *elf = obj->data;386 Elfhdr *hdr = &elf->hdr;387 Elfunpack *u = elf->unpack;388 unsigned char buf[ELFH64SZ];389390 if (fread(buf, u->hdrsiz, 1, fp) != 1)391 return 0;392 (*u->hdr)(ORDER(obj->type), buf, hdr);393394 if (hdr->shnum > INT_MAX || hdr->phnum > INT_MAX)395 return 0;396397 switch (hdr->type) {398 case ET_REL:399 case ET_EXEC:400 case ET_DYN:401 return 1;402 default:403 return 0;404 }405}406407static int408readphdr(Obj *obj, FILE *fp)409{410 int i, r;411 Elfphdr *phdr;412 Elf *elf = obj->data;413 Elfhdr *hdr = &elf->hdr;414 Elfunpack *u = elf->unpack;415 unsigned char *buf;416417 r = 0;418 if (hdr->phnum > 0419 && (hdr->phoff == 0 || hdr->phentsize < u->phdrsiz)) {420 errno = ERANGE;421 goto err0;422 }423 if (hdr->phoff == 0 || hdr->phnum == 0)424 return 1;425426 if ((buf = malloc(hdr->phentsize)) == NULL)427 goto err0;428 if ((phdr = calloc(hdr->phnum, sizeof(*phdr))) == NULL)429 goto err1;430 elf->phdr = phdr;431432 if (!objpos(obj, fp, hdr->phoff))433 goto err1;434435 for (i = 0; i < hdr->phnum; i++) {436 if (fread(buf, hdr->phentsize, 1, fp) != 1)437 goto err1;438 (*u->phdr)(ORDER(obj->type), buf, &phdr[i]);439 if (phdr[i].offset > LONG_MAX)440 goto err1;441 }442 r = 1;443444err1:445 free(buf);446err0:447 return r;448}449450static int451readshdr(Obj *obj, FILE *fp)452{453 int r, nsec;454 Elfsec *sec;455 Elf *elf = obj->data;456 Elfhdr *hdr = &elf->hdr;457 Elfunpack *u = elf->unpack;458 unsigned char *buf;459460 if (hdr->shoff == 0)461 return 1;462463 if (!objpos(obj, fp, hdr->shoff))464 return 0;465466 if (hdr->shnum != SHN_UNDEF) {467 if (hdr->shnum > INT_MAX)468 return 0;469 nsec = hdr->shnum;470 } else {471 Elfsec sec0;472 fpos_t pos;473 unsigned char buf0[ELFS64SZ];474475 fgetpos(fp, &pos);476 fread(buf0, u->shentsiz, 1, fp);477 fsetpos(fp, &pos);478479 if (ferror(fp))480 return 0;481482 (*u->sec)(ORDER(obj->type), buf0, &sec0);483 if (sec0.size > INT_MAX)484 return 0;485 nsec = sec0.size;486 }487488 if (nsec == 0)489 return 1;490491 r = 0;492 if ((buf = malloc(hdr->shentsize)) == NULL)493 return 0;494 if ((sec = calloc(nsec, sizeof(*sec))) == NULL)495 goto err;496 elf->secs = sec;497 elf->nsec = nsec;498499 for ( ; nsec-- > 0; ++sec) {500 if (fread(buf, hdr->shentsize, 1, fp) != 1)501 goto err;502 (*u->sec)(ORDER(obj->type), buf, sec);503 }504 r = 1;505err:506 free(buf);507 return r;508}509510static int511readstrtbl(Obj *obj, FILE *fp)512{513 char *s;514 int idx;515 Elfsec *tbl, *sec;516 Elf *elf = obj->data;517 Elfhdr *hdr = &elf->hdr;518519 if (hdr->shstrndx != SHN_XINDEX) {520 idx = hdr->shstrndx;521 } else {522 if (hdr->shnum == 0)523 return 0;524 sec = elf->secs;525 if (sec->link > INT_MAX)526 return 0;527 idx = sec->link;528 }529 if (idx > elf->nsec || elf->secs[idx].type != SHT_STRTAB)530 return 0;531 elf->secstrtbl = idx;532533 for (sec = elf->secs; sec < &elf->secs[elf->nsec]; ++sec) {534 if (sec->type != SHT_STRTAB)535 continue;536537 if (sec->size > SIZE_MAX)538 return 0;539 if ((s = malloc(sec->size)) == NULL)540 return 0;541 sec->strtbl = s;542543 if (!objpos(obj, fp, sec->offset))544 return 0;545 if (fread(s, sec->size, 1, fp) != 1)546 return 0;547 }548549 return 1;550}551552static int553secsize(Elfsec *sec, int onent, int entsiz)554{555 unsigned long long nent;556557 if (sec->entsize == 0 || sec->entsize < entsiz)558 return -1;559 nent = sec->size / sec->entsize;560 if (nent > INT_MAX - onent)561 return -1;562563 return nent;564}565566static int567readsyms(Obj *obj, Elfsec *sec, FILE *fp)568{569 int r = 0, n, oldn;570 Elfsym *sym;571 Elfsec *tbl;572 Elf *elf = obj->data;573 Elfunpack *u = elf->unpack;574 Elfhdr *hdr = &elf->hdr;575 unsigned char *buf;576577 if ((n = secsize(sec, elf->nsym, u->symsiz)) <= 0)578 return n;579 if ((buf = malloc(sec->entsize)) == NULL)580 return 0;581582 oldn = elf->nsym;583 sym = realloc(elf->syms, (oldn + n) * sizeof(Elfsym));584 if (!sym)585 goto err;586 elf->syms = sym;587 elf->nsym += n;588589 if (!objpos(obj, fp, sec->offset))590 goto err;591592 if (sec->link >= hdr->shnum)593 goto err;594 tbl = &elf->secs[sec->link];595 if (tbl->type != SHT_STRTAB)596 goto err;597598 for (sym = &elf->syms[oldn] ; n-- > 0 ; ++sym) {599 if (fread(buf, sec->entsize, 1, fp) != 1)600 goto err;601 (*u->sym)(ORDER(obj->type), buf, sym);602 sym->symsec = sec;603 if (sym->st_name >= tbl->size)604 goto err;605 sym->name = &tbl->strtbl[sym->st_name];606607 switch (sym->shndx) {608 case SHN_XINDEX:609 /*610 * Elf supports an extension mechanism to allow611 * indexes bigger than 4 bytes. We don't care612 * and we reject elf files using this feature.613 */614 goto err;615 case SHN_UNDEF:616 case SHN_ABS:617 case SHN_COMMON:618 break;619 default:620 if (sym->shndx >= elf->nsec)621 goto err;622 break;623 }624 }625 r = 1;626627err:628 free(buf);629 return r;630}631632static int633readrels(Obj *obj, Elfsec *sec, FILE *fp)634{635 int r = 0, oldn, n, min;636 Elf *elf = obj->data;637 Elfunpack *u = elf->unpack;638 Elfrel *rp;639 void (*fn)(int, unsigned char *, Elfrel *);640 unsigned char *buf;641642 if (sec->type == SHT_RELA) {643 fn = u->rela;644 min = u->relasiz;645 } else {646 fn = u->rel;647 min = u->relsiz;648 }649650 if (!objpos(obj, fp, sec->offset))651 goto err;652653 if ((n = secsize(sec, elf->nrel, min)) <= 0)654 return n;655 if ((buf = malloc(sec->entsize)) == NULL)656 return 0;657658 oldn = elf->nrel;659 rp = realloc(elf->rels, (oldn + n) * sizeof(Elfrel));660 if (!rp)661 goto err;662 elf->rels = rp;663 elf->nrel += n;664665 for (rp = &elf->rels[oldn]; n-- > 0; ++rp) {666 if (fread(buf, sec->entsize, 1, fp) != 1)667 goto err;668 (*fn)(ORDER(obj->type), buf, rp);669 }670 r = 1;671672err:673 free(buf);674 return r;675}676677static int678procsecs(Obj *obj, FILE *fp)679{680 Elf *elf = obj->data;681 Elfsec *tbl, *sec;682683 tbl = &elf->secs[elf->secstrtbl];684 for (sec = elf->secs; sec < &elf->secs[elf->nsec]; ++sec) {685 if (sec->sh_name >= tbl->size)686 return 0;687 sec->name = &tbl->strtbl[sec->sh_name];688689 switch (sec->type) {690 case SHT_DYNSYM:691 case SHT_SYMTAB:692 if (!readsyms(obj, sec, fp))693 return 0;694 break;695 case SHT_RELA:696 case SHT_REL:697 if (!readrels(obj, sec, fp))698 return 0;699 break;700 }701 }702703 return 1;704}705706int707elfread(Obj *obj, FILE *fp)708{709 fpos_t pos;710 Elf *elf = obj->data;711 unsigned char buf[EI_CLASS+1];712713 fgetpos(fp, &pos);714 fread(buf, sizeof(buf), 1, fp);715 fsetpos(fp, &pos);716717 if (buf[EI_CLASS] == ELFCLASS64) {718 if (elf->is32)719 return 0;720 elf->is32 = 0;721 elf->unpack = &unpack64;722 } else {723 elf->is32 = 1;724 elf->unpack = &unpack32;725 }726727 if (!readhdr(obj, fp))728 return -1;729 if (!readphdr(obj, fp))730 return -1;731 if (!readshdr(obj, fp))732 return -1;733 if (!readstrtbl(obj, fp))734 return -1;735 if (!procsecs(obj, fp))736 return -1;737738 return 0;739}740741struct elfunpack unpack64 = {742 .hdr = unpack_hdr64,743 .phdr = unpack_phdr64,744 .sec = unpack_shdr64,745 .sym = unpack_sym64,746 .rel = unpack_rel64,747 .rela = unpack_rela64,748749 .hdrsiz = ELFH64SZ,750 .phdrsiz = ELFP64SZ,751 .shentsiz = ELFS64SZ,752 .symsiz = ELFE64SZ,753 .relsiz = ELFR64SZ,754 .relasiz = ELFRA64SZ,755};756757struct elfunpack unpack32 = {758 .hdr = unpack_hdr32,759 .phdr = unpack_phdr32,760 .sec = unpack_shdr32,761 .sym = unpack_sym32,762 .rel = unpack_rel32,763 .rela = unpack_rela32,764765 .hdrsiz = ELFH32SZ,766 .phdrsiz = ELFP32SZ,767 .shentsiz = ELFS32SZ,768 .symsiz = ELFE32SZ,769 .relsiz = ELFR32SZ,770 .relasiz = ELFRA32SZ,771};