URI:
       telf.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       telf.c (10236B)
       ---
            1 /*
            2  * Parse 32-bit ELF files.
            3  * Copyright (c) 2004 Russ Cox.  See LICENSE.
            4  */
            5 
            6 #include <u.h>
            7 #include <libc.h>
            8 #include <mach.h>
            9 #include "elf.h"
           10 
           11 typedef struct ElfHdrBytes ElfHdrBytes;
           12 typedef struct ElfSectBytes ElfSectBytes;
           13 typedef struct ElfProgBytes ElfProgBytes;
           14 typedef struct ElfSymBytes ElfSymBytes;
           15 
           16 typedef struct ElfHdrBytes64 ElfHdrBytes64;
           17 typedef struct ElfSectBytes64 ElfSectBytes64;
           18 typedef struct ElfProgBytes64 ElfProgBytes64;
           19 typedef struct ElfSymBytes64 ElfSymBytes64;
           20 
           21 struct ElfHdrBytes
           22 {
           23         uchar        ident[16];
           24         uchar        type[2];
           25         uchar        machine[2];
           26         uchar        version[4];
           27         uchar        entry[4];
           28         uchar        phoff[4];
           29         uchar        shoff[4];
           30         uchar        flags[4];
           31         uchar        ehsize[2];
           32         uchar        phentsize[2];
           33         uchar        phnum[2];
           34         uchar        shentsize[2];
           35         uchar        shnum[2];
           36         uchar        shstrndx[2];
           37 };
           38 
           39 struct ElfHdrBytes64
           40 {
           41         uchar        ident[16];
           42         uchar        type[2];
           43         uchar        machine[2];
           44         uchar        version[4];
           45         uchar        entry[8];
           46         uchar        phoff[8];
           47         uchar        shoff[8];
           48         uchar        flags[4];
           49         uchar        ehsize[2];
           50         uchar        phentsize[2];
           51         uchar        phnum[2];
           52         uchar        shentsize[2];
           53         uchar        shnum[2];
           54         uchar        shstrndx[2];
           55 };
           56 
           57 struct ElfSectBytes
           58 {
           59         uchar        name[4];
           60         uchar        type[4];
           61         uchar        flags[4];
           62         uchar        addr[4];
           63         uchar        offset[4];
           64         uchar        size[4];
           65         uchar        link[4];
           66         uchar        info[4];
           67         uchar        align[4];
           68         uchar        entsize[4];
           69 };
           70 
           71 struct ElfSectBytes64
           72 {
           73         uchar        name[4];
           74         uchar        type[4];
           75         uchar        flags[8];
           76         uchar        addr[8];
           77         uchar        offset[8];
           78         uchar        size[8];
           79         uchar        link[4];
           80         uchar        info[4];
           81         uchar        align[8];
           82         uchar        entsize[8];
           83 };
           84 
           85 struct ElfSymBytes
           86 {
           87         uchar        name[4];
           88         uchar        value[4];
           89         uchar        size[4];
           90         uchar        info;        /* top4: bind, bottom4: type */
           91         uchar        other;
           92         uchar        shndx[2];
           93 };
           94 
           95 struct ElfSymBytes64
           96 {
           97         uchar        name[4];
           98         uchar        info;
           99         uchar        other;
          100         uchar        shndx[2];
          101         uchar        value[8];
          102         uchar        size[8];
          103 };
          104 
          105 struct ElfProgBytes
          106 {
          107         uchar        type[4];
          108         uchar        offset[4];
          109         uchar        vaddr[4];
          110         uchar        paddr[4];
          111         uchar        filesz[4];
          112         uchar        memsz[4];
          113         uchar        flags[4];
          114         uchar        align[4];
          115 };
          116 
          117 struct ElfProgBytes64
          118 {
          119         uchar        type[4];
          120         uchar        flags[4];
          121         uchar        offset[8];
          122         uchar        vaddr[8];
          123         uchar        paddr[8];
          124         uchar        filesz[8];
          125         uchar        memsz[8];
          126         uchar        align[8];
          127 };
          128 
          129 uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
          130 
          131 static void        unpackhdr(ElfHdr*, void*);
          132 static void        unpackprog(ElfHdr*, ElfProg*, void*);
          133 static void        unpacksect(ElfHdr*, ElfSect*, void*);
          134 
          135 static char *elftypes[] = {
          136         "none",
          137         "relocatable",
          138         "executable",
          139         "shared object",
          140         "core",
          141 };
          142 
          143 char*
          144 elftype(int t)
          145 {
          146         if(t < 0 || t >= nelem(elftypes))
          147                 return "unknown";
          148         return elftypes[t];
          149 }
          150 
          151 static char *elfmachs[] = {
          152         "none",
          153         "32100",
          154         "sparc",
          155         "386",
          156         "68000",
          157         "88000",
          158         "486",
          159         "860",
          160         "MIPS",
          161 };
          162 
          163 char*
          164 elfmachine(int t)
          165 {
          166         if(t < 0 || t >= nelem(elfmachs))
          167                 return "unknown";
          168         return elfmachs[t];
          169 }
          170 
          171 Elf*
          172 elfopen(char *name)
          173 {
          174         int fd;
          175         Elf *e;
          176 
          177         if((fd = open(name, OREAD)) < 0)
          178                 return nil;
          179         if((e = elfinit(fd)) == nil)
          180                 close(fd);
          181         return e;
          182 }
          183 
          184 Elf*
          185 elfinit(int fd)
          186 {
          187         int i;
          188         Elf *e;
          189         ElfHdr *h;
          190         union {
          191                 ElfHdrBytes h32;
          192                 ElfHdrBytes64 h64;
          193         } hdrb;
          194         void *p = nil;
          195         ElfSect *s;
          196 
          197         e = mallocz(sizeof(Elf), 1);
          198         if(e == nil)
          199                 return nil;
          200         e->fd = fd;
          201 
          202         /*
          203          * parse header
          204          */
          205         seek(fd, 0, 0);
          206         if(readn(fd, &hdrb, sizeof hdrb) != sizeof hdrb)
          207                 goto err;
          208         h = &e->hdr;
          209         unpackhdr(h, &hdrb);
          210         if(h->class != ElfClass32 && h->class != ElfClass64){
          211                 werrstr("bad ELF class - not 32-bit, 64-bit");
          212                 goto err;
          213         }
          214         if(h->encoding != ElfDataLsb && h->encoding != ElfDataMsb){
          215                 werrstr("bad ELF encoding - not LSB, MSB");
          216                 goto err;
          217         }
          218         if(hdrb.h32.ident[6] != h->version){
          219                 werrstr("bad ELF encoding - version mismatch %02ux and %08ux",
          220                         (uint)hdrb.h32.ident[6], (uint)h->version);
          221                 goto err;
          222         }
          223 
          224         /*
          225          * the prog+section info is almost always small - just load it into memory.
          226          */
          227         e->nprog = h->phnum;
          228         e->prog = mallocz(sizeof(ElfProg)*e->nprog, 1);
          229         p = mallocz(h->phentsize, 1);
          230         for(i=0; i<e->nprog; i++){
          231                 if(seek(fd, h->phoff+i*h->phentsize, 0) < 0
          232                 || readn(fd, p, h->phentsize) != h->phentsize)
          233                         goto err;
          234                 unpackprog(h, &e->prog[i], p);
          235         }
          236         free(p);
          237         p = nil;
          238 
          239         e->nsect = h->shnum;
          240         if(e->nsect == 0)
          241                 goto nosects;
          242         e->sect = mallocz(sizeof(ElfSect)*e->nsect, 1);
          243         p = mallocz(h->shentsize, 1);
          244         for(i=0; i<e->nsect; i++){
          245                 if(seek(fd, h->shoff+i*h->shentsize, 0) < 0
          246                 || readn(fd, p, h->shentsize) != h->shentsize)
          247                         goto err;
          248                 unpacksect(h, &e->sect[i], p);
          249         }
          250         free(p);
          251         p = nil;
          252 
          253         if(h->shstrndx >= e->nsect){
          254                 fprint(2, "warning: bad string section index %d >= %d", h->shstrndx, e->nsect);
          255                 h->shnum = 0;
          256                 e->nsect = 0;
          257                 goto nosects;
          258         }
          259         s = &e->sect[h->shstrndx];
          260         if(elfmap(e, s) < 0)
          261                 goto err;
          262 
          263         for(i=0; i<e->nsect; i++)
          264                 if(e->sect[i].name)
          265                         e->sect[i].name = (char*)s->base + (ulong)e->sect[i].name;
          266 
          267         e->symtab = elfsection(e, ".symtab");
          268         if(e->symtab){
          269                 if(e->symtab->link >= e->nsect)
          270                         e->symtab = nil;
          271                 else{
          272                         e->symstr = &e->sect[e->symtab->link];
          273                         e->nsymtab = e->symtab->size / sizeof(ElfSymBytes);
          274                 }
          275         }
          276         e->dynsym = elfsection(e, ".dynsym");
          277         if(e->dynsym){
          278                 if(e->dynsym->link >= e->nsect)
          279                         e->dynsym = nil;
          280                 else{
          281                         e->dynstr = &e->sect[e->dynsym->link];
          282                         e->ndynsym = e->dynsym->size / sizeof(ElfSymBytes);
          283                 }
          284         }
          285 
          286         e->bss = elfsection(e, ".bss");
          287 
          288 nosects:
          289         return e;
          290 
          291 err:
          292         free(p);
          293         free(e->sect);
          294         free(e->prog);
          295         free(e->shstrtab);
          296         free(e);
          297         return nil;
          298 }
          299 
          300 void
          301 elfclose(Elf *elf)
          302 {
          303         int i;
          304 
          305         for(i=0; i<elf->nsect; i++)
          306                 free(elf->sect[i].base);
          307         free(elf->sect);
          308         free(elf->prog);
          309         free(elf->shstrtab);
          310         free(elf);
          311 }
          312 
          313 static void
          314 unpackhdr(ElfHdr *h, void *v)
          315 {
          316         u16int (*e2)(uchar*);
          317         u32int (*e4)(uchar*);
          318         u64int (*e8)(uchar*);
          319         ElfHdrBytes *b;
          320         ElfHdrBytes64 *b64;
          321 
          322         b = v;
          323         memmove(h->magic, b->ident, 4);
          324         h->class = b->ident[4];
          325         h->encoding = b->ident[5];
          326         switch(h->encoding){
          327         case ElfDataLsb:
          328                 e2 = leload2;
          329                 e4 = leload4;
          330                 e8 = leload8;
          331                 break;
          332         case ElfDataMsb:
          333                 e2 = beload2;
          334                 e4 = beload4;
          335                 e8 = beload8;
          336                 break;
          337         default:
          338                 return;
          339         }
          340         h->abi = b->ident[7];
          341         h->abiversion = b->ident[8];
          342 
          343         h->e2 = e2;
          344         h->e4 = e4;
          345         h->e8 = e8;
          346 
          347         if(h->class == ElfClass64)
          348                 goto b64;
          349 
          350         h->type = e2(b->type);
          351         h->machine = e2(b->machine);
          352         h->version = e4(b->version);
          353         h->entry = e4(b->entry);
          354         h->phoff = e4(b->phoff);
          355         h->shoff = e4(b->shoff);
          356         h->flags = e4(b->flags);
          357         h->ehsize = e2(b->ehsize);
          358         h->phentsize = e2(b->phentsize);
          359         h->phnum = e2(b->phnum);
          360         h->shentsize = e2(b->shentsize);
          361         h->shnum = e2(b->shnum);
          362         h->shstrndx = e2(b->shstrndx);
          363         return;
          364 
          365 b64:
          366         b64 = v;
          367         h->type = e2(b64->type);
          368         h->machine = e2(b64->machine);
          369         h->version = e4(b64->version);
          370         h->entry = e8(b64->entry);
          371         h->phoff = e8(b64->phoff);
          372         h->shoff = e8(b64->shoff);
          373         h->flags = e4(b64->flags);
          374         h->ehsize = e2(b64->ehsize);
          375         h->phentsize = e2(b64->phentsize);
          376         h->phnum = e2(b64->phnum);
          377         h->shentsize = e2(b64->shentsize);
          378         h->shnum = e2(b64->shnum);
          379         h->shstrndx = e2(b64->shstrndx);
          380         return;
          381 }
          382 
          383 static void
          384 unpackprog(ElfHdr *h, ElfProg *p, void *v)
          385 {
          386         u32int (*e4)(uchar*);
          387         u64int (*e8)(uchar*);
          388 
          389         if(h->class == ElfClass32) {
          390                 ElfProgBytes *b;
          391 
          392                 b = v;
          393                 e4 = h->e4;
          394                 p->type = e4(b->type);
          395                 p->offset = e4(b->offset);
          396                 p->vaddr = e4(b->vaddr);
          397                 p->paddr = e4(b->paddr);
          398                 p->filesz = e4(b->filesz);
          399                 p->memsz = e4(b->memsz);
          400                 p->flags = e4(b->flags);
          401                 p->align = e4(b->align);
          402         } else {
          403                 ElfProgBytes64 *b;
          404 
          405                 b = v;
          406                 e4 = h->e4;
          407                 e8 = h->e8;
          408                 p->type = e4(b->type);
          409                 p->offset = e8(b->offset);
          410                 p->vaddr = e8(b->vaddr);
          411                 p->paddr = e8(b->paddr);
          412                 p->filesz = e8(b->filesz);
          413                 p->memsz = e8(b->memsz);
          414                 p->flags = e4(b->flags);
          415                 p->align = e8(b->align);
          416         }
          417 }
          418 
          419 static void
          420 unpacksect(ElfHdr *h, ElfSect *s, void *v)
          421 {
          422         u32int (*e4)(uchar*);
          423         u64int (*e8)(uchar*);
          424 
          425         if(h->class == ElfClass32) {
          426                 ElfSectBytes *b;
          427 
          428                 b = v;
          429                 e4 = h->e4;
          430                 s->name = (char*)(uintptr)e4(b->name);
          431                 s->type = e4(b->type);
          432                 s->flags = e4(b->flags);
          433                 s->addr = e4(b->addr);
          434                 s->offset = e4(b->offset);
          435                 s->size = e4(b->size);
          436                 s->link = e4(b->link);
          437                 s->info = e4(b->info);
          438                 s->align = e4(b->align);
          439                 s->entsize = e4(b->entsize);
          440         } else {
          441                 ElfSectBytes64 *b;
          442 
          443                 b = v;
          444                 e4 = h->e4;
          445                 e8 = h->e8;
          446                 s->name = (char*)(uintptr)e4(b->name);
          447                 s->type = e4(b->type);
          448                 s->flags = e8(b->flags);
          449                 s->addr = e8(b->addr);
          450                 s->offset = e8(b->offset);
          451                 s->size = e8(b->size);
          452                 s->link = e4(b->link);
          453                 s->info = e4(b->info);
          454                 s->align = e8(b->align);
          455                 s->entsize = e8(b->entsize);
          456         }
          457 }
          458 
          459 ElfSect*
          460 elfsection(Elf *elf, char *name)
          461 {
          462         int i;
          463 
          464         for(i=0; i<elf->nsect; i++){
          465                 if(elf->sect[i].name == name)
          466                         return &elf->sect[i];
          467                 if(elf->sect[i].name && name
          468                 && strcmp(elf->sect[i].name, name) == 0)
          469                         return &elf->sect[i];
          470         }
          471         werrstr("elf section '%s' not found", name);
          472         return nil;
          473 }
          474 
          475 int
          476 elfmap(Elf *elf, ElfSect *sect)
          477 {
          478         if(sect->base)
          479                 return 0;
          480         if((sect->base = malloc(sect->size)) == nil)
          481                 return -1;
          482         werrstr("short read");
          483         if(seek(elf->fd, sect->offset, 0) < 0
          484         || readn(elf->fd, sect->base, sect->size) != sect->size){
          485                 free(sect->base);
          486                 sect->base = nil;
          487                 return -1;
          488         }
          489         return 0;
          490 }
          491 
          492 int
          493 elfsym(Elf *elf, int i, ElfSym *sym)
          494 {
          495         ElfSect *symtab, *strtab;
          496         uchar *p;
          497         char *s;
          498         ulong x;
          499 
          500         if(i < 0){
          501                 werrstr("bad index %d in elfsym", i);
          502                 return -1;
          503         }
          504 
          505         if(i < elf->nsymtab){
          506                 symtab = elf->symtab;
          507                 strtab = elf->symstr;
          508         extract:
          509                 if(elfmap(elf, symtab) < 0 || elfmap(elf, strtab) < 0)
          510                         return -1;
          511                 if(elf->hdr.class == ElfClass32) {
          512                         p = symtab->base + i * sizeof(ElfSymBytes);
          513                         s = (char*)strtab->base;
          514                         x = elf->hdr.e4(p);
          515                         if(x >= strtab->size){
          516                                 werrstr("bad symbol name offset 0x%lux", x);
          517                                 return -1;
          518                         }
          519                         sym->name = s + x;
          520                         sym->value = elf->hdr.e4(p+4);
          521                         sym->size = elf->hdr.e4(p+8);
          522                         x = p[12];
          523                         sym->bind = x>>4;
          524                         sym->type = x & 0xF;
          525                         sym->other = p[13];
          526                         sym->shndx = elf->hdr.e2(p+14);
          527                 } else {
          528                         p = symtab->base + i * sizeof(ElfSymBytes64);
          529                         s = (char*)strtab->base;
          530                         x = elf->hdr.e4(p);
          531                         if(x >= strtab->size){
          532                                 werrstr("bad symbol name offset 0x%lux", x);
          533                                 return -1;
          534                         }
          535                         sym->name = s + x;
          536                         x = p[4];
          537                         sym->bind = x>>4;
          538                         sym->type = x & 0xF;
          539                         sym->other = p[5];
          540                         sym->shndx = elf->hdr.e2(p+6);
          541                         sym->value = elf->hdr.e8(p+8);
          542                         sym->size = elf->hdr.e8(p+16);
          543                 }
          544                 return 0;
          545         }
          546         i -= elf->nsymtab;
          547         if(i < elf->ndynsym){
          548                 symtab = elf->dynsym;
          549                 strtab = elf->dynstr;
          550                 goto extract;
          551         }
          552         /* i -= elf->ndynsym */
          553 
          554         werrstr("symbol index out of range");
          555         return -1;
          556 }