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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "@(#)lintdump.c 1.6 06/06/04 SMI (from meem)"
28 #pragma ident "%Z%%M% %I% %E% SMI"
31 * Tool for dumping lint libraries.
40 #include <sys/types.h>
42 #include "lnstuff.h" /* silly header name from alint */
50 #define LSU_HASHSIZE 512
51 static lsu_t
*lsu_table
[LSU_HASHSIZE
];
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
;
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_lintmod(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);
77 main(int argc
, char **argv
)
84 progname
= strrchr(argv
[0], '/');
90 while ((c
= getopt(argc
, argv
, "ip:r")) != EOF
) {
96 justpass
= strtoul(optarg
, NULL
, 0);
97 if (justpass
< 1 || justpass
> 3)
101 justrelpaths
= B_TRUE
;
111 for (i
= optind
; i
< argc
; i
++) {
112 fp
= fopen(argv
[i
], "r");
114 warn("cannot open \"%s\"", argv
[i
]);
119 if (justrelpaths
&& lnname
[0] == '/')
120 lnname
= strrchr(lnname
, '/') + 1;
123 * Dump out all of the modules in the lint object.
125 for (mod
= 1; fread(&hdr
, sizeof (hdr
), 1, fp
) == 1; mod
++) {
126 if (hdr
.ver
!= LINTVER
) {
127 warn("%s: unsupported lint object version "
128 "%d\n", argv
[i
], hdr
.ver
);
133 infohdr("LINTOBJ", "%s\n", lnname
);
136 * First build the table of structure/union names,
137 * then print the lint module. Finally, empty the
138 * table out before dumping the next module.
141 print_lintmod(lnname
, fp
, &hdr
);
147 return (EXIT_SUCCESS
);
151 * Print a lint module and advance past it in the stream.
154 print_lintmod(const char *lnname
, FILE *fp
, FLENS
*hp
)
165 infohdr("LINTMOD", "%hu: %lu+%lu+%lu+%lu = %lu bytes\n", hp
->mno
,
166 hp
->f1
, hp
->f2
, hp
->f3
, hp
->f4
, hp
->f1
+ hp
->f2
+ hp
->f3
+ hp
->f4
);
168 for (pass
= 1; pass
<= 4; pass
++) {
169 if ((justpass
< 0 || justpass
== pass
) && pass
< 4) {
170 infohdr("SECTION", "PASS%u: %lu bytes\n", pass
,
172 print_pass(lnname
, fp
);
174 (void) fseek(fp
, psizes
[pass
], SEEK_CUR
);
180 * Print out a PASS section of a lint module.
183 print_pass(const char *lnname
, FILE *fp
)
190 boolean_t wasfile
= B_FALSE
;
193 if (fread(&rec
, sizeof (rec
), 1, fp
) != 1)
194 die("%s: unexpected end of file\n", lnname
);
197 if (line
.decflag
& LND
) /* end-of-pass marker */
200 getstr(fp
, name
, sizeof (name
));
203 * Check if this is a file record.
205 if (line
.decflag
& LFN
) {
206 if (wasfile
|| !justrelpaths
)
207 infohdr("FILE", "%s\n", name
);
214 * Check if this is a function or variable record.
217 if (line
.decflag
& (LIB
|LDS
|LDI
|LPR
|LDX
|LDC
|LRV
|LUE
|LUV
|LUM
)) {
221 if (line
.decflag
& LDS
)
223 else if (line
.decflag
& (LPR
|LDX
|LDC
))
226 args
= calloc(sizeof (atype
), nargs
);
228 die("cannot allocate argument information");
230 if (fread(args
, sizeof (atype
), nargs
, fp
) != nargs
)
231 die("%s: unexpected end of file\n", lnname
);
233 print_atype(&line
.type
, line
.nargs
, args
, name
);
236 if (line
.decflag
& LRV
)
237 info(" <returns value>");
238 if (line
.decflag
& LUE
)
239 info(" <use: side-effects context>");
240 if (line
.decflag
& LUV
)
241 info(" <use: return value context>");
242 if (line
.decflag
& LUM
)
243 info(" <use: unspecified context>");
245 if (line
.decflag
& LPF
)
246 info(" <PRINTFLIKE%d>", nargs
);
247 else if (line
.decflag
& LSF
)
248 info(" <SCANFLIKE%d>", nargs
);
250 if (line
.decflag
& LDI
)
251 info(" { <definition> }");
252 else if (line
.decflag
& LDX
)
253 info(" = <definition>");
260 * Check if this is a structure or union record.
262 if (line
.decflag
& LSU
) {
263 if (line
.decflag
& ~(LSU
))
270 info("<tag %lu> ", line
.type
.extra
.ty
);
274 for (; nargs
> 0; nargs
--) {
275 if (fread(&atype
, sizeof (atype
), 1, fp
) != 1) {
276 die("%s: unexpected end of file\n",
279 getstr(fp
, name
, sizeof (name
));
280 print_atype(&atype
, 0, NULL
, name
);
288 warn("%s: unknown record type 0%o\n", lnname
, line
.decflag
);
293 * Print the C datatype or function `atp' named `name'. If `name' is a
294 * function, then `nargs' indicates the number of C datatypes pointed to
298 print_atype(ATYPE
*atp
, int nargs
, ATYPE
*args
, const char *name
)
300 static const char *basetypes
[] = { "",
301 "char", "unsigned char", "signed char",
302 "short", "unsigned short", "signed short",
303 "int", "unsigned int", "signed int",
304 "long", "unsigned long", "signed long",
305 "long long", "unsigned long long", "signed long long",
306 "enum", "float", "double",
307 "long double", "void", "struct",
308 "union", "_Bool", "<genchar>",
309 "<genshort>", "<genint>", "<genlong>",
312 uint16_t basetype
= atp
->aty
& LNQUAL
;
319 if (atp
->aty
& LCONV
)
320 info("integer const ");
323 basetype
> (sizeof (basetypes
) / sizeof (*basetypes
)))
324 info("<unknown type %x>", basetype
);
329 lsup
= lsu_lookup(atp
->extra
.ty
);
330 if (lsup
!= NULL
&& lsup
->name
[0] != '.') {
331 info("%s %s", basetypes
[basetype
], lsup
->name
);
333 info("%s", basetypes
[basetype
]);
335 info(" <tag %lu>", atp
->extra
.ty
);
341 info("%s", basetypes
[basetype
]);
344 print_mods(name
, atp
, nargs
, args
, 14);
348 * Recursively print type modifiers.
351 print_mods(const char *name
, ATYPE
*atp
, int nargs
, ATYPE
*args
, uint_t pos
)
354 int mods
= atp
->dcl_mod
>> (pos
* 2);
355 int lastmods
= atp
->dcl_mod
>> ((pos
+ 1) * 2);
356 boolean_t isvarargs
= B_FALSE
;
358 if (LN_ISPTR(mods
)) {
359 if (!LN_ISPTR(lastmods
) && !LN_ISFTN(lastmods
))
364 if (atp
->dcl_con
& (1 << pos
))
366 if (atp
->dcl_vol
& (1 << pos
))
372 print_mods(name
, atp
, nargs
, args
, pos
- 1);
381 if (!LN_ISPTR(lastmods
) && !LN_ISPTR(mods
))
385 if (LN_ISARY(mods
)) {
387 } else if (LN_ISFTN(mods
)) {
398 for (arg
= 0; arg
< nargs
; arg
++) {
399 print_atype(&args
[arg
], 0, NULL
, "");
400 if ((arg
+ 1) < nargs
)
411 * Add an LSU entry to the LSU table.
414 lsu_add(const char *name
, ATYPE
*atp
)
416 unsigned int i
= atp
->extra
.ty
% LSU_HASHSIZE
;
419 lsup
= malloc(sizeof (lsu_t
));
424 lsup
->next
= lsu_table
[i
];
425 lsup
->name
= strdup(name
);
426 if (lsup
->name
== NULL
) {
436 * Lookup an LSU entry by ID.
439 lsu_lookup(T1WORD ty
)
441 unsigned int i
= ty
% LSU_HASHSIZE
;
444 for (lsup
= lsu_table
[i
]; lsup
!= NULL
; lsup
= lsup
->next
) {
445 if (lsup
->atype
.extra
.ty
== ty
)
453 * Read all LSU (structure and union definition) records in order to
454 * build a structure and union name table, called the LSU table.
455 * Although `fp' is read from, the original file offset is preserved.
463 off_t curoff
= ftello(fp
);
466 if (fread(&rec
, sizeof (rec
), 1, fp
) != 1)
469 if (rec
.l
.decflag
& LND
) /* end-of-pass marker */
472 getstr(fp
, name
, sizeof (name
));
475 if (rec
.l
.decflag
& (LIB
|LDS
|LDI
)) {
479 (void) fseek(fp
, sizeof (ATYPE
) * nargs
, SEEK_CUR
);
483 if (rec
.l
.decflag
& LSU
) {
484 if (lsu_add(name
, &rec
.l
.type
) != 0)
485 warn("cannot allocate struct `%s' info", name
);
487 for (; nargs
> 0; nargs
--) {
488 (void) fseek(fp
, sizeof (ATYPE
), SEEK_CUR
);
489 getstr(fp
, name
, sizeof (name
));
494 (void) fseek(fp
, curoff
, SEEK_SET
);
498 * Empty the LSU table.
503 lsu_t
*lsup
, *lsup_next
;
506 for (i
= 0; i
< LSU_HASHSIZE
; i
++) {
507 for (lsup
= lsu_table
[i
]; lsup
!= NULL
; lsup
= lsup_next
) {
508 lsup_next
= lsup
->next
;
516 * Read the NUL-terminated string at `fp' into `buf', which is at most
520 getstr(FILE *fp
, char *buf
, size_t bufsize
)
525 for (i
= 0; i
< bufsize
- 1; i
++) {
527 if (c
== EOF
|| c
== '\0' || !isascii(c
))
550 (void) fprintf(stderr
, "usage: %s [-i] [-p 1|2|3] [-r] lintobj"
551 " [ lintobj ... ]\n", progname
);
557 info(const char *format
, ...)
560 static int complete
= 1;
563 (void) printf("%*s", indentlevel
, "");
565 va_start(alist
, format
);
566 (void) vprintf(format
, alist
);
569 complete
= strrchr(format
, '\n') != NULL
;
574 infohdr(const char *hdr
, const char *format
, ...)
577 static int complete
= 1;
580 (void) printf("%7s: ", hdr
);
582 va_start(alist
, format
);
583 (void) vprintf(format
, alist
);
586 complete
= strrchr(format
, '\n') != NULL
;
591 warn(const char *format
, ...)
594 char *errstr
= strerror(errno
);
596 (void) fprintf(stderr
, "%s: warning: ", progname
);
598 va_start(alist
, format
);
599 (void) vfprintf(stderr
, format
, alist
);
602 if (strrchr(format
, '\n') == NULL
)
603 (void) fprintf(stderr
, ": %s\n", errstr
);
608 die(const char *format
, ...)
611 char *errstr
= strerror(errno
);
613 (void) fprintf(stderr
, "%s: fatal: ", progname
);
615 va_start(alist
, format
);
616 (void) vfprintf(stderr
, format
, alist
);
619 if (strrchr(format
, '\n') == NULL
)
620 (void) fprintf(stderr
, ": %s\n", errstr
);