xref: /plan9/sys/src/libmach/sym.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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
7*219b2ee8SDavid du Colombier #define	NNAME	20		/* a relic of the past */
8bd389b36SDavid du Colombier 
9*219b2ee8SDavid du Colombier typedef	struct txtsym Txtsym;
10*219b2ee8SDavid du Colombier typedef	struct file File;
11*219b2ee8SDavid du Colombier typedef	struct hist Hist;
123e12c5d1SDavid du Colombier 
13*219b2ee8SDavid du Colombier struct txtsym {				/* Text Symbol table */
14*219b2ee8SDavid du Colombier 	int 	n;			/* number of local vars */
15*219b2ee8SDavid du Colombier 	Sym	**locals;		/* array of ptrs to autos */
16*219b2ee8SDavid du Colombier 	Sym	*sym;			/* function symbol entry */
17*219b2ee8SDavid du Colombier };
18*219b2ee8SDavid du Colombier 
19*219b2ee8SDavid du Colombier struct hist {		/* Stack of include files & #line directives */
20*219b2ee8SDavid du Colombier 	char	*name;			/* Assumes names Null terminated in file */
21*219b2ee8SDavid du Colombier 	long	line;			/* line # where it was included */
22*219b2ee8SDavid du Colombier 	long	offset;			/* line # of #line directive */
23*219b2ee8SDavid du Colombier };
24*219b2ee8SDavid du Colombier 
25*219b2ee8SDavid du Colombier struct file {				/* Per input file header to history stack */
26*219b2ee8SDavid du Colombier 	long		addr;		/* address of first text sym */
27*219b2ee8SDavid du Colombier 	union {
28*219b2ee8SDavid du Colombier 		Txtsym		*txt;	/* first text symbol */
29*219b2ee8SDavid du Colombier 		Sym		*sym;	/* only during initilization */
30*219b2ee8SDavid du Colombier 	};
31*219b2ee8SDavid du Colombier 	int		n;		/* size of history stack */
32*219b2ee8SDavid du Colombier 	Hist		*hist;		/* history stack */
33*219b2ee8SDavid du Colombier };
34*219b2ee8SDavid du Colombier 
35*219b2ee8SDavid du Colombier static	int	debug = 0;
36*219b2ee8SDavid du Colombier 
37*219b2ee8SDavid du Colombier static	Sym	**autos;		/* Base of auto variables */
38*219b2ee8SDavid du Colombier static	File	*files;			/* Base of file arena */
39*219b2ee8SDavid du Colombier static	int	fmax;			/* largest file path index */
40*219b2ee8SDavid du Colombier static	Sym	**fnames;		/* file names path component table */
41*219b2ee8SDavid du Colombier static	Sym	**globals;		/* globals by addr table */
42*219b2ee8SDavid du Colombier static	Hist	*hist;			/* base of history stack */
43*219b2ee8SDavid du Colombier static	int	isbuilt;		/* internal table init flag */
44*219b2ee8SDavid du Colombier static	long	nauto;			/* number of automatics */
45*219b2ee8SDavid du Colombier static	long	nfiles;			/* number of files */
46*219b2ee8SDavid du Colombier static	long	nglob;			/* number of globals */
47*219b2ee8SDavid du Colombier static	long	nhist;			/* number of history stack entries */
483e12c5d1SDavid du Colombier static	long	nsym;			/* number of symbols */
49*219b2ee8SDavid du Colombier static	int	ntxt;			/* number of text symbols */
50*219b2ee8SDavid du Colombier static	uchar	*pcline;		/* start of pc-line state table */
513e12c5d1SDavid du Colombier static	uchar 	*pclineend;		/* end of pc-line table */
52*219b2ee8SDavid du Colombier static	uchar	*spoff;			/* start of pc-sp state table */
53*219b2ee8SDavid du Colombier static	uchar	*spoffend;		/* end of pc-sp offset table */
54*219b2ee8SDavid du Colombier static	Sym	*symbols;		/* symbol table */
55*219b2ee8SDavid du Colombier static	Txtsym	*txt;			/* Base of text symbol table */
56*219b2ee8SDavid du Colombier static	long	txtstart;		/* start of text segment */
573e12c5d1SDavid du Colombier static	long	txtend;			/* end of text segment */
583e12c5d1SDavid du Colombier 
59*219b2ee8SDavid du Colombier static void	cleansyms(void);
60*219b2ee8SDavid du Colombier static int	decodename(Biobuf*, Sym*);
61*219b2ee8SDavid du Colombier static short	*encfname(char *);
62*219b2ee8SDavid du Colombier static Hist 	*fline(char *, int, long, Hist *);
63*219b2ee8SDavid du Colombier static void	fillsym(Sym *, Symbol *);
64*219b2ee8SDavid du Colombier static int	findglobal(char *, Symbol *);
65*219b2ee8SDavid du Colombier static int	findlocvar(Symbol *, char *, Symbol *);
66*219b2ee8SDavid du Colombier static int	findtext(char *, Symbol *);
67*219b2ee8SDavid du Colombier static int	hcomp(Hist *, short *);
68*219b2ee8SDavid du Colombier static int	hline(File *, short *, ulong *);
69*219b2ee8SDavid du Colombier static void	printhist(char *, Hist *, int);
70*219b2ee8SDavid du Colombier static int	buildtbls(void);
71*219b2ee8SDavid du Colombier static int	symcomp(void *, void *);
72*219b2ee8SDavid du Colombier static int	symerrmsg(int, char*);
73*219b2ee8SDavid du Colombier static int	txtcomp(void *, void *);
74*219b2ee8SDavid du Colombier static int	filecomp(void *, void *);
75*219b2ee8SDavid du Colombier 
763e12c5d1SDavid du Colombier /*
773e12c5d1SDavid du Colombier  *	initialize the symbol tables
783e12c5d1SDavid du Colombier  */
793e12c5d1SDavid du Colombier int
803e12c5d1SDavid du Colombier syminit(int fd, Fhdr *fp)
813e12c5d1SDavid du Colombier {
82*219b2ee8SDavid du Colombier 	Sym *p;
83*219b2ee8SDavid du Colombier 	int i, size;
84*219b2ee8SDavid du Colombier 	Biobuf b;
853e12c5d1SDavid du Colombier 
863e12c5d1SDavid du Colombier 	if(fp->symsz == 0)
873e12c5d1SDavid du Colombier 		return 0;
88*219b2ee8SDavid du Colombier 	if(fp->type == FNONE)
89*219b2ee8SDavid du Colombier 		return 0;
903e12c5d1SDavid du Colombier 
91*219b2ee8SDavid du Colombier 	cleansyms();
92*219b2ee8SDavid du Colombier 	textseg(fp->txtaddr, fp);
93*219b2ee8SDavid du Colombier 		/* minimum symbol record size = 4+1+2 bytes */
94*219b2ee8SDavid du Colombier 	symbols = malloc((fp->symsz/(4+1+2)+1)*sizeof(Sym));
953e12c5d1SDavid du Colombier 	if(symbols == 0) {
96*219b2ee8SDavid du Colombier 		werrstr("can't malloc %d bytes", fp->symsz);
973e12c5d1SDavid du Colombier 		return -1;
983e12c5d1SDavid du Colombier 	}
99*219b2ee8SDavid du Colombier 
100*219b2ee8SDavid du Colombier 	Binit(&b, fd, OREAD);
101*219b2ee8SDavid du Colombier 	Bseek(&b, fp->symoff, 0);
102*219b2ee8SDavid du Colombier 	nsym = 0;
103*219b2ee8SDavid du Colombier 	size = 0;
104*219b2ee8SDavid du Colombier 	for(p = symbols; size < fp->symsz; p++, nsym++) {
105*219b2ee8SDavid du Colombier 		if(Bread(&b, &p->value, sizeof(p->value)) != sizeof(p->value))
106*219b2ee8SDavid du Colombier 			return symerrmsg(sizeof(p->value), "symbol");
107*219b2ee8SDavid du Colombier 		p->value = beswal(p->value);
108*219b2ee8SDavid du Colombier 		if(Bread(&b, &p->type, sizeof(p->type)) != sizeof(p->type))
109*219b2ee8SDavid du Colombier 			return symerrmsg(sizeof(p->value), "symbol");
110*219b2ee8SDavid du Colombier 
111*219b2ee8SDavid du Colombier 		i = decodename(&b, p);
112*219b2ee8SDavid du Colombier 		if(i < 0)
1133e12c5d1SDavid du Colombier 			return -1;
114*219b2ee8SDavid du Colombier 		size += i+sizeof(p->value)+sizeof(p->type);
115*219b2ee8SDavid du Colombier 
116*219b2ee8SDavid du Colombier 		/* count global & auto vars, text symbols, and file names */
117*219b2ee8SDavid du Colombier 		switch (p->type) {
118*219b2ee8SDavid du Colombier 		case 'l':
119*219b2ee8SDavid du Colombier 		case 'L':
120*219b2ee8SDavid du Colombier 		case 't':
121*219b2ee8SDavid du Colombier 		case 'T':
122*219b2ee8SDavid du Colombier 			ntxt++;
123*219b2ee8SDavid du Colombier 			break;
124*219b2ee8SDavid du Colombier 		case 'd':
125*219b2ee8SDavid du Colombier 		case 'D':
126*219b2ee8SDavid du Colombier 		case 'b':
127*219b2ee8SDavid du Colombier 		case 'B':
128*219b2ee8SDavid du Colombier 			nglob++;
129*219b2ee8SDavid du Colombier 			break;
130*219b2ee8SDavid du Colombier 		case 'f':
131*219b2ee8SDavid du Colombier 			if(strcmp(p->name, ".frame") == 0) {
132*219b2ee8SDavid du Colombier 				p->type = 'm';
133*219b2ee8SDavid du Colombier 				nauto++;
1343e12c5d1SDavid du Colombier 			}
135*219b2ee8SDavid du Colombier 			else if(p->value > fmax)
136*219b2ee8SDavid du Colombier 				fmax = p->value;	/* highest path index */
137*219b2ee8SDavid du Colombier 			break;
138*219b2ee8SDavid du Colombier 		case 'a':
139*219b2ee8SDavid du Colombier 		case 'p':
140*219b2ee8SDavid du Colombier 		case 'm':
141*219b2ee8SDavid du Colombier 			nauto++;
142*219b2ee8SDavid du Colombier 			break;
143*219b2ee8SDavid du Colombier 		case 'z':
144*219b2ee8SDavid du Colombier 			if(p->value == 1) {		/* one extra per file */
145*219b2ee8SDavid du Colombier 				nhist++;
146*219b2ee8SDavid du Colombier 				nfiles++;
1473e12c5d1SDavid du Colombier 			}
148*219b2ee8SDavid du Colombier 			nhist++;
149*219b2ee8SDavid du Colombier 			break;
150*219b2ee8SDavid du Colombier 		default:
151*219b2ee8SDavid du Colombier 			break;
152*219b2ee8SDavid du Colombier 		}
153*219b2ee8SDavid du Colombier 	}
154*219b2ee8SDavid du Colombier 	if (debug)
155*219b2ee8SDavid du Colombier 		print("NG: %d NT: %d NF: %d\n", nglob, ntxt, fmax);
1563e12c5d1SDavid du Colombier 	if (fp->sppcsz) {			/* pc-sp offset table */
1573e12c5d1SDavid du Colombier 		spoff = (uchar *)malloc(fp->sppcsz);
1583e12c5d1SDavid du Colombier 		if(spoff == 0) {
159*219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", fp->sppcsz);
1603e12c5d1SDavid du Colombier 			return -1;
1613e12c5d1SDavid du Colombier 		}
162*219b2ee8SDavid du Colombier 		Bseek(&b, fp->sppcoff, 0);
163*219b2ee8SDavid du Colombier 		i = Bread(&b, spoff, fp->sppcsz);
1643e12c5d1SDavid du Colombier 		if(i != fp->sppcsz){
1653e12c5d1SDavid du Colombier 			spoff = 0;
166*219b2ee8SDavid du Colombier 			return symerrmsg(fp->sppcsz, "sp-pc");
1673e12c5d1SDavid du Colombier 		}
1683e12c5d1SDavid du Colombier 		spoffend = spoff+fp->sppcsz;
1693e12c5d1SDavid du Colombier 	}
1703e12c5d1SDavid du Colombier 	if (fp->lnpcsz) {			/* pc-line number table */
1713e12c5d1SDavid du Colombier 		pcline = (uchar *)malloc(fp->lnpcsz);
1723e12c5d1SDavid du Colombier 		if(pcline == 0) {
173*219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", fp->lnpcsz);
1743e12c5d1SDavid du Colombier 			return -1;
1753e12c5d1SDavid du Colombier 		}
176*219b2ee8SDavid du Colombier 		Bseek(&b, fp->lnpcoff, 0);
177*219b2ee8SDavid du Colombier 		i = Bread(&b, pcline, fp->lnpcsz);
1783e12c5d1SDavid du Colombier 		if(i != fp->lnpcsz){
1793e12c5d1SDavid du Colombier 			pcline = 0;
180*219b2ee8SDavid du Colombier 			return symerrmsg(fp->lnpcsz, "pc-line");
1813e12c5d1SDavid du Colombier 		}
1823e12c5d1SDavid du Colombier 		pclineend = pcline+fp->lnpcsz;
1833e12c5d1SDavid du Colombier 	}
1843e12c5d1SDavid du Colombier 	return nsym;
1853e12c5d1SDavid du Colombier }
186*219b2ee8SDavid du Colombier 
187*219b2ee8SDavid du Colombier static int
188*219b2ee8SDavid du Colombier symerrmsg(int n, char *table)
189*219b2ee8SDavid du Colombier {
190*219b2ee8SDavid du Colombier 	werrstr("can't read %d bytes of %s table", n, table);
191*219b2ee8SDavid du Colombier 	return -1;
192*219b2ee8SDavid du Colombier }
193*219b2ee8SDavid du Colombier 
194*219b2ee8SDavid du Colombier static int
195*219b2ee8SDavid du Colombier decodename(Biobuf *bp, Sym *p)
196*219b2ee8SDavid du Colombier {
197*219b2ee8SDavid du Colombier 	char *cp;
198*219b2ee8SDavid du Colombier 	int c1, c2;
199*219b2ee8SDavid du Colombier 	int n;
200*219b2ee8SDavid du Colombier 
201*219b2ee8SDavid du Colombier 	if((p->type & 0x80) == 0) {		/* old-style, fixed length names */
202*219b2ee8SDavid du Colombier 		p->name = malloc(NNAME);
203*219b2ee8SDavid du Colombier 		if(p->name == 0) {
204*219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", NNAME);
205*219b2ee8SDavid du Colombier 			return -1;
206*219b2ee8SDavid du Colombier 		}
207*219b2ee8SDavid du Colombier 		if(Bread(bp, p->name, NNAME) != NNAME)
208*219b2ee8SDavid du Colombier 			return symerrmsg(NNAME, "symbol");
209*219b2ee8SDavid du Colombier 		Bseek(bp, 3, 1);
210*219b2ee8SDavid du Colombier 		return NNAME+3;
211*219b2ee8SDavid du Colombier 	}
212*219b2ee8SDavid du Colombier 
213*219b2ee8SDavid du Colombier 	p->type &= ~0x80;
214*219b2ee8SDavid du Colombier 	if(p->type == 'z' || p->type == 'Z') {
215*219b2ee8SDavid du Colombier 		n = Bseek(bp, 0, 1);
216*219b2ee8SDavid du Colombier 		if(Bgetc(bp) < 0) {
217*219b2ee8SDavid du Colombier 			werrstr("can't read symbol name");
218*219b2ee8SDavid du Colombier 			return -1;
219*219b2ee8SDavid du Colombier 		}
220*219b2ee8SDavid du Colombier 		for(;;) {
221*219b2ee8SDavid du Colombier 			c1 = Bgetc(bp);
222*219b2ee8SDavid du Colombier 			c2 = Bgetc(bp);
223*219b2ee8SDavid du Colombier 			if(c1 < 0 || c2 < 0) {
224*219b2ee8SDavid du Colombier 				werrstr("can't read symbol name");
225*219b2ee8SDavid du Colombier 				return -1;
226*219b2ee8SDavid du Colombier 			}
227*219b2ee8SDavid du Colombier 			if(c1 == 0 && c2 == 0)
228*219b2ee8SDavid du Colombier 				break;
229*219b2ee8SDavid du Colombier 		}
230*219b2ee8SDavid du Colombier 		n = Bseek(bp, 0, 1)-n;
231*219b2ee8SDavid du Colombier 		p->name = malloc(n);
232*219b2ee8SDavid du Colombier 		if(p->name == 0) {
233*219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", n);
234*219b2ee8SDavid du Colombier 			return -1;
235*219b2ee8SDavid du Colombier 		}
236*219b2ee8SDavid du Colombier 		Bseek(bp, -n, 1);
237*219b2ee8SDavid du Colombier 		if(Bread(bp, p->name, n) != n) {
238*219b2ee8SDavid du Colombier 			werrstr("can't read %d bytes of symbol name", n);
239*219b2ee8SDavid du Colombier 			return -1;
240*219b2ee8SDavid du Colombier 		}
241*219b2ee8SDavid du Colombier 	} else {
242*219b2ee8SDavid du Colombier 		cp = Brdline(bp, '\0');
243*219b2ee8SDavid du Colombier 		if(cp == 0) {
244*219b2ee8SDavid du Colombier 			werrstr("can't read symbol name");
245*219b2ee8SDavid du Colombier 			return -1;
246*219b2ee8SDavid du Colombier 		}
247*219b2ee8SDavid du Colombier 		n = Blinelen(bp);
248*219b2ee8SDavid du Colombier 		p->name = malloc(n);
249*219b2ee8SDavid du Colombier 		if(p->name == 0) {
250*219b2ee8SDavid du Colombier 			werrstr("can't malloc %d bytes", n);
251*219b2ee8SDavid du Colombier 			return -1;
252*219b2ee8SDavid du Colombier 		}
253*219b2ee8SDavid du Colombier 		strcpy(p->name, cp);
254*219b2ee8SDavid du Colombier 	}
255*219b2ee8SDavid du Colombier 	return n;
256*219b2ee8SDavid du Colombier }
257*219b2ee8SDavid du Colombier /*
258*219b2ee8SDavid du Colombier  *	free any previously loaded symbol tables
259*219b2ee8SDavid du Colombier  */
260*219b2ee8SDavid du Colombier static void
261*219b2ee8SDavid du Colombier cleansyms(void)
262*219b2ee8SDavid du Colombier {
263*219b2ee8SDavid du Colombier 	if(globals)
264*219b2ee8SDavid du Colombier 		free(globals);
265*219b2ee8SDavid du Colombier 	globals = 0;
266*219b2ee8SDavid du Colombier 	nglob = 0;
267*219b2ee8SDavid du Colombier 	if(txt)
268*219b2ee8SDavid du Colombier 		free(txt);
269*219b2ee8SDavid du Colombier 	txt = 0;
270*219b2ee8SDavid du Colombier 	ntxt = 0;
271*219b2ee8SDavid du Colombier 	if(fnames)
272*219b2ee8SDavid du Colombier 		free(fnames);
273*219b2ee8SDavid du Colombier 	fnames = 0;
274*219b2ee8SDavid du Colombier 	fmax = 0;
275*219b2ee8SDavid du Colombier 
276*219b2ee8SDavid du Colombier 	if(files)
277*219b2ee8SDavid du Colombier 		free(files);
278*219b2ee8SDavid du Colombier 	files = 0;
279*219b2ee8SDavid du Colombier 	nfiles = 0;
280*219b2ee8SDavid du Colombier 	if(hist)
281*219b2ee8SDavid du Colombier 		free(hist);
282*219b2ee8SDavid du Colombier 	hist = 0;
283*219b2ee8SDavid du Colombier 	nhist = 0;
284*219b2ee8SDavid du Colombier 	if(autos)
285*219b2ee8SDavid du Colombier 		free(autos);
286*219b2ee8SDavid du Colombier 	autos = 0;
287*219b2ee8SDavid du Colombier 	nauto = 0;
288*219b2ee8SDavid du Colombier 	isbuilt = 0;
289*219b2ee8SDavid du Colombier 	if(symbols)
290*219b2ee8SDavid du Colombier 		free(symbols);
291*219b2ee8SDavid du Colombier 	symbols = 0;
292*219b2ee8SDavid du Colombier 	nsym = 0;
293*219b2ee8SDavid du Colombier 	if(spoff)
294*219b2ee8SDavid du Colombier 		free(spoff);
295*219b2ee8SDavid du Colombier 	spoff = 0;
296*219b2ee8SDavid du Colombier 	if(pcline)
297*219b2ee8SDavid du Colombier 		free(pcline);
298*219b2ee8SDavid du Colombier 	pcline = 0;
299*219b2ee8SDavid du Colombier }
300*219b2ee8SDavid du Colombier /*
301*219b2ee8SDavid du Colombier  *	delimit the text segment
302*219b2ee8SDavid du Colombier  */
303*219b2ee8SDavid du Colombier void
304*219b2ee8SDavid du Colombier textseg(ulong base, Fhdr *fp)
305*219b2ee8SDavid du Colombier {
306*219b2ee8SDavid du Colombier 	txtstart = base;
307*219b2ee8SDavid du Colombier 	txtend = base+fp->txtsz;
308*219b2ee8SDavid du Colombier }
3093e12c5d1SDavid du Colombier /*
3103e12c5d1SDavid du Colombier  *	symbase: return base and size of raw symbol table
3113e12c5d1SDavid du Colombier  *		(special hack for high access rate operations)
3123e12c5d1SDavid du Colombier  */
3133e12c5d1SDavid du Colombier Sym *
3143e12c5d1SDavid du Colombier symbase(long *n)
3153e12c5d1SDavid du Colombier {
3163e12c5d1SDavid du Colombier 	*n = nsym;
3173e12c5d1SDavid du Colombier 	return symbols;
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier /*
3203e12c5d1SDavid du Colombier  *	Get the ith symbol table entry
3213e12c5d1SDavid du Colombier  */
3223e12c5d1SDavid du Colombier Sym *
3233e12c5d1SDavid du Colombier getsym(int index)
3243e12c5d1SDavid du Colombier {
3253e12c5d1SDavid du Colombier 	if(index < nsym)
3263e12c5d1SDavid du Colombier 		return &symbols[index];
3273e12c5d1SDavid du Colombier 	return 0;
3283e12c5d1SDavid du Colombier }
329*219b2ee8SDavid du Colombier 
330*219b2ee8SDavid du Colombier /*
331*219b2ee8SDavid du Colombier  *	initialize internal symbol tables
332*219b2ee8SDavid du Colombier  */
333*219b2ee8SDavid du Colombier static int
334*219b2ee8SDavid du Colombier buildtbls(void)
335*219b2ee8SDavid du Colombier {
336*219b2ee8SDavid du Colombier 	int i, j, nh, ng, nt;
337*219b2ee8SDavid du Colombier 	File *f;
338*219b2ee8SDavid du Colombier 	Txtsym *tp;
339*219b2ee8SDavid du Colombier 	Hist *hp;
340*219b2ee8SDavid du Colombier 	Sym *p, **ap;
341*219b2ee8SDavid du Colombier 
342*219b2ee8SDavid du Colombier 	if(isbuilt)
343*219b2ee8SDavid du Colombier 		return 1;
344*219b2ee8SDavid du Colombier 	isbuilt = 1;
345*219b2ee8SDavid du Colombier 			/* allocate the tables */
346*219b2ee8SDavid du Colombier 	if(nglob) {
347*219b2ee8SDavid du Colombier 		globals = malloc(nglob*sizeof(*globals));
348*219b2ee8SDavid du Colombier 		if(!globals) {
349*219b2ee8SDavid du Colombier 			werrstr("can't malloc global symbol table");
350*219b2ee8SDavid du Colombier 			return 0;
351*219b2ee8SDavid du Colombier 		}
352*219b2ee8SDavid du Colombier 	}
353*219b2ee8SDavid du Colombier 	if(ntxt) {
354*219b2ee8SDavid du Colombier 		txt = malloc(ntxt*sizeof(*txt));
355*219b2ee8SDavid du Colombier 		if (!txt) {
356*219b2ee8SDavid du Colombier 			werrstr("can't malloc text symbol table");
357*219b2ee8SDavid du Colombier 			return 0;
358*219b2ee8SDavid du Colombier 		}
359*219b2ee8SDavid du Colombier 	}
360*219b2ee8SDavid du Colombier 	fmax++;
361*219b2ee8SDavid du Colombier 	fnames = malloc(fmax*sizeof(*fnames));
362*219b2ee8SDavid du Colombier 	if (!fnames) {
363*219b2ee8SDavid du Colombier 		werrstr("can't malloc file name table");
364*219b2ee8SDavid du Colombier 		return 0;
365*219b2ee8SDavid du Colombier 	}
366*219b2ee8SDavid du Colombier 	memset(fnames, 0, fmax*sizeof(*fnames));
367*219b2ee8SDavid du Colombier 	files = malloc(nfiles*sizeof(*files));
368*219b2ee8SDavid du Colombier 	if(!files) {
369*219b2ee8SDavid du Colombier 		werrstr("can't malloc file table");
370*219b2ee8SDavid du Colombier 		return 0;
371*219b2ee8SDavid du Colombier 	}
372*219b2ee8SDavid du Colombier 	hist = malloc(nhist*sizeof(Hist));
373*219b2ee8SDavid du Colombier 	if(hist == 0) {
374*219b2ee8SDavid du Colombier 		werrstr("can't malloc history stack");
375*219b2ee8SDavid du Colombier 		return 0;
376*219b2ee8SDavid du Colombier 	}
377*219b2ee8SDavid du Colombier 	autos = malloc(nauto*sizeof(Sym*));
378*219b2ee8SDavid du Colombier 	if(autos == 0) {
379*219b2ee8SDavid du Colombier 		werrstr("can't malloc auto symbol table");
380*219b2ee8SDavid du Colombier 		return 0;
381*219b2ee8SDavid du Colombier 	}
382*219b2ee8SDavid du Colombier 		/* load the tables */
383*219b2ee8SDavid du Colombier 	ng = nt = nh = 0;
384*219b2ee8SDavid du Colombier 	f = 0;
385*219b2ee8SDavid du Colombier 	tp = 0;
386*219b2ee8SDavid du Colombier 	i = nsym;
387*219b2ee8SDavid du Colombier 	hp = hist;
388*219b2ee8SDavid du Colombier 	ap = autos;
389*219b2ee8SDavid du Colombier 	for(p = symbols; i-- > 0; p++) {
390*219b2ee8SDavid du Colombier 		switch(p->type) {
391*219b2ee8SDavid du Colombier 		case 'D':
392*219b2ee8SDavid du Colombier 		case 'd':
393*219b2ee8SDavid du Colombier 		case 'B':
394*219b2ee8SDavid du Colombier 		case 'b':
395*219b2ee8SDavid du Colombier 			if(debug)
396*219b2ee8SDavid du Colombier 				print("Global: %s %lux\n", p->name, p->value);
397*219b2ee8SDavid du Colombier 			globals[ng++] = p;
398*219b2ee8SDavid du Colombier 			break;
399*219b2ee8SDavid du Colombier 		case 'z':
400*219b2ee8SDavid du Colombier 			if(p->value == 1) {		/* New file */
401*219b2ee8SDavid du Colombier 				if(f) {
402*219b2ee8SDavid du Colombier 					f->n = nh;
403*219b2ee8SDavid du Colombier 					f->hist[nh].name = 0;	/* one extra */
404*219b2ee8SDavid du Colombier 					hp += nh+1;
405*219b2ee8SDavid du Colombier 					f++;
406*219b2ee8SDavid du Colombier 				}
407*219b2ee8SDavid du Colombier 				else f = files;
408*219b2ee8SDavid du Colombier 				f->hist = hp;
409*219b2ee8SDavid du Colombier 				f->sym = 0;
410*219b2ee8SDavid du Colombier 				f->addr = 0;
411*219b2ee8SDavid du Colombier 				nh = 0;
412*219b2ee8SDavid du Colombier 			}
413*219b2ee8SDavid du Colombier 				/* alloc one slot extra as terminator */
414*219b2ee8SDavid du Colombier 			f->hist[nh].name = p->name;
415*219b2ee8SDavid du Colombier 			f->hist[nh].line = p->value;
416*219b2ee8SDavid du Colombier 			f->hist[nh].offset = 0;
417*219b2ee8SDavid du Colombier 			if(debug)
418*219b2ee8SDavid du Colombier 				printhist("-> ", &f->hist[nh], 1);
419*219b2ee8SDavid du Colombier 			nh++;
420*219b2ee8SDavid du Colombier 			break;
421*219b2ee8SDavid du Colombier 		case 'Z':
422*219b2ee8SDavid du Colombier 			if(f && nh > 0)
423*219b2ee8SDavid du Colombier 				f->hist[nh-1].offset = p->value;
424*219b2ee8SDavid du Colombier 			break;
425*219b2ee8SDavid du Colombier 		case 'T':
426*219b2ee8SDavid du Colombier 		case 't':	/* Text: terminate history if first in file */
427*219b2ee8SDavid du Colombier 		case 'L':
428*219b2ee8SDavid du Colombier 		case 'l':
429*219b2ee8SDavid du Colombier 			tp = &txt[nt++];
430*219b2ee8SDavid du Colombier 			tp->n = 0;
431*219b2ee8SDavid du Colombier 			tp->sym = p;
432*219b2ee8SDavid du Colombier 			tp->locals = ap;
433*219b2ee8SDavid du Colombier 			if(debug)
434*219b2ee8SDavid du Colombier 				print("TEXT: %s at %lux\n", p->name, p->value);
435*219b2ee8SDavid du Colombier 			if(f && !f->sym) {			/* first  */
436*219b2ee8SDavid du Colombier 				f->sym = p;
437*219b2ee8SDavid du Colombier 				f->addr = p->value;
438*219b2ee8SDavid du Colombier 			}
439*219b2ee8SDavid du Colombier 			break;
440*219b2ee8SDavid du Colombier 		case 'a':
441*219b2ee8SDavid du Colombier 		case 'p':
442*219b2ee8SDavid du Colombier 		case 'm':		/* Local Vars */
443*219b2ee8SDavid du Colombier 			if(!tp)
444*219b2ee8SDavid du Colombier 				print("Warning: Free floating local var");
445*219b2ee8SDavid du Colombier 			else {
446*219b2ee8SDavid du Colombier 				if(debug)
447*219b2ee8SDavid du Colombier 					print("Local: %s %lux\n", p->name, p->value);
448*219b2ee8SDavid du Colombier 				tp->locals[tp->n] = p;
449*219b2ee8SDavid du Colombier 				tp->n++;
450*219b2ee8SDavid du Colombier 				ap++;
451*219b2ee8SDavid du Colombier 			}
452*219b2ee8SDavid du Colombier 			break;
453*219b2ee8SDavid du Colombier 		case 'f':		/* File names */
454*219b2ee8SDavid du Colombier 			if(debug)
455*219b2ee8SDavid du Colombier 				print("Fname: %s\n", p->name);
456*219b2ee8SDavid du Colombier 			fnames[p->value] = p;
457*219b2ee8SDavid du Colombier 			break;
458*219b2ee8SDavid du Colombier 		default:
459*219b2ee8SDavid du Colombier 			break;
460*219b2ee8SDavid du Colombier 		}
461*219b2ee8SDavid du Colombier 	}
462*219b2ee8SDavid du Colombier 		/* sort global and text tables into ascending address order */
463*219b2ee8SDavid du Colombier 	qsort(globals, nglob, sizeof(Sym*), symcomp);
464*219b2ee8SDavid du Colombier 	qsort(txt, ntxt, sizeof(Txtsym), txtcomp);
465*219b2ee8SDavid du Colombier 	qsort(files, nfiles, sizeof(File), filecomp);
466*219b2ee8SDavid du Colombier 	tp = txt;
467*219b2ee8SDavid du Colombier 	for(i = 0, f = files; i < nfiles; i++, f++) {
468*219b2ee8SDavid du Colombier 		for(j = 0; j < ntxt; j++) {
469*219b2ee8SDavid du Colombier 			if(f->sym == tp->sym) {
470*219b2ee8SDavid du Colombier 				if(debug) {
471*219b2ee8SDavid du Colombier 					print("LINK: %s to", f->sym->name);
472*219b2ee8SDavid du Colombier 					printhist("... ", f->hist, 1);
473*219b2ee8SDavid du Colombier 				}
474*219b2ee8SDavid du Colombier 				f->txt = tp++;
475*219b2ee8SDavid du Colombier 				break;
476*219b2ee8SDavid du Colombier 			}
477*219b2ee8SDavid du Colombier 			if(++tp >= txt+ntxt)	/* wrap around */
478*219b2ee8SDavid du Colombier 				tp = txt;
479*219b2ee8SDavid du Colombier 		}
480*219b2ee8SDavid du Colombier 	}
481*219b2ee8SDavid du Colombier 	return 1;
482*219b2ee8SDavid du Colombier }
483*219b2ee8SDavid du Colombier 
484*219b2ee8SDavid du Colombier /*
485*219b2ee8SDavid du Colombier  * find symbol function.var by name.
486*219b2ee8SDavid du Colombier  *	fn != 0 && var != 0	=> look for fn in text, var in data
487*219b2ee8SDavid du Colombier  *	fn != 0 && var == 0	=> look for fn in text
488*219b2ee8SDavid du Colombier  *	fn == 0 && var != 0	=> look for var first in text then in data space.
489*219b2ee8SDavid du Colombier  */
490*219b2ee8SDavid du Colombier int
491*219b2ee8SDavid du Colombier lookup(char *fn, char *var, Symbol *s)
492*219b2ee8SDavid du Colombier {
493*219b2ee8SDavid du Colombier 	int found;
494*219b2ee8SDavid du Colombier 
495*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
496*219b2ee8SDavid du Colombier 		return 0;
497*219b2ee8SDavid du Colombier 	if(fn) {
498*219b2ee8SDavid du Colombier 		found = findtext(fn, s);
499*219b2ee8SDavid du Colombier 		if(var == 0)		/* case 2: fn not in text */
500*219b2ee8SDavid du Colombier 			return found;
501*219b2ee8SDavid du Colombier 		else if(!found)		/* case 1: fn not found */
502*219b2ee8SDavid du Colombier 			return 0;
503*219b2ee8SDavid du Colombier 	} else if(var) {
504*219b2ee8SDavid du Colombier 		found = findtext(var, s);
505*219b2ee8SDavid du Colombier 		if(found)
506*219b2ee8SDavid du Colombier 			return 1;	/* case 3: var found in text */
507*219b2ee8SDavid du Colombier 	} else return 0;		/* case 4: fn & var == zero */
508*219b2ee8SDavid du Colombier 
509*219b2ee8SDavid du Colombier 	if(found)
510*219b2ee8SDavid du Colombier 		return findlocal(s, var, s);	/* case 1: fn found */
511*219b2ee8SDavid du Colombier 	return findglobal(var, s);		/* case 3: var not found */
512*219b2ee8SDavid du Colombier 
513*219b2ee8SDavid du Colombier }
514*219b2ee8SDavid du Colombier /*
515*219b2ee8SDavid du Colombier  * find a function by name
516*219b2ee8SDavid du Colombier  */
517*219b2ee8SDavid du Colombier static int
518*219b2ee8SDavid du Colombier findtext(char *name, Symbol *s)
519*219b2ee8SDavid du Colombier {
520*219b2ee8SDavid du Colombier 	int i;
521*219b2ee8SDavid du Colombier 
522*219b2ee8SDavid du Colombier 	for(i = 0; i < ntxt; i++) {
523*219b2ee8SDavid du Colombier 		if(strcmp(txt[i].sym->name, name) == 0) {
524*219b2ee8SDavid du Colombier 			fillsym(txt[i].sym, s);
525*219b2ee8SDavid du Colombier 			s->handle = (void *) &txt[i];
526*219b2ee8SDavid du Colombier 			return 1;
527*219b2ee8SDavid du Colombier 		}
528*219b2ee8SDavid du Colombier 	}
529*219b2ee8SDavid du Colombier 	return 0;
530*219b2ee8SDavid du Colombier }
531*219b2ee8SDavid du Colombier /*
532*219b2ee8SDavid du Colombier  * find global variable by name
533*219b2ee8SDavid du Colombier  */
534*219b2ee8SDavid du Colombier static int
535*219b2ee8SDavid du Colombier findglobal(char *name, Symbol *s)
536*219b2ee8SDavid du Colombier {
537*219b2ee8SDavid du Colombier 	int i;
538*219b2ee8SDavid du Colombier 
539*219b2ee8SDavid du Colombier 	for(i = 0; i < nglob; i++) {
540*219b2ee8SDavid du Colombier 		if(strcmp(globals[i]->name, name) == 0) {
541*219b2ee8SDavid du Colombier 			fillsym(globals[i], s);
542*219b2ee8SDavid du Colombier 			return 1;
543*219b2ee8SDavid du Colombier 		}
544*219b2ee8SDavid du Colombier 	}
545*219b2ee8SDavid du Colombier 	return 0;
546*219b2ee8SDavid du Colombier }
547*219b2ee8SDavid du Colombier /*
548*219b2ee8SDavid du Colombier  *	find the local variable by name within a given function
549*219b2ee8SDavid du Colombier  */
550*219b2ee8SDavid du Colombier int
551*219b2ee8SDavid du Colombier findlocal(Symbol *s1, char *name, Symbol *s2)
552*219b2ee8SDavid du Colombier {
553*219b2ee8SDavid du Colombier 	if(s1 == 0)
554*219b2ee8SDavid du Colombier 		return 0;
555*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
556*219b2ee8SDavid du Colombier 		return 0;
557*219b2ee8SDavid du Colombier 	return findlocvar(s1, name, s2);
558*219b2ee8SDavid du Colombier }
559*219b2ee8SDavid du Colombier /*
560*219b2ee8SDavid du Colombier  *	find the local variable by name within a given function
561*219b2ee8SDavid du Colombier  *		(internal function - does no parameter validation)
562*219b2ee8SDavid du Colombier  */
563*219b2ee8SDavid du Colombier static int
564*219b2ee8SDavid du Colombier findlocvar(Symbol *s1, char *name, Symbol *s2)
565*219b2ee8SDavid du Colombier {
566*219b2ee8SDavid du Colombier 	Txtsym *tp;
567*219b2ee8SDavid du Colombier 	int i;
568*219b2ee8SDavid du Colombier 
569*219b2ee8SDavid du Colombier 	tp = (Txtsym *)s1->handle;
570*219b2ee8SDavid du Colombier 	if(tp && tp->locals) {
571*219b2ee8SDavid du Colombier 		for(i = 0; i < tp->n; i++)
572*219b2ee8SDavid du Colombier 			if (strcmp(tp->locals[i]->name, name) == 0) {
573*219b2ee8SDavid du Colombier 				fillsym(tp->locals[i], s2);
574*219b2ee8SDavid du Colombier 				s2->handle = (void *)tp;
575*219b2ee8SDavid du Colombier 				return 1;
576*219b2ee8SDavid du Colombier 			}
577*219b2ee8SDavid du Colombier 	}
578*219b2ee8SDavid du Colombier 	return 0;
579*219b2ee8SDavid du Colombier }
580*219b2ee8SDavid du Colombier /*
581*219b2ee8SDavid du Colombier  *	Get ith text symbol
582*219b2ee8SDavid du Colombier  */
583*219b2ee8SDavid du Colombier int
584*219b2ee8SDavid du Colombier textsym(Symbol *s, int index)
585*219b2ee8SDavid du Colombier {
586*219b2ee8SDavid du Colombier 
587*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
588*219b2ee8SDavid du Colombier 		return 0;
589*219b2ee8SDavid du Colombier 	if(index >= ntxt)
590*219b2ee8SDavid du Colombier 		return 0;
591*219b2ee8SDavid du Colombier 	fillsym(txt[index].sym, s);
592*219b2ee8SDavid du Colombier 	s->handle = (void *)&txt[index];
593*219b2ee8SDavid du Colombier 	return 1;
594*219b2ee8SDavid du Colombier }
595*219b2ee8SDavid du Colombier /*
596*219b2ee8SDavid du Colombier  *	Get ith file name
597*219b2ee8SDavid du Colombier  */
598*219b2ee8SDavid du Colombier int
599*219b2ee8SDavid du Colombier filesym(int index, char *buf, int n)
600*219b2ee8SDavid du Colombier {
601*219b2ee8SDavid du Colombier 	Hist *hp;
602*219b2ee8SDavid du Colombier 
603*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
604*219b2ee8SDavid du Colombier 		return 0;
605*219b2ee8SDavid du Colombier 	if(index >= nfiles)
606*219b2ee8SDavid du Colombier 		return 0;
607*219b2ee8SDavid du Colombier 	hp = files[index].hist;
608*219b2ee8SDavid du Colombier 	if(!hp || !hp->name)
609*219b2ee8SDavid du Colombier 		return 0;
610*219b2ee8SDavid du Colombier 	return fileelem(fnames, (uchar*)hp->name, buf, n);
611*219b2ee8SDavid du Colombier }
612*219b2ee8SDavid du Colombier /*
613*219b2ee8SDavid du Colombier  *	Lookup name of local variable located at an offset into the frame.
614*219b2ee8SDavid du Colombier  *	The type selects either a parameter or automatic.
615*219b2ee8SDavid du Colombier  */
616*219b2ee8SDavid du Colombier int
617*219b2ee8SDavid du Colombier getauto(Symbol *s1, int off, int type, Symbol *s2)
618*219b2ee8SDavid du Colombier {
619*219b2ee8SDavid du Colombier 	Txtsym *tp;
620*219b2ee8SDavid du Colombier 	Sym *p;
621*219b2ee8SDavid du Colombier 	int i, t;
622*219b2ee8SDavid du Colombier 
623*219b2ee8SDavid du Colombier 	if(s1 == 0)
624*219b2ee8SDavid du Colombier 		return 0;
625*219b2ee8SDavid du Colombier 	if(type == CPARAM)
626*219b2ee8SDavid du Colombier 		t = 'p';
627*219b2ee8SDavid du Colombier 	else if(type == CAUTO)
628*219b2ee8SDavid du Colombier 		t = 'a';
629*219b2ee8SDavid du Colombier 	else
630*219b2ee8SDavid du Colombier 		return 0;
631*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
632*219b2ee8SDavid du Colombier 		return 0;
633*219b2ee8SDavid du Colombier 	tp = (Txtsym *)s1->handle;
634*219b2ee8SDavid du Colombier 	if(tp == 0)
635*219b2ee8SDavid du Colombier 		return 0;
636*219b2ee8SDavid du Colombier 	for(i = 0; i < tp->n; i++) {
637*219b2ee8SDavid du Colombier 		p = tp->locals[i];
638*219b2ee8SDavid du Colombier 		if(p->type == t && p->value == off) {
639*219b2ee8SDavid du Colombier 			fillsym(p, s2);
640*219b2ee8SDavid du Colombier 			s2->handle = s1->handle;
641*219b2ee8SDavid du Colombier 			return 1;
642*219b2ee8SDavid du Colombier 		}
643*219b2ee8SDavid du Colombier 	}
644*219b2ee8SDavid du Colombier 	return 0;
645*219b2ee8SDavid du Colombier }
646*219b2ee8SDavid du Colombier 
647*219b2ee8SDavid du Colombier /*
648*219b2ee8SDavid du Colombier  * Find text symbol containing addr; binary search assumes text array is sorted by addr
649*219b2ee8SDavid du Colombier  */
650*219b2ee8SDavid du Colombier static int
651*219b2ee8SDavid du Colombier srchtext(long addr)
652*219b2ee8SDavid du Colombier {
653*219b2ee8SDavid du Colombier 	ulong val;
654*219b2ee8SDavid du Colombier 	int top, bot, mid;
655*219b2ee8SDavid du Colombier 	Sym *sp;
656*219b2ee8SDavid du Colombier 
657*219b2ee8SDavid du Colombier 	val = addr;
658*219b2ee8SDavid du Colombier 	bot = 0;
659*219b2ee8SDavid du Colombier 	top = ntxt;
660*219b2ee8SDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
661*219b2ee8SDavid du Colombier 		sp = txt[mid].sym;
662*219b2ee8SDavid du Colombier 		if(val < (ulong)sp->value)
663*219b2ee8SDavid du Colombier 			top = mid;
664*219b2ee8SDavid du Colombier 		else if(mid != ntxt-1 && val >= (ulong)txt[mid+1].sym->value)
665*219b2ee8SDavid du Colombier 			bot = mid;
666*219b2ee8SDavid du Colombier 		else
667*219b2ee8SDavid du Colombier 			return mid;
668*219b2ee8SDavid du Colombier 	}
669*219b2ee8SDavid du Colombier 	return -1;
670*219b2ee8SDavid du Colombier }
671*219b2ee8SDavid du Colombier 
672*219b2ee8SDavid du Colombier /*
673*219b2ee8SDavid du Colombier  * Find data symbol containing addr; binary search assumes data array is sorted by addr
674*219b2ee8SDavid du Colombier  */
675*219b2ee8SDavid du Colombier static
676*219b2ee8SDavid du Colombier int srchdata(long addr)
677*219b2ee8SDavid du Colombier {
678*219b2ee8SDavid du Colombier 	ulong val;
679*219b2ee8SDavid du Colombier 	int top, bot, mid;
680*219b2ee8SDavid du Colombier 	Sym *sp;
681*219b2ee8SDavid du Colombier 
682*219b2ee8SDavid du Colombier 	bot = 0;
683*219b2ee8SDavid du Colombier 	top = nglob;
684*219b2ee8SDavid du Colombier 	val = addr;
685*219b2ee8SDavid du Colombier 	for(mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
686*219b2ee8SDavid du Colombier 		sp = globals[mid];
687*219b2ee8SDavid du Colombier 		if(val < (ulong)sp->value)
688*219b2ee8SDavid du Colombier 			top = mid;
689*219b2ee8SDavid du Colombier 		else if(mid < nglob-1 && val >= (ulong)globals[mid+1]->value)
690*219b2ee8SDavid du Colombier 			bot = mid;
691*219b2ee8SDavid du Colombier 		else
692*219b2ee8SDavid du Colombier 			return mid;
693*219b2ee8SDavid du Colombier 	}
694*219b2ee8SDavid du Colombier 	return -1;
695*219b2ee8SDavid du Colombier }
696*219b2ee8SDavid du Colombier /*
697*219b2ee8SDavid du Colombier  * Find symbol containing val in specified search space
698*219b2ee8SDavid du Colombier  * There is a special case when a value falls beyond the end
699*219b2ee8SDavid du Colombier  * of the text segment; if the search space is CTEXT, that value
700*219b2ee8SDavid du Colombier  * (usually etext) is returned.  If the search space is CANY, symbols in the
701*219b2ee8SDavid du Colombier  * data space are searched for a match.
702*219b2ee8SDavid du Colombier  */
703*219b2ee8SDavid du Colombier int
704*219b2ee8SDavid du Colombier findsym(long w, int type, Symbol *s)
705*219b2ee8SDavid du Colombier {
706*219b2ee8SDavid du Colombier 	int i;
707*219b2ee8SDavid du Colombier 
708*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
709*219b2ee8SDavid du Colombier 		return 0;
710*219b2ee8SDavid du Colombier 
711*219b2ee8SDavid du Colombier 	if(type == CTEXT || type == CANY) {
712*219b2ee8SDavid du Colombier 		i = srchtext(w);
713*219b2ee8SDavid du Colombier 		if(i >= 0) {
714*219b2ee8SDavid du Colombier 			if(type == CTEXT || i != ntxt-1) {
715*219b2ee8SDavid du Colombier 				fillsym(txt[i].sym, s);
716*219b2ee8SDavid du Colombier 				s->handle = (void *) &txt[i];
717*219b2ee8SDavid du Colombier 				return 1;
718*219b2ee8SDavid du Colombier 			}
719*219b2ee8SDavid du Colombier 		}
720*219b2ee8SDavid du Colombier 	}
721*219b2ee8SDavid du Colombier 	if(type == CDATA || type == CANY) {
722*219b2ee8SDavid du Colombier 		i = srchdata(w);
723*219b2ee8SDavid du Colombier 		if(i >= 0) {
724*219b2ee8SDavid du Colombier 			fillsym(globals[i], s);
725*219b2ee8SDavid du Colombier 			return 1;
726*219b2ee8SDavid du Colombier 		}
727*219b2ee8SDavid du Colombier 	}
728*219b2ee8SDavid du Colombier 	return 0;
729*219b2ee8SDavid du Colombier }
730*219b2ee8SDavid du Colombier 
731*219b2ee8SDavid du Colombier /*
732*219b2ee8SDavid du Colombier  *	Find the start and end address of the function containing addr
733*219b2ee8SDavid du Colombier  */
734*219b2ee8SDavid du Colombier int
735*219b2ee8SDavid du Colombier fnbound(long addr, ulong *bounds)
736*219b2ee8SDavid du Colombier {
737*219b2ee8SDavid du Colombier 	int i;
738*219b2ee8SDavid du Colombier 
739*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
740*219b2ee8SDavid du Colombier 		return 0;
741*219b2ee8SDavid du Colombier 
742*219b2ee8SDavid du Colombier 	i = srchtext(addr);
743*219b2ee8SDavid du Colombier 	if(0 <= i && i < ntxt-1) {
744*219b2ee8SDavid du Colombier 		bounds[0] = txt[i].sym->value;
745*219b2ee8SDavid du Colombier 		bounds[1] = txt[i+1].sym->value;
746*219b2ee8SDavid du Colombier 		return 1;
747*219b2ee8SDavid du Colombier 	}
748*219b2ee8SDavid du Colombier 	return 0;
749*219b2ee8SDavid du Colombier }
750*219b2ee8SDavid du Colombier 
751*219b2ee8SDavid du Colombier /*
752*219b2ee8SDavid du Colombier  * get the ith local symbol for a function
753*219b2ee8SDavid du Colombier  * the input symbol table is reverse ordered, so we reverse
754*219b2ee8SDavid du Colombier  * accesses here to maintain approx. parameter ordering in a stack trace.
755*219b2ee8SDavid du Colombier  */
756*219b2ee8SDavid du Colombier int
757*219b2ee8SDavid du Colombier localsym(Symbol *s, int index)
758*219b2ee8SDavid du Colombier {
759*219b2ee8SDavid du Colombier 	Txtsym *tp;
760*219b2ee8SDavid du Colombier 
761*219b2ee8SDavid du Colombier 	if(s == 0)
762*219b2ee8SDavid du Colombier 		return 0;
763*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
764*219b2ee8SDavid du Colombier 		return 0;
765*219b2ee8SDavid du Colombier 
766*219b2ee8SDavid du Colombier 	tp = (Txtsym *)s->handle;
767*219b2ee8SDavid du Colombier 	if(tp && tp->locals && index < tp->n) {
768*219b2ee8SDavid du Colombier 		fillsym(tp->locals[tp->n-index-1], s);	/* reverse */
769*219b2ee8SDavid du Colombier 		s->handle = (void *)tp;
770*219b2ee8SDavid du Colombier 		return 1;
771*219b2ee8SDavid du Colombier 	}
772*219b2ee8SDavid du Colombier 	return 0;
773*219b2ee8SDavid du Colombier }
774*219b2ee8SDavid du Colombier /*
775*219b2ee8SDavid du Colombier  * get the ith global symbol
776*219b2ee8SDavid du Colombier  */
777*219b2ee8SDavid du Colombier int
778*219b2ee8SDavid du Colombier globalsym(Symbol *s, int index)
779*219b2ee8SDavid du Colombier {
780*219b2ee8SDavid du Colombier 	if(s == 0)
781*219b2ee8SDavid du Colombier 		return 0;
782*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
783*219b2ee8SDavid du Colombier 		return 0;
784*219b2ee8SDavid du Colombier 
785*219b2ee8SDavid du Colombier 	if(index < nglob) {
786*219b2ee8SDavid du Colombier 		fillsym(globals[index], s);
787*219b2ee8SDavid du Colombier 		return 1;
788*219b2ee8SDavid du Colombier 	}
789*219b2ee8SDavid du Colombier 	return 0;
790*219b2ee8SDavid du Colombier }
791*219b2ee8SDavid du Colombier /*
792*219b2ee8SDavid du Colombier  *	find the pc given a file name and line offset into it.
793*219b2ee8SDavid du Colombier  */
794*219b2ee8SDavid du Colombier long
795*219b2ee8SDavid du Colombier file2pc(char *file, ulong line)
796*219b2ee8SDavid du Colombier {
797*219b2ee8SDavid du Colombier 	File *fp;
798*219b2ee8SDavid du Colombier 	int i;
799*219b2ee8SDavid du Colombier 	long pc;
800*219b2ee8SDavid du Colombier 	ulong start, end;
801*219b2ee8SDavid du Colombier 	short *name;
802*219b2ee8SDavid du Colombier 
803*219b2ee8SDavid du Colombier 	if(buildtbls() == 0 || files == 0)
804*219b2ee8SDavid du Colombier 		return -1;
805*219b2ee8SDavid du Colombier 	name = encfname(file);
806*219b2ee8SDavid du Colombier 	if(name == 0) {			/* encode the file name */
807*219b2ee8SDavid du Colombier 		werrstr("file %s not found", file);
808*219b2ee8SDavid du Colombier 		return -1;
809*219b2ee8SDavid du Colombier 	}
810*219b2ee8SDavid du Colombier 		/* find this history stack */
811*219b2ee8SDavid du Colombier 	for(i = 0, fp = files; i < nfiles; i++, fp++)
812*219b2ee8SDavid du Colombier 		if (hline(fp, name, &line))
813*219b2ee8SDavid du Colombier 			break;
814*219b2ee8SDavid du Colombier 	free(name);
815*219b2ee8SDavid du Colombier 	if(i >= nfiles) {
816*219b2ee8SDavid du Colombier 		werrstr("line %d in file %s not found", line, file);
817*219b2ee8SDavid du Colombier 		return -1;
818*219b2ee8SDavid du Colombier 	}
819*219b2ee8SDavid du Colombier 	start = fp->addr;		/* first text addr this file */
820*219b2ee8SDavid du Colombier 	if(i < nfiles-1)
821*219b2ee8SDavid du Colombier 		end = (fp+1)->addr;	/* first text addr next file */
822*219b2ee8SDavid du Colombier 	else
823*219b2ee8SDavid du Colombier 		end = 0;		/* last file in load module */
824*219b2ee8SDavid du Colombier 	/*
825*219b2ee8SDavid du Colombier 	 * At this point, line contains the offset into the file.
826*219b2ee8SDavid du Colombier 	 * run the state machine to locate the pc closest to that value.
827*219b2ee8SDavid du Colombier 	 */
828*219b2ee8SDavid du Colombier 	if(debug)
829*219b2ee8SDavid du Colombier 		print("find pc for %d - between: %lux and %lux\n", line, start, end);
830*219b2ee8SDavid du Colombier 	pc = line2addr(line, start, end);
831*219b2ee8SDavid du Colombier 	if(pc == -1) {
832*219b2ee8SDavid du Colombier 		werrstr("line %d not in file %s", line, file);
833*219b2ee8SDavid du Colombier 		return -1;
834*219b2ee8SDavid du Colombier 	}
835*219b2ee8SDavid du Colombier 	return pc;
836*219b2ee8SDavid du Colombier }
837*219b2ee8SDavid du Colombier /*
838*219b2ee8SDavid du Colombier  *	search for a path component index
839*219b2ee8SDavid du Colombier  */
840*219b2ee8SDavid du Colombier static int
841*219b2ee8SDavid du Colombier pathcomp(char *s, int n)
842*219b2ee8SDavid du Colombier {
843*219b2ee8SDavid du Colombier 	int i;
844*219b2ee8SDavid du Colombier 
845*219b2ee8SDavid du Colombier 	for(i = 0; i <= fmax; i++)
846*219b2ee8SDavid du Colombier 		if(fnames[i] && strncmp(s, fnames[i]->name, n) == 0)
847*219b2ee8SDavid du Colombier 			return i;
848*219b2ee8SDavid du Colombier 	return -1;
849*219b2ee8SDavid du Colombier }
850*219b2ee8SDavid du Colombier /*
851*219b2ee8SDavid du Colombier  *	Encode a char file name as a sequence of short indices
852*219b2ee8SDavid du Colombier  *	into the file name dictionary.
853*219b2ee8SDavid du Colombier  */
854*219b2ee8SDavid du Colombier static short*
855*219b2ee8SDavid du Colombier encfname(char *file)
856*219b2ee8SDavid du Colombier {
857*219b2ee8SDavid du Colombier 	int i, j;
858*219b2ee8SDavid du Colombier 	char *cp, *cp2;
859*219b2ee8SDavid du Colombier 	short *dest;
860*219b2ee8SDavid du Colombier 
861*219b2ee8SDavid du Colombier 	if(*file == '/')	/* always check first '/' */
862*219b2ee8SDavid du Colombier 		cp2 = file+1;
863*219b2ee8SDavid du Colombier 	else {
864*219b2ee8SDavid du Colombier 		cp2 = strchr(file, '/');
865*219b2ee8SDavid du Colombier 		if(!cp2)
866*219b2ee8SDavid du Colombier 			cp2 = strchr(file, 0);
867*219b2ee8SDavid du Colombier 	}
868*219b2ee8SDavid du Colombier 	cp = file;
869*219b2ee8SDavid du Colombier 	dest = 0;
870*219b2ee8SDavid du Colombier 	for(i = 0; *cp; i++) {
871*219b2ee8SDavid du Colombier 		j = pathcomp(cp, cp2-cp);
872*219b2ee8SDavid du Colombier 		if(j < 0)
873*219b2ee8SDavid du Colombier 			return 0;	/* not found */
874*219b2ee8SDavid du Colombier 		dest = realloc(dest, (i+1)*sizeof(short));
875*219b2ee8SDavid du Colombier 		dest[i] = j;
876*219b2ee8SDavid du Colombier 		cp = cp2;
877*219b2ee8SDavid du Colombier 		while(*cp == '/')	/* skip embedded '/'s */
878*219b2ee8SDavid du Colombier 			cp++;
879*219b2ee8SDavid du Colombier 		cp2 = strchr(cp, '/');
880*219b2ee8SDavid du Colombier 		if(!cp2)
881*219b2ee8SDavid du Colombier 			cp2 = strchr(cp, 0);
882*219b2ee8SDavid du Colombier 	}
883*219b2ee8SDavid du Colombier 	dest = realloc(dest, (i+1)*sizeof(short));
884*219b2ee8SDavid du Colombier 	dest[i] = 0;
885*219b2ee8SDavid du Colombier 	return dest;
886*219b2ee8SDavid du Colombier }
887*219b2ee8SDavid du Colombier /*
888*219b2ee8SDavid du Colombier  *	Search a history stack for a matching file name accumulating
889*219b2ee8SDavid du Colombier  *	the size of intervening files in the stack.
890*219b2ee8SDavid du Colombier  */
891*219b2ee8SDavid du Colombier static int
892*219b2ee8SDavid du Colombier hline(File *fp, short *name, ulong *line)
893*219b2ee8SDavid du Colombier {
894*219b2ee8SDavid du Colombier 	Hist *hp;
895*219b2ee8SDavid du Colombier 	int offset, depth;
896*219b2ee8SDavid du Colombier 	long ln;
897*219b2ee8SDavid du Colombier 
898*219b2ee8SDavid du Colombier 	for(hp = fp->hist; hp->name; hp++)		/* find name in stack */
899*219b2ee8SDavid du Colombier 		if(hp->name[1] || hp->name[2]) {
900*219b2ee8SDavid du Colombier 			if(hcomp(hp, name))
901*219b2ee8SDavid du Colombier 				break;
902*219b2ee8SDavid du Colombier 		}
903*219b2ee8SDavid du Colombier 	if(!hp->name)		/* match not found */
904*219b2ee8SDavid du Colombier 		return 0;
905*219b2ee8SDavid du Colombier 	if(debug)
906*219b2ee8SDavid du Colombier 		printhist("hline found ... ", hp, 1);
907*219b2ee8SDavid du Colombier 	/*
908*219b2ee8SDavid du Colombier 	 * unwind the stack until empty or we hit an entry beyond our line
909*219b2ee8SDavid du Colombier 	 */
910*219b2ee8SDavid du Colombier 	ln = *line;
911*219b2ee8SDavid du Colombier 	offset = hp->line-1;
912*219b2ee8SDavid du Colombier 	depth = 1;
913*219b2ee8SDavid du Colombier 	for(hp++; depth && hp->name; hp++) {
914*219b2ee8SDavid du Colombier 		if(debug)
915*219b2ee8SDavid du Colombier 			printhist("hline inspect ... ", hp, 1);
916*219b2ee8SDavid du Colombier 		if(hp->name[1] || hp->name[2]) {
917*219b2ee8SDavid du Colombier 			if(hp->offset){			/* Z record */
918*219b2ee8SDavid du Colombier 				offset = 0;
919*219b2ee8SDavid du Colombier 				if(hcomp(hp, name)) {
920*219b2ee8SDavid du Colombier 					if(*line <= hp->offset)
921*219b2ee8SDavid du Colombier 						break;
922*219b2ee8SDavid du Colombier 					ln = *line+hp->line-hp->offset;
923*219b2ee8SDavid du Colombier 					depth = 1;	/* implicit pop */
924*219b2ee8SDavid du Colombier 				} else
925*219b2ee8SDavid du Colombier 					depth = 2;	/* implicit push */
926*219b2ee8SDavid du Colombier 			} else if(depth == 1 && ln < hp->line-offset)
927*219b2ee8SDavid du Colombier 					break;		/* Beyond our line */
928*219b2ee8SDavid du Colombier 			else if(depth++ == 1)		/* push	*/
929*219b2ee8SDavid du Colombier 				offset -= hp->line;
930*219b2ee8SDavid du Colombier 		} else if(--depth == 1)		/* pop */
931*219b2ee8SDavid du Colombier 			offset += hp->line;
932*219b2ee8SDavid du Colombier 	}
933*219b2ee8SDavid du Colombier 	*line = ln+offset;
934*219b2ee8SDavid du Colombier 	return 1;
935*219b2ee8SDavid du Colombier }
936*219b2ee8SDavid du Colombier /*
937*219b2ee8SDavid du Colombier  *	compare two encoded file names
938*219b2ee8SDavid du Colombier  */
939*219b2ee8SDavid du Colombier static int
940*219b2ee8SDavid du Colombier hcomp(Hist *hp, short *sp)
941*219b2ee8SDavid du Colombier {
942*219b2ee8SDavid du Colombier 	uchar *cp;
943*219b2ee8SDavid du Colombier 	int i, j;
944*219b2ee8SDavid du Colombier 	short *s;
945*219b2ee8SDavid du Colombier 
946*219b2ee8SDavid du Colombier 	cp = (uchar *)hp->name;
947*219b2ee8SDavid du Colombier 	s = sp;
948*219b2ee8SDavid du Colombier 	if (*s == 0)
949*219b2ee8SDavid du Colombier 		return 0;
950*219b2ee8SDavid du Colombier 	for (i = 1; j = (cp[i]<<8)|cp[i+1]; i += 2) {
951*219b2ee8SDavid du Colombier 		if(j == 0)
952*219b2ee8SDavid du Colombier 			break;
953*219b2ee8SDavid du Colombier 		if(*s == j)
954*219b2ee8SDavid du Colombier 			s++;
955*219b2ee8SDavid du Colombier 		else
956*219b2ee8SDavid du Colombier 			s = sp;
957*219b2ee8SDavid du Colombier 	}
958*219b2ee8SDavid du Colombier 	return *s == 0;
959*219b2ee8SDavid du Colombier }
960*219b2ee8SDavid du Colombier /*
961*219b2ee8SDavid du Colombier  *	Convert a pc to a "file:line {file:line}" string.
962*219b2ee8SDavid du Colombier  */
963*219b2ee8SDavid du Colombier int
964*219b2ee8SDavid du Colombier fileline(char *str, int n, ulong dot)
965*219b2ee8SDavid du Colombier {
966*219b2ee8SDavid du Colombier 	long line;
967*219b2ee8SDavid du Colombier 	int top, bot, mid;
968*219b2ee8SDavid du Colombier 	File *f;
969*219b2ee8SDavid du Colombier 
970*219b2ee8SDavid du Colombier 	*str = 0;
971*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
972*219b2ee8SDavid du Colombier 		return 0;
973*219b2ee8SDavid du Colombier 
974*219b2ee8SDavid du Colombier 		/* binary search assumes file list is sorted by addr */
975*219b2ee8SDavid du Colombier 	bot = 0;
976*219b2ee8SDavid du Colombier 	top = nfiles;
977*219b2ee8SDavid du Colombier 	for (mid = (bot+top)/2; mid < top; mid = (bot+top)/2) {
978*219b2ee8SDavid du Colombier 		f = &files[mid];
979*219b2ee8SDavid du Colombier 		if(dot < f->addr)
980*219b2ee8SDavid du Colombier 			top = mid;
981*219b2ee8SDavid du Colombier 		else if(mid < nfiles-1 && dot >= (f+1)->addr)
982*219b2ee8SDavid du Colombier 			bot = mid;
983*219b2ee8SDavid du Colombier 		else {
984*219b2ee8SDavid du Colombier 			line = pc2line(dot);
985*219b2ee8SDavid du Colombier 			if(line > 0 && fline(str, n, line, f->hist))
986*219b2ee8SDavid du Colombier 				return 1;
987*219b2ee8SDavid du Colombier 			break;
988*219b2ee8SDavid du Colombier 		}
989*219b2ee8SDavid du Colombier 	}
990*219b2ee8SDavid du Colombier 	return 0;
991*219b2ee8SDavid du Colombier }
992*219b2ee8SDavid du Colombier 
993*219b2ee8SDavid du Colombier /*
994*219b2ee8SDavid du Colombier  *	Convert a line number within a composite file to relative line
995*219b2ee8SDavid du Colombier  *	number in a source file.  A composite file is the source
996*219b2ee8SDavid du Colombier  *	file with included files inserted in line.
997*219b2ee8SDavid du Colombier  */
998*219b2ee8SDavid du Colombier static Hist *
999*219b2ee8SDavid du Colombier fline(char *str, int n, long line, Hist *base)
1000*219b2ee8SDavid du Colombier {
1001*219b2ee8SDavid du Colombier 	Hist *start;			/* start of current level */
1002*219b2ee8SDavid du Colombier 	Hist *h;			/* current entry */
1003*219b2ee8SDavid du Colombier 	int delta;			/* sum of size of files this level */
1004*219b2ee8SDavid du Colombier 	int k;
1005*219b2ee8SDavid du Colombier 
1006*219b2ee8SDavid du Colombier 	start = base;
1007*219b2ee8SDavid du Colombier 	h = base;
1008*219b2ee8SDavid du Colombier 	delta = h->line;
1009*219b2ee8SDavid du Colombier 	while(h && h->name && line > h->line) {
1010*219b2ee8SDavid du Colombier 		if(h->name[1] || h->name[2]) {
1011*219b2ee8SDavid du Colombier 			if(h->offset != 0) {	/* #line Directive */
1012*219b2ee8SDavid du Colombier 				delta = h->line-h->offset+1;
1013*219b2ee8SDavid du Colombier 				start = h;
1014*219b2ee8SDavid du Colombier 				base = h++;
1015*219b2ee8SDavid du Colombier 			} else {		/* beginning of File */
1016*219b2ee8SDavid du Colombier 				if(start == base)
1017*219b2ee8SDavid du Colombier 					start = h++;
1018*219b2ee8SDavid du Colombier 				else {
1019*219b2ee8SDavid du Colombier 					h = fline(str, n, line, start);
1020*219b2ee8SDavid du Colombier 					if(!h)
1021*219b2ee8SDavid du Colombier 						break;
1022*219b2ee8SDavid du Colombier 				}
1023*219b2ee8SDavid du Colombier 			}
1024*219b2ee8SDavid du Colombier 		} else {
1025*219b2ee8SDavid du Colombier 			if(start == base)	/* end of recursion level */
1026*219b2ee8SDavid du Colombier 				return h;
1027*219b2ee8SDavid du Colombier 			else {			/* end of included file */
1028*219b2ee8SDavid du Colombier 				delta += h->line-start->line;
1029*219b2ee8SDavid du Colombier 				h++;
1030*219b2ee8SDavid du Colombier 				start = base;
1031*219b2ee8SDavid du Colombier 			}
1032*219b2ee8SDavid du Colombier 		}
1033*219b2ee8SDavid du Colombier 	}
1034*219b2ee8SDavid du Colombier 	if(!h)
1035*219b2ee8SDavid du Colombier 		return 0;
1036*219b2ee8SDavid du Colombier 	if(start != base)
1037*219b2ee8SDavid du Colombier 		line = line-start->line+1;
1038*219b2ee8SDavid du Colombier 	else
1039*219b2ee8SDavid du Colombier 		line = line-delta+1;
1040*219b2ee8SDavid du Colombier 	if(!h->name)
1041*219b2ee8SDavid du Colombier 		strncpy(str, "<eof>", n);
1042*219b2ee8SDavid du Colombier 	else {
1043*219b2ee8SDavid du Colombier 		k = fileelem(fnames, (uchar*)start->name, str, n);
1044*219b2ee8SDavid du Colombier 		if(k+8 < n)
1045*219b2ee8SDavid du Colombier 			sprint(str+k, ":%ld", line);
1046*219b2ee8SDavid du Colombier 	}
1047*219b2ee8SDavid du Colombier /**********Remove comments for complete back-trace of include sequence
1048*219b2ee8SDavid du Colombier  *	if(start != base) {
1049*219b2ee8SDavid du Colombier  *		k = strlen(str);
1050*219b2ee8SDavid du Colombier  *		if(k+2 < n) {
1051*219b2ee8SDavid du Colombier  *			str[k++] = ' ';
1052*219b2ee8SDavid du Colombier  *			str[k++] = '{';
1053*219b2ee8SDavid du Colombier  *		}
1054*219b2ee8SDavid du Colombier  *		k += fileelem(fnames, (uchar*) base->name, str+k, n-k);
1055*219b2ee8SDavid du Colombier  *		if(k+10 < n)
1056*219b2ee8SDavid du Colombier  *			sprint(str+k, ":%ld}", start->line-delta);
1057*219b2ee8SDavid du Colombier  *	}
1058*219b2ee8SDavid du Colombier  ********************/
1059*219b2ee8SDavid du Colombier 	return h;
1060*219b2ee8SDavid du Colombier }
1061*219b2ee8SDavid du Colombier /*
1062*219b2ee8SDavid du Colombier  *	convert an encoded file name to a string.
1063*219b2ee8SDavid du Colombier  */
1064*219b2ee8SDavid du Colombier int
1065*219b2ee8SDavid du Colombier fileelem(Sym **fp, uchar *cp, char *buf, int n)
1066*219b2ee8SDavid du Colombier {
1067*219b2ee8SDavid du Colombier 	int i, j;
1068*219b2ee8SDavid du Colombier 	char *c, *bp, *end;
1069*219b2ee8SDavid du Colombier 
1070*219b2ee8SDavid du Colombier 	bp = buf;
1071*219b2ee8SDavid du Colombier 	end = buf+n-1;
1072*219b2ee8SDavid du Colombier 	for(i = 1; j = (cp[i]<<8)|cp[i+1]; i+=2){
1073*219b2ee8SDavid du Colombier 		c = fp[j]->name;
1074*219b2ee8SDavid du Colombier 		if(bp != buf && bp[-1] != '/' && bp < end)
1075*219b2ee8SDavid du Colombier 			*bp++ = '/';
1076*219b2ee8SDavid du Colombier 		while(bp < end && *c)
1077*219b2ee8SDavid du Colombier 			*bp++ = *c++;
1078*219b2ee8SDavid du Colombier 	}
1079*219b2ee8SDavid du Colombier 	*bp = 0;
1080*219b2ee8SDavid du Colombier 	return bp-buf;
1081*219b2ee8SDavid du Colombier }
1082*219b2ee8SDavid du Colombier /*
1083*219b2ee8SDavid du Colombier  *	compare the values of two symbol table entries.
1084*219b2ee8SDavid du Colombier  */
1085*219b2ee8SDavid du Colombier static int
1086*219b2ee8SDavid du Colombier symcomp(void *a, void *b)
1087*219b2ee8SDavid du Colombier {
1088*219b2ee8SDavid du Colombier 	return (*(Sym**)a)->value - (*(Sym**)b)->value;
1089*219b2ee8SDavid du Colombier }
1090*219b2ee8SDavid du Colombier /*
1091*219b2ee8SDavid du Colombier  *	compare the values of the symbols referenced by two text table entries
1092*219b2ee8SDavid du Colombier  */
1093*219b2ee8SDavid du Colombier static int
1094*219b2ee8SDavid du Colombier txtcomp(void *a, void *b)
1095*219b2ee8SDavid du Colombier {
1096*219b2ee8SDavid du Colombier 	return ((Txtsym*)a)->sym->value - ((Txtsym*)b)->sym->value;
1097*219b2ee8SDavid du Colombier }
1098*219b2ee8SDavid du Colombier /*
1099*219b2ee8SDavid du Colombier  *	compare the values of the symbols referenced by two file table entries
1100*219b2ee8SDavid du Colombier  */
1101*219b2ee8SDavid du Colombier static int
1102*219b2ee8SDavid du Colombier filecomp(void *a, void *b)
1103*219b2ee8SDavid du Colombier {
1104*219b2ee8SDavid du Colombier 	return ((File*)a)->addr - ((File*)b)->addr;
1105*219b2ee8SDavid du Colombier }
1106*219b2ee8SDavid du Colombier /*
1107*219b2ee8SDavid du Colombier  *	fill an interface Symbol structure from a symbol table entry
1108*219b2ee8SDavid du Colombier  */
1109*219b2ee8SDavid du Colombier static void
1110*219b2ee8SDavid du Colombier fillsym(Sym *sp, Symbol *s)
1111*219b2ee8SDavid du Colombier {
1112*219b2ee8SDavid du Colombier 	s->type = sp->type;
1113*219b2ee8SDavid du Colombier 	s->value = sp->value;
1114*219b2ee8SDavid du Colombier 	s->name = sp->name;
1115*219b2ee8SDavid du Colombier 	switch(sp->type) {
1116*219b2ee8SDavid du Colombier 	case 'b':
1117*219b2ee8SDavid du Colombier 	case 'B':
1118*219b2ee8SDavid du Colombier 	case 'D':
1119*219b2ee8SDavid du Colombier 	case 'd':
1120*219b2ee8SDavid du Colombier 		s->class = CDATA;
1121*219b2ee8SDavid du Colombier 		break;
1122*219b2ee8SDavid du Colombier 	case 't':
1123*219b2ee8SDavid du Colombier 	case 'T':
1124*219b2ee8SDavid du Colombier 	case 'l':
1125*219b2ee8SDavid du Colombier 	case 'L':
1126*219b2ee8SDavid du Colombier 		s->class = CTEXT;
1127*219b2ee8SDavid du Colombier 		break;
1128*219b2ee8SDavid du Colombier 	case 'a':
1129*219b2ee8SDavid du Colombier 		s->class = CAUTO;
1130*219b2ee8SDavid du Colombier 		break;
1131*219b2ee8SDavid du Colombier 	case 'p':
1132*219b2ee8SDavid du Colombier 		s->class = CPARAM;
1133*219b2ee8SDavid du Colombier 		break;
1134*219b2ee8SDavid du Colombier 	case 'm':
1135*219b2ee8SDavid du Colombier 		s->class = CSTAB;
1136*219b2ee8SDavid du Colombier 		break;
1137*219b2ee8SDavid du Colombier 	default:
1138*219b2ee8SDavid du Colombier 		s->class = CNONE;
1139*219b2ee8SDavid du Colombier 		break;
1140*219b2ee8SDavid du Colombier 	}
1141*219b2ee8SDavid du Colombier 	s->handle = 0;
1142*219b2ee8SDavid du Colombier }
11433e12c5d1SDavid du Colombier /*
11443e12c5d1SDavid du Colombier  *	find the stack frame, given the pc
11453e12c5d1SDavid du Colombier  */
11463e12c5d1SDavid du Colombier long
11473e12c5d1SDavid du Colombier pc2sp(ulong pc)
11483e12c5d1SDavid du Colombier {
11493e12c5d1SDavid du Colombier 	uchar *c;
11503e12c5d1SDavid du Colombier 	uchar u;
11513e12c5d1SDavid du Colombier 	ulong currpc;
11523e12c5d1SDavid du Colombier 	long currsp;
11533e12c5d1SDavid du Colombier 
11543e12c5d1SDavid du Colombier 	if(spoff == 0)
11553e12c5d1SDavid du Colombier 		return -1;
11563e12c5d1SDavid du Colombier 	currsp = 0;
11573e12c5d1SDavid du Colombier 	currpc = txtstart - mach->pcquant;
11583e12c5d1SDavid du Colombier 
11593e12c5d1SDavid du Colombier 	if(pc<currpc || pc>txtend)
11603e12c5d1SDavid du Colombier 		return -1;
11613e12c5d1SDavid du Colombier 	for(c = spoff; c < spoffend; c++) {
11623e12c5d1SDavid du Colombier 		if (currpc >= pc)
11633e12c5d1SDavid du Colombier 			return currsp;
11643e12c5d1SDavid du Colombier 		u = *c;
11653e12c5d1SDavid du Colombier 		if (u == 0) {
11663e12c5d1SDavid du Colombier 			currsp += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
11673e12c5d1SDavid du Colombier 			c += 4;
1168*219b2ee8SDavid du Colombier 		}
1169*219b2ee8SDavid du Colombier 		else if (u < 65)
11703e12c5d1SDavid du Colombier 			currsp += 4*u;
11713e12c5d1SDavid du Colombier 		else if (u < 129)
11723e12c5d1SDavid du Colombier 			currsp -= 4*(u-64);
11733e12c5d1SDavid du Colombier 		else
11743e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
11753e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
11763e12c5d1SDavid du Colombier 	}
11773e12c5d1SDavid du Colombier 	return -1;
11783e12c5d1SDavid du Colombier }
11793e12c5d1SDavid du Colombier /*
11803e12c5d1SDavid du Colombier  *	find the source file line number for a given value of the pc
11813e12c5d1SDavid du Colombier  */
11823e12c5d1SDavid du Colombier long
11833e12c5d1SDavid du Colombier pc2line(ulong pc)
11843e12c5d1SDavid du Colombier {
11853e12c5d1SDavid du Colombier 	uchar *c;
11863e12c5d1SDavid du Colombier 	uchar u;
11873e12c5d1SDavid du Colombier 	ulong currpc;
11883e12c5d1SDavid du Colombier 	long currline;
11893e12c5d1SDavid du Colombier 
11903e12c5d1SDavid du Colombier 	if(pcline == 0)
11913e12c5d1SDavid du Colombier 		return -1;
11923e12c5d1SDavid du Colombier 	currline = 0;
11933e12c5d1SDavid du Colombier 	currpc = txtstart-mach->pcquant;
11943e12c5d1SDavid du Colombier 	if(pc<currpc || pc>txtend)
11953e12c5d1SDavid du Colombier 		return -1;
1196*219b2ee8SDavid du Colombier 
11973e12c5d1SDavid du Colombier 	for(c = pcline; c < pclineend; c++) {
11983e12c5d1SDavid du Colombier 		if(currpc >= pc)
11993e12c5d1SDavid du Colombier 			return currline;
12003e12c5d1SDavid du Colombier 		u = *c;
12013e12c5d1SDavid du Colombier 		if(u == 0) {
12023e12c5d1SDavid du Colombier 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
12033e12c5d1SDavid du Colombier 			c += 4;
1204*219b2ee8SDavid du Colombier 		}
1205*219b2ee8SDavid du Colombier 		else if(u < 65)
12063e12c5d1SDavid du Colombier 			currline += u;
12073e12c5d1SDavid du Colombier 		else if(u < 129)
12083e12c5d1SDavid du Colombier 			currline -= (u-64);
12093e12c5d1SDavid du Colombier 		else
12103e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
12113e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
12123e12c5d1SDavid du Colombier 	}
12133e12c5d1SDavid du Colombier 	return -1;
12143e12c5d1SDavid du Colombier }
12153e12c5d1SDavid du Colombier /*
1216bd389b36SDavid du Colombier  *	find the pc associated with a line number
1217bd389b36SDavid du Colombier  *	basepc and endpc are text addresses bounding the search.
1218bd389b36SDavid du Colombier  *	if endpc == 0, the end of the table is used (i.e., no upper bound).
1219bd389b36SDavid du Colombier  *	usually, basepc and endpc contain the first text address in
1220bd389b36SDavid du Colombier  *	a file and the first text address in the following file, respectively.
12213e12c5d1SDavid du Colombier  */
12223e12c5d1SDavid du Colombier long
1223bd389b36SDavid du Colombier line2addr(ulong line, ulong basepc, ulong endpc)
12243e12c5d1SDavid du Colombier {
12253e12c5d1SDavid du Colombier 	uchar *c;
12263e12c5d1SDavid du Colombier 	uchar u;
1227bd389b36SDavid du Colombier 	ulong currpc;
1228bd389b36SDavid du Colombier 	long currline;
1229bd389b36SDavid du Colombier 	long delta, d;
1230bd389b36SDavid du Colombier 	long pc, found;
12313e12c5d1SDavid du Colombier 
12323e12c5d1SDavid du Colombier 	if(pcline == 0 || line == 0)
12333e12c5d1SDavid du Colombier 		return -1;
1234*219b2ee8SDavid du Colombier 
1235bd389b36SDavid du Colombier 	currline = 0;
1236bd389b36SDavid du Colombier 	currpc = txtstart-mach->pcquant;
1237bd389b36SDavid du Colombier 	pc = -1;
1238bd389b36SDavid du Colombier 	found = 0;
1239bd389b36SDavid du Colombier 	delta = HUGEINT;
12403e12c5d1SDavid du Colombier 
12413e12c5d1SDavid du Colombier 	for(c = pcline; c < pclineend; c++) {
1242bd389b36SDavid du Colombier 		if(endpc && currpc >= endpc)	/* end of file of interest */
1243bd389b36SDavid du Colombier 			break;
1244bd389b36SDavid du Colombier 		if(currpc >= basepc) {		/* proper file */
1245bd389b36SDavid du Colombier 			if(currline >= line) {
1246bd389b36SDavid du Colombier 				d = currline-line;
1247bd389b36SDavid du Colombier 				found = 1;
1248bd389b36SDavid du Colombier 			} else
1249bd389b36SDavid du Colombier 				d = line-currline;
1250bd389b36SDavid du Colombier 			if(d < delta) {
1251bd389b36SDavid du Colombier 				delta = d;
1252bd389b36SDavid du Colombier 				pc = currpc;
12533e12c5d1SDavid du Colombier 			}
1254bd389b36SDavid du Colombier 		}
12553e12c5d1SDavid du Colombier 		u = *c;
12563e12c5d1SDavid du Colombier 		if(u == 0) {
12573e12c5d1SDavid du Colombier 			currline += (c[1]<<24)|(c[2]<<16)|(c[3]<<8)|c[4];
12583e12c5d1SDavid du Colombier 			c += 4;
1259*219b2ee8SDavid du Colombier 		}
1260*219b2ee8SDavid du Colombier 		else if(u < 65)
12613e12c5d1SDavid du Colombier 			currline += u;
12623e12c5d1SDavid du Colombier 		else if(u < 129)
12633e12c5d1SDavid du Colombier 			currline -= (u-64);
12643e12c5d1SDavid du Colombier 		else
12653e12c5d1SDavid du Colombier 			currpc += mach->pcquant*(u-129);
12663e12c5d1SDavid du Colombier 		currpc += mach->pcquant;
12673e12c5d1SDavid du Colombier 	}
1268bd389b36SDavid du Colombier 	if(found)
1269bd389b36SDavid du Colombier 		return pc;
12703e12c5d1SDavid du Colombier 	return -1;
12713e12c5d1SDavid du Colombier }
12723e12c5d1SDavid du Colombier /*
1273*219b2ee8SDavid du Colombier  *	Print a history stack (debug). if count is 0, prints the whole stack
12743e12c5d1SDavid du Colombier  */
1275*219b2ee8SDavid du Colombier void
1276*219b2ee8SDavid du Colombier printhist(char *msg, Hist *hp, int count)
12773e12c5d1SDavid du Colombier {
1278*219b2ee8SDavid du Colombier 	int i;
1279*219b2ee8SDavid du Colombier 	uchar *cp;
1280*219b2ee8SDavid du Colombier 	char buf[128];
12813e12c5d1SDavid du Colombier 
1282*219b2ee8SDavid du Colombier 	i = 0;
1283*219b2ee8SDavid du Colombier 	while(hp->name) {
1284*219b2ee8SDavid du Colombier 		if(count && ++i > count)
12853e12c5d1SDavid du Colombier 			break;
1286*219b2ee8SDavid du Colombier 		print("%s Line: %x (%d)  Offset: %x (%d)  Name: ", msg,
1287*219b2ee8SDavid du Colombier 			hp->line, hp->line, hp->offset, hp->offset);
1288*219b2ee8SDavid du Colombier 		for(cp = (uchar *)hp->name+1; (*cp<<8)|cp[1]; cp += 2) {
1289*219b2ee8SDavid du Colombier 			if (cp != (uchar *)hp->name+1)
1290*219b2ee8SDavid du Colombier 				print("/");
1291*219b2ee8SDavid du Colombier 			print("%x", (*cp<<8)|cp[1]);
12923e12c5d1SDavid du Colombier 		}
1293*219b2ee8SDavid du Colombier 		fileelem(fnames, (uchar *) hp->name, buf, sizeof(buf));
1294*219b2ee8SDavid du Colombier 		print(" (%s)\n", buf);
1295*219b2ee8SDavid du Colombier 		hp++;
12963e12c5d1SDavid du Colombier 	}
1297*219b2ee8SDavid du Colombier }
1298*219b2ee8SDavid du Colombier 
1299*219b2ee8SDavid du Colombier #ifdef DEBUG
1300*219b2ee8SDavid du Colombier /*
1301*219b2ee8SDavid du Colombier  *	print the history stack for a file. (debug only)
1302*219b2ee8SDavid du Colombier  *	if (name == 0) => print all history stacks.
1303*219b2ee8SDavid du Colombier  */
1304*219b2ee8SDavid du Colombier void
1305*219b2ee8SDavid du Colombier dumphist(char *name)
1306*219b2ee8SDavid du Colombier {
1307*219b2ee8SDavid du Colombier 	int i;
1308*219b2ee8SDavid du Colombier 	File *f;
1309*219b2ee8SDavid du Colombier 	short *fname;
1310*219b2ee8SDavid du Colombier 
1311*219b2ee8SDavid du Colombier 	if(buildtbls() == 0)
1312*219b2ee8SDavid du Colombier 		return;
1313*219b2ee8SDavid du Colombier 	if(name)
1314*219b2ee8SDavid du Colombier 		fname = encfname(name);
1315*219b2ee8SDavid du Colombier 	for(i = 0, f = files; i < nfiles; i++, f++)
1316*219b2ee8SDavid du Colombier 		if(fname == 0 || hcomp(f->hist, fname))
1317*219b2ee8SDavid du Colombier 			printhist("> ", f->hist, f->n);
1318*219b2ee8SDavid du Colombier 
1319*219b2ee8SDavid du Colombier 	if(fname)
1320*219b2ee8SDavid du Colombier 		free(fname);
1321*219b2ee8SDavid du Colombier }
1322*219b2ee8SDavid du Colombier #endif
1323