summaryrefslogtreecommitdiff
path: root/utils/5coff
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /utils/5coff
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'utils/5coff')
-rw-r--r--utils/5coff/5coff.c316
-rw-r--r--utils/5coff/NOTICE27
-rw-r--r--utils/5coff/auxi.c251
-rw-r--r--utils/5coff/auxi.h46
-rw-r--r--utils/5coff/coff.c642
-rw-r--r--utils/5coff/mkfile23
-rw-r--r--utils/5coff/readcoff.c298
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);
+ }
+}