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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "@(#)lintdump.c 1.6 06/06/04 SMI (from meem)" 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 /* 31 * Tool for dumping lint libraries. 32 */ 33 34 #include <ctype.h> 35 #include <errno.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sys/types.h> 41 42 #include "lnstuff.h" /* silly header name from alint */ 43 44 typedef struct lsu { 45 const char *name; 46 ATYPE atype; 47 struct lsu *next; 48 } lsu_t; 49 50 #define LSU_HASHSIZE 512 51 static lsu_t *lsu_table[LSU_HASHSIZE]; 52 53 static boolean_t showids = B_TRUE; 54 static boolean_t justrelpaths = B_FALSE; 55 static int justpass = -1; 56 static int indentlevel = 9; 57 static const char *progname; 58 59 static void info(const char *, ...); 60 static void infohdr(const char *, const char *, ...); 61 static void warn(const char *, ...); 62 static void die(const char *, ...); 63 static void usage(void); 64 static void indent(void); 65 static void unindent(void); 66 static void print_lintlib(const char *, FILE *, FLENS *); 67 static void print_pass(const char *, FILE *); 68 static void print_atype(ATYPE *, int, ATYPE *, const char *); 69 static void print_mods(const char *, ATYPE *, int, ATYPE *, uint_t); 70 static void getstr(FILE *, char *, size_t); 71 static void lsu_build(FILE *); 72 static void lsu_empty(void); 73 static int lsu_add(const char *, ATYPE *); 74 static lsu_t *lsu_lookup(unsigned long); 75 76 int 77 main(int argc, char **argv) 78 { 79 int i, c; 80 FILE *fp; 81 FLENS hdr; 82 83 progname = strrchr(argv[0], '/'); 84 if (progname == NULL) 85 progname = argv[0]; 86 else 87 progname++; 88 89 while ((c = getopt(argc, argv, "ip:r")) != EOF) { 90 switch (c) { 91 case 'i': 92 showids = B_FALSE; 93 break; 94 case 'p': 95 justpass = strtoul(optarg, NULL, 0); 96 if (justpass < 1 || justpass > 3) 97 usage(); 98 break; 99 case 'r': 100 justrelpaths = B_TRUE; 101 break; 102 default: 103 usage(); 104 } 105 } 106 107 if (optind == argc) 108 usage(); 109 110 for (i = optind; i < argc; i++) { 111 fp = fopen(argv[i], "r"); 112 if (fp == NULL) { 113 warn("cannot open \"%s\"", argv[i]); 114 continue; 115 } 116 117 if (fread(&hdr, sizeof (hdr), 1, fp) < 1) { 118 warn("%s: cannot read lint library header\n", argv[i]); 119 (void) fclose(fp); 120 continue; 121 } 122 123 if (hdr.ver != LINTVER) { 124 warn("%s: lint library version %d unsupported\n", 125 argv[i], hdr.ver); 126 (void) fclose(fp); 127 continue; 128 } 129 130 /* 131 * First build the table of structure/union names, then seek 132 * back to the start and print the lint library. Finally, 133 * empty the table out before dumping the next library. 134 */ 135 lsu_build(fp); 136 (void) fseek(fp, sizeof (hdr), SEEK_SET); 137 print_lintlib(argv[i], fp, &hdr); 138 (void) fclose(fp); 139 lsu_empty(); 140 } 141 142 return (EXIT_SUCCESS); 143 } 144 145 /* 146 * Print a lint library. 147 */ 148 static void 149 print_lintlib(const char *lnname, FILE *fp, FLENS *hp) 150 { 151 off_t passoff = 0; 152 ulong_t psizes[4]; 153 uint_t pass; 154 155 psizes[0] = 0; 156 psizes[1] = hp->f1; 157 psizes[2] = hp->f2; 158 psizes[3] = hp->f3; 159 160 if (justrelpaths && lnname[0] == '/') 161 lnname = strrchr(lnname, '/') + 1; 162 163 infohdr("LINTLIB", "%s <mid %hu> %lu+%lu+%lu+%lu = %lu bytes\n", lnname, 164 hp->mno, hp->f1, hp->f2, hp->f3, hp->f4, 165 hp->f1 + hp->f2 + hp->f3 + hp->f4); 166 167 for (pass = 1; pass <= 3; pass++) { 168 if (justpass < 0 || justpass == pass) { 169 infohdr("SECTION", "PASS%u: %lu bytes\n", pass, 170 psizes[pass]); 171 print_pass(lnname, fp); 172 } 173 passoff += psizes[pass]; 174 (void) fseek(fp, passoff, SEEK_SET); 175 } 176 } 177 178 /* 179 * Print out a PASS section of a lint library. 180 */ 181 static void 182 print_pass(const char *lnname, FILE *fp) 183 { 184 union rec rec; 185 int nargs; 186 char name[1024]; 187 ATYPE atype, *args; 188 LINE line; 189 boolean_t wasfile = B_FALSE; 190 191 for (;;) { 192 if (fread(&rec, sizeof (rec), 1, fp) != 1) 193 die("%s: unexpected end of file\n", lnname); 194 195 line = rec.l; 196 if (line.decflag & LND) /* end-of-pass marker */ 197 break; 198 199 getstr(fp, name, sizeof (name)); 200 201 /* 202 * Check if this is a file record. 203 */ 204 if (line.decflag & LFN) { 205 if (wasfile || !justrelpaths) 206 infohdr("FILE", "%s\n", name); 207 wasfile = B_TRUE; 208 continue; 209 } 210 wasfile = B_FALSE; 211 212 /* 213 * Check if this is a function or variable record. 214 */ 215 nargs = line.nargs; 216 if (line.decflag & (LIB|LDS|LDI|LPR|LDX|LDC|LRV|LUE|LUV|LUM)) { 217 if (nargs < 0) 218 nargs = -nargs - 1; 219 220 if (line.decflag & LDS) 221 info("static "); 222 else if (line.decflag & (LPR|LDX|LDC)) 223 info("extern "); 224 225 args = calloc(sizeof (atype), nargs); 226 if (args == NULL) 227 die("cannot allocate argument information"); 228 229 if (fread(args, sizeof (atype), nargs, fp) != nargs) 230 die("%s: unexpected end of file\n", lnname); 231 232 print_atype(&line.type, line.nargs, args, name); 233 free(args); 234 235 if (line.decflag & LRV) 236 info(" <returns value>"); 237 if (line.decflag & LUE) 238 info(" <use: side-effects context>"); 239 if (line.decflag & LUV) 240 info(" <use: return value context>"); 241 if (line.decflag & LUM) 242 info(" <use: unspecified context>"); 243 244 if (line.decflag & LPF) 245 info(" <PRINTFLIKE%d>", nargs); 246 else if (line.decflag & LSF) 247 info(" <SCANFLIKE%d>", nargs); 248 249 if (line.decflag & LDI) 250 info(" { <definition> }"); 251 else if (line.decflag & LDX) 252 info(" = <definition>"); 253 254 info(";\n"); 255 continue; 256 } 257 258 /* 259 * Check if this is a structure or union record. 260 */ 261 if (line.decflag & LSU) { 262 if (line.decflag & ~(LSU)) 263 info("??? "); 264 265 info("struct "); 266 if (name[0] != '.') 267 info("%s ", name); 268 if (showids) 269 info("<tag %lu> ", line.type.extra.ty); 270 info("{ \n"); 271 272 indent(); 273 for (; nargs > 0; nargs--) { 274 if (fread(&atype, sizeof (atype), 1, fp) != 1) { 275 die("%s: unexpected end of file\n", 276 lnname); 277 } 278 getstr(fp, name, sizeof (name)); 279 print_atype(&atype, 0, NULL, name); 280 info(";\n"); 281 } 282 unindent(); 283 info("};\n"); 284 continue; 285 } 286 287 warn("%s: unknown record type 0%o\n", lnname, line.decflag); 288 } 289 } 290 291 /* 292 * Print the C datatype or function `atp' named `name'. If `name' is a 293 * function, then `nargs' indicates the number of C datatypes pointed to 294 * by `args'. 295 */ 296 static void 297 print_atype(ATYPE *atp, int nargs, ATYPE *args, const char *name) 298 { 299 static const char *basetypes[] = { "", 300 "char", "unsigned char", "signed char", 301 "short", "unsigned short", "signed short", 302 "int", "unsigned int", "signed int", 303 "long", "unsigned long", "signed long", 304 "long long", "unsigned long long", "signed long long", 305 "enum", "float", "double", 306 "long double", "void", "struct", 307 "union", "_Bool", "<genchar>", 308 "<genshort>", "<genint>", "<genlong>", 309 "<genlonglong>" 310 }; 311 uint16_t basetype = atp->aty & LNQUAL; 312 lsu_t *lsup; 313 314 if (atp->aty & LCON) 315 info("const "); 316 if (atp->aty & LVOL) 317 info("volatile "); 318 if (atp->aty & LCONV) 319 info("integer const "); 320 321 if (basetype < 1 || 322 basetype > (sizeof (basetypes) / sizeof (*basetypes))) 323 info("<unknown type %x>", basetype); 324 325 switch (basetype) { 326 case LN_UNION: 327 case LN_STRUCT: 328 lsup = lsu_lookup(atp->extra.ty); 329 if (lsup != NULL && lsup->name[0] != '.') { 330 info("%s %s", basetypes[basetype], lsup->name); 331 } else { 332 info("%s", basetypes[basetype]); 333 if (showids) 334 info(" <tag %lu>", atp->extra.ty); 335 else 336 info(" <anon>"); 337 } 338 break; 339 default: 340 info("%s", basetypes[basetype]); 341 }; 342 343 print_mods(name, atp, nargs, args, 14); 344 } 345 346 /* 347 * Recursively print type modifiers. 348 */ 349 static void 350 print_mods(const char *name, ATYPE *atp, int nargs, ATYPE *args, uint_t pos) 351 { 352 int arg; 353 int mods = atp->dcl_mod >> (pos * 2); 354 int lastmods = atp->dcl_mod >> ((pos + 1) * 2); 355 boolean_t isvarargs = B_FALSE; 356 357 if (LN_ISPTR(mods)) { 358 if (!LN_ISPTR(lastmods) && !LN_ISFTN(lastmods)) 359 info(" "); 360 info("*"); 361 } 362 363 if (atp->dcl_con & (1 << pos)) 364 info(" const "); 365 if (atp->dcl_vol & (1 << pos)) 366 info(" volatile "); 367 368 if (pos != 0) { 369 if (LN_ISFTN(mods)) 370 info(" ("); 371 print_mods(name, atp, nargs, args, pos - 1); 372 if (LN_ISFTN(mods)) 373 info(")()"); 374 return; 375 } 376 377 if (name[0] == '\0') 378 return; 379 380 if (!LN_ISPTR(lastmods) && !LN_ISPTR(mods)) 381 info(" "); 382 info("%s", name); 383 384 if (LN_ISARY(mods)) { 385 info("[]"); 386 } else if (LN_ISFTN(mods)) { 387 info("("); 388 389 if (nargs < 0) { 390 nargs = -nargs - 1; 391 isvarargs = B_TRUE; 392 } 393 394 if (nargs == 0) { 395 info("void"); 396 } else { 397 for (arg = 0; arg < nargs; arg++) { 398 print_atype(&args[arg], 0, NULL, ""); 399 if ((arg + 1) < nargs) 400 info(", "); 401 else if (isvarargs) 402 info(", ..."); 403 } 404 } 405 info(")"); 406 } 407 } 408 409 /* 410 * Add an LSU entry to the LSU table. 411 */ 412 static int 413 lsu_add(const char *name, ATYPE *atp) 414 { 415 unsigned int i = atp->extra.ty % LSU_HASHSIZE; 416 lsu_t *lsup; 417 418 lsup = malloc(sizeof (lsu_t)); 419 if (lsup == NULL) 420 return (ENOMEM); 421 422 lsup->atype = *atp; 423 lsup->next = lsu_table[i]; 424 lsup->name = strdup(name); 425 if (lsup->name == NULL) { 426 free(lsup); 427 return (ENOMEM); 428 } 429 430 lsu_table[i] = lsup; 431 return (0); 432 } 433 434 /* 435 * Lookup an LSU entry by ID. 436 */ 437 static lsu_t * 438 lsu_lookup(T1WORD ty) 439 { 440 unsigned int i = ty % LSU_HASHSIZE; 441 lsu_t *lsup; 442 443 for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup->next) { 444 if (lsup->atype.extra.ty == ty) 445 return (lsup); 446 } 447 448 return (NULL); 449 } 450 451 /* 452 * Read all LSU (structure and union definition) records in order to 453 * build a structure and union name table, called the LSU table. 454 */ 455 static void 456 lsu_build(FILE *fp) 457 { 458 union rec rec; 459 char name[1024]; 460 int nargs; 461 462 for (;;) { 463 if (fread(&rec, sizeof (rec), 1, fp) != 1) 464 return; 465 466 if (rec.l.decflag & LND) /* end-of-pass marker */ 467 break; 468 469 getstr(fp, name, sizeof (name)); 470 nargs = rec.l.nargs; 471 472 if (rec.l.decflag & (LIB|LDS|LDI)) { 473 if (nargs < 0) 474 nargs = -nargs - 1; 475 476 (void) fseek(fp, sizeof (ATYPE) * nargs, SEEK_CUR); 477 continue; 478 } 479 480 if (rec.l.decflag & LSU) { 481 if (lsu_add(name, &rec.l.type) != 0) 482 warn("cannot allocate struct `%s' info", name); 483 484 for (; nargs > 0; nargs--) { 485 (void) fseek(fp, sizeof (ATYPE), SEEK_CUR); 486 getstr(fp, name, sizeof (name)); 487 } 488 } 489 } 490 } 491 492 /* 493 * Empty the LSU table. 494 */ 495 static void 496 lsu_empty(void) 497 { 498 lsu_t *lsup, *lsup_next; 499 unsigned int i; 500 501 for (i = 0; i < LSU_HASHSIZE; i++) { 502 for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup_next) { 503 lsup_next = lsup->next; 504 free(lsup); 505 } 506 lsu_table[i] = NULL; 507 } 508 } 509 510 /* 511 * Read the NUL-terminated string at `fp' into `buf', which is at most 512 * `bufsize' bytes. 513 */ 514 static void 515 getstr(FILE *fp, char *buf, size_t bufsize) 516 { 517 int c; 518 size_t i; 519 520 for (i = 0; i < bufsize - 1; i++) { 521 c = fgetc(fp); 522 if (c == EOF || c == '\0' || !isascii(c)) 523 break; 524 buf[i] = (char)c; 525 } 526 527 buf[i] = '\0'; 528 } 529 530 static void 531 indent(void) 532 { 533 indentlevel += 4; 534 } 535 536 static void 537 unindent(void) 538 { 539 indentlevel -= 4; 540 } 541 542 static void 543 usage(void) 544 { 545 (void) fprintf(stderr, "usage: %s [-i] [-p 1|2|3] [-r] lintlib" 546 " [ lintlib ... ]\n", progname); 547 exit(EXIT_FAILURE); 548 } 549 550 /* PRINTFLIKE1 */ 551 static void 552 info(const char *format, ...) 553 { 554 va_list alist; 555 static int complete = 1; 556 557 if (complete) 558 (void) printf("%*s", indentlevel, ""); 559 560 va_start(alist, format); 561 (void) vprintf(format, alist); 562 va_end(alist); 563 564 complete = strrchr(format, '\n') != NULL; 565 } 566 567 /* PRINTFLIKE2 */ 568 static void 569 infohdr(const char *hdr, const char *format, ...) 570 { 571 va_list alist; 572 static int complete = 1; 573 574 if (complete) 575 (void) printf("%7s: ", hdr); 576 577 va_start(alist, format); 578 (void) vprintf(format, alist); 579 va_end(alist); 580 581 complete = strrchr(format, '\n') != NULL; 582 } 583 584 /* PRINTFLIKE1 */ 585 static void 586 warn(const char *format, ...) 587 { 588 va_list alist; 589 char *errstr = strerror(errno); 590 591 (void) fprintf(stderr, "%s: warning: ", progname); 592 593 va_start(alist, format); 594 (void) vfprintf(stderr, format, alist); 595 va_end(alist); 596 597 if (strrchr(format, '\n') == NULL) 598 (void) fprintf(stderr, ": %s\n", errstr); 599 } 600 601 /* PRINTFLIKE1 */ 602 static void 603 die(const char *format, ...) 604 { 605 va_list alist; 606 char *errstr = strerror(errno); 607 608 (void) fprintf(stderr, "%s: fatal: ", progname); 609 610 va_start(alist, format); 611 (void) vfprintf(stderr, format, alist); 612 va_end(alist); 613 614 if (strrchr(format, '\n') == NULL) 615 (void) fprintf(stderr, ": %s\n", errstr); 616 617 exit(EXIT_FAILURE); 618 } 619