/* * elf2cnk * Copyright (C) 2008 Ronald G. Minnich * * derived from: * * lar - lightweight archiver * * This includes code from previous versions of the LAR utility, * including create.c, list.c, extract.c and bootblock.c * * Copyright (C) 2006-2007 coresystems GmbH * (Written by Stefan Reinauer for coresystems GmbH) * Copyright (C) 2007 Patrick Georgi * Copyright (C) 2007 Advanced Micro Devices, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA, 02110-1301 USA */ #include #include #include #include #include "elf.h" int verbose(void){ return 1; } void errexit(char *s) { fprint(2, smprint("%s\n", s)); exits("life sucks"); } void ssize(int fd, u32int va, u32int size) { char *cmd; /* round size up to nearest MB */ size += 0xfffff; size &= ~0xfffff; cmd = smprint("va %#x %#x", va, size); if (write(fd, cmd, strlen(cmd)) < 0) errexit("Setting size"); } unsigned char *makeseg(char *name, u32int addr, u32int size, int markheap) { char *segname = smprint("/n/cnk/%s", name); char *ctl = smprint("/n/cnk/%s/ctl", name); int ctlfd; unsigned char *ptr; remove(segname); if (create(segname, 0, DMDIR|0777)<0) errexit(segname); if ((ctlfd = open(ctl, ORDWR)) < 0) errexit(ctl); ssize(ctlfd, addr, size); if (markheap) { if (write(ctlfd, "heap", 4) < 0) errexit("Setting heap"); } ptr = segattach(0, name, (void *)addr,size); if (ptr == (unsigned char *)-1) errexit("segattach"); memset(ptr, 0, size); return ptr; } /* aux vector structure. Can NOT be null. */ typedef struct { u32int a_type; /* Entry type */ union { u32int a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; } Elf32_auxv_t; /* * All a.out header types. The dummy entry allows canonical * processing of the union as a sequence of longs */ typedef struct { union{ Ehdr; /* elf.h */ } e; long dummy; /* padding to ensure extra long */ } ExecHdr; extern void *exechdr(void); extern void *phdr(void); /* we need an array of these. Cheese it out and just make 32 of them. * they will start out empty (zero'd) and we'll just add what we need. */ int auxc = 0; Elf32_auxv_t aux[32]; void naux(int type, u32int val) { aux[auxc].a_type = type; aux[auxc].a_un.a_val = val; auxc++; } /* * Elf32 binaries. */ Phdr * hdr(int fd) { Ehdr *ep; Phdr *ph; int i; ep = exechdr(); ph = phdr(); fprint(2,"elf add %d entries at %p\n", ep->phnum, ph); for(i = 0; i < ep->phnum; i++) fprint(2,"%d: type %d va %p pa %p \n", i, ph[i].type, ph[i].vaddr, ph[i].paddr); /* GNU ELF is weird. GNUSTACK is the last phdr and it's confusing libmach. */ naux(AT_PHNUM, ep->phnum-1); naux(AT_PHDR, (u32int)ph); return ph; } void usage(void) { errexit(smprint("usage: machcnk [-b] [breakpoint] [a]rgstosyscall [s]yscall [u]regsbefore [U]uregsafter [f]aultpower [F]aultpowerregs elf\n")); } main(int argc, char *argv[]) { char *ctlpath = "#P/cnk"; void callcnk(void (*f)(int, char **), int, char **, char **); int fd, ctl; unsigned char *textp, *datap, *bssp; void (*f)(int argc, char *argv[]); Fhdr fp; Map *map; int textseg, dataseg; int i; u32int breakpoint = 0; char *av[256]; int cnk = 2; char cmd[2]; ARGBEGIN{ case 'b': breakpoint = strtoul(EARGF(usage()), 0, 0); break; case 'f': cnk |= 4; break; case 'F': cnk |= 8; break; case 's': cnk |= 16; break; case 'u': cnk |= 32; break; case 'U': cnk |= 64; break; case 'a': cnk |= 128; break; default: usage(); break; }ARGEND if (argc < 1) errexit("usage: elfcnk filename"); fd = open(argv[0], OREAD); if (fd < 0) errexit(smprint("Can't open %s\n", argv[1])); if (crackhdr(fd, &fp) < 0) errexit("crackhdr failed"); map = loadmap(nil, fd, &fp); if (! map) errexit("loadmap failed"); textseg = findseg(map, "text"); if (textseg < 0) errexit("no text segment"); dataseg = findseg(map, "data"); if (dataseg < 0) errexit("no data segment"); naux(AT_DCACHEBSIZE, 0x20); naux(AT_PAGESZ, 0x1000); naux(AT_UID, 0x17be); naux(AT_EUID, 0x17be); naux(AT_GID, 0x64); naux(AT_EGID, 0x64); naux(AT_HWCAP, 0x4); hdr(fd); fprint(2, "textseg is %d and dataseg is %d\n", textseg, dataseg); fprint(2, "base %#llx end %#llx off %#llx \n", map->seg[0].b, map->seg[0].e, map->seg[2].f); fprint(2, "base %#llx end %#llx off %#llx \n", map->seg[1].b, map->seg[1].e, map->seg[1].f); fprint(2, "txtaddr %#llx dataaddr %#llx entry %#llx txtsz %#lx datasz %#lx bsssz %#lx\n", fp.txtaddr, fp.dataddr, fp.entry, fp.txtsz, fp.datsz, fp.bsssz); if (dirstat("/n/cnk") == nil) if (create("/n/cnk", 0, DMDIR|0777)<0) errexit("/n/cnk"); /* let's make us some seggies */ if (bind("#g", "/n/cnk", MREPL|MCREATE) < 0) errexit("bind segdriver"); textp = makeseg("0", fp.txtaddr, fp.txtsz, 0); datap = makeseg("1", fp.dataddr, fp.datsz + fp.bsssz, 0); bssp = makeseg("3",512*1024*1024, 0x1000, 1); print("bssp is %p\n", bssp); /* now the big fun. Just copy it out */ pread(fd, textp, fp.txtsz, fp.txtoff); pread(fd, datap, fp.datsz, fp.datoff); /* hangpath = smprint("/proc/%d/ctl", getpid()); fprint(2, "Open %s\n", hangpath); hang = open(hangpath, OWRITE); if (hang < 0){ errexit(smprint("%s: %r", hangpath)); } if (write(hang, "hang", 4) < 4){ errexit(smprint("write cnk: %r")); } */ /* gnu is odd. they start out knowing args are on stack (sort of) */ /* av is going to become the start of the stack. */ /* this is where argc goes. */ av[0] = (char *)argc; for(i = 0; i < argc; i++) av[i+1] = argv[i]; i++; av[i++] = nil; av[i++] = "LANG=C"; av[i++] = nil; /* now just copy the aux array over av */ memcpy(&av[i], aux, sizeof(aux)); fprint(2, "env %p *env %p\n", &av[argc+2], av[argc+2]); /* set the breakpoint */ if (breakpoint){ *(u32int *)breakpoint = 0; fprint(2, "Breakpoint set at %#x\n", breakpoint); } fprint(2, "Open %s\n", ctlpath); ctl = open(ctlpath, OWRITE); if (ctl < 0){ errexit(smprint("%s: %r", ctlpath)); } sprint(cmd, "%1x", cnk); fprint(2, "write cnk cmd (%s)\n", cmd); if (write(ctl, cmd, 1) < 1){ errexit(smprint("write cnk: %r")); } // callcnk(f, argc, argv); f = (void *)fp.entry; callcnk(f, argc, &av[1], av); return 0; } /* qc -wF machcnk.c; ql -o machcnk machcnk.q */ /* 8c -wF machcnk.c; 8l -o machcnk machcnk.8 */ /* fcp q.out /mnt/term/tmp/machcnk */