xref: /titanic_52/usr/src/tools/lintdump/lintdump.c (revision fa5e8906f3e76cdbc7921f3f3e6976469620aae3)
134c98957Smeem /*
234c98957Smeem  * CDDL HEADER START
334c98957Smeem  *
434c98957Smeem  * The contents of this file are subject to the terms of the
534c98957Smeem  * Common Development and Distribution License (the "License").
634c98957Smeem  * You may not use this file except in compliance with the License.
734c98957Smeem  *
834c98957Smeem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
934c98957Smeem  * or http://www.opensolaris.org/os/licensing.
1034c98957Smeem  * See the License for the specific language governing permissions
1134c98957Smeem  * and limitations under the License.
1234c98957Smeem  *
1334c98957Smeem  * When distributing Covered Code, include this CDDL HEADER in each
1434c98957Smeem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1534c98957Smeem  * If applicable, add the following below this CDDL HEADER, with the
1634c98957Smeem  * fields enclosed by brackets "[]" replaced with your own identifying
1734c98957Smeem  * information: Portions Copyright [yyyy] [name of copyright owner]
1834c98957Smeem  *
1934c98957Smeem  * CDDL HEADER END
2034c98957Smeem  */
2134c98957Smeem 
2234c98957Smeem /*
23*fa5e8906Smeem  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2434c98957Smeem  * Use is subject to license terms.
2534c98957Smeem  */
2634c98957Smeem 
2734c98957Smeem #pragma ident	"@(#)lintdump.c	1.6	06/06/04 SMI (from meem)"
2834c98957Smeem #pragma ident	"%Z%%M%	%I%	%E% SMI"
2934c98957Smeem 
3034c98957Smeem /*
3134c98957Smeem  * Tool for dumping lint libraries.
3234c98957Smeem  */
3334c98957Smeem 
3434c98957Smeem #include <ctype.h>
3534c98957Smeem #include <errno.h>
3634c98957Smeem #include <stdarg.h>
3734c98957Smeem #include <stdio.h>
3834c98957Smeem #include <stdlib.h>
3934c98957Smeem #include <string.h>
4034c98957Smeem #include <sys/types.h>
4134c98957Smeem 
4234c98957Smeem #include "lnstuff.h"		/* silly header name from alint */
4334c98957Smeem 
4434c98957Smeem typedef struct lsu {
4534c98957Smeem 	const char	*name;
4634c98957Smeem 	ATYPE		atype;
4734c98957Smeem 	struct lsu	*next;
4834c98957Smeem } lsu_t;
4934c98957Smeem 
5034c98957Smeem #define	LSU_HASHSIZE	512
5134c98957Smeem static lsu_t		*lsu_table[LSU_HASHSIZE];
5234c98957Smeem 
5334c98957Smeem static boolean_t	showids = B_TRUE;
5434c98957Smeem static boolean_t	justrelpaths = B_FALSE;
5534c98957Smeem static int		justpass = -1;
5634c98957Smeem static int		indentlevel = 9;
5734c98957Smeem static const char	*progname;
5834c98957Smeem 
5934c98957Smeem static void info(const char *, ...);
6034c98957Smeem static void infohdr(const char *, const char *, ...);
6134c98957Smeem static void warn(const char *, ...);
6234c98957Smeem static void die(const char *, ...);
6334c98957Smeem static void usage(void);
6434c98957Smeem static void indent(void);
6534c98957Smeem static void unindent(void);
66*fa5e8906Smeem static void print_lintmod(const char *, FILE *, FLENS *);
67b4034a75Smeem static void print_pass(const char *, FILE *);
6834c98957Smeem static void print_atype(ATYPE *, int, ATYPE *, const char *);
6934c98957Smeem static void print_mods(const char *, ATYPE *, int, ATYPE *, uint_t);
7034c98957Smeem static void getstr(FILE *, char *, size_t);
7134c98957Smeem static void lsu_build(FILE *);
7234c98957Smeem static void lsu_empty(void);
7334c98957Smeem static int lsu_add(const char *, ATYPE *);
7434c98957Smeem static lsu_t *lsu_lookup(unsigned long);
7534c98957Smeem 
7634c98957Smeem int
7734c98957Smeem main(int argc, char **argv)
7834c98957Smeem {
79*fa5e8906Smeem 	int		i, c, mod;
8034c98957Smeem 	FILE		*fp;
8134c98957Smeem 	FLENS		hdr;
82*fa5e8906Smeem 	const char	*lnname;
8334c98957Smeem 
8434c98957Smeem 	progname = strrchr(argv[0], '/');
8534c98957Smeem 	if (progname == NULL)
8634c98957Smeem 		progname = argv[0];
8734c98957Smeem 	else
8834c98957Smeem 		progname++;
8934c98957Smeem 
9034c98957Smeem 	while ((c = getopt(argc, argv, "ip:r")) != EOF) {
9134c98957Smeem 		switch (c) {
9234c98957Smeem 		case 'i':
9334c98957Smeem 			showids = B_FALSE;
9434c98957Smeem 			break;
9534c98957Smeem 		case 'p':
9634c98957Smeem 			justpass = strtoul(optarg, NULL, 0);
9734c98957Smeem 			if (justpass < 1 || justpass > 3)
9834c98957Smeem 				usage();
9934c98957Smeem 			break;
10034c98957Smeem 		case 'r':
10134c98957Smeem 			justrelpaths = B_TRUE;
10234c98957Smeem 			break;
10334c98957Smeem 		default:
10434c98957Smeem 			usage();
10534c98957Smeem 		}
10634c98957Smeem 	}
10734c98957Smeem 
10834c98957Smeem 	if (optind == argc)
10934c98957Smeem 		usage();
11034c98957Smeem 
11134c98957Smeem 	for (i = optind; i < argc; i++) {
11234c98957Smeem 		fp = fopen(argv[i], "r");
11334c98957Smeem 		if (fp == NULL) {
11434c98957Smeem 			warn("cannot open \"%s\"", argv[i]);
11534c98957Smeem 			continue;
11634c98957Smeem 		}
11734c98957Smeem 
118*fa5e8906Smeem 		lnname = argv[i];
119*fa5e8906Smeem 		if (justrelpaths && lnname[0] == '/')
120*fa5e8906Smeem 			lnname = strrchr(lnname, '/') + 1;
12134c98957Smeem 
12234c98957Smeem 		/*
123*fa5e8906Smeem 		 * Dump out all of the modules in the lint object.
124*fa5e8906Smeem 		 */
125*fa5e8906Smeem 		for (mod = 1; fread(&hdr, sizeof (hdr), 1, fp) == 1; mod++) {
126*fa5e8906Smeem 			if (hdr.ver != LINTVER) {
127*fa5e8906Smeem 				warn("%s: unsupported lint object version "
128*fa5e8906Smeem 				    "%d\n", argv[i], hdr.ver);
129*fa5e8906Smeem 				break;
130*fa5e8906Smeem 			}
131*fa5e8906Smeem 
132*fa5e8906Smeem 			if (mod == 1)
133*fa5e8906Smeem 				infohdr("LINTOBJ", "%s\n", lnname);
134*fa5e8906Smeem 
135*fa5e8906Smeem 			/*
136*fa5e8906Smeem 			 * First build the table of structure/union names,
137*fa5e8906Smeem 			 * then print the lint module.  Finally, empty the
138*fa5e8906Smeem 			 * table out before dumping the next module.
13934c98957Smeem 			 */
14034c98957Smeem 			lsu_build(fp);
141*fa5e8906Smeem 			print_lintmod(lnname, fp, &hdr);
14234c98957Smeem 			lsu_empty();
14334c98957Smeem 		}
144*fa5e8906Smeem 		(void) fclose(fp);
145*fa5e8906Smeem 	}
14634c98957Smeem 
14734c98957Smeem 	return (EXIT_SUCCESS);
14834c98957Smeem }
14934c98957Smeem 
15034c98957Smeem /*
151*fa5e8906Smeem  * Print a lint module and advance past it in the stream.
15234c98957Smeem  */
15334c98957Smeem static void
154*fa5e8906Smeem print_lintmod(const char *lnname, FILE *fp, FLENS *hp)
15534c98957Smeem {
156*fa5e8906Smeem 	ulong_t		psizes[5];
15734c98957Smeem 	uint_t		pass;
15834c98957Smeem 
15934c98957Smeem 	psizes[0] = 0;
16034c98957Smeem 	psizes[1] = hp->f1;
16134c98957Smeem 	psizes[2] = hp->f2;
16234c98957Smeem 	psizes[3] = hp->f3;
163*fa5e8906Smeem 	psizes[4] = hp->f4;
16434c98957Smeem 
165*fa5e8906Smeem 	infohdr("LINTMOD", "%hu: %lu+%lu+%lu+%lu = %lu bytes\n", hp->mno,
166*fa5e8906Smeem 	    hp->f1, hp->f2, hp->f3, hp->f4, hp->f1 + hp->f2 + hp->f3 + hp->f4);
16734c98957Smeem 
168*fa5e8906Smeem 	for (pass = 1; pass <= 4; pass++) {
169*fa5e8906Smeem 		if ((justpass < 0 || justpass == pass) && pass < 4) {
17034c98957Smeem 			infohdr("SECTION", "PASS%u: %lu bytes\n", pass,
17134c98957Smeem 			    psizes[pass]);
172b4034a75Smeem 			print_pass(lnname, fp);
173*fa5e8906Smeem 		} else {
174*fa5e8906Smeem 			(void) fseek(fp, psizes[pass], SEEK_CUR);
17534c98957Smeem 		}
17634c98957Smeem 	}
17734c98957Smeem }
17834c98957Smeem 
17934c98957Smeem /*
180*fa5e8906Smeem  * Print out a PASS section of a lint module.
18134c98957Smeem  */
18234c98957Smeem static void
183b4034a75Smeem print_pass(const char *lnname, FILE *fp)
18434c98957Smeem {
18534c98957Smeem 	union rec	rec;
18634c98957Smeem 	int		nargs;
18734c98957Smeem 	char		name[1024];
18834c98957Smeem 	ATYPE		atype, *args;
18934c98957Smeem 	LINE		line;
19034c98957Smeem 	boolean_t	wasfile = B_FALSE;
19134c98957Smeem 
19234c98957Smeem 	for (;;) {
19334c98957Smeem 		if (fread(&rec, sizeof (rec), 1, fp) != 1)
194b4034a75Smeem 			die("%s: unexpected end of file\n", lnname);
19534c98957Smeem 
19634c98957Smeem 		line = rec.l;
19734c98957Smeem 		if (line.decflag & LND)		/* end-of-pass marker */
19834c98957Smeem 			break;
19934c98957Smeem 
20034c98957Smeem 		getstr(fp, name, sizeof (name));
20134c98957Smeem 
20234c98957Smeem 		/*
20334c98957Smeem 		 * Check if this is a file record.
20434c98957Smeem 		 */
20534c98957Smeem 		if (line.decflag & LFN) {
20634c98957Smeem 			if (wasfile || !justrelpaths)
20734c98957Smeem 				infohdr("FILE", "%s\n", name);
20834c98957Smeem 			wasfile = B_TRUE;
20934c98957Smeem 			continue;
21034c98957Smeem 		}
21134c98957Smeem 		wasfile = B_FALSE;
21234c98957Smeem 
21334c98957Smeem 		/*
21434c98957Smeem 		 * Check if this is a function or variable record.
21534c98957Smeem 		 */
21634c98957Smeem 		nargs = line.nargs;
21734c98957Smeem 		if (line.decflag & (LIB|LDS|LDI|LPR|LDX|LDC|LRV|LUE|LUV|LUM)) {
21834c98957Smeem 			if (nargs < 0)
21934c98957Smeem 				nargs = -nargs - 1;
22034c98957Smeem 
22134c98957Smeem 			if (line.decflag & LDS)
22234c98957Smeem 				info("static ");
22334c98957Smeem 			else if (line.decflag & (LPR|LDX|LDC))
22434c98957Smeem 				info("extern ");
22534c98957Smeem 
22634c98957Smeem 			args = calloc(sizeof (atype), nargs);
22734c98957Smeem 			if (args == NULL)
22834c98957Smeem 				die("cannot allocate argument information");
22934c98957Smeem 
23034c98957Smeem 			if (fread(args, sizeof (atype), nargs, fp) != nargs)
231b4034a75Smeem 				die("%s: unexpected end of file\n", lnname);
23234c98957Smeem 
23334c98957Smeem 			print_atype(&line.type, line.nargs, args, name);
23434c98957Smeem 			free(args);
23534c98957Smeem 
23634c98957Smeem 			if (line.decflag & LRV)
23734c98957Smeem 				info(" <returns value>");
23834c98957Smeem 			if (line.decflag & LUE)
23934c98957Smeem 				info(" <use: side-effects context>");
24034c98957Smeem 			if (line.decflag & LUV)
24134c98957Smeem 				info(" <use: return value context>");
24234c98957Smeem 			if (line.decflag & LUM)
24334c98957Smeem 				info(" <use: unspecified context>");
24434c98957Smeem 
24534c98957Smeem 			if (line.decflag & LPF)
24634c98957Smeem 				info(" <PRINTFLIKE%d>", nargs);
24734c98957Smeem 			else if (line.decflag & LSF)
24834c98957Smeem 				info(" <SCANFLIKE%d>", nargs);
24934c98957Smeem 
25034c98957Smeem 			if (line.decflag & LDI)
25134c98957Smeem 				info(" { <definition> }");
25234c98957Smeem 			else if (line.decflag & LDX)
25334c98957Smeem 				info(" = <definition>");
25434c98957Smeem 
25534c98957Smeem 			info(";\n");
25634c98957Smeem 			continue;
25734c98957Smeem 		}
25834c98957Smeem 
25934c98957Smeem 		/*
26034c98957Smeem 		 * Check if this is a structure or union record.
26134c98957Smeem 		 */
26234c98957Smeem 		if (line.decflag & LSU) {
26334c98957Smeem 			if (line.decflag & ~(LSU))
26434c98957Smeem 				info("??? ");
26534c98957Smeem 
2665cb4fc81Smeem 			info("struct ");
2675cb4fc81Smeem 			if (name[0] != '.')
2685cb4fc81Smeem 				info("%s ", name);
26934c98957Smeem 			if (showids)
27034c98957Smeem 				info("<tag %lu> ", line.type.extra.ty);
27134c98957Smeem 			info("{ \n");
27234c98957Smeem 
27334c98957Smeem 			indent();
27434c98957Smeem 			for (; nargs > 0; nargs--) {
275b4034a75Smeem 				if (fread(&atype, sizeof (atype), 1, fp) != 1) {
276b4034a75Smeem 					die("%s: unexpected end of file\n",
277b4034a75Smeem 					    lnname);
278b4034a75Smeem 				}
27934c98957Smeem 				getstr(fp, name, sizeof (name));
28034c98957Smeem 				print_atype(&atype, 0, NULL, name);
28134c98957Smeem 				info(";\n");
28234c98957Smeem 			}
28334c98957Smeem 			unindent();
28434c98957Smeem 			info("};\n");
28534c98957Smeem 			continue;
28634c98957Smeem 		}
28734c98957Smeem 
288b4034a75Smeem 		warn("%s: unknown record type 0%o\n", lnname, line.decflag);
28934c98957Smeem 	}
29034c98957Smeem }
29134c98957Smeem 
29234c98957Smeem /*
29334c98957Smeem  * Print the C datatype or function `atp' named `name'.  If `name' is a
29434c98957Smeem  * function, then `nargs' indicates the number of C datatypes pointed to
29534c98957Smeem  * by `args'.
29634c98957Smeem  */
29734c98957Smeem static void
29834c98957Smeem print_atype(ATYPE *atp, int nargs, ATYPE *args, const char *name)
29934c98957Smeem {
30034c98957Smeem 	static const char *basetypes[] = {		"",
30134c98957Smeem 		"char",		"unsigned char",	"signed char",
30234c98957Smeem 		"short",	"unsigned short",	"signed short",
30334c98957Smeem 		"int",		"unsigned int",		"signed int",
30434c98957Smeem 		"long",		"unsigned long",	"signed long",
30534c98957Smeem 		"long long",	"unsigned long long",	"signed long long",
30634c98957Smeem 		"enum",		"float",		"double",
30734c98957Smeem 		"long double",	"void",			"struct",
30834c98957Smeem 		"union",	"_Bool",		"<genchar>",
30934c98957Smeem 		"<genshort>",	"<genint>",		"<genlong>",
31034c98957Smeem 		"<genlonglong>"
31134c98957Smeem 	};
31234c98957Smeem 	uint16_t basetype = atp->aty & LNQUAL;
31334c98957Smeem 	lsu_t *lsup;
31434c98957Smeem 
31534c98957Smeem 	if (atp->aty & LCON)
31634c98957Smeem 		info("const ");
31734c98957Smeem 	if (atp->aty & LVOL)
31834c98957Smeem 		info("volatile ");
31934c98957Smeem 	if (atp->aty & LCONV)
32034c98957Smeem 		info("integer const ");
32134c98957Smeem 
32234c98957Smeem 	if (basetype < 1 ||
32334c98957Smeem 	    basetype > (sizeof (basetypes) / sizeof (*basetypes)))
32434c98957Smeem 		info("<unknown type %x>", basetype);
32534c98957Smeem 
32634c98957Smeem 	switch (basetype) {
32734c98957Smeem 	case LN_UNION:
32834c98957Smeem 	case LN_STRUCT:
32934c98957Smeem 		lsup = lsu_lookup(atp->extra.ty);
33034c98957Smeem 		if (lsup != NULL && lsup->name[0] != '.') {
33134c98957Smeem 			info("%s %s", basetypes[basetype], lsup->name);
33234c98957Smeem 		} else {
33334c98957Smeem 			info("%s", basetypes[basetype]);
33434c98957Smeem 			if (showids)
33534c98957Smeem 				info(" <tag %lu>", atp->extra.ty);
33634c98957Smeem 			else
33734c98957Smeem 				info(" <anon>");
33834c98957Smeem 		}
33934c98957Smeem 		break;
34034c98957Smeem 	default:
3415cb4fc81Smeem 		info("%s", basetypes[basetype]);
34234c98957Smeem 	};
34334c98957Smeem 
34434c98957Smeem 	print_mods(name, atp, nargs, args, 14);
34534c98957Smeem }
34634c98957Smeem 
34734c98957Smeem /*
34834c98957Smeem  * Recursively print type modifiers.
34934c98957Smeem  */
35034c98957Smeem static void
35134c98957Smeem print_mods(const char *name, ATYPE *atp, int nargs, ATYPE *args, uint_t pos)
35234c98957Smeem {
35334c98957Smeem 	int arg;
35434c98957Smeem 	int mods = atp->dcl_mod >> (pos * 2);
35534c98957Smeem 	int lastmods = atp->dcl_mod >> ((pos + 1) * 2);
35634c98957Smeem 	boolean_t isvarargs = B_FALSE;
35734c98957Smeem 
35834c98957Smeem 	if (LN_ISPTR(mods)) {
35934c98957Smeem 		if (!LN_ISPTR(lastmods) && !LN_ISFTN(lastmods))
36034c98957Smeem 			info(" ");
36134c98957Smeem 		info("*");
36234c98957Smeem 	}
36334c98957Smeem 
36434c98957Smeem 	if (atp->dcl_con & (1 << pos))
36534c98957Smeem 		info(" const ");
36634c98957Smeem 	if (atp->dcl_vol & (1 << pos))
36734c98957Smeem 		info(" volatile ");
36834c98957Smeem 
36934c98957Smeem 	if (pos != 0) {
37034c98957Smeem 		if (LN_ISFTN(mods))
37134c98957Smeem 			info(" (");
37234c98957Smeem 		print_mods(name, atp, nargs, args, pos - 1);
37334c98957Smeem 		if (LN_ISFTN(mods))
37434c98957Smeem 			info(")()");
37534c98957Smeem 		return;
37634c98957Smeem 	}
37734c98957Smeem 
37834c98957Smeem 	if (name[0] == '\0')
37934c98957Smeem 		return;
38034c98957Smeem 
38134c98957Smeem 	if (!LN_ISPTR(lastmods) && !LN_ISPTR(mods))
38234c98957Smeem 		info(" ");
38334c98957Smeem 	info("%s", name);
38434c98957Smeem 
38534c98957Smeem 	if (LN_ISARY(mods)) {
38634c98957Smeem 		info("[]");
38734c98957Smeem 	} else if (LN_ISFTN(mods)) {
38834c98957Smeem 		info("(");
38934c98957Smeem 
39034c98957Smeem 		if (nargs < 0) {
39134c98957Smeem 			nargs = -nargs - 1;
39234c98957Smeem 			isvarargs = B_TRUE;
39334c98957Smeem 		}
39434c98957Smeem 
39534c98957Smeem 		if (nargs == 0) {
39634c98957Smeem 			info("void");
39734c98957Smeem 		} else {
39834c98957Smeem 			for (arg = 0; arg < nargs; arg++) {
39934c98957Smeem 				print_atype(&args[arg], 0, NULL, "");
40034c98957Smeem 				if ((arg + 1) < nargs)
40134c98957Smeem 					info(", ");
40234c98957Smeem 				else if (isvarargs)
40334c98957Smeem 					info(", ...");
40434c98957Smeem 			}
40534c98957Smeem 		}
40634c98957Smeem 		info(")");
40734c98957Smeem 	}
40834c98957Smeem }
40934c98957Smeem 
41034c98957Smeem /*
41134c98957Smeem  * Add an LSU entry to the LSU table.
41234c98957Smeem  */
41334c98957Smeem static int
41434c98957Smeem lsu_add(const char *name, ATYPE *atp)
41534c98957Smeem {
41634c98957Smeem 	unsigned int	i = atp->extra.ty % LSU_HASHSIZE;
41734c98957Smeem 	lsu_t		*lsup;
41834c98957Smeem 
41934c98957Smeem 	lsup = malloc(sizeof (lsu_t));
42034c98957Smeem 	if (lsup == NULL)
42134c98957Smeem 		return (ENOMEM);
42234c98957Smeem 
42334c98957Smeem 	lsup->atype = *atp;
42434c98957Smeem 	lsup->next = lsu_table[i];
42534c98957Smeem 	lsup->name = strdup(name);
42634c98957Smeem 	if (lsup->name == NULL) {
42734c98957Smeem 		free(lsup);
42834c98957Smeem 		return (ENOMEM);
42934c98957Smeem 	}
43034c98957Smeem 
43134c98957Smeem 	lsu_table[i] = lsup;
43234c98957Smeem 	return (0);
43334c98957Smeem }
43434c98957Smeem 
43534c98957Smeem /*
43634c98957Smeem  * Lookup an LSU entry by ID.
43734c98957Smeem  */
43834c98957Smeem static lsu_t *
43934c98957Smeem lsu_lookup(T1WORD ty)
44034c98957Smeem {
44134c98957Smeem 	unsigned int	i = ty % LSU_HASHSIZE;
44234c98957Smeem 	lsu_t		*lsup;
44334c98957Smeem 
44434c98957Smeem 	for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup->next) {
44534c98957Smeem 		if (lsup->atype.extra.ty == ty)
44634c98957Smeem 			return (lsup);
44734c98957Smeem 	}
44834c98957Smeem 
44934c98957Smeem 	return (NULL);
45034c98957Smeem }
45134c98957Smeem 
45234c98957Smeem /*
45334c98957Smeem  * Read all LSU (structure and union definition) records in order to
45434c98957Smeem  * build a structure and union name table, called the LSU table.
455*fa5e8906Smeem  * Although `fp' is read from, the original file offset is preserved.
45634c98957Smeem  */
45734c98957Smeem static void
45834c98957Smeem lsu_build(FILE *fp)
45934c98957Smeem {
46034c98957Smeem 	union rec	rec;
46134c98957Smeem 	char		name[1024];
46234c98957Smeem 	int		nargs;
463*fa5e8906Smeem 	off_t		curoff = ftello(fp);
46434c98957Smeem 
46534c98957Smeem 	for (;;) {
46634c98957Smeem 		if (fread(&rec, sizeof (rec), 1, fp) != 1)
467*fa5e8906Smeem 			break;
46834c98957Smeem 
46934c98957Smeem 		if (rec.l.decflag & LND)	/* end-of-pass marker */
47034c98957Smeem 			break;
47134c98957Smeem 
47234c98957Smeem 		getstr(fp, name, sizeof (name));
47334c98957Smeem 		nargs = rec.l.nargs;
47434c98957Smeem 
47534c98957Smeem 		if (rec.l.decflag & (LIB|LDS|LDI)) {
47634c98957Smeem 			if (nargs < 0)
47734c98957Smeem 				nargs = -nargs - 1;
47834c98957Smeem 
47934c98957Smeem 			(void) fseek(fp, sizeof (ATYPE) * nargs, SEEK_CUR);
48034c98957Smeem 			continue;
48134c98957Smeem 		}
48234c98957Smeem 
48334c98957Smeem 		if (rec.l.decflag & LSU) {
48434c98957Smeem 			if (lsu_add(name, &rec.l.type) != 0)
48534c98957Smeem 				warn("cannot allocate struct `%s' info", name);
48634c98957Smeem 
48734c98957Smeem 			for (; nargs > 0; nargs--) {
48834c98957Smeem 				(void) fseek(fp, sizeof (ATYPE), SEEK_CUR);
48934c98957Smeem 				getstr(fp, name, sizeof (name));
49034c98957Smeem 			}
49134c98957Smeem 		}
49234c98957Smeem 	}
493*fa5e8906Smeem 
494*fa5e8906Smeem 	(void) fseek(fp, curoff, SEEK_SET);
49534c98957Smeem }
49634c98957Smeem 
49734c98957Smeem /*
49834c98957Smeem  * Empty the LSU table.
49934c98957Smeem  */
50034c98957Smeem static void
50134c98957Smeem lsu_empty(void)
50234c98957Smeem {
50334c98957Smeem 	lsu_t		*lsup, *lsup_next;
50434c98957Smeem 	unsigned int	i;
50534c98957Smeem 
50634c98957Smeem 	for (i = 0; i < LSU_HASHSIZE; i++) {
50734c98957Smeem 		for (lsup = lsu_table[i]; lsup != NULL; lsup = lsup_next) {
50834c98957Smeem 			lsup_next = lsup->next;
50934c98957Smeem 			free(lsup);
51034c98957Smeem 		}
51134c98957Smeem 		lsu_table[i] = NULL;
51234c98957Smeem 	}
51334c98957Smeem }
51434c98957Smeem 
51534c98957Smeem /*
51634c98957Smeem  * Read the NUL-terminated string at `fp' into `buf', which is at most
51734c98957Smeem  * `bufsize' bytes.
51834c98957Smeem  */
51934c98957Smeem static void
52034c98957Smeem getstr(FILE *fp, char *buf, size_t bufsize)
52134c98957Smeem {
52234c98957Smeem 	int c;
52334c98957Smeem 	size_t i;
52434c98957Smeem 
52534c98957Smeem 	for (i = 0; i < bufsize - 1; i++) {
52634c98957Smeem 		c = fgetc(fp);
52734c98957Smeem 		if (c == EOF || c == '\0' || !isascii(c))
52834c98957Smeem 			break;
52934c98957Smeem 		buf[i] = (char)c;
53034c98957Smeem 	}
53134c98957Smeem 
53234c98957Smeem 	buf[i] = '\0';
53334c98957Smeem }
53434c98957Smeem 
53534c98957Smeem static void
53634c98957Smeem indent(void)
53734c98957Smeem {
53834c98957Smeem 	indentlevel += 4;
53934c98957Smeem }
54034c98957Smeem 
54134c98957Smeem static void
54234c98957Smeem unindent(void)
54334c98957Smeem {
54434c98957Smeem 	indentlevel -= 4;
54534c98957Smeem }
54634c98957Smeem 
54734c98957Smeem static void
54834c98957Smeem usage(void)
54934c98957Smeem {
550*fa5e8906Smeem 	(void) fprintf(stderr, "usage: %s [-i] [-p 1|2|3] [-r] lintobj"
551*fa5e8906Smeem 	    " [ lintobj ... ]\n", progname);
55234c98957Smeem 	exit(EXIT_FAILURE);
55334c98957Smeem }
55434c98957Smeem 
55534c98957Smeem /* PRINTFLIKE1 */
55634c98957Smeem static void
55734c98957Smeem info(const char *format, ...)
55834c98957Smeem {
55934c98957Smeem 	va_list alist;
56034c98957Smeem 	static int complete = 1;
56134c98957Smeem 
56234c98957Smeem 	if (complete)
56334c98957Smeem 		(void) printf("%*s", indentlevel, "");
56434c98957Smeem 
56534c98957Smeem 	va_start(alist, format);
56634c98957Smeem 	(void) vprintf(format, alist);
56734c98957Smeem 	va_end(alist);
56834c98957Smeem 
56934c98957Smeem 	complete = strrchr(format, '\n') != NULL;
57034c98957Smeem }
57134c98957Smeem 
57234c98957Smeem /* PRINTFLIKE2 */
57334c98957Smeem static void
57434c98957Smeem infohdr(const char *hdr, const char *format, ...)
57534c98957Smeem {
57634c98957Smeem 	va_list alist;
57734c98957Smeem 	static int complete = 1;
57834c98957Smeem 
57934c98957Smeem 	if (complete)
58034c98957Smeem 		(void) printf("%7s: ", hdr);
58134c98957Smeem 
58234c98957Smeem 	va_start(alist, format);
58334c98957Smeem 	(void) vprintf(format, alist);
58434c98957Smeem 	va_end(alist);
58534c98957Smeem 
58634c98957Smeem 	complete = strrchr(format, '\n') != NULL;
58734c98957Smeem }
58834c98957Smeem 
58934c98957Smeem /* PRINTFLIKE1 */
59034c98957Smeem static void
59134c98957Smeem warn(const char *format, ...)
59234c98957Smeem {
59334c98957Smeem 	va_list alist;
59434c98957Smeem 	char *errstr = strerror(errno);
59534c98957Smeem 
59634c98957Smeem 	(void) fprintf(stderr, "%s: warning: ", progname);
59734c98957Smeem 
59834c98957Smeem 	va_start(alist, format);
59934c98957Smeem 	(void) vfprintf(stderr, format, alist);
60034c98957Smeem 	va_end(alist);
60134c98957Smeem 
60234c98957Smeem 	if (strrchr(format, '\n') == NULL)
60334c98957Smeem 		(void) fprintf(stderr, ": %s\n", errstr);
60434c98957Smeem }
60534c98957Smeem 
60634c98957Smeem /* PRINTFLIKE1 */
60734c98957Smeem static void
60834c98957Smeem die(const char *format, ...)
60934c98957Smeem {
61034c98957Smeem 	va_list alist;
61134c98957Smeem 	char *errstr = strerror(errno);
61234c98957Smeem 
61334c98957Smeem 	(void) fprintf(stderr, "%s: fatal: ", progname);
61434c98957Smeem 
61534c98957Smeem 	va_start(alist, format);
61634c98957Smeem 	(void) vfprintf(stderr, format, alist);
61734c98957Smeem 	va_end(alist);
61834c98957Smeem 
61934c98957Smeem 	if (strrchr(format, '\n') == NULL)
62034c98957Smeem 		(void) fprintf(stderr, ": %s\n", errstr);
62134c98957Smeem 
62234c98957Smeem 	exit(EXIT_FAILURE);
62334c98957Smeem }
624