diff options
author | raf <none@none> | 2006-09-20 12:15:03 -0700 |
---|---|---|
committer | raf <none@none> | 2006-09-20 12:15:03 -0700 |
commit | 753d2d2e8e7fd0c9bcf736d9bf2f2faf4d6234cc (patch) | |
tree | 0e82e5bff3540f84dc0e9088fec8662fe12afd1e /usr/src | |
parent | d25d47ee62f52e470a91221e64abe838a0af786d (diff) | |
download | illumos-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')
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 |