This source file includes following definitions.
- addvarint
- funcpctab
- pctofileline
- pctospadj
- pctopcdata
- linkpcln
- getvarint
- pciternext
- pciterinit
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
static void
addvarint(Link *ctxt, Pcdata *d, uint32 val)
{
int32 n;
uint32 v;
uchar *p;
USED(ctxt);
n = 0;
for(v = val; v >= 0x80; v >>= 7)
n++;
n++;
if(d->n + n > d->m) {
d->m = (d->n + n)*2;
d->p = erealloc(d->p, d->m);
}
p = d->p + d->n;
for(v = val; v >= 0x80; v >>= 7)
*p++ = v | 0x80;
*p = v;
d->n += n;
}
static void
funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
{
int dbg, i;
int32 oldval, val, started;
uint32 delta;
vlong pc;
Prog *p;
dbg = 0;
ctxt->debugpcln += dbg;
dst->n = 0;
if(ctxt->debugpcln)
Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
val = -1;
oldval = val;
if(func->text == nil) {
ctxt->debugpcln -= dbg;
return;
}
pc = func->text->pc;
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
started = 0;
for(p=func->text; p != nil; p = p->link) {
val = valfunc(ctxt, func, val, p, 0, arg);
if(val == oldval && started) {
val = valfunc(ctxt, func, val, p, 1, arg);
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
continue;
}
if(p->link && p->link->pc == p->pc) {
val = valfunc(ctxt, func, val, p, 1, arg);
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
continue;
}
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
if(started) {
addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
pc = p->pc;
}
delta = val - oldval;
if(delta>>31)
delta = 1 | ~(delta<<1);
else
delta <<= 1;
addvarint(ctxt, dst, delta);
oldval = val;
started = 1;
val = valfunc(ctxt, func, val, p, 1, arg);
}
if(started) {
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
addvarint(ctxt, dst, 0);
}
if(ctxt->debugpcln) {
Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
for(i=0; i<dst->n; i++)
Bprint(ctxt->bso, " %02ux", dst->p[i]);
Bprint(ctxt->bso, "\n");
}
ctxt->debugpcln -= dbg;
}
static int32
pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
int32 i, l;
LSym *f;
Pcln *pcln;
USED(sym);
if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
return oldval;
linkgetline(ctxt, p->lineno, &f, &l);
if(f == nil) {
return oldval;
}
if(arg == nil)
return l;
pcln = arg;
if(f == pcln->lastfile)
return pcln->lastindex;
for(i=0; i<pcln->nfile; i++) {
if(pcln->file[i] == f) {
pcln->lastfile = f;
pcln->lastindex = i;
return i;
}
}
if(pcln->nfile >= pcln->mfile) {
pcln->mfile = (pcln->nfile+1)*2;
pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
}
pcln->file[pcln->nfile++] = f;
pcln->lastfile = f;
pcln->lastindex = i;
return i;
}
static int32
pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
USED(arg);
USED(sym);
if(oldval == -1)
oldval = 0;
if(phase == 0)
return oldval;
if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
sysfatal("bad code");
}
return oldval + p->spadj;
}
static int32
pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
USED(sym);
if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
return oldval;
if((int32)p->to.offset != p->to.offset) {
ctxt->diag("overflow in PCDATA instruction: %P", p);
sysfatal("bad code");
}
return p->to.offset;
}
void
linkpcln(Link *ctxt, LSym *cursym)
{
Prog *p;
Pcln *pcln;
int i, npcdata, nfuncdata, n;
uint32 *havepc, *havefunc;
ctxt->cursym = cursym;
pcln = emallocz(sizeof *pcln);
cursym->pcln = pcln;
npcdata = 0;
nfuncdata = 0;
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
npcdata = p->from.offset+1;
if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
nfuncdata = p->from.offset+1;
}
pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
pcln->npcdata = npcdata;
pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
pcln->nfuncdata = nfuncdata;
funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
havepc = emallocz(n);
havefunc = havepc + (npcdata+31)/32;
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->AFUNCDATA) {
if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
if(p->as == ctxt->arch->APCDATA)
havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
for(i=0; i<npcdata; i++) {
if(!(havepc[i/32]>>(i%32))&1)
continue;
funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
}
free(havepc);
if(nfuncdata > 0) {
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->AFUNCDATA) {
i = p->from.offset;
pcln->funcdataoff[i] = p->to.offset;
if(p->to.type != ctxt->arch->D_CONST) {
pcln->funcdata[i] = p->to.sym;
}
}
}
}
}
static uint32
getvarint(uchar **pp)
{
uchar *p;
int shift;
uint32 v;
v = 0;
p = *pp;
for(shift = 0;; shift += 7) {
v |= (uint32)(*p & 0x7F) << shift;
if(!(*p++ & 0x80))
break;
}
*pp = p;
return v;
}
void
pciternext(Pciter *it)
{
uint32 v;
int32 dv;
it->pc = it->nextpc;
if(it->done)
return;
if(it->p >= it->d.p + it->d.n) {
it->done = 1;
return;
}
v = getvarint(&it->p);
if(v == 0 && !it->start) {
it->done = 1;
return;
}
it->start = 0;
dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
it->value += dv;
v = getvarint(&it->p);
it->nextpc = it->pc + v*it->pcscale;
}
void
pciterinit(Link *ctxt, Pciter *it, Pcdata *d)
{
it->d = *d;
it->p = it->d.p;
it->pc = 0;
it->nextpc = 0;
it->value = -1;
it->start = 1;
it->done = 0;
it->pcscale = ctxt->arch->minlc;
pciternext(it);
}