diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /utils/5coff | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'utils/5coff')
| -rw-r--r-- | utils/5coff/5coff.c | 316 | ||||
| -rw-r--r-- | utils/5coff/NOTICE | 27 | ||||
| -rw-r--r-- | utils/5coff/auxi.c | 251 | ||||
| -rw-r--r-- | utils/5coff/auxi.h | 46 | ||||
| -rw-r--r-- | utils/5coff/coff.c | 642 | ||||
| -rw-r--r-- | utils/5coff/mkfile | 23 | ||||
| -rw-r--r-- | utils/5coff/readcoff.c | 298 |
7 files changed, 1603 insertions, 0 deletions
diff --git a/utils/5coff/5coff.c b/utils/5coff/5coff.c new file mode 100644 index 00000000..cae73108 --- /dev/null +++ b/utils/5coff/5coff.c @@ -0,0 +1,316 @@ +#include "auxi.h" + +#define RND(x, y) ((((x)+(y)-1)/(y))*(y)) + +char *cmd; +int sflag, dflag; + +int ifd, ofd; +Fhdr ihdr; + +long HEADR, INITTEXT, INITDAT, INITRND, INITENTRY; +long textsize, datsize, bsssize; + +int cout; +int thumb; + +static void get_file(char *); +static void put_file(char *); +static void usage(char *); +static long strxtol(char *); +static void readsyms(void); + +char *fail = "error"; + +void +main(int argc, char *argv[]) +{ + char *a, *ifile, *ofile; + + cmd = argv[0]; + + INITTEXT = -1; + INITDAT = -1; + INITRND = -1; + INITENTRY = -1; + + ARGBEGIN { + /* + * Options without args + */ + case 's': + sflag = 1; + break; + /* + * Options with args + */ + case 'T': + a = ARGF(); + if(a) + INITTEXT = strxtol(a); + break; + case 'D': + a = ARGF(); + if(a) + INITDAT = strxtol(a); + break; + case 'R': + a = ARGF(); + if(a) + INITRND = strxtol(a); + break; + case 'E': + a = ARGF(); + if(a) + INITENTRY = strxtol(a); + break; + case 'd': + dflag |= strxtol(ARGF()); + break; + default: + usage("Invalid option"); + } ARGEND + + if (argc != 2) + usage("Wrong number of arguments"); + + ifile = argv[0]; + ofile = argv[1]; + + get_file(ifile); + put_file(ofile); + exits(0); +} + +char usagemsg[] = +"usage: %s options infile outfile\n\t options (for outfile): -H[1234] -s -T<text> -D<data> -R<rnd> -E<entry>\n"; + +static void +usage(char *msg) +{ + fprint(2, "***Error: %s\n", msg); + fprint(2, usagemsg, cmd); + exits("usage"); +} + +static long +strxtol(char *s) +{ + char *es; + int base = 0; + long r; + + if (*s == '0') + if (*++s == 'x'){ + base = 16; + s++; + } + else + base = 8; + r = strtol(s, &es, base); + if (*es) + usage("bad number"); + return(r); +} + +static void +get_file(char *ifile) +{ + int h; + + ifd = open(ifile, OREAD); + if (ifd < 0) { + fprint(2, "5coff: open %s: %r\n", ifile); + exits("open"); + } + h = crackhdr(ifd, &ihdr); + if (!h || dflag){ + fprint(2, "Crackhdr: %d, type: %d, name: %s\n", h, ihdr.type, ihdr.name); + fprint(2, "txt %lux, ent %lux, txtsz %lux, dataddr %lux\n", + ihdr.txtaddr, ihdr.entry, ihdr.txtsz, ihdr.dataddr); + } + if (!h) + usage("File type not recognized"); + machbytype(ihdr.type); + if (dflag) + fprint(2, "name: <%s> pgsize:%ux\n", mach->name, mach->pgsize); + + HEADR = 22+28+3*48; + if(INITTEXT == -1) + INITTEXT = ihdr.txtaddr; + else + ihdr.txtaddr = INITTEXT; + if(INITDAT == -1) + INITDAT = ihdr.dataddr; + else + ihdr.dataddr = INITDAT; + if(INITENTRY == -1) + INITENTRY = ihdr.entry; + else + ihdr.entry = INITENTRY; + textsize = ihdr.txtsz; + datsize = ihdr.datsz; + bsssize = ihdr.bsssz; + if(INITRND > 0) + ihdr.dataddr = INITDAT = RND(INITTEXT+textsize, INITRND); + if(0){ + INITTEXT = INITENTRY; + INITDAT = RND(INITTEXT+textsize, 4); + } + if(0){ + print("H=%lux T=%lux D=%lux t=%lux d=%lux b=%lux e=%lux\n", HEADR, INITTEXT, INITDAT, textsize, datsize, bsssize, INITENTRY); + print("%lux %lux %lux %lux %lux %lux\n", ihdr.txtaddr, ihdr.dataddr, ihdr.entry, ihdr.txtsz, ihdr.datsz, ihdr.bsssz); + } + + readsyms(); +} + +#define WB 128 +#define WSAFE (WB-4) +char Wbuf[WB]; +char *wp = Wbuf; + +void +cflush(void) +{ + if(wp > Wbuf) + write(ofd, Wbuf, wp-Wbuf); + wp = Wbuf; +} + +void +lput(long l) +{ + wp[0] = l>>24; + wp[1] = l>>16; + wp[2] = l>>8; + wp[3] = l; + wp += 4; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +cput(int l) +{ + wp[0] = l; + wp += 1; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +hputl(int l) +{ + wp[1] = l>>8; + wp[0] = l; + wp += 2; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +void +lputl(long l) +{ + wp[3] = l>>24; + wp[2] = l>>16; + wp[1] = l>>8; + wp[0] = l; + wp += 4; + if(wp >= Wbuf+WSAFE) + cflush(); +} + +static void +copyseg(long sz) +{ + char buf[1024]; + + cflush(); + while (sz > 0){ + long n; + long r; + + n = sz; + if (n > sizeof buf) + n = sizeof buf; + sz -= n; + + if ((r = read(ifd, buf, n)) != n){ + fprint(2, "%ld = read(...%ld) at %ld\n", r, n, (long)seek(ifd, 0, 1)); + perror("Premature eof"); + exits(fail); + } + if ((r = write(ofd, buf, n)) != n){ + fprint(2, "%ld = write(...%ld)\n", r, n); + perror("Write error!"); + exits(fail); + } + } + cflush(); +} + +static void +put_file(char *ofile) +{ + ofd = create(ofile, OWRITE, 0666); + if (ofd < 0) { + fprint(2, "5coff: create %s: %r\n", ofile); + exits("create"); + } + cout = ofd; + + /* TBS lput for Plan9 header before ? */ + + seek(ifd, ihdr.txtoff, 0); + seek(ofd, HEADR, 0); + copyseg(ihdr.txtsz); + + seek(ifd, ihdr.datoff, 0); + seek(ofd, HEADR+textsize, 0); + copyseg(ihdr.datsz); + + seek(ofd, HEADR+textsize+datsize, 0); + coffsym(); + cflush(); + cofflc(); + cflush(); + + seek(ofd, 0, 0); + coffhdr(); + cflush(); + + close(ifd); + close(ofd); +} + +long +entryvalue(void) +{ + return INITENTRY; +} + +void +diag(char *s, ...) +{ + fprint(2, "%s\n", s); + exits("error"); +} + +static void +readsyms(void) +{ + int i; + long n; + Sym *s; + + if(sflag) + return; + n = syminit(ifd, &ihdr); + beginsym(); + for(i = 0; i < n; i++){ + s = getsym(i); + newsym(i, s->name, s->value, s->type); + } + endsym(); +} diff --git a/utils/5coff/NOTICE b/utils/5coff/NOTICE new file mode 100644 index 00000000..3b08f95f --- /dev/null +++ b/utils/5coff/NOTICE @@ -0,0 +1,27 @@ +This copyright NOTICE applies to all files in this directory and +subdirectories, unless another copyright notice appears in a given +file or subdirectory. If you take substantial code from this software to use in +other programs, you must somehow include with it an appropriate +copyright notice that includes the copyright notice and the other +notices below. It is fine (and often tidier) to do that in a separate +file such as NOTICE, LICENCE or COPYING. + + Copyright © 2001-2003 Vita Nuova Holdings Limited. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/utils/5coff/auxi.c b/utils/5coff/auxi.c new file mode 100644 index 00000000..93e56c29 --- /dev/null +++ b/utils/5coff/auxi.c @@ -0,0 +1,251 @@ +#include "auxi.h" + +Prog *firstp, *textp, *curtext, *lastp, *etextp; +Symx *hash[NHASH]; +Auto *lasta; +long autosize; +int version = 0; + +static int +private(char *s) +{ + return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0; +} + +static int +zlen(char *s) +{ + int i; + + for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) + ; + i++; + return i+1; +} + +static Symx* +allocsym(char *symb, int l, int v) +{ + Symx *s; + + s = malloc(sizeof(Symx)); + s->name = malloc(l); + memmove(s->name, symb, l); + s->name[l-1] = '\0'; + s->type = 0; + s->version = v; + s->value = 0; + s->link = nil; + return s; +} + +Symx* +lookupsym(char *symb, int v) +{ + Symx *s, **as; + char *p; + long h; + int c, l; + + h = v; + for(p=symb; c = *p; p++) + h = h+h+h + c; + l = (p - symb) + 1; + if(h < 0) + h = ~h; + h %= NHASH; + for(s = hash[h]; s != nil; s = s->link) + if(s->version == v) + if(memcmp(s->name, symb, l) == 0) + return s; + s = allocsym(symb, l, v); + for(as = &hash[h]; *as != nil; as = &((*as)->link)) + ; + *as = s; + // s->link = hash[h]; + // hash[h] = s; + return s; +} + +static void +addauto(Auto **aut, Symx *s, int t, long v) +{ + Auto *a, **aa; + + a = (Auto*)malloc(sizeof(Auto)); + a->asym = s; + a->link = nil; + a->aoffset = v; + a->type = t; + for(aa = aut; *aa != nil; aa = &((*aa)->link)) + ; + *aa = a; +} + +static Prog* +newprog(int as, long pc, long ln) +{ + Prog *p; + + p = (Prog *)malloc(sizeof(Prog)); + p->as = as; + p->pc = pc; + p->line = ln; + p->link = p->cond = P; + if(firstp == P) + firstp = p; + else + lastp->link = p; + lastp = p; + if(as == ATEXT){ + if(textp == P) + textp = p; + else + etextp->cond = p; + etextp = p; + } + return p; +} + +static int +line(long pc) +{ + char buf[1024], *s; + + // return pc2line(pc); + if(fileline(buf, sizeof(buf), pc)){ + for(s = buf; *s != ':' && *s != '\0'; s++) + ; + if(*s != ':') + return -1; + return atoi(s+1); + } + return -1; +} + +static void +lines(long v) +{ + long ll, nl, pc; + if(etextp != P){ + ll = 0; + for(pc = etextp->pc; pc < v; pc += 4){ + nl = line(pc); + if(nl != -1 && nl != ll){ + newprog(ATEXT-1, pc, nl); + ll = nl; + } + } + pc -= 4; + if(lastp->pc != pc){ + nl = line(pc); + if(nl != -1) + newprog(ATEXT-1, pc, nl); + } + } +} + +void +beginsym(void) +{ +} + +/* create the same structures as in 5l so we can use same coff.c source file */ +void +newsym(int i, char *nm, long v, int t) +{ + long l, ver; + char *os; + Symx *s; + Prog *p; + + if(i == 0 && (t == 't' || t == 'T') && strcmp(nm, "etext") == 0) + return; + if(nm[0] == '.' && private(nm+1)) + return; +// print("%s %ld %c\n", nm, v, t); + ver = 0; + if(t == 't' || t == 'l' || t == 'd' || t == 'b'){ + ver = ++version; + if(ver == 0) + diag("0 version for static"); + } + if(t == 'a' || t == 'p') + s = allocsym(nm, strlen(nm)+1, 0); + else if(t == 'z' || t == 'Z') + s = allocsym(nm, zlen(nm), 0); + else if(t != 'm'){ + s = lookupsym(nm, ver); + if(s->type != 0) + diag("seen sym before in newsym"); + s->value = v; + } + else + s = nil; + switch(t){ + case 'T': + case 'L': + case 't': + case 'l': + lines(v); + if(t == 'l' || t == 'L') + s->type = SLEAF; + else + s->type = STEXT; + p = newprog(ATEXT, v, line(v)); + p->from.sym = s; + p->to.autom = lasta; + lasta = nil; + break; + case 'D': + case 'd': + s->type = SDATA; + s->value -= INITDAT; + break; + case 'B': + case 'b': + s->type = SBSS; + s->value -= INITDAT; + break; + case 'f': + // version++; + s->type = SFILE; + os = s->name; + l = strlen(os)+1; + s->name = malloc(l+1); + s->name[0] = '>'; + memmove(s->name+1, os, l); + free(os); + break; +/* + case 'f'+'a'-'A': + s->type = SFILE; + break; +*/ + case 'z': + addauto(&lasta, s, D_FILE, v); + break; + case 'Z': + addauto(&lasta, s, D_FILE1, v); + break; + case 'a': + addauto(&(etextp->to.autom), s, D_AUTO, -v); + break; + case 'p': + addauto(&(etextp->to.autom), s, D_PARAM, v); + break; + case 'm': + etextp->to.offset = v-4; + autosize = v; + break; + default: + diag("bad case in newsym"); + break; + } +} + +void +endsym(void) +{ + lines(INITTEXT+textsize); +} diff --git a/utils/5coff/auxi.h b/utils/5coff/auxi.h new file mode 100644 index 00000000..e9907523 --- /dev/null +++ b/utils/5coff/auxi.h @@ -0,0 +1,46 @@ +#define COFFCVT +#define Sym Symx +#include "../5l/l.h" +#undef Sym +#include <mach.h> + +/* + * auxi.c + */ +extern Symx *hash[NHASH]; +Symx *lookupsym(char*, int); +void beginsym(void); +void endsym(void); +void newsym(int, char*, long, int); + +extern long autosize; +extern Prog *firstp, *textp, *curtext, *lastp, *etextp; + +/* + * coff.c + */ +void coffhdr(void); +void coffsym(void); +void cofflc(void); +void endsym(void); + +/* + * 5coff.c + */ +void cflush(void); +void lput(long); +void cput(int); +void hputl(int); +void lputl(long); +long entryvalue(void); +void diag(char*, ...); +extern long HEADR; /* length of header */ +extern long INITDAT; /* data location */ +extern long INITRND; /* data round above text location */ +extern long INITTEXT; /* text location */ +extern long INITENTRY; /* entry point */ +extern long textsize; +extern long datsize; +extern long bsssize; +extern int cout; +extern int thumb; diff --git a/utils/5coff/coff.c b/utils/5coff/coff.c new file mode 100644 index 00000000..7a057ea5 --- /dev/null +++ b/utils/5coff/coff.c @@ -0,0 +1,642 @@ +#include "auxi.h" + +/* + * in some embedded coff files, edata and end have type 0 not 4, + * and file value is pointer to next file sym (as here), but the last one + * points to an external symbol, not 0 as here. + */ + +#define C_NULL 0 +#define C_AUTO 1 +#define C_EXT 2 +#define C_STAT 3 +#define C_ARG 9 +#define C_FCN 101 +#define C_FILE 103 + +#define T_VOID 0 +#define T_CHAR 2 +#define T_SHORT 3 +#define T_INT 4 +#define T_LONG 5 + +#define DT_NON 0 +#define DT_PTR 1 +#define DT_FCN 2 +#define DT_ARY 3 + +#define T(a, b) (((a)<<4)|b) + +#define DOTTEXT ".text" +#define DOTDATA ".data" +#define DOTBSS ".bss" +#define DOTBF ".bf" +#define DOTEF ".ef" + +#define SINDEX(s) (*((long*)(&s->become))) +#define LINDEX(s) (*((long*)(&s->used))) + +typedef struct Hist Hist; + +struct Hist{ + Auto *a; + Hist *n; +}; + +static int nsym, nlc, lines; + +static void cofflcsz(void); + +static Hist *freeh, *curh; + +static void +dohist(Auto *a) +{ + Hist *h, **ha; + + if(a->aoffset == 1){ /* new file */ + for(ha = &curh; *ha != nil; ha = &((*ha)->n)) + ; + *ha = freeh; + freeh = curh; + curh = nil; + } + if(freeh != nil){ + h = freeh; + freeh = freeh->n; + } + else + h = malloc(sizeof(Hist)); + h->a = a; + h->n = nil; + for(ha = &curh; *ha != nil; ha = &((*ha)->n)) + ; + *ha = h; +} + +static long +lineno(long n) +{ + long o, d; + Hist *h; + + if(1) + return n; /* now using fileline() not pc2line() */ + + if(curh == nil) + return 0; + o = curh->a->aoffset-1; + d = 1; + for(h = curh->n; d && h != nil; h = h->n){ + if(h->a->asym->name[1] || h->a->asym->name[2]){ + if(h->a->type == D_FILE1) { + ; + } + else if(d == 1 && n < h->a->aoffset) + break; + else if(d++ == 1) + o -= h->a->aoffset; + } + else if(--d == 1) + o += h->a->aoffset; + } + return n-o; +} + +static char * +filelookup(int k) +{ + int i; + Symx *s; + + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->type == SFILE && k == s->value) + return s->name+1; + } + } + return ""; +} + +static char* +filename(char *s) +{ + int j, k, l; + static char buf[256]; + + buf[0] = '\0'; + if(s[0] != 0) + diag("bad filename"); + for(j = 1; ; j += 2){ + k = (s[j]<<8)|s[j+1]; + if(k == 0) + break; + l = strlen(buf); + if(l != 0 && buf[l-1] != '/') + strcat(buf, "/"); + strcat(buf, filelookup(k)); + } + return buf; +} + +static void +sput(char *s, int n) +{ + int i; + + for(i = 0; i < n && s != nil && *s != '\0'; i++, s++) + cput(*s); + for( ; i < n; i++) + cput(0); +} + +static void +coffsect(char *s, long a, long sz, long o, long lp, long nl, long f) +{ + if(0) + print("sect %s pa=%lux va=%lux sz=%lux\n", s, a, a, sz); + sput(s, 8); /* name <= 8 chars in len */ + lputl(a); /* pa */ + lputl(a); /* va */ + lputl(sz); /* size */ + lputl(o); /* file offset */ + lputl(0); /* reloc */ + lputl(lp); /* line nos */ + lputl(0); /* no reloc entries */ + lputl(nl); /* no line no entries */ + lputl(f); /* flags */ + hputl(0); /* reserved */ + hputl(0); /* mem page no */ +} + +void +coffhdr(void) +{ + if(0){ + print("H=%lux t=%lux d=%lux b=%lux\n", HEADR, textsize, datsize, bsssize); + print("e=%lux ts=%lux ds=%lux\n", entryvalue(), INITTEXT, INITDAT); + } + + /* + * file header + */ + hputl(0xc2); /* version ID */ + hputl(3); /* no section hdrs */ + lputl(0); /* date stamp */ + lputl(HEADR+textsize+datsize+6*nlc); /* sym table */ + lputl(nsym); /* no sym table entries */ + hputl(28); /* size optional hdr */ + hputl(0x0103); /* flags */ + hputl(0x97); /* target ID */ + /* + * optional file header + */ + hputl(0x108); /* magic */ + hputl(0); /* version stamp */ + lputl(textsize); /* text size */ + lputl(datsize); /* data size */ + lputl(bsssize); /* bss size */ + lputl(entryvalue()); /* entry pt */ + lputl(INITTEXT); /* text start */ + lputl(INITDAT); /* data start */ + /* + * sections + */ + coffsect(DOTTEXT, INITTEXT, textsize, HEADR, HEADR+textsize+datsize, nlc, 0x20); + coffsect(DOTDATA, INITDAT, datsize, HEADR+textsize, 0, 0, 0x40); + coffsect(DOTBSS, INITDAT+datsize, bsssize, 0, 0, 0, 0x80); +} + +static int +private(char *s) +{ + return strcmp(s, "safe") == 0 || strcmp(s, "ret") == 0 || strcmp(s, "string") == 0; +} + +static long stoff = 4; + +static long +stput(char *s) +{ + long r; + + r = stoff; + stoff += strlen(s)+1; + return r; +} + +static long +strput(char *s) +{ + int l; + + if((l = strlen(s)) > 8){ + if(*s == '.' && private(s+1)) + return 0; + while(*s) + cput(*s++); + cput(*s); + return l+1; + } + return 0; +} + +static void +stflush(void) +{ + int i; + long o; + Prog *p; + Auto *a, *f; + Symx *s; + char *fn, file[256]; + + lputl(stoff); + o = 4; + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT){ + f = nil; + fn = nil; + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE){ + f = a; + break; + } + } + if(f != nil) + fn = filename(f->asym->name); + if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ + strcpy(file, fn); + o += strput(file); + } + o += strput(p->from.sym->name); + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_AUTO || a->type == D_PARAM) + o += strput(a->asym->name); + } + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) + o += strput(s->name); + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) + o += strput(s->name); + } + } + if(o != stoff) + diag("bad stflush offset"); +} + +static int +putsect(Symx *s) +{ + int sz, ln; + + sz = ln = 0; + // isn't this repetition ? + if(strcmp(s->name, DOTTEXT) == 0){ + sz = textsize; + ln = nlc; + } + else if(strcmp(s->name, DOTDATA) == 0) + sz = datsize; + else if(strcmp(s->name, DOTBSS) == 0) + sz = bsssize; + else + diag("bad putsect sym"); + lputl(sz); + hputl(0); + hputl(ln); + sput(nil, 10); + return 1; +} + +static int +putfun(Symx *s) +{ + /* lputl(SINDEX(s)+2); */ + lputl(0); + lputl(0); /* patched later */ + lputl(HEADR+textsize+datsize+LINDEX(s)); + lputl(0); /* patched later */ + sput(nil, 2); + return 1; +} + +static int +putbf(int lno) +{ + lputl(0); + hputl(lno); + hputl(lines); + lputl(autosize); + lputl(0); /* patched later */ + sput(nil, 2); + return 1; +} + +static int +putef(int lno) +{ + sput(nil, 4); + hputl(lno); + sput(nil, 12); + return 1; +} + +static int +putsym(Symx *s, int sc, int t, int lno) +{ + long v; + + if(s == nil || s->name == nil || s->name[0] == '\0' || (s->name[0] == '.' && private(s->name+1))) + return 0; + if(0) + print("putsym %s %d %ld %d %d\n", s->name, s->type, s->value, sc, t); + if(strlen(s->name) <= 8) + sput(s->name, 8); + else{ + lputl(0); + lputl(stput(s->name)); + } + /* value */ + v = s->value; + if(s->type == SDATA || s->type == SDATA1 || s->type == SBSS) + lputl(INITDAT+v); + else if(sc == C_AUTO) + lputl(autosize+v); + else if(sc == C_ARG) + lputl(autosize+v+4); + else + lputl(v); + switch(s->type){ /* section number */ + case STEXT: + case SLEAF: + hputl(1); + break; + case SDATA: + case SDATA1: + hputl(2); + break; + case SBSS: + hputl(3); + break; + case SFILE: + hputl(-2); + break; + default: + diag("type %d in putsym", s->type); + break; + } + hputl(t); /* type */ + cput(sc); /* storage class */ + /* aux entries */ + if(sc == C_STAT && t == T_VOID && s->name[0] == '.'){ /* section */ + cput(1); + return 1+putsect(s); + } + else if((t>>4) == DT_FCN){ /* function */ + cput(1); + return 1+putfun(s); + } + else if(sc == C_FCN && strcmp(s->name, DOTBF) == 0){ /* bf */ + cput(1); + return 1+putbf(lno); + } + else if(sc == C_FCN && strcmp(s->name, DOTEF) == 0){ /* ef */ + cput(1); + return 1+putef(lno); + } + cput(0); /* 0 aux entry */ + return 1; +} + +static Symx* +defsym(char *p, int t, long v) +{ + Symx *s; + + s = lookupsym(p, 0); + if(s->type == SDATA || s->type == SBSS) + return nil; /* already output */ + if(s->type == 0 || s->type == SXREF){ + s->type = t; + s->value = v; + } + return s; +} + +static int +specsym(char *p, int t, long v, int c) +{ + return putsym(defsym(p, t, v), c, T_VOID, 0); +} + +static int +cclass(Symx *s) +{ +/* + if(s->version > 0 && dclass == D_EXTERN) + diag("%s: version %d dclass EXTERN", s->name, s->version); + if(s->version == 0 && dclass == D_STATIC) + diag("%s: version %d dclass STATIC", s->name, s->version); +*/ + return s->version > 0 ? C_STAT : C_EXT; +} + +static void +patchsym(long i, long o, long v) +{ + long oo; + + cflush(); + oo = seek(cout, 0, 1); + seek(cout, HEADR+textsize+datsize+6*nlc+18*i+o, 0); + lputl(v); + cflush(); + seek(cout, oo, 0); +} + +void +coffsym(void) +{ + int i; + long ns, lno, lpc, v, vs, lastf; + Prog *p; + Auto *a, *f; + Symx *s, *bf, *ef, ts; + char *fn, file[256]; + + file[0] = '\0'; + cofflcsz(); + seek(cout, 6*nlc, 1); /* advance over line table */ + ns = 0; + lpc = -1; + lno = -1; + lastf = -1; + bf = defsym(DOTBF, STEXT, 0); + ef = defsym(DOTEF, STEXT, 0); + for(p = firstp; p != P; p = p->link){ + setarch(p); + if(p->as != ATEXT){ + if(p->line != 0) + lno = lineno(p->line); + } + if(p->as == ATEXT){ + curtext = p; + autosize = p->to.offset+4; + if(lpc >= 0){ + ef->value = lpc; + ns += putsym(ef, C_FCN, T_VOID, lno); + } + f = nil; + fn = nil; + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE || a->type == D_FILE1) + dohist(a); + if(f == nil && a->type == D_FILE) + f = a; /* main filename */ + } + if(f != nil) + fn = filename(f->asym->name); + if(fn != nil && *fn != '\0' && strcmp(fn, file) != 0){ + strcpy(file, fn); + ts.name = file; + ts.type = SFILE; + ts.value = 0; + if(lastf >= 0) + patchsym(lastf, 8, ns); + lastf = ns; + ns += putsym(&ts, C_FILE, T_VOID, 0); + } + if(p->link != P && p->link->line != 0) + lno = lineno(p->link->line); + else if(p->line != 0) + lno = lineno(p->line); + s = p->from.sym; + SINDEX(s) = ns; + ns += putsym(s, cclass(s), T(DT_FCN, T_INT), 0); + if(p->cond != P) + lines = LINDEX(p->cond->from.sym)-LINDEX(s)-1; + else + lines = 0; + bf->value = p->pc; + ns += putsym(bf, C_FCN, T_VOID, lno); + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_AUTO || a->type == D_PARAM){ + ts.name = a->asym->name; + ts.type = STEXT; + ts.value = a->aoffset; + ns += putsym(&ts, a->type == D_AUTO ? C_AUTO : C_ARG, T_INT, 0); + } + } + } + lpc = p->pc; + } + if(lpc >= 0){ + ef->value = lpc; + ns += putsym(ef, C_FCN, T_VOID, lno); + } + /* patch up */ + for(p = textp; p != P; p = p->cond){ + s = p->from.sym; + if(p->cond != P){ + v = SINDEX(p->cond->from.sym); + vs = p->cond->pc - p->pc; + } + else{ + v = 0; + vs = INITTEXT+textsize-p->pc; + } + patchsym(SINDEX(s)+1, 4, 8*vs); + patchsym(SINDEX(s)+1, 12, v); + patchsym(SINDEX(s)+3, 12, v); + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version > 0 && (s->type == SDATA || s->type == SBSS)) + ns += putsym(s, cclass(s), T_INT, 0); + } + } + for(i = 0; i < NHASH; i++){ + for(s = hash[i]; s != nil; s = s->link){ + if(s->version == 0 && (s->type == SDATA || s->type == SBSS)) + ns += putsym(s, cclass(s), T_INT, 0); + } + } + ns += specsym(DOTTEXT, STEXT, INITTEXT, C_STAT); + ns += specsym(DOTDATA, SDATA, 0, C_STAT); + ns += specsym(DOTBSS, SBSS, datsize, C_STAT); + ns += specsym("etext", STEXT, INITTEXT+textsize, C_EXT); + ns += specsym("edata", SDATA, datsize, C_EXT); + ns += specsym("end", SBSS, datsize+bsssize, C_EXT); + nsym = ns; + stflush(); +} + +void +cofflc(void) +{ + long olc, nl; + Symx *s; + Prog *p; + Auto *a; + + cflush(); + seek(cout, HEADR+textsize+datsize, 0); + nl = 0; + /* opc = INITTEXT; */ + olc = 0; + for(p = firstp; p != P; p = p->link){ + setarch(p); + if(p->as == ATEXT){ + curtext = p; + s = p->from.sym; + /* opc = p->pc; */ + for(a = p->to.autom; a != nil; a = a->link){ + if(a->type == D_FILE || a->type == D_FILE1) + dohist(a); + } + lputl(SINDEX(s)); + hputl(0); + nl++; + continue; + } + if(p->line == 0 || p->line == olc || p->as == ANOP) + continue; + lputl(p->pc); + hputl(lineno(p->line)); + nl++; + olc = p->line; + } + if(nl != nlc) + diag("bad line count in cofflc()"); + nlc = nl; +} + +static void +cofflcsz(void) +{ + long olc, nl; + Prog *p; + + nl = 0; + olc = 0; + for(p = firstp; p != P; p = p->link){ + if(p->as == ATEXT){ + LINDEX(p->from.sym) = nl; + nl++; + continue; + } + if(p->line == 0 || p->line == olc || p->as == ANOP) + continue; + nl++; + olc = p->line; + } + nlc = nl; +} diff --git a/utils/5coff/mkfile b/utils/5coff/mkfile new file mode 100644 index 00000000..22d389ba --- /dev/null +++ b/utils/5coff/mkfile @@ -0,0 +1,23 @@ +<../../mkconfig + +TARG=5coff + +OFILES= 5coff.$O\ + coff.$O\ + auxi.$O\ + +HFILES=\ + a.out.h\ + bio.h\ + mach.h\ + +LIBS=mach bio 9 # order matters. + +CFLAGS=$CFLAGS -I../include + +BIN=$ROOT/$OBJDIR/bin + +<$ROOT/mkfiles/mkone-$SHELLTYPE + +$O.readcoff: readcoff.$O + $LD $LDFLAGS -o $target readcoff.$O $libs $SYSLIBS diff --git a/utils/5coff/readcoff.c b/utils/5coff/readcoff.c new file mode 100644 index 00000000..aa74ecc1 --- /dev/null +++ b/utils/5coff/readcoff.c @@ -0,0 +1,298 @@ +#include <lib9.h> +#include <bio.h> +#include <mach.h> + +int fd; +static void readf(void); + +static void +usage(char *msg) +{ + fprint(2, "***Error: %s\n", msg); + exits("usage"); +} + +static int +cget(void) +{ + uchar b[1]; + + if(read(fd, b, 1) != 1){ + fprint(2, "bad cget\n"); + exits("cget"); + } + return b[0]; +} + +static int +hget(void) +{ + uchar b[2]; + + if(read(fd, b, 2) != 2){ + fprint(2, "bad hget\n"); + exits("hget"); + } + return b[1]<<8 | b[0]; +} + +static int +lget(void) +{ + uchar b[4]; + + if(read(fd, b, 4) != 4){ + fprint(2, "bad lget\n"); + exits("lget"); + } + return b[3]<<24 | b[2]<<16 | b[1]<<8 | b[0]; +} + +static char * +sget(char *st) +{ + int i; + static uchar buf[8+1]; + + for(i = 0; i < 8+1; i++) + buf[i] = 0; + if(read(fd, buf, 8) != 8){ + fprint(2, "bad sget\n"); + exits("sget"); + } + if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) + return st+(buf[7]<<24|buf[6]<<16|buf[5]<<8|buf[4]); + return (char*)buf; +} + +void +main(int argc, char *argv[]) +{ + if (argc != 2) + usage("Wrong number of arguments"); + + fd = open(argv[1], OREAD); + if (fd < 0) { + fprint(2, "5coff: open %s: %r\n", argv[1]); + exits("open"); + } + readf(); + exits(0); +} + +static void +section(int i, char *st, int *linoff, int *linn) +{ + int pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno; + char *nm; + + nm = sget(st); + pa = lget(); + va = lget(); + sz = lget(); + off = lget(); + rel = lget(); + lin = lget(); + nrel = lget(); + nlin = lget(); + f = lget(); + res = hget(); + pno = hget(); + print("sect %d %s: pa=0x%x va=0x%x sz=%d off=%d rel=%d lin=%d nrel=%d nlin=%d f=0x%x res=%d pno=%d\n", i, nm, pa, va, sz, off, rel, lin, nrel, nlin, f, res, pno); + *linoff = lin; + *linn = nlin; +} + +static void +opthdr(void) +{ + int mag, ver, textsz, datasz, bsssz, entry, text, data; + + mag = hget(); + ver = hget(); + textsz = lget(); + datasz = lget(); + bsssz = lget(); + entry = lget(); + text = lget(); + data = lget(); + print("opt: mag=0x%x ver=%d txtsz=%d datsz=%d bsssz=%d ent=0x%x txt=0x%x dat=0x%x\n", mag, ver, textsz, datasz, bsssz, entry, text, data); +} + +static void +readhdr(int *o, int *ns, int *sy, int *nsy) +{ + int vid, nsec, date, sym, nsym, opt, f, tid; + + vid = hget(); + nsec = hget(); + date = lget(); + sym = lget(); + nsym = lget(); + opt = hget(); + f = hget(); + tid = hget(); + print("hdr: vid=0x%x nsect=%d date=%d sym=%d nsym=%d opt=%d f=0x%x tid=0x%x\n", vid, nsec, date, sym, nsym, opt, f, tid); + *o = opt; + *ns = nsec; + *sy = sym; + *nsy = nsym; +} + +static void +readauxsect(int i) +{ + int sz, nrel, ln; + + sz = lget(); + nrel = hget(); + ln = hget(); + lget(); + hget(); + lget(); + print("sym auxsect %d: sz=%d nrel=%d ln=%d\n", i, sz, nrel, ln); +} + +static void +readauxfun(int i) +{ + int ind, sz, fpln, nind; + + ind = lget(); + sz = lget(); + fpln = lget(); + nind = lget(); + hget(); + print("sym auxfun %d: ind=%d sz=%d fpln=%d nind=%d\n", i, ind, sz, fpln, nind); +} + +static void +readauxbf(int i) +{ + int rsav, lno, lns, fsz, nind; + + rsav = lget(); + lno = hget(); + lns = hget(); + fsz = lget(); + nind = lget(); + hget(); + print("sym auxbf %d: rsav=%x lno=%d lns=%d fsz=%d nind=%d\n", i, rsav, lno, lns, fsz, nind); +} + +static void +readauxef(int i) +{ + int lno; + + lget(); + lno = hget(); + lget(); + lget(); + lget(); + print("sym auxef %d: lno=%d\n", i, lno); +} + +static void +readauxother(int i) +{ + lget(); + lget(); + hget(); + lget(); + lget(); + print("sym auxother %d\n", i); +} + +static int +readsym(int i, char *st) +{ + int v, s, t, c, aux; + char *nm; + + nm = sget(st); + v = lget(); + s = hget(); + t = hget(); + c = cget(); + aux = cget(); + print("sym %d %s: val=%d sec=%d type=%d class=%d aux=%d\n", i, nm, v, s, t, c, aux); + if(aux){ + i++; + if(strcmp(nm, ".text") == 0 || strcmp(nm, ".data") == 0 || strcmp(nm, ".bss") == 0) + readauxsect(i); + else if(strcmp(nm, ".bf") == 0) + readauxbf(i); + else if(strcmp(nm, ".ef") == 0) + readauxef(i); + else if((t&0x30) == 0x20) // will do + readauxfun(i); + else + readauxother(i); + return 1; + } + return 0; +} + +static char * +readstr(int n) +{ + char *s = malloc(n); + + if(read(fd, s+4, n-4) != n-4){ + fprint(2, "bad readstr\n"); + exits("sget"); + } + return s; +} + +static void +readln(int i) +{ + int a, l; + + a = lget(); + l = hget(); + if(l == 0) + print("line %d: sym=%d\n", i, a); + else + print("line %d: addr=0x%x line=%d\n", i, a, l); +} + +static void +readf() +{ + int i, opt, nsec, sym, nsym, stoff, strsz, linoff, nlin, lino, linn; + char *st; + + seek(fd, 0, 0); + readhdr(&opt, &nsec, &sym, &nsym); + if(opt) + opthdr(); + stoff = sym+18*nsym; + seek(fd, stoff, 0); + strsz = lget(); + st = readstr(strsz); + linoff = nlin = 0; + seek(fd, 22+28, 0); + for(i = 0; i < nsec; i++){ + section(i, st, &lino, &linn); + if(linn != 0){ + if(nlin == 0){ + nlin = linn; + linoff = lino; + } + else + print("multiple line no. tables\n"); + } + } + seek(fd, sym, 0); + for(i = 0; i < nsym; i++) + i += readsym(i, st); + print("strsz = %d\n", strsz); + if(nlin != 0){ + seek(fd, linoff, 0); + for(i = 0; i < nlin; i++) + readln(i); + } +} |
