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