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
main(int argc,char ** argv)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
nextchar(char * cp)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 *
start_printf(void)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
emit_printf(cp)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
read_spec(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
get_type(void)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
generate(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
emit_print(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
emit_offset(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
emit_indirect(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
emit_offsetok(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
emit_sizeof(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
emit_expr(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
emit_end(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
emit_call(char * name,int nargs)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