1bd389b36SDavid du Colombier #include <u.h> 2bd389b36SDavid du Colombier #include <libc.h> 3bd389b36SDavid du Colombier #include <bio.h> 4bd389b36SDavid du Colombier #include <bootexec.h> 5bd389b36SDavid du Colombier #include <mach.h> 67dd7cddfSDavid du Colombier #include "elf.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier /* 93e12c5d1SDavid du Colombier * All a.out header types. The dummy entry allows canonical 103e12c5d1SDavid du Colombier * processing of the union as a sequence of longs 113e12c5d1SDavid du Colombier */ 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier typedef struct { 143e12c5d1SDavid du Colombier union{ 153e12c5d1SDavid du Colombier Exec; /* in a.out.h */ 167dd7cddfSDavid du Colombier Ehdr; /* in elf.h */ 177dd7cddfSDavid du Colombier struct mipsexec; 18219b2ee8SDavid du Colombier struct mips4kexec; 193e12c5d1SDavid du Colombier struct sparcexec; 203e12c5d1SDavid du Colombier struct nextexec; 213e12c5d1SDavid du Colombier } e; 223e12c5d1SDavid du Colombier long dummy; /* padding to ensure extra long */ 233e12c5d1SDavid du Colombier } ExecHdr; 243e12c5d1SDavid du Colombier 257dd7cddfSDavid du Colombier static int nextboot(int, Fhdr*, ExecHdr*); 267dd7cddfSDavid du Colombier static int sparcboot(int, Fhdr*, ExecHdr*); 277dd7cddfSDavid du Colombier static int mipsboot(int, Fhdr*, ExecHdr*); 287dd7cddfSDavid du Colombier static int mips4kboot(int, Fhdr*, ExecHdr*); 297dd7cddfSDavid du Colombier static int common(int, Fhdr*, ExecHdr*); 307dd7cddfSDavid du Colombier static int adotout(int, Fhdr*, ExecHdr*); 317dd7cddfSDavid du Colombier static int elfdotout(int, Fhdr*, ExecHdr*); 327dd7cddfSDavid du Colombier static int armdotout(int, Fhdr*, ExecHdr*); 337dd7cddfSDavid du Colombier static int alphadotout(int, Fhdr*, ExecHdr*); 343e12c5d1SDavid du Colombier static void setsym(Fhdr*, long, long, long, long); 353e12c5d1SDavid du Colombier static void setdata(Fhdr*, long, long, long, long); 363e12c5d1SDavid du Colombier static void settext(Fhdr*, long, long, long, long); 373e12c5d1SDavid du Colombier static void hswal(long*, int, long(*)(long)); 38219b2ee8SDavid du Colombier static long _round(long, long); 393e12c5d1SDavid du Colombier 403e12c5d1SDavid du Colombier /* 413e12c5d1SDavid du Colombier * definition of per-executable file type structures 423e12c5d1SDavid du Colombier */ 433e12c5d1SDavid du Colombier 443e12c5d1SDavid du Colombier typedef struct Exectable{ 453e12c5d1SDavid du Colombier long magic; /* big-endian magic number of file */ 463e12c5d1SDavid du Colombier char *name; /* executable identifier */ 47*12fd1c83SDavid du Colombier char *dlmname; /* dynamically loadable module identifier */ 483e12c5d1SDavid du Colombier int type; /* Internal code */ 493e12c5d1SDavid du Colombier Mach *mach; /* Per-machine data */ 503e12c5d1SDavid du Colombier ulong hsize; /* header size */ 513e12c5d1SDavid du Colombier long (*swal)(long); /* beswal or leswal */ 527dd7cddfSDavid du Colombier int (*hparse)(int, Fhdr*, ExecHdr*); 533e12c5d1SDavid du Colombier } ExecTable; 543e12c5d1SDavid du Colombier 553e12c5d1SDavid du Colombier extern Mach mmips; 567dd7cddfSDavid du Colombier extern Mach mmips2le; 577dd7cddfSDavid du Colombier extern Mach mmips2be; 583e12c5d1SDavid du Colombier extern Mach msparc; 593e12c5d1SDavid du Colombier extern Mach m68020; 603e12c5d1SDavid du Colombier extern Mach mi386; 617dd7cddfSDavid du Colombier extern Mach marm; 627dd7cddfSDavid du Colombier extern Mach mpower; 637dd7cddfSDavid du Colombier extern Mach malpha; 643e12c5d1SDavid du Colombier 653e12c5d1SDavid du Colombier ExecTable exectab[] = 663e12c5d1SDavid du Colombier { 673e12c5d1SDavid du Colombier { V_MAGIC, /* Mips v.out */ 683e12c5d1SDavid du Colombier "mips plan 9 executable", 69*12fd1c83SDavid du Colombier "mips plan 9 dlm", 703e12c5d1SDavid du Colombier FMIPS, 713e12c5d1SDavid du Colombier &mmips, 723e12c5d1SDavid du Colombier sizeof(Exec), 733e12c5d1SDavid du Colombier beswal, 743e12c5d1SDavid du Colombier adotout }, 757dd7cddfSDavid du Colombier { M_MAGIC, /* Mips 4.out */ 767dd7cddfSDavid du Colombier "mips 4k plan 9 executable BE", 77*12fd1c83SDavid du Colombier "mips 4k plan 9 dlm BE", 787dd7cddfSDavid du Colombier FMIPS2BE, 797dd7cddfSDavid du Colombier &mmips2be, 807dd7cddfSDavid du Colombier sizeof(Exec), 817dd7cddfSDavid du Colombier beswal, 827dd7cddfSDavid du Colombier adotout }, 837dd7cddfSDavid du Colombier { N_MAGIC, /* Mips 0.out */ 847dd7cddfSDavid du Colombier "mips 4k plan 9 executable LE", 85*12fd1c83SDavid du Colombier "mips 4k plan 9 dlm LE", 867dd7cddfSDavid du Colombier FMIPS2LE, 877dd7cddfSDavid du Colombier &mmips2le, 887dd7cddfSDavid du Colombier sizeof(Exec), 897dd7cddfSDavid du Colombier beswal, 907dd7cddfSDavid du Colombier adotout }, 913e12c5d1SDavid du Colombier { 0x160<<16, /* Mips boot image */ 923e12c5d1SDavid du Colombier "mips plan 9 boot image", 93*12fd1c83SDavid du Colombier nil, 943e12c5d1SDavid du Colombier FMIPSB, 953e12c5d1SDavid du Colombier &mmips, 963e12c5d1SDavid du Colombier sizeof(struct mipsexec), 973e12c5d1SDavid du Colombier beswal, 983e12c5d1SDavid du Colombier mipsboot }, 99219b2ee8SDavid du Colombier { (0x160<<16)|3, /* Mips boot image */ 100219b2ee8SDavid du Colombier "mips 4k plan 9 boot image", 101*12fd1c83SDavid du Colombier nil, 102219b2ee8SDavid du Colombier FMIPSB, 10380ee5cbfSDavid du Colombier &mmips2be, 104219b2ee8SDavid du Colombier sizeof(struct mips4kexec), 1053e12c5d1SDavid du Colombier beswal, 106219b2ee8SDavid du Colombier mips4kboot }, 1073e12c5d1SDavid du Colombier { K_MAGIC, /* Sparc k.out */ 1083e12c5d1SDavid du Colombier "sparc plan 9 executable", 109*12fd1c83SDavid du Colombier "sparc plan 9 dlm", 1103e12c5d1SDavid du Colombier FSPARC, 1113e12c5d1SDavid du Colombier &msparc, 1123e12c5d1SDavid du Colombier sizeof(Exec), 1133e12c5d1SDavid du Colombier beswal, 1143e12c5d1SDavid du Colombier adotout }, 1153e12c5d1SDavid du Colombier { 0x01030107, /* Sparc boot image */ 1163e12c5d1SDavid du Colombier "sparc plan 9 boot image", 117*12fd1c83SDavid du Colombier nil, 1183e12c5d1SDavid du Colombier FSPARCB, 1193e12c5d1SDavid du Colombier &msparc, 1203e12c5d1SDavid du Colombier sizeof(struct sparcexec), 1213e12c5d1SDavid du Colombier beswal, 1223e12c5d1SDavid du Colombier sparcboot }, 1233e12c5d1SDavid du Colombier { A_MAGIC, /* 68020 2.out & boot image */ 1243e12c5d1SDavid du Colombier "68020 plan 9 executable", 125*12fd1c83SDavid du Colombier "68020 plan 9 dlm", 1263e12c5d1SDavid du Colombier F68020, 1273e12c5d1SDavid du Colombier &m68020, 1283e12c5d1SDavid du Colombier sizeof(Exec), 1293e12c5d1SDavid du Colombier beswal, 1303e12c5d1SDavid du Colombier common }, 1313e12c5d1SDavid du Colombier { 0xFEEDFACE, /* Next boot image */ 1323e12c5d1SDavid du Colombier "next plan 9 boot image", 133*12fd1c83SDavid du Colombier nil, 1343e12c5d1SDavid du Colombier FNEXTB, 1353e12c5d1SDavid du Colombier &m68020, 1363e12c5d1SDavid du Colombier sizeof(struct nextexec), 1373e12c5d1SDavid du Colombier beswal, 1383e12c5d1SDavid du Colombier nextboot }, 1393e12c5d1SDavid du Colombier { I_MAGIC, /* I386 8.out & boot image */ 1403e12c5d1SDavid du Colombier "386 plan 9 executable", 141*12fd1c83SDavid du Colombier "386 plan 9 dlm", 1423e12c5d1SDavid du Colombier FI386, 1433e12c5d1SDavid du Colombier &mi386, 1443e12c5d1SDavid du Colombier sizeof(Exec), 1453e12c5d1SDavid du Colombier beswal, 1463e12c5d1SDavid du Colombier common }, 1479a747e4fSDavid du Colombier { Q_MAGIC, /* PowerPC q.out & boot image */ 1487dd7cddfSDavid du Colombier "power plan 9 executable", 149*12fd1c83SDavid du Colombier "power plan 9 dlm", 1507dd7cddfSDavid du Colombier FPOWER, 1517dd7cddfSDavid du Colombier &mpower, 1527dd7cddfSDavid du Colombier sizeof(Exec), 1537dd7cddfSDavid du Colombier beswal, 1547dd7cddfSDavid du Colombier common }, 1557dd7cddfSDavid du Colombier { ELF_MAG, 1567dd7cddfSDavid du Colombier "Irix 5.X Elf executable", 157*12fd1c83SDavid du Colombier nil, 1587dd7cddfSDavid du Colombier FMIPS, 1597dd7cddfSDavid du Colombier &mmips, 1607dd7cddfSDavid du Colombier sizeof(Ehdr), 1617dd7cddfSDavid du Colombier beswal, 1627dd7cddfSDavid du Colombier elfdotout }, 1637dd7cddfSDavid du Colombier { E_MAGIC, /* Arm 5.out */ 1647dd7cddfSDavid du Colombier "Arm plan 9 executable", 165*12fd1c83SDavid du Colombier "Arm plan 9 dlm", 1667dd7cddfSDavid du Colombier FARM, 1677dd7cddfSDavid du Colombier &marm, 1687dd7cddfSDavid du Colombier sizeof(Exec), 1697dd7cddfSDavid du Colombier beswal, 1707dd7cddfSDavid du Colombier common }, 1717dd7cddfSDavid du Colombier { (143<<16)|0413, /* (Free|Net)BSD Arm */ 1727dd7cddfSDavid du Colombier "Arm *BSD executable", 173*12fd1c83SDavid du Colombier nil, 1747dd7cddfSDavid du Colombier FARM, 1757dd7cddfSDavid du Colombier &marm, 1767dd7cddfSDavid du Colombier sizeof(Exec), 1777dd7cddfSDavid du Colombier leswal, 1787dd7cddfSDavid du Colombier armdotout }, 1797dd7cddfSDavid du Colombier { L_MAGIC, /* alpha 7.out */ 1807dd7cddfSDavid du Colombier "alpha plan 9 executable", 181*12fd1c83SDavid du Colombier "alpha plan 9 dlm", 1827dd7cddfSDavid du Colombier FALPHA, 1837dd7cddfSDavid du Colombier &malpha, 1847dd7cddfSDavid du Colombier sizeof(Exec), 1857dd7cddfSDavid du Colombier beswal, 1867dd7cddfSDavid du Colombier common }, 1877dd7cddfSDavid du Colombier { 0x0700e0c3, /* alpha boot image */ 1887dd7cddfSDavid du Colombier "alpha plan 9 boot image", 189*12fd1c83SDavid du Colombier nil, 1907dd7cddfSDavid du Colombier FALPHAB, 1917dd7cddfSDavid du Colombier &malpha, 1927dd7cddfSDavid du Colombier sizeof(Exec), 1937dd7cddfSDavid du Colombier beswal, 1947dd7cddfSDavid du Colombier alphadotout }, 1953e12c5d1SDavid du Colombier { 0 }, 1963e12c5d1SDavid du Colombier }; 1973e12c5d1SDavid du Colombier 1987dd7cddfSDavid du Colombier Mach *mach = &mi386; /* Global current machine table */ 1997dd7cddfSDavid du Colombier 2007dd7cddfSDavid du Colombier static ExecTable* 2017dd7cddfSDavid du Colombier couldbe4k(ExecTable *mp) 2027dd7cddfSDavid du Colombier { 2039a747e4fSDavid du Colombier Dir *d; 2047dd7cddfSDavid du Colombier ExecTable *f; 2057dd7cddfSDavid du Colombier 2069a747e4fSDavid du Colombier if((d=dirstat("/proc/1/regs")) == nil) 2077dd7cddfSDavid du Colombier return mp; 2089a747e4fSDavid du Colombier if(d->length < 32*8){ /* R3000 */ 2099a747e4fSDavid du Colombier free(d); 2107dd7cddfSDavid du Colombier return mp; 2119a747e4fSDavid du Colombier } 2129a747e4fSDavid du Colombier free(d); 2137dd7cddfSDavid du Colombier for (f = exectab; f->magic; f++) 2147dd7cddfSDavid du Colombier if(f->magic == M_MAGIC) { 2157dd7cddfSDavid du Colombier f->name = "mips plan 9 executable on mips2 kernel"; 2167dd7cddfSDavid du Colombier return f; 2177dd7cddfSDavid du Colombier } 2187dd7cddfSDavid du Colombier return mp; 2197dd7cddfSDavid du Colombier } 2207dd7cddfSDavid du Colombier 2213e12c5d1SDavid du Colombier int 2223e12c5d1SDavid du Colombier crackhdr(int fd, Fhdr *fp) 2233e12c5d1SDavid du Colombier { 2243e12c5d1SDavid du Colombier ExecTable *mp; 2253e12c5d1SDavid du Colombier ExecHdr d; 2267dd7cddfSDavid du Colombier int nb, magic, ret; 2273e12c5d1SDavid du Colombier 2283e12c5d1SDavid du Colombier fp->type = FNONE; 2297dd7cddfSDavid du Colombier nb = read(fd, (char *)&d.e, sizeof(d.e)); 2307dd7cddfSDavid du Colombier if (nb <= 0) 2313e12c5d1SDavid du Colombier return 0; 2327dd7cddfSDavid du Colombier 2337dd7cddfSDavid du Colombier ret = 0; 2343e12c5d1SDavid du Colombier fp->magic = magic = beswal(d.e.magic); /* big-endian */ 2353e12c5d1SDavid du Colombier for (mp = exectab; mp->magic; mp++) { 236*12fd1c83SDavid du Colombier if (nb < mp->hsize) 237*12fd1c83SDavid du Colombier continue; 238*12fd1c83SDavid du Colombier if (mp->magic == (magic & ~DYN_MAGIC)) { 2397dd7cddfSDavid du Colombier if(mp->magic == V_MAGIC) 2407dd7cddfSDavid du Colombier mp = couldbe4k(mp); 2417dd7cddfSDavid du Colombier 2423e12c5d1SDavid du Colombier hswal((long *) &d, sizeof(d.e)/sizeof(long), mp->swal); 2433e12c5d1SDavid du Colombier fp->type = mp->type; 244*12fd1c83SDavid du Colombier if ((magic & DYN_MAGIC) && mp->dlmname != nil) 245*12fd1c83SDavid du Colombier fp->name = mp->dlmname; 246*12fd1c83SDavid du Colombier else 2473e12c5d1SDavid du Colombier fp->name = mp->name; 248219b2ee8SDavid du Colombier fp->hdrsz = mp->hsize; /* zero on bootables */ 2493e12c5d1SDavid du Colombier mach = mp->mach; 2507dd7cddfSDavid du Colombier ret = mp->hparse(fd, fp, &d); 2513e12c5d1SDavid du Colombier seek(fd, mp->hsize, 0); /* seek to end of header */ 2527dd7cddfSDavid du Colombier break; 2533e12c5d1SDavid du Colombier } 2543e12c5d1SDavid du Colombier } 2557dd7cddfSDavid du Colombier if(mp->magic == 0) 2567dd7cddfSDavid du Colombier werrstr("unknown header type"); 2577dd7cddfSDavid du Colombier return ret; 2583e12c5d1SDavid du Colombier } 2593e12c5d1SDavid du Colombier /* 2603e12c5d1SDavid du Colombier * Convert header to canonical form 2613e12c5d1SDavid du Colombier */ 2623e12c5d1SDavid du Colombier static void 2633e12c5d1SDavid du Colombier hswal(long *lp, int n, long (*swap) (long)) 2643e12c5d1SDavid du Colombier { 2653e12c5d1SDavid du Colombier while (n--) { 2663e12c5d1SDavid du Colombier *lp = (*swap) (*lp); 2673e12c5d1SDavid du Colombier lp++; 2683e12c5d1SDavid du Colombier } 2693e12c5d1SDavid du Colombier } 2703e12c5d1SDavid du Colombier /* 2713e12c5d1SDavid du Colombier * Crack a normal a.out-type header 2723e12c5d1SDavid du Colombier */ 2737dd7cddfSDavid du Colombier static int 2747dd7cddfSDavid du Colombier adotout(int fd, Fhdr *fp, ExecHdr *hp) 2753e12c5d1SDavid du Colombier { 2767dd7cddfSDavid du Colombier long pgsize; 2773e12c5d1SDavid du Colombier 2787dd7cddfSDavid du Colombier USED(fd); 2797dd7cddfSDavid du Colombier pgsize = mach->pgsize; 280219b2ee8SDavid du Colombier settext(fp, hp->e.entry, pgsize+sizeof(Exec), 281219b2ee8SDavid du Colombier hp->e.text, sizeof(Exec)); 282219b2ee8SDavid du Colombier setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize), 283219b2ee8SDavid du Colombier hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 2843e12c5d1SDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 2857dd7cddfSDavid du Colombier return 1; 2863e12c5d1SDavid du Colombier } 2873e12c5d1SDavid du Colombier 2883e12c5d1SDavid du Colombier /* 2893e12c5d1SDavid du Colombier * 68020 2.out and 68020 bootable images 2903e12c5d1SDavid du Colombier * 386I 8.out and 386I bootable images 2917dd7cddfSDavid du Colombier * alpha plan9-style bootable images for axp "headerless" boot 2923e12c5d1SDavid du Colombier * 2933e12c5d1SDavid du Colombier */ 2947dd7cddfSDavid du Colombier static int 2957dd7cddfSDavid du Colombier common(int fd, Fhdr *fp, ExecHdr *hp) 2963e12c5d1SDavid du Colombier { 2977dd7cddfSDavid du Colombier long kbase; 2983e12c5d1SDavid du Colombier 2997dd7cddfSDavid du Colombier adotout(fd, fp, hp); 3009a747e4fSDavid du Colombier if(hp->e.magic & DYN_MAGIC) { 3019a747e4fSDavid du Colombier fp->txtaddr = 0; 3029a747e4fSDavid du Colombier fp->dataddr = fp->txtsz; 3039a747e4fSDavid du Colombier return 1; 3049a747e4fSDavid du Colombier } 3057dd7cddfSDavid du Colombier kbase = mach->kbase; 3067dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 3073e12c5d1SDavid du Colombier switch(fp->type) { 3083e12c5d1SDavid du Colombier case F68020: 3093e12c5d1SDavid du Colombier fp->type = F68020B; 3103e12c5d1SDavid du Colombier fp->name = "68020 plan 9 boot image"; 311219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3123e12c5d1SDavid du Colombier break; 3133e12c5d1SDavid du Colombier case FI386: 3143e12c5d1SDavid du Colombier fp->type = FI386B; 315219b2ee8SDavid du Colombier fp->txtaddr = sizeof(Exec); 3163e12c5d1SDavid du Colombier fp->name = "386 plan 9 boot image"; 317219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 318219b2ee8SDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3193e12c5d1SDavid du Colombier break; 3207dd7cddfSDavid du Colombier case FARM: 32180ee5cbfSDavid du Colombier fp->txtaddr = kbase+0x8010; 3227dd7cddfSDavid du Colombier fp->name = "ARM plan 9 boot image"; 3237dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3247dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3257dd7cddfSDavid du Colombier return 1; 3267dd7cddfSDavid du Colombier case FALPHA: 3277dd7cddfSDavid du Colombier fp->type = FALPHAB; 3287dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 3299a747e4fSDavid du Colombier fp->name = "alpha plan 9 boot image?"; 3307dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3317dd7cddfSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3327dd7cddfSDavid du Colombier break; 3339a747e4fSDavid du Colombier case FPOWER: 3349a747e4fSDavid du Colombier fp->type = FPOWERB; 3359a747e4fSDavid du Colombier fp->txtaddr = fp->entry; 3369a747e4fSDavid du Colombier fp->name = "power plan 9 boot image"; 3377dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3389a747e4fSDavid du Colombier fp->dataddr = fp->txtaddr+fp->txtsz; 3399a747e4fSDavid du Colombier break; 3403e12c5d1SDavid du Colombier default: 3413e12c5d1SDavid du Colombier break; 3423e12c5d1SDavid du Colombier } 3433e12c5d1SDavid du Colombier fp->txtaddr |= kbase; 3443e12c5d1SDavid du Colombier fp->entry |= kbase; 3453e12c5d1SDavid du Colombier fp->dataddr |= kbase; 3463e12c5d1SDavid du Colombier } 3477dd7cddfSDavid du Colombier return 1; 3483e12c5d1SDavid du Colombier } 3493e12c5d1SDavid du Colombier 3503e12c5d1SDavid du Colombier /* 3513e12c5d1SDavid du Colombier * mips bootable image. 3523e12c5d1SDavid du Colombier */ 3537dd7cddfSDavid du Colombier static int 3547dd7cddfSDavid du Colombier mipsboot(int fd, Fhdr *fp, ExecHdr *hp) 3553e12c5d1SDavid du Colombier { 3567dd7cddfSDavid du Colombier USED(fd); 3573e12c5d1SDavid du Colombier switch(hp->e.amagic) { 3583e12c5d1SDavid du Colombier default: 3593e12c5d1SDavid du Colombier case 0407: /* some kind of mips */ 3603e12c5d1SDavid du Colombier fp->type = FMIPSB; 3613e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 3623e12c5d1SDavid du Colombier sizeof(struct mipsexec)+4); 3633e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, 3643e12c5d1SDavid du Colombier fp->txtoff+hp->e.tsize, hp->e.bsize); 3653e12c5d1SDavid du Colombier break; 3663e12c5d1SDavid du Colombier case 0413: /* some kind of mips */ 3673e12c5d1SDavid du Colombier fp->type = FMIPSB; 3683e12c5d1SDavid du Colombier settext(fp, hp->e.mentry, hp->e.text_start, hp->e.tsize, 0); 3693e12c5d1SDavid du Colombier setdata(fp, hp->e.data_start, hp->e.dsize, hp->e.tsize, 3703e12c5d1SDavid du Colombier hp->e.bsize); 3713e12c5d1SDavid du Colombier break; 3723e12c5d1SDavid du Colombier } 3733e12c5d1SDavid du Colombier setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr); 374219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 3757dd7cddfSDavid du Colombier return 1; 3763e12c5d1SDavid du Colombier } 377219b2ee8SDavid du Colombier 3783e12c5d1SDavid du Colombier /* 379219b2ee8SDavid du Colombier * mips4k bootable image. 3803e12c5d1SDavid du Colombier */ 3817dd7cddfSDavid du Colombier static int 3827dd7cddfSDavid du Colombier mips4kboot(int fd, Fhdr *fp, ExecHdr *hp) 3833e12c5d1SDavid du Colombier { 3847dd7cddfSDavid du Colombier USED(fd); 385219b2ee8SDavid du Colombier switch(hp->e.h.amagic) { 386219b2ee8SDavid du Colombier default: 387219b2ee8SDavid du Colombier case 0407: /* some kind of mips */ 388219b2ee8SDavid du Colombier fp->type = FMIPSB; 389219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 390219b2ee8SDavid du Colombier sizeof(struct mips4kexec)); 391219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, 392219b2ee8SDavid du Colombier fp->txtoff+hp->e.h.tsize, hp->e.h.bsize); 393219b2ee8SDavid du Colombier break; 394219b2ee8SDavid du Colombier case 0413: /* some kind of mips */ 395219b2ee8SDavid du Colombier fp->type = FMIPSB; 396219b2ee8SDavid du Colombier settext(fp, hp->e.h.mentry, hp->e.h.text_start, hp->e.h.tsize, 0); 397219b2ee8SDavid du Colombier setdata(fp, hp->e.h.data_start, hp->e.h.dsize, hp->e.h.tsize, 398219b2ee8SDavid du Colombier hp->e.h.bsize); 399219b2ee8SDavid du Colombier break; 4003e12c5d1SDavid du Colombier } 401219b2ee8SDavid du Colombier setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr); 402219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4037dd7cddfSDavid du Colombier return 1; 404219b2ee8SDavid du Colombier } 405219b2ee8SDavid du Colombier 4063e12c5d1SDavid du Colombier /* 4073e12c5d1SDavid du Colombier * sparc bootable image 4083e12c5d1SDavid du Colombier */ 4097dd7cddfSDavid du Colombier static int 4107dd7cddfSDavid du Colombier sparcboot(int fd, Fhdr *fp, ExecHdr *hp) 4113e12c5d1SDavid du Colombier { 4127dd7cddfSDavid du Colombier USED(fd); 4133e12c5d1SDavid du Colombier fp->type = FSPARCB; 4143e12c5d1SDavid du Colombier settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext, 4153e12c5d1SDavid du Colombier sizeof(struct sparcexec)); 4163e12c5d1SDavid du Colombier setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata, 4173e12c5d1SDavid du Colombier fp->txtoff+hp->e.stext, hp->e.sbss); 4183e12c5d1SDavid du Colombier setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata); 419219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4207dd7cddfSDavid du Colombier return 1; 4213e12c5d1SDavid du Colombier } 4223e12c5d1SDavid du Colombier 4233e12c5d1SDavid du Colombier /* 4243e12c5d1SDavid du Colombier * next bootable image 4253e12c5d1SDavid du Colombier */ 4267dd7cddfSDavid du Colombier static int 4277dd7cddfSDavid du Colombier nextboot(int fd, Fhdr *fp, ExecHdr *hp) 4283e12c5d1SDavid du Colombier { 4297dd7cddfSDavid du Colombier USED(fd); 4303e12c5d1SDavid du Colombier fp->type = FNEXTB; 4313e12c5d1SDavid du Colombier settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr, 4323e12c5d1SDavid du Colombier hp->e.texts.size, hp->e.texts.offset); 4333e12c5d1SDavid du Colombier setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size, 4343e12c5d1SDavid du Colombier hp->e.datas.offset, hp->e.bsss.size); 4353e12c5d1SDavid du Colombier setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff, 4363e12c5d1SDavid du Colombier hp->e.symc.symoff); 437219b2ee8SDavid du Colombier fp->hdrsz = 0; /* header stripped */ 4387dd7cddfSDavid du Colombier return 1; 4393e12c5d1SDavid du Colombier } 4403e12c5d1SDavid du Colombier 4417dd7cddfSDavid du Colombier static Shdr* 4427dd7cddfSDavid du Colombier elfsectbyname(int fd, Ehdr *hp, Shdr *sp, char *name) 4437dd7cddfSDavid du Colombier { 4447dd7cddfSDavid du Colombier int i, offset, n; 4457dd7cddfSDavid du Colombier char s[64]; 4467dd7cddfSDavid du Colombier 4477dd7cddfSDavid du Colombier offset = sp[hp->shstrndx].offset; 4487dd7cddfSDavid du Colombier for(i = 1; i < hp->shnum; i++) { 4497dd7cddfSDavid du Colombier seek(fd, offset+sp[i].name, 0); 4507dd7cddfSDavid du Colombier n = read(fd, s, sizeof(s)-1); 4517dd7cddfSDavid du Colombier if(n < 0) 4527dd7cddfSDavid du Colombier continue; 4537dd7cddfSDavid du Colombier s[n] = 0; 4547dd7cddfSDavid du Colombier if(strcmp(s, name) == 0) 4557dd7cddfSDavid du Colombier return &sp[i]; 4567dd7cddfSDavid du Colombier } 4577dd7cddfSDavid du Colombier return 0; 4587dd7cddfSDavid du Colombier } 4597dd7cddfSDavid du Colombier /* 4607dd7cddfSDavid du Colombier * Decode an Irix 5.x ELF header 4617dd7cddfSDavid du Colombier */ 4627dd7cddfSDavid du Colombier static int 4637dd7cddfSDavid du Colombier elfdotout(int fd, Fhdr *fp, ExecHdr *hp) 4647dd7cddfSDavid du Colombier { 4657dd7cddfSDavid du Colombier 4667dd7cddfSDavid du Colombier Ehdr *ep; 4677dd7cddfSDavid du Colombier Shdr *es, *txt, *init, *s; 4687dd7cddfSDavid du Colombier long addr, size, offset, bsize; 4697dd7cddfSDavid du Colombier 4707dd7cddfSDavid du Colombier ep = &hp->e; 4717dd7cddfSDavid du Colombier if(ep->type != 8 || ep->machine != 2 || ep->version != 1) 4727dd7cddfSDavid du Colombier return 0; 4737dd7cddfSDavid du Colombier 4747dd7cddfSDavid du Colombier fp->magic = ELF_MAG; 4757dd7cddfSDavid du Colombier fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15; 4767dd7cddfSDavid du Colombier 4777dd7cddfSDavid du Colombier if(ep->shnum <= 0) { 4787dd7cddfSDavid du Colombier werrstr("no ELF header sections"); 4797dd7cddfSDavid du Colombier return 0; 4807dd7cddfSDavid du Colombier } 4817dd7cddfSDavid du Colombier es = malloc(sizeof(Shdr)*ep->shnum); 4827dd7cddfSDavid du Colombier if(es == 0) 4837dd7cddfSDavid du Colombier return 0; 4847dd7cddfSDavid du Colombier 4857dd7cddfSDavid du Colombier seek(fd, ep->shoff, 0); 4867dd7cddfSDavid du Colombier if(read(fd, es, sizeof(Shdr)*ep->shnum) < 0){ 4877dd7cddfSDavid du Colombier free(es); 4887dd7cddfSDavid du Colombier return 0; 4897dd7cddfSDavid du Colombier } 4907dd7cddfSDavid du Colombier 4917dd7cddfSDavid du Colombier txt = elfsectbyname(fd, ep, es, ".text"); 4927dd7cddfSDavid du Colombier init = elfsectbyname(fd, ep, es, ".init"); 4937dd7cddfSDavid du Colombier if(txt == 0 || init == 0 || init != txt+1) 4947dd7cddfSDavid du Colombier goto bad; 4957dd7cddfSDavid du Colombier if(txt->addr+txt->size != init->addr) 4967dd7cddfSDavid du Colombier goto bad; 4977dd7cddfSDavid du Colombier settext(fp, ep->elfentry, txt->addr, txt->size+init->size, txt->offset); 4987dd7cddfSDavid du Colombier 4997dd7cddfSDavid du Colombier addr = 0; 5007dd7cddfSDavid du Colombier offset = 0; 5017dd7cddfSDavid du Colombier size = 0; 5027dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".data"); 5037dd7cddfSDavid du Colombier if(s) { 5047dd7cddfSDavid du Colombier addr = s->addr; 5057dd7cddfSDavid du Colombier size = s->size; 5067dd7cddfSDavid du Colombier offset = s->offset; 5077dd7cddfSDavid du Colombier } 5087dd7cddfSDavid du Colombier 5097dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".rodata"); 5107dd7cddfSDavid du Colombier if(s) { 5117dd7cddfSDavid du Colombier if(addr){ 5127dd7cddfSDavid du Colombier if(addr+size != s->addr) 5137dd7cddfSDavid du Colombier goto bad; 5147dd7cddfSDavid du Colombier } else { 5157dd7cddfSDavid du Colombier addr = s->addr; 5167dd7cddfSDavid du Colombier offset = s->offset; 5177dd7cddfSDavid du Colombier } 5187dd7cddfSDavid du Colombier size += s->size; 5197dd7cddfSDavid du Colombier } 5207dd7cddfSDavid du Colombier 5217dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".got"); 5227dd7cddfSDavid du Colombier if(s) { 5237dd7cddfSDavid du Colombier if(addr){ 5247dd7cddfSDavid du Colombier if(addr+size != s->addr) 5257dd7cddfSDavid du Colombier goto bad; 5267dd7cddfSDavid du Colombier } else { 5277dd7cddfSDavid du Colombier addr = s->addr; 5287dd7cddfSDavid du Colombier offset = s->offset; 5297dd7cddfSDavid du Colombier } 5307dd7cddfSDavid du Colombier size += s->size; 5317dd7cddfSDavid du Colombier } 5327dd7cddfSDavid du Colombier 5337dd7cddfSDavid du Colombier bsize = 0; 5347dd7cddfSDavid du Colombier s = elfsectbyname(fd, ep, es, ".bss"); 5357dd7cddfSDavid du Colombier if(s) { 5367dd7cddfSDavid du Colombier if(addr){ 5377dd7cddfSDavid du Colombier if(addr+size != s->addr) 5387dd7cddfSDavid du Colombier goto bad; 5397dd7cddfSDavid du Colombier } else { 5407dd7cddfSDavid du Colombier addr = s->addr; 5417dd7cddfSDavid du Colombier offset = s->offset; 5427dd7cddfSDavid du Colombier } 5437dd7cddfSDavid du Colombier bsize = s->size; 5447dd7cddfSDavid du Colombier } 5457dd7cddfSDavid du Colombier 5467dd7cddfSDavid du Colombier if(addr == 0) 5477dd7cddfSDavid du Colombier goto bad; 5487dd7cddfSDavid du Colombier 5497dd7cddfSDavid du Colombier setdata(fp, addr, size, offset, bsize); 5507dd7cddfSDavid du Colombier fp->name = "IRIX Elf a.out executable"; 5517dd7cddfSDavid du Colombier free(es); 5527dd7cddfSDavid du Colombier return 1; 5537dd7cddfSDavid du Colombier bad: 5547dd7cddfSDavid du Colombier free(es); 5557dd7cddfSDavid du Colombier werrstr("ELF sections scrambled"); 5567dd7cddfSDavid du Colombier return 0; 5577dd7cddfSDavid du Colombier } 5587dd7cddfSDavid du Colombier 5597dd7cddfSDavid du Colombier /* 5607dd7cddfSDavid du Colombier * alpha bootable 5617dd7cddfSDavid du Colombier */ 5627dd7cddfSDavid du Colombier static int 5637dd7cddfSDavid du Colombier alphadotout(int fd, Fhdr *fp, ExecHdr *hp) 5647dd7cddfSDavid du Colombier { 5657dd7cddfSDavid du Colombier long kbase; 5667dd7cddfSDavid du Colombier 5677dd7cddfSDavid du Colombier USED(fd); 5687dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 5697dd7cddfSDavid du Colombier setdata(fp, fp->txtsz+sizeof(Exec), hp->e.data, fp->txtsz+sizeof(Exec), hp->e.bss); 5707dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 5717dd7cddfSDavid du Colombier 5727dd7cddfSDavid du Colombier /* 5737dd7cddfSDavid du Colombier * Boot images have some of bits <31:28> set: 5747dd7cddfSDavid du Colombier * 0x80400000 kernel 5757dd7cddfSDavid du Colombier * 0x20000000 secondary bootstrap 5767dd7cddfSDavid du Colombier */ 5777dd7cddfSDavid du Colombier kbase = 0xF0000000; 5787dd7cddfSDavid du Colombier if (fp->entry & kbase) { 5797dd7cddfSDavid du Colombier fp->txtaddr = fp->entry; 5807dd7cddfSDavid du Colombier fp->name = "alpha plan 9 boot image"; 5817dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 5827dd7cddfSDavid du Colombier fp->dataddr = fp->entry+fp->txtsz; 5837dd7cddfSDavid du Colombier } 5847dd7cddfSDavid du Colombier return 1; 5857dd7cddfSDavid du Colombier } 5867dd7cddfSDavid du Colombier 5877dd7cddfSDavid du Colombier /* 5887dd7cddfSDavid du Colombier * (Free|Net)BSD ARM header. 5897dd7cddfSDavid du Colombier */ 5907dd7cddfSDavid du Colombier static int 5917dd7cddfSDavid du Colombier armdotout(int fd, Fhdr *fp, ExecHdr *hp) 5927dd7cddfSDavid du Colombier { 5937dd7cddfSDavid du Colombier long kbase; 5947dd7cddfSDavid du Colombier 5957dd7cddfSDavid du Colombier USED(fd); 5967dd7cddfSDavid du Colombier settext(fp, hp->e.entry, sizeof(Exec), hp->e.text, sizeof(Exec)); 5977dd7cddfSDavid du Colombier setdata(fp, fp->txtsz, hp->e.data, fp->txtsz, hp->e.bss); 5987dd7cddfSDavid du Colombier setsym(fp, hp->e.syms, hp->e.spsz, hp->e.pcsz, fp->datoff+fp->datsz); 5997dd7cddfSDavid du Colombier 6007dd7cddfSDavid du Colombier kbase = 0xF0000000; 6017dd7cddfSDavid du Colombier if ((fp->entry & kbase) == kbase) { /* Boot image */ 6027dd7cddfSDavid du Colombier fp->txtaddr = kbase+sizeof(Exec); 6037dd7cddfSDavid du Colombier fp->name = "ARM *BSD boot image"; 6047dd7cddfSDavid du Colombier fp->hdrsz = 0; /* header stripped */ 6057dd7cddfSDavid du Colombier fp->dataddr = kbase+fp->txtsz; 6067dd7cddfSDavid du Colombier } 6077dd7cddfSDavid du Colombier return 1; 6087dd7cddfSDavid du Colombier } 6093e12c5d1SDavid du Colombier 6103e12c5d1SDavid du Colombier static void 6113e12c5d1SDavid du Colombier settext(Fhdr *fp, long e, long a, long s, long off) 6123e12c5d1SDavid du Colombier { 6133e12c5d1SDavid du Colombier fp->txtaddr = a; 6143e12c5d1SDavid du Colombier fp->entry = e; 6153e12c5d1SDavid du Colombier fp->txtsz = s; 6163e12c5d1SDavid du Colombier fp->txtoff = off; 6173e12c5d1SDavid du Colombier } 6183e12c5d1SDavid du Colombier static void 6193e12c5d1SDavid du Colombier setdata(Fhdr *fp, long a, long s, long off, long bss) 6203e12c5d1SDavid du Colombier { 6213e12c5d1SDavid du Colombier fp->dataddr = a; 6223e12c5d1SDavid du Colombier fp->datsz = s; 6233e12c5d1SDavid du Colombier fp->datoff = off; 6243e12c5d1SDavid du Colombier fp->bsssz = bss; 6253e12c5d1SDavid du Colombier } 6263e12c5d1SDavid du Colombier static void 6273e12c5d1SDavid du Colombier setsym(Fhdr *fp, long sy, long sppc, long lnpc, long symoff) 6283e12c5d1SDavid du Colombier { 6293e12c5d1SDavid du Colombier fp->symsz = sy; 6303e12c5d1SDavid du Colombier fp->symoff = symoff; 6313e12c5d1SDavid du Colombier fp->sppcsz = sppc; 6323e12c5d1SDavid du Colombier fp->sppcoff = fp->symoff+fp->symsz; 6333e12c5d1SDavid du Colombier fp->lnpcsz = lnpc; 6343e12c5d1SDavid du Colombier fp->lnpcoff = fp->sppcoff+fp->sppcsz; 6353e12c5d1SDavid du Colombier } 6363e12c5d1SDavid du Colombier 637219b2ee8SDavid du Colombier 638219b2ee8SDavid du Colombier static long 639219b2ee8SDavid du Colombier _round(long a, long b) 640219b2ee8SDavid du Colombier { 641219b2ee8SDavid du Colombier long w; 642219b2ee8SDavid du Colombier 643219b2ee8SDavid du Colombier w = (a/b)*b; 644219b2ee8SDavid du Colombier if (a!=w) 645219b2ee8SDavid du Colombier w += b; 646219b2ee8SDavid du Colombier return(w); 647219b2ee8SDavid du Colombier } 648