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 2006 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(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(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(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("unexpected end of data stream\n"); 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("unexpected end of data stream\n"); 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 %s ", name); 266 if (showids) 267 info("<tag %lu> ", line.type.extra.ty); 268 info("{ \n"); 269 270 indent(); 271 for (; nargs > 0; nargs--) { 272 if (fread(&atype, sizeof (atype), 1, fp) != 1) 273 die("unexpected end of data stream\n"); 274 275 getstr(fp, name, sizeof (name)); 276 print_atype(&atype, 0, NULL, name); 277 info(";\n"); 278 } 279 unindent(); 280 info("};\n"); 281 continue; 282 } 283 284 warn("unknown record type 0%o\n", line.decflag); 285 } 286 } 287 288 /* 289 * Print the C datatype or function `atp' named `name'. If `name' is a 290 * function, then `nargs' indicates the number of C datatypes pointed to 291 * by `args'. 292 */ 293 static void 294 print_atype(ATYPE *atp, int nargs, ATYPE *args, const char *name) 295 { 296 static const char *basetypes[] = { "", 297 "char", "unsigned char", "signed char", 298 "short", "unsigned short", "signed short", 299 "int", "unsigned int", "signed int", 300 "long", "unsigned long", "signed long", 301 "long long", "unsigned long long", "signed long long", 302 "enum", "float", "double", 303 "long double", "void", "struct", 304 "union", "_Bool", "<genchar>", 305 "<genshort>", "<genint>", "<genlong>", 306 "<genlonglong>" 307 }; 308 uint16_t basetype = atp->aty & LNQUAL; 309 lsu_t *lsup; 310 311 if (atp->aty & LCON) 312 info("const "); 313 if (atp->aty & LVOL) 314 info("volatile "); 315 if (atp->aty & LCONV) 316 info("integer const "); 317 318 if (basetype < 1 || 319 basetype > (sizeof (basetypes) / sizeof (*basetypes))) 320 info("<unknown type %x>", basetype); 321 322 switch (basetype) { 323 case LN_UNION: 324 case LN_STRUCT: 325 lsup = lsu_lookup(atp->extra.ty); 326 if (lsup != NULL && lsup->name[0] != '.') { 327 info("%s %s", basetypes[basetype], lsup->name); 328 } else { 329 info("%s", basetypes[basetype]); 330 if (showids) 331 info(" <tag %lu>", atp->extra.ty); 332 else 333 info(" <anon>"); 334 } 335 break; 336 default: 337 info(basetypes[basetype]); 338 }; 339 340 print_mods(name, atp, nargs, args, 14); 341 } 342 343 /* 344 * Recursively print type modifiers. 345 */ 346 static void 347 print_mods(const char *name, ATYPE *atp, int nargs, ATYPE *args, uint_t pos) 348 { 349 int arg; 350 int mods = atp->dcl_mod >> (pos * 2); 351 int lastmods = atp->dcl_mod >> ((pos + 1) * 2); 352 boolean_t isvarargs = B_FALSE; 353 354 if (LN_ISPTR(mods)) { 355 if (!LN_ISPTR(lastmods) && !LN_ISFTN(lastmods)) 356 info(" "); 357 info("*"); 358 } 359 360 if (atp->dcl_con & (1 << pos)) 361 info(" const "); 362 if (atp->dcl_vol & (1 << pos)) 363 info(" volatile "); 364 365 if (pos != 0) { 366 if (LN_ISFTN(mods)) 367 info(" ("); 368 print_mods(name, atp, nargs, args, pos - 1); 369 if (LN_ISFTN(mods)) 370 info(")()"); 371 return; 372 } 373 374 if (name[0] == '\0') 375 return; 376 377 if (!LN_ISPTR(lastmods) && !LN_ISPTR(mods)) 378 info(" "); 379 info("%s", name); 380 381 if (LN_ISARY(mods)) { 382 info("[]"); 383 } else if (LN_ISFTN(mods)) { 384 info("("); 385 386 if (nargs < 0) { 387 nargs = -nargs - 1; 388 isvarargs = B_TRUE; 389 } 390 391 if (nargs == 0) { 392 info("void"); 393 } else { 394 for (arg = 0; arg < nargs; arg++) { 395 print_atype(&args[arg], 0, NULL, ""); 396 if ((arg + 1) < nargs) 397 info(", "); 398 else if (isvarargs) 399 info(", ..."); 400 } 401 } 402 info(")"); 403 } 404 } 405 406 /* 407 * Add an LSU entry to the LSU table. 408 */ 409 static int 410 lsu_add(const char *name, ATYPE *atp) 411 { 412 unsigned int i = atp->extra.ty % LSU_HASHSIZE; 413 lsu_t *lsup; 414 415 lsup = malloc(sizeof (lsu_t)); 416 if (lsup == NULL) 417 return (ENOMEM); 418 419 lsup->atype = *atp; 420 lsup->next = lsu_table[i]; 421 lsup->name = strdup(name); 422 if (lsup->name == NULL) { 423 free(lsup); 424 return (ENOMEM); 425 } 426 427 lsu_table[i] = lsup; 428 return (0); 429 } 430 431 /* 432 * Lookup an LSU entry by ID. 433 */ 434 static lsu_t * 435 lsu_lookup(T1WORD ty) 436 { 437 unsigned int i = ty % LSU_HASHSIZE; 438 lsu_t *lsup; 439 440 for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup->next) { 441 if (lsup->atype.extra.ty == ty) 442 return (lsup); 443 } 444 445 return (NULL); 446 } 447 448 /* 449 * Read all LSU (structure and union definition) records in order to 450 * build a structure and union name table, called the LSU table. 451 */ 452 static void 453 lsu_build(FILE *fp) 454 { 455 union rec rec; 456 char name[1024]; 457 int nargs; 458 459 for (;;) { 460 if (fread(&rec, sizeof (rec), 1, fp) != 1) 461 return; 462 463 if (rec.l.decflag & LND) /* end-of-pass marker */ 464 break; 465 466 getstr(fp, name, sizeof (name)); 467 nargs = rec.l.nargs; 468 469 if (rec.l.decflag & (LIB|LDS|LDI)) { 470 if (nargs < 0) 471 nargs = -nargs - 1; 472 473 (void) fseek(fp, sizeof (ATYPE) * nargs, SEEK_CUR); 474 continue; 475 } 476 477 if (rec.l.decflag & LSU) { 478 if (lsu_add(name, &rec.l.type) != 0) 479 warn("cannot allocate struct `%s' info", name); 480 481 for (; nargs > 0; nargs--) { 482 (void) fseek(fp, sizeof (ATYPE), SEEK_CUR); 483 getstr(fp, name, sizeof (name)); 484 } 485 } 486 } 487 } 488 489 /* 490 * Empty the LSU table. 491 */ 492 static void 493 lsu_empty(void) 494 { 495 lsu_t *lsup, *lsup_next; 496 unsigned int i; 497 498 for (i = 0; i < LSU_HASHSIZE; i++) { 499 for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup_next) { 500 lsup_next = lsup->next; 501 free(lsup); 502 } 503 lsu_table[i] = NULL; 504 } 505 } 506 507 /* 508 * Read the NUL-terminated string at `fp' into `buf', which is at most 509 * `bufsize' bytes. 510 */ 511 static void 512 getstr(FILE *fp, char *buf, size_t bufsize) 513 { 514 int c; 515 size_t i; 516 517 for (i = 0; i < bufsize - 1; i++) { 518 c = fgetc(fp); 519 if (c == EOF || c == '\0' || !isascii(c)) 520 break; 521 buf[i] = (char)c; 522 } 523 524 buf[i] = '\0'; 525 } 526 527 static void 528 indent(void) 529 { 530 indentlevel += 4; 531 } 532 533 static void 534 unindent(void) 535 { 536 indentlevel -= 4; 537 } 538 539 static void 540 usage(void) 541 { 542 (void) fprintf(stderr, "usage: %s [-i] [-p 1|2|3] [-r] lintlib" 543 " [ lintlib ... ]\n", progname); 544 exit(EXIT_FAILURE); 545 } 546 547 /* PRINTFLIKE1 */ 548 static void 549 info(const char *format, ...) 550 { 551 va_list alist; 552 static int complete = 1; 553 554 if (complete) 555 (void) printf("%*s", indentlevel, ""); 556 557 va_start(alist, format); 558 (void) vprintf(format, alist); 559 va_end(alist); 560 561 complete = strrchr(format, '\n') != NULL; 562 } 563 564 /* PRINTFLIKE2 */ 565 static void 566 infohdr(const char *hdr, const char *format, ...) 567 { 568 va_list alist; 569 static int complete = 1; 570 571 if (complete) 572 (void) printf("%7s: ", hdr); 573 574 va_start(alist, format); 575 (void) vprintf(format, alist); 576 va_end(alist); 577 578 complete = strrchr(format, '\n') != NULL; 579 } 580 581 /* PRINTFLIKE1 */ 582 static void 583 warn(const char *format, ...) 584 { 585 va_list alist; 586 char *errstr = strerror(errno); 587 588 (void) fprintf(stderr, "%s: warning: ", progname); 589 590 va_start(alist, format); 591 (void) vfprintf(stderr, format, alist); 592 va_end(alist); 593 594 if (strrchr(format, '\n') == NULL) 595 (void) fprintf(stderr, ": %s\n", errstr); 596 } 597 598 /* PRINTFLIKE1 */ 599 static void 600 die(const char *format, ...) 601 { 602 va_list alist; 603 char *errstr = strerror(errno); 604 605 (void) fprintf(stderr, "%s: fatal: ", progname); 606 607 va_start(alist, format); 608 (void) vfprintf(stderr, format, alist); 609 va_end(alist); 610 611 if (strrchr(format, '\n') == NULL) 612 (void) fprintf(stderr, ": %s\n", errstr); 613 614 exit(EXIT_FAILURE); 615 } 616