xref: /csrg-svn/old/sdb/symt.c (revision 1352)
1*1352Sbill static	char sccsid[] = "@(#)symt.c 4.1 10/09/80";
2*1352Sbill #include "head.h"
3*1352Sbill #include <a.out.h>
4*1352Sbill #include <stab.h>
5*1352Sbill 
6*1352Sbill #ifndef STABTYPES
7*1352Sbill #define	STABTYPES N_STAB
8*1352Sbill #endif
9*1352Sbill #include <sys/stat.h>
10*1352Sbill 
11*1352Sbill struct user u;
12*1352Sbill int compar();
13*1352Sbill char *symfil;
14*1352Sbill 
15*1352Sbill #ifdef FLEXNAMES
16*1352Sbill 
17*1352Sbill struct	nlist *symtab;
18*1352Sbill char	nullname[] = {0,0,0,0,0,0,0,0,0};	/* a few 0 bytes */
19*1352Sbill off_t	stoff;
20*1352Sbill 
21*1352Sbill stread(buff, nbytes)
22*1352Sbill struct nlist *buff;
23*1352Sbill int nbytes;
24*1352Sbill {
25*1352Sbill 	register int from = stoff;
26*1352Sbill 
27*1352Sbill 	stoff += nbytes;
28*1352Sbill 	if (stoff >= gstart)
29*1352Sbill 		return (-1);
30*1352Sbill 	if (nbytes < 0) {
31*1352Sbill 		from = stoff;
32*1352Sbill 		buff--;
33*1352Sbill 	}
34*1352Sbill 	from = (from - ststart);
35*1352Sbill 	*buff = symtab[from/sizeof (struct nlist)];
36*1352Sbill 	return (sizeof (struct nlist));
37*1352Sbill }
38*1352Sbill 
39*1352Sbill stseek(off, rel)
40*1352Sbill long off;
41*1352Sbill {
42*1352Sbill 
43*1352Sbill 	if (rel == 1)
44*1352Sbill 		stoff += off;
45*1352Sbill 	else
46*1352Sbill 		stoff = off;
47*1352Sbill }
48*1352Sbill #define	bread(a,b,c)	stread(b,c)
49*1352Sbill #define	blseek(a,b,c)	stseek(b,c)
50*1352Sbill #endif
51*1352Sbill 
52*1352Sbill /* initialize file and procedure tables */
53*1352Sbill initfp() {
54*1352Sbill 	struct nlist stentry;
55*1352Sbill 	register struct proct *procp;
56*1352Sbill 	register struct filet *filep;
57*1352Sbill 	struct stat stbuf;
58*1352Sbill 
59*1352Sbill 	long soffset;
60*1352Sbill 	int i, gflag = 0;
61*1352Sbill 	char class;
62*1352Sbill 	register char *p, *q;
63*1352Sbill 
64*1352Sbill #ifdef FLEXNAMES
65*1352Sbill 	register struct nlist *sp;
66*1352Sbill 	int malformed = 0;
67*1352Sbill 	lseek(txtmap.ufd, gstart, 0);
68*1352Sbill 	if (read(txtmap.ufd, &ssiz, sizeof(ssiz)) != sizeof (ssiz)) {
69*1352Sbill 		printf("%s: no string table (old format?)\n", symfil);
70*1352Sbill 		exit(1);
71*1352Sbill 	}
72*1352Sbill 	strtab = (char *)malloc(ssiz);
73*1352Sbill 	if (strtab == 0) {
74*1352Sbill 		printf("no room for %d bytes of string table\n", ssiz);
75*1352Sbill 		exit(1);
76*1352Sbill 	}
77*1352Sbill 	ssiz -= sizeof (ssiz);
78*1352Sbill 	if (read(txtmap.ufd, strtab+sizeof (ssiz), ssiz) != ssiz) {
79*1352Sbill 		printf("%s: error reading string table\n", symfil);
80*1352Sbill 		exit(1);
81*1352Sbill 	}
82*1352Sbill 	i = gstart - ststart;
83*1352Sbill 	symtab = (struct nlist *)malloc(i);
84*1352Sbill 	if (symtab == 0) {
85*1352Sbill 		printf("no room for %d bytes of symbol table\n", i);
86*1352Sbill 		exit(1);
87*1352Sbill 	}
88*1352Sbill 	lseek(txtmap.ufd, ststart, 0);
89*1352Sbill 	if (read(txtmap.ufd, symtab, i) != i) {
90*1352Sbill 		printf("%s: error reading symbol table\n", symfil);
91*1352Sbill 		exit(1);
92*1352Sbill 	}
93*1352Sbill 	for (sp = &symtab[i/sizeof (struct nlist)]; --sp >= symtab; )
94*1352Sbill 	if (sp->n_un.n_strx != 0) {
95*1352Sbill 		if (sp->n_un.n_strx < sizeof (ssiz) || sp->n_un.n_strx >= ssiz) {
96*1352Sbill 			if (malformed == 0) {
97*1352Sbill 				printf("danger: mangled symbol table\n");
98*1352Sbill 				malformed = 1;
99*1352Sbill 			}
100*1352Sbill 			sp->n_un.n_name = nullname;
101*1352Sbill 		} else
102*1352Sbill 			sp->n_un.n_name = strtab + sp->n_un.n_strx;
103*1352Sbill 	} else
104*1352Sbill 		sp->n_un.n_name = nullname;
105*1352Sbill #endif
106*1352Sbill #ifndef VMUNIX
107*1352Sbill 	sbuf.fd = txtmap.ufd;
108*1352Sbill #endif
109*1352Sbill 	firstdata = MAXPOS;
110*1352Sbill 	soffset = ststart;
111*1352Sbill 	blseek(&sbuf,ststart,0);
112*1352Sbill 	filep = files = badfile = (struct filet *) sbrk(sizeof filep[0]);
113*1352Sbill 	procp = procs = badproc = (struct proct *) sbrk(sizeof procp[0]);
114*1352Sbill 
115*1352Sbill 	for(;;) {
116*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) <
117*1352Sbill 				sizeof stentry) break;
118*1352Sbill 		class = stentry.n_type & STABMASK;
119*1352Sbill 		switch (class & STABMASK) {
120*1352Sbill 		case N_SO:
121*1352Sbill 		case N_SOL:
122*1352Sbill 			gflag++;
123*1352Sbill 			if (filep == badfile) {
124*1352Sbill 				p = sbrk(FILEINCR*sizeof filep[0]);
125*1352Sbill 				if (p < 0) {
126*1352Sbill 					perror("sdb");
127*1352Sbill 					exit(4);
128*1352Sbill 				}
129*1352Sbill 				q = p + FILEINCR*sizeof filep[0];
130*1352Sbill 				while (p > (char *) procs)
131*1352Sbill 					*--q = *--p;
132*1352Sbill 				badfile += FILEINCR;
133*1352Sbill 				procp = (struct proct *)
134*1352Sbill 				    ((char *) procp +
135*1352Sbill 						FILEINCR*sizeof filep[0]);
136*1352Sbill 				procs = (struct proct *)
137*1352Sbill 				    ((char *) procs +
138*1352Sbill 						FILEINCR*sizeof filep[0]);
139*1352Sbill 				badproc = (struct proct *)
140*1352Sbill 				    ((char *)badproc +
141*1352Sbill 						FILEINCR*sizeof filep[0]);
142*1352Sbill 			}
143*1352Sbill 			filep->faddr = stentry.n_value;
144*1352Sbill 			filep->lineflag = (class == N_SOL);
145*1352Sbill 			filep->stf_offset = soffset;
146*1352Sbill #ifndef FLEXNAMES
147*1352Sbill 			p = filep->sfilename;
148*1352Sbill 			for (;;) {
149*1352Sbill 				for (i=0; i<8; i++) *p++ = stentry.n_un.n_name[i];
150*1352Sbill 				if (*(p-1) == '\0') break;
151*1352Sbill 				if (bread(&sbuf, &stentry, sizeof stentry)
152*1352Sbill 						< sizeof stentry)
153*1352Sbill 					error("Bad N_SO entry (1)");
154*1352Sbill 				if ((stentry.n_type & STABMASK) !=
155*1352Sbill 						(unsigned char) class)
156*1352Sbill 					error("Bad N_SO entry (2)");
157*1352Sbill 				soffset += sizeof stentry;
158*1352Sbill 			}
159*1352Sbill #else
160*1352Sbill 			filep->sfilename = stentry.n_un.n_name;
161*1352Sbill #endif
162*1352Sbill 			q = filep->sfilename;
163*1352Sbill 			for (p=fp; *q; *p++ = *q++) ;
164*1352Sbill 			*p = 0;
165*1352Sbill 			if (stat(filework, &stbuf) == -1)
166*1352Sbill 				printf("Warning: `%s' not found\n",
167*1352Sbill 					filep->sfilename);
168*1352Sbill 			else if (stbuf.st_mtime > symtime)
169*1352Sbill 				printf("Warning: `%s' newer than `%s'\n",
170*1352Sbill 					filep->sfilename,
171*1352Sbill 					symfil);
172*1352Sbill 			filep++;
173*1352Sbill 			break;
174*1352Sbill 
175*1352Sbill 		case N_TEXT:
176*1352Sbill 			if (stentry.n_un.n_name[0] != '_') break;
177*1352Sbill 		case N_FUN:
178*1352Sbill 		case N_ENTRY:
179*1352Sbill 			if (procp == badproc) {
180*1352Sbill 				if (sbrk(PROCINCR*sizeof procp[0]) < 0) {
181*1352Sbill 					perror("sdb");
182*1352Sbill 					exit(4);
183*1352Sbill 				}
184*1352Sbill 				badproc += PROCINCR;
185*1352Sbill 			}
186*1352Sbill #ifndef FLEXNAMES
187*1352Sbill 			for(i=0; i<8; i++)
188*1352Sbill 				procp->pname[i] = stentry.n_un.n_name[i];
189*1352Sbill #else
190*1352Sbill 			procp->pname = stentry.n_un.n_name;
191*1352Sbill #endif
192*1352Sbill 			procp->paddr = stentry.n_value;
193*1352Sbill 			procp->st_offset = soffset;
194*1352Sbill 			procp->sfptr = (class != N_TEXT) ? filep - 1 : badfile;
195*1352Sbill 			procp->lineno = (class != N_TEXT) ? stentry.n_desc : 0;
196*1352Sbill 			procp->entrypt = (class & STABMASK) == N_ENTRY;
197*1352Sbill 			procp++;
198*1352Sbill 			break;
199*1352Sbill 		}
200*1352Sbill 		if (stentry.n_type & N_EXT) {
201*1352Sbill 			if (!extstart)
202*1352Sbill 				extstart = soffset;
203*1352Sbill 			if (stentry.n_type == N_DATA | N_EXT ||
204*1352Sbill 					stentry.n_type == N_BSS | N_EXT ||
205*1352Sbill 					stentry.n_value < firstdata)
206*1352Sbill 				firstdata = stentry.n_value;
207*1352Sbill 		}
208*1352Sbill 		soffset += sizeof stentry;
209*1352Sbill 	}
210*1352Sbill 	qsort(procs, procp-procs, sizeof procs[0], compar);
211*1352Sbill 	badproc->st_offset = badfile->stf_offset = soffset;
212*1352Sbill 	badproc->sfptr = procp->sfptr = badfile;
213*1352Sbill #ifndef FLEXNAMES
214*1352Sbill 	badproc->pname[0] = badfile->sfilename[0]=
215*1352Sbill 		procp->pname[0] = filep->sfilename[0] = '\0';
216*1352Sbill #else
217*1352Sbill 	badproc->pname = badfile->sfilename=
218*1352Sbill 		procp->pname = filep->sfilename = nullname;
219*1352Sbill #endif
220*1352Sbill 
221*1352Sbill 	if (!gflag)
222*1352Sbill 		printf("Warning: `%s' not compiled with -g\n", symfil);
223*1352Sbill 	setcur(1);
224*1352Sbill }
225*1352Sbill 
226*1352Sbill /* returns current procedure from state (curfile, fline) */
227*1352Sbill struct proct *
228*1352Sbill curproc() {
229*1352Sbill 	register ADDR addr;
230*1352Sbill 
231*1352Sbill 	addr = getaddr("", fline);
232*1352Sbill 	if (addr == -1) return(badproc);
233*1352Sbill 	return(adrtoprocp(addr));
234*1352Sbill 
235*1352Sbill }
236*1352Sbill 
237*1352Sbill /* returns procedure s, uses curproc() if s == NULL */
238*1352Sbill 
239*1352Sbill struct proct *
240*1352Sbill findproc(s)
241*1352Sbill char *s; {
242*1352Sbill 	register struct proct *p, *altproc;
243*1352Sbill 
244*1352Sbill 	if (s[0] == '\0') return(curproc());
245*1352Sbill 	altproc = badproc;
246*1352Sbill 
247*1352Sbill 	for (p=procs; p->pname[0]; p++) {
248*1352Sbill 		if (eqpat(s, p->pname)) return(p);
249*1352Sbill 		if (p->pname[0] == '_' && eqpatr(s, p->pname+1, 1))
250*1352Sbill 			altproc = p;
251*1352Sbill 	}
252*1352Sbill 	return(altproc);
253*1352Sbill }
254*1352Sbill 
255*1352Sbill /* returns file s containing filename */
256*1352Sbill struct filet *
257*1352Sbill findfile(s)
258*1352Sbill char *s; {
259*1352Sbill 	register struct filet *f;
260*1352Sbill 	for (f=files; f->sfilename[0]; f++) {
261*1352Sbill 		if (eqpat(f->sfilename, s)) {
262*1352Sbill 			for( ; f->lineflag; f--) ;
263*1352Sbill 			if (f < files) error("Bad file array");
264*1352Sbill 			return(f);
265*1352Sbill 		}
266*1352Sbill 	}
267*1352Sbill 	return(f);
268*1352Sbill }
269*1352Sbill 
270*1352Sbill /*
271*1352Sbill  * slookup():
272*1352Sbill  * looks up variable matching pat starting at (offset + sizeof stentry)
273*1352Sbill  * in a.out, searching backwards,
274*1352Sbill  * ignoring nested blocks to beginning to procedure.
275*1352Sbill  * Returns its offset and symbol table entries decoded in sl_*
276*1352Sbill  *
277*1352Sbill  * If comblk == "*" then match both within and outside common blocks,
278*1352Sbill  * if comblk == ""  then match only outside common blocks,
279*1352Sbill  *                  else match only within comblk.
280*1352Sbill  */
281*1352Sbill 
282*1352Sbill long
283*1352Sbill slookup(pat, poffset, stelt)
284*1352Sbill long poffset; char *pat; {
285*1352Sbill 	slookinit();
286*1352Sbill 	slooknext(pat, poffset, stelt, "*");
287*1352Sbill }
288*1352Sbill 
289*1352Sbill int clevel, level, fnameflag, comfound, incomm;
290*1352Sbill 
291*1352Sbill slookinit() {
292*1352Sbill 	clevel = level = fnameflag = comfound = incomm = 0;
293*1352Sbill }
294*1352Sbill 
295*1352Sbill long
296*1352Sbill slooknext(pat, poffset, stelt, comblk)
297*1352Sbill long poffset; char *pat, *comblk; {
298*1352Sbill 	register int i;
299*1352Sbill 	register long offset;
300*1352Sbill 	char class, *q;
301*1352Sbill 	struct nlist stentry;
302*1352Sbill 	struct proct *procp, *p;
303*1352Sbill 
304*1352Sbill 	offset = poffset + sizeof stentry;
305*1352Sbill 	if (debug) printf("slookup(%s,%d)\n",pat,offset);
306*1352Sbill 	blseek(&sbuf, offset, 0);
307*1352Sbill 
308*1352Sbill 	for (;;) {
309*1352Sbill 		offset -= sizeof stentry;
310*1352Sbill 		if (offset < ststart) break;
311*1352Sbill 		if (bread(&sbuf, &stentry+1, -sizeof stentry)
312*1352Sbill 			< sizeof stentry) break;
313*1352Sbill 		class = stentry.n_type & STABMASK;
314*1352Sbill 		switch (class & STABMASK) {
315*1352Sbill 		case 0:
316*1352Sbill 			break;
317*1352Sbill 		case N_FUN:
318*1352Sbill 			return(-1);
319*1352Sbill 		case N_RBRAC:
320*1352Sbill 			level++;
321*1352Sbill 			break;
322*1352Sbill 		case N_LBRAC:
323*1352Sbill 			level--;
324*1352Sbill 			break;
325*1352Sbill 		case N_ECOMM:
326*1352Sbill #ifndef FLEXNAMES
327*1352Sbill 			for (q = &stentry.n_un.n_name[7]; q>=stentry.n_un.n_name; q--) {
328*1352Sbill 				if (*q == '_') {
329*1352Sbill 					*q = '\0';
330*1352Sbill 					break;
331*1352Sbill 				}
332*1352Sbill 			}
333*1352Sbill #else
334*1352Sbill 			for (q = stentry.n_un.n_name; *q; q++)
335*1352Sbill 				continue;
336*1352Sbill 			if (*--q == '_')
337*1352Sbill 				*q = 0;
338*1352Sbill #endif
339*1352Sbill 			if (eqpat(comblk, stentry.n_un.n_name))
340*1352Sbill 				comfound = 1;
341*1352Sbill 			incomm = 1;
342*1352Sbill 		case N_ECOML:
343*1352Sbill 			clevel++;
344*1352Sbill 			break;
345*1352Sbill 		case N_BCOMM:
346*1352Sbill 			comfound = incomm = 0;
347*1352Sbill 			clevel--;
348*1352Sbill 			break;
349*1352Sbill 		case N_FNAME:
350*1352Sbill 			if (fnameflag)
351*1352Sbill 				break;
352*1352Sbill 			procp = findproc(stentry.n_un.n_name);
353*1352Sbill 			for (p=procs; p->pname[0]; p++) {
354*1352Sbill 				if (p->entrypt == 0 &&
355*1352Sbill 					p->st_offset > procp->st_offset &&
356*1352Sbill 					p->st_offset < offset)
357*1352Sbill 						offset = p->st_offset;
358*1352Sbill 			}
359*1352Sbill 			clevel = level = 0;
360*1352Sbill 			fnameflag++;
361*1352Sbill 			blseek(&sbuf, offset, 0);
362*1352Sbill 			break;
363*1352Sbill 		default:
364*1352Sbill 			if (level <= 0  &&  eqpat(pat, stentry.n_un.n_name) &&
365*1352Sbill 				stentry.n_un.n_name[0] && class & STABTYPES &&
366*1352Sbill 				(eqstr("*", comblk) ||
367*1352Sbill 				 (comblk[0] == '\0' && incomm == 0) ||
368*1352Sbill 				 comfound) &&
369*1352Sbill 				(stelt == (class == N_SSYM))) {
370*1352Sbill 				if (class == N_LENG) {
371*1352Sbill 					sl_size = stentry.n_value;
372*1352Sbill 					offset -= sizeof stentry;
373*1352Sbill 					bread(&sbuf, &stentry+1,
374*1352Sbill 							-sizeof stentry);
375*1352Sbill 					if (stentry.n_type&~N_EXT == N_BSS) {
376*1352Sbill 						bread(&sbuf, &stentry+1,
377*1352Sbill 						    -sizeof stentry);
378*1352Sbill 						offset -= sizeof stentry;
379*1352Sbill 					}
380*1352Sbill 				}
381*1352Sbill 				else sl_size = 0;
382*1352Sbill 				sl_class = stentry.n_type & STABMASK;
383*1352Sbill 				sl_type = stentry.n_desc;
384*1352Sbill 				sl_addr = stentry.n_value;
385*1352Sbill #ifndef FLEXNAMES
386*1352Sbill 				for (i=0; i<8; i++) sl_name[i] =
387*1352Sbill 						stentry.n_un.n_name[i];
388*1352Sbill #else
389*1352Sbill 				sl_name = stentry.n_un.n_name;
390*1352Sbill #endif
391*1352Sbill 				if (clevel != 0) docomm(offset);
392*1352Sbill 				return(offset - sizeof stentry);
393*1352Sbill 			}
394*1352Sbill 		}
395*1352Sbill 	}
396*1352Sbill 	return(-1);
397*1352Sbill }
398*1352Sbill 
399*1352Sbill /*
400*1352Sbill  * Look up global variable matching pat starting at (filestart+sizeof stentry)
401*1352Sbill  * Return its offset and symbol table entries decoded in sl_*
402*1352Sbill  */
403*1352Sbill long
404*1352Sbill globallookup(pat, filestart, stelt)
405*1352Sbill char *pat; long filestart; {
406*1352Sbill 	register int offset, i;
407*1352Sbill 	struct nlist stentry;
408*1352Sbill 	int class, clevel;
409*1352Sbill 
410*1352Sbill 	if (debug) printf("globallookup(%s,%d)\n", pat,filestart);
411*1352Sbill 	blseek(&sbuf, filestart, 0);
412*1352Sbill 	offset = filestart - sizeof stentry;
413*1352Sbill 	clevel = 0;
414*1352Sbill 	do {
415*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) <
416*1352Sbill 				sizeof stentry) return(-1);
417*1352Sbill 		offset += sizeof stentry;
418*1352Sbill 	} while ((stentry.n_type & STABMASK) == N_SO);
419*1352Sbill 	for (;;) {
420*1352Sbill 		class = stentry.n_type & STABMASK;
421*1352Sbill 		switch (class & STABMASK) {
422*1352Sbill 		case N_SO:
423*1352Sbill 			return(-1);
424*1352Sbill 		case N_ECOMM:
425*1352Sbill 			clevel--;
426*1352Sbill 			break;
427*1352Sbill 		case N_BCOMM:
428*1352Sbill 			clevel++;
429*1352Sbill 			break;
430*1352Sbill 		default:
431*1352Sbill 		if (eqpat(pat, stentry.n_un.n_name)
432*1352Sbill 				&& stentry.n_un.n_name[0] && class & STABTYPES) {
433*1352Sbill 			sl_class = stentry.n_type & STABMASK;
434*1352Sbill 			if (sl_class != N_GSYM && sl_class != N_SSYM &&
435*1352Sbill 				sl_class != N_STSYM && sl_class != N_LCSYM) goto g1;
436*1352Sbill 			if (stelt != (sl_class == N_SSYM)) goto g1;
437*1352Sbill 			sl_size = 0;
438*1352Sbill 			sl_type = stentry.n_desc;
439*1352Sbill 			sl_addr = stentry.n_value;
440*1352Sbill #ifndef FLEXNAMES
441*1352Sbill 			for (i=0; i<8; i++) sl_name[i] = stentry.n_un.n_name[i];
442*1352Sbill #else
443*1352Sbill 			sl_name = stentry.n_un.n_name;
444*1352Sbill #endif
445*1352Sbill 			if (clevel != 0) docomm(offset);
446*1352Sbill 			goto g2;
447*1352Sbill 		}
448*1352Sbill 		}
449*1352Sbill g1:		if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
450*1352Sbill 			return(-1);
451*1352Sbill 		offset += sizeof stentry;
452*1352Sbill 	}
453*1352Sbill g2:	bread(&sbuf, &stentry, sizeof stentry);
454*1352Sbill 	if (stentry.n_type&~N_EXT==N_BSS) {
455*1352Sbill 		bread(&sbuf, &stentry, sizeof stentry);
456*1352Sbill 		offset += sizeof stentry;
457*1352Sbill 	}
458*1352Sbill 	if (((stentry.n_type & STABMASK) == N_LENG) &&
459*1352Sbill 			(eqpat(sl_name, stentry.n_un.n_name)))
460*1352Sbill 		sl_size = stentry.n_value;
461*1352Sbill 
462*1352Sbill 	if (sl_class == N_GSYM && (clevel == 0)) {
463*1352Sbill 		blseek(&sbuf, extstart, 0);
464*1352Sbill 		for(;;) {
465*1352Sbill 			if (bread(&sbuf, &stentry, sizeof stentry)
466*1352Sbill 					< sizeof stentry)
467*1352Sbill 				return(-1);
468*1352Sbill 			if (stentry.n_un.n_name[0] != '_') continue;
469*1352Sbill 			if (eqpatr(sl_name, stentry.n_un.n_name+1, 1)) {
470*1352Sbill 				sl_addr = stentry.n_value;
471*1352Sbill 				break;
472*1352Sbill 			}
473*1352Sbill 		}
474*1352Sbill 	}
475*1352Sbill 	return(offset + sizeof stentry);
476*1352Sbill }
477*1352Sbill 
478*1352Sbill /* core address to procedure (pointer to proc array) */
479*1352Sbill struct proct *
480*1352Sbill adrtoprocp(addr)
481*1352Sbill ADDR addr; {
482*1352Sbill 	register struct proct *procp, *lastproc;
483*1352Sbill 	lastproc = badproc;
484*1352Sbill 	for (procp=procs; procp->pname[0]; procp++) {
485*1352Sbill 		if (procp->paddr > addr) break;
486*1352Sbill 		if (procp->entrypt == 0)
487*1352Sbill 			lastproc = procp;
488*1352Sbill 	}
489*1352Sbill 	return (lastproc);
490*1352Sbill }
491*1352Sbill 
492*1352Sbill 
493*1352Sbill /* core address to file (pointer to file array) */
494*1352Sbill struct filet *
495*1352Sbill adrtofilep(addr)
496*1352Sbill ADDR addr; {
497*1352Sbill 	register struct filet *filep;
498*1352Sbill 	for (filep=files; filep->sfilename[0]; filep++) {
499*1352Sbill 		if (filep->faddr > addr) break;
500*1352Sbill 	}
501*1352Sbill 	return (filep != files ? filep-1 : badfile);
502*1352Sbill }
503*1352Sbill 
504*1352Sbill /*
505*1352Sbill  * core address to linenumber
506*1352Sbill  *  Sets external exactaddr to addr if addr is NOT the first instruction
507*1352Sbill  * of a line, set to -1 otherwise.
508*1352Sbill  *  Sets external lnfaddr to address of first statement in line.
509*1352Sbill  */
510*1352Sbill long lastoffset;
511*1352Sbill 
512*1352Sbill adrtolineno(addr)
513*1352Sbill ADDR addr; {
514*1352Sbill 	register int lineno;
515*1352Sbill 	long offset;
516*1352Sbill 	struct nlist stentry;
517*1352Sbill 
518*1352Sbill 	exactaddr = addr;
519*1352Sbill 	lineno = lastoffset = -1;
520*1352Sbill 	offset = adrtoprocp(addr)->st_offset;
521*1352Sbill 	blseek(&sbuf, offset, 0);
522*1352Sbill 	for (;;) {
523*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry)
524*1352Sbill 				< sizeof stentry) break;
525*1352Sbill 		if (stentry.n_type == N_SO)
526*1352Sbill 			break;
527*1352Sbill 		if (stentry.n_type == N_SLINE) {
528*1352Sbill 			if (stentry.n_value > addr)
529*1352Sbill 				break;
530*1352Sbill 			lastoffset = offset;
531*1352Sbill 			lineno = stentry.n_desc;
532*1352Sbill 			lnfaddr = stentry.n_value;
533*1352Sbill 			if (stentry.n_value == addr)
534*1352Sbill 				exactaddr = -1;
535*1352Sbill 		}
536*1352Sbill 		offset += sizeof stentry;
537*1352Sbill 	}
538*1352Sbill 	return (lineno);
539*1352Sbill }
540*1352Sbill 
541*1352Sbill 
542*1352Sbill /* address to a.out offset */
543*1352Sbill long
544*1352Sbill adrtostoffset(addr)
545*1352Sbill ADDR addr; {
546*1352Sbill 	adrtolineno(addr);
547*1352Sbill 	return(lastoffset);
548*1352Sbill }
549*1352Sbill 
550*1352Sbill 
551*1352Sbill /*
552*1352Sbill  * Set (curfile, lineno) from core image.
553*1352Sbill  * Returns 1 if there is a core image, 0 otherwise.
554*1352Sbill  *
555*1352Sbill  * Print the current line iff verbose is set.
556*1352Sbill  */
557*1352Sbill setcur(verbose) {
558*1352Sbill 	register struct proct *procp;
559*1352Sbill 
560*1352Sbill 	dot = *(ADDR *) (((ADDR) &u) + PC);
561*1352Sbill 
562*1352Sbill 	if (dot == 0) {
563*1352Sbill 		printf("No core image\n");
564*1352Sbill 		goto setmain;
565*1352Sbill 	}
566*1352Sbill 	procp = adrtoprocp(dot);
567*1352Sbill 	if ((procp->sfptr) != badfile) {
568*1352Sbill 		finit(adrtofilep(procp->paddr)->sfilename);
569*1352Sbill 		ffind(adrtolineno(dot));
570*1352Sbill 		if (verbose) {
571*1352Sbill 			if (exactaddr != -1)
572*1352Sbill 				printf("0x%x in ", exactaddr);
573*1352Sbill #ifndef FLEXNAMES
574*1352Sbill 			printf("%.8s:", procp->pname);
575*1352Sbill #else
576*1352Sbill 			printf("%s:", procp->pname);
577*1352Sbill #endif
578*1352Sbill 			fprint();
579*1352Sbill 		}
580*1352Sbill 		return(1);
581*1352Sbill 	}
582*1352Sbill 	if (verbose) {
583*1352Sbill 		if (procp->pname[0] == '_')
584*1352Sbill #ifndef FLEXNAMES
585*1352Sbill 			printf("%.7s: address 0x%x\n", procp->pname+1, dot);
586*1352Sbill #else
587*1352Sbill 			printf("%s: address 0x%x\n", procp->pname+1, dot);
588*1352Sbill #endif
589*1352Sbill 		else
590*1352Sbill #ifndef FLEXNAMES
591*1352Sbill 			printf("%.8s: address %d\n", procp->pname, dot);
592*1352Sbill #else
593*1352Sbill 			printf("%s: address %d\n", procp->pname, dot);
594*1352Sbill #endif
595*1352Sbill 	}
596*1352Sbill 
597*1352Sbill setmain:
598*1352Sbill 	procp = findproc("MAIN_");
599*1352Sbill 	if ((procp->pname[0] != 'M') || (procp->sfptr == badfile)) {
600*1352Sbill 		procp = findproc("main");
601*1352Sbill 		if ((procp->pname[0] != 'm') || (procp->sfptr == badfile)) {
602*1352Sbill 			/* printf("main not compiled with debug flag\n"); */
603*1352Sbill 			return(0);
604*1352Sbill 		}
605*1352Sbill 	}
606*1352Sbill 	finit(procp->sfptr->sfilename);
607*1352Sbill 	ffind(procp->lineno);
608*1352Sbill 	return(0);
609*1352Sbill }
610*1352Sbill 
611*1352Sbill compar(a, b)
612*1352Sbill struct proct *a, *b; {
613*1352Sbill 	if (a->paddr == b->paddr) {
614*1352Sbill 		if (a->pname[0] == '_') return(-1);
615*1352Sbill 		if (b->pname[0] == '_') return(1);
616*1352Sbill 		return(0);
617*1352Sbill 	}
618*1352Sbill 	return(a->paddr < b->paddr ? -1 : 1);
619*1352Sbill }
620*1352Sbill 
621*1352Sbill /* gets offset of file or procedure named s */
622*1352Sbill nametooffset(s)
623*1352Sbill char *s; {
624*1352Sbill 	register struct filet *f;
625*1352Sbill 	register struct proct *p;
626*1352Sbill 
627*1352Sbill 	if (*s == '\0')
628*1352Sbill 		return(-1);
629*1352Sbill 	if (eqany('.', s)) {
630*1352Sbill 		f = findfile(s);
631*1352Sbill 		return(f->sfilename[0] ? f->stf_offset : -1);
632*1352Sbill 	}
633*1352Sbill 	p = findproc(s);
634*1352Sbill 	return(p->pname[0] ? p->st_offset : -1);
635*1352Sbill }
636*1352Sbill 
637*1352Sbill /* returns s if its a filename, its file otherwise */
638*1352Sbill char *
639*1352Sbill nametofile(s)
640*1352Sbill char *s; {
641*1352Sbill 	register struct proct *p;
642*1352Sbill 
643*1352Sbill 	if (eqany('.', s)) {
644*1352Sbill 		return(s);
645*1352Sbill 	}
646*1352Sbill 	p = findproc(s);
647*1352Sbill 	return(adrtofilep(p->paddr)->sfilename);
648*1352Sbill }
649*1352Sbill 
650*1352Sbill 
651*1352Sbill /* line number to address, starting at offset in a.out */
652*1352Sbill /* assumes that offset is within file */
653*1352Sbill lntoaddr(lineno, offset, file)
654*1352Sbill long offset; char *file; {
655*1352Sbill 	struct nlist stentry;
656*1352Sbill 	register int i, ignore = 0;
657*1352Sbill 	register int bestln=BIGNUM;
658*1352Sbill 	ADDR bestaddr;
659*1352Sbill 	char *p;
660*1352Sbill 
661*1352Sbill 	blseek(&sbuf, offset, 0);
662*1352Sbill 
663*1352Sbill 	do {
664*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) <
665*1352Sbill 				sizeof stentry) return(-1);
666*1352Sbill 	} while ((stentry.n_type & STABMASK) == N_SO);
667*1352Sbill 	for (;;) {
668*1352Sbill 		switch(stentry.n_type & STABMASK) {
669*1352Sbill 		case N_SLINE:
670*1352Sbill 			if (!ignore) {
671*1352Sbill 				if (stentry.n_desc == lineno)
672*1352Sbill 					return(stentry.n_value);
673*1352Sbill 				if (stentry.n_desc > lineno &&
674*1352Sbill 					stentry.n_desc < bestln) {
675*1352Sbill 					bestln = stentry.n_desc;
676*1352Sbill 					bestaddr = stentry.n_value;
677*1352Sbill 				}
678*1352Sbill 			}
679*1352Sbill 			break;
680*1352Sbill 
681*1352Sbill 		case N_SO:
682*1352Sbill 			goto ret;
683*1352Sbill 
684*1352Sbill 		case N_SOL:
685*1352Sbill 			p = file;
686*1352Sbill #ifndef FLEXNAMES
687*1352Sbill 			for (;;) {
688*1352Sbill 				for (i=0; i<8; i++) {
689*1352Sbill 					if (*p != stentry.n_un.n_name[i]) goto neq;
690*1352Sbill 					if (*p++ == '\0') break;
691*1352Sbill 				}
692*1352Sbill 				if (stentry.n_un.n_name[7] == '\0')
693*1352Sbill 					break;
694*1352Sbill 				if (bread(&sbuf, &stentry, sizeof stentry)
695*1352Sbill 						< sizeof stentry)
696*1352Sbill 					error("Bad N_SO entry (1)");
697*1352Sbill 				if ((stentry.n_type & STABMASK) !=
698*1352Sbill 						(unsigned char) N_SOL)
699*1352Sbill 					error("Bad N_SO entry (2)");
700*1352Sbill 			}
701*1352Sbill #else
702*1352Sbill 			if (strcmp(file, stentry.n_un.n_name))
703*1352Sbill 				goto neq;
704*1352Sbill #endif
705*1352Sbill 			ignore = 0;
706*1352Sbill 			break;
707*1352Sbill 
708*1352Sbill neq:			ignore++;
709*1352Sbill 			break;
710*1352Sbill 		}
711*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
712*1352Sbill 			break;
713*1352Sbill 	}
714*1352Sbill ret:	return(bestln == BIGNUM ? -1 : bestaddr);
715*1352Sbill }
716*1352Sbill 
717*1352Sbill /* gets address of proc:number */
718*1352Sbill getaddr(proc,integ)
719*1352Sbill char *proc; {
720*1352Sbill 	register long offset;
721*1352Sbill 	register char *s, *f;
722*1352Sbill 	ADDR addr;
723*1352Sbill 
724*1352Sbill 	s = proc[0] ? proc : curfile;
725*1352Sbill 	if (*s == '\0')
726*1352Sbill 		return(-1);
727*1352Sbill 	offset = nametooffset(s);
728*1352Sbill 	f = nametofile(s);
729*1352Sbill 	if (debug) printf("getaddr() computed offset %d", offset);
730*1352Sbill 	if (offset == -1) {
731*1352Sbill 		addr = extaddr(proc);
732*1352Sbill 		if (addr != -1) addr += 2;  /* MACHINE DEPENDENT */
733*1352Sbill 		if (debug) printf(" extaddr computed %d\n", addr);
734*1352Sbill 		return(addr);
735*1352Sbill 	}
736*1352Sbill 	if (integ)
737*1352Sbill 		addr = lntoaddr(integ, offset, s);
738*1352Sbill 	else {
739*1352Sbill 		ADDR oldaddr;
740*1352Sbill 		oldaddr = findproc(proc)->paddr + 2;  /* MACHINE DEPENDENT */
741*1352Sbill 		addr = lntoaddr(adrtolineno(addr)+1, offset, f);
742*1352Sbill 		if (addr == -1)
743*1352Sbill 			addr = oldaddr;
744*1352Sbill 	}
745*1352Sbill 	if (debug) printf(" and addr %d\n", addr);
746*1352Sbill 	if (addr == -1) return(-1);
747*1352Sbill 	return(addr);
748*1352Sbill }
749*1352Sbill 
750*1352Sbill /* returns address of external */
751*1352Sbill ADDR
752*1352Sbill extaddr(name)
753*1352Sbill char *name; {
754*1352Sbill 	struct nlist stentry;
755*1352Sbill 	blseek(&sbuf, extstart, 0);
756*1352Sbill 
757*1352Sbill 	for (;;) {
758*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
759*1352Sbill 			return(-1);
760*1352Sbill 		if (stentry.n_un.n_name[0] == '_' &&
761*1352Sbill 			    eqpatr(name, stentry.n_un.n_name+1, 1))
762*1352Sbill 			return(stentry.n_value);
763*1352Sbill 	}
764*1352Sbill }
765*1352Sbill 
766*1352Sbill 
767*1352Sbill /*
768*1352Sbill  * Look up external data symbol matching pat starting at
769*1352Sbill  *  (filestart+sizeof stentry)
770*1352Sbill  * Return its address in sl_addr and name in sl_name.
771*1352Sbill  */
772*1352Sbill long
773*1352Sbill extlookup(pat, filestart)
774*1352Sbill char *pat; long filestart; {
775*1352Sbill 	register int offset, i;
776*1352Sbill 	struct nlist stentry;
777*1352Sbill 
778*1352Sbill 	blseek(&sbuf, filestart, 0);
779*1352Sbill 	offset = filestart - sizeof stentry;
780*1352Sbill 	do {
781*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) <
782*1352Sbill 				sizeof stentry) return(-1);
783*1352Sbill 		offset += sizeof stentry;
784*1352Sbill 	} while ((stentry.n_type & STABMASK) == N_SO);
785*1352Sbill 	for (;;) {
786*1352Sbill 		if (stentry.n_un.n_name[0] == '_' &&
787*1352Sbill 			    stentry.n_type == (N_DATA | N_EXT) &&
788*1352Sbill 			    eqpatr(pat, stentry.n_un.n_name+1, 1)) {
789*1352Sbill 			sl_addr = stentry.n_value;
790*1352Sbill #ifndef FLEXNAMES
791*1352Sbill 			for (i=0; i<7; i++) sl_name[i] = stentry.n_un.n_name[i+1];
792*1352Sbill #else
793*1352Sbill 			sl_name = stentry.n_un.n_name;
794*1352Sbill #endif
795*1352Sbill 			return(offset + sizeof stentry);
796*1352Sbill 		}
797*1352Sbill g1:		if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry)
798*1352Sbill 			return(-1);
799*1352Sbill 		offset += sizeof stentry;
800*1352Sbill 	}
801*1352Sbill }
802*1352Sbill 
803*1352Sbill /* find enclosing common blocks and fix up addresses */
804*1352Sbill docomm(offset)
805*1352Sbill long offset; {
806*1352Sbill 	struct nlist stentry;
807*1352Sbill 
808*1352Sbill 	for (;;) {
809*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry) < sizeof stentry) {
810*1352Sbill 			error("Bad common block");
811*1352Sbill 			return;
812*1352Sbill 		}
813*1352Sbill 		sl_class = N_GSYM;
814*1352Sbill 		if ((stentry.n_type & STABMASK) == N_ECOMM) {
815*1352Sbill 			sl_addr += extaddr(stentry.n_un.n_name);
816*1352Sbill 			blseek(&sbuf, offset, 0);
817*1352Sbill 			return;
818*1352Sbill 		}
819*1352Sbill 		if ((stentry.n_type & STABMASK) == N_ECOML) {
820*1352Sbill 			sl_addr += stentry.n_value;
821*1352Sbill 			blseek(&sbuf, offset, 0);
822*1352Sbill 			return;
823*1352Sbill 		}
824*1352Sbill 	}
825*1352Sbill }
826*1352Sbill 
827*1352Sbill /* determine if class is that of a variable */
828*1352Sbill char pctypes[] = {N_GSYM, N_STSYM, N_LCSYM, N_RSYM, N_SSYM, N_LSYM,
829*1352Sbill 			N_PSYM, 0};
830*1352Sbill varclass(class)
831*1352Sbill char class; {
832*1352Sbill 	char *p;
833*1352Sbill 
834*1352Sbill 	for (p=pctypes; *p; p++) {
835*1352Sbill 		if (class == *p)
836*1352Sbill 			return(1);
837*1352Sbill 	}
838*1352Sbill 	return(0);
839*1352Sbill }
840*1352Sbill 
841*1352Sbill /*
842*1352Sbill  * address to external name
843*1352Sbill  * returns difference between addr and address of external
844*1352Sbill  * name returned in sl_name
845*1352Sbill  */
846*1352Sbill adrtoext(addr)
847*1352Sbill ADDR addr; {
848*1352Sbill 	struct nlist stentry;
849*1352Sbill 	register int i, prevdiff = MAXPOS, diff;
850*1352Sbill 
851*1352Sbill 	blseek(&sbuf, extstart, 0);
852*1352Sbill 	for (;;) {
853*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry)
854*1352Sbill 				< sizeof stentry)
855*1352Sbill 			return (prevdiff!=MAXPOS ? prevdiff : -1);
856*1352Sbill 		if (stentry.n_type == (N_DATA | N_EXT) ||
857*1352Sbill 		    stentry.n_type == (N_BSS | N_EXT)) {
858*1352Sbill 			diff = addr - stentry.n_value;
859*1352Sbill 			if (diff >= 0 && diff < prevdiff) {
860*1352Sbill #ifndef FLEXNAMES
861*1352Sbill 				for (i=0; i<7; i++)
862*1352Sbill 					sl_name[i] = stentry.n_un.n_name[i+1];
863*1352Sbill #else
864*1352Sbill 				sl_name = stentry.n_un.n_name;
865*1352Sbill #endif
866*1352Sbill 				if (diff == 0)
867*1352Sbill 					return(0);
868*1352Sbill 				prevdiff = diff;
869*1352Sbill 			}
870*1352Sbill 		}
871*1352Sbill 	}
872*1352Sbill }
873*1352Sbill 
874*1352Sbill /*
875*1352Sbill  * address to local name in procp
876*1352Sbill  * returns difference between addr and address of local
877*1352Sbill  * returned in sl_name
878*1352Sbill  */
879*1352Sbill adrtolocal(addr, procp)
880*1352Sbill ADDR addr; struct proct *procp; {
881*1352Sbill 	struct nlist stentry;
882*1352Sbill 	register int i, prevdiff = MAXPOS, diff;
883*1352Sbill 
884*1352Sbill 	blseek(&sbuf, procp->st_offset + sizeof stentry, 0);
885*1352Sbill 	for (;;) {
886*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry)
887*1352Sbill 				< sizeof stentry)
888*1352Sbill 			return(prevdiff!=MAXPOS ? prevdiff : -1);
889*1352Sbill 		if (stentry.n_type == N_FUN)
890*1352Sbill 			return(prevdiff!=MAXPOS ? prevdiff : -1);
891*1352Sbill 		if (stentry.n_type == N_LSYM) {
892*1352Sbill 			diff = addr - stentry.n_value;
893*1352Sbill 			if (diff >= 0 && diff < prevdiff) {
894*1352Sbill #ifndef FLEXNAMES
895*1352Sbill 				for (i=0; i<8; i++)
896*1352Sbill 					sl_name[i] = stentry.n_un.n_name[i];
897*1352Sbill #else
898*1352Sbill 				sl_name = stentry.n_un.n_name;
899*1352Sbill #endif
900*1352Sbill 				if (diff == 0)
901*1352Sbill 					return(0);
902*1352Sbill 				prevdiff = diff;
903*1352Sbill 			}
904*1352Sbill 		}
905*1352Sbill 	}
906*1352Sbill }
907*1352Sbill 
908*1352Sbill /*
909*1352Sbill  * address to parameter name in procp
910*1352Sbill  * returns difference between addr and address of local
911*1352Sbill  * returned in sl_name
912*1352Sbill  */
913*1352Sbill adrtoparam(addr, procp)
914*1352Sbill ADDR addr; struct proct *procp; {
915*1352Sbill 	struct nlist stentry;
916*1352Sbill 	register int i, prevdiff = MAXPOS, diff;
917*1352Sbill 
918*1352Sbill 	blseek(&sbuf, procp->st_offset + sizeof stentry, 0);
919*1352Sbill 	for (;;) {
920*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry)
921*1352Sbill 				< sizeof stentry)
922*1352Sbill 			return(prevdiff!=MAXPOS ? prevdiff : -1);
923*1352Sbill 		if (stentry.n_type == N_FUN)
924*1352Sbill 			return(prevdiff!=MAXPOS ? prevdiff : -1);
925*1352Sbill 		if (stentry.n_type == N_PSYM) {
926*1352Sbill 			diff = addr - stentry.n_value;
927*1352Sbill 			if (diff >= 0 && diff < prevdiff) {
928*1352Sbill #ifndef FLEXNAMES
929*1352Sbill 				for (i=0; i<8; i++)
930*1352Sbill 					sl_name[i] = stentry.n_un.n_name[i];
931*1352Sbill #else
932*1352Sbill 				sl_name = stentry.n_un.n_name;
933*1352Sbill #endif
934*1352Sbill 				if (diff == 0)
935*1352Sbill 					return(0);
936*1352Sbill 				prevdiff = diff;
937*1352Sbill 			}
938*1352Sbill 		}
939*1352Sbill 	}
940*1352Sbill }
941*1352Sbill 
942*1352Sbill /*
943*1352Sbill  * register number to register variable name in procp
944*1352Sbill  * returned in sl_name
945*1352Sbill  */
946*1352Sbill adrtoregvar(regno, procp)
947*1352Sbill ADDR regno; struct proct *procp; {
948*1352Sbill 	struct nlist stentry;
949*1352Sbill 	register int i;
950*1352Sbill 
951*1352Sbill 	blseek(&sbuf, procp->st_offset + sizeof stentry, 0);
952*1352Sbill 	for (;;) {
953*1352Sbill 		if (bread(&sbuf, &stentry, sizeof stentry)
954*1352Sbill 				< sizeof stentry) return(-1);
955*1352Sbill 		if (stentry.n_type == N_FUN)
956*1352Sbill 			return(-1);
957*1352Sbill 		if (stentry.n_type == N_RSYM) {
958*1352Sbill 			if (stentry.n_value == regno) {
959*1352Sbill #ifndef FLEXNAMES
960*1352Sbill 				for (i=0; i<8; i++)
961*1352Sbill 					sl_name[i] = stentry.n_un.n_name[i];
962*1352Sbill #else
963*1352Sbill 				sl_name = stentry.n_un.n_name;
964*1352Sbill #endif
965*1352Sbill 				return(0);
966*1352Sbill 			}
967*1352Sbill 		}
968*1352Sbill 	}
969*1352Sbill }
970*1352Sbill 
971*1352Sbill /* sets file map for M command */
972*1352Sbill setmap(s)
973*1352Sbill char *s; {
974*1352Sbill 	union {
975*1352Sbill 		MAP *m;
976*1352Sbill 		L_INT *mp;
977*1352Sbill 	} amap;
978*1352Sbill 	int starflag = 0;
979*1352Sbill 
980*1352Sbill 	amap.mp = 0;
981*1352Sbill 	for (; *s; s++) {
982*1352Sbill 		switch (*s) {
983*1352Sbill 		case '/':
984*1352Sbill 			amap.m = &datmap;
985*1352Sbill 			break;
986*1352Sbill 		case '?':
987*1352Sbill 			amap.m = &txtmap;
988*1352Sbill 			break;
989*1352Sbill 		case '*':
990*1352Sbill 			starflag++;
991*1352Sbill 			break;
992*1352Sbill 		default:
993*1352Sbill 			goto sout;
994*1352Sbill 		}
995*1352Sbill 	}
996*1352Sbill 
997*1352Sbill sout:	if (amap.mp == 0) {
998*1352Sbill 		error("Map `?' or `/' must be specified");
999*1352Sbill 		return;
1000*1352Sbill 	}
1001*1352Sbill 	if (starflag)
1002*1352Sbill 		amap.mp += 3;
1003*1352Sbill 	for (; *s; s++) {
1004*1352Sbill 		if (*s >= '0' && *s <= '9')
1005*1352Sbill 			*(amap.mp)++ = readint(&s);
1006*1352Sbill 	}
1007*1352Sbill }
1008