plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

symdwarf.c (10005B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <bio.h>
      4 #include <mach.h>
      5 #include "elf.h"
      6 #include "dwarf.h"
      7 
      8 static void	dwarfsymclose(Fhdr*);
      9 static int	dwarfpc2file(Fhdr*, u64int, char*, uint, ulong*);
     10 static int	dwarfline2pc(Fhdr*, u64int, ulong, u64int*);
     11 static int	dwarflookuplsym(Fhdr*, Symbol*, char*, Symbol*);
     12 static int	dwarfindexlsym(Fhdr*, Symbol*, uint, Symbol*);
     13 static int	dwarffindlsym(Fhdr*, Symbol*, Loc, Symbol*);
     14 static void	dwarfsyminit(Fhdr*);
     15 static int	dwarftosym(Fhdr*, Dwarf*, DwarfSym*, Symbol*, int);
     16 static int	_dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol*);
     17 
     18 int
     19 symdwarf(Fhdr *hdr)
     20 {
     21 	if(hdr->dwarf == nil){
     22 		werrstr("no dwarf debugging symbols");
     23 		return -1;
     24 	}
     25 
     26 	hdr->symclose = dwarfsymclose;
     27 	hdr->pc2file = dwarfpc2file;
     28 	hdr->line2pc = dwarfline2pc;
     29 	hdr->lookuplsym = dwarflookuplsym;
     30 	hdr->indexlsym = dwarfindexlsym;
     31 	hdr->findlsym = dwarffindlsym;
     32 	hdr->unwind = _dwarfunwind;
     33 	dwarfsyminit(hdr);
     34 
     35 	return 0;
     36 }
     37 
     38 static void
     39 dwarfsymclose(Fhdr *hdr)
     40 {
     41 	dwarfclose(hdr->dwarf);
     42 	hdr->dwarf = nil;
     43 }
     44 
     45 static int
     46 dwarfpc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *line)
     47 {
     48 	char *cdir, *dir, *file;
     49 
     50 	if(dwarfpctoline(fhdr->dwarf, pc, &cdir, &dir, &file, line, nil, nil) < 0)
     51 		return -1;
     52 
     53 	if(file[0] == '/' || (dir==nil && cdir==nil))
     54 		strecpy(buf, buf+nbuf, file);
     55 	else if((dir && dir[0] == '/') || cdir==nil)
     56 		snprint(buf, nbuf, "%s/%s", dir, file);
     57 	else
     58 		snprint(buf, nbuf, "%s/%s/%s", cdir, dir ? dir : "", file);
     59 	cleanname(buf);
     60 	return 0;;
     61 }
     62 
     63 static int
     64 dwarfline2pc(Fhdr *fhdr, u64int basepc, ulong line, u64int *pc)
     65 {
     66 	werrstr("dwarf line2pc not implemented");
     67 	return -1;
     68 }
     69 
     70 static uint
     71 typesize(Dwarf *dwarf, ulong unit, ulong tref, char *name)
     72 {
     73 	DwarfSym ds;
     74 
     75 top:
     76 	if(dwarfseeksym(dwarf, unit, tref-unit, &ds) < 0){
     77 	cannot:
     78 		fprint(2, "warning: cannot compute size of parameter %s (%lud %lud: %r)\n",
     79 			name, unit, tref);
     80 		return 0;
     81 	}
     82 
     83 	if(ds.attrs.have.bytesize)
     84 		return ds.attrs.bytesize;
     85 
     86 	switch(ds.attrs.tag){
     87 	case TagVolatileType:
     88 	case TagRestrictType:
     89 	case TagTypedef:
     90 		if(ds.attrs.have.type != TReference)
     91 			goto cannot;
     92 		tref = ds.attrs.type;
     93 		goto top;
     94 	}
     95 
     96 	goto cannot;
     97 }
     98 
     99 static int
    100 roundup(int s, int n)
    101 {
    102 	return (s+n-1)&~(n-1);
    103 }
    104 
    105 static int
    106 dwarflenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
    107 {
    108 	int depth, bpoff;
    109 	DwarfSym ds;
    110 	Symbol s1;
    111 
    112 	if(p == nil)
    113 		return -1;
    114 
    115 	if(p->u.dwarf.unit == 0 && p->u.dwarf.uoff == 0)
    116 		return -1;
    117 
    118 	if(dwarfseeksym(fhdr->dwarf, p->u.dwarf.unit, p->u.dwarf.uoff, &ds) < 0)
    119 		return -1;
    120 
    121 	ds.depth = 1;
    122 	depth = 1;
    123 
    124 	bpoff = 8;
    125 	while(dwarfnextsym(fhdr->dwarf, &ds) == 1 && depth < ds.depth){
    126 		if(ds.attrs.tag != TagVariable){
    127 			if(ds.attrs.tag != TagFormalParameter
    128 			&& ds.attrs.tag != TagUnspecifiedParameters)
    129 				continue;
    130 			if(ds.depth != depth+1)
    131 				continue;
    132 		}
    133 		if(dwarftosym(fhdr, fhdr->dwarf, &ds, &s1, 1) < 0)
    134 			continue;
    135 		/* XXX move this out once there is another architecture */
    136 		/*
    137 		 * gcc tells us the registers where the parameters might be
    138 		 * held for an instruction or two.  use the parameter list to
    139 		 * recompute the actual stack locations.
    140 		 */
    141 		if(fhdr->mtype == M386)
    142 		if(ds.attrs.tag==TagFormalParameter || ds.attrs.tag==TagUnspecifiedParameters){
    143 			if(s1.loc.type==LOFFSET
    144 			&& strcmp(s1.loc.reg, "BP")==0
    145 			&& s1.loc.offset >= 8)
    146 				bpoff = s1.loc.offset;
    147 			else{
    148 				s1.loc.type = LOFFSET;
    149 				s1.loc.reg = "BP";
    150 				s1.loc.offset = bpoff;
    151 			}
    152 			if(ds.attrs.tag == TagFormalParameter){
    153 				if(ds.attrs.have.type)
    154 					bpoff += roundup(typesize(fhdr->dwarf, p->u.dwarf.unit, ds.attrs.type, s1.name), 4);
    155 				else
    156 					fprint(2, "warning: cannot compute size of parameter %s\n", s1.name);
    157 			}
    158 		}
    159 		if(name){
    160 			if(strcmp(ds.attrs.name, name) != 0)
    161 				continue;
    162 		}else if(l.type){
    163 			if(loccmp(&s1.loc, &l) != 0)
    164 				continue;
    165 		}else{
    166 			if(j-- > 0)
    167 				continue;
    168 		}
    169 		*s = s1;
    170 		return 0;
    171 	}
    172 	return -1;
    173 }
    174 
    175 static Loc zl;
    176 
    177 static int
    178 dwarflookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
    179 {
    180 	return dwarflenum(fhdr, p, name, 0, zl, s);
    181 }
    182 
    183 static int
    184 dwarfindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
    185 {
    186 	return dwarflenum(fhdr, p, nil, i, zl, s);
    187 }
    188 
    189 static int
    190 dwarffindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
    191 {
    192 	return dwarflenum(fhdr, p, nil, 0, l, s);
    193 }
    194 
    195 static void
    196 dwarfsyminit(Fhdr *fp)
    197 {
    198 	Dwarf *d;
    199 	DwarfSym s;
    200 	Symbol sym;
    201 
    202 	d = fp->dwarf;
    203 	if(dwarfenum(d, &s) < 0)
    204 		return;
    205 
    206 	while(dwarfnextsymat(d, &s, 0) == 1)
    207 	while(dwarfnextsymat(d, &s, 1) == 1){
    208 		if(s.attrs.name == nil)
    209 			continue;
    210 		switch(s.attrs.tag){
    211 		case TagSubprogram:
    212 		case TagVariable:
    213 			if(dwarftosym(fp, d, &s, &sym, 0) < 0)
    214 				continue;
    215 			_addsym(fp, &sym);
    216 		}
    217 	}
    218 }
    219 
    220 static char*
    221 regname(Dwarf *d, int i)
    222 {
    223 	if(i < 0 || i >= d->nreg)
    224 		return nil;
    225 	return d->reg[i];
    226 }
    227 
    228 static int
    229 dwarftosym(Fhdr *fp, Dwarf *d, DwarfSym *ds, Symbol *s, int infn)
    230 {
    231 	DwarfBuf buf;
    232 	DwarfBlock b;
    233 
    234 	memset(s, 0, sizeof *s);
    235 	s->u.dwarf.uoff = ds->uoff;
    236 	s->u.dwarf.unit = ds->unit;
    237 	switch(ds->attrs.tag){
    238 	default:
    239 		return -1;
    240 	case TagUnspecifiedParameters:
    241 		ds->attrs.name = "...";
    242 		s->type = 'p';
    243 		goto sym;
    244 	case TagFormalParameter:
    245 		s->type = 'p';
    246 		s->class = CPARAM;
    247 		goto sym;
    248 	case TagSubprogram:
    249 		s->type = 't';
    250 		s->class = CTEXT;
    251 		goto sym;
    252 	case TagVariable:
    253 		if(infn){
    254 			s->type = 'a';
    255 			s->class = CAUTO;
    256 		}else{
    257 			s->type = 'd';
    258 			s->class = CDATA;
    259 		}
    260 	sym:
    261 		s->name = ds->attrs.name;
    262 		if(ds->attrs.have.lowpc){
    263 			s->loc.type = LADDR;
    264 			s->loc.addr = ds->attrs.lowpc;
    265 			if(ds->attrs.have.highpc){
    266 				s->hiloc.type = LADDR;
    267 				s->hiloc.addr = ds->attrs.highpc;
    268 			}
    269 		}else if(ds->attrs.have.location == TConstant){
    270 			s->loc.type = LADDR;
    271 			s->loc.addr = ds->attrs.location.c;
    272 		}else if(ds->attrs.have.location == TBlock){
    273 			b = ds->attrs.location.b;
    274 			if(b.len == 0)
    275 				return -1;
    276 			buf.p = b.data+1;
    277 			buf.ep = b.data+b.len;
    278 			buf.d = d;
    279 			buf.addrsize = 0;
    280 			if(b.data[0]==OpAddr){
    281 				if(b.len != 5)
    282 					return -1;
    283 				s->loc.type = LADDR;
    284 				s->loc.addr = dwarfgetaddr(&buf);
    285 			}else if(OpReg0 <= b.data[0] && b.data[0] < OpReg0+0x20){
    286 				if(b.len != 1 || (s->loc.reg = regname(d, b.data[0]-OpReg0)) == nil)
    287 					return -1;
    288 				s->loc.type = LREG;
    289 			}else if(OpBreg0 <= b.data[0] && b.data[0] < OpBreg0+0x20){
    290 				s->loc.type = LOFFSET;
    291 				s->loc.reg = regname(d, b.data[0]-0x70);
    292 				s->loc.offset = dwarfget128s(&buf);
    293 				if(s->loc.reg == nil)
    294 					return -1;
    295 			}else if(b.data[0] == OpRegx){
    296 				s->loc.type = LREG;
    297 				s->loc.reg = regname(d, dwarfget128(&buf));
    298 				if(s->loc.reg == nil)
    299 					return -1;
    300 			}else if(b.data[0] == OpFbreg){
    301 				s->loc.type = LOFFSET;
    302 				s->loc.reg = mach->fp;
    303 				s->loc.offset = dwarfget128s(&buf);
    304 			}else if(b.data[0] == OpBregx){
    305 				s->loc.type = LOFFSET;
    306 				s->loc.reg = regname(d, dwarfget128(&buf));
    307 				s->loc.offset = dwarfget128s(&buf);
    308 				if(s->loc.reg == nil)
    309 					return -1;
    310 			}else
    311 				s->loc.type = LNONE;
    312 			if(buf.p != buf.ep)
    313 				s->loc.type = LNONE;
    314 		}else
    315 			return -1;
    316 		if(ds->attrs.isexternal)
    317 			s->type += 'A' - 'a';
    318 		if(ds->attrs.tag==TagVariable && s->loc.type==LADDR && s->loc.addr>=fp->dataddr+fp->datsz)
    319 			s->type += 'b' - 'd';
    320 		s->fhdr = fp;
    321 		return 0;
    322 	}
    323 }
    324 
    325 static int
    326 dwarfeval(Dwarf *d, Map *map, Regs *regs, ulong cfa, int rno, DwarfExpr e, u64int *u)
    327 {
    328 	int i;
    329 	u32int u4;
    330 	u64int uu;
    331 
    332 	switch(e.type){
    333 	case RuleUndef:
    334 		*u = 0;
    335 		return 0;
    336 	case RuleSame:
    337 		if(rno == -1){
    338 			werrstr("pc cannot be `same'");
    339 			return -1;
    340 		}
    341 		return rget(regs, regname(d, rno), u);
    342 	case RuleRegister:
    343 		if((i = windindex(regname(d, e.reg))) < 0)
    344 			return -1;
    345 		return rget(regs, regname(d, i), u);
    346 	case RuleCfaOffset:
    347 		if(cfa == 0){
    348 			werrstr("unknown cfa");
    349 			return -1;
    350 		}
    351 		if(get4(map, cfa + e.offset, &u4) < 0)
    352 			return -1;
    353 		*u = u4;
    354 		return 0;
    355 	case RuleRegOff:
    356 		if(rget(regs, regname(d, e.reg), &uu) < 0)
    357 			return -1;
    358 		if(get4(map, uu+e.offset, &u4) < 0)
    359 			return -1;
    360 		*u = u4;
    361 		return 0;
    362 	case RuleLocation:
    363 		werrstr("not evaluating dwarf loc expressions");
    364 		return -1;
    365 	}
    366 	werrstr("not reached in dwarfeval");
    367 	return -1;
    368 }
    369 
    370 #if 0
    371 static int
    372 dwarfexprfmt(Fmt *fmt)
    373 {
    374 	DwarfExpr *e;
    375 
    376 	if((e = va_arg(fmt->args, DwarfExpr*)) == nil)
    377 		return fmtstrcpy(fmt, "<nil>");
    378 
    379 	switch(e->type){
    380 	case RuleUndef:
    381 		return fmtstrcpy(fmt, "undef");
    382 	case RuleSame:
    383 		return fmtstrcpy(fmt, "same");
    384 	case RuleCfaOffset:
    385 		return fmtprint(fmt, "%ld(cfa)", e->offset);
    386 	case RuleRegister:
    387 		return fmtprint(fmt, "r%ld", e->reg);
    388 	case RuleRegOff:
    389 		return fmtprint(fmt, "%ld(r%ld)", e->offset, e->reg);
    390 	case RuleLocation:
    391 		return fmtprint(fmt, "l.%.*H", e->loc.len, e->loc.data);
    392 	default:
    393 		return fmtprint(fmt, "?%d", e->type);
    394 	}
    395 }
    396 #endif
    397 
    398 static int
    399 _dwarfunwind(Fhdr *fhdr, Map *map, Regs *regs, u64int *next, Symbol *sym)
    400 {
    401 	char *name;
    402 	int i, j;
    403 	u64int cfa, pc, u;
    404 	Dwarf *d;
    405 	DwarfExpr *e, epc, ecfa;
    406 
    407 
    408 	/*
    409 	 * Use dwarfunwind to tell us what to do.
    410 	 */
    411 	d = fhdr->dwarf;
    412 	e = malloc(d->nreg*sizeof(e[0]));
    413 	if(e == nil)
    414 		return -1;
    415 	if(rget(regs, mach->pc, &pc) < 0)
    416 		goto err;
    417 	if(dwarfunwind(d, pc, &ecfa, &epc, e, d->nreg) < 0)
    418 		goto err;
    419 
    420 	/*
    421 	 * Compute CFA.
    422 	 */
    423 	switch(ecfa.type){
    424 	default:
    425 		werrstr("invalid call-frame-address in _dwarfunwind");
    426 		goto err;
    427 	case RuleRegister:
    428 		ecfa.offset = 0;
    429 	case RuleRegOff:
    430 		if((name = regname(d, ecfa.reg)) == nil){
    431 			werrstr("invalid call-frame-address register %d", (int)ecfa.reg);
    432 			goto err;
    433 		}
    434 		if(rget(regs, name, &cfa) < 0){
    435 			werrstr("fetching %s for call-frame-address: %r", name);
    436 			goto err;
    437 		}
    438 		cfa += ecfa.offset;
    439 	}
    440 
    441 	/*
    442 	 * Compute registers.
    443 	 */
    444 	for(i=0; i<d->nreg; i++){
    445 		j = windindex(d->reg[i]);
    446 		if(j == -1)
    447 			continue;
    448 		if(dwarfeval(d, map, regs, cfa, i, e[i], &u) < 0)
    449 			u = ~(ulong)0;
    450 		next[j] = u;
    451 	}
    452 
    453 	/*
    454 	 * Compute caller pc
    455 	 */
    456 	if(dwarfeval(d, map, regs, cfa, -1, epc, &u) < 0){
    457 		werrstr("computing caller %s: %r", mach->pc);
    458 		goto err;
    459 	}
    460 	next[windindex(mach->pc)] = u;
    461 	free(e);
    462 	return 0;
    463 
    464 err:
    465 	free(e);
    466 	return -1;
    467 }