#include "l.h"#include <ar.h> char *noname = "<none>";char symname[] = SYMDEF; char** libdir;int nlibdir = 0;static int maxlibdir = 0; intisobjfile(char *f){ int n, v; Biobuf *b; char buf1[5], buf2[SARMAG]; b = Bopen(f, OREAD); if(b == nil) return 0; n = Bread(b, buf1, 5); if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<')) v = 1; /* good enough for our purposes */ else{ Bseek(b, 0, 0); n = Bread(b, buf2, SARMAG); v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0; } Bterm(b); return v;} voidloadlib(void){ int i; long h; Sym *s; loop: xrefresolv = 0; for(i=0; i<libraryp; i++) { if(debug['v']) Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]); objfile(library[i]); } if(xrefresolv) for(h=0; h<nelem(hash); h++) for(s = hash[h]; s != S; s = s->link) if(s->type == SXREF) goto loop;} voidobjfile(char *file){ long off, esym, cnt, l; int f, work; Sym *s; char magbuf[SARMAG]; char name[LIBNAMELEN], pname[LIBNAMELEN]; struct ar_hdr arhdr; char *e, *start, *stop; if(debug['v']) Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file); Bflush(&bso); if(file[0] == '-' && file[1] == 'l') { snprint(pname, sizeof(pname), "lib%s.a", file+2); e = findlib(pname); if(e == nil) { diag("cannot find library: %s", file); errorexit(); } snprint(name, sizeof(name), "%s/%s", e, pname); file = name; } f = open(file, 0); if(f < 0) { diag("cannot open %s: %r", file); errorexit(); } l = read(f, magbuf, SARMAG); if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){ /* load it as a regular file */ l = seek(f, 0L, 2); seek(f, 0L, 0); ldobj(f, l, file); close(f); return; } if(debug['v']) Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file); l = read(f, &arhdr, SAR_HDR); if(l != SAR_HDR) { diag("%s: short read on archive file symbol header", file); goto out; } if(strncmp(arhdr.name, symname, strlen(symname))) { diag("%s: first entry not symbol header", file); goto out; } esym = SARMAG + SAR_HDR + atolwhex(arhdr.size); off = SARMAG + SAR_HDR; /* * just bang the whole symbol file into memory */ seek(f, off, 0); cnt = esym - off; start = malloc(cnt + 10); cnt = read(f, start, cnt); if(cnt <= 0){ close(f); return; } stop = &start[cnt]; memset(stop, 0, 10); work = 1; while(work){ if(debug['v']) Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file); Bflush(&bso); work = 0; for(e = start; e < stop; e = strchr(e+5, 0) + 1) { s = lookup(e+5, 0); if(s->type != SXREF) continue; sprint(pname, "%s(%s)", file, s->name); if(debug['v']) Bprint(&bso, "%5.2f library: %s\n", cputime(), pname); Bflush(&bso); l = e[1] & 0xff; l |= (e[2] & 0xff) << 8; l |= (e[3] & 0xff) << 16; l |= (e[4] & 0xff) << 24; seek(f, l, 0); l = read(f, &arhdr, SAR_HDR); if(l != SAR_HDR) goto bad; if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag))) goto bad; l = atolwhex(arhdr.size); ldobj(f, l, pname); if(s->type == SXREF) { diag("%s: failed to load: %s", file, s->name); errorexit(); } work = 1; xrefresolv = 1; } } return; bad: diag("%s: bad or out of date archive", file);out: close(f);} voidaddlibpath(char *arg){ char **p; if(nlibdir >= maxlibdir) { if(maxlibdir == 0) maxlibdir = 8; else maxlibdir *= 2; p = malloc(maxlibdir*sizeof(*p)); if(p == nil) { diag("out of memory"); errorexit(); } memmove(p, libdir, nlibdir*sizeof(*p)); free(libdir); libdir = p; } libdir[nlibdir++] = strdup(arg);} char*findlib(char *file){ int i; char name[LIBNAMELEN]; for(i = 0; i < nlibdir; i++) { snprint(name, sizeof(name), "%s/%s", libdir[i], file); if(fileexists(name)) return libdir[i]; } return nil;} voidaddlibroot(void){ char *a; char name[LIBNAMELEN]; a = getenv("ccroot"); if(a != nil && *a != '\0') { if(!fileexists(a)) { diag("nonexistent $ccroot: %s", a); errorexit(); } }else a = ""; snprint(name, sizeof(name), "%s/%s/lib", a, thestring); addlibpath(name);} voidaddlib(char *obj){ char fn1[LIBNAMELEN], fn2[LIBNAMELEN], comp[LIBNAMELEN], *p, *name; int i, search; if(histfrogp <= 0) return; name = fn1; search = 0; if(histfrog[0]->name[1] == '/') { sprint(name, ""); i = 1; } else if(histfrog[0]->name[1] == '.') { sprint(name, "."); i = 0; } else { sprint(name, ""); i = 0; search = 1; } for(; i<histfrogp; i++) { snprint(comp, sizeof comp, histfrog[i]->name+1); for(;;) { p = strstr(comp, "$O"); if(p == 0) break; memmove(p+1, p+2, strlen(p+2)+1); p[0] = thechar; } for(;;) { p = strstr(comp, "$M"); if(p == 0) break; if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) { diag("library component too long"); return; } memmove(p+strlen(thestring), p+2, strlen(p+2)+1); memmove(p, thestring, strlen(thestring)); } if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) { diag("library component too long"); return; } if(i > 0 || !search) strcat(fn1, "/"); strcat(fn1, comp); } cleanname(name); if(search){ p = findlib(name); if(p != nil){ snprint(fn2, sizeof(fn2), "%s/%s", p, name); name = fn2; } } for(i=0; i<libraryp; i++) if(strcmp(name, library[i]) == 0) return; if(libraryp == nelem(library)){ diag("too many autolibs; skipping %s", name); return; } p = malloc(strlen(name) + 1); strcpy(p, name); library[libraryp] = p; p = malloc(strlen(obj) + 1); strcpy(p, obj); libraryobj[libraryp] = p; libraryp++;} voidaddhist(long line, int type){ Auto *u; Sym *s; int i, j, k; u = malloc(sizeof(Auto)); s = malloc(sizeof(Sym)); s->name = malloc(2*(histfrogp+1) + 1); u->asym = s; u->type = type; u->aoffset = line; u->link = curhist; curhist = u; j = 1; for(i=0; i<histfrogp; i++) { k = histfrog[i]->value; s->name[j+0] = k>>8; s->name[j+1] = k; j += 2; }} voidhisttoauto(void){ Auto *l; while((l = curhist) != nil) { curhist = l->link; l->link = curauto; curauto = l; }} voidcollapsefrog(Sym *s){ int i; /* * bad encoding of path components only allows * MAXHIST components. if there is an overflow, * first try to collapse xxx/.. */ for(i=1; i<histfrogp; i++) if(strcmp(histfrog[i]->name+1, "..") == 0) { memmove(histfrog+i-1, histfrog+i+1, (histfrogp-i-1)*sizeof(histfrog[0])); histfrogp--; goto out; } /* * next try to collapse . */ for(i=0; i<histfrogp; i++) if(strcmp(histfrog[i]->name+1, ".") == 0) { memmove(histfrog+i, histfrog+i+1, (histfrogp-i-1)*sizeof(histfrog[0])); goto out; } /* * last chance, just truncate from front */ memmove(histfrog+0, histfrog+1, (histfrogp-1)*sizeof(histfrog[0])); out: histfrog[histfrogp-1] = s;} uchar*readsome(int f, uchar *buf, uchar *good, uchar *stop, int max){ int n; n = stop - good; memmove(buf, good, stop - good); stop = buf + n; n = MAXIO - n; if(n > max) n = max; n = read(f, stop, n); if(n <= 0) return 0; return stop + n;} Sym*lookup(char *symb, int v){ Sym *s; 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 != S; s = s->link) if(s->version == v) if(memcmp(s->name, symb, l) == 0) return s; s = halloc(sizeof(Sym)); s->name = malloc(l + 1); memmove(s->name, symb, l); s->link = hash[h]; s->type = 0; s->version = v; s->value = 0; s->sig = 0; hash[h] = s; return s;} intfind1(long l, int c){ char *p; int i; p = (char*)&l; for(i=0; i<4; i++) if(*p++ == c) return i; return 0;} longieeedtof(Ieee *ieeep){ int exp; long v; if(ieeep->h == 0) return 0; exp = (ieeep->h>>20) & ((1L<<11)-1L); exp -= (1L<<10) - 2L; v = (ieeep->h & 0xfffffL) << 3; v |= (ieeep->l >> 29) & 0x7L; if((ieeep->l >> 28) & 1) { v++; if(v & 0x800000L) { v = (v & 0x7fffffL) >> 1; exp++; } } if(exp <= -126 || exp >= 130) diag("double fp to single fp overflow"); v |= ((exp + 126) & 0xffL) << 23; v |= ieeep->h & 0x80000000L; return v;} doubleieeedtod(Ieee *ieeep){ Ieee e; double fr; int exp; if(ieeep->h & (1L<<31)) { e.h = ieeep->h & ~(1L<<31); e.l = ieeep->l; return -ieeedtod(&e); } if(ieeep->l == 0 && ieeep->h == 0) return 0; fr = ieeep->l & ((1L<<16)-1L); fr /= 1L<<16; fr += (ieeep->l>>16) & ((1L<<16)-1L); fr /= 1L<<16; fr += (ieeep->h & (1L<<20)-1L) | (1L<<20); fr /= 1L<<21; exp = (ieeep->h>>20) & ((1L<<11)-1L); exp -= (1L<<10) - 2L; return ldexp(fr, exp);}
#include "l.h"
#include <ar.h>
char *noname = "<none>";
char symname[] = SYMDEF;
char** libdir;
int nlibdir = 0;
static int maxlibdir = 0;
int
isobjfile(char *f)
{
int n, v;
Biobuf *b;
char buf1[5], buf2[SARMAG];
b = Bopen(f, OREAD);
if(b == nil)
return 0;
n = Bread(b, buf1, 5);
if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
v = 1; /* good enough for our purposes */
else{
Bseek(b, 0, 0);
n = Bread(b, buf2, SARMAG);
v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
}
Bterm(b);
return v;
}
void
loadlib(void)
{
int i;
long h;
Sym *s;
loop:
xrefresolv = 0;
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
objfile(library[i]);
}
if(xrefresolv)
for(h=0; h<nelem(hash); h++)
for(s = hash[h]; s != S; s = s->link)
if(s->type == SXREF)
goto loop;
}
void
objfile(char *file)
{
long off, esym, cnt, l;
int f, work;
Sym *s;
char magbuf[SARMAG];
char name[LIBNAMELEN], pname[LIBNAMELEN];
struct ar_hdr arhdr;
char *e, *start, *stop;
if(debug['v'])
Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
Bflush(&bso);
if(file[0] == '-' && file[1] == 'l') {
snprint(pname, sizeof(pname), "lib%s.a", file+2);
e = findlib(pname);
if(e == nil) {
diag("cannot find library: %s", file);
errorexit();
}
snprint(name, sizeof(name), "%s/%s", e, pname);
file = name;
}
f = open(file, 0);
if(f < 0) {
diag("cannot open %s: %r", file);
errorexit();
}
l = read(f, magbuf, SARMAG);
if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
/* load it as a regular file */
l = seek(f, 0L, 2);
seek(f, 0L, 0);
ldobj(f, l, file);
close(f);
return;
}
if(debug['v'])
Bprint(&bso, "%5.2f ldlib: %s\n", cputime(), file);
l = read(f, &arhdr, SAR_HDR);
if(l != SAR_HDR) {
diag("%s: short read on archive file symbol header", file);
goto out;
}
if(strncmp(arhdr.name, symname, strlen(symname))) {
diag("%s: first entry not symbol header", file);
goto out;
}
esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
off = SARMAG + SAR_HDR;
/*
* just bang the whole symbol file into memory
*/
seek(f, off, 0);
cnt = esym - off;
start = malloc(cnt + 10);
cnt = read(f, start, cnt);
if(cnt <= 0){
close(f);
return;
}
stop = &start[cnt];
memset(stop, 0, 10);
work = 1;
while(work){
if(debug['v'])
Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
Bflush(&bso);
work = 0;
for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
s = lookup(e+5, 0);
if(s->type != SXREF)
continue;
sprint(pname, "%s(%s)", file, s->name);
if(debug['v'])
Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
Bflush(&bso);
l = e[1] & 0xff;
l |= (e[2] & 0xff) << 8;
l |= (e[3] & 0xff) << 16;
l |= (e[4] & 0xff) << 24;
seek(f, l, 0);
l = read(f, &arhdr, SAR_HDR);
if(l != SAR_HDR)
goto bad;
if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
goto bad;
l = atolwhex(arhdr.size);
ldobj(f, l, pname);
if(s->type == SXREF) {
diag("%s: failed to load: %s", file, s->name);
errorexit();
}
work = 1;
xrefresolv = 1;
}
}
return;
bad:
diag("%s: bad or out of date archive", file);
out:
close(f);
}
void
addlibpath(char *arg)
{
char **p;
if(nlibdir >= maxlibdir) {
if(maxlibdir == 0)
maxlibdir = 8;
else
maxlibdir *= 2;
p = malloc(maxlibdir*sizeof(*p));
if(p == nil) {
diag("out of memory");
errorexit();
}
memmove(p, libdir, nlibdir*sizeof(*p));
free(libdir);
libdir = p;
}
libdir[nlibdir++] = strdup(arg);
}
char*
findlib(char *file)
{
int i;
char name[LIBNAMELEN];
for(i = 0; i < nlibdir; i++) {
snprint(name, sizeof(name), "%s/%s", libdir[i], file);
if(fileexists(name))
return libdir[i];
}
return nil;
}
void
addlibroot(void)
{
char *a;
char name[LIBNAMELEN];
a = getenv("ccroot");
if(a != nil && *a != '\0') {
if(!fileexists(a)) {
diag("nonexistent $ccroot: %s", a);
errorexit();
}
}else
a = "";
snprint(name, sizeof(name), "%s/%s/lib", a, thestring);
addlibpath(name);
}
void
addlib(char *obj)
{
char fn1[LIBNAMELEN], fn2[LIBNAMELEN], comp[LIBNAMELEN], *p, *name;
int i, search;
if(histfrogp <= 0)
return;
name = fn1;
search = 0;
if(histfrog[0]->name[1] == '/') {
sprint(name, "");
i = 1;
} else if(histfrog[0]->name[1] == '.') {
sprint(name, ".");
i = 0;
} else {
sprint(name, "");
i = 0;
search = 1;
}
for(; i<histfrogp; i++) {
snprint(comp, sizeof comp, histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
break;
memmove(p+1, p+2, strlen(p+2)+1);
p[0] = thechar;
}
for(;;) {
p = strstr(comp, "$M");
if(p == 0)
break;
if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
diag("library component too long");
return;
}
memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
memmove(p, thestring, strlen(thestring));
}
if(strlen(fn1) + strlen(comp) + 3 >= sizeof(fn1)) {
diag("library component too long");
return;
}
if(i > 0 || !search)
strcat(fn1, "/");
strcat(fn1, comp);
}
cleanname(name);
if(search){
p = findlib(name);
if(p != nil){
snprint(fn2, sizeof(fn2), "%s/%s", p, name);
name = fn2;
}
}
for(i=0; i<libraryp; i++)
if(strcmp(name, library[i]) == 0)
return;
if(libraryp == nelem(library)){
diag("too many autolibs; skipping %s", name);
return;
}
p = malloc(strlen(name) + 1);
strcpy(p, name);
library[libraryp] = p;
p = malloc(strlen(obj) + 1);
strcpy(p, obj);
libraryobj[libraryp] = p;
libraryp++;
}
void
addhist(long line, int type)
{
Auto *u;
Sym *s;
int i, j, k;
u = malloc(sizeof(Auto));
s = malloc(sizeof(Sym));
s->name = malloc(2*(histfrogp+1) + 1);
u->asym = s;
u->type = type;
u->aoffset = line;
u->link = curhist;
curhist = u;
j = 1;
for(i=0; i<histfrogp; i++) {
k = histfrog[i]->value;
s->name[j+0] = k>>8;
s->name[j+1] = k;
j += 2;
}
}
void
histtoauto(void)
{
Auto *l;
while((l = curhist) != nil) {
curhist = l->link;
l->link = curauto;
curauto = l;
}
}
void
collapsefrog(Sym *s)
{
int i;
/*
* bad encoding of path components only allows
* MAXHIST components. if there is an overflow,
* first try to collapse xxx/..
*/
for(i=1; i<histfrogp; i++)
if(strcmp(histfrog[i]->name+1, "..") == 0) {
memmove(histfrog+i-1, histfrog+i+1,
(histfrogp-i-1)*sizeof(histfrog[0]));
histfrogp--;
goto out;
}
/*
* next try to collapse .
*/
for(i=0; i<histfrogp; i++)
if(strcmp(histfrog[i]->name+1, ".") == 0) {
memmove(histfrog+i, histfrog+i+1,
(histfrogp-i-1)*sizeof(histfrog[0]));
goto out;
}
/*
* last chance, just truncate from front
*/
memmove(histfrog+0, histfrog+1,
(histfrogp-1)*sizeof(histfrog[0]));
out:
histfrog[histfrogp-1] = s;
}
uchar*
readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
{
int n;
n = stop - good;
memmove(buf, good, stop - good);
stop = buf + n;
n = MAXIO - n;
if(n > max)
n = max;
n = read(f, stop, n);
if(n <= 0)
return 0;
return stop + n;
}
Sym*
lookup(char *symb, int v)
{
Sym *s;
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 != S; s = s->link)
if(s->version == v)
if(memcmp(s->name, symb, l) == 0)
return s;
s = halloc(sizeof(Sym));
s->name = malloc(l + 1);
memmove(s->name, symb, l);
s->link = hash[h];
s->type = 0;
s->version = v;
s->value = 0;
s->sig = 0;
hash[h] = s;
return s;
}
int
find1(long l, int c)
{
char *p;
int i;
p = (char*)&l;
for(i=0; i<4; i++)
if(*p++ == c)
return i;
return 0;
}
long
ieeedtof(Ieee *ieeep)
{
int exp;
long v;
if(ieeep->h == 0)
return 0;
exp = (ieeep->h>>20) & ((1L<<11)-1L);
exp -= (1L<<10) - 2L;
v = (ieeep->h & 0xfffffL) << 3;
v |= (ieeep->l >> 29) & 0x7L;
if((ieeep->l >> 28) & 1) {
v++;
if(v & 0x800000L) {
v = (v & 0x7fffffL) >> 1;
exp++;
}
}
if(exp <= -126 || exp >= 130)
diag("double fp to single fp overflow");
v |= ((exp + 126) & 0xffL) << 23;
v |= ieeep->h & 0x80000000L;
return v;
}
double
ieeedtod(Ieee *ieeep)
{
Ieee e;
double fr;
int exp;
if(ieeep->h & (1L<<31)) {
e.h = ieeep->h & ~(1L<<31);
e.l = ieeep->l;
return -ieeedtod(&e);
}
if(ieeep->l == 0 && ieeep->h == 0)
return 0;
fr = ieeep->l & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (ieeep->l>>16) & ((1L<<16)-1L);
fr /= 1L<<16;
fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
fr /= 1L<<21;
exp = (ieeep->h>>20) & ((1L<<11)-1L);
exp -= (1L<<10) - 2L;
return ldexp(fr, exp);
}