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