diff options
author | meem <none@none> | 2006-06-16 20:17:06 -0700 |
---|---|---|
committer | meem <none@none> | 2006-06-16 20:17:06 -0700 |
commit | 34c989574817eca41f72a5f02c848e51cfef32f0 (patch) | |
tree | 1a0692ebd8e11a4ae32e734a2babfc14b14a4da2 /usr/src | |
parent | 51fd492135573005d200c766ef62f709b4cb312c (diff) | |
download | illumos-joyent-34c989574817eca41f72a5f02c848e51cfef32f0.tar.gz |
6433092 ON needs a tool for dumping lint libraries
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/tools/Makefile | 4 | ||||
-rw-r--r-- | usr/src/tools/README.tools | 15 | ||||
-rw-r--r-- | usr/src/tools/SUNWonbld/prototype_com | 2 | ||||
-rw-r--r-- | usr/src/tools/lintdump/Makefile | 44 | ||||
-rw-r--r-- | usr/src/tools/lintdump/lintdump.1 | 313 | ||||
-rw-r--r-- | usr/src/tools/lintdump/lintdump.c | 615 | ||||
-rw-r--r-- | usr/src/tools/lintdump/lnstuff.h | 111 |
7 files changed, 1096 insertions, 8 deletions
diff --git a/usr/src/tools/Makefile b/usr/src/tools/Makefile index 1c3b37e33b..3bf6dcf572 100644 --- a/usr/src/tools/Makefile +++ b/usr/src/tools/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -45,6 +45,7 @@ COMMON_SUBDIRS= \ pmodes \ gk \ install.bin \ + lintdump \ protocmp \ protolist \ scripts @@ -67,6 +68,7 @@ LINTSUBDIRS= \ ctf \ cw \ findunref \ + lintdump \ protocmp \ protolist diff --git a/usr/src/tools/README.tools b/usr/src/tools/README.tools index 47e76a4c1f..149f7e4279 100644 --- a/usr/src/tools/README.tools +++ b/usr/src/tools/README.tools @@ -2,9 +2,8 @@ # CDDL HEADER START # # The contents of this file are subject to the terms of the -# Common Development and Distribution License, Version 1.0 only -# (the "License"). You may not use this file except in compliance -# with the License. +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -187,6 +186,9 @@ install.bin intf_check detects and reports ABI versioning and stability problems. +lintdump + dumps the contents of one or more lint libraries; see lintdump(1) + keywords checks files for proper SCCS keywords. @@ -289,6 +291,5 @@ Files you have to update to add a tool 1. Add the tool in its appropriate place. 2. Update the Makefile as required. 3. Update usr/src/tools/SUNWonbld/prototype_*. -4. Update usr/src/pkgdefs/etc/exception_list_*. -5. Update usr/src/tools/README.tools (this file). -6. Repeat 1-5 for any man pages. +4. Update usr/src/tools/README.tools (this file). +5. Repeat 1-4 for any man pages. diff --git a/usr/src/tools/SUNWonbld/prototype_com b/usr/src/tools/SUNWonbld/prototype_com index 3f23ea599b..a50f3e0412 100644 --- a/usr/src/tools/SUNWonbld/prototype_com +++ b/usr/src/tools/SUNWonbld/prototype_com @@ -75,6 +75,7 @@ f none opt/onbld/bin/hdrchk 555 root bin f none opt/onbld/bin/intf_check 555 root bin f none opt/onbld/bin/jstyle 555 root bin f none opt/onbld/bin/keywords 555 root bin +f none opt/onbld/bin/lintdump 555 root bin f none opt/onbld/bin/makebfu 555 root bin f none opt/onbld/bin/make_pkg_db 555 root bin f none opt/onbld/bin/mkacr 555 root bin @@ -121,6 +122,7 @@ f none opt/onbld/man/man1/cw.1 644 root bin f none opt/onbld/man/man1/flg.flp.1 644 root bin f none opt/onbld/man/man1/get_depend_info.1 644 root bin f none opt/onbld/man/man1/intf_check.1 644 root bin +f none opt/onbld/man/man1/lintdump.1 644 root bin f none opt/onbld/man/man1/make_pkg_db.1 644 root bin f none opt/onbld/man/man1/mkacr.1 644 root bin f none opt/onbld/man/man1/nightly.1 644 root bin diff --git a/usr/src/tools/lintdump/Makefile b/usr/src/tools/lintdump/Makefile new file mode 100644 index 0000000000..ddd756bef9 --- /dev/null +++ b/usr/src/tools/lintdump/Makefile @@ -0,0 +1,44 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PROG = lintdump +MAN1FILES = lintdump.1 +CFLAGS += $(CCVERBOSE) + +include ../Makefile.tools + +.KEEP_STATE: + +all: $(PROG) + +install: all .WAIT $(ROOTONBLDMACHPROG) $(ROOTONBLDMAN1FILES) + +lint: lint_PROG + +clean: + +include ../Makefile.targ diff --git a/usr/src/tools/lintdump/lintdump.1 b/usr/src/tools/lintdump/lintdump.1 new file mode 100644 index 0000000000..00747e8004 --- /dev/null +++ b/usr/src/tools/lintdump/lintdump.1 @@ -0,0 +1,313 @@ +.\" ident "%Z%%M% %I% %E% SMI" +.\" " CDDL HEADER START +.\" " +.\" " The contents of this file are subject to the terms of the +.\" " Common Development and Distribution License (the "License"). +.\" " You may not use this file except in compliance with the License. +.\" " +.\" " You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" " or http://www.opensolaris.org/os/licensing. +.\" " See the License for the specific language governing permissions +.\" " and limitations under the License. +.\" " +.\" " When distributing Covered Code, include this CDDL HEADER in each +.\" " file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" " If applicable, add the following below this CDDL HEADER, with the +.\" " fields enclosed by brackets "[]" replaced with your own identifying +.\" " information: Portions Copyright [yyyy] [name of copyright owner] +.\" " +.\" " CDDL HEADER END +.\" " +.\" "Copyright 2006 Sun Microsystems, Inc. All rights reserved. +.\" "Use is subject to license terms." +.TH lintdump 1 "04 Jun 2006" +.I lintdump +\- dump the contents of one or more lint libraries +.SH SYNOPSIS +\fBlintdump [-i] [-p 1|2|3] [-r] \fIlintlib\fP [ \fIlintlib\fP ... ] +.LP +.SH DESCRIPTION +.IX "OS-Net build tools" "lintdump" "" "\fBlintdump\fP" +.LP +The lintdump utility dumps the contents of one or more lint +libraries. This is chiefly useful when trying to understand the cause of +unexpected or obtuse lint warnings (see EXAMPLES), but can also be used to +find differences between lint libraries across builds or releases, or to +debug problems in lint itself. +.LP +A lint library is a binary object constructed using the "-o" option to +lint(1). The format of a lint library is unstable and subject to change +at any time, but its current structure is summarized here in order to aid +in understanding the current output of lintdump. A lint library is +consists of a header and four sections, called PASS1, PASS2, PASS3, and +STRINGS. Generally speaking, PASS1 contains definitions, PASS2 contains +declarations, and PASS3 contains information on whether or how functions +or variables are used. The STRINGS section holds the strings for +printf(3C)/scanf(3C) checking. +.LP +Each PASS section consists of a sequence of binary records of assorted +types. The sequence of records is further partitioned by FILE records, +which indicate the source or header file that is responsible for the +records that follow. The remaining record types provide lint with +information about the functions, variables, and structures defined or used +by the library. +.SH OPTIONS +.TP 10 +.B -i +Do not output structure tag IDs (see EXAMPLES). +.TP 10 +.B -p 1|2|3 +Just output the PASS1, PASS2, or PASS3 section. +.TP 10 +.B -r +Output records using relative paths (see EXAMPLES). +.LP +.SH OUTPUT +.LP +The contents of each specified \fIlintlib\fP is dumped in command-line +order. For each \fIlintlib\fP, lintdump outputs a single line beginning +with "LINTLIB:" that provides its name, module ID, the size of its PASS1, +PASS2, PASS3, STRING sections, and its total size, in that order. +.LP +Next, unless the -p option is used, the contents of the PASS1, PASS2, and +PASS3 sections are dumped, in order. Before each section is dumped, +lintdump outputs a single line beginning with "SECTION:" that +provides the name and size of the section. For each section, +lintdump outputs each record in order. The display format of each +record depends on its type: +.LP +.B FILE RECORDS +.RS 4 +Each FILE record is displayed on a single line beginning with "FILE:". +Note that FILE records are often found in pairs, the first providing the +absolute path to the file. FILE records containing absolute paths are +omitted if -r is used. Other record types following a FILE record are +indented to show their relationship to the FILE record. +.RE +.LP +.B FUNCTION AND VARIABLE RECORDS +.RS 4 +Each function or variable record is displayed on a single line using an +extended version of the format used in The C Programming Language, Second +Edition. In particular, properties contained in the record that cannot be +conveyed in C are displayed in angle brackets following definition or +declaration; a full list of these and their meanings are given below in +RECORD PROPERTIES. In addition, note that some structures or unions may +only be known by a numeric \fIID\fP, and thus output as "<struct tag +\fIID\fP>". This ID can be used to pair the structure with its definition +via structure records. If -i is used, then "<struct anon>" is printed +instead. +.RE +.LP +.B STRUCTURE AND UNION RECORDS +.RS 4 +Each structure or union record is displayed using an extended version of +the standard multi-line format used in The C Programming Language, Second +Edition. In particular, to facilitate problem analysis, unless -i is +used, each structure or union definition includes a numeric ID enclosed in +angle-brackets, such as "struct FILE <tag 1298> {". +.RE +.LP +To illustrate each of the common record formats, suppose the following +lint library is built: +.LP +.nf +$ cat > liba.c +/* LINTLIBRARY */ +/* PROTOLIB1 */ +int af(int); +struct as { + char as_name[32]; + int as_flag; +} as; +$ lint -oa liba.c +.fi +.LP +Then lintdump will produce the following output: +.LP +.nf +LINTLIB: llib-la.ln <mid 6484> 268+24+130+9 = 431 bytes +SECTION: PASS1: 268 bytes + FILE: /home/meem/hacks/liba.c + FILE: liba.c + extern int af(int); + struct as as; + struct as <tag 98> { + char as_name[]; + int as_flag; + }; +SECTION: PASS2: 24 bytes +SECTION: PASS3: 130 bytes + FILE: /home/meem/hacks/liba.c + FILE: liba.c + int af(void) <returns value>; +.fi +.LP +.SH RECORD PROPERTIES +.LP +As discussed in OUTPUT, some records are displayed using an extended +format to convey information that cannot be expressed in C. The following +extended information may be displayed: +.RE +.LP +.B <PRINTFLIKE\fIn\fP> +.RS 4 +Indicates to lint that argument \fIn\fP to the variable-argument function +is a format string in printf(3C) format, which enhances lint's argument +checking. +.RE +.LP +.B <SCANFLIKE\fIn\fP> +.RS 4 +Indicates to lint that argument \fIn\fP to the variable-argument function +is a format string in scanf(3C) format, which enhances lint's argument +checking. +.RE +.LP +.B <definition> +.RS 4 +Indicates to lint that this record represents the definition of the given +variable or function (rather than a declaration). +.RE +.LP +.B <use: side-effects context> +.RS 4 +Indicates to lint that the associated function is called in a context that +suggests it has side effects. +.RE +.LP +.B <use: return value context> +.RS 4 +Indicates to lint that the associated function is called in a context where +its return value is used. +.RE +.LP +.B <use: unspecified context> +.RS 4 +Indicates to lint that the associated function is used in an unspecified +manner. +.RE +.LP +.B <returns value> +.RS 4 +Indicates to lint that the function returns a value. +.RE +.LP +.SH EXAMPLES +.LP +One common problem is that lint does not always provide sufficient +information to understand the reason for a type mismatch. For instance, +sometimes lint will confusingly report a type mismatch between +apparently-identical types: +.LP +.nf +$ lint msghdr.c -lsocket +function argument ( number ) used inconsistently + recvmsg (arg 2) llib-lsocket:socket.h(437) struct msghdr * :: + msghdr.c(12) struct msghdr * +.fi +.LP +By using lintdump, we can pinpoint the problem by examining both +definitions for \fIstruct msghdr\fP: +.LP +.nf +$ lintdump /lib/llib-lsocket.ln + \fI[ ... ]\fP + FILE: llib-lsocket:socket.h + struct msghdr <tag 4532> { + void *msg_name; + unsigned int msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + \fBchar *msg_accrights;\fP + \fBint msg_accrightslen;\fP + }; +.fi +.LP +.nf +$ lint -omsghdr msghdr.c -lsocket +$ lintdump llib-lmsghdr.ln + \fI[ ... ]\fP + FILE: socket.h + struct msghdr <tag 1315> { + void *msg_name; + unsigned int msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + \fBvoid *msg_control;\fP + \fBunsigned int msg_controllen;\fP + \fBint msg_flags;\fP + }; +.fi +.LP +Looking at <sys/socket.h>, the problem becomes apparent: the structure +changes depending on compile-time options, which clearly differ between +the application and the library: +.LP +.nf +struct msghdr { + void *msg_name; + socklen_t msg_namelen; + struct iovec *msg_iov; + int msg_iovlen; + +#if defined(_XPG4_2) || defined(_KERNEL) + void *msg_control; + socklen_t msg_controllen; + int msg_flags; +#else + caddr_t msg_accrights; + int msg_accrightslen; +#endif /* defined(_XPG4_2) || defined(_KERNEL) */ +}; +.fi +.LP +Another use of lintdump is to compare two versions of a lint library to +see whether anything of significance has changed. For instance, lintdump +can be used to understand why a lint library is different between a +project gate and a patch gate, and thus to determine whether the library +will need to be redelivered in the patch including the project: +.LP +.nf +$ PATCHROOT=/ws/on10-patch/proto/root_i386 +$ diff llib-lkstat.ln $PATCHROOT/lib/llib-lkstat.ln +Binary files llib-lkstat.ln and + /ws/on10-patch/proto/root_i386/lib/llib-lkstat.ln differ +$ lintdump -ir llib-lkstat.ln > /tmp/proj-kstat.out +$ lintdump -ir $PATCHROOT/lib/llib-lkstat.ln > /tmp/patch-kstat.out +.fi +.LP +.nf +$ diff /tmp/patch-kstat.out /tmp/proj-kstat.out +1,2c1,2 +< LINTLIB: llib-lkstat.ln <mid 3675> 4995+26812+1045+9 = 32861 bytes +< SECTION: PASS1: 4995 bytes +--- +> LINTLIB: llib-lkstat.ln <mid 39982> 5144+27302+1057+9 = 33512 bytes +> SECTION: PASS1: 5144 bytes +19c19 +< unsigned char _file; +--- +> unsigned char _magic; +22a23,24 +> unsigned int __extendedfd; +> unsigned int __xf_nocheck; +\fI[ ... ]\fP +.fi +.LP +Note that -r option removes spurious differences that would otherwise +arise from different absolute paths to the same source file, and the -i +option removes spurious differences due to ID generation inside lint. +.LP +.SH SEE ALSO +.LP +.IR lint(1), +.IR printf(3C), +.IR scanf(3C) +.SH NOTES +This utility is provided as an interim solution until a stable utility +can be bundled with Sun Studio. As such, any use of this utility in +scripts or embedded inside programs should be done with knowledge that +subsequent changes will be required in order to transition to the stable +solution. + diff --git a/usr/src/tools/lintdump/lintdump.c b/usr/src/tools/lintdump/lintdump.c new file mode 100644 index 0000000000..48308d1570 --- /dev/null +++ b/usr/src/tools/lintdump/lintdump.c @@ -0,0 +1,615 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "@(#)lintdump.c 1.6 06/06/04 SMI (from meem)" +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Tool for dumping lint libraries. + */ + +#include <ctype.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "lnstuff.h" /* silly header name from alint */ + +typedef struct lsu { + const char *name; + ATYPE atype; + struct lsu *next; +} lsu_t; + +#define LSU_HASHSIZE 512 +static lsu_t *lsu_table[LSU_HASHSIZE]; + +static boolean_t showids = B_TRUE; +static boolean_t justrelpaths = B_FALSE; +static int justpass = -1; +static int indentlevel = 9; +static const char *progname; + +static void info(const char *, ...); +static void infohdr(const char *, const char *, ...); +static void warn(const char *, ...); +static void die(const char *, ...); +static void usage(void); +static void indent(void); +static void unindent(void); +static void print_lintlib(const char *, FILE *, FLENS *); +static void print_pass(FILE *); +static void print_atype(ATYPE *, int, ATYPE *, const char *); +static void print_mods(const char *, ATYPE *, int, ATYPE *, uint_t); +static void getstr(FILE *, char *, size_t); +static void lsu_build(FILE *); +static void lsu_empty(void); +static int lsu_add(const char *, ATYPE *); +static lsu_t *lsu_lookup(unsigned long); + +int +main(int argc, char **argv) +{ + int i, c; + FILE *fp; + FLENS hdr; + + progname = strrchr(argv[0], '/'); + if (progname == NULL) + progname = argv[0]; + else + progname++; + + while ((c = getopt(argc, argv, "ip:r")) != EOF) { + switch (c) { + case 'i': + showids = B_FALSE; + break; + case 'p': + justpass = strtoul(optarg, NULL, 0); + if (justpass < 1 || justpass > 3) + usage(); + break; + case 'r': + justrelpaths = B_TRUE; + break; + default: + usage(); + } + } + + if (optind == argc) + usage(); + + for (i = optind; i < argc; i++) { + fp = fopen(argv[i], "r"); + if (fp == NULL) { + warn("cannot open \"%s\"", argv[i]); + continue; + } + + if (fread(&hdr, sizeof (hdr), 1, fp) < 1) { + warn("%s: cannot read lint library header\n", argv[i]); + (void) fclose(fp); + continue; + } + + if (hdr.ver != LINTVER) { + warn("%s: lint library version %d unsupported\n", + argv[i], hdr.ver); + (void) fclose(fp); + continue; + } + + /* + * First build the table of structure/union names, then seek + * back to the start and print the lint library. Finally, + * empty the table out before dumping the next library. + */ + lsu_build(fp); + (void) fseek(fp, sizeof (hdr), SEEK_SET); + print_lintlib(argv[i], fp, &hdr); + (void) fclose(fp); + lsu_empty(); + } + + return (EXIT_SUCCESS); +} + +/* + * Print a lint library. + */ +static void +print_lintlib(const char *lnname, FILE *fp, FLENS *hp) +{ + off_t passoff = 0; + ulong_t psizes[4]; + uint_t pass; + + psizes[0] = 0; + psizes[1] = hp->f1; + psizes[2] = hp->f2; + psizes[3] = hp->f3; + + if (justrelpaths && lnname[0] == '/') + lnname = strrchr(lnname, '/') + 1; + + infohdr("LINTLIB", "%s <mid %hu> %lu+%lu+%lu+%lu = %lu bytes\n", lnname, + hp->mno, hp->f1, hp->f2, hp->f3, hp->f4, + hp->f1 + hp->f2 + hp->f3 + hp->f4); + + for (pass = 1; pass <= 3; pass++) { + if (justpass < 0 || justpass == pass) { + infohdr("SECTION", "PASS%u: %lu bytes\n", pass, + psizes[pass]); + print_pass(fp); + } + passoff += psizes[pass]; + (void) fseek(fp, passoff, SEEK_SET); + } +} + +/* + * Print out a PASS section of a lint library. + */ +static void +print_pass(FILE *fp) +{ + union rec rec; + int nargs; + char name[1024]; + ATYPE atype, *args; + LINE line; + boolean_t wasfile = B_FALSE; + + for (;;) { + if (fread(&rec, sizeof (rec), 1, fp) != 1) + die("unexpected end of data stream\n"); + + line = rec.l; + if (line.decflag & LND) /* end-of-pass marker */ + break; + + getstr(fp, name, sizeof (name)); + + /* + * Check if this is a file record. + */ + if (line.decflag & LFN) { + if (wasfile || !justrelpaths) + infohdr("FILE", "%s\n", name); + wasfile = B_TRUE; + continue; + } + wasfile = B_FALSE; + + /* + * Check if this is a function or variable record. + */ + nargs = line.nargs; + if (line.decflag & (LIB|LDS|LDI|LPR|LDX|LDC|LRV|LUE|LUV|LUM)) { + if (nargs < 0) + nargs = -nargs - 1; + + if (line.decflag & LDS) + info("static "); + else if (line.decflag & (LPR|LDX|LDC)) + info("extern "); + + args = calloc(sizeof (atype), nargs); + if (args == NULL) + die("cannot allocate argument information"); + + if (fread(args, sizeof (atype), nargs, fp) != nargs) + die("unexpected end of data stream\n"); + + print_atype(&line.type, line.nargs, args, name); + free(args); + + if (line.decflag & LRV) + info(" <returns value>"); + if (line.decflag & LUE) + info(" <use: side-effects context>"); + if (line.decflag & LUV) + info(" <use: return value context>"); + if (line.decflag & LUM) + info(" <use: unspecified context>"); + + if (line.decflag & LPF) + info(" <PRINTFLIKE%d>", nargs); + else if (line.decflag & LSF) + info(" <SCANFLIKE%d>", nargs); + + if (line.decflag & LDI) + info(" { <definition> }"); + else if (line.decflag & LDX) + info(" = <definition>"); + + info(";\n"); + continue; + } + + /* + * Check if this is a structure or union record. + */ + if (line.decflag & LSU) { + if (line.decflag & ~(LSU)) + info("??? "); + + info("struct %s ", name); + if (showids) + info("<tag %lu> ", line.type.extra.ty); + info("{ \n"); + + indent(); + for (; nargs > 0; nargs--) { + if (fread(&atype, sizeof (atype), 1, fp) != 1) + die("unexpected end of data stream\n"); + + getstr(fp, name, sizeof (name)); + print_atype(&atype, 0, NULL, name); + info(";\n"); + } + unindent(); + info("};\n"); + continue; + } + + warn("unknown record type 0%o\n", line.decflag); + } +} + +/* + * Print the C datatype or function `atp' named `name'. If `name' is a + * function, then `nargs' indicates the number of C datatypes pointed to + * by `args'. + */ +static void +print_atype(ATYPE *atp, int nargs, ATYPE *args, const char *name) +{ + static const char *basetypes[] = { "", + "char", "unsigned char", "signed char", + "short", "unsigned short", "signed short", + "int", "unsigned int", "signed int", + "long", "unsigned long", "signed long", + "long long", "unsigned long long", "signed long long", + "enum", "float", "double", + "long double", "void", "struct", + "union", "_Bool", "<genchar>", + "<genshort>", "<genint>", "<genlong>", + "<genlonglong>" + }; + uint16_t basetype = atp->aty & LNQUAL; + lsu_t *lsup; + + if (atp->aty & LCON) + info("const "); + if (atp->aty & LVOL) + info("volatile "); + if (atp->aty & LCONV) + info("integer const "); + + if (basetype < 1 || + basetype > (sizeof (basetypes) / sizeof (*basetypes))) + info("<unknown type %x>", basetype); + + switch (basetype) { + case LN_UNION: + case LN_STRUCT: + lsup = lsu_lookup(atp->extra.ty); + if (lsup != NULL && lsup->name[0] != '.') { + info("%s %s", basetypes[basetype], lsup->name); + } else { + info("%s", basetypes[basetype]); + if (showids) + info(" <tag %lu>", atp->extra.ty); + else + info(" <anon>"); + } + break; + default: + info(basetypes[basetype]); + }; + + print_mods(name, atp, nargs, args, 14); +} + +/* + * Recursively print type modifiers. + */ +static void +print_mods(const char *name, ATYPE *atp, int nargs, ATYPE *args, uint_t pos) +{ + int arg; + int mods = atp->dcl_mod >> (pos * 2); + int lastmods = atp->dcl_mod >> ((pos + 1) * 2); + boolean_t isvarargs = B_FALSE; + + if (LN_ISPTR(mods)) { + if (!LN_ISPTR(lastmods) && !LN_ISFTN(lastmods)) + info(" "); + info("*"); + } + + if (atp->dcl_con & (1 << pos)) + info(" const "); + if (atp->dcl_vol & (1 << pos)) + info(" volatile "); + + if (pos != 0) { + if (LN_ISFTN(mods)) + info(" ("); + print_mods(name, atp, nargs, args, pos - 1); + if (LN_ISFTN(mods)) + info(")()"); + return; + } + + if (name[0] == '\0') + return; + + if (!LN_ISPTR(lastmods) && !LN_ISPTR(mods)) + info(" "); + info("%s", name); + + if (LN_ISARY(mods)) { + info("[]"); + } else if (LN_ISFTN(mods)) { + info("("); + + if (nargs < 0) { + nargs = -nargs - 1; + isvarargs = B_TRUE; + } + + if (nargs == 0) { + info("void"); + } else { + for (arg = 0; arg < nargs; arg++) { + print_atype(&args[arg], 0, NULL, ""); + if ((arg + 1) < nargs) + info(", "); + else if (isvarargs) + info(", ..."); + } + } + info(")"); + } +} + +/* + * Add an LSU entry to the LSU table. + */ +static int +lsu_add(const char *name, ATYPE *atp) +{ + unsigned int i = atp->extra.ty % LSU_HASHSIZE; + lsu_t *lsup; + + lsup = malloc(sizeof (lsu_t)); + if (lsup == NULL) + return (ENOMEM); + + lsup->atype = *atp; + lsup->next = lsu_table[i]; + lsup->name = strdup(name); + if (lsup->name == NULL) { + free(lsup); + return (ENOMEM); + } + + lsu_table[i] = lsup; + return (0); +} + +/* + * Lookup an LSU entry by ID. + */ +static lsu_t * +lsu_lookup(T1WORD ty) +{ + unsigned int i = ty % LSU_HASHSIZE; + lsu_t *lsup; + + for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup->next) { + if (lsup->atype.extra.ty == ty) + return (lsup); + } + + return (NULL); +} + +/* + * Read all LSU (structure and union definition) records in order to + * build a structure and union name table, called the LSU table. + */ +static void +lsu_build(FILE *fp) +{ + union rec rec; + char name[1024]; + int nargs; + + for (;;) { + if (fread(&rec, sizeof (rec), 1, fp) != 1) + return; + + if (rec.l.decflag & LND) /* end-of-pass marker */ + break; + + getstr(fp, name, sizeof (name)); + nargs = rec.l.nargs; + + if (rec.l.decflag & (LIB|LDS|LDI)) { + if (nargs < 0) + nargs = -nargs - 1; + + (void) fseek(fp, sizeof (ATYPE) * nargs, SEEK_CUR); + continue; + } + + if (rec.l.decflag & LSU) { + if (lsu_add(name, &rec.l.type) != 0) + warn("cannot allocate struct `%s' info", name); + + for (; nargs > 0; nargs--) { + (void) fseek(fp, sizeof (ATYPE), SEEK_CUR); + getstr(fp, name, sizeof (name)); + } + } + } +} + +/* + * Empty the LSU table. + */ +static void +lsu_empty(void) +{ + lsu_t *lsup, *lsup_next; + unsigned int i; + + for (i = 0; i < LSU_HASHSIZE; i++) { + for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup_next) { + lsup_next = lsup->next; + free(lsup); + } + lsu_table[i] = NULL; + } +} + +/* + * Read the NUL-terminated string at `fp' into `buf', which is at most + * `bufsize' bytes. + */ +static void +getstr(FILE *fp, char *buf, size_t bufsize) +{ + int c; + size_t i; + + for (i = 0; i < bufsize - 1; i++) { + c = fgetc(fp); + if (c == EOF || c == '\0' || !isascii(c)) + break; + buf[i] = (char)c; + } + + buf[i] = '\0'; +} + +static void +indent(void) +{ + indentlevel += 4; +} + +static void +unindent(void) +{ + indentlevel -= 4; +} + +static void +usage(void) +{ + (void) fprintf(stderr, "usage: %s [-i] [-p 1|2|3] [-r] lintlib" + " [ lintlib ... ]\n", progname); + exit(EXIT_FAILURE); +} + +/* PRINTFLIKE1 */ +static void +info(const char *format, ...) +{ + va_list alist; + static int complete = 1; + + if (complete) + (void) printf("%*s", indentlevel, ""); + + va_start(alist, format); + (void) vprintf(format, alist); + va_end(alist); + + complete = strrchr(format, '\n') != NULL; +} + +/* PRINTFLIKE2 */ +static void +infohdr(const char *hdr, const char *format, ...) +{ + va_list alist; + static int complete = 1; + + if (complete) + (void) printf("%7s: ", hdr); + + va_start(alist, format); + (void) vprintf(format, alist); + va_end(alist); + + complete = strrchr(format, '\n') != NULL; +} + +/* PRINTFLIKE1 */ +static void +warn(const char *format, ...) +{ + va_list alist; + char *errstr = strerror(errno); + + (void) fprintf(stderr, "%s: warning: ", progname); + + va_start(alist, format); + (void) vfprintf(stderr, format, alist); + va_end(alist); + + if (strrchr(format, '\n') == NULL) + (void) fprintf(stderr, ": %s\n", errstr); +} + +/* PRINTFLIKE1 */ +static void +die(const char *format, ...) +{ + va_list alist; + char *errstr = strerror(errno); + + (void) fprintf(stderr, "%s: fatal: ", progname); + + va_start(alist, format); + (void) vfprintf(stderr, format, alist); + va_end(alist); + + if (strrchr(format, '\n') == NULL) + (void) fprintf(stderr, ": %s\n", errstr); + + exit(EXIT_FAILURE); +} diff --git a/usr/src/tools/lintdump/lnstuff.h b/usr/src/tools/lintdump/lnstuff.h new file mode 100644 index 0000000000..b772c58f92 --- /dev/null +++ b/usr/src/tools/lintdump/lnstuff.h @@ -0,0 +1,111 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1989 AT&T */ +/* All Rights Reserved */ + +/* + * Based on @(#)lnstuff.h 1.5 02/06/05 from lint + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef LNSTUFF_H +#define LNSTUFF_H + +#include <sys/types.h> + +#define LDI 01 /* defined and initialized: storage set aside */ +#define LIB 02 /* defined on a library */ +#define LDC 04 /* defined as a common region on UNIX */ +#define LDX 010 /* defined by an extern: if ! pflag, same as LDI */ +#define LRV 020 /* function returns a value */ +#define LUV 040 /* function used in a value context */ +#define LUE 0100 /* function used in effects context */ +#define LUM 0200 /* mentioned somewhere other than at the declaration */ +#define LDS 0400 /* defined static object (like LDI) */ +#define LFN 01000 /* filename record */ +#define LSU 02000 /* struct/union def */ +#define LPR 04000 /* prototype declaration */ +#define LND 010000 /* end module marker */ +#define LPF 020000 /* printf like */ +#define LSF 040000 /* scanf like */ + +#define LNQUAL 00037 /* type w/o qualifiers */ +#define LNUNQUAL 0174000 /* remove type, keep other info */ +#define LCON (1<<15) /* type qualified by const */ +#define LVOL (1<<14) /* type qualified by volatile */ +#define LNOAL (1<<13) /* not used */ +#define LCONV (1<<12) /* type is an integer constant */ +#define LPTR (1<<11) /* last modifier is a pointer */ +#define LINTVER 4 + +typedef unsigned long T1WORD; +typedef long FILEPOS; +typedef short TY; + +typedef struct flens { + long f1, f2, f3, f4; + unsigned short ver, mno; +} FLENS; + +typedef struct { + TY aty; /* base type */ + unsigned long dcl_mod; /* ptr/ftn/ary modifiers */ + unsigned short dcl_con; /* const qualifiers */ + unsigned short dcl_vol; /* volatile qualifiers */ + union { + T1WORD ty; + FILEPOS pos; + } extra; +} ATYPE; + +typedef struct { + short decflag; /* what type of record is this */ + short nargs; /* # of args (or members) */ + int fline; /* line defined/used in */ + ATYPE type; /* type information */ +} LINE; + +union rec { + LINE l; + struct { + short decflag; + char *fn; + } f; +}; + +/* type modifiers */ +#define LN_TMASK 3 +#define LN_ISPTR(x) (((x)&LN_TMASK) == 1) /* is x a pointer type */ +#define LN_ISFTN(x) (((x)&LN_TMASK) == 2) /* is x a function type */ +#define LN_ISARY(x) (((x)&LN_TMASK) == 3) /* is x an array type */ + +/* type numbers for pass2 */ +#define LN_STRUCT 21 /* generic struct */ +#define LN_UNION 22 /* generic union */ + +#endif /* LNSTUFF_H */ |