xref: /plan9/sys/src/libmach/sym.c (revision 8ccc32ef0b9b7222ff49b683668eb07a18989e02)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3bd389b36SDavid du Colombier #include <bio.h>
43e12c5d1SDavid du Colombier #include <mach.h>
53e12c5d1SDavid du Colombier 
6bd389b36SDavid du Colombier #define	HUGEINT	0x7fffffff
7219b2ee8SDavid du Colombier #define	NNAME	20		/* a relic of the past */
8bd389b36SDavid du Colombier 
9219b2ee8SDavid du Colombier typedef	struct txtsym Txtsym;
10219b2ee8SDavid du Colombier typedef	struct file File;
11219b2ee8SDavid du Colombier typedef	struct hist Hist;
123e12c5d1SDavid du Colombier 
13219b2ee8SDavid du Colombier struct txtsym {				/* Text Symbol table */
14219b2ee8SDavid du Colombier 	int 	n;			/* number of local vars */
15219b2ee8SDavid du Colombier 	Sym	**locals;		/* array of ptrs to autos */
16219b2ee8SDavid du Colombier 	Sym	*sym;			/* function symbol entry */
17219b2ee8SDavid du Colombier };
18219b2ee8SDavid du Colombier 
19219b2ee8SDavid du Colombier struct hist {				/* Stack of include files & #line directives */
20219b2ee8SDavid du Colombier 	char	*name;			/* Assumes names Null terminated in file */
21219b2ee8SDavid du Colombier 	long	line;			/* line # where it was included */
22219b2ee8SDavid du Colombier 	long	offset;			/* line # of #line directive */
23219b2ee8SDavid du Colombier };
24219b2ee8SDavid du Colombier 
25219b2ee8SDavid du Colombier struct file {				/* Per input file header to history stack */
264de34a7eSDavid du Colombier 	uvlong	addr;			/* address of first text sym */
27219b2ee8SDavid du Colombier 	union {
28219b2ee8SDavid du Colombier 		Txtsym	*txt;		/* first text symbol */
29219b2ee8SDavid du Colombier 		Sym	*sym;		/* only during initilization */
30219b2ee8SDavid du Colombier 	};
31219b2ee8SDavid du Colombier 	int	n;			/* size of history stack */
32219b2ee8SDavid du Colombier 	Hist	*hist;			/* history stack */
33219b2ee8SDavid du Colombier };
34219b2ee8SDavid du Colombier 
35219b2ee8SDavid du Colombier static	int	debug = 0;
36219b2ee8SDavid du Colombier 
37219b2ee8SDavid du Colombier static	Sym	**autos;		/* Base of auto variables */
38219b2ee8SDavid du Colombier static	File	*files;			/* Base of file arena */
39219b2ee8SDavid du Colombier static	int	fmax;			/* largest file path index */
40219b2ee8SDavid du Colombier static	Sym	**fnames;		/* file names path component table */
41219b2ee8SDavid du Colombier static	Sym	**globals;		/* globals by addr table */
42219b2ee8SDavid du Colombier static	Hist	*hist;			/* base of history stack */
43219b2ee8SDavid du Colombier static	int	isbuilt;		/* internal table init flag */
44219b2ee8SDavid du Colombier static	long	nauto;			/* number of automatics */
45219b2ee8SDavid du Colombier static	long	nfiles;			/* number of files */
46219b2ee8SDavid du Colombier static	long	nglob;			/* number of globals */
47219b2ee8SDavid du Colombier static	long	nhist;			/* number of history stack entries */
483e12c5d1SDavid du Colombier static	long	nsym;			/* number of symbols */
49219b2ee8SDavid du Colombier static	int	ntxt;			/* number of text symbols */
50219b2ee8SDavid du Colombier static	uchar	*pcline;		/* start of pc-line state table */
513e12c5d1SDavid du Colombier static	uchar 	*pclineend;		/* end of pc-line table */
52219b2ee8SDavid du Colombier static	uchar	*spoff;			/* start of pc-sp state table */
53219b2ee8SDavid du Colombier static	uchar	*spoffend;		/* end of pc-sp offset table */
54219b2ee8SDavid du Colombier static	Sym	*symbols;		/* symbol table */
55219b2ee8SDavid du Colombier static	Txtsym	*txt;			/* Base of text symbol table */
564de34a7eSDavid du Colombier static	uvlong	txtstart;		/* start of text segment */
574de34a7eSDavid du Colombier static	uvlong	txtend;			/* end of text segment */
583e12c5d1SDavid du Colombier 
59219b2ee8SDavid du Colombier static void	cleansyms(void);
604de34a7eSDavid du Colombier static long	decodename(Biobuf*, Sym*);
61219b2ee8SDavid du Colombier static short	*encfname(char*);
627dd7cddfSDavid du Colombier static int 	fline(char*, int, long, Hist*, Hist**);
63219b2ee8SDavid du Colombier static void	fillsym(Sym*, Symbol*);
64219b2ee8SDavid du Colombier static int	findglobal(char*, Symbol*);
65219b2ee8SDavid du Colombier static int	findlocvar(Symbol*, char *, Symbol*);
66219b2ee8SDavid du Colombier static int	findtext(char*, Symbol*);
67219b2ee8SDavid du Colombier static int	hcomp(Hist*, short*);
684de34a7eSDavid du Colombier static int	hline(File*, short*, long*);
69219b2ee8SDavid du Colombier static void	printhist(char*, Hist*, int);
70219b2ee8SDavid du Colombier static int	buildtbls(void);
71219b2ee8SDavid du Colombier static int	symcomp(void*, void*);
72219b2ee8SDavid du Colombier static int	symerrmsg(int, char*);
73219b2ee8SDavid du Colombier static int	txtcomp(void*, void*);
74219b2ee8SDavid du Colombier static int	filecomp(void*, void*);
75219b2ee8SDavid du Colombier 
763e12c5d1SDavid du Colombier /*
773e12c5d1SDavid du Colombier  *	initialize the symbol tables
783e12c5d1SDavid du Colombier  */
793e12c5d1SDavid du Colombier int
syminit(int fd,Fhdr * fp)803e12c5d1SDavid du Colombier syminit(int fd, Fhdr *fp)
813e12c5d1SDavid du Colombier {
82219b2ee8SDavid du Colombier 	Sym *p;
834de34a7eSDavid du Colombier 	long i, l, size;
844de34a7eSDavid du Colombier 	vlong vl;
85219b2ee8SDavid du Colombier 	Biobuf b;
864de34a7eSDavid du Colombier 	int svalsz;
873e12c5d1SDavid du Colombier 
883e12c5d1SDavid du Colombier 	if(fp->symsz == 0)
893e12c5d1SDavid du Colombier 		return 0;
90219b2ee8SDavid du Colombier 	if(fp->type == FNONE)
91219b2ee8SDavid du Colombier 		return 0;
923e12c5d1SDavid du Colombier 
93219b2ee8SDavid du Colombier 	cleansyms();
94219b2ee8SDavid du Colombier 	textseg(fp->txtaddr, fp);
95219b2ee8SDavid du Colombier 		/* minimum symbol record size = 4+1+2 bytes */
96219b2ee8SDavid du Colombier 	symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
973e12c5d1SDavid du Colombier 	if(symbols == 0) {
987dd7cddfSDavid du Colombier 		werrstr("can't malloc %ld bytes", fp->symsz);
993e12c5d1SDavid du Colombier 		return -1;
1003e12c5d1SDavid du Colombier 	}
101219b2ee8SDavid du Colombier 	Binit(&b, fd, OREAD);
102219b2ee8SDavid du Colombier 	Bseek(&b, fp->symoff, 0);
103219b2ee8SDavid du Colombier 	nsym = 0;
104219b2ee8SDavid du Colombier 	size = 0;
105d3993254SDavid du Colombier 	if((fp->_magic && (fp->magic & HDR_MAGIC)) || mach->szaddr == 8)
1064de34a7eSDavid du Colombier 		svalsz = 8;
107d3993254SDavid du Colombier 	else
108d3993254SDavid du Colombier 		svalsz = 4;
109d3993254SDavid du Colombier 	for(p = symbols; size < fp->symsz; p++, nsym++) {
110d3993254SDavid du Colombier 		if(svalsz == 8){
1114de34a7eSDavid du Colombier 			if(Bread(&b, &vl, 8) != 8)
1124de34a7eSDavid du Colombier 				return symerrmsg(8, "symbol");
1134de34a7eSDavid du Colombier 			p->value = beswav(vl);
1144de34a7eSDavid du Colombier 		}
1154de34a7eSDavid du Colombier 		else{
1164de34a7eSDavid du Colombier 			if(Bread(&b, &l, 4) != 4)
1174de34a7eSDavid du Colombier 				return symerrmsg(4, "symbol");
1184de34a7eSDavid du Colombier 			p->value = (u32int)beswal(l);
1194de34a7eSDavid du Colombier 		}
120219b2ee8SDavid du Colombier 		if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
121219b2ee8SDavid du Colombier 			return symerrmsg(sizeof(p->value), "symbol");
122219b2ee8SDavid du Colombier 
123219b2ee8SDavid du Colombier 		i = decodename(&b, p);
124219b2ee8SDavid du Colombier 		if(i < 0)
1253e12c5d1SDavid du Colombier 			return -1;
1264de34a7eSDavid du Colombier 		size += i+svalsz+sizeof(p->type);
127219b2ee8SDavid du Colombier 
128219b2ee8SDavid du Colombier 		/* count global & auto vars, text symbols, and file names */
129219b2ee8SDavid du Colombier 		switch (p->type) {
130219b2ee8SDavid du Colombier 		case 'l':
131219b2ee8SDavid du Colombier 		case 'L':
132219b2ee8SDavid du Colombier 		case 't':
133219b2ee8SDavid du Colombier 		case 'T':
134219b2ee8SDavid du Colombier 			ntxt++;
135219b2ee8SDavid du Colombier 			break;
136219b2ee8SDavid du Colombier 		case 'd':
137219b2ee8SDavid du Colombier 		case 'D':
138219b2ee8SDavid du Colombier 		case 'b':
139219b2ee8SDavid du Colombier 		case 'B':
140219b2ee8SDavid du Colombier 			nglob++;
141219b2ee8SDavid du Colombier 			break;
142219b2ee8SDavid du Colombier 		case 'f':
143219b2ee8SDavid du Colombier 			if(strcmp(p->name, ".frame") == 0) {
144219b2ee8SDavid du Colombier 				p->type = 'm';
145219b2ee8SDavid du Colombier 				nauto++;
1463e12c5d1SDavid du Colombier 			}
147219b2ee8SDavid du Colombier 			else if(p->value > fmax)
148219b2ee8SDavid du Colombier 				fmax = p->value;	/* highest path index */
149219b2ee8SDavid du Colombier 			break;
150219b2ee8SDavid du Colombier 		case 'a':
151219b2ee8SDavid du Colombier 		case 'p':
152219b2ee8SDavid du Colombier 		case 'm':
153219b2ee8SDavid du Colombier 			nauto++;
154219b2ee8SDavid du Colombier 			break;
155219b2ee8SDavid du Colombier 		case 'z':
156219b2ee8SDavid du Colombier 			if(p->value == 1) {		/* one extra per file */
157219b2ee8SDavid du Colombier 				nhist++;
158219b2ee8SDavid du Colombier 				nfiles++;
1593e12c5d1SDavid du Colombier 			}
160219b2ee8SDavid du Colombier 			nhist++;
161219b2ee8SDavid du Colombier 			break;
162219b2ee8SDavid du Colombier 		default:
163219b2ee8SDavid du Colombier 			break;
164219b2ee8SDavid du Colombier 		}
165219b2ee8SDavid du Colombier 	}
166219b2ee8SDavid du Colombier 	if (debug)
1677dd7cddfSDavid du Colombier 		print("NG: %ld NT: %d NF: %d\n", nglob, ntxt, fmax);
1683e12c5d1SDavid du Colombier 	if (fp->sppcsz) {			/* pc-sp offset table */
1693e12c5d1SDavid du Colombier 		spoff = (uchar *)malloc(fp->sppcsz);
1703e12c5d1SDavid du Colombier 		if(spoff == 0) {
1717dd7cddfSDavid du Colombier 			werrstr("can't malloc %ld bytes", fp->sppcsz);
1723e12c5d1SDavid du Colombier 			return -1;
1733e12c5d1SDavid du Colombier 		}
174219b2ee8SDavid du Colombier 		Bseek(&b, fp->sppcoff, 0);
1754de34a7eSDavid du Colombier 		if(Bread(&b, spoff, fp->sppcsz) != fp->sppcsz){
1763e12c5d1SDavid du Colombier 			spoff = 0;
177219b2ee8SDavid du Colombier 			return symerrmsg(fp->sppcsz, "sp-pc");
1783e12c5d1SDavid du Colombier 		}
1793e12c5d1SDavid du Colombier 		spoffend = spoff+fp->sppcsz;
1803e12c5d1SDavid du Colombier 	}
1813e12c5d1SDavid du Colombier 	if (fp->lnpcsz) {			/* pc-line number table */
1823e12c5d1SDavid du Colombier 		pcline = (uchar *)malloc(fp->lnpcsz);
1833e12c5d1SDavid du Colombier 		if(pcline == 0) {
1847dd7cddfSDavid du Colombier 			werrstr("can't malloc %ld bytes", fp->lnpcsz);
1853e12c5d1SDavid du Colombier 			return -1;
1863e12c5d1SDavid du Colombier 		}
187219b2ee8SDavid du Colombier 		Bseek(&b, fp->lnpcoff, 0);
1884de34a7eSDavid du Colombier 		if(Bread(&b, pcline, fp->lnpcsz) != fp->lnpcsz){
1893e12c5d1SDavid du Colombier 			pcline = 0;
190219b2ee8SDavid du Colombier 			return symerrmsg(fp->lnpcsz, "pc-line");
1913e12c5d1SDavid du Colombier 		}
1923e12c5d1SDavid du Colombier 		pclineend = pcline+fp->lnpcsz;
1933e12c5d1SDavid du Colombier 	}
1943e12c5d1SDavid du Colombier 	return nsym;
1953e12c5d1SDavid du Colombier }
196219b2ee8SDavid du Colombier 
197219b2ee8SDavid du Colombier static int
symerrmsg(int n,char * table)198219b2ee8SDavid du Colombier symerrmsg(int n, char *table)
199219b2ee8SDavid du Colombier {
200219b2ee8SDavid du Colombier 	werrstr("can't read %d bytes of %s table", n, table);
201219b2ee8SDavid du Colombier 	return -1;
202219b2ee8SDavid du Colombier }
203219b2ee8SDavid du Colombier 
2044de34a7eSDavid du Colombier static long
decodename(Biobuf * bp,Sym * p)205219b2ee8SDavid du Colombier decodename(Biobuf *bp, Sym *p)
206219b2ee8SDavid du Colombier {
207219b2ee8SDavid du Colombier 	char *cp;
208219b2ee8SDavid du Colombier 	int c1, c2;
2094de34a7eSDavid du Colombier 	long n;
2104de34a7eSDavid du Colombier 	vlong o;
211219b2ee8SDavid du Colombier 
212219b2ee8SDavid du Colombier 	if((p->type & 0x80) == 0) {		/* old-style, fixed length names */
213219b2ee8SDavid du Colombier 		p->name = malloc(NNAME);
214219b2ee8SDavid du Colombier 		if(p->name == 0) {
215219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", NNAME);
216219b2ee8SDavid du Colombier 			return -1;
217219b2ee8SDavid du Colombier 		}
218219b2ee8SDavid du Colombier 		if(Bread(bp, p->name, NNAME) != NNAME)
219219b2ee8SDavid du Colombier 			return symerrmsg(NNAME, "symbol");
220219b2ee8SDavid du Colombier 		Bseek(bp, 3, 1);
221219b2ee8SDavid du Colombier 		return NNAME+3;
222219b2ee8SDavid du Colombier 	}
223219b2ee8SDavid du Colombier 
224219b2ee8SDavid du Colombier 	p->type &= ~0x80;
225219b2ee8SDavid du Colombier 	if(p->type == 'z' || p->type == 'Z') {
2264de34a7eSDavid du Colombier 		o = Bseek(bp, 0, 1);
227219b2ee8SDavid du Colombier 		if(Bgetc(bp) < 0) {
228219b2ee8SDavid du Colombier 			werrstr("can't read symbol name");
229219b2ee8SDavid du Colombier 			return -1;
230219b2ee8SDavid du Colombier 		}
231219b2ee8SDavid du Colombier 		for(;;) {
232219b2ee8SDavid du Colombier 			c1 = Bgetc(bp);
233219b2ee8SDavid du Colombier 			c2 = Bgetc(bp);
234219b2ee8SDavid du Colombier 			if(c1 < 0 || c2 < 0) {
235219b2ee8SDavid du Colombier 				werrstr("can't read symbol name");
236219b2ee8SDavid du Colombier 				return -1;
237219b2ee8SDavid du Colombier 			}
238219b2ee8SDavid du Colombier 			if(c1 == 0 && c2 == 0)
239219b2ee8SDavid du Colombier 				break;
240219b2ee8SDavid du Colombier 		}
2414de34a7eSDavid du Colombier 		n = Bseek(bp, 0, 1)-o;
242219b2ee8SDavid du Colombier 		p->name = malloc(n);
243219b2ee8SDavid du Colombier 		if(p->name == 0) {
2444de34a7eSDavid du Colombier 			werrstr("can't malloc %ld bytes", n);
245219b2ee8SDavid du Colombier 			return -1;
246219b2ee8SDavid du Colombier 		}
247219b2ee8SDavid du Colombier 		Bseek(bp, -n, 1);
248219b2ee8SDavid du Colombier 		if(Bread(bp, p->name, n) != n) {
2494de34a7eSDavid du Colombier 			werrstr("can't read %ld bytes of symbol name", n);
250219b2ee8SDavid du Colombier 			return -1;
251219b2ee8SDavid du Colombier 		}
252219b2ee8SDavid du Colombier 	} else {
253219b2ee8SDavid du Colombier 		cp = Brdline(bp, '\0');
254219b2ee8SDavid du Colombier 		if(cp == 0) {
255219b2ee8SDavid du Colombier 			werrstr("can't read symbol name");
256219b2ee8SDavid du Colombier 			return -1;
257219b2ee8SDavid du Colombier 		}
258219b2ee8SDavid du Colombier 		n = Blinelen(bp);
259219b2ee8SDavid du Colombier 		p->name = malloc(n);
260219b2ee8SDavid du Colombier 		if(p->name == 0) {
2614de34a7eSDavid du Colombier 			werrstr("can't malloc %ld bytes", n);
262219b2ee8SDavid du Colombier 			return -1;
263219b2ee8SDavid du Colombier 		}
264219b2ee8SDavid du Colombier 		strcpy(p->name, cp);
265219b2ee8SDavid du Colombier 	}
266219b2ee8SDavid du Colombier 	return n;
267219b2ee8SDavid du Colombier }
2684de34a7eSDavid du Colombier 
269219b2ee8SDavid du Colombier /*
270219b2ee8SDavid du Colombier  *	free any previously loaded symbol tables
271219b2ee8SDavid du Colombier  */
272219b2ee8SDavid du Colombier static void
cleansyms(void)273219b2ee8SDavid du Colombier cleansyms(void)
274219b2ee8SDavid du Colombier {
275219b2ee8SDavid du Colombier 	if(globals)
276219b2ee8SDavid du Colombier 		free(globals);
277219b2ee8SDavid du Colombier 	globals = 0;
278219b2ee8SDavid du Colombier 	nglob = 0;
279219b2ee8SDavid du Colombier 	if(txt)
280219b2ee8SDavid du Colombier 		free(txt);
281219b2ee8SDavid du Colombier 	txt = 0;
282219b2ee8SDavid du Colombier 	ntxt = 0;
283219b2ee8SDavid du Colombier 	if(fnames)
284219b2ee8SDavid du Colombier 		free(fnames);
285219b2ee8SDavid du Colombier 	fnames = 0;
286219b2ee8SDavid du Colombier 	fmax = 0;
287219b2ee8SDavid du Colombier 
288219b2ee8SDavid du Colombier 	if(files)
289219b2ee8SDavid du Colombier 		free(files);
290219b2ee8SDavid du Colombier 	files = 0;
291219b2ee8SDavid du Colombier 	nfiles = 0;
292219b2ee8SDavid du Colombier 	if(hist)
293219b2ee8SDavid du Colombier 		free(hist);
294219b2ee8SDavid du Colombier 	hist = 0;
295219b2ee8SDavid du Colombier 	nhist = 0;
296219b2ee8SDavid du Colombier 	if(autos)
297219b2ee8SDavid du Colombier 		free(autos);
298219b2ee8SDavid du Colombier 	autos = 0;
299219b2ee8SDavid du Colombier 	nauto = 0;
300219b2ee8SDavid du Colombier 	isbuilt = 0;
301219b2ee8SDavid du Colombier 	if(symbols)
302219b2ee8SDavid du Colombier 		free(symbols);
303219b2ee8SDavid du Colombier 	symbols = 0;
304219b2ee8SDavid du Colombier 	nsym = 0;
305219b2ee8SDavid du Colombier 	if(spoff)
306219b2ee8SDavid du Colombier 		free(spoff);
307219b2ee8SDavid du Colombier 	spoff = 0;
308219b2ee8SDavid du Colombier 	if(pcline)
309219b2ee8SDavid du Colombier 		free(pcline);
310219b2ee8SDavid du Colombier 	pcline = 0;
311219b2ee8SDavid du Colombier }
3124de34a7eSDavid du Colombier 
313219b2ee8SDavid du Colombier /*
314219b2ee8SDavid du Colombier  *	delimit the text segment
315219b2ee8SDavid du Colombier  */
316219b2ee8SDavid du Colombier void
textseg(uvlong base,Fhdr * fp)3174de34a7eSDavid du Colombier textseg(uvlong base, Fhdr *fp)
318219b2ee8SDavid du Colombier {
319219b2ee8SDavid du Colombier 	txtstart = base;
320219b2ee8SDavid du Colombier 	txtend = base+fp->txtsz;
321219b2ee8SDavid du Colombier }
3224de34a7eSDavid du Colombier 
3233e12c5d1SDavid du Colombier /*
3243e12c5d1SDavid du Colombier  *	symbase: return base and size of raw symbol table
3253e12c5d1SDavid du Colombier  *		(special hack for high access rate operations)
3263e12c5d1SDavid du Colombier  */
3273e12c5d1SDavid du Colombier Sym *
symbase(long * n)3283e12c5d1SDavid du Colombier symbase(long *n)
3293e12c5d1SDavid du Colombier {
3303e12c5d1SDavid du Colombier 	*n = nsym;
3313e12c5d1SDavid du Colombier 	return symbols;
3323e12c5d1SDavid du Colombier }
3334de34a7eSDavid du Colombier 
3343e12c5d1SDavid du Colombier /*
3353e12c5d1SDavid du Colombier  *	Get the ith symbol table entry
3363e12c5d1SDavid du Colombier  */
3373e12c5d1SDavid du Colombier Sym *
getsym(int index)3383e12c5d1SDavid du Colombier getsym(int index)
3393e12c5d1SDavid du Colombier {
3407f061a25SDavid du Colombier 	if(index >= 0 && index < nsym)
3413e12c5d1SDavid du Colombier 		return &symbols[index];
3423e12c5d1SDavid du Colombier 	return 0;
3433e12c5d1SDavid du Colombier }
344219b2ee8SDavid du Colombier 
345219b2ee8SDavid du Colombier /*
346219b2ee8SDavid du Colombier  *	initialize internal symbol tables
347219b2ee8SDavid du Colombier  */
348219b2ee8SDavid du Colombier static int
buildtbls(void)349219b2ee8SDavid du Colombier buildtbls(void)
350219b2ee8SDavid du Colombier {
3514de34a7eSDavid du Colombier 	long i;
3524de34a7eSDavid du Colombier 	int j, nh, ng, nt;
353219b2ee8SDavid du Colombier 	File *f;
354219b2ee8SDavid du Colombier 	Txtsym *tp;
355219b2ee8SDavid du Colombier 	Hist *hp;
356219b2ee8SDavid du Colombier 	Sym *p, **ap;
357219b2ee8SDavid du Colombier 
358219b2ee8SDavid du Colombier 	if(isbuilt)
359219b2ee8SDavid du Colombier 		return 1;
360219b2ee8SDavid du Colombier 	isbuilt = 1;
361219b2ee8SDavid du Colombier 			/* allocate the tables */
362219b2ee8SDavid du Colombier 	if(nglob) {
363219b2ee8SDavid du Colombier 		globals = malloc(nglob*sizeof(*globals));
364219b2ee8SDavid du Colombier 		if(!globals) {
365219b2ee8SDavid du Colombier 			werrstr("can't malloc global symbol table");
366219b2ee8SDavid du Colombier 			return 0;
367219b2ee8SDavid du Colombier 		}
368219b2ee8SDavid du Colombier 	}
369219b2ee8SDavid du Colombier 	if(ntxt) {
370219b2ee8SDavid du Colombier 		txt = malloc(ntxt*sizeof(*txt));
371219b2ee8SDavid du Colombier 		if (!txt) {
372219b2ee8SDavid du Colombier 			werrstr("can't malloc text symbol table");
373219b2ee8SDavid du Colombier 			return 0;
374219b2ee8SDavid du Colombier 		}
375219b2ee8SDavid du Colombier 	}
376d9d5974cSDavid du Colombier 	fnames = malloc((fmax+1)*sizeof(*fnames));
377219b2ee8SDavid du Colombier 	if (!fnames) {
378219b2ee8SDavid du Colombier 		werrstr("can't malloc file name table");
379219b2ee8SDavid du Colombier 		return 0;
380219b2ee8SDavid du Colombier 	}
381d9d5974cSDavid du Colombier 	memset(fnames, 0, (fmax+1)*sizeof(*fnames));
382219b2ee8SDavid du Colombier 	files = malloc(nfiles*sizeof(*files));
383219b2ee8SDavid du Colombier 	if(!files) {
384219b2ee8SDavid du Colombier 		werrstr("can't malloc file table");
385219b2ee8SDavid du Colombier 		return 0;
386219b2ee8SDavid du Colombier 	}
387219b2ee8SDavid du Colombier 	hist = malloc(nhist*sizeof(Hist));
388219b2ee8SDavid du Colombier 	if(hist == 0) {
389219b2ee8SDavid du Colombier 		werrstr("can't malloc history stack");
390219b2ee8SDavid du Colombier 		return 0;
391219b2ee8SDavid du Colombier 	}
392219b2ee8SDavid du Colombier 	autos = malloc(nauto*sizeof(Sym*));
393219b2ee8SDavid du Colombier 	if(autos == 0) {
394219b2ee8SDavid du Colombier 		werrstr("can't malloc auto symbol table");
395219b2ee8SDavid du Colombier 		return 0;
396219b2ee8SDavid du Colombier 	}
397219b2ee8SDavid du Colombier 		/* load the tables */
398219b2ee8SDavid du Colombier 	ng = nt = nh = 0;
399219b2ee8SDavid du Colombier 	f = 0;
400219b2ee8SDavid du Colombier 	tp = 0;
401219b2ee8SDavid du Colombier 	i = nsym;
402219b2ee8SDavid du Colombier 	hp = hist;
403219b2ee8SDavid du Colombier 	ap = autos;
404219b2ee8SDavid du Colombier 	for(p = symbols; i-- > 0; p++) {
405219b2ee8SDavid du Colombier 		switch(p->type) {
406219b2ee8SDavid du Colombier 		case 'D':
407219b2ee8SDavid du Colombier 		case 'd':
408219b2ee8SDavid du Colombier 		case 'B':
409219b2ee8SDavid du Colombier 		case 'b':
410219b2ee8SDavid du Colombier 			if(debug)
4114de34a7eSDavid du Colombier 				print("Global: %s %llux\n", p->name, p->value);
412219b2ee8SDavid du Colombier 			globals[ng++] = p;
413219b2ee8SDavid du Colombier 			break;
414219b2ee8SDavid du Colombier 		case 'z':
415219b2ee8SDavid du Colombier 			if(p->value == 1) {		/* New file */
416219b2ee8SDavid du Colombier 				if(f) {
417219b2ee8SDavid du Colombier 					f->n = nh;
418219b2ee8SDavid du Colombier 					f->hist[nh].name = 0;	/* one extra */
419219b2ee8SDavid du Colombier 					hp += nh+1;
420219b2ee8SDavid du Colombier 					f++;
421219b2ee8SDavid du Colombier 				}
4227dd7cddfSDavid du Colombier 				else
4237dd7cddfSDavid du Colombier 					f = files;
424219b2ee8SDavid du Colombier 				f->hist = hp;
425219b2ee8SDavid du Colombier 				f->sym = 0;
426219b2ee8SDavid du Colombier 				f->addr = 0;
427219b2ee8SDavid du Colombier 				nh = 0;
428219b2ee8SDavid du Colombier 			}
429219b2ee8SDavid du Colombier 				/* alloc one slot extra as terminator */
430219b2ee8SDavid du Colombier 			f->hist[nh].name = p->name;
431219b2ee8SDavid du Colombier 			f->hist[nh].line = p->value;
432219b2ee8SDavid du Colombier 			f->hist[nh].offset = 0;
433219b2ee8SDavid du Colombier 			if(debug)
434219b2ee8SDavid du Colombier 				printhist("-> ", &f->hist[nh], 1);
435219b2ee8SDavid du Colombier 			nh++;
436219b2ee8SDavid du Colombier 			break;
437219b2ee8SDavid du Colombier 		case 'Z':
438219b2ee8SDavid du Colombier 			if(f && nh > 0)
439219b2ee8SDavid du Colombier 				f->hist[nh-1].offset = p->value;
440219b2ee8SDavid du Colombier 			break;
441219b2ee8SDavid du Colombier 		case 'T':
442219b2ee8SDavid du Colombier 		case 't':	/* Text: terminate history if first in file */
443219b2ee8SDavid du Colombier 		case 'L':
444219b2ee8SDavid du Colombier 		case 'l':
445219b2ee8SDavid du Colombier 			tp = &txt[nt++];
446219b2ee8SDavid du Colombier 			tp->n = 0;
447219b2ee8SDavid du Colombier 			tp->sym = p;
448219b2ee8SDavid du Colombier 			tp->locals = ap;
449219b2ee8SDavid du Colombier 			if(debug)
4504de34a7eSDavid du Colombier 				print("TEXT: %s at %llux\n", p->name, p->value);
451219b2ee8SDavid du Colombier 			if(f && !f->sym) {			/* first  */
452219b2ee8SDavid du Colombier 				f->sym = p;
453219b2ee8SDavid du Colombier 				f->addr = p->value;
454219b2ee8SDavid du Colombier 			}
455219b2ee8SDavid du Colombier 			break;
456219b2ee8SDavid du Colombier 		case 'a':
457219b2ee8SDavid du Colombier 		case 'p':
458219b2ee8SDavid du Colombier 		case 'm':		/* Local Vars */
459219b2ee8SDavid du Colombier 			if(!tp)
4607dd7cddfSDavid du Colombier 				print("Warning: Free floating local var: %s\n",
4617dd7cddfSDavid du Colombier 					p->name);
462219b2ee8SDavid du Colombier 			else {
463219b2ee8SDavid du Colombier 				if(debug)
4644de34a7eSDavid du Colombier 					print("Local: %s %llux\n", p->name, p->value);
465219b2ee8SDavid du Colombier 				tp->locals[tp->n] = p;
466219b2ee8SDavid du Colombier 				tp->n++;
467219b2ee8SDavid du Colombier 				ap++;
468219b2ee8SDavid du Colombier 			}
469219b2ee8SDavid du Colombier 			break;
470219b2ee8SDavid du Colombier 		case 'f':		/* File names */
471219b2ee8SDavid du Colombier 			if(debug)
472219b2ee8SDavid du Colombier 				print("Fname: %s\n", p->name);
473219b2ee8SDavid du Colombier 			fnames[p->value] = p;
474219b2ee8SDavid du Colombier 			break;
475219b2ee8SDavid du Colombier 		default:
476219b2ee8SDavid du Colombier 			break;
477219b2ee8SDavid du Colombier 		}
478219b2ee8SDavid du Colombier 	}
479219b2ee8SDavid du Colombier 		/* sort global and text tables into ascending address order */
480219b2ee8SDavid du Colombier 	qsort(globals, nglob, sizeof(Sym*), symcomp);
481219b2ee8SDavid du Colombier 	qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
482219b2ee8SDavid du Colombier 	qsort(files, nfiles, sizeof(File), filecomp);
483219b2ee8SDavid du Colombier 	tp = txt;
484219b2ee8SDavid du Colombier 	for(i = 0, f = files; i < nfiles; i++, f++) {
485219b2ee8SDavid du Colombier 		for(j = 0; j < ntxt; j++) {
486219b2ee8SDavid du Colombier 			if(f->sym == tp->sym) {
487219b2ee8SDavid du Colombier 				if(debug) {
4884de34a7eSDavid du Colombier 					print("LINK: %s to at %llux", f->sym->name, f->addr);
489219b2ee8SDavid du Colombier 					printhist("... ", f->hist, 1);
490219b2ee8SDavid du Colombier 				}
491219b2ee8SDavid du Colombier 				f->txt = tp++;
492219b2ee8SDavid du Colombier 				break;
493219b2ee8SDavid du Colombier 			}
494219b2ee8SDavid du Colombier 			if(++tp >= txt+ntxt)	/* wrap around */
495219b2ee8SDavid du Colombier 				tp = txt;
496219b2ee8SDavid du Colombier 		}
497219b2ee8SDavid du Colombier 	}
498219b2ee8SDavid du Colombier 	return 1;
499219b2ee8SDavid du Colombier }
500219b2ee8SDavid du Colombier 
501219b2ee8SDavid du Colombier /*
502219b2ee8SDavid du Colombier  * find symbol function.var by name.
503219b2ee8SDavid du Colombier  *	fn != 0 && var != 0	=> look for fn in text, var in data
504219b2ee8SDavid du Colombier  *	fn != 0 && var == 0	=> look for fn in text
505219b2ee8SDavid du Colombier  *	fn == 0 && var != 0	=> look for var first in text then in data space.
506219b2ee8SDavid du Colombier  */
507219b2ee8SDavid du Colombier int
lookup(char * fn,char * var,Symbol * s)508219b2ee8SDavid du Colombier lookup(char *fn, char *var, Symbol *s)
509219b2ee8SDavid du Colombier {
510219b2ee8SDavid du Colombier 	int found;
511219b2ee8SDavid du Colombier 
512219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
513219b2ee8SDavid du Colombier 		return 0;
514219b2ee8SDavid du Colombier 	if(fn) {
515219b2ee8SDavid du Colombier 		found = findtext(fn, s);
516219b2ee8SDavid du Colombier 		if(var == 0)		/* case 2: fn not in text */
517219b2ee8SDavid du Colombier 			return found;
518219b2ee8SDavid du Colombier 		else if(!found)		/* case 1: fn not found */
519219b2ee8SDavid du Colombier 			return 0;
520219b2ee8SDavid du Colombier 	} else if(var) {
521219b2ee8SDavid du Colombier 		found = findtext(var, s);
522219b2ee8SDavid du Colombier 		if(found)
523219b2ee8SDavid du Colombier 			return 1;	/* case 3: var found in text */
524219b2ee8SDavid du Colombier 	} else return 0;		/* case 4: fn & var == zero */
525219b2ee8SDavid du Colombier 
526219b2ee8SDavid du Colombier 	if(found)
527219b2ee8SDavid du Colombier 		return findlocal(s, var, s);	/* case 1: fn found */
528219b2ee8SDavid du Colombier 	return findglobal(var, s);		/* case 3: var not found */
529219b2ee8SDavid du Colombier 
530219b2ee8SDavid du Colombier }
5314de34a7eSDavid du Colombier 
532219b2ee8SDavid du Colombier /*
533219b2ee8SDavid du Colombier  * find a function by name
534219b2ee8SDavid du Colombier  */
535219b2ee8SDavid du Colombier static int
findtext(char * name,Symbol * s)536219b2ee8SDavid du Colombier findtext(char *name, Symbol *s)
537219b2ee8SDavid du Colombier {
538219b2ee8SDavid du Colombier 	int i;
539219b2ee8SDavid du Colombier 
540219b2ee8SDavid du Colombier 	for(i = 0; i < ntxt; i++) {
541219b2ee8SDavid du Colombier 		if(strcmp(txt[i].sym->name, name) == 0) {
542219b2ee8SDavid du Colombier 			fillsym(txt[i].sym, s);
543219b2ee8SDavid du Colombier 			s->handle = (void *) &txt[i];
544867bfcc6SDavid du Colombier 			s->index = i;
545219b2ee8SDavid du Colombier 			return 1;
546219b2ee8SDavid du Colombier 		}
547219b2ee8SDavid du Colombier 	}
548219b2ee8SDavid du Colombier 	return 0;
549219b2ee8SDavid du Colombier }
550219b2ee8SDavid du Colombier /*
551219b2ee8SDavid du Colombier  * find global variable by name
552219b2ee8SDavid du Colombier  */
553219b2ee8SDavid du Colombier static int
findglobal(char * name,Symbol * s)554219b2ee8SDavid du Colombier findglobal(char *name, Symbol *s)
555219b2ee8SDavid du Colombier {
5564de34a7eSDavid du Colombier 	long i;
557219b2ee8SDavid du Colombier 
558219b2ee8SDavid du Colombier 	for(i = 0; i < nglob; i++) {
559219b2ee8SDavid du Colombier 		if(strcmp(globals[i]->name, name) == 0) {
560219b2ee8SDavid du Colombier 			fillsym(globals[i], s);
561867bfcc6SDavid du Colombier 			s->index = i;
562219b2ee8SDavid du Colombier 			return 1;
563219b2ee8SDavid du Colombier 		}
564219b2ee8SDavid du Colombier 	}
565219b2ee8SDavid du Colombier 	return 0;
566219b2ee8SDavid du Colombier }
5674de34a7eSDavid du Colombier 
568219b2ee8SDavid du Colombier /*
569219b2ee8SDavid du Colombier  *	find the local variable by name within a given function
570219b2ee8SDavid du Colombier  */
571219b2ee8SDavid du Colombier int
findlocal(Symbol * s1,char * name,Symbol * s2)572219b2ee8SDavid du Colombier findlocal(Symbol *s1, char *name, Symbol *s2)
573219b2ee8SDavid du Colombier {
574219b2ee8SDavid du Colombier 	if(s1 == 0)
575219b2ee8SDavid du Colombier 		return 0;
576219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
577219b2ee8SDavid du Colombier 		return 0;
578219b2ee8SDavid du Colombier 	return findlocvar(s1, name, s2);
579219b2ee8SDavid du Colombier }
5804de34a7eSDavid du Colombier 
581219b2ee8SDavid du Colombier /*
582219b2ee8SDavid du Colombier  *	find the local variable by name within a given function
583219b2ee8SDavid du Colombier  *		(internal function - does no parameter validation)
584219b2ee8SDavid du Colombier  */
585219b2ee8SDavid du Colombier static int
findlocvar(Symbol * s1,char * name,Symbol * s2)586219b2ee8SDavid du Colombier findlocvar(Symbol *s1, char *name, Symbol *s2)
587219b2ee8SDavid du Colombier {
588219b2ee8SDavid du Colombier 	Txtsym *tp;
589219b2ee8SDavid du Colombier 	int i;
590219b2ee8SDavid du Colombier 
591219b2ee8SDavid du Colombier 	tp = (Txtsym *)s1->handle;
592219b2ee8SDavid du Colombier 	if(tp && tp->locals) {
593219b2ee8SDavid du Colombier 		for(i = 0; i < tp->n; i++)
594219b2ee8SDavid du Colombier 			if (strcmp(tp->locals[i]->name, name) == 0) {
595219b2ee8SDavid du Colombier 				fillsym(tp->locals[i], s2);
596219b2ee8SDavid du Colombier 				s2->handle = (void *)tp;
597867bfcc6SDavid du Colombier 				s2->index = tp->n-1 - i;
598219b2ee8SDavid du Colombier 				return 1;
599219b2ee8SDavid du Colombier 			}
600219b2ee8SDavid du Colombier 	}
601219b2ee8SDavid du Colombier 	return 0;
602219b2ee8SDavid du Colombier }
6034de34a7eSDavid du Colombier 
604219b2ee8SDavid du Colombier /*
605219b2ee8SDavid du Colombier  *	Get ith text symbol
606219b2ee8SDavid du Colombier  */
607219b2ee8SDavid du Colombier int
textsym(Symbol * s,int index)608219b2ee8SDavid du Colombier textsym(Symbol *s, int index)
609219b2ee8SDavid du Colombier {
610219b2ee8SDavid du Colombier 
611219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
612219b2ee8SDavid du Colombier 		return 0;
6137f061a25SDavid du Colombier 	if(index < 0 || index >= ntxt)
614219b2ee8SDavid du Colombier 		return 0;
615219b2ee8SDavid du Colombier 	fillsym(txt[index].sym, s);
616219b2ee8SDavid du Colombier 	s->handle = (void *)&txt[index];
617867bfcc6SDavid du Colombier 	s->index = index;
618219b2ee8SDavid du Colombier 	return 1;
619219b2ee8SDavid du Colombier }
6204de34a7eSDavid du Colombier 
621219b2ee8SDavid du Colombier /*
622219b2ee8SDavid du Colombier  *	Get ith file name
623219b2ee8SDavid du Colombier  */
624219b2ee8SDavid du Colombier int
filesym(int index,char * buf,int n)625219b2ee8SDavid du Colombier filesym(int index, char *buf, int n)
626219b2ee8SDavid du Colombier {
627219b2ee8SDavid du Colombier 	Hist *hp;
628219b2ee8SDavid du Colombier 
629219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
630219b2ee8SDavid du Colombier 		return 0;
6317f061a25SDavid du Colombier 	if(index < 0 || index >= nfiles)
632219b2ee8SDavid du Colombier 		return 0;
633219b2ee8SDavid du Colombier 	hp = files[index].hist;
634219b2ee8SDavid du Colombier 	if(!hp || !hp->name)
635219b2ee8SDavid du Colombier 		return 0;
636219b2ee8SDavid du Colombier 	return fileelem(fnames, (uchar*)hp->name, buf, n);
637219b2ee8SDavid du Colombier }
6384de34a7eSDavid du Colombier 
639219b2ee8SDavid du Colombier /*
640219b2ee8SDavid du Colombier  *	Lookup name of local variable located at an offset into the frame.
641219b2ee8SDavid du Colombier  *	The type selects either a parameter or automatic.
642219b2ee8SDavid du Colombier  */
643219b2ee8SDavid du Colombier int
getauto(Symbol * s1,int off,int type,Symbol * s2)644219b2ee8SDavid du Colombier getauto(Symbol *s1, int off, int type, Symbol *s2)
645219b2ee8SDavid du Colombier {
646219b2ee8SDavid du Colombier 	Txtsym *tp;
647219b2ee8SDavid du Colombier 	Sym *p;
648219b2ee8SDavid du Colombier 	int i, t;
649219b2ee8SDavid du Colombier 
650219b2ee8SDavid du Colombier 	if(s1 == 0)
651219b2ee8SDavid du Colombier 		return 0;
652219b2ee8SDavid du Colombier 	if(type == CPARAM)
653219b2ee8SDavid du Colombier 		t = 'p';
654219b2ee8SDavid du Colombier 	else if(type == CAUTO)
655219b2ee8SDavid du Colombier 		t = 'a';
656219b2ee8SDavid du Colombier 	else
657219b2ee8SDavid du Colombier 		return 0;
658219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
659219b2ee8SDavid du Colombier 		return 0;
660219b2ee8SDavid du Colombier 	tp = (Txtsym *)s1->handle;
661219b2ee8SDavid du Colombier 	if(tp == 0)
662219b2ee8SDavid du Colombier 		return 0;
663219b2ee8SDavid du Colombier 	for(i = 0; i < tp->n; i++) {
664219b2ee8SDavid du Colombier 		p = tp->locals[i];
665219b2ee8SDavid du Colombier 		if(p->type == t && p->value == off) {
666219b2ee8SDavid du Colombier 			fillsym(p, s2);
667219b2ee8SDavid du Colombier 			s2->handle = s1->handle;
668867bfcc6SDavid du Colombier 			s2->index = tp->n-1 - i;
669219b2ee8SDavid du Colombier 			return 1;
670219b2ee8SDavid du Colombier 		}
671219b2ee8SDavid du Colombier 	}
672219b2ee8SDavid du Colombier 	return 0;
673219b2ee8SDavid du Colombier }
674219b2ee8SDavid du Colombier 
675219b2ee8SDavid du Colombier /*
676219b2ee8SDavid du Colombier  * Find text symbol containing addr; binary search assumes text array is sorted by addr
677219b2ee8SDavid du Colombier  */
678219b2ee8SDavid du Colombier static int
srchtext(uvlong addr)6794de34a7eSDavid du Colombier srchtext(uvlong addr)
680219b2ee8SDavid du Colombier {
6814de34a7eSDavid du Colombier 	uvlong val;
682219b2ee8SDavid du Colombier 	int top, bot, mid;
683219b2ee8SDavid du Colombier 	Sym *sp;
684219b2ee8SDavid du Colombier 
685219b2ee8SDavid du Colombier 	val = addr;
686219b2ee8SDavid du Colombier 	bot = 0;
687219b2ee8SDavid du Colombier 	top = ntxt;
688219b2ee8SDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
689219b2ee8SDavid du Colombier 		sp = txt[mid].sym;
6905482313dSDavid du Colombier 		if(sp == nil)
6915482313dSDavid du Colombier 			return -1;
6924de34a7eSDavid du Colombier 		if(val < sp->value)
693219b2ee8SDavid du Colombier 			top = mid;
6944de34a7eSDavid du Colombier 		else if(mid != ntxt-1 && val >= txt[mid+1].sym->value)
695219b2ee8SDavid du Colombier 			bot = mid;
696219b2ee8SDavid du Colombier 		else
697219b2ee8SDavid du Colombier 			return mid;
698219b2ee8SDavid du Colombier 	}
699219b2ee8SDavid du Colombier 	return -1;
700219b2ee8SDavid du Colombier }
701219b2ee8SDavid du Colombier 
702219b2ee8SDavid du Colombier /*
703219b2ee8SDavid du Colombier  * Find data symbol containing addr; binary search assumes data array is sorted by addr
704219b2ee8SDavid du Colombier  */
7054de34a7eSDavid du Colombier static int
srchdata(uvlong addr)7064de34a7eSDavid du Colombier srchdata(uvlong addr)
707219b2ee8SDavid du Colombier {
7084de34a7eSDavid du Colombier 	uvlong val;
709219b2ee8SDavid du Colombier 	int top, bot, mid;
710219b2ee8SDavid du Colombier 	Sym *sp;
711219b2ee8SDavid du Colombier 
712219b2ee8SDavid du Colombier 	bot = 0;
713219b2ee8SDavid du Colombier 	top = nglob;
714219b2ee8SDavid du Colombier 	val = addr;
715219b2ee8SDavid du Colombier 	for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
716219b2ee8SDavid du Colombier 		sp = globals[mid];
7175482313dSDavid du Colombier 		if(sp == nil)
7185482313dSDavid du Colombier 			return -1;
7194de34a7eSDavid du Colombier 		if(val < sp->value)
720219b2ee8SDavid du Colombier 			top = mid;
7214de34a7eSDavid du Colombier 		else if(mid < nglob-1 && val >= globals[mid+1]->value)
722219b2ee8SDavid du Colombier 			bot = mid;
723219b2ee8SDavid du Colombier 		else
724219b2ee8SDavid du Colombier 			return mid;
725219b2ee8SDavid du Colombier 	}
726219b2ee8SDavid du Colombier 	return -1;
727219b2ee8SDavid du Colombier }
7284de34a7eSDavid du Colombier 
729219b2ee8SDavid du Colombier /*
730219b2ee8SDavid du Colombier  * Find symbol containing val in specified search space
731219b2ee8SDavid du Colombier  * There is a special case when a value falls beyond the end
732219b2ee8SDavid du Colombier  * of the text segment; if the search space is CTEXT, that value
733219b2ee8SDavid du Colombier  * (usually etext) is returned.  If the search space is CANY, symbols in the
734219b2ee8SDavid du Colombier  * data space are searched for a match.
735219b2ee8SDavid du Colombier  */
736219b2ee8SDavid du Colombier int
findsym(uvlong val,int type,Symbol * s)7374de34a7eSDavid du Colombier findsym(uvlong val, int type, Symbol *s)
738219b2ee8SDavid du Colombier {
739219b2ee8SDavid du Colombier 	int i;
740219b2ee8SDavid du Colombier 
741219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
742219b2ee8SDavid du Colombier 		return 0;
743219b2ee8SDavid du Colombier 
744219b2ee8SDavid du Colombier 	if(type == CTEXT || type == CANY) {
7454de34a7eSDavid du Colombier 		i = srchtext(val);
746219b2ee8SDavid du Colombier 		if(i >= 0) {
747219b2ee8SDavid du Colombier 			if(type == CTEXT || i != ntxt-1) {
748219b2ee8SDavid du Colombier 				fillsym(txt[i].sym, s);
749219b2ee8SDavid du Colombier 				s->handle = (void *) &txt[i];
750867bfcc6SDavid du Colombier 				s->index = i;
751219b2ee8SDavid du Colombier 				return 1;
752219b2ee8SDavid du Colombier 			}
753219b2ee8SDavid du Colombier 		}
754219b2ee8SDavid du Colombier 	}
755219b2ee8SDavid du Colombier 	if(type == CDATA || type == CANY) {
7564de34a7eSDavid du Colombier 		i = srchdata(val);
757219b2ee8SDavid du Colombier 		if(i >= 0) {
758219b2ee8SDavid du Colombier 			fillsym(globals[i], s);
759867bfcc6SDavid du Colombier 			s->index = i;
760219b2ee8SDavid du Colombier 			return 1;
761219b2ee8SDavid du Colombier 		}
762219b2ee8SDavid du Colombier 	}
763219b2ee8SDavid du Colombier 	return 0;
764219b2ee8SDavid du Colombier }
765219b2ee8SDavid du Colombier 
766219b2ee8SDavid du Colombier /*
767219b2ee8SDavid du Colombier  *	Find the start and end address of the function containing addr
768219b2ee8SDavid du Colombier  */
769219b2ee8SDavid du Colombier int
fnbound(uvlong addr,uvlong * bounds)7704de34a7eSDavid du Colombier fnbound(uvlong addr, uvlong *bounds)
771219b2ee8SDavid du Colombier {
772219b2ee8SDavid du Colombier 	int i;
773219b2ee8SDavid du Colombier 
774219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
775219b2ee8SDavid du Colombier 		return 0;
776219b2ee8SDavid du Colombier 
777219b2ee8SDavid du Colombier 	i = srchtext(addr);
778219b2ee8SDavid du Colombier 	if(0 <= i && i < ntxt-1) {
779219b2ee8SDavid du Colombier 		bounds[0] = txt[i].sym->value;
780219b2ee8SDavid du Colombier 		bounds[1] = txt[i+1].sym->value;
781219b2ee8SDavid du Colombier 		return 1;
782219b2ee8SDavid du Colombier 	}
783219b2ee8SDavid du Colombier 	return 0;
784219b2ee8SDavid du Colombier }
785219b2ee8SDavid du Colombier 
786219b2ee8SDavid du Colombier /*
787219b2ee8SDavid du Colombier  * get the ith local symbol for a function
788219b2ee8SDavid du Colombier  * the input symbol table is reverse ordered, so we reverse
789219b2ee8SDavid du Colombier  * accesses here to maintain approx. parameter ordering in a stack trace.
790219b2ee8SDavid du Colombier  */
791219b2ee8SDavid du Colombier int
localsym(Symbol * s,int index)792219b2ee8SDavid du Colombier localsym(Symbol *s, int index)
793219b2ee8SDavid du Colombier {
794219b2ee8SDavid du Colombier 	Txtsym *tp;
795219b2ee8SDavid du Colombier 
7967f061a25SDavid du Colombier 	if(s == 0 || index < 0)
797219b2ee8SDavid du Colombier 		return 0;
798219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
799219b2ee8SDavid du Colombier 		return 0;
800219b2ee8SDavid du Colombier 
801219b2ee8SDavid du Colombier 	tp = (Txtsym *)s->handle;
802219b2ee8SDavid du Colombier 	if(tp && tp->locals && index < tp->n) {
803219b2ee8SDavid du Colombier 		fillsym(tp->locals[tp->n-index-1], s);	/* reverse */
804219b2ee8SDavid du Colombier 		s->handle = (void *)tp;
805867bfcc6SDavid du Colombier 		s->index = index;
806219b2ee8SDavid du Colombier 		return 1;
807219b2ee8SDavid du Colombier 	}
808219b2ee8SDavid du Colombier 	return 0;
809219b2ee8SDavid du Colombier }
8104de34a7eSDavid du Colombier 
811219b2ee8SDavid du Colombier /*
812219b2ee8SDavid du Colombier  * get the ith global symbol
813219b2ee8SDavid du Colombier  */
814219b2ee8SDavid du Colombier int
globalsym(Symbol * s,int index)815219b2ee8SDavid du Colombier globalsym(Symbol *s, int index)
816219b2ee8SDavid du Colombier {
817219b2ee8SDavid du Colombier 	if(s == 0)
818219b2ee8SDavid du Colombier 		return 0;
819219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
820219b2ee8SDavid du Colombier 		return 0;
821219b2ee8SDavid du Colombier 
8227f061a25SDavid du Colombier 	if(index >=0 && index < nglob) {
823219b2ee8SDavid du Colombier 		fillsym(globals[index], s);
824867bfcc6SDavid du Colombier 		s->index = index;
825219b2ee8SDavid du Colombier 		return 1;
826219b2ee8SDavid du Colombier 	}
827219b2ee8SDavid du Colombier 	return 0;
828219b2ee8SDavid du Colombier }
8294de34a7eSDavid du Colombier 
830219b2ee8SDavid du Colombier /*
831219b2ee8SDavid du Colombier  *	find the pc given a file name and line offset into it.
832219b2ee8SDavid du Colombier  */
8334de34a7eSDavid du Colombier uvlong
file2pc(char * file,long line)8344de34a7eSDavid du Colombier file2pc(char *file, long line)
835219b2ee8SDavid du Colombier {
836219b2ee8SDavid du Colombier 	File *fp;
8374de34a7eSDavid du Colombier 	long i;
8384de34a7eSDavid du Colombier 	uvlong pc, start, end;
839219b2ee8SDavid du Colombier 	short *name;
840219b2ee8SDavid du Colombier 
841219b2ee8SDavid du Colombier 	if(buildtbls() == 0 || files == 0)
8424de34a7eSDavid du Colombier 		return ~0;
843219b2ee8SDavid du Colombier 	name = encfname(file);
844219b2ee8SDavid du Colombier 	if(name == 0) {			/* encode the file name */
845219b2ee8SDavid du Colombier 		werrstr("file %s not found", file);
8464de34a7eSDavid du Colombier 		return ~0;
847219b2ee8SDavid du Colombier 	}
848219b2ee8SDavid du Colombier 		/* find this history stack */
849219b2ee8SDavid du Colombier 	for(i = 0, fp = files; i < nfiles; i++, fp++)
850219b2ee8SDavid du Colombier 		if (hline(fp, name, &line))
851219b2ee8SDavid du Colombier 			break;
852219b2ee8SDavid du Colombier 	free(name);
853219b2ee8SDavid du Colombier 	if(i >= nfiles) {
8547dd7cddfSDavid du Colombier 		werrstr("line %ld in file %s not found", line, file);
8554de34a7eSDavid du Colombier 		return ~0;
856219b2ee8SDavid du Colombier 	}
857219b2ee8SDavid du Colombier 	start = fp->addr;		/* first text addr this file */
858219b2ee8SDavid du Colombier 	if(i < nfiles-1)
859219b2ee8SDavid du Colombier 		end = (fp+1)->addr;	/* first text addr next file */
860219b2ee8SDavid du Colombier 	else
861219b2ee8SDavid du Colombier 		end = 0;		/* last file in load module */
862219b2ee8SDavid du Colombier 	/*
863219b2ee8SDavid du Colombier 	 * At this point, line contains the offset into the file.
864219b2ee8SDavid du Colombier 	 * run the state machine to locate the pc closest to that value.
865219b2ee8SDavid du Colombier 	 */
866219b2ee8SDavid du Colombier 	if(debug)
8674de34a7eSDavid du Colombier 		print("find pc for %ld - between: %llux and %llux\n", line, start, end);
868219b2ee8SDavid du Colombier 	pc = line2addr(line, start, end);
8694de34a7eSDavid du Colombier 	if(pc == ~0) {
8707dd7cddfSDavid du Colombier 		werrstr("line %ld not in file %s", line, file);
8714de34a7eSDavid du Colombier 		return ~0;
872219b2ee8SDavid du Colombier 	}
873219b2ee8SDavid du Colombier 	return pc;
874219b2ee8SDavid du Colombier }
8754de34a7eSDavid du Colombier 
876219b2ee8SDavid du Colombier /*
877219b2ee8SDavid du Colombier  *	search for a path component index
878219b2ee8SDavid du Colombier  */
879219b2ee8SDavid du Colombier static int
pathcomp(char * s,int n)880219b2ee8SDavid du Colombier pathcomp(char *s, int n)
881219b2ee8SDavid du Colombier {
882219b2ee8SDavid du Colombier 	int i;
883219b2ee8SDavid du Colombier 
884219b2ee8SDavid du Colombier 	for(i = 0; i <= fmax; i++)
885219b2ee8SDavid du Colombier 		if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
886219b2ee8SDavid du Colombier 			return i;
887219b2ee8SDavid du Colombier 	return -1;
888219b2ee8SDavid du Colombier }
8894de34a7eSDavid du Colombier 
890219b2ee8SDavid du Colombier /*
891219b2ee8SDavid du Colombier  *	Encode a char file name as a sequence of short indices
892219b2ee8SDavid du Colombier  *	into the file name dictionary.
893219b2ee8SDavid du Colombier  */
894219b2ee8SDavid du Colombier static short*
encfname(char * file)895219b2ee8SDavid du Colombier encfname(char *file)
896219b2ee8SDavid du Colombier {
897219b2ee8SDavid du Colombier 	int i, j;
898219b2ee8SDavid du Colombier 	char *cp, *cp2;
899219b2ee8SDavid du Colombier 	short *dest;
900219b2ee8SDavid du Colombier 
901219b2ee8SDavid du Colombier 	if(*file == '/')	/* always check first '/' */
902219b2ee8SDavid du Colombier 		cp2 = file+1;
903219b2ee8SDavid du Colombier 	else {
904219b2ee8SDavid du Colombier 		cp2 = strchr(file, '/');
905219b2ee8SDavid du Colombier 		if(!cp2)
906219b2ee8SDavid du Colombier 			cp2 = strchr(file, 0);
907219b2ee8SDavid du Colombier 	}
908219b2ee8SDavid du Colombier 	cp = file;
909219b2ee8SDavid du Colombier 	dest = 0;
910219b2ee8SDavid du Colombier 	for(i = 0; *cp; i++) {
911219b2ee8SDavid du Colombier 		j = pathcomp(cp, cp2-cp);
912219b2ee8SDavid du Colombier 		if(j < 0)
913219b2ee8SDavid du Colombier 			return 0;	/* not found */
914219b2ee8SDavid du Colombier 		dest = realloc(dest, (i+1)*sizeof(short));
915219b2ee8SDavid du Colombier 		dest[i] = j;
916219b2ee8SDavid du Colombier 		cp = cp2;
917219b2ee8SDavid du Colombier 		while(*cp == '/')	/* skip embedded '/'s */
918219b2ee8SDavid du Colombier 			cp++;
919219b2ee8SDavid du Colombier 		cp2 = strchr(cp, '/');
920219b2ee8SDavid du Colombier 		if(!cp2)
921219b2ee8SDavid du Colombier 			cp2 = strchr(cp, 0);
922219b2ee8SDavid du Colombier 	}
923219b2ee8SDavid du Colombier 	dest = realloc(dest, (i+1)*sizeof(short));
924219b2ee8SDavid du Colombier 	dest[i] = 0;
925219b2ee8SDavid du Colombier 	return dest;
926219b2ee8SDavid du Colombier }
9274de34a7eSDavid du Colombier 
928219b2ee8SDavid du Colombier /*
929219b2ee8SDavid du Colombier  *	Search a history stack for a matching file name accumulating
930219b2ee8SDavid du Colombier  *	the size of intervening files in the stack.
931219b2ee8SDavid du Colombier  */
932219b2ee8SDavid du Colombier static int
hline(File * fp,short * name,long * line)9334de34a7eSDavid du Colombier hline(File *fp, short *name, long *line)
934219b2ee8SDavid du Colombier {
935219b2ee8SDavid du Colombier 	Hist *hp;
936219b2ee8SDavid du Colombier 	int offset, depth;
937219b2ee8SDavid du Colombier 	long ln;
938219b2ee8SDavid du Colombier 
939219b2ee8SDavid du Colombier 	for(hp = fp->hist; hp->name; hp++)		/* find name in stack */
940219b2ee8SDavid du Colombier 		if(hp->name[1] || hp->name[2]) {
941219b2ee8SDavid du Colombier 			if(hcomp(hp, name))
942219b2ee8SDavid du Colombier 				break;
943219b2ee8SDavid du Colombier 		}
944219b2ee8SDavid du Colombier 	if(!hp->name)		/* match not found */
945219b2ee8SDavid du Colombier 		return 0;
946219b2ee8SDavid du Colombier 	if(debug)
947219b2ee8SDavid du Colombier 		printhist("hline found ... ", hp, 1);
948219b2ee8SDavid du Colombier 	/*
949219b2ee8SDavid du Colombier 	 * unwind the stack until empty or we hit an entry beyond our line
950219b2ee8SDavid du Colombier 	 */
951219b2ee8SDavid du Colombier 	ln = *line;
952219b2ee8SDavid du Colombier 	offset = hp->line-1;
953219b2ee8SDavid du Colombier 	depth = 1;
954219b2ee8SDavid du Colombier 	for(hp++; depth && hp->name; hp++) {
955219b2ee8SDavid du Colombier 		if(debug)
956219b2ee8SDavid du Colombier 			printhist("hline inspect ... ", hp, 1);
957219b2ee8SDavid du Colombier 		if(hp->name[1] || hp->name[2]) {
958219b2ee8SDavid du Colombier 			if(hp->offset){			/* Z record */
959219b2ee8SDavid du Colombier 				offset = 0;
960219b2ee8SDavid du Colombier 				if(hcomp(hp, name)) {
961219b2ee8SDavid du Colombier 					if(*line <= hp->offset)
962219b2ee8SDavid du Colombier 						break;
963219b2ee8SDavid du Colombier 					ln = *line+hp->line-hp->offset;
964219b2ee8SDavid du Colombier 					depth = 1;	/* implicit pop */
965219b2ee8SDavid du Colombier 				} else
966219b2ee8SDavid du Colombier 					depth = 2;	/* implicit push */
967219b2ee8SDavid du Colombier 			} else if(depth == 1 && ln < hp->line-offset)
968219b2ee8SDavid du Colombier 					break;		/* Beyond our line */
969219b2ee8SDavid du Colombier 			else if(depth++ == 1)		/* push	*/
970219b2ee8SDavid du Colombier 				offset -= hp->line;
971219b2ee8SDavid du Colombier 		} else if(--depth == 1)		/* pop */
972219b2ee8SDavid du Colombier 			offset += hp->line;
973219b2ee8SDavid du Colombier 	}
974219b2ee8SDavid du Colombier 	*line = ln+offset;
975219b2ee8SDavid du Colombier 	return 1;
976219b2ee8SDavid du Colombier }
9774de34a7eSDavid du Colombier 
978219b2ee8SDavid du Colombier /*
979219b2ee8SDavid du Colombier  *	compare two encoded file names
980219b2ee8SDavid du Colombier  */
981219b2ee8SDavid du Colombier static int
hcomp(Hist * hp,short * sp)982219b2ee8SDavid du Colombier hcomp(Hist *hp, short *sp)
983219b2ee8SDavid du Colombier {
984219b2ee8SDavid du Colombier 	uchar *cp;
985219b2ee8SDavid du Colombier 	int i, j;
986219b2ee8SDavid du Colombier 	short *s;
987219b2ee8SDavid du Colombier 
988219b2ee8SDavid du Colombier 	cp = (uchar *)hp->name;
989219b2ee8SDavid du Colombier 	s = sp;
990219b2ee8SDavid du Colombier 	if (*s == 0)
991219b2ee8SDavid du Colombier 		return 0;
992219b2ee8SDavid du Colombier 	for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
993219b2ee8SDavid du Colombier 		if(j == 0)
994219b2ee8SDavid du Colombier 			break;
995219b2ee8SDavid du Colombier 		if(*s == j)
996219b2ee8SDavid du Colombier 			s++;
997219b2ee8SDavid du Colombier 		else
998219b2ee8SDavid du Colombier 			s = sp;
999219b2ee8SDavid du Colombier 	}
1000219b2ee8SDavid du Colombier 	return *s == 0;
1001219b2ee8SDavid du Colombier }
10024de34a7eSDavid du Colombier 
1003219b2ee8SDavid du Colombier /*
1004219b2ee8SDavid du Colombier  *	Convert a pc to a "file:line {file:line}" string.
1005219b2ee8SDavid du Colombier  */
10064de34a7eSDavid du Colombier long
fileline(char * str,int n,uvlong dot)10074de34a7eSDavid du Colombier fileline(char *str, int n, uvlong dot)
1008219b2ee8SDavid du Colombier {
10094de34a7eSDavid du Colombier 	long line, top, bot, mid;
1010219b2ee8SDavid du Colombier 	File *f;
1011219b2ee8SDavid du Colombier 
1012219b2ee8SDavid du Colombier 	*str = 0;
1013219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
1014219b2ee8SDavid du Colombier 		return 0;
1015219b2ee8SDavid du Colombier 		/* binary search assumes file list is sorted by addr */
1016219b2ee8SDavid du Colombier 	bot = 0;
1017219b2ee8SDavid du Colombier 	top = nfiles;
1018219b2ee8SDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
1019219b2ee8SDavid du Colombier 		f = &files[mid];
1020219b2ee8SDavid du Colombier 		if(dot < f->addr)
1021219b2ee8SDavid du Colombier 			top = mid;
1022219b2ee8SDavid du Colombier 		else if(mid < nfiles-1 && dot >= (f+1)->addr)
1023219b2ee8SDavid du Colombier 			bot = mid;
1024219b2ee8SDavid du Colombier 		else {
1025219b2ee8SDavid du Colombier 			line = pc2line(dot);
10267dd7cddfSDavid du Colombier 			if(line > 0 && fline(str, n, line, f->hist, 0) >= 0)
1027219b2ee8SDavid du Colombier 				return 1;
1028219b2ee8SDavid du Colombier 			break;
1029219b2ee8SDavid du Colombier 		}
1030219b2ee8SDavid du Colombier 	}
1031219b2ee8SDavid du Colombier 	return 0;
1032219b2ee8SDavid du Colombier }
1033219b2ee8SDavid du Colombier 
1034219b2ee8SDavid du Colombier /*
1035219b2ee8SDavid du Colombier  *	Convert a line number within a composite file to relative line
1036219b2ee8SDavid du Colombier  *	number in a source file.  A composite file is the source
1037219b2ee8SDavid du Colombier  *	file with included files inserted in line.
1038219b2ee8SDavid du Colombier  */
10397dd7cddfSDavid du Colombier static int
fline(char * str,int n,long line,Hist * base,Hist ** ret)10407dd7cddfSDavid du Colombier fline(char *str, int n, long line, Hist *base, Hist **ret)
1041219b2ee8SDavid du Colombier {
1042219b2ee8SDavid du Colombier 	Hist *start;			/* start of current level */
1043219b2ee8SDavid du Colombier 	Hist *h;			/* current entry */
10444de34a7eSDavid du Colombier 	long delta;			/* sum of size of files this level */
1045219b2ee8SDavid du Colombier 	int k;
1046219b2ee8SDavid du Colombier 
1047219b2ee8SDavid du Colombier 	start = base;
1048219b2ee8SDavid du Colombier 	h = base;
1049219b2ee8SDavid du Colombier 	delta = h->line;
1050219b2ee8SDavid du Colombier 	while(h && h->name && line > h->line) {
1051219b2ee8SDavid du Colombier 		if(h->name[1] || h->name[2]) {
1052219b2ee8SDavid du Colombier 			if(h->offset != 0) {	/* #line Directive */
1053219b2ee8SDavid du Colombier 				delta = h->line-h->offset+1;
1054219b2ee8SDavid du Colombier 				start = h;
1055219b2ee8SDavid du Colombier 				base = h++;
1056219b2ee8SDavid du Colombier 			} else {		/* beginning of File */
1057219b2ee8SDavid du Colombier 				if(start == base)
1058219b2ee8SDavid du Colombier 					start = h++;
1059219b2ee8SDavid du Colombier 				else {
10607dd7cddfSDavid du Colombier 					k = fline(str, n, line, start, &h);
10617dd7cddfSDavid du Colombier 					if(k <= 0)
10627dd7cddfSDavid du Colombier 						return k;
1063219b2ee8SDavid du Colombier 				}
1064219b2ee8SDavid du Colombier 			}
1065219b2ee8SDavid du Colombier 		} else {
10667dd7cddfSDavid du Colombier 			if(start == base && ret) {	/* end of recursion level */
10677dd7cddfSDavid du Colombier 				*ret = h;
10687dd7cddfSDavid du Colombier 				return 1;
10697dd7cddfSDavid du Colombier 			} else {			/* end of included file */
1070219b2ee8SDavid du Colombier 				delta += h->line-start->line;
1071219b2ee8SDavid du Colombier 				h++;
1072219b2ee8SDavid du Colombier 				start = base;
1073219b2ee8SDavid du Colombier 			}
1074219b2ee8SDavid du Colombier 		}
1075219b2ee8SDavid du Colombier 	}
1076219b2ee8SDavid du Colombier 	if(!h)
10777dd7cddfSDavid du Colombier 		return -1;
1078219b2ee8SDavid du Colombier 	if(start != base)
1079219b2ee8SDavid du Colombier 		line = line-start->line+1;
1080219b2ee8SDavid du Colombier 	else
1081219b2ee8SDavid du Colombier 		line = line-delta+1;
1082219b2ee8SDavid du Colombier 	if(!h->name)
1083219b2ee8SDavid du Colombier 		strncpy(str, "<eof>", n);
1084219b2ee8SDavid du Colombier 	else {
1085219b2ee8SDavid du Colombier 		k = fileelem(fnames, (uchar*)start->name, str, n);
1086219b2ee8SDavid du Colombier 		if(k+8 < n)
1087219b2ee8SDavid du Colombier 			sprint(str+k, ":%ld", line);
1088219b2ee8SDavid du Colombier 	}
1089219b2ee8SDavid du Colombier /**********Remove comments for complete back-trace of include sequence
1090219b2ee8SDavid du Colombier  *	if(start != base) {
1091219b2ee8SDavid du Colombier  *		k = strlen(str);
1092219b2ee8SDavid du Colombier  *		if(k+2 < n) {
1093219b2ee8SDavid du Colombier  *			str[k++] = ' ';
1094219b2ee8SDavid du Colombier  *			str[k++] = '{';
1095219b2ee8SDavid du Colombier  *		}
1096219b2ee8SDavid du Colombier  *		k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
1097219b2ee8SDavid du Colombier  *		if(k+10 < n)
1098219b2ee8SDavid du Colombier  *			sprint(str+k, ":%ld}", start->line-delta);
1099219b2ee8SDavid du Colombier  *	}
1100219b2ee8SDavid du Colombier  ********************/
11017dd7cddfSDavid du Colombier 	return 0;
1102219b2ee8SDavid du Colombier }
11034de34a7eSDavid du Colombier 
1104219b2ee8SDavid du Colombier /*
1105219b2ee8SDavid du Colombier  *	convert an encoded file name to a string.
1106219b2ee8SDavid du Colombier  */
1107219b2ee8SDavid du Colombier int
fileelem(Sym ** fp,uchar * cp,char * buf,int n)1108219b2ee8SDavid du Colombier fileelem(Sym **fp, uchar *cp, char *buf, int n)
1109219b2ee8SDavid du Colombier {
1110219b2ee8SDavid du Colombier 	int i, j;
1111219b2ee8SDavid du Colombier 	char *c, *bp, *end;
1112*8ccc32efSDavid du Colombier 	Sym *sym;
1113219b2ee8SDavid du Colombier 
1114219b2ee8SDavid du Colombier 	bp = buf;
1115219b2ee8SDavid du Colombier 	end = buf+n-1;
1116219b2ee8SDavid du Colombier 	for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
1117*8ccc32efSDavid du Colombier 		sym = fp[j];
1118*8ccc32efSDavid du Colombier 		if (sym == nil)
1119*8ccc32efSDavid du Colombier 			break;
1120*8ccc32efSDavid du Colombier 		c = sym->name;
1121219b2ee8SDavid du Colombier 		if(bp != buf && bp[-1] != '/' && bp < end)
1122219b2ee8SDavid du Colombier 			*bp++ = '/';
1123219b2ee8SDavid du Colombier 		while(bp < end && *c)
1124219b2ee8SDavid du Colombier 			*bp++ = *c++;
1125219b2ee8SDavid du Colombier 	}
1126219b2ee8SDavid du Colombier 	*bp = 0;
11277dd7cddfSDavid du Colombier 	i =  bp-buf;
11287dd7cddfSDavid du Colombier 	if(i > 1) {
11297dd7cddfSDavid du Colombier 		cleanname(buf);
11307dd7cddfSDavid du Colombier 		i = strlen(buf);
11317dd7cddfSDavid du Colombier 	}
11327dd7cddfSDavid du Colombier 	return i;
1133219b2ee8SDavid du Colombier }
11344de34a7eSDavid du Colombier 
1135219b2ee8SDavid du Colombier /*
1136219b2ee8SDavid du Colombier  *	compare the values of two symbol table entries.
1137219b2ee8SDavid du Colombier  */
1138219b2ee8SDavid du Colombier static int
symcomp(void * a,void * b)1139219b2ee8SDavid du Colombier symcomp(void *a, void *b)
1140219b2ee8SDavid du Colombier {
1141867bfcc6SDavid du Colombier 	int i;
1142867bfcc6SDavid du Colombier 
1143867bfcc6SDavid du Colombier 	i = (*(Sym**)a)->value - (*(Sym**)b)->value;
1144867bfcc6SDavid du Colombier 	if (i)
1145867bfcc6SDavid du Colombier 		return i;
1146867bfcc6SDavid du Colombier 	return strcmp((*(Sym**)a)->name, (*(Sym**)b)->name);
1147219b2ee8SDavid du Colombier }
11484de34a7eSDavid du Colombier 
1149219b2ee8SDavid du Colombier /*
1150219b2ee8SDavid du Colombier  *	compare the values of the symbols referenced by two text table entries
1151219b2ee8SDavid du Colombier  */
1152219b2ee8SDavid du Colombier static int
txtcomp(void * a,void * b)1153219b2ee8SDavid du Colombier txtcomp(void *a, void *b)
1154219b2ee8SDavid du Colombier {
1155219b2ee8SDavid du Colombier 	return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
1156219b2ee8SDavid du Colombier }
11574de34a7eSDavid du Colombier 
1158219b2ee8SDavid du Colombier /*
1159219b2ee8SDavid du Colombier  *	compare the values of the symbols referenced by two file table entries
1160219b2ee8SDavid du Colombier  */
1161219b2ee8SDavid du Colombier static int
filecomp(void * a,void * b)1162219b2ee8SDavid du Colombier filecomp(void *a, void *b)
1163219b2ee8SDavid du Colombier {
1164219b2ee8SDavid du Colombier 	return ((File*)a)->addr - ((File*)b)->addr;
1165219b2ee8SDavid du Colombier }
11664de34a7eSDavid du Colombier 
1167219b2ee8SDavid du Colombier /*
1168219b2ee8SDavid du Colombier  *	fill an interface Symbol structure from a symbol table entry
1169219b2ee8SDavid du Colombier  */
1170219b2ee8SDavid du Colombier static void
fillsym(Sym * sp,Symbol * s)1171219b2ee8SDavid du Colombier fillsym(Sym *sp, Symbol *s)
1172219b2ee8SDavid du Colombier {
1173219b2ee8SDavid du Colombier 	s->type = sp->type;
1174219b2ee8SDavid du Colombier 	s->value = sp->value;
1175219b2ee8SDavid du Colombier 	s->name = sp->name;
1176867bfcc6SDavid du Colombier 	s->index = 0;
1177219b2ee8SDavid du Colombier 	switch(sp->type) {
1178219b2ee8SDavid du Colombier 	case 'b':
1179219b2ee8SDavid du Colombier 	case 'B':
1180219b2ee8SDavid du Colombier 	case 'D':
1181219b2ee8SDavid du Colombier 	case 'd':
1182219b2ee8SDavid du Colombier 		s->class = CDATA;
1183219b2ee8SDavid du Colombier 		break;
1184219b2ee8SDavid du Colombier 	case 't':
1185219b2ee8SDavid du Colombier 	case 'T':
1186219b2ee8SDavid du Colombier 	case 'l':
1187219b2ee8SDavid du Colombier 	case 'L':
1188219b2ee8SDavid du Colombier 		s->class = CTEXT;
1189219b2ee8SDavid du Colombier 		break;
1190219b2ee8SDavid du Colombier 	case 'a':
1191219b2ee8SDavid du Colombier 		s->class = CAUTO;
1192219b2ee8SDavid du Colombier 		break;
1193219b2ee8SDavid du Colombier 	case 'p':
1194219b2ee8SDavid du Colombier 		s->class = CPARAM;
1195219b2ee8SDavid du Colombier 		break;
1196219b2ee8SDavid du Colombier 	case 'm':
1197219b2ee8SDavid du Colombier 		s->class = CSTAB;
1198219b2ee8SDavid du Colombier 		break;
1199219b2ee8SDavid du Colombier 	default:
1200219b2ee8SDavid du Colombier 		s->class = CNONE;
1201219b2ee8SDavid du Colombier 		break;
1202219b2ee8SDavid du Colombier 	}
1203219b2ee8SDavid du Colombier 	s->handle = 0;
1204219b2ee8SDavid du Colombier }
12054de34a7eSDavid du Colombier 
12063e12c5d1SDavid du Colombier /*
12073e12c5d1SDavid du Colombier  *	find the stack frame, given the pc
12083e12c5d1SDavid du Colombier  */
12094de34a7eSDavid du Colombier uvlong
pc2sp(uvlong pc)12104de34a7eSDavid du Colombier pc2sp(uvlong pc)
12113e12c5d1SDavid du Colombier {
12124de34a7eSDavid du Colombier 	uchar *c, u;
12134de34a7eSDavid du Colombier 	uvlong currpc, currsp;
12143e12c5d1SDavid du Colombier 
12153e12c5d1SDavid du Colombier 	if(spoff == 0)
12164de34a7eSDavid du Colombier 		return ~0;
12173e12c5d1SDavid du Colombier 	currsp = 0;
12183e12c5d1SDavid du Colombier 	currpc = txtstart - mach->pcquant;
12193e12c5d1SDavid du Colombier 
12203e12c5d1SDavid du Colombier 	if(pc<currpc || pc>txtend)
12214de34a7eSDavid du Colombier 		return ~0;
12223e12c5d1SDavid du Colombier 	for(c = spoff; c < spoffend; c++) {
12233e12c5d1SDavid du Colombier 		if (currpc >= pc)
12243e12c5d1SDavid du Colombier 			return currsp;
12253e12c5d1SDavid du Colombier 		u = *c;
12263e12c5d1SDavid du Colombier 		if (u == 0) {
12273e12c5d1SDavid du Colombier 			currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
12283e12c5d1SDavid du Colombier 			c += 4;
1229219b2ee8SDavid du Colombier 		}
1230219b2ee8SDavid du Colombier 		else if (u < 65)
12313e12c5d1SDavid du Colombier 			currsp += 4*u;
12323e12c5d1SDavid du Colombier 		else if (u < 129)
12333e12c5d1SDavid du Colombier 			currsp -= 4*(u-64);
12343e12c5d1SDavid du Colombier 		else
12353e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
12363e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
12373e12c5d1SDavid du Colombier 	}
12384de34a7eSDavid du Colombier 	return ~0;
12393e12c5d1SDavid du Colombier }
12404de34a7eSDavid du Colombier 
12413e12c5d1SDavid du Colombier /*
12423e12c5d1SDavid du Colombier  *	find the source file line number for a given value of the pc
12433e12c5d1SDavid du Colombier  */
12443e12c5d1SDavid du Colombier long
pc2line(uvlong pc)12454de34a7eSDavid du Colombier pc2line(uvlong pc)
12463e12c5d1SDavid du Colombier {
12474de34a7eSDavid du Colombier 	uchar *c, u;
12484de34a7eSDavid du Colombier 	uvlong currpc;
12493e12c5d1SDavid du Colombier 	long currline;
12503e12c5d1SDavid du Colombier 
12513e12c5d1SDavid du Colombier 	if(pcline == 0)
12523e12c5d1SDavid du Colombier 		return -1;
12533e12c5d1SDavid du Colombier 	currline = 0;
12543e12c5d1SDavid du Colombier 	currpc = txtstart-mach->pcquant;
12553e12c5d1SDavid du Colombier 	if(pc<currpc || pc>txtend)
12564de34a7eSDavid du Colombier 		return ~0;
1257219b2ee8SDavid du Colombier 
12583e12c5d1SDavid du Colombier 	for(c = pcline; c < pclineend; c++) {
12593e12c5d1SDavid du Colombier 		if(currpc >= pc)
12603e12c5d1SDavid du Colombier 			return currline;
12613e12c5d1SDavid du Colombier 		u = *c;
12623e12c5d1SDavid du Colombier 		if(u == 0) {
12633e12c5d1SDavid du Colombier 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
12643e12c5d1SDavid du Colombier 			c += 4;
1265219b2ee8SDavid du Colombier 		}
1266219b2ee8SDavid du Colombier 		else if(u < 65)
12673e12c5d1SDavid du Colombier 			currline += u;
12683e12c5d1SDavid du Colombier 		else if(u < 129)
12693e12c5d1SDavid du Colombier 			currline -= (u-64);
12703e12c5d1SDavid du Colombier 		else
12713e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
12723e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
12733e12c5d1SDavid du Colombier 	}
12744de34a7eSDavid du Colombier 	return ~0;
12753e12c5d1SDavid du Colombier }
12764de34a7eSDavid du Colombier 
12773e12c5d1SDavid du Colombier /*
1278bd389b36SDavid du Colombier  *	find the pc associated with a line number
1279bd389b36SDavid du Colombier  *	basepc and endpc are text addresses bounding the search.
1280bd389b36SDavid du Colombier  *	if endpc == 0, the end of the table is used (i.e., no upper bound).
1281bd389b36SDavid du Colombier  *	usually, basepc and endpc contain the first text address in
1282bd389b36SDavid du Colombier  *	a file and the first text address in the following file, respectively.
12833e12c5d1SDavid du Colombier  */
12844de34a7eSDavid du Colombier uvlong
line2addr(long line,uvlong basepc,uvlong endpc)12854de34a7eSDavid du Colombier line2addr(long line, uvlong basepc, uvlong endpc)
12863e12c5d1SDavid du Colombier {
12874de34a7eSDavid du Colombier 	uchar *c,  u;
12884de34a7eSDavid du Colombier 	uvlong currpc, pc;
1289bd389b36SDavid du Colombier 	long currline;
1290bd389b36SDavid du Colombier 	long delta, d;
12914de34a7eSDavid du Colombier 	int found;
12923e12c5d1SDavid du Colombier 
12933e12c5d1SDavid du Colombier 	if(pcline == 0 || line == 0)
12944de34a7eSDavid du Colombier 		return ~0;
1295219b2ee8SDavid du Colombier 
1296bd389b36SDavid du Colombier 	currline = 0;
1297bd389b36SDavid du Colombier 	currpc = txtstart-mach->pcquant;
12984de34a7eSDavid du Colombier 	pc = ~0;
1299bd389b36SDavid du Colombier 	found = 0;
1300bd389b36SDavid du Colombier 	delta = HUGEINT;
13013e12c5d1SDavid du Colombier 
13023e12c5d1SDavid du Colombier 	for(c = pcline; c < pclineend; c++) {
1303bd389b36SDavid du Colombier 		if(endpc && currpc >= endpc)	/* end of file of interest */
1304bd389b36SDavid du Colombier 			break;
1305bd389b36SDavid du Colombier 		if(currpc >= basepc) {		/* proper file */
1306bd389b36SDavid du Colombier 			if(currline >= line) {
1307bd389b36SDavid du Colombier 				d = currline-line;
1308bd389b36SDavid du Colombier 				found = 1;
1309bd389b36SDavid du Colombier 			} else
1310bd389b36SDavid du Colombier 				d = line-currline;
1311bd389b36SDavid du Colombier 			if(d < delta) {
1312bd389b36SDavid du Colombier 				delta = d;
1313bd389b36SDavid du Colombier 				pc = currpc;
13143e12c5d1SDavid du Colombier 			}
1315bd389b36SDavid du Colombier 		}
13163e12c5d1SDavid du Colombier 		u = *c;
13173e12c5d1SDavid du Colombier 		if(u == 0) {
13183e12c5d1SDavid du Colombier 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
13193e12c5d1SDavid du Colombier 			c += 4;
1320219b2ee8SDavid du Colombier 		}
1321219b2ee8SDavid du Colombier 		else if(u < 65)
13223e12c5d1SDavid du Colombier 			currline += u;
13233e12c5d1SDavid du Colombier 		else if(u < 129)
13243e12c5d1SDavid du Colombier 			currline -= (u-64);
13253e12c5d1SDavid du Colombier 		else
13263e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
13273e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
13283e12c5d1SDavid du Colombier 	}
1329bd389b36SDavid du Colombier 	if(found)
1330bd389b36SDavid du Colombier 		return pc;
13314de34a7eSDavid du Colombier 	return ~0;
13323e12c5d1SDavid du Colombier }
13334de34a7eSDavid du Colombier 
13343e12c5d1SDavid du Colombier /*
1335219b2ee8SDavid du Colombier  *	Print a history stack (debug). if count is 0, prints the whole stack
13363e12c5d1SDavid du Colombier  */
13377dd7cddfSDavid du Colombier static void
printhist(char * msg,Hist * hp,int count)1338219b2ee8SDavid du Colombier printhist(char *msg, Hist *hp, int count)
13393e12c5d1SDavid du Colombier {
1340219b2ee8SDavid du Colombier 	int i;
1341219b2ee8SDavid du Colombier 	uchar *cp;
1342219b2ee8SDavid du Colombier 	char buf[128];
13433e12c5d1SDavid du Colombier 
1344219b2ee8SDavid du Colombier 	i = 0;
1345219b2ee8SDavid du Colombier 	while(hp->name) {
1346219b2ee8SDavid du Colombier 		if(count && ++i > count)
13473e12c5d1SDavid du Colombier 			break;
13487dd7cddfSDavid du Colombier 		print("%s Line: %lx (%ld)  Offset: %lx (%ld)  Name: ", msg,
1349219b2ee8SDavid du Colombier 			hp->line, hp->line, hp->offset, hp->offset);
1350219b2ee8SDavid du Colombier 		for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
1351219b2ee8SDavid du Colombier 			if (cp != (uchar *)hp->name+1)
1352219b2ee8SDavid du Colombier 				print("/");
1353219b2ee8SDavid du Colombier 			print("%x", (*cp<<8)|cp[1]);
13543e12c5d1SDavid du Colombier 		}
1355219b2ee8SDavid du Colombier 		fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
1356219b2ee8SDavid du Colombier 		print(" (%s)\n", buf);
1357219b2ee8SDavid du Colombier 		hp++;
13583e12c5d1SDavid du Colombier 	}
1359219b2ee8SDavid du Colombier }
1360219b2ee8SDavid du Colombier 
1361219b2ee8SDavid du Colombier #ifdef DEBUG
1362219b2ee8SDavid du Colombier /*
1363219b2ee8SDavid du Colombier  *	print the history stack for a file. (debug only)
1364219b2ee8SDavid du Colombier  *	if (name == 0) => print all history stacks.
1365219b2ee8SDavid du Colombier  */
1366219b2ee8SDavid du Colombier void
dumphist(char * name)1367219b2ee8SDavid du Colombier dumphist(char *name)
1368219b2ee8SDavid du Colombier {
1369219b2ee8SDavid du Colombier 	int i;
1370219b2ee8SDavid du Colombier 	File *f;
1371219b2ee8SDavid du Colombier 	short *fname;
1372219b2ee8SDavid du Colombier 
1373219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
1374219b2ee8SDavid du Colombier 		return;
1375219b2ee8SDavid du Colombier 	if(name)
1376219b2ee8SDavid du Colombier 		fname = encfname(name);
1377219b2ee8SDavid du Colombier 	for(i = 0, f = files; i < nfiles; i++, f++)
1378219b2ee8SDavid du Colombier 		if(fname == 0 || hcomp(f->hist, fname))
1379219b2ee8SDavid du Colombier 			printhist("> ", f->hist, f->n);
1380219b2ee8SDavid du Colombier 
1381219b2ee8SDavid du Colombier 	if(fname)
1382219b2ee8SDavid du Colombier 		free(fname);
1383219b2ee8SDavid du Colombier }
1384219b2ee8SDavid du Colombier #endif
1385