summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authormeem <none@none>2006-06-16 20:17:06 -0700
committermeem <none@none>2006-06-16 20:17:06 -0700
commit34c989574817eca41f72a5f02c848e51cfef32f0 (patch)
tree1a0692ebd8e11a4ae32e734a2babfc14b14a4da2 /usr/src
parent51fd492135573005d200c766ef62f709b4cb312c (diff)
downloadillumos-joyent-34c989574817eca41f72a5f02c848e51cfef32f0.tar.gz
6433092 ON needs a tool for dumping lint libraries
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/tools/Makefile4
-rw-r--r--usr/src/tools/README.tools15
-rw-r--r--usr/src/tools/SUNWonbld/prototype_com2
-rw-r--r--usr/src/tools/lintdump/Makefile44
-rw-r--r--usr/src/tools/lintdump/lintdump.1313
-rw-r--r--usr/src/tools/lintdump/lintdump.c615
-rw-r--r--usr/src/tools/lintdump/lnstuff.h111
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 */