blob: cdc11b85db7119cc51cb92da780a7375aa3ae595 [file] [log] [blame]
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
// funcpctab writes to dst a pc-value table mapping the code in func to the values
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
// current value is, for each p,
//
// val = valfunc(func, val, p, 0, arg);
// record val as value at p->pc;
// val = valfunc(func, val, p, 1, arg);
//
// where func is the function, val is the current value, p is the instruction being
// considered, and arg can be used to further parameterize valfunc.
// pctofileline computes either the file number (arg == 0)
// or the line number (arg == 1) to use at p.
// Because p->lineno applies to p, phase == 0 (before p)
// takes care of the update.
// pctospadj computes the sp adjustment in effect.
// It is oldval plus any adjustment made by p itself.
// The adjustment by p takes effect only after p, so we
// apply the change during phase == 1.
// pctopcdata computes the pcdata value in effect at p.
// A PCDATA instruction sets the value in effect at future
// non-PCDATA instructions.
// Since PCDATA instructions have no width in the final code,
// it does not matter which phase we use for the update.
// iteration over encoded pcdata tables.
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;
}
// value delta
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;
// pc delta
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);
}