github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/liblink/pcln.c (about)

     1  // Copyright 2013 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include <u.h>
     6  #include <libc.h>
     7  #include <bio.h>
     8  #include <link.h>
     9  
    10  static void
    11  addvarint(Link *ctxt, Pcdata *d, uint32 val)
    12  {
    13  	int32 n;
    14  	uint32 v;
    15  	uchar *p;
    16  
    17  	USED(ctxt);
    18  
    19  	n = 0;
    20  	for(v = val; v >= 0x80; v >>= 7)
    21  		n++;
    22  	n++;
    23  
    24  	if(d->n + n > d->m) {
    25  		d->m = (d->n + n)*2;
    26  		d->p = erealloc(d->p, d->m);
    27  	}
    28  
    29  	p = d->p + d->n;
    30  	for(v = val; v >= 0x80; v >>= 7)
    31  		*p++ = v | 0x80;
    32  	*p = v;
    33  	d->n += n;
    34  }
    35  
    36  // funcpctab writes to dst a pc-value table mapping the code in func to the values
    37  // returned by valfunc parameterized by arg. The invocation of valfunc to update the
    38  // current value is, for each p,
    39  //
    40  //	val = valfunc(func, val, p, 0, arg);
    41  //	record val as value at p->pc;
    42  //	val = valfunc(func, val, p, 1, arg);
    43  //
    44  // where func is the function, val is the current value, p is the instruction being
    45  // considered, and arg can be used to further parameterize valfunc.
    46  static void
    47  funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
    48  {
    49  	int dbg, i;
    50  	int32 oldval, val, started;
    51  	uint32 delta;
    52  	vlong pc;
    53  	Prog *p;
    54  
    55  	// To debug a specific function, uncomment second line and change name.
    56  	dbg = 0;
    57  	//dbg = strcmp(func->name, "main.main") == 0;
    58  	//dbg = strcmp(desc, "pctofile") == 0;
    59  
    60  	ctxt->debugpcln += dbg;
    61  
    62  	dst->n = 0;
    63  
    64  	if(ctxt->debugpcln)
    65  		Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
    66  
    67  	val = -1;
    68  	oldval = val;
    69  	if(func->text == nil) {
    70  		ctxt->debugpcln -= dbg;
    71  		return;
    72  	}
    73  
    74  	pc = func->text->pc;
    75  	
    76  	if(ctxt->debugpcln)
    77  		Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
    78  
    79  	started = 0;
    80  	for(p=func->text; p != nil; p = p->link) {
    81  		// Update val. If it's not changing, keep going.
    82  		val = valfunc(ctxt, func, val, p, 0, arg);
    83  		if(val == oldval && started) {
    84  			val = valfunc(ctxt, func, val, p, 1, arg);
    85  			if(ctxt->debugpcln)
    86  				Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
    87  			continue;
    88  		}
    89  
    90  		// If the pc of the next instruction is the same as the
    91  		// pc of this instruction, this instruction is not a real
    92  		// instruction. Keep going, so that we only emit a delta
    93  		// for a true instruction boundary in the program.
    94  		if(p->link && p->link->pc == p->pc) {
    95  			val = valfunc(ctxt, func, val, p, 1, arg);
    96  			if(ctxt->debugpcln)
    97  				Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
    98  			continue;
    99  		}
   100  
   101  		// The table is a sequence of (value, pc) pairs, where each
   102  		// pair states that the given value is in effect from the current position
   103  		// up to the given pc, which becomes the new current position.
   104  		// To generate the table as we scan over the program instructions,
   105  		// we emit a "(value" when pc == func->value, and then
   106  		// each time we observe a change in value we emit ", pc) (value".
   107  		// When the scan is over, we emit the closing ", pc)".
   108  		//
   109  		// The table is delta-encoded. The value deltas are signed and
   110  		// transmitted in zig-zag form, where a complement bit is placed in bit 0,
   111  		// and the pc deltas are unsigned. Both kinds of deltas are sent
   112  		// as variable-length little-endian base-128 integers,
   113  		// where the 0x80 bit indicates that the integer continues.
   114  
   115  		if(ctxt->debugpcln)
   116  			Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
   117  
   118  		if(started) {
   119  			addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
   120  			pc = p->pc;
   121  		}
   122  		delta = val - oldval;
   123  		if(delta>>31)
   124  			delta = 1 | ~(delta<<1);
   125  		else
   126  			delta <<= 1;
   127  		addvarint(ctxt, dst, delta);
   128  		oldval = val;
   129  		started = 1;
   130  		val = valfunc(ctxt, func, val, p, 1, arg);
   131  	}
   132  
   133  	if(started) {
   134  		if(ctxt->debugpcln)
   135  			Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
   136  		addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
   137  		addvarint(ctxt, dst, 0); // terminator
   138  	}
   139  
   140  	if(ctxt->debugpcln) {
   141  		Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
   142  		for(i=0; i<dst->n; i++)
   143  			Bprint(ctxt->bso, " %02ux", dst->p[i]);
   144  		Bprint(ctxt->bso, "\n");
   145  	}
   146  
   147  	ctxt->debugpcln -= dbg;
   148  }
   149  
   150  // pctofileline computes either the file number (arg == 0)
   151  // or the line number (arg == 1) to use at p.
   152  // Because p->lineno applies to p, phase == 0 (before p)
   153  // takes care of the update.
   154  static int32
   155  pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
   156  {
   157  	int32 i, l;
   158  	LSym *f;
   159  	Pcln *pcln;
   160  
   161  	USED(sym);
   162  
   163  	if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
   164  		return oldval;
   165  	linkgetline(ctxt, p->lineno, &f, &l);
   166  	if(f == nil) {
   167  	//	print("getline failed for %s %P\n", ctxt->cursym->name, p);
   168  		return oldval;
   169  	}
   170  	if(arg == nil)
   171  		return l;
   172  	pcln = arg;
   173  	
   174  	if(f == pcln->lastfile)
   175  		return pcln->lastindex;
   176  
   177  	for(i=0; i<pcln->nfile; i++) {
   178  		if(pcln->file[i] == f) {
   179  			pcln->lastfile = f;
   180  			pcln->lastindex = i;
   181  			return i;
   182  		}
   183  	}
   184  
   185  	if(pcln->nfile >= pcln->mfile) {
   186  		pcln->mfile = (pcln->nfile+1)*2;
   187  		pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
   188  	}
   189  	pcln->file[pcln->nfile++] = f;
   190  	pcln->lastfile = f;
   191  	pcln->lastindex = i;
   192  	return i;
   193  }
   194  
   195  // pctospadj computes the sp adjustment in effect.
   196  // It is oldval plus any adjustment made by p itself.
   197  // The adjustment by p takes effect only after p, so we
   198  // apply the change during phase == 1.
   199  static int32
   200  pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
   201  {
   202  	USED(arg);
   203  	USED(sym);
   204  
   205  	if(oldval == -1) // starting
   206  		oldval = 0;
   207  	if(phase == 0)
   208  		return oldval;
   209  	if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
   210  		ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
   211  		sysfatal("bad code");
   212  	}
   213  	return oldval + p->spadj;
   214  }
   215  
   216  // pctopcdata computes the pcdata value in effect at p.
   217  // A PCDATA instruction sets the value in effect at future
   218  // non-PCDATA instructions.
   219  // Since PCDATA instructions have no width in the final code,
   220  // it does not matter which phase we use for the update.
   221  static int32
   222  pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
   223  {
   224  	USED(sym);
   225  
   226  	if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
   227  		return oldval;
   228  	if((int32)p->to.offset != p->to.offset) {
   229  		ctxt->diag("overflow in PCDATA instruction: %P", p);
   230  		sysfatal("bad code");
   231  	}
   232  	return p->to.offset;
   233  }
   234  
   235  void
   236  linkpcln(Link *ctxt, LSym *cursym)
   237  {
   238  	Prog *p;
   239  	Pcln *pcln;
   240  	int i, npcdata, nfuncdata, n;
   241  	uint32 *havepc, *havefunc;
   242  
   243  	ctxt->cursym = cursym;
   244  
   245  	pcln = emallocz(sizeof *pcln);
   246  	cursym->pcln = pcln;
   247  
   248  	npcdata = 0;
   249  	nfuncdata = 0;
   250  	for(p = cursym->text; p != nil; p = p->link) {
   251  		if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
   252  			npcdata = p->from.offset+1;
   253  		if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
   254  			nfuncdata = p->from.offset+1;
   255  	}
   256  
   257  	pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
   258  	pcln->npcdata = npcdata;
   259  	pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
   260  	pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
   261  	pcln->nfuncdata = nfuncdata;
   262  
   263  	funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
   264  	funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
   265  	funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
   266  	
   267  	// tabulate which pc and func data we have.
   268  	n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
   269  	havepc = emallocz(n);
   270  	havefunc = havepc + (npcdata+31)/32;
   271  	for(p = cursym->text; p != nil; p = p->link) {
   272  		if(p->as == ctxt->arch->AFUNCDATA) {
   273  			if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
   274  				ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
   275  			havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
   276  		}
   277  		if(p->as == ctxt->arch->APCDATA)
   278  			havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
   279  	}
   280  	// pcdata.
   281  	for(i=0; i<npcdata; i++) {
   282  		if(((havepc[i/32]>>(i%32))&1) == 0) 
   283  			continue;
   284  		funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
   285  	}
   286  	free(havepc);
   287  	
   288  	// funcdata
   289  	if(nfuncdata > 0) {
   290  		for(p = cursym->text; p != nil; p = p->link) {
   291  			if(p->as == ctxt->arch->AFUNCDATA) {
   292  				i = p->from.offset;
   293  				pcln->funcdataoff[i] = p->to.offset;
   294  				if(p->to.type != ctxt->arch->D_CONST) {
   295  					// TODO: Dedup.
   296  					//funcdata_bytes += p->to.sym->size;
   297  					pcln->funcdata[i] = p->to.sym;
   298  				}
   299  			}
   300  		}
   301  	}
   302  }
   303  
   304  // iteration over encoded pcdata tables.
   305  
   306  static uint32
   307  getvarint(uchar **pp)
   308  {
   309  	uchar *p;
   310  	int shift;
   311  	uint32 v;
   312  
   313  	v = 0;
   314  	p = *pp;
   315  	for(shift = 0;; shift += 7) {
   316  		v |= (uint32)(*p & 0x7F) << shift;
   317  		if(!(*p++ & 0x80))
   318  			break;
   319  	}
   320  	*pp = p;
   321  	return v;
   322  }
   323  
   324  void
   325  pciternext(Pciter *it)
   326  {
   327  	uint32 v;
   328  	int32 dv;
   329  
   330  	it->pc = it->nextpc;
   331  	if(it->done)
   332  		return;
   333  	if(it->p >= it->d.p + it->d.n) {
   334  		it->done = 1;
   335  		return;
   336  	}
   337  
   338  	// value delta
   339  	v = getvarint(&it->p);
   340  	if(v == 0 && !it->start) {
   341  		it->done = 1;
   342  		return;
   343  	}
   344  	it->start = 0;
   345  	dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
   346  	it->value += dv;
   347  	
   348  	// pc delta
   349  	v = getvarint(&it->p);
   350  	it->nextpc = it->pc + v*it->pcscale;
   351  }
   352  
   353  void
   354  pciterinit(Link *ctxt, Pciter *it, Pcdata *d)
   355  {
   356  	it->d = *d;
   357  	it->p = it->d.p;
   358  	it->pc = 0;
   359  	it->nextpc = 0;
   360  	it->value = -1;
   361  	it->start = 1;
   362  	it->done = 0;
   363  	it->pcscale = ctxt->arch->minlc;
   364  	pciternext(it);
   365  }