plan9port

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

symstabs.c (8399B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <mach.h>
      4 #include "stabs.h"
      5 
      6 static int
      7 strcmpcolon(char *a, char *bcolon)
      8 {
      9 	int i, len;
     10 	char *p;
     11 
     12 	p = strchr(bcolon, ':');
     13 	if(p == nil)
     14 		return strcmp(a, bcolon);
     15 	len = p-bcolon;
     16 	i = strncmp(a, bcolon, len);
     17 	if(i)
     18 		return i;
     19 	if(a[len] == 0)
     20 		return 0;
     21 	return 1;
     22 }
     23 
     24 static int
     25 stabcvtsym(StabSym *stab, Symbol *sym, char *dir, char *file, int i)
     26 {
     27 	char *p;
     28 
     29 	/*
     30 	 * Zero out the : to avoid allocating a new name string.
     31 	 * The type info can be found by looking past the NUL.
     32 	 * This is going to get us in trouble...
     33 	 */
     34 	if((p = strchr(stab->name, ':')) != nil)
     35 		*p++ = 0;
     36 	else
     37 		p = stab->name+strlen(stab->name)+1;
     38 
     39 	sym->name = stab->name;
     40 	sym->u.stabs.dir = dir;
     41 	sym->u.stabs.file = file;
     42 	sym->u.stabs.i = i;
     43 	switch(stab->type){
     44 	default:
     45 		return -1;
     46 	case N_FUN:
     47 		sym->class = CTEXT;
     48 		switch(*p){
     49 		default:
     50 			return -1;
     51 		case 'F':	/* global function */
     52 			sym->type = 'T';
     53 			break;
     54 		case 'Q':	/* static procedure */
     55 		case 'f':	/* static function */
     56 		case 'I':	/* nested procedure */
     57 		case 'J':	/* nested function */
     58 			sym->type = 't';
     59 			break;
     60 		}
     61 		sym->loc.type = LADDR;
     62 		sym->loc.addr = stab->value;
     63 		break;
     64 	case N_GSYM:
     65 	case N_PSYM:
     66 	case N_LSYM:
     67 	case N_LCSYM:
     68 		sym->class = CDATA;
     69 		sym->loc.type = LADDR;
     70 		sym->loc.addr = stab->value;
     71 		switch(*p){
     72 		default:
     73 			return -1;
     74 		case 'S':	/* file-scope static variable */
     75 			sym->type = 'd';
     76 			break;
     77 		case 'G':	/* global variable */
     78 			sym->type = 'D';
     79 			sym->loc.type = LNONE;
     80 			break;
     81 		case 'r':	/* register variable */
     82 			sym->class = CAUTO;
     83 			sym->type = 'a';
     84 			sym->loc.type = LREG;
     85 			sym->loc.reg = "XXX";
     86 			break;
     87 		case 's':	/* local variable */
     88 			sym->class = CAUTO;
     89 			sym->type = 'a';
     90 			sym->loc.type = LOFFSET;
     91 			sym->loc.offset = stab->value;
     92 			sym->loc.reg = "XXX";
     93 			break;
     94 		case 'a':	/* by reference */
     95 		case 'D':	/* f.p. parameter */
     96 		case 'i':	/* register parameter */
     97 		case 'p':	/* "normal" parameter */
     98 		case 'P':	/* register parameter */
     99 		case 'v':	/* by reference */
    100 		case 'X':	/* function return variable */
    101 			sym->class = CPARAM;
    102 			sym->type = 'p';
    103 			if(*p == 'i'){
    104 				sym->loc.type = LREG;
    105 				sym->loc.reg = "XXX";
    106 			}else{
    107 				sym->loc.type = LOFFSET;
    108 				sym->loc.offset = stab->value;
    109 				sym->loc.reg = "XXX";
    110 			}
    111 			break;
    112 		}
    113 		break;
    114 	}
    115 	return 0;
    116 }
    117 
    118 static int
    119 stabssyminit(Fhdr *fp)
    120 {
    121 	int i;
    122 	char *dir, *file;
    123 	Stab *stabs;
    124 	StabSym sym, lastfun;
    125 	Symbol s, *fun;
    126 	char **inc, **xinc;
    127 	int ninc, minc;
    128 	int locals, autos, params;
    129 
    130 	stabs = &fp->stabs;
    131 	if(stabs == nil){
    132 		werrstr("no stabs info");
    133 		return -1;
    134 	}
    135 
    136 	dir = nil;
    137 	file = nil;
    138 	inc = nil;
    139 	fun = nil;
    140 	ninc = 0;
    141 	minc = 0;
    142 	locals = 0;
    143 	params = 0;
    144 	autos = 0;
    145 	memset(&lastfun, 0, sizeof lastfun);
    146 	for(i=0; stabsym(stabs, i, &sym)>=0; i++){
    147 		switch(sym.type){
    148 		case N_SO:
    149 			if(sym.name == nil || *sym.name == 0){
    150 				file = nil;
    151 				break;
    152 			}
    153 			if(sym.name[strlen(sym.name)-1] == '/')
    154 				dir = sym.name;
    155 			else
    156 				file = sym.name;
    157 			break;
    158 		case N_BINCL:
    159 			if(ninc >= minc){
    160 				xinc = realloc(inc, (ninc+32)*sizeof(inc[0]));
    161 				if(xinc){
    162 					memset(xinc+ninc, 0, 32*sizeof(inc[0]));
    163 					inc = xinc;
    164 				}
    165 				ninc += 32;
    166 			}
    167 			if(ninc < minc)
    168 				inc[ninc] = sym.name;
    169 			ninc++;
    170 			break;
    171 		case N_EINCL:
    172 			if(ninc > 0)
    173 				ninc--;
    174 			break;
    175 		case N_EXCL:
    176 			/* condensed include - same effect as previous BINCL/EINCL pair */
    177 			break;
    178 		case N_GSYM:	/* global variable */
    179 			/* only includes type, so useless for now */
    180 			break;
    181 		case N_FUN:
    182 			if(sym.name == nil){
    183 				/* marks end of function */
    184 				if(fun){
    185 					fun->hiloc.type = LADDR;
    186 					fun->hiloc.addr = fun->loc.addr + sym.value;
    187 				}
    188 				break;
    189 			}
    190 			if(fun && lastfun.value==sym.value && lastfun.name==sym.name){
    191 				fun->u.stabs.locals = i;
    192 				break;
    193 			}
    194 			/* create new symbol, add it */
    195 			lastfun = sym;
    196 			fun = nil;
    197 			if(stabcvtsym(&sym, &s, dir, file, i) < 0)
    198 				continue;
    199 			if((fun = _addsym(fp, &s)) == nil)
    200 				goto err;
    201 			locals = 0;
    202 			params = 0;
    203 			autos = 0;
    204 			break;
    205 		case N_PSYM:
    206 		case N_LSYM:
    207 		case N_LCSYM:
    208 			if(fun){
    209 				if(fun->u.stabs.frameptr == -1){
    210 					/*
    211 					 * Try to distinguish functions with a real frame pointer
    212 				 	 * from functions with a virtual frame pointer, based on
    213 					 * whether the first parameter is in the right location and
    214 					 * whether the autos have negative offsets.
    215 					 *
    216 					 * This heuristic works most of the time.  On the 386, we
    217 					 * cannot distinguish between a v. function with no autos
    218 					 * but a frame of size 4 and a f.p. function with no autos and
    219 					 * no frame.   Anything else we'll get right.
    220 					 *
    221 					 * Another way to go about this would be to have
    222 					 * mach-specific functions to inspect the function
    223 					 * prologues when we're not sure.  What we have
    224 					 * already should be enough, though.
    225 					 */
    226 					if(params==0 && sym.type == N_PSYM){
    227 						if(sym.value != 8 && sym.value >= 4){
    228 							/* XXX 386 specific, but let's find another system before generalizing */
    229 							fun->u.stabs.frameptr = 0;
    230 							fun->u.stabs.framesize = sym.value - 4;
    231 						}
    232 					}else if(sym.type == N_LSYM){
    233 						if((int32)sym.value >= 0){
    234 							fun->u.stabs.frameptr = 0;
    235 							if(params)
    236 								fun->u.stabs.framesize = 8 - 4;
    237 						}else
    238 							fun->u.stabs.frameptr = 1;
    239 					}
    240 				}
    241 				if(sym.type == N_PSYM)
    242 					params++;
    243 				if(sym.type == N_LSYM)
    244 					autos++;
    245 			}
    246 			break;
    247 
    248 		case N_STSYM:	/* static file-scope variable */
    249 			/* create new symbol, add it */
    250 			if(stabcvtsym(&sym, &s, dir, file, i) < 0)
    251 				continue;
    252 			if(_addsym(fp, &s) == nil)
    253 				goto err;
    254 			break;
    255 		}
    256 	}
    257 	USED(locals);
    258 	free(inc);
    259 	return 0;
    260 
    261 err:
    262 	free(inc);
    263 	return -1;
    264 }
    265 
    266 static int
    267 stabspc2file(Fhdr *fhdr, u64int pc, char *buf, uint nbuf, ulong *pline)
    268 {
    269 	int i;
    270 	Symbol *s;
    271 	StabSym ss;
    272 	ulong line, basepc;
    273 	Loc l;
    274 
    275 	l.type = LADDR;
    276 	l.addr = pc;
    277 	if((s = ffindsym(fhdr, l, CTEXT)) == nil
    278 	|| stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
    279 		return -1;
    280 
    281 	line = ss.desc;
    282 	basepc = ss.value;
    283 	for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
    284 		if(ss.type == N_FUN && ss.name == nil)
    285 			break;
    286 		if(ss.type == N_SLINE){
    287 			if(basepc+ss.value > pc)
    288 				break;
    289 			else
    290 				line = ss.desc;
    291 		}
    292 	}
    293 	*pline = line;
    294 	if(s->u.stabs.dir)
    295 		snprint(buf, nbuf, "%s%s", s->u.stabs.dir, s->u.stabs.file);
    296 	else
    297 		snprint(buf, nbuf, "%s", s->u.stabs.file);
    298 	return 0;
    299 }
    300 
    301 static int
    302 stabsline2pc(Fhdr *fhdr, u64int startpc, ulong line, u64int *pc)
    303 {
    304 	int i, trigger;
    305 	Symbol *s;
    306 	StabSym ss;
    307 	ulong basepc;
    308 	Loc l;
    309 
    310 	l.type = LADDR;
    311 	l.addr = startpc;
    312 	if((s = ffindsym(fhdr, l, CTEXT)) == nil
    313 	|| stabsym(&fhdr->stabs, s->u.stabs.i, &ss) < 0)
    314 		return -1;
    315 
    316 	trigger = 0;
    317 	line = ss.desc;
    318 	basepc = ss.value;
    319 	for(i=s->u.stabs.i+1; stabsym(&fhdr->stabs, i, &ss) >= 0; i++){
    320 		if(ss.type == N_FUN)
    321 			basepc = ss.value;
    322 		if(ss.type == N_SLINE){
    323 			if(basepc+ss.value >= startpc)
    324 				trigger = 1;
    325 			if(trigger && ss.desc >= line){
    326 				*pc = basepc+ss.value;
    327 				return 0;
    328 			}
    329 		}
    330 	}
    331 	return -1;
    332 }
    333 
    334 static int
    335 stabslenum(Fhdr *fhdr, Symbol *p, char *name, uint j, Loc l, Symbol *s)
    336 {
    337 	int i;
    338 	StabSym ss;
    339 
    340 	for(i=p->u.stabs.locals; stabsym(&fhdr->stabs, i, &ss)>=0; i++){
    341 		if(ss.type == N_FUN && ss.name == nil)
    342 			break;
    343 		switch(ss.type){
    344 		case N_PSYM:
    345 		case N_LSYM:
    346 		case N_LCSYM:
    347 			if(name){
    348 				if(strcmpcolon(name, ss.name) != 0)
    349 					break;
    350 			}else if(l.type){
    351 				/* wait for now */
    352 			}else{
    353 				if(j-- > 0)
    354 					break;
    355 			}
    356 			if(stabcvtsym(&ss, s, p->u.stabs.dir, p->u.stabs.file, i) < 0)
    357 				return -1;
    358 			if(s->loc.type == LOFFSET){
    359 				if(p->u.stabs.frameptr == 0)
    360 					s->loc.reg = mach->sp;
    361 				else
    362 					s->loc.reg = mach->fp;
    363 			}
    364 			if(l.type && loccmp(&l, &s->loc) != 0)
    365 				break;
    366 			return 0;
    367 		}
    368 	}
    369 	return -1;
    370 }
    371 
    372 static Loc zl;
    373 
    374 static int
    375 stabslookuplsym(Fhdr *fhdr, Symbol *p, char *name, Symbol *s)
    376 {
    377 	return stabslenum(fhdr, p, name, 0, zl, s);
    378 }
    379 
    380 static int
    381 stabsindexlsym(Fhdr *fhdr, Symbol *p, uint i, Symbol *s)
    382 {
    383 	return stabslenum(fhdr, p, nil, i, zl, s);
    384 }
    385 
    386 static int
    387 stabsfindlsym(Fhdr *fhdr, Symbol *p, Loc l, Symbol *s)
    388 {
    389 	return stabslenum(fhdr, p, nil, 0, l, s);
    390 }
    391 
    392 int
    393 symstabs(Fhdr *fp)
    394 {
    395 	if(stabssyminit(fp) < 0)
    396 		return -1;
    397 	fp->pc2file = stabspc2file;
    398 	fp->line2pc = stabsline2pc;
    399 	fp->lookuplsym = stabslookuplsym;
    400 	fp->indexlsym = stabsindexlsym;
    401 	fp->findlsym = stabsfindlsym;
    402 	return 0;
    403 }