1/*	Id: stabs.c,v 1.33 2012/03/22 18:04:41 plunky Exp 	*/
2/*	$NetBSD: stabs.c,v 1.1.1.5 2012/03/26 14:26: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 */
74static 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];
81static int ntypes;
82static char *curfun;
83static int stablbl = 10;
84extern int inftn;
85
86void ptype(char *name, int num, int inhnum, long long min, long long max);
87struct stabtype *addtype(TWORD, union dimfun *, struct attr *);
88struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue);
89void printtype(struct symtab *s, char *str, int len);
90void cprint(int p2, char *fmt, ...);
91
92#define	MAXPSTR	100
93
94extern int isinlining;
95
96/*
97 * Output type definitions for the stab debugging format.
98 * Note that "int" is always internal number 1.
99 */
100void
101stabs_init()
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 */
134void
135ptype(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 */
145struct stabtype *
146addtype(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 */
163struct stabtype *
164findtype(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 */
197void
198stabs_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 */
215void
216stabs_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 */
231void
232stabs_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
244static char *mainfile;
245
246/*
247 * Print current file and set mark.
248 */
249void
250stabs_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 */
262void
263stabs_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 */
273void
274stabs_func(struct symtab *s)
275{
276	char str[MAXPSTR];
277
278	if ((curfun = s->soname) == NULL)
279		curfun = addname(exname(s->sname));
280	printtype(s, str, sizeof(str));
281	cprint(1, "\t.stabs	\"%s:%c%s\",%d,0,%d,%s\n",
282	    curfun, s->sclass == STATIC ? 'f' : 'F', str,
283	    N_FUN, 0, curfun);
284}
285
286/*
287 * Print a (complex) type.
288 * Will also create subtypes.
289 * Printed string is like "20=*21=*1".
290 */
291void
292printtype(struct symtab *s, char *ostr, int len)
293{
294	struct stabtype *st;
295	union dimfun *df = s->sdf;
296	struct attr *ap = s->sap;
297	TWORD t = s->stype;
298	int op = 0;
299
300	/* Print out not-yet-found types */
301	if (ISFTN(t))
302		t = DECREF(t);
303	st = findtype(t, df, ap);
304	while (st == NULL && t > BTMASK) {
305		st = addtype(t, df, ap);
306		op+=snprintf(ostr+op, len - op, "%d=", st->num);
307		if (ISFTN(t))
308			ostr[op++] = 'f';
309		else if (ISPTR(t))
310			ostr[op++] = '*';
311		else if (ISARY(t)) {
312			op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1);
313		} else
314			cerror("printtype: notype");
315		if (ISARY(t))
316			df++;
317		t = DECREF(t);
318		st = findtype(t, df, ap);
319		if (op > MAXPSTR-10)
320			cerror("printtype: too difficult expression");
321	}
322	/* print out basic type. may have to be entered in case of sue */
323	snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num);
324	/* snprintf here null-terminated the string */
325}
326
327void
328stabs_newsym(struct symtab *s)
329{
330	extern int fun_inline;
331	char *sname;
332	char ostr[MAXPSTR];
333	OFFSZ suesize, sz;
334
335	if (ISFTN(s->stype))
336		return; /* functions are handled separate */
337
338	if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS ||
339	    s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE ||
340	    s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype))
341		return; /* XXX - fix structs */
342
343	if ((sname = s->soname) == NULL)
344		sname = exname(s->sname);
345	sz = tsize(s->stype, s->sdf, s->sap);
346	suesize = BIT2BYTE(sz);
347	if (suesize > 32767)
348		suesize = 32767;
349	else if (suesize < -32768)
350		suesize = -32768;
351
352	printtype(s, ostr, sizeof(ostr));
353	switch (s->sclass) {
354	case PARAM:
355		cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n",
356		    sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
357		break;
358
359	case AUTO:
360		cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n",
361		    sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset));
362		break;
363
364	case STATIC:
365		if (blevel)
366			cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n",
367			    sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset);
368		else
369			cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n",
370			    sname, ostr, N_LCSYM, (CONSZ)suesize, sname);
371		break;
372
373	case EXTERN:
374	case EXTDEF:
375		cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n",
376		    sname, ostr, N_GSYM, (CONSZ)suesize);
377		break;
378
379	case REGISTER:
380		cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n",
381		    sname, ostr, N_RSYM, 1, s->soffset);
382		break;
383
384	case SNULL:
385		if (fun_inline)
386			break;
387		/* FALLTHROUGH */
388	default:
389		cerror("fix stab_newsym; class %d", s->sclass);
390	}
391}
392
393void
394stabs_chgsym(struct symtab *s)
395{
396}
397
398/*
399 * define a struct.
400 */
401void
402stabs_struct(struct symtab *p, struct attr *ap)
403{
404}
405
406struct stabsv {
407	SLIST_ENTRY(stabsv) next;
408	char *str;
409} ;
410static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw };
411
412/*
413 * Global variable debug info is printed out directly.
414 * For functions and their declarations, both the labels and
415 * the debug info is put into ASM nodes and follows their statements
416 * into pass2.
417 * Due to the possible unsync between pass1 and 2 and where the
418 * stabs info for text is sent over the following syncing is used:
419 * curfun == 0
420 *	print out everything; only data will be.
421 * curfun != 0 && inftn == 0
422 *	save in linked list
423 * curfun != 0 && inftn != 0
424 *	print linked list first, empty it, then arg.
425 */
426void
427cprint(int p2, char *fmt, ...)
428{
429#define	CPBSZ	200
430	char buf[CPBSZ];
431	struct stabsv *w;
432	va_list ap;
433	char *str;
434
435	if (isinlining)
436		return; /* XXX do not save any inline functions currently */
437
438	va_start(ap, fmt);
439	if (p2) {
440		if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ)
441			werror("stab symbol line too long, truncating");
442		str = tmpstrdup(buf);
443		if (inftn == 0) {
444			w = tmpalloc(sizeof(struct stabsv));
445			w->str = str;
446			SLIST_INSERT_LAST(&stpole, w, next);
447		} else {
448			if (stpole.q_last != &stpole.q_forw) {
449				SLIST_FOREACH(w, &stpole, next) {
450					send_passt(IP_ASM, w->str);
451				}
452				SLIST_INIT(&stpole);
453			}
454			send_passt(IP_ASM, str);
455		}
456	} else
457		vprintf(fmt, ap);
458	va_end(ap);
459}
460
461#endif
462