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