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