forsyth20121205-174063a80cc13 years agoHistory
1375 lines · 26.2 KB · C
RawDownload
#include <lib9.h>#include <bio.h>#include "mach.h" #define	HUGEINT	0x7fffffff#define	NNAME	20		/* a relic of the past */ typedef	struct txtsym Txtsym;typedef	struct file File;typedef	struct hist Hist; struct txtsym {				/* Text Symbol table */	int 	n;			/* number of local vars */	Sym	**locals;		/* array of ptrs to autos */	Sym	*sym;			/* function symbol entry */}; struct hist {				/* Stack of include files & #line directives */	char	*name;			/* Assumes names Null terminated in file */	long	line;			/* line # where it was included */	long	offset;			/* line # of #line directive */}; struct file {				/* Per input file header to history stack */	uvlong	addr;			/* address of first text sym */	/* union { */		Txtsym	*txt;		/* first text symbol */		Sym	*sym;		/* only during initilization */	/* }; */	int	n;			/* size of history stack */	Hist	*hist;			/* history stack */}; static	int	debug = 0; static	Sym	**autos;		/* Base of auto variables */static	File	*files;			/* Base of file arena */static	int	fpmax;			/* largest file path index */static	Sym	**fnames;		/* file names path component table */static	Sym	**globals;		/* globals by addr table */static	Hist	*hist;			/* base of history stack */static	int	isbuilt;		/* internal table init flag */static	long	nauto;			/* number of automatics */static	long	nfiles;			/* number of files */static	long	nglob;			/* number of globals */static	long	nhist;			/* number of history stack entries */static	long	nsym;			/* number of symbols */static	int	ntxt;			/* number of text symbols */static	uchar	*pcline;		/* start of pc-line state table */static	uchar 	*pclineend;		/* end of pc-line table */static	uchar	*spoff;			/* start of pc-sp state table */static	uchar	*spoffend;		/* end of pc-sp offset table */static	Sym	*symbols;		/* symbol table */static	Txtsym	*txt;			/* Base of text symbol table */static	uvlong	txtstart;		/* start of text segment */static	uvlong	txtend;			/* end of text segment */ static void	cleansyms(void);static long	decodename(Biobuf*, Sym*);static short	*encfname(char*);static int 	fline(char*, int, long, Hist*, Hist**);static void	fillsym(Sym*, Symbol*);static int	findglobal(char*, Symbol*);static int	findlocvar(Symbol*, char *, Symbol*);static int	findtext(char*, Symbol*);static int	hcomp(Hist*, short*);static int	hline(File*, short*, long*);static void	printhist(char*, Hist*, int);static int	buildtbls(void);static int	symcomp(void*, void*);static int	symerrmsg(int, char*);static int	txtcomp(void*, void*);static int	filecomp(void*, void*); /* *	initialize the symbol tables */intsyminit(int fd, Fhdr *fp){	Sym *p;	long i, l, size;	vlong vl;	Biobuf b;	int svalsz; 	if(fp->symsz == 0)		return 0;	if(fp->type == FNONE)		return 0; 	cleansyms();	textseg(fp->txtaddr, fp);		/* minimum symbol record size = 4+1+2 bytes */	symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));	if(symbols == 0) {		werrstr("can't malloc %ld bytes", fp->symsz);		return -1;	}	Binit(&b, fd, OREAD);	Bseek(&b, fp->symoff, 0);	nsym = 0;	size = 0;	for(p = symbols; size < fp->symsz; p++, nsym++) {		if(fp->_magic && (fp->magic & HDR_MAGIC)){			svalsz = 8;			if(Bread(&b, &vl, 8) != 8)				return symerrmsg(8, "symbol");			p->value = beswav(vl);		}		else{			svalsz = 4;			if(Bread(&b, &l, 4) != 4)				return symerrmsg(4, "symbol");			p->value = (u32int)beswal(l);		}		if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))			return symerrmsg(sizeof(p->value), "symbol"); 		i = decodename(&b, p);		if(i < 0)			return -1;		size += i+svalsz+sizeof(p->type); 		/* count global & auto vars, text symbols, and file names */		switch (p->type) {		case 'l':		case 'L':		case 't':		case 'T':			ntxt++;			break;		case 'd':		case 'D':		case 'b':		case 'B':			nglob++;			break;		case 'f':			if(strcmp(p->name, ".frame") == 0) {				p->type = 'm';				nauto++;			}			else if(p->value > fpmax)				fpmax = p->value;	/* highest path index */			break;		case 'a':		case 'p':		case 'm':			nauto++;			break;		case 'z':			if(p->value == 1) {		/* one extra per file */				nhist++;				nfiles++;			}			nhist++;			break;		default:			break;		}	}	if (debug)		print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fpmax);	if (fp->sppcsz) {			/* pc-sp offset table */		spoff = (uchar *)malloc(fp->sppcsz);		if(spoff == 0) {			werrstr("can't malloc %ld bytes", fp->sppcsz);			return -1;		}		Bseek(&b, fp->sppcoff, 0);		if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){			spoff = 0;			return symerrmsg(fp->sppcsz, "sp-pc");		}		spoffend = spoff+fp->sppcsz;	}	if (fp->lnpcsz) {			/* pc-line number table */		pcline = (uchar *)malloc(fp->lnpcsz);		if(pcline == 0) {			werrstr("can't malloc %ld bytes", fp->lnpcsz);			return -1;		}		Bseek(&b, fp->lnpcoff, 0);		if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){			pcline = 0;			return symerrmsg(fp->lnpcsz, "pc-line");		}		pclineend = pcline+fp->lnpcsz;	}	if(fp->type == FARM)	/* thumb pc table */		thumbpctab(&b, fp);	return nsym;} static intsymerrmsg(int n, char *table){	werrstr("can't read %d bytes of %s table", n, table);	return -1;} static longdecodename(Biobuf *bp, Sym *p){	char *cp;	int c1, c2;	long n;	vlong o; 	if((p->type & 0x80) == 0) {		/* old-style, fixed length names */		p->name = malloc(NNAME);		if(p->name == 0) {			werrstr("can't malloc %d bytes", NNAME);			return -1;		}		if(Bread(bp, p->name, NNAME) != NNAME)			return symerrmsg(NNAME, "symbol");		Bseek(bp, 3, 1);		return NNAME+3;	} 	p->type &= ~0x80;	if(p->type == 'z' || p->type == 'Z') {		o = Bseek(bp, 0, 1);		if(Bgetc(bp) < 0) {			werrstr("can't read symbol name");			return -1;		}		for(;;) {			c1 = Bgetc(bp);			c2 = Bgetc(bp);			if(c1 < 0 || c2 < 0) {				werrstr("can't read symbol name");				return -1;			}			if(c1 == 0 && c2 == 0)				break;		}		n = Bseek(bp, 0, 1)-o;		p->name = malloc(n);		if(p->name == 0) {			werrstr("can't malloc %ld bytes", n);			return -1;		}		Bseek(bp, -n, 1);		if(Bread(bp, p->name, n) != n) {			werrstr("can't read %ld bytes of symbol name", n);			return -1;		}	} else {		cp = Brdline(bp, '\0');		if(cp == 0) {			werrstr("can't read symbol name");			return -1;		}		n = Blinelen(bp);		p->name = malloc(n);		if(p->name == 0) {			werrstr("can't malloc %ld bytes", n);			return -1;		}		strcpy(p->name, cp);	}	return n;} /* *	free any previously loaded symbol tables */static voidcleansyms(void){	if(globals)		free(globals);	globals = 0;	nglob = 0;	if(txt)		free(txt);	txt = 0;	ntxt = 0;	if(fnames)		free(fnames);	fnames = 0;	fpmax = 0; 	if(files)		free(files);	files = 0;	nfiles = 0;	if(hist)		free(hist);	hist = 0;	nhist = 0;	if(autos)		free(autos);	autos = 0;	nauto = 0;	isbuilt = 0;	if(symbols)		free(symbols);	symbols = 0;	nsym = 0;	if(spoff)		free(spoff);	spoff = 0;	if(pcline)		free(pcline);	pcline = 0;} /* *	delimit the text segment */voidtextseg(uvlong base, Fhdr *fp){	txtstart = base;	txtend = base+fp->txtsz;} /* *	symbase: return base and size of raw symbol table *		(special hack for high access rate operations) */Sym *symbase(long *n){	*n = nsym;	return symbols;} /* *	Get the ith symbol table entry */Sym *getsym(int index){	if(index >= 0 && index < nsym)		return &symbols[index];	return 0;} /* *	initialize internal symbol tables */static intbuildtbls(void){	long i;	int j, nh, ng, nt;	File *f;	Txtsym *tp;	Hist *hp;	Sym *p, **ap; 	if(isbuilt)		return 1;	isbuilt = 1;			/* allocate the tables */	if(nglob) {		globals = malloc(nglob*sizeof(*globals));		if(!globals) {			werrstr("can't malloc global symbol table");			return 0;		}	}	if(ntxt) {		txt = malloc(ntxt*sizeof(*txt));		if (!txt) {			werrstr("can't malloc text symbol table");			return 0;		}	}	fnames = malloc((fpmax+1)*sizeof(*fnames));	if (!fnames) {		werrstr("can't malloc file name table");		return 0;	}	memset(fnames, 0, (fpmax+1)*sizeof(*fnames));	files = malloc(nfiles*sizeof(*files));	if(!files) {		werrstr("can't malloc file table");		return 0;	}	hist = malloc(nhist*sizeof(Hist));	if(hist == 0) {		werrstr("can't malloc history stack");		return 0;	}	autos = malloc(nauto*sizeof(Sym*));	if(autos == 0) {		werrstr("can't malloc auto symbol table");		return 0;	}		/* load the tables */	ng = nt = nh = 0;	f = 0;	tp = 0;	i = nsym;	hp = hist;	ap = autos;	for(p = symbols; i-- > 0; p++) {		switch(p->type) {		case 'D':		case 'd':		case 'B':		case 'b':			if(debug)				print("Global: %s %llux\n", p->name, p->value);			globals[ng++] = p;			break;		case 'z':			if(p->value == 1) {		/* New file */				if(f) {					f->n = nh;					f->hist[nh].name = 0;	/* one extra */					hp += nh+1;					f++;				}				else					f = files;				f->hist = hp;				f->sym = 0;				f->addr = 0;				nh = 0;			}				/* alloc one slot extra as terminator */			f->hist[nh].name = p->name;			f->hist[nh].line = p->value;			f->hist[nh].offset = 0;			if(debug)				printhist("-> ", &f->hist[nh], 1);			nh++;			break;		case 'Z':			if(f && nh > 0)				f->hist[nh-1].offset = p->value;			break;		case 'T':		case 't':	/* Text: terminate history if first in file */		case 'L':		case 'l':			tp = &txt[nt++];			tp->n = 0;			tp->sym = p;			tp->locals = ap;			if(debug)				print("TEXT: %s at %llux\n", p->name, p->value);			if(f && !f->sym) {			/* first  */				f->sym = p;				f->addr = p->value;			}			break;		case 'a':		case 'p':		case 'm':		/* Local Vars */			if(!tp)				print("Warning: Free floating local var: %s\n",					p->name);			else {				if(debug)					print("Local: %s %llux\n", p->name, p->value);				tp->locals[tp->n] = p;				tp->n++;				ap++;			}			break;		case 'f':		/* File names */			if(debug)				print("Fname: %s\n", p->name);			fnames[p->value] = p;			break;		default:			break;		}	}		/* sort global and text tables into ascending address order */	qsort(globals, nglob, sizeof(Sym*), symcomp);	qsort(txt, ntxt, sizeof(Txtsym), txtcomp);	qsort(files, nfiles, sizeof(File), filecomp);	tp = txt;	for(i = 0, f = files; i < nfiles; i++, f++) {		for(j = 0; j < ntxt; j++) {			if(f->sym == tp->sym) {				if(debug) {					print("LINK: %s to at %llux", f->sym->name, f->addr);					printhist("... ", f->hist, 1);				}				f->txt = tp++;				break;			}			if(++tp >= txt+ntxt)	/* wrap around */				tp = txt;		}	}	return 1;} /*

Lines 1–500 of 1375.