summaryrefslogtreecommitdiff
path: root/usr/src/tools/lintdump/lintdump.c
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/tools/lintdump/lintdump.c
parent51fd492135573005d200c766ef62f709b4cb312c (diff)
downloadillumos-joyent-34c989574817eca41f72a5f02c848e51cfef32f0.tar.gz
6433092 ON needs a tool for dumping lint libraries
Diffstat (limited to 'usr/src/tools/lintdump/lintdump.c')
-rw-r--r--usr/src/tools/lintdump/lintdump.c615
1 files changed, 615 insertions, 0 deletions
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);
+}