summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorraf <none@none>2006-09-20 12:15:03 -0700
committerraf <none@none>2006-09-20 12:15:03 -0700
commit753d2d2e8e7fd0c9bcf736d9bf2f2faf4d6234cc (patch)
tree0e82e5bff3540f84dc0e9088fec8662fe12afd1e /usr/src
parentd25d47ee62f52e470a91221e64abe838a0af786d (diff)
downloadillumos-gate-753d2d2e8e7fd0c9bcf736d9bf2f2faf4d6234cc.tar.gz
6472057 /usr/lib/abi/spec2map missing from snv_48
--HG-- rename : deleted_files/usr/src/cmd/abi/spectrans/Makefile => usr/src/cmd/abi/spectrans/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/Makefile.arch => usr/src/cmd/abi/spectrans/Makefile.arch rename : deleted_files/usr/src/cmd/abi/spectrans/Makefile.cmd => usr/src/cmd/abi/spectrans/Makefile.cmd rename : deleted_files/usr/src/cmd/abi/spectrans/parser/Makefile => usr/src/cmd/abi/spectrans/parser/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/parser/Makefile.targ => usr/src/cmd/abi/spectrans/parser/Makefile.targ rename : deleted_files/usr/src/cmd/abi/spectrans/parser/errlog.c => usr/src/cmd/abi/spectrans/parser/errlog.c rename : deleted_files/usr/src/cmd/abi/spectrans/parser/errlog.h => usr/src/cmd/abi/spectrans/parser/errlog.h rename : deleted_files/usr/src/cmd/abi/spectrans/parser/extends.c => usr/src/cmd/abi/spectrans/parser/extends.c rename : deleted_files/usr/src/cmd/abi/spectrans/parser/frontend.c => usr/src/cmd/abi/spectrans/parser/frontend.c rename : deleted_files/usr/src/cmd/abi/spectrans/parser/i386/Makefile => usr/src/cmd/abi/spectrans/parser/i386/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/parser/main.c => usr/src/cmd/abi/spectrans/parser/main.c rename : deleted_files/usr/src/cmd/abi/spectrans/parser/parser.h => usr/src/cmd/abi/spectrans/parser/parser.h rename : deleted_files/usr/src/cmd/abi/spectrans/parser/sparc/Makefile => usr/src/cmd/abi/spectrans/parser/sparc/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/Makefile => usr/src/cmd/abi/spectrans/spec2map/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/Makefile.targ => usr/src/cmd/abi/spectrans/spec2map/Makefile.targ rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/bucket.c => usr/src/cmd/abi/spectrans/spec2map/bucket.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/bucket.h => usr/src/cmd/abi/spectrans/spec2map/bucket.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/i386/Makefile => usr/src/cmd/abi/spectrans/spec2map/i386/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile => usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/util.c => usr/src/cmd/abi/spectrans/spec2map/util.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/util.h => usr/src/cmd/abi/spectrans/spec2map/util.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/versions.c => usr/src/cmd/abi/spectrans/spec2map/versions.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/xlator.c => usr/src/cmd/abi/spectrans/spec2map/xlator.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2map/xlator.h => usr/src/cmd/abi/spectrans/spec2map/xlator.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/Makefile => usr/src/cmd/abi/spectrans/spec2trace/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ => usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/bindings.c => usr/src/cmd/abi/spectrans/spec2trace/bindings.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/bindings.h => usr/src/cmd/abi/spectrans/spec2trace/bindings.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/db.c => usr/src/cmd/abi/spectrans/spec2trace/db.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/db.h => usr/src/cmd/abi/spectrans/spec2trace/db.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile => usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/interceptor.c => usr/src/cmd/abi/spectrans/spec2trace/interceptor.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/io.c => usr/src/cmd/abi/spectrans/spec2trace/io.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/io.h => usr/src/cmd/abi/spectrans/spec2trace/io.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/linkage.c => usr/src/cmd/abi/spectrans/spec2trace/linkage.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/parseproto.h => usr/src/cmd/abi/spectrans/spec2trace/parseproto.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/parseproto.y => usr/src/cmd/abi/spectrans/spec2trace/parseproto.y rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c => usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h => usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile => usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/symtab.c => usr/src/cmd/abi/spectrans/spec2trace/symtab.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/symtab.h => usr/src/cmd/abi/spectrans/spec2trace/symtab.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/trace.c => usr/src/cmd/abi/spectrans/spec2trace/trace.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/trace.h => usr/src/cmd/abi/spectrans/spec2trace/trace.h rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/util.c => usr/src/cmd/abi/spectrans/spec2trace/util.c rename : deleted_files/usr/src/cmd/abi/spectrans/spec2trace/util.h => usr/src/cmd/abi/spectrans/spec2trace/util.h
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/abi/Makefile2
-rw-r--r--usr/src/cmd/abi/spectrans/Makefile47
-rw-r--r--usr/src/cmd/abi/spectrans/Makefile.arch49
-rw-r--r--usr/src/cmd/abi/spectrans/Makefile.cmd81
-rw-r--r--usr/src/cmd/abi/spectrans/parser/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/parser/Makefile.targ56
-rw-r--r--usr/src/cmd/abi/spectrans/parser/errlog.c139
-rw-r--r--usr/src/cmd/abi/spectrans/parser/errlog.h91
-rw-r--r--usr/src/cmd/abi/spectrans/parser/extends.c394
-rw-r--r--usr/src/cmd/abi/spectrans/parser/frontend.c569
-rw-r--r--usr/src/cmd/abi/spectrans/parser/i386/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/parser/main.c231
-rw-r--r--usr/src/cmd/abi/spectrans/parser/parser.h136
-rw-r--r--usr/src/cmd/abi/spectrans/parser/sparc/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/Makefile.targ39
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/bucket.c748
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/bucket.h92
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/i386/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/util.c208
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/util.h63
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/versions.c683
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/xlator.c1034
-rw-r--r--usr/src/cmd/abi/spectrans/spec2map/xlator.h93
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ51
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/bindings.c278
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/bindings.h47
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/db.c273
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/db.h66
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/interceptor.c437
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/io.c177
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/io.h50
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/linkage.c121
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/parseproto.h273
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/parseproto.y2227
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c313
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h56
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile32
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/symtab.c919
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/symtab.h114
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/trace.c988
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/trace.h67
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/util.c385
-rw-r--r--usr/src/cmd/abi/spectrans/spec2trace/util.h76
-rw-r--r--usr/src/pkgdefs/SUNWtoo/prototype_com3
48 files changed, 11963 insertions, 1 deletions
diff --git a/usr/src/cmd/abi/Makefile b/usr/src/cmd/abi/Makefile
index b198edbe1f..9c60e71559 100644
--- a/usr/src/cmd/abi/Makefile
+++ b/usr/src/cmd/abi/Makefile
@@ -25,7 +25,7 @@
# ident "%Z%%M% %I% %E% SMI"
#
-SUBDIRS = apptracecmd appcert
+SUBDIRS = spectrans apptracecmd appcert
all := TARGET= all
install := TARGET= install
diff --git a/usr/src/cmd/abi/spectrans/Makefile b/usr/src/cmd/abi/spectrans/Makefile
new file mode 100644
index 0000000000..8b8dd4d7e6
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/Makefile
@@ -0,0 +1,47 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 1996,1998-1999,2002 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/abi/spectrans/Makefile
+
+.KEEP_STATE:
+
+SUBDIRS = parser spec2map spec2trace
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+
+all install clean clobber lint: $(SUBDIRS)
+
+_msg: # No messages for these tools
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
diff --git a/usr/src/cmd/abi/spectrans/Makefile.arch b/usr/src/cmd/abi/spectrans/Makefile.arch
new file mode 100644
index 0000000000..0edfcf6be7
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/Makefile.arch
@@ -0,0 +1,49 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/Makefile.arch
+
+i386_ARCHITECTURES = i386
+sparc_ARCHITECTURES = sparc
+ALL_ARCHITECTURES = $(i386_ARCHITECTURES) \
+ $(sparc_ARCHITECTURES)
+
+all := TARGET= all
+install := TARGET= install
+clean := TARGET= clean
+clobber := TARGET= clobber
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all install clean clobber lint: $($(MACH)_ARCHITECTURES)
+
+$($(MACH)_ARCHITECTURES): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
diff --git a/usr/src/cmd/abi/spectrans/Makefile.cmd b/usr/src/cmd/abi/spectrans/Makefile.cmd
new file mode 100644
index 0000000000..83b1d60cc5
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/Makefile.cmd
@@ -0,0 +1,81 @@
+#
+# 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"
+#
+
+include $(SRC)/cmd/Makefile.cmd
+
+PROG_BIN = $(ROOTLIB)/abi/$(PROG)
+.PRECIOUS: $(PROG)
+
+U_LIB = parse
+U_BASE = ../../parser
+U_DIR = $(U_BASE)/$(MACH)
+U_LIB_A = $(U_DIR)/lib$(U_LIB).a
+
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(U_BASE) -I..
+LDFLAGS += -L$(U_DIR)
+LINTFLAGS += -xsuF -errtags=yes
+
+LDLIBS += -l$(U_LIB) -lgen
+LINTLIBS = -L$(U_DIR) -l$(U_LIB)
+
+SRCS = $(OBJECTS:%.o=../%.c)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+%.o: ../%.y
+ $(YACC.y) $<
+ $(COMPILE.c) -o $@ y.tab.c
+ $(RM) y.tab.c
+
+%.o: ../%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+$(PROG): $(U_LIB_A) $(OBJECTS) $(YACC_OBJS)
+ $(LINK.c) -o $@ $(OBJECTS) $(YACC_OBJS) $(LDLIBS)
+ $(POST_PROCESS)
+
+$(U_LIB_A):
+ @cd $(U_DIR); pwd; $(MAKE) all
+
+install: $(PROG_BIN)
+
+$(PROG_BIN) := FILEMODE = 755
+$(PROG_BIN): $(PROG)
+ $(INS.file) $(PROG)
+
+clean:
+ -$(RM) $(OBJECTS) $(YACC_OBJS)
+
+clobber: clean
+ -$(RM) $(PROG) $(CLOBBERFILES)
+
+lint:
+ $(LINT.c) $(SRCS) $(LINTLIBS)
diff --git a/usr/src/cmd/abi/spectrans/parser/Makefile b/usr/src/cmd/abi/spectrans/parser/Makefile
new file mode 100644
index 0000000000..0f98d165d9
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/lib/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.arch
diff --git a/usr/src/cmd/abi/spectrans/parser/Makefile.targ b/usr/src/cmd/abi/spectrans/parser/Makefile.targ
new file mode 100644
index 0000000000..c00da5548c
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/Makefile.targ
@@ -0,0 +1,56 @@
+#
+# 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.
+#
+# 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 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+# cmd/abi/spectrans/util/Makefile.targ
+#
+
+.KEEP_STATE:
+
+LIBRARY = libparse.a
+
+OBJECTS = errlog.o \
+ extends.o \
+ frontend.o \
+ main.o
+
+include $(SRC)/lib/Makefile.lib
+
+SRCS = $(OBJECTS:%.o=../%.c)
+
+LINTFLAGS += -xsuF -errtags=yes
+CLEANFILES += $(LINTOUT)
+CLOBBERFILES += $(LINTLIB)
+
+objs/%.o: ../%.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+all install: $(LIBRARY)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/parser/errlog.c b/usr/src/cmd/abi/spectrans/parser/errlog.c
new file mode 100644
index 0000000000..25c1f140d6
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/errlog.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * errlog -- error logging facility for application programs
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "errlog.h"
+
+/* Statics (this object is not threadable). */
+static int Severity;
+static struct location {
+ char *l_file;
+ int l_lineno;
+ char *l_tag;
+ char *l_line;
+} Location;
+
+/* Indentation */
+static int Trace_indent;
+/* XXX YES, its 80 spaces !@#$%^ */
+static char Trace_padding[] =
+ " "
+ " ";
+
+#define INDENT &Trace_padding[80-(Trace_indent*4)]
+#define PRINTHDR INPUT
+
+/*
+ * errlog -- simulate the syslog printf-like interface, but
+ * with a first argument oriented toward reporting
+ * application errors.
+ */
+/*VARARGS2*/
+void
+errlog(const int descriptor, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if ((Severity < (descriptor & FATAL)) &&
+ ((descriptor & FATAL) != FATAL)) {
+ /* We don't need to say/do anything. */
+ return;
+ }
+
+ /* Produce the message. */
+ (void) fflush(stdout); /* Synchronize streams. */
+ if ((descriptor & PRINTHDR) != 0) {
+ if (Location.l_file == NULL) {
+ (void) fprintf(stderr, "programmer error, logerr "
+ "told to print file, line number, "
+ "but file was not set.\n");
+ } else {
+ (void) fprintf(stderr, "\"%s\", line %d: ",
+ Location.l_file, Location.l_lineno);
+ }
+ }
+
+ /* Indent/outdent. */
+ if (descriptor & INDENTED) {
+ (void) fprintf(stderr, "%s", INDENT);
+ Trace_indent = (Trace_indent < 20)? Trace_indent + 1: 20;
+ } else if (descriptor & OUTDENTED) {
+ Trace_indent = (Trace_indent > 0)? Trace_indent - 1: 0;
+ (void) fprintf(stderr, "%s", INDENT);
+ } else {
+ (void) fprintf(stderr, "%s", INDENT);
+ }
+
+ /* Print the stuff we did all this for. */
+ (void) vfprintf(stderr, format, ap);
+
+ if ((descriptor & INPUT) && Location.l_line != NULL) {
+ /* Emit trailers. Formatting TBD. */
+ (void) putc('\n', stderr);
+ (void) fprintf(stderr, "\tLine was: %s %s",
+ Location.l_tag, Location.l_line);
+ }
+ (void) putc('\n', stderr);
+ (void) fflush(stderr); /* No-op on Solaris. */
+
+ if ((descriptor & FATAL) == FATAL) {
+ /* Say goodbye! */
+ exit(1);
+ }
+ va_end(ap);
+}
+
+/*
+ * seterrline -- tell errlog what the context of the error is.
+ */
+void
+seterrline(const int lineno, const char *file,
+ const char *tag, const char *line)
+{
+ Location.l_lineno = lineno;
+ Location.l_file = (char *)file;
+ Location.l_tag = (char *)tag;
+ Location.l_line = (char *)line;
+}
+
+/*
+ * seterrseverity -- set the severity/loudness variable.
+ * This is traditionally the ``Verbosity'' level.
+ */
+void
+seterrseverity(const int loudness)
+{
+ Severity = (loudness & FATAL);
+}
diff --git a/usr/src/cmd/abi/spectrans/parser/errlog.h b/usr/src/cmd/abi/spectrans/parser/errlog.h
new file mode 100644
index 0000000000..04150936be
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/errlog.h
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _ERRLOG_H
+#define _ERRLOG_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * errlog -- error logging facility for application programs
+ *
+ */
+
+extern void errlog(const int, const char *, ...);
+extern void seterrline(const int, const char *, const char *, const char *);
+extern void seterrseverity(const int);
+extern void openerrlog(const char *, const int, const int);
+extern void closeerrlog(void);
+
+/*
+ * The first (non-short) int of errlog really describes a packed
+ * form of three extensible enumerations, similar to:
+ * typedef struct severity {
+ * int descriptor: 8; OTHER=0, INPUT or PROGRAM.
+ * int attributes: 8; NONE=0, INDENTED, OUTDENTED, etc.
+ * int severity: 16; FATAL (_ERROR)=-1, (RECOVERABLE_) ERROR=0
+ * WARNING, TRACING, VERBOSE (_TRACING), etc.
+ * } severity_t;
+ */
+
+#define FATAL 0x00FF
+#define ERROR 0
+
+#define WARNING 1
+#define STATUS 2
+#define TRACING 3
+#define VERBOSE 4
+
+#define INPUT (1 << 8)
+#define PROGRAM (2 << 8)
+#define OTHER 0
+
+/* Reserved for implementor. */
+#define INDENTED (1 << 16)
+#define OUTDENTED (2 << 16)
+#define BEGIN (OTHER | TRACING | INDENTED)
+#define END (OTHER | TRACING | OUTDENTED)
+
+#ifndef assert
+/* EXPERIMENTAL assert replacement, deliberately not source-compatable */
+#define assert(cond, string) \
+ if (!(cond)) { \
+ seterrline(__LINE__, __FILE__, NULL, NULL); \
+ errlog(FATAL|PROGRAM, string); \
+ }
+#else
+#error "assert.h and errlog.h both define assert: choose only one"
+#endif /* assert */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ERRLOG_H */
diff --git a/usr/src/cmd/abi/spectrans/parser/extends.c b/usr/src/cmd/abi/spectrans/parser/extends.c
new file mode 100644
index 0000000000..d74dbdd88c
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/extends.c
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <errno.h>
+#include "parser.h"
+#include "errlog.h"
+
+static int find_fun(char *key, char *value, char *parentfun);
+
+/*
+ * handles the extends clause of the 'function' keyword
+ * Returns the number of errors encountered
+ * This function is recursive.
+ */
+int
+do_extends(const Meta_info parentM, const Translator_info *T_info, char *value)
+{
+ static int extends_count = 0;
+ char funname[BUFSIZ], filename[MAXPATHLEN], parentfun[BUFSIZ],
+ buf[BUFSIZ], key[20];
+ char *ifilename, *f, *p;
+ char *localvalue = NULL, *buf2 = NULL;
+ FILE *efp;
+ Meta_info M;
+ int found = 0, errors = 0, ki = 0;
+ int retval;
+ int scan;
+
+ ++extends_count;
+
+ if (extends_count > MAX_EXTENDS) {
+ errlog(ERROR, "\"%s\", line %d: Error: Too many levels of "
+ "extends\n", parentM.mi_filename, parentM.mi_line_number);
+ ++errors;
+ goto ret;
+ }
+
+ scan = sscanf(value, "%s %s %s %s", funname, buf, filename, parentfun);
+ switch (scan) {
+ case 0: /* funname not set */
+ case 1: /* buf not set, though ignored */
+ case 2: /* filename not set */
+ errlog(ERROR, "\"%s\", line %d: Error: Couldn't parse "
+ "'data' or 'function' line\n",
+ parentM.mi_filename, parentM.mi_line_number);
+ ++errors;
+ goto ret;
+ break;
+ case 3:
+ (void) strncpy(parentfun, funname, BUFSIZ);
+ parentfun[BUFSIZ-1] = '\0';
+ break;
+ default:
+ break;
+ }
+
+ /* All info is from parent file - extends */
+ M.mi_ext_cnt = extends_count;
+
+ if (T_info->ti_verbosity >= TRACING) {
+ errlog(TRACING, "Extending file %s\nExtending function %s\n"
+ "SPEC's from %s\n", filename, parentfun,
+ T_info->ti_dash_I);
+ }
+
+ f = pathfind(T_info->ti_dash_I, filename, "f");
+ if (f == NULL) {
+ errlog(ERROR, "\"%s\", line %d: Error: Unable to find spec "
+ "file \"%s\"\n", parentM.mi_filename,
+ parentM.mi_line_number, filename);
+ ++errors;
+ goto ret;
+ }
+ ifilename = strdup(f);
+ if (ifilename == NULL) {
+ errlog(ERROR | FATAL, "Error: strdup() of filename failed\n");
+ }
+ efp = fopen(ifilename, "r");
+ if (efp == NULL) {
+ errlog(ERROR, "\"%s\", line %d: Error: Unable to open "
+ "file \"%s\"\n", parentM.mi_filename,
+ parentM.mi_line_number, ifilename);
+ free(ifilename);
+ ++errors;
+ goto ret;
+ }
+
+ (void) strncpy(M.mi_filename, ifilename, MAXPATHLEN);
+ M.mi_line_number = 0;
+
+ /* search for begin function */
+ while (M.mi_nlines = readline(&buf2, efp)) {
+ M.mi_line_number += M.mi_nlines;
+
+ if (!non_empty(buf2)) { /* is line non empty */
+ free(buf2);
+ buf2 = NULL;
+ continue;
+ }
+ p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ errlog(ERROR | FATAL, "Error (do_extends): "
+ "Unable to allocate memory\n");
+ }
+ localvalue = p;
+ split(buf2, key, localvalue);
+ if ((found = find_fun(key, localvalue, parentfun))) {
+ /* check if architecture matches */
+ if (found = arch_match(efp, T_info->ti_archtoken))
+ break;
+ }
+ free(buf2);
+ buf2 = NULL;
+ }
+
+ if (found) {
+ int extends_err = 0;
+ static int extends_warn = 0;
+ extends_err = check4extends(ifilename, localvalue,
+ T_info->ti_archtoken, efp);
+ switch (extends_err) {
+ case -1: /* Error */
+ errlog(ERROR, "\"%s\", line %d: Error occurred while "
+ "checking for extends clause\n",
+ M.mi_filename, M.mi_line_number);
+ ++errors;
+ /*FALLTHRU*/
+ case 0: /* No Extends */
+ break;
+ case 1: /* Extends */
+ /*
+ * Warning on more then one level of extends
+ * but only warn once.
+ */
+ if (extends_count == 1) {
+ extends_warn = 1;
+ }
+ if ((extends_err = do_extends(M, T_info, localvalue))
+ != 0) {
+ if (extends_count == 1) {
+ errlog(ERROR, "\"%s\", line %d: "
+ "Error occurred while "
+ "processing 'extends'\n",
+ parentM.mi_filename,
+ parentM.mi_line_number);
+ }
+ errors += extends_err;
+ }
+ if (extends_warn == 1 && extends_count == 1) {
+ errlog(ERROR, "\"%s\", line %d: "
+ "Warning: \"%s\" does not extend "
+ "a base specification",
+ parentM.mi_filename,
+ parentM.mi_line_number,
+ funname);
+ }
+ break;
+ default: /* Programmer Error */
+ errlog(ERROR | FATAL,
+ "Error: invalid return from "
+ "check4extends: %d\n", extends_err);
+ }
+
+ free(buf2);
+ buf2 = NULL;
+
+ while (M.mi_nlines = readline(&buf2, efp)) {
+ M.mi_line_number += M.mi_nlines;
+
+ if (!non_empty(buf2)) { /* is line non empty */
+ free(buf2);
+ buf2 = NULL;
+ continue;
+ }
+ p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ p = realloc(NULL,
+ sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: unable to "
+ "allocate memory\n");
+ }
+ }
+ localvalue = p;
+ split(buf2, key, localvalue);
+ ki = interesting_keyword(keywordlist, key);
+ switch (ki) {
+ case XLATOR_KW_END:
+ goto end;
+ break;
+ case XLATOR_KW_FUNC:
+ case XLATOR_KW_DATA:
+ errlog(ERROR, "\"%s\", line %d: "
+ "Error: Interface is missing \"end\"\n"
+ "\"%s\", line %d: Error while processing "
+ "%s\n", M.mi_filename, M.mi_line_number,
+ parentM.mi_filename,
+ parentM.mi_line_number, ifilename);
+ ++errors;
+ goto end;
+ break;
+ case XLATOR_KW_NOTFOUND:
+ if (T_info->ti_verbosity >= TRACING)
+ errlog(STATUS,
+ "uninteresting keyword: %s\n", key);
+ break;
+ default:
+ retval = xlator_take_kvpair(M, ki, localvalue);
+ if (retval) {
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS,
+ "Error in "
+ "xlator_take_kvpair\n");
+ ++errors;
+ }
+ }
+ free(buf2);
+ buf2 = NULL;
+ }
+ } else {
+ errlog(ERROR, "\"%s\", line %d: Error: Unable to find "
+ "function %s in %s\n", parentM.mi_filename,
+ parentM.mi_line_number, parentfun, ifilename);
+ ++errors;
+ }
+end:
+ (void) fclose(efp);
+ free(localvalue);
+ free(ifilename);
+ free(buf2);
+ret:
+ extends_count--;
+ return (errors);
+}
+
+/*
+ * find_fun()
+ * given a key value pair, and the name of the function you are
+ * searching for in the SPEC source file, this function returns 1
+ * if the beginning of the function in the SPEC source file is found.
+ * returns 0 otherwise.
+ */
+static int
+find_fun(char *key, char *value, char *parentfun)
+{
+ char pfun[BUFSIZ];
+
+ if (strcasecmp(key, "function") != 0 &&
+ strcasecmp(key, "data") != 0) {
+ return (0);
+ }
+
+ (void) sscanf(value, "%1023s", pfun);
+
+ if (strcmp(pfun, parentfun) == 0) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * arch_match(FILE *fp, int arch)
+ * This function takes a FILE pointer, and an architecture token
+ * The FILE pointer is assumed to point at the beginning of a Function
+ * or Data specification (specifically at the first line of spec AFTER
+ * the Function or Data line)
+ * It reads all the way to the "End" line.
+ * If it finds an "arch" keyword along the way, it is checked to see if
+ * it matches the architecture currently being generated and returns
+ * 1 if a match is found. If a match is not found, it returns a
+ * 0. If no "arch" keyword is found, it returns 1.
+ *
+ * XXX - the algorithm in arch_match is very inefficient. it read through
+ * the file to find "arch" and rewinds before returning.
+ * Later all the data that was skipped while searching for "arch" may
+ * be needed and it is re-read from the disk. It would be nice to just
+ * read the data once.
+ */
+int
+arch_match(FILE *fp, int arch)
+{
+ off_t offset;
+ char key[20], buf[BUFSIZ], *buf2 = NULL, *localvalue = NULL, *p;
+ int len;
+ int has_arch = 0;
+ int archset = 0;
+
+ offset = ftello(fp);
+ if (offset == -1) {
+ errlog(ERROR|FATAL, "Unable to determine file position\n");
+ }
+
+ while (fgets(buf, BUFSIZ, fp)) {
+ /* replace comments with single whitespace */
+ remcomment(buf);
+
+ /* get complete line */
+ buf2 = line_to_buf(buf2, buf); /* append buf to buf2 */
+ len = strlen(buf);
+ if (len > 1) {
+ while (buf[len-2] == '\\') {
+ if (!fgets(buf, BUFSIZ, fp)) {
+ buf2 = line_to_buf(buf2, buf);
+ break;
+ }
+ len = strlen(buf);
+ buf2 = line_to_buf(buf2, buf);
+ }
+ } /* end of 'get complete line' */
+
+ if (!non_empty(buf2)) { /* is line non empty */
+ free(buf2);
+ buf2 = NULL;
+ continue;
+ }
+ p = realloc(localvalue, sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ p = realloc(NULL,
+ sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: unable to "
+ "allocate memory\n");
+ }
+ }
+ localvalue = p;
+ split(buf2, key, localvalue);
+ if (strcasecmp(key, "arch") == 0) {
+ char *alist = localvalue, *a;
+ has_arch = 1;
+ while ((a = strtok(alist, " ,\n")) != NULL) {
+ archset = arch_strtoi(a);
+ if (arch & archset) {
+ free(buf2);
+ free(p);
+ if (fseeko(fp, offset, SEEK_SET) < 0) {
+ errlog(ERROR|FATAL,
+ "%s", strerror(errno));
+ }
+ return (1);
+ }
+ alist = NULL;
+ }
+ } else if (strcasecmp(key, "end") == 0) {
+ break;
+ }
+ free(buf2);
+ buf2 = NULL;
+ }
+
+end:
+ free(buf2);
+ free(p);
+
+ if (fseeko(fp, offset, SEEK_SET) < 0) {
+ errlog(ERROR|FATAL, "%s", strerror(errno));
+ }
+ if (has_arch == 0)
+ return (1);
+
+ return (0);
+}
diff --git a/usr/src/cmd/abi/spectrans/parser/frontend.c b/usr/src/cmd/abi/spectrans/parser/frontend.c
new file mode 100644
index 0000000000..db33b99442
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/frontend.c
@@ -0,0 +1,569 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <sys/param.h>
+#include <errno.h>
+
+#include "parser.h"
+#include "errlog.h"
+
+static char const *ARCH_I386 = "i386";
+static char const *ARCH_SPARC = "sparc";
+static char const *ARCH_SPARCV9 = "sparcv9";
+static char const *ARCH_IA64 = "ia64";
+static char const *ARCH_AMD64 = "amd64";
+static char const *ARCH_ALL = "all";
+
+static int dofiles(const Translator_info *);
+static int read_spec(const Translator_info *, char *);
+
+static int Curlineno;
+
+xlator_keyword_t *keywordlist;
+
+/*
+ * frontend entry point
+ * returns the number of errors encountered
+ */
+int
+frontend(const Translator_info *T_info)
+{
+ int retval, i = 0, errors = 0;
+
+ keywordlist = xlator_init(T_info);
+ if (keywordlist == NULL) {
+ errlog(ERROR, "Error: Unable to get keywordlist\n");
+ return (1);
+ }
+
+ if (T_info->ti_verbosity >= STATUS) {
+ errlog(STATUS, "interesting keywords:\n");
+ while (keywordlist[i].key != NULL) {
+ errlog(STATUS, "\t%s\n", keywordlist[i].key);
+ ++i;
+ };
+ }
+
+ retval = xlator_startlib(T_info->ti_liblist);
+ switch (retval) {
+ case XLATOR_SKIP:
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Skipping %s\n", T_info->ti_liblist);
+ retval = 0;
+ break;
+
+ case XLATOR_NONFATAL:
+ ++errors;
+ retval = 0;
+ break;
+
+ case XLATOR_SUCCESS:
+ retval = dofiles(T_info);
+ errors += retval;
+ if ((retval = xlator_endlib()) != XLATOR_SUCCESS)
+ ++errors;
+ retval = 0;
+ break;
+
+ default:
+ errlog(ERROR | FATAL,
+ "Error: Invalid return code from xlator_startlib()\n");
+ exit(1);
+ }
+
+ if ((retval = xlator_end()) != XLATOR_SUCCESS)
+ ++errors;
+
+ return (errors);
+}
+
+/*
+ * dofiles(const Translator_info *T_info);
+ * iterate through files specified in the command line and process
+ * them one by one
+ * requires spec files to have a ".spec" suffix
+ * returns the number of errors;
+ */
+static int
+dofiles(const Translator_info *T_info)
+{
+ int nfiles, flen, findex, retval = 0, errors = 0;
+
+ nfiles = T_info->ti_nfiles;
+
+ for (findex = 0; findex < nfiles; ++findex) {
+ flen = strlen(filelist[findex]);
+ if ((flen <= 5) ||
+ strcmp(&filelist[findex][flen-5], ".spec") != 0) {
+ errlog(ERROR,
+ "Error: File specified does not have the "
+ ".spec extension: %s\n", filelist[findex]);
+ ++errors;
+ continue;
+ };
+ retval = read_spec(T_info, filelist[findex]);
+ errors += retval;
+ }
+ return (errors);
+}
+
+/*
+ * read_spec -
+ * Given a filename, this function will reads the spec file to
+ * recognize keywords which it passes along with the corresponding
+ * value to the back-end translator to process. The following
+ * back-end interfaces are called:
+ * xlator_startfile
+ * xlator_start_if
+ * xlator_take_kvpair
+ * xlator_end_if
+ * xlator_endfile
+ */
+static int
+read_spec(const Translator_info *T_info, char *spec_filename)
+{
+ FILE *spec_fp;
+ Meta_info meta_info;
+ char key[BUFSIZ], *value = NULL, *p = NULL;
+ char *buf2 = NULL;
+ int retval = 0, errors = 0, ki = 0; /* keyword indicator */
+ int start_if_fail = 0, skip_if = 0;
+ int extends_err = 0;
+
+ meta_info.mi_ext_cnt = 0; /* All info is non-extends */
+ meta_info.mi_flags = 0;
+
+ retval = xlator_startfile(spec_filename);
+
+ switch (retval) {
+ case XLATOR_SKIP:
+ if (T_info->ti_verbosity >= WARNING)
+ errlog(WARNING, "Warning: Skipping %s\n",
+ spec_filename);
+ return (errors);
+
+ case XLATOR_NONFATAL:
+ errlog(ERROR, "Error in xlator_startfile\n");
+ ++errors;
+ return (errors);
+
+ case XLATOR_SUCCESS:
+ break;
+
+ default:
+ errlog(ERROR,
+ "Error: Invalid return code from xlator_startfile()\n");
+ ++errors;
+ return (errors);
+ };
+
+ /* file processing */
+ spec_fp = fopen(spec_filename, "r");
+ if (spec_fp == NULL) {
+ errlog(ERROR, "Error: Unable to open spec file %s: %s\n",
+ spec_filename, strerror(errno));
+ ++errors;
+ return (errors);
+ }
+
+ (void) strncpy(meta_info.mi_filename, spec_filename, BUFSIZ);
+ meta_info.mi_line_number = 0;
+ Curlineno = meta_info.mi_line_number;
+ while (meta_info.mi_nlines = readline(&buf2, spec_fp)) {
+ meta_info.mi_line_number += meta_info.mi_nlines;
+ Curlineno = meta_info.mi_line_number;
+ if (!non_empty(buf2)) {
+ free(buf2);
+ buf2 = NULL;
+ continue;
+ }
+ p = realloc(value, sizeof (char)*(strlen(buf2)+1));
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for "
+ "value: %d\n", errno);
+ }
+ value = p;
+ split(buf2, key, value);
+ ki = interesting_keyword(keywordlist, key);
+ switch (ki) {
+ case XLATOR_KW_FUNC: /* Function keyword */
+ case XLATOR_KW_DATA: /* Data keyword */
+ meta_info.mi_extended = 0;
+ retval = xlator_start_if(meta_info, ki, value);
+ switch (retval) {
+ case XLATOR_FATAL: /* FATAL ERROR */
+ if (T_info->ti_verbosity >= STATUS) {
+ errlog(STATUS,
+ "Error in xlator_start_if: ");
+ }
+ ++errors;
+ return (errors);
+ case XLATOR_NONFATAL: /* NON-FATAL ERROR */
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS,
+ "Error in xlator_start_if\n");
+ ++errors;
+ start_if_fail = 1;
+ break;
+ case XLATOR_SUCCESS: /* OK */
+ start_if_fail = 0;
+ extends_err = check4extends(spec_filename,
+ value, T_info->ti_archtoken, spec_fp);
+ switch (extends_err) {
+ case -1: /* Error */
+ errlog(ERROR, "\"%s\", line %d: "
+ "Error occurred while "
+ "checking for extends clause\n",
+ spec_filename, Curlineno);
+ ++errors;
+ /*FALLTHRU*/
+ case 0: /* No Extends */
+ break;
+ case 1: /* Extends */
+ meta_info.mi_extended = 1;
+ extends_err = do_extends(meta_info,
+ T_info, value);
+ if (extends_err) {
+ errors += extends_err;
+ }
+ break;
+ default: /* Programmer Error */
+ errlog(ERROR | FATAL,
+ "Error: invalid return from "
+ "check4extends %d\n", extends_err);
+ }
+ break;
+ case XLATOR_SKIP: /* SKIP */
+ if (T_info->ti_verbosity >= WARNING)
+ errlog(WARNING, "Warning: Skipping "
+ "interface %s\n", value);
+ skip_if = 1;
+ start_if_fail = 0;
+ break;
+ default:
+ /* Invalid Return */
+ errlog(ERROR | FATAL,
+ "Error: Invalid return code "
+ "from xlator_start_if (): %d\n", retval);
+ }
+ break;
+ case XLATOR_KW_END: /* END keyword */
+ if (start_if_fail == 0 && skip_if == 0) {
+ retval = xlator_end_if(meta_info, value);
+ if (retval)
+ ++errors;
+ }
+ skip_if = 0;
+ break;
+ case XLATOR_KW_NOTFOUND:
+ if (T_info->ti_verbosity >= TRACING)
+ errlog(TRACING, "uninteresting keyword: %s\n",
+ key);
+ break;
+ default:
+ if (skip_if == 0 && start_if_fail == 0) {
+ retval = xlator_take_kvpair(meta_info,
+ ki, value);
+ if (retval) {
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Error in "
+ "xlator_take_kvpair\n");
+ ++errors;
+ }
+ }
+ }
+ free(buf2);
+ buf2 = NULL;
+ }
+
+ if ((retval = xlator_endfile()) != XLATOR_SUCCESS) {
+ if (T_info->ti_verbosity >= STATUS)
+ errlog(STATUS, "Error in xlator_endfile\n");
+ ++errors;
+ }
+ free(p);
+ (void) fclose(spec_fp);
+ return (errors);
+}
+
+/*
+ * interesting_keyword(char **keywordlist, const char *key) {
+ * returns the token associated with key if key is found in keywordlist
+ * returns XLATOR_KW_NOTFOUND if key is NOT found in keywordlist
+ * "Function" and "End" are always interesting, return XLATOR_KW_FUNC
+ * and XLATOR_KW_DATA respectively;
+ * "End" is always interesting, return XLATOR_KW_END;
+ *
+ */
+int
+interesting_keyword(xlator_keyword_t *keywordlist, const char *key)
+{
+ int i = 0;
+
+ if (strcasecmp(key, "data") == 0) {
+ return (XLATOR_KW_DATA);
+ }
+ if (strcasecmp(key, "function") == 0) {
+ return (XLATOR_KW_FUNC);
+ }
+
+ if (strcasecmp(key, "end") == 0)
+ return (XLATOR_KW_END);
+
+ while (keywordlist[i].key != NULL) {
+ if (strcasecmp(keywordlist[i].key, key) == 0)
+ return (keywordlist[i].token);
+ ++i;
+ }
+ return (XLATOR_KW_NOTFOUND);
+}
+
+/*
+ * line_to_buf(char *dest, const char *src) {
+ * appends src to dest, dynamically increasing the size of dest.
+ * replaces the trailing '\' continuation character with a space.
+ *
+ * if src is continuation of dest, dest != NULL, and
+ * the last character in dest before the newline must be a `\'
+ * if src is not continuation of dest, then dest must be NULL
+ */
+char *
+line_to_buf(char *dest, const char *src)
+{
+ int slen = strlen(src);
+ int dlen;
+
+ if (dest == NULL) {
+ /* We're being called for the first time */
+ dest = malloc(sizeof (char) * (slen + 1));
+ if (dest == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for dest\n");
+ }
+ (void) strcpy(dest, src);
+ return (dest);
+ }
+
+ dlen = strlen(dest);
+
+ dest = realloc(dest, (size_t)(sizeof (char) * (dlen+slen+1)));
+ if (dest == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory for dest\n");
+ }
+
+ if (dlen > 1) {
+ /*
+ * remove continuation character
+ * we replace the '\' from the previous line with a space
+ */
+ if (dest[dlen-2] == '\\') {
+ dest[dlen-2] = ' ';
+ }
+ }
+
+ /* join the two strings */
+ (void) strcat(dest, src);
+
+ return (dest);
+}
+
+/*
+ * non_empty(const char *str)
+ * assumes str is non null
+ * checks if str is a non empty string
+ * returns 1 if string contains non whitespace
+ * returns 0 if string contains only whitespace
+ */
+int
+non_empty(const char *str)
+{
+ while (*str != '\0') {
+ if (!isspace(*str))
+ return (1);
+ ++str;
+ };
+ return (0);
+}
+
+/*
+ * split(const char *line, char *key, char *value);
+ * splits the line into keyword (key) and value pair
+ */
+void
+split(const char *line, char *key, char *value)
+{
+ char *p;
+
+ p = (char *)line;
+
+ /* skip leading whitespace */
+ while (isspace(*p)&& *p != '\0')
+ ++p;
+
+ /* copy keyword from line into key */
+ while (!isspace(*p) && *p != '\0')
+ *key++ = *p++;
+
+ *key = '\0';
+
+ /* skip whitespace */
+ while (isspace(*p) && *p != '\0')
+ p++;
+
+ (void) strcpy(value, p);
+
+}
+
+/*
+ * check4extends(char *filename, char *value, int arch, FILE *fp)
+ * if no arch keyword is found or there is a MATCHING arch keyword
+ * returns 1 if value is of the form "data|function name extends"
+ * -1 for error
+ * 0 no other keyword after the function name
+ * else
+ * return 0
+ *
+ * filename is used only for error reporting
+ */
+int
+check4extends(const char *filename, const char *value, int arch, FILE *fp)
+{
+ char fun[BUFSIZ];
+ char extends[BUFSIZ];
+ int n;
+
+ if (arch_match(fp, arch)) {
+ split(value, fun, extends);
+ n = strlen(extends);
+ if (extends[n-1] == '\n')
+ extends[n-1] = '\0';
+ if (strncasecmp("extends", extends, 7) == 0) {
+ return (1);
+ } else {
+ if (*extends != '\0') {
+ errlog(ERROR, "\"%s\", line %d: Error: "
+ "Trailing garbage after function name\n",
+ filename, Curlineno);
+ return (-1);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * remcomment (char *buf)
+ * replace comments with single whitespace
+ */
+/* XXX: There is currently no way to escape a comment character */
+void
+remcomment(char const *buf)
+{
+ char *p;
+ p = strchr(buf, '#');
+ if (p) {
+ *p = ' ';
+ *(p+1) = '\0';
+ }
+}
+
+/*
+ * arch_strtoi()
+ *
+ * input: string
+ * return: XLATOR_I386 if string == ARCH_I386
+ * XLATOR_SPARC if string == ARCH_SPARC
+ * XLATOR_SPARCV9 if string == ARCH_SPARCV9
+ * XLATOR_IA64 if string == ARCH_IA64
+ * XLATOR_AMD64 if string == ARCH_AMD64
+ * XLATOR_ALLARCH if string == ARCH_ALL
+ * 0 if outside the known set {i386, sparc, sparcv9, ia64, amd64}.
+ */
+int
+arch_strtoi(const char *arch_str)
+{
+ if (arch_str != NULL) {
+ if (strcmp(arch_str, ARCH_I386) == 0)
+ return (XLATOR_I386);
+ else if (strcmp(arch_str, ARCH_SPARC) == 0)
+ return (XLATOR_SPARC);
+ else if (strcmp(arch_str, ARCH_SPARCV9) == 0)
+ return (XLATOR_SPARCV9);
+ else if (strcmp(arch_str, ARCH_IA64) == 0)
+ return (XLATOR_IA64);
+ else if (strcmp(arch_str, ARCH_AMD64) == 0)
+ return (XLATOR_AMD64);
+ else if (strcmp(arch_str, ARCH_ALL) == 0)
+ return (XLATOR_ALLARCH);
+ } else {
+ errlog(ERROR, "\"%s\", line %d: Error: "
+ "arch keyword with no value");
+ }
+ return (0);
+}
+
+int
+readline(char **buffer, FILE *fp)
+{
+ int nlines = 0;
+ int len;
+ char buf[BUFSIZ];
+
+ if (fgets(buf, BUFSIZ, fp)) {
+ nlines++;
+ /* replace comments with single whitespace */
+ remcomment(buf);
+
+ /* get complete line */
+ *buffer = line_to_buf(*buffer, buf); /* append buf to buffer */
+ len = strlen(buf);
+ if (len > 1) {
+ /* handle continuation lines */
+ while (buf[len-2] == '\\') {
+ if (!fgets(buf, BUFSIZ, fp)) {
+ *buffer = line_to_buf(*buffer, buf);
+ break;
+ }
+ nlines++;
+ len = strlen(buf);
+ *buffer = line_to_buf(*buffer, buf);
+ }
+ } /* end of 'get complete line' */
+ }
+ return (nlines);
+}
diff --git a/usr/src/cmd/abi/spectrans/parser/i386/Makefile b/usr/src/cmd/abi/spectrans/parser/i386/Makefile
new file mode 100644
index 0000000000..96eaa781f7
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/util/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/parser/main.c b/usr/src/cmd/abi/spectrans/parser/main.c
new file mode 100644
index 0000000000..1e3046ddc6
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/main.c
@@ -0,0 +1,231 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include "parser.h"
+#include "errlog.h"
+
+#define SPEC_PARSER_VERSION "2.1"
+
+char **filelist;
+
+static char *prog;
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ int c, retval, size = 0;
+ int lflag = 0,
+ iflag = 0,
+ aflag = 0,
+ vflag = 0;
+ char *tmpptr;
+
+ Translator_info T_info;
+
+ prog = basename(argv[0]);
+
+ T_info.ti_verbosity = 0;
+ T_info.ti_flags = 0;
+ T_info.ti_dash_I = NULL;
+ T_info.ti_output_file = NULL;
+ T_info.ti_libtype = NORMALLIB;
+ T_info.ti_versfile = "version";
+
+ while ((c = getopt(argc, argv, "FVpd:v:l:o:I:a:")) != EOF) {
+ switch (c) {
+ case 'F':
+ /* Library is a filter */
+ T_info.ti_libtype = FILTERLIB;
+ break;
+ case 'a':
+ /* set the target architecture */
+ if ((T_info.ti_archtoken = arch_strtoi(optarg)) == 0) {
+ errlog(ERROR,
+ "Error: architecture specified must "
+ "be one of: i386, sparc, sparcv9, "
+ "ia64 or amd64\n");
+ usage();
+ }
+ T_info.ti_arch = optarg;
+ ++aflag;
+ break;
+ case 'V':
+ /* print the version info */
+ (void) fprintf(stderr,
+ "%s Version %s\n", prog, SPEC_PARSER_VERSION);
+ return (0);
+ break;
+ case 'd':
+ /* set debugging level */
+ if (!isdigit(*optarg) ||
+ (T_info.ti_verbosity = atoi(optarg)) < 0) {
+ errlog(ERROR,
+ "Error: -d option must be given a "
+ "positive integer argument\n");
+ usage();
+ }
+ break;
+ case 'l':
+ /* set library name */
+ ++lflag;
+ if (!isalnum(optarg[0])) {
+ errlog(ERROR,
+ "Error: -l must be given the name of "
+ "a library as an argument\n");
+ usage();
+ }
+ T_info.ti_liblist = optarg;
+ break;
+ case 'I':
+ /* set path to spec files */
+ ++iflag;
+ if (iflag == 1) {
+ size = 1;
+ } else {
+ (void) strcat(T_info.ti_dash_I, ":");
+ size = strlen(T_info.ti_dash_I);
+ }
+ tmpptr = realloc(T_info.ti_dash_I,
+ sizeof (char) * (size + strlen(optarg) + 3));
+ if (tmpptr == NULL) {
+ errlog(ERROR | FATAL,
+ "Error: Unable to allocate memory "
+ "for command line arguments\n");
+ }
+ T_info.ti_dash_I = tmpptr;
+ if (iflag == 1) {
+ (void) strcpy(T_info.ti_dash_I, optarg);
+ } else {
+ (void) strcat(T_info.ti_dash_I, optarg);
+ }
+ break;
+ case 'v':
+ /* set version filename */
+ if (vflag != 0) {
+ errlog(ERROR, "Error: Multiple -v options "
+ "in command line\n");
+ usage();
+ }
+ T_info.ti_versfile = optarg;
+ ++vflag;
+ break;
+ case 'o':
+ /* set name of output file */
+ T_info.ti_output_file = optarg;
+ break;
+ case 'p':
+ /* set picky flag */
+ T_info.ti_flags = T_info.ti_flags | XLATOR_PICKY_FLAG;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if (lflag == 0) {
+ errlog(ERROR,
+ "Error: -l library argument must be specified\n");
+ usage();
+ }
+ if (aflag == 0) {
+ errlog(ERROR, "Error: -a i386|sparc|sparcv9|ia64|amd64 "
+ "argument must be specified\n");
+ usage();
+ }
+
+ if (optind < argc) {
+ filelist = &argv[optind];
+ } else {
+ filelist = NULL;
+ errlog(ERROR, "Error: Must specify at least one spec "
+ "file to process\n");
+ usage();
+ }
+
+ T_info.ti_nfiles = argc-optind;
+ seterrseverity(T_info.ti_verbosity);
+
+ if (T_info.ti_dash_I == NULL) {
+ T_info.ti_dash_I = ".";
+ } else {
+ (void) strcat(T_info.ti_dash_I, ":.");
+ }
+
+ errlog(STATUS, "using %s for spec path\n", T_info.ti_dash_I);
+
+ if ((retval = frontend(&T_info)) != 0) {
+ errlog(ERROR, "%d Error(s) occurred\n", retval);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * usage()
+ * prints the usage string and exits
+ */
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "Usage:\n\t%s [-d n] [-V] [ -v version_file] "
+ "-a i386|sparc|sparcv9|ia64|amd64 -l lib [-I path_to_spec ] "
+ "[-o outfile ] [-p] [-F] file.spec [ ... ]\n"
+ "Command line arguments:\n"
+ " -d n n is an integer specifying "
+ "the level of verbosity\n"
+ " -V Print the Version info\n"
+ " -a arch Target cpu architecture. "
+ "Must be one of\n"
+ " i386, sparc, sparcv9, ia64 or amd64\n"
+ " -v version_file Name of version file\n"
+ " -o file Name of output file\n"
+ " this option can only be used when "
+ "processing single\n spec files. "
+ "Using this with multiple source .spec\n"
+ " filenames will cause "
+ "unpredictable results\n"
+ " -l lib library to process\n"
+ " -I path_to_spec path to spec files\n"
+ " -p be picky with interface versioning\n"
+ " -F library is a filter library\n", prog);
+ exit(1);
+}
diff --git a/usr/src/cmd/abi/spectrans/parser/parser.h b/usr/src/cmd/abi/spectrans/parser/parser.h
new file mode 100644
index 0000000000..cd9c40dfde
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/parser.h
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PARSER_H
+#define _PARSER_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <sys/param.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct metainfo {
+ char mi_filename[MAXPATHLEN];
+ int mi_line_number;
+ int mi_nlines;
+ int mi_ext_cnt;
+ int mi_flags;
+ int mi_extended;
+} Meta_info;
+
+typedef struct translator_info {
+ char *ti_liblist;
+ char *ti_dash_I;
+ char *ti_output_file;
+ int ti_nfiles;
+ int ti_verbosity;
+ int ti_flags;
+ char *ti_versfile;
+ char *ti_arch;
+ int ti_archtoken;
+ int ti_libtype; /* set to FILTERLIB if processing filter lib */
+} Translator_info;
+
+typedef struct {
+ char *key;
+ int token;
+} xlator_keyword_t;
+
+/*
+ * Translator Flags
+ * These are values for the ti_flags member of the Translator_info
+ * structure. Each bit of ti_flags represents a flag.
+ * first bit = picky flag; translator runs in picky mode
+ * picky mode means complain about interfaces with no versions
+ */
+#define XLATOR_PICKY_FLAG 0x01
+
+/* Return Codes from xlator_* functions */
+#define XLATOR_FATAL -2
+#define XLATOR_NONFATAL -1
+#define XLATOR_SUCCESS 0
+#define XLATOR_SKIP 1
+
+/* Misc Return Codes from Utility Functions */
+enum {
+ XLATOR_KW_NOTFOUND,
+ XLATOR_KW_FUNC,
+ XLATOR_KW_DATA,
+ XLATOR_KW_END
+};
+
+/* Library Type */
+#define NORMALLIB 0
+#define FILTERLIB 1
+
+/* Maxmimum levels of extends */
+#define MAX_EXTENDS 16
+
+/* Architecture Bitmap */
+#define XLATOR_SPARC 0x01
+#define XLATOR_SPARCV9 0x02
+#define XLATOR_I386 0x04
+#define XLATOR_IA64 0x08
+#define XLATOR_AMD64 0x10
+#define XLATOR_ALLARCH 0xFF
+
+extern xlator_keyword_t *keywordlist;
+extern char **filelist;
+extern int verbosity;
+
+extern int frontend(const Translator_info *);
+extern int do_extends(const Meta_info, const Translator_info *, char *);
+extern void split(const char *, char *, char *);
+extern void remcomment(char const *);
+extern void getlinecont(char *, char *, int, FILE *, Meta_info *);
+extern char *line_to_buf(char *, const char *);
+extern int non_empty(const char *);
+extern int check4extends(const char *, const char *, int, FILE *);
+extern int interesting_keyword(xlator_keyword_t *, const char *);
+extern int arch_strtoi(const char *);
+extern int readline(char **, FILE *);
+extern int arch_match(FILE *, int);
+
+/* xlator_ functions */
+extern xlator_keyword_t *xlator_init(const Translator_info *);
+extern int xlator_startlib(char const *libname);
+extern int xlator_startfile(char const *filename);
+extern int xlator_start_if(const Meta_info meta_info, const int token,
+ char *value);
+extern int xlator_take_kvpair(const Meta_info, const int token, char *value);
+extern int xlator_end_if(const Meta_info, const char *value);
+extern int xlator_endfile(void);
+extern int xlator_endlib(void);
+extern int xlator_end(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PARSER_H */
diff --git a/usr/src/cmd/abi/spectrans/parser/sparc/Makefile b/usr/src/cmd/abi/spectrans/parser/sparc/Makefile
new file mode 100644
index 0000000000..ead0073869
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/parser/sparc/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/parser/sparc/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/spec2map/Makefile b/usr/src/cmd/abi/spectrans/spec2map/Makefile
new file mode 100644
index 0000000000..0866e6cf5c
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/spec2map/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.arch
diff --git a/usr/src/cmd/abi/spectrans/spec2map/Makefile.targ b/usr/src/cmd/abi/spectrans/spec2map/Makefile.targ
new file mode 100644
index 0000000000..eba87b10e7
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/Makefile.targ
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/spec2map/Makefile.targ
+
+.KEEP_STATE:
+
+PROG = spec2map
+
+OBJECTS = xlator.o \
+ versions.o \
+ bucket.o \
+ util.o
+
+include ../../Makefile.cmd
diff --git a/usr/src/cmd/abi/spectrans/spec2map/bucket.c b/usr/src/cmd/abi/spectrans/spec2map/bucket.c
new file mode 100644
index 0000000000..5a031a1706
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/bucket.c
@@ -0,0 +1,748 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "xlator.h"
+#include "util.h"
+#include "bucket.h"
+#include "errlog.h"
+
+/* Statics: */
+#define TRUE 1
+#define FALSE 0
+#define NLISTS 50
+#define NPAR 25
+
+static bucket_t **Buckethead;
+static int N_lists;
+
+static int Bc = -1; /* For iterators. */
+static bucket_t *Bp;
+
+static void start_new_list(const bucket_t *);
+static void grow_lists(void);
+static bucket_t *new_bucket(const char *, int);
+static void print_iface(const Interface *);
+static void new_hashmap(void);
+static int add_to_hashmap(const char *, const bucket_t *);
+static bucket_t *find_in_hashmap(const char *);
+/*
+ * initialization interfaces.
+ */
+
+/*
+ * create_lists -- initialize the bucket list and hash map.
+ */
+void
+create_lists(void)
+{
+
+ errlog(BEGIN, "create_lists() {");
+ new_hashmap();
+ if ((Buckethead = calloc(sizeof (bucket_t *), NLISTS)) == NULL) {
+ errlog(FATAL, "out of memory creating initial "
+ "list of versions");
+
+ }
+ N_lists = NLISTS;
+ errlog(END, "}");
+}
+
+
+/*
+ * data-loading interfaces -- adding buckets to lists and
+ * interfaces to buckets.
+ */
+
+/*
+ * add_parent -- add a parent node. Returns TRUE or FALSE.
+ *
+ * if *version == NULL, then
+ * the bucket version (eg, SUNW_1.1) hasn't
+ * been parsed correctly. Die.
+ * if *after == NULL, then this is the ``initial case'',
+ * where no predecessor (child) exists. We start a new
+ * tree of buckets.
+ * if *after != NULL, we have the normal case, and
+ * add to an existing tree.
+ * if *after is not a version name found among the buckets,
+ * then something got misparsed or the versions file is
+ * malformed. Function will print problem and
+ * return 0 so caller can report location of error.
+ * If either version or after is NULL, it's a programmer error.
+ */
+int
+add_parent(const char *version, const char *after, int weak)
+{
+ bucket_t *new, *child;
+
+ /* Sanity-check parameters. */
+ assert(version != NULL, "passed a null version to add_parent");
+ assert(after != NULL, "passed a null after to add_parent");
+ errlog(BEGIN, "add_parent(%s,%s,%d) {", version, after, weak);
+ if ((new = find_in_hashmap(version)) == NULL) {
+ /* We don't have one have one yet. */
+ new = new_bucket(version, weak);
+ }
+ new->b_weak = weak;
+ if (*after == '\0') {
+ /*
+ * This is the ``initial case'', where no
+ * child exists. We start a new tree of buckets.
+ */
+ (void) add_to_hashmap(version, new);
+ start_new_list(new);
+ } else {
+ if ((child = find_in_hashmap(after)) == NULL) {
+ /*
+ * The version in the spec doesn't appear in the
+ * versions file. One or the other is lying.
+ */
+ errlog(WARNING, "set file: can't find version \"%s\","
+ "therefor can't add it's parent, \"%s\"",
+ after, version);
+ errlog(END, "} /* add_parent */");
+ return (FALSE);
+ }
+ (void) add_to_hashmap(version, new);
+ child->b_parent = new;
+ }
+ errlog(END, "} /* add_parent */");
+ return (TRUE);
+}
+
+/*
+ * add_uncle -- adds an uncle node
+ */
+int
+add_uncle(const char *version, const char *after, int weak)
+{
+ bucket_t *new, *child;
+ struct bucketlist *uncle;
+
+ /* Sanity-check parameters. */
+ assert(version != NULL, "passed a null version to add_uncle");
+ assert(after != NULL, "passed a null after to add_uncle");
+ errlog(BEGIN, "add_uncle(%s,%s,%d) {", version, after, weak);
+ if ((new = find_in_hashmap(version)) == NULL) {
+ /* We don't have one have one yet. */
+ new = new_bucket(version, weak);
+ }
+ if (*after == '\0') {
+ /*
+ * This is the ``initial case'', where no
+ * child exists. We start a new tree of buckets.
+ */
+ (void) add_to_hashmap(version, new);
+ start_new_list(new);
+ } else {
+ if ((child = find_in_hashmap(after)) == NULL) {
+ /*
+ * The version in the spec doesn't appear in the
+ * versions file. One or the other is lying.
+ */
+ errlog(WARNING, "set file: can't find version \"%s\","
+ "therefor can't add it's uncle, \"%s\"",
+ after, version);
+ errlog(END, "}");
+ return (FALSE);
+ }
+ (void) add_to_hashmap(version, new);
+ uncle = malloc(sizeof (struct bucketlist));
+ uncle->bl_next = child->b_uncles;
+ uncle->bl_bucket = new;
+ child->b_uncles = uncle;
+ }
+ errlog(END, "}");
+ return (TRUE);
+}
+
+/*
+ * set_weak -- set a version to be a weak version
+ */
+void
+set_weak(const char *version, int weak)
+{
+ bucket_t *v;
+ if ((v = find_in_hashmap(version)) == NULL) {
+ /* We don't have one have one yet. */
+ errlog(ERROR|FATAL, "Unable to set weak. Version not found");
+ }
+ v->b_weak = weak;
+}
+
+/*
+ * add_by_name -- look up bucket and add an interface to it.
+ * Returns 0 for success or an errno.h value for failure.
+ *
+ * if *version is not among the buckets, then the
+ * version in the spec doesn't appear in the
+ * set file. One or the other is lying. Function will
+ * report the problem and return ENOENT
+ * so the front end can report and exit (or
+ * continue if it wants).
+ * if interface ore version is NULL, then
+ * the begin line code should
+ * have caught it long before, to avoid passing
+ * a null pointer around. Die.
+ *
+ */
+#define ADD_EQUALS(str) if (strchr(str, '=') == NULL) (void) strcat(str, " =")
+
+int
+add_by_name(const char *version, const Interface *interface)
+{
+ bucket_t *b;
+ char buffer[1024];
+
+ assert(version != NULL, "passed a null version to add_by_name");
+ assert(interface != NULL, "passed a null interface to add_by_name");
+
+ errlog(BEGIN, "add_by_name(%s,", version);
+ print_iface(interface);
+ errlog(TRACING, ");");
+
+ /* Sanity-check the parameters. */
+ if ((b = find_in_hashmap(version)) == NULL) {
+ /*
+ * The version in the spec doesn't appear in the
+ * versions file. Alas, this isn't an error. It can
+ * happen whenever doing just sparc, just i386
+ * or the like.
+ */
+ errlog(END, "}");
+ return (ENOENT);
+ }
+ /*
+ * Add to bucket.
+ */
+ (void) snprintf(buffer, sizeof (buffer), "%s", interface->IF_name);
+
+ if (interface->IF_filter && interface->IF_auxiliary) {
+ errlog(FATAL, "Error: cannot set both FILTER and AUXILIARY "
+ "for an interface: %s", interface->IF_name);
+ }
+
+ if (interface->IF_filter) {
+ ADD_EQUALS(buffer);
+ if (interface->IF_type == FUNCTION) {
+ (void) strcat(buffer, " FUNCTION");
+ } else if (interface->IF_type == DATA) {
+ (void) strcat(buffer, " DATA");
+ }
+ (void) strcat(buffer, " FILTER ");
+ (void) strcat(buffer, interface->IF_filter);
+ } else if (interface->IF_auxiliary) {
+ ADD_EQUALS(buffer);
+ (void) strcat(buffer, " AUXILIARY ");
+ (void) strcat(buffer, interface->IF_auxiliary);
+ } else if (IsFilterLib) {
+ /*
+ * For DATA types it is currently assumed that they are
+ * handled via a minimal C file, e.g. 'data.c', in the
+ * library's build. Hence, we do not append '= DATA' here.
+ */
+ if (interface->IF_type == FUNCTION) {
+ ADD_EQUALS(buffer);
+ (void) strcat(buffer, " FUNCTION");
+ }
+ }
+
+ switch (interface->IF_binding) {
+ case DIRECT:
+ ADD_EQUALS(buffer);
+ (void) strcat(buffer, " DIRECT");
+ break;
+ case NODIRECT:
+ ADD_EQUALS(buffer);
+ (void) strcat(buffer, " NODIRECT");
+ break;
+ }
+
+ if (interface->IF_binding == PROTECTED) {
+ /* Assign in case of realloc. */
+ b->b_protected_table =
+ add_to_stringtable(b->b_protected_table, buffer);
+ b->b_has_protecteds = 1;
+ errlog(VERBOSE, "set has_protecteds on bucket 0x%p", b);
+ } else {
+ /* Assign in case of realloc. */
+ b->b_global_table = add_to_stringtable(b->b_global_table,
+ buffer);
+ }
+ errlog(END, "}");
+ return (0);
+}
+
+
+/*
+ * Processing interfaces
+ */
+
+/*
+ * sort_buckets -- sort the interfaces within the buckets into
+ * alphabetical order.
+ */
+void
+sort_buckets(void)
+{
+ bucket_t *l, *b;
+
+ errlog(BEGIN, "sort_buckets() {");
+ for (l = first_list(); l != NULL; l = next_list()) {
+ errlog(VERBOSE, "l-bucket: %s", l->b_name);
+ for (b = first_from_list(l); b != NULL; b = next_from_list()) {
+ errlog(VERBOSE, " b-bkt: %s", b->b_name);
+ sort_stringtable(b->b_global_table);
+ sort_stringtable(b->b_protected_table);
+ if (b->b_uncles) {
+
+ if (b->b_uncles->bl_bucket) {
+ sort_stringtable(b->b_uncles->bl_bucket->b_global_table);
+ sort_stringtable(b->b_uncles->bl_bucket->b_protected_table);
+ }
+ }
+ }
+ }
+ errlog(END, "}");
+}
+
+
+/*
+ * add_local -- set the local flag on the logically first bucket.
+ * This decision may belong in the caller, as it is about
+ * mapfiles, not inherent ordering or bucket contents...
+ */
+void
+add_local(void)
+{
+ bucket_t *b, *list;
+ int done = 0;
+
+ errlog(BEGIN, "add_local() {");
+ /* Iterate across lists of buckets */
+ for (list = first_list(); list != NULL; list = next_list()) {
+ /* Traverse the list found. */
+ for (b = list; b != NULL; b = b->b_parent) {
+ if (b->b_weak != 1) {
+ /* We've found the first non-weak. */
+ b->b_has_locals = done = 1;
+ errlog(VERBOSE,
+ "set has_locals on bucket 0x%p", b);
+ break;
+ }
+ }
+ if (b != NULL && b->b_has_locals == 1)
+ break;
+ }
+ if (done == 0) {
+ errlog(WARNING, "has_locals never set");
+ }
+ errlog(END, "}");
+}
+
+
+/*
+ * Output interfaces, mostly iterators
+ */
+
+
+/*
+ * parents_of -- return a list of all parents.
+ */
+char **
+parents_of(const bucket_t *start)
+{
+ static char *a[NPAR] = {NULL};
+ const bucket_t *b = start;
+ char **p = &a[0];
+
+ assert(start != NULL, "passed a null start to parents_of");
+ errlog(BEGIN, "parents_of() {");
+ a[0] = '\0';
+
+ /* Go to parent, print it and all its uncle. */
+ if (b->b_parent == NULL) {
+ errlog(TRACING, "returning empty string");
+ errlog(END, "}");
+ return (a);
+ }
+ b = b->b_parent;
+ *p++ = b->b_name;
+ *p = '\0';
+
+ assert(p < &a[NPAR], "p fell off the end of a in parents_of");
+ errlog(END, "}");
+ return (a);
+}
+
+/*
+ * first, next_from_bucket --iterators for bucket contents. Serially
+ * reusable only.
+ */
+int Ic = -1;
+
+/*
+ * debugging interfaces
+ */
+void
+print_bucket(const bucket_t *b)
+{
+
+ errlog(TRACING, "bucket_t at 0x%p {", (void *)b);
+ errlog(TRACING, " char *b_name = \"%s\";", b->b_name);
+ errlog(TRACING, " struct bucket_t *b_parent = 0x%p;",
+ (void *)b->b_parent);
+ errlog(TRACING, " struct bucketlist *b_uncles = 0x%p;",
+ (void *)b->b_uncles);
+ errlog(TRACING, " struct bucket_t *b_thread = 0x%p;",
+ (void *)b->b_thread);
+ errlog(TRACING, " int b_has_locals = %d;",
+ b->b_has_locals);
+ errlog(TRACING, " int b_has_protecteds = %d;",
+ b->b_has_protecteds);
+ errlog(TRACING, " int b_was_printed = %d;",
+ b->b_was_printed);
+ errlog(TRACING, " int b_weak = %d;",
+ b->b_weak);
+ errlog(TRACING, " table_t *b_global_table = 0x%p;",
+ (void *)b->b_global_table);
+ errlog(TRACING, " table_t *b_protected_table = 0x%p;",
+ (void *)b->b_protected_table);
+ errlog(TRACING, "}");
+}
+
+void
+print_all_buckets(void)
+{
+ bucket_t *l, *b;
+ int i = 0, j = 0;
+ char **p;
+
+ for (i = 0, l = first_list(); l != NULL; l = next_list(), ++i) {
+ errlog(TRACING, "list %d", i);
+ for (j = 0, b = first_from_list(l);
+ b != NULL; b = next_from_list(), ++j) {
+ errlog(TRACING, "bucket %d", j);
+ print_bucket(b);
+ errlog(TRACING, "global interfaces = {");
+ print_stringtable(b->b_global_table);
+ errlog(TRACING, "}");
+ errlog(TRACING, "protected interfaces = {");
+ print_stringtable(b->b_protected_table);
+ errlog(TRACING, "}");
+
+ for (p = parents_of(b); p != NULL && *p != NULL; ++p) {
+ errlog(TRACING, " %s", *p);
+ }
+ errlog(TRACING, ";");
+
+ if (b->b_uncles) {
+ errlog(TRACING, " uncle bucket %d.1", j);
+ print_bucket(b->b_uncles->bl_bucket);
+ errlog(TRACING, "global interfaces = {");
+ print_stringtable(
+ b->b_uncles->bl_bucket->b_global_table);
+ errlog(TRACING, "}");
+ errlog(TRACING, "protected interfaces = {");
+ print_stringtable(
+ b->b_uncles->bl_bucket->b_protected_table);
+ errlog(TRACING, "}");
+ }
+ }
+ }
+}
+
+
+/*
+ * lower-level functions, not visible outside the file.
+ */
+
+/*
+ * new_bucket -- create a bucket for a given version. Must not fail.
+ */
+static bucket_t *
+new_bucket(const char *name, int weak)
+{
+ bucket_t *b;
+
+ if ((b = (bucket_t *)calloc(1, sizeof (bucket_t))) == NULL) {
+ errlog(FATAL, "out of memory creating a bucket "
+ "to store interfaces in");
+ }
+ if ((b->b_name = strdup(name)) == NULL) {
+ errlog(FATAL, "out of memory storing an interface "
+ "in a version bucket");
+ }
+ b->b_uncles = NULL;
+ b->b_global_table = create_stringtable(TABLE_INITIAL);
+ b->b_protected_table = create_stringtable(TABLE_INITIAL);
+ b->b_weak = weak;
+ return (b);
+}
+
+
+/*
+ * start_new_list -- start a list of buckets.
+ */
+static void
+start_new_list(const bucket_t *b)
+{
+ int i;
+
+ errlog(BEGIN, "start_new_list() {");
+ assert(Buckethead != NULL, "Buckethead null in start_new_list");
+ for (i = 0; Buckethead[i] != NULL && i < N_lists; ++i)
+ continue;
+ if (i >= N_lists) {
+ grow_lists();
+ }
+ Buckethead[i] = (bucket_t *)b;
+ errlog(END, "}");
+}
+
+/*
+ * grow_list -- make more lists. This should never occur...
+ */
+static void
+grow_lists(void)
+{
+ int i = N_lists;
+
+ errlog(BEGIN, "grow_lists() {");
+ errlog(WARNING, "Warning: more than %d version lists "
+ "required (< %d is normal). Check sets file "
+ "to see why so many lines appear.",
+ N_lists, NLISTS);
+
+ N_lists *= 2;
+ if ((Buckethead = realloc(Buckethead, sizeof (bucket_t *) * N_lists))
+ == NULL) {
+ errlog(FATAL, "out of memory growing list of "
+ "version buckets");
+ }
+ for (; i < N_lists; ++i) {
+ Buckethead[i] = NULL;
+ }
+}
+
+/*
+ * delete_lists -- clean up afterwards.
+ */
+void
+delete_lists(void)
+{
+ N_lists = 0;
+ free(Buckethead);
+ Buckethead = 0;
+}
+
+/*
+ * first_list, next_list -- an iterator for lists themselves. Serially
+ * reusable only.
+ */
+bucket_t *
+first_list(void)
+{
+ Bc = 0;
+ return (Buckethead[Bc]);
+}
+
+bucket_t *
+next_list(void)
+{
+ return (Buckethead[++Bc]);
+}
+
+
+/*
+ * first, next, last_from_list -- iterators for individual lists. Serially
+ * reusable only.
+ */
+bucket_t *
+first_from_list(const bucket_t *l)
+{
+ return (Bp = (bucket_t *)l);
+}
+
+bucket_t *
+next_from_list(void)
+{
+ return (Bp = Bp->b_parent);
+}
+
+
+
+/*
+ * Iface print utility
+ */
+static void
+print_iface(const Interface * p)
+{
+
+ errlog(TRACING, "%s (%s, %s, %s %d)", p->IF_name,
+ (p->IF_type == FUNCTION) ? "function" :
+ (p->IF_type == DATA) ? "data" : "unknown type",
+ (p->IF_version) ? p->IF_version : "unknown version",
+ (p->IF_class) ? p->IF_class : "unknown class",
+ p->IF_binding);
+}
+
+
+
+#define HASHMAPSIZE 100
+#define ERR (-1)
+
+static struct {
+ hashmap_t *hh_map;
+ int hh_map_size;
+ int hh_mapC;
+ hashmap_t *hh_last;
+} Hashhead = {
+ NULL, -1, -1, NULL
+};
+
+static int checksum(const char *);
+static void print_hashmap(const hashmap_t *);
+
+/*
+ * new_hashmap -- create the hash.
+ */
+static void
+new_hashmap(void)
+{
+
+ errlog(BEGIN, "new_hashmap() {");
+ if ((Hashhead.hh_map = calloc(sizeof (hashmap_t), HASHMAPSIZE))
+ == NULL) {
+ errlog(FATAL, "out of memory creating a hash-map of "
+ "the versions");
+ }
+ Hashhead.hh_mapC = 0;
+ errlog(END, "}");
+}
+
+/*
+ * add_to_hashmap -- add a bucket to the map. This is strictly for
+ * use by add_parent()/add_uncle().
+ */
+static int
+add_to_hashmap(const char *version_name, const bucket_t *bucket)
+{
+ hashmap_t *p;
+
+ assert(Hashhead.hh_map != NULL,
+ "Hashead.map was null in add_to_hashmap");
+ assert(Hashhead.hh_mapC < HASHMAPSIZE,
+ "mapC too big in add_to_hashmap");
+ errlog(BEGIN, "add_to_hashmap(%s, %s) {", version_name, bucket);
+ if (find_in_hashmap(version_name) != NULL) {
+ /* Seen for the second time. TBD... */
+ errlog(END, "} /* add_to_hashmap */");
+ return (ERR);
+ }
+ p = &Hashhead.hh_map[Hashhead.hh_mapC++];
+ if ((p->h_version_name = strdup(version_name)) == NULL) {
+ errlog(FATAL, "out of memory storing a version name");
+
+ }
+ p->h_bucket = (bucket_t *)bucket;
+ p->h_hash = checksum(version_name);
+ Hashhead.hh_last = p;
+ print_hashmap(p);
+ errlog(END, "} /* add_to_hashmap */");
+ return (0);
+}
+
+
+/*
+ * find_in_hashmap -- find a bucket by name. Strictly for use by addByName().
+ */
+static bucket_t *
+find_in_hashmap(const char *version_name)
+{
+ hashmap_t *current;
+ int hash = checksum(version_name);
+
+ assert(Hashhead.hh_map != NULL,
+ "Hashhead.hh_map was null in find_in_hashmap");
+ errlog(BEGIN, "find_in_hashmap(%s) {", version_name);
+ if (Hashhead.hh_last != NULL && Hashhead.hh_last->h_hash == hash &&
+ strcmp(Hashhead.hh_last->h_version_name, version_name) == 0) {
+ errlog(END, "}");
+ return (Hashhead.hh_last->h_bucket);
+ }
+ for (current = Hashhead.hh_map;
+ current->h_version_name != NULL; ++current) {
+ if (current->h_hash == hash &&
+ strcmp(current->h_version_name, version_name) == 0) {
+ /* Found it */
+ Hashhead.hh_last = current;
+ errlog(END, "}");
+ return (current->h_bucket);
+ }
+ }
+ /* Doesn't exist, meaning version name is bogus. */
+ errlog(END, "}");
+ return (NULL);
+}
+
+/*
+ * checksum -- from sum(1), algorithm 1.
+ */
+static int
+checksum(const char *p)
+{
+ int sum;
+
+ for (sum = 0; *p != NULL; ++p) {
+ if (sum & 01)
+ sum = (sum >> 1) + 0x8000;
+ else
+ sum >>= 1;
+ sum += *p;
+ sum &= 0xFFFF;
+ }
+ return (sum);
+}
+
+static void
+print_hashmap(const hashmap_t *h)
+{
+ errlog(VERBOSE, "struct hashmap_t at 0x4.4x {", h);
+ errlog(VERBOSE, " int h_hash = %d;", h->h_hash);
+ errlog(VERBOSE, " char *h_version_name = \"%s\";",
+ h->h_version_name);
+ errlog(VERBOSE, " bucket_t *h_bucket = 0x%p;;",
+ (void *) h->h_bucket);
+ errlog(VERBOSE, "}");
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2map/bucket.h b/usr/src/cmd/abi/spectrans/spec2map/bucket.h
new file mode 100644
index 0000000000..ab5356fe76
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/bucket.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * 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 1997-1999,2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _BUCKET_H
+#define _BUCKET_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct bucketlist {
+ struct bucket *bl_bucket;
+ struct bucketlist *bl_next;
+};
+
+typedef struct bucket {
+ char *b_name;
+ struct bucket *b_parent;
+ struct bucketlist *b_uncles;
+ struct bucket *b_thread;
+ int b_has_locals; /* Should contain ``local:*;'' */
+ int b_has_protecteds; /* Has ``protected:'' section */
+ int b_was_printed; /* For loop detection. */
+ int b_weak; /* Weak interface. */
+ table_t *b_global_table;
+ table_t *b_protected_table;
+} bucket_t;
+
+
+/* Bucket interfaces, general. */
+extern void create_lists(void);
+extern void delete_lists(void);
+extern void print_bucket(const bucket_t *);
+extern void print_all_buckets(void);
+
+/* Transformation interfaces. */
+extern void sort_buckets(void);
+extern void thread_trees(void);
+extern void add_local(void);
+
+/* Composite interfaces for insertion. */
+extern int add_by_name(const char *, const Interface *);
+extern int add_parent(const char *, const char *, int);
+extern int add_uncle(const char *, const char *, int);
+
+/* Output Interfaces, iterators */
+extern bucket_t *first_list(void);
+extern bucket_t *next_list(void);
+extern bucket_t *first_from_list(const bucket_t *);
+extern bucket_t *next_from_list(void);
+
+/* Output Interfaces, extraction. */
+extern char **parents_of(const bucket_t *);
+
+extern void set_weak(const char *, int);
+
+typedef struct {
+ int h_hash;
+ char *h_version_name;
+ bucket_t *h_bucket;
+} hashmap_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BUCKET_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2map/i386/Makefile b/usr/src/cmd/abi/spectrans/spec2map/i386/Makefile
new file mode 100644
index 0000000000..8bbe98a92f
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/spec/map/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile b/usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile
new file mode 100644
index 0000000000..501b453f7f
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/sparc/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/spec2map/sparc/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/spec2map/util.c b/usr/src/cmd/abi/spectrans/spec2map/util.c
new file mode 100644
index 0000000000..c467290c5a
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/util.c
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * util.c -- low-level utilities used by map*.c
+ */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "xlator.h"
+#include "util.h"
+#include "errlog.h"
+
+/*
+ * String tables -- WARNING! This uses realloc to recreate tables,
+ * so always assign table_t * return value to the current
+ * table pointer, lest the table address change in the
+ * called function.
+ */
+static char *strset(char *, char *);
+
+table_t *
+create_stringtable(int size)
+{
+ table_t *t;
+
+ /* Solaris idiom: malloc && memset. TBD. */
+ if ((t = calloc((size_t)1, (size_t)(sizeof (table_t) +
+ ((sizeof (char *)) * size)))) == NULL) {
+ errlog(FATAL,
+ "\nOut of memory.\n"
+ "We wish to hold the whole sky,\n"
+ "But we never will.\n");
+ }
+ t->nelem = size;
+ t->used = -1;
+ return (t);
+}
+
+
+table_t *
+add_to_stringtable(table_t *t, char *value)
+{
+ table_t *t2;
+
+ int i;
+
+ if (t == NULL) {
+ seterrline(__LINE__, __FILE__, NULL, NULL);
+ errlog(FATAL|PROGRAM, "programmer error: tried to add to "
+ "a NULL table");
+ }
+ if (in_stringtable(t, value)) {
+ return (t);
+ }
+ ++t->used;
+ if (t->used >= t->nelem) {
+ if ((t2 = realloc(t, (size_t)(sizeof (table_t) +
+ ((sizeof (char *)) * (t->nelem + TABLE_INCREMENT)))))
+ == NULL) {
+ print_stringtable(t);
+ seterrline(__LINE__, __FILE__, NULL, NULL);
+ errlog(FATAL|PROGRAM, "out of memory extending a "
+ "string table");
+ }
+ t = t2;
+ t->nelem += TABLE_INCREMENT;
+ for (i = t->used; i < t->nelem; ++i) {
+ t->elements[i] = NULL;
+ }
+ }
+ t->elements[t->used] = strset(t->elements[t->used], value);
+ return (t);
+}
+
+/*
+ * free_stringtable -- really only mark it empty for reuse.
+ */
+table_t *
+free_stringtable(table_t *t)
+{
+
+ if (t != NULL) {
+ t->used = -1;
+ }
+ return (t);
+}
+
+
+char *
+get_stringtable(table_t *t, int index)
+{
+
+ if (t == NULL) {
+ return (NULL);
+ } else if (index > t->used) {
+ return (NULL);
+ } else {
+ return (t->elements[index]);
+ }
+}
+
+int
+in_stringtable(table_t *t, const char *value)
+{
+ int i;
+
+ if (t == NULL) {
+ return (0);
+ }
+ for (i = 0; i <= t->used; ++i) {
+ if (strcmp(value, t->elements[i]) == 0)
+ return (1);
+ }
+ return (0);
+}
+
+
+void
+print_stringtable(table_t *t)
+{
+ int i;
+
+ if (t == NULL)
+ return;
+
+ errlog(VERBOSE,
+ "table size = %d elements out of %d elements/%d bytes\n",
+ t->used + 1, t->nelem,
+ sizeof (table_t) + (sizeof (char *) * t->nelem));
+
+ for (i = 0; i <= t->used; ++i) {
+ (void) fprintf(stderr, "\t%s\n",
+ get_stringtable(t, i));
+ }
+}
+
+static int
+compare(const void *p, const void *q)
+{
+ return (strcmp((char *)p, (char *)q));
+}
+
+void
+sort_stringtable(table_t *t)
+{
+
+ if (t && t->used > 0) {
+ qsort((char *)t->elements, (size_t)t->used,
+ sizeof (char *), compare);
+ }
+}
+
+
+/*
+ * strset -- update a dynamically-allocated string or die trying.
+ */
+/*ARGSUSED*/
+static char *
+strset(char *string, char *value)
+{
+ size_t vlen;
+
+ assert(value != NULL, "passed a null value to strset");
+ vlen = strlen(value);
+ if (string == NULL) {
+ /* It was never allocated, so allocate it. */
+ if ((string = malloc(vlen + 1)) == NULL) {
+ seterrline(__LINE__, __FILE__, NULL, NULL);
+ errlog(FATAL|PROGRAM, "out of memory allocating a "
+ "string");
+ }
+ } else if (strlen(string) < vlen) {
+ /* Reallocate bigger. */
+ if ((string = realloc(string, vlen + 1)) == NULL) {
+ seterrline(__LINE__, __FILE__, NULL, NULL);
+ errlog(FATAL|PROGRAM, "out of memory reallocating"
+ "a string");
+ }
+ }
+ (void) strcpy(string, value);
+ return (string);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2map/util.h b/usr/src/cmd/abi/spectrans/spec2map/util.h
new file mode 100644
index 0000000000..58a7d7ac6f
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/util.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* String tables */
+typedef struct table_head_t {
+ int nelem;
+ int used;
+ char *elements[1]; /* Actually elements[nelem] */
+} table_t;
+
+#define TABLE_INITIAL 50
+#define TABLE_INCREMENT 50
+
+
+extern char *get_stringtable(table_t *, int);
+extern int in_stringtable(table_t *, const char *);
+extern int in_stringset(char *, char *);
+extern void print_stringtable(table_t *);
+extern void sort_stringtable(table_t *);
+
+/* Caveat: never discard return value: see note in .c file. */
+extern table_t *add_to_stringtable(table_t *, char *);
+
+extern table_t *create_stringtable(int);
+extern table_t *free_stringtable(table_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2map/versions.c b/usr/src/cmd/abi/spectrans/spec2map/versions.c
new file mode 100644
index 0000000000..8eae89de68
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/versions.c
@@ -0,0 +1,683 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "xlator.h"
+#include "util.h"
+#include "bucket.h"
+#include "errlog.h"
+
+/* Types: */
+#define TRUE 1
+#define FALSE 0
+#define MAXLINE 1024
+
+
+typedef enum {
+ PARENT, UNCLE
+} RELATION;
+
+
+/* Statics: */
+/* The parser is a dfa, driven by the following: */
+static FILE *Fp;
+static const char *Filename;
+static char Previous[MAXLINE];
+static char LeftMostChild[MAXLINE];
+static int Selected = FALSE;
+static int Line;
+static int Errors;
+
+
+/* The grammar is: */
+static int arch(void);
+static int comment(void);
+static int arch_name(void);
+static int set_list(void);
+static int set(void);
+
+/* The supporting code is: */
+static int accept_token(char *);
+static void skip_to(char *);
+
+/* And the tokenizer is: */
+static char *tokenize(char *);
+static char *currtok(void);
+static char *nexttok(void);
+static char *skipb(char *);
+static char *skipover(char *);
+static char *CurrTok = NULL;
+
+static int set_parents(void);
+
+static table_t *Vers;
+static table_t *Varch;
+
+static void init_tables(void);
+
+static void add_valid_arch(char *);
+static void add_valid_version(char *vers_name);
+
+
+#define in_specials(c) ((c) == '{' || (c) == '}' || (c) == '+' || \
+ (c) == '-' || (c) == ';' || (c) == ':' || (c) == ',' || \
+ (c) == '[' || (c) == ']')
+
+#define eq(s1, s2) (strcmp((s1), (s2)) == 0)
+
+
+/*
+ * parse_versions -- parse the file whose name is passed, return
+ * the number of (fatal) errors encountered. Currently only
+ * knows about reading set files and writing vers files.
+ */
+int
+parse_versions(const char *fileName)
+{
+
+ /* Prime the set-file parser dfa: */
+ assert(fileName != NULL, "passed null filename to parse_versions");
+ errlog(BEGIN, "parse_versions(%s) {", fileName);
+
+
+ if ((Fp = fopen(fileName, "r")) == NULL) {
+ (void) fprintf(stderr, "Cannot open version file \"%s\"\n",
+ fileName);
+ errlog(END, "} /* parse_versions */");
+ return (1);
+ }
+ Filename = fileName;
+ Line = 0;
+
+ errlog(VERBOSE, "reading set file %s looking for architecture %s",
+ Filename, TargetArchStr);
+
+ /* Run the dfa. */
+ while (arch())
+ continue;
+
+ (void) fclose(Fp);
+ /* print_all_buckets(); */
+ errlog(END, "} /* parse_versions */");
+ return (Errors);
+}
+
+
+/*
+ * The parser. This implements the grammar:
+ * setfile::= (arch())+ <EOF>
+ * | <EOF>
+ * arch::= <ARCHITECTURE> "{" (set_list())* "}"
+ * set_list::= (set())+ ";"
+ * set::= <IDENTIFIER> ["[" "WEAK" "]"] ":" "{" (ancestors) "}" ";"
+ * ancestors::= <IDENTIFIER> | <ancestors> "," <IDENTIFIER>
+ * where <ARCHITECTURE> and <IDENTIFIER> are tokens.
+ */
+static int
+arch(void)
+{
+ int olderrors;
+
+ errlog(BEGIN, "arch() {");
+ if (comment()) {
+ errlog(END, "} /* arch */");
+ return (TRUE);
+ }
+ if (arch_name() == FALSE) {
+ errlog(END, "} /* arch */");
+ return (FALSE);
+ }
+ if (accept_token("{") == FALSE) {
+ errlog(END, "} /* arch */");
+ return (FALSE);
+ }
+
+ olderrors = Errors;
+ if (set_list() == FALSE) {
+ if (olderrors != Errors) {
+ errlog(END, "} /* arch */");
+ return (FALSE);
+ }
+ }
+
+ errlog(END, "} /* arch */");
+ return (TRUE);
+}
+
+static int
+comment(void)
+{
+ char *token = currtok();
+
+ if (token == NULL || *token != '#') {
+ return (FALSE);
+ } else {
+ /* Swallow token. */
+ token = nexttok();
+ return (TRUE);
+ }
+}
+
+static int
+arch_name(void)
+{
+ char *token = currtok();
+
+ errlog(BEGIN, "arch_name() {");
+ errlog(VERBOSE, "token = '%s';",
+ token ? token : "<NULL>");
+
+ if (token == NULL) {
+ errlog(END, "} /* arch_name */");
+ return (FALSE);
+
+ } else if (in_specials(*token)) {
+ /* It's not an architecture */
+ Selected = FALSE;
+
+ /* Report a syntax error: TBD */
+ errlog(INPUT | ERROR, "found special char. %c "
+ "while looking for an architecture name",
+ *token);
+
+ skip_to("}"); /* The follower set for arch_name. */
+ errlog(END, "} /* arch name */");
+
+ Errors++;
+ return (FALSE);
+
+ } else if (!eq(token, TargetArchStr)) {
+ /* It's an architecture ... */
+ errlog(VERBOSE, "Begin unselected architecture: %s", token);
+ add_valid_arch(token);
+ (void) nexttok();
+
+ /* ... but the the wrong one. */
+ Selected = FALSE;
+ errlog(END, "} /* arch name */");
+ return (TRUE);
+ } else {
+ /* Found the right architecture. */
+ errlog(VERBOSE, "Begin selected architecture: %s", token);
+ add_valid_arch(token);
+ (void) nexttok();
+ Selected = TRUE;
+ errlog(END, "} /* arch name */");
+ return (TRUE);
+ }
+}
+
+
+static int
+set_list(void)
+{
+ int olderrors;
+ char *token = currtok();
+
+ errlog(BEGIN, "set_list() {");
+ errlog(VERBOSE, "token = '%s'",
+ (token) ? token : "<NULL>");
+ if (set() == FALSE) {
+ errlog(END, "} /* set_list */");
+ return (FALSE);
+ }
+
+ olderrors = Errors;
+ while (set()) {
+ continue;
+ }
+ if (olderrors != Errors) {
+ errlog(END, "} /* set_list */");
+ return (FALSE);
+ }
+
+ errlog(END, "} /* set_list */");
+ return (TRUE);
+}
+
+
+static int
+set(void)
+{
+ char *token = currtok();
+ int has_parent = 0;
+
+ errlog(BEGIN, "set() {");
+ errlog(VERBOSE, "token = '%s'",
+ (token) ? token : "<NULL>");
+
+ if (in_specials(*token)) {
+ errlog(INPUT|ERROR, "unexpected token \"%s\" found. "
+ "Version name expected", token);
+ Errors++;
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+
+ errlog(VERBOSE, "Begin Version: %s", token);
+ *Previous = '\0';
+ if (Selected) {
+ if (add_parent(token, Previous, 0) == FALSE) {
+ errlog(INPUT | ERROR, "unable to add a parent version "
+ "from the set file");
+ Errors++;
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ }
+
+ add_valid_version(token);
+ (void) strncpy(LeftMostChild, token, MAXLINE);
+ LeftMostChild[MAXLINE-1] = '\0';
+ (void) strncpy(Previous, token, MAXLINE);
+ Previous[MAXLINE-1] = '\0';
+
+ token = nexttok();
+
+ switch (*token) {
+ case ':':
+ errlog(VERBOSE, "token ':' found");
+ (void) accept_token(":");
+ if (set_parents() == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ if (accept_token(";") == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ errlog(VERBOSE, "End Version");
+ break;
+
+ case ';':
+ errlog(VERBOSE, "token ';' found");
+ (void) accept_token(";");
+ errlog(VERBOSE, "End version ':'");
+ break;
+
+ case '[':
+ (void) accept_token("[");
+ if (accept_token("WEAK") == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ if (accept_token("]") == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ token = currtok();
+ if (eq(token, ":")) {
+ (void) accept_token(":");
+ has_parent = 1;
+ } else if (eq(token, ";")) {
+ (void) accept_token(";");
+ } else {
+ errlog(ERROR|INPUT,
+ "Unexpected token \"%s\" found. ':'"
+ "or ';' expected.", token);
+ Errors++;
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ errlog(VERBOSE, "WEAK version detected\n");
+ if (Selected)
+ set_weak(LeftMostChild, TRUE);
+
+ if (has_parent) {
+ if (set_parents() == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ if (accept_token(";") == FALSE) {
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+ }
+ errlog(VERBOSE, "End Version");
+ break;
+ default:
+ /* CSTYLED */
+ errlog(ERROR|INPUT,
+ "Unexpected token \"%s\" found. ';' expected.",
+ token);
+ Errors++;
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+
+ token = currtok();
+ if (eq(token, "}")) {
+ (void) accept_token("}");
+ errlog(VERBOSE, "End architecture");
+ errlog(END, "} /* set */");
+ return (FALSE);
+ }
+
+ errlog(END, "} /* set */");
+ return (TRUE);
+}
+
+static int
+set_parents(void)
+{
+ char *token = currtok();
+ int uncle;
+
+ errlog(BEGIN, "set_parents() {");
+ errlog(VERBOSE, "token = '%s'",
+ (token) ? token : "<NULL>");
+
+ if (accept_token("{") == FALSE) {
+ errlog(INPUT|ERROR, "set_parents(): Unexpected token: %s\n",
+ token);
+ Errors++;
+ errlog(END, "} /* set_parents */");
+ return (FALSE);
+ }
+
+ token = currtok();
+
+ if (in_specials(*token)) {
+ errlog(INPUT|ERROR, "set_parents(): Unexpected token: %c "
+ "found. Version token expected", *token);
+ Errors++;
+ errlog(END, "} /* set_parents */");
+ return (FALSE);
+ }
+
+ uncle = 0;
+ while (token && *token != '}') {
+ errlog(VERBOSE, "Begin parent list: %s\n", token);
+ if (Selected) {
+ if (uncle)
+ (void) add_uncle(token, LeftMostChild, 0);
+ else
+ (void) add_parent(token, Previous, 0);
+ }
+ (void) strncpy(Previous, token, MAXLINE);
+ add_valid_version(token);
+ Previous[MAXLINE-1] = '\0';
+
+ token = nexttok();
+
+ if (*token == ',') {
+ token = nexttok();
+ /* following identifiers are all uncles */
+ uncle = 1;
+ continue;
+ }
+
+ if (*token == '}') {
+ if (accept_token("}") == FALSE) {
+ errlog(END, "} /* set_parents */");
+ return (FALSE);
+ }
+ errlog(VERBOSE, "set_parent: End of parent list");
+ errlog(END, "} /* set_parents */");
+ return (TRUE);
+ }
+
+ errlog(INPUT|ERROR,
+ "set_parents(): Unexpected token \"%s\" "
+ "found. ',' or '}' were expected", token);
+ Errors++;
+ errlog(END, "} /* set_parents */");
+ return (FALSE);
+ }
+ errlog(END, "} /* set_parents */");
+ return (TRUE);
+}
+
+
+/*
+ * parser support routines
+ */
+
+
+/*
+ * accept_token -- get a specified token or complain loudly.
+ */
+static int
+accept_token(char *expected)
+{
+ char *token = currtok();
+
+ assert(expected != NULL, "null token passed to accept_token");
+ errlog(OTHER | TRACING, "accept_token, at %s expecting %s",
+ (token) ? token : "<NULL>", expected);
+
+ if (token == NULL) {
+ /* We're at EOF */
+ return (TRUE);
+ }
+ if (eq(token, expected)) {
+ (void) nexttok();
+ return (TRUE);
+ } else {
+ errlog(INPUT | ERROR,
+ "accept_token, found %s while looking for %s",
+ (token) ? token : "<NULL>", expected);
+ ++Errors;
+ return (FALSE);
+ }
+}
+
+static void
+skip_to(char *target)
+{
+ char *token = currtok();
+
+ assert(target != NULL, "null target passed to skip_to");
+ while (token && !eq(token, target)) {
+ errlog(VERBOSE, "skipping over %s",
+ (token) ? token : "<NULL>");
+ token = nexttok();
+ }
+}
+
+
+/*
+ * tokenizer -- below the grammar lives this, like a troll
+ * under a bridge.
+ */
+
+
+/*
+ * skipb -- skip over blanks (whitespace, actually), stopping
+ * on first non-blank.
+ */
+static char *
+skipb(char *p)
+{
+
+ while (*p && isspace(*p))
+ ++p;
+ return (p);
+}
+
+/*
+ * skipover -- skip over non-separators (alnum, . and _, actually),
+ * stopping on first separator.
+ */
+static char *
+skipover(char *p)
+{
+
+ while (*p && (isalnum(*p) || (*p == '_' || *p == '.')))
+ ++p;
+ return (p);
+}
+
+
+/*
+ * currtok/nexttok -- get the current/next token
+ */
+static char *
+currtok(void)
+{
+
+ if (CurrTok == NULL) {
+ (void) nexttok();
+ }
+ return (CurrTok);
+}
+
+static char *
+nexttok(void)
+{
+ static char line[MAXLINE];
+ char *p;
+
+ if ((p = tokenize(NULL)) == NULL) {
+ /* We're at an end of line. */
+ do {
+ if (fgets(line, sizeof (line), Fp) == NULL) {
+ /* Which is also end of file. */
+ CurrTok = NULL;
+ return (NULL);
+ }
+ ++Line;
+ seterrline(Line, Filename, "", line);
+ } while ((p = tokenize(line)) == NULL);
+ }
+ CurrTok = p;
+ return (p);
+}
+
+
+
+/*
+ * tokenize -- a version of the standard strtok with specific behavior.
+ */
+static char *
+tokenize(char *line)
+{
+ static char *p = NULL;
+ static char saved = 0;
+ char *q;
+
+ if (line == NULL && p == NULL) {
+ /* It's the very first time */
+ return (NULL);
+ } else if (line != NULL) {
+ /* Initialize with a new line */
+ q = skipb(line);
+ } else {
+ /* Restore previous line. */
+ *p = saved;
+ q = skipb(p);
+ }
+ /* q is at the beginning of a token or at EOL, p is irrelevant. */
+
+ if (*q == '\0') {
+ /* It's at EOL. */
+ p = q;
+ } else if (in_specials(*q)) {
+ /* We have a special-character token. */
+ p = q + 1;
+ } else if (*q == '#') {
+ /* The whole rest of the line is a comment token. */
+ return (NULL);
+ } else {
+ /* We have a word token. */
+ p = skipover(q);
+ }
+ saved = *p;
+ *p = '\0';
+
+ if (p == q) {
+ /* End of line */
+ return (NULL);
+ } else {
+ return (q);
+ }
+}
+
+
+/*
+ * valid_version -- see if a version string was mentioned in the set file.
+ */
+int
+valid_version(const char *vers_name)
+{
+
+ if (Vers == NULL) {
+ init_tables();
+ }
+ return (in_stringtable(Vers, vers_name));
+}
+
+/*
+ * valid_arch -- see if the arch was mentioned in the set file.
+ */
+int
+valid_arch(const char *arch_name)
+{
+
+ if (Vers == NULL) {
+ init_tables();
+ }
+ return (in_stringtable(Varch, arch_name));
+}
+
+/*
+ * add_valid_version and _arch -- add a name to the table.
+ */
+static void
+add_valid_version(char *vers_name)
+{
+ errlog(BEGIN, "add_valid_version(\"%s\") {", vers_name);
+ if (Vers == NULL) {
+ init_tables();
+ }
+ Vers = add_to_stringtable(Vers, vers_name);
+ errlog(END, "}");
+}
+
+static void
+add_valid_arch(char *arch_name)
+{
+
+ errlog(BEGIN, "add_valid_arch(\"%s\") {", arch_name);
+ if (Vers == NULL) {
+ init_tables();
+ }
+ Varch = add_to_stringtable(Varch, arch_name);
+ errlog(END, "}");
+}
+
+/*
+ * init_tables -- creat them when first used.
+ */
+static void
+init_tables(void)
+{
+ Vers = create_stringtable(TABLE_INITIAL);
+ Varch = create_stringtable(TABLE_INITIAL);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2map/xlator.c b/usr/src/cmd/abi/spectrans/spec2map/xlator.c
new file mode 100644
index 0000000000..9d2fdbb16e
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/xlator.c
@@ -0,0 +1,1034 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Back-end functions for spec to mapfile converter
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/utsname.h>
+#include "xlator.h"
+#include "util.h"
+#include "bucket.h"
+
+/* Globals */
+enum {
+ /* These first four (commented out) are defined in parser.h */
+ /* XLATOR_KW_NOTFOUND = 0, */
+ /* XLATOR_KW_FUNC, */
+ /* XLATOR_KW_DATA, */
+ /* XLATOR_KW_END, */
+ XLATOR_KW_VERSION = 4,
+ XLATOR_KW_ARCH,
+ XLATOR_KW_BINDING,
+ XLATOR_KW_FILTER,
+ XLATOR_KW_AUXILIARY
+};
+#define FIRST_TOKEN 4 /* Must match the first token in the enum above */
+
+static xlator_keyword_t Keywords[] = {
+ { "version", XLATOR_KW_VERSION },
+ { "arch", XLATOR_KW_ARCH },
+ { "binding", XLATOR_KW_BINDING },
+ { "filter", XLATOR_KW_FILTER },
+ { "auxiliary", XLATOR_KW_AUXILIARY },
+ { NULL, XLATOR_KW_NOTFOUND }
+};
+
+static char const *OutputFile;
+static char const *Curfile;
+static char *Curfun;
+static int Curline;
+static Interface Iface;
+
+static int Verbosity;
+static int TargetArchToken; /* set from -a option to front-end */
+char *TargetArchStr = NULL; /* from -a option to front-end */
+int IsFilterLib = 0; /* set from -F option to front-end */
+static int Supported_Arch = XLATOR_ALLARCH; /* from "Arch" SPEC keyword */
+static int Flags;
+
+/*
+ * WHAT!?
+ * from Version line
+ * 0 means architecture is not specified in the
+ * version line so it applies to all versions
+ */
+static int Version_Arch;
+int Num_versfiles = 0;
+static int Has_Version;
+
+static char *Versfile;
+
+static char *getversion(const char *);
+static int version_sanity(const char *value, char **subv);
+static int arch_version_sanity(char *av);
+static char *getfilter(const char *);
+static void writemapfile(FILE *);
+static int set_version_arch(const char *);
+static int set_supported_arch(const char *);
+
+/*
+ * xlator_init()
+ * back-end initialization
+ * returns pointer to Keywords on success
+ * returns NULL pointer on failure
+ */
+xlator_keyword_t *
+xlator_init(const Translator_info *t_info)
+{
+ /*
+ * initially so we don't lose error messages from version_check
+ * we'll set this again later based on ti_info.ti_verbosity
+ */
+ seterrseverity(WARNING);
+
+ /* set verbosity */
+ Verbosity = t_info->ti_verbosity;
+ seterrseverity(t_info->ti_verbosity);
+
+ /* Obtain translator flags */
+ Flags = t_info->ti_flags;
+
+ /*
+ * set Library Type
+ * 1 if filter lib, 0 otherwise
+ */
+ IsFilterLib = t_info->ti_libtype;
+
+ /* set target architecture */
+ TargetArchStr = t_info->ti_arch;
+ TargetArchToken = t_info->ti_archtoken;
+
+ errlog(STATUS, "Architecture set to \"%s\"", TargetArchStr);
+
+ /* set output file */
+ OutputFile = t_info->ti_output_file;
+ if (OutputFile) {
+ errlog(STATUS, "Output will go into %s",
+ OutputFile);
+ } else {
+ OutputFile = "mapfile";
+ errlog(STATUS, "Using default output filename: %s",
+ OutputFile);
+ }
+
+ /* obtain name of version file */
+ Versfile = t_info->ti_versfile;
+
+ /* call create_lists() to setup for parse_versions() */
+ create_lists();
+
+ /* Process Vers Files */
+ if (parse_versions(Versfile)) {
+ return (NULL);
+ }
+
+ return (Keywords);
+}
+
+/*
+ * xlator_startlib()
+ * start of library
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_SKIP if library is to be skipped
+ * XLATOR_NONFATAL on error
+ */
+/*ARGSUSED*/
+int
+xlator_startlib(char const *libname)
+{
+ errlog(TRACING, "xlator_startlib");
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * xlator_startfile()
+ * start of spec file
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_SKIP if file is to be skipped
+ * XLATOR_NONFATAL on error
+ */
+int
+xlator_startfile(char const *filename)
+{
+ errlog(TRACING, "xlator_startfile");
+
+ Curfile = filename;
+
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * xlator_start_if ()
+ * start of interface specification
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_SKIP if interface is to be skipped
+ * XLATOR_NONFATAL on error
+ * XLATOR_FATAL on fatal error
+ */
+int
+xlator_start_if(const Meta_info meta_info, const int token, char *value)
+{
+ char rhs[BUFSIZ];
+ char *kw;
+ int err;
+
+ errlog(TRACING, "xlator_start_if %s", value);
+
+ switch (token) {
+ case XLATOR_KW_FUNC:
+ kw = "Function";
+ break;
+ case XLATOR_KW_DATA:
+ kw = "Data";
+ break;
+ default:
+ /* This should never happen */
+ errlog(ERROR,
+ "\"%s\", line %d: Implementation error! "
+ "Please file a bug\n", __FILE__, __LINE__);
+ return (XLATOR_FATAL);
+ }
+
+ Curline = meta_info.mi_line_number;
+ seterrline(Curline, meta_info.mi_filename, kw, value);
+
+ if (Curfun != NULL) {
+ errlog(INPUT|ERROR,
+ "Error: Interface spec is missing the "
+ "End keyword: %s", Curfun);
+ return (XLATOR_NONFATAL);
+ }
+
+ err = sscanf(value, "%s", rhs);
+ if (err == 0 || err == EOF) {
+ errlog(INPUT|ERROR,
+ "Error: Missing argument in \"%s\" line", kw);
+ return (XLATOR_NONFATAL);
+ }
+
+ Curfun = strdup(rhs);
+
+ if (Curfun == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure in xlator_startif()");
+ }
+
+ Iface.IF_name = Curfun;
+ Iface.IF_type = token; /* FUNCTION or DATA */
+
+ Iface.IF_version = NULL;
+ Iface.IF_class = NULL;
+ Has_Version = 0;
+ Supported_Arch = XLATOR_ALLARCH;
+ Version_Arch = 0;
+
+ Iface.IF_binding = DEFAULT;
+
+ Iface.IF_filter = NULL;
+ Iface.IF_auxiliary = NULL;
+
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * xlator_take_kvpair()
+ * processes spec keyword-value pairs
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_NONFATAL on error
+ */
+int
+xlator_take_kvpair(const Meta_info meta_info, const int token,
+ char *value)
+{
+ char *p;
+ char *subv = NULL;
+ char *key = Keywords[token-FIRST_TOKEN].key;
+
+ Curline = meta_info.mi_line_number;
+ seterrline(Curline, meta_info.mi_filename, key, value);
+
+ errlog(TRACING,
+ "take_kvpair called. ext_cnt=%d token=%d key=%s value=%s",
+ meta_info.mi_ext_cnt, token, key, value);
+
+ if (Curfun == NULL) {
+ errlog(INPUT|ERROR, "Error: Keyword found outside "
+ "an interface specification block, line %d", Curline);
+ return (XLATOR_NONFATAL);
+ }
+
+ switch (token) {
+ case XLATOR_KW_VERSION:
+ if (meta_info.mi_ext_cnt != 0)
+ return (XLATOR_SUCCESS);
+
+ errlog(TRACING, "Version found. Setting Version to %s", value);
+
+ /* Version line found ; used for auditing the SPEC */
+ Has_Version = 1;
+
+ /* remove trailing white space */
+ p = strrchr(value, '\n');
+ if (p) {
+ while (p >= value && isspace(*p)) {
+ *p = '\0';
+ --p;
+ }
+ }
+
+ /* is the version line valid */
+ switch (version_sanity(value, &subv)) {
+ case VS_OK: /* OK, subv not set */
+ break;
+
+ case VS_INVARCH: /* Invalid Arch */
+ errlog(INPUT|ERROR, "Error: Invalid architecture "
+ "string found in spec or version file: %s", subv);
+ free(subv);
+ return (XLATOR_NONFATAL);
+
+ case VS_INVVERS: /* Invalid Version String */
+ errlog(INPUT|ERROR, "Error: Invalid version string "
+ "in spec or version file: %s", subv);
+ free(subv);
+ return (XLATOR_NONFATAL);
+
+ case VS_INVALID: /* Both Version and Arch are invalid */
+ errlog(INPUT|ERROR, "Error: Invalid version and "
+ "architecture string in spec or version file"
+ ": %s", subv);
+ free(subv);
+ return (XLATOR_NONFATAL);
+
+ default: /* BAD IMPLEMENTATION OF version_sanity */
+ errlog(FATAL, "Error: bad return value from "
+ "version_sanity()! This should never happen!");
+ }
+
+ errlog(TRACING, "Version_Arch=%d", Version_Arch);
+
+ Iface.IF_version = getversion(value);
+ break;
+
+ case XLATOR_KW_ARCH:
+ if (meta_info.mi_ext_cnt != 0)
+ return (XLATOR_SUCCESS);
+
+ if (value[0] != '\0') {
+ Supported_Arch = 0;
+ if (set_supported_arch(value)) {
+ errlog(INPUT|ERROR,
+ "Error: Unable to parse Arch line");
+ return (XLATOR_NONFATAL);
+ }
+ } else {
+ errlog(INPUT | ERROR, "Error: Empty Arch line.");
+ }
+
+ if (Supported_Arch == 0) {
+ errlog(INPUT | ERROR,
+ "Error: Unknown architecture defined in Arch line");
+ }
+
+ errlog(TRACING,
+ "Interface %s supports the following architectures: "
+ "%s\tSupported_Arch=%d", Curfun, value, Supported_Arch);
+ break;
+
+ case XLATOR_KW_BINDING:
+
+ /*
+ * Note that we allow extends for the binding keyword by
+ * not checking that meta_info.mi_ext_cnt == 0 here.
+ */
+
+ /* remove trailing white space */
+ p = strrchr(value, '\n');
+ if (p) {
+ while (p >= value && isspace(*p)) {
+ *p = '\0';
+ --p;
+ }
+ }
+
+ if (value[0] != '\0') {
+ if (strcmp(value, "direct") == 0) {
+ Iface.IF_binding = DIRECT;
+ } else if (strcmp(value, "nodirect") == 0) {
+ Iface.IF_binding = NODIRECT;
+ } else if (strcmp(value, "protected") == 0) {
+ Iface.IF_binding = PROTECTED;
+ } else {
+ errlog(INPUT|ERROR,
+ "Error: Invalid binding value: %s", value);
+ }
+ } else {
+ errlog(INPUT | ERROR, "Error: Empty Binding line.");
+ }
+
+ errlog(TRACING,
+ "Interface %s has binding value: "
+ "%s", Curfun, value);
+ break;
+
+ case XLATOR_KW_FILTER:
+ case XLATOR_KW_AUXILIARY:
+ /*
+ * The following is for the "extends" clause. As with
+ * XLATOR_KW_VERSION, we do not want to follow an "extends"
+ * chain to get the filter or auxiliary values: we want
+ * the first/most-tightly-bound one (mi_ext_cnt = 0).
+ */
+ if (meta_info.mi_ext_cnt != 0)
+ return (XLATOR_SUCCESS);
+
+ errlog(TRACING, "Filter[token=%d] found. Setting Filter to %s",
+ token, value);
+
+ /* remove trailing white space */
+ p = strrchr(value, '\n');
+ if (p) {
+ while (p >= value && isspace(*p)) {
+ *p = '\0';
+ --p;
+ }
+ }
+
+ errlog(TRACING, "Version_Arch=%d", Version_Arch);
+
+ if (token == XLATOR_KW_FILTER) {
+ Iface.IF_filter = getfilter(value);
+ } else if (token == XLATOR_KW_AUXILIARY) {
+ Iface.IF_auxiliary = getfilter(value);
+ }
+
+ break;
+ default:
+ errlog(INPUT|ERROR, "Error: Unrecognized keyword snuck in!"
+ "\tThis is a programmer error: %s", key);
+ return (XLATOR_NONFATAL);
+ }
+
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * xlator_end_if ()
+ * signal end of spec interface spec
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_NONFATAL on error
+ */
+/*ARGSUSED*/
+int
+xlator_end_if(const Meta_info M, const char *value)
+{
+ int retval = XLATOR_NONFATAL;
+ int picky = Flags & XLATOR_PICKY_FLAG;
+
+ seterrline(M.mi_line_number, M.mi_filename, "End", "");
+ errlog(TRACING, "xlator_end_if");
+
+ if (Curfun == NULL) {
+ errlog(INPUT | ERROR, "Error: End without "
+ "matching Function or Data in file \"%s\"", Curfile);
+ goto cleanup;
+ }
+
+ errlog(TRACING, "Interface=%s", Iface.IF_name);
+
+ if (!Has_Version) {
+ if (picky) {
+ errlog(INPUT | ERROR, "Error: Interface has no "
+ "Version!\n\tInterface=%s\n\tSPEC File=%s",
+ Iface.IF_name, Curfile);
+ } else {
+ errlog(INPUT | WARNING, "Warning: Interface has "
+ "no Version!\n\tInterface=%s\n\tSPEC File=%s",
+ Iface.IF_name, Curfile);
+ retval = XLATOR_SUCCESS;
+ }
+ goto cleanup;
+ }
+
+ if (Version_Arch & (~Supported_Arch)) {
+ errlog(INPUT | ERROR, "Error: Architectures in Version "
+ "line must be a subset of Architectures in Arch line\n"
+ "\tInterface=%s\n\tSPEC File=%s", Iface.IF_name, Curfile);
+ goto cleanup;
+ }
+
+ if ((TargetArchToken & Supported_Arch) == 0) {
+ /*
+ * This interface is not for the architecture
+ * we are currently processing, so we skip it.
+ */
+ retval = XLATOR_SUCCESS;
+ goto cleanup;
+ }
+
+ if (Iface.IF_version == NULL) {
+ if (picky) {
+ errlog(ERROR|INPUT,
+ "Error: Version was not found for "
+ "\"%s\" architecture\n\tInterface=%s",
+ TargetArchStr, Iface.IF_name);
+ } else {
+ errlog(WARNING | INPUT,
+ "Warning: Version was not found for "
+ "\"%s\" architecture\n\tInterface=%s",
+ TargetArchStr, Iface.IF_name);
+ retval = XLATOR_SUCCESS;
+ }
+ goto cleanup;
+ }
+
+ /* check Iface.IF_type */
+ switch (Iface.IF_type) {
+ case FUNCTION:
+ errlog(VERBOSE, "Interface type = FUNCTION");
+ break;
+ case DATA:
+ errlog(VERBOSE, "Interface type = DATA");
+ break;
+ case NOTYPE:
+ errlog(WARNING,
+ "Warning: Interface is neither "
+ "DATA nor FUNCTION!!\n\t"
+ "Interface=%s\n\tSPEC File=%s",
+ Iface.IF_name, Curfile);
+ break;
+ default:
+ errlog(ERROR, "Error: Bad spec2map implementation!\n"
+ "\tInterface type is invalid\n"
+ "\tThis should never happen.\n"
+ "\tInterface=%s\tSPEC File=%s", Iface.IF_name, Curfile);
+ goto cleanup;
+ }
+
+ (void) add_by_name(Iface.IF_version, &Iface);
+
+ retval = XLATOR_SUCCESS;
+
+cleanup:
+
+ /* cleanup */
+ Iface.IF_name = NULL;
+
+ free(Iface.IF_version);
+ Iface.IF_version = NULL;
+
+ free(Iface.IF_class);
+ Iface.IF_class = NULL;
+
+ free(Curfun);
+ Curfun = NULL;
+
+ Supported_Arch = XLATOR_ALLARCH;
+ return (retval);
+}
+
+/*
+ * xlator_endfile()
+ * signal end of spec file
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_NONFATAL on error
+ */
+int
+xlator_endfile(void)
+{
+
+ errlog(TRACING, "xlator_endfile");
+
+ Curfile = NULL;
+
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * xlator_endlib()
+ * signal end of library
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_NONFATAL on error
+ */
+int
+xlator_endlib(void)
+{
+ FILE *mapfp;
+ int retval = XLATOR_SUCCESS;
+
+ errlog(TRACING, "xlator_endlib");
+
+ /* Pretend to print mapfile */
+ if (Verbosity >= TRACING) {
+ print_all_buckets();
+ }
+
+ /* Everything read, now organize it! */
+ sort_buckets();
+ add_local();
+
+ /* Create Output */
+ mapfp = fopen(OutputFile, "w");
+ if (mapfp == NULL) {
+ errlog(ERROR,
+ "Error: Unable to open output file \"%s\"\n\t%s",
+ OutputFile, strerror(errno));
+ retval = XLATOR_NONFATAL;
+ } else {
+ writemapfile(mapfp);
+ (void) fclose(mapfp);
+ }
+
+ return (retval);
+}
+
+/*
+ * xlator_end()
+ * signal end of translation
+ * returns: XLATOR_SUCCESS on success
+ * XLATOR_NONFATAL on error
+ */
+int
+xlator_end(void)
+{
+ errlog(TRACING, "xlator_end");
+
+ /* Destroy the list created by create_lists */
+ delete_lists();
+
+ return (XLATOR_SUCCESS);
+}
+
+/*
+ * getversion()
+ * called by xlator_take_kvpair when Version keyword is found
+ * parses the Version string and returns the one that matches
+ * the current target architecture
+ *
+ * the pointer returned by this function must be freed later.
+ */
+static char *
+getversion(const char *value)
+{
+ char *v, *p;
+ char arch[ARCHBUFLEN];
+ int archlen;
+
+ /* up to ARCHBUFLEN-1 */
+ (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1);
+ arch[ARCHBUFLEN-2] = '\0';
+ (void) strcat(arch, "="); /* append an '=' */
+ archlen = strlen(arch);
+
+ errlog(VERBOSE, "getversion: value=%s", value);
+
+ if (strchr(value, '=') != NULL) {
+ if ((v = strstr(value, arch)) != NULL) {
+ p = strdup(v + archlen);
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure "
+ "in getversion()");
+ }
+ v = p;
+ while (!isspace(*v) && *v != '\0')
+ ++v;
+ *v = '\0';
+ } else {
+ errlog(VERBOSE, "getversion returns: NULL");
+ return (NULL);
+ }
+ } else {
+ p = strdup(value);
+ if (p == NULL) {
+ errlog(ERROR | FATAL, "Internal Error: strdup() "
+ "failure in getversion()");
+ }
+ }
+
+ if (p != NULL)
+ errlog(VERBOSE, "getversion returns: %s", p);
+ else
+ errlog(VERBOSE, "getversion returns: NULL");
+
+ return (p);
+}
+
+/*
+ * getfilter()
+ * Called by xlator_take_kvpair when "filter" or "auxiliary" keyword is
+ * found. Parses the Filter/Auxiliary string and returns the one that
+ * matches the current target architecture
+ *
+ * The pointer returned by this function must be freed later.
+ *
+ * Note that returning NULL here indicates there was no desired
+ * arch=path item in value, i.e. for TargetArchStr the interface is
+ * not a filter.
+ */
+static char *
+getfilter(const char *value)
+{
+ char *v, *p;
+ char arch[ARCHBUFLEN];
+ int archlen;
+
+ /* up to ARCHBUFLEN-1 */
+ (void) strncpy(arch, TargetArchStr, ARCHBUFLEN-1);
+ arch[ARCHBUFLEN-2] = '\0';
+ (void) strcat(arch, "="); /* append an '=' */
+ archlen = strlen(arch);
+
+ errlog(VERBOSE, "getfilter: value=%s", value);
+
+ if (strchr(value, '=') != NULL) {
+ if ((v = strstr(value, arch)) != NULL) {
+ p = strdup(v + archlen);
+ if (p == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure "
+ "in getfilter()");
+ }
+ v = p;
+ while (!isspace(*v) && *v != '\0')
+ ++v;
+ *v = '\0';
+ } else {
+ errlog(VERBOSE, "getfilter returns: NULL");
+ return (NULL);
+ }
+ } else {
+ p = strdup(value);
+ if (p == NULL) {
+ errlog(ERROR | FATAL, "Internal Error: strdup() "
+ "failure in getfilter()");
+ }
+ }
+
+ if (p != NULL)
+ errlog(VERBOSE, "getfilter returns: %s", p);
+ else
+ errlog(VERBOSE, "getfilter returns: NULL");
+
+ return (p);
+}
+
+/*
+ * version_sanity()
+ * for each version info in the Version line
+ * check for its validity.
+ * Set Version_arch to reflect all supported architectures if successful.
+ * Upon return on failure, subv will contain the last version string
+ * processed
+ * returns: VS_OK OK
+ * VS_INVARCH Invalid Architecture
+ * VS_INVVERS Invalid Version String
+ * VS_INVALID Both Version and Architecture are invalid;
+ */
+static int
+version_sanity(const char *value, char **subv)
+{
+ char *p, *v, *a;
+ int retval = VS_INVALID;
+
+ if (strchr(value, '=')) {
+ /* Form 1: Version arch=Version_string */
+ v = strdup(value);
+ if (v == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure in "
+ "version_sanity()");
+ }
+
+ /* process each arch=version string */
+ p = v;
+ while ((a = strtok(p, " \t\n"))) {
+ if ((retval = arch_version_sanity(a)) != VS_OK) {
+ *subv = strdup(a);
+ if (subv == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure "
+ "in version_sanity()");
+ }
+ break;
+ }
+ if ((retval = set_version_arch(a)) != VS_OK) {
+ /* set the global Version_arch */
+ *subv = strdup(a);
+ if (subv == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure "
+ "in version_sanity()");
+ }
+ break;
+ }
+ p = NULL;
+ }
+ free(v);
+ } else {
+ /* Form 2: Version Version_string */
+ if (valid_version(value)) {
+ retval = VS_OK;
+ } else {
+ *subv = strdup(value);
+ if (subv == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure "
+ "in version_sanity()");
+ }
+ }
+ }
+ return (retval);
+}
+
+/*
+ * arch_version_sanity()
+ * checks version lines of the form "arch=version"
+ * av MUST be a string of the form "arch=version" (no spaces)
+ * returns: VS_OK OK
+ * VS_INVARCH Invalid Architecture
+ * VS_INVVERS Invalid Version String
+ * VS_INVALID Both Versions are invalid;
+ */
+static int
+arch_version_sanity(char *av)
+{
+ char *p, *v;
+ int retval = VS_OK;
+
+ p = strchr(av, '=');
+ if (p == NULL) {
+ errlog(INPUT|ERROR, "Error: Incorrect format of Version line");
+ return (VS_INVALID);
+ }
+
+ *p = '\0'; /* stick a '\0' where the '=' was */
+ v = p + 1;
+
+ if (valid_arch(av) == 0)
+ retval = VS_INVARCH;
+
+ if (valid_version(v) == 0)
+ retval += VS_INVVERS;
+
+ *p = '='; /* restore the '=' */
+
+ return (retval);
+}
+
+/*
+ * writemapfile()
+ * called by xlator_endlib();
+ * writes out the map file
+ */
+static void
+writemapfile(FILE *mapfp)
+{
+ bucket_t *l; /* List of buckets. */
+ bucket_t *b; /* Bucket within list. */
+ struct bucketlist *bl;
+ table_t *t;
+ int i = 0, n = 0;
+ char **p;
+
+ errlog(BEGIN, "writemapfile() {");
+ for (l = first_list(); l != NULL; l = next_list()) {
+
+ for (b = first_from_list(l); b != NULL; b = next_from_list()) {
+ errlog(TRACING, "b_name = %s", b->b_name);
+ print_bucket(b); /* Debugging routine. */
+
+ if (!b->b_was_printed) {
+ /* Ok, we can print it. */
+ b->b_was_printed = 1;
+ (void) fprintf(mapfp, "%s {\n", b->b_name);
+
+ if (b->b_weak != 1) {
+ char *strtab;
+
+ (void) fprintf(mapfp, " global:\n");
+
+ strtab = get_stringtable(
+ b->b_global_table, 0);
+
+ if (strtab == NULL) {
+ /*
+ * There were no interfaces
+ * in the bucket.
+ * Insert a dummy entry
+ * to avoid a "weak version"
+ */
+ (void) fprintf(mapfp,
+ "\t%s;\n", b->b_name);
+ }
+ } else {
+ (void) fprintf(mapfp,
+ " # Weak version\n");
+ }
+ /* Print all the interfaces in the bucket. */
+ t = b->b_global_table;
+ n = t->used;
+
+ for (i = 0; i <= n; ++i) {
+ (void) fprintf(mapfp, "\t%s;\n",
+ get_stringtable(t, i));
+ }
+
+ if (b->b_has_protecteds) {
+ t = b->b_protected_table;
+ n = t->used;
+
+ (void) fprintf(mapfp,
+ " protected:\n");
+
+ for (i = 0; i <= n; ++i) {
+ (void) fprintf(mapfp, "\t%s;\n",
+ get_stringtable(t, i));
+ }
+ }
+
+ /* Conditionally add ``local: *;''. */
+ if (b->b_has_locals) {
+ (void) fprintf(mapfp,
+ " local:\n\t*;\n}");
+ } else {
+ (void) fprintf(mapfp, "}");
+ }
+ /* Print name of all parents. */
+ for (p = parents_of(b);
+ p != NULL && *p != '\0'; ++p) {
+ (void) fprintf(mapfp, " %s", *p);
+ }
+ bl = b->b_uncles;
+ while (bl != NULL) {
+ (void) fprintf(mapfp, " %s",
+ bl->bl_bucket->b_name);
+ bl = bl->bl_next;
+ }
+
+ (void) fprintf(mapfp, ";\n\n");
+ } else {
+ /*
+ * We've printed this one before,
+ * so don't do it again.
+ */
+ /*EMPTY*/;
+ }
+ }
+ }
+ errlog(END, "}");
+}
+
+/*
+ * set_version_arch ()
+ * input must be a string of the form "arch=version"
+ * turns on bits of global Version_Arch that correspond to the "arch"
+ * return VS_OK upon success
+ * VS_INVARCH if architecture is invalid
+ * EINVAL on other failure
+ */
+static int
+set_version_arch(const char *arch)
+{
+ char *a, *p;
+ int x;
+ int retval = EINVAL;
+
+ if (arch == NULL)
+ return (retval);
+
+ a = strdup(arch);
+ if (a == NULL) {
+ errlog(ERROR | FATAL,
+ "Internal Error: strdup() failure in "
+ "set_version_arch()");
+ }
+
+ p = strchr(a, '=');
+ if (p) {
+ *p = '\0';
+ x = arch_strtoi(a);
+ if (x == 0) {
+ errlog(INPUT|ERROR,
+ "Error: Invalid architecture: %s", a);
+ retval = VS_INVARCH;
+ } else {
+ Version_Arch |= x;
+ retval = 0;
+ }
+ }
+
+ free(a);
+ return (retval);
+}
+
+/*
+ * set_supported_arch ()
+ * input must be a string listing the architectures to be supported
+ * turns on bits of global Supported_Arch that correspond to the architecture
+ * return 0 upon success, EINVAL on failure
+ */
+static int
+set_supported_arch(const char *arch)
+{
+ char *a, *p, *tmp;
+ int retval = EINVAL;
+
+ if (arch == NULL || *arch == '\0')
+ return (EINVAL);
+
+ tmp = strdup(arch);
+ if (tmp == NULL) {
+ errlog(ERROR | FATAL, "Internal Error: strdup() failure in "
+ "set_supported_arch()");
+ }
+
+ p = tmp;
+ while ((a = strtok(p, " ,\t\n"))) {
+ int x;
+ x = arch_strtoi(a);
+ if (x == 0) {
+ errlog(INPUT|ERROR,
+ "Error: Invalid architecture: %s", a);
+ free(tmp);
+ return (EINVAL);
+ }
+ Supported_Arch |= x;
+ retval = 0;
+ p = NULL;
+ }
+
+ free(tmp);
+ return (retval);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2map/xlator.h b/usr/src/cmd/abi/spectrans/spec2map/xlator.h
new file mode 100644
index 0000000000..9befe2b6ef
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2map/xlator.h
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _XLATOR_H
+#define _XLATOR_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <parser.h>
+#include <errlog.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ARCHBUFLEN 80
+
+/* Architecture Bitmap */
+#define XLATOR_SPARC 0x01
+#define XLATOR_SPARCV9 0x02
+#define XLATOR_I386 0x04
+#define XLATOR_IA64 0x08
+#define XLATOR_AMD64 0x10
+#define XLATOR_ALLARCH 0xFF
+
+/* *_sanity() return codes */
+#define VS_OK 0
+#define VS_INVARCH 1
+#define VS_INVVERS 2
+#define VS_INVALID 3
+
+typedef enum {
+ NOTYPE, /* A type has not yet been assigned */
+ /* to the interface */
+ FUNCTION = XLATOR_KW_FUNC, /* Functional Interface */
+ DATA = XLATOR_KW_DATA /* Data Interface */
+} Iftype;
+
+typedef enum {
+ DEFAULT, /* No special mapfile treatment */
+ DIRECT, /* Needs "<sym> DIRECT;" in mapfile */
+ NODIRECT, /* Needs "<sym> NODIRECT;" in mapfile */
+ PROTECTED /* Needs to be in a "protected:" section */
+} Ifbinding;
+
+typedef struct Interface {
+ char const *IF_name; /* Name of interface */
+ Iftype IF_type; /* type: FUNCTION or DATA */
+ char *IF_version; /* Version information */
+ char *IF_class; /* public or private or some color */
+ Ifbinding IF_binding; /* direct or nodirect or protected */
+ char *IF_filter; /* path string for "filter" keyword */
+ char *IF_auxiliary; /* path string for "auxiliary" keyword */
+} Interface;
+
+extern char *TargetArchStr;
+extern int IsFilterLib;
+
+extern int check_version(const int, const int, const char);
+extern int parse_setfile(const char *);
+extern int parse_versions(const char *);
+
+extern int valid_version(const char *);
+extern int valid_arch(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _XLATOR_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/Makefile b/usr/src/cmd/abi/spectrans/spec2trace/Makefile
new file mode 100644
index 0000000000..6f65ecdedc
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1998-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/spec2trace/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.arch
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ b/usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ
new file mode 100644
index 0000000000..18d83707af
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/Makefile.targ
@@ -0,0 +1,51 @@
+#
+# 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.
+#
+# 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
+#
+#
+#pragma ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/spectrans/spec2trace/Makefile.targ
+
+.KEEP_STATE:
+
+PROG = spec2trace
+
+YACC_OBJS = parseproto.o
+
+OBJECTS = trace.o \
+ util.o \
+ db.o \
+ symtab.o \
+ bindings.o \
+ printfuncs.o \
+ io.o \
+ linkage.o \
+ interceptor.o
+
+include ../../Makefile.cmd
+
+parseproto := RM = @echo keeping # do not remove generated C code
+parseproto := COPTFLAG = -g -DDEBUG -DMEM_DEBUG -DTRACE
+parseproto: parseproto.o
+ $(LINK.c) -o parseproto parseproto.o
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/bindings.c b/usr/src/cmd/abi/spectrans/spec2trace/bindings.c
new file mode 100644
index 0000000000..7c6f7d74de
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/bindings.c
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "symtab.h"
+#include "io.h"
+#include "bindings.h"
+#include "errlog.h"
+
+
+/* File globals. */
+static void generate_a_binding(char *, char *);
+
+static int strpqcmp(char *, char *, char *);
+static void strpqprint(char *, char *, FILE *);
+
+/*
+ * Bindings: do three-valued logic, where a binding can be
+ * an expression to evaluate for truthfulness,
+ * true,
+ * false, or
+ * empty.
+ *
+ * Exception Result Evaluate? Notes
+ * --------- ------ --------- -----
+ *
+ * true ok yes warn[1]
+ * false ok no
+ * empty ok no treat as true
+ * expr ok yes s = !e
+ *
+ * Notes:
+ * [1] Always exceptional, shows errno at run-time
+ *
+ */
+
+/*
+ * need_bindings -- see if we have to do anything at all. Implements
+ * the following rows from the table above (die and evaluate=no lines)
+ * Returns NO if we don't have to evaluate bindings at all.
+ *
+ * Exception Result Evaluate? Notes
+ * --------- ------ --------- -----
+ * false ok no
+ * empty ok no treat as true
+ */
+int
+need_bindings(char *exception)
+{
+
+ errlog(BEGIN, "need_bindings() {");
+
+ if (exception == NULL)
+ exception = "";
+
+ /* empty false ok no */
+ /* empty empty ok no, treat as true */
+ if (strcmp(exception, "false") == 0 ||
+ *exception == '\0') {
+ errlog(END, "}");
+ return (NO);
+ }
+ errlog(END, "}");
+ return (YES);
+}
+
+
+int
+need_exception_binding(void)
+{
+ ENTRY *e;
+ char *exception;
+
+ exception = ((e = symtab_get_exception()) != NULL)?
+ (name_of(e)? name_of(e): ""): "";
+
+ return (need_bindings(exception));
+
+}
+
+/*
+ * generate_bindings -- make the code for exception bindings
+ *
+ * Exception Result Evaluate? Notes
+ * --------- ------ --------- -----
+ * true ok yes warn[2]
+ * expr ok yes s::= !e
+ *
+ * Returns NO if we need both bindings, YES (ANTONYM) if we
+ * only need to evaluate success.
+ */
+int
+generate_bindings(char *exception)
+{
+ int ret = NO;
+
+ errlog(BEGIN, "generate_bindings() {");
+ errlog(TRACING, "exception=%s\n", exception ? exception : "NULL");
+
+ /* Exception Result Evaluate? Notes */
+ /* --------- ------ --------- ----- */
+ /* true ok yes warn[2] */
+ if (exception != NULL) {
+ generate_a_binding("exception", exception);
+ errlog(END, "}");
+ }
+
+ return (ret);
+}
+
+/*
+ * bindings_exist -- make sure we don't use one if they're not there.
+ */
+int
+bindings_exist(void)
+{
+ int ret;
+
+ errlog(BEGIN, "bindings_exist() {");
+ errlog(END, "}");
+
+ ret = validity_of(symtab_get_exception()) == YES;
+
+ return (ret);
+}
+
+
+
+/*
+ * generate_a_binding -- generate just one, with a set of transformations
+ * applied. Eg, return->_return, errno->functions_errvar,
+ * unchanged(x)->x == 0, etc. Oneof and someof TBD.
+ */
+static void
+generate_a_binding(char *name, char *value)
+{
+ char *p = value;
+ ENTRY *e = symtab_get_errval();
+ char *errvar = (e == NULL)? NULL: name_of(e);
+ char *q;
+
+ errlog(BEGIN, "generate_a_binding() {");
+ if (*value == NULL) {
+ errlog(FATAL, "programmer error: asked to generate an "
+ "empty binding");
+ }
+
+ {
+ /*
+ * XXX - friggin spaghetti
+ */
+ ENTRY *exc = symtab_get_exception();
+
+ if (exc != NULL)
+ (void) fprintf(Bodyfp,
+ "#line %d \"%s\"\n",
+ line_of(exc), symtab_get_filename());
+ }
+
+ /* Generate prefix. */
+ (void) fprintf(Bodyfp, " %s = (", name);
+
+ /* Walk across line, emitting tokens and transformed tokens */
+
+ for (; *p != NULL; p = q) {
+ p = skipb(p);
+ q = nextsep(p);
+
+ if (p == q) {
+ /* We're at the end, a "(", ")" or an operator. */
+ if (*p == '(') {
+ /* We're at a parenthesized expression */
+ q++;
+ } else if (*p == ')') {
+ /* And the end of an expression. */
+ q++;
+ } else if (*p == '!' && *(p+1) != '=') {
+ /* Or a negated expression */
+ q++;
+ } else if ((q = nextb(p)) == p) {
+ /* Real end! */
+ break;
+ }
+
+ /* Else it was an operator, boogy onwards. */
+ }
+ if (strpqcmp("$return", p, q) == 0) {
+ (void) fputs("_return", Bodyfp);
+ } else if (errvar != NULL && strpqcmp(errvar, p, q) == 0) {
+ (void) fputs("functions_errvar", Bodyfp);
+ } else if (strpqcmp("unchanged", p, q) == 0) {
+ /* This will look odd. */
+ (void) fputs("0 == ", Bodyfp);
+ } else if (strpqcmp("oneof", p, q) == 0) {
+ errlog(WARNING, "Oneof unimplemented in spec2trace"
+ "It will be treated as the token 'false'");
+ (void) fputs("false", Bodyfp);
+ break;
+ } else if (strpqcmp("someof", p, q) == 0) {
+ errlog(WARNING, "Someof unimplemented in spec2trace, "
+ "It will be treated as the token 'false'");
+ (void) fputs("false", Bodyfp);
+ break;
+ } else if (strpqcmp("errno", p, q) == 0) {
+ (void) fputs("ABI_ERRNO", Bodyfp);
+ } else {
+ /* Just copy it. */
+
+ strpqprint(p, q, Bodyfp);
+ }
+ (void) putc(' ', Bodyfp);
+ }
+ (void) (void) fputs(");\n", Bodyfp);
+ errlog(END, "}");
+}
+
+/*
+ * strpqcmp -- compare a null-terminated string with a pq-bracketed string.
+ */
+static int
+strpqcmp(char *v1, char *p, char *q)
+{
+ int rc;
+ char saved;
+
+ errlog(BEGIN, "strpqcmp() {");
+ saved = *q;
+ *q = NULL;
+ rc = (strcmp(v1, p));
+ *q = saved;
+ errlog(END, "}");
+ return (rc);
+}
+
+/*
+ * strpqprint -- print a pq-bracketed string
+ */
+static void
+strpqprint(char *p, char *q, FILE *fp)
+{
+ char saved;
+
+ errlog(BEGIN, "strpqprint() {");
+ saved = *q;
+ *q = NULL;
+ (void) fputs(p, fp);
+ *q = saved;
+ errlog(END, "}");
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/bindings.h b/usr/src/cmd/abi/spectrans/spec2trace/bindings.h
new file mode 100644
index 0000000000..e606ddfc1b
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/bindings.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _BINDINGS_H
+#define _BINDINGS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ANTONYMS YES
+
+extern int bindings_exist(void);
+extern int need_exception_binding(void);
+extern int need_bindings(char *);
+extern int generate_bindings(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _BINDINGS_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/db.c b/usr/src/cmd/abi/spectrans/spec2trace/db.c
new file mode 100644
index 0000000000..6540bb6a37
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/db.c
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * db.c -- the tiny database for trace. Only stores
+ * global things: see symtab for per-function data.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <limits.h>
+#include <sys/param.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "errlog.h"
+#include "db.h"
+
+static int curr_print_type;
+
+static struct {
+ char Current_Library[PATH_MAX];
+ char Current_File[PATH_MAX];
+ char Output_File[PATH_MAX];
+ char Current_Interface[PATH_MAX];
+ char Source_Directory[PATH_MAX];
+ char Target_Directory[PATH_MAX];
+ int NFiles;
+ int Verbosity;
+ char Library_List[PATH_MAX];
+ char Translator[MAXNAMELEN];
+ char Test_Type[MAXNAMELEN];
+ char Kludge[PATH_MAX];
+ int Flags;
+ char const *Arch;
+ table_t *Print_Types;
+ table_t *File;
+ table_t *Exclusions;
+
+} Database;
+
+
+/* Generated by m4 -- character string values */
+void
+db_set_current_library(char const *p)
+{
+ errlog(BEGIN, "db_set_current_library() {");
+ (void) strncpy(Database.Current_Library, p,
+ sizeof (Database.Current_Library));
+ Database.Current_Library[sizeof (Database.Current_Library) - 1] = NULL;
+ errlog(END, "}");
+}
+
+char *
+db_get_current_library(void)
+{
+ errlog(BEGIN, "db_get_current_library() {"); errlog(END, "}");
+ return (Database.Current_Library);
+}
+
+void
+db_set_current_interface(char const *p)
+{
+ errlog(BEGIN, "db_set_current_interface() {");
+ (void) strncpy(Database.Current_Interface, p,
+ sizeof (Database.Current_Interface));
+ Database.Current_Interface[
+ sizeof (Database.Current_Interface) - 1] = '\0';
+ errlog(END, "}");
+}
+
+char *
+db_get_current_interface(void)
+{
+ errlog(BEGIN, "db_get_current_interface() {"); errlog(END, "}");
+ return (Database.Current_Interface);
+}
+
+
+void
+db_set_source_directory(char const *p)
+{
+ errlog(BEGIN, "db_set_source_directory() {");
+ (void) strncpy(Database.Source_Directory, p,
+ sizeof (Database.Source_Directory));
+ Database.Source_Directory[sizeof (Database.Source_Directory) - 1] =
+ '\0';
+ errlog(END, "}");
+}
+
+char *
+db_get_source_directory(void)
+{
+ errlog(BEGIN, "db_get_source_directory() {"); errlog(END, "}");
+ return (Database.Source_Directory);
+}
+
+
+void
+db_set_target_directory(char const *p)
+{
+ errlog(BEGIN, "db_set_target_directory() {");
+ (void) strncpy(Database.Target_Directory, p,
+ sizeof (Database.Target_Directory));
+ Database.Target_Directory[sizeof (Database.Target_Directory) - 1] =
+ '\0';
+ errlog(END, "}");
+}
+
+char *
+db_get_target_directory(void)
+{
+ errlog(BEGIN, "db_get_target_directory() {"); errlog(END, "}");
+ return (Database.Target_Directory);
+}
+
+void
+db_set_current_file(char const *p)
+{
+ (void) strncpy(Database.Current_File, p,
+ sizeof (Database.Current_File));
+ Database.Current_File[sizeof (Database.Current_File) - 1] = '\0';
+}
+
+char *
+db_get_current_file(void)
+{
+ return (Database.Current_File);
+}
+
+
+/*
+ * Output File -- set from either -o option or file name.
+ */
+void
+db_set_output_file(char const *p)
+{
+ char *q;
+
+ errlog(BEGIN, "db_set_output_file() {");
+ if (p == NULL) {
+ errlog(END, "}");
+ return;
+ }
+
+ (void) strncpy(Database.Output_File, p, sizeof (Database.Output_File));
+ if ((q = strrchr(Database.Output_File, '.')) != NULL) {
+ *q = '\0';
+ } else {
+ Database.Output_File[sizeof (Database.Output_File) - 1] = '\0';
+ }
+ errlog(VERBOSE, "output file = '%s'\n", Database.Output_File);
+ errlog(END, "}");
+}
+
+char *
+db_get_output_file(void)
+{
+ static char buffer[MAXLINE];
+ char *p, *q;
+
+ errlog(BEGIN, "db_get_output_file() {");
+ if (*Database.Output_File != NULL) {
+ /* It was set with the -o option */
+ errlog(VERBOSE, "output file from -o = '%s'\n",
+ Database.Output_File);
+ errlog(END, "}");
+ return (Database.Output_File);
+ } else {
+ /* We generate it from the current input file. */
+ (void) strncpy(buffer, Database.Current_File, sizeof (buffer));
+ p = basename(buffer);
+ if ((q = strrchr(p, '.')) != NULL) {
+ *q = '\0';
+ }
+ errlog(VERBOSE, "output file from input = '%s'\n", p);
+ errlog(END, "}");
+ return (p);
+ }
+}
+
+/*
+ * Manually written table code.
+ */
+
+/*
+ * add_print_types -- add legal print types. Check for void
+ * moved here out of collect, as collect isn't good enough
+ * quality of parser to have a single code path for
+ * types. (Shudder) Subsequently changed to use special-purpose
+ * test for membership. Also shudder!
+ */
+
+void
+db_add_print_types(char *print_type, char *c_type)
+{
+ char buffer[MAXLINE];
+
+ errlog(BEGIN, "db_add_print_types() {");
+
+ (void) snprintf(buffer, sizeof (buffer), "%s, %s", print_type, c_type);
+ if (Database.Print_Types == NULL) {
+ Database.Print_Types = create_string_table(50);
+ }
+ if (in_string_table(Database.Print_Types, print_type) == NO) {
+ Database.Print_Types = add_string_table(Database.Print_Types,
+ &buffer[0]);
+ }
+
+ errlog(END, "}");
+}
+
+char *
+db_get_first_print_type(void)
+{
+ curr_print_type = 1;
+ return (get_string_table(Database.Print_Types, 0));
+}
+
+char *
+db_get_next_print_type(void)
+{
+
+ return (get_string_table(Database.Print_Types, curr_print_type++));
+}
+
+
+void
+db_sort_print_types(void)
+{
+ errlog(BEGIN, "db_sort_print_types() {");
+ sort_string_table(Database.Print_Types);
+ errlog(END, "}");
+}
+
+void
+db_set_arch(char const *arch)
+{
+ Database.Arch = arch;
+}
+
+char const *
+db_get_arch(void)
+{
+ return (Database.Arch);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/db.h b/usr/src/cmd/abi/spectrans/spec2trace/db.h
new file mode 100644
index 0000000000..60eb8d8805
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/db.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _DB_H
+#define _DB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generated by m4 */
+extern void db_set_current_library(char const *);
+extern char *db_get_current_library(void);
+extern void db_set_current_file(char const *);
+extern char *db_get_current_file(void);
+extern void db_set_output_file(char const *);
+extern char *db_get_output_file(void);
+extern void db_set_current_interface(char const *);
+extern char *db_get_current_interface(void);
+extern void db_set_source_directory(char const *);
+extern char *db_get_source_directory(void);
+extern void db_set_target_directory(char const *);
+extern char *db_get_target_directory(void);
+
+/* By hand. */
+extern void db_add_print_types(char *, char *);
+extern char *db_get_first_print_type(void);
+extern char *db_get_next_print_type(void);
+extern void db_sort_print_types(void);
+extern void db_print_print_types(void);
+
+extern void db_set_arch(char const *);
+extern char const *db_get_arch(void);
+
+extern void db_report();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DB_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile b/usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile
new file mode 100644
index 0000000000..10a2f9aed8
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/i386/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/spec2truss/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/interceptor.c b/usr/src/cmd/abi/spectrans/spec2trace/interceptor.c
new file mode 100644
index 0000000000..e95765926a
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/interceptor.c
@@ -0,0 +1,437 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-2000 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * interceptor.c -- a functional decomposition of generate.c,
+ * the code generator for apptrace
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "db.h"
+#include "symtab.h"
+#include "io.h"
+#include "bindings.h"
+#include "printfuncs.h"
+#include "errlog.h"
+#include "parseproto.h"
+
+static void generate_i_declarations(char *, int, char *);
+static void generate_i_preamble(ENTRY *);
+static void generate_i_call();
+static int generate_i_bindings(int);
+static void generate_i_postamble(ENTRY *, int, char *, char *);
+static void generate_i_evaluations(ENTRY *);
+static void generate_i_prints(ENTRY *, char *, char *);
+static void generate_i_closedown(char *, int);
+static void generate_i_live_vars(ENTRY *);
+static void generate_return_printf(int);
+static char *variables_get_errorname(void);
+
+/*
+ * generate_interceptor -- make code for an individual interceptor, written
+ * as an output grammar
+ */
+void
+generate_interceptor(ENTRY *function)
+{
+ char *prototype = symtab_get_prototype(),
+ *library_name = db_get_current_library(),
+ *function_name,
+ *error_name;
+ int void_func;
+
+ errlog(BEGIN, "generate_interceptor() {");
+
+ /* Check for required information. */
+ if (validity_of(function) == NO) {
+ symtab_set_skip(YES);
+ errlog(WARNING|INPUT, "No prototype for interface, "
+ "it will be skipped");
+ errlog(END, "}");
+ return;
+ }
+
+ /* Collect things we'll use more than once. */
+ function_name = name_of(function);
+
+ error_name = variables_get_errorname();
+
+ void_func = is_void(function);
+
+ /*
+ * Emit "artificial" prototype here so that if there's a
+ * disagreement between it and the prototype contained in the
+ * declaring header, the compiler will flag it.
+ * First #undef the function to make sure the prototype in the header
+ * is exposed and to avoid breaking the artificial prototype if it's
+ * not.
+ */
+ {
+ decl_t *dp;
+ char *buf;
+ char const *err;
+ size_t s;
+
+ s = strlen(prototype) + 2;
+ buf = malloc(s);
+ if (buf == NULL)
+ abort();
+ (void) strcpy(buf, prototype);
+ buf[s - 2] = ';';
+ buf[s - 1] = '\0';
+
+ err = decl_Parse(buf, &dp);
+ if (err != NULL)
+ errlog(FATAL, "\"%s\", line %d: %s: %s",
+ symtab_get_filename(), line_of(function),
+ err, prototype);
+
+ /* generate the mapfile entry */
+ (void) fprintf(Mapfp, "\t__abi_%s;\n", decl_GetName(dp));
+
+ (void) decl_ToString(buf, DTS_DECL, dp, function_name);
+ (void) fprintf(Bodyfp, "#line %d \"%s\"\n",
+ line_of(function), symtab_get_filename());
+ (void) fprintf(Bodyfp, "#undef %s\n", function_name);
+ (void) fprintf(Bodyfp, "extern %s;\n", buf);
+
+ (void) fprintf(Bodyfp, "static %s\n{\n", prototype);
+
+ (void) decl_ToString(buf, DTS_RET, dp, "_return");
+ generate_i_declarations(error_name, void_func, buf);
+ decl_Destroy(dp);
+ free(buf);
+ }
+
+ generate_i_preamble(function);
+ generate_i_call(function, void_func, library_name, error_name);
+ generate_i_postamble(function, void_func, error_name, library_name);
+
+ errlog(END, "}");
+}
+
+/*
+ * print_function_signature -- print the line defining the function, without
+ * an ``extern'' prefix or either a ``;'' or ''{'' suffix.
+ */
+void
+print_function_signature(char *xtype, char *name, char *formals)
+{
+ char buffer[MAXLINE];
+
+ (void) snprintf(buffer, sizeof (buffer), "%s", name);
+ (void) fprintf(Bodyfp, xtype, buffer);
+ if (strstr(xtype, "(*") == NULL) {
+ (void) fprintf(Bodyfp, "(%s)", formals);
+ }
+}
+
+
+/*
+ * generate_i_declarations -- generate the declarations which
+ * are local to the interceptor function itself.
+ */
+static void
+generate_i_declarations(char *errname, int voidfunc, char *ret_str)
+{
+
+ errlog(BEGIN, "generate_i_declarations() {");
+ if (*errname != NULL) {
+ /* Create locals for errno-type variable, */
+ (void) fprintf(Bodyfp,
+ " int saved_errvar = %s;\n", errname);
+ (void) fprintf(Bodyfp, " int functions_errvar;\n");
+ }
+
+ if (need_exception_binding()) {
+ /* Create a local for that. */
+ (void) fprintf(Bodyfp, " int exception = 0;\n");
+ }
+ if (! voidfunc) {
+ /* Create a return value. */
+ (void) fprintf(Bodyfp, " %s;\n", ret_str);
+ }
+ (void) fprintf(Bodyfp, " sigset_t omask;\n");
+ (void) putc('\n', Bodyfp);
+ errlog(END, "}");
+}
+
+
+/*
+ * generate_i_preamble -- do the actions which must occur
+ * before the call.
+ */
+static void
+generate_i_preamble(ENTRY *function)
+{
+ errlog(BEGIN, "generate_i_preamble() {");
+ generate_i_live_vars(function); /* Deferred. */
+
+ if (symtab_get_nonreturn() == YES) {
+ /* Make things safe for printing */
+ (void) fprintf(Bodyfp,
+ " abilock(&omask);\n");
+ /* Print all the args in terse format. */
+ generate_printf(function);
+ (void) fputs(" putc('\\n', ABISTREAM);\n\n", Bodyfp);
+ /* unlock stdio */
+ (void) fprintf(Bodyfp,
+ " abiunlock(&omask);\n");
+ }
+
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_call -- implement the save/call/restore cycle
+ */
+static void
+generate_i_call(
+ ENTRY *function,
+ int void_func,
+ char *library_name,
+ char *error_name)
+{
+ char *function_name = name_of(function),
+ *function_cast = symtab_get_cast(),
+ *actual_args = symtab_get_actuals();
+
+ errlog(BEGIN, "generate_i_call() {");
+ /* Zero the error variable. */
+ if (*error_name != NULL) {
+ (void) fprintf(Bodyfp, " %s = 0;\n", error_name);
+ }
+
+ /* Then print the call itself. */
+ if (void_func) {
+ (void) fprintf(Bodyfp,
+ " (void) ABI_CALL_REAL(%s, %s, %s)(%s);\n",
+ library_name, function_name, function_cast, actual_args);
+ } else {
+ (void) fprintf(Bodyfp,
+ " _return = ABI_CALL_REAL(%s, %s, %s)(%s);\n",
+ library_name, function_name, function_cast, actual_args);
+ }
+
+ /* Then set the local copy of the error variable. */
+ if (*error_name != NULL) {
+ (void) fprintf(Bodyfp,
+ " functions_errvar = %s;\n", error_name);
+ }
+ (void) putc('\n', Bodyfp);
+
+ /* Make things safe for printing */
+ (void) fprintf(Bodyfp,
+ " abilock(&omask);\n");
+
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_postamble -- do all the things which come
+ * after the call. In the case of apptrace, this is most of the work.
+ */
+static void
+generate_i_postamble(ENTRY *function, int void_func,
+ char *error_name, char *library_name)
+{
+ errlog(BEGIN, "generate_i_postamble() {");
+ if (symtab_get_nonreturn() == NO) {
+ /* Print all the args in terse format. */
+ generate_printf(function);
+ }
+
+ /* If it isn't supposed to return, and actually ends up here, */
+ /* we'd better be prepared to print all sorts of diagnostic stuff */
+ (void) putc('\n', Bodyfp);
+ if (generate_i_bindings(void_func) == YES) {
+ generate_return_printf(void_func);
+ }
+
+ generate_i_prints(function, library_name, name_of(function));
+ generate_i_evaluations(function); /* Deferred */
+ generate_i_closedown(error_name, void_func);
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_bindings -- see about success and failure, so we can decide
+ * what to do next.
+ */
+static int
+generate_i_bindings(int void_func)
+{
+ ENTRY *e;
+ char *exception;
+
+ exception = ((e = symtab_get_exception()) != NULL)?
+ (name_of(e)? name_of(e): ""): "";
+
+ errlog(BEGIN, "generate_i_bindings() {");
+ if (void_func && bindings_exist()) {
+ /* To become a warning, as there are spec errors! TBD */
+ errlog(FATAL, "exception bindings found in a "
+ "void function");
+ } else if (void_func || need_bindings(exception) == NO) {
+ (void) fprintf(Bodyfp,
+ " (void) putc('\\n', ABISTREAM);\n");
+ (void) putc('\n', Bodyfp);
+ errlog(END, "}");
+ return (NO);
+ } else {
+ /*
+ * Then there is a return value, so we try to
+ * generate exception bindings
+ * and code to print errno on exception.
+ */
+ if ((generate_bindings(exception)) != ANTONYMS) {
+ /* Generate code to cross-evaluate them. */
+ (void) fprintf(Bodyfp,
+ " if (!exception) {\n");
+ errlog(END, "}");
+ return (YES);
+ }
+ }
+
+ /* should not get here */
+ errlog(END, "}");
+ return (NO);
+}
+
+/*
+ * generate_return_printf -- print the return value and end the line
+ */
+static void
+generate_return_printf(int void_func)
+{
+ errlog(BEGIN, "generate_return_printf() {");
+ if (void_func) {
+ (void) fprintf(Bodyfp, " putc('\\n', ABISTREAM);\n");
+ errlog(END, "}");
+ return;
+ }
+ /* If its a non-void function there are bindings. */
+ (void) fprintf(Bodyfp,
+ "\t/* Just end the line */\n"
+ "\tputc('\\n', ABISTREAM);\n"
+ " }\n"
+ " else {\n"
+ " fprintf(ABISTREAM, \"%%s%%d (%%s)\\n\", errnostr, "
+ "functions_errvar, strerror((int)functions_errvar));\n"
+ " }\n\n");
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_prints -- if we're doing the verbose stuff,
+ * generate verbose printouts of the variables.
+ */
+static void
+generate_i_prints(ENTRY *function, char *lib, char *func)
+{
+ ENTRY *e;
+
+ errlog(BEGIN, "generate_i_prints() {");
+ if ((e = symtab_get_first_arg()) != NULL || !is_void(e)) {
+ /* Then we have to generate code for verbose reports. */
+ (void) fprintf(Bodyfp, " if (ABI_VFLAG(%s, %s) != 0) {\n",
+ lib, func);
+ generate_printfunc_calls(function);
+ (void) fprintf(Bodyfp, " }\n");
+ }
+ (void) putc('\n', Bodyfp);
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_closedown -- restore error variables and return.
+ */
+static void
+generate_i_closedown(char *error_name, int void_func)
+{
+ errlog(BEGIN, "generate_i_closedown() {");
+
+ /* unlock stdio */
+ (void) fprintf(Bodyfp,
+ " abiunlock(&omask);\n");
+
+ if (*error_name != NULL) {
+ /* Restore error variables. */
+ (void) fprintf(Bodyfp,
+ " %s = (functions_errvar == 0)? "
+ " saved_errvar: functions_errvar;\n",
+ error_name);
+ }
+
+ /* And return. */
+ (void) fprintf(Bodyfp,
+ " return%s;\n",
+ (void_func)? "": " _return");
+ (void) fprintf(Bodyfp, "}\n");
+ (void) putc('\n', Bodyfp);
+ errlog(END, "}");
+}
+
+
+/*
+ * generate_i_live_vars -- generate temps for any ``out''
+ * or ``inout'' variables in the function. Deferred.
+ */
+/*ARGSUSED*/
+static void
+generate_i_live_vars(ENTRY *function)
+{
+ errlog(BEGIN, "generate_i_live_vars() {");
+ errlog(END, "}");
+}
+
+/*
+ * generate_i_evaluations -- generate evaluations for
+ * all the expressions. Deferred.
+ */
+/*ARGSUSED*/
+static void
+generate_i_evaluations(ENTRY *function)
+{
+ errlog(BEGIN, "generate_i_evaluations() {");
+ errlog(END, "}");
+}
+
+
+static char *
+variables_get_errorname(void)
+{
+ return ("ABI_ERRNO");
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/io.c b/usr/src/cmd/abi/spectrans/spec2trace/io.c
new file mode 100644
index 0000000000..302b27b3fa
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/io.c
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include "parser.h"
+#include "trace.h"
+#include "db.h"
+#include "util.h"
+#include "errlog.h"
+
+/* Types and Globals */
+FILE *Bodyfp = NULL;
+FILE *Headfp = NULL;
+FILE *Mapfp = NULL;
+
+static char headfile_name[MAXLINE]; /* Saved for later. */
+static char mapfile_name[MAXLINE]; /* Saved for later. */
+
+/* File globals. */
+static int alt_code_file(void);
+static void abort_code_file(void);
+
+/*
+ * open_code_file - open the code file and the invisible temp file.
+ */
+int
+open_code_file(void)
+{
+ char *dir = db_get_target_directory();
+ char *body_file_name;
+ int rc = YES;
+
+ errlog(BEGIN, "open_code_file() {");
+
+ /* Open the Head file, which gets the headers, includes and */
+ /* definitions, and eventually gets the body concatenated to it. */
+ (void) snprintf(headfile_name, sizeof (headfile_name), "%s.c",
+ db_get_output_file());
+ if ((Headfp = fopen(headfile_name, "w")) == NULL) {
+ errlog(FATAL, "%s: %s", headfile_name, strerror(errno));
+ }
+
+ (void) snprintf(mapfile_name, sizeof (mapfile_name), "%s-vers",
+ db_get_output_file());
+
+ if ((Mapfp = fopen(mapfile_name, "w")) == NULL) {
+ errlog(FATAL, "%s: %s", mapfile_name, strerror(errno));
+ }
+ (void) fputs("SUNWabi_1.1 {\n global:\n", Mapfp);
+
+ /* Now the Body file, which is an ephemeral temp-file. */
+ if ((body_file_name = tempnam(dir, NULL)) == NULL) {
+ errlog(FATAL, "out of memory creating a temp-file name");
+ }
+
+ if ((Bodyfp = fopen(body_file_name, "w+")) == NULL) {
+ errlog(FATAL, "%s: %s", body_file_name, strerror(errno));
+ }
+
+ if (unlink(body_file_name) != 0) {
+ errlog(FATAL, "unlink %s: %s", body_file_name, strerror(errno));
+ }
+
+ (void) free(body_file_name);
+ errlog(END, "}");
+ return (rc);
+}
+
+/*
+ * abort_code_file -- close and discard files.
+ * this function is also called from alt_code_file, so
+ * it is not cool to unlink the code file or the mapfile
+ */
+static void
+abort_code_file(void)
+{
+ errlog(BEGIN, "abort_code_file() {");
+ (void) fclose(Bodyfp);
+ (void) fclose(Headfp);
+ if (unlink(headfile_name) != 0) {
+ errlog(FATAL, "unlink %s: %s", headfile_name, strerror(errno));
+ }
+ errlog(END, "}");
+}
+
+int
+alt_code_file(void)
+{
+ char hfn[MAXLINE];
+ FILE *hfp;
+
+ abort_code_file();
+ (void) snprintf(hfn, sizeof (hfn), "%s.c", db_get_output_file());
+ if ((hfp = fopen(hfn, "w")) == NULL) {
+ errlog(FATAL, "%s: %s", headfile_name, strerror(errno));
+ }
+
+ (void) fputs("static int __abi_place_holder;\n", hfp);
+ (void) fclose(hfp);
+
+ return (YES);
+}
+
+/*
+ * commit_code_file -- close and commit files that have advanced
+ * beyond byte position 0.
+ */
+int
+commit_code_file(void)
+{
+ char copy_buffer[BUFSIZ*8];
+ size_t n;
+
+ errlog(BEGIN, "commit_code_file() {");
+ /*
+ * We unconditionally want a .pf and a -vers file
+ */
+ (void) fputs(" local:\n\t*;\n};\n", Mapfp);
+ if (fclose(Mapfp) != 0) {
+ errlog(FATAL, "fclose %s: %s", mapfile_name, strerror(errno));
+ }
+ if (ftell(Bodyfp) == 0) {
+ /*
+ * special case, redo C file with place holder
+ * so that makefiles won't break...
+ */
+ errlog(END, "}");
+ return (alt_code_file());
+ } else {
+ /* Concatenate body file to head file, close both. */
+ rewind(Bodyfp);
+ while ((n = fread(copy_buffer, 1,
+ sizeof (copy_buffer), Bodyfp)) != 0) {
+ (void) fwrite(copy_buffer, 1, n, Headfp);
+ }
+ (void) fclose(Bodyfp);
+ if (fclose(Headfp) != 0) {
+ errlog(FATAL, "fclose <temp file>: %s",
+ strerror(errno));
+ }
+ }
+
+ errlog(END, "}");
+ return (YES);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/io.h b/usr/src/cmd/abi/spectrans/spec2trace/io.h
new file mode 100644
index 0000000000..3c3f53a2ce
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/io.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _IO_H
+#define _IO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern FILE *Bodyfp;
+extern FILE *Headfp;
+extern FILE *Mapfp;
+
+extern void explain_fopen_failure(int, char *);
+extern void explain_fclose_failure(int, char *);
+
+extern int open_code_file(void);
+extern int commit_code_file(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _IO_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/linkage.c b/usr/src/cmd/abi/spectrans/spec2trace/linkage.c
new file mode 100644
index 0000000000..4d0f4c69a7
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/linkage.c
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "db.h"
+#include "symtab.h"
+#include "io.h"
+#include "printfuncs.h"
+#include "errlog.h"
+#include "parseproto.h"
+
+static void generate_interface_predeclaration(char *, ENTRY *);
+static void generate_linkage_function(char *, char *);
+
+
+/*
+ * generate_linkage -- make code for the linkage part of an individual
+ * interface. Assumes Bodyfp.
+ */
+void
+generate_linkage(ENTRY *function)
+{
+ char *library_name = db_get_current_library(),
+ *function_name;
+ char composite_name[MAXLINE];
+
+ errlog(BEGIN, "generate_linkage() {");
+
+ function_name = name_of(function);
+ (void) snprintf(composite_name, sizeof (composite_name),
+ "%s_%s", library_name, function_name);
+
+ /* Print the predeclaration of the interceptor. */
+ generate_interface_predeclaration(composite_name, function);
+ /* Collect things we'll use more than once. */
+
+ /* Next the struct used to pass parameters. */
+ (void) fprintf(Bodyfp, "static abisym_t __abi_%s_%s_sym;\n",
+ library_name, function_name);
+
+ /* The linkage function, */
+ generate_linkage_function(library_name, function_name);
+
+ (void) fputs("\n\n", Bodyfp);
+ errlog(END, "}");
+}
+
+
+/*
+ * generate_interface_predeclaration -- make things know so the compiler
+ * won't kak.
+ */
+static void
+generate_interface_predeclaration(char *composite_name, ENTRY *function)
+{
+ decl_t *pp;
+ char *p = symtab_get_prototype();
+ char buf[BUFSIZ];
+
+ (void) fprintf(Bodyfp, "\n/* from \"%s\", line %d */\n",
+ symtab_get_filename(), line_of(function));
+ (void) fprintf(Bodyfp, "static ");
+
+ if (p[strlen(p)-1] != ';')
+ (void) snprintf(buf, BUFSIZ, "%s;", strnormalize(p));
+ else
+ (void) snprintf(buf, BUFSIZ, "%s", strnormalize(p));
+
+ decl_Parse(buf, &pp);
+ decl_AddArgNames(pp);
+ symtab_set_prototype(decl_ToString(buf, DTS_DECL, pp, composite_name));
+ (void) fprintf(Bodyfp, "%s;\n", symtab_get_prototype());
+ decl_Destroy(pp);
+}
+
+
+
+/*
+ * generate_linkage_function -- The linkage function itself.
+ */
+static void
+generate_linkage_function(char *lib, char *func)
+{
+ (void) fprintf(Bodyfp,
+ "void *__abi_%s_%s(void *real, int vflag) { \n", lib, func);
+ (void) fprintf(Bodyfp, " ABI_REAL(%s, %s) = real;\n", lib, func);
+ (void) fprintf(Bodyfp, " ABI_VFLAG(%s, %s) = vflag;\n", lib, func);
+ (void) fprintf(Bodyfp,
+ " return ((void *) %s_%s);\n}\n", lib, func);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/parseproto.h b/usr/src/cmd/abi/spectrans/spec2trace/parseproto.h
new file mode 100644
index 0000000000..b377100526
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/parseproto.h
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _PARSEPROTO_H
+#define _PARSEPROTO_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * DECL - parse C type declarations.
+ *
+ * 1) Does not understand struct, union or enum definitions.
+ * 2) Does not understand auto, static, extern or typedef storage class
+ * specifiers.
+ * 3) Does not support initialization.
+ * 4) Does not support type definition.
+ * 5) Only understands array dimension specified as constant decimal
+ * integer or identifier.
+ *
+ * Supported Operations
+ *
+ * decl_Parse convert string to a decl_t.
+ * decl_Destroy Free space associated with a (previously returned)
+ * decl_t. The function follows the argument list.
+ * decl_SetName set identifier.
+ * decl_GetName return identifier.
+ * decl_ToString convert a (previously returned) decl_t into a
+ * printable representation.
+ * decl_GetArgLength return length of argument list.
+ * decl_GetNext return the next decl_t associated with the given
+ * decl_t.
+ * decl_GetDeclSpec return the declaration specifier.
+ * decl_GetDSName return identifier associated with a
+ * declaration specifier.
+ * decl_GetType return the type_t associated with a decl_t.
+ * decl_IsVarargs return true if the given decl_t is a varargs function.
+ * decl_IsFunction return true if the given decl_t is a function.
+ *
+ * type_GetNext return the next type_t associated with a given type_t.
+ * type_IsArray return true if the given type_t is an array.
+ * type_GetArraySize return size of array.
+ *
+ * type_IsPtrTo return true if the given type_t is a pointer to ... .
+ * type_GetPtrToTypeQual return type qualifiers for a pointer to ... .
+ *
+ * type_IsFunction return true if the given type_t is a function.
+ * type_GetArgLength return length of argument list.
+ * type_IsVarargs return true if function signature includes ... .
+ * type_GetArg return the decl_t associated with a given type_t.
+ * type_IsPtrFun return true if the given type_t is a pointer* to a
+ * function.
+ */
+
+/* Include Files */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+/* Macros and Constants */
+
+#define loop for (;;)
+
+#define STT_isvoid(s) ((s) & (TS_VOID))
+#define STT_isfloat(s) ((s) & (TS_FLOAT | TS_DOUBLE))
+#define STT_ischar(s) ((s) & (TS_CHAR))
+#define STT_isint(s) ((s) & \
+ (TS_SHORT | TS_INT | TS_LONG | TS_LONGLONG | TS_CHAR))
+#define STT_isarith(s) (STT_isfloat(s) || STT_isint(s))
+#define STT_isbasic(s) (STT_isarith(s) || STT_isvoid(s))
+#define STT_isderived(s) ((s) & (TS_STRUCT | TS_UNION | TS_ENUM | TS_TYPEDEF))
+#define STT_has_explicit_sign(s) ((s) & (TS_SIGNED | TS_UNSIGNED))
+
+/* Data Declarations */
+
+/*
+ * The overall type encoding is thus:
+ *
+ * decl_t encodes a declaration which consists of:
+ * identifier
+ * declaration specifier (storage class specifier, type specifier,
+ * type qualifier)
+ * type modifiers (array, function, pointer to)
+ * ancillary (varargs?, argument list)
+ *
+ * The argument list is an ordered, NULL terminated, linked list.
+ *
+ * An empty argument list (== NULL) indicates an unknown argument
+ * list, i.e. "()".
+ *
+ * declaration specifiers are encoded as bits in an enum (stt_t).
+ *
+ * type modifiers are encoded as a linked list of variant records,
+ * i.e. "array of ..."
+ * "function returning ..." and "pointer to ...".
+ *
+ * An empty list of type modifiers (== NULL) indicates a "plain" type.
+ *
+ *
+ * OK, here goes some ASCII art...
+ *
+ *
+ * base object
+ * |
+ * |
+ * V
+ *
+ * ---------- ---------- ---------- ----------
+ * | | | | | | | |
+ * | decl_t | --> | type_t | --> | type_t | ... | type_t | --> NULL
+ * | | | | |(DD_FUN)| | |
+ * ---------- ---------- ---------- ----------
+ * | |
+ * | |
+ * V V
+ * A ---------- ----------
+ * NULL r | | | |
+ * g | decl_t | --> | type_t | ... --> NULL
+ * u | | | |
+ * m ---------- ----------
+ * e |
+ * n |
+ * t V
+ * ----------
+ * L | |
+ * i | decl_t | ... --> NULL
+ * s | |
+ * t ----------
+ *
+ * ...
+ *
+ * |
+ * |
+ * V
+ *
+ * NULL
+ */
+
+/*
+ * The encoding of a declaration specifier is done primarily with an
+ * stt_t type.
+ * This type must support bit-wise operations.
+ */
+
+typedef enum {
+ SCS_MASK = 0x000000ff, /* storage class specifiers */
+ SCS_NONE = 0x00000000,
+ SCS_REGISTER = 0x00000001,
+ SCS_TYPEDEF = 0x00000002,
+ SCS_EXTERN = 0x00000004,
+ SCS_AUTO = 0x00000008,
+ SCS_STATIC = 0x00000010,
+
+ TS_MASK = 0x00ffff00, /* type specifiers */
+ TS_NO_TS = 0x00000000,
+ TS_CHAR = 0x00000100,
+ TS_SHORT = 0x00000200,
+ TS_INT = 0x00000400,
+ TS_LONG = 0x00000800,
+ TS_SIGNED = 0x00001000,
+ TS_UNSIGNED = 0x00002000,
+ TS_ENUM = 0x00004000,
+ TS_FLOAT = 0x00010000,
+ TS_DOUBLE = 0x00020000,
+ TS_STRUCT = 0x00040000,
+ TS_UNION = 0x00080000,
+ TS_TYPEDEF = 0x00100000,
+ TS_VOID = 0x00200000,
+ TS_LONGLONG = 0x00400000, /* non-ANSI type: long long */
+
+ TQ_MASK = 0x0f000000, /* type qualifiers */
+ TQ_NONE = 0x00000000,
+ TQ_CONST = 0x01000000,
+ TQ_VOLATILE = 0x02000000,
+ TQ_RESTRICT = 0x04000000,
+ TQ_RESTRICT_KYWD = 0x08000000
+} stt_t;
+
+typedef enum { /* declarator options */
+ DD_NONE = 0,
+ DD_ARY = 1, /* array of [size] ... */
+ DD_FUN = 2, /* function [taking and] returning ... */
+ DD_PTR = 3 /* [tq] pointer to ... */
+} decl_type_t;
+
+typedef enum {
+ DTS_DECL = 0,
+ DTS_CAST = 1,
+ DTS_RET = 3
+} decl_dts_t;
+
+typedef struct {
+ stt_t ds_stt; /* scs|ts|tq */
+ char *ds_id; /* id for struct|union|enum|typedef */
+} decl_spec_t;
+
+typedef struct _declarator decl_t;
+
+typedef struct _type {
+ struct _type *t_next; /* next type_t or NULL */
+ decl_type_t t_dt; /* oneof DD_* */
+ /* DD_FUN */
+ int t_nargs; /* number of arguments */
+ int t_ellipsis; /* a varargs? */
+ decl_t *t_args; /* list of arguments */
+ /* DD_PTR */
+ stt_t t_stt; /* type qualifier, TQ_* */
+ /* DD_ARY */
+ char *t_sizestr; /* size as a string */
+} type_t;
+
+struct _declarator {
+ char *d_name; /* name of declarator */
+ decl_spec_t *d_ds; /* ts|scs|tq */
+ type_t *d_type; /* list of attributes or NULL */
+ int d_ellipsis; /* a varargs? */
+ decl_t *d_next; /* next link in chain (arglist) */
+};
+
+/* External Declarations */
+
+extern char *declspec_ToString(char *, decl_spec_t *);
+
+extern void decl_Destroy(decl_t *);
+extern int decl_GetArgLength(decl_t *);
+extern decl_t *decl_SetName(decl_t *, char *);
+extern char *decl_GetName(decl_t *);
+extern type_t *decl_GetType(decl_t *);
+extern int decl_IsVarargs(decl_t *dp);
+extern char *decl_ToString(char *, decl_dts_t, decl_t *,
+ const char *);
+extern const char *decl_Parse(char *, decl_t **);
+extern void decl_GetTraceInfo(decl_t *, char *, char *, decl_t **);
+extern char *decl_ToFormal(decl_t *);
+extern int type_IsArray(type_t *);
+extern int type_IsPtrTo(type_t *);
+extern int type_IsFunction(type_t *);
+extern int type_IsVarargs(type_t *);
+extern int type_IsPtrFun(type_t *);
+extern decl_t *decl_AddArgNames(decl_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PARSEPROTO_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/parseproto.y b/usr/src/cmd/abi/spectrans/spec2trace/parseproto.y
new file mode 100644
index 0000000000..4b851ce044
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/parseproto.y
@@ -0,0 +1,2227 @@
+%{
+/*
+ * 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.
+ *
+ * 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 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "parseproto.h"
+#include <assert.h>
+
+static decl_spec_t *declspec_Construct(void);
+static void declspec_Destroy(decl_spec_t *);
+static decl_spec_t *declspec_Init(stt_t, char *);
+static char *declspec_VerifySTT(stt_t, stt_t);
+static decl_spec_t *declspec_AddSTT(decl_spec_t *, stt_t, const char **);
+static decl_spec_t *declspec_AddDS(decl_spec_t *,
+ decl_spec_t *, const char **);
+static stt_t declspec_GetSTT(decl_spec_t *);
+static char *declspec_GetTag(decl_spec_t *);
+static type_t *type_Construct(void);
+static void type_Destroy(type_t *);
+static type_t *type_SetPtr(type_t *, stt_t);
+static type_t *type_SetFun(type_t *, decl_t *);
+static type_t *type_AddTail(type_t *, type_t *);
+static const char *type_Verify(type_t *);
+
+static decl_t *decl_Construct(void);
+static decl_t *decl_AddArg(decl_t *, decl_t *);
+static int decl_IsVoid(decl_t *);
+static int decl_IsVoidArray(decl_t *);
+static const char *decl_VerifyArgs(decl_t *);
+static decl_t *decl_AddDS(decl_t *, decl_spec_t *, const char **);
+static decl_t *decl_AddTypeTail(decl_t *, type_t *);
+static decl_t *decl_addptr(decl_t *, type_t *);
+static decl_t *decl_addary(decl_t *, char *);
+static decl_t *decl_addfun(decl_t *, decl_t *);
+static decl_t *decl_addellipsis(decl_t *);
+
+#if defined(DEBUG)
+static void type_PrintType(type_t *, int);
+static void decl_PrintDecl(decl_t *, int);
+static void decl_PrintTraceInfo(decl_t *);
+static char *de_const(char *);
+#endif
+
+
+
+static int yylex(void);
+static void yyerror(const char *);
+static int yyparse(void);
+
+#if defined(MEM_DEBUG)
+static int declspec_Construct_calls;
+static int type_Construct_calls;
+static int decl_Construct_calls;
+#endif
+
+#if defined(DEBUG)
+static char *de_const(char *);
+#endif
+%}
+
+%union {
+ char *s_val;
+ int i_val;
+ stt_t stt_val;
+ decl_spec_t *ds_val;
+ type_t *t_val;
+ decl_t *d_val;
+}
+
+%token <i_val> ELLIPSIS
+
+%token <s_val> INTEGER
+%token <s_val> IDENTIFIER
+%token <s_val> TYPEDEF_NAME
+%type <s_val> constant_expression
+
+%token <stt_val> REGISTER
+%token <stt_val> TYPEDEF EXTERN AUTO STATIC
+%token <stt_val> VOID CHAR SHORT INT LONG
+%token <stt_val> FLOAT DOUBLE SIGNED UNSIGNED
+%token <stt_val> CONST VOLATILE RESTRICT RESTRICT_KYWD
+%type <stt_val> struct_or_union
+%type <ds_val> storage_class_specifier
+%type <ds_val> type_qualifier
+%type <ds_val> type_qualifier_list
+
+%token <ds_val> STRUCT UNION
+%token <ds_val> ENUM
+%type <ds_val> declaration_specifiers
+%type <ds_val> type_specifier
+%type <ds_val> struct_or_union_specifier enum_specifier
+%type <ds_val> typedef_name
+
+%type <t_val> pointer
+
+%type <d_val> declaration
+%type <d_val> init_declarator_list init_declarator
+%type <d_val> declarator
+%type <d_val> direct_declarator
+%type <d_val> parameter_type_list parameter_list
+%type <d_val> parameter_declaration
+%type <d_val> abstract_declarator
+%type <d_val> direct_abstract_declarator
+
+%start declaration
+
+%%
+
+/*
+ * The grammar is derived from ANSI/ISO 9899-1990.
+ */
+
+declaration
+ : declaration_specifiers init_declarator_list ';'
+ {
+ decl_t *dp;
+
+ protop = $$ = $2;
+
+ /* only one declaration allowed */
+ assert(protop->d_next == NULL);
+
+ for (dp = $2; dp && (errstr == NULL);
+ dp = dp->d_next) {
+ const char *sp;
+
+ decl_AddDS(dp, $1, &errstr);
+ if (sp = decl_Verify(dp))
+ errstr = sp;
+ }
+ declspec_Destroy($1);
+ }
+ | error ';'
+ {
+ protop = $$ = NULL;
+ errstr = "function prototype syntax error";
+ }
+/*
+ * XXX - Does not support a "stand-alone" declaration specifier. It is
+ * essentially a type declaration, for example:
+ *
+ * typedef enum { FALSE = 0, TRUE = 1 } boolean_t;
+ * or
+ * struct _name { char *first; char *last };
+ */
+
+/* XXX | declaration_specifiers */
+ ;
+
+declaration_specifiers
+ : storage_class_specifier declaration_specifiers
+ {
+ char const *ep;
+
+ $$ = declspec_AddDS($2, $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ | storage_class_specifier
+ | type_specifier declaration_specifiers
+ {
+ const char *ep;
+
+ $$ = declspec_AddDS($2, $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ | type_specifier
+ | type_qualifier declaration_specifiers
+ {
+ const char *ep;
+
+ $$ = declspec_AddDS($2, $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ | type_qualifier
+ ;
+
+storage_class_specifier
+ : REGISTER
+ {
+ $$ = declspec_Init(SCS_REGISTER, NULL);
+ }
+/*
+ * XXX - Does not support any storage class specifier other than
+ * register, and then only for function arguments.
+ *
+ | TYPEDEF
+ {
+ $$ = declspec_Init(SCS_TYPEDEF, NULL);
+ }
+ | EXTERN
+ {
+ $$ = declspec_Init(SCS_EXTERN, NULL);
+ }
+ | STATIC
+ {
+ $$ = declspec_Init(SCS_STATIC, NULL);
+ }
+ | AUTO
+ {
+ $$ = declspec_Init(SCS_AUTO, NULL);
+ }
+ */
+ ;
+
+type_specifier
+ : VOID
+ {
+ $$ = declspec_Init(TS_VOID, NULL);
+ atIDENT = 1;
+ }
+ | CHAR
+ {
+ $$ = declspec_Init(TS_CHAR, NULL);
+ atIDENT = 1;
+ }
+ | SHORT
+ {
+ $$ = declspec_Init(TS_SHORT, NULL);
+ atIDENT = 1;
+ }
+ | INT
+ {
+ $$ = declspec_Init(TS_INT, NULL);
+ atIDENT = 1;
+ }
+ | LONG
+ {
+ $$ = declspec_Init(TS_LONG, NULL);
+ atIDENT = 1;
+ }
+ | FLOAT
+ {
+ $$ = declspec_Init(TS_FLOAT, NULL);
+ atIDENT = 1;
+ }
+ | DOUBLE
+ {
+ $$ = declspec_Init(TS_DOUBLE, NULL);
+ atIDENT = 1;
+ }
+ | SIGNED
+ {
+ $$ = declspec_Init(TS_SIGNED, NULL);
+ atIDENT = 1;
+ }
+ | UNSIGNED
+ {
+ $$ = declspec_Init(TS_UNSIGNED, NULL);
+ atIDENT = 1;
+ }
+ | struct_or_union_specifier
+ | enum_specifier
+ | typedef_name
+ ;
+
+typedef_name
+ : TYPEDEF_NAME
+ {
+ $$ = declspec_Init(TS_TYPEDEF, $1);
+ atIDENT = 1;
+ free($1);
+ }
+ ;
+
+/*
+ * The "restrict" keyword is new in the C99 standard.
+ * It is type qualifier like const and volatile.
+ * We are using "_RESTRICT_KYWD" in headers and source code so
+ * it is easily turned on and off by various macros at compile time.
+ * In order for the "restrict" keyword to be recognized you must
+ * be using a C99 compliant compiler in its native mode.
+ */
+type_qualifier
+ : CONST
+ {
+ $$ = declspec_Init(TQ_CONST, NULL);
+ }
+ | VOLATILE
+ {
+ $$ = declspec_Init(TQ_VOLATILE, NULL);
+ }
+ | RESTRICT
+ {
+ $$ = declspec_Init(TQ_RESTRICT, NULL);
+ }
+ | RESTRICT_KYWD
+ {
+ $$ = declspec_Init(TQ_RESTRICT_KYWD, NULL);
+ }
+ ;
+
+struct_or_union_specifier
+ : struct_or_union { atIDENT = 1; } IDENTIFIER
+ {
+ $$ = declspec_Init($1, $3);
+ free($3);
+ }
+/*
+ * XXX - struct or union definitions are not supported. It is generally
+ * not done within the context of a function declaration (prototype) or
+ * variable definition.
+
+ | struct_or_union IDENTIFIER '{' struct_declaration_list '}'
+ | struct_or_union '{' struct_declaration_list '}'
+ */
+ ;
+
+struct_or_union
+ : STRUCT
+ {
+ $$ = TS_STRUCT;
+ }
+ | UNION
+ {
+ $$ = TS_UNION;
+ }
+ ;
+
+init_declarator_list
+ : init_declarator
+ {
+ $$ = $1;
+ atIDENT = 1;
+ }
+/*
+ * XXX - Does not support a comma separated list of declarations or
+ * definitions. Function prototypes or variable definitions must be
+ * given as one per C statement.
+
+ | init_declarator_list ',' init_declarator
+ {
+ $$ = decl_AddArg($1, $3);
+ atIDENT = 1;
+ }
+*/
+ ;
+
+init_declarator
+ : declarator
+/*
+ * XXX - Initialization is not supported.
+
+ | declarator '=' initializer
+*/
+ ;
+
+
+enum_specifier
+ : ENUM { atIDENT = 1; } IDENTIFIER
+ {
+ $$ = declspec_Init(TS_ENUM, $3);
+ free($3);
+ }
+/*
+ * XXX - enumerator definition is not supported for the same reasons
+ * struct|union definition is not supported.
+
+ | ENUM IDENTIFIER '{' enumerator_list '}'
+ | ENUM '{' enumerator_list '}'
+*/
+ ;
+
+
+declarator
+ : pointer direct_declarator
+ {
+ $$ = decl_addptr($2, $1);
+ }
+ | direct_declarator
+ ;
+
+direct_declarator
+ : IDENTIFIER
+ {
+ $$ = decl_SetName(decl_Construct(), $1);
+ atIDENT = 0;
+ free($1);
+ }
+ | '(' declarator ')'
+ {
+ $$ = $2;
+ }
+ | direct_declarator '[' constant_expression ']'
+ {
+ $$ = decl_addary($1, $3);
+ free($3);
+ }
+ | direct_declarator '[' ']'
+ {
+ $$ = decl_addary($1, NULL);
+ }
+ | direct_declarator '(' parameter_type_list ')'
+ {
+ $$ = decl_addfun($1, $3);
+ }
+ | direct_declarator '(' ')'
+ {
+ $$ = decl_addfun($1, NULL);
+ }
+ ;
+
+pointer
+ : '*' type_qualifier_list
+ {
+ $$ = type_SetPtr(type_Construct(), ($2)->ds_stt);
+ declspec_Destroy($2);
+ }
+ | '*'
+ {
+ $$ = type_SetPtr(type_Construct(), TQ_NONE);
+ }
+ | '*' type_qualifier_list pointer
+ {
+ type_t *tp = type_Construct();
+
+ type_SetPtr(tp, ($2)->ds_stt);
+ declspec_Destroy($2);
+ $$ = type_AddTail($3, tp);
+ }
+ | '*' pointer
+ {
+ type_t *tp = type_Construct();
+
+ type_SetPtr(tp, TQ_NONE);
+ $$ = type_AddTail($2, tp);
+ }
+ ;
+
+type_qualifier_list
+ : type_qualifier
+ | type_qualifier_list type_qualifier
+ {
+ const char *ep;
+
+ /* XXX - ignore any error */
+ $$ = declspec_AddDS($1, $2, &ep);
+ declspec_Destroy($2);
+ }
+ ;
+
+parameter_type_list
+ : parameter_list
+ | parameter_list ',' ELLIPSIS
+ {
+ $$ = decl_addellipsis($1);
+ }
+ ;
+
+parameter_list
+ : parameter_declaration
+ {
+ const char *sp = type_Verify($1->d_type);
+
+ if (sp)
+ errstr = sp;
+
+ $$ = $1;
+ atIDENT = 0;
+ }
+ | parameter_list ',' parameter_declaration
+ {
+ const char *sp = type_Verify($3->d_type);
+
+ if (sp)
+ errstr = sp;
+
+ $$ = decl_AddArg($1, $3);
+ atIDENT = 0;
+ }
+ ;
+
+parameter_declaration
+ : declaration_specifiers declarator
+ {
+ const char *ep;
+
+ $$ = decl_AddDS($2, $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ | declaration_specifiers abstract_declarator
+ {
+ const char *ep;
+
+ $$ = decl_AddDS($2, $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ | declaration_specifiers
+ {
+ const char *ep;
+
+ $$ = decl_AddDS(decl_Construct(), $1, &ep);
+ declspec_Destroy($1);
+
+ if (errstr == NULL)
+ errstr = ep;
+ }
+ ;
+
+abstract_declarator
+ : pointer
+ {
+ $$ = decl_addptr(decl_Construct(), $1);
+ }
+ | pointer direct_abstract_declarator
+ {
+ $$ = decl_addptr($2, $1);
+ }
+ | direct_abstract_declarator
+ ;
+
+direct_abstract_declarator
+ : '(' abstract_declarator ')'
+ {
+ $$ = $2;
+ }
+ | direct_abstract_declarator '[' constant_expression ']'
+ {
+ $$ = decl_addary($1, $3);
+ free($3);
+ }
+ | '[' constant_expression ']'
+ {
+ $$ = decl_addary(decl_Construct(), $2);
+ free($2);
+ }
+ | direct_abstract_declarator '[' ']'
+ {
+ $$ = decl_addary($1, NULL);
+ }
+ | '[' ']'
+ {
+ $$ = decl_addary(decl_Construct(), NULL);
+ }
+ | direct_abstract_declarator '(' parameter_type_list ')'
+ {
+ $$ = decl_addfun($1, $3);
+ }
+ | '(' parameter_type_list ')'
+ {
+ $$ = decl_addfun(decl_Construct(), $2);
+ }
+ | direct_abstract_declarator '(' ')'
+ {
+ $$ = decl_addfun($1, NULL);
+ }
+ | '(' ')'
+ {
+ $$ = decl_addfun(decl_Construct(), NULL);
+ }
+ ;
+
+/*
+ * XXX - General case constant expressions are not supported. It would
+ * be easy to implement (for the most part), but there are no cases to
+ * date that require such a facility. The grammar does allow an
+ * identifier (or typedef name) to be used since the prototype is not
+ * processed by CPP. The only integer constant that is supported is
+ * decimal.
+ */
+
+constant_expression
+ : INTEGER
+ | IDENTIFIER
+ | TYPEDEF_NAME
+ ;
+
+%%
+
+/* Data Declarations */
+
+typedef struct {
+ char *name;
+ int token;
+ stt_t stt;
+} keyword_t;
+
+typedef struct {
+ stt_t s_stt;
+ char *s_str;
+} sttpair_t;
+
+/* External Declarations */
+
+static const keyword_t *lookup_keyword(const char *);
+static const char *lookup_sttpair(stt_t);
+static int getch(void);
+static void ungetch(int);
+static void skipwhitespace(void);
+static int lookahead(int);
+static void skipcomment(void);
+
+/* External Definitions */
+
+static char *input = NULL; /* current place in the input stream */
+/* at point in stream were identifier is expected */
+static int atIDENT = 0;
+static decl_t *protop = NULL; /* pointer to prototype */
+static const char *errstr = NULL; /* error message */
+
+/*
+ * lookup_keyword - Given a string, return the keyword_t or NULL.
+ */
+
+static const keyword_t *
+lookup_keyword(const char *name) {
+ static const keyword_t keytbl[] = {
+ { "register", REGISTER, SCS_REGISTER },
+#if UNSUPPORTED
+ { "typedef", TYPEDEF, SCS_TYPEDEF },
+ { "auto", AUTO, SCS_AUTO },
+ { "static", STATIC, SCS_STATIC },
+ { "extern", EXTERN, SCS_EXTERN },
+#endif /* UNSUPPORTED */
+ { "void", VOID, TS_VOID },
+ { "char", CHAR, TS_CHAR },
+ { "short", SHORT, TS_SHORT },
+ { "int", INT, TS_INT },
+ { "long", LONG, TS_LONG },
+ { "float", FLOAT, TS_FLOAT },
+ { "double", DOUBLE, TS_DOUBLE },
+ { "signed", SIGNED, TS_SIGNED },
+ { "unsigned", UNSIGNED, TS_UNSIGNED },
+ { "struct", STRUCT, TS_STRUCT },
+ { "union", UNION, TS_UNION },
+ { "enum", ENUM, TS_ENUM },
+
+ { "const", CONST, TQ_CONST },
+ { "volatile", VOLATILE, TQ_VOLATILE },
+ { "restrict", RESTRICT, TQ_RESTRICT },
+ { "_RESTRICT_KYWD",RESTRICT_KYWD, TQ_RESTRICT_KYWD},
+ };
+#define NKEYWORD (sizeof (keytbl)/sizeof (keyword_t))
+
+ int i;
+
+ for (i = 0; i < NKEYWORD; ++i) {
+ char *s = keytbl[i].name;
+
+ if ((*s == *name) && (strcmp(s, name) == 0))
+ return (&keytbl[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * lookup_sttpair - Given an stt_t return a string or NULL.
+ *
+ */
+
+static const char *
+lookup_sttpair(stt_t s) {
+ /* valid type specifier combinations */
+ static const sttpair_t stttbl[] = {
+ { TS_VOID, "void" },
+ { TS_CHAR, "char" },
+ { TS_SIGNED | TS_CHAR, "signed char" },
+ { TS_UNSIGNED | TS_CHAR, "unsigned char" },
+ { TS_SHORT, "short" },
+ { TS_SIGNED | TS_SHORT, "signed short" },
+ { TS_SHORT | TS_INT, "short int" },
+ { TS_SIGNED | TS_SHORT | TS_INT,
+ "signed short int" },
+ { TS_UNSIGNED | TS_SHORT,
+ "unsigned short" },
+ { TS_UNSIGNED | TS_SHORT | TS_INT,
+ "unsigned short int" },
+ { TS_INT, "int" },
+ { TS_SIGNED, "signed" },
+ { TS_SIGNED | TS_INT, "signed int" },
+ { TS_NO_TS, "" },
+ { TS_UNSIGNED, "unsigned" },
+ { TS_UNSIGNED | TS_INT, "unsigned int" },
+ { TS_LONG, "long" },
+ { TS_SIGNED | TS_LONG, "signed long" },
+ { TS_LONG | TS_INT, "long int" },
+ { TS_SIGNED | TS_LONG | TS_INT,
+ "signed long int" },
+ { TS_UNSIGNED | TS_LONG, "unsigned long" },
+ { TS_UNSIGNED | TS_LONG | TS_INT,
+ "unsigned long int" },
+ { TS_FLOAT, "float" },
+ { TS_DOUBLE, "double" },
+ { TS_LONG | TS_DOUBLE, "long double" },
+ { TS_STRUCT, "struct" },
+ { TS_UNION, "union" },
+ { TS_ENUM, "enum" },
+ { TS_TYPEDEF, "" },
+ /* non-ANSI type: long long */
+ { TS_LONGLONG, "long long" },
+ { TS_LONGLONG | TS_INT, "long long int" },
+ { TS_SIGNED | TS_LONGLONG,
+ "signed long long" },
+ { TS_UNSIGNED | TS_LONGLONG,
+ "unsigned long long" },
+ { TS_SIGNED | TS_LONGLONG | TS_INT,
+ "signed long long int" },
+ { TS_UNSIGNED | TS_LONGLONG | TS_INT,
+ "unsigned long long int" },
+ };
+
+#define NDECLSPEC (sizeof (stttbl)/sizeof (sttpair_t))
+
+ int i;
+
+ for (i = 0; i < NDECLSPEC; ++i)
+ if (s == stttbl[i].s_stt)
+ return (stttbl[i].s_str);
+
+ return (NULL);
+}
+
+/*
+ * yylex - return next token from the the input stream.
+ *
+ * The lexical analyzer does not recognize all possible C lexical
+ * elements. It only recognizes those associated with function
+ * declarations (read: prototypes) and data definitions.
+ */
+
+static int
+yylex(void) {
+ char buf[BUFSIZ]; /* string version of token */
+ int c;
+ int i = 0;
+
+restart:
+ skipwhitespace();
+
+ switch (c = getch()) {
+ case '/':
+ if (lookahead('*')) {
+ skipcomment();
+ goto restart;
+ }
+
+ case '.':
+ if (lookahead('.')) {
+ if (lookahead('.'))
+ return (ELLIPSIS);
+ }
+
+ case EOF:
+ case '(':
+ case ')':
+ case ',':
+ case '[':
+ case ']':
+ case ';':
+ case '*':
+ return (c);
+
+ default:
+ if ((c == '_') || isalpha(c)) {
+ const keyword_t *kp;
+
+ do {
+ buf[i++] = c;
+ c = getch();
+ } while ((c == '_') || isalnum(c));
+
+ ungetch(c);
+
+ buf[i] = '\0';
+
+ if ((kp = lookup_keyword(buf)) != NULL) {
+ yylval.stt_val = kp->stt;
+ return (kp->token);
+ } else {
+ yylval.s_val = strdup(buf);
+
+ return ((atIDENT) ? IDENTIFIER : TYPEDEF_NAME);
+ }
+ } else if (isdigit(c)) {
+ do {
+ buf[i++] = c;
+ } while (isdigit(c = getch()));
+
+ ungetch(c);
+
+ buf[i] = '\0';
+ yylval.s_val = strdup(buf);
+
+ return (INTEGER);
+ } else
+ return (c);
+ }
+/* NOTREACHED */
+}
+
+/* getch - return the next character from the input stream. */
+
+static int
+getch(void) {
+ int c;
+
+ if ((c = *input) == '\0')
+ c = EOF;
+ else /* only advance on non-NULL */
+ input++;
+
+ return (c);
+}
+
+/* ungetch - return a character to the input stream. */
+
+static void
+ungetch(int c) {
+ *(--input) = c;
+}
+
+/* skipwhitespace - skip over whitespace in the input stream. */
+
+static void
+skipwhitespace(void) {
+ int c;
+
+ while (isspace(c = getch()))
+ ;
+
+ ungetch(c);
+}
+
+/* skipcomment - scan ahead to the next end of comment. */
+
+static void
+skipcomment(void) {
+ loop {
+ int c;
+
+ switch (c = getch()) {
+ case EOF:
+ return;
+
+ case '*':
+ if (lookahead('/'))
+ return;
+ }
+ }
+/* NOTREACHED */
+}
+
+/* lookahead - does next character match 'c'? */
+
+static int
+lookahead(int c) {
+ int ch = getch();
+ int match;
+
+ if (!(match = (ch == c)))
+ ungetch(ch);
+
+ return (match);
+}
+
+/* putNtabs - write N '\t' to standard output. */
+
+#if defined(DEBUG)
+
+static void
+putNTabs(int n) {
+ int i;
+
+ for (i = 0; i < n; ++i)
+ putchar('\t');
+}
+#endif /* DEBUG */
+
+/* D E C L A R A T I O N S P E C I F I E R S */
+
+/*
+ * Declaration specifiers encode storage class, type specifier and type
+ * qualifier information. This includes any identifiers associated with
+ * struct, union or enum declarations. Typedef names are also encoded
+ * in declaration specifiers.
+ */
+
+/* declspec_Construct - allocate and initialize a declspec_t. */
+
+static decl_spec_t *
+declspec_Construct(void) {
+ decl_spec_t *dsp = malloc(sizeof (decl_spec_t));
+
+ assert(dsp != NULL);
+ dsp->ds_stt = SCS_NONE | TS_NO_TS | TQ_NONE;
+ dsp->ds_id = NULL;
+#if defined(MEM_DEBUG)
+ ++declspec_Construct_calls;
+#endif
+ return (dsp);
+}
+
+/* declspec_Destroy - free a declspec_t. */
+
+static void
+declspec_Destroy(decl_spec_t *dsp) {
+ free(dsp->ds_id);
+ free(dsp);
+#if defined(MEM_DEBUG)
+ --declspec_Construct_calls;
+#endif
+}
+
+/*
+ * declspec_Init - allocate and initialize a declspec_t given an
+ * stt_t and identifier.
+ *
+ * Note:
+ * 1) identifier can be NULL.
+ * 2) errors resulting in the stt_t and identifier are ignored.
+ */
+
+static decl_spec_t *
+declspec_Init(stt_t s, char *tagp) {
+ const char *p;
+ decl_spec_t *dsp = declspec_Construct();
+ decl_spec_t tmp;
+
+ tmp.ds_stt = s;
+ tmp.ds_id = tagp;
+
+ declspec_AddDS(dsp, &tmp, &p); /* XXX ignore any error */
+
+ return (dsp);
+}
+
+/*
+ * declspec_VerifySTT - verify that the two given stt_t can be combined.
+ *
+ * Note:
+ * 1) The return value is a const char *, non-NULL to indicate an error.
+ */
+
+static char *
+declspec_VerifySTT(stt_t s1, stt_t s2) {
+ stt_t result;
+
+ if ((s1 | s2) != (s1 ^ s2))
+ return ("attempt to add declaration specifier "
+ "that is already present");
+
+ result = (s1 | s2) & TS_MASK;
+
+ if (lookup_sttpair(result) == NULL) {
+ if (STT_isbasic(result) && STT_isderived(result))
+ return ("attempt to combine basic and "
+ "derived types");
+
+ if (STT_isvoid(result) &&
+ (STT_isbasic(result) || STT_isderived(result)))
+ return ("attempt to combine void with "
+ "other type specifiers");
+
+ if (STT_isfloat(result) && STT_isint(result))
+ return ("attempt to combine floating and "
+ "integer type specifiers");
+
+ if (STT_ischar(result) && STT_isint(result))
+ return ("attempt to combine character and "
+ "integer type specifiers");
+
+ if (STT_has_explicit_sign(result) &&
+ (STT_isfloat(result) || STT_isderived(result)))
+ return ("attempt to combine signed or "
+ "unsigned with float or derived type");
+
+ return ("invalid declaration specifier");
+ }
+
+ return (NULL);
+}
+
+/*
+ * declspec_AddSTT - add an stt_t to a decl_spec_t.
+ *
+ * Note:
+ * 1) The "long long" type is handled here.
+ * If both stt_t include TS_LONG then this is an attempt to use
+ * "long long". The TS_LONG is cleared from the s1 and s2 and
+ * then TS_LONGLONG is added to s2. The resulting s1 and s2 are
+ * passed to declspec_VerifySTT to determine if the result is valid.
+ *
+ * 2) This method of handling "long long" does detect the case of
+ * "long double long" and all it's variant forms.
+ */
+
+static decl_spec_t *
+declspec_AddSTT(decl_spec_t *dsp, stt_t s2, const char **err) {
+ stt_t s1 = dsp->ds_stt;
+
+ /* non-ANSI type: long long */
+ if ((s1 & TS_LONG) && (s2 & TS_LONG)) {
+ s1 &= ~(TS_LONG);
+ dsp->ds_stt = s1;
+ s2 &= ~(TS_LONG);
+ s2 |= TS_LONGLONG;
+ }
+
+ if ((*err = declspec_VerifySTT(s1, s2)) == NULL)
+ dsp->ds_stt |= s2;
+
+ return (dsp);
+}
+
+/*
+ * declpec_AddDS - add a decl_spec_t to an existing decl_spec_t.
+ */
+
+static decl_spec_t *
+declspec_AddDS(decl_spec_t *dsp, decl_spec_t *tsp, const char **err) {
+ declspec_AddSTT(dsp, tsp->ds_stt, err);
+
+ if ((*err == NULL) && tsp->ds_id) {
+ free(dsp->ds_id);
+ dsp->ds_id = strdup(tsp->ds_id);
+
+ assert(dsp->ds_id != NULL);
+ }
+
+ return (dsp);
+}
+
+/*
+ * declspec_GetSTT - return the stt_t within a decl_spec_t.
+ */
+
+static stt_t
+declspec_GetSTT(decl_spec_t *dsp) {
+ return (dsp->ds_stt);
+}
+
+/*
+ * declspec_GetTag - return the identifier within a decl_spec_t.
+ */
+
+static char *
+declspec_GetTag(decl_spec_t *dsp) {
+ return (dsp->ds_id);
+}
+
+/*
+ * declspec_ToString - convert a decl_spec_t into a string.
+ *
+ * Note:
+ * 1) The form of the resulting string is always the same, i.e.
+ *
+ * [register] [type_specifier] [const] [volatile]
+ *
+ * dsp must be correct
+ *
+ */
+
+char *
+declspec_ToString(char *bufp, decl_spec_t *dsp) {
+ const char *s;
+ int something = 0;
+
+ *bufp = '\0';
+
+ /* storage class specifier */
+ switch (dsp->ds_stt & SCS_MASK) {
+ case SCS_REGISTER:
+ strcat(bufp, "register");
+ something = 1;
+ break;
+ }
+
+ s = lookup_sttpair(dsp->ds_stt & TS_MASK);
+
+ /* type specifier */
+ switch (dsp->ds_stt & TS_MASK) {
+ case TS_STRUCT:
+ case TS_UNION:
+ case TS_ENUM:
+ if (something)
+ strcat(bufp, " ");
+
+ strcat(bufp, s);
+ strcat(bufp, " ");
+ strcat(bufp, dsp->ds_id);
+ break;
+
+ case TS_TYPEDEF:
+ if (something)
+ strcat(bufp, " ");
+
+ strcat(bufp, dsp->ds_id);
+ break;
+
+ default:
+ if (something)
+ strcat(bufp, " ");
+
+ strcat(bufp, s);
+ break;
+ }
+
+ if (s)
+ something = 1;
+
+ if (something && (dsp->ds_stt & TQ_MASK))
+ strcat(bufp, " ");
+
+ if (dsp->ds_stt & TQ_CONST) /* type qualifier */
+ strcat(bufp, "const");
+
+ if (dsp->ds_stt & TQ_VOLATILE) {
+ if (dsp->ds_stt & TQ_CONST)
+ strcat(bufp, " ");
+
+ strcat(bufp, "volatile");
+ }
+
+ /*
+ * It currently acknowledges and ignores restrict or _RESTRICT_KYWD
+ * in code generation because of the uncertain behavior of "restrict".
+ */
+ if (dsp->ds_stt & TQ_RESTRICT)
+ strcat(bufp, "");
+
+ if (dsp->ds_stt & TQ_RESTRICT_KYWD)
+ strcat(bufp, "");
+
+ return (bufp);
+}
+
+/* T Y P E M O D I F I E R S */
+
+/*
+ * Type modifiers encode the "array of...", "pointer to ..." and
+ * "function returning ..." aspects of C types. The modifiers are kept
+ * as a linked list in precedence order. The grammar encodes the
+ * precedence order described by the standard.
+ *
+ * Type modifiers are always added at the end of list and the list is
+ * always traversed from head to tail.
+ */
+
+/* type_Construct - allocate and initialize a type_t. */
+
+static type_t *
+type_Construct(void) {
+ type_t *tp = malloc(sizeof (type_t));
+
+ assert(tp != NULL);
+
+ tp->t_next = NULL; /* generic */
+ tp->t_dt = DD_NONE;
+
+ tp->t_nargs = 0; /* DD_FUN */
+ tp->t_ellipsis = 0;
+ tp->t_args = NULL;
+ /* DD_PTR */
+ tp->t_stt = (SCS_NONE | TS_NO_TS | TQ_NONE);
+
+ tp->t_sizestr = NULL; /* DD_ARY */
+#if defined(MEM_DEBUG)
+ ++type_Construct_calls;
+#endif
+ return (tp);
+}
+
+/* type_Destroy - free a type_t list. */
+
+static void
+type_Destroy(type_t *tp) {
+ while (tp) {
+ type_t *nextp = tp->t_next;
+
+ switch (tp->t_dt) {
+ case DD_FUN:
+ decl_Destroy(tp->t_args);
+ break;
+
+ case DD_PTR:
+ break;
+
+ case DD_ARY:
+ free(tp->t_sizestr);
+ break;
+ }
+
+ free(tp);
+
+ tp = nextp;
+#if defined(MEM_DEBUG)
+ --type_Construct_calls;
+#endif
+ }
+}
+
+/*
+ * type_SetPtr - make a type_t into a "pointer to ..." variant.
+ *
+ * Note:
+ * 1) The stt_t will encode any type qualifiers (const, volatile).
+ */
+
+static type_t *
+type_SetPtr(type_t *tp, stt_t s) {
+ assert(tp->t_dt == DD_NONE);
+
+ tp->t_dt = DD_PTR;
+ tp->t_stt = s & TQ_MASK;
+
+ return (tp);
+}
+
+/*
+ * type_SetAry - make a type_t into an "array of ...", variant.
+ *
+ * Note:
+ * 1) The array dimension can be NULL to indicate undefined, i.e. [].
+ */
+
+static type_t *
+type_SetAry(type_t *tp, char *dim) {
+ assert(tp->t_dt == DD_NONE);
+ assert(tp->t_sizestr == NULL);
+
+ tp->t_dt = DD_ARY;
+
+ if (dim) {
+ tp->t_sizestr = strdup(dim);
+ assert(tp->t_sizestr != NULL);
+ } else
+ tp->t_sizestr = NULL;
+
+ return (tp);
+}
+
+/*
+ * type_SetFun - make a type_t into a "function returning ..." variant.
+ *
+ * Note:
+ * 1) The argument list can be NULL to indicate undefined, i.e. ().
+ */
+
+static type_t *
+type_SetFun(type_t *tp, decl_t *arglist) {
+ assert(tp->t_dt == DD_NONE);
+
+ tp->t_dt = DD_FUN;
+
+ if (arglist) {
+ tp->t_nargs = decl_GetArgLength(arglist);
+ tp->t_args = arglist;
+ tp->t_ellipsis = arglist->d_ellipsis;
+ }
+
+ return (tp);
+}
+
+/*
+ * type_AddTail - add a type_t to the end of an existing type_t list.
+ *
+ * Note:
+ * 1) The type_t *tp is added to the end of the type_t *dp list.
+ */
+
+static type_t *
+type_AddTail(type_t *dp, type_t *tp) {
+ type_t *lastp = dp;
+ type_t *p;
+
+ while (p = lastp->t_next)
+ lastp = p;
+
+ lastp->t_next = tp;
+
+ return (dp);
+}
+
+#if defined(DEBUG)
+
+/* type_PrintType - print a type_t list onto standard output. */
+
+static void
+type_PrintType(type_t *tp, int lvl) {
+ decl_spec_t tmp;
+ char buf[BUFSIZ];
+
+ while (tp) {
+ putNTabs(lvl);
+
+ switch (tp->t_dt) {
+ case DD_PTR:
+ tmp.ds_stt = tp->t_stt;
+ tmp.ds_id = NULL;
+
+ printf("[%s] ptr to\n", declspec_ToString(buf, &tmp));
+ break;
+
+ case DD_FUN:
+ printf("fun [%d%c] %s\n",
+ tp->t_nargs,
+ (tp->t_ellipsis)? '+' : '=',
+ (tp->t_args)? "with arguments" :
+ "undefined arguments");
+
+ if (tp->t_args) {
+ decl_PrintDecl(tp->t_args, lvl + 1);
+
+ if (tp->t_ellipsis) {
+ putNTabs(lvl + 1);
+ printf("...\n");
+ }
+ }
+ break;
+
+ case DD_ARY:
+ printf("ary [%s] of\n",
+ (tp->t_sizestr)? tp->t_sizestr : "");
+ break;
+ }
+
+ tp = tp->t_next;
+ }
+}
+#endif /* DEBUG */
+
+/*
+ * type_Verify - verify a type_t list for semantic correctness.
+ *
+ * Note:
+ * 1) C supports most combinations of type modifiers.
+ * It does not support three combinations, they are:
+ *
+ * function returning array
+ * array of functions
+ * function returning function
+ *
+ * 2) The enum values associated with type modifiers (i.e. DD_*)
+ * cannot be modified without changing the table included within the
+ * function.
+ *
+ * 3) The function returns NULL to indicate that the type modifier
+ * list is valid and non-NULL to indicate an error.
+ *
+ * 4) A type_t of NULL is permitted to indicate an empty type_t list.
+ */
+
+static const char *
+type_Verify(type_t *tp) {
+ static const char *dttbl[4][4] = {
+ /* NONE ARY FUN PTR */
+/* NONE */ {NULL, NULL, NULL, NULL},
+/* ARY */ {NULL, NULL, "array of functions", NULL},
+/* FUN */ {NULL, "function returning array",
+ "function returning function", NULL},
+/* PTR */ {NULL, NULL, NULL, NULL},
+ };
+
+ if (tp) {
+ type_t *nextp;
+
+ do {
+ const char *p;
+ decl_type_t nt;
+
+ nt = (nextp = tp->t_next)? nextp->t_dt : DD_NONE;
+
+ if ((p = dttbl[tp->t_dt][nt]) != NULL)
+ return (p);
+
+ } while (tp = nextp);
+ }
+
+ return (NULL);
+}
+
+/* type_GetNext - return the next type_t in the list. */
+
+type_t *
+type_GetNext(type_t *tp) {
+ return (tp->t_next);
+}
+
+/*
+ * The following group of functions return and or
+ * test various aspects of type modifiers.
+ *
+ * 1) The three functions: type_IsPtrTo, type_IsFunction and
+ * type_IsArray will accept an argument of NULL.
+ *
+ * 2) All other functions require one of the above three to be true.
+ * Various asserts are in place to verify correct usage.
+ */
+
+int
+type_IsArray(type_t *tp) {
+ return (tp && (tp->t_dt == DD_ARY));
+}
+
+char *
+type_GetArraySize(type_t *tp) {
+ assert(tp->t_dt == DD_ARY);
+
+ return (tp->t_sizestr);
+}
+
+int
+type_IsPtrTo(type_t *tp) {
+ return (tp && (tp->t_dt == DD_PTR));
+}
+
+stt_t
+type_GetPtrToTypeQual(type_t *tp) {
+ assert(tp->t_dt == DD_PTR);
+
+ return (tp->t_stt);
+}
+
+int
+type_IsFunction(type_t *tp) {
+ return (tp && (tp->t_dt == DD_FUN));
+}
+
+int
+type_GetArgLength(type_t *tp) {
+ assert(tp->t_dt == DD_FUN);
+
+ return (tp->t_nargs);
+}
+
+int
+type_IsVarargs(type_t *tp) {
+ while (tp && tp->t_dt == DD_PTR)
+ tp = tp->t_next;
+
+ assert(tp->t_dt == DD_FUN);
+
+ return (tp->t_ellipsis);
+}
+
+decl_t *
+type_GetArg(type_t *tp) {
+ assert(tp->t_dt == DD_FUN);
+
+ return (tp->t_args);
+}
+
+/*
+ * type_IsPtrFun - determine if the type_t results in a call-able function.
+ *
+ * Note:
+ * 1) The argument can be NULL.
+ *
+ * 2) The test is true if the type_t list is number of DD_PTR followed
+ * by a DD_FUN.
+ */
+
+int
+type_IsPtrFun(type_t *tp) {
+
+ if (! (tp && (tp->t_dt == DD_PTR)))
+ return (0);
+
+ tp = tp->t_next;
+
+ while (tp && (tp->t_dt == DD_PTR))
+ tp = tp->t_next;
+
+ return (tp && (tp->t_dt == DD_FUN));
+}
+
+/* D E C L A R A T O R */
+
+/*
+ * A decl_t encodes the name,
+ * declaration specifiers and type modifiers of an object.
+ */
+
+/* decl_Construct - allocate a decl_t. */
+
+static decl_t *
+decl_Construct(void) {
+ decl_t *dp = malloc(sizeof (decl_t));
+
+ assert(dp != NULL);
+
+ dp->d_name = NULL;
+ dp->d_type = NULL;
+ dp->d_next = NULL;
+ dp->d_ds = declspec_Construct();
+ dp->d_ellipsis = 0;
+#if defined(MEM_DEBUG)
+ ++decl_Construct_calls;
+#endif
+ return (dp);
+}
+
+/* decl_Destroy - free a decl_t list. */
+
+void
+decl_Destroy(decl_t *dp) {
+ while (dp) {
+ decl_t *nextp = dp->d_next;
+
+ type_Destroy(dp->d_type);
+ declspec_Destroy(dp->d_ds);
+ free(dp->d_name);
+ free(dp);
+
+ dp = nextp;
+#if defined(MEM_DEBUG)
+ --decl_Construct_calls;
+#endif
+ }
+}
+
+/*
+ * decl_GetArgLength - return the length of a decl_t list.
+ *
+ * Note:
+ * 1) The argument may be NULL to indicate an empty list, len == 0.
+ */
+
+int
+decl_GetArgLength(decl_t *dp) {
+ int len;
+
+ for (len = 0; dp; dp = dp->d_next)
+ ++len;
+
+ return (len);
+}
+
+/*
+ * The following group of functions get or test various aspects of a decl_t.
+ */
+
+decl_t *
+decl_GetNext(decl_t *dp) {
+ return (dp->d_next);
+}
+
+stt_t
+decl_GetDeclSpec(decl_t *dp) {
+ return (declspec_GetSTT(dp->d_ds));
+}
+
+char *
+decl_GetDSName(decl_t *dp) {
+ return (declspec_GetTag(dp->d_ds));
+}
+
+type_t *
+decl_GetType(decl_t *dp) {
+ return (dp->d_type);
+}
+
+int
+decl_IsVarargs(decl_t *dp) {
+ return (dp->d_ellipsis);
+}
+
+int
+decl_IsFunction(decl_t *dp) {
+ return (type_IsFunction(dp->d_type));
+}
+
+char *
+decl_GetName(decl_t *dp) {
+ return (dp->d_name);
+}
+
+/*
+ * decl_AddArg - add a decl_t to the end of an decl_t list.
+ */
+
+static decl_t *
+decl_AddArg(decl_t *dp, decl_t *tp) {
+ decl_t *lastp = dp;
+ decl_t *p;
+
+ while (p = lastp->d_next)
+ lastp = p;
+
+ lastp->d_next = tp;
+
+ return (dp);
+}
+
+/*
+ * decl_IsVoid - return true if the decl_t is a "pure" void declaration.
+ */
+
+static int
+decl_IsVoid(decl_t *dp) {
+ return ((declspec_GetSTT(dp->d_ds) & TS_VOID) && (dp->d_type == NULL));
+}
+
+/*
+ * decl_IsVoidArray - return true if the decl_t includes "void []".
+ */
+
+static int
+decl_IsVoidArray(decl_t *dp) {
+ int retval = 0;
+ type_t *tp = dp->d_type;
+
+ if (tp) {
+ type_t *np;
+
+ while (np = type_GetNext(tp))
+ tp = np;
+
+ retval = type_IsArray(tp) &&
+ (declspec_GetSTT(dp->d_ds) & TS_VOID);
+ }
+
+ return (retval);
+}
+
+/*
+ * decl_Verify - verify a decl_t.
+ */
+
+static const char *
+decl_Verify(decl_t *dp) {
+ const char *ep = NULL;
+
+ if (decl_IsVoid(dp))
+ ep = "type is void";
+ else if (decl_IsVoidArray(dp))
+ ep = "type is void []";
+ else
+ ep = type_Verify(dp->d_type);
+
+ return (ep);
+}
+
+/*
+ * decl_VerifyArgs - verify a decl_t list.
+ */
+
+static const char *
+decl_VerifyArgs(decl_t *dp) {
+ decl_t *tp = dp;
+ const char *ep = NULL;
+
+ if (dp) {
+ int nv = 0;
+ int nargs = decl_GetArgLength(dp);
+
+ for (; dp; dp = dp->d_next)
+ if (decl_IsVoid(dp)) {
+ ++nv;
+
+ if (decl_GetName(dp))
+ ep = "argument list includes "
+ "void with identifier";
+ } else if (decl_IsVoidArray(dp))
+ ep = "argument list includes void []";
+
+ if (nv) { /* there was some void */
+ if (nargs > 1)
+ ep = "argument list includes void";
+
+ if (tp->d_ellipsis)
+ ep = "argument list includes void and \"...\"";
+ }
+ }
+
+ return (ep);
+}
+
+/* decl_AddDS - add a decl_spec_t to a decl_t. */
+
+static decl_t *
+decl_AddDS(decl_t *dp, decl_spec_t *dsp, const char **err) {
+ declspec_AddDS(dp->d_ds, dsp, err);
+
+ return (dp);
+}
+
+/*
+ * decl_SetName - set the name associated with a decl_t.
+ *
+ * Note:
+ * 1) Any previously known name is free'd.
+ */
+
+decl_t *
+decl_SetName(decl_t *dp, char *s) {
+ free(dp->d_name);
+ dp->d_name = strdup(s);
+ assert(dp->d_name != NULL);
+
+ return (dp);
+}
+
+/*
+ * decl_AddTypeTail - add a type_t to the end of a decl_t type_t list.
+ */
+
+static decl_t *
+decl_AddTypeTail(decl_t *dp, type_t *tp) {
+ if (dp->d_type)
+ type_AddTail(dp->d_type, tp);
+ else
+ dp->d_type = tp;
+
+ return (dp);
+}
+
+/*
+ * decl_addptr - add a DD_PTR type_t to the end of a decl_t type_t list.
+ */
+
+static decl_t *
+decl_addptr(decl_t *dp, type_t *tp) {
+ decl_AddTypeTail(dp, tp);
+
+ return (dp);
+}
+
+/*
+ * decl_addary - allocate and add a DD_ARY type_t to the end of
+ * a decl_t type_t list.
+ */
+
+static decl_t *
+decl_addary(decl_t *dp, char *sizep) {
+ type_t *tp = type_Construct();
+
+ type_SetAry(tp, sizep);
+ decl_AddTypeTail(dp, tp);
+
+ return (dp);
+}
+
+/*
+ * decl_addfun - allocate and add a DD_FUN type_t to the end of a
+ * decl_t type_t list.
+ */
+
+static decl_t *
+decl_addfun(decl_t *dp, decl_t *arglist) {
+ const char *sp;
+ type_t *tp = type_Construct();
+
+ if (sp = decl_VerifyArgs(arglist))
+ yyerror(sp);
+
+ type_SetFun(tp, arglist);
+ decl_AddTypeTail(dp, tp);
+
+ return (dp);
+}
+
+/*
+ * decl_addellipsis - set the ellipsis state in a decl_t.
+ *
+ * Note:
+ * 1) This function is only used in the grammar in the
+ * parameter list parsing.
+ */
+
+static decl_t *
+decl_addellipsis(decl_t *dp) {
+ dp->d_ellipsis = 1;
+
+ return (dp);
+}
+
+#if defined(DEBUG)
+
+static void
+decl_PrintDecl(decl_t *dp, int lvl) {
+ char buf[BUFSIZ];
+
+ while (dp) {
+ putNTabs(lvl);
+
+ printf("name = %s, ds = %s\n",
+ (dp->d_name)? dp->d_name : "<null>",
+ declspec_ToString(buf, dp->d_ds));
+
+ if (dp->d_type)
+ type_PrintType(dp->d_type, lvl + 1);
+
+ dp = dp->d_next;
+ }
+}
+#endif /* DEBUG */
+
+static char *
+char_getend(char *s) {
+ while (*s != '\0')
+ ++s;
+
+ return (s);
+}
+
+char *
+decl_ToString(char *bufp, decl_dts_t out, decl_t *dp,
+ const char *altname) {
+ char tmp[BUFSIZ];
+ char tmp2[BUFSIZ];
+ const char *namep;
+ char *bend = bufp;
+ type_t *tp = dp->d_type;
+ int ffun = 1;
+
+ switch (out) {
+ default:
+ out = DTS_DECL;
+ /* FALLTHRU */
+ case DTS_DECL:
+ if (altname == NULL) {
+ namep = dp->d_name;
+ } else {
+ namep = altname;
+ }
+ break;
+ case DTS_CAST:
+ namep = "(*)";
+ break;
+ case DTS_RET:
+ if (altname == NULL) {
+ namep = "_return";
+ } else {
+ namep = altname;
+ }
+ break;
+ }
+
+ *bufp = '\0';
+
+ strcpy(tmp, (namep) ? namep : "");
+
+ while (tp) {
+ switch (tp->t_dt) {
+ case DD_PTR:
+ if (tp->t_next &&
+ ((tp->t_next->t_dt == DD_ARY) ||
+ (tp->t_next->t_dt == DD_FUN))) {
+ if (out == DTS_RET) {
+ sprintf(bufp, "(*%s)", namep);
+ } else {
+ sprintf(bufp, "(*%s)", tmp);
+ }
+ } else if (tp->t_stt == TQ_CONST) {
+ sprintf(bufp, "*const %s", tmp);
+ } else if (tp->t_stt == TQ_VOLATILE) {
+ sprintf(bufp, "*volatile %s", tmp);
+ /*
+ * It currently acknowledges and ignores restrict
+ * or _RESTRICT_KYWD in code generation because
+ * of the uncertain behavior of "restrict".
+ */
+ } else if (tp->t_stt == TQ_RESTRICT) {
+ sprintf(bufp, "*%s", tmp);
+ } else if (tp->t_stt == TQ_RESTRICT_KYWD) {
+ sprintf(bufp, "*%s", tmp);
+ } else {
+ sprintf(bufp, "*%s", tmp);
+ }
+
+ break;
+
+ case DD_ARY:
+ sprintf(bufp, "%s[%s]",
+ tmp, (tp->t_sizestr)? tp->t_sizestr : "");
+ break;
+
+ case DD_FUN:
+ if (out == DTS_RET && ffun == 1) {
+ strcpy(bufp, namep);
+ ffun = 0;
+ } else if (tp->t_args == NULL) {
+ sprintf(bufp, "%s()", tmp);
+ } else {
+ char buf2[BUFSIZ];
+ decl_t *argp = tp->t_args;
+
+ sprintf(bufp, "%s(", tmp);
+ bend = char_getend(bufp);
+
+ for (argp = tp->t_args; argp; /* noinc */) {
+ decl_ToString(buf2, DTS_DECL, argp,
+ NULL);
+ sprintf(bend, " %s", buf2);
+
+ bend = char_getend(bend);
+
+ if (argp = argp->d_next) {
+ sprintf(bend, ",");
+ bend = char_getend(bend);
+ }
+ }
+
+ if (tp->t_ellipsis) {
+ sprintf(bend, ", ...");
+ bend = char_getend(bend);
+ }
+
+ sprintf(bend, ")");
+ }
+ break;
+ }
+
+ tp = tp->t_next;
+
+ strcpy(tmp, bufp);
+ }
+
+ if (out == DTS_CAST) {
+ sprintf(bufp, "(%s %s)",
+ declspec_ToString(tmp2, dp->d_ds), tmp);
+ } else {
+ sprintf(bufp, "%s %s",
+ declspec_ToString(tmp2, dp->d_ds), tmp);
+ }
+
+ return (bufp);
+}
+
+decl_t *
+decl_AddArgNames(decl_t *dp) {
+ int argno = 0;
+ decl_t *p = dp;
+
+ if (decl_IsFunction(dp)) {
+ int argno = 0;
+ decl_t *p = dp->d_type->t_args;
+
+ while (p) {
+ char *s = decl_GetName(p);
+
+ if ((s == NULL) && !decl_IsVoid(p)) {
+ char buf[BUFSIZ];
+
+ sprintf(buf, "arg%d", argno);
+ s = strdup(buf);
+ decl_SetName(p, s);
+ }
+
+ p = p->d_next;
+ ++argno;
+ }
+ }
+ return (dp);
+}
+
+const char *
+decl_Parse(char *str, decl_t **dpp) {
+ errstr = NULL; /* setup the (static) globals */
+ input = str;
+ atIDENT = 0;
+ protop = NULL;
+
+ yyparse(); /* parse the prototype */
+
+ if (errstr == NULL) { /* success */
+ *dpp = protop;
+ decl_AddArgNames(protop);
+ } else { /* failure */
+ *dpp = NULL;
+ decl_Destroy(protop);
+ }
+
+ return (errstr);
+}
+
+static void
+yyerror(const char *err) {
+ errstr = err;
+}
+
+#if defined(DEBUG)
+
+/* main */
+
+static int yydebug = 1;
+
+int
+main(int argc, char *argv[]) {
+ int i;
+
+ yydebug = 1;
+
+ for (i = 1; i < argc; ++i) {
+ const char *es;
+ char buf[BUFSIZ];
+ decl_t *pp;
+
+ if (es = decl_Parse(argv[i], &pp))
+ printf("parse failure: %s\n", es);
+ else {
+#if GR_DEBUG
+ decl_PrintDecl(pp, 0);
+ decl_AddArgNames(pp);
+#endif
+ printf("---\n%s;\n",
+ decl_ToString(buf, DTS_DECL, pp, NULL));
+ printf("%s\n",
+ decl_ToString(buf, DTS_CAST, pp, NULL));
+ printf("%s;\n",
+ decl_ToString(buf, DTS_RET, pp, "%s"));
+
+#ifdef TRACE
+ printf("\n\nTrace Info\n");
+ decl_PrintTraceInfo(pp);
+#endif
+ }
+
+ decl_Destroy(pp);
+
+#if defined(MEM_DEBUG)
+ printf("declspec : %d\n", declspec_Construct_calls);
+ printf("type : %d\n", type_Construct_calls);
+ printf("decl : %d\n", decl_Construct_calls);
+#endif
+ }
+
+ return (0);
+}
+
+#ifdef TRACE
+void
+decl_PrintTraceInfo(decl_t *dp) {
+ char buf[BUFSIZ];
+ char f_type[BUFSIZ];
+ char f_print[BUFSIZ];
+ char a_name[BUFSIZ];
+ char a_type[BUFSIZ];
+ char a_print[BUFSIZ];
+ decl_t *funargs;
+ type_t *tp;
+ int isptrfun;
+
+ if (dp == NULL)
+ return;
+
+ fprintf(stderr, "interface = %s\n",
+ (dp->d_name) ? dp->d_name : "<null>");
+
+ isptrfun = type_IsPtrFun(dp->d_type);
+ if (type_IsFunction(dp->d_type) || isptrfun)
+ decl_GetTraceInfo(dp, f_type, f_print, &funargs);
+ else
+ return;
+
+ fprintf(stderr, "return type = %s\n", f_type);
+ fprintf(stderr, "print function = %s\n", f_print);
+
+ if (isptrfun)
+ fprintf(stderr, "function is function pointer\n");
+
+ if (type_IsVarargs(dp->d_type))
+ fprintf(stderr, "function is varargs\n");
+
+ while (funargs) {
+ snprintf(a_type, BUFSIZ, "%s ",
+ declspec_ToString(buf, funargs->d_ds));
+ snprintf(a_print, BUFSIZ, "%s",
+ de_const(declspec_ToString(buf, funargs->d_ds)));
+
+ tp = funargs->d_type;
+
+ while (tp) {
+ if (tp->t_dt == DD_PTR || tp->t_dt == DD_ARY) {
+ strcat(a_type, "*");
+ strcat(a_print, "_P");
+ }
+ tp = tp->t_next;
+ }
+
+ if (funargs->d_name) {
+ snprintf(a_name, BUFSIZ, "%s",
+ funargs->d_name ? funargs->d_name : "<nil>");
+ fprintf(stderr, "arg name = %s\n", a_name);
+ fprintf(stderr, "arg type = %s\n", a_type);
+ fprintf(stderr, "print function = %s\n", a_print);
+ } else {
+ strcpy(a_name, "");
+ strcpy(a_print, "");
+ fprintf(stderr, "arg type = %s\n", a_type);
+ }
+
+ funargs = funargs->d_next;
+ }
+}
+#endif /* TRACE */
+#endif /* DEBUG */
+
+static char *
+de_const(char *str)
+{
+ return (str);
+}
+
+
+void
+decl_GetTraceInfo(decl_t *dp, char *f_type, char *f_print, decl_t **funargs)
+{
+ char buf[BUFSIZ];
+ type_t *tp;
+
+ if (dp == NULL)
+ return;
+
+ snprintf(f_type, BUFSIZ, "%s ",
+ declspec_ToString(buf, dp->d_ds));
+ snprintf(f_print, BUFSIZ, "%s",
+ de_const(declspec_ToString(buf, dp->d_ds)));
+ tp = dp->d_type;
+ while (tp) {
+ if (tp->t_dt == DD_PTR) {
+ strcat(f_type, "*");
+ strcat(f_print, "*");
+ }
+ tp = tp->t_next;
+ }
+
+ strcat(f_type, "%s");
+
+ tp = decl_GetType(dp);
+ if (type_IsPtrFun(tp)) {
+ while (tp->t_dt != DD_FUN)
+ tp = tp->t_next;
+ *funargs = tp->t_args;
+ } else {
+ *funargs = dp->d_type->t_args;
+ }
+}
+
+char *
+decl_ToFormal(decl_t *dp)
+{
+ char tmp[BUFSIZ];
+ static char bufp[BUFSIZ];
+ char *bend;
+ type_t *tp = dp->d_type;
+
+ tmp[0] = 0;
+ bufp[0] = 0;
+ bend = bufp;
+
+ while (tp) {
+ switch (tp->t_dt) {
+ case DD_ARY:
+ sprintf(bufp, "%s[%s]", tmp,
+ (tp->t_sizestr)? tp->t_sizestr : "");
+ break;
+
+ case DD_FUN:
+ if (tp->t_args != NULL) {
+ char buf2[BUFSIZ];
+ decl_t *argp = tp->t_args;
+
+ bend = char_getend(bufp);
+
+ for (argp = tp->t_args; argp; /* noinc */) {
+ decl_ToString(buf2, DTS_DECL, argp,
+ NULL);
+ sprintf(bend, " %s", buf2);
+
+ bend = char_getend(bend);
+
+ if (argp = argp->d_next) {
+ sprintf(bend, ",");
+ bend = char_getend(bend);
+ }
+ }
+ if (tp->t_ellipsis) {
+ sprintf(bend, ", ...");
+ bend = char_getend(bend);
+ }
+
+ sprintf(bend, "");
+ }
+ break;
+ }
+
+ tp = tp->t_next;
+
+ strcpy(tmp, bufp);
+ }
+
+ sprintf(bufp, "%s", tmp);
+
+ return (bufp);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c b/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c
new file mode 100644
index 0000000000..22dea8d903
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.c
@@ -0,0 +1,313 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "db.h"
+#include "symtab.h"
+#include "io.h"
+#include "printfuncs.h"
+#include "errlog.h"
+
+static int prepare_printf_part(ENTRY *, char *, char *, int);
+static char *space_to_uscore(char const *);
+
+static char arglist[_POSIX_ARG_MAX];
+
+/*
+ * generate_printf -- make the cleanest possible printf for the
+ * parameters, in a relatively terse apptrace/dbx-like format,
+ * ending in ") = ", or ) if its a void function we're doing.
+ */
+void
+generate_printf(ENTRY *f)
+{
+ ENTRY *e;
+ char *p, *name;
+ int l, n;
+
+ errlog(BEGIN, "generate_printf");
+ (void) fprintf(Bodyfp, " fprintf(ABISTREAM, \"");
+ p = &arglist[0];
+ l = (int)sizeof (arglist);
+ *p = NULL;
+ for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
+ errlog(TRACING, "arglist = '%s'", arglist);
+
+ if (is_void(e)) {
+ /* This placeholder means there are no real args. */
+ break;
+ }
+ /* Insert punctuation. */
+ if (p != &arglist[0]) {
+ (void) fprintf(Bodyfp, ", ");
+ }
+ if (*(name = name_of(e)) == NULL) {
+ /* It's a varargs indicator instead */
+ (void) fprintf(Bodyfp, "...");
+ } else {
+ (void) fprintf(Bodyfp, "%s = ", name);
+ n = prepare_printf_part(e, name, p, l);
+ l -= n;
+ p += n;
+ *(p+1) = NULL;
+ }
+ }
+
+ if (is_void(f) || symtab_get_nonreturn() == YES) {
+ /* It is a function returning void, or a function */
+ /* which doesn't return. Close off args. */
+ (void) fprintf(Bodyfp, ")\"");
+ } else {
+ /* Make some more printf for the return type. */
+ (void) fprintf(Bodyfp, ") = ");
+ (void) prepare_printf_part(f, "_return", p, l);
+ (void) fprintf(Bodyfp, "\"");
+
+ }
+ (void) fprintf(Bodyfp, "%s);\n", arglist);
+ errlog(END, "}");
+}
+
+
+/*
+ * prepare_printf_part -- do one element of a printf/argument string,
+ * for printing non-verbose parameter lists
+ */
+static int
+prepare_printf_part(ENTRY *e, char *name, char *place, int size)
+{
+ char *bt;
+ int li;
+
+ errlog(BEGIN, "prepare_printf_part() {");
+ errlog(TRACING, "name = '%s'", name);
+
+ bt = basetype_of(e);
+ li = levels_of(e);
+
+ if (li == 1 && (strcmp(bt, "char") == 0)) {
+ /* It's a string, print the beginning of it. */
+ (void) fputs("\\\"%.*s\\\"", Bodyfp);
+ size = snprintf(place, size,
+ /*CSTYLED*/
+ ",\n\tabi_strpsz, (%s) ? %s : nilstr",
+ name, name);
+ } else {
+ /* Just print a hex value */
+ (void) fprintf(Bodyfp, "%s", "0x%p");
+ size = snprintf(place, size, ", \n\t%s", name);
+ }
+
+ errlog(TRACING, "place='%s'\n", place);
+ errlog(END, "}");
+ return (size);
+
+}
+
+
+/*
+ * generate_printfunc_calls -- generate print commands for primitive types
+ * and calls to print functions for composite types, cleanly.
+ * Needs to know about base types of primitives, difference
+ * between primitives and composite types: TBD.
+ */
+void
+generate_printfunc_calls(ENTRY *f)
+{
+ ENTRY *e;
+ char *name;
+ char *pf_str_name;
+ int li;
+ char *format;
+
+ errlog(BEGIN, "generate_printfunc_calls() {");
+ for (e = symtab_get_first_arg(); e != NULL; e = symtab_get_next_arg()) {
+ if (is_void(e)) {
+ break;
+ }
+ if (*(name = name_of(e)) == NULL) {
+ (void) fprintf(Bodyfp, " fputs(\" ...\\n\", "
+ "ABISTREAM);\n");
+ }
+ errlog(TRACING, "name = '%s'\n", name);
+ (void) fprintf(Bodyfp,
+ " fprintf(ABISTREAM, \" %s = \");\n",
+ name);
+
+ pf_str_name = space_to_uscore(basetype_of(e));
+
+ /*
+ * If we're dealing with a scalar (non-pointer) then
+ * we need to call the printer with a &
+ */
+ li = levels_of(e);
+ if (li)
+ format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
+ "(void const *)%s);\n";
+ else
+ format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
+ "(void const *)&%s);\n";
+
+ (void) fprintf(Bodyfp, format, pf_str_name, li, name);
+
+ free(pf_str_name);
+ }
+
+ if (is_void(f)) {
+ /*EMPTY*/;
+ } else {
+ pf_str_name = space_to_uscore(basetype_of(f));
+
+ li = levels_of(f);
+ if (li)
+ format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
+ "(void const *)_return);\n";
+ else
+ format = "\tspf_prtype(ABISTREAM, pf_%s_str, %d, "
+ "(void const *)&_return);\n";
+
+ (void) fputs(" fputs(retstr, ABISTREAM);\n", Bodyfp);
+ (void) fprintf(Bodyfp, format, pf_str_name, li);
+
+ free(pf_str_name);
+ }
+
+ errlog(END, "}");
+}
+
+
+/*
+ * Print Function Pointers -- definition, declaration and initialization.
+ * Use is above...
+ */
+
+/*
+ * generate_print_definitions -- generate variable definitions and
+ * initialize them to NULL.
+ * These will be set non-null by a lazy evaluation in the
+ * main.c file if and only if the print function will be used.
+ * All print functions which can be called must be defined.
+ */
+void
+generate_print_definitions(FILE *fp)
+{
+ char *print_type,
+ *c_type,
+ *pf_str_name;
+
+ errlog(BEGIN, "generate_print_definitions() {");
+ for (print_type = db_get_first_print_type();
+ print_type != NULL;
+ print_type = db_get_next_print_type()) {
+ c_type = strchr(print_type, ','); /* Safe by construction. */
+ *c_type++ = NULL;
+ errlog(TRACING, "print_type=%s\n", print_type);
+
+ pf_str_name = space_to_uscore(print_type);
+
+ (void) fprintf(fp,
+ "char const *pf_%s_str = \"%s\";\n",
+ pf_str_name, print_type);
+
+ free(pf_str_name);
+
+ *--c_type = ',';
+ }
+
+ errlog(END, "}");
+}
+
+/*
+ * generate_print_declarations -- generate variable declarations
+ * for the strings that'll be used as arguments to the type
+ * printing function.
+ */
+void
+generate_print_declarations(FILE *fp)
+{
+ char *print_type,
+ *c_type,
+ *pf_str_name;
+
+ errlog(BEGIN, "generate_print_declarations() {");
+ for (print_type = symtab_get_first_print_type();
+ print_type != NULL;
+ print_type = symtab_get_next_print_type()) {
+
+ errlog(TRACING, "print_type, c_type=%s\n", print_type);
+
+ c_type = strchr(print_type, ','); /* Safe by construction. */
+ *c_type++ = NULL;
+
+ pf_str_name = space_to_uscore(print_type);
+
+ (void) fprintf(fp, "extern char const *pf_%s_str;\n",
+ pf_str_name);
+
+ free(pf_str_name);
+
+ *--c_type = ',';
+ }
+
+ errlog(END, "}");
+}
+
+/*
+ * is_void -- see if a type is void.
+ */
+int
+is_void(ENTRY *e)
+{
+ if ((e != NULL) &&
+ levels_of(e) == 0 && (strcmp(basetype_of(e), "void") == 0))
+ return (1);
+ else
+ return (0);
+}
+
+static char *
+space_to_uscore(char const *str)
+{
+ char *strp, *p;
+
+ strp = strdup(str);
+
+ assert(strp != NULL, "strdup failed");
+
+ for (p = strp; *p != '\0'; p++)
+ if (*p == ' ')
+ *p = '_';
+
+ return (strp);
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h b/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h
new file mode 100644
index 0000000000..87cd9881be
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/printfuncs.h
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _PRINTFUNCS_H
+#define _PRINTFUNCS_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Types */
+enum { CHAR, SHORT, UNSIGNED_SHORT, INT, UNSIGNED, LONG, UNSIGNED_LONG,
+ CHAR_P, POINTER, FLOAT, LONG_LONG, UNSIGNED_LONG_LONG, VOID_,
+ NONPRIMITIVE};
+
+void generate_printf(ENTRY *);
+
+/* Define, declare, initialize and use pointers to printfuncs. */
+void generate_print_definitions(FILE *);
+void generate_print_declarations(FILE *);
+void generate_print_initializations(void);
+void generate_printfunc_calls(ENTRY *); /* Use. */
+
+int is_void(ENTRY *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PRINTFUNCS_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile b/usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile
new file mode 100644
index 0000000000..423e916f3e
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/sparc/Makefile
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+# 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
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 1997-1999 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/abi/daa2x/spec2truss/sparc/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/symtab.c b/usr/src/cmd/abi/spectrans/spec2trace/symtab.c
new file mode 100644
index 0000000000..9eba8969bb
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/symtab.c
@@ -0,0 +1,919 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <malloc.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "symtab.h"
+#include "errlog.h"
+
+/* Types */
+enum kind_t { PRIMITIVE = 0, COMPOSITE, VARARG };
+
+struct entry_t {
+ char *e_name;
+ int e_valid;
+ int e_line;
+ char *e_file;
+ int e_kind; /* PRIMITIVE, COMPOSITE... */
+ char *e_type; /* where kind == PRIMITIVE */
+ /* base type, ie. char if e_type is char */
+ char *e_basetype;
+ int e_levels; /* levels of indirection */
+ char *e_attribute; /* kind == COMPOSITE or VARARG. */
+ char *e_assertion; /* reserved for kind == VARARG. */
+ char *e_comment; /* reserved for per-element comments. */
+ int e_pre_uses;
+ int e_post_uses;
+};
+
+typedef struct entry_head_t {
+ int used;
+ int n_entries;
+ ENTRY entry[1]; /* Actually entry[n_entries]. */
+} EHEAD;
+
+static struct symtab_t {
+ ENTRY *Function;
+ EHEAD *Args;
+ EHEAD *Varargs;
+ EHEAD *Globals;
+ ENTRY *Errval;
+
+ /* Includes */
+ table_t *Includes;
+
+ /* Bindings */
+ ENTRY *Exception;
+
+ /* Types */
+ table_t *Print_Types;
+
+ /* Error-message information. */
+ int Line;
+ char Filename[MAXLINE];
+
+ /* Trace additions */
+ char Prototype[MAXLINE];
+ char Formals[MAXLINE];
+ char Actuals[MAXLINE];
+ char Cast[MAXLINE];
+ int Nonreturn;
+ int Skip;
+
+ /* Adl additions */
+ /* various assertions, one hopes */
+} Symtab;
+
+/* File Globals. */
+static EHEAD *create_entry_table(int);
+static EHEAD *add_entry_table(EHEAD *,
+ char *, int, char *, int, char *, char *, int, char *, int, int);
+static ENTRY *get_entry_table(EHEAD *, int);
+static EHEAD *free_entry_table(EHEAD *);
+static void clear_entries(EHEAD *, int, int);
+static ENTRY *allocate_entry(ENTRY *, char *, int, char *, int,
+ char *, char *, int, char *, int, int);
+static ENTRY *set_entry(ENTRY *,
+ char *, int, char *, int, char *, char *, int, char *, int, int);
+static ENTRY *free_entry(ENTRY *);
+static void symtab_clear_varargs(void);
+static void symtab_clear_globals(void);
+static void symtab_clear_print_types(void);
+static void symtab_set_nonreturn(int);
+static table_t *symtab_free_print_types(table_t *);
+
+/*
+ * symtab_new_function -- clear counts, variables for a new function.
+ */
+void
+symtab_new_function(const int line, const char *file)
+{
+ errlog(BEGIN, "symtab_new_function() {");
+ Symtab.Line = line; /* Set, don't clear. */
+ symtab_set_filename(file);
+
+ symtab_clear_function();
+ symtab_clear_varargs();
+ symtab_clear_globals();
+ symtab_clear_errval();
+ symtab_clear_exception();
+ symtab_clear_print_types();
+
+ symtab_set_nonreturn(NO);
+ symtab_set_skip(NO);
+ errlog(END, "}");
+}
+
+
+/*
+ * symtab_clear_function -- clear function-prototype-derived
+ * values. Called on each prototype line and at beginning
+ * of interface.
+ */
+void
+symtab_clear_function(void)
+{
+
+ errlog(BEGIN, "symtab_clear_function() {");
+ Symtab.Function = free_entry(Symtab.Function);
+ Symtab.Args = free_entry_table(Symtab.Args);
+ Symtab.Prototype[0] = NULL;
+ Symtab.Formals[0] = NULL;
+ Symtab.Actuals[0] = NULL;
+ Symtab.Cast[0] = NULL;
+ errlog(END, "}");
+}
+
+
+/*
+ * symtab_clear_varargs -- called only at end
+ */
+static void
+symtab_clear_varargs(void)
+{
+
+ errlog(BEGIN, "symtab_clear_varargs() {");
+ Symtab.Varargs = free_entry_table(Symtab.Varargs);
+ errlog(END, "}");
+}
+
+/*
+ * symtab_clear_includes -- clear only at end of file (union++)
+ */
+void
+symtab_clear_includes(void)
+{
+
+ errlog(BEGIN, "symtab_clear_includes() {");
+ Symtab.Includes = free_string_table(Symtab.Includes);
+ errlog(END, "}");
+}
+
+static void
+symtab_clear_globals(void)
+{
+
+ errlog(BEGIN, "symtab_clear_globals() {");
+ Symtab.Globals = free_entry_table(Symtab.Globals);
+ errlog(END, "}");
+}
+
+void
+symtab_clear_errval(void)
+{
+
+ errlog(BEGIN, "symtab_clear_errval() {");
+ Symtab.Errval = free_entry(Symtab.Errval);
+ errlog(END, "}");
+}
+
+void
+symtab_clear_exception(void)
+{
+
+ errlog(BEGIN, "symtab_clear_exception() {");
+ Symtab.Exception = free_entry(Symtab.Exception);
+ errlog(END, "}");
+}
+
+static void
+symtab_clear_print_types(void)
+{
+
+ errlog(BEGIN, "symtab_clear_print_types() {");
+ Symtab.Print_Types = symtab_free_print_types(Symtab.Print_Types);
+ errlog(END, "}");
+}
+
+
+/* Generated by m4 -- character string values */
+
+void
+symtab_set_prototype(char *p)
+{
+
+ errlog(BEGIN, "symtab_set_prototype(void) {");
+ (void) strncpy(Symtab.Prototype, p, sizeof (Symtab.Prototype));
+ Symtab.Prototype[sizeof (Symtab.Prototype)-1] = NULL;
+ errlog(END, "}");
+}
+
+char *
+symtab_get_prototype(void)
+{
+ errlog(BEGIN, "symtab_get_prototype() {"); errlog(END, "}");
+ return (Symtab.Prototype);
+}
+
+void
+symtab_set_formals(char *p)
+{
+ errlog(BEGIN, "symtab_set_formals() {");
+ errlog(VERBOSE, "p = %s", p);
+ (void) strncpy(Symtab.Formals, p, sizeof (Symtab.Formals));
+ Symtab.Formals[sizeof (Symtab.Formals)-1] = NULL;
+ errlog(END, "}");
+}
+
+char *
+symtab_get_formals(void)
+{
+ errlog(BEGIN, "symtab_get_formals() {"); errlog(END, "}");
+ return (Symtab.Formals);
+}
+
+void
+symtab_set_actuals(char *p)
+{
+ errlog(BEGIN, "symtab_set_actuals() {"); errlog(END, "}");
+ errlog(VERBOSE, "p = %s", p);
+ (void) strncpy(Symtab.Actuals, p, sizeof (Symtab.Actuals));
+ Symtab.Actuals[sizeof (Symtab.Actuals)-1] = NULL;
+}
+
+char *
+symtab_get_actuals(void)
+{
+ errlog(BEGIN, "symtab_get_actuals() {"); errlog(END, "}");
+ return (Symtab.Actuals);
+}
+
+void
+symtab_set_cast(char *p)
+{
+ errlog(BEGIN, "symtab_set_cast() {"); errlog(END, "}");
+ (void) strncpy(Symtab.Cast, p, sizeof (Symtab.Cast));
+ Symtab.Cast[sizeof (Symtab.Cast)-1] = NULL;
+}
+
+char *
+symtab_get_cast(void)
+{
+ errlog(BEGIN, "symtab_get_cast() {"); errlog(END, "}");
+ return (Symtab.Cast);
+}
+
+
+void
+symtab_set_filename(const char *p)
+{
+ errlog(BEGIN, "symtab_set_filename() {"); errlog(END, "}");
+ (void) strncpy(Symtab.Filename, p, sizeof (Symtab.Filename));
+ Symtab.Filename[sizeof (Symtab.Filename)-1] = NULL;
+}
+
+char *
+symtab_get_filename(void)
+{
+ errlog(BEGIN, "symtab_get_filename() {"); errlog(END, "}");
+ return (Symtab.Filename);
+}
+
+
+/* Generated by m4 -- int values */
+
+static void
+symtab_set_nonreturn(int val)
+{
+ errlog(BEGIN, "symtab_set_nonreturn() {"); errlog(END, "}");
+ Symtab.Nonreturn = val;
+}
+
+int
+symtab_get_nonreturn(void)
+{
+ errlog(BEGIN, "symtab_get_nonreturn() {"); errlog(END, "}");
+ return (Symtab.Nonreturn);
+}
+
+void
+symtab_set_line(int val)
+{
+ errlog(BEGIN, "symtab_set_line() {"); errlog(END, "}");
+ Symtab.Line = val;
+}
+
+int
+symtab_get_line(void)
+{
+ errlog(BEGIN, "symtab_get_line() {"); errlog(END, "}");
+ return (Symtab.Line);
+}
+
+
+void
+symtab_set_skip(int value)
+{
+ errlog(BEGIN, "symtab_set_skip() {"); errlog(END, "}");
+ Symtab.Skip = value;
+}
+
+int
+symtab_get_skip(void)
+{
+ errlog(BEGIN, "symtab_get_skip() {"); errlog(END, "}");
+ return (Symtab.Skip);
+}
+
+/*
+ * Manually written access functions for ENTRY * variables.
+ */
+
+void
+symtab_set_function(char *name, int line, char *file,
+ char *type, char *basetype, int levels)
+{
+
+ errlog(BEGIN, "symtab_set_function() {");
+ Symtab.Function = allocate_entry(Symtab.Function,
+ name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1);
+ errlog(END, "}");
+}
+
+ENTRY *
+symtab_get_function(void)
+{
+ errlog(BEGIN, "symtab_get_function() {"); errlog(END, "}");
+ if (Symtab.Function == NULL)
+ return (NULL);
+ else
+ return ((Symtab.Function->e_valid)? Symtab.Function: NULL);
+}
+
+void
+symtab_set_exception(char *value, int line, char *file)
+{
+
+ errlog(BEGIN, "symtab_set_exception() {");
+ Symtab.Exception = allocate_entry(Symtab.Exception,
+ value, line, file, COMPOSITE, "", "", 0, "", -1, -1);
+ errlog(END, "}");
+}
+
+ENTRY *
+symtab_get_exception(void)
+{
+
+ errlog(BEGIN, "symtab_get_exception() {"); errlog(END, "}");
+ if (Symtab.Exception == NULL)
+ return (NULL);
+ else
+ return ((Symtab.Exception->e_valid)? Symtab.Exception: NULL);
+}
+
+void
+symtab_set_errval(char *name, int line, char *file, char *type, char *basetype,
+ int levels)
+{
+
+ errlog(BEGIN, "symtab_set_errval() {");
+ Symtab.Errval = allocate_entry(Symtab.Errval,
+ name, line, file, PRIMITIVE, type, basetype, levels,
+ "", -1, -1);
+ errlog(END, "}");
+}
+
+ENTRY *
+symtab_get_errval(void)
+{
+
+ errlog(BEGIN, "symtab_get_errval() {"); errlog(END, "}");
+ if (Symtab.Errval == NULL)
+ return (NULL);
+ else
+ return ((Symtab.Errval->e_valid)? Symtab.Errval: NULL);
+}
+
+/*
+ * Manually written access function for tables of ENTRYs
+ */
+void
+symtab_add_args(char *name, int line, char *file,
+ char *type, char *basetype, int levels)
+{
+
+ errlog(BEGIN, "symtab_add_args() {");
+ if (Symtab.Args == NULL) {
+ Symtab.Args = create_entry_table(10);
+ }
+ Symtab.Args = add_entry_table(Symtab.Args,
+ name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1);
+ errlog(END, "}");
+}
+
+static int curr_arg;
+
+ENTRY *
+symtab_get_first_arg(void)
+{
+
+ errlog(BEGIN, "symtab_get_first_arg() {"); errlog(END, "}");
+ curr_arg = 1;
+ return (get_entry_table(Symtab.Args, 0));
+}
+
+ENTRY *
+symtab_get_next_arg(void)
+{
+
+ errlog(BEGIN, "symtab_get_next_arg() {"); errlog(END, "}");
+ return (get_entry_table(Symtab.Args, curr_arg++));
+}
+
+ENTRY *
+symtab_get_last_arg(void)
+{
+
+ errlog(BEGIN, "symtab_get_last_arg() {"); errlog(END, "}");
+ return (get_entry_table(Symtab.Args, Symtab.Args->used));
+}
+
+void
+symtab_add_varargs(char *name, int line, char *file, char *type, char *print)
+{
+
+ errlog(BEGIN, "symtab_add_varargs() {");
+ if (Symtab.Varargs == NULL) {
+ Symtab.Varargs = create_entry_table(10);
+ }
+ Symtab.Varargs = add_entry_table(Symtab.Varargs,
+ name, line, file, PRIMITIVE, type, print, 0, "", -1, -1);
+ errlog(END, "}");
+}
+
+static int curr_vararg;
+
+ENTRY *
+symtab_get_first_vararg(void)
+{
+
+ errlog(BEGIN, "symtab_get_first_vararg() {"); errlog(END, "}");
+ curr_vararg = 1;
+ return (get_entry_table(Symtab.Varargs, 0));
+}
+
+ENTRY *
+symtab_get_next_vararg(void)
+{
+
+ errlog(BEGIN, "symtab_get_next_vararg() {"); errlog(END, "}");
+ return (get_entry_table(Symtab.Varargs, curr_vararg++));
+}
+
+void
+symtab_add_globals(char *name, int line, char *file, char *type,
+ char *basetype, int levels)
+{
+
+ errlog(BEGIN, "symtab_add_globals() {");
+ if (Symtab.Globals == NULL) {
+ Symtab.Globals = create_entry_table(10);
+ }
+ Symtab.Globals = add_entry_table(Symtab.Globals,
+ name, line, file, PRIMITIVE, type, basetype, levels, "", -1, -1);
+ errlog(END, "}");
+}
+
+
+static int curr_global;
+
+ENTRY *
+symtab_get_first_global(void)
+{
+
+ errlog(BEGIN, "symtab_get_first_global() {"); errlog(END, "}");
+ curr_global = 1;
+ return (get_entry_table(Symtab.Globals, 0));
+}
+
+ENTRY *
+symtab_get_next_global(void)
+{
+
+ errlog(BEGIN, "symtab_get_next_global() {"); errlog(END, "}");
+ return (get_entry_table(Symtab.Globals, curr_global++));
+}
+
+/*
+ * manually written functions for accessing tables of strings
+ */
+
+/*
+ * symtab_add_print_types -- add only non-void print types (due to
+ * parser errors in collect.c, yuck). Also note trick compare...
+ * TBD : common code in db, symtab needs to be
+ * pulled out, as they're getting out of sync.
+ */
+void
+symtab_add_print_types(char *print_type, char *c_type)
+{
+ char buffer[MAXLINE];
+
+ errlog(BEGIN, "symtab_add_print_types() {");
+#ifdef notdef
+ if (strcmp(print_type, "void") == 0 || *print_type == NULL) {
+ errlog(END, "}");
+ return;
+ }
+#endif
+ (void) snprintf(buffer, sizeof (buffer), "%s, %s", print_type, c_type);
+ if (Symtab.Print_Types == NULL) {
+ Symtab.Print_Types = create_string_table(50);
+ }
+ if (in_string_table(Symtab.Print_Types, print_type) == NO) {
+ Symtab.Print_Types = add_string_table(Symtab.Print_Types,
+ &buffer[0]);
+ }
+ errlog(END, "}");
+}
+
+static table_t *
+symtab_free_print_types(table_t *t)
+{
+ errlog(BEGIN, "symtab_free_print_types() {"); errlog(END, "}");
+ return (free_string_table(t));
+}
+
+
+static int curr_print_type;
+
+char *
+symtab_get_first_print_type(void)
+{
+
+ errlog(BEGIN, "symtab_get_first_print_type() {"); errlog(END, "}");
+ curr_print_type = 1;
+ return (get_string_table(Symtab.Print_Types, 0));
+}
+
+char *
+symtab_get_next_print_type(void)
+{
+
+ errlog(BEGIN, "symtab_get_next_print_type() {"); errlog(END, "}");
+ return (get_string_table(Symtab.Print_Types, curr_print_type++));
+}
+
+void
+symtab_add_includes(char *value)
+{
+
+ errlog(BEGIN, "symtab_add_includes() {");
+ if (Symtab.Includes == NULL) {
+ Symtab.Includes = create_string_table(50);
+ }
+ if (in_string_table(Symtab.Includes, value) == NO) {
+ Symtab.Includes = add_string_table(Symtab.Includes, value);
+ }
+ errlog(END, "}");
+}
+
+static int curr_include;
+
+char *
+symtab_get_first_include(void)
+{
+
+ errlog(BEGIN, "symtab_get_first_include() {"); errlog(END, "}");
+ curr_include = 1;
+ return (get_string_table(Symtab.Includes, 0));
+}
+
+char *
+symtab_get_next_include(void)
+{
+
+ errlog(BEGIN, "symtab_get_next_include() {"); errlog(END, "}");
+ return (get_string_table(Symtab.Includes, curr_include++));
+}
+
+
+void
+symtab_sort_includes(void)
+{
+ errlog(BEGIN, "symtab_sort_includes() {");
+ sort_string_table(Symtab.Includes);
+ errlog(END, "}");
+}
+
+/*
+ * ENTRYs -- access functions to contents of an entry.
+ */
+
+char *
+name_of(ENTRY *e)
+{
+ return (e->e_name);
+}
+
+int
+validity_of(ENTRY *e)
+{
+
+ if (e == NULL)
+ return (NO);
+ else
+ return (e->e_valid);
+}
+
+int
+line_of(ENTRY *e)
+{
+ return (e->e_line);
+}
+
+
+char *
+file_of(ENTRY *e)
+{
+ return (e->e_file);
+}
+
+/*
+ * x_type_of -- return (type with an extension: an embedded %s where
+ * the name goes.
+ */
+char *
+x_type_of(ENTRY *e)
+{
+ if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG))
+ return (e->e_type);
+ else
+ return (NULL);
+}
+
+
+/*
+ * type_of -- return (just the type, with the %s removed. This is the common
+ * case, and its also the slowest... TBD.
+ */
+char *
+type_of(ENTRY *e)
+{
+ static char buffer[MAXLINE];
+ char *p, *q;
+
+ if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG)) {
+ p = e->e_type;
+ q = &buffer[0];
+ while (*p != NULL) {
+ if (*p == '%') {
+ p += 2;
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = NULL;
+ return (strtrim(&buffer[0]));
+ }
+ else
+ return (NULL);
+}
+
+char *
+basetype_of(ENTRY *e)
+{
+ if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG))
+ return (e->e_basetype);
+ else
+ return (NULL);
+}
+
+int
+levels_of(ENTRY *e)
+{
+ if (e != NULL && (e->e_kind == PRIMITIVE || e->e_kind == VARARG))
+ return (e->e_levels);
+ else
+ return (NULL);
+}
+
+char *
+inverse_of(ENTRY *e)
+{
+
+ if (e != NULL && e->e_kind == COMPOSITE)
+ return (e->e_attribute);
+ else
+ return (NULL);
+}
+
+char *
+selector_of(ENTRY *e)
+{
+
+ if (e != NULL && e->e_kind == VARARG)
+ return (e->e_attribute);
+ else
+ return (NULL);
+}
+
+int
+preuses_of(ENTRY *e)
+{
+
+ if (e)
+ return (e->e_pre_uses);
+ else
+ return (-1);
+}
+
+int
+postuses_of(ENTRY *e)
+{
+
+ if (e)
+ return (e->e_post_uses);
+ else
+ return (-1);
+}
+
+
+/*
+ * allocate_entry -- make a parameter list into a complete
+ * ENTRY struct, allocated dynamically.
+ */
+ /* ARGSUSED -- lint bug */
+static ENTRY *
+allocate_entry(ENTRY *e,
+ char *name, int line, char *file,
+ int kind, char *type, char *basetype, int levels, char *attribute,
+ int npre, int npost)
+{
+
+ errlog(BEGIN, "allocate_entry() {");
+ if (e == NULL) {
+ if ((e = (ENTRY *)calloc(1, sizeof (ENTRY))) == NULL) {
+ errlog(FATAL, "can't allocate space for an ENTRY");
+ }
+ }
+ errlog(END, "}");
+ return (set_entry(e, name, line, file, kind, type, basetype, levels,
+ attribute, npre, npost));
+}
+
+/*
+ * set_entry -- set a passed-in entry, using
+ * passed parameters, to values suitable for a
+ * symtab entry
+ */
+static ENTRY *
+set_entry(ENTRY *e,
+ char *name, int line, char *file,
+ int kind, char *type, char *basetype, int levels, char *attribute,
+ int npre, int npost)
+{
+
+ errlog(BEGIN, "set_entry() {");
+ if (e == NULL) {
+ errlog(FATAL, "programmer error: passed a NULL ENTRY");
+ }
+ e->e_name = strset(e->e_name, name);
+ e->e_valid = YES;
+ e->e_line = line,
+ e->e_file = strset(e->e_file, file);
+ e->e_kind = kind;
+ switch (kind) {
+ case PRIMITIVE:
+ e->e_type = strset(e->e_type, type);
+ e->e_basetype = strset(e->e_basetype, basetype);
+ e->e_levels = levels;
+ break;
+ case COMPOSITE:
+ e->e_attribute = strset(e->e_attribute, attribute);
+ break;
+ case VARARG:
+ e->e_attribute = strset(e->e_attribute, attribute);
+ break;
+ default:
+ errlog(FATAL, "programmer error: impossible kind of ENTRY");
+ }
+
+ e->e_pre_uses = npre;
+ e->e_post_uses = npost;
+ errlog(END, "}");
+ return (e);
+}
+
+
+/*
+ * free_entry -- really just mark an entry as invalid
+ */
+static ENTRY *
+free_entry(ENTRY *e)
+{
+ if (e != NULL)
+ e->e_valid = NO;
+ return (e);
+}
+
+
+/*
+ * ENTRY tables.
+ */
+#define ENTRY_INCREMENT 10
+
+static EHEAD *
+create_entry_table(int n)
+{
+ EHEAD *p;
+
+ errlog(BEGIN, "create_entry_table() {");
+ if ((p = (EHEAD *)calloc(1,
+ sizeof (EHEAD)+(n*sizeof (ENTRY)))) == NULL) {
+ errlog(FATAL, "can't allocate space for an ENTRY table");
+ }
+ p->used = -1;
+ p->n_entries = n;
+ errlog(END, "}");
+ return (p);
+}
+
+static EHEAD *
+add_entry_table(EHEAD *t, char *name, int line, char *file,
+ int kind, char *type, char *basetype, int levels, char *attribute,
+ int npre, int npost)
+{
+ EHEAD *t2;
+
+ errlog(BEGIN, "add_entry_table() {");
+ if (t == NULL) {
+ errlog(FATAL, "programmer error: tried to add to NULL EHEAD");
+ }
+ t->used++;
+ if (t->used >= t->n_entries) {
+ if ((t2 = (EHEAD *)realloc(t,
+ sizeof (EHEAD)+(sizeof (ENTRY)*
+ (t->n_entries+ENTRY_INCREMENT)))) == NULL) {
+ errlog(FATAL, "out of memory extending an EHEAD");
+ }
+ t = t2;
+ clear_entries(t, t->n_entries, (t->n_entries+ENTRY_INCREMENT));
+ t->n_entries += ENTRY_INCREMENT;
+ }
+ (void) set_entry(&t->entry[t->used],
+ name, line, file, kind, type, basetype, levels,
+ attribute, npre, npost);
+ errlog(END, "}");
+ return (t);
+}
+
+static ENTRY *
+get_entry_table(EHEAD *t, int index)
+{
+ if (t == NULL) {
+ return (NULL);
+ } else if (index > t->used) {
+ return (NULL);
+ } else {
+ return (&(t->entry[index]));
+ }
+}
+
+static EHEAD *
+free_entry_table(EHEAD *t)
+{
+ if (t != NULL)
+ t->used = -1;
+ return (t);
+}
+
+static void
+clear_entries(EHEAD *t, int start, int end)
+{
+ int i;
+
+ for (i = start; i < end; i++) {
+ (void) memset(&t->entry[i], 0, sizeof (ENTRY));
+ }
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/symtab.h b/usr/src/cmd/abi/spectrans/spec2trace/symtab.h
new file mode 100644
index 0000000000..cc0f236dcd
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/symtab.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _SYMTAB_H
+#define _SYMTAB_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct entry_t ENTRY; /* Forward declaration */
+
+extern void symtab_new_function(const int, const char *);
+extern void symtab_clear_function(void);
+extern void symtab_clear_includes(void);
+extern void symtab_clear_errval(void);
+extern void symtab_clear_exception(void);
+
+/* Generated by m4 -- character string values */
+extern void symtab_set_prototype(char *p);
+extern char *symtab_get_prototype(void);
+extern void symtab_set_formals(char *);
+extern char *symtab_get_formals(void);
+extern void symtab_set_actuals(char *);
+extern char *symtab_get_actuals(void);
+extern char *symtab_get_cast(void);
+extern void symtab_set_cast(char *);
+extern void symtab_set_filename(char const *);
+extern char *symtab_get_filename(void);
+
+extern int symtab_get_nonreturn(void);
+extern void symtab_set_line(int);
+extern int symtab_get_line(void);
+extern void symtab_set_skip(int);
+extern int symtab_get_skip(void);
+
+/* Manual code */
+extern void symtab_set_function(char *, int, char *, char *, char *, int);
+extern ENTRY *symtab_get_function(void);
+
+extern void symtab_set_exception(char *, int, char *);
+extern ENTRY *symtab_get_exception(void);
+
+extern void symtab_set_errval(char *, int, char *, char *, char *, int);
+extern ENTRY *symtab_get_errval(void);
+
+extern void symtab_add_args(char *, int, char *, char *, char *, int);
+extern ENTRY *symtab_get_first_arg(void);
+extern ENTRY *symtab_get_next_arg(void);
+extern ENTRY *symtab_get_last_arg(void);
+
+extern void symtab_add_varargs(char *, int, char *, char *, char *);
+extern ENTRY *symtab_get_first_vararg(void);
+extern ENTRY *symtab_get_next_vararg(void);
+extern void symtab_print_varargs(void);
+
+extern void symtab_add_globals(char *, int, char *, char *, char *, int);
+extern ENTRY *symtab_get_first_global(void);
+extern ENTRY *symtab_get_next_global(void);
+
+extern void symtab_add_print_types(char *, char *);
+extern char *symtab_get_first_print_type(void);
+extern char *symtab_get_next_print_type(void);
+
+extern void symtab_add_includes(char *);
+extern char *symtab_get_first_include(void);
+extern char *symtab_get_next_include(void);
+extern void symtab_sort_includes(void);
+
+/* ENTRYs */
+extern char *name_of(ENTRY *);
+extern int validity_of(ENTRY *);
+extern int line_of(ENTRY *);
+extern char *file_of(ENTRY *);
+extern char *type_of(ENTRY *);
+extern char *x_type_of(ENTRY *);
+extern char *basetype_of(ENTRY *);
+extern int levels_of(ENTRY *);
+extern char *inverse_of(ENTRY *);
+extern char *selector_of(ENTRY *);
+extern int preuses_of(ENTRY *);
+extern int postuses_of(ENTRY *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SYMTAB_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/trace.c b/usr/src/cmd/abi/spectrans/spec2trace/trace.c
new file mode 100644
index 0000000000..a9fab97c02
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/trace.c
@@ -0,0 +1,988 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-2001 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ *
+ * trace.c -- a simple translator from spec source to c source for
+ * a apptrace interposer library. This file implements the
+ * (interface to) the front end. Other files implement the middle
+ * and databases, and generate.c implements the back end.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <time.h>
+#include <string.h>
+
+#include "parser.h"
+#include "trace.h"
+
+#include "util.h"
+#include "db.h"
+#include "symtab.h"
+#include "io.h"
+#include "printfuncs.h"
+#include "errlog.h"
+#include "parseproto.h"
+
+static int Verbose;
+
+/* File globals. This would be better as a class. */
+/* The first four (commented out) of these enums are defined in parser.h */
+enum {
+ /* XLATOR_KW_NOTFOUND = 0, */
+ /* XLATOR_KW_FUNC, */
+ /* XLATOR_KW_DATA */
+ /* XLATOR_KW_END */
+ XLATOR_KW_EXCP = 4,
+ XLATOR_KW_DECL,
+ XLATOR_KW_INCL,
+ XLATOR_KW_ERRNO,
+ XLATOR_KW_ERRVAL,
+ XLATOR_KW_ARCH,
+ XLATOR_KW_WEAK
+};
+#define FIRST_TOKEN 4 /* Must match the first token in the above enum */
+
+static xlator_keyword_t Keywords[] = {
+ { "exception", XLATOR_KW_EXCP },
+ { "declaration", XLATOR_KW_DECL },
+ { "include", XLATOR_KW_INCL },
+ { "errno", XLATOR_KW_ERRNO },
+ { "errval", XLATOR_KW_ERRVAL},
+ { "arch", XLATOR_KW_ARCH},
+ { "weak", XLATOR_KW_WEAK},
+ { "weakfor", XLATOR_KW_WEAK},
+ { "alias", XLATOR_KW_WEAK},
+ { NULL, XLATOR_KW_NOTFOUND }
+};
+
+static struct stats_t {
+ int libraries,
+ files,
+ interfaces,
+ lines;
+ int errors,
+ warnings,
+ skips;
+ time_t start,
+ end;
+} Statistics;
+
+#define LINE (m.mi_line_number-(m.mi_nlines-1))
+
+static void stats_init(void);
+static void stats_report(void);
+
+static int collect_binding(int const, char *, int);
+static int collect_prototype(char *, int, int);
+static int collect_include(char *, int);
+static int collect_errval(char *, int);
+static int collect_arch(char *);
+
+static void generate_includes(void);
+static void generate_init(void);
+static void generate_interface(void);
+static void generate_closedown(void);
+static int generate_aux_file();
+
+/* Local (static) parsing functions. */
+static char *to_actual();
+static int to_basetype(char *);
+static char *de_const(char *);
+static char *strpqcpy(char *, char *, char *);
+
+/*
+ * xlator_init -- initialize translator, called at startup-time
+ * with a struct translator_info of information the translator
+ * might need, returning a list of ``interesting'' spec keywords
+ * for the front end to select and pass to the back end translator.
+ *
+ */
+xlator_keyword_t *
+xlator_init(const Translator_info *t_info)
+{
+ int i;
+
+ errlog(BEGIN, "xlator_init() {");
+
+ /* Save interesting parameters. */
+ stats_init();
+ db_set_source_directory(".");
+ db_set_target_directory(".");
+ Verbose = t_info->ti_verbosity;
+ seterrseverity(Verbose); /* Ditto. */
+ db_set_output_file(t_info->ti_output_file);
+ db_set_arch(t_info->ti_arch);
+
+ /* Display passed argument and return value. */
+ errlog(VERBOSE, "Keywords[] = {");
+ for (i = 0; Keywords[i].key != NULL; i++) {
+ errlog(VERBOSE, " \"%s\", ", Keywords[i].key);
+ }
+ errlog(VERBOSE, " (char *) NULL");
+ errlog(VERBOSE, "};");
+
+ errlog(END, "}");
+ return (Keywords);
+}
+
+/*
+ * xlator_startlib -- called on starting a new library, so back end
+ * translator can decide to change output file/directory if desired.
+ */
+int
+xlator_startlib(char const *libname)
+{
+ errlog(BEGIN, "xlator_startlib() ");
+
+ Statistics.libraries++;
+ db_set_current_library(libname);
+ errlog(VERBOSE, "now in library \"%s\"", libname);
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * xlator_startfile -- ditto, called on starting each new spec file in the
+ * specified library.
+ */
+int
+xlator_startfile(char const *filename)
+{
+ int rc = SUCCESS_RC;
+ char infile[MAXLINE],
+ outfile[MAXLINE],
+ *lib = db_get_current_library();
+
+ seterrline(0, filename, "", "");
+ errlog(BEGIN, "xlator_startfile() {");
+ Statistics.files++;
+ db_set_current_file(filename);
+ errlog(TRACING, "now in file \"%s\" in lib \"%s\"",
+ filename, lib);
+
+ /* Generate filenames. */
+ (void) snprintf(infile, sizeof (infile), "%s", filename);
+ (void) snprintf(outfile, sizeof (outfile), "%s.c",
+ db_get_output_file());
+
+ /* Open .c file. */
+ if (open_code_file() == NO) {
+ rc = ERROR_RC;
+ }
+
+ generate_init(); /* Write stuff to the c file. */
+ symtab_clear_includes(); /* Clear out the per-file data. */
+ errlog(END, "}");
+ return (rc);
+}
+
+/*
+ * xlator_start_if -- tritto, called on starting each new
+ * interface in the spec file.
+ */
+int
+xlator_start_if(const Meta_info m, int const token, char *value)
+{
+ char ifname[BUFSIZ];
+ char *kw;
+
+ switch (token) {
+ case XLATOR_KW_FUNC:
+ kw = "Function";
+ break;
+ case XLATOR_KW_DATA:
+ kw = "Data";
+ break;
+ default:
+ /* This should never happen */
+ errlog(ERROR,
+ "\"%s\", line %d: Implementation error! "
+ "Please file a bug\n", __FILE__, __LINE__);
+ return (XLATOR_FATAL);
+ }
+
+ seterrline(LINE, m.mi_filename, kw, value);
+ errlog(BEGIN, "xlator_start_if() {");
+
+/*
+ * XXX Note whether interface is function or data in some state data item.
+ * We'll need it later when writing interceptors.
+ */
+
+ Statistics.interfaces++;
+ (void) strpqcpy(ifname, value, nextsep2(value));
+ if (*ifname == '\0') {
+ errlog(INPUT|ERROR|FATAL,
+ "missing argument in \"%s\" line", kw);
+ }
+ db_set_current_interface(ifname);
+ errlog(VERBOSE, "interface='%s'", value);
+ if (token == XLATOR_KW_DATA) {
+ Statistics.skips++;
+ errlog(VERBOSE, "telling front end to skip '%s'", value);
+ errlog(END, "}");
+ return (SKIP_RC); /* Tell front end to skip it for us. */
+ }
+
+ errlog(TRACING, "now in interface \"%s\"", value);
+
+ symtab_new_function(m.mi_line_number, m.mi_filename);
+ /* Also cleans junk out of symbol table. */
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * xlator_take_kvpair -- the primary call: collect a datum provide by the
+ * front-end wrapper.
+ */
+int
+xlator_take_kvpair(Meta_info m, int const token, char *value)
+{
+ int retval;
+ char *key = Keywords[token-FIRST_TOKEN].key;
+
+ int line = LINE; /* TBD */
+ symtab_set_filename(m.mi_filename);
+
+ value = strnormalize(value);
+
+ seterrline(line, m.mi_filename, key, value);
+ errlog(BEGIN, "xlator_take_kvpair() {");
+ Statistics.lines++;
+ errlog(VERBOSE, "key='%s', value='%s'",
+ (key) ? key : "<nil>",
+ (value) ? value : "<nil>");
+ switch (token) {
+ case XLATOR_KW_DECL:
+
+ /*
+ * XXX Check state item to see that it is a function,
+ * else do not emit interceptor
+ */
+ symtab_clear_function(); /* Always use last one. */
+ errlog(END, "}");
+ retval = collect_prototype(value, line, m.mi_ext_cnt);
+ break;
+
+ case XLATOR_KW_INCL:
+ errlog(END, "}"); /* Use union of all includes. */
+ retval = collect_include(value, line);
+ if (retval == ERROR_RC) {
+ errlog(FATAL|INPUT, "Bad include line in spec file");
+ }
+ break;
+
+ case XLATOR_KW_EXCP:
+ symtab_clear_exception(); /* Always use last. */
+ retval = collect_binding(token, value, line);
+ break;
+
+ case XLATOR_KW_ERRNO:
+ symtab_clear_errval(); /* Always use last. */
+ retval = collect_errval("errno", line);
+ break;
+
+ case XLATOR_KW_ERRVAL:
+ symtab_clear_errval(); /* Always use last. */
+ retval = collect_errval(value, line);
+ break;
+
+ case XLATOR_KW_ARCH:
+ retval = collect_arch(value);
+ break;
+
+ case XLATOR_KW_WEAK:
+ if (m.mi_extended == 1) {
+ errlog(ERROR, "\"%s\", line %d: "
+ "Warning: Cannot use extends with a weak "
+ "interface",
+ m.mi_filename,
+ m.mi_line_number);
+ }
+ retval = SUCCESS_RC;
+ break;
+ default:
+ retval = ERROR_RC;
+ }
+
+ errlog(END, "}");
+
+ return (retval);
+}
+
+/*
+ * xlator_end_if -- called at the end of the interface, to trigger
+ * per-interface processing now entire thing has been seen.
+ */
+/*ARGSUSED*/
+int
+xlator_end_if(const Meta_info m, char const *value)
+{
+ seterrline(LINE, m.mi_filename, "end", value);
+ errlog(BEGIN, "xlator_end_if() {");
+ if (symtab_get_skip() == YES) {
+ symtab_set_skip(NO);
+ Statistics.skips++;
+ } else {
+ generate_interface();
+ }
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * xlator_endfile -- called at the end of the file, to trigger per-file
+ * processing.
+ */
+int
+xlator_endfile(void)
+{
+ errlog(BEGIN, "xlator_endfile() {");
+
+ generate_closedown();
+ errlog(END, "}");
+ return ((commit_code_file() == YES)? SUCCESS_RC: ERROR_RC);
+}
+
+/*
+ * xlator_endlib -- ditto, at the end of the library.
+ */
+int
+xlator_endlib(void)
+{
+ errlog(BEGIN, "xlator_endlib() {");
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * xlator_end -- the end of the processing, called so translator
+ * can do cleanup, write makefiles, etc.
+ */
+int
+xlator_end(void)
+{
+ int rc = SUCCESS_RC;
+
+ errlog(BEGIN, "xlator_end() {");
+ rc += !generate_aux_file();
+ stats_report();
+ errlog(END, "}");
+ return (rc);
+}
+
+
+/*
+** utilities for this layer/phase only.
+*/
+
+/*
+ * stats_init -- note what time it is...
+ */
+static void
+stats_init(void)
+{
+ Statistics.start = time(NULL);
+}
+
+/*
+ * stats_report -- say how much we just did
+ */
+#define max(a, b) (a > b)? a: b
+
+static void
+stats_report(void)
+{
+ double seconds;
+
+ Statistics.end = time(NULL);
+ seconds = difftime(Statistics.end, Statistics.start);
+
+ switch (Verbose) {
+ default:
+ /*FALLTHROUGH*/
+ case 1:
+ (void) fprintf(stderr, "Statistics:\n"
+ " %d libraries\n %d files\n"
+ " %d interfaces\n %d lines\n"
+ " %d errors\n %d warnings\n"
+ " %d skips\n"
+ "in %.0f seconds, at %.1f lines/minute.\n",
+ Statistics.libraries, Statistics.files,
+ Statistics.interfaces, Statistics.lines,
+ Statistics.errors, Statistics.warnings,
+ Statistics.skips,
+ seconds, Statistics.lines*60.0/seconds);
+ break;
+ case 0:
+ if (Statistics.errors != 0 || Statistics.warnings != 0) {
+ (void) fprintf(stderr,
+ "spec2trace: %d errors %d warnings.\n",
+ Statistics.errors, Statistics.warnings);
+ }
+ break;
+ }
+}
+
+
+/*
+ * Tiny stats class...
+ */
+void
+stats_add_warning(void)
+{
+ Statistics.warnings++;
+}
+
+void
+stats_add_error(void)
+{
+ Statistics.errors++;
+}
+
+/*
+ * collect_includes -- collect a global list of include files,
+ * converting the comma- or space-separated input list into a
+ * structure for the database to store.
+ * As this can cause problems will ill-structured
+ * files, there is a mechanism to allow exclusion of
+ * certain files, (or certain combinations). At
+ * the moment, the mechanism is TBD, as is the second arg.
+ */
+/*ARGSUSED1*/
+int
+collect_include(char *p, int line)
+{
+ char *include;
+ int len;
+
+ errlog(BEGIN, "collect_include() {");
+ if ((include = strtok(p, ", ")) != NULL) {
+ for (; include != NULL; include = strtok(NULL, ", ")) {
+ include = skipb(include);
+
+ /*
+ * Make sure the include file's name
+ * has legitimate C syntax - i.e. it's in double
+ * quotes or angle brackets.
+ */
+ if (*include != '"' && *include != '<')
+ return (ERROR_RC);
+
+ len = strlen(include);
+
+ if (include[len-1] != '"' && include[len-1] != '>')
+ return (ERROR_RC);
+
+ /*
+ * If include filename syntax is OK, add it to
+ * the list
+ */
+ symtab_add_includes(include);
+ }
+ }
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * collect_binding -- take a binding and stuff it into the database
+ * in canonical form (with the word return in it).
+ */
+int
+collect_binding(int const token, char *value, int line)
+{
+ char *file = db_get_current_file();
+
+ errlog(BEGIN, "collect_binding() {");
+ errlog(VERBOSE, "name=\"%s\", value=\"%s\", line=%d\n",
+ Keywords[token-FIRST_TOKEN].key, value, line);
+
+ if (token == XLATOR_KW_EXCP) {
+ symtab_set_exception(value, line, file);
+ } else {
+ errlog(FATAL|INPUT, "programmer error: impossible binding.");
+ }
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * collect_errval -- collect the error variable name (only)
+ * from the line. This is expected to be the first
+ * or only thing in a space- or comma-separated list.
+ * Collecting errno/errval possible value is left TBD.
+ */
+int
+collect_errval(char *p, int line)
+{
+ char *name;
+
+ errlog(BEGIN, "collect_errval() {");
+ name = strtok(p, " \t\n\r");
+ symtab_set_errval(name, line, db_get_current_file(), "int", "int", 0);
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+/*
+ * collect_arch -- collect architecture.
+ */
+int
+collect_arch(char *value)
+{
+ char const *arch = db_get_arch();
+ char *buf, *p;
+ char *t;
+
+ errlog(BEGIN, "collect_arch() {");
+ if (value == 0 || *value == '\0')
+ errlog(FATAL|INPUT, "No architectures defined in ARCH line");
+
+ if ((buf = strdup(value)) == NULL)
+ errlog(FATAL, "Could not allocate memory in ARCH directive");
+
+ t = buf;
+ while ((p = strtok(t, " \r\t\n")) != NULL) {
+ if (strcmp(p, arch) == 0 || strcmp(p, "all") == 0)
+ goto cleanup;
+ t = NULL;
+ }
+ symtab_set_skip(YES);
+
+cleanup:
+ free(buf);
+ return (SUCCESS_RC);
+}
+
+/*
+ * de_const -- get rid of const meta-types. This is actually a
+ * dodge to avoid writing a base-type function early in the
+ * process. This may turn into to_basetype() or to_primitivetype().
+ */
+static char *
+de_const(char *type)
+{
+ char *p, *q;
+ int i;
+
+ p = skipb(type);
+
+ q = strstr(type, "const");
+ if (q > p) {
+ for (i = 0; i < 5; i++) {
+ *q++ = '\0';
+ }
+ (void) sprintf(type, "%s%s", strnormalize(p), q);
+ return (type);
+ } else if (p == q) {
+ return (skipb(nextsep(p)));
+ } else {
+ return (type);
+ }
+
+}
+
+/*
+ * to_basetype -- convert a C type declaration into its base type and return
+ * the number of levels of indirection.
+ * Destructive and eats ``const''.
+ */
+static int
+to_basetype(char *str)
+{
+ char *p = str,
+ buffer[MAXLINE+1],
+ *q = &buffer[0];
+ int levels = 0;
+
+ assert(strlen(str) < MAXLINE, "string exceeded MAXLINE");
+ buffer[0] = NULL;
+ for (; *p != NULL; p++) {
+ switch (*p) {
+ case ' ': /* Convert spaces to single ' '. */
+ if (*(q-1) != ' ')
+ *q++ = ' ';
+ break;
+ case '*': /* Convert * to _P. */
+ if (*(q-1) != ' ')
+ *q++ = ' ';
+ levels++;
+ break;
+ case 'c': /* This might be a const */
+ if (strncmp(p, "const", 5) == 0) {
+ p += 4;
+ } else {
+ *q++ = *p;
+ }
+ break;
+ default:
+ /* Otherwise just copy. */
+ *q++ = *p;
+ break;
+ }
+ *q = NULL;
+ }
+ assert(q < &buffer[MAXLINE], "q fell off end of buffer");
+ q--;
+ while (*q == ' ') {
+ *q-- = NULL;
+ }
+ assert(strlen(buffer) < MAXLINE, "buffer length exceeded MAXLINE");
+ (void) strcpy(str, buffer);
+ return (levels);
+}
+
+/*
+ * to_actual -- create an actual-argument list for use
+ * when calling the function.
+ */
+static char *
+to_actual(void)
+{
+ ENTRY *p;
+ static char buffer[MAXLINE+1];
+ int n;
+
+ *buffer = NULL;
+ if ((p = symtab_get_first_arg()) != NULL) {
+ n = MAXLINE - snprintf(buffer, MAXLINE, "%s", name_of(p));
+ for (p = symtab_get_next_arg(); p != NULL;
+ p = symtab_get_next_arg()) {
+ if (*name_of(p) != NULL)
+ n -= snprintf(strend(buffer), n,
+ ", %s", name_of(p));
+ }
+ }
+ return (buffer);
+}
+
+/*
+ * strpqcpy -- string copy that takes whatever begins with p and ends
+ * just before q.
+ */
+static char *
+strpqcpy(char *target, char *p, char *q)
+{
+ char saved;
+
+ saved = *q;
+ *q = NULL;
+ (void) strcpy(target, p);
+ *q = saved;
+ return (target);
+}
+
+#ifndef lint
+int
+breakpoint(void)
+{
+ return (0);
+}
+#endif
+
+
+int
+collect_prototype(char *p, int line, int extcnt)
+{
+ char f_type[BUFSIZ]; /* The function. */
+ char f_basetype[BUFSIZ];
+ char f_name[BUFSIZ];
+ char a_name[BUFSIZ]; /* The arguments. */
+ char a_basetype[BUFSIZ];
+ char a_type[BUFSIZ];
+ char *file = db_get_current_file();
+ char *interface = db_get_current_interface();
+ char *q;
+ char const *parse_err;
+ char tmp_proto[BUFSIZ], buf[BUFSIZ];
+ decl_t *pp, *funargs;
+ type_t *tp;
+ int levels, a_levels;
+
+ tmp_proto[BUFSIZ-1] = 0;
+ errlog(BEGIN, "collect_prototype() {");
+ if (p[strlen(p)-1] != ';')
+ (void) snprintf(tmp_proto, BUFSIZ, "%s;", p);
+ else
+ (void) snprintf(tmp_proto, BUFSIZ, "%s", p);
+
+ /* save prototype in symbol table */
+ symtab_set_prototype(p);
+
+ errlog(VERBOSE, "parsing prototype: %s\n", tmp_proto);
+
+ /* Parse Prototype */
+ if ((parse_err = decl_Parse(tmp_proto, &pp)) != NULL) {
+ errlog(FATAL|INPUT, "bad prototype: %s\n\t%s\n", parse_err, p);
+ }
+
+ if (extcnt == 0) {
+ char *dname = decl_GetName(pp);
+ if (strcmp(interface, dname) != 0)
+ errlog(FATAL|INPUT, "function and declaration"
+ " name mismatch\nfunction name = %s,"
+ " declaration name = %s\n", interface,
+ dname);
+ }
+
+ tp = decl_GetType(pp);
+
+ if (type_IsPtrFun(tp)) {
+ errlog(FATAL|INPUT, "function %s is declared as a data item"
+ " (pointer to function)\n", interface);
+ } else if (!type_IsFunction(tp)) {
+ errlog(FATAL|INPUT, "function %s is declared as a data item",
+ interface);
+ }
+
+ if (type_IsVarargs(tp)) {
+ symtab_set_skip(YES);
+ decl_Destroy(pp);
+ return (SUCCESS_RC);
+ }
+
+ decl_GetTraceInfo(pp, f_type, f_basetype, &funargs);
+ (void) sprintf(buf, "%s", strnormalize(f_type));
+ (void) strcpy(f_type, buf);
+ (void) sprintf(buf, "%s", strnormalize(f_basetype));
+ (void) strcpy(f_basetype, buf);
+ levels = to_basetype(f_basetype);
+
+ /* get interface name from 'Begin' line */
+ (void) strpqcpy(f_name, interface, nextsep(interface));
+ (void) decl_SetName(pp, f_name);
+
+ errlog(VERBOSE, "f_name=%s, f_basetype=%s, f_type=%s\n",
+ f_name, f_basetype, f_type);
+
+ symtab_set_function(f_name, line, file, f_type, f_basetype, levels);
+
+ db_add_print_types(f_basetype,
+ (q = de_const(type_of(symtab_get_function()))));
+
+ symtab_add_print_types(f_basetype, q);
+
+ /* args list */
+ while (funargs) {
+ (void) snprintf(a_type, BUFSIZ, "%s ",
+ strnormalize(declspec_ToString(buf, funargs->d_ds)));
+ (void) snprintf(a_basetype, BUFSIZ, "%s",
+ strnormalize(de_const(declspec_ToString(buf,
+ funargs->d_ds))));
+
+ tp = funargs->d_type;
+
+ for (a_levels = 0; tp; ) {
+ if (tp->t_dt == DD_PTR || tp->t_dt == DD_ARY) {
+ (void) strcat(a_type, "*");
+ a_levels++;
+ }
+ tp = tp->t_next;
+ }
+
+ /*
+ * XXX: This is a hack to work around bug in yacc parser
+ * "int foo(void)" prototypes get interpreted as having 1
+ * argument with the d_name of the argument being NULL.
+ */
+ if (funargs->d_name) {
+ (void) snprintf(a_name, 20, "%s", funargs->d_name);
+
+ errlog(VERBOSE,
+ "a_name = %s, a_basetype = %s, a_type = %s\n",
+ a_name, a_basetype, a_type);
+
+ symtab_add_args(a_name, line, file,
+ a_type, a_basetype, a_levels);
+ db_add_print_types(a_basetype,
+ q = de_const(type_of(symtab_get_last_arg())));
+ symtab_add_print_types(a_basetype, q);
+ }
+
+ funargs = funargs->d_next;
+ }
+ symtab_set_formals(decl_ToFormal(pp));
+ symtab_set_actuals(to_actual());
+
+ symtab_set_cast(decl_ToString(buf, DTS_CAST, pp, NULL));
+
+ decl_Destroy(pp);
+
+ errlog(END, "}");
+ return (SUCCESS_RC);
+}
+
+
+/*
+ * generators
+ */
+
+/*
+ * generate_init -- prime the code generator as required.
+ */
+static void
+generate_init(void)
+{
+ errlog(BEGIN, "generate_init() {");
+
+ (void) fprintf(Headfp,
+ "/*\n"
+ " * Generated by spec2trace %s: do not edit this file.\n */\n\n",
+ TRACE_VERSION);
+
+ (void) fprintf(Headfp,
+ "#ifndef true\n"
+ "#define\ttrue 1\n"
+ "#define\tfalse 0\n"
+ "#endif\n\n"
+ "static char const *oparen = \"(\";\n"
+ "static char const *retstr = \" return = \";\n"
+ "static char const *errnostr = \" errno = \";\n"
+ "static char const *nilstr = \"<nil>\";\n"
+ "\n");
+
+ errlog(END, "}");
+}
+
+
+/*
+ * generate_interface -- call the two main parts of the per-interface
+ * code generation.
+ */
+static void
+generate_interface(void)
+{
+ ENTRY *function = symtab_get_function();
+
+ errlog(BEGIN, "generate_interface() {");
+ /* Check for required information. */
+ if (validity_of(function) == NO) {
+ symtab_set_skip(YES);
+ errlog(WARNING|INPUT, "no prototype for interface "
+ "it will be skipped");
+ errlog(END, "}");
+ return;
+ }
+
+ /* Generate the current interface 's print-functions declarations. */
+ generate_print_declarations(Bodyfp);
+
+ /* Generate the linkage part (a function and a struct */
+ generate_linkage(function);
+
+ /* Generate the actual interceptor. */
+ generate_interceptor(function);
+ errlog(END, "}");
+}
+
+
+/*
+ * generate_closedown -- produce includes.
+ */
+static void
+generate_closedown(void)
+{
+ errlog(BEGIN, "generate_closedown() {");
+
+ /* Print includes to primary file. */
+ generate_includes();
+ (void) putc('\n', Headfp);
+ errlog(END, "}");
+}
+
+/*
+ * generate_aux_file -- generate one additional .pf file with
+ * print-function pointers.
+ */
+static int
+generate_aux_file(void)
+{
+ FILE *fp;
+ char pathname[MAXLINE];
+
+ errlog(BEGIN, "generate_aux_file() {");
+ /* Open file */
+ (void) snprintf(pathname, sizeof (pathname), "%s.pf",
+ db_get_output_file());
+ errlog(TRACING, "output file = '%s'", pathname);
+ if ((fp = fopen(pathname, "w")) == NULL) {
+ errlog(FATAL, "%s: %s", pathname, strerror(errno));
+ }
+
+ /*
+ * Declare and initialize all print function pointers to null.
+ * Some spec files result in nothing being put into the .pf
+ * file. We must create the file since make(1) does not cope
+ * well with absent files that it expects to have built. So
+ * now the build gets empty compilation unit warnings... So
+ * we unconditionally create a static pointer.
+ */
+ (void) fprintf(fp,
+ "/* Do not edit this file: it is a generated one. */\n\n"
+ "static char const *__abi_place_holder;\n\n");
+
+ generate_print_definitions(fp);
+
+ /* Close file */
+ if (fclose(fp) != 0) {
+ errlog(FATAL, "fclose %s: %s", pathname, strerror(errno));
+ }
+ errlog(END, "}");
+ return (YES);
+}
+
+
+
+/*
+ * generate_includes -- generate #includes to Headfp
+ */
+static void
+generate_includes(void)
+{
+ char *include;
+
+ errlog(BEGIN, "generate_includes() {");
+ errlog(TRACING, "includes=");
+ for (include = symtab_get_first_include(); include != NULL;
+ include = symtab_get_next_include())
+ (void) fprintf(Headfp, "#include %s\n", include);
+
+ (void) fprintf(Headfp, "\n#include <stdio.h>\n"
+ "#include <dlfcn.h>\n"
+ "#include <apptrace.h>\n\n");
+
+ errlog(TRACING, "\n");
+ errlog(END, "}");
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/trace.h b/usr/src/cmd/abi/spectrans/spec2trace/trace.h
new file mode 100644
index 0000000000..ad53c1db51
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/trace.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ *
+ * 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 2003 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _TRACE_H
+#define _TRACE_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "symtab.h"
+
+#define TRACE_VERSION "1.1.1"
+
+/* Return codes from back- to front-end. */
+enum retcode_t { SUCCESS_RC = 0, ERROR_RC = -1, SKIP_RC = 1};
+
+/* Kinds of code-generation to do. */
+typedef enum {AUDIT, PRELOAD} CODE;
+
+/* Global functions. */
+extern void stats_add_warning(void);
+extern void stats_add_error(void);
+extern void generate_interceptor(ENTRY *);
+extern void print_function_signature(char *, char *, char *);
+extern void generate_linkage(ENTRY *function);
+
+/* Global variables */
+extern CODE Generate;
+
+/* Defines. */
+#define YES 1
+#define NO 0
+#define ERR (-1)
+
+#define MAXLINE 1024
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TRACE_H */
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/util.c b/usr/src/cmd/abi/spectrans/spec2trace/util.c
new file mode 100644
index 0000000000..55eb115f7a
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/util.c
@@ -0,0 +1,385 @@
+/*
+ * 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.
+ *
+ * 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 1997-2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "parser.h"
+#include "trace.h"
+#include "util.h"
+#include "errlog.h"
+
+#define TABLE_INITIAL 50
+#define TABLE_INCREMENT 50
+
+/*
+ * String processing
+ */
+
+/*
+ * strnormalize -- combined tab-to-space and strtrim, plus removal
+ * of leading and trailing *$%$^@!!! semicolons.
+ * Not internationalized: TBD.
+ */
+char *
+strnormalize(char *str)
+{
+ char *p;
+
+ if (str == NULL || *str == NULL)
+ return (str);
+ for (p = str; *p != NULL; p++) {
+ if (isspace(*p)) {
+ *p = ' ';
+ }
+ }
+ p--;
+ while (p >= str && (isspace(*p) || *p == ';'))
+ *p-- = NULL;
+
+ /* ERA - remove leading spaces */
+ while (isspace(*str))
+ str++;
+
+ return (str);
+}
+
+char *
+strtrim(char *str)
+{
+ char *p;
+
+ for (p = str; *p != NULL; p++)
+ continue;
+ p--;
+ while (p >= str && isspace(*p))
+ *p-- = NULL;
+ return (str);
+}
+
+/*
+ * strlower -- make a string lower-case, destructively.
+ * Not internationalized: TBD.
+ */
+char *
+strlower(char *str)
+{
+ char *p;
+
+ for (p = str; *p != NULL; p++) {
+ *p = tolower(*p);
+ }
+ return (str);
+}
+
+/*
+ * strset -- update a dynamically-allocated string or die trying.
+ */
+char *
+strset(char *string, char *value)
+{
+ size_t vlen;
+
+ assert(value != NULL, "passed a NULL value to strset");
+ vlen = strlen(value);
+ if (string == NULL) {
+ /* It was never allocated, so allocate it. */
+ if ((string = malloc(vlen+1)) == NULL) {
+ errlog(FATAL, "malloc ran out of space");
+ }
+ } else if (strlen(string) < vlen) {
+
+ /* Reallocate bigger. */
+ if ((string = realloc(string, vlen+1)) == NULL) {
+ errlog(FATAL, "realloc ran out of space", "", 0);
+ }
+ }
+ (void) strcpy(string, value);
+ return (string);
+}
+
+/*
+ * in_string_set --see if string matches any member of a space-separated
+ * set of strings.
+ */
+int
+in_string_set(char *p, char *set)
+{
+ char *q;
+ char save;
+
+ errlog(BEGIN, "in_string_set( p = \"%s\", set = \"%s\") {", p, set);
+
+ for (;;) {
+ set = skipb(set);
+ q = nextsep(set);
+ if (q == set) {
+ /* We've hit the end */
+ break;
+ }
+ save = *q;
+ *q = NULL;
+ if (strcmp(p, set) == 0) {
+ *q = save;
+ errlog(VERBOSE, "return YES");
+ errlog(END, "}");
+ return (YES);
+ }
+ *q = save;
+ set = q;
+ }
+ errlog(VERBOSE, "return NO");
+ errlog(END, "}");
+ return (NO);
+
+}
+
+char *
+strend(char *p)
+{
+
+ while (*p)
+ p++;
+ return (p);
+}
+
+char *
+lastspace(char *p)
+{
+ char *q;
+
+ q = strend(p);
+ q--;
+ while (q >= p && isspace(*q))
+ q--;
+ return (++q);
+}
+
+/*
+ * skipb -- skip over blanks (whitespace, actually), stopping
+ * on first non-blank.
+ */
+char *
+skipb(char *p)
+{
+ while (*p && isspace(*p))
+ p++;
+ return (p);
+}
+
+/*
+ * nextb -- skip over non-blanks (including operators!)
+ * stopping on first blank.
+ */
+char *
+nextb(char *p)
+{
+ while (*p && !isspace(*p))
+ p++;
+ return (p);
+}
+
+/*
+ * skipsep -- skip over separators (all but alnum and _),
+ * stopping on first non-separator.
+ */
+char *
+skipsep(char *p)
+{
+ errlog(BEGIN, "skipsep() {");
+ errlog(VERBOSE, "p (in) = %s", p);
+ while (*p && !(isalnum(*p) || *p == '_' || *p == '$'))
+ p++;
+ errlog(VERBOSE, "p (out) = %s", p);
+ errlog(END, "}");
+ return (p);
+}
+
+/*
+ * nextsep -- skip over non-separators (alnum and _, actually),
+ * stopping on first separator.
+ */
+char *
+nextsep(char *p)
+{
+ errlog(BEGIN, "nextsep() {");
+ errlog(VERBOSE, "p (in) = %s", p);
+ while (*p && isalnum(*p) || *p == '_' || *p == '$')
+ p++;
+ errlog(VERBOSE, "p (out) = %s", p);
+ errlog(END, "}");
+ return (p);
+}
+
+/*
+ * nextsep2 -- same as nextsep but also skips '.'
+ */
+char *
+nextsep2(char *p)
+{
+ errlog(BEGIN, "nextsep() {");
+ errlog(VERBOSE, "p (in) = %s", p);
+ while (*p && isalnum(*p) || *p == '_' || *p == '$' || *p == '.')
+ p++;
+ errlog(VERBOSE, "p (out) = %s", p);
+ errlog(END, "}");
+ return (p);
+}
+
+/*
+ * objectname -- basename was taken (in man3c), so...
+ */
+char *
+objectname(char *name)
+{
+ char *p;
+ static char basename[MAXLINE];
+
+ p = strrchr(name, '/');
+ while (p != NULL && *(p+1) == NULL) {
+ /* The / was at the end of the name. */
+ *p = NULL;
+ p = strrchr(name, '/');
+ }
+ (void) strlcpy(basename, p? p+1: name, MAXLINE);
+ if ((p = strstr(basename, ".c")) != NULL) {
+ *p = NULL;
+ }
+ return (strcat(basename, ".o"));
+}
+
+/*
+ * String tables
+ */
+
+table_t *
+create_string_table(int size)
+{
+ table_t *t;
+
+ errlog(BEGIN, "create_string_table() {");
+ if ((t = (table_t *)calloc((size_t)1,
+ (size_t)(sizeof (table_t) + (sizeof (char *)*size)))) == NULL) {
+ errlog(FATAL, "out of memory creating a string table");
+ }
+ t->nelem = size;
+ t->used = -1;
+ errlog(END, "}");
+ return (t);
+}
+
+table_t *
+add_string_table(table_t *t, char *value)
+{
+ table_t *t2;
+ int i;
+
+ if (t == NULL) {
+ errlog(FATAL, "programmer error: tried to add to "
+ "a NULL table");
+ }
+ if (in_string_table(t, value)) {
+ return (t);
+ }
+ t->used++;
+ if (t->used >= t->nelem) {
+ if ((t2 = realloc(t, (size_t)(sizeof (table_t)+(sizeof
+ (char *)*(t->nelem+TABLE_INCREMENT)))))
+ == NULL) {
+ errlog(FATAL, "out of memory extending string table");
+ }
+ t = t2;
+ t->nelem += TABLE_INCREMENT;
+ for (i = t->used; i < t->nelem; i++) {
+ t->elements[i] = NULL;
+ }
+ }
+
+ t->elements[t->used] = strset(t->elements[t->used], value);
+ return (t);
+}
+
+/*
+ * free_string_table -- really only mark it empty for reuse.
+ */
+table_t *
+free_string_table(table_t *t)
+{
+ errlog(BEGIN, "free_string_table() {");
+ if (t != NULL) {
+ t->used = -1;
+ }
+ errlog(END, "}");
+ return (t);
+}
+
+char *
+get_string_table(table_t *t, int index)
+{
+ if (t == NULL) {
+ return (NULL);
+ } else if (index > t->used) {
+ return (NULL);
+ } else {
+ return (t->elements[index]);
+ }
+}
+
+int
+in_string_table(table_t *t, char *value)
+{
+ int i;
+ size_t len = strlen(value);
+
+ if (t == NULL) {
+ return (0);
+ }
+ for (i = 0; i <= t->used; i++) {
+ if (strncmp(value, t->elements[i], len) == 0 &&
+ (t->elements[i][len] == NULL ||
+ t->elements[i][len] == ','))
+ return (1);
+ }
+ return (0);
+}
+
+static int
+compare(const void *p, const void *q)
+{
+ return (strcmp((char *)(*(char **)p), (char *)(*(char **)q)));
+}
+
+void
+sort_string_table(table_t *t)
+{
+ if (t) {
+ qsort((char *)t->elements, (size_t)t->used,
+ sizeof (char *), compare);
+ }
+}
diff --git a/usr/src/cmd/abi/spectrans/spec2trace/util.h b/usr/src/cmd/abi/spectrans/spec2trace/util.h
new file mode 100644
index 0000000000..5381beacc7
--- /dev/null
+++ b/usr/src/cmd/abi/spectrans/spec2trace/util.h
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ *
+ * 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 (c) 1997-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* String tables */
+typedef struct table_head_t {
+ int nelem;
+ int used;
+ char *elements[1]; /* Actually elements[nelem] */
+} table_t;
+
+
+/* Debugging information */
+extern void print_metainfo(const Meta_info *);
+extern void print_translatorinfo(const Translator_info *);
+
+extern char *get_string_table(table_t *, int);
+extern table_t *add_string_table(table_t *, char *);
+extern table_t *create_string_table(int);
+extern table_t *free_string_table(table_t *);
+extern int in_string_table(table_t *, char *);
+extern int in_string_set(char *, char *);
+extern void print_string_table(table_t *);
+extern void sort_string_table(table_t *);
+
+/* Generic parsing of strings */
+extern char *strnormalize(char *);
+extern char *strtrim(char *);
+extern char *strlower(char *);
+extern char *strset(char *, char *);
+extern char *strend(char *);
+extern char *lastspace(char *);
+extern char *skipb(char *);
+extern char *nextb(char *);
+extern char *skipsep(char *);
+extern char *nextsep(char *);
+extern char *nextsep2(char *);
+extern char *objectname(char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UTIL_H */
diff --git a/usr/src/pkgdefs/SUNWtoo/prototype_com b/usr/src/pkgdefs/SUNWtoo/prototype_com
index a37f0d3eff..750ae8588c 100644
--- a/usr/src/pkgdefs/SUNWtoo/prototype_com
+++ b/usr/src/pkgdefs/SUNWtoo/prototype_com
@@ -80,3 +80,6 @@ s none usr/lib/link_audit/32=.
f none usr/lib/link_audit/ldprof.so.1 755 root bin
f none usr/lib/link_audit/truss.so.1 755 root bin
f none usr/lib/link_audit/who.so.1 755 root bin
+d none usr/lib/abi 755 root bin
+f none usr/lib/abi/spec2map 755 root bin
+f none usr/lib/abi/spec2trace 755 root bin