xref: /inferno-os/utils/libmach/sym.c (revision 45a20ab721a513710138340faff3d59a31c3e01e)
174a4d8c2SCharles.Forsyth #include <lib9.h>
274a4d8c2SCharles.Forsyth #include <bio.h>
374a4d8c2SCharles.Forsyth #include "mach.h"
474a4d8c2SCharles.Forsyth 
574a4d8c2SCharles.Forsyth #define	HUGEINT	0x7fffffff
674a4d8c2SCharles.Forsyth #define	NNAME	20		/* a relic of the past */
774a4d8c2SCharles.Forsyth 
874a4d8c2SCharles.Forsyth typedef	struct txtsym Txtsym;
974a4d8c2SCharles.Forsyth typedef	struct file File;
1074a4d8c2SCharles.Forsyth typedef	struct hist Hist;
1174a4d8c2SCharles.Forsyth 
1274a4d8c2SCharles.Forsyth struct txtsym {				/* Text Symbol table */
1374a4d8c2SCharles.Forsyth 	int 	n;			/* number of local vars */
1474a4d8c2SCharles.Forsyth 	Sym	**locals;		/* array of ptrs to autos */
1574a4d8c2SCharles.Forsyth 	Sym	*sym;			/* function symbol entry */
1674a4d8c2SCharles.Forsyth };
1774a4d8c2SCharles.Forsyth 
1874a4d8c2SCharles.Forsyth struct hist {				/* Stack of include files & #line directives */
1974a4d8c2SCharles.Forsyth 	char	*name;			/* Assumes names Null terminated in file */
2074a4d8c2SCharles.Forsyth 	long	line;			/* line # where it was included */
2174a4d8c2SCharles.Forsyth 	long	offset;			/* line # of #line directive */
2274a4d8c2SCharles.Forsyth };
2374a4d8c2SCharles.Forsyth 
2474a4d8c2SCharles.Forsyth struct file {				/* Per input file header to history stack */
25*d67b7dadSforsyth 	uvlong	addr;			/* address of first text sym */
26*d67b7dadSforsyth 	/* union { */
27*d67b7dadSforsyth 		Txtsym	*txt;		/* first text symbol */
28*d67b7dadSforsyth 		Sym	*sym;		/* only during initilization */
29*d67b7dadSforsyth 	/* }; */
3074a4d8c2SCharles.Forsyth 	int	n;			/* size of history stack */
3174a4d8c2SCharles.Forsyth 	Hist	*hist;			/* history stack */
3274a4d8c2SCharles.Forsyth };
3374a4d8c2SCharles.Forsyth 
3474a4d8c2SCharles.Forsyth static	int	debug = 0;
3574a4d8c2SCharles.Forsyth 
3674a4d8c2SCharles.Forsyth static	Sym	**autos;		/* Base of auto variables */
3774a4d8c2SCharles.Forsyth static	File	*files;			/* Base of file arena */
38fb67f84dSCharles.Forsyth static	int	fpmax;			/* largest file path index */
3974a4d8c2SCharles.Forsyth static	Sym	**fnames;		/* file names path component table */
4074a4d8c2SCharles.Forsyth static	Sym	**globals;		/* globals by addr table */
4174a4d8c2SCharles.Forsyth static	Hist	*hist;			/* base of history stack */
4274a4d8c2SCharles.Forsyth static	int	isbuilt;		/* internal table init flag */
4374a4d8c2SCharles.Forsyth static	long	nauto;			/* number of automatics */
4474a4d8c2SCharles.Forsyth static	long	nfiles;			/* number of files */
4574a4d8c2SCharles.Forsyth static	long	nglob;			/* number of globals */
4674a4d8c2SCharles.Forsyth static	long	nhist;			/* number of history stack entries */
4774a4d8c2SCharles.Forsyth static	long	nsym;			/* number of symbols */
48*d67b7dadSforsyth static	int	ntxt;			/* number of text symbols */
4974a4d8c2SCharles.Forsyth static	uchar	*pcline;		/* start of pc-line state table */
5074a4d8c2SCharles.Forsyth static	uchar 	*pclineend;		/* end of pc-line table */
5174a4d8c2SCharles.Forsyth static	uchar	*spoff;			/* start of pc-sp state table */
5274a4d8c2SCharles.Forsyth static	uchar	*spoffend;		/* end of pc-sp offset table */
5374a4d8c2SCharles.Forsyth static	Sym	*symbols;		/* symbol table */
5474a4d8c2SCharles.Forsyth static	Txtsym	*txt;			/* Base of text symbol table */
55*d67b7dadSforsyth static	uvlong	txtstart;		/* start of text segment */
56*d67b7dadSforsyth static	uvlong	txtend;			/* end of text segment */
5774a4d8c2SCharles.Forsyth 
5874a4d8c2SCharles.Forsyth static void	cleansyms(void);
59*d67b7dadSforsyth static long	decodename(Biobuf*, Sym*);
6074a4d8c2SCharles.Forsyth static short	*encfname(char*);
6174a4d8c2SCharles.Forsyth static int 	fline(char*, int, long, Hist*, Hist**);
6274a4d8c2SCharles.Forsyth static void	fillsym(Sym*, Symbol*);
6374a4d8c2SCharles.Forsyth static int	findglobal(char*, Symbol*);
6474a4d8c2SCharles.Forsyth static int	findlocvar(Symbol*, char *, Symbol*);
6574a4d8c2SCharles.Forsyth static int	findtext(char*, Symbol*);
6674a4d8c2SCharles.Forsyth static int	hcomp(Hist*, short*);
67*d67b7dadSforsyth static int	hline(File*, short*, long*);
6874a4d8c2SCharles.Forsyth static void	printhist(char*, Hist*, int);
6974a4d8c2SCharles.Forsyth static int	buildtbls(void);
7074a4d8c2SCharles.Forsyth static int	symcomp(void*, void*);
7174a4d8c2SCharles.Forsyth static int	symerrmsg(int, char*);
7274a4d8c2SCharles.Forsyth static int	txtcomp(void*, void*);
7374a4d8c2SCharles.Forsyth static int	filecomp(void*, void*);
7474a4d8c2SCharles.Forsyth 
7574a4d8c2SCharles.Forsyth /*
7674a4d8c2SCharles.Forsyth  *	initialize the symbol tables
7774a4d8c2SCharles.Forsyth  */
7874a4d8c2SCharles.Forsyth int
syminit(int fd,Fhdr * fp)7974a4d8c2SCharles.Forsyth syminit(int fd, Fhdr *fp)
8074a4d8c2SCharles.Forsyth {
8174a4d8c2SCharles.Forsyth 	Sym *p;
82*d67b7dadSforsyth 	long i, l, size;
83*d67b7dadSforsyth 	vlong vl;
8474a4d8c2SCharles.Forsyth 	Biobuf b;
85*d67b7dadSforsyth 	int svalsz;
8674a4d8c2SCharles.Forsyth 
8774a4d8c2SCharles.Forsyth 	if(fp->symsz == 0)
8874a4d8c2SCharles.Forsyth 		return 0;
8974a4d8c2SCharles.Forsyth 	if(fp->type == FNONE)
9074a4d8c2SCharles.Forsyth 		return 0;
9174a4d8c2SCharles.Forsyth 
9274a4d8c2SCharles.Forsyth 	cleansyms();
9374a4d8c2SCharles.Forsyth 	textseg(fp->txtaddr, fp);
9474a4d8c2SCharles.Forsyth 		/* minimum symbol record size = 4+1+2 bytes */
9574a4d8c2SCharles.Forsyth 	symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
9674a4d8c2SCharles.Forsyth 	if(symbols == 0) {
9774a4d8c2SCharles.Forsyth 		werrstr("can't malloc %ld bytes", fp->symsz);
9874a4d8c2SCharles.Forsyth 		return -1;
9974a4d8c2SCharles.Forsyth 	}
10074a4d8c2SCharles.Forsyth 	Binit(&b, fd, OREAD);
10174a4d8c2SCharles.Forsyth 	Bseek(&b, fp->symoff, 0);
10274a4d8c2SCharles.Forsyth 	nsym = 0;
10374a4d8c2SCharles.Forsyth 	size = 0;
10474a4d8c2SCharles.Forsyth 	for(p = symbols; size < fp->symsz; p++, nsym++) {
105*d67b7dadSforsyth 		if(fp->_magic && (fp->magic & HDR_MAGIC)){
106*d67b7dadSforsyth 			svalsz = 8;
107*d67b7dadSforsyth 			if(Bread(&b, &vl, 8) != 8)
108*d67b7dadSforsyth 				return symerrmsg(8, "symbol");
109*d67b7dadSforsyth 			p->value = beswav(vl);
110*d67b7dadSforsyth 		}
111*d67b7dadSforsyth 		else{
112*d67b7dadSforsyth 			svalsz = 4;
113*d67b7dadSforsyth 			if(Bread(&b, &l, 4) != 4)
114*d67b7dadSforsyth 				return symerrmsg(4, "symbol");
115*d67b7dadSforsyth 			p->value = (u32int)beswal(l);
116*d67b7dadSforsyth 		}
11774a4d8c2SCharles.Forsyth 		if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
11874a4d8c2SCharles.Forsyth 			return symerrmsg(sizeof(p->value), "symbol");
11974a4d8c2SCharles.Forsyth 
12074a4d8c2SCharles.Forsyth 		i = decodename(&b, p);
12174a4d8c2SCharles.Forsyth 		if(i < 0)
12274a4d8c2SCharles.Forsyth 			return -1;
123*d67b7dadSforsyth 		size += i+svalsz+sizeof(p->type);
12474a4d8c2SCharles.Forsyth 
12574a4d8c2SCharles.Forsyth 		/* count global & auto vars, text symbols, and file names */
12674a4d8c2SCharles.Forsyth 		switch (p->type) {
12774a4d8c2SCharles.Forsyth 		case 'l':
12874a4d8c2SCharles.Forsyth 		case 'L':
12974a4d8c2SCharles.Forsyth 		case 't':
13074a4d8c2SCharles.Forsyth 		case 'T':
13174a4d8c2SCharles.Forsyth 			ntxt++;
13274a4d8c2SCharles.Forsyth 			break;
13374a4d8c2SCharles.Forsyth 		case 'd':
13474a4d8c2SCharles.Forsyth 		case 'D':
13574a4d8c2SCharles.Forsyth 		case 'b':
13674a4d8c2SCharles.Forsyth 		case 'B':
13774a4d8c2SCharles.Forsyth 			nglob++;
13874a4d8c2SCharles.Forsyth 			break;
13974a4d8c2SCharles.Forsyth 		case 'f':
14074a4d8c2SCharles.Forsyth 			if(strcmp(p->name, ".frame") == 0) {
14174a4d8c2SCharles.Forsyth 				p->type = 'm';
14274a4d8c2SCharles.Forsyth 				nauto++;
14374a4d8c2SCharles.Forsyth 			}
144fb67f84dSCharles.Forsyth 			else if(p->value > fpmax)
145fb67f84dSCharles.Forsyth 				fpmax = p->value;	/* highest path index */
14674a4d8c2SCharles.Forsyth 			break;
14774a4d8c2SCharles.Forsyth 		case 'a':
14874a4d8c2SCharles.Forsyth 		case 'p':
14974a4d8c2SCharles.Forsyth 		case 'm':
15074a4d8c2SCharles.Forsyth 			nauto++;
15174a4d8c2SCharles.Forsyth 			break;
15274a4d8c2SCharles.Forsyth 		case 'z':
15374a4d8c2SCharles.Forsyth 			if(p->value == 1) {		/* one extra per file */
15474a4d8c2SCharles.Forsyth 				nhist++;
15574a4d8c2SCharles.Forsyth 				nfiles++;
15674a4d8c2SCharles.Forsyth 			}
15774a4d8c2SCharles.Forsyth 			nhist++;
15874a4d8c2SCharles.Forsyth 			break;
15974a4d8c2SCharles.Forsyth 		default:
16074a4d8c2SCharles.Forsyth 			break;
16174a4d8c2SCharles.Forsyth 		}
16274a4d8c2SCharles.Forsyth 	}
16374a4d8c2SCharles.Forsyth 	if (debug)
164*d67b7dadSforsyth 		print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fpmax);
16574a4d8c2SCharles.Forsyth 	if (fp->sppcsz) {			/* pc-sp offset table */
16674a4d8c2SCharles.Forsyth 		spoff = (uchar *)malloc(fp->sppcsz);
16774a4d8c2SCharles.Forsyth 		if(spoff == 0) {
16874a4d8c2SCharles.Forsyth 			werrstr("can't malloc %ld bytes", fp->sppcsz);
16974a4d8c2SCharles.Forsyth 			return -1;
17074a4d8c2SCharles.Forsyth 		}
17174a4d8c2SCharles.Forsyth 		Bseek(&b, fp->sppcoff, 0);
172*d67b7dadSforsyth 		if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
17374a4d8c2SCharles.Forsyth 			spoff = 0;
17474a4d8c2SCharles.Forsyth 			return symerrmsg(fp->sppcsz, "sp-pc");
17574a4d8c2SCharles.Forsyth 		}
17674a4d8c2SCharles.Forsyth 		spoffend = spoff+fp->sppcsz;
17774a4d8c2SCharles.Forsyth 	}
17874a4d8c2SCharles.Forsyth 	if (fp->lnpcsz) {			/* pc-line number table */
17974a4d8c2SCharles.Forsyth 		pcline = (uchar *)malloc(fp->lnpcsz);
18074a4d8c2SCharles.Forsyth 		if(pcline == 0) {
18174a4d8c2SCharles.Forsyth 			werrstr("can't malloc %ld bytes", fp->lnpcsz);
18274a4d8c2SCharles.Forsyth 			return -1;
18374a4d8c2SCharles.Forsyth 		}
18474a4d8c2SCharles.Forsyth 		Bseek(&b, fp->lnpcoff, 0);
185*d67b7dadSforsyth 		if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
18674a4d8c2SCharles.Forsyth 			pcline = 0;
18774a4d8c2SCharles.Forsyth 			return symerrmsg(fp->lnpcsz, "pc-line");
18874a4d8c2SCharles.Forsyth 		}
18974a4d8c2SCharles.Forsyth 		pclineend = pcline+fp->lnpcsz;
19074a4d8c2SCharles.Forsyth 	}
19174a4d8c2SCharles.Forsyth 	return nsym;
19274a4d8c2SCharles.Forsyth }
19374a4d8c2SCharles.Forsyth 
19474a4d8c2SCharles.Forsyth static int
symerrmsg(int n,char * table)19574a4d8c2SCharles.Forsyth symerrmsg(int n, char *table)
19674a4d8c2SCharles.Forsyth {
19774a4d8c2SCharles.Forsyth 	werrstr("can't read %d bytes of %s table", n, table);
19874a4d8c2SCharles.Forsyth 	return -1;
19974a4d8c2SCharles.Forsyth }
20074a4d8c2SCharles.Forsyth 
201*d67b7dadSforsyth static long
decodename(Biobuf * bp,Sym * p)20274a4d8c2SCharles.Forsyth decodename(Biobuf *bp, Sym *p)
20374a4d8c2SCharles.Forsyth {
20474a4d8c2SCharles.Forsyth 	char *cp;
20574a4d8c2SCharles.Forsyth 	int c1, c2;
206*d67b7dadSforsyth 	long n;
207*d67b7dadSforsyth 	vlong o;
20874a4d8c2SCharles.Forsyth 
20974a4d8c2SCharles.Forsyth 	if((p->type & 0x80) == 0) {		/* old-style, fixed length names */
21074a4d8c2SCharles.Forsyth 		p->name = malloc(NNAME);
21174a4d8c2SCharles.Forsyth 		if(p->name == 0) {
21274a4d8c2SCharles.Forsyth 			werrstr("can't malloc %d bytes", NNAME);
21374a4d8c2SCharles.Forsyth 			return -1;
21474a4d8c2SCharles.Forsyth 		}
21574a4d8c2SCharles.Forsyth 		if(Bread(bp, p->name, NNAME) != NNAME)
21674a4d8c2SCharles.Forsyth 			return symerrmsg(NNAME, "symbol");
21774a4d8c2SCharles.Forsyth 		Bseek(bp, 3, 1);
21874a4d8c2SCharles.Forsyth 		return NNAME+3;
21974a4d8c2SCharles.Forsyth 	}
22074a4d8c2SCharles.Forsyth 
22174a4d8c2SCharles.Forsyth 	p->type &= ~0x80;
22274a4d8c2SCharles.Forsyth 	if(p->type == 'z' || p->type == 'Z') {
223*d67b7dadSforsyth 		o = Bseek(bp, 0, 1);
22474a4d8c2SCharles.Forsyth 		if(Bgetc(bp) < 0) {
22574a4d8c2SCharles.Forsyth 			werrstr("can't read symbol name");
22674a4d8c2SCharles.Forsyth 			return -1;
22774a4d8c2SCharles.Forsyth 		}
22874a4d8c2SCharles.Forsyth 		for(;;) {
22974a4d8c2SCharles.Forsyth 			c1 = Bgetc(bp);
23074a4d8c2SCharles.Forsyth 			c2 = Bgetc(bp);
23174a4d8c2SCharles.Forsyth 			if(c1 < 0 || c2 < 0) {
23274a4d8c2SCharles.Forsyth 				werrstr("can't read symbol name");
23374a4d8c2SCharles.Forsyth 				return -1;
23474a4d8c2SCharles.Forsyth 			}
23574a4d8c2SCharles.Forsyth 			if(c1 == 0 && c2 == 0)
23674a4d8c2SCharles.Forsyth 				break;
23774a4d8c2SCharles.Forsyth 		}
238*d67b7dadSforsyth 		n = Bseek(bp, 0, 1)-o;
23974a4d8c2SCharles.Forsyth 		p->name = malloc(n);
24074a4d8c2SCharles.Forsyth 		if(p->name == 0) {
241*d67b7dadSforsyth 			werrstr("can't malloc %ld bytes", n);
24274a4d8c2SCharles.Forsyth 			return -1;
24374a4d8c2SCharles.Forsyth 		}
24474a4d8c2SCharles.Forsyth 		Bseek(bp, -n, 1);
24574a4d8c2SCharles.Forsyth 		if(Bread(bp, p->name, n) != n) {
246*d67b7dadSforsyth 			werrstr("can't read %ld bytes of symbol name", n);
24774a4d8c2SCharles.Forsyth 			return -1;
24874a4d8c2SCharles.Forsyth 		}
24974a4d8c2SCharles.Forsyth 	} else {
25074a4d8c2SCharles.Forsyth 		cp = Brdline(bp, '\0');
25174a4d8c2SCharles.Forsyth 		if(cp == 0) {
25274a4d8c2SCharles.Forsyth 			werrstr("can't read symbol name");
25374a4d8c2SCharles.Forsyth 			return -1;
25474a4d8c2SCharles.Forsyth 		}
25574a4d8c2SCharles.Forsyth 		n = Blinelen(bp);
25674a4d8c2SCharles.Forsyth 		p->name = malloc(n);
25774a4d8c2SCharles.Forsyth 		if(p->name == 0) {
258*d67b7dadSforsyth 			werrstr("can't malloc %ld bytes", n);
25974a4d8c2SCharles.Forsyth 			return -1;
26074a4d8c2SCharles.Forsyth 		}
26174a4d8c2SCharles.Forsyth 		strcpy(p->name, cp);
26274a4d8c2SCharles.Forsyth 	}
26374a4d8c2SCharles.Forsyth 	return n;
26474a4d8c2SCharles.Forsyth }
265*d67b7dadSforsyth 
26674a4d8c2SCharles.Forsyth /*
26774a4d8c2SCharles.Forsyth  *	free any previously loaded symbol tables
26874a4d8c2SCharles.Forsyth  */
26974a4d8c2SCharles.Forsyth static void
cleansyms(void)27074a4d8c2SCharles.Forsyth cleansyms(void)
27174a4d8c2SCharles.Forsyth {
27274a4d8c2SCharles.Forsyth 	if(globals)
27374a4d8c2SCharles.Forsyth 		free(globals);
27474a4d8c2SCharles.Forsyth 	globals = 0;
27574a4d8c2SCharles.Forsyth 	nglob = 0;
27674a4d8c2SCharles.Forsyth 	if(txt)
27774a4d8c2SCharles.Forsyth 		free(txt);
27874a4d8c2SCharles.Forsyth 	txt = 0;
27974a4d8c2SCharles.Forsyth 	ntxt = 0;
28074a4d8c2SCharles.Forsyth 	if(fnames)
28174a4d8c2SCharles.Forsyth 		free(fnames);
28274a4d8c2SCharles.Forsyth 	fnames = 0;
283fb67f84dSCharles.Forsyth 	fpmax = 0;
28474a4d8c2SCharles.Forsyth 
28574a4d8c2SCharles.Forsyth 	if(files)
28674a4d8c2SCharles.Forsyth 		free(files);
28774a4d8c2SCharles.Forsyth 	files = 0;
28874a4d8c2SCharles.Forsyth 	nfiles = 0;
28974a4d8c2SCharles.Forsyth 	if(hist)
29074a4d8c2SCharles.Forsyth 		free(hist);
29174a4d8c2SCharles.Forsyth 	hist = 0;
29274a4d8c2SCharles.Forsyth 	nhist = 0;
29374a4d8c2SCharles.Forsyth 	if(autos)
29474a4d8c2SCharles.Forsyth 		free(autos);
29574a4d8c2SCharles.Forsyth 	autos = 0;
29674a4d8c2SCharles.Forsyth 	nauto = 0;
29774a4d8c2SCharles.Forsyth 	isbuilt = 0;
29874a4d8c2SCharles.Forsyth 	if(symbols)
29974a4d8c2SCharles.Forsyth 		free(symbols);
30074a4d8c2SCharles.Forsyth 	symbols = 0;
30174a4d8c2SCharles.Forsyth 	nsym = 0;
30274a4d8c2SCharles.Forsyth 	if(spoff)
30374a4d8c2SCharles.Forsyth 		free(spoff);
30474a4d8c2SCharles.Forsyth 	spoff = 0;
30574a4d8c2SCharles.Forsyth 	if(pcline)
30674a4d8c2SCharles.Forsyth 		free(pcline);
30774a4d8c2SCharles.Forsyth 	pcline = 0;
30874a4d8c2SCharles.Forsyth }
309*d67b7dadSforsyth 
31074a4d8c2SCharles.Forsyth /*
31174a4d8c2SCharles.Forsyth  *	delimit the text segment
31274a4d8c2SCharles.Forsyth  */
31374a4d8c2SCharles.Forsyth void
textseg(uvlong base,Fhdr * fp)314*d67b7dadSforsyth textseg(uvlong base, Fhdr *fp)
31574a4d8c2SCharles.Forsyth {
31674a4d8c2SCharles.Forsyth 	txtstart = base;
31774a4d8c2SCharles.Forsyth 	txtend = base+fp->txtsz;
31874a4d8c2SCharles.Forsyth }
319*d67b7dadSforsyth 
32074a4d8c2SCharles.Forsyth /*
32174a4d8c2SCharles.Forsyth  *	symbase: return base and size of raw symbol table
32274a4d8c2SCharles.Forsyth  *		(special hack for high access rate operations)
32374a4d8c2SCharles.Forsyth  */
32474a4d8c2SCharles.Forsyth Sym *
symbase(long * n)32574a4d8c2SCharles.Forsyth symbase(long *n)
32674a4d8c2SCharles.Forsyth {
32774a4d8c2SCharles.Forsyth 	*n = nsym;
32874a4d8c2SCharles.Forsyth 	return symbols;
32974a4d8c2SCharles.Forsyth }
330*d67b7dadSforsyth 
33174a4d8c2SCharles.Forsyth /*
33274a4d8c2SCharles.Forsyth  *	Get the ith symbol table entry
33374a4d8c2SCharles.Forsyth  */
33474a4d8c2SCharles.Forsyth Sym *
getsym(int index)33574a4d8c2SCharles.Forsyth getsym(int index)
33674a4d8c2SCharles.Forsyth {
337*d67b7dadSforsyth 	if(index >= 0 && index < nsym)
33874a4d8c2SCharles.Forsyth 		return &symbols[index];
33974a4d8c2SCharles.Forsyth 	return 0;
34074a4d8c2SCharles.Forsyth }
34174a4d8c2SCharles.Forsyth 
34274a4d8c2SCharles.Forsyth /*
34374a4d8c2SCharles.Forsyth  *	initialize internal symbol tables
34474a4d8c2SCharles.Forsyth  */
34574a4d8c2SCharles.Forsyth static int
buildtbls(void)34674a4d8c2SCharles.Forsyth buildtbls(void)
34774a4d8c2SCharles.Forsyth {
348*d67b7dadSforsyth 	long i;
349*d67b7dadSforsyth 	int j, nh, ng, nt;
35074a4d8c2SCharles.Forsyth 	File *f;
35174a4d8c2SCharles.Forsyth 	Txtsym *tp;
35274a4d8c2SCharles.Forsyth 	Hist *hp;
35374a4d8c2SCharles.Forsyth 	Sym *p, **ap;
35474a4d8c2SCharles.Forsyth 
35574a4d8c2SCharles.Forsyth 	if(isbuilt)
35674a4d8c2SCharles.Forsyth 		return 1;
35774a4d8c2SCharles.Forsyth 	isbuilt = 1;
35874a4d8c2SCharles.Forsyth 			/* allocate the tables */
35974a4d8c2SCharles.Forsyth 	if(nglob) {
36074a4d8c2SCharles.Forsyth 		globals = malloc(nglob*sizeof(*globals));
36174a4d8c2SCharles.Forsyth 		if(!globals) {
36274a4d8c2SCharles.Forsyth 			werrstr("can't malloc global symbol table");
36374a4d8c2SCharles.Forsyth 			return 0;
36474a4d8c2SCharles.Forsyth 		}
36574a4d8c2SCharles.Forsyth 	}
36674a4d8c2SCharles.Forsyth 	if(ntxt) {
36774a4d8c2SCharles.Forsyth 		txt = malloc(ntxt*sizeof(*txt));
36874a4d8c2SCharles.Forsyth 		if (!txt) {
36974a4d8c2SCharles.Forsyth 			werrstr("can't malloc text symbol table");
37074a4d8c2SCharles.Forsyth 			return 0;
37174a4d8c2SCharles.Forsyth 		}
37274a4d8c2SCharles.Forsyth 	}
373*d67b7dadSforsyth 	fnames = malloc((fpmax+1)*sizeof(*fnames));
37474a4d8c2SCharles.Forsyth 	if (!fnames) {
37574a4d8c2SCharles.Forsyth 		werrstr("can't malloc file name table");
37674a4d8c2SCharles.Forsyth 		return 0;
37774a4d8c2SCharles.Forsyth 	}
378*d67b7dadSforsyth 	memset(fnames, 0, (fpmax+1)*sizeof(*fnames));
37974a4d8c2SCharles.Forsyth 	files = malloc(nfiles*sizeof(*files));
38074a4d8c2SCharles.Forsyth 	if(!files) {
38174a4d8c2SCharles.Forsyth 		werrstr("can't malloc file table");
38274a4d8c2SCharles.Forsyth 		return 0;
38374a4d8c2SCharles.Forsyth 	}
38474a4d8c2SCharles.Forsyth 	hist = malloc(nhist*sizeof(Hist));
38574a4d8c2SCharles.Forsyth 	if(hist == 0) {
38674a4d8c2SCharles.Forsyth 		werrstr("can't malloc history stack");
38774a4d8c2SCharles.Forsyth 		return 0;
38874a4d8c2SCharles.Forsyth 	}
38974a4d8c2SCharles.Forsyth 	autos = malloc(nauto*sizeof(Sym*));
39074a4d8c2SCharles.Forsyth 	if(autos == 0) {
39174a4d8c2SCharles.Forsyth 		werrstr("can't malloc auto symbol table");
39274a4d8c2SCharles.Forsyth 		return 0;
39374a4d8c2SCharles.Forsyth 	}
39474a4d8c2SCharles.Forsyth 		/* load the tables */
39574a4d8c2SCharles.Forsyth 	ng = nt = nh = 0;
39674a4d8c2SCharles.Forsyth 	f = 0;
39774a4d8c2SCharles.Forsyth 	tp = 0;
39874a4d8c2SCharles.Forsyth 	i = nsym;
39974a4d8c2SCharles.Forsyth 	hp = hist;
40074a4d8c2SCharles.Forsyth 	ap = autos;
40174a4d8c2SCharles.Forsyth 	for(p = symbols; i-- > 0; p++) {
40274a4d8c2SCharles.Forsyth 		switch(p->type) {
40374a4d8c2SCharles.Forsyth 		case 'D':
40474a4d8c2SCharles.Forsyth 		case 'd':
40574a4d8c2SCharles.Forsyth 		case 'B':
40674a4d8c2SCharles.Forsyth 		case 'b':
40774a4d8c2SCharles.Forsyth 			if(debug)
408*d67b7dadSforsyth 				print("Global: %s %llux\n", p->name, p->value);
40974a4d8c2SCharles.Forsyth 			globals[ng++] = p;
41074a4d8c2SCharles.Forsyth 			break;
41174a4d8c2SCharles.Forsyth 		case 'z':
41274a4d8c2SCharles.Forsyth 			if(p->value == 1) {		/* New file */
41374a4d8c2SCharles.Forsyth 				if(f) {
41474a4d8c2SCharles.Forsyth 					f->n = nh;
41574a4d8c2SCharles.Forsyth 					f->hist[nh].name = 0;	/* one extra */
41674a4d8c2SCharles.Forsyth 					hp += nh+1;
41774a4d8c2SCharles.Forsyth 					f++;
41874a4d8c2SCharles.Forsyth 				}
419*d67b7dadSforsyth 				else
420*d67b7dadSforsyth 					f = files;
42174a4d8c2SCharles.Forsyth 				f->hist = hp;
422*d67b7dadSforsyth 				f->sym = 0;
42374a4d8c2SCharles.Forsyth 				f->addr = 0;
42474a4d8c2SCharles.Forsyth 				nh = 0;
42574a4d8c2SCharles.Forsyth 			}
42674a4d8c2SCharles.Forsyth 				/* alloc one slot extra as terminator */
42774a4d8c2SCharles.Forsyth 			f->hist[nh].name = p->name;
42874a4d8c2SCharles.Forsyth 			f->hist[nh].line = p->value;
42974a4d8c2SCharles.Forsyth 			f->hist[nh].offset = 0;
43074a4d8c2SCharles.Forsyth 			if(debug)
43174a4d8c2SCharles.Forsyth 				printhist("-> ", &f->hist[nh], 1);
43274a4d8c2SCharles.Forsyth 			nh++;
43374a4d8c2SCharles.Forsyth 			break;
43474a4d8c2SCharles.Forsyth 		case 'Z':
43574a4d8c2SCharles.Forsyth 			if(f && nh > 0)
43674a4d8c2SCharles.Forsyth 				f->hist[nh-1].offset = p->value;
43774a4d8c2SCharles.Forsyth 			break;
43874a4d8c2SCharles.Forsyth 		case 'T':
43974a4d8c2SCharles.Forsyth 		case 't':	/* Text: terminate history if first in file */
44074a4d8c2SCharles.Forsyth 		case 'L':
44174a4d8c2SCharles.Forsyth 		case 'l':
44274a4d8c2SCharles.Forsyth 			tp = &txt[nt++];
44374a4d8c2SCharles.Forsyth 			tp->n = 0;
44474a4d8c2SCharles.Forsyth 			tp->sym = p;
44574a4d8c2SCharles.Forsyth 			tp->locals = ap;
44674a4d8c2SCharles.Forsyth 			if(debug)
447*d67b7dadSforsyth 				print("TEXT: %s at %llux\n", p->name, p->value);
448*d67b7dadSforsyth 			if(f && !f->sym) {			/* first  */
449*d67b7dadSforsyth 				f->sym = p;
45074a4d8c2SCharles.Forsyth 				f->addr = p->value;
45174a4d8c2SCharles.Forsyth 			}
45274a4d8c2SCharles.Forsyth 			break;
45374a4d8c2SCharles.Forsyth 		case 'a':
45474a4d8c2SCharles.Forsyth 		case 'p':
45574a4d8c2SCharles.Forsyth 		case 'm':		/* Local Vars */
45674a4d8c2SCharles.Forsyth 			if(!tp)
457*d67b7dadSforsyth 				print("Warning: Free floating local var: %s\n",
458*d67b7dadSforsyth 					p->name);
45974a4d8c2SCharles.Forsyth 			else {
46074a4d8c2SCharles.Forsyth 				if(debug)
461*d67b7dadSforsyth 					print("Local: %s %llux\n", p->name, p->value);
46274a4d8c2SCharles.Forsyth 				tp->locals[tp->n] = p;
46374a4d8c2SCharles.Forsyth 				tp->n++;
46474a4d8c2SCharles.Forsyth 				ap++;
46574a4d8c2SCharles.Forsyth 			}
46674a4d8c2SCharles.Forsyth 			break;
46774a4d8c2SCharles.Forsyth 		case 'f':		/* File names */
46874a4d8c2SCharles.Forsyth 			if(debug)
469*d67b7dadSforsyth 				print("Fname: %s\n", p->name);
47074a4d8c2SCharles.Forsyth 			fnames[p->value] = p;
47174a4d8c2SCharles.Forsyth 			break;
47274a4d8c2SCharles.Forsyth 		default:
47374a4d8c2SCharles.Forsyth 			break;
47474a4d8c2SCharles.Forsyth 		}
47574a4d8c2SCharles.Forsyth 	}
47674a4d8c2SCharles.Forsyth 		/* sort global and text tables into ascending address order */
47774a4d8c2SCharles.Forsyth 	qsort(globals, nglob, sizeof(Sym*), symcomp);
47874a4d8c2SCharles.Forsyth 	qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
47974a4d8c2SCharles.Forsyth 	qsort(files, nfiles, sizeof(File), filecomp);
48074a4d8c2SCharles.Forsyth 	tp = txt;
48174a4d8c2SCharles.Forsyth 	for(i = 0, f = files; i < nfiles; i++, f++) {
48274a4d8c2SCharles.Forsyth 		for(j = 0; j < ntxt; j++) {
483*d67b7dadSforsyth 			if(f->sym == tp->sym) {
48474a4d8c2SCharles.Forsyth 				if(debug) {
485*d67b7dadSforsyth 					print("LINK: %s to at %llux", f->sym->name, f->addr);
48674a4d8c2SCharles.Forsyth 					printhist("... ", f->hist, 1);
48774a4d8c2SCharles.Forsyth 				}
488*d67b7dadSforsyth 				f->txt = tp++;
48974a4d8c2SCharles.Forsyth 				break;
49074a4d8c2SCharles.Forsyth 			}
49174a4d8c2SCharles.Forsyth 			if(++tp >= txt+ntxt)	/* wrap around */
49274a4d8c2SCharles.Forsyth 				tp = txt;
49374a4d8c2SCharles.Forsyth 		}
49474a4d8c2SCharles.Forsyth 	}
49574a4d8c2SCharles.Forsyth 	return 1;
49674a4d8c2SCharles.Forsyth }
49774a4d8c2SCharles.Forsyth 
49874a4d8c2SCharles.Forsyth /*
49974a4d8c2SCharles.Forsyth  * find symbol function.var by name.
50074a4d8c2SCharles.Forsyth  *	fn != 0 && var != 0	=> look for fn in text, var in data
50174a4d8c2SCharles.Forsyth  *	fn != 0 && var == 0	=> look for fn in text
50274a4d8c2SCharles.Forsyth  *	fn == 0 && var != 0	=> look for var first in text then in data space.
50374a4d8c2SCharles.Forsyth  */
50474a4d8c2SCharles.Forsyth int
lookup(char * fn,char * var,Symbol * s)50574a4d8c2SCharles.Forsyth lookup(char *fn, char *var, Symbol *s)
50674a4d8c2SCharles.Forsyth {
50774a4d8c2SCharles.Forsyth 	int found;
50874a4d8c2SCharles.Forsyth 
50974a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
51074a4d8c2SCharles.Forsyth 		return 0;
51174a4d8c2SCharles.Forsyth 	if(fn) {
51274a4d8c2SCharles.Forsyth 		found = findtext(fn, s);
51374a4d8c2SCharles.Forsyth 		if(var == 0)		/* case 2: fn not in text */
51474a4d8c2SCharles.Forsyth 			return found;
51574a4d8c2SCharles.Forsyth 		else if(!found)		/* case 1: fn not found */
51674a4d8c2SCharles.Forsyth 			return 0;
51774a4d8c2SCharles.Forsyth 	} else if(var) {
51874a4d8c2SCharles.Forsyth 		found = findtext(var, s);
51974a4d8c2SCharles.Forsyth 		if(found)
52074a4d8c2SCharles.Forsyth 			return 1;	/* case 3: var found in text */
52174a4d8c2SCharles.Forsyth 	} else return 0;		/* case 4: fn & var == zero */
52274a4d8c2SCharles.Forsyth 
52374a4d8c2SCharles.Forsyth 	if(found)
52474a4d8c2SCharles.Forsyth 		return findlocal(s, var, s);	/* case 1: fn found */
52574a4d8c2SCharles.Forsyth 	return findglobal(var, s);		/* case 3: var not found */
52674a4d8c2SCharles.Forsyth 
52774a4d8c2SCharles.Forsyth }
528*d67b7dadSforsyth 
52974a4d8c2SCharles.Forsyth /*
53074a4d8c2SCharles.Forsyth  * find a function by name
53174a4d8c2SCharles.Forsyth  */
53274a4d8c2SCharles.Forsyth static int
findtext(char * name,Symbol * s)53374a4d8c2SCharles.Forsyth findtext(char *name, Symbol *s)
53474a4d8c2SCharles.Forsyth {
53574a4d8c2SCharles.Forsyth 	int i;
53674a4d8c2SCharles.Forsyth 
53774a4d8c2SCharles.Forsyth 	for(i = 0; i < ntxt; i++) {
53874a4d8c2SCharles.Forsyth 		if(strcmp(txt[i].sym->name, name) == 0) {
53974a4d8c2SCharles.Forsyth 			fillsym(txt[i].sym, s);
54074a4d8c2SCharles.Forsyth 			s->handle = (void *) &txt[i];
541*d67b7dadSforsyth 			s->index = i;
54274a4d8c2SCharles.Forsyth 			return 1;
54374a4d8c2SCharles.Forsyth 		}
54474a4d8c2SCharles.Forsyth 	}
54574a4d8c2SCharles.Forsyth 	return 0;
54674a4d8c2SCharles.Forsyth }
54774a4d8c2SCharles.Forsyth /*
54874a4d8c2SCharles.Forsyth  * find global variable by name
54974a4d8c2SCharles.Forsyth  */
55074a4d8c2SCharles.Forsyth static int
findglobal(char * name,Symbol * s)55174a4d8c2SCharles.Forsyth findglobal(char *name, Symbol *s)
55274a4d8c2SCharles.Forsyth {
553*d67b7dadSforsyth 	long i;
55474a4d8c2SCharles.Forsyth 
55574a4d8c2SCharles.Forsyth 	for(i = 0; i < nglob; i++) {
55674a4d8c2SCharles.Forsyth 		if(strcmp(globals[i]->name, name) == 0) {
55774a4d8c2SCharles.Forsyth 			fillsym(globals[i], s);
558*d67b7dadSforsyth 			s->index = i;
55974a4d8c2SCharles.Forsyth 			return 1;
56074a4d8c2SCharles.Forsyth 		}
56174a4d8c2SCharles.Forsyth 	}
56274a4d8c2SCharles.Forsyth 	return 0;
56374a4d8c2SCharles.Forsyth }
564*d67b7dadSforsyth 
56574a4d8c2SCharles.Forsyth /*
56674a4d8c2SCharles.Forsyth  *	find the local variable by name within a given function
56774a4d8c2SCharles.Forsyth  */
56874a4d8c2SCharles.Forsyth int
findlocal(Symbol * s1,char * name,Symbol * s2)56974a4d8c2SCharles.Forsyth findlocal(Symbol *s1, char *name, Symbol *s2)
57074a4d8c2SCharles.Forsyth {
57174a4d8c2SCharles.Forsyth 	if(s1 == 0)
57274a4d8c2SCharles.Forsyth 		return 0;
57374a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
57474a4d8c2SCharles.Forsyth 		return 0;
57574a4d8c2SCharles.Forsyth 	return findlocvar(s1, name, s2);
57674a4d8c2SCharles.Forsyth }
577*d67b7dadSforsyth 
57874a4d8c2SCharles.Forsyth /*
57974a4d8c2SCharles.Forsyth  *	find the local variable by name within a given function
58074a4d8c2SCharles.Forsyth  *		(internal function - does no parameter validation)
58174a4d8c2SCharles.Forsyth  */
58274a4d8c2SCharles.Forsyth static int
findlocvar(Symbol * s1,char * name,Symbol * s2)58374a4d8c2SCharles.Forsyth findlocvar(Symbol *s1, char *name, Symbol *s2)
58474a4d8c2SCharles.Forsyth {
58574a4d8c2SCharles.Forsyth 	Txtsym *tp;
58674a4d8c2SCharles.Forsyth 	int i;
58774a4d8c2SCharles.Forsyth 
58874a4d8c2SCharles.Forsyth 	tp = (Txtsym *)s1->handle;
58974a4d8c2SCharles.Forsyth 	if(tp && tp->locals) {
59074a4d8c2SCharles.Forsyth 		for(i = 0; i < tp->n; i++)
59174a4d8c2SCharles.Forsyth 			if (strcmp(tp->locals[i]->name, name) == 0) {
59274a4d8c2SCharles.Forsyth 				fillsym(tp->locals[i], s2);
59374a4d8c2SCharles.Forsyth 				s2->handle = (void *)tp;
594*d67b7dadSforsyth 				s2->index = tp->n-1 - i;
59574a4d8c2SCharles.Forsyth 				return 1;
59674a4d8c2SCharles.Forsyth 			}
59774a4d8c2SCharles.Forsyth 	}
59874a4d8c2SCharles.Forsyth 	return 0;
59974a4d8c2SCharles.Forsyth }
600*d67b7dadSforsyth 
60174a4d8c2SCharles.Forsyth /*
60274a4d8c2SCharles.Forsyth  *	Get ith text symbol
60374a4d8c2SCharles.Forsyth  */
60474a4d8c2SCharles.Forsyth int
textsym(Symbol * s,int index)60574a4d8c2SCharles.Forsyth textsym(Symbol *s, int index)
60674a4d8c2SCharles.Forsyth {
60774a4d8c2SCharles.Forsyth 
60874a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
60974a4d8c2SCharles.Forsyth 		return 0;
610*d67b7dadSforsyth 	if(index < 0 || index >= ntxt)
61174a4d8c2SCharles.Forsyth 		return 0;
61274a4d8c2SCharles.Forsyth 	fillsym(txt[index].sym, s);
61374a4d8c2SCharles.Forsyth 	s->handle = (void *)&txt[index];
614*d67b7dadSforsyth 	s->index = index;
61574a4d8c2SCharles.Forsyth 	return 1;
61674a4d8c2SCharles.Forsyth }
617*d67b7dadSforsyth 
61874a4d8c2SCharles.Forsyth /*
61974a4d8c2SCharles.Forsyth  *	Get ith file name
62074a4d8c2SCharles.Forsyth  */
62174a4d8c2SCharles.Forsyth int
filesym(int index,char * buf,int n)62274a4d8c2SCharles.Forsyth filesym(int index, char *buf, int n)
62374a4d8c2SCharles.Forsyth {
62474a4d8c2SCharles.Forsyth 	Hist *hp;
62574a4d8c2SCharles.Forsyth 
62674a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
62774a4d8c2SCharles.Forsyth 		return 0;
628*d67b7dadSforsyth 	if(index < 0 || index >= nfiles)
62974a4d8c2SCharles.Forsyth 		return 0;
63074a4d8c2SCharles.Forsyth 	hp = files[index].hist;
63174a4d8c2SCharles.Forsyth 	if(!hp || !hp->name)
63274a4d8c2SCharles.Forsyth 		return 0;
63374a4d8c2SCharles.Forsyth 	return fileelem(fnames, (uchar*)hp->name, buf, n);
63474a4d8c2SCharles.Forsyth }
635*d67b7dadSforsyth 
63674a4d8c2SCharles.Forsyth /*
63774a4d8c2SCharles.Forsyth  *	Lookup name of local variable located at an offset into the frame.
63874a4d8c2SCharles.Forsyth  *	The type selects either a parameter or automatic.
63974a4d8c2SCharles.Forsyth  */
64074a4d8c2SCharles.Forsyth int
getauto(Symbol * s1,int off,int type,Symbol * s2)64174a4d8c2SCharles.Forsyth getauto(Symbol *s1, int off, int type, Symbol *s2)
64274a4d8c2SCharles.Forsyth {
64374a4d8c2SCharles.Forsyth 	Txtsym *tp;
64474a4d8c2SCharles.Forsyth 	Sym *p;
64574a4d8c2SCharles.Forsyth 	int i, t;
64674a4d8c2SCharles.Forsyth 
64774a4d8c2SCharles.Forsyth 	if(s1 == 0)
64874a4d8c2SCharles.Forsyth 		return 0;
64974a4d8c2SCharles.Forsyth 	if(type == CPARAM)
65074a4d8c2SCharles.Forsyth 		t = 'p';
65174a4d8c2SCharles.Forsyth 	else if(type == CAUTO)
65274a4d8c2SCharles.Forsyth 		t = 'a';
65374a4d8c2SCharles.Forsyth 	else
65474a4d8c2SCharles.Forsyth 		return 0;
65574a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
65674a4d8c2SCharles.Forsyth 		return 0;
65774a4d8c2SCharles.Forsyth 	tp = (Txtsym *)s1->handle;
65874a4d8c2SCharles.Forsyth 	if(tp == 0)
65974a4d8c2SCharles.Forsyth 		return 0;
66074a4d8c2SCharles.Forsyth 	for(i = 0; i < tp->n; i++) {
66174a4d8c2SCharles.Forsyth 		p = tp->locals[i];
66274a4d8c2SCharles.Forsyth 		if(p->type == t && p->value == off) {
66374a4d8c2SCharles.Forsyth 			fillsym(p, s2);
66474a4d8c2SCharles.Forsyth 			s2->handle = s1->handle;
665*d67b7dadSforsyth 			s2->index = tp->n-1 - i;
66674a4d8c2SCharles.Forsyth 			return 1;
66774a4d8c2SCharles.Forsyth 		}
66874a4d8c2SCharles.Forsyth 	}
66974a4d8c2SCharles.Forsyth 	return 0;
67074a4d8c2SCharles.Forsyth }
67174a4d8c2SCharles.Forsyth 
67274a4d8c2SCharles.Forsyth /*
67374a4d8c2SCharles.Forsyth  * Find text symbol containing addr; binary search assumes text array is sorted by addr
67474a4d8c2SCharles.Forsyth  */
67574a4d8c2SCharles.Forsyth static int
srchtext(uvlong addr)676*d67b7dadSforsyth srchtext(uvlong addr)
67774a4d8c2SCharles.Forsyth {
678*d67b7dadSforsyth 	uvlong val;
67974a4d8c2SCharles.Forsyth 	int top, bot, mid;
68074a4d8c2SCharles.Forsyth 	Sym *sp;
68174a4d8c2SCharles.Forsyth 
68274a4d8c2SCharles.Forsyth 	val = addr;
68374a4d8c2SCharles.Forsyth 	bot = 0;
68474a4d8c2SCharles.Forsyth 	top = ntxt;
68574a4d8c2SCharles.Forsyth 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
68674a4d8c2SCharles.Forsyth 		sp = txt[mid].sym;
687*d67b7dadSforsyth 		if(val < sp->value)
68874a4d8c2SCharles.Forsyth 			top = mid;
689*d67b7dadSforsyth 		else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
69074a4d8c2SCharles.Forsyth 			bot = mid;
69174a4d8c2SCharles.Forsyth 		else
69274a4d8c2SCharles.Forsyth 			return mid;
69374a4d8c2SCharles.Forsyth 	}
69474a4d8c2SCharles.Forsyth 	return -1;
69574a4d8c2SCharles.Forsyth }
69674a4d8c2SCharles.Forsyth 
69774a4d8c2SCharles.Forsyth /*
69874a4d8c2SCharles.Forsyth  * Find data symbol containing addr; binary search assumes data array is sorted by addr
69974a4d8c2SCharles.Forsyth  */
700*d67b7dadSforsyth static int
srchdata(uvlong addr)701*d67b7dadSforsyth srchdata(uvlong addr)
70274a4d8c2SCharles.Forsyth {
703*d67b7dadSforsyth 	uvlong val;
70474a4d8c2SCharles.Forsyth 	int top, bot, mid;
70574a4d8c2SCharles.Forsyth 	Sym *sp;
70674a4d8c2SCharles.Forsyth 
70774a4d8c2SCharles.Forsyth 	bot = 0;
70874a4d8c2SCharles.Forsyth 	top = nglob;
70974a4d8c2SCharles.Forsyth 	val = addr;
71074a4d8c2SCharles.Forsyth 	for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
71174a4d8c2SCharles.Forsyth 		sp = globals[mid];
712*d67b7dadSforsyth 		if(val < sp->value)
71374a4d8c2SCharles.Forsyth 			top = mid;
714*d67b7dadSforsyth 		else if(mid < nglob-1 && val >= globals[mid+1]->value)
71574a4d8c2SCharles.Forsyth 			bot = mid;
71674a4d8c2SCharles.Forsyth 		else
71774a4d8c2SCharles.Forsyth 			return mid;
71874a4d8c2SCharles.Forsyth 	}
71974a4d8c2SCharles.Forsyth 	return -1;
72074a4d8c2SCharles.Forsyth }
721*d67b7dadSforsyth 
72274a4d8c2SCharles.Forsyth /*
72374a4d8c2SCharles.Forsyth  * Find symbol containing val in specified search space
72474a4d8c2SCharles.Forsyth  * There is a special case when a value falls beyond the end
72574a4d8c2SCharles.Forsyth  * of the text segment; if the search space is CTEXT, that value
72674a4d8c2SCharles.Forsyth  * (usually etext) is returned.  If the search space is CANY, symbols in the
72774a4d8c2SCharles.Forsyth  * data space are searched for a match.
72874a4d8c2SCharles.Forsyth  */
72974a4d8c2SCharles.Forsyth int
findsym(uvlong val,int type,Symbol * s)730*d67b7dadSforsyth findsym(uvlong val, int type, Symbol *s)
73174a4d8c2SCharles.Forsyth {
73274a4d8c2SCharles.Forsyth 	int i;
73374a4d8c2SCharles.Forsyth 
73474a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
73574a4d8c2SCharles.Forsyth 		return 0;
73674a4d8c2SCharles.Forsyth 
73774a4d8c2SCharles.Forsyth 	if(type == CTEXT || type == CANY) {
738*d67b7dadSforsyth 		i = srchtext(val);
73974a4d8c2SCharles.Forsyth 		if(i >= 0) {
74074a4d8c2SCharles.Forsyth 			if(type == CTEXT || i != ntxt-1) {
74174a4d8c2SCharles.Forsyth 				fillsym(txt[i].sym, s);
74274a4d8c2SCharles.Forsyth 				s->handle = (void *) &txt[i];
743*d67b7dadSforsyth 				s->index = i;
74474a4d8c2SCharles.Forsyth 				return 1;
74574a4d8c2SCharles.Forsyth 			}
74674a4d8c2SCharles.Forsyth 		}
74774a4d8c2SCharles.Forsyth 	}
74874a4d8c2SCharles.Forsyth 	if(type == CDATA || type == CANY) {
749*d67b7dadSforsyth 		i = srchdata(val);
75074a4d8c2SCharles.Forsyth 		if(i >= 0) {
75174a4d8c2SCharles.Forsyth 			fillsym(globals[i], s);
752*d67b7dadSforsyth 			s->index = i;
75374a4d8c2SCharles.Forsyth 			return 1;
75474a4d8c2SCharles.Forsyth 		}
75574a4d8c2SCharles.Forsyth 	}
75674a4d8c2SCharles.Forsyth 	return 0;
75774a4d8c2SCharles.Forsyth }
75874a4d8c2SCharles.Forsyth 
75974a4d8c2SCharles.Forsyth /*
76074a4d8c2SCharles.Forsyth  *	Find the start and end address of the function containing addr
76174a4d8c2SCharles.Forsyth  */
76274a4d8c2SCharles.Forsyth int
fnbound(uvlong addr,uvlong * bounds)763*d67b7dadSforsyth fnbound(uvlong addr, uvlong *bounds)
76474a4d8c2SCharles.Forsyth {
76574a4d8c2SCharles.Forsyth 	int i;
76674a4d8c2SCharles.Forsyth 
76774a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
76874a4d8c2SCharles.Forsyth 		return 0;
76974a4d8c2SCharles.Forsyth 
77074a4d8c2SCharles.Forsyth 	i = srchtext(addr);
77174a4d8c2SCharles.Forsyth 	if(0 <= i && i < ntxt-1) {
77274a4d8c2SCharles.Forsyth 		bounds[0] = txt[i].sym->value;
77374a4d8c2SCharles.Forsyth 		bounds[1] = txt[i+1].sym->value;
77474a4d8c2SCharles.Forsyth 		return 1;
77574a4d8c2SCharles.Forsyth 	}
77674a4d8c2SCharles.Forsyth 	return 0;
77774a4d8c2SCharles.Forsyth }
77874a4d8c2SCharles.Forsyth 
77974a4d8c2SCharles.Forsyth /*
78074a4d8c2SCharles.Forsyth  * get the ith local symbol for a function
78174a4d8c2SCharles.Forsyth  * the input symbol table is reverse ordered, so we reverse
78274a4d8c2SCharles.Forsyth  * accesses here to maintain approx. parameter ordering in a stack trace.
78374a4d8c2SCharles.Forsyth  */
78474a4d8c2SCharles.Forsyth int
localsym(Symbol * s,int index)78574a4d8c2SCharles.Forsyth localsym(Symbol *s, int index)
78674a4d8c2SCharles.Forsyth {
78774a4d8c2SCharles.Forsyth 	Txtsym *tp;
78874a4d8c2SCharles.Forsyth 
789*d67b7dadSforsyth 	if(s == 0 || index < 0)
79074a4d8c2SCharles.Forsyth 		return 0;
79174a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
79274a4d8c2SCharles.Forsyth 		return 0;
79374a4d8c2SCharles.Forsyth 
79474a4d8c2SCharles.Forsyth 	tp = (Txtsym *)s->handle;
79574a4d8c2SCharles.Forsyth 	if(tp && tp->locals && index < tp->n) {
79674a4d8c2SCharles.Forsyth 		fillsym(tp->locals[tp->n-index-1], s);	/* reverse */
79774a4d8c2SCharles.Forsyth 		s->handle = (void *)tp;
798*d67b7dadSforsyth 		s->index = index;
79974a4d8c2SCharles.Forsyth 		return 1;
80074a4d8c2SCharles.Forsyth 	}
80174a4d8c2SCharles.Forsyth 	return 0;
80274a4d8c2SCharles.Forsyth }
803*d67b7dadSforsyth 
80474a4d8c2SCharles.Forsyth /*
80574a4d8c2SCharles.Forsyth  * get the ith global symbol
80674a4d8c2SCharles.Forsyth  */
80774a4d8c2SCharles.Forsyth int
globalsym(Symbol * s,int index)80874a4d8c2SCharles.Forsyth globalsym(Symbol *s, int index)
80974a4d8c2SCharles.Forsyth {
81074a4d8c2SCharles.Forsyth 	if(s == 0)
81174a4d8c2SCharles.Forsyth 		return 0;
81274a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
81374a4d8c2SCharles.Forsyth 		return 0;
81474a4d8c2SCharles.Forsyth 
815*d67b7dadSforsyth 	if(index >=0 && index < nglob) {
81674a4d8c2SCharles.Forsyth 		fillsym(globals[index], s);
817*d67b7dadSforsyth 		s->index = index;
81874a4d8c2SCharles.Forsyth 		return 1;
81974a4d8c2SCharles.Forsyth 	}
82074a4d8c2SCharles.Forsyth 	return 0;
82174a4d8c2SCharles.Forsyth }
822*d67b7dadSforsyth 
82374a4d8c2SCharles.Forsyth /*
82474a4d8c2SCharles.Forsyth  *	find the pc given a file name and line offset into it.
82574a4d8c2SCharles.Forsyth  */
826*d67b7dadSforsyth uvlong
file2pc(char * file,long line)827*d67b7dadSforsyth file2pc(char *file, long line)
82874a4d8c2SCharles.Forsyth {
82974a4d8c2SCharles.Forsyth 	File *fp;
830*d67b7dadSforsyth 	long i;
831*d67b7dadSforsyth 	uvlong pc, start, end;
83274a4d8c2SCharles.Forsyth 	short *name;
83374a4d8c2SCharles.Forsyth 
83474a4d8c2SCharles.Forsyth 	if(buildtbls() == 0 || files == 0)
835*d67b7dadSforsyth 		return ~0;
83674a4d8c2SCharles.Forsyth 	name = encfname(file);
83774a4d8c2SCharles.Forsyth 	if(name == 0) {			/* encode the file name */
83874a4d8c2SCharles.Forsyth 		werrstr("file %s not found", file);
839*d67b7dadSforsyth 		return ~0;
84074a4d8c2SCharles.Forsyth 	}
84174a4d8c2SCharles.Forsyth 		/* find this history stack */
84274a4d8c2SCharles.Forsyth 	for(i = 0, fp = files; i < nfiles; i++, fp++)
84374a4d8c2SCharles.Forsyth 		if (hline(fp, name, &line))
84474a4d8c2SCharles.Forsyth 			break;
84574a4d8c2SCharles.Forsyth 	free(name);
84674a4d8c2SCharles.Forsyth 	if(i >= nfiles) {
84774a4d8c2SCharles.Forsyth 		werrstr("line %ld in file %s not found", line, file);
848*d67b7dadSforsyth 		return ~0;
84974a4d8c2SCharles.Forsyth 	}
85074a4d8c2SCharles.Forsyth 	start = fp->addr;		/* first text addr this file */
85174a4d8c2SCharles.Forsyth 	if(i < nfiles-1)
85274a4d8c2SCharles.Forsyth 		end = (fp+1)->addr;	/* first text addr next file */
85374a4d8c2SCharles.Forsyth 	else
85474a4d8c2SCharles.Forsyth 		end = 0;		/* last file in load module */
85574a4d8c2SCharles.Forsyth 	/*
85674a4d8c2SCharles.Forsyth 	 * At this point, line contains the offset into the file.
85774a4d8c2SCharles.Forsyth 	 * run the state machine to locate the pc closest to that value.
85874a4d8c2SCharles.Forsyth 	 */
85974a4d8c2SCharles.Forsyth 	if(debug)
860*d67b7dadSforsyth 		print("find pc for %ld - between: %llux and %llux\n", line, start, end);
86174a4d8c2SCharles.Forsyth 	pc = line2addr(line, start, end);
862*d67b7dadSforsyth 	if(pc == ~0) {
86374a4d8c2SCharles.Forsyth 		werrstr("line %ld not in file %s", line, file);
864*d67b7dadSforsyth 		return ~0;
86574a4d8c2SCharles.Forsyth 	}
86674a4d8c2SCharles.Forsyth 	return pc;
86774a4d8c2SCharles.Forsyth }
868*d67b7dadSforsyth 
86974a4d8c2SCharles.Forsyth /*
87074a4d8c2SCharles.Forsyth  *	search for a path component index
87174a4d8c2SCharles.Forsyth  */
87274a4d8c2SCharles.Forsyth static int
pathcomp(char * s,int n)87374a4d8c2SCharles.Forsyth pathcomp(char *s, int n)
87474a4d8c2SCharles.Forsyth {
87574a4d8c2SCharles.Forsyth 	int i;
87674a4d8c2SCharles.Forsyth 
877fb67f84dSCharles.Forsyth 	for(i = 0; i <= fpmax; i++)
878*d67b7dadSforsyth 		if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
87974a4d8c2SCharles.Forsyth 			return i;
88074a4d8c2SCharles.Forsyth 	return -1;
88174a4d8c2SCharles.Forsyth }
882*d67b7dadSforsyth 
88374a4d8c2SCharles.Forsyth /*
88474a4d8c2SCharles.Forsyth  *	Encode a char file name as a sequence of short indices
88574a4d8c2SCharles.Forsyth  *	into the file name dictionary.
88674a4d8c2SCharles.Forsyth  */
88774a4d8c2SCharles.Forsyth static short*
encfname(char * file)88874a4d8c2SCharles.Forsyth encfname(char *file)
88974a4d8c2SCharles.Forsyth {
89074a4d8c2SCharles.Forsyth 	int i, j;
89174a4d8c2SCharles.Forsyth 	char *cp, *cp2;
89274a4d8c2SCharles.Forsyth 	short *dest;
89374a4d8c2SCharles.Forsyth 
89474a4d8c2SCharles.Forsyth 	if(*file == '/')	/* always check first '/' */
89574a4d8c2SCharles.Forsyth 		cp2 = file+1;
89674a4d8c2SCharles.Forsyth 	else {
89774a4d8c2SCharles.Forsyth 		cp2 = strchr(file, '/');
89874a4d8c2SCharles.Forsyth 		if(!cp2)
89974a4d8c2SCharles.Forsyth 			cp2 = strchr(file, 0);
90074a4d8c2SCharles.Forsyth 	}
90174a4d8c2SCharles.Forsyth 	cp = file;
90274a4d8c2SCharles.Forsyth 	dest = 0;
90374a4d8c2SCharles.Forsyth 	for(i = 0; *cp; i++) {
90474a4d8c2SCharles.Forsyth 		j = pathcomp(cp, cp2-cp);
90574a4d8c2SCharles.Forsyth 		if(j < 0)
90674a4d8c2SCharles.Forsyth 			return 0;	/* not found */
90774a4d8c2SCharles.Forsyth 		dest = realloc(dest, (i+1)*sizeof(short));
90874a4d8c2SCharles.Forsyth 		dest[i] = j;
90974a4d8c2SCharles.Forsyth 		cp = cp2;
91074a4d8c2SCharles.Forsyth 		while(*cp == '/')	/* skip embedded '/'s */
91174a4d8c2SCharles.Forsyth 			cp++;
91274a4d8c2SCharles.Forsyth 		cp2 = strchr(cp, '/');
91374a4d8c2SCharles.Forsyth 		if(!cp2)
91474a4d8c2SCharles.Forsyth 			cp2 = strchr(cp, 0);
91574a4d8c2SCharles.Forsyth 	}
91674a4d8c2SCharles.Forsyth 	dest = realloc(dest, (i+1)*sizeof(short));
91774a4d8c2SCharles.Forsyth 	dest[i] = 0;
91874a4d8c2SCharles.Forsyth 	return dest;
91974a4d8c2SCharles.Forsyth }
920*d67b7dadSforsyth 
92174a4d8c2SCharles.Forsyth /*
92274a4d8c2SCharles.Forsyth  *	Search a history stack for a matching file name accumulating
92374a4d8c2SCharles.Forsyth  *	the size of intervening files in the stack.
92474a4d8c2SCharles.Forsyth  */
92574a4d8c2SCharles.Forsyth static int
hline(File * fp,short * name,long * line)926*d67b7dadSforsyth hline(File *fp, short *name, long *line)
92774a4d8c2SCharles.Forsyth {
92874a4d8c2SCharles.Forsyth 	Hist *hp;
92974a4d8c2SCharles.Forsyth 	int offset, depth;
93074a4d8c2SCharles.Forsyth 	long ln;
93174a4d8c2SCharles.Forsyth 
93274a4d8c2SCharles.Forsyth 	for(hp = fp->hist; hp->name; hp++)		/* find name in stack */
93374a4d8c2SCharles.Forsyth 		if(hp->name[1] || hp->name[2]) {
93474a4d8c2SCharles.Forsyth 			if(hcomp(hp, name))
93574a4d8c2SCharles.Forsyth 				break;
93674a4d8c2SCharles.Forsyth 		}
93774a4d8c2SCharles.Forsyth 	if(!hp->name)		/* match not found */
93874a4d8c2SCharles.Forsyth 		return 0;
93974a4d8c2SCharles.Forsyth 	if(debug)
94074a4d8c2SCharles.Forsyth 		printhist("hline found ... ", hp, 1);
94174a4d8c2SCharles.Forsyth 	/*
94274a4d8c2SCharles.Forsyth 	 * unwind the stack until empty or we hit an entry beyond our line
94374a4d8c2SCharles.Forsyth 	 */
94474a4d8c2SCharles.Forsyth 	ln = *line;
94574a4d8c2SCharles.Forsyth 	offset = hp->line-1;
94674a4d8c2SCharles.Forsyth 	depth = 1;
94774a4d8c2SCharles.Forsyth 	for(hp++; depth && hp->name; hp++) {
94874a4d8c2SCharles.Forsyth 		if(debug)
94974a4d8c2SCharles.Forsyth 			printhist("hline inspect ... ", hp, 1);
95074a4d8c2SCharles.Forsyth 		if(hp->name[1] || hp->name[2]) {
95174a4d8c2SCharles.Forsyth 			if(hp->offset){			/* Z record */
95274a4d8c2SCharles.Forsyth 				offset = 0;
95374a4d8c2SCharles.Forsyth 				if(hcomp(hp, name)) {
95474a4d8c2SCharles.Forsyth 					if(*line <= hp->offset)
95574a4d8c2SCharles.Forsyth 						break;
95674a4d8c2SCharles.Forsyth 					ln = *line+hp->line-hp->offset;
95774a4d8c2SCharles.Forsyth 					depth = 1;	/* implicit pop */
95874a4d8c2SCharles.Forsyth 				} else
95974a4d8c2SCharles.Forsyth 					depth = 2;	/* implicit push */
96074a4d8c2SCharles.Forsyth 			} else if(depth == 1 && ln < hp->line-offset)
96174a4d8c2SCharles.Forsyth 					break;		/* Beyond our line */
96274a4d8c2SCharles.Forsyth 			else if(depth++ == 1)		/* push	*/
96374a4d8c2SCharles.Forsyth 				offset -= hp->line;
96474a4d8c2SCharles.Forsyth 		} else if(--depth == 1)		/* pop */
96574a4d8c2SCharles.Forsyth 			offset += hp->line;
96674a4d8c2SCharles.Forsyth 	}
96774a4d8c2SCharles.Forsyth 	*line = ln+offset;
96874a4d8c2SCharles.Forsyth 	return 1;
96974a4d8c2SCharles.Forsyth }
970*d67b7dadSforsyth 
97174a4d8c2SCharles.Forsyth /*
97274a4d8c2SCharles.Forsyth  *	compare two encoded file names
97374a4d8c2SCharles.Forsyth  */
97474a4d8c2SCharles.Forsyth static int
hcomp(Hist * hp,short * sp)97574a4d8c2SCharles.Forsyth hcomp(Hist *hp, short *sp)
97674a4d8c2SCharles.Forsyth {
97774a4d8c2SCharles.Forsyth 	uchar *cp;
97874a4d8c2SCharles.Forsyth 	int i, j;
97974a4d8c2SCharles.Forsyth 	short *s;
98074a4d8c2SCharles.Forsyth 
98174a4d8c2SCharles.Forsyth 	cp = (uchar *)hp->name;
98274a4d8c2SCharles.Forsyth 	s = sp;
98374a4d8c2SCharles.Forsyth 	if (*s == 0)
98474a4d8c2SCharles.Forsyth 		return 0;
98574a4d8c2SCharles.Forsyth 	for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
98674a4d8c2SCharles.Forsyth 		if(j == 0)
98774a4d8c2SCharles.Forsyth 			break;
98874a4d8c2SCharles.Forsyth 		if(*s == j)
98974a4d8c2SCharles.Forsyth 			s++;
99074a4d8c2SCharles.Forsyth 		else
99174a4d8c2SCharles.Forsyth 			s = sp;
99274a4d8c2SCharles.Forsyth 	}
99374a4d8c2SCharles.Forsyth 	return *s == 0;
99474a4d8c2SCharles.Forsyth }
995*d67b7dadSforsyth 
99674a4d8c2SCharles.Forsyth /*
99774a4d8c2SCharles.Forsyth  *	Convert a pc to a "file:line {file:line}" string.
99874a4d8c2SCharles.Forsyth  */
999*d67b7dadSforsyth long
fileline(char * str,int n,uvlong dot)1000*d67b7dadSforsyth fileline(char *str, int n, uvlong dot)
100174a4d8c2SCharles.Forsyth {
1002*d67b7dadSforsyth 	long line, top, bot, mid;
100374a4d8c2SCharles.Forsyth 	File *f;
100474a4d8c2SCharles.Forsyth 
100574a4d8c2SCharles.Forsyth 	*str = 0;
100674a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
100774a4d8c2SCharles.Forsyth 		return 0;
100874a4d8c2SCharles.Forsyth 		/* binary search assumes file list is sorted by addr */
100974a4d8c2SCharles.Forsyth 	bot = 0;
101074a4d8c2SCharles.Forsyth 	top = nfiles;
101174a4d8c2SCharles.Forsyth 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
101274a4d8c2SCharles.Forsyth 		f = &files[mid];
101374a4d8c2SCharles.Forsyth 		if(dot < f->addr)
101474a4d8c2SCharles.Forsyth 			top = mid;
101574a4d8c2SCharles.Forsyth 		else if(mid < nfiles-1 && dot >= (f+1)->addr)
101674a4d8c2SCharles.Forsyth 			bot = mid;
1017*d67b7dadSforsyth 		else {
1018*d67b7dadSforsyth 			line = pc2line(dot);
1019*d67b7dadSforsyth 			if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
1020*d67b7dadSforsyth 				return 1;
1021*d67b7dadSforsyth 			break;
102274a4d8c2SCharles.Forsyth 		}
1023*d67b7dadSforsyth 	}
1024*d67b7dadSforsyth 	return 0;
102574a4d8c2SCharles.Forsyth }
102674a4d8c2SCharles.Forsyth 
102774a4d8c2SCharles.Forsyth /*
102874a4d8c2SCharles.Forsyth  *	Convert a line number within a composite file to relative line
102974a4d8c2SCharles.Forsyth  *	number in a source file.  A composite file is the source
103074a4d8c2SCharles.Forsyth  *	file with included files inserted in line.
103174a4d8c2SCharles.Forsyth  */
103274a4d8c2SCharles.Forsyth static int
fline(char * str,int n,long line,Hist * base,Hist ** ret)103374a4d8c2SCharles.Forsyth fline(char *str, int n, long line, Hist *base, Hist **ret)
103474a4d8c2SCharles.Forsyth {
103574a4d8c2SCharles.Forsyth 	Hist *start;			/* start of current level */
103674a4d8c2SCharles.Forsyth 	Hist *h;			/* current entry */
1037*d67b7dadSforsyth 	long delta;			/* sum of size of files this level */
103874a4d8c2SCharles.Forsyth 	int k;
103974a4d8c2SCharles.Forsyth 
104074a4d8c2SCharles.Forsyth 	start = base;
104174a4d8c2SCharles.Forsyth 	h = base;
104274a4d8c2SCharles.Forsyth 	delta = h->line;
104374a4d8c2SCharles.Forsyth 	while(h && h->name && line > h->line) {
104474a4d8c2SCharles.Forsyth 		if(h->name[1] || h->name[2]) {
104574a4d8c2SCharles.Forsyth 			if(h->offset != 0) {	/* #line Directive */
104674a4d8c2SCharles.Forsyth 				delta = h->line-h->offset+1;
104774a4d8c2SCharles.Forsyth 				start = h;
104874a4d8c2SCharles.Forsyth 				base = h++;
104974a4d8c2SCharles.Forsyth 			} else {		/* beginning of File */
105074a4d8c2SCharles.Forsyth 				if(start == base)
105174a4d8c2SCharles.Forsyth 					start = h++;
105274a4d8c2SCharles.Forsyth 				else {
105374a4d8c2SCharles.Forsyth 					k = fline(str, n, line, start, &h);
105474a4d8c2SCharles.Forsyth 					if(k <= 0)
105574a4d8c2SCharles.Forsyth 						return k;
105674a4d8c2SCharles.Forsyth 				}
105774a4d8c2SCharles.Forsyth 			}
105874a4d8c2SCharles.Forsyth 		} else {
1059*d67b7dadSforsyth 			if(start == base && ret) {	/* end of recursion level */
106074a4d8c2SCharles.Forsyth 				*ret = h;
106174a4d8c2SCharles.Forsyth 				return 1;
106274a4d8c2SCharles.Forsyth 			} else {			/* end of included file */
106374a4d8c2SCharles.Forsyth 				delta += h->line-start->line;
106474a4d8c2SCharles.Forsyth 				h++;
106574a4d8c2SCharles.Forsyth 				start = base;
106674a4d8c2SCharles.Forsyth 			}
106774a4d8c2SCharles.Forsyth 		}
106874a4d8c2SCharles.Forsyth 	}
106974a4d8c2SCharles.Forsyth 	if(!h)
107074a4d8c2SCharles.Forsyth 		return -1;
107174a4d8c2SCharles.Forsyth 	if(start != base)
107274a4d8c2SCharles.Forsyth 		line = line-start->line+1;
107374a4d8c2SCharles.Forsyth 	else
107474a4d8c2SCharles.Forsyth 		line = line-delta+1;
107574a4d8c2SCharles.Forsyth 	if(!h->name)
107674a4d8c2SCharles.Forsyth 		strncpy(str, "<eof>", n);
107774a4d8c2SCharles.Forsyth 	else {
107874a4d8c2SCharles.Forsyth 		k = fileelem(fnames, (uchar*)start->name, str, n);
107974a4d8c2SCharles.Forsyth 		if(k+8 < n)
108074a4d8c2SCharles.Forsyth 			sprint(str+k, ":%ld", line);
108174a4d8c2SCharles.Forsyth 	}
108274a4d8c2SCharles.Forsyth /**********Remove comments for complete back-trace of include sequence
108374a4d8c2SCharles.Forsyth  *	if(start != base) {
108474a4d8c2SCharles.Forsyth  *		k = strlen(str);
108574a4d8c2SCharles.Forsyth  *		if(k+2 < n) {
108674a4d8c2SCharles.Forsyth  *			str[k++] = ' ';
108774a4d8c2SCharles.Forsyth  *			str[k++] = '{';
108874a4d8c2SCharles.Forsyth  *		}
108974a4d8c2SCharles.Forsyth  *		k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
109074a4d8c2SCharles.Forsyth  *		if(k+10 < n)
109174a4d8c2SCharles.Forsyth  *			sprint(str+k, ":%ld}", start->line-delta);
109274a4d8c2SCharles.Forsyth  *	}
109374a4d8c2SCharles.Forsyth  ********************/
109474a4d8c2SCharles.Forsyth 	return 0;
109574a4d8c2SCharles.Forsyth }
1096*d67b7dadSforsyth 
109774a4d8c2SCharles.Forsyth /*
109874a4d8c2SCharles.Forsyth  *	convert an encoded file name to a string.
109974a4d8c2SCharles.Forsyth  */
110074a4d8c2SCharles.Forsyth int
fileelem(Sym ** fp,uchar * cp,char * buf,int n)110174a4d8c2SCharles.Forsyth fileelem(Sym **fp, uchar *cp, char *buf, int n)
110274a4d8c2SCharles.Forsyth {
110374a4d8c2SCharles.Forsyth 	int i, j;
110474a4d8c2SCharles.Forsyth 	char *c, *bp, *end;
110574a4d8c2SCharles.Forsyth 
110674a4d8c2SCharles.Forsyth 	bp = buf;
110774a4d8c2SCharles.Forsyth 	end = buf+n-1;
110874a4d8c2SCharles.Forsyth 	for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
110974a4d8c2SCharles.Forsyth 		c = fp[j]->name;
111074a4d8c2SCharles.Forsyth 		if(bp != buf && bp[-1] != '/' && bp < end)
111174a4d8c2SCharles.Forsyth 			*bp++ = '/';
111274a4d8c2SCharles.Forsyth 		while(bp < end && *c)
111374a4d8c2SCharles.Forsyth 			*bp++ = *c++;
111474a4d8c2SCharles.Forsyth 	}
111574a4d8c2SCharles.Forsyth 	*bp = 0;
1116*d67b7dadSforsyth 	i =  bp-buf;
1117*d67b7dadSforsyth 	if(i > 1) {
1118*d67b7dadSforsyth 		cleanname(buf);
1119*d67b7dadSforsyth 		i = strlen(buf);
112074a4d8c2SCharles.Forsyth 	}
1121*d67b7dadSforsyth 	return i;
1122*d67b7dadSforsyth }
1123*d67b7dadSforsyth 
112474a4d8c2SCharles.Forsyth /*
112574a4d8c2SCharles.Forsyth  *	compare the values of two symbol table entries.
112674a4d8c2SCharles.Forsyth  */
112774a4d8c2SCharles.Forsyth static int
symcomp(void * a,void * b)112874a4d8c2SCharles.Forsyth symcomp(void *a, void *b)
112974a4d8c2SCharles.Forsyth {
1130*d67b7dadSforsyth 	int i;
1131*d67b7dadSforsyth 
1132*d67b7dadSforsyth 	i = (*(Sym**)a)->value - (*(Sym**)b)->value;
1133*d67b7dadSforsyth 	if (i)
1134*d67b7dadSforsyth 		return i;
1135*d67b7dadSforsyth 	return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
113674a4d8c2SCharles.Forsyth }
1137*d67b7dadSforsyth 
113874a4d8c2SCharles.Forsyth /*
113974a4d8c2SCharles.Forsyth  *	compare the values of the symbols referenced by two text table entries
114074a4d8c2SCharles.Forsyth  */
114174a4d8c2SCharles.Forsyth static int
txtcomp(void * a,void * b)114274a4d8c2SCharles.Forsyth txtcomp(void *a, void *b)
114374a4d8c2SCharles.Forsyth {
114474a4d8c2SCharles.Forsyth 	return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
114574a4d8c2SCharles.Forsyth }
1146*d67b7dadSforsyth 
114774a4d8c2SCharles.Forsyth /*
114874a4d8c2SCharles.Forsyth  *	compare the values of the symbols referenced by two file table entries
114974a4d8c2SCharles.Forsyth  */
115074a4d8c2SCharles.Forsyth static int
filecomp(void * a,void * b)115174a4d8c2SCharles.Forsyth filecomp(void *a, void *b)
115274a4d8c2SCharles.Forsyth {
115374a4d8c2SCharles.Forsyth 	return ((File*)a)->addr - ((File*)b)->addr;
115474a4d8c2SCharles.Forsyth }
1155*d67b7dadSforsyth 
115674a4d8c2SCharles.Forsyth /*
115774a4d8c2SCharles.Forsyth  *	fill an interface Symbol structure from a symbol table entry
115874a4d8c2SCharles.Forsyth  */
115974a4d8c2SCharles.Forsyth static void
fillsym(Sym * sp,Symbol * s)116074a4d8c2SCharles.Forsyth fillsym(Sym *sp, Symbol *s)
116174a4d8c2SCharles.Forsyth {
116274a4d8c2SCharles.Forsyth 	s->type = sp->type;
116374a4d8c2SCharles.Forsyth 	s->value = sp->value;
116474a4d8c2SCharles.Forsyth 	s->name = sp->name;
1165*d67b7dadSforsyth 	s->index = 0;
116674a4d8c2SCharles.Forsyth 	switch(sp->type) {
116774a4d8c2SCharles.Forsyth 	case 'b':
116874a4d8c2SCharles.Forsyth 	case 'B':
116974a4d8c2SCharles.Forsyth 	case 'D':
117074a4d8c2SCharles.Forsyth 	case 'd':
117174a4d8c2SCharles.Forsyth 		s->class = CDATA;
117274a4d8c2SCharles.Forsyth 		break;
117374a4d8c2SCharles.Forsyth 	case 't':
117474a4d8c2SCharles.Forsyth 	case 'T':
117574a4d8c2SCharles.Forsyth 	case 'l':
117674a4d8c2SCharles.Forsyth 	case 'L':
117774a4d8c2SCharles.Forsyth 		s->class = CTEXT;
117874a4d8c2SCharles.Forsyth 		break;
117974a4d8c2SCharles.Forsyth 	case 'a':
118074a4d8c2SCharles.Forsyth 		s->class = CAUTO;
118174a4d8c2SCharles.Forsyth 		break;
118274a4d8c2SCharles.Forsyth 	case 'p':
118374a4d8c2SCharles.Forsyth 		s->class = CPARAM;
118474a4d8c2SCharles.Forsyth 		break;
118574a4d8c2SCharles.Forsyth 	case 'm':
118674a4d8c2SCharles.Forsyth 		s->class = CSTAB;
118774a4d8c2SCharles.Forsyth 		break;
118874a4d8c2SCharles.Forsyth 	default:
118974a4d8c2SCharles.Forsyth 		s->class = CNONE;
119074a4d8c2SCharles.Forsyth 		break;
119174a4d8c2SCharles.Forsyth 	}
119274a4d8c2SCharles.Forsyth 	s->handle = 0;
119374a4d8c2SCharles.Forsyth }
1194*d67b7dadSforsyth 
119574a4d8c2SCharles.Forsyth /*
119674a4d8c2SCharles.Forsyth  *	find the stack frame, given the pc
119774a4d8c2SCharles.Forsyth  */
1198*d67b7dadSforsyth uvlong
pc2sp(uvlong pc)1199*d67b7dadSforsyth pc2sp(uvlong pc)
120074a4d8c2SCharles.Forsyth {
1201*d67b7dadSforsyth 	uchar *c, u;
1202*d67b7dadSforsyth 	uvlong currpc, currsp;
120374a4d8c2SCharles.Forsyth 
120474a4d8c2SCharles.Forsyth 	if(spoff == 0)
1205*d67b7dadSforsyth 		return ~0;
120674a4d8c2SCharles.Forsyth 	currsp = 0;
120774a4d8c2SCharles.Forsyth 	currpc = txtstart - mach->pcquant;
120874a4d8c2SCharles.Forsyth 
120974a4d8c2SCharles.Forsyth 	if(pc<currpc || pc>txtend)
1210*d67b7dadSforsyth 		return ~0;
121174a4d8c2SCharles.Forsyth 	for(c = spoff; c < spoffend; c++) {
121274a4d8c2SCharles.Forsyth 		if (currpc >= pc)
121374a4d8c2SCharles.Forsyth 			return currsp;
121474a4d8c2SCharles.Forsyth 		u = *c;
121574a4d8c2SCharles.Forsyth 		if (u == 0) {
121674a4d8c2SCharles.Forsyth 			currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
121774a4d8c2SCharles.Forsyth 			c += 4;
121874a4d8c2SCharles.Forsyth 		}
121974a4d8c2SCharles.Forsyth 		else if (u < 65)
122074a4d8c2SCharles.Forsyth 			currsp += 4*u;
122174a4d8c2SCharles.Forsyth 		else if (u < 129)
122274a4d8c2SCharles.Forsyth 			currsp -= 4*(u-64);
122374a4d8c2SCharles.Forsyth 		else
122474a4d8c2SCharles.Forsyth 			currpc += mach->pcquant*(u-129);
122574a4d8c2SCharles.Forsyth 		currpc += mach->pcquant;
122674a4d8c2SCharles.Forsyth 	}
1227*d67b7dadSforsyth 	return ~0;
122874a4d8c2SCharles.Forsyth }
1229*d67b7dadSforsyth 
123074a4d8c2SCharles.Forsyth /*
123174a4d8c2SCharles.Forsyth  *	find the source file line number for a given value of the pc
123274a4d8c2SCharles.Forsyth  */
123374a4d8c2SCharles.Forsyth long
pc2line(uvlong pc)1234*d67b7dadSforsyth pc2line(uvlong pc)
123574a4d8c2SCharles.Forsyth {
1236*d67b7dadSforsyth 	uchar *c, u;
1237*d67b7dadSforsyth 	uvlong currpc;
123874a4d8c2SCharles.Forsyth 	long currline;
123974a4d8c2SCharles.Forsyth 
1240*d67b7dadSforsyth 	if(pcline == 0)
124174a4d8c2SCharles.Forsyth 		return -1;
1242*d67b7dadSforsyth 	currline = 0;
1243*d67b7dadSforsyth 	currpc = txtstart-mach->pcquant;
124474a4d8c2SCharles.Forsyth 	if(pc<currpc || pc>txtend)
1245*d67b7dadSforsyth 		return ~0;
1246*d67b7dadSforsyth 
1247*d67b7dadSforsyth 	for(c = pcline; c < pclineend; c++) {
1248*d67b7dadSforsyth 		if(currpc >= pc)
124974a4d8c2SCharles.Forsyth 			return currline;
125074a4d8c2SCharles.Forsyth 		u = *c;
125174a4d8c2SCharles.Forsyth 		if(u == 0) {
125274a4d8c2SCharles.Forsyth 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
125374a4d8c2SCharles.Forsyth 			c += 4;
125474a4d8c2SCharles.Forsyth 		}
125574a4d8c2SCharles.Forsyth 		else if(u < 65)
125674a4d8c2SCharles.Forsyth 			currline += u;
125774a4d8c2SCharles.Forsyth 		else if(u < 129)
125874a4d8c2SCharles.Forsyth 			currline -= (u-64);
125974a4d8c2SCharles.Forsyth 		else
126074a4d8c2SCharles.Forsyth 			currpc += mach->pcquant*(u-129);
126174a4d8c2SCharles.Forsyth 		currpc += mach->pcquant;
126274a4d8c2SCharles.Forsyth 	}
1263*d67b7dadSforsyth 	return ~0;
126474a4d8c2SCharles.Forsyth }
1265*d67b7dadSforsyth 
126674a4d8c2SCharles.Forsyth /*
126774a4d8c2SCharles.Forsyth  *	find the pc associated with a line number
126874a4d8c2SCharles.Forsyth  *	basepc and endpc are text addresses bounding the search.
126974a4d8c2SCharles.Forsyth  *	if endpc == 0, the end of the table is used (i.e., no upper bound).
127074a4d8c2SCharles.Forsyth  *	usually, basepc and endpc contain the first text address in
127174a4d8c2SCharles.Forsyth  *	a file and the first text address in the following file, respectively.
127274a4d8c2SCharles.Forsyth  */
1273*d67b7dadSforsyth uvlong
line2addr(long line,uvlong basepc,uvlong endpc)1274*d67b7dadSforsyth line2addr(long line, uvlong basepc, uvlong endpc)
127574a4d8c2SCharles.Forsyth {
1276*d67b7dadSforsyth 	uchar *c,  u;
1277*d67b7dadSforsyth 	uvlong currpc, pc;
127874a4d8c2SCharles.Forsyth 	long currline;
127974a4d8c2SCharles.Forsyth 	long delta, d;
1280*d67b7dadSforsyth 	int found;
128174a4d8c2SCharles.Forsyth 
128274a4d8c2SCharles.Forsyth 	if(pcline == 0 || line == 0)
1283*d67b7dadSforsyth 		return ~0;
128474a4d8c2SCharles.Forsyth 
128574a4d8c2SCharles.Forsyth 	currline = 0;
128674a4d8c2SCharles.Forsyth 	currpc = txtstart-mach->pcquant;
1287*d67b7dadSforsyth 	pc = ~0;
128874a4d8c2SCharles.Forsyth 	found = 0;
128974a4d8c2SCharles.Forsyth 	delta = HUGEINT;
129074a4d8c2SCharles.Forsyth 
129174a4d8c2SCharles.Forsyth 	for(c = pcline; c < pclineend; c++) {
129274a4d8c2SCharles.Forsyth 		if(endpc && currpc >= endpc)	/* end of file of interest */
129374a4d8c2SCharles.Forsyth 			break;
129474a4d8c2SCharles.Forsyth 		if(currpc >= basepc) {		/* proper file */
129574a4d8c2SCharles.Forsyth 			if(currline >= line) {
129674a4d8c2SCharles.Forsyth 				d = currline-line;
129774a4d8c2SCharles.Forsyth 				found = 1;
129874a4d8c2SCharles.Forsyth 			} else
129974a4d8c2SCharles.Forsyth 				d = line-currline;
130074a4d8c2SCharles.Forsyth 			if(d < delta) {
130174a4d8c2SCharles.Forsyth 				delta = d;
130274a4d8c2SCharles.Forsyth 				pc = currpc;
130374a4d8c2SCharles.Forsyth 			}
130474a4d8c2SCharles.Forsyth 		}
130574a4d8c2SCharles.Forsyth 		u = *c;
130674a4d8c2SCharles.Forsyth 		if(u == 0) {
130774a4d8c2SCharles.Forsyth 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
130874a4d8c2SCharles.Forsyth 			c += 4;
130974a4d8c2SCharles.Forsyth 		}
131074a4d8c2SCharles.Forsyth 		else if(u < 65)
131174a4d8c2SCharles.Forsyth 			currline += u;
131274a4d8c2SCharles.Forsyth 		else if(u < 129)
131374a4d8c2SCharles.Forsyth 			currline -= (u-64);
131474a4d8c2SCharles.Forsyth 		else
131574a4d8c2SCharles.Forsyth 			currpc += mach->pcquant*(u-129);
131674a4d8c2SCharles.Forsyth 		currpc += mach->pcquant;
131774a4d8c2SCharles.Forsyth 	}
131874a4d8c2SCharles.Forsyth 	if(found)
131974a4d8c2SCharles.Forsyth 		return pc;
1320*d67b7dadSforsyth 	return ~0;
132174a4d8c2SCharles.Forsyth }
1322*d67b7dadSforsyth 
132374a4d8c2SCharles.Forsyth /*
132474a4d8c2SCharles.Forsyth  *	Print a history stack (debug). if count is 0, prints the whole stack
132574a4d8c2SCharles.Forsyth  */
132674a4d8c2SCharles.Forsyth static void
printhist(char * msg,Hist * hp,int count)132774a4d8c2SCharles.Forsyth printhist(char *msg, Hist *hp, int count)
132874a4d8c2SCharles.Forsyth {
132974a4d8c2SCharles.Forsyth 	int i;
133074a4d8c2SCharles.Forsyth 	uchar *cp;
133174a4d8c2SCharles.Forsyth 	char buf[128];
133274a4d8c2SCharles.Forsyth 
133374a4d8c2SCharles.Forsyth 	i = 0;
133474a4d8c2SCharles.Forsyth 	while(hp->name) {
133574a4d8c2SCharles.Forsyth 		if(count && ++i > count)
133674a4d8c2SCharles.Forsyth 			break;
1337*d67b7dadSforsyth 		print("%s Line: %lx (%ld)  Offset: %lx (%ld)  Name: ", msg,
133874a4d8c2SCharles.Forsyth 			hp->line, hp->line, hp->offset, hp->offset);
133974a4d8c2SCharles.Forsyth 		for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
134074a4d8c2SCharles.Forsyth 			if (cp != (uchar *)hp->name+1)
1341*d67b7dadSforsyth 				print("/");
1342*d67b7dadSforsyth 			print("%x", (*cp<<8)|cp[1]);
134374a4d8c2SCharles.Forsyth 		}
134474a4d8c2SCharles.Forsyth 		fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
1345*d67b7dadSforsyth 		print(" (%s)\n", buf);
134674a4d8c2SCharles.Forsyth 		hp++;
134774a4d8c2SCharles.Forsyth 	}
134874a4d8c2SCharles.Forsyth }
134974a4d8c2SCharles.Forsyth 
135074a4d8c2SCharles.Forsyth #ifdef DEBUG
135174a4d8c2SCharles.Forsyth /*
135274a4d8c2SCharles.Forsyth  *	print the history stack for a file. (debug only)
135374a4d8c2SCharles.Forsyth  *	if (name == 0) => print all history stacks.
135474a4d8c2SCharles.Forsyth  */
135574a4d8c2SCharles.Forsyth void
dumphist(char * name)135674a4d8c2SCharles.Forsyth dumphist(char *name)
135774a4d8c2SCharles.Forsyth {
135874a4d8c2SCharles.Forsyth 	int i;
135974a4d8c2SCharles.Forsyth 	File *f;
136074a4d8c2SCharles.Forsyth 	short *fname;
136174a4d8c2SCharles.Forsyth 
136274a4d8c2SCharles.Forsyth 	if(buildtbls() == 0)
136374a4d8c2SCharles.Forsyth 		return;
136474a4d8c2SCharles.Forsyth 	if(name)
136574a4d8c2SCharles.Forsyth 		fname = encfname(name);
136674a4d8c2SCharles.Forsyth 	for(i = 0, f = files; i < nfiles; i++, f++)
136774a4d8c2SCharles.Forsyth 		if(fname == 0 || hcomp(f->hist, fname))
136874a4d8c2SCharles.Forsyth 			printhist("> ", f->hist, f->n);
136974a4d8c2SCharles.Forsyth 
137074a4d8c2SCharles.Forsyth 	if(fname)
137174a4d8c2SCharles.Forsyth 		free(fname);
137274a4d8c2SCharles.Forsyth }
137374a4d8c2SCharles.Forsyth #endif
1374