xref: /netbsd-src/external/bsd/pcc/dist/pcc/cc/ccom/stabs.c (revision c38e7cc395b1472a774ff828e46123de44c628e9)
1 /*	Id: stabs.c,v 1.35 2015/09/15 20:01:10 ragge Exp 	*/
2 /*	$NetBSD: stabs.c,v 1.1.1.7 2016/02/09 20:28:52 plunky Exp $	*/
3 
4 /*
5  * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /*
32  * Simple implementation of the "stabs" debugging format.
33  * Not complete but at least makes it possible to set breakpoints,
34  * examine simple variables and do stack traces.
35  * Based on the stabs documentation that follows gdb.
36  */
37 
38 #include "pass1.h"
39 
40 #ifdef STABS
41 
42 #include <sys/types.h>
43 #include <stdarg.h>
44 #include <string.h>
45 
46 #define	STABHASH	256
47 #define	INTNUM		1	/* internal number of type "int" */
48 #undef BIT2BYTE /* from external.h */
49 #define	BIT2BYTE(x)	((x)/SZCHAR)
50 
51 #ifndef STABLBL
52 #error macdefs.h must define STABLBL
53 #endif
54 
55 /* defines taken from BSD <stab.h> */
56 #define N_GSYM          0x20    /* global symbol */
57 #define N_FUN           0x24    /* procedure name */
58 #define N_LCSYM         0x28    /* bss segment variable */
59 #define N_RSYM          0x40    /* register variable */
60 #define N_SLINE         0x44    /* text segment line number */
61 #define N_SO            0x64    /* main source file name */
62 #define N_LSYM          0x80    /* stack variable */
63 #define N_SOL           0x84    /* included source file name */
64 #define N_PSYM          0xa0    /* parameter variable */
65 #define N_LBRAC         0xc0    /* left bracket */
66 #define N_RBRAC         0xe0    /* right bracket */
67 
68 /*
69  * Local type mapping
70  * Types are defined as a typeword, a dimension pointer (in the case
71  * of arrays) and struct/union/enum declarations.
72  * Function prototypes are ignored.
73  */
74 static struct stabtype {
75 	struct stabtype *next;	/* linked list */
76 	TWORD type;		/* pcc type number */
77 	union dimfun *df;	/* dimension of arrays */
78 	struct attr *ap;	/* struct/union/enum declarations */
79 	int num;		/* local type number */
80 } *stabhash[STABHASH];
81 static int ntypes;
82 static char *curfun;
83 static int stablbl = 10;
84 extern int inftn;
85 
86 void ptype(char *name, int num, int inhnum, long long min, long long max);
87 struct stabtype *addtype(TWORD, union dimfun *, struct attr *);
88 struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue);
89 void printtype(struct symtab *s, char *str, int len);
90 void cprint(int p2, char *fmt, ...);
91 
92 #define	MAXPSTR	100
93 
94 extern int isinlining;
95 
96 /*
97  * Output type definitions for the stab debugging format.
98  * Note that "int" is always internal number 1.
99  */
100 void
101 stabs_init(void)
102 {
103 	struct stabtype *st;
104 
105 #define	ADDTYPE(y) addtype(y, NULL, 0)
106 
107 	ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT);
108 
109 	st = ADDTYPE(CHAR);
110 	ptype("char", st->num, st->num, 0, MAX_CHAR);
111 	ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT);
112 	ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG);
113 	ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM,
114 	     MIN_LONGLONG, MAX_LONGLONG);
115 	ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR);
116 	ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT);
117 	ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED);
118 	ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG);
119 	ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM,
120 	    0, MAX_ULONGLONG);
121 
122 	ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0);
123 	ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0);
124 	ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0);
125 	st = ADDTYPE(VOID);
126 	cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n",
127 	    st->num, st->num, N_LSYM);
128 
129 }
130 
131 /*
132  * Print a type in stabs format
133  */
134 void
135 ptype(char *name, int num, int inhnum, long long min, long long max)
136 {
137 	cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n",
138 	    name, num, inhnum, min, max, N_LSYM);
139 }
140 
141 /*
142  * Add a new local type to the hash table.
143  * The search key is the (type, df, sue) triple.
144  */
145 struct stabtype *
146 addtype(TWORD t, union dimfun *df, struct attr *ap)
147 {
148 	struct stabtype *st;
149 
150 	st = permalloc(sizeof(struct stabtype));
151 	st->type = t;
152 	st->df = df;
153 	st->ap = ap;
154 	st->num = ++ntypes;
155 	st->next = stabhash[t & (STABHASH-1)];
156 	stabhash[t & (STABHASH-1)] = st;
157 	return st;
158 }
159 
160 /*
161  * Search for a given type and return a type pointer (or NULL).
162  */
163 struct stabtype *
164 findtype(TWORD t, union dimfun *df, struct attr *ap)
165 {
166 	struct stabtype *st;
167 	union dimfun *dw, *dx;
168 	TWORD tw;
169 
170 	st = stabhash[t & (STABHASH-1)];
171 	for (; st; st = st->next) {
172 		if (t != st->type || ap != st->ap)
173 			continue;
174 		/* Ok, type and sue matches, check dimensions */
175 		if (st->df == NULL)
176 			return st; /* no arrays, got match */
177 		dw = st->df;
178 		dx = df;
179 		tw = t;
180 		for (; tw > BTMASK; tw = DECREF(tw)) {
181 			if (ISARY(tw)) {
182 				if (dw->ddim == dx->ddim)
183 					dw++, dx++;
184 				else
185 					break;
186 			}
187 		}
188 		if (tw <= BTMASK)
189 			return st;
190 	}
191 	return NULL;
192 }
193 
194 /*
195  * Print current line number.
196  */
197 void
198 stabs_line(int line)
199 {
200 	if (inftn == 0)
201 		return; /* ignore */
202 #ifdef STAB_LINE_ABSOLUTE
203 	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
204 	    N_SLINE, line, stablbl, stablbl);
205 #else
206 	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
207 	    N_SLINE, line, stablbl, curfun, stablbl);
208 #endif
209 	stablbl++;
210 }
211 
212 /*
213  * Start of block.
214  */
215 void
216 stabs_lbrac(int blklvl)
217 {
218 #ifdef STAB_LINE_ABSOLUTE
219 	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
220 	    N_LBRAC, blklvl, stablbl, stablbl);
221 #else
222 	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
223 	    N_LBRAC, blklvl, stablbl, curfun, stablbl);
224 #endif
225 	stablbl++;
226 }
227 
228 /*
229  * End of block.
230  */
231 void
232 stabs_rbrac(int blklvl)
233 {
234 #ifdef STAB_LINE_ABSOLUTE
235 	cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n",
236 	    N_RBRAC, blklvl, stablbl, stablbl);
237 #else
238 	cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n",
239 	    N_RBRAC, blklvl, stablbl, curfun, stablbl);
240 #endif
241 	stablbl++;
242 }
243 
244 static char *mainfile;
245 
246 /*
247  * Print current file and set mark.
248  */
249 void
250 stabs_file(char *fname)
251 {
252 	if (mainfile == NULL)
253 		mainfile = fname; /* first call */
254 	cprint(inftn, "\t.stabs	\"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n",
255 	    fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
256 	stablbl++;
257 }
258 
259 /*
260  * Print end mark
261  */
262 void
263 stabs_efile(char *fname)
264 {
265 	cprint(inftn, "\t.stabs	\"\",%d,0,0," STABLBL "\n" STABLBL ":\n",
266 	    fname == mainfile ? N_SO : N_SOL, stablbl, stablbl);
267 	stablbl++;
268 }
269 
270 /*
271  * Print beginning of function.
272  */
273 void
274 stabs_func(struct symtab *s)
275 {
276 	char str[MAXPSTR];
277 
278 	curfun = getexname(s);
279 	printtype(s, str, sizeof(str));
280 	cprint(1, "\t.stabs	\"%s:%c%s\",%d,0,%d,%s\n",
281 	    curfun, s->sclass == STATIC ? 'f' : 'F', str,
282 	    N_FUN, 0, curfun);
283 }
284 
285 /*
286  * Print a (complex) type.
287  * Will also create subtypes.
288  * Printed string is like "20=*21=*1".
289  */
290 void
291 printtype(struct symtab *s, char *ostr, int len)
292 {
293 	struct stabtype *st;
294 	union dimfun *df = s->sdf;
295 	struct attr *ap = s->sap;
296 	TWORD t = s->stype;
297 	int op = 0;
298 
299 	/* Print out not-yet-found types */
300 	if (ISFTN(t))
301 		t = DECREF(t);
302 	st = findtype(t, df, ap);
303 	while (st == NULL && t > BTMASK) {
304 		st = addtype(t, df, ap);
305 		op+=snprintf(ostr+op, len - op, "%d=", st->num);
306 		if (ISFTN(t))
307 			ostr[op++] = 'f';
308 		else if (ISPTR(t))
309 			ostr[op++] = '*';
310 		else if (ISARY(t)) {
311 			op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1);
312 		} else
313 			cerror("printtype: notype");
314 		if (ISARY(t))
315 			df++;
316 		t = DECREF(t);
317 		st = findtype(t, df, ap);
318 		if (op > MAXPSTR-10)
319 			cerror("printtype: too difficult expression");
320 	}
321 	/* print out basic type. may have to be entered in case of sue */
322 	snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num);
323 	/* snprintf here null-terminated the string */
324 }
325 
326 void
327 stabs_newsym(struct symtab *s)
328 {
329 	extern int fun_inline;
330 	char *sname;
331 	char ostr[MAXPSTR];
332 	OFFSZ suesize, sz;
333 
334 	if (ISFTN(s->stype))
335 		return; /* functions are handled separate */
336 
337 	if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS ||
338 	    s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE ||
339 	    s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype))
340 		return; /* XXX - fix structs */
341 
342 	sname = getexname(s);
343 	sz = tsize(s->stype, s->sdf, s->sap);
344 	suesize = BIT2BYTE(sz);
345 	if (suesize > 32767)
346 		suesize = 32767;
347 	else if (suesize < -32768)
348 		suesize = -32768;
349 
350 	printtype(s, ostr, sizeof(ostr));
351 	switch (s->sclass) {
352 	case PARAM:
353 		cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n",
354 		    sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
355 		break;
356 
357 	case AUTO:
358 		cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n",
359 		    sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
360 		break;
361 
362 	case STATIC:
363 		if (blevel)
364 			cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n",
365 			    sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset);
366 		else
367 			cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n",
368 			    sname, ostr, N_LCSYM, (CONSZ)suesize, sname);
369 		break;
370 
371 	case EXTERN:
372 	case EXTDEF:
373 		cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n",
374 		    sname, ostr, N_GSYM, (CONSZ)suesize);
375 		break;
376 
377 	case REGISTER:
378 		cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n",
379 		    sname, ostr, N_RSYM, 1, s->soffset);
380 		break;
381 
382 	case SNULL:
383 		if (fun_inline)
384 			break;
385 		/* FALLTHROUGH */
386 	default:
387 		cerror("fix stab_newsym; class %d", s->sclass);
388 	}
389 }
390 
391 void
392 stabs_chgsym(struct symtab *s)
393 {
394 }
395 
396 /*
397  * define a struct.
398  */
399 void
400 stabs_struct(struct symtab *p, struct attr *ap)
401 {
402 }
403 
404 struct stabsv {
405 	SLIST_ENTRY(stabsv) next;
406 	char *str;
407 } ;
408 static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
409 
410 /*
411  * Global variable debug info is printed out directly.
412  * For functions and their declarations, both the labels and
413  * the debug info is put into ASM nodes and follows their statements
414  * into pass2.
415  * Due to the possible unsync between pass1 and 2 and where the
416  * stabs info for text is sent over the following syncing is used:
417  * curfun == 0
418  *	print out everything; only data will be.
419  * curfun != 0 && inftn == 0
420  *	save in linked list
421  * curfun != 0 && inftn != 0
422  *	print linked list first, empty it, then arg.
423  */
424 void
425 cprint(int p2, char *fmt, ...)
426 {
427 #define	CPBSZ	200
428 	char buf[CPBSZ];
429 	struct stabsv *w;
430 	va_list ap;
431 	char *str;
432 
433 	if (isinlining)
434 		return; /* XXX do not save any inline functions currently */
435 
436 	va_start(ap, fmt);
437 	if (p2) {
438 		if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ)
439 			werror("stab symbol line too long, truncating");
440 		str = tmpstrdup(buf);
441 		if (inftn == 0) {
442 			w = tmpalloc(sizeof(struct stabsv));
443 			w->str = str;
444 			SLIST_INSERT_LAST(&stpole, w, next);
445 		} else {
446 			if (stpole.q_last != &stpole.q_forw) {
447 				SLIST_FOREACH(w, &stpole, next) {
448 					send_passt(IP_ASM, w->str);
449 				}
450 				SLIST_INIT(&stpole);
451 			}
452 			send_passt(IP_ASM, str);
453 		}
454 	} else
455 		vprintf(fmt, ap);
456 	va_end(ap);
457 }
458 
459 #endif
460