xref: /illumos-gate/usr/src/cmd/adbgen/common/adbgen1.c (revision 942c5e3c2dd127463517e5cc1694ee94ca45e021)
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 2004 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 /*
30  * Read in "high-level" adb script and emit C program.
31  * The input may have specifications within {} which
32  * we analyze and then emit C code to generate the
33  * ultimate adb acript.
34  * We are just a filter; no arguments are accepted.
35  */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #define	streq(s1, s2)	(strcmp(s1, s2) == 0)
42 
43 #define	LINELEN  	1024	/* max line length expected in input */
44 #define	STRLEN		128	/* for shorter strings */
45 #define	NARGS		5	/* number of emitted subroutine arguments */
46 
47 /*
48  * Format specifier strings
49  * which are recognized by adbgen when surrounded by {}
50  */
51 #define	FSTR_PTR	"POINTER"
52 #define	FSTR_LONG_DEC	"LONGDEC"
53 #define	FSTR_LONG_OCT	"LONGOCT"
54 #define	FSTR_ULONG_DEC	"ULONGDEC"
55 #define	FSTR_ULONG_HEX	"ULONGHEX"
56 #define	FSTR_ULONG_OCT	"ULONGOCT"
57 
58 /*
59  * Types of specifications in {}.
60  */
61 #define	PTR_HEX		0	/* emit hex pointer format char */
62 #define	LONG_DEC	1	/* emit decimal long format char */
63 #define	LONG_OCT	2	/* emit octal unsigned long format char */
64 #define	ULONG_DEC	3	/* emit decimal unsigned long format char */
65 #define	ULONG_HEX	4	/* emit hexadecimal long format char */
66 #define	ULONG_OCT	5	/* emit octal unsigned long format char */
67 
68 #define	FMT_ENTRIES	6	/* number of adbgen format specifier strings */
69 
70 #define	PRINT   	6	/* print member name with format */
71 #define	INDIRECT	7	/* fetch member value */
72 #define	OFFSETOK	8	/* insist that the offset is ok */
73 #define	SIZEOF		9	/* print sizeof struct */
74 #define	END		10	/* get offset to end of struct */
75 #define	OFFSET		11	/* just emit offset */
76 #define	EXPR		12	/* arbitrary C expression */
77 
78 /*
79  * Special return code from nextchar.
80  */
81 #define	CPP		-2	/* cpp line, restart parsing */
82 
83 typedef struct adbgen_fmt {
84 	char *f_str;
85 	char f_char;
86 } adbgen_fmt_t;
87 
88 char struct_name[STRLEN];	/* struct name */
89 char member[STRLEN];		/* member name */
90 char format[STRLEN];		/* adb format spec */
91 char arg[NARGS][STRLEN];	/* arg list for called subroutine */
92 char *ptr_hex_fmt;		/* adb format character for pointer in hex */
93 char *long_dec_fmt;		/* adb format character for long in decimal */
94 char *ulong_dec_fmt;		/* adb format character for ulong in decimal */
95 char *ulong_hex_fmt;		/* adb format character for ulong in hex */
96 char *long_oct_fmt;		/* adb format character for long in octal */
97 char *ulong_oct_fmt;		/* adb format character for ulong in octal */
98 
99 int line_no = 1;		/* input line number - for error messages */
100 int specsize;			/* size of {} specification - 1 or 2 parts */
101 int state;			/* XXX 1 = gathering a printf */
102 				/* This is a kludge so we emit pending */
103 				/* printf's when we see a CPP line */
104 
105 adbgen_fmt_t adbgen_fmt_tbl [FMT_ENTRIES] = {
106 	{FSTR_PTR},
107 	{FSTR_LONG_DEC},
108 	{FSTR_LONG_OCT},
109 	{FSTR_ULONG_DEC},
110 	{FSTR_ULONG_HEX},
111 	{FSTR_ULONG_OCT}
112 };
113 
114 void emit_call(char *name, int nargs);
115 void emit_end(void);
116 void emit_expr(void);
117 void emit_indirect(void);
118 void emit_offset(void);
119 void emit_offsetok(void);
120 void emit_print(void);
121 void emit_printf(char *cp);
122 void emit_sizeof(void);
123 void generate(void);
124 int get_type(void);
125 int nextchar(char *cp);
126 void read_spec(void);
127 char *start_printf(void);
128 
129 int
130 main(int argc, char **argv)
131 {
132 	char *cp;
133 	int c;
134 	int warn_flag = 0;
135 	int is_lp64 = 0;
136 	char *usage = "adbgen1 [-w] [-m ilp32|lp64] < <macro file>\n";
137 
138 	while ((c = getopt(argc, argv, "m:w")) != EOF) {
139 		switch (c) {
140 		case 'm':
141 			if (streq(optarg, "ilp32"))
142 				is_lp64 = 0;
143 			else if (streq(optarg, "lp64"))
144 				is_lp64 = 1;
145 			else
146 				fprintf(stderr, usage);
147 			break;
148 		case 'w':
149 			warn_flag++;
150 			break;
151 		case '?':
152 			fprintf(stderr, usage);
153 			break;
154 		}
155 	}
156 	if (is_lp64) {
157 		adbgen_fmt_tbl[PTR_HEX].f_char = 'J';
158 		adbgen_fmt_tbl[LONG_DEC].f_char = 'e';
159 		adbgen_fmt_tbl[LONG_OCT].f_char = 'g';
160 		adbgen_fmt_tbl[ULONG_DEC].f_char = 'E';
161 		adbgen_fmt_tbl[ULONG_HEX].f_char = 'J';
162 		adbgen_fmt_tbl[ULONG_OCT].f_char = 'G';
163 	} else {
164 		adbgen_fmt_tbl[PTR_HEX].f_char = 'X';
165 		adbgen_fmt_tbl[LONG_DEC].f_char = 'D';
166 		adbgen_fmt_tbl[LONG_OCT].f_char = 'Q';
167 		adbgen_fmt_tbl[ULONG_DEC].f_char = 'U';
168 		adbgen_fmt_tbl[ULONG_HEX].f_char = 'X';
169 		adbgen_fmt_tbl[ULONG_OCT].f_char = 'O';
170 	}
171 
172 	/*
173 	 * Get structure name.
174 	 */
175 	cp = struct_name;
176 	while ((c = nextchar(NULL)) != '\n') {
177 		if (c == EOF) {
178 			fprintf(stderr, "Premature EOF\n");
179 			exit(1);
180 		}
181 		if (c == CPP)
182 			continue;
183 		*cp++ = (char)c;
184 	}
185 	*cp = '\0';
186 	/*
187 	 * Basically, the generated program is just an ongoing printf
188 	 * with breaks for {} format specifications.
189 	 */
190 	printf("\n");
191 	printf("#include <sys/types.h>\n");
192 	printf("#include <sys/inttypes.h>\n");
193 	printf("\n\n");
194 	printf("int do_fmt(char *acp);\n");
195 	printf("void format(char *name, size_t size, char *fmt);\n");
196 	printf("void indirect(off_t offset, size_t size, "
197 	    "char *base, char *member);\n");
198 	printf("void offset(off_t off);\n");
199 	printf("void offsetok(void);\n");
200 	printf("\n\n");
201 	printf("main(int argc, char *argv[])\n");
202 	printf("{\n");
203 	if (warn_flag) {
204 		printf("\textern int warnings;\n\n\twarnings = 0;\n");
205 	}
206 	cp = start_printf();
207 	while ((c = nextchar(cp)) != EOF) {
208 		switch (c) {
209 		case '"':
210 			*cp++ = '\\';	/* escape ' in string */
211 			*cp++ = '"';
212 			break;
213 		case '\n':
214 			*cp++ = '\\';	/* escape newline in string */
215 			*cp++ = 'n';
216 			break;
217 		case '{':
218 			emit_printf(cp);
219 			read_spec();
220 			generate();
221 			cp = start_printf();
222 			break;
223 		case CPP:
224 			/*
225 			 * Restart printf after cpp line.
226 			 */
227 			cp = start_printf();
228 			break;
229 		default:
230 			*cp++ = c;
231 			break;
232 		}
233 		if (cp - arg[1] >= STRLEN - 10) {
234 			emit_printf(cp);
235 			cp = start_printf();
236 		}
237 	}
238 	emit_printf(cp);
239 
240 	/* terminate program, checking for "error" mode */
241 	printf("\n\tif (argc > 1 && strcmp(argv[1], \"-e\") == 0) {\n");
242 	printf("\t\textern int warns;\n\n");
243 	printf("\t\tif (warns)\n");
244 	printf("\t\t\treturn (1);\n");
245 	printf("\t}\n");
246 	printf("\treturn (0);\n");
247 	printf("}\n");
248 
249 	return (0);
250 }
251 
252 int
253 nextchar(char *cp)
254 {
255 	int c;
256 	static int newline = 1;
257 
258 	c = getchar();
259 	/*
260 	 * Lines beginning with '#' and blank lines are passed right through.
261 	 */
262 	while (newline) {
263 		switch (c) {
264 		case '#':
265 			if (state)
266 				emit_printf(cp);
267 			do {
268 				putchar(c);
269 				c = getchar();
270 				if (c == EOF)
271 					return (c);
272 			} while (c != '\n');
273 			putchar(c);
274 			line_no++;
275 			return (CPP);
276 		case '\n':
277 			if (state)
278 				emit_printf(cp);
279 			putchar(c);
280 			c = getchar();
281 			line_no++;
282 			break;
283 		default:
284 			newline = 0;
285 			break;
286 		}
287 	}
288 	if (c == '\n') {
289 		newline++;
290 		line_no++;
291 	}
292 	return (c);
293 }
294 
295 /*
296  * Get started on printf of ongoing adb script.
297  */
298 char *
299 start_printf(void)
300 {
301 	char *cp;
302 
303 	strcpy(arg[0], "\"%s\"");
304 	cp = arg[1];
305 	*cp++ = '"';
306 	state = 1;			/* XXX */
307 	return (cp);
308 }
309 
310 /*
311  * Emit call to printf to print part of ongoing adb script.
312  */
313 void
314 emit_printf(cp)
315 	char *cp;
316 {
317 	*cp++ = '"';
318 	*cp = '\0';
319 	emit_call("printf", 2);
320 	state = 0;			/* XXX */
321 }
322 
323 /*
324  * Read {} specification.
325  * The first part (up to a comma) is put into "member".
326  * The second part, if present, is put into "format".
327  */
328 void
329 read_spec(void)
330 {
331 	char *cp;
332 	int c;
333 	int nesting;
334 
335 	cp = member;
336 	specsize = 1;
337 	nesting = 0;
338 	while ((c = nextchar(NULL)) != '}' || (c == '}' && nesting)) {
339 		switch (c) {
340 		case EOF:
341 			fprintf(stderr, "Unexpected EOF inside {}\n");
342 			exit(1);
343 		case '\n':
344 			fprintf(stderr, "Newline not allowed in {}, line %d\n",
345 				line_no);
346 			exit(1);
347 		case '#':
348 			fprintf(stderr, "# not allowed in {}, line %d\n",
349 				line_no);
350 			exit(1);
351 		case ',':
352 			if (specsize == 2) {
353 				fprintf(stderr, "Excessive commas in {}, ");
354 				fprintf(stderr, "line %d\n", line_no);
355 				exit(1);
356 			}
357 			specsize = 2;
358 			*cp = '\0';
359 			cp = format;
360 			break;
361 		case '{':
362 			/*
363 			 * Allow up to one set of nested {}'s for adbgen
364 			 * requests of the form {member, {format string}}
365 			 */
366 			if (!nesting) {
367 				nesting = 1;
368 				*cp++ = c;
369 			} else {
370 				fprintf(stderr, "Too many {'s, line %d\n",
371 					line_no);
372 				exit(1);
373 			}
374 			break;
375 		case '}':
376 			*cp++ = c;
377 			nesting = 0;
378 			break;
379 		default:
380 			*cp++ = c;
381 			break;
382 		}
383 	}
384 	*cp = '\0';
385 	if (cp == member) {
386 		specsize = 0;
387 	}
388 }
389 
390 /*
391  * Decide what type of input specification we have.
392  */
393 int
394 get_type(void)
395 {
396 	int i;
397 
398 	if (specsize == 1) {
399 		if (streq(member, "SIZEOF")) {
400 			return (SIZEOF);
401 		}
402 		if (streq(member, "OFFSETOK")) {
403 			return (OFFSETOK);
404 		}
405 		if (streq(member, "END")) {
406 			return (END);
407 		}
408 		for (i = 0; i < FMT_ENTRIES; i++)
409 			if (streq(member, adbgen_fmt_tbl[i].f_str))
410 				return (i);
411 		return (OFFSET);
412 	}
413 	if (specsize == 2) {
414 		if (member[0] == '*') {
415 			return (INDIRECT);
416 		}
417 		if (streq(member, "EXPR")) {
418 			return (EXPR);
419 		}
420 		return (PRINT);
421 	}
422 	fprintf(stderr, "Invalid specification, line %d\n", line_no);
423 	exit(1);
424 }
425 
426 /*
427  * Generate the appropriate output for an input specification.
428  */
429 void
430 generate(void)
431 {
432 	char *cp;
433 	int type;
434 
435 	type = get_type();
436 
437 	switch (type) {
438 	case PTR_HEX:
439 	case LONG_DEC:
440 	case LONG_OCT:
441 	case ULONG_DEC:
442 	case ULONG_HEX:
443 	case ULONG_OCT:
444 		cp = start_printf();
445 		*cp++ = adbgen_fmt_tbl[type].f_char;
446 		emit_printf(cp);
447 		break;
448 	case PRINT:
449 		emit_print();
450 		break;
451 	case OFFSET:
452 		emit_offset();
453 		break;
454 	case INDIRECT:
455 		emit_indirect();
456 		break;
457 	case OFFSETOK:
458 		emit_offsetok();
459 		break;
460 	case SIZEOF:
461 		emit_sizeof();
462 		break;
463 	case EXPR:
464 		emit_expr();
465 		break;
466 	case END:
467 		emit_end();
468 		break;
469 	default:
470 		fprintf(stderr, "Internal error in generate\n");
471 		exit(1);
472 	}
473 }
474 
475 /*
476  * Emit calls to set the offset and print a member.
477  */
478 void
479 emit_print(void)
480 {
481 	char *cp;
482 	char fmt_request[STRLEN];
483 	int i;
484 	char number[STRLEN];
485 
486 	emit_offset();
487 	/*
488 	 * Emit call to "format" subroutine
489 	 */
490 	sprintf(arg[0], "\"%s\"", member);
491 	sprintf(arg[1], "sizeof ((struct %s *)0)->%s",
492 		struct_name, member);
493 
494 	/*
495 	 * Split the format string into <number><format character string>
496 	 * This is for format strings that contain format specifier requests
497 	 * like {POINTER_HEX}, {LONG_DEC}, etc. which need to be substituted
498 	 * with a format character instead.
499 	 */
500 	for (cp = format, i = 0; *cp >= '0' && *cp <= '9' && *cp != '\0';
501 	    cp++, i++)
502 		number[i] = *cp;
503 	number[i] = '\0';
504 
505 	for (i = 0; i < FMT_ENTRIES; i++) {
506 		(void) sprintf(fmt_request, "{%s}", adbgen_fmt_tbl[i].f_str);
507 		if (streq(cp, fmt_request)) {
508 			sprintf(arg[2], "\"%s%c\"",
509 				number, adbgen_fmt_tbl[i].f_char);
510 			break;
511 		}
512 	}
513 	if (i == FMT_ENTRIES)
514 		sprintf(arg[2], "\"%s\"", format);
515 
516 	emit_call("format", 3);
517 }
518 
519 /*
520  * Emit calls to set the offset and print a member.
521  */
522 void
523 emit_offset(void)
524 {
525 	/*
526 	 * Emit call to "offset" subroutine
527 	 */
528 	sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
529 		struct_name, member);
530 	emit_call("offset", 1);
531 }
532 
533 /*
534  * Emit call to indirect routine.
535  */
536 void
537 emit_indirect(void)
538 {
539 	sprintf(arg[0], "(off_t) &(((struct %s *)0)->%s)",
540 		struct_name, member+1);
541 	sprintf(arg[1], "sizeof ((struct %s *)0)->%s", struct_name, member+1);
542 	sprintf(arg[2], "\"%s\"", format);	/* adb register name */
543 	sprintf(arg[3], "\"%s\"", member);
544 	emit_call("indirect", 4);
545 }
546 
547 /*
548  * Emit call to "offsetok" routine.
549  */
550 void
551 emit_offsetok(void)
552 {
553 	emit_call("offsetok", 0);
554 }
555 
556 /*
557  * Emit call to printf the sizeof the structure.
558  */
559 void
560 emit_sizeof(void)
561 {
562 	sprintf(arg[0], "\"0t%%d\"");
563 	sprintf(arg[1], "sizeof (struct %s)", struct_name);
564 	emit_call("printf", 2);
565 }
566 
567 /*
568  * Emit call to printf an arbitrary C expression.
569  */
570 void
571 emit_expr(void)
572 {
573 	sprintf(arg[0], "\"0t%%d\"");
574 	sprintf(arg[1], "(%s)", format);
575 	emit_call("printf", 2);
576 }
577 
578 /*
579  * Emit call to set offset to end of struct.
580  */
581 void
582 emit_end(void)
583 {
584 	sprintf(arg[0], "sizeof (struct %s)", struct_name);
585 	emit_call("offset", 1);
586 }
587 
588 /*
589  * Emit call to subroutine name with nargs arguments from arg array.
590  */
591 void
592 emit_call(char *name, int nargs)
593 {
594 	int i;
595 
596 	printf("\t%s(", name);		/* name of subroutine */
597 	for (i = 0; i < nargs; i++) {
598 		if (i > 0) {
599 			printf(", ");	/* argument separator */
600 		}
601 		printf("%s", arg[i]);	/* argument */
602 	}
603 	printf(");\n");			/* end of call */
604 }
605