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