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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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