1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 1996-2002 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <limits.h>
30#include <stdarg.h>
31#include <stdio.h>
32
33#include "stabs.h"
34
35static struct tdesc *hash_table[BUCKETS];
36static struct tdesc *name_table[BUCKETS];
37
38static void reset(void);
39static jmp_buf	resetbuf;
40
41static char *get_line(void);
42static void parseline(char *cp);
43static char *soudef(char *cp, enum type type, struct tdesc **rtdp);
44static void enumdef(char *cp, struct tdesc **rtdp);
45static int compute_sum(char *w);
46static struct tdesc *lookup(int h);
47
48static char *number(char *cp, int *n);
49static char *name(char *cp, char **w);
50static char *id(char *cp, int *h);
51static char *offsize(char *cp, struct mlist *mlp);
52static char *whitesp(char *cp);
53static void addhash(struct tdesc *tdp, int num);
54static void tagadd(char *w, int h, struct tdesc *tdp);
55static void tagdecl(char *cp, struct tdesc **rtdp, int h, char *w);
56static char *tdefdecl(char *cp, int h, struct tdesc **rtdp);
57static char *intrinsic(char *cp, struct tdesc **rtdp);
58static char *arraydef(char *cp, struct tdesc **rtdp);
59
60static int line_number = 0;
61static int debug_line  = 0;
62static char linebuf[MAXLINE];
63
64extern int debug_level;
65
66static void
67debug(int level, char *cp, char *fmt, ...)
68{
69	va_list ap;
70	char buf[1024];
71	char tmp[32];
72	int i;
73
74	if (level > debug_level)
75		return;
76
77	if (cp != NULL) {
78		for (i = 0; i < 30; i++) {
79			if (cp[i] == '\0')
80				break;
81			if (!iscntrl(cp[i]))
82				tmp[i] = cp[i];
83		}
84		tmp[i] = '\0';
85		(void) sprintf(buf, "%s [cp='%s']\n", fmt, tmp);
86	} else {
87		strcpy(buf, fmt);
88		strcat(buf, "\n");
89	}
90
91	va_start(ap, fmt);
92	(void) vfprintf(stderr, buf, ap);
93	va_end(ap);
94}
95
96
97/* Report unexpected syntax in stabs. */
98static void
99expected(
100	char *who,	/* what function, or part thereof, is reporting */
101	char *what,	/* what was expected */
102	char *where)	/* where we were in the line of input */
103{
104	fprintf(stderr, "%s, input line %d: expecting \"%s\" at \"%s\"\n",
105		who, line_number, what, where);
106	exit(1);
107}
108
109/* Read a line from stdin into linebuf and increment line_number. */
110static char *
111get_line(void)
112{
113	char *cp = fgets(linebuf, MAXLINE, stdin);
114	line_number++;
115
116	/* For debugging, you can set debug_line to a line to stop on. */
117	if (line_number == debug_line) {
118		fprintf(stderr, "Hit debug line number %d\n", line_number);
119		for (;;)
120			sleep(1);
121	}
122	return (cp);
123}
124
125/* Get the continuation of the current input line. */
126static char *
127get_continuation(void)
128{
129	char *cp = get_line();
130	if (!cp) {
131		fprintf(stderr, "expecting continuation line, "
132		    "got end of input\n");
133		exit(1);
134	}
135
136	/* Skip to the quoted stuff. */
137	while (*cp++ != '"')
138		;
139	return (cp);
140}
141
142void
143parse_input(void)
144{
145	char *cp;
146	int i = 0;
147
148	for (i = 0; i < BUCKETS; i++) {
149		hash_table[i] = NULL;
150		name_table[i] = NULL;
151	}
152
153	/*
154	 * get a line at a time from the .s stabs file and parse.
155	 */
156	while ((cp = get_line()) != NULL)
157		parseline(cp);
158}
159
160/*
161 * Parse each line of the .s file (stabs entry) gather meaningful information
162 * like name of type, size, offsets of fields etc.
163 */
164static void
165parseline(char *cp)
166{
167	struct tdesc *tdp;
168	char c, *w;
169	int h, tagdef;
170
171	/*
172	 * setup for reset()
173	 */
174	if (setjmp(resetbuf))
175		return;
176
177	/*
178	 * Look for lines of the form
179	 *	.stabs	"str",n,n,n,n
180	 * The part in '"' is then parsed.
181	 */
182	cp = whitesp(cp);
183#define	STLEN	6
184	debug(2, cp, "parseline");
185	if (strncmp(cp, ".stabs", STLEN) != 0)
186		reset();
187	cp += STLEN;
188#undef STLEN
189	cp = whitesp(cp);
190	if (*cp++ != '"')
191		reset();
192
193	/*
194	 * name:type		variable (ignored)
195	 * name:ttype		typedef
196	 * name:Ttype		struct tag define
197	 */
198	cp = whitesp(cp);
199	cp = name(cp, &w);
200
201	tagdef = 0;
202	switch (c = *cp++) {
203	case 't': /* type */
204		break;
205	case 'T': /* struct, union, enum */
206		tagdef = 1;
207		break;
208	default:
209		reset();
210	}
211
212	/*
213	 * The type id and definition follow.
214	 */
215	cp = id(cp, &h);
216	if (*cp == '"') {
217		struct tdesc *ntdp;
218
219		cp++;
220		ntdp = lookup(h);
221		if (ntdp == NULL) {  /* if that type isn't defined yet */
222			if (*cp++ != '=')  /* better be defining it now */
223				expected("parseline/'0-9'", "=", cp - 1);
224			cp = tdefdecl(cp, h, &tdp);
225			addhash(tdp, h); /* for *(x,y) types */
226		} else { /* that type is already defined */
227			tdp = malloc(sizeof (*tdp));
228			tdp->type = TYPEOF;
229			tdp->name = (w != NULL) ? strdup(w) : NULL;
230			tdp->data.tdesc = ntdp;
231			addhash(tdp, h); /* for *(x,y) types */
232			debug(3, NULL, "    %s defined as %s(%d)", w,
233			    (ntdp->name != NULL) ? ntdp->name : "anon", h);
234		}
235		return;
236	} else if (*cp++ != '=') {
237		expected("parseline", "=", cp - 1);
238	}
239	if (tagdef) {
240		tagdecl(cp, &tdp, h, w);
241	} else {
242		tdefdecl(cp, h, &tdp);
243		tagadd(w, h, tdp);
244	}
245}
246
247/*
248 * Check if we have this node in the hash table already
249 */
250static struct tdesc *
251lookup(int h)
252{
253	int hash = HASH(h);
254	struct tdesc *tdp = hash_table[hash];
255
256	while (tdp != NULL) {
257		if (tdp->id == h)
258			return (tdp);
259		tdp = tdp->hash;
260	}
261	return (NULL);
262}
263
264static char *
265whitesp(char *cp)
266{
267	char *orig, c;
268
269	orig = cp;
270	for (c = *cp++; isspace(c); c = *cp++)
271		;
272	--cp;
273	return (cp);
274}
275
276static char *
277name(char *cp, char **w)
278{
279	char *new, *orig, c;
280	int len;
281
282	orig = cp;
283	c = *cp++;
284	if (c == ':')
285		*w = NULL;
286	else if (isalpha(c) || c == '_') {
287		for (c = *cp++; isalnum(c) || c == ' ' || c == '_'; c = *cp++)
288			;
289		if (c != ':')
290			reset();
291		len = cp - orig;
292		new = malloc(len);
293		while (orig < cp - 1)
294			*new++ = *orig++;
295		*new = '\0';
296		*w = new - (len - 1);
297	} else
298		reset();
299
300	return (cp);
301}
302
303static char *
304number(char *cp, int *n)
305{
306	char *next;
307
308	*n = (int)strtol(cp, &next, 10);
309	if (next == cp)
310		expected("number", "<number>", cp);
311	return (next);
312}
313
314static char *
315id(char *cp, int *h)
316{
317	int n1, n2;
318
319	if (*cp == '(') {	/* SunPro style */
320		cp++;
321		cp = number(cp, &n1);
322		if (*cp++ != ',')
323			expected("id", ",", cp - 1);
324		cp = number(cp, &n2);
325		if (*cp++ != ')')
326			expected("id", ")", cp - 1);
327		*h = n1 * 1000 + n2;
328	} else if (isdigit(*cp)) { /* gcc style */
329		cp = number(cp, &n1);
330		*h = n1;
331	} else {
332		expected("id", "(/0-9", cp);
333	}
334	return (cp);
335}
336
337static void
338tagadd(char *w, int h, struct tdesc *tdp)
339{
340	struct tdesc *otdp;
341
342	tdp->name = w;
343	if (!(otdp = lookup(h)))
344		addhash(tdp, h);
345	else if (otdp != tdp) {
346		fprintf(stderr, "duplicate entry\n");
347		fprintf(stderr, "old: %s %d %d %d\n",
348		    otdp->name ? otdp->name : "NULL",
349		    otdp->type, otdp->id / 1000, otdp->id % 1000);
350		fprintf(stderr, "new: %s %d %d %d\n",
351		    tdp->name ? tdp->name : "NULL",
352		    tdp->type, tdp->id / 1000, tdp->id % 1000);
353	}
354}
355
356static void
357tagdecl(char *cp, struct tdesc **rtdp, int h, char *w)
358{
359	debug(1, NULL, "tagdecl: declaring '%s'", w ? w : "(anon)");
360	if ((*rtdp = lookup(h)) != NULL) {
361		if (w != NULL) {
362			if ((*rtdp)->name != NULL &&
363			    strcmp((*rtdp)->name, w) != 0) {
364				struct tdesc *tdp;
365
366				tdp = malloc(sizeof (*tdp));
367				tdp->name = strdup(w);
368				tdp->type = TYPEOF;
369				tdp->data.tdesc = *rtdp;
370				addhash(tdp, h); /* for *(x,y) types */
371				debug(3, NULL, "    %s defined as %s(%d)", w,
372				    ((*rtdp)->name != NULL) ?
373				    (*rtdp)->name : "anon", h);
374			} else if ((*rtdp)->name == NULL) {
375				(*rtdp)->name = w;
376				addhash(*rtdp, h);
377			}
378		}
379	} else {
380		*rtdp = malloc(sizeof (**rtdp));
381		(*rtdp)->name = w;
382		addhash(*rtdp, h);
383	}
384
385	switch (*cp++) {
386	case 's':
387		soudef(cp, STRUCT, rtdp);
388		break;
389	case 'u':
390		soudef(cp, UNION, rtdp);
391		break;
392	case 'e':
393		enumdef(cp, rtdp);
394		break;
395	default:
396		expected("tagdecl", "<tag type s/u/e>", cp - 1);
397		break;
398	}
399}
400
401static char *
402tdefdecl(char *cp, int h, struct tdesc **rtdp)
403{
404	struct tdesc *ntdp;
405	char *w;
406	int c, h2;
407	char type;
408
409	debug(3, cp, "tdefdecl h=%d", h);
410
411	/* Type codes */
412	switch (type = *cp) {
413	case 'b': /* integer */
414		c = *++cp;
415		if (c != 's' && c != 'u')
416			expected("tdefdecl/b", "[su]", cp - 1);
417		c = *++cp;
418		if (c == 'c')
419			cp++;
420		cp = intrinsic(cp, rtdp);
421		break;
422	case 'R': /* fp */
423		/* skip up to and past ';' */
424		while (*cp++ != ';')
425			/* NULL */;
426		cp = intrinsic(cp, rtdp);
427		break;
428	case '(': /* equiv to another type */
429		cp = id(cp, &h2);
430		ntdp = lookup(h2);
431		if (ntdp == NULL) {  /* if that type isn't defined yet */
432			if (*cp++ != '=')  /* better be defining it now */
433				expected("tdefdecl/'('", "=", cp - 1);
434			cp = tdefdecl(cp, h2, rtdp);
435			ntdp = malloc(sizeof (*ntdp));
436			ntdp->type = TYPEOF;
437			ntdp->data.tdesc = *rtdp;
438			addhash(ntdp, h2);
439		} else { /* that type is already defined */
440			*rtdp = malloc(sizeof (**rtdp));
441			(*rtdp)->type = TYPEOF;
442			(*rtdp)->data.tdesc = ntdp;
443		}
444		break;
445	case '*':
446		ntdp = NULL;
447		cp = tdefdecl(cp + 1, h, &ntdp);
448		if (ntdp == NULL)
449			expected("tdefdecl/*", "id", cp);
450
451		*rtdp = malloc(sizeof (**rtdp));
452		(*rtdp)->type = POINTER;
453		(*rtdp)->size = model->pointersize;
454		(*rtdp)->name = "pointer";
455		(*rtdp)->data.tdesc = ntdp;
456		break;
457	case 'f':
458		cp = tdefdecl(cp + 1, h, &ntdp);
459		*rtdp = malloc(sizeof (**rtdp));
460		(*rtdp)->type = FUNCTION;
461		(*rtdp)->size = model->pointersize;
462		(*rtdp)->name = "function";
463		(*rtdp)->data.tdesc = ntdp;
464		break;
465	case 'a':
466		cp++;
467		if (*cp++ != 'r')
468			expected("tdefdecl/a", "r", cp - 1);
469		*rtdp = malloc(sizeof (**rtdp));
470		(*rtdp)->type = ARRAY;
471		(*rtdp)->name = "array";
472		cp = arraydef(cp, rtdp);
473		break;
474	case 'x':
475		c = *++cp;
476		if (c != 's' && c != 'u' && c != 'e')
477			expected("tdefdecl/x", "[sue]", cp - 1);
478		cp = name(cp + 1, &w);
479		*rtdp = malloc(sizeof (**rtdp));
480		(*rtdp)->type = FORWARD;
481		(*rtdp)->name = w;
482		break;
483	case 'B': /* volatile */
484		cp = tdefdecl(cp + 1, h, &ntdp);
485		*rtdp = malloc(sizeof (**rtdp));
486		(*rtdp)->type = VOLATILE;
487		(*rtdp)->size = 0;
488		(*rtdp)->name = "volatile";
489		(*rtdp)->data.tdesc = ntdp;
490		break;
491	case 'k': /* const */
492		cp = tdefdecl(cp + 1, h, &ntdp);
493		*rtdp = malloc(sizeof (**rtdp));
494		(*rtdp)->type = CONST;
495		(*rtdp)->size = 0;
496		(*rtdp)->name = "const";
497		(*rtdp)->data.tdesc = ntdp;
498		break;
499	case '0': case '1': case '2': case '3':	case '4':
500	case '5': case '6': case '7': case '8': case '9':
501		/* gcc equiv to another type */
502		cp = id(cp, &h2);
503		ntdp = lookup(h2);
504		if (ntdp == NULL) {  /* if that type isn't defined yet */
505			/* better be defining it now */
506			if (*cp++ != '=') {
507				if (h != h2)
508					expected("tdefdecl/'0-9'", "=", cp - 1);
509				/* defined in terms of itself */
510				*rtdp = malloc(sizeof (**rtdp));
511				(*rtdp)->type = INTRINSIC;
512				(*rtdp)->name = "void";
513				(*rtdp)->size = 0;
514			} else {
515				cp = tdefdecl(cp, h2, rtdp);
516				ntdp = malloc(sizeof (*ntdp));
517				ntdp->type = TYPEOF;
518				ntdp->data.tdesc = *rtdp;
519				addhash(ntdp, h2);
520			}
521		} else { /* that type is already defined */
522			*rtdp = malloc(sizeof (**rtdp));
523			(*rtdp)->type = TYPEOF;
524			(*rtdp)->data.tdesc = ntdp;
525		}
526		break;
527	case 'u':
528	case 's':
529		cp++;
530
531		*rtdp = malloc(sizeof (**rtdp));
532		(*rtdp)->name = NULL;
533		cp = soudef(cp, (type == 'u') ? UNION : STRUCT, rtdp);
534		break;
535	default:
536		expected("tdefdecl", "<type code>", cp);
537	}
538	return (cp);
539}
540
541static char *
542intrinsic(char *cp, struct tdesc **rtdp)
543{
544	struct tdesc *tdp;
545	int size;
546
547	cp = number(cp, &size);
548	tdp = malloc(sizeof (*tdp));
549	tdp->type = INTRINSIC;
550	tdp->size = size;
551	tdp->name = NULL;
552	debug(3, NULL, "intrinsic: size=%ld", size);
553	*rtdp = tdp;
554	return (cp);
555}
556
557static char *
558soudef(char *cp, enum type type, struct tdesc **rtdp)
559{
560	struct mlist **next_pp, *prev_p = NULL;
561	char *w;
562	int size;
563	struct tdesc *tdp;
564
565	cp = number(cp, &size);
566	(*rtdp)->size = size;
567	(*rtdp)->type = type; /* s or u */
568
569	/*
570	 * An '@' here indicates a bitmask follows.   This is so the
571	 * compiler can pass information to debuggers about how structures
572	 * are passed in the v9 world.  We don't need this information
573	 * so we skip over it.
574	 */
575	if (cp[0] == '@')
576		cp += 3;
577
578	debug(3, cp, "soudef: %s size=%d",
579	    (*rtdp)->name ? (*rtdp)->name : "(anonsou)",
580	    (*rtdp)->size);
581
582	next_pp = &((*rtdp)->data.members.forw); /* head for forward linklist */
583	/* fill up the fields */
584	while ((*cp != '"') && (*cp != ';')) { /* signifies end of fields */
585		int h;
586		struct mlist *mlp = malloc(sizeof (*mlp));
587
588		mlp->prev = prev_p;	/* links for the backward list */
589		prev_p = mlp;
590		*next_pp = mlp;		/* links for the forward list */
591		next_pp = &mlp->next;
592
593		cp = name(cp, &w);
594		mlp->name = w;
595		cp = id(cp, &h);
596		/*
597		 * find the tdesc struct in the hash table for this type
598		 * and stick a ptr in here
599		 */
600		tdp = lookup(h);
601		if (tdp == NULL) { /* not in hash list */
602			debug(3, NULL, "      defines %s (%d)", w, h);
603			if (*cp++ != '=')
604				expected("soudef", "=", cp - 1);
605			cp = tdefdecl(cp, h, &tdp);
606			addhash(tdp, h);
607			debug(4, cp, "     soudef now looking at    ");
608			cp++;
609
610		} else {
611			debug(3, NULL, "      refers to %s (%d, %s)",
612			    w ? w : "anon", h, tdp->name ? tdp->name : "anon");
613		}
614
615		mlp->fdesc = tdp;
616		cp = offsize(cp, mlp);	/* cp is now pointing to next field */
617		if (*cp == '\\')	/* could be a continuation */
618			cp = get_continuation();
619	}
620	(*rtdp)->data.members.back = prev_p;	/* head for backward linklist */
621	return (cp);
622}
623
624static char *
625offsize(char *cp, struct mlist *mlp)
626{
627	int offset, size;
628
629	if (*cp == ',')
630		cp++;
631	cp = number(cp, &offset);
632	if (*cp++ != ',')
633		expected("offsize/2", ",", cp - 1);
634	cp = number(cp, &size);
635	if (*cp++ != ';')
636		expected("offsize/3", ";", cp - 1);
637	mlp->offset = offset;
638	mlp->size = size;
639	return (cp);
640}
641
642static char *
643arraydef(char *cp, struct tdesc **rtdp)
644{
645	int h;
646	int start, end;
647
648	cp = id(cp, &h);
649	if (*cp++ != ';')
650		expected("arraydef/1", ";", cp - 1);
651
652	(*rtdp)->data.ardef = malloc(sizeof (struct ardef));
653	(*rtdp)->data.ardef->indices = malloc(sizeof (struct element));
654	(*rtdp)->data.ardef->indices->index_type = lookup(h);
655
656	cp = number(cp, &start); /* lower */
657	if (*cp++ != ';')
658		expected("arraydef/2", ";", cp - 1);
659	cp = number(cp, &end);	/* upper */
660	if (*cp++ != ';')
661		expected("arraydef/3", ";", cp - 1);
662	(*rtdp)->data.ardef->indices->range_start = start;
663	(*rtdp)->data.ardef->indices->range_end = end;
664#if 0
665	if (isdigit(*cp)) {
666		cp = number(cp, &contents_type); /* lower */
667		tdp = lookup(contents_type);
668		if (tdp != NULL) {
669			(*rtdp)->data.ardef->contents = tdp;
670		} else {
671			if (*cp != '=')
672				expected("arraydef/4", "=", cp);
673			cp = tdefdecl(cp + 1, h, &tdp);
674			addhash(tdp, h); /* for *(x,y) types */
675			(*rtdp)->data.ardef->contents = tdp;
676		}
677	} /* else  */
678#endif
679	cp = tdefdecl(cp, h, &((*rtdp)->data.ardef->contents));
680	return (cp);
681}
682
683static void
684enumdef(char *cp, struct tdesc **rtdp)
685{
686	struct elist *elp, **prev;
687	char *w;
688
689	(*rtdp)->type = ENUM;
690	(*rtdp)->data.emem = NULL;
691
692	prev = &((*rtdp)->data.emem);
693	while (*cp != ';') {
694		elp = malloc(sizeof (*elp));
695		elp->next = NULL;
696		*prev = elp;
697		cp = name(cp, &w);
698		elp->name = w;
699		cp = number(cp, &elp->number);
700		debug(3, NULL, "enum %s: %s=%ld",
701		    (*rtdp)->name ? (*rtdp)->name : "(anon enum)",
702		    elp->name, elp->number);
703		prev = &elp->next;
704		if (*cp++ != ',')
705			expected("enumdef", ",", cp - 1);
706		if (*cp == '\\')
707			cp = get_continuation();
708	}
709}
710
711/*
712 * Add a node to the hash queues.
713 */
714static void
715addhash(struct tdesc *tdp, int num)
716{
717	int hash = HASH(num);
718	struct tdesc *ttdp;
719	char added_num = 0, added_name = 0;
720
721	/*
722	 * If it already exists in the hash table don't add it again
723	 * (but still check to see if the name should be hashed).
724	 */
725	ttdp = lookup(num);
726	if (ttdp == NULL) {
727		tdp->id = num;
728		tdp->hash = hash_table[hash];
729		hash_table[hash] = tdp;
730		added_num = 1;
731	}
732
733	if (tdp->name != NULL) {
734		ttdp = lookupname(tdp->name);
735		if (ttdp == NULL) {
736			hash = compute_sum(tdp->name);
737			tdp->next = name_table[hash];
738			name_table[hash] = tdp;
739			added_name = 1;
740		}
741	}
742	if (!added_num && !added_name) {
743		fprintf(stderr, "stabs: broken hash\n");
744		exit(1);
745	}
746}
747
748struct tdesc *
749lookupname(char *name)
750{
751	int hash = compute_sum(name);
752	struct tdesc *tdp, *ttdp = NULL;
753
754	for (tdp = name_table[hash]; tdp != NULL; tdp = tdp->next) {
755		if (tdp->name != NULL && strcmp(tdp->name, name) == 0) {
756			if (tdp->type == STRUCT || tdp->type == UNION ||
757			    tdp->type == ENUM || tdp->type == INTRINSIC)
758				return (tdp);
759			if (tdp->type == TYPEOF)
760				ttdp = tdp;
761		}
762	}
763	return (ttdp);
764}
765
766static int
767compute_sum(char *w)
768{
769	char c;
770	int sum;
771
772	for (sum = 0; (c = *w) != '\0'; sum += c, w++)
773		;
774	return (HASH(sum));
775}
776
777static void
778reset(void)
779{
780	longjmp(resetbuf, 1);
781	/* NOTREACHED */
782}
783