--- old/usr/src/pkg/manifests/system-test-libctest.mf	Thu Apr  2 18:43:03 2015
+++ new/usr/src/pkg/manifests/system-test-libctest.mf	Thu Apr  2 18:43:03 2015
@@ -12,7 +12,7 @@
 #
 # Copyright (c) 2012 by Delphix. All rights reserved.
 # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved.
-# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
 #
 
 set name=pkg.fmri value=pkg:/system/test/libctest@$(PKGVERS)
@@ -23,36 +23,72 @@
 set name=variant.arch value=$(ARCH)
 dir path=opt/libc-tests
 dir path=opt/libc-tests/bin
+dir path=opt/libc-tests/cfg
+dir path=opt/libc-tests/cfg/symbols
 dir path=opt/libc-tests/runfiles
 dir path=opt/libc-tests/tests
+dir path=opt/libc-tests/tests
+dir path=opt/libc-tests/tests/symbols
 file path=opt/libc-tests/README mode=0444
 file path=opt/libc-tests/bin/libctest mode=0555
+file path=opt/libc-tests/cfg/README mode=0444
+file path=opt/libc-tests/cfg/compilation.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/README mode=0444
+file path=opt/libc-tests/cfg/symbols/ctype_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/dirent_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/fcntl_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/locale_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/math_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/netdb_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/pthread_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/signal_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/stdio_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/stdlib_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/strings_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/sys_stat_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/sys_time_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/sys_timeb_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/ucontext_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/unistd_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/wchar_h.cfg mode=0444
+file path=opt/libc-tests/cfg/symbols/wctype_h.cfg mode=0444
 file path=opt/libc-tests/runfiles/default.run mode=0444
 file path=opt/libc-tests/tests/fpround_test mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/fpround_test.amd64 mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/fpround_test.i386 mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/fpround_test.sparc mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/fpround_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/fpround_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/fpround_test.$(ARCH64) mode=0555
 file path=opt/libc-tests/tests/newlocale_test mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/newlocale_test.amd64 mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/newlocale_test.i386 mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/newlocale_test.sparc mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/newlocale_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/newlocale_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/newlocale_test.$(ARCH64) mode=0555
 file path=opt/libc-tests/tests/nl_langinfo_test mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.amd64 mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.i386 mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.sparc mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/nl_langinfo_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/nl_langinfo_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/nl_langinfo_test.$(ARCH64) mode=0555
+file path=opt/libc-tests/tests/symbols/setup mode=0555
+file path=opt/libc-tests/tests/symbols/symbols_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/symbols/symbols_test.$(ARCH64) mode=0555
 file path=opt/libc-tests/tests/wcsrtombs_test mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.amd64 mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.i386 mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.sparc mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/wcsrtombs_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/wcsrtombs_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/wcsrtombs_test.$(ARCH64) mode=0555
 file path=opt/libc-tests/tests/wctype_test mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/wctype_test.amd64 mode=0555
-$(i386_ONLY)file path=opt/libc-tests/tests/wctype_test.i386 mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/wctype_test.sparc mode=0555
-$(sparc_ONLY)file path=opt/libc-tests/tests/wctype_test.sparcv9 mode=0555
+file path=opt/libc-tests/tests/wctype_test.$(ARCH) mode=0555
+file path=opt/libc-tests/tests/wctype_test.$(ARCH64) mode=0555
+hardlink path=opt/libc-tests/tests/symbols/ctype_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/dirent_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/fcntl_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/locale_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/math_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/netdb_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/pthread_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/signal_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/stdio_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/stdlib_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/strings_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/sys_stat_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/sys_time_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/sys_timeb_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/ucontext_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/unistd_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/wchar_h target=setup
+hardlink path=opt/libc-tests/tests/symbols/wctype_h target=setup
 license lic_CDDL license=lic_CDDL
 depend fmri=locale/de type=require
 depend fmri=locale/en type=require
--- old/usr/src/test/libc-tests/Makefile	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/Makefile	Thu Apr  2 18:43:04 2015
@@ -16,6 +16,6 @@
 
 .PARALLEL: $(SUBDIRS)
 
-SUBDIRS = cmd runfiles tests doc
+SUBDIRS = cfg cmd runfiles tests doc
 
 include $(SRC)/test/Makefile.com
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/Makefile	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,60 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+# Copyright (c) 2012 by Delphix. All rights reserved.
+#
+
+include $(SRC)/Makefile.master
+
+CFGS = README \
+	compilation.cfg \
+	symbols/README \
+	symbols/ctype_h.cfg \
+	symbols/dirent_h.cfg \
+	symbols/fcntl_h.cfg \
+	symbols/locale_h.cfg \
+	symbols/math_h.cfg \
+	symbols/netdb_h.cfg \
+	symbols/pthread_h.cfg \
+	symbols/signal_h.cfg \
+	symbols/stdio_h.cfg \
+	symbols/stdlib_h.cfg \
+	symbols/strings_h.cfg \
+	symbols/sys_stat_h.cfg \
+	symbols/sys_time_h.cfg \
+	symbols/sys_timeb_h.cfg \
+	symbols/ucontext_h.cfg \
+	symbols/unistd_h.cfg \
+	symbols/wchar_h.cfg \
+	symbols/wctype_h.cfg
+
+ROOTOPTPKG = $(ROOT)/opt/libc-tests
+ROOTOPTPKGCFG = $(ROOT)/opt/libc-tests/cfg
+ROOTOPTPKGDIRS = $(ROOTOPTPKG) \
+	$(ROOTOPTPKGCFG) \
+	$(ROOTOPTPKGCFG)/symbols
+
+FILES = $(CFGS:%=$(ROOTOPTPKGCFG)/%)
+$(FILES) := FILEMODE = 0444
+
+all: $(CFGS)
+
+install: $(ROOTOPTPKG) $(ROOTOPTPKGCFG) $(FILES)
+
+clean lint clobber:
+
+$(ROOTOPTPKGDIRS):
+	$(INS.dir)
+
+$(ROOTOPTPKGCFG)/%: % $(ROOTOPTPKGDIRS)
+	$(INS.file)
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/README	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,83 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+The configuration files in this directory are structured as lines,
+where each line is made up of fields, separated by "|" characters,
+possibly surrounded by whitespace.
+
+New lines preceeded by backslashes are ignored, allowing for a continuation
+of lines, in the usual UNIX way.
+
+A line beginning with a hashmark is a comment, and is ignored, as are lines
+consisting solely of whitespace.
+
+The first field is always the "keyword", which determines the meaning and
+presence of any other fields.
+
+These files are parsed using the test_load_config() function.  This
+function has the following prototype:
+
+	int test_load_config(test_t, const char *, ...);
+
+The variable arguments are the keywords and handling functions.  These
+must be supplied in pairs and the list is terminated with a NULL, like this:
+
+	test_config_load(t, "myfile.cfg", "mykeyword", keywordcb, NULL);
+
+The test_config_load function will search for the named file (provided it
+is not an absolute path) in a few locations:
+
+	* relative to the current directory, exactly as specified
+	* relative to $STF_SUITE/cfg/	(if $STF_SUITE is defined)
+	* relative to ../../cfg/	(if $STF_SUITE is undefined)
+	* relative to cfg/
+
+The handling functions (keywordcb in the example above) have the following
+typedef:
+
+	typedef int (*test_cfg_func_t)(char **fields, int nfields, char **err);
+
+so for example, keywordcb should be declared thusly:
+
+	int keywordcb(char **fields, int nfields, char **err);
+
+These functions are called each time a paired keyword is seen in the file.
+"fields" is an array of fields, pre-split with surrounding whitespace removed,
+and contains "nfields" items.  Internal whitespace is unaffected.
+
+The function should return 0 on successful handling, or -1 on failure.  In
+the event of failure, it should record an error string in "err" using
+asprintf() or strdup(). ("err" should be unmodified otherwise.)
+
+This parser is rather simplistic, and it lacks support for embedding "|"
+fields in lines, and also doesn't support escaping, so you can't add "\"
+at the end of a line (if you need that, leave some trailing whitespace).
+
+There are also some internal limits on the length of lines (1K), and on the
+number of fields (20).  As this is only used for these test suites, this
+should not be a significant limitation.
+
+Please see ../tests/symbols/symbols_test.c for an example of correct usage.
+
+Aside:
+
+  Astute readers may ask why invent a new configuration file, and why use
+  position based parsing instead of name value pairs.  These files are
+  optimized for specific needs, and intended to support relatively dense
+  information in a format that is easy for humans to work with.  JSON or XML
+  or even YAML could have served, but the overhead of a syntax was more than
+  we wanted to introduce.  Test suites are free to use other formats if they
+  choose, but this simple format has the advantage of being built-in and
+  easy to use.
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/compilation.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,87 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Compilation environments.
+#
+# Each compilation environment is declared using the keyword "env", like
+# this:
+#
+# env | <name> | <std> | <defs>
+#
+# <name> is just a symbolic name for environment.
+# <std>  indicates either c89 or c99, i.e. which C standard to compile
+#        under.  This infuences choice of compiler and switches.
+# <defs> is a list of CPP style -D or -U flags to define C preprocessor
+#        symbols.
+#
+# Groups of compilation environments can be named, using the "env_group"
+# keyword (this can also be used to create aliases):
+#
+# env_group | <name> | <envs>
+#
+# <name> is a name for the group or alias
+# <envs> is a whitespace separated list of previously declared environments
+#        or environment groups (or aliases).
+#
+
+env | XPG3		| c89 | -D_XOPEN_SOURCE
+env | XPG4		| c89 | -D_XOPEN_SOURCE -D_XOPEN_VERSION=4
+env | SUSv1		| c89 | -D_XOPEN_SOURCE -D_XOPEN_SOURCE_EXTENDED=1
+env | SUSv2		| c89 | -D_XOPEN_SOURCE=500
+env | SUSv3		| c99 | -D_XOPEN_SOURCE=600
+env | SUSv4		| c99 | -D_XOPEN_SOURCE=700
+env | POSIX-1990	| c89 | -D_POSIX_SOURCE
+env | POSIX-1992	| c89 | -D_POSIX_SOURCE -D_POSIX_C_SOURCE=2
+env | POSIX-1993	| c89 | -D_POSIX_C_SOURCE=199309L
+env | POSIX-1995	| c89 | -D_POSIX_C_SOURCE=199506L
+env | POSIX-2001	| c99 | -D_POSIX_C_SOURCE=200112L
+env | POSIX-2008	| c99 | -D_POSIX_C_SOURCE=200809L
+env | C90		| c89 |
+env | C99		| c99 |
+
+#
+# These are ordered from less inclusive (most recent) to most inclusive.
+# This allows for us to "include" by reference.
+#
+env_group | POSIX-2008+	| POSIX-2008
+env_group | POSIX-2001+	| POSIX-2008+ POSIX-2001
+env_group | POSIX-1995+ | POSIX-2001+ POSIX-1995
+env_group | POSIX-1993+ | POSIX-1995+ POSIX-1993
+env_group | POSIX-1992+ | POSIX-1993+ POSIX-1992
+env_group | POSIX-1990+ | POSIX-1992+ POSIX-1990
+env_group | POSIX+	| POSIX-1990+
+env_group | SUSv4+	| SUSv4 POSIX-2008+
+env_group | SUSv3+	| SUSv3 SUSv4+ POSIX-2001+
+env_group | SUSv2+	| SUSv2 SUSv3+
+env_group | SUSv1+	| SUSv1 SUSv2+
+env_group | SUS+	| SUSv1+
+env_group | XPG4+	| XPG4 SUSv1+
+env_group | XPG3+	| XPG3 XPG4+
+env_group | C99+	| C99 POSIX-2001+ SUSv3+
+env_group | C+		| C90 C99 POSIX+ SUS+
+env_group | ALL		| C+
+
+#
+# Aliases.
+#
+env_group | XPG4v2	| SUSv1
+env_group | XPG4v2+	| SUSv1+
+env_group | XPG5	| SUSv2
+env_group | XPG5+	| SUSv2+
+env_group | XPG6	| SUSv3
+env_group | XPG6+	| SUSv3+
+env_group | XPG7	| SUSv4
+env_group | XPG7+	| SUSv4+
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/README	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,72 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+The configuration files in this directory are structured using the
+syntax defined in the ../README file.  They make use of the compilation
+environments declared in ../compilation.cfg, and are processed by the
+symbols test.
+
+We have organized the files by header file, that is the tests for symbols
+declared in a header file (e.g. <unistd.h> appear in a file based on that
+header file's name (e.g. unistd_h.cfg.)  This is purely for convenience.
+
+Within these various declarations, we have the following field types:
+
+<envs>    This is a list of compilation environments where the symbol
+          should be legal.  To indicate that the symbol must not be legal
+          an environment group can be prefixed with "-".  For example,
+          "SUS+ -SUSv4+" indicates a symbol that is legal in all SUS
+	  environments up to SUSv3, and was removed in SUSv4 and subsequent
+          versions of SUS.  As you can see, we can list multiple environments
+          or environment groups, and we can add or remove to previous groups
+          with subsequent ones.
+
+<name>    This is a symbol name.  It follows the rules for C symbol names.
+
+<header>  This is a header file, for example, unistd.h.  Conventionally,
+          the header files used should match the file where the test is
+          declared.
+
+<type>    This is a C type.  Function types can be declared without their
+          names, e.g. "void (*)(int)".  Structures (e.g. "struct stat") and
+          pointer types (e.g. "pthead_t *") are legal as well.
+
+Here are the types of declarations in these files:
+
+type | <name> | <header> | <envs>
+
+    Tests for a C type with <name>.  The test verifies that a variable with
+    this type can be declared when the <header> is included.
+
+value | <name> | <type> | <header> | <envs>
+
+    Tests for a value named <name>, of type <type>.  The test attempts to
+    assign the given value to a scratch variable declared with the given
+    type.  The value can be a macro or other C symbol.
+
+func | <name> | <type> | <type> [; <type> ]... | <header> | <envs>
+
+    Tests whether a function <name>, returning the first <type>, and
+    taking arguments of following <type> values, is declared.  Note that
+    the argument types are separated by semicolons.  For varargs style
+    functions, leave out the ... part.  For function declarations
+    that have no declared arguments, either void can specified, or
+    the type list can be omitted.
+
+Examples:
+
+    type | size_t | sys/types.h | ALL
+    value | NULL | void * | stdlib.h | ALL
+    func strnlen | int | const char *; int | string.h | ALL
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/ctype_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in ctype.h
+#
+
+#
+# Types.
+#
+type | locale_t | ctype.h | -ALL +SUSv4+
+
+#
+# Values.
+#
+
+#
+# Functions
+#
+func | isalnum	| int	| int	| ctype.h	| +ALL
+func | isalpha	| int	| int	| ctype.h	| +ALL
+func | isascii	| int	| int	| ctype.h	| -ALL +XPG3+
+func | isblank	| int	| int	| ctype.h	| -ALL +C99+
+func | iscntrl	| int	| int	| ctype.h	| +ALL
+func | isdigit	| int	| int	| ctype.h	| +ALL
+func | isgraph	| int	| int	| ctype.h	| +ALL
+func | islower	| int	| int	| ctype.h	| +ALL
+func | isprint	| int	| int	| ctype.h	| +ALL
+func | ispunct	| int	| int	| ctype.h	| +ALL
+func | isspace	| int	| int	| ctype.h	| +ALL
+func | isupper	| int	| int	| ctype.h	| +ALL
+func | isxdigit	| int	| int	| ctype.h	| +ALL
+func | toascii	| int	| int	| ctype.h	| -ALL +XPG3+
+func | tolower	| int	| int	| ctype.h	| +ALL
+func | toupper	| int	| int	| ctype.h	| +ALL
+func | _tolower	| int	| int	| ctype.h	| -ALL +XPG3+
+func | _toupper	| int	| int	| ctype.h	| -ALL +XPG3+
+
+func | isalnum_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isalpha_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isblank_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | iscntrl_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isdigit_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isgraph_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | islower_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isprint_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | ispunct_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isspace_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isupper_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | isxdigit_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | tolower_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
+func | toupper_l	| int	| int; locale_t	| ctype.h	| -ALL +SUSv4+
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/dirent_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,69 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in dirent.h
+#
+# Note that this header is not defined prior to the POSIX & XPG3
+# specifications.  Therefore, applications which #include it in earlier
+# environments may reasonably obtain their contents, although such use
+# would not be conformant to those specifications.
+#
+# As a result, we only test the newer specifications.
+#
+
+#
+# Types.
+#
+type |	DIR *		| dirent.h | XPG3+ POSIX+
+type |	struct dirent	| dirent.h | XPG3+ POSIX+
+
+#
+# Values.
+#
+
+#
+# Functions
+#
+
+func |	opendir								|\
+	DIR *								|\
+	const char *							|\
+	dirent.h | POSIX+ XPG3+
+
+func |	readdir								|\
+	struct dirent *							|\
+	DIR *								|\
+	dirent.h | POSIX+ XPG3+
+
+# We are not going to test the draft interface.
+func |	readdir_r							|\
+	int								|\
+	DIR *; struct dirent *; struct dirent **			|\
+	dirent.h | POSIX-1995+
+
+func |	rewinddir							|\
+	void								|\
+	DIR * | dirent.h | POSIX+ XPG3+
+
+func |	seekdir								|\
+	void								|\
+	DIR *; long							|\
+	dirent.h | -POSIX+ XPG3+
+
+func |	telldir								|\
+	long								|\
+	DIR *								|\
+	dirent.h | -POSIX+ XPG3+
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/fcntl_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,62 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in fcntl.h
+#
+
+#
+# Types.
+#
+type |	mode_t		| fcntl.h | ALL
+type |	off_t		| fcntl.h | ALL
+type |	pid_t		| fcntl.h | ALL
+type |	struct flock	| fcntl.h | ALL
+
+#
+# Values.
+#
+value | O_ACCMODE	| int	| fcntl.h | POSIX+ SUS+
+value | O_APPEND	| int	| fcntl.h | POSIX+ SUS+
+value | O_CLOEXEC	| int	| fcntl.h | POSIX+ SUS+
+value | O_CREAT		| int	| fcntl.h | POSIX+ SUS+
+value | O_DSYNC		| int	| fcntl.h | XPG3+ POSIX-1993+
+value | O_EXCL		| int	| fcntl.h | POSIX+ SUS+
+value | O_NDELAY	| int	| fcntl.h | -POSIX-1993+
+value | O_NOCTTY	| int	| fcntl.h | POSIX+ SUS+
+value | O_NONBLOCK	| int	| fcntl.h | POSIX+ SUS+
+value | O_RDONLY	| int	| fcntl.h | POSIX+ SUS+
+value | O_RDWR		| int	| fcntl.h | POSIX+ SUS+
+value | O_RSYNC		| int	| fcntl.h | XPG3+ POSIX-1993+
+value | O_SYNC		| int	| fcntl.h | XPG3+ POSIX-1993+
+value | O_WRONLY	| int	| fcntl.h | POSIX+ SUS+
+
+#
+# Functions
+#
+func |	creat								|\
+	int								|\
+	const char *; mode_t						|\
+	fcntl.h | ALL
+
+func |	open								|\
+	int								|\
+	const char *; mode_t						|\
+	fcntl.h | ALL
+
+func |	fcntl								|\
+	int								|\
+	int; int							|\
+	fcntl.h | ALL
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/locale_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,64 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in locale.h
+#
+
+#
+# Types.
+#
+type |	locale_t	| locale.h | -ALL SUSv4+
+type |	struct lconv	| locale.h | ALL
+
+#
+# Values.
+#
+value |	LC_CTYPE		| int		| locale.h | ALL
+value | LC_COLLATE		| int		| locale.h | ALL
+value | LC_TIME			| int		| locale.h | ALL
+value | LC_NUMERIC		| int		| locale.h | ALL
+value |	LC_MONETARY		| int		| locale.h | ALL
+value |	LC_MESSAGES		| int		| locale.h | ALL
+value |	LC_GLOBAL_LOCALE	| locale_t	| locale.h | -ALL SUSv4+
+value |	NULL			| void *	| locale.h | ALL
+
+#
+# Functions
+#
+func |	duplocale							|\
+	locale_t							|\
+	locale_t							|\
+	locale.h | -ALL SUSv4+
+
+func |	newlocale							|\
+	locale_t							|\
+	int; const char *; locale_t					|\
+	locale.h | -ALL SUSv4+
+
+func |	freelocale							|\
+	void								|\
+	locale_t							|\
+	locale.h | -ALL SUSv4+
+
+func |	localeconv							|\
+	struct lconv *							|\
+	void								|\
+	locale.h | ALL
+
+func |	setlocale							|\
+	char *								|\
+	int; const char *						|\
+	locale.h | ALL
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/math_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,37 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in math.h
+#
+
+
+#
+# Types.
+#
+
+#
+# Values.
+#
+value | M_PI		| double	| math.h | SUS+
+value | INFINITY	| float		| math.h | C99+
+value | NAN		| float		| math.h | C99+
+value | FP_NAN		| int		| math.h | C99+
+
+#
+# Functions
+#
+func | cos	| double	| double	| math.h | ALL
+func | cosf	| float		| float		| math.h | -ALL +C99+
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/netdb_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,53 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in netdb.h
+#
+
+#
+# Types.
+#
+
+#
+# Values.
+#
+#value | h_errno	| int | netdb.h | -ALL SUS+ -SUSv4+
+#value | HOST_NOT_FOUND	| int | netdb.h | -ALL SUS+ -SUSv4+
+#value | NO_DATA	| int | netdb.h | -ALL SUS+ -SUSv4+
+#value | NO_RECOVERY	| int | netdb.h | -ALL SUS+ -SUSv4+
+#value | TRY_AGAIN	| int | netdb.h | -ALL SUS+ -SUSv4+
+
+#
+# Functions
+#
+
+func |	endhostent			|\
+	void				|\
+	void				|\
+	netdb.h				|\
+	SUS+
+
+func |	gethostent			|\
+	struct hostent *		|\
+	void				|\
+	netdb.h				|\
+	SUS+
+
+func |	sethostent			|\
+	void				|\
+	int				|\
+	netdb.h				|\
+	SUS+ 
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/pthread_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,63 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in pthread.h
+#
+# Note that this header is not defined prior to the POSIX 1995 & SUSv2
+# specifications.  Therefore, applications which #include it in earlier
+# environments may reasonably obtain their contents, although such use
+# would not be conformant to those specifications.
+#
+# As a result, we only test the newer specifications.
+#
+
+#
+# Types.
+#
+type |	pthread_t *	| pthread.h | POSIX-1995+ SUSv2+
+
+#
+# Values.
+#
+value |	PTHREAD_SCOPE_PROCESS	| int	| pthread.h | POSIX-1995+ SUSv2+
+value |	PTHREAD_SCOPE_SYSTEM	| int	| pthread.h | POSIX-1995+ SUSv2+
+
+#
+# Functions
+#
+func |	pthread_create							|\
+	int								|\
+	pthread_t *; const pthread_attr_t *; void *(*)(void *); void *	|\
+	pthread.h							|\
+	POSIX-1995+ SUSv2+
+
+func |	pthread_self							|\
+	pthread_t							|\
+	void								|\
+	pthread.h							|\
+	POSIX-1995+ SUSv2+
+
+func |	pthread_attr_getscope						|\
+	int								|\
+	const pthread_attr_t *; int *					|\
+	pthread.h							|\
+	POSIX-1995+ SUSv2+
+
+func |	pthread_attr_setscope						|\
+	int								|\
+	pthread_attr_t *; int						|\
+	pthread.h							|\
+	POSIX-1995+ SUSv2+
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/signal_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,32 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in signal.h
+#
+
+#
+# Types.
+#
+type | ucontext_t | signal.h | -ALL SUS+
+
+#
+# Values.
+#
+value | SIG_DFL | void (*)(int) | signal.h | ALL
+
+#
+# Functions.
+#
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/stdio_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,53 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in stdio.h
+#
+
+#
+# Types.
+#
+type |	FILE	| stdio.h | ALL
+type |	fpos_t	| stdio.h | ALL
+type |	size_t	| stdio.h | ALL
+
+#
+# Values.
+#
+value |	BUFSIZ	| int		| stdio.h | ALL
+value |	EOF	| int		| stdio.h | ALL
+value |	NULL	| void *	| stdio.h | ALL
+value | stderr	| FILE *	| stdio.h | ALL
+value |	stdin	| FILE *	| stdio.h | ALL
+value | stdout	| FILE *	| stdio.h | ALL
+value | optarg	| char *	| stdio.h | -ALL +XPG3+ -SUSv3+
+value | optind	| int		| stdio.h | -ALL +XPG3+ -SUSv3+
+value | opterr	| int		| stdio.h | -ALL +XPG3+ -SUSv3+
+value | optopt	| int		| stdio.h | -ALL +XPG3+ -SUSv3+
+
+#
+# Functions
+#
+
+func |	printf								|\
+	int								|\
+	const char * 							|\
+	stdio.h | ALL
+	
+func |	rename								|\
+	int 								|\
+	const char *; const char *					|\
+	stdio.h | ALL
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/stdlib_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,57 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in stdlib.h
+#
+
+#
+# Types.
+#
+type |	size_t		| stdlib.h | ALL
+
+#
+# Values.
+#
+value |	EXIT_FAILURE	| int		| stdlib.h | ALL
+value |	EXIT_SUCCESS	| int		| stdlib.h | ALL
+value |	NULL		| void *	| stdlib.h | ALL
+
+#
+# Functions
+#
+func |	calloc								|\
+	void * 								|\
+	size_t; size_t							|\
+	stdlib.h							|\
+	ALL
+
+func |	exit								|\
+	void 								|\
+	int								|\
+	stdlib.h							|\
+	ALL
+
+func |	free								|\
+	void 								|\
+	void *								|\
+	stdlib.h							|\
+	ALL
+
+func |	malloc								|\
+	void * 								|\
+	size_t								|\
+	stdlib.h							|\
+	ALL
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/strings_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,30 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in strings.h
+#
+
+#
+# Types.
+#
+
+#
+# Values.
+#
+
+#
+# Functions
+#
--- /dev/null	Thu Apr  2 18:43:04 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/sys_stat_h.cfg	Thu Apr  2 18:43:04 2015
@@ -0,0 +1,58 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in sys/stat.h
+#
+
+#
+# Types.
+#
+type |	mode_t		| sys/stat.h | ALL
+type |	struct stat	| sys/stat.h | ALL
+
+#
+# Values.
+#
+value | S_IFMT		| mode_t | sys/stat.h | ALL
+value |	S_IFBLK		| mode_t | sys/stat.h | ALL
+
+#
+# Functions
+#
+func |	chmod							|\
+	int							|\
+	const char *; mode_t					|\
+	sys/stat.h | POSIX+ XPG3+
+
+func |	fchmod							|\
+	int							|\
+	int; mode_t						|\
+	sys/stat.h | -POSIX+ -XPG3+ POSIX-1993+ SUS+	
+
+func |	fstat							|\
+	int							|\
+	int; struct stat *					|\
+	sys/stat.h | XPG3+ POSIX+
+
+func |	mkdir							|\
+	int							|\
+	const char *; mode_t					|\
+	sys/stat.h | XPG3+ POSIX+
+
+func |	mknod							|\
+	int							|\
+	const char *; mode_t; dev_t				|\
+	sys/stat.h | -XPG3+ -POSIX+ SUS+
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/sys_time_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,42 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in sys/time.h
+#
+
+#
+# Types.
+#
+#type | time_t | sys/timeb.h | -ALL SUS+ -SUSv4+
+#type | struct timeb | sys/timeb.h | -ALL SUS+ -SUSv4+
+
+#
+# Values.
+#
+
+#
+# Functions
+#
+func |	futimesat					|\
+	int						|\
+	int; const char *; const struct timeval [2]	|\
+	sys/time.h					|\
+	-SUS+ -POSIX+
+
+func |	utimes						|\
+	int						|\
+	const char *; const struct timeval [2]		|\
+	sys/time.h | -POSIX+ -XPG3+ SUS+
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/sys_timeb_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,30 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in sys/timeb.h
+#
+
+#
+# Types.
+#
+
+#
+# Values.
+#
+
+#
+# Functions
+#
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/ucontext_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,30 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in ucontext.h
+#
+
+#
+# Types.
+#
+
+#
+# Values.
+#
+
+#
+# Functions
+#
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/unistd_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,140 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in unistd.h
+#
+
+#
+# Types.
+#
+type | pid_t | unistd.h | POSIX+ SUS+
+
+#
+# Values.
+#
+# Note that the standard requires the user declare environ.
+# value | environ | char ** | unistd.h | POSIX+ SUS+
+value | _CS_PATH				| int | unistd.h | SUS+
+
+value | _CS_POSIX_V6_ILP32_OFF32_CFLAGS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_ILP32_OFF32_LDFLAGS	| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_ILP32_OFF32_LIBS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS	| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS	| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_ILP32_OFFBIG_LIBS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LP64_OFF64_CFLAGS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LP64_OFF64_LDFLAGS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LP64_OFF64_LIBS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS	| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS	| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_LPBIG_OFFBIG_LIBS		| int | unistd.h | SUSv3+
+value | _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS	| int | unistd.h | SUSv3+
+
+#
+# Functions
+#
+func |	access							|\
+	int							|\
+	const char *; int					|\
+	unistd.h | POSIX+ SUS+
+
+func |	chown							|\
+	int							|\
+	const char *; uid_t; gid_t				|\
+	unistd.h | POSIX+ SUS+
+
+func |	execl 							|\
+	int							|\
+	const char *; const char *				|\
+	unistd.h | POSIX+ SUS+
+
+func |	execle 							|\
+	int							|\
+	const char *; const char *; char *; char *const []	|\
+	unistd.h | POSIX+ SUS+
+
+func |	execlp 							|\
+	int							|\
+	const char *; const char *; char *			|\
+	unistd.h | POSIX+ SUS+
+
+func |	execv 							|\
+	int							|\
+	const char *; char *const []				|\
+	unistd.h | POSIX+ SUS+
+
+func |	execve 							|\
+	int							|\
+	const char *; char *const []; char *const []		|\
+	unistd.h | POSIX+ SUS+
+
+func |	execvp 							|\
+	int							|\
+	const char *; char *const []				|\
+	unistd.h | POSIX+ SUS+
+
+func |	fchown							|\
+	int							|\
+	int; uid_t; gid_t					|\
+	unistd.h | -POSIX+ SUS+
+
+func |	getlogin						|\
+	char *							|\
+	void							|\
+	unistd.h | POSIX+ SUS+
+
+func |	getlogin_r						|\
+	int							|\
+	char *; size_t						|\
+	unistd.h | -POSIX+ -SUS+ +POSIX-1995+ SUSv2+
+
+func |	lchown							|\
+	int							|\
+	const char *; uid_t; gid_t				|\
+	unistd.h | -POSIX+ SUS+
+
+func |	link							|\
+	int							|\
+	const char *; const char *				|\
+	unistd.h | POSIX+ SUS+
+
+# XPG3 may have put this here incorrectly (Open Group says no..., but...)
+# Probably this is actually our error, and we should kill it, but we can
+# do that when kill off XPG3 support altogether.
+func |	rename							|\
+	int							|\
+	const char *; const char *				|\
+	unistd.h | -POSIX+ +XPG3 -XPG4+
+
+func |	symlink							|\
+	int							|\
+	const char *; const char *				|\
+	unistd.h | -XPG3+ -POSIX+ SUS+
+
+func |	ttyname							|\
+	char *							|\
+	int							|\
+	unistd.h | POSIX+ SUS+
+
+func |	ttyname_r						|\
+	int							|\
+	int; char *; size_t					|\
+	unistd.h | -POSIX+ -SUS+ +POSIX-1995+ SUSv2+
+
+func |	unlink							|\
+	int							|\
+	const char *						|\
+	unistd.h | POSIX+ XPG3+
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/wchar_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,83 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in wchar.h
+#
+
+#
+# Types.
+#
+type | locale_t | wchar.h |  -ALL SUSv4+
+type | wctype_t | wchar.h |  -ALL XPG3+
+
+#
+# Values.
+#
+value | NULL | void * | wchar.h | ALL
+
+#
+# Functions
+#
+func |	wcpcpy							|\
+	wchar_t *						|\
+	wchar_t *; const wchar_t *				|\
+	wchar.h | -ALL SUSv4+
+
+func |	wcpncpy							|\
+	wchar_t *						|\
+	wchar_t *; const wchar_t *; size_t			|\
+	wchar.h	| -ALL SUSv4+
+
+func |	wcsdup							|\
+	wchar_t *						|\
+	const wchar_t *						|\
+	wchar.h | -ALL SUSv4+
+
+func |	wcscasecmp						|\
+	int							|\
+	const wchar_t *; const wchar_t *			|\
+	wchar.h	| -ALL SUSv4+
+
+func |	wcscasecmp_l						|\
+	int							|\
+	const wchar_t *; const wchar_t *; locale_t		|\
+	wchar.h | -ALL SUSv4+
+
+# technically this is new in C90-Amd1, but we don't have a test for it.
+func |	wcslen							|\
+	size_t							|\
+	const wchar_t *						|\
+	wchar.h | ALL
+
+func |	wcsncasecmp						|\
+	int							|\
+	const wchar_t *; const wchar_t *; size_t		|\
+	wchar.h	| -ALL SUSv4+
+
+func |	wcsncasecmp_l						|\
+	int							|\
+	const wchar_t *; const wchar_t *; size_t; locale_t	|\
+	wchar.h	| -ALL SUSv4+
+
+func |	wcsnlen							|\
+	size_t							|\
+	const wchar_t *; size_t					|\
+	wchar.h	| -ALL SUSv4+
+
+func |	wcswcs							|\
+	wchar_t *						|\
+	const wchar_t *; const wchar_t *			|\
+	wchar.h	| -ALL XPG4+
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/cfg/symbols/wctype_h.cfg	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,36 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
+#
+
+#
+# Definitions found in wctype.h
+#
+
+#
+# Types.
+#
+type |	wint_t		| wctype.h | ALL
+
+#
+# Values.
+#
+value |	WEOF		| wint_t	| wctype.h | ALL -XPG4+ SUSv2+
+
+#
+# Functions
+#
+func |	iswalnum							|\
+	int								|\
+	wint_t								|\
+	wctype.h | ALL
--- old/usr/src/test/libc-tests/runfiles/default.run	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/runfiles/default.run	Thu Apr  2 18:43:05 2015
@@ -31,3 +31,26 @@
 [/opt/libc-tests/tests/wcsrtombs_test]
 
 [/opt/libc-tests/tests/wctype_test]
+
+[/opt/libc-tests/tests/symbols]
+pre = setup
+tests = [
+	'ctype_h',
+	'dirent_h',
+	'fcntl_h',
+	'locale_h',
+	'math_h',
+	'netdb_h',
+	'pthread_h',
+	'signal_h',
+	'stdio_h',
+	'stdlib_h',
+	'strings_h',
+	'sys_stat_h',
+	'sys_time_h',
+	'sys_timeb_h',
+	'ucontext_h',
+	'unistd_h',
+	'wchar_h',
+	'wctype_h'
+	 ]
--- old/usr/src/test/libc-tests/tests/Makefile	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/Makefile	Thu Apr  2 18:43:05 2015
@@ -11,10 +11,10 @@
 
 #
 # Copyright (c) 2012 by Delphix. All rights reserved.
-# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+# Copyright 2015 Garrett D'Amore <garrett@damore.org>
 #
 
-SUBDIRS = fpround newlocale nl_langinfo wcsrtombs wctype
+SUBDIRS = fpround newlocale nl_langinfo symbols wcsrtombs wctype
 
 include $(SRC)/Makefile.master
 include $(SRC)/test/Makefile.com
--- old/usr/src/test/libc-tests/tests/Makefile.com	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/Makefile.com	Thu Apr  2 18:43:05 2015
@@ -29,13 +29,15 @@
 
 C99MODE = -xc99=%all
 LINTFLAGS += -I../common -DARCH=\"ARCH\" -DLINT
-CPPFLAGS += -I../common
+CPPFLAGS += -I$(ROOT)/usr/include -I../common
 
 ROOTOPTPKG = $(ROOT)/opt/libc-tests
-TESTDIR = $(ROOTOPTPKG)/tests
+TESTDIR = $(ROOTOPTPKG)/tests/$(TESTSUBDIR)
 
 CMDS = $(PROG32:%=$(TESTDIR)/%) $(PROG64:%=$(TESTDIR)/%) \
-	$(KSHPROG:%=$(TESTDIR)/%) $(ARCHPROG:%=$(TESTDIR)/%)
+	$(KSHPROG:%=$(TESTDIR)/%) $(ARCHPROG:%=$(TESTDIR)/%) \
+	$(EXTRAPROG:%=$(TESTDIR)/%)
+
 $(CMDS) := FILEMODE = 0555
 
 all: $(PROG32) $(PROG64) $(KSHPROG) $(ARCHPROG) $(SUBDIRS)
--- old/usr/src/test/libc-tests/tests/common/test_common.c	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/common/test_common.c	Thu Apr  2 18:43:05 2015
@@ -10,7 +10,7 @@
  */
 
 /*
- * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  */
 
 /*
@@ -20,7 +20,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <string.h>
+#include <errno.h>
 #include <pthread.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/param.h>
 #include "test_common.h"
 
 static int debug = 0;
@@ -27,6 +32,9 @@
 static int force = 0;
 static pthread_mutex_t lk;
 
+static int passes;
+static int tests;
+
 struct test {
 	char		*name;
 	int		ntids;
@@ -76,10 +84,12 @@
 	test_passed(t);
 	test_set_debug();
 	test_set_force();
+	test_summary();
+	(void) test_load_config(t, NULL, NULL);
 #endif
 
+	tests++;
 	return (t);
-
 }
 
 void
@@ -88,6 +98,16 @@
 	va_list args;
 
 	(void) pthread_mutex_lock(&lk);
+	if (t == NULL) {
+		(void) printf("FAILURE: ");
+		va_start(args, format);
+		(void) vprintf(format, args);
+		va_end(args);
+		(void) printf("\n");
+		(void) fflush(stdout);
+		(void) pthread_mutex_unlock(&lk);
+		return;
+	}
 	if (force || (t->ntids > 0)) {
 		(void) printf("TEST FAILING %s: ", t->name);
 	} else {
@@ -114,6 +134,9 @@
 void
 test_passed(test_t t)
 {
+	if (t == NULL) {
+		return;
+	}
 	if (t->ntids > 0) {
 		if (debug) {
 			(void) pthread_mutex_lock(&lk);
@@ -124,6 +147,7 @@
 	}
 	(void) pthread_mutex_lock(&lk);
 	if (t->fails == 0) {
+		passes++;
 		(void) printf("TEST PASS: %s\n", t->name);
 	} else {
 		(void) printf("TEST FAILED: %d failures\n", t->fails);
@@ -138,6 +162,17 @@
 }
 
 void
+test_summary(void)
+{
+	if (passes == tests) {
+		(void) printf("TEST SUMMARY: %d / %d (ok)\n", passes, tests);
+	} else {
+		(void) printf("TEST SUMMARY: %d / %d (%d failing)\n",
+		    passes, tests, tests - passes);
+	}
+}
+
+void
 test_debugf(test_t t, const char *format, ...)
 {
 	va_list args;
@@ -146,8 +181,11 @@
 		return;
 
 	(void) pthread_mutex_lock(&lk);
-	(void) printf("TEST DEBUG %s: ", t->name);
-
+	if (t) {
+		(void) printf("TEST DEBUG %s: ", t->name);
+	} else {
+		(void) printf("TEST DEBUG: ");
+	}
 	va_start(args, format);
 	(void) vprintf(format, args);
 	va_end(args);
@@ -203,4 +241,166 @@
 		t->ntids--;
 	}
 	test_passed(t);
+}
+
+void
+test_trim(char **ptr)
+{
+	char *p = *ptr;
+	while (isspace(*p)) {
+		p++;
+	}
+	*ptr = p;
+	p += strlen(p);
+	while ((--p >= *ptr) && (isspace(*p))) {
+		*p = 0;
+	}
+}
+
+#define	MAXCB		20
+#define	MAXFIELD	20
+
+int
+test_load_config(test_t t, const char *fname, ...)
+{
+	va_list		va;
+	const char	*keyws[MAXCB];
+	test_cfg_func_t	callbs[MAXCB];
+	char		*fields[MAXFIELD];
+	int		nfields;
+
+	FILE    	*cfg;
+	char    	line[1024];
+	char    	buf[1024];
+	int		done;
+	char		*ptr;
+	char		*tok;
+	char		*err;
+	int		lineno;
+	int		rv;
+	int		found;
+	char		path[MAXPATHLEN];
+	int		i;
+
+	va_start(va, fname);
+	for (i = 0; i < MAXCB; i++) {
+		keyws[i] = (const char *)va_arg(va, const char *);
+		if (keyws[i] == NULL)
+			break;
+		callbs[i] = (test_cfg_func_t)va_arg(va, test_cfg_func_t);
+	}
+	va_end(va);
+	if (i == MAXCB) {
+		test_debugf(t, "too many arguments to function >= %d", MAXCB);
+	}
+
+	found = 0;
+
+	if (access(fname, F_OK) == 0) {
+		found++;
+	}
+	if (!found && fname[0] != '/') {
+		char *stf = getenv("STF_SUITE");
+		if (stf == NULL) {
+			stf = "../..";
+		}
+		(void) snprintf(path, sizeof (path), "%s/cfg/%s", stf, fname);
+		if (access(path, F_OK) == 0) {
+			fname = path;
+			found++;
+		} else {
+			(void) snprintf(path, sizeof (path), "cfg/%s", fname);
+			if (access(path, F_OK) == 0) {
+				fname = path;
+				found++;
+			}
+		}
+	}
+
+	if ((cfg = fopen(fname, "r")) ==  NULL) {
+		test_failed(t, "open(%s): %s", fname, strerror(errno));
+		return (-1);
+	}
+
+	line[0] = 0;
+	done = 0;
+	lineno = 0;
+
+	while (!done) {
+
+		lineno++;
+
+		if (fgets(buf, sizeof (buf), cfg) == NULL) {
+			done++;
+		} else {
+			(void) strtok(buf, "\n");
+			if ((*buf != 0) && (buf[strlen(buf)-1] == '\\')) {
+				/*
+				 * Continuation.  This isn't quite right,
+				 * as it doesn't allow for a "\" at the
+				 * end of line (no escaping).
+				 */
+				buf[strlen(buf)-1] = 0;
+				(void) strlcat(line, buf, sizeof (line));
+				continue;
+			}
+			(void) strlcat(line, buf, sizeof (line));
+		}
+
+		/* got a line */
+		ptr = line;
+		test_trim(&ptr);
+
+		/* skip comments and empty lines */
+		if (ptr[0] == 0 || ptr[0] == '#') {
+			line[0] = 0;
+			continue;
+		}
+
+		tok = strsep(&ptr, "|");
+		if (tok == NULL) {
+			break;
+		}
+		test_trim(&tok);
+
+		for (nfields = 0; nfields < MAXFIELD; nfields++) {
+			fields[nfields] = strsep(&ptr, "|");
+			if (fields[nfields] == NULL) {
+				break;
+			}
+			test_trim(&fields[nfields]);
+		}
+
+		found = 0;
+		rv = 0;
+
+		for (int i = 0; keyws[i] != NULL; i++) {
+			if (strcmp(tok, keyws[i]) == 0) {
+				found++;
+				err = NULL;
+				rv = callbs[i](fields, nfields, &err);
+			}
+		}
+		if (!found) {
+			rv = -1;
+			err = NULL;
+			(void) asprintf(&err, "unknown keyword %s", tok);
+		}
+		if (rv != 0) {
+			if (err) {
+				test_failed(t, "%s:%d: %s", fname,
+				    lineno, err);
+				free(err);
+			} else {
+				test_failed(t, "%s:%d: unknown error",
+				    fname, lineno);
+			}
+			(void) fclose(cfg);
+			return (rv);
+		}
+
+		line[0] = 0;
+	}
+	(void) fclose(cfg);
+	return (0);
 }
--- old/usr/src/test/libc-tests/tests/common/test_common.h	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/common/test_common.h	Thu Apr  2 18:43:05 2015
@@ -34,7 +34,18 @@
 extern void test_passed(test_t);
 extern void test_debugf(test_t, const char *format, ...);
 extern void test_run(int nthr, test_func_t, void *arg, const char *, ...);
+extern void test_summary(void);
 
+extern void test_trim(char **);
+
+typedef int (*test_cfg_func_t)(char **fields, int nfields, char **err);
+
+/*
+ * Args list is array of pairs of const char *keyword, test_config_func_t,
+ * terminated by NULL.
+ */
+extern int test_load_config(test_t, const char *, ...);
+
 #ifdef	__cplusplus
 }
 #endif
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/symbols/Makefile	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,47 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+include $(SRC)/Makefile.master
+
+TESTSUBDIR = symbols
+PROG = symbols_test
+KSHPROG = setup
+SYMTESTS = \
+	ctype_h \
+	dirent_h \
+	fcntl_h \
+	locale_h \
+	math_h \
+	netdb_h \
+	pthread_h \
+	signal_h \
+	stdio_h \
+	stdlib_h \
+	strings_h \
+	sys_stat_h \
+	sys_time_h \
+	sys_timeb_h \
+	ucontext_h \
+	unistd_h \
+	wchar_h \
+	wctype_h
+
+EXTRAPROG += $(SYMTESTS)
+
+include ../Makefile.com
+
+$(SYMTESTS:%=$(TESTDIR)/%): $(TESTDIR)/setup
+	-$(RM) $@
+	$(LN) $(TESTDIR)/setup $@
--- /dev/null	Thu Apr  2 18:43:05 2015
+++ new/usr/src/test/libc-tests/tests/symbols/setup.ksh	Thu Apr  2 18:43:05 2015
@@ -0,0 +1,75 @@
+#!/usr/bin/ksh
+#
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2014 Garrett D'Amore <garrett@damore.org>
+#
+
+export STF_SUITE=/opt/libc-tests
+
+# First we set $dir to dirname $0, using efficient ksh builtins.
+case $0 in
+*/*)	
+	dir=${0%/*}
+	prog=${0##*/}
+	;;
+*)
+	dir=.
+	prog=${0}
+	;;
+esac
+
+cfg=symbols/${prog%.ksh}.cfg
+
+if [[ ! -f ${cfg} && $cfg == symbols/setup.cfg ]]
+then
+	# compiler check only
+	cfg=-C
+fi
+
+prog=symbols_test
+
+for a in $* 
+do
+	if [[ $a == "-d" ]]
+	then
+		debug=yes
+	fi
+done
+
+# We look for architecture specific versions of the program,
+# searching in several candidate directories.  We run each one as
+# we find it.
+for f in $(/usr/bin/isainfo)
+do
+	found=
+	[[ -n $debug ]] && print "Checking for arch $f:"
+	for p in \
+		${dir}/${prog}.${f} \
+		${dir}/${f}/${prog}.${f} \
+		${dir}/${f}/${prog}
+	do
+		[[ -n $found ]] && continue
+		[[ -n $debug ]] && print -n "     $p"
+		if [[ -f $p ]]; then
+			[[ -n $debug ]] && print " FOUND"
+			[[ -n $debug ]] && print "Executing $p $* ${cfg}"
+			found=yes
+			$p $* ${cfg} || exit 1
+		else
+			[[ -n $debug ]] && print
+		fi
+	done
+	[[ -z $found ]] && [[ -n $debug ]] && print "NOT PRESENT"
+done
+exit 0
--- /dev/null	Thu Apr  2 18:43:06 2015
+++ new/usr/src/test/libc-tests/tests/symbols/symbols_test.c	Thu Apr  2 18:43:06 2015
@@ -0,0 +1,957 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2015 Garrett D'Amore <garrett@damore.org>
+ */
+
+/*
+ * This program tests symbol visibility using the /usr/bin/c89 and
+ * /usr/bin/c99 programs.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <note.h>
+#include <sys/wait.h>
+#include "test_common.h"
+
+char *dname;
+char *cfile;
+char *ofile;
+char *lfile;
+char *efile;
+
+const char *sym = NULL;
+
+static int good_count = 0;
+static int fail_count = 0;
+static int full_count = 0;
+static int extra_debug = 0;
+static char *compilation = "compilation.cfg";
+
+#if defined(_LP64)
+#define	MFLAG "-m64"
+#elif defined(_ILP32)
+#define	MFLAG "-m32"
+#endif
+
+const char *compilers[] = {
+	"cc",
+	"gcc",
+	"/opt/SUNWspro/bin/cc",
+	"/opt/gcc/4.4.4/bin/gcc",
+	"/opt/sunstudio12.1/bin/cc",
+	"/opt/sfw/bin/gcc",
+	"/usr/local/bin/gcc",
+	NULL
+};
+
+char *compiler = NULL;
+const char *c89flags = NULL;
+const char *c99flags = NULL;
+
+#define	MAXENV	64	/* maximum number of environments (bitmask width) */
+#define	MAXHDR	10	/* maximum # headers to require to access symbol */
+#define	MAXARG	20	/* maximum # of arguments */
+
+#define	WS	" \t"
+
+static int next_env = 0;
+
+struct compile_env {
+	char		*ce_name;
+	char		*ce_lang;
+	char		*ce_defs;
+	int		ce_index;
+};
+
+static struct compile_env compile_env[MAXENV];
+
+struct env_group {
+	char			*eg_name;
+	uint64_t		eg_mask;
+	struct env_group	*eg_next;
+};
+
+typedef enum { SYM_TYPE, SYM_VALUE, SYM_FUNC } sym_type_t;
+
+struct sym_test {
+	char			*st_name;
+	sym_type_t		st_type;
+	char			*st_hdrs[MAXHDR];
+	char			*st_rtype;
+	char			*st_atypes[MAXARG];
+	uint64_t		st_test_mask;
+	uint64_t		st_need_mask;
+	char			*st_prog;
+	struct sym_test		*st_next;
+};
+
+struct env_group *env_groups = NULL;
+
+struct sym_test *sym_tests = NULL;
+struct sym_test **sym_insert = &sym_tests;
+
+static char *
+mystrdup(const char *s)
+{
+	char *r;
+	if ((r = strdup(s)) == NULL) {
+		perror("strdup");
+		exit(1);
+	}
+	return (r);
+}
+
+static void *
+myzalloc(size_t sz)
+{
+	void *buf; 
+	if ((buf = calloc(1, sz)) == NULL) {
+		perror("calloc");
+		exit(1);
+	}
+	return (buf);
+}
+
+static void
+myasprintf(char **buf, const char *fmt, ...)
+{
+	int rv;
+	va_list va;
+	va_start(va, fmt);
+	rv = vasprintf(buf, fmt, va);
+	va_end(va);
+	if (rv < 0) {
+		perror("vasprintf");
+		exit(1);
+	}
+}
+
+static void
+append_sym_test(struct sym_test *st)
+{
+	*sym_insert = st;
+	sym_insert = &st->st_next;
+}
+
+static int
+find_env_mask(const char *name, uint64_t *mask)
+{
+	for (int i = 0; i < MAXENV; i++) {
+		if (compile_env[i].ce_name != NULL &&
+		    strcmp(compile_env[i].ce_name, name) == 0) {
+			*mask |= (1ULL << i);
+			return (0);
+		}
+	}
+
+	for (struct env_group *eg = env_groups; eg != NULL; eg = eg->eg_next) {
+		if (strcmp(name, eg->eg_name) == 0) {
+			*mask |= eg->eg_mask;
+			return (0);
+		}
+	}
+	return (-1);
+}
+
+
+static int
+expand_env(char *list, uint64_t *mask, char **erritem)
+{
+	char *item;
+	for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
+		if (find_env_mask(item, mask) < 0) {
+			if (erritem != NULL) {
+				*erritem = item;
+			}
+			return (-1);
+		}
+	}
+	return (0);
+}
+
+static int
+expand_env_list(char *list, uint64_t *test, uint64_t *need, char **erritem)
+{
+	uint64_t mask = 0;
+	int act;
+	char *item;
+	for (item = strtok(list, WS); item != NULL; item = strtok(NULL, WS)) {
+		switch (item[0]) {
+		case '+':
+			act = 1;
+			item++;
+			break;
+		case '-':
+			act = 0;
+			item++;
+			break;
+		default:
+			act = 1;
+			break;
+		}
+
+		mask = 0;
+		if (find_env_mask(item, &mask) < 0) {
+			if (erritem != NULL) {
+				*erritem = item;
+			}
+			return (-1);
+		}
+		*test |= mask;
+		if (act) {
+			*need |= mask;
+		} else {
+			*need &= ~(mask);
+		}
+	}
+	return (0);
+}
+
+static int
+do_env(char **fields, int nfields, char **err)
+{
+	char *name;
+	char *lang;
+	char *defs;
+
+	if (nfields != 3) {
+		myasprintf(err, "number of fields (%d) != 3", nfields);
+		return (-1);
+	}
+
+	if (next_env >= MAXENV) {
+		myasprintf(err, "too many environments");
+		return (-1);
+	}
+
+	name = fields[0];
+	lang = fields[1];
+	defs = fields[2];
+
+	compile_env[next_env].ce_name = mystrdup(name);
+	compile_env[next_env].ce_lang = mystrdup(lang);
+	compile_env[next_env].ce_defs = mystrdup(defs);
+	compile_env[next_env].ce_index = next_env;
+	next_env++;
+	return (0);
+}
+
+static int
+do_env_group(char **fields, int nfields, char **err)
+{
+	char *name;
+	char *list;
+	struct env_group *eg;
+	uint64_t mask;
+	char *item;
+
+	if (nfields != 2) {
+		myasprintf(err, "number of fields (%d) != 2", nfields);
+		return (-1);
+	}
+
+	name = fields[0];
+	list = fields[1];
+	mask = 0;
+
+	if (expand_env(list, &mask, &item) < 0) {
+		myasprintf(err, "reference to undefined env %s", item);
+		return (-1);
+	}
+
+	eg = myzalloc(sizeof (*eg));
+	eg->eg_name = mystrdup(name);
+	eg->eg_mask = mask;
+	eg->eg_next = env_groups;
+	env_groups = eg;
+	return (0);
+}
+
+static char *progbuf = NULL;
+size_t proglen = 0;
+size_t progsiz = 0;
+
+static void 
+addprogch(char c)
+{
+	while (progsiz <= (proglen + 1)) {
+		progbuf = realloc(progbuf, progsiz + 4096);
+		if (progbuf == NULL) {
+			perror("realloc");
+			exit(1);
+		}
+		progsiz += 1024;
+	}
+	progbuf[proglen++] = c;
+	progbuf[proglen] = 0;
+}
+
+static void
+addprogstr(char *s)
+{
+	while (*s != NULL) {
+		addprogch(*s);
+		s++;
+	}
+}
+
+static void
+addprogfmt(const char *fmt, ...)
+{
+	va_list va;
+	char *buf = NULL;
+	va_start(va, fmt);
+	if (vasprintf(&buf, fmt, va) < 0) {
+		perror("vasprintf");
+		exit(1);
+	}
+	va_end(va);
+	addprogstr(buf);
+	free(buf);
+}
+
+static void
+mkprog(struct sym_test *st)
+{
+	char *s;
+
+	proglen = 0;
+
+	for (int i = 0; i < MAXHDR && st->st_hdrs[i] != NULL; i++) {
+		addprogfmt("#include <%s>\n", st->st_hdrs[i]);
+	}
+
+	for (s = st->st_rtype; *s; s++) {
+		addprogch(*s);
+		if (*s == '(') {
+			s++;
+			addprogch(*s);
+			s++;
+			break;
+		}
+	}
+	addprogch(' ');
+
+	/* for function pointers, s is closing suffix, otherwise empty */
+
+	switch (st->st_type) {
+	case SYM_TYPE:
+		addprogstr("test_type;");
+		break;
+
+	case SYM_VALUE:
+		addprogfmt("test_value%s;\n", s);	/* s usually empty */
+		addprogstr("void\ntest_func(void)\n{\n");
+		addprogfmt("\ttest_value = %s;\n}", st->st_name);
+		break;
+
+	case SYM_FUNC:
+		addprogstr("\ntest_func(");
+		for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) {
+			int didname = 0;
+			if (i > 0) {
+				addprogstr(", ");
+			}
+			if (strcmp(st->st_atypes[i], "void") == 0) {
+				didname = 1;
+			}
+			if (strcmp(st->st_atypes[i], "") == 0) {
+				didname = 1;
+				addprogstr("void");
+			}
+
+			/* print the argument list */
+			for (char *a = st->st_atypes[i]; *a; a++) {
+				if (*a == '(' && a[1] == '*' && !didname) {
+					addprogfmt("(*a%d", i);
+					didname = 1;
+					a++;
+				} else if (*a == '[' && !didname) {
+					addprogfmt("a%d[", i);
+					didname = 1;
+				} else {
+					addprogch(*a);
+				}
+			}
+			if (!didname) {
+				addprogfmt(" a%d", i);
+			}
+		}
+
+		if (st->st_atypes[0] == NULL) {
+			addprogstr("void");
+		}
+
+		/*
+		 * Close argument list, and closing ")" for func ptrs.
+		 * Note that for non-function pointers, s will be empty
+		 * below, otherwise it points to the trailing argument
+		 * list.
+		 */
+		addprogfmt(")%s\n{\n\t", s);
+
+		if (strcmp(st->st_rtype, "") != 0 &&
+		    strcmp(st->st_rtype, "void") != 0) {
+			addprogstr("return ");
+		}
+
+		/* add the function call */
+		addprogfmt("%s(", st->st_name);
+		for (int i = 0; st->st_atypes[i] != NULL && i < MAXARG; i++) {
+			if (strcmp(st->st_atypes[i], "") != 0 &&
+			    strcmp(st->st_atypes[i], "void") != 0) {
+				addprogfmt("%sa%d", i > 0 ? ", " : "", i);
+			}
+		}
+
+		addprogstr(");\n}");
+		break;
+	}
+
+	addprogch('\n');
+
+	st->st_prog = progbuf;
+}
+
+static int
+add_envs(struct sym_test *st, char *envs, char **err)
+{
+	char *item;
+	if (expand_env_list(envs, &st->st_test_mask, &st->st_need_mask,
+	    &item) < 0) {
+		myasprintf(err, "bad env action %s", item);
+		return (-1);
+	}
+	return (0);
+}
+
+static int
+add_headers(struct sym_test *st, char *hdrs, char **err)
+{
+	int i = 0;
+
+	for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) {
+		if (i >= MAXHDR) {
+			myasprintf(err, "too many headers");
+			return (-1);
+		}
+		test_trim(&h);
+		st->st_hdrs[i++] = mystrdup(h);
+	}
+
+	return (0);
+}
+
+static int
+add_arg_types(struct sym_test *st, char *atype, char **err)
+{
+	int i = 0;
+	char *a;
+	for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) {
+		if (i >= MAXARG) {
+			myasprintf(err, "too many arguments");
+			return (-1);
+		}
+		test_trim(&a);
+		st->st_atypes[i++] = mystrdup(a);
+	}
+
+	return (0);
+}
+
+static int
+do_type(char **fields, int nfields, char **err)
+{
+	char *decl;
+	char *hdrs;
+	char *envs;
+	struct sym_test *st;
+
+	if (nfields != 3) {
+		myasprintf(err, "number of fields (%d) != 3", nfields);
+		return (-1);
+	}
+	decl = fields[0];
+	hdrs = fields[1];
+	envs = fields[2];
+
+	st = myzalloc(sizeof (*st));
+	st->st_type = SYM_TYPE;
+	st->st_name = mystrdup(decl);
+	st->st_rtype = mystrdup(decl);
+
+	if ((add_envs(st, envs, err) < 0) ||
+	    (add_headers(st, hdrs, err) < 0)) {
+		return (-1);
+	}
+	append_sym_test(st);
+
+	return (0);
+}
+
+static int
+do_value(char **fields, int nfields, char **err)
+{
+	char *name;
+	char *type;
+	char *hdrs;
+	char *envs;
+	struct sym_test *st;
+
+	if (nfields != 4) {
+		myasprintf(err, "number of fields (%d) != 4", nfields);
+		return (-1);
+	}
+	name = fields[0];
+	type = fields[1];
+	hdrs = fields[2];
+	envs = fields[3];
+
+	st = myzalloc(sizeof (*st));
+	st->st_type = SYM_VALUE;
+	st->st_name = mystrdup(name);
+	st->st_rtype = mystrdup(type);
+
+	if ((add_envs(st, envs, err) < 0) ||
+	    (add_headers(st, hdrs, err) < 0)) {
+		return (-1);
+	}
+	append_sym_test(st);
+
+	return (0);
+}
+
+static int
+do_func(char **fields, int nfields, char **err)
+{
+	char *name;
+	char *rtype;
+	char *atype;
+	char *hdrs;
+	char *envs;
+	struct sym_test *st;
+
+	if (nfields != 5) {
+		myasprintf(err, "number of fields (%d) != 5", nfields);
+		return (-1);
+	}
+	name = fields[0];
+	rtype = fields[1];
+	atype = fields[2];
+	hdrs = fields[3];
+	envs = fields[4];
+
+	st = myzalloc(sizeof (*st));
+	st->st_type = SYM_FUNC;
+	st->st_name = mystrdup(name);
+	st->st_rtype = mystrdup(rtype);
+
+	if ((add_envs(st, envs, err) < 0) ||
+	    (add_headers(st, hdrs, err) < 0) ||
+	    (add_arg_types(st, atype, err) < 0)) {
+		return (-1);
+	}
+	append_sym_test(st);
+
+	return (0);
+}
+
+struct sym_test *
+next_sym_test(struct sym_test *st)
+{
+	return (st == NULL ? sym_tests : st->st_next);
+}
+
+const char *
+sym_test_prog(struct sym_test *st)
+{
+	if (st->st_prog == NULL) {
+		mkprog(st);
+	}
+	return (st->st_prog);
+}
+
+const char *
+sym_test_name(struct sym_test *st)
+{
+	return (st->st_name);
+}
+
+/*
+ * Iterate through tests.  Pass in NULL for cenv to begin the iteration. For
+ * subsequent iterations, use the return value from the previous iteration.
+ * Returns NULL when there are no more environments.
+ */
+struct compile_env *
+sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need)
+{
+	int i = cenv ? cenv->ce_index + 1: 0;
+	uint64_t b = 1ULL << i;
+
+	while ((i < MAXENV) && (b != 0)) {
+		cenv = &compile_env[i];
+		if (b & st->st_test_mask) {
+			*need = (st->st_need_mask & b) ? 1 : 0;
+			return (cenv);
+		}
+		b <<= 1;
+		i++;
+	}
+	return (NULL);
+}
+
+const char *
+env_name(struct compile_env *cenv)
+{
+	return (cenv->ce_name);
+}
+
+const char *
+env_lang(struct compile_env *cenv)
+{
+	return (cenv->ce_lang);
+}
+
+const char *
+env_defs(struct compile_env *cenv)
+{
+	return (cenv->ce_defs);
+}
+
+static void
+show_file(test_t t, const char *path)
+{
+	FILE *f;
+	char *buf = NULL;
+	size_t cap = 0;
+	int line = 1;
+
+	f = fopen(path, "r");
+	if (f == NULL) {
+		test_debugf(t, "fopen(%s): %s", path, strerror(errno));
+		return;
+	}
+
+	test_debugf(t, "----->> begin (%s) <<------", path);
+	while (getline(&buf, &cap, f) >= 0) {
+		(void) strtok(buf, "\r\n");
+		test_debugf(t, "%d: %s", line, buf);
+		line++;
+	}
+	test_debugf(t, "----->> end (%s) <<------", path);
+	(void) fclose(f);
+}
+
+static void
+cleanup(void)
+{
+	if (ofile != NULL) {
+		(void) unlink(ofile);
+		free(ofile);
+		ofile = NULL;
+	}
+	if (lfile != NULL) {
+		(void) unlink(lfile);
+		free(lfile);
+		lfile = NULL;
+	}
+	if (cfile != NULL) {
+		(void) unlink(cfile);
+		free(cfile);
+		cfile = NULL;
+	}
+	if (efile != NULL) {
+		(void) unlink(efile);
+		free(efile);
+		efile = NULL;
+	}
+	if (dname) {
+		(void) rmdir(dname);
+		free(dname);
+		dname = NULL;
+	}
+}
+
+static int
+mkworkdir(void)
+{
+	char b[32];
+	char *d;
+
+	cleanup();
+
+	(void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b));
+	if ((d = mkdtemp(b)) == NULL) {
+		perror("mkdtemp");
+		return (-1);
+	}
+	dname = mystrdup(d);
+	myasprintf(&cfile, "%s/compile_test.c", d);
+	myasprintf(&ofile, "%s/compile_test.o", d);
+	myasprintf(&lfile, "%s/compile_test.log", d);
+	myasprintf(&efile, "%s/compile_test.exe", d);
+	return (0);
+}
+
+void
+find_compiler(void)
+{
+	test_t t;
+	int i;
+	FILE *cf;
+
+	t = test_start("finding compiler");
+
+	if ((cf = fopen(cfile, "w+")) == NULL) {
+		test_failed(t, "Unable to open %s for write: %s", cfile,
+		    strerror(errno));
+		return;
+	}
+	(void) fprintf(cf, "#include <stdio.h>\n");
+	(void) fprintf(cf, "int main(int argc, char **argv) {\n");
+	(void) fprintf(cf, "#if defined(__SUNPRO_C)\n");
+	(void) fprintf(cf, "exit(51);\n");
+	(void) fprintf(cf, "#elif defined(__GNUC__)\n");
+	(void) fprintf(cf, "exit(52);\n");
+	(void) fprintf(cf, "#else\n");
+	(void) fprintf(cf, "exit(99)\n");
+	(void) fprintf(cf, "#endif\n}\n");
+	(void) fclose(cf);
+
+	for (i = 0; compilers[i] != NULL; i++) {
+		char cmd[256];
+		int rv;
+
+		(void) snprintf(cmd, sizeof (cmd),
+		    "%s %s %s -o %s >/dev/null 2>&1",
+		    compilers[i], MFLAG, cfile, efile);
+		test_debugf(t, "trying %s", cmd);
+		rv = system(cmd);
+
+		test_debugf(t, "result: %d", rv);
+
+		if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0)
+			continue;
+
+		rv = system(efile);
+		if (rv >= 0 && WIFEXITED(rv)) {
+			rv = WEXITSTATUS(rv);
+		} else {
+			rv = -1;
+		}
+
+		switch (rv) {
+		case 51:	/* STUDIO */
+			test_debugf(t, "Found Studio C");
+			c89flags = "-Xc -errwarn=%all -v -xc99=%none " MFLAG;
+			c99flags = "-Xc -errwarn=%all -v -xc99=%all " MFLAG;
+			if (extra_debug) {
+				test_debugf(t, "c89flags: %s", c89flags);
+				test_debugf(t, "c99flags: %s", c99flags);
+			}
+			test_passed(t);
+			break;
+		case 52:	/* GCC */
+			test_debugf(t, "Found GNU C");
+			c89flags = "-Wall -Werror -std=c89 " MFLAG;
+			c99flags = "-Wall -Werror -std=c99 " MFLAG;
+			if (extra_debug) {
+				test_debugf(t, "c89flags: %s", c89flags);
+				test_debugf(t, "c99flags: %s", c99flags);
+			}
+			test_passed(t);
+			break;
+		case 99:
+			test_debugf(t, "Found unknown (unsupported) compiler");
+			continue;
+		default:
+			continue;
+		}
+		myasprintf(&compiler, "%s", compilers[i]);
+		test_debugf(t, "compiler: %s", compiler);
+		return;
+	}
+	test_failed(t, "No compiler found.");
+}
+
+int
+do_compile(test_t t, struct sym_test *st, struct compile_env *cenv, int need)
+{
+	char *cmd;
+	FILE *logf;
+	FILE *dotc;
+	const char *prog;
+
+	full_count++;
+
+	if ((dotc = fopen(cfile, "w+")) == NULL) {
+		test_failed(t, "fopen(%s): %s", cfile, strerror(errno));
+		return (-1);
+	}
+	prog = sym_test_prog(st);
+	if (fwrite(prog, 1, strlen(prog), dotc) < strlen(prog)) {
+		test_failed(t, "fwrite: %s", strerror(errno));
+		(void) fclose(dotc);
+		return (-1);
+	}
+	if (fclose(dotc) < 0) {
+		test_failed(t, "fclose: %s", strerror(errno));
+		return (-1);
+	}
+
+	(void) unlink(ofile);
+
+	myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1",
+	    compiler, strcmp(env_lang(cenv), "c99") == 0 ? c99flags : c89flags,
+	    env_defs(cenv), cfile, ofile, lfile);
+
+	if (extra_debug) {
+		test_debugf(t, "command: %s", cmd);
+	}
+
+	if ((logf = fopen(lfile, "w+")) == NULL) {
+		test_failed(t, "fopen: %s", strerror(errno));
+		return (-1);
+	}
+	(void) fprintf(logf, "===================\n");
+	(void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st));
+	(void) fprintf(logf, "COMMAND: %s\n", cmd);
+	(void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL");
+	(void) fclose(logf);
+
+	switch (system(cmd)) {
+	case -1:
+		test_failed(t, "error compiling in %s: %s", env_name(cenv),
+		    strerror(errno));
+		return (-1);
+	case 0:
+		if (!need) {
+			fail_count++;
+			show_file(t, lfile);
+			test_failed(t, "symbol visible in %s", env_name(cenv));
+			return (-1);
+		}
+		break;
+	default:
+		if (need) {
+			fail_count++;
+			show_file(t, lfile);
+			test_failed(t, "error compiling in %s", env_name(cenv));
+			return (-1);
+		}
+		break;
+	}
+	good_count++;
+	return (0);
+}
+
+void
+test_compile(void)
+{
+	struct sym_test *st;
+	struct compile_env *cenv;
+	test_t t;
+	int need;
+
+	for (st = next_sym_test(NULL); st; st = next_sym_test(st)) {
+		if ((sym != NULL) && strcmp(sym, sym_test_name(st))) {
+			continue;
+		}
+		/* XXX: we really want a sym_test_desc() */
+		for (cenv = sym_test_env(st, NULL, &need);
+		    cenv != NULL;
+		    cenv = sym_test_env(st, cenv, &need)) {
+			t = test_start("%s : %c%s", sym_test_name(st),
+			    need ? '+' : '-', env_name(cenv));
+			if (do_compile(t, st, cenv, need) == 0) {
+				test_passed(t);
+			}
+		}
+	}
+
+	if (full_count > 0) {
+		test_summary();
+	}
+}
+
+int
+main(int argc, char **argv)
+{
+	int optc;
+	int optC = 0;
+
+	while ((optc = getopt(argc, argv, "DdfCs:c:")) != EOF) {
+		switch (optc) {
+		case 'd':
+			test_set_debug();
+			break;
+		case 'f':
+			test_set_force();
+			break;
+		case 'D':
+			test_set_debug();
+			extra_debug++;
+			break;
+		case 'c':
+			compilation = optarg;
+			break;
+		case 'C':
+			optC++;
+			break;
+		case 's':
+			sym = optarg;
+			break;
+		default:
+			(void) fprintf(stderr, "Usage: %s [-df]\n", argv[0]);
+			exit(1);
+		}
+	}
+
+	if (test_load_config(NULL, compilation,
+	    "env", do_env, "env_group", do_env_group, NULL) < 0) {
+		exit(1);
+	}
+
+	while (optind < argc) {
+		if (test_load_config(NULL, argv[optind++],
+		    "type", do_type,
+		    "value", do_value,
+		    "func", do_func,
+		    NULL) < 0) {
+			exit(1);
+		}
+	}
+
+	if (atexit(cleanup) != 0) {
+		perror("atexit");
+		exit(1);
+	}
+
+	if (mkworkdir() < 0) {
+		perror("mkdir");
+		exit(1);
+	}
+
+	find_compiler();
+	if (!optC)
+		test_compile();
+
+	exit(0);
+}
