int32_t pcollgnextoff(int32_t fromoff) { int c, state = 0, defoff = -1; if(Bseek(bdict, fromoff, 0) < 0) return -1; while((c = Bgetc(bdict)) >= 0){ if(c == '\r') defoff = Boffset(bdict); switch(state){ case 0: if(c == 0x05) state = 1; break; case 1: if(c == 'h') state = 2; else state = 0; break; case 2: if(c == 0x06) return (Boffset(bdict)-3); else state = 0; break; } } return defoff; }
void join(int seekf) { int cmp, less; int n[NIN]; int64_t top, bot; less = seekf == F2; top = 0; bot = Boffset(f[seekf]); readboth(n); while((n[F1]>0 && n[F2]>0) || ((a1||a2) && n[F1]+n[F2]>0)) { cmp = comp(); if((n[F1]>0 && n[F2]>0 && cmp>0) || n[F1]==0) { if(a2) output(0, n[F2]); if (seekf == F2) bot = Boffset(f[seekf]); n[F2] = input(F2); } else if((n[F1]>0 && n[F2]>0 && cmp<0) || n[F2]==0) { if(a1) output(n[F1], 0); if (seekf == F1) bot = Boffset(f[seekf]); n[F1] = input(F1); } else { /* n[F1]>0 && n[F2]>0 && cmp==0 */ while(n[F2]>0 && cmp==0) { output(n[F1], n[F2]); top = Boffset(f[seekf]); n[seekf] = input(seekf); cmp = comp(); } seekbotreadboth(seekf, bot, n); for(;;) { cmp = comp(); if(n[F1]>0 && n[F2]>0 && cmp==0) { output(n[F1], n[F2]); n[seekf] = input(seekf); } else if((n[F1]>0 && n[F2]>0 && (less? cmp<0 :cmp>0)) || n[seekf]==0) seekbotreadboth(seekf, bot, n); else { /* * n[F1]>0 && n[F2]>0 && * (less? cmp>0 :cmp<0) || * n[seekf==F1? F2: F1]==0 */ Bseek(f[seekf], top, 0); bot = top; n[seekf] = input(seekf); break; } } } } }
vlong Bseek(Biobufhdr *bp, vlong offset, int base) { vlong n, d; switch(bp->state) { default: fprint(2, "Bseek: unknown state %d\n", bp->state); return Beof; case Bracteof: bp->state = Bractive; bp->icount = 0; bp->gbuf = bp->ebuf; case Bractive: n = offset; if(base == 1) { n += Boffset(bp); base = 0; } /* * try to seek within buffer */ if(base == 0) { /* * if d is too large for an int, icount may wrap, * so we need to ensure that icount hasn't wrapped * and points within the buffer's valid data. */ d = n - Boffset(bp); bp->icount += d; if(d <= bp->bsize && bp->icount <= 0 && bp->ebuf - bp->gbuf >= -bp->icount) return n; } /* * reset the buffer */ n = seek(bp->fid, n, base); bp->icount = 0; bp->gbuf = bp->ebuf; break; case Bwactive: Bflush(bp); n = seek(bp->fid, offset, base); break; } bp->offset = n; return n; }
/* * CD image buffering routines. */ void Cputc(Cdimg *cd, int c) { assert(Boffset(&cd->bwr) >= 16*Blocksize || c == 0); if(Boffset(&cd->bwr) == 0x9962) if(c >= 256) abort(); if(Bputc(&cd->bwr, c) < 0) sysfatal("Bputc: %r"); Bflush(&cd->brd); }
long Bseek(Biobuf *bp, long offset, int base) { long n, d; switch(bp->state) { default: fprint(2, "Bseek: unknown state %d\n", bp->state); return Beof; case Bracteof: bp->state = Bractive; bp->icount = 0; bp->gbuf = bp->ebuf; case Bractive: n = offset; if(base == 1) { n += Boffset(bp); base = 0; } /* * try to seek within buffer */ if(base == 0) { d = n - Boffset(bp); bp->icount += d; if(d >= 0) { if(bp->icount <= 0) return n; } else { if(bp->ebuf - bp->gbuf >= -bp->icount) return n; } } /* * reset the buffer */ n = seek(bp->fid, n, base); bp->icount = 0; bp->gbuf = bp->ebuf; break; case Bwactive: Bflush(bp); n = seek(bp->fid, offset, base); break; } bp->offset = n; return n; }
static int marker(Header *h) { int c; while((c=readbyte(h)) == 0) fprint(2, "ReadJPG: skipping zero byte at offset %lld\n", Boffset(h->fd)); if(c != 0xFF) jpgerror(h, "ReadJPG: expecting marker; found 0x%x at offset %lld\n", c, Boffset(h->fd)); while(c == 0xFF) c = readbyte(h); return c; }
/* * Return offset into bdict where next webster entry after fromoff starts. * Webster entries start with <p><hw> */ long pgwnextoff(long fromoff) { long a, n; int c; a = Bseek(bdict, fromoff, 0); if(a != fromoff) return -1; n = 0; for(;;) { c = Bgetc(bdict); if(c < 0) break; if(c == '<' && Bgetc(bdict) == 'p' && Bgetc(bdict) == '>') { c = Bgetc(bdict); if(c == '<') { if (Bgetc(bdict) == 'h' && Bgetc(bdict) == 'w' && Bgetc(bdict) == '>') n = 7; } else if (c == '{') n = 4; if(n) break; } } return (Boffset(bdict)-n); }
/* * read the header for the next archive member */ Armember * getdir(Biobuf *b) { Armember *bp; char *cp; static char name[ARNAMESIZE+1]; bp = newmember(); if(HEADER_IO(Bread, b, bp->hdr)) { free(bp); return 0; } if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag)) != 0) phaseerr(Boffset(b)); strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); cp = name+sizeof(name)-1; *cp = '\0'; /* skip trailing spaces and (gnu-produced) slashes */ while(*--cp == ' ' || *cp == '/') ; cp[1] = '\0'; file = name; bp->date = strtol(bp->hdr.date, 0, 0); bp->size = strtol(bp->hdr.size, 0, 0); return bp; }
static int header(Biobuf *bin, ZipHead *zh) { uint32_t v; int flen, xlen; v = get4(bin); if(v != ZHeader){ if(v == ZCHeader) return 0; error("bad magic number %lx at %lld", v, Boffset(bin)-4); } zh->extvers = get1(bin); zh->extos = get1(bin); zh->flags = get2(bin); zh->meth = get2(bin); zh->modtime = get2(bin); zh->moddate = get2(bin); zh->crc = get4(bin); zh->csize = get4(bin); zh->uncsize = get4(bin); flen = get2(bin); xlen = get2(bin); zh->file = getname(bin, flen); while(xlen-- > 0) get1(bin); return 1; }
static void doar(Biobuf *bp, char *file) { int offset, size, obj; char membername[SARNAME]; char symname[]="__.SYMDEF"; /* table of contents file name */ for (offset = Boffset(bp);;offset += size) { size = nextar(bp, offset, membername); if (size < 0) { fprint(2, "%s: phase error on ar header %ld", file, offset); return; } if (size == 0) return; if (strcmp(membername, symname) == 0) continue; obj = objtype(bp, 0); if (obj < 0) { fprint(2, "%s: %s inconsistent file", file, membername); return; } if (!readar(bp, obj, offset+size, 1)) { fprint(2, "%s: %s invalid symbol reference in file", file, membername); return; } objtraverse(addfunc, 0); } }
/* * read an archive file, * processing the symbols for each intermediate file in it. */ void doar(Biobuf *bp) { int offset, size, obj; char membername[SARNAME]; multifile = 1; for (offset = Boffset(bp);;offset += size) { size = nextar(bp, offset, membername); if (size < 0) { error("phase error on ar header %ld", offset); return; } if (size == 0) return; if (strcmp(membername, symname) == 0) continue; obj = objtype(bp, 0); if (obj < 0) { error("inconsistent file %s in %s", membername, filename); return; } if (!readar(bp, obj, offset+size, 1)) { error("invalid symbol reference in file %s", membername); return; } filename = membername; nsym=0; objtraverse(psym, 0); printsyms(symptr, nsym); } }
void Cwrite(Cdimg *cd, void *buf, int n) { assert(Boffset(&cd->bwr) >= 16*Blocksize); if(Bwrite(&cd->bwr, buf, n) != n) sysfatal("Bwrite: %r"); Bflush(&cd->brd); }
void stringit(char *str) { long posn, start; int cnt = 0; long c; Rune buf[BUFSIZE]; if ((fin = Bopen(str, OREAD)) == 0) { perror("open"); return; } start = 0; posn = Boffset(fin); while((c = Bgetrune(fin)) >= 0) { if(isprint(c)) { if(start == 0) start = posn; buf[cnt++] = c; if(cnt == BUFSIZE-1) { buf[cnt] = 0; Bprint(&fout, "%8ld: %S ...\n", start, buf); start = 0; cnt = 0; } } else { if(cnt >= minspan) { buf[cnt] = 0; Bprint(&fout, "%8ld: %S\n", start, buf); } start = 0; cnt = 0; } posn = Boffset(fin); } if(cnt >= minspan){ buf[cnt] = 0; Bprint(&fout, "%8ld: %S\n", start, buf); } Bterm(fin); }
int locate(void) { vlong top, bot, mid; long c; int n; bot = 0; top = Bseek(dfile, 0, 2); for(;;) { mid = (top+bot) / 2; Bseek(dfile, mid, 0); do c = Bgetrune(dfile); while(c>=0 && c!='\n'); mid = Boffset(dfile); if(!getword(dfile, entry, sizeof(entry)/sizeof(entry[0]))) break; rcanon(entry, word); n = compare(key, word); switch(n) { case -2: case -1: case 0: if(top <= mid) break; top = mid; continue; case 1: case 2: bot = mid; continue; } break; } Bseek(dfile, bot, 0); while(getword(dfile, entry, sizeof(entry)/sizeof(entry[0]))) { rcanon(entry, word); n = compare(key, word); switch(n) { case -2: return 0; case -1: if(exact) return 0; case 0: return 1; case 1: case 2: continue; } } return 0; }
Link_Data::Link_Data (int link) : Class_Index (link) { Anode (0); Bnode (0); Length (0); Aoffset (0); Boffset (0); Use (0); Type (0); AB_Dir (0); BA_Dir (0); Shape (0); }
void thumbpctab(Biobuf *b, Fhdr *fp) { int n, o, ta; uchar c[8]; pcentry *tab; Bseek(b, fp->lnpcoff+fp->lnpcsz, 0); o = (int)Boffset(b); Bseek(b, 0, 2); n = (int)Boffset(b)-o; pctab = (pcentry*)malloc(n); if(pctab == 0) return; ta = fp->txtaddr; tab = pctab; Bseek(b, fp->lnpcoff+fp->lnpcsz, 0); while(Bread(b, c, sizeof(c)) == sizeof(c)){ tab->start = ta + (c[0]<<24)|(c[1]<<16)|(c[2]<<8)|c[3]; tab->stop = ta + (c[4]<<24)|(c[5]<<16)|(c[6]<<8)|c[7]; tab++; } npctab = n/sizeof(c); }
/* * extract files using the info in the central directory structure */ static int unzip(Biobuf *bin, char *file) { ZipHead zh; int64_t off; int ok, eok, entries; entries = findCDir(bin, file); if(entries < 0) return 0; ok = 1; while(entries-- > 0){ if(setjmp(zjmp)){ free(zh.file); return 0; } memset(&zh, 0, sizeof(zh)); if(!cheader(bin, &zh)) return ok; off = Boffset(bin); if(wantFile(zh.file)){ if(Bseek(bin, zh.off, 0) < 0){ fprint(2, "unzip: can't seek to start of %s, skipping\n", zh.file); ok = 0; }else{ eok = unzipEntry(bin, &zh); if(eok <= 0){ fprint(2, "unzip: skipping %s\n", zh.file); ok = 0; } } } free(zh.file); zh.file = nil; if(Bseek(bin, off, 0) < 0){ fprint(2, "unzip: can't seek to start of next entry, terminating extraction\n"); return 0; } } return ok; }
static int gunzip(int ofd, char *ofile, Biobuf *bin) { Dir *d; GZHead h; int err; h.file = nil; gzok = 0; for(;;){ if(Bgetc(bin) < 0) return 1; Bungetc(bin); if(setjmp(zjmp)) return 0; header(bin, &h); gzok = 0; wlen = 0; crc = 0; if(!table && verbose) fprint(2, "extracting %s to %s\n", h.file, ofile); err = inflate((void*)ofd, crcwrite, bin, (int(*)(void*))Bgetc); if(err != FlateOk) error("inflate failed: %s", flateerr(err)); trailer(bin, wlen); if(table){ if(verbose) print("%-32s %10ld %s", h.file, wlen, ctime(h.mtime)); else print("%s\n", h.file); }else if(settimes && h.mtime && (d=dirfstat(ofd)) != nil){ d->mtime = h.mtime; dirfwstat(ofd, d); free(d); } free(h.file); h.file = nil; gzok = Boffset(bin); } }
long pcollnextoff(long fromoff) { long a; char *p; a = Bseek(bdict, fromoff, 0); if(a < 0) return -1; for(;;) { p = Brdline(bdict, '\n'); if(!p) break; if(p[0] == '>' && p[1] == 'H' && p[2] == '<') return (Boffset(bdict)-Blinelen(bdict)); } return -1; }
void rl(int fd) { Biobuf b; char *cp; struct ar_hdr a; long len; Binit(&b, fd, OWRITE); Bseek(&b,seek(fd,0,1), 0); len = symdefsize; if(len&01) len++; sprint(a.date, "%-12ld", time(0)); sprint(a.uid, "%-6d", 0); sprint(a.gid, "%-6d", 0); sprint(a.mode, "%-8o", 0644); sprint(a.size, "%-10ld", len); strncpy(a.fmag, ARFMAG, 2); strcpy(a.name, symdef); for (cp = strchr(a.name, 0); /* blank pad on right */ cp < a.name+sizeof(a.name); cp++) *cp = ' '; if(HEADER_IO(Bwrite, &b, a)) wrerr(); len += Boffset(&b); if (astart) { wrsym(&b, len, astart->sym); len += astart->size; } if(amiddle) { wrsym(&b, len, amiddle->sym); len += amiddle->size; } if(aend) wrsym(&b, len, aend->sym); if(symdefsize&0x01) Bputc(&b, 0); Bterm(&b); }
void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file) { int i, isinternal; Hostobj *h; isinternal = 0; for(i=0; i<nelem(internalpkg); i++) { if(strcmp(pkg, internalpkg[i]) == 0) { isinternal = 1; break; } } // DragonFly declares errno with __thread, which results in a symbol // type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not // currently know how to handle TLS relocations, hence we have to // force external linking for any libraries that link in code that // uses errno. This can be removed if the Go linker ever supports // these relocation types. if(HEADTYPE == Hdragonfly) if(strcmp(pkg, "net") == 0 || strcmp(pkg, "os/user") == 0) isinternal = 0; if(!isinternal) externalobj = 1; if(nhostobj >= mhostobj) { if(mhostobj == 0) mhostobj = 16; else mhostobj *= 2; hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]); } h = &hostobj[nhostobj++]; h->ld = ld; h->pkg = estrdup(pkg); h->pn = estrdup(pn); h->file = estrdup(file); h->off = Boffset(f); h->len = len; }
/* * extract the symbol references from an object file */ void scanobj(Biobuf *b, Arfile *ap, int size) { int obj; long offset; Dir *d; static int lastobj = -1; if (!allobj) /* non-object file encountered */ return; offset = Boffset(b); obj = objtype(b, 0); if (obj < 0) { /* not an object file */ allobj = 0; d = dirfstat(Bfildes(b)); if (d != nil && d->length == 0) fprint(2, "ar: zero length file %s\n", file); free(d); Bseek(b, offset, 0); return; } if (lastobj >= 0 && obj != lastobj) { fprint(2, "ar: inconsistent object file %s\n", file); allobj = 0; Bseek(b, offset, 0); return; } lastobj = obj; if (!readar(b, obj, offset+size, 0)) { fprint(2, "ar: invalid symbol reference in file %s\n", file); allobj = 0; Bseek(b, offset, 0); return; } Bseek(b, offset, 0); objtraverse(objsym, ap); }
/* * read the header for the next archive member */ Armember * getdir(Biobuf *b) { Armember *bp; char *cp; static char name[ARNAMESIZE+1]; bp = newmember(); if(HEADER_IO(Bread, b, bp->hdr)) { free(bp); return 0; } if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag))) phaseerr(Boffset(b)); strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); cp = name+sizeof(name)-1; while(*--cp==' ') ; cp[1] = '\0'; file = name; bp->date = atol(bp->hdr.date); bp->size = atol(bp->hdr.size); return bp; }
ulong writeBlock(uchar *b, int type) { uchar *cb, *ob; int n; PaqBlock bh; uchar buf[BlockSize]; ulong offset; offset = Boffset(out); bh.magic = BlockMagic; bh.size = blocksize; bh.type = type; bh.encoding = NoEnc; bh.adler32 = adler32(0, b, blocksize); ob = b; if(!uflag) { cb = emallocz(blocksize); n = deflateblock(cb, blocksize, b, blocksize, 6, 0); if(n > 0 && n < blocksize) { bh.encoding = DeflateEnc; bh.size = n; ob = cb; } } putBlock(buf, &bh); outWrite(buf, sizeof(buf)); outWrite(ob, bh.size); if(ob != b) free(ob); return offset; }
Document* initps(Biobuf *b, int argc, char **argv, uchar *buf, int nbuf) { Document *d; PSInfo *ps; char *p; char *q, *r; char eol; char *nargv[1]; char fdbuf[20]; char tmp[32]; int fd; int i; int incomments; int cantranslate; int trailer=0; int nesting=0; int dumb=0; int landscape=0; long psoff; long npage, mpage; Page *page; Rectangle bbox = Rect(0,0,0,0); if(argc > 1) { fprint(2, "can only view one ps file at a time\n"); return nil; } fprint(2, "reading through postscript...\n"); if(b == nil){ /* standard input; spool to disk (ouch) */ fd = spooltodisk(buf, nbuf, nil); sprint(fdbuf, "/dev/fd/%d", fd); b = Bopen(fdbuf, OREAD); if(b == nil){ fprint(2, "cannot open disk spool file\n"); wexits("Bopen temp"); } nargv[0] = fdbuf; argv = nargv; } /* find %!, perhaps after PCL nonsense */ Bseek(b, 0, 0); psoff = 0; eol = 0; for(i=0; i<16; i++){ psoff = Boffset(b); if(!(p = Brdline(b, eol='\n')) && !(p = Brdline(b, eol='\r'))) { fprint(2, "cannot find end of first line\n"); wexits("initps"); } if(p[0]=='\x1B') p++, psoff++; if(p[0] == '%' && p[1] == '!') break; } if(i == 16){ werrstr("not ps"); return nil; } /* page counting */ npage = 0; mpage = 16; page = emalloc(mpage*sizeof(*page)); memset(page, 0, mpage*sizeof(*page)); cantranslate = goodps; incomments = 1; Keepreading: while(p = Brdline(b, eol)) { if(p[0] == '%') if(chatty) fprint(2, "ps %.*s\n", utfnlen(p, Blinelen(b)-1), p); if(npage == mpage) { mpage *= 2; page = erealloc(page, mpage*sizeof(*page)); memset(&page[npage], 0, npage*sizeof(*page)); } if(p[0] != '%' || p[1] != '%') continue; if(prefix(p, "%%BeginDocument")) { nesting++; continue; } if(nesting > 0 && prefix(p, "%%EndDocument")) { nesting--; continue; } if(nesting) continue; if(prefix(p, "%%EndComment")) { incomments = 0; continue; } if(reverse == -1 && prefix(p, "%%PageOrder")) { /* glean whether we should reverse the viewing order */ p[Blinelen(b)-1] = 0; if(strstr(p, "Ascend")) reverse = 0; else if(strstr(p, "Descend")) reverse = 1; else if(strstr(p, "Special")) dumb = 1; p[Blinelen(b)-1] = '\n'; continue; } else if(prefix(p, "%%Trailer")) { incomments = 1; page[npage].offset = Boffset(b)-Blinelen(b); trailer = 1; continue; } else if(incomments && prefix(p, "%%Orientation")) { if(strstr(p, "Landscape")) landscape = 1; } else if(incomments && Dx(bbox)==0 && prefix(p, q="%%BoundingBox")) { bbox = rdbbox(p+strlen(q)+1); if(chatty) /* can't use %R because haven't initdraw() */ fprint(2, "document bbox [%d %d %d %d]\n", RECT(bbox)); continue; } /* * If they use the initgraphics command, we can't play our translation tricks. */ p[Blinelen(b)-1] = 0; if((q=strstr(p, "initgraphics")) && ((r=strchr(p, '%'))==nil || r > q)) cantranslate = 0; p[Blinelen(b)-1] = eol; if(!prefix(p, "%%Page:")) continue; /* * figure out of the %%Page: line contains a page number * or some other page description to use in the menu bar. * * lines look like %%Page: x y or %%Page: x * we prefer just x, and will generate our * own if necessary. */ p[Blinelen(b)-1] = 0; if(chatty) fprint(2, "page %s\n", p); r = p+7; while(*r == ' ' || *r == '\t') r++; q = r; while(*q && *q != ' ' && *q != '\t') q++; free(page[npage].name); if(*r) { if(*r == '"' && *q == '"') r++, q--; if(*q) *q = 0; page[npage].name = estrdup(r); *q = 'x'; } else { snprint(tmp, sizeof tmp, "p %ld", npage+1); page[npage].name = estrdup(tmp); } /* * store the offset info for later viewing */ trailer = 0; p[Blinelen(b)-1] = eol; page[npage++].offset = Boffset(b)-Blinelen(b); } if(Blinelen(b) > 0){ fprint(2, "page: linelen %d\n", Blinelen(b)); Bseek(b, Blinelen(b), 1); goto Keepreading; } if(Dx(bbox) == 0 || Dy(bbox) == 0) bbox = Rect(0,0,612,792); /* 8½×11 */ /* * if we didn't find any pages, assume the document * is one big page */ if(npage == 0) { dumb = 1; if(chatty) fprint(2, "don't know where pages are\n"); reverse = 0; goodps = 0; trailer = 0; page[npage].name = "p 1"; page[npage++].offset = 0; } if(npage+2 > mpage) { mpage += 2; page = erealloc(page, mpage*sizeof(*page)); memset(&page[mpage-2], 0, 2*sizeof(*page)); } if(!trailer) page[npage].offset = Boffset(b); Bseek(b, 0, 2); /* EOF */ page[npage+1].offset = Boffset(b); d = emalloc(sizeof(*d)); ps = emalloc(sizeof(*ps)); ps->page = page; ps->npage = npage; ps->bbox = bbox; ps->psoff = psoff; d->extra = ps; d->npage = ps->npage; d->b = b; d->drawpage = psdrawpage; d->pagename = pspagename; d->fwdonly = ps->clueless = dumb; d->docname = argv[0]; /* * "tag" the doc as an image for now since there still is the "blank page" * problem for ps files. */ d->type = Tgfx; if(spawngs(&ps->gs, "-dSAFER") < 0) return nil; if(!cantranslate) bbox.min = ZP; setdim(&ps->gs, bbox, ppi, landscape); if(goodps){ /* * We want to only send the page (i.e. not header and trailer) information * for each page, so initialize the device by sending the header now. */ pswritepage(d, ps->gs.gsfd, -1); waitgs(&ps->gs); } if(dumb) { fprint(ps->gs.gsfd, "(%s) run\n", argv[0]); fprint(ps->gs.gsfd, "(/dev/fd/3) (w) file dup (THIS IS NOT A PLAN9 BITMAP 01234567890123456789012345678901234567890123456789\\n) writestring flushfile\n"); } ps->bbox = bbox; return d; }
void ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) { int32 ipc; Prog *p; int v, o, r, skip; Sym *h[NSYM], *s; uint32 sig; int ntext; int32 eof; char *name, *x; char src[1024]; Prog *lastp; lastp = nil; ntext = 0; eof = Boffset(f) + len; src[0] = 0; newloop: memset(h, 0, sizeof(h)); version++; histfrogp = 0; ipc = pc; skip = 0; loop: if(f->state == Bracteof || Boffset(f) >= eof) goto eof; o = Bgetc(f); if(o == Beof) goto eof; o |= Bgetc(f) << 8; if(o <= AXXX || o >= ALAST) { if(o < 0) goto eof; diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); print(" probably not a .%c file\n", thechar); errorexit(); } if(o == ANAME || o == ASIGNAME) { sig = 0; if(o == ASIGNAME) sig = Bget4(f); v = Bgetc(f); /* type */ o = Bgetc(f); /* sym */ r = 0; if(v == D_STATIC) r = version; name = Brdline(f, '\0'); if(name == nil) { if(Blinelen(f) > 0) { fprint(2, "%s: name too long\n", pn); errorexit(); } goto eof; } x = expandpkg(name, pkg); s = lookup(x, r); if(x != name) free(x); if(debug['S'] && r == 0) sig = 1729; if(sig != 0){ if(s->sig != 0 && s->sig != sig) diag("incompatible type signatures" "%ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); s->sig = sig; s->file = pn; } if(debug['W']) print(" ANAME %s\n", s->name); if(o < 0 || o >= nelem(h)) mangle(pn); h[o] = s; if((v == D_EXTERN || v == D_STATIC) && s->type == 0) s->type = SXREF; if(v == D_FILE) { if(s->type != SFILE) { histgen++; s->type = SFILE; s->value = histgen; } if(histfrogp < MAXHIST) { histfrog[histfrogp] = s; histfrogp++; } else collapsefrog(s); dwarfaddfrag(s->value, s->name); } goto loop; } p = mal(sizeof(*p)); p->as = o; p->line = Bget4(f); p->back = 2; p->ft = 0; p->tt = 0; zaddr(pn, f, &p->from, h); fromgotype = adrgotype; zaddr(pn, f, &p->to, h); if(debug['W']) print("%P\n", p); switch(p->as) { case AHISTORY: if(p->to.offset == -1) { addlib(src, pn); histfrogp = 0; goto loop; } if(src[0] == '\0') copyhistfrog(src, sizeof src); addhist(p->line, D_FILE); /* 'z' */ if(p->to.offset) addhist(p->to.offset, D_FILE1); /* 'Z' */ histfrogp = 0; goto loop; case AEND: histtoauto(); if(cursym != nil && cursym->text) cursym->autom = curauto; curauto = 0; cursym = nil; if(Boffset(f) == eof) return; goto newloop; case AGLOBL: s = p->from.sym; if(s->type == 0 || s->type == SXREF) { s->type = SBSS; s->size = 0; } if(s->type != SBSS && !s->dupok) { diag("%s: redefinition: %s in %s", pn, s->name, TNAME); s->type = SBSS; s->size = 0; } if(p->to.offset > s->size) s->size = p->to.offset; if(p->from.scale & DUPOK) s->dupok = 1; if(p->from.scale & RODATA) s->type = SRODATA; goto loop; case ADATA: // Assume that AGLOBL comes after ADATA. // If we've seen an AGLOBL that said this sym was DUPOK, // ignore any more ADATA we see, which must be // redefinitions. s = p->from.sym; if(s->dupok) { // if(debug['v']) // Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); goto loop; } if(s->file == nil) s->file = pn; else if(s->file != pn) { diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); errorexit(); } savedata(s, p, pn); unmal(p, sizeof *p); goto loop; case AGOK: diag("%s: GOK opcode in %s", pn, TNAME); pc++; goto loop; case ATEXT: s = p->from.sym; if(s->text != nil) { diag("%s: %s: redefinition", pn, s->name); return; } if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { /* redefinition, so file has probably been seen before */ if(debug['v']) diag("skipping: %s: redefinition: %s", pn, s->name); return; } if(cursym != nil && cursym->text) { histtoauto(); cursym->autom = curauto; curauto = 0; } skip = 0; if(etextp) etextp->next = s; else textp = s; etextp = s; s->text = p; cursym = s; if(s->type != 0 && s->type != SXREF) { if(p->from.scale & DUPOK) { skip = 1; goto casdef; } diag("%s: redefinition: %s\n%P", pn, s->name, p); } s->type = STEXT; s->value = pc; lastp = p; p->pc = pc++; goto loop; case AFMOVF: case AFADDF: case AFSUBF: case AFSUBRF: case AFMULF: case AFDIVF: case AFDIVRF: case AFCOMF: case AFCOMFP: if(skip) goto casdef; if(p->from.type == D_FCONST) { /* size sb 9 max */ sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); s = lookup(literal, 0); if(s->type == 0) { s->type = SDATA; adduint32(s, ieeedtof(&p->from.ieee)); s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; p->from.offset = 0; } goto casdef; case AFMOVD: case AFADDD: case AFSUBD: case AFSUBRD: case AFMULD: case AFDIVD: case AFDIVRD: case AFCOMD: case AFCOMDP: if(skip) goto casdef; if(p->from.type == D_FCONST) { /* size sb 18 max */ sprint(literal, "$%ux.%ux", p->from.ieee.l, p->from.ieee.h); s = lookup(literal, 0); if(s->type == 0) { s->type = SDATA; adduint32(s, p->from.ieee.l); adduint32(s, p->from.ieee.h); s->reachable = 0; } p->from.type = D_EXTERN; p->from.sym = s; p->from.offset = 0; } goto casdef; casdef: default: if(skip) nopout(p); p->pc = pc; pc++; if(p->to.type == D_BRANCH) p->to.offset += ipc; if(lastp == nil) { if(p->as != ANOP) diag("unexpected instruction: %P", p); goto loop; } lastp->link = p; lastp = p; goto loop; } eof: diag("truncated object file: %s", pn); }
void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence) { char *line; int n, c1, c2, c3, c4; uint32 magic; vlong import0, import1, eof; char *t; eof = Boffset(f) + len; pn = estrdup(pn); c1 = BGETC(f); c2 = BGETC(f); c3 = BGETC(f); c4 = BGETC(f); Bungetc(f); Bungetc(f); Bungetc(f); Bungetc(f); magic = c1<<24 | c2<<16 | c3<<8 | c4; if(magic == 0x7f454c46) { // \x7F E L F ldhostobj(ldelf, f, pkg, len, pn, file); return; } if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) { ldhostobj(ldmacho, f, pkg, len, pn, file); return; } if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) { ldhostobj(ldpe, f, pkg, len, pn, file); return; } /* check the header */ line = Brdline(f, '\n'); if(line == nil) { if(Blinelen(f) > 0) { diag("%s: not an object file", pn); return; } goto eof; } n = Blinelen(f) - 1; line[n] = '\0'; if(strncmp(line, "go object ", 10) != 0) { if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) { print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar); errorexit(); } if(strcmp(line, thestring) == 0) { // old header format: just $GOOS diag("%s: stale object file", pn); return; } diag("%s: not an object file", pn); free(pn); return; } // First, check that the basic goos, string, and version match. t = smprint("%s %s %s ", goos, thestring, getgoversion()); line[n] = ' '; if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) { line[n] = '\0'; diag("%s: object is [%s] expected [%s]", pn, line+10, t); free(t); free(pn); return; } // Second, check that longer lines match each other exactly, // so that the Go compiler and write additional information // that must be the same from run to run. line[n] = '\0'; if(n-10 > strlen(t)) { if(theline == nil) theline = estrdup(line+10); else if(strcmp(theline, line+10) != 0) { line[n] = '\0'; diag("%s: object is [%s] expected [%s]", pn, line+10, theline); free(t); free(pn); return; } } free(t); line[n] = '\n'; /* skip over exports and other info -- ends with \n!\n */ import0 = Boffset(f); c1 = '\n'; // the last line ended in \n c2 = BGETC(f); c3 = BGETC(f); while(c1 != '\n' || c2 != '!' || c3 != '\n') { c1 = c2; c2 = c3; c3 = BGETC(f); if(c3 == Beof) goto eof; } import1 = Boffset(f); Bseek(f, import0, 0); ldpkg(f, pkg, import1 - import0 - 2, pn, whence); // -2 for !\n Bseek(f, import1, 0); ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn); free(pn); return; eof: diag("truncated object file: %s", pn); free(pn); }
void objfile(char *file, char *pkg) { vlong off, l; Biobuf *f; char magbuf[SARMAG]; char pname[150]; struct ar_hdr arhdr; pkg = smprint("%i", pkg); if(debug['v'] > 1) Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg); Bflush(&bso); f = Bopen(file, 0); if(f == nil) { diag("cannot open file: %s", file); errorexit(); } l = Bread(f, magbuf, SARMAG); if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ /* load it as a regular file */ l = Bseek(f, 0L, 2); Bseek(f, 0L, 0); ldobj(f, pkg, l, file, file, FileObj); Bterm(f); free(pkg); return; } /* skip over optional __.GOSYMDEF and process __.PKGDEF */ off = Boffset(f); l = nextar(f, off, &arhdr); if(l <= 0) { diag("%s: short read on archive file symbol header", file); goto out; } if(strncmp(arhdr.name, symname, strlen(symname)) == 0) { off += l; l = nextar(f, off, &arhdr); if(l <= 0) { diag("%s: short read on archive file symbol header", file); goto out; } } if(strncmp(arhdr.name, pkgname, strlen(pkgname))) { diag("%s: cannot find package header", file); goto out; } off += l; if(debug['u']) ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef); /* * load all the object files from the archive now. * this gives us sequential file access and keeps us * from needing to come back later to pick up more * objects. it breaks the usual C archive model, but * this is Go, not C. the common case in Go is that * we need to load all the objects, and then we throw away * the individual symbols that are unused. * * loading every object will also make it possible to * load foreign objects not referenced by __.GOSYMDEF. */ for(;;) { l = nextar(f, off, &arhdr); if(l == 0) break; if(l < 0) { diag("%s: malformed archive", file); goto out; } off += l; l = SARNAME; while(l > 0 && arhdr.name[l-1] == ' ') l--; snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name); l = atolwhex(arhdr.size); ldobj(f, pkg, l, pname, file, ArchiveObj); } out: Bterm(f); free(pkg); }
void ldpe(Biobuf *f, char *pkg, int64 len, char *pn) { char *name; int32 base; int i, j, l, numaux; PeObj *obj; PeSect *sect, *rsect; IMAGE_SECTION_HEADER sh; uchar symbuf[18]; Sym *s; Reloc *r, *rp; PeSym *sym; USED(len); USED(pkg); if(debug['v']) Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn); sect = nil; version++; base = Boffset(f); obj = mal(sizeof *obj); obj->f = f; obj->base = base; obj->name = pn; // read header if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh) goto bad; // load section list obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]); obj->nsect = obj->fh.NumberOfSections; for(i=0; i < obj->fh.NumberOfSections; i++) { if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh) goto bad; obj->sect[i].size = obj->sect[i].sh.SizeOfRawData; obj->sect[i].name = (char*)obj->sect[i].sh.Name; // TODO return error if found .cormeta } // load string table Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); if(Bread(f, &l, sizeof l) != sizeof l) goto bad; obj->snames = mal(l); Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0); if(Bread(f, obj->snames, l) != l) goto bad; // read symbols obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]); obj->npesym = obj->fh.NumberOfSymbols; Bseek(f, base+obj->fh.PointerToSymbolTable, 0); for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) { Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0); if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf) goto bad; if((symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0)) { l = le32(&symbuf[4]); obj->pesym[i].name = (char*)&obj->snames[l]; } else { // sym name length <= 8 obj->pesym[i].name = mal(9); strncpy(obj->pesym[i].name, (char*)symbuf, 8); obj->pesym[i].name[8] = 0; } obj->pesym[i].value = le32(&symbuf[8]); obj->pesym[i].sectnum = le16(&symbuf[12]); obj->pesym[i].sclass = symbuf[16]; obj->pesym[i].aux = symbuf[17]; obj->pesym[i].type = le16(&symbuf[14]); numaux = obj->pesym[i].aux; if (numaux < 0) numaux = 0; } // create symbols for mapped sections for(i=0; i<obj->nsect; i++) { sect = &obj->sect[i]; if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; if(map(obj, sect) < 0) goto bad; name = smprint("%s(%s)", pn, sect->name); s = lookup(name, version); free(name); switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA| IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) { case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata s->type = SRODATA; break; case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss s->type = SBSS; break; case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data s->type = SDATA; break; case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text s->type = STEXT; break; default: werrstr("unexpected flags for PE section %s", sect->name); goto bad; } s->p = sect->base; s->np = sect->size; s->size = sect->size; if(s->type == STEXT) { if(etextp) etextp->next = s; else textp = s; etextp = s; } sect->sym = s; if(strcmp(sect->name, ".rsrc") == 0) setpersrc(sect->sym); } // load relocations for(i=0; i<obj->nsect; i++) { rsect = &obj->sect[i]; if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0) continue; if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE) continue; r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]); Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0); for(j=0; j<rsect->sh.NumberOfRelocations; j++) { rp = &r[j]; if(Bread(f, symbuf, 10) != 10) goto bad; uint32 rva, symindex; uint16 type; rva = le32(&symbuf[0]); symindex = le32(&symbuf[4]); type = le16(&symbuf[8]); if(readsym(obj, symindex, &sym) < 0) goto bad; if(sym->sym == nil) { werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type); goto bad; } rp->sym = sym->sym; rp->siz = 4; rp->off = rva; switch(type) { default: diag("%s: unknown relocation type %d;", pn, type); case IMAGE_REL_I386_REL32: case IMAGE_REL_AMD64_REL32: case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32 case IMAGE_REL_AMD64_ADDR32NB: rp->type = D_PCREL; rp->add = le32(rsect->base+rp->off); break; case IMAGE_REL_I386_DIR32NB: case IMAGE_REL_I386_DIR32: rp->type = D_ADDR; // load addend from image rp->add = le32(rsect->base+rp->off); break; case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 rp->siz = 8; rp->type = D_ADDR; // load addend from image rp->add = le64(rsect->base+rp->off); break; } } qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff); s = rsect->sym; s->r = r; s->nr = rsect->sh.NumberOfRelocations; } // enter sub-symbols into symbol table. for(i=0; i<obj->npesym; i++) { if(obj->pesym[i].name == 0) continue; if(obj->pesym[i].name[0] == '.') //skip section continue; if(obj->pesym[i].sectnum > 0) { sect = &obj->sect[obj->pesym[i].sectnum-1]; if(sect->sym == 0) continue; } if(readsym(obj, i, &sym) < 0) goto bad; s = sym->sym; if(sym->sectnum == 0) {// extern if(s->type == SDYNIMPORT) s->plt = -2; // flag for dynimport in PE object files. if (s->type == SXREF && sym->value > 0) {// global data s->type = SDATA; s->size = sym->value; } continue; } else if (sym->sectnum > 0) { sect = &obj->sect[sym->sectnum-1]; if(sect->sym == 0) diag("%s: %s sym == 0!", pn, s->name); } else { diag("%s: %s sectnum < 0!", pn, s->name); } if(sect == nil) return; s->sub = sect->sym->sub; sect->sym->sub = s; s->type = sect->sym->type | SSUB; s->value = sym->value; s->size = 4; s->outer = sect->sym; if(sect->sym->type == STEXT) { Prog *p; if(s->text != P) diag("%s: duplicate definition of %s", pn, s->name); // build a TEXT instruction with a unique pc // just to make the rest of the linker happy. p = prg(); p->as = ATEXT; p->from.type = D_EXTERN; p->from.sym = s; p->textflag = 7; p->to.type = D_CONST; p->link = nil; p->pc = pc++; s->text = p; etextp->next = s; etextp = s; } } return; bad: diag("%s: malformed pe file: %r", pn); }
void dumpobj(void) { NodeList *externs, *tmp; char arhdr[ArhdrSize]; vlong startobj, size; Sym *zero; bout = Bopen(outfile, OWRITE); if(bout == nil) { flusherrors(); print("can't create %s: %r\n", outfile); errorexit(); } startobj = 0; if(writearchive) { Bwrite(bout, "!<arch>\n", 8); memset(arhdr, 0, sizeof arhdr); Bwrite(bout, arhdr, sizeof arhdr); startobj = Boffset(bout); } Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); dumpexport(); if(writearchive) { Bflush(bout); size = Boffset(bout) - startobj; if(size&1) Bputc(bout, 0); Bseek(bout, startobj - ArhdrSize, 0); formathdr(arhdr, "__.PKGDEF", size); Bwrite(bout, arhdr, ArhdrSize); Bflush(bout); Bseek(bout, startobj + size + (size&1), 0); memset(arhdr, 0, ArhdrSize); Bwrite(bout, arhdr, ArhdrSize); startobj = Boffset(bout); Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring()); } Bprint(bout, "\n!\n"); externs = nil; if(externdcl != nil) externs = externdcl->end; dumpglobls(); dumptypestructs(); // Dump extra globals. tmp = externdcl; if(externs != nil) externdcl = externs->next; dumpglobls(); externdcl = tmp; zero = pkglookup("zerovalue", runtimepkg); ggloblsym(zero, zerosize, 1, 1); dumpdata(); writeobj(ctxt, bout); if(writearchive) { Bflush(bout); size = Boffset(bout) - startobj; if(size&1) Bputc(bout, 0); Bseek(bout, startobj - ArhdrSize, 0); snprint(namebuf, sizeof namebuf, "_go_.%c", thechar); formathdr(arhdr, namebuf, size); Bwrite(bout, arhdr, ArhdrSize); } Bterm(bout); }