xref: /illumos-gate/usr/src/tools/stabs/main.c (revision 7c478bd9)
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 <unistd.h>
30 #include <math.h>
31 #include <stdlib.h>
32 #include "stabs.h"
33 
34 int debug_level = 0;
35 int line;
36 
37 boolean_t error = B_FALSE;
38 char *program = NULL;
39 
40 extern void forth_do_sou(struct tdesc *, struct node *);
41 extern void forth_do_enum(struct tdesc *, struct node *);
42 extern void forth_do_intrinsic(struct tdesc *, struct node *);
43 extern void genassym_do_sou(struct tdesc *, struct node *);
44 extern void genassym_do_enum(struct tdesc *, struct node *);
45 extern void genassym_do_intrinsic(struct tdesc *, struct node *);
46 extern void squander_do_sou(struct tdesc *, struct node *);
47 extern void squander_do_enum(struct tdesc *, struct node *);
48 extern void squander_do_intrinsic(struct tdesc *, struct node *);
49 
50 struct model_info models[] = {
51 	{ "ilp32", 4, 1, 2, 4, 4 },
52 	{ "lp64",  8, 1, 2, 4, 8 },
53 	{ NULL, 0, 0, 0 }
54 };
55 
56 struct stab_ops {
57 	char *type;
58 	void (*do_sou)(struct tdesc *, struct node *);
59 	void (*do_enum)(struct tdesc *, struct node *);
60 	void (*do_intrinsic)(struct tdesc *, struct node *);
61 } ops_table[] = {
62 	{ "forth",
63 	    forth_do_sou, forth_do_enum, forth_do_intrinsic },
64 	{ "genassym",
65 	    genassym_do_sou, genassym_do_enum, genassym_do_intrinsic },
66 	{ "squander",
67 	    squander_do_sou, squander_do_enum, squander_do_intrinsic },
68 	{ NULL, NULL, NULL }
69 };
70 
71 static void get_dbgs(int argc, char **argv);
72 static void parse_dbg(FILE *sp);
73 static void printnode(struct node *np);
74 static struct tdesc *find_member(struct tdesc *tdp, char *name);
75 static char *namex(char *cp, char **w);
76 static void addchild(char *cp, struct node *np);
77 static struct node *getnode(char *cp);
78 
79 struct stab_ops *ops;
80 struct model_info *model;
81 
82 int
main(int argc,char ** argv)83 main(int argc, char **argv)
84 {
85 	char *output_type = NULL;
86 	char *model_name = NULL;
87 	int c;
88 
89 	program = strrchr(argv[0], '/');
90 	if (program != NULL)
91 		program++;
92 	else
93 		program = argv[0];
94 
95 	/* defaults */
96 	output_type = "forth";
97 	model_name = "ilp32";
98 
99 	while (!error && ((c = getopt(argc, argv, "dt:m:")) != EOF)) {
100 		switch (c) {
101 		case 't':
102 			output_type = optarg;
103 			break;
104 		case 'm':
105 			model_name = optarg;
106 			break;
107 		case 'd':
108 			debug_level++;
109 			break;
110 		case '?':
111 		default:
112 			error = B_TRUE;
113 			break;
114 		}
115 	}
116 
117 	if (!error) {
118 		/*
119 		 * Find ops for the specified output type
120 		 */
121 		for (ops = ops_table; ops->type != NULL; ops++) {
122 			if (strcmp(ops->type, output_type) == 0)
123 				break;
124 		}
125 		if (ops->type == NULL)
126 			error = B_TRUE;
127 	}
128 
129 	if (!error) {
130 		/*
131 		 * Find model characteristics
132 		 */
133 		for (model = models; model->name != NULL; model++) {
134 			if (strcmp(model->name, model_name) == 0)
135 				break;
136 		}
137 		if (model->name == NULL)
138 			error = B_TRUE;
139 	}
140 
141 	/* skip over previously processed arguments */
142 	argc -= optind;
143 	argv += optind;
144 	if (argc < 1)
145 		error = B_TRUE;
146 
147 	if (error) {
148 		fprintf(stderr, "Usage: %s [-d] {-m datamodel} "
149 		    "{-t output_type} files\n", program);
150 		fprintf(stderr, "\tSupported data models:\n");
151 		for (model = models; model->name != NULL; model++)
152 			fprintf(stderr, "\t\t%s\n", model->name);
153 		fprintf(stderr, "\tSupported output types:\n");
154 		for (ops = ops_table; ops->type != NULL; ops++)
155 			fprintf(stderr, "\t\t%s\n", ops->type);
156 		return (1);
157 	}
158 
159 	parse_input();
160 
161 	get_dbgs(argc, argv);
162 
163 	return (error ? 1 : 0);
164 }
165 
166 /*
167  * This routine will read the .dbg files and build a list of the structures
168  * and fields that user is interested in. Any struct specified will get all
169  * its fields included. If nested struct needs to be printed - then the
170  * field name and name of struct type needs to be included in the next line.
171  */
172 static void
get_dbgs(int argc,char ** argv)173 get_dbgs(int argc, char **argv)
174 {
175 	FILE *fp;
176 
177 	for (; argc != 0; argc--, argv++) {
178 		if ((fp = fopen(*argv, "r")) == NULL) {
179 			fprintf(stderr, "Cannot open %s\n", *argv);
180 			error = B_TRUE;
181 			return;
182 		}
183 		/* add all types in this file to our table */
184 		parse_dbg(fp);
185 	}
186 }
187 
188 static char *
namex(char * cp,char ** w)189 namex(char *cp, char **w)
190 {
191 	char *new, *orig, c;
192 	int len;
193 
194 	if (*cp == '\0') {
195 		*w = NULL;
196 		return (cp);
197 	}
198 
199 	for (c = *cp++; isspace(c); c = *cp++)
200 		;
201 	orig = --cp;
202 	c = *cp++;
203 	if (isalpha(c) || ispunct(c)) {
204 		for (c = *cp++; isalnum(c) || ispunct(c); c = *cp++)
205 			;
206 		len = cp - orig;
207 		new = (char *)malloc(len);
208 		while (orig < cp - 1)
209 			*new++ = *orig++;
210 		*new = '\0';
211 		*w = new - (len - 1);
212 	} else if (c != '\0') {
213 		fprintf(stderr, "line %d has bad character %c\n", line, c);
214 		error = B_TRUE;
215 	}
216 
217 	return (cp);
218 }
219 
220 /*
221  * checks to see if this field in the struct was requested for by user
222  * in the .dbg file.
223  */
224 struct child *
find_child(struct node * np,char * w)225 find_child(struct node *np, char *w)
226 {
227 	struct child *chp;
228 
229 	for (chp = np->child; chp != NULL; chp = chp->next) {
230 		if (strcmp(chp->name, w) == 0)
231 			return (chp);
232 	}
233 	return (NULL);
234 }
235 
236 static struct tdesc *
find_member(struct tdesc * tdp,char * name)237 find_member(struct tdesc *tdp, char *name)
238 {
239 	struct mlist *mlp;
240 
241 	while (tdp->type == TYPEOF)
242 		tdp = tdp->data.tdesc;
243 	if (tdp->type != STRUCT && tdp->type != UNION)
244 		return (NULL);
245 	for (mlp = tdp->data.members.forw; mlp != NULL; mlp = mlp->next)
246 		if (strcmp(mlp->name, name) == 0)
247 			return (mlp->fdesc);
248 	return (NULL);
249 }
250 
251 /*
252  * add this field to our table of structs/fields that the user has
253  * requested in the .dbg files
254  */
255 static void
addchild(char * cp,struct node * np)256 addchild(char *cp, struct node *np)
257 {
258 	struct child *chp;
259 	char *w;
260 
261 	chp = malloc(sizeof (*chp));
262 	cp = namex(cp, &w);
263 	chp->name = w;
264 	cp = namex(cp, &w);
265 	if (w == NULL) {
266 		if (chp->name == NULL) {
267 			fprintf(stderr, "NULL child name\n");
268 			exit(1);
269 		}
270 		/* XXX - always convert to upper-case? */
271 		chp->format = uc(chp->name);
272 	} else {
273 		chp->format = w;
274 	}
275 	chp->next = np->child;
276 	np->child = chp;
277 }
278 
279 /*
280  * add this struct to our table of structs/fields that the user has
281  * requested in the .dbg files
282  */
283 static struct node *
getnode(char * cp)284 getnode(char *cp)
285 {
286 	char *w;
287 	struct node *np;
288 
289 	cp = namex(cp, &w);
290 	np = malloc(sizeof (*np));
291 	np->name = w;
292 
293 	/*
294 	 * XXX - These positional parameters are a hack
295 	 * We have two right now for genassym.  The back-ends
296 	 * can use format and format2 any way they'd like.
297 	 */
298 	cp = namex(cp, &w);
299 	np->format = w;
300 	if (w != NULL) {
301 		w = NULL;
302 		cp = namex(cp, &w);
303 		np->format2 = w;
304 	} else {
305 		np->format2 = NULL;
306 	}
307 	np->child = NULL;
308 	return (np);
309 }
310 
311 /*
312  * Format for .dbg files should be
313  * Ex:
314  * seg
315  *	as		s_as
316  * if you wanted the contents of "s_as" (a pointer) to be printed in
317  * the format of a "as"
318  */
319 static void
parse_dbg(FILE * sp)320 parse_dbg(FILE *sp)
321 {
322 	char *cp;
323 	struct node *np;
324 	static char linebuf[MAXLINE];
325 	int copy_flag = 0;
326 	int ignore_flag = 0;
327 	size_t c;
328 
329 	/* grab each line and add them to our table */
330 	for (line = 1; (cp = fgets(linebuf, MAXLINE, sp)) != NULL; line++) {
331 		if (*cp == '\n') {
332 			if (copy_flag)
333 				printf("\n");
334 			continue;
335 		}
336 		if (*cp == '\\') {
337 			if (cp[1] == '#')
338 				printf("%s", (cp + 1));
339 			continue;
340 		}
341 		if (strcmp(cp, "model_end\n") == 0) {
342 			if (ignore_flag)
343 				ignore_flag = 0;
344 			continue;
345 		}
346 		if (ignore_flag)
347 			continue;
348 		c = strlen("model_start ");
349 		if (strncmp(cp, "model_start ", c) == 0) {
350 			if (strncmp(cp + c, model->name, strlen(model->name))
351 			    == 0 && *(cp + c + strlen(model->name)) == '\n')
352 				/* model matches */;
353 			else
354 				ignore_flag = 1;
355 			continue;
356 		}
357 		if ((strcmp(cp, "verbatim_begin\n") == 0) ||
358 		    (strcmp(cp, "forth_start\n") == 0)) {
359 			copy_flag = 1;
360 			continue;
361 		}
362 		if ((strcmp(cp, "verbatim_end\n") == 0) ||
363 		    (strcmp(cp, "forth_end\n") == 0)) {
364 			copy_flag = 0;
365 			continue;
366 		}
367 		if (copy_flag) {
368 			printf("%s", cp);
369 			continue;
370 		}
371 		np = getnode(cp);
372 		for (line++;
373 		    ((cp = fgets(linebuf, MAXLINE, sp)) != NULL) &&
374 			 *cp != '\n'; line++) {
375 			/* members of struct, union or enum */
376 			addchild(cp, np);
377 		}
378 		printnode(np);
379 	}
380 }
381 
382 static void
printnode(struct node * np)383 printnode(struct node *np)
384 {
385 	struct tdesc *tdp;
386 
387 	tdp = lookupname(np->name);
388 	if (tdp == NULL) {
389 		char *member;
390 		struct tdesc *ptdp;
391 
392 		if ((member = strchr(np->name, '.')) != NULL) {
393 			*member = '\0';
394 			ptdp = lookupname(np->name);
395 			if (ptdp != NULL)
396 				tdp = find_member(ptdp, member + 1);
397 			*member = '.';
398 		}
399 		if (tdp == NULL) {
400 			fprintf(stderr, "Can't find %s\n", np->name);
401 			error = B_TRUE;
402 			return;
403 		}
404 	}
405 again:
406 	switch (tdp->type) {
407 	case STRUCT:
408 	case UNION:
409 		ops->do_sou(tdp, np);
410 		break;
411 	case ENUM:
412 		ops->do_enum(tdp, np);
413 		break;
414 	case TYPEOF:
415 		tdp = tdp->data.tdesc;
416 		goto again;
417 	case INTRINSIC:
418 		ops->do_intrinsic(tdp, np);
419 		break;
420 	default:
421 		fprintf(stderr, "%s isn't aggregate\n", np->name);
422 		error = B_TRUE;
423 		break;
424 	}
425 }
426 
427 
428 char *
convert_format(char * format,char * dfault)429 convert_format(char *format, char *dfault)
430 {
431 	static char dot[3] = ".";
432 
433 	if (format == NULL)
434 		return (dfault);
435 	else if (strlen(format) == 1) {
436 		dot[1] = *format;
437 		return (dot);
438 	} else
439 		return (format);
440 }
441 
442 char *
uc(const char * s)443 uc(const char *s)
444 {
445 	char *buf;
446 	int i;
447 
448 	buf = strdup(s);
449 	for (i = 0; i < strlen(buf); i++)
450 		buf[i] = toupper(buf[i]);
451 	buf[i] = '\0';
452 	return (buf);
453 }
454