summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/Makefile3
-rw-r--r--usr/src/lib/c_synonyms/amd64/Makefile4
-rw-r--r--usr/src/lib/c_synonyms/i386/Makefile4
-rw-r--r--usr/src/lib/c_synonyms/sparc/Makefile4
-rw-r--r--usr/src/lib/c_synonyms/sparcv9/Makefile4
-rw-r--r--usr/src/lib/efcode/engine/sparcv9/Makefile4
-rw-r--r--usr/src/lib/fm/libmdesc/Makefile.com4
-rw-r--r--usr/src/lib/gss_mechs/mech_krb5/Makefile2
-rw-r--r--usr/src/lib/libast/amd64/Makefile2
-rw-r--r--usr/src/lib/libast/i386/Makefile2
-rw-r--r--usr/src/lib/libast/sparc/Makefile2
-rw-r--r--usr/src/lib/libast/sparcv9/Makefile2
-rw-r--r--usr/src/lib/libbc/sparc/Makefile24
-rw-r--r--usr/src/lib/libc/capabilities/sun4u-opl/Makefile.com2
-rw-r--r--usr/src/lib/libc/capabilities/sun4u-us3-hwcap1/Makefile.com2
-rw-r--r--usr/src/lib/libc/capabilities/sun4u-us3-hwcap2/Makefile.com2
-rw-r--r--usr/src/lib/libc/capabilities/sun4u/Makefile.com2
-rw-r--r--usr/src/lib/libc/capabilities/sun4v-hwcap1/Makefile.com2
-rw-r--r--usr/src/lib/libc/capabilities/sun4v-hwcap2/Makefile.com2
-rw-r--r--usr/src/lib/libc/sparc/Makefile.com4
-rw-r--r--usr/src/lib/libc/sparcv9/Makefile.com4
-rw-r--r--usr/src/lib/libdemangle/Makefile41
-rw-r--r--usr/src/lib/libdemangle/Makefile.com43
-rw-r--r--usr/src/lib/libdemangle/THIRDPARTYLICENSE76
-rw-r--r--usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip1
-rw-r--r--usr/src/lib/libdemangle/amd64/Makefile30
-rw-r--r--usr/src/lib/libdemangle/common/cxx.c4217
-rw-r--r--usr/src/lib/libdemangle/common/cxx.h87
-rw-r--r--usr/src/lib/libdemangle/common/cxx_util.c600
-rw-r--r--usr/src/lib/libdemangle/common/demangle-sys.h41
-rw-r--r--usr/src/lib/libdemangle/common/demangle.c87
-rw-r--r--usr/src/lib/libdemangle/common/demangle_int.h39
-rw-r--r--usr/src/lib/libdemangle/common/llib-ldemangle-sys29
-rw-r--r--usr/src/lib/libdemangle/common/mapfile-vers36
-rw-r--r--usr/src/lib/libdemangle/common/str.c313
-rw-r--r--usr/src/lib/libdemangle/common/str.h63
-rw-r--r--usr/src/lib/libdemangle/common/util.c85
-rw-r--r--usr/src/lib/libdemangle/i386/Makefile30
-rw-r--r--usr/src/lib/libdemangle/sparc/Makefile30
-rw-r--r--usr/src/lib/libdemangle/sparcv9/Makefile29
-rw-r--r--usr/src/lib/libdtrace/sparc/Makefile2
-rw-r--r--usr/src/lib/libdtrace/sparcv9/Makefile2
-rw-r--r--usr/src/lib/libdtrace_jni/Makefile.com4
-rw-r--r--usr/src/lib/libndmp/sparcv9/Makefile6
-rw-r--r--usr/src/lib/libnsl/sparcv9/Makefile5
-rw-r--r--usr/src/lib/libresolv2/sparcv9/Makefile6
-rw-r--r--usr/src/lib/libsmbfs/smb/ctx.c7
-rw-r--r--usr/src/lib/libsmbfs/smb/findvc.c5
-rw-r--r--usr/src/lib/libsmbfs/smb/mapfile-vers1
-rw-r--r--usr/src/lib/libtnfprobe/Makefile.com4
-rw-r--r--usr/src/lib/libzfs/sparcv9/Makefile3
-rw-r--r--usr/src/lib/libzfs_core/sparcv9/Makefile2
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/sparc/Makefile3
-rw-r--r--usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile5
-rw-r--r--usr/src/lib/smbsrv/libsmbrp/sparcv9/Makefile3
55 files changed, 5938 insertions, 78 deletions
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index bdff519dd6..15c0a77e37 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -30,6 +30,7 @@
# Copyright 2018 Nexenta Systems, Inc.
# Copyright (c) 2016, Chris Fraire <cfraire@me.com>.
# Copyright 2017 RackTop Systems.
+# Copyirght 2018 Jason King
#
include ../Makefile.master
@@ -107,6 +108,7 @@ SUBDIRS += \
libctf \
libcurses \
libcustr \
+ libdemangle \
libdevice \
libdevid \
libdevinfo \
@@ -389,6 +391,7 @@ HDRSUBDIRS= \
libctf \
libcurses \
libcustr \
+ libdemangle \
libdevice \
libdevid \
libdevinfo \
diff --git a/usr/src/lib/c_synonyms/amd64/Makefile b/usr/src/lib/c_synonyms/amd64/Makefile
index 5cfacdba09..f7402f33aa 100644
--- a/usr/src/lib/c_synonyms/amd64/Makefile
+++ b/usr/src/lib/c_synonyms/amd64/Makefile
@@ -22,10 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-ASFLAGS= -K pic -P -D__STDC__ -D_ASM $(amd64_AS_XARCH)
+ASFLAGS= $(AS_PICFLAGS) -P -D__STDC__ -D_ASM $(amd64_AS_XARCH)
include ../Makefile.com
include ../../Makefile.lib.64
diff --git a/usr/src/lib/c_synonyms/i386/Makefile b/usr/src/lib/c_synonyms/i386/Makefile
index 0670d3021e..56e547b520 100644
--- a/usr/src/lib/c_synonyms/i386/Makefile
+++ b/usr/src/lib/c_synonyms/i386/Makefile
@@ -22,10 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-ASFLAGS= -K pic -P -D__STDC__ -D_ASM $(i386_AS_XARCH)
+ASFLAGS= $(AS_PICFLAGS) -P -D__STDC__ -D_ASM $(i386_AS_XARCH)
include ../Makefile.com
diff --git a/usr/src/lib/c_synonyms/sparc/Makefile b/usr/src/lib/c_synonyms/sparc/Makefile
index f9643fd890..93df1b115c 100644
--- a/usr/src/lib/c_synonyms/sparc/Makefile
+++ b/usr/src/lib/c_synonyms/sparc/Makefile
@@ -22,10 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-ASFLAGS= -K pic -P -D__STDC__ -D_ASM $(sparc_AS_XARCH)
+ASFLAGS= $(AS_PICFLAGS) -P -D__STDC__ -D_ASM $(sparc_AS_XARCH)
include ../Makefile.com
diff --git a/usr/src/lib/c_synonyms/sparcv9/Makefile b/usr/src/lib/c_synonyms/sparcv9/Makefile
index 13d51d128a..0f5cceeeb9 100644
--- a/usr/src/lib/c_synonyms/sparcv9/Makefile
+++ b/usr/src/lib/c_synonyms/sparcv9/Makefile
@@ -22,10 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
-ASFLAGS= -K pic -P -D__STDC__ -D_ASM $(sparcv9_AS_XARCH)
+ASFLAGS= $(AS_PICFLAGS) -P -D__STDC__ -D_ASM $(sparcv9_AS_XARCH)
include ../Makefile.com
include ../../Makefile.lib.64
diff --git a/usr/src/lib/efcode/engine/sparcv9/Makefile b/usr/src/lib/efcode/engine/sparcv9/Makefile
index af568ee0b3..3673ac4986 100644
--- a/usr/src/lib/efcode/engine/sparcv9/Makefile
+++ b/usr/src/lib/efcode/engine/sparcv9/Makefile
@@ -23,12 +23,10 @@
# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
include ../Makefile.com
include $(SRC)/lib/Makefile.lib.64
-sparcv9_C_PICFLAGS = -KPIC
+sparcv9_C_PICFLAGS = $(C_BIGPICFLAGS64)
install: all $(ROOTLIBS64)
diff --git a/usr/src/lib/fm/libmdesc/Makefile.com b/usr/src/lib/fm/libmdesc/Makefile.com
index 7d3f814c59..c09447e182 100644
--- a/usr/src/lib/fm/libmdesc/Makefile.com
+++ b/usr/src/lib/fm/libmdesc/Makefile.com
@@ -50,8 +50,8 @@ LIBS = $(DYNLIB) $(LINTLIB)
SRCDIR = ../common
CPPFLAGS += -I../common -I.
-CFLAGS += $(CCVERBOSE) -K PIC
-CFLAGS64 += $(CCVERBOSE) -K PIC
+CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
+CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS64)
LDLIBS += -lc
LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN -v
diff --git a/usr/src/lib/gss_mechs/mech_krb5/Makefile b/usr/src/lib/gss_mechs/mech_krb5/Makefile
index 6d5fa74ac8..c725934855 100644
--- a/usr/src/lib/gss_mechs/mech_krb5/Makefile
+++ b/usr/src/lib/gss_mechs/mech_krb5/Makefile
@@ -39,7 +39,7 @@ include ../../Makefile.lib
GREP= find . \( -name SCCS -prune -o -name '*.[ch]' \) -print | sort | xargs grep
-sparcv9_C_PICFLAGS = -K PIC
+sparcv9_C_PICFLAGS = $(sparcv9_C_BIGPICFLAGS)
TEXT_DOMAIN = SUNW_OST_NETRPC
POFILE = mech_krb5.po
POFILES = generic.po
diff --git a/usr/src/lib/libast/amd64/Makefile b/usr/src/lib/libast/amd64/Makefile
index 0419980509..baa59970af 100644
--- a/usr/src/lib/libast/amd64/Makefile
+++ b/usr/src/lib/libast/amd64/Makefile
@@ -38,7 +38,7 @@ OBJDIRS = \
include ../Makefile.com
include ../../Makefile.lib.64
-# Use -KPIC since libast is too big for -Kpic on 64bit
+# Use big PIC since libast is too big for pic on 64bit
# (and on 32bit it is close to the barrier)
amd64_C_PICFLAGS = $(C_BIGPICFLAGS)
diff --git a/usr/src/lib/libast/i386/Makefile b/usr/src/lib/libast/i386/Makefile
index 309ec29f43..f601e12e04 100644
--- a/usr/src/lib/libast/i386/Makefile
+++ b/usr/src/lib/libast/i386/Makefile
@@ -37,7 +37,7 @@ OBJDIRS = \
include ../Makefile.com
-# Use -KPIC since libast is too big for -Kpic on 64bit
+# Use big PIC since libast is too big for pic on 64bit
# (and on 32bit it is close to the barrier)
i386_C_PICFLAGS = $(C_BIGPICFLAGS)
diff --git a/usr/src/lib/libast/sparc/Makefile b/usr/src/lib/libast/sparc/Makefile
index 63d22de006..54f6ad2f28 100644
--- a/usr/src/lib/libast/sparc/Makefile
+++ b/usr/src/lib/libast/sparc/Makefile
@@ -38,7 +38,7 @@ OBJDIRS = \
include ../Makefile.com
-# Use -KPIC since libast is too big for -Kpic on 64bit
+# Use big PIC since libast is too big for pic on 64bit
# (and on 32bit it is close to the barrier)
sparc_C_PICFLAGS = $(C_BIGPICFLAGS)
diff --git a/usr/src/lib/libast/sparcv9/Makefile b/usr/src/lib/libast/sparcv9/Makefile
index 6a680ee6c6..ec4370867f 100644
--- a/usr/src/lib/libast/sparcv9/Makefile
+++ b/usr/src/lib/libast/sparcv9/Makefile
@@ -39,7 +39,7 @@ OBJDIRS = \
include ../Makefile.com
include ../../Makefile.lib.64
-# Use -KPIC since libast is too big for -Kpic on 64bit
+# Use big PIC since libast is too big for pic on 64bit
# (and on 32bit it is close to the barrier)
sparcv9_C_PICFLAGS = $(C_BIGPICFLAGS)
diff --git a/usr/src/lib/libbc/sparc/Makefile b/usr/src/lib/libbc/sparc/Makefile
index c624b62c2f..b35b87a3f4 100644
--- a/usr/src/lib/libbc/sparc/Makefile
+++ b/usr/src/lib/libbc/sparc/Makefile
@@ -44,7 +44,7 @@ utime.o
COMPAT4.1=\
ftime.o nice.o rand.o vlimit.o vtimes.o getpw.o times.o
-
+
COMPATSYS5=\
nice.o rand.o getpw.o times.o
@@ -97,14 +97,14 @@ calloc.o malloc.o \
getpass.o localtime.o ttyslot.o
GENCOMSPARC=\
-alloca.o ffs.o insque.o remque.o isinf.o base_conv.o
+alloca.o ffs.o insque.o remque.o isinf.o base_conv.o
GEN4.2=\
nlist.o timezone.o sleep.o system.o
GENSYS5=\
assert.o nlist.o sgetl.o sleep.o sputl.o system.o \
-sighold.o
+sighold.o
STDIOCOM=\
clrerr.o ctermid.o cuserid.o doprnt.o doscan.o fdopen.o \
@@ -150,7 +150,7 @@ creat.o execve.o getpgrp.o link.o mkdir.o \
mknod.o open.o readlink.o rename.o rmdir.o \
setpgrp.o stat.o symlink.o truncate.o unlink.o \
statfs.o fcntl.o read.o write.o readv.o \
-writev.o setjmp.o mount.o
+writev.o setjmp.o mount.o
SYS4.2SPARC=\
getgroups.o setgroups.o
@@ -340,9 +340,9 @@ CERRWARN += -_gcc=-Wno-address
$(DYNLIB4X) := SONAME = $(DYNLIB4X)
$(DYNLIBS5) := SONAME = $(DYNLIBS5)
-pics/%.o:= ASFLAGS += -K pic -DPIC
-pics/%.o:= CPPFLAGS += -K pic -DPIC
-s5pics/%.o:= ASFLAGS += -K pic -DPIC
+pics/%.o:= ASFLAGS += $(AS_PICFLAGS) -DPIC
+pics/%.o:= CPPFLAGS += $(C_PICFLAGS) -DPIC
+s5pics/%.o:= ASFLAGS += $(AS_PICFLAGS) -DPIC
DYNFLAGS += $(ZINTERPOSE)
BUILD.s= $(AS) $(ASFLAGS) $< -o $@
@@ -352,14 +352,14 @@ BUILD.AR= $(RM) $@ ; \
$(AR) q $@ $(OBJECTS:%=$(DIR)/%)
# the TXTS macro is used for NSE bootstrapping.
-TXTS= inc/SYS.h inc/PIC.h inc/machine/asm_linkage.h
+TXTS= inc/SYS.h inc/PIC.h inc/machine/asm_linkage.h
LIBS = $(DYNLIB4X) $(DYNLIBS5)
OBJECTS= $(COMPATCOM) $(COMPAT4.1) $(CRTSPARC) $(GENCOM) \
$(GENCOMSPARC) $(GEN4.2) $(STDIOCOM) $(STDIO4.2) \
$(INET) $(NET) $(NETSPARC) $(YP) \
-$(SYSCOM) $(SYSCOMSPARC) $(SYS4.2)
+$(SYSCOM) $(SYSCOMSPARC) $(SYS4.2)
#
# Since this library is strictly for binary compability with ancient
@@ -381,7 +381,7 @@ CLEANFILES= ../libc/yp/ypupdate_prot.c ../inc/include/rpcsvc/ypupdate_prot.h \
CLOBBERFILES= ../libc/compat/sys5/mkepoch
# conditional assignments
-s5pics/%.o:= CPPFLAGS = -Dsparc -DS5EMUL -K pic -DPIC -I. -Iinc \
+s5pics/%.o:= CPPFLAGS = -Dsparc -DS5EMUL $(C_PICFLAGS) -DPIC -I. -Iinc \
-I../inc/5include -I../inc/include -I../inc/include/sys \
$(CPPFLAGS.master)
@@ -414,7 +414,7 @@ s5pics:
# special cases
PSEUDO_POBJS= $(PSEUDO_SRCS:%.s=pics/%.o)
-PSEUDO_PS5OBJS= $(PSEUDO_SRCS:%.s=s5pics/%.o)
+PSEUDO_PS5OBJS= $(PSEUDO_SRCS:%.s=s5pics/%.o)
$(PSEUDO_POBJS) $(PSEUDO_PS5OBJS):
@(echo '#include "SYS.h"'; \
@@ -451,7 +451,7 @@ s5pics/yp_update.o : ../inc/include/rpcsvc/ypupdate_prot.h ../libc/yp/yp_update.
$(POST_PROCESS_O)
pics/ypupdate_prot.o s5pics/ypupdate_prot.o : ../inc/include/rpcsvc/ypupdate_prot.h\
- ../libc/yp/ypupdate_prot.c
+ ../libc/yp/ypupdate_prot.c
$(COMPILE.c) -o $@ ../libc/yp/ypupdate_prot.c
$(POST_PROCESS_O)
diff --git a/usr/src/lib/libc/capabilities/sun4u-opl/Makefile.com b/usr/src/lib/libc/capabilities/sun4u-opl/Makefile.com
index 0080c16a0e..c50532689c 100644
--- a/usr/src/lib/libc/capabilities/sun4u-opl/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4u-opl/Makefile.com
@@ -37,4 +37,4 @@ IFLAGS = -I$(SRC)/uts/$(GEN_PLATFORM) \
-I$(ROOT)/usr/platform/$(GEN_PLATFORM)/include
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS)
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
diff --git a/usr/src/lib/libc/capabilities/sun4u-us3-hwcap1/Makefile.com b/usr/src/lib/libc/capabilities/sun4u-us3-hwcap1/Makefile.com
index b459a6ac2d..1dab8dae63 100644
--- a/usr/src/lib/libc/capabilities/sun4u-us3-hwcap1/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4u-us3-hwcap1/Makefile.com
@@ -39,4 +39,4 @@ MAPFILE-CAP += ../../$(TRG_PLATFORM)/common/mapfile-cap
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS) \
-DBSTORE_SIZE=256
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
diff --git a/usr/src/lib/libc/capabilities/sun4u-us3-hwcap2/Makefile.com b/usr/src/lib/libc/capabilities/sun4u-us3-hwcap2/Makefile.com
index 039b50259c..6620a802f3 100644
--- a/usr/src/lib/libc/capabilities/sun4u-us3-hwcap2/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4u-us3-hwcap2/Makefile.com
@@ -39,4 +39,4 @@ MAPFILE-CAP += ../../$(TRG_PLATFORM)/common/mapfile-cap
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS) \
-DBSTORE_SIZE=65536 -DPANTHER_ONLY
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
diff --git a/usr/src/lib/libc/capabilities/sun4u/Makefile.com b/usr/src/lib/libc/capabilities/sun4u/Makefile.com
index 0d8a28bfa1..033f0dc43e 100644
--- a/usr/src/lib/libc/capabilities/sun4u/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4u/Makefile.com
@@ -36,7 +36,7 @@ IFLAGS = -I$(SRC)/uts/$(GEN_PLATFORM) \
-I$(ROOT)/usr/platform/$(GEN_PLATFORM)/include
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS)
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
# memcpy.s provides __align_cpy_1 as an alias for memcpy. However, this isn't
# a WEAK symbol, and hence ld(1)'s ability to cull duplicate local symbols with
diff --git a/usr/src/lib/libc/capabilities/sun4v-hwcap1/Makefile.com b/usr/src/lib/libc/capabilities/sun4v-hwcap1/Makefile.com
index 0b1a16be84..8e7800a6d2 100644
--- a/usr/src/lib/libc/capabilities/sun4v-hwcap1/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4v-hwcap1/Makefile.com
@@ -38,7 +38,7 @@ IFLAGS = -I$(SRC)/uts/$(GEN_PLATFORM) \
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS) \
-DNIAGARA_IMPL
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
# memcpy.s provides __align_cpy_1 as an alias for memcpy. However, this isn't
# a WEAK symbol, and hence ld(1)'s ability to cull duplicate local symbols with
diff --git a/usr/src/lib/libc/capabilities/sun4v-hwcap2/Makefile.com b/usr/src/lib/libc/capabilities/sun4v-hwcap2/Makefile.com
index af1273234c..a652b280be 100644
--- a/usr/src/lib/libc/capabilities/sun4v-hwcap2/Makefile.com
+++ b/usr/src/lib/libc/capabilities/sun4v-hwcap2/Makefile.com
@@ -38,7 +38,7 @@ IFLAGS = -I$(SRC)/uts/$(GEN_PLATFORM) \
AS_CPPFLAGS += -D__STDC__ -D_ASM -DPIC -D_REENTRANT -D$(MACH) $(IFLAGS) \
-DNIAGARA2_IMPL
-ASFLAGS = -P -K pic
+ASFLAGS = -P $(AS_PICFLAGS)
# memcpy.s provides __align_cpy_1 as an alias for memcpy. However, this isn't
# a WEAK symbol, and hence ld(1)'s ability to cull duplicate local symbols with
diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com
index 4e09e44571..0bdbdd1bb7 100644
--- a/usr/src/lib/libc/sparc/Makefile.com
+++ b/usr/src/lib/libc/sparc/Makefile.com
@@ -1131,7 +1131,7 @@ MAPFILES = $(LIBCDIR)/port/mapfile-vers
CFLAGS += $(EXTN_CFLAGS)
CPPFLAGS= -D_REENTRANT -Dsparc $(EXTN_CPPFLAGS) $(THREAD_DEBUG) \
-I$(LIBCBASE)/inc -I$(LIBCDIR)/inc $(CPPFLAGS.master)
-ASFLAGS= $(EXTN_ASFLAGS) -K pic -P -D__STDC__ -D_ASM $(CPPFLAGS) $(sparc_AS_XARCH)
+ASFLAGS= $(EXTN_ASFLAGS) $(AS_PICFLAGS) -P -D__STDC__ -D_ASM $(CPPFLAGS) $(sparc_AS_XARCH)
# As a favor to the dtrace syscall provider, libc still calls the
# old syscall traps that have been obsoleted by the *at() interfaces.
@@ -1383,7 +1383,7 @@ $(STRETS:%=pics/%): $(LIBCBASE)/crt/stret.s
$(POST_PROCESS_O)
$(LIBCBASE)/crt/_rtbootld.s: $(LIBCBASE)/crt/_rtboot.s $(LIBCBASE)/crt/_rtld.c
- $(CC) $(CPPFLAGS) $(CTF_FLAGS) -O -S -K pic \
+ $(CC) $(CPPFLAGS) $(CTF_FLAGS) -O -S $(C_PICFLAGS) \
$(LIBCBASE)/crt/_rtld.c -o $(LIBCBASE)/crt/_rtld.s
$(CAT) $(LIBCBASE)/crt/_rtboot.s $(LIBCBASE)/crt/_rtld.s > $@
$(RM) $(LIBCBASE)/crt/_rtld.s
diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com
index 240ecef7db..2a5e14b625 100644
--- a/usr/src/lib/libc/sparcv9/Makefile.com
+++ b/usr/src/lib/libc/sparcv9/Makefile.com
@@ -1068,11 +1068,11 @@ $(DYNLIB) := BUILD.SO = $(LD) -o $@ -G $(DYNFLAGS) $(PICS) $(ALTPICS) $(EXTPICS)
MAPFILES = $(LIBCDIR)/port/mapfile-vers
-sparcv9_C_PICFLAGS= -K PIC
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
CFLAGS64 += $(EXTN_CFLAGS)
CPPFLAGS= -D_REENTRANT -Dsparc $(EXTN_CPPFLAGS) $(THREAD_DEBUG) \
-I$(LIBCBASE)/inc -I$(LIBCDIR)/inc $(CPPFLAGS.master)
-ASFLAGS= $(EXTN_ASFLAGS) -K PIC -P -D__STDC__ -D_ASM -D__sparcv9 $(CPPFLAGS) \
+ASFLAGS= $(EXTN_ASFLAGS) $(AS_BIGPICFLAGS) -P -D__STDC__ -D_ASM -D__sparcv9 $(CPPFLAGS) \
$(sparcv9_AS_XARCH)
# As a favor to the dtrace syscall provider, libc still calls the
diff --git a/usr/src/lib/libdemangle/Makefile b/usr/src/lib/libdemangle/Makefile
new file mode 100644
index 0000000000..2d17d76e7f
--- /dev/null
+++ b/usr/src/lib/libdemangle/Makefile
@@ -0,0 +1,41 @@
+#
+# 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 2018 Jason King.
+# Copyright 2017, Joyent. Inc.
+#
+
+include ../Makefile.lib
+
+HDRS = demangle-sys.h
+HDRDIR = common
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all := TARGET= all
+clean := TARGET= clean
+clobber := TARGET= clobber
+install := TARGET= install
+lint := TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/lib/libdemangle/Makefile.com b/usr/src/lib/libdemangle/Makefile.com
new file mode 100644
index 0000000000..0b0d495df7
--- /dev/null
+++ b/usr/src/lib/libdemangle/Makefile.com
@@ -0,0 +1,43 @@
+#
+# 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 2018 Jason King
+# Copyright 2018, Joyent, Inc.
+#
+
+LIBRARY = libdemangle-sys.a
+VERS = .1
+OBJECTS = str.o util.o cxx_util.o cxx.o demangle.o
+
+include ../../Makefile.lib
+
+LIBS = $(DYNLIB) $(LINTLIB)
+LDLIBS += -lc
+
+SRCDIR = ../common
+$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC)
+
+CSTD = $(CSTD_GNU99)
+CFLAGS += $(CCVERBOSE)
+CPPFLAGS += -I$(SRCDIR) -D_REENTRANT -D__EXTENSIONS__
+
+LINTFLAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2
+LINTFLAGS64 += -erroff=E_BAD_FORMAT_ARG_TYPE2
+C99LMODE = -Xc99=%all
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+lint: lintcheck
+
+include $(SRC)/lib/Makefile.targ
diff --git a/usr/src/lib/libdemangle/THIRDPARTYLICENSE b/usr/src/lib/libdemangle/THIRDPARTYLICENSE
new file mode 100644
index 0000000000..7381b74c4d
--- /dev/null
+++ b/usr/src/lib/libdemangle/THIRDPARTYLICENSE
@@ -0,0 +1,76 @@
+==============================================================================
+libc++abi License
+==============================================================================
+
+The libc++abi library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip b/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip
new file mode 100644
index 0000000000..ee4e5590cf
--- /dev/null
+++ b/usr/src/lib/libdemangle/THIRDPARTYLICENSE.descrip
@@ -0,0 +1 @@
+PORTIONS OF LIBSYSDEMANGLE FUNCTIONALITY
diff --git a/usr/src/lib/libdemangle/amd64/Makefile b/usr/src/lib/libdemangle/amd64/Makefile
new file mode 100644
index 0000000000..137dd0cf23
--- /dev/null
+++ b/usr/src/lib/libdemangle/amd64/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libdemangle/common/cxx.c b/usr/src/lib/libdemangle/common/cxx.c
new file mode 100644
index 0000000000..66d7170544
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/cxx.c
@@ -0,0 +1,4217 @@
+/*
+ * Ported from LLVM's libcxxabi trunk/src/cxa_demangle.cpp
+ * LICENSE.TXT contents is available as ../THIRDPARTYLICENSE
+ *
+ * The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ */
+
+/*
+ * Copyright 2018 Jason King.
+ */
+#include <ctype.h>
+#include <errno.h>
+#include <locale.h>
+#include <note.h>
+#include <string.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/isa_defs.h>
+#include <sys/debug.h>
+#include "demangle-sys.h"
+#include "demangle_int.h"
+#include "cxx.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
+#endif
+
+#define CPP_QUAL_CONST (1U)
+#define CPP_QUAL_VOLATILE (2U)
+#define CPP_QUAL_RESTRICT (4U)
+
+typedef struct cpp_db_s {
+ sysdem_ops_t *cpp_ops;
+ jmp_buf cpp_jmp;
+ name_t cpp_name;
+ sub_t cpp_subs;
+ templ_t cpp_templ;
+ unsigned cpp_cv;
+ unsigned cpp_ref;
+ unsigned cpp_depth;
+ boolean_t cpp_parsed_ctor_dtor_cv;
+ boolean_t cpp_tag_templates;
+ boolean_t cpp_fix_forward_references;
+ boolean_t cpp_try_to_parse_template_args;
+ locale_t cpp_loc;
+} cpp_db_t;
+
+#define CK(x) \
+ do { \
+ if (!(x)) { \
+ longjmp(db->cpp_jmp, 1); \
+ } \
+ NOTE(CONSTCOND) \
+ } while (0)
+
+#define TOP_L(db) (&(name_top(&(db)->cpp_name)->strp_l))
+#define RLEN(f, l) ((size_t)((l) - (f)))
+#define NAMT(db, n) (nlen(db) - n)
+
+static inline boolean_t is_xdigit(int);
+
+static boolean_t nempty(cpp_db_t *);
+static size_t nlen(cpp_db_t *);
+static void nadd_l(cpp_db_t *, const char *, size_t);
+static void njoin(cpp_db_t *, size_t, const char *);
+static void nfmt(cpp_db_t *, const char *, const char *);
+
+static void save_top(cpp_db_t *, size_t);
+static void sub(cpp_db_t *, size_t);
+
+static boolean_t tempty(const cpp_db_t *);
+static size_t ttlen(const cpp_db_t *);
+
+static void tsub(cpp_db_t *, size_t);
+static void tpush(cpp_db_t *);
+static void tpop(cpp_db_t *);
+static void tsave(cpp_db_t *, size_t);
+
+static boolean_t db_init(cpp_db_t *, sysdem_ops_t *);
+static void db_fini(cpp_db_t *);
+static void dump(cpp_db_t *, FILE *);
+
+static void demangle(const char *, const char *, cpp_db_t *);
+
+static const char *parse_type(const char *, const char *, cpp_db_t *);
+static const char *parse_builtin_type(const char *, const char *, cpp_db_t *);
+static const char *parse_qual_type(const char *, const char *, cpp_db_t *);
+static const char *parse_encoding(const char *, const char *, cpp_db_t *);
+static const char *parse_dot_suffix(const char *, const char *, cpp_db_t *);
+static const char *parse_block_invoke(const char *, const char *, cpp_db_t *);
+static const char *parse_special_name(const char *, const char *, cpp_db_t *);
+static const char *parse_name(const char *, const char *, boolean_t *,
+ cpp_db_t *);
+static const char *parse_call_offset(const char *, const char *, locale_t);
+static const char *parse_number(const char *, const char *, locale_t);
+static const char *parse_nested_name(const char *, const char *, boolean_t *,
+ cpp_db_t *);
+static const char *parse_local_name(const char *, const char *, boolean_t *,
+ cpp_db_t *);
+static const char *parse_unscoped_name(const char *, const char *, cpp_db_t *);
+static const char *parse_template_args(const char *, const char *, cpp_db_t *);
+static const char *parse_substitution(const char *, const char *, cpp_db_t *);
+static const char *parse_discriminator(const char *, const char *, locale_t);
+static const char *parse_cv_qualifiers(const char *, const char *, unsigned *);
+static const char *parse_template_param(const char *, const char *, cpp_db_t *);
+static const char *parse_decltype(const char *, const char *, cpp_db_t *);
+static const char *parse_template_args(const char *, const char *, cpp_db_t *);
+static const char *parse_unqualified_name(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_template_arg(const char *, const char *, cpp_db_t *);
+static const char *parse_expression(const char *, const char *, cpp_db_t *);
+static const char *parse_expr_primary(const char *, const char *, cpp_db_t *);
+static const char *parse_binary_expr(const char *, const char *,
+ const char *, cpp_db_t *);
+static const char *parse_prefix_expr(const char *, const char *,
+ const char *, cpp_db_t *);
+static const char *parse_gs(const char *, const char *, cpp_db_t *);
+static const char *parse_idx_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_mm_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_pp_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_trinary_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_new_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_del_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_cast_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_sizeof_param_pack_expr(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_typeid_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_throw_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_dot_star_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_dot_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_call_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_arrow_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_conv_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_function_param(const char *, const char *, cpp_db_t *);
+static const char *parse_base_unresolved_name(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_unresolved_name(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_noexcept_expr(const char *, const char *, cpp_db_t *);
+static const char *parse_alignof(const char *, const char *, cpp_db_t *);
+static const char *parse_sizeof(const char *, const char *, cpp_db_t *);
+static const char *parse_unnamed_type_name(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_ctor_dtor_name(const char *, const char *, cpp_db_t *);
+static const char *parse_source_name(const char *, const char *, cpp_db_t *);
+static const char *parse_operator_name(const char *, const char *, cpp_db_t *);
+static const char *parse_pack_expansion(const char *, const char *, cpp_db_t *);
+static const char *parse_unresolved_type(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_unresolved_qualifier_level(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_destructor_name(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_function_type(const char *, const char *, cpp_db_t *);
+static const char *parse_array_type(const char *, const char *, cpp_db_t *);
+static const char *parse_pointer_to_member_type(const char *, const char *,
+ cpp_db_t *);
+static const char *parse_vector_type(const char *, const char *, cpp_db_t *);
+
+size_t cpp_name_max_depth = 1024; /* max depth of name stack */
+
+char *
+cpp_demangle(const char *src, sysdem_ops_t *ops)
+{
+ char *result = NULL;
+ cpp_db_t db;
+ size_t srclen = strlen(src);
+
+ if (!db_init(&db, ops))
+ goto done;
+ if (setjmp(db.cpp_jmp) != 0)
+ goto done;
+
+ errno = 0;
+ demangle(src, src + srclen, &db);
+
+ if (errno == 0 && db.cpp_fix_forward_references &&
+ !templ_empty(&db.cpp_templ) &&
+ !sub_empty(&db.cpp_templ.tpl_items[0])) {
+ db.cpp_fix_forward_references = B_FALSE;
+ db.cpp_tag_templates = B_FALSE;
+ name_clear(&db.cpp_name);
+ sub_clear(&db.cpp_subs);
+
+ if (setjmp(db.cpp_jmp) != 0)
+ goto done;
+
+ demangle(src, src + srclen, &db);
+
+ if (db.cpp_fix_forward_references) {
+ errno = EINVAL;
+ goto done;
+ }
+ }
+
+ if (errno != 0)
+ goto done;
+
+ if (nempty(&db)) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ njoin(&db, 1, "");
+
+ if (nlen(&db) > 0) {
+ str_t *s = TOP_L(&db);
+ result = zalloc(ops, s->str_len + 1);
+ if (result == NULL)
+ goto done;
+
+ (void) memcpy(result, s->str_s, s->str_len);
+ }
+
+done:
+ if (demangle_debug)
+ dump(&db, stdout);
+
+ db_fini(&db);
+ return (result);
+}
+
+static void
+demangle(const char *first, const char *last, cpp_db_t *db)
+{
+ const char *t = NULL;
+
+ if (first >= last) {
+ errno = EINVAL;
+ return;
+ }
+
+ if (first[0] != '_') {
+ t = parse_type(first, last, db);
+ if (t == first) {
+ errno = EINVAL;
+ return;
+ }
+ goto done;
+ }
+
+ if (last - first < 4) {
+ errno = EINVAL;
+ return;
+ }
+
+ if (first[1] == 'Z') {
+ t = parse_encoding(first + 2, last, db);
+
+ if (t != first + 2 && t != last && t[0] == '.') {
+ t = parse_dot_suffix(t, last, db);
+ if (nlen(db) > 1)
+ njoin(db, 2, "");
+ }
+
+ goto done;
+ }
+
+ if (first[1] != '_' || first[2] != '_' || first[3] != 'Z')
+ goto done;
+
+ t = parse_encoding(first + 4, last, db);
+ if (t != first + 4 && t != last)
+ t = parse_block_invoke(t, last, db);
+
+done:
+ if (t != last)
+ errno = EINVAL;
+}
+
+static const char *
+parse_dot_suffix(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last || first[0] != '.')
+ return (first);
+
+ if (nempty(db))
+ return (first);
+
+ nadd_l(db, first, RLEN(first, last));
+ nfmt(db, " ({0})", NULL);
+
+ return (last);
+}
+
+/*
+ * _block_invoke
+ * _block_invoke<digit>*
+ * _block_invoke_<digit>+
+ */
+static const char *
+parse_block_invoke(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 13)
+ return (first);
+
+ const char test[] = "_block_invoke";
+ const char *t = first;
+
+ if (strncmp(first, test, sizeof (test) - 1) != 0)
+ return (first);
+
+ t += sizeof (test);
+ if (t == last)
+ goto done;
+
+ if (t[0] == '_') {
+ /* need at least one digit */
+ if (t + 1 == last || !isdigit_l(t[1], db->cpp_loc))
+ return (first);
+ t += 2;
+ }
+
+ while (t < last && isdigit_l(t[0], db->cpp_loc))
+ t++;
+
+done:
+ if (nempty(db))
+ return (first);
+
+ nfmt(db, "invocation function for block in {0}", NULL);
+ return (t);
+}
+
+/*
+ * <encoding> ::= <function name><bare-function-type>
+ * ::= <data name>
+ * ::= <special name>
+ */
+static const char *
+parse_encoding(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ const char *t = NULL;
+ const char *t2 = NULL;
+ unsigned cv = 0;
+ unsigned ref = 0;
+ boolean_t tag_templ_save = db->cpp_tag_templates;
+
+ if (++db->cpp_depth > 1)
+ db->cpp_tag_templates = B_TRUE;
+
+ if (first[0] == 'G' || first[0] == 'T') {
+ t = parse_special_name(first, last, db);
+ goto done;
+ }
+
+ boolean_t ends_with_template_args = B_FALSE;
+ t = parse_name(first, last, &ends_with_template_args, db);
+ if (t == first)
+ goto fail;
+
+ cv = db->cpp_cv;
+ ref = db->cpp_ref;
+
+ if (t == last || t[0] == 'E' || t[0] == '.')
+ goto done;
+
+ db->cpp_tag_templates = B_FALSE;
+ if (nempty(db) || str_length(TOP_L(db)) == 0)
+ goto fail;
+
+ if (!db->cpp_parsed_ctor_dtor_cv && ends_with_template_args) {
+ t2 = parse_type(t, last, db);
+ if (t2 == t || nlen(db) < 2)
+ goto fail;
+
+ str_pair_t *sp = name_top(&db->cpp_name);
+
+ if (str_length(&sp->strp_r) == 0)
+ (void) str_append(&sp->strp_l, " ", 1);
+
+ nfmt(db, "{0:L}{1:L}", "{1:R}{0:R}");
+ t = t2;
+ }
+
+ if (t == last || nempty(db))
+ goto fail;
+
+ size_t n = nlen(db);
+
+ if (t[0] == 'v') {
+ t++;
+ } else {
+ for (;;) {
+ t2 = parse_type(t, last, db);
+ if (t2 == t || t == last)
+ break;
+
+ t = t2;
+ }
+ }
+
+ /*
+ * a bit of a hack, but a template substitution can apparently be
+ * an empty string at the end of an argument list, so avoid
+ * <...., >
+ */
+ if (NAMT(db, n) > 1 && str_pair_len(name_top(&db->cpp_name)) == 0)
+ name_pop(&db->cpp_name, NULL);
+
+ njoin(db, NAMT(db, n), ", ");
+ nfmt(db, "({0})", NULL);
+
+ str_t *s = TOP_L(db);
+
+ if (cv & CPP_QUAL_CONST) {
+ CK(str_append(s, " const", 0));
+ }
+ if (cv & CPP_QUAL_VOLATILE) {
+ CK(str_append(s, " volatile", 0));
+ }
+ if (cv & CPP_QUAL_RESTRICT) {
+ CK(str_append(s, " restrict", 0));
+ }
+ if (ref == 1) {
+ CK(str_append(s, " &", 0));
+ }
+ if (ref == 2) {
+ CK(str_append(s, " &&", 0));
+ }
+
+ nfmt(db, "{1:L}{0}{1:R}", NULL);
+
+done:
+ db->cpp_tag_templates = tag_templ_save;
+ db->cpp_depth--;
+ return (t);
+
+fail:
+ db->cpp_tag_templates = tag_templ_save;
+ db->cpp_depth--;
+ return (first);
+}
+
+/*
+ * <special-name> ::= TV <type> # virtual table
+ * ::= TT <type> # VTT structure (construction vtable index)
+ * ::= TI <type> # typeinfo structure
+ * ::= TS <type> # typeinfo name (null-terminated byte string)
+ * ::= Tc <call-offset> <call-offset> <base encoding>
+ * # base is the nominal target function of thunk
+ * # first call-offset is 'this' adjustment
+ * # second call-offset is result adjustment
+ * ::= T <call-offset> <base encoding>
+ * # base is the nominal target function of thunk
+ * ::= GV <object name> # Guard variable for one-time init
+ * # No <type>
+ * ::= TW <object name> # Thread-local wrapper
+ * ::= TH <object name> # Thread-local initialization
+ * extension ::= TC <first type> <number> _ <second type>
+ * # construction vtable for second-in-first
+ * extension ::= GR <object name> # reference temporary for object
+ */
+static const char *
+parse_special_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = first;
+ const char *t1 = NULL;
+ size_t n = nlen(db);
+
+ if (last - first < 2)
+ return (first);
+
+ switch (t[0]) {
+ case 'T':
+ switch (t[1]) {
+ case 'V':
+ nadd_l(db, "vtable for", 0);
+ t = parse_type(first + 2, last, db);
+ break;
+ case 'T':
+ nadd_l(db, "VTT for", 0);
+ t = parse_type(first + 2, last, db);
+ break;
+ case 'I':
+ nadd_l(db, "typeinfo for", 0);
+ t = parse_type(first + 2, last, db);
+ break;
+ case 'S':
+ nadd_l(db, "typeinfo name for", 0);
+ t = parse_type(first + 2, last, db);
+ break;
+ case 'c':
+ nadd_l(db, "covariant return thunk to", 0);
+ t1 = parse_call_offset(first + 2, last, db->cpp_loc);
+ if (t1 == t)
+ return (first);
+ t = parse_call_offset(t1, last, db->cpp_loc);
+ if (t == t1)
+ return (first);
+ t1 = parse_encoding(t, last, db);
+ if (t1 == t)
+ return (first);
+ break;
+ case 'C':
+ t = parse_type(first + 2, last, db);
+ if (t == first + 2)
+ return (first);
+ t1 = parse_number(t, last, db->cpp_loc);
+ if (*t1 != '_')
+ return (first);
+ t = parse_type(t1 + 1, last, db);
+ if (t == t1 + 1 || nlen(db) < 2)
+ return (first);
+ nfmt(db, "construction vtable for {0}-in-{1}", NULL);
+ return (t);
+ case 'W':
+ nadd_l(db, "thread-local wrapper routine for", 0);
+ t = parse_name(first + 2, last, NULL, db);
+ break;
+ case 'H':
+ nadd_l(db, "thread-local initialization routine for",
+ 0);
+ t = parse_name(first + 2, last, NULL, db);
+ break;
+ default:
+ if (first[1] == 'v') {
+ nadd_l(db, "virtual thunk to", 0);
+ } else {
+ nadd_l(db, "non-virtual thunk to", 0);
+ }
+
+ t = parse_call_offset(first + 1, last, db->cpp_loc);
+ if (t == first + 1)
+ return (first);
+ t1 = parse_encoding(t, last, db);
+ if (t == t1)
+ return (first);
+ t = t1;
+ break;
+ }
+ break;
+ case 'G':
+ switch (first[1]) {
+ case 'V':
+ nadd_l(db, "guard variable for", 0);
+ t = parse_name(first + 2, last, NULL, db);
+ break;
+ case 'R':
+ nadd_l(db, "reference temporary for", 0);
+ t = parse_name(first + 2, last, NULL, db);
+ break;
+ default:
+ return (first);
+ }
+ break;
+ default:
+ return (first);
+ }
+
+ size_t amt = NAMT(db, n);
+ if (t == first + 2 || amt < 2)
+ return (first);
+
+ njoin(db, amt, " ");
+ return (t);
+}
+
+/*
+ * <call-offset> ::= h <nv-offset> _
+ * ::= v <v-offset> _
+ *
+ * <nv-offset> ::= <offset number>
+ * # non-virtual base override
+ *
+ * <v-offset> ::= <offset number> _ <virtual offset number>
+ * # virtual base override, with vcall offset
+ */
+static const char *
+parse_call_offset(const char *first, const char *last, locale_t loc)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+
+ if (first == last)
+ return (first);
+
+ if (first[0] != 'h' && first[0] != 'v')
+ return (first);
+
+ t = parse_number(first + 1, last, loc);
+ if (t == first + 1 || t == last || t[0] != '_')
+ return (first);
+
+ /* skip _ */
+ t++;
+
+ if (first[0] == 'h')
+ return (t);
+
+ t1 = parse_number(t, last, loc);
+ if (t == t1 || t1 == last || t1[0] != '_')
+ return (first);
+
+ /* skip _ */
+ t1++;
+
+ return (t1);
+}
+
+/*
+ * <name> ::= <nested-name> // N
+ * ::= <local-name> # See Scope Encoding below // Z
+ * ::= <unscoped-template-name> <template-args>
+ * ::= <unscoped-name>
+ *
+ * <unscoped-template-name> ::= <unscoped-name>
+ * ::= <substitution>
+ */
+static const char *
+parse_name(const char *first, const char *last,
+ boolean_t *ends_with_template_args, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = first;
+ const char *t1 = NULL;
+
+ if (last - first < 2)
+ return (first);
+
+ /* extension: ignore L here */
+ if (t[0] == 'L')
+ t++;
+
+ switch (t[0]) {
+ case 'N':
+ t1 = parse_nested_name(t, last, ends_with_template_args, db);
+ return ((t == t1) ? first : t1);
+ case 'Z':
+ t1 = parse_local_name(t, last, ends_with_template_args, db);
+ return ((t == t1) ? first : t1);
+ }
+
+ /*
+ * <unscoped-name>
+ * <unscoped-name> <template-args>
+ * <substitution> <template-args>
+ */
+ t1 = parse_unscoped_name(t, last, db);
+
+ /* <unscoped-name> */
+ if (t != t1 && t1[0] != 'I')
+ return (t1);
+
+ if (t == t1) {
+ t1 = parse_substitution(t, last, db);
+ if (t == t1 || t1 == last || t1[0] != 'I')
+ return (first);
+ } else {
+ save_top(db, 1);
+ }
+
+ t = parse_template_args(t1, last, db);
+ if (t1 == t || nlen(db) < 2)
+ return (first);
+
+ nfmt(db, "{1:L}{0}", "{1:R}");
+
+ if (ends_with_template_args != NULL)
+ *ends_with_template_args = B_TRUE;
+
+ return (t);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ * := Z <function encoding> E s [<discriminator>]
+ * := Z <function encoding> Ed [ <parameter number> ] _ <entity name>
+ */
+/* END CSTYLED */
+const char *
+parse_local_name(const char *first, const char *last,
+ boolean_t *ends_with_template_args, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+ const char *t2 = NULL;
+
+ if (first == last || first[0] != 'Z')
+ return (first);
+
+ t = parse_encoding(first + 1, last, db);
+ if (t == first + 1 || t == last || t[0] != 'E')
+ return (first);
+
+ VERIFY(!nempty(db));
+
+ /* skip E */
+ t++;
+
+ if (t[0] == 's') {
+ nfmt(db, "{0:L}::string literal", "{0:R}");
+ return (parse_discriminator(t, last, db->cpp_loc));
+ }
+
+ if (t[0] == 'd') {
+ t1 = parse_number(t + 1, last, db->cpp_loc);
+ if (t1[0] != '_')
+ return (first);
+ t1++;
+ } else {
+ t1 = t;
+ }
+
+ t2 = parse_name(t1, last, ends_with_template_args, db);
+ if (t2 == t1)
+ return (first);
+
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+
+ /* parsed, but ignored */
+ if (t[0] != 'd')
+ t2 = parse_discriminator(t2, last, db->cpp_loc);
+
+ return (t2);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ * ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E
+ *
+ * <prefix> ::= <prefix> <unqualified-name>
+ * ::= <template-prefix> <template-args>
+ * ::= <template-param>
+ * ::= <decltype>
+ * ::= # empty
+ * ::= <substitution>
+ * ::= <prefix> <data-member-prefix>
+ * extension ::= L
+ *
+ * <template-prefix> ::= <prefix> <template unqualified-name>
+ * ::= <template-param>
+ * ::= <substitution>
+ */
+/* END CSTYLED */
+static const char *
+parse_nested_name(const char *first, const char *last,
+ boolean_t *ends_with_template_args, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last || first[0] != 'N')
+ return (first);
+
+ unsigned cv = 0;
+ const char *t = parse_cv_qualifiers(first + 1, last, &cv);
+
+ if (t == last)
+ return (first);
+
+ boolean_t more = B_FALSE;
+
+ switch (t[0]) {
+ case 'R':
+ db->cpp_ref = 1;
+ t++;
+ break;
+ case 'O':
+ db->cpp_ref = 2;
+ t++;
+ break;
+ case 'S':
+ if (last - first < 2 || t[1] != 't')
+ break;
+ if (last - first == 2)
+ return (first);
+ nadd_l(db, "std", 3);
+ more = B_TRUE;
+ t += 2;
+ break;
+ }
+
+ boolean_t pop_subs = B_FALSE;
+ boolean_t component_ends_with_template_args = B_FALSE;
+
+ while (t[0] != 'E' && t != last) {
+ const char *t1 = NULL;
+ size_t n = nlen(db);
+ component_ends_with_template_args = B_FALSE;
+
+ switch (t[0]) {
+ case 'S':
+ if (t + 1 != last && t[1] == 't')
+ break;
+
+ t1 = parse_substitution(t, last, db);
+ if (t1 == t || t1 == last || NAMT(db, n) != 1)
+ return (first);
+
+ if (!more) {
+ nfmt(db, "{0}", NULL);
+ } else {
+ VERIFY3U(nlen(db), >, 1);
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+ save_top(db, 1);
+ }
+
+ more = B_TRUE;
+ pop_subs = B_TRUE;
+ t = t1;
+ continue;
+
+ case 'T':
+ t1 = parse_template_param(t, last, db);
+ if (t1 == t || t1 == last || NAMT(db, n) != 1)
+ return (first);
+
+ if (!more) {
+ nfmt(db, "{0}", NULL);
+ } else {
+ VERIFY3U(nlen(db), >, 1);
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+ }
+
+ save_top(db, 1);
+ more = B_TRUE;
+ pop_subs = B_TRUE;
+ t = t1;
+ continue;
+
+ case 'D':
+ if (t + 1 != last && t[1] != 't' && t[1] != 'T')
+ break;
+ t1 = parse_decltype(t, last, db);
+ if (t1 == t || t1 == last || NAMT(db, n) != 1)
+ return (first);
+
+ if (!more) {
+ nfmt(db, "{0}", NULL);
+ } else {
+ VERIFY3U(nlen(db), >, 1);
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+ }
+
+ save_top(db, 1);
+ more = B_TRUE;
+ pop_subs = B_TRUE;
+ t = t1;
+ continue;
+
+ case 'I':
+ /*
+ * Must have at least one component before
+ * <template-args>
+ */
+ if (!more)
+ return (first);
+
+ t1 = parse_template_args(t, last, db);
+ if (t1 == t || t1 == last)
+ return (first);
+
+ VERIFY3U(nlen(db), >, 1);
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ save_top(db, 1);
+ t = t1;
+ component_ends_with_template_args = B_TRUE;
+ continue;
+
+ case 'L':
+ if (t + 1 == last)
+ return (first);
+ t++;
+ continue;
+
+ default:
+ break;
+ }
+
+ t1 = parse_unqualified_name(t, last, db);
+ if (t1 == t || t1 == last || NAMT(db, n) != 1)
+ return (first);
+
+ if (!more) {
+ nfmt(db, "{0}", NULL);
+ } else {
+ VERIFY3U(nlen(db), >, 1);
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+ }
+
+ save_top(db, 1);
+ more = B_TRUE;
+ pop_subs = B_TRUE;
+ t = t1;
+ }
+
+ /* need to parse at least one thing */
+ if (!more)
+ return (first);
+
+ db->cpp_cv = cv;
+ if (pop_subs && !sub_empty(&db->cpp_subs))
+ sub_pop(&db->cpp_subs);
+
+ if (ends_with_template_args != NULL)
+ *ends_with_template_args = component_ends_with_template_args;
+
+ if (t[0] != 'E')
+ return (first);
+
+ return (t + 1);
+}
+
+/*
+ * <template-arg> ::= <type> # type or template
+ * ::= X <expression> E # expression
+ * ::= <expr-primary> # simple expressions
+ * ::= J <template-arg>* E # argument pack
+ * ::= LZ <encoding> E # extension
+ */
+static const char *
+parse_template_arg(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+
+ if (first == last)
+ return (first);
+
+ switch (first[0]) {
+ case 'X':
+ t = parse_expression(first + 1, last, db);
+ if (t == first + 1 || t[0] != 'E')
+ return (first);
+
+ /* E */
+ t++;
+ break;
+
+ case 'J':
+ t = first + 1;
+ if (t == last)
+ return (first);
+
+ while (t[0] != 'E') {
+ t1 = parse_template_arg(t, last, db);
+ if (t == t1)
+ return (first);
+ t = t1;
+ }
+
+ /* E */
+ t++;
+ break;
+
+ case 'L':
+ if (first + 1 == last || first[1] != 'Z') {
+ t = parse_expr_primary(first, last, db);
+ } else {
+ t = parse_encoding(first + 2, last, db);
+ if (t == first + 2 || t == last || t[0] != 'E')
+ return (first);
+
+ /* E */
+ t++;
+ }
+ break;
+
+ default:
+ t = parse_type(first, last, db);
+ }
+
+ return (t);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <expression> ::= <unary operator-name> <expression>
+ * ::= <binary operator-name> <expression> <expression>
+ * ::= <ternary operator-name> <expression> <expression> <expression>
+ * ::= cl <expression>+ E # call
+ * ::= cv <type> <expression> # conversion with one argument
+ * ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+ * ::= [gs] nw <expression>* _ <type> E # new (expr-list) type
+ * ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+ * ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type
+ * ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+ * ::= [gs] dl <expression> # delete expression
+ * ::= [gs] da <expression> # delete[] expression
+ * ::= pp_ <expression> # prefix ++
+ * ::= mm_ <expression> # prefix --
+ * ::= ti <type> # typeid (type)
+ * ::= te <expression> # typeid (expression)
+ * ::= dc <type> <expression> # dynamic_cast<type> (expression)
+ * ::= sc <type> <expression> # static_cast<type> (expression)
+ * ::= cc <type> <expression> # const_cast<type> (expression)
+ * ::= rc <type> <expression> # reinterpret_cast<type> (expression)
+ * ::= st <type> # sizeof (a type)
+ * ::= sz <expression> # sizeof (an expression)
+ * ::= at <type> # alignof (a type)
+ * ::= az <expression> # alignof (an expression)
+ * ::= nx <expression> # noexcept (expression)
+ * ::= <template-param>
+ * ::= <function-param>
+ * ::= dt <expression> <unresolved-name> # expr.name
+ * ::= pt <expression> <unresolved-name> # expr->name
+ * ::= ds <expression> <expression> # expr.*expr
+ * ::= sZ <template-param> # size of a parameter pack
+ * ::= sZ <function-param> # size of a function parameter pack
+ * ::= sp <expression> # pack expansion
+ * ::= tw <expression> # throw expression
+ * ::= tr # throw with no operand (rethrow)
+ * ::= <unresolved-name> # f(p), N::f(p), ::f(p),
+ * # freestanding dependent name (e.g., T::x),
+ * # objectless nonstatic member reference
+ * ::= <expr-primary>
+ */
+/* END CSTYLED */
+
+#define PA(cd, arg, fn) { \
+ .code = cd, \
+ .p.parse_expr_arg = fn, \
+ .fntype = EXPR_ARG, \
+ .val = arg \
+}
+
+#define PN(cd, fn) { \
+ .code = cd, \
+ .p.parse_expr_noarg = fn, \
+ .fntype = EXPR_NOARG \
+}
+
+static struct {
+ const char code[3];
+ union {
+ const char *(*parse_expr_arg)(const char *, const char *,
+ const char *, cpp_db_t *);
+ const char *(*parse_expr_noarg)(const char *, const char *,
+ cpp_db_t *);
+ } p;
+ enum {
+ EXPR_ARG,
+ EXPR_NOARG
+ } fntype;
+ const char val[4];
+} expr_tbl[] = {
+ PA("aN", "&=", parse_binary_expr),
+ PA("aS", "=", parse_binary_expr),
+ PA("aa", "&&", parse_binary_expr),
+ PA("ad", "&", parse_prefix_expr),
+ PA("an", "&", parse_binary_expr),
+ PN("at", parse_alignof),
+ PN("az", parse_alignof),
+ PN("cc", parse_cast_expr),
+ PN("cl", parse_call_expr),
+ PA("cm", ",", parse_binary_expr),
+ PA("co", "~", parse_prefix_expr),
+ PN("cv", parse_conv_expr),
+ PN("da", parse_del_expr),
+ PA("dV", "/=", parse_binary_expr),
+ PN("dc", parse_cast_expr),
+ PA("de", "*", parse_prefix_expr),
+ PN("dl", parse_del_expr),
+ PN("dn", parse_unresolved_name),
+ PN("ds", parse_dot_star_expr),
+ PN("dt", parse_dot_expr),
+ PA("dv", "/", parse_binary_expr),
+ PA("eO", "^=", parse_binary_expr),
+ PA("eo", "^", parse_binary_expr),
+ PA("eq", "==", parse_binary_expr),
+ PA("ge", ">=", parse_binary_expr),
+ PN("gs", parse_gs),
+ PA("gt", ">", parse_binary_expr),
+ PN("ix", parse_idx_expr),
+ PA("lS", "<<=", parse_binary_expr),
+ PA("le", "<=", parse_binary_expr),
+ PA("ls", "<<", parse_binary_expr),
+ PA("lt", "<", parse_binary_expr),
+ PA("mI", "-=", parse_binary_expr),
+ PA("mL", "*=", parse_binary_expr),
+ PN("mm", parse_mm_expr),
+ PA("mi", "-", parse_binary_expr),
+ PA("ml", "*", parse_binary_expr),
+ PN("na", parse_new_expr),
+ PA("ne", "!=", parse_binary_expr),
+ PA("ng", "-", parse_prefix_expr),
+ PA("nt", "!", parse_prefix_expr),
+ PN("nw", parse_new_expr),
+ PN("nx", parse_noexcept_expr),
+ PA("oR", "|=", parse_binary_expr),
+ PN("on", parse_unresolved_name),
+ PA("oo", "||", parse_binary_expr),
+ PA("or", "|", parse_binary_expr),
+ PA("pL", "+=", parse_binary_expr),
+ PA("pl", "+", parse_binary_expr),
+ PA("pm", "->*", parse_binary_expr),
+ PN("pp", parse_pp_expr),
+ PA("ps", "+", parse_prefix_expr),
+ PN("pt", parse_arrow_expr),
+ PN("qu", parse_trinary_expr),
+ PA("rM", "%=", parse_binary_expr),
+ PA("rS", ">>=", parse_binary_expr),
+ PN("rc", parse_cast_expr),
+ PA("rm", "%", parse_binary_expr),
+ PA("rs", ">>", parse_binary_expr),
+ PN("sc", parse_cast_expr),
+ PN("sp", parse_pack_expansion),
+ PN("sr", parse_unresolved_name),
+ PN("st", parse_sizeof),
+ PN("sz", parse_sizeof),
+ PN("sZ", parse_sizeof_param_pack_expr),
+ PN("te", parse_typeid_expr),
+ PN("tr", parse_throw_expr),
+ PN("tw", parse_throw_expr)
+};
+#undef PA
+#undef PN
+
+static const char *
+parse_expression(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ for (size_t i = 0; i < ARRAY_SIZE(expr_tbl); i++) {
+ if (strncmp(expr_tbl[i].code, first, 2) != 0)
+ continue;
+ switch (expr_tbl[i].fntype) {
+ case EXPR_ARG:
+ return (expr_tbl[i].p.parse_expr_arg(first, last,
+ expr_tbl[i].val, db));
+ case EXPR_NOARG:
+ return (expr_tbl[i].p.parse_expr_noarg(first, last,
+ db));
+ }
+ }
+
+ switch (first[0]) {
+ case 'L':
+ return (parse_expr_primary(first, last, db));
+ case 'T':
+ return (parse_template_param(first, last, db));
+ case 'f':
+ return (parse_function_param(first, last, db));
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return (parse_unresolved_name(first, last, db));
+ }
+
+ return (first);
+}
+
+static const char *
+parse_binary_expr(const char *first, const char *last, const char *op,
+ cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ size_t n = nlen(db);
+
+ const char *t1 = parse_expression(first + 2, last, db);
+ if (t1 == first + 2)
+ return (first);
+
+ nadd_l(db, op, 0);
+
+ const char *t2 = parse_expression(t1, last, db);
+ if (t2 == t1)
+ return (first);
+
+ if (NAMT(db, n) != 3)
+ return (first);
+
+ VERIFY3U(nlen(db), >, 2);
+
+ nfmt(db, "({2}) {1} ({0})", NULL);
+ if (strcmp(op, ">") == 0)
+ nfmt(db, "({0})", NULL);
+
+ return (t2);
+}
+
+static const char *
+parse_prefix_expr(const char *first, const char *last, const char *op,
+ cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ nadd_l(db, op, 0);
+
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2) {
+ return (first);
+ }
+
+ VERIFY3U(nlen(db), >, 1);
+
+ nfmt(db, "{1}({0})", NULL);
+ return (t);
+}
+
+static const char *
+parse_gs(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+
+ if (last - first < 4)
+ return (first);
+
+ if (first[2] == 'n' && (first[3] == 'a' || first[3] == 'w'))
+ t = parse_new_expr(first + 2, last, db);
+ else if (first[2] == 'd' && (first[3] == 'l' || first[3] == 'a'))
+ t = parse_del_expr(first + 2, last, db);
+ else
+ return (first);
+
+ if (t == first + 2)
+ return (first);
+
+ VERIFY3U(nlen(db), >, 0);
+
+ nfmt(db, "::{0}", NULL);
+ return (t);
+}
+
+/*
+ * [gs] nw <expression>* _ <type> E # new (expr-list) type
+ * [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init)
+ * [gs] na <expression>* _ <type> E # new[] (expr-list) type
+ * [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init)
+ * <initializer> ::= pi <expression>* E # parenthesized initialization
+ */
+static const char *
+parse_new_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ /* note [gs] is already handled by parse_gs() */
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'n');
+ VERIFY(first[1] == 'a' || first[1] == 'w');
+
+ const char *t1 = first + 2;
+ const char *t2 = NULL;
+ size_t n = nlen(db);
+
+ nadd_l(db, (first[1] == 'w') ? "new" : "new[]", 0);
+
+ while (t1 != last && t1[0] != '_') {
+ t2 = parse_expression(t1, last, db);
+ VERIFY3P(t2, !=, NULL);
+ if (t2 == t1)
+ return (first);
+ t1 = t2;
+ }
+ if (t1 == last)
+ return (first);
+
+ if (NAMT(db, n) > 1) {
+ njoin(db, NAMT(db, n) - 1, ", ");
+ nfmt(db, "({0})", NULL);
+ }
+
+ t2 = parse_type(t1 + 1, last, db);
+ if (t1 + 1 == t2)
+ return (first);
+
+ if (t2[0] != 'E') {
+ if (last - t2 < 3)
+ return (first);
+ if (t2[0] != 'p' && t2[1] != 'i')
+ return (first);
+
+ t2 += 2;
+ const char *t3 = t2;
+ size_t n1 = nlen(db);
+
+ while (t2[0] != 'E' && t2 != last) {
+ t3 = parse_expression(t2, last, db);
+
+ if (t2 == t3)
+ return (first);
+ t2 = t3;
+ }
+ if (t3 == last || t3[0] != 'E')
+ return (first);
+
+ if (NAMT(db, n1) > 0) {
+ njoin(db, NAMT(db, n1), ", ");
+ nfmt(db, "({0})", NULL);
+ }
+ }
+
+ njoin(db, NAMT(db, n), " ");
+ return (t2 + 1);
+}
+
+static const char *
+parse_del_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'd');
+ VERIFY(first[1] == 'l' || first[1] == 'a');
+
+ size_t n = nlen(db);
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, (first[1] == 'a') ? "delete[] {0}" : "delete {0}", NULL);
+ return (t);
+}
+
+static const char *
+parse_idx_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+ VERIFY3U(first[0], ==, 'i');
+ VERIFY3U(first[1], ==, 'x');
+
+ size_t n = nlen(db);
+ const char *t1 = parse_expression(first + 2, last, db);
+ if (t1 == first + 2)
+ return (first);
+
+ const char *t2 = parse_expression(t1, last, db);
+ if (t2 == t1 || NAMT(db, n) != 2)
+ return (first);
+
+ nfmt(db, "({0})[{1}]", NULL);
+ return (t2);
+}
+
+static const char *
+parse_ppmm_expr(const char *first, const char *last, const char *fmt,
+ cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ const char *t = NULL;
+ size_t n = nlen(db);
+
+ if (first[2] == '_') {
+ t = parse_binary_expr(first + 3, last, "--", db);
+ if (t == first + 3)
+ return (first);
+ return (t);
+ }
+
+ t = parse_expression(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) < 1)
+ return (first);
+
+ nfmt(db, fmt, NULL);
+ return (t);
+}
+
+static const char *
+parse_mm_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+ VERIFY3U(first[0], ==, 'm');
+ VERIFY3U(first[1], ==, 'm');
+
+ return (parse_ppmm_expr(first, last, "({0})--", db));
+}
+
+static const char *
+parse_pp_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ VERIFY3U(first[0], ==, 'p');
+ VERIFY3U(first[0], ==, 'p');
+
+ return (parse_ppmm_expr(first, last, "({0})++", db));
+}
+
+static const char *
+parse_trinary_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t1, *t2, *t3;
+ size_t n = nlen(db);
+
+ if (last - first < 2)
+ return (first);
+
+ t1 = parse_expression(first + 2, last, db);
+ if (t1 == first + 2)
+ return (first);
+ t2 = parse_expression(t1, last, db);
+ if (t1 == t2)
+ return (first);
+ t3 = parse_expression(t2, last, db);
+ if (t3 == t2)
+ return (first);
+
+ if (NAMT(db, n) != 3)
+ return (first);
+
+ nfmt(db, "({2}) ? ({1}) : ({0})", NULL);
+ return (t3);
+}
+
+static const char *
+parse_noexcept_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ size_t n = nlen(db);
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, "noexcept ({0})", NULL);
+ return (t);
+}
+
+/*
+ * cc <type> <expression> # const_cast<type> (expression)
+ * dc <type> <expression> # dynamic_cast<type> (expression)
+ * rc <type> <expression> # reinterpret_cast<type> (expression)
+ * sc <type> <expression> # static_cast<type> (expression)
+ */
+static const char *
+parse_cast_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ const char *fmt = NULL;
+ switch (first[0]) {
+ case 'c':
+ fmt = "const_cast<{1}> ({0})";
+ break;
+ case 'd':
+ fmt = "dynamic_cast<{1}> ({0})";
+ break;
+ case 'r':
+ fmt = "reinterpret_cast<{1}> ({0})";
+ break;
+ case 's':
+ fmt = "static_cast<{1}> ({0})";
+ break;
+ default:
+ return (first);
+ }
+
+ VERIFY3U(first[1], ==, 'c');
+
+ const char *t1 = parse_type(first + 2, last, db);
+ if (t1 == first + 2)
+ return (first);
+
+ const char *t2 = parse_expression(t1, last, db);
+ if (t2 == t1)
+ return (first);
+
+ VERIFY3U(nlen(db), >, 1);
+
+ nfmt(db, fmt, NULL);
+ return (t2);
+}
+
+/* pt <expression> <expression> # expr->name */
+static const char *
+parse_arrow_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 4)
+ return (first);
+
+ size_t n = nlen(db);
+
+ const char *t1 = parse_expression(first + 2, last, db);
+ if (t1 == first + 2)
+ return (first);
+
+ const char *t2 = parse_expression(t1, last, db);
+ if (t2 == t1 || NAMT(db, n) != 2)
+ return (first);
+
+ nfmt(db, "{1}->{0}", NULL);
+ return (t2);
+}
+
+/* wrap value in () when necessary */
+static void
+paren(str_pair_t *sp)
+{
+ str_t *l = &sp->strp_l;
+ str_t *r = &sp->strp_r;
+
+ if (str_length(r) > 1 &&
+ r->str_s[0] == ' ' && r->str_s[1] == '[') {
+ (void) str_append(l, " (", 2);
+ (void) str_insert(r, 0, ")", 1);
+ } else if (str_length(r) > 0 && r->str_s[0] == '(') {
+ (void) str_append(l, "(", 1);
+ (void) str_insert(r, 0, ")", 1);
+ }
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <type> ::= <builtin-type>
+ * ::= <function-type>
+ * ::= <class-enum-type>
+ * ::= <array-type>
+ * ::= <pointer-to-member-type>
+ * ::= <template-param>
+ * ::= <template-template-param> <template-args>
+ * ::= <decltype>
+ * ::= <substitution>
+ * ::= <CV-qualifiers> <type>
+ * ::= P <type> # pointer-to
+ * ::= R <type> # reference-to
+ * ::= O <type> # rvalue reference-to (C++0x)
+ * ::= C <type> # complex pair (C 2000)
+ * ::= G <type> # imaginary (C 2000)
+ * ::= Dp <type> # pack expansion (C++0x)
+ * ::= U <source-name> <type> # vendor extended type qualifier
+ * extension := U <objc-name> <objc-type> # objc-type<identifier>
+ * extension := <vector-type> # <vector-type> starts with Dv
+ *
+ * <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1
+ * <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name>
+ */
+/* END CSTYLED */
+static const char *
+parse_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ switch (first[0]) {
+ case 'r':
+ case 'V':
+ case 'K':
+ return (parse_qual_type(first, last, db));
+ }
+
+ const char *t = first;
+ const char *t1 = NULL;
+ str_pair_t *sp = NULL;
+ size_t n = nlen(db);
+ size_t amt = 0;
+
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ return (t);
+
+ switch (first[0]) {
+ case 'A':
+ t = parse_array_type(first, last, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+ save_top(db, 1);
+ return (t);
+
+ case 'C':
+ t = parse_type(first + 1, last, db);
+ if (t == first + 1 || NAMT(db, n) == 0)
+ return (first);
+
+ (void) str_append(TOP_L(db), " complex", 8);
+ save_top(db, 1);
+ return (t);
+
+ case 'F':
+ t = parse_function_type(first, last, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+ save_top(db, 1);
+ return (t);
+
+ case 'G':
+ t = parse_type(first + 1, last, db);
+ if (t == first + 1 || NAMT(db, n) == 0)
+ return (first);
+
+ (void) str_append(TOP_L(db), " imaginary", 10);
+ save_top(db, 1);
+ return (t);
+
+ case 'M':
+ t = parse_pointer_to_member_type(first, last, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+ save_top(db, 1);
+ return (t);
+
+ case 'O':
+ t = parse_type(first + 1, last, db);
+ amt = NAMT(db, n);
+ if (t == first + 1 || amt == 0)
+ return (first);
+
+ sp = name_at(&db->cpp_name, amt - 1);
+ for (size_t i = 0; i < amt; i++, sp++) {
+ paren(sp);
+ if (str_pair_len(sp) > 0)
+ (void) str_append(&sp->strp_l, "&&", 2);
+ }
+
+ save_top(db, amt);
+ return (t);
+
+ case 'P':
+ t = parse_type(first + 1, last, db);
+ amt = NAMT(db, n);
+ if (t == first + 1 || amt == 0)
+ return (first);
+
+ sp = name_at(&db->cpp_name, amt - 1);
+ for (size_t i = 0; i < amt; i++, sp++) {
+ str_t *l = &sp->strp_l;
+
+ if (str_pair_len(sp) == 0)
+ continue;
+
+ paren(sp);
+ if (first[1] != 'U' ||
+ strncmp(l->str_s, "objc_object<", 12) != 0) {
+ (void) str_append(l, "*", 1);
+ } else {
+ (void) str_erase(l, 0, 11);
+ (void) str_insert(l, 0, "id", 2);
+ }
+ }
+ save_top(db, amt);
+ return (t);
+
+ case 'R':
+ t = parse_type(first + 1, last, db);
+ amt = NAMT(db, n);
+ if (t == first + 1 || amt == 0)
+ return (first);
+
+ sp = name_at(&db->cpp_name, amt - 1);
+ for (size_t i = 0; i < amt; i++, sp++) {
+ if (str_length(&sp->strp_l) == 0 &&
+ str_length(&sp->strp_r) == 0)
+ continue;
+
+ paren(sp);
+ (void) str_append(&sp->strp_l, "&", 1);
+ }
+
+ save_top(db, amt);
+ return (t);
+
+ case 'T':
+ t = parse_template_param(first, last, db);
+ if (t == first)
+ return (first);
+
+ amt = NAMT(db, n);
+ save_top(db, amt);
+ if (!db->cpp_try_to_parse_template_args || amt != 1)
+ return (t);
+
+ t1 = parse_template_args(t, last, db);
+ if (t1 == t)
+ return (t);
+
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ save_top(db, 1);
+ return (t1);
+
+ case 'U':
+ if (first + 1 == last)
+ return (first);
+
+ t = parse_source_name(first + 1, last, db);
+ if (t == first + 1)
+ return (first);
+
+ nfmt(db, "{0}", NULL);
+
+ t1 = parse_type(t, last, db);
+ if (t1 == t || NAMT(db, n) < 2)
+ return (first);
+
+ const str_t *name = &name_at(&db->cpp_name, 1)->strp_l;
+
+ if (str_length(name) > 0 &&
+ strncmp(name->str_s, "objcproto", 9) != 0) {
+ nfmt(db, "{0} {1}", NULL);
+ } else {
+ t = parse_source_name(name->str_s + 9,
+ name->str_s + name->str_len, db);
+ if (t != name->str_s + 9) {
+ nfmt(db, "{1}<{0}>", NULL);
+
+ str_pair_t save = {0};
+
+ name_pop(&db->cpp_name, &save);
+
+ /* get rid of 'objcproto' */
+ name_pop(&db->cpp_name, NULL);
+ CK(name_add_str(&db->cpp_name, &save.strp_l,
+ &save.strp_r));
+ } else {
+ nfmt(db, "{1} {0}", NULL);
+ }
+ }
+
+ save_top(db, 1);
+ return (t1);
+
+ case 'S':
+ if (first + 1 != last && first[1] == 't') {
+ t = parse_name(first, last, NULL, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+
+ save_top(db, 1);
+ return (t);
+ }
+
+ t = parse_substitution(first, last, db);
+ if (t == first)
+ return (first);
+
+ /*
+ * If the substitution is a <template-param>, it might
+ * be followed by <template-args>
+ */
+ t1 = parse_template_args(t, last, db);
+ if (t1 == t)
+ return (t);
+
+ if (NAMT(db, n) < 2)
+ return (t);
+
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ save_top(db, 1);
+ return (t1);
+
+ case 'D':
+ if (first + 1 == last)
+ return (first);
+
+ switch (first[1]) {
+ case 'p':
+ t = parse_type(first + 2, last, db);
+ if (t == first + 2)
+ break;
+
+ save_top(db, NAMT(db, n));
+ return (t);
+
+ case 't':
+ case 'T':
+ t = parse_decltype(first, last, db);
+ if (first == t)
+ break;
+
+ save_top(db, 1);
+ return (t);
+
+ case 'v':
+ t = parse_vector_type(first, last, db);
+ if (first == t)
+ break;
+
+ if (NAMT(db, n) == 0)
+ return (first);
+
+ save_top(db, 1);
+ return (t);
+ }
+ break;
+ }
+
+ /*
+ * must check for builtin-types before class-enum-types to avoid
+ * ambiguities with operator-names
+ */
+ t = parse_builtin_type(first, last, db);
+ if (t != first)
+ return (t);
+
+ t = parse_name(first, last, NULL, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+
+ save_top(db, 1);
+ return (t);
+}
+
+static const char *
+parse_qual_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+ unsigned cv = 0;
+
+ t = parse_cv_qualifiers(first, last, &cv);
+ if (t == first)
+ return (first);
+
+ size_t n = nlen(db);
+ boolean_t is_func = !!(t[0] == 'F');
+
+ t1 = parse_type(t, last, db);
+ size_t amt = NAMT(db, n);
+ if (t == t1 || amt == 0)
+ return (first);
+
+ if (is_func)
+ sub_pop(&db->cpp_subs);
+
+ str_pair_t *sp = name_at(&db->cpp_name, amt - 1);
+
+ for (size_t i = 0; i < amt; i++, sp++) {
+ str_t *s = NULL;
+
+ if (!is_func) {
+ s = &sp->strp_l;
+
+ if (str_length(s) == 0)
+ continue;
+
+ if (cv & 1)
+ (void) str_append(s, " const", 6);
+ if (cv & 2)
+ (void) str_append(s, " volatile", 9);
+ if (cv & 4)
+ (void) str_append(s, " restrict", 9);
+
+ continue;
+ }
+
+ s = &sp->strp_r;
+ size_t pos = str_length(s);
+
+ if (pos > 0 && s->str_s[pos - 1] == '&') {
+ pos--;
+ if (s->str_s[pos - 1] == '&')
+ pos--;
+ }
+
+ if (cv & 1) {
+ (void) str_insert(s, pos, " const", 6);
+ pos += 6;
+ }
+ if (cv & 2) {
+ (void) str_insert(s, pos, " volatile", 9);
+ pos += 9;
+ }
+ if (cv & 4) {
+ (void) str_insert(s, pos, " restrict", 9);
+ }
+ }
+
+ save_top(db, amt);
+ return (t1);
+}
+
+/*
+ * at <type> # alignof (a type)
+ * az <expression> # alignof (a expression)
+ */
+static const char *
+parse_alignof(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ const char *(*fn)(const char *, const char *, cpp_db_t *);
+
+ fn = (first[1] == 't') ? parse_type : parse_expression;
+
+ size_t n = nlen(db);
+ const char *t = fn(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, "alignof ({0})", NULL);
+ return (t);
+}
+
+/*
+ * st <type> # sizeof (a type)
+ * sz <expr> # sizeof (a expression)
+ */
+static const char *
+parse_sizeof(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ VERIFY3U(first[0], ==, 's');
+
+ const char *t = NULL;
+ size_t n = nlen(db);
+
+ switch (first[1]) {
+ case 't':
+ t = parse_type(first + 2, last, db);
+ break;
+ case 'z':
+ t = parse_expression(first + 2, last, db);
+ break;
+ default:
+ return (first);
+ }
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, "sizeof ({0})", NULL);
+ return (t);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter
+ * ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters
+ * ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter
+ * ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters
+ */
+/* END CSTYLED */
+static const char *
+parse_function_param(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3 || first[0] != 'f')
+ return (first);
+
+ const char *t1 = first + 2;
+ const char *t2 = NULL;
+ unsigned cv = 0;
+
+ if (first[1] == 'L') {
+ t2 = parse_number(t1, last, db->cpp_loc);
+ if (t2 == last || t2[0] != 'p')
+ return (first);
+ t1 = t2;
+ }
+
+ if (first[1] != 'p')
+ return (first);
+
+ t1 = parse_cv_qualifiers(t1, last, &cv);
+ t2 = parse_number(t1, last, db->cpp_loc);
+ if (t2 == last || t2[0] != '_')
+ return (first);
+
+ if (t2 - t1 > 0)
+ nadd_l(db, t1, (size_t)(t2 - t1));
+ else
+ nadd_l(db, "", 0);
+
+ nfmt(db, "fp{0}", NULL);
+ return (t2 + 1);
+}
+
+/*
+ * sZ <template-param> # size of a parameter pack
+ * sZ <function-param> # size of a function parameter pack
+ */
+static const char *
+parse_sizeof_param_pack_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 's');
+ VERIFY3U(first[1], ==, 'Z');
+
+ if (first[2] != 'T' && first[2] != 'f')
+ return (first);
+
+ const char *t = NULL;
+ size_t n = nlen(db);
+
+ if (first[2] == 'T')
+ t = parse_template_param(first + 2, last, db);
+ else
+ t = parse_function_param(first + 2, last, db);
+
+ if (t == first + 2)
+ return (first);
+
+ njoin(db, NAMT(db, n), ", ");
+ nfmt(db, "sizeof...({0})", NULL);
+ return (t);
+}
+
+/*
+ * te <expression> # typeid (expression)
+ * ti <type> # typeid (type)
+ */
+static const char *
+parse_typeid_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 't');
+ VERIFY(first[1] == 'e' || first[1] == 'i');
+
+ const char *t = NULL;
+ size_t n = nlen(db);
+
+ if (first[1] == 'e')
+ t = parse_expression(first + 2, last, db);
+ else
+ t = parse_type(first + 2, last, db);
+
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, "typeid ({0})", NULL);
+ return (t);
+}
+
+/*
+ * tr # throw
+ * tw <expression> # throw expression
+ */
+static const char *
+parse_throw_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 't');
+ VERIFY(first[1] == 'w' || first[1] == 'r');
+
+ if (first[1] == 'r') {
+ nadd_l(db, "throw", 0);
+ return (first + 2);
+ }
+
+ size_t n = nlen(db);
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) != 1)
+ return (first);
+
+ nfmt(db, "throw {0}", NULL);
+ return (t);
+}
+
+/* ds <expression> <expression> # expr.*expr */
+static const char *
+parse_dot_star_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'd');
+ VERIFY3U(first[1], ==, 's');
+
+ size_t n = nlen(db);
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2)
+ return (first);
+
+ const char *t2 = parse_expression(t, last, db);
+ if (t == t2 || NAMT(db, n) != 2)
+ return (first);
+
+ nfmt(db, "{1}.*{0}", NULL);
+ return (t2);
+}
+
+/* dt <expression> <unresolved-name> # expr.name */
+static const char *
+parse_dot_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'd');
+ VERIFY3U(first[1], ==, 't');
+
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first + 2)
+ return (first);
+
+ const char *t1 = parse_unresolved_name(t, last, db);
+ if (t1 == t)
+ return (first);
+
+ nfmt(db, "{1}.{0}", NULL);
+ return (t1);
+}
+
+/* cl <expression>+ E # call */
+static const char *
+parse_call_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 4)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'c');
+ VERIFY3U(first[1], ==, 'l');
+
+ const char *t = first + 2;
+ const char *t1 = NULL;
+ size_t n = nlen(db);
+
+ for (t = first + 2; t != last && t[0] != 'E'; t = t1) {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return (first);
+ }
+
+ size_t amt = NAMT(db, n);
+
+ if (t == last || amt == 0)
+ return (first);
+
+ njoin(db, amt - 1, ", ");
+ nfmt(db, "{1}({0})", NULL);
+
+ VERIFY3U(t[0], ==, 'E');
+ return (t + 1);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * cv <type> <expression> # conversion with one argument
+ * cv <type> _ <expression>* E # conversion with a different number of arguments
+ */
+/* END CSTYLED */
+static const char *
+parse_conv_expr(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'c');
+ VERIFY3U(first[1], ==, 'v');
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+ size_t n = nlen(db);
+
+ boolean_t try_to_parse_template_args =
+ db->cpp_try_to_parse_template_args;
+
+ db->cpp_try_to_parse_template_args = B_FALSE;
+ t = parse_type(first + 2, last, db);
+ db->cpp_try_to_parse_template_args = try_to_parse_template_args;
+
+ if (t == first + 2)
+ return (first);
+
+ if (t[0] != '_') {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return (first);
+
+ t = t1;
+ } else {
+ size_t n1 = nlen(db);
+
+ /* skip _ */
+ t++;
+ while (t[0] != 'E' && t != last) {
+ t1 = parse_expression(t, last, db);
+ if (t1 == t)
+ return (first);
+ t1 = t;
+ }
+
+ /* E */
+ t++;
+
+ njoin(db, NAMT(db, n1), ", ");
+ }
+
+ if (NAMT(db, n) < 2)
+ return (first);
+
+ nfmt(db, "({1})({0})", NULL);
+ return (t);
+}
+
+/* <simple-id> ::= <source-name> [ <template-args> ] */
+static const char *
+parse_simple_id(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = parse_source_name(first, last, db);
+ if (t == first)
+ return (t);
+
+ const char *t1 = parse_template_args(t, last, db);
+ if (t == t1)
+ return (t);
+
+ nfmt(db, "{1}{0}", NULL);
+ return (t1);
+}
+
+/*
+ * <unresolved-type> ::= <template-param>
+ * ::= <decltype>
+ * ::= <substitution>
+ */
+static const char *
+parse_unresolved_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ const char *t = first;
+ size_t n = nlen(db);
+
+ switch (first[0]) {
+ case 'T':
+ t = parse_template_param(first, last, db);
+ if (t == first || NAMT(db, n) != 1) {
+ for (size_t i = 0; i < NAMT(db, n); i++)
+ name_pop(&db->cpp_name, NULL);
+ return (first);
+ }
+ save_top(db, 1);
+ return (t);
+
+ case 'D':
+ t = parse_decltype(first, last, db);
+ if (t == first || NAMT(db, n) == 0)
+ return (first);
+ save_top(db, 1);
+ return (t);
+
+ case 'S':
+ t = parse_substitution(first, last, db);
+ if (t != first)
+ return (t);
+
+ if (last - first < 2 || first[1] != 't')
+ return (first);
+
+ t = parse_unqualified_name(first + 2, last, db);
+ if (t == first + 2 || NAMT(db, n) == 0)
+ return (first);
+
+ nfmt(db, "std::{0:L}", "{0:R}");
+ save_top(db, 1);
+ return (t);
+ }
+
+ return (first);
+}
+
+/* sp <expression> # pack expansion */
+static const char *
+parse_pack_expansion(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 's');
+ VERIFY3U(first[1], ==, 'p');
+
+ const char *t = parse_expression(first + 2, last, db);
+ if (t == first +2)
+ return (first);
+
+ return (t);
+}
+
+/*
+ * <unscoped-name> ::= <unqualified-name>
+ * ::= St <unqualified-name> # ::std::
+ * extension ::= StL<unqualified-name>
+ */
+static const char *
+parse_unscoped_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ const char *t = first;
+ const char *t1 = NULL;
+ boolean_t st = B_FALSE;
+
+ if (first[0] == 'S' && first[1] == 't') {
+ st = B_TRUE;
+ t = first + 2;
+
+ if (first + 3 != last && first[2] == 'L')
+ t++;
+ }
+
+ t1 = parse_unqualified_name(t, last, db);
+ if (t == t1)
+ return (first);
+
+ if (st)
+ nfmt(db, "std::{0}", NULL);
+
+ return (t1);
+}
+
+/*
+ * <unqualified-name> ::= <operator-name>
+ * ::= <ctor-dtor-name>
+ * ::= <source-name>
+ * ::= <unnamed-type-name>
+ */
+const char *
+parse_unqualified_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ switch (*first) {
+ case 'C':
+ case 'D':
+ return (parse_ctor_dtor_name(first, last, db));
+ case 'U':
+ return (parse_unnamed_type_name(first, last, db));
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return (parse_source_name(first, last, db));
+ default:
+ return (parse_operator_name(first, last, db));
+ }
+}
+
+/*
+ * <unnamed-type-name> ::= Ut [ <nonnegative number> ] _
+ * ::= <closure-type-name>
+ *
+ * <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _
+ *
+ * <lambda-sig> ::= <parameter type>+
+ * # Parameter types or "v" if the lambda has no parameters
+ */
+static const char *
+parse_unnamed_type_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2 || first[0] != 'U')
+ return (first);
+
+ if (first[1] != 't' && first[1] != 'l')
+ return (first);
+
+ const char *t1 = first + 2;
+ const char *t2 = NULL;
+
+ if (first[1] == 't') {
+ while (t1 != last && t1[0] != '_' &&
+ isdigit_l(t1[0], db->cpp_loc))
+ t1++;
+
+ if (t1[0] != '_')
+ return (first);
+
+ if (t1 == first + 2)
+ nadd_l(db, "", 0);
+ else
+ nadd_l(db, first + 2, (size_t)(t1 - first - 2));
+
+ nfmt(db, "'unnamed{0}'", NULL);
+ return (t1 + 1);
+ }
+
+ size_t n = nlen(db);
+
+ if (first[2] != 'v') {
+ do {
+ t2 = parse_type(t1, last, db);
+ if (t1 == t2)
+ return (first);
+ t1 = t2;
+ } while (t1 != last && t1[0] != 'E');
+
+ if (t1 == last || NAMT(db, n) < 1)
+ return (first);
+
+ if (NAMT(db, n) < 1)
+ return (first);
+ } else {
+ t1++;
+ if (t1[0] != 'E')
+ return (first);
+ }
+
+ njoin(db, NAMT(db, n), ", ");
+
+ /* E */
+ t1++;
+
+ t2 = t1;
+ while (t2 != last && t2[0] != '_') {
+ if (!isdigit_l(*t2++, db->cpp_loc))
+ return (first);
+ }
+
+ if (t2[0] != '_')
+ return (first);
+
+ if (t2 - t1 > 0)
+ nadd_l(db, t1, (size_t)(t2 - t1));
+ else
+ nadd_l(db, "", 0);
+
+ nfmt(db, "'lambda{0}'({1})", NULL);
+
+ /* _ */
+ return (t2 + 1);
+}
+
+static struct {
+ const char *alias;
+ const char *fullname;
+ const char *basename;
+} aliases[] = {
+ {
+ "std::string",
+ "std::basic_string<char, std::char_traits<char>, "
+ "std::allocator<char> >",
+ "basic_string"
+ },
+ {
+ "std::istream",
+ "std::basic_istream<char, std::char_traits<char> >",
+ "basic_istream"
+ },
+ {
+ "std::ostream",
+ "std::basic_ostream<char, std::char_traits<char> >",
+ "basic_ostream"
+ },
+ {
+ "std::iostream",
+ "std::basic_iostream<char, std::char_traits<char> >",
+ "basic_iostream"
+ }
+};
+
+static void
+basename(cpp_db_t *db)
+{
+ str_t *s = TOP_L(db);
+
+ for (size_t i = 0; i < ARRAY_SIZE(aliases); i++) {
+ if (str_length(s) != strlen(aliases[i].alias))
+ continue;
+ if (strncmp(aliases[i].alias, s->str_s, str_length(s)) != 0)
+ continue;
+
+ /* swap out alias for full name */
+ sysdem_ops_t *ops = s->str_ops;
+ str_fini(s);
+ str_init(s, ops);
+ str_set(s, aliases[i].fullname, 0);
+
+ nadd_l(db, aliases[i].basename, 0);
+ return;
+ }
+
+ const char *start = s->str_s;
+ const char *end = s->str_s + s->str_len;
+
+ /*
+ * if name ends with a template i.e. <.....> back up to start
+ * of outermost template
+ */
+ unsigned c = 0;
+
+ if (end[-1] == '>') {
+ for (; end > start; end--) {
+ switch (end[-1]) {
+ case '<':
+ if (--c == 0) {
+ end--;
+ goto out;
+ }
+ break;
+ case '>':
+ c++;
+ break;
+ }
+ }
+ }
+
+out:
+ VERIFY3P(end, >=, start);
+
+ if (end - start < 2) {
+ nadd_l(db, "", 0);
+ return;
+ }
+
+ for (start = end - 1; start > s->str_s; start--) {
+ if (start[0] == ':') {
+ start++;
+ break;
+ }
+ }
+
+ VERIFY3P(end, >=, start);
+
+ nadd_l(db, start, (size_t)(end - start));
+}
+
+/*
+ * <ctor-dtor-name> ::= C1 # complete object constructor
+ * ::= C2 # base object constructor
+ * ::= C3 # complete object allocating constructor
+ * extension ::= C5 # ?
+ * ::= D0 # deleting destructor
+ * ::= D1 # complete object destructor
+ * ::= D2 # base object destructor
+ * extension ::= D5 # ?
+ */
+static const char *
+parse_ctor_dtor_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2 || nempty(db) || str_length(TOP_L(db)) == 0)
+ return (first);
+
+ switch (first[0]) {
+ case 'C':
+ switch (first[1]) {
+ case '1':
+ case '2':
+ case '3':
+ case '5':
+ basename(db);
+ break;
+ default:
+ return (first);
+ }
+ break;
+ case 'D':
+ switch (first[1]) {
+ case '0':
+ case '1':
+ case '2':
+ case '5':
+ basename(db);
+ (void) str_insert(TOP_L(db), 0, "~", 1);
+ break;
+ default:
+ return (first);
+ }
+ break;
+ default:
+ return (first);
+ }
+
+ db->cpp_parsed_ctor_dtor_cv = B_TRUE;
+ return (first + 2);
+}
+
+static const char *
+parse_integer_literal(const char *first, const char *last, const char *fmt,
+ cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = parse_number(first, last, db->cpp_loc);
+ const char *start = first;
+
+ if (t == first || t == last || t[0] != 'E')
+ return (first);
+
+ if (first[0] == 'n')
+ start++;
+
+ nadd_l(db, start, (size_t)(t - start));
+ if (start != first)
+ nfmt(db, "-{0}", NULL);
+
+ nfmt(db, fmt, NULL);
+ return (t + 1);
+}
+
+static struct float_data_s {
+ const char *spec;
+ size_t mangled_size;
+ size_t max_demangled_size;
+ char type;
+} float_info[] = {
+ { "%af", 8, 24, 'f' }, /* float */
+ { "%a", 16, 32, 'd' }, /* double */
+ { "%LaL", 20, 40, 'e' } /* long double */
+};
+
+static const char *
+parse_floating_literal(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+ VERIFY(first[0] == 'f' || first[0] == 'd' || first[0] == 'e');
+
+ const struct float_data_s *fd = NULL;
+
+ for (size_t i = 0; i < ARRAY_SIZE(float_info); i++) {
+ if (float_info[i].type != first[0])
+ continue;
+
+ fd = &float_info[i];
+ break;
+ }
+
+ if (fd == NULL || (size_t)(last - first) < fd->mangled_size)
+ return (first);
+
+ union {
+ union {
+ float v;
+ char buf[sizeof (float)];
+ } f;
+ union {
+ double v;
+ char buf[sizeof (double)];
+ } d;
+ union {
+ long double v;
+ char buf[sizeof (long double)];
+ } ld;
+ } conv;
+
+ const char *t = NULL;
+ char *e = NULL;
+
+ switch (first[0]) {
+ case 'f':
+ e = conv.f.buf;
+ break;
+ case 'd':
+ e = conv.d.buf;
+ break;
+ case 'e':
+ e = conv.ld.buf;
+ break;
+ }
+ last = first + fd->mangled_size + 1;
+
+#if defined(_BIG_ENDIAN)
+ for (t = first + 1; t != last; t++, e++) {
+ if (!is_xdigit(t[0]))
+ return (first);
+
+ unsigned d1 = isdigit_l(t[0], db->cpp_loc) ?
+ t[0] - '0' : t[0] - 'a' + 10;
+ t++;
+ unsigned d0 = isdigit_l(t[0], db->cpp_loc) ?
+ t[0] - '0' : t[0] - 'a' + 10;
+
+ *e = (d1 << 4) + d0;
+ }
+#elif defined(_LITTLE_ENDIAN)
+ for (t = last - 1; t > first; t--, e++) {
+ if (!is_xdigit(t[0]))
+ return (first);
+
+ unsigned d0 = isdigit_l(t[0], db->cpp_loc) ?
+ t[0] - '0' : t[0] - 'a' + 10;
+ t--;
+ unsigned d1 = isdigit_l(t[0], db->cpp_loc) ?
+ t[0] - '0' : t[0] - 'a' + 10;
+
+ *e = (d1 << 4) + d0;
+ }
+ t = last;
+#else
+#error One of _BIG_ENDIAN or _LITTLE_ENDIAN must be defined
+#endif
+
+ if (t[0] != 'E')
+ return (first);
+
+ str_t num = { 0 };
+ str_init(&num, db->cpp_ops);
+
+ num.str_size = fd->max_demangled_size + 1;
+ num.str_s = zalloc(db->cpp_ops, num.str_size);
+ CK(num.str_s != NULL);
+
+ int n = 0;
+
+ switch (first[0]) {
+ case 'f':
+ n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
+ conv.f.v);
+ break;
+ case 'd':
+ n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
+ conv.d.v);
+ break;
+ case 'e':
+ n = snprintf(num.str_s, fd->max_demangled_size, fd->spec,
+ conv.ld.v);
+ }
+
+ if (n >= fd->max_demangled_size || n <= 0) {
+ str_fini(&num);
+ return (first);
+ }
+
+ num.str_len = n;
+ (void) name_add_str(&db->cpp_name, &num, NULL);
+
+ return (t + 1);
+}
+
+/*
+ * <expr-primary> ::= L <type> <value number> E # integer literal
+ * ::= L <type> <value float> E # floating literal
+ * ::= L <string type> E # string literal
+ * ::= L <nullptr type> E # nullptr literal (i.e., "LDnE")
+ *
+ * ::= L <type> <real-part float> _ <imag-part float> E
+ * # complex floating point
+ * # literal (C 2000)
+ *
+ * ::= L <mangled-name> E # external name
+ */
+static struct {
+ int c;
+ const char *fmt;
+} int_lits[] = {
+ { 'a', "(signed char){0}" },
+ { 'c', "(char){0}" },
+ { 'h', "(unsigned char){0}" },
+ { 'i', "{0}" },
+ { 'j', "{0}u" },
+ { 'l', "{0}l" },
+ { 'm', "{0}ul" },
+ { 'n', "(__int128){0}" },
+ { 'o', "(unsigned __int128){0}" },
+ { 's', "(short){0}" },
+ { 't', "(unsigned short){0}" },
+ { 'w', "(wchar_t){0}" },
+ { 'x', "{0}ll" },
+ { 'y', "{0}ull" }
+};
+
+static const char *
+parse_expr_primary(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 4 || first[0] != 'L')
+ return (first);
+
+ const char *t = NULL;
+
+ for (size_t i = 0; i < ARRAY_SIZE(int_lits); i++) {
+ if (first[1] == int_lits[i].c) {
+ t = parse_integer_literal(first + 2, last,
+ int_lits[i].fmt, db);
+ return ((t == first + 2) ? first : t);
+ }
+ }
+
+ switch (first[1]) {
+ case 'b':
+ if (first[3] != 'E')
+ return (first);
+
+ switch (first[2]) {
+ case '0':
+ nadd_l(db, "false", 5);
+ break;
+ case '1':
+ nadd_l(db, "true", 4);
+ break;
+ default:
+ return (first);
+ }
+ return (first + 4);
+ case 'd': /* double */
+ case 'e': /* long double */
+ case 'f': /* float */
+ t = parse_floating_literal(first + 1, last, db);
+ return ((t == first + 1) ? first : t);
+ case 'T':
+/* BEGIN CSTYLED */
+ /*
+ * Invalid mangled name per
+ * http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html
+ *
+ */
+/* END CSTYLED */
+ return (first);
+ case '_':
+ if (first[2] != 'Z')
+ return (first);
+
+ t = parse_encoding(first + 3, last, db);
+ if (t == first + 3 || t == last || t[0] != 'E')
+ return (first);
+
+ /* skip E */
+ return (t + 1);
+ default:
+ t = parse_type(first + 1, last, db);
+ if (t == first + 1 || t == last)
+ return (first);
+
+ if (t[0] == 'E')
+ return (t + 1);
+
+ const char *n;
+ for (n = t; n != last && isdigit_l(n[0], db->cpp_loc); n++)
+ ;
+ if (n == last || nempty(db) || n[0] != 'E')
+ return (first);
+ if (n == t)
+ return (t);
+
+ nadd_l(db, t, (size_t)(n - t));
+ nfmt(db, "({1}){0}", NULL);
+
+ return (n + 1);
+ }
+}
+
+/*
+ * <operator-name>
+ * ::= aa # &&
+ * ::= ad # & (unary)
+ * ::= an # &
+ * ::= aN # &=
+ * ::= aS # =
+ * ::= cl # ()
+ * ::= cm # ,
+ * ::= co # ~
+ * ::= cv <type> # (cast)
+ * ::= da # delete[]
+ * ::= de # * (unary)
+ * ::= dl # delete
+ * ::= dv # /
+ * ::= dV # /=
+ * ::= eo # ^
+ * ::= eO # ^=
+ * ::= eq # ==
+ * ::= ge # >=
+ * ::= gt # >
+ * ::= ix # []
+ * ::= le # <=
+ * ::= li <source-name> # operator ""
+ * ::= ls # <<
+ * ::= lS # <<=
+ * ::= lt # <
+ * ::= mi # -
+ * ::= mI # -=
+ * ::= ml # *
+ * ::= mL # *=
+ * ::= mm # -- (postfix in <expression> context)
+ * ::= na # new[]
+ * ::= ne # !=
+ * ::= ng # - (unary)
+ * ::= nt # !
+ * ::= nw # new
+ * ::= oo # ||
+ * ::= or # |
+ * ::= oR # |=
+ * ::= pm # ->*
+ * ::= pl # +
+ * ::= pL # +=
+ * ::= pp # ++ (postfix in <expression> context)
+ * ::= ps # + (unary)
+ * ::= pt # ->
+ * ::= qu # ?
+ * ::= rm # %
+ * ::= rM # %=
+ * ::= rs # >>
+ * ::= rS # >>=
+ * ::= v <digit> <source-name> # vendor extended operator
+ */
+static struct {
+ const char code[3];
+ const char *op;
+} op_tbl[] = {
+ { "aa", "operator&&" },
+ { "ad", "operator&" },
+ { "an", "operator&" },
+ { "aN", "operator&=" },
+ { "aS", "operator=" },
+ { "cl", "operator()" },
+ { "cm", "operator," },
+ { "co", "operator~" },
+ { "da", "operator delete[]" },
+ { "de", "operator*" },
+ { "dl", "operator delete" },
+ { "dv", "operator/" },
+ { "dV", "operator/=" },
+ { "eo", "operator^" },
+ { "eO", "operator^=" },
+ { "eq", "operator==" },
+ { "ge", "operator>=" },
+ { "gt", "operator>" },
+ { "ix", "operator[]" },
+ { "le", "operator<=" },
+ { "ls", "operator<<" },
+ { "lS", "operator<<=" },
+ { "lt", "operator<" },
+ { "mi", "operator-" },
+ { "mI", "operator-=" },
+ { "ml", "operator*" },
+ { "mL", "operator*=" },
+ { "mm", "operator--" },
+ { "na", "operator new[]" },
+ { "ne", "operator!=" },
+ { "ng", "operator-" },
+ { "nt", "operator!" },
+ { "nw", "operator new" },
+ { "oo", "operator||" },
+ { "or", "operator|" },
+ { "oR", "operator|=" },
+ { "pm", "operator->*" },
+ { "pl", "operator+" },
+ { "pL", "operator+=" },
+ { "pp", "operator++" },
+ { "ps", "operator+" },
+ { "pt", "operator->" },
+ { "qu", "operator?" },
+ { "rm", "operator%" },
+ { "rM", "operator%=" },
+ { "rs", "operator>>" },
+ { "rS", "operator>>=" }
+};
+
+static const char *
+parse_operator_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ for (size_t i = 0; i < ARRAY_SIZE(op_tbl); i++) {
+ if (strncmp(first, op_tbl[i].code, 2) != 0)
+ continue;
+
+ nadd_l(db, op_tbl[i].op, 0);
+ return (first + 2);
+ }
+
+ const char *t = NULL;
+
+ if (first[0] == 'l' && first[1] == 'i') {
+ t = parse_source_name(first + 2, last, db);
+ if (t == first + 2 || nempty(db))
+ return (first);
+
+ nfmt(db, "operator\"\" {0}", NULL);
+ return (t);
+ }
+
+ if (first[0] == 'v') {
+ if (!isdigit_l(first[1], db->cpp_loc))
+ return (first);
+
+ t = parse_source_name(first + 2, last, db);
+ if (t == first + 2)
+ return (first);
+
+ nfmt(db, "operator {0}", NULL);
+ return (t);
+ }
+
+ if (first[0] != 'c' && first[1] != 'v')
+ return (first);
+
+ boolean_t try_to_parse_template_args =
+ db->cpp_try_to_parse_template_args;
+
+ db->cpp_try_to_parse_template_args = B_FALSE;
+ t = parse_type(first + 2, last, db);
+ db->cpp_try_to_parse_template_args = try_to_parse_template_args;
+
+ if (t == first + 2 || nempty(db))
+ return (first);
+
+ nfmt(db, "operator {0}", NULL);
+ db->cpp_parsed_ctor_dtor_cv = B_TRUE;
+ return (t);
+}
+
+struct type_tbl_s {
+ int code;
+ const char *name;
+};
+
+static struct type_tbl_s type_tbl1[] = {
+ { 'a', "signed char" },
+ { 'b', "bool" },
+ { 'c', "char" },
+ { 'd', "double" },
+ { 'e', "long double" },
+ { 'f', "float" },
+ { 'g', "__float128" },
+ { 'h', "unsigned char" },
+ { 'i', "int" },
+ { 'j', "unsigned int" },
+ { 'l', "long" },
+ { 'm', "unsigned long" },
+ { 'n', "__int128" },
+ { 'o', "unsigned __int128" },
+ { 's', "short" },
+ { 't', "unsigned short" },
+ { 'v', "void" },
+ { 'w', "wchar_t" },
+ { 'x', "long long" },
+ { 'y', "unsigned long long" },
+ { 'z', "..." }
+};
+
+static struct type_tbl_s type_tbl2[] = {
+ { 'a', "auto" },
+ { 'c', "decltype(auto)" },
+ { 'd', "decimal64" },
+ { 'e', "decimal128" },
+ { 'f', "decimal32" },
+ { 'h', "decimal16" },
+ { 'i', "char32_t" },
+ { 'n', "std::nullptr_t" },
+ { 's', "char16_t" }
+};
+
+static const char *
+parse_builtin_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(type_tbl1); i++) {
+ if (first[0] == type_tbl1[i].code) {
+ nadd_l(db, type_tbl1[i].name, 0);
+ return (first + 1);
+ }
+ }
+
+ if (first[0] == 'D') {
+ if (first + 1 == last)
+ return (first);
+ for (i = 0; i < ARRAY_SIZE(type_tbl2); i++) {
+ if (first[1] == type_tbl2[i].code) {
+ nadd_l(db, type_tbl2[i].name, 0);
+ return (first + 2);
+ }
+ }
+ }
+
+ if (first[0] == 'u') {
+ const char *t = parse_source_name(first + 1, last, db);
+ if (t == first + 1)
+ return (first);
+ return (t);
+ }
+
+ return (first);
+}
+
+static const char *
+parse_base36(const char *first, const char *last, size_t *val, locale_t loc)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t;
+
+ for (t = first, *val = 0; t != last; t++) {
+ if (!isdigit_l(t[0], loc) && !isupper_l(t[0], loc))
+ return (t);
+
+ *val *= 36;
+
+ if (isdigit_l(t[0], loc))
+ *val += t[0] - '0';
+ else
+ *val += t[0] - 'A' + 10;
+ }
+ return (t);
+}
+
+static struct type_tbl_s sub_tbl[] = {
+ { 'a', "std::allocator" },
+ { 'b', "std::basic_string" },
+ { 's', "std::string" },
+ { 'i', "std::istream" },
+ { 'o', "std::ostream" },
+ { 'd', "std::iostream" }
+};
+
+static const char *
+parse_substitution(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last || last - first < 2)
+ return (first);
+
+ if (first[0] != 'S')
+ return (first);
+
+ for (size_t i = 0; i < ARRAY_SIZE(sub_tbl); i++) {
+ if (first[1] == sub_tbl[i].code) {
+ nadd_l(db, sub_tbl[i].name, 0);
+ return (first + 2);
+ }
+ }
+
+ const char *t = first + 1;
+ size_t n = 0;
+
+ if (t[0] != '_') {
+ t = parse_base36(first + 1, last, &n, db->cpp_loc);
+ if (t == first + 1 || t[0] != '_')
+ return (first);
+
+ /*
+ * S_ == substitution 0,
+ * S0_ == substituion 1,
+ * ...
+ */
+ n++;
+ }
+
+ if (n >= sub_len(&db->cpp_subs))
+ return (first);
+
+ sub(db, n);
+
+ /* skip _ */
+ VERIFY3U(t[0], ==, '_');
+
+ return (t + 1);
+}
+
+static const char *
+parse_source_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ const char *t = NULL;
+ size_t n = 0;
+
+ for (t = first; t != last && isdigit_l(t[0], db->cpp_loc); t++) {
+ /* make sure we don't overflow */
+ size_t nn = n * 10;
+ if (nn < n)
+ return (first);
+
+ nn += t[0] - '0';
+ if (nn < n)
+ return (first);
+
+ n = nn;
+ }
+
+ if (n == 0 || t == last || t + n > last ||
+ (uintptr_t)t + n < (uintptr_t)t)
+ return (first);
+
+ if (strncmp(t, "_GLOBAL__N", 10) == 0)
+ nadd_l(db, "(anonymous namespace)", 0);
+ else
+ nadd_l(db, t, n);
+
+ return (t + n);
+}
+
+/*
+ * extension:
+ * <vector-type> ::= Dv <positive dimension number> _
+ * <extended element type>
+ * ::= Dv [<dimension expression>] _ <element type>
+ * <extended element type> ::= <element type>
+ * ::= p # AltiVec vector pixel
+ */
+static const char *
+parse_vector_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'D');
+ VERIFY3U(first[1], ==, 'v');
+
+ const char *t = first + 2;
+ const char *t1 = NULL;
+
+ if (isdigit_l(first[2], db->cpp_loc) && first[2] != '0') {
+ t1 = parse_number(t, last, db->cpp_loc);
+ if (t1 == last || t1 + 1 == last || t1[0] != '_')
+ return (first);
+
+ nadd_l(db, t, (size_t)(t1 - t));
+
+ /* skip _ */
+ t = t1 + 1;
+
+ if (t[0] != 'p') {
+ t1 = parse_type(t, last, db);
+ if (t1 == t)
+ return (first);
+
+ nfmt(db, "{0} vector[{1}]", NULL);
+ return (t1);
+ }
+ nfmt(db, "{0} pixel vector[{1}]", NULL);
+ return (t1);
+ }
+
+ if (first[2] != '_') {
+ t1 = parse_expression(first + 2, last, db);
+ if (first == last || t1 == first + 2 || t1[0] != '_')
+ return (first);
+
+ /* skip _ */
+ t = t1 + 1;
+ } else {
+ nadd_l(db, "", 0);
+ }
+
+ t1 = parse_type(t, last, db);
+ if (t == t1)
+ return (first);
+
+ nfmt(db, "{1:L} vector[{0}]", "{1:R}");
+ return (t1);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x)
+ * ::= DT <expression> E # decltype of an expression (C++0x)
+ */
+/* END CSTYLED */
+static const char *
+parse_decltype(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 4)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'D');
+
+ if (first[1] != 't' && first[1] != 'T')
+ return (first);
+
+ size_t n = nlen(db);
+ const char *t = parse_expression(first + 2, last, db);
+ if (NAMT(db, n) != 1 || t == first + 2 || t == last || t[0] != 'E')
+ return (first);
+
+ nfmt(db, "decltype({0})", NULL);
+
+ /* skip E */
+ return (t + 1);
+}
+
+/*
+ * <array-type> ::= A <positive dimension number> _ <element type>
+ * ::= A [<dimension expression>] _ <element type>
+ */
+static const char *
+parse_array_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+ VERIFY3U(first[0], ==, 'A');
+
+ if (last - first < 3)
+ return (first);
+
+ const char *t = first + 1;
+ const char *t1 = NULL;
+ size_t n = nlen(db);
+
+ if (t[0] != '_') {
+ if (isdigit_l(t[0], db->cpp_loc) && t[0] != '0') {
+ t1 = parse_number(t, last, db->cpp_loc);
+ if (t1 == last)
+ return (first);
+
+ nadd_l(db, t, (size_t)(t1 - t));
+ } else {
+ t1 = parse_expression(t, last, db);
+ if (t1 == last || t == t1)
+ return (first);
+ }
+
+ if (t1[0] != '_')
+ return (first);
+
+ t = t1;
+ } else {
+ nadd_l(db, "", 0);
+ }
+
+ VERIFY3U(t[0], ==, '_');
+
+ t1 = parse_type(t + 1, last, db);
+ if (t1 == t + 1 || NAMT(db, n) != 2)
+ return (first);
+
+ /*
+ * if we have " [xxx]" already, want new result to be
+ * " [yyy][xxx]"
+ */
+ str_t *r = &name_top(&db->cpp_name)->strp_r;
+ if (r->str_len > 1 && r->str_s[0] == ' ' && r->str_s[1] == '[')
+ (void) str_erase(r, 0, 1);
+
+ nfmt(db, "{0:L}", " [{1}]{0:R}");
+ return (t1);
+}
+
+/* <pointer-to-member-type> ::= M <class type> <member type> */
+static const char *
+parse_pointer_to_member_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 3)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'M');
+
+ const char *t1 = first + 1;
+ const char *t2 = NULL;
+ size_t n = nlen(db);
+
+ t2 = parse_type(t1, last, db);
+ if (t1 == t2)
+ return (first);
+
+ t1 = t2;
+ t2 = parse_type(t1, last, db);
+ if (t1 == t2)
+ return (first);
+
+ if (NAMT(db, n) != 2)
+ return (first);
+
+ str_pair_t *func = name_top(&db->cpp_name);
+
+ if (str_length(&func->strp_r) > 0 && func->strp_r.str_s[0] == '(')
+ nfmt(db, "{0:L}({1}::*", "){0:R}");
+ else
+ nfmt(db, "{0:L} {1}::*", "{0:R}");
+
+ return (t2);
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <unresolved-name>
+ * extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name>
+ * ::= [gs] <base-unresolved-name> # x or (with "gs") ::x
+ * ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name>
+ * # A::x, N::y, A<T>::z; "gs" means leading "::"
+ * ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x
+ * extension ::= sr <unresolved-type> <template-args> <base-unresolved-name>
+ * # T::N::x /decltype(p)::N::x
+ * (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name>
+ */
+/* END CSTYLED */
+static const char *
+parse_unresolved_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ const char *t = first;
+ const char *t2 = NULL;
+ boolean_t global = B_FALSE;
+ size_t n;
+
+ if (t[0] == 'g' && t[1] == 's') {
+ global = B_TRUE;
+ t += 2;
+ }
+ if (t == last)
+ return (first);
+
+ t2 = parse_base_unresolved_name(t, last, db);
+ if (t != t2) {
+ if (global) {
+ if (nempty(db))
+ return (first);
+
+ (void) str_insert(TOP_L(db), 0, "::", 2);
+ }
+ return (t2);
+ }
+
+ if (t[0] != 's' || t[1] != 'r' || last - t < 2)
+ return (first);
+
+ n = nlen(db);
+ if (t[2] == 'N') {
+ t += 3;
+ t2 = parse_unresolved_type(t, last, db);
+ if (t2 == t || t2 == last)
+ return (first);
+ t = t2;
+
+ t2 = parse_template_args(t, last, db);
+ if (t2 != t) {
+ if (NAMT(db, n) < 2 || t2 == last)
+ return (first);
+
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ t = t2;
+ }
+
+ VERIFY3U(NAMT(db, n), ==, 1);
+
+ while (t[0] != 'E') {
+ size_t nn = nlen(db);
+ t2 = parse_unresolved_qualifier_level(t, last, db);
+ if (t == t2 || t == last || NAMT(db, nn) != 1)
+ return (first);
+
+ t = t2;
+ }
+
+ /* skip E */
+ t++;
+
+ t2 = parse_base_unresolved_name(t, last, db);
+ if (t == t2 || NAMT(db, n) < 2)
+ return (first);
+
+ njoin(db, NAMT(db, n), "::");
+ return (t2);
+ }
+
+ t += 2;
+
+ t2 = parse_unresolved_type(t, last, db);
+ if (t != t2) {
+ t = t2;
+ t2 = parse_template_args(t, last, db);
+ if (t2 != t)
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ t = t2;
+
+ t2 = parse_base_unresolved_name(t, last, db);
+ if (t == t2 || nlen(db) < 2)
+ return (first);
+
+ nfmt(db, "{1:L}::{0}", "{1:R}");
+ return (t2);
+ }
+
+ t2 = parse_unresolved_qualifier_level(t, last, db);
+ if (t2 == t || t2 == last)
+ return (first);
+
+ t = t2;
+ if (global && nlen(db) > 0)
+ nfmt(db, "::{0:L}", "{0:R}");
+
+ while (t[0] != 'E') {
+ t2 = parse_unresolved_qualifier_level(t, last, db);
+ if (t == t2 || t == last || nlen(db) < 2)
+ return (first);
+
+ t = t2;
+ }
+
+ /* skip E */
+ t++;
+
+ t2 = parse_base_unresolved_name(t, last, db);
+ if (t == t2 || nlen(db) < 2)
+ return (first);
+
+ njoin(db, NAMT(db, n), "::");
+ return (t2);
+}
+
+/* <unresolved-qualifier-level> ::= <simple-id> */
+static const char *
+parse_unresolved_qualifier_level(const char *first, const char *last,
+ cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+ return (parse_simple_id(first, last, db));
+}
+
+/* BEGIN CSTYLED */
+/*
+ * <base-unresolved-name> ::= <simple-id> # unresolved name
+ * extension ::= <operator-name> # unresolved operator-function-id
+ * extension ::= <operator-name> <template-args> # unresolved operator template-id
+ * ::= on <operator-name> # unresolved operator-function-id
+ * ::= on <operator-name> <template-args> # unresolved operator template-id
+ * ::= dn <destructor-name> # destructor or pseudo-destructor;
+ * # e.g. ~X or ~X<N-1>
+ */
+/* END CSTYLED */
+static const char *
+parse_base_unresolved_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ const char *t = NULL;
+ const char *t1 = NULL;
+
+ if ((first[0] != 'o' && first[0] != 'd') || first[1] != 'n') {
+ t = parse_simple_id(first, last, db);
+ if (t != first)
+ return (t);
+
+ t = parse_operator_name(first, last, db);
+ if (t == first)
+ return (first);
+
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t) {
+ if (nlen(db) < 2)
+ return (first);
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ }
+
+ return (t1);
+ }
+
+ if (first[0] == 'd') {
+ t = parse_destructor_name(first + 2, last, db);
+ return ((t != first + 2) ? t : first);
+ }
+
+ t = parse_operator_name(first + 2, last, db);
+ if (t == first + 2)
+ return (first);
+
+ t1 = parse_template_args(t, last, db);
+ if (t1 != t)
+ nfmt(db, "{1:L}{0}", "{1:R}");
+ return (t1);
+}
+
+/*
+ * <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f())
+ * ::= <simple-id> # e.g., ~A<2*N>
+ */
+static const char *
+parse_destructor_name(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ const char *t = parse_unresolved_type(first, last, db);
+
+ if (t == first)
+ t = parse_simple_id(first, last, db);
+
+ if (t == first)
+ return (first);
+
+ nfmt(db, "~{0:L}", "{0:R}");
+ return (t);
+}
+
+/*
+ * <ref-qualifier> ::= R # & ref-qualifier
+ * <ref-qualifier> ::= O # && ref-qualifier
+ *
+ * <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E
+ */
+static const char *
+parse_function_type(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2)
+ return (first);
+
+ VERIFY3U(first[0], ==, 'F');
+
+ const char *t = first + 1;
+
+ /* extern "C" */
+ if (t[0] == 'Y')
+ t++;
+
+ const char *t1 = parse_type(t, last, db);
+ if (t1 == t)
+ return (first);
+
+ size_t n = nlen(db);
+ int ref_qual = 0;
+
+ t = t1;
+
+ while (t != last && t[0] != 'E') {
+ if (t[0] == 'v') {
+ t++;
+ continue;
+ }
+
+ if (t[0] == 'R' && t + 1 != last && t[1] == 'E') {
+ ref_qual = 1;
+ t++;
+ continue;
+ }
+
+ if (t[0] == 'O' && t + 1 != last && t[1] == 'E') {
+ ref_qual = 2;
+ t++;
+ continue;
+ }
+
+
+ t1 = parse_type(t, last, db);
+ if (t1 == t || t == last)
+ return (first);
+
+ t = t1;
+ }
+
+ if (t == last)
+ return (first);
+
+ njoin(db, NAMT(db, n), ", ");
+ nfmt(db, "({0})", NULL);
+
+ switch (ref_qual) {
+ case 1:
+ nfmt(db, "{0} &", NULL);
+ break;
+ case 2:
+ nfmt(db, "{0} &&", NULL);
+ break;
+ }
+
+ nfmt(db, "{1:L} ", "{0}{1:R}");
+
+ /* skip E */
+ return (t + 1);
+}
+
+/*
+ * <template-param> ::= T_ # first template parameter
+ * ::= T <parameter-2 non-negative number> _
+ */
+static const char *
+parse_template_param(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2 || first[0] != 'T')
+ return (first);
+
+ const char *t = first + 1;
+ size_t idx = 0;
+
+ while (t != last && t[0] != '_') {
+ if (!isdigit_l(t[0], db->cpp_loc))
+ return (first);
+
+ idx *= 10;
+ idx += t[0] - '0';
+ t++;
+ }
+
+ if (t == last)
+ return (first);
+
+ VERIFY3U(t[0], ==, '_');
+
+ /*
+ * T_ -> idx 0
+ * T0 -> idx 1
+ * T1 -> idx 2
+ * ...
+ */
+ if (first[1] != '_')
+ idx++;
+
+ /* skip _ */
+ t++;
+
+ if (tempty(db))
+ return (first);
+
+ if (idx >= ttlen(db)) {
+ nadd_l(db, first, (size_t)(t - first));
+ db->cpp_fix_forward_references = B_TRUE;
+ return (t);
+ }
+
+ tsub(db, idx);
+ return (t);
+}
+
+/*
+ * <template-args> ::= I <template-arg>* E
+ * extension, the abi says <template-arg>+
+ */
+static const char *
+parse_template_args(const char *first, const char *last, cpp_db_t *db)
+{
+ VERIFY3P(first, <=, last);
+
+ if (last - first < 2 || first[0] != 'I')
+ return (first);
+
+ if (db->cpp_tag_templates)
+ sub_clear(templ_top(&db->cpp_templ));
+
+ const char *t = first + 1;
+ size_t n = nlen(db);
+
+ while (t[0] != 'E') {
+ if (db->cpp_tag_templates)
+ tpush(db);
+
+ size_t n1 = nlen(db);
+ const char *t1 = parse_template_arg(t, last, db);
+
+ if (db->cpp_tag_templates)
+ tpop(db);
+
+ if (t1 == t || t == last)
+ return (first);
+
+ if (db->cpp_tag_templates)
+ tsave(db, NAMT(db, n1));
+
+ t = t1;
+ }
+
+ /*
+ * ugly, but if the last thing pushed was an empty string,
+ * get rid of it so we dont get "<..., >"
+ */
+ if (NAMT(db, n) > 1 &&
+ str_pair_len(name_top(&db->cpp_name)) == 0)
+ name_pop(&db->cpp_name, NULL);
+
+ njoin(db, NAMT(db, n), ", ");
+
+ VERIFY3U(nlen(db), >, 0);
+
+ /* make sure we don't bitshift ourselves into oblivion */
+ str_t *top = TOP_L(db);
+ if (str_length(top) > 0 &&
+ top->str_s[top->str_len - 1] == '>')
+ nfmt(db, "<{0} >", NULL);
+ else
+ nfmt(db, "<{0}>", NULL);
+
+ /* skip E */
+ return (t + 1);
+}
+
+/*
+ * <discriminator> := _ <non-negative number> # when number < 10
+ * := __ <non-negative number> _ # when number >= 10
+ * extension := decimal-digit+ # at the end of string
+ */
+static const char *
+parse_discriminator(const char *first, const char *last, locale_t loc)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = NULL;
+
+ if (first == last)
+ return (first);
+
+ if (isdigit_l(first[0], loc)) {
+ for (t = first; t != last && isdigit_l(t[0], loc); t++)
+ ;
+
+ /* not at the end of the string */
+ if (t != last)
+ return (first);
+
+ return (t);
+ } else if (first[0] != '_' || first + 1 == last) {
+ return (first);
+ }
+
+ t = first + 1;
+ if (isdigit_l(t[0], loc))
+ return (t + 1);
+
+ if (t[0] != '_' || t + 1 == last)
+ return (first);
+
+ for (t++; t != last && isdigit_l(t[0], loc); t++)
+ ;
+ if (t == last || t[0] != '_')
+ return (first);
+
+ return (t);
+}
+
+/* <CV-qualifiers> ::= [r] [V] [K] */
+const char *
+parse_cv_qualifiers(const char *first, const char *last, unsigned *cv)
+{
+ VERIFY3P(first, <=, last);
+
+ if (first == last)
+ return (first);
+
+ *cv = 0;
+ if (first[0] == 'r') {
+ *cv |= CPP_QUAL_RESTRICT;
+ first++;
+ }
+ if (first != last && first[0] == 'V') {
+ *cv |= CPP_QUAL_VOLATILE;
+ first++;
+ }
+ if (first != last && first[0] == 'K') {
+ *cv |= CPP_QUAL_CONST;
+ first++;
+ }
+
+ return (first);
+}
+
+/*
+ * <number> ::= [n] <non-negative decimal integer>
+ */
+static const char *
+parse_number(const char *first, const char *last, locale_t loc)
+{
+ VERIFY3P(first, <=, last);
+
+ const char *t = first;
+
+ if (first == last || (first[0] != 'n' && !isdigit_l(first[0], loc)))
+ return (first);
+
+ if (t[0] == 'n')
+ t++;
+
+ if (t[0] == '0')
+ return (t + 1);
+
+ while (isdigit_l(t[0], loc))
+ t++;
+
+ return (t);
+}
+
+/*
+ * Like isxdigit(3C), except we can only accept lower case letters as
+ * that's only what is allowed when [de]mangling floating point constants into
+ * their hex representation.
+ */
+static inline boolean_t
+is_xdigit(int c)
+{
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'))
+ return (B_TRUE);
+ return (B_FALSE);
+}
+
+static boolean_t
+nempty(cpp_db_t *db)
+{
+ return (name_empty(&db->cpp_name));
+}
+
+static size_t
+nlen(cpp_db_t *db)
+{
+ return (name_len(&db->cpp_name));
+}
+
+static void
+nadd_l(cpp_db_t *db, const char *s, size_t len)
+{
+ CK(name_add(&db->cpp_name, s, len, NULL, 0));
+}
+
+static void
+njoin(cpp_db_t *db, size_t amt, const char *sep)
+{
+ name_t *nm = &db->cpp_name;
+
+ CK(name_join(nm, amt, sep));
+}
+
+static void
+nfmt(cpp_db_t *db, const char *fmt_l, const char *fmt_r)
+{
+ CK(name_fmt(&db->cpp_name, fmt_l, fmt_r));
+}
+
+static void
+save_top(cpp_db_t *db, size_t amt)
+{
+ CK(sub_save(&db->cpp_subs, &db->cpp_name, amt));
+}
+
+static void
+sub(cpp_db_t *db, size_t n)
+{
+ CK(sub_substitute(&db->cpp_subs, n, &db->cpp_name));
+}
+
+static boolean_t
+tempty(const cpp_db_t *db)
+{
+ return (templ_empty(&db->cpp_templ) ? B_TRUE : B_FALSE);
+}
+
+static size_t
+ttlen(const cpp_db_t *db)
+{
+ return (templ_top_len(&db->cpp_templ));
+}
+
+static void
+tsub(cpp_db_t *db, size_t n)
+{
+ CK(templ_sub(&db->cpp_templ, n, &db->cpp_name));
+}
+
+static void
+tpush(cpp_db_t *db)
+{
+ CK(templ_push(&db->cpp_templ));
+}
+
+static void
+tpop(cpp_db_t *db)
+{
+ templ_pop(&db->cpp_templ);
+}
+
+static void
+tsave(cpp_db_t *db, size_t amt)
+{
+ CK(templ_save(&db->cpp_name, amt, &db->cpp_templ));
+}
+
+static boolean_t
+db_init(cpp_db_t *db, sysdem_ops_t *ops)
+{
+ (void) memset(db, 0, sizeof (*db));
+ db->cpp_ops = ops;
+ name_init(&db->cpp_name, ops);
+ sub_init(&db->cpp_subs, ops);
+ templ_init(&db->cpp_templ, ops);
+ db->cpp_tag_templates = B_TRUE;
+ db->cpp_try_to_parse_template_args = B_TRUE;
+ tpush(db);
+ db->cpp_loc = newlocale(LC_CTYPE_MASK, "C", 0);
+ return ((db->cpp_loc != NULL) ? B_TRUE : B_FALSE);
+}
+
+static void
+db_fini(cpp_db_t *db)
+{
+ name_fini(&db->cpp_name);
+ sub_fini(&db->cpp_subs);
+ templ_fini(&db->cpp_templ);
+ freelocale(db->cpp_loc);
+ (void) memset(db, 0, sizeof (*db));
+}
+
+static void
+print_sp(const str_pair_t *sp, FILE *out)
+{
+ (void) fprintf(out, "{%.*s#%.*s}",
+ (int)sp->strp_l.str_len, sp->strp_l.str_s,
+ (int)sp->strp_r.str_len, sp->strp_r.str_s);
+}
+
+static void
+print_name(const name_t *n, FILE *out)
+{
+ const str_pair_t *sp = name_top((name_t *)n);
+ size_t i;
+
+ (void) fprintf(out, "Name:\n");
+
+ if (name_len(n) == 0)
+ return;
+
+ for (i = 0; i < n->nm_len; i++, sp--) {
+ (void) fprintf(out, " [%02zu] ", i);
+ print_sp(sp, out);
+ (void) fputc('\n', out);
+ }
+
+ (void) fputc('\n', out);
+}
+
+/* Print a base-36 number (for substitutions) */
+static char *
+base36(char *buf, size_t val)
+{
+ char tmp[16] = { 0 };
+ char *p = tmp;
+
+ if (val == 0) {
+ buf[0] = '0';
+ buf[1] = '\0';
+ return (buf);
+ }
+
+ while (val > 0) {
+ size_t r = val % 36;
+
+ if (r < 10)
+ *p++ = r + '0';
+ else
+ *p++ = r - 10 + 'A';
+
+ val /= 36;
+ }
+
+ char *q = buf;
+ while (--p >= tmp)
+ *q++ = *p;
+
+ return (buf);
+}
+
+static void
+print_sub(const sub_t *sub, FILE *out)
+{
+ const name_t *n = sub->sub_items;
+
+ (void) fprintf(out, "Substitutions:\n");
+
+ if (sub->sub_len == 0)
+ return;
+
+ for (size_t i = 0; i < sub->sub_len; i++, n++) {
+ (void) printf(" ");
+ if (i == 0) {
+ (void) fprintf(out, "%-4s", "S_");
+ } else {
+ char buf[16] = { 0 };
+ char buf2[16] = { 0 };
+
+ (void) snprintf(buf, sizeof (buf), "S%s_",
+ base36(buf2, i));
+ (void) fprintf(out, "%-4s", buf);
+ }
+ (void) fprintf(out, " = ");
+
+ (void) fputc('{', out);
+ for (size_t j = 0; j < n->nm_len; j++) {
+ if (j > 0)
+ (void) fputc(' ', out);
+ print_sp(&n->nm_items[j], out);
+ }
+ (void) fputc('}', out);
+
+ (void) fputc('\n', out);
+ }
+ (void) fputc('\n', out);
+}
+
+static void
+print_templ(const templ_t *tpl, FILE *out)
+{
+
+ (void) fprintf(out, "Template\n");
+
+ const sub_t *s = templ_top((templ_t *)tpl);
+
+ for (size_t i = 0; i < s->sub_len; i++) {
+ char buf[16] = { 0 };
+
+ if (i == 0)
+ (void) snprintf(buf, sizeof (buf), "%s", "T_");
+ else
+ (void) snprintf(buf, sizeof (buf), "T%zu_", i - 1);
+
+ (void) fprintf(out, " %-4s = ", buf);
+
+ (void) fputc('{', out);
+
+ const name_t *n = &s->sub_items[i];
+ for (size_t j = 0; j < n->nm_len; j++) {
+ const str_pair_t *sp = &n->nm_items[j];
+
+ if (j > 0)
+ (void) fputc(' ', out);
+
+ (void) fprintf(out, "{%.*s#%.*s}",
+ (int)sp->strp_l.str_len, sp->strp_l.str_s,
+ (int)sp->strp_r.str_len, sp->strp_r.str_s);
+ }
+ (void) fprintf(out, "}\n");
+ }
+ (void) fprintf(out, "\n");
+}
+
+static void
+dump(cpp_db_t *db, FILE *out)
+{
+ print_name(&db->cpp_name, out);
+ print_sub(&db->cpp_subs, out);
+ print_templ(&db->cpp_templ, out);
+}
diff --git a/usr/src/lib/libdemangle/common/cxx.h b/usr/src/lib/libdemangle/common/cxx.h
new file mode 100644
index 0000000000..eab265d7e1
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/cxx.h
@@ -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 2017 Jason King
+ */
+
+#ifndef _CPP_H
+#define _CPP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include "demangle-sys.h"
+#include "str.h"
+
+typedef struct name_s {
+ str_pair_t *nm_items;
+ sysdem_ops_t *nm_ops;
+ size_t nm_len;
+ size_t nm_size;
+} name_t;
+
+extern size_t cpp_name_max_depth;
+
+void name_clear(name_t *);
+void name_init(name_t *, sysdem_ops_t *);
+void name_fini(name_t *);
+size_t name_len(const name_t *);
+boolean_t name_empty(const name_t *);
+boolean_t name_add(name_t *, const char *, size_t, const char *, size_t);
+boolean_t name_add_str(name_t *, str_t *, str_t *);
+boolean_t name_join(name_t *, size_t, const char *);
+boolean_t name_fmt(name_t *, const char *, const char *);
+str_pair_t *name_at(const name_t *, size_t);
+str_pair_t *name_top(name_t *);
+void name_pop(name_t *, str_pair_t *);
+
+typedef struct sub_s {
+ name_t *sub_items;
+ sysdem_ops_t *sub_ops;
+ size_t sub_len;
+ size_t sub_size;
+} sub_t;
+
+void sub_clear(sub_t *);
+void sub_init(sub_t *, sysdem_ops_t *);
+void sub_fini(sub_t *);
+void sub_pop(sub_t *);
+boolean_t sub_save(sub_t *, const name_t *, size_t);
+boolean_t sub_substitute(const sub_t *, size_t, name_t *);
+boolean_t sub_empty(const sub_t *);
+size_t sub_len(const sub_t *);
+
+typedef struct templ_s {
+ sub_t *tpl_items;
+ sysdem_ops_t *tpl_ops;
+ size_t tpl_len;
+ size_t tpl_size;
+} templ_t;
+
+void templ_init(templ_t *, sysdem_ops_t *);
+void templ_fini(templ_t *);
+boolean_t templ_empty(const templ_t *);
+size_t templ_top_len(const templ_t *);
+boolean_t templ_sub(const templ_t *, size_t, name_t *);
+boolean_t templ_save(const name_t *, size_t, templ_t *);
+
+boolean_t templ_push(templ_t *);
+void templ_pop(templ_t *);
+sub_t *templ_top(templ_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CPP_H */
diff --git a/usr/src/lib/libdemangle/common/cxx_util.c b/usr/src/lib/libdemangle/common/cxx_util.c
new file mode 100644
index 0000000000..91abb504d3
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/cxx_util.c
@@ -0,0 +1,600 @@
+/*
+ * 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 2017 Jason King
+ */
+
+#include <sys/debug.h>
+#include <sys/sysmacros.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "demangle_int.h"
+#include "cxx.h"
+
+#define CHUNK_SIZE (8U)
+
+/*
+ * A name_t is essentially a stack of str_pair_t's. Generally, the parsing
+ * code will push (via name_add() or the like) portions of the demangled
+ * name into a name_t, and periodically combine them via name_join().
+ *
+ * As such it should be noted that since items are added at the end of
+ * name_t->nm_items, the numbering of name_at() starts at the end
+ * of name_t->nm_items, i.e. name_at(n, 0) == &n->nm_items[n->nm_len - 1].
+ *
+ * It should also be noted that for name_t's, adding is a move operation in
+ * that it takes ownership of the passed in string/str_t/etc
+ */
+
+void
+name_init(name_t *n, sysdem_ops_t *ops)
+{
+ (void) memset(n, 0, sizeof (*n));
+ n->nm_ops = (ops != NULL) ? ops : sysdem_ops_default;
+}
+
+void
+name_fini(name_t *n)
+{
+ if (n == NULL)
+ return;
+
+ name_clear(n);
+ xfree(n->nm_ops, n->nm_items, n->nm_size);
+ n->nm_items = NULL;
+ n->nm_size = 0;
+}
+
+size_t
+name_len(const name_t *n)
+{
+ return (n->nm_len);
+}
+
+boolean_t
+name_empty(const name_t *n)
+{
+ return (name_len(n) == 0 ? B_TRUE : B_FALSE);
+}
+
+void
+name_clear(name_t *n)
+{
+ if (n == NULL)
+ return;
+
+ for (size_t i = 0; i < n->nm_len; i++) {
+ str_pair_t *sp = &n->nm_items[i];
+ sysdem_ops_t *ops = sp->strp_l.str_ops;
+
+ str_pair_fini(sp);
+ (void) str_pair_init(sp, ops);
+ }
+
+ n->nm_len = 0;
+}
+
+static boolean_t
+name_reserve(name_t *n, size_t amt)
+{
+ size_t newlen = n->nm_len + amt;
+
+ if (newlen == cpp_name_max_depth) {
+ errno = ENAMETOOLONG;
+ return (B_FALSE);
+ }
+
+ if (newlen < n->nm_size)
+ return (B_TRUE);
+
+ size_t newsize = roundup(newlen, CHUNK_SIZE);
+ if (newsize > cpp_name_max_depth)
+ newsize = cpp_name_max_depth;
+
+ void *temp = xrealloc(n->nm_ops, n->nm_items,
+ n->nm_size * sizeof (str_pair_t), newsize * sizeof (str_pair_t));
+
+ if (temp == NULL)
+ return (B_FALSE);
+
+ n->nm_items = temp;
+ n->nm_size = newsize;
+ return (B_TRUE);
+}
+
+boolean_t
+name_add(name_t *n, const char *l, size_t l_len, const char *r, size_t r_len)
+{
+ str_t sl = { 0 };
+ str_t sr = { 0 };
+
+ str_init(&sl, n->nm_ops);
+ str_init(&sr, n->nm_ops);
+ str_set(&sl, l, l_len);
+ str_set(&sr, r, r_len);
+ return (name_add_str(n, &sl, &sr));
+}
+
+boolean_t
+name_add_str(name_t *n, str_t *l, str_t *r)
+{
+ str_pair_t sp;
+
+ (void) str_pair_init(&sp, n->nm_ops);
+
+ if (!name_reserve(n, 1))
+ return (B_FALSE);
+
+ if (l != NULL) {
+ sp.strp_l = *l;
+ (void) memset(l, 0, sizeof (*l));
+ }
+
+ if (r != NULL) {
+ sp.strp_r = *r;
+ (void) memset(r, 0, sizeof (*r));
+ }
+
+ n->nm_items[n->nm_len++] = sp;
+
+ return (B_TRUE);
+}
+
+str_pair_t *
+name_at(const name_t *n, size_t idx)
+{
+ VERIFY(!name_empty(n));
+ VERIFY3U(idx, <, n->nm_len);
+ return (&n->nm_items[n->nm_len - idx - 1]);
+}
+
+str_pair_t *
+name_top(name_t *n)
+{
+ return (name_at(n, 0));
+}
+
+void
+name_pop(name_t *n, str_pair_t *sp)
+{
+ if (n->nm_len == 0)
+ return;
+
+ str_pair_t *top = name_top(n);
+
+ if (sp != NULL) {
+ *sp = *top;
+ (void) memset(top, 0, sizeof (*top));
+ } else {
+ str_pair_fini(top);
+ }
+
+ n->nm_len--;
+}
+
+boolean_t
+name_join(name_t *n, size_t amt, const char *sep)
+{
+ str_pair_t *sp = NULL;
+ str_t res = { 0 };
+ size_t seplen = strlen(sep);
+
+ VERIFY3U(amt, <=, n->nm_len);
+
+ /*
+ * A join of 0 elements places an empty string on the stack. This
+ * simplifies code that wants to do things like:
+ * name_join(...); name_fmt(.., "({0})", ...)
+ */
+ if (amt == 0) {
+ (void) name_add(n, "", 0, "", 0);
+ return (B_TRUE);
+ }
+
+ /* A join of 1 element just implies merging the top str_pair_t */
+ if (amt == 1) {
+ VERIFY3U(name_len(n), >, 0);
+ return (str_pair_merge(name_top(n)));
+ }
+
+ (void) str_init(&res, n->nm_ops);
+
+ sp = name_at(n, amt - 1);
+ for (size_t i = 0; i < amt; i++) {
+ if (i > 0) {
+ if (!str_append(&res, sep, seplen))
+ goto error;
+ }
+
+ if (!str_append_str(&res, &sp->strp_l))
+ goto error;
+ if (!str_append_str(&res, &sp->strp_r))
+ goto error;
+
+ sp++;
+ }
+
+ for (size_t i = 0; i < amt; i++)
+ name_pop(n, NULL);
+
+ /* since we've removed at least 1 entry, this should always succeed */
+ VERIFY(name_add_str(n, &res, NULL));
+ return (B_TRUE);
+
+error:
+ str_fini(&res);
+ return (B_FALSE);
+}
+
+static boolean_t
+name_fmt_s(name_t *n, str_t *s, const char *fmt, long *maxp)
+{
+ const char *p;
+ long max = -1;
+
+ if (fmt == NULL)
+ return (B_TRUE);
+
+ for (p = fmt; *p != '\0'; p++) {
+ if (*p != '{') {
+ (void) str_append_c(s, *p);
+ continue;
+ }
+
+ errno = 0;
+ char *q = NULL;
+ long val = strtol(p + 1, &q, 10);
+
+ VERIFY(val != 0 || errno == 0);
+ VERIFY3U(val, <, n->nm_len);
+
+ str_pair_t *sp = name_at(n, val);
+
+ if (val > max)
+ max = val;
+
+ switch (q[0]) {
+ case '}':
+ if (!str_append_str(s, &sp->strp_l))
+ return (B_FALSE);
+ if (!str_append_str(s, &sp->strp_r))
+ return (B_FALSE);
+ p = q;
+ continue;
+ case ':':
+ switch (q[1]) {
+ case 'L':
+ if (!str_append_str(s, &sp->strp_l))
+ return (B_FALSE);
+ break;
+ case 'R':
+ if (!str_append_str(s, &sp->strp_r))
+ return (B_FALSE);
+ break;
+ }
+
+ p = q + 2;
+ VERIFY(*p == '}');
+ break;
+ }
+ }
+
+ if (*maxp < max)
+ *maxp = max;
+
+ return (B_TRUE);
+}
+
+/*
+ * Replace a number of elements in the name stack with a formatted string
+ * for format is a plain string with optional {nnn} or {nnn:L|R} substitutions
+ * where nnn is the stack position of an element and it's contents (both
+ * left and right pieces) are inserted. Optionally, only the left or
+ * right piece can specified using :L|R e.g. {2:L}{3}{2:R} would insert
+ * the left piece of element 2, all of element 3, then the right piece of
+ * element 2.
+ *
+ * Once complete, all elements up to the deepest one references are popped
+ * off the stack, and the resulting formatted string is pushed into n.
+ *
+ * This could be done as a sequence of push & pops, but this makes the
+ * intended output far clearer to see.
+ */
+boolean_t
+name_fmt(name_t *n, const char *fmt_l, const char *fmt_r)
+{
+ str_pair_t res;
+ long max = -1;
+
+ (void) str_pair_init(&res, n->nm_ops);
+
+ if (!name_reserve(n, 1))
+ return (B_FALSE);
+
+ if (!name_fmt_s(n, &res.strp_l, fmt_l, &max))
+ goto error;
+ if (!name_fmt_s(n, &res.strp_r, fmt_r, &max))
+ goto error;
+
+ if (max >= 0) {
+ for (size_t i = 0; i <= max; i++)
+ name_pop(n, NULL);
+ }
+
+ n->nm_items[n->nm_len++] = res;
+ return (B_TRUE);
+
+error:
+ str_pair_fini(&res);
+ return (B_FALSE);
+}
+
+/*
+ * The substitution list is a list of name_t's that get added as the
+ * demangled name is parsed. Adding a name_t to the substitution list
+ * is a copy operation, and likewise inserting a substitution into a name_t
+ * is also a copy operation.
+ */
+void
+sub_init(sub_t *sub, sysdem_ops_t *ops)
+{
+ (void) memset(sub, 0, sizeof (*sub));
+ sub->sub_ops = (ops != NULL) ? ops : sysdem_ops_default;
+}
+
+void
+sub_fini(sub_t *sub)
+{
+ if (sub == NULL)
+ return;
+
+ sub_clear(sub);
+ xfree(sub->sub_ops, sub->sub_items, sub->sub_size);
+ sub->sub_items = NULL;
+ sub->sub_size = 0;
+}
+
+void
+sub_clear(sub_t *sub)
+{
+ if (sub == NULL)
+ return;
+
+ for (size_t i = 0; i < sub->sub_len; i++)
+ name_fini(&sub->sub_items[i]);
+
+ sub->sub_len = 0;
+}
+
+boolean_t
+sub_empty(const sub_t *sub)
+{
+ return ((sub->sub_len == 0) ? B_TRUE : B_FALSE);
+}
+
+size_t
+sub_len(const sub_t *sub)
+{
+ return (sub->sub_len);
+}
+
+static boolean_t
+sub_reserve(sub_t *sub, size_t amt)
+{
+ if (sub->sub_len + amt < sub->sub_size)
+ return (B_TRUE);
+
+ size_t newsize = roundup(sub->sub_size + amt, CHUNK_SIZE);
+ void *temp = xrealloc(sub->sub_ops, sub->sub_items,
+ sub->sub_size * sizeof (name_t), newsize * sizeof (name_t));
+
+ if (temp == NULL)
+ return (B_FALSE);
+
+ sub->sub_items = temp;
+ sub->sub_size = newsize;
+
+ return (B_TRUE);
+}
+
+/* save the element of n (up to depth elements deep) as a substitution */
+boolean_t
+sub_save(sub_t *sub, const name_t *n, size_t depth)
+{
+ if (depth == 0)
+ return (B_TRUE);
+
+ if (!sub_reserve(sub, 1))
+ return (B_FALSE);
+
+ name_t *dest = &sub->sub_items[sub->sub_len++];
+ name_init(dest, sub->sub_ops);
+
+ if (!name_reserve(dest, depth)) {
+ name_fini(dest);
+ sub->sub_len--;
+ return (B_FALSE);
+ }
+
+ const str_pair_t *src_sp = name_at(n, depth - 1);
+
+ for (size_t i = 0; i < depth; i++, src_sp++) {
+ str_pair_t copy = { 0 };
+ (void) str_pair_init(&copy, n->nm_ops);
+ if (!str_pair_copy(src_sp, &copy)) {
+ str_pair_fini(&copy);
+ name_fini(dest);
+ return (B_FALSE);
+ }
+
+ VERIFY(name_add_str(dest, &copy.strp_l, &copy.strp_r));
+ }
+
+ return (B_TRUE);
+}
+
+/* push substitution idx onto n */
+boolean_t
+sub_substitute(const sub_t *sub, size_t idx, name_t *n)
+{
+ VERIFY3U(idx, <, sub->sub_len);
+
+ const name_t *src = &sub->sub_items[idx];
+ const str_pair_t *sp = src->nm_items;
+ size_t save = name_len(n);
+
+ for (size_t i = 0; i < src->nm_len; i++, sp++) {
+ str_pair_t copy = { 0 };
+
+ if (!str_pair_copy(sp, &copy))
+ goto fail;
+
+ if (!name_add_str(n, &copy.strp_l, &copy.strp_r))
+ goto fail;
+ }
+
+ return (B_TRUE);
+
+fail:
+ for (size_t i = 0; i < name_len(n) - save; i++)
+ name_pop(n, NULL);
+ return (B_FALSE);
+}
+
+void
+sub_pop(sub_t *sub)
+{
+ name_t *top = &sub->sub_items[--sub->sub_len];
+ name_fini(top);
+}
+
+/*
+ * Templates can use substitutions for it's arguments (using T instead of
+ * S). Since templates can nest however, each nesting requires a new
+ * set of substitutions. As such a new, empty list of template substitutions
+ * is pushed onto cpp_templ each time templates are nested, and popped at
+ * the end of the current template argument list.
+ */
+static boolean_t
+templ_reserve(templ_t *tpl, size_t n)
+{
+ if (tpl->tpl_len + n < tpl->tpl_size)
+ return (B_TRUE);
+
+ size_t newsize = tpl->tpl_size + CHUNK_SIZE;
+ void *temp = xrealloc(tpl->tpl_ops, tpl->tpl_items,
+ tpl->tpl_size * sizeof (sub_t), newsize * sizeof (sub_t));
+
+ if (temp == NULL)
+ return (B_FALSE);
+
+ tpl->tpl_items = temp;
+ tpl->tpl_size = newsize;
+ return (B_TRUE);
+}
+
+void
+templ_init(templ_t *tpl, sysdem_ops_t *ops)
+{
+ (void) memset(tpl, 0, sizeof (*tpl));
+ tpl->tpl_ops = ops;
+}
+
+void
+templ_fini(templ_t *tpl)
+{
+ if (tpl == NULL)
+ return;
+
+ for (size_t i = 0; i < tpl->tpl_len; i++)
+ sub_fini(&tpl->tpl_items[i]);
+
+ xfree(tpl->tpl_ops, tpl->tpl_items, tpl->tpl_size * sizeof (sub_t));
+ sysdem_ops_t *ops = tpl->tpl_ops;
+ (void) memset(tpl, 0, sizeof (*tpl));
+ tpl->tpl_ops = ops;
+}
+
+boolean_t
+templ_push(templ_t *tpl)
+{
+ if (!templ_reserve(tpl, 1))
+ return (B_FALSE);
+
+ sub_t *sub = &tpl->tpl_items[tpl->tpl_len++];
+ sub_init(sub, tpl->tpl_ops);
+ return (B_TRUE);
+}
+
+void
+templ_pop(templ_t *tpl)
+{
+ VERIFY(!templ_empty(tpl));
+
+ sub_t *sub = &tpl->tpl_items[--tpl->tpl_len];
+ sub_fini(sub);
+}
+
+sub_t *
+templ_top(templ_t *tpl)
+{
+ if (tpl->tpl_len == 0)
+ return (NULL);
+ return (&tpl->tpl_items[tpl->tpl_len - 1]);
+}
+
+boolean_t
+templ_empty(const templ_t *tpl)
+{
+ return ((tpl->tpl_len == 0) ? B_TRUE : B_FALSE);
+}
+
+size_t
+templ_top_len(const templ_t *tpl)
+{
+ const sub_t *sub = templ_top((templ_t *)tpl);
+
+ return (sub->sub_len);
+}
+
+boolean_t
+templ_sub(const templ_t *tpl, size_t idx, name_t *n)
+{
+ const sub_t *sub = templ_top((templ_t *)tpl);
+
+ return (sub_substitute(sub, idx, n));
+}
+
+boolean_t
+templ_save(const name_t *n, size_t amt, templ_t *tpl)
+{
+ VERIFY3U(tpl->tpl_len, >, 0);
+
+ sub_t *s = templ_top(tpl);
+ boolean_t res = B_TRUE;
+
+ /* a bit of a hack -- want an 'empty' entry when saving 0 params */
+ if (amt == 0) {
+ name_t name = { 0 };
+
+ name_init(&name, tpl->tpl_ops);
+ res &= name_add(&name, "", 0, "", 0);
+ if (res)
+ res &= sub_save(s, &name, 1);
+ name_fini(&name);
+ } else {
+ res &= sub_save(s, n, amt);
+ }
+
+ return (res);
+}
diff --git a/usr/src/lib/libdemangle/common/demangle-sys.h b/usr/src/lib/libdemangle/common/demangle-sys.h
new file mode 100644
index 0000000000..02636c9521
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/demangle-sys.h
@@ -0,0 +1,41 @@
+/*
+ * 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 2017 Jason King
+ */
+
+#ifndef _DEMANGLE_SYS_H
+#define _DEMANGLE_SYS_H
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum sysdem_lang_e {
+ SYSDEM_LANG_AUTO,
+ SYSDEM_LANG_CPP
+} sysdem_lang_t;
+
+typedef struct sysdem_alloc_s {
+ void *(*alloc)(size_t);
+ void (*free)(void *, size_t);
+} sysdem_ops_t;
+
+char *sysdemangle(const char *, sysdem_lang_t, sysdem_ops_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DEMANGLE_SYS_H */
diff --git a/usr/src/lib/libdemangle/common/demangle.c b/usr/src/lib/libdemangle/common/demangle.c
new file mode 100644
index 0000000000..e827fd8cec
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/demangle.c
@@ -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 2018 Jason King
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/debug.h>
+#include "demangle-sys.h"
+#include "demangle_int.h"
+
+#define DEMANGLE_DEBUG "DEMANGLE_DEBUG"
+
+static pthread_once_t debug_once = PTHREAD_ONCE_INIT;
+volatile boolean_t demangle_debug;
+
+static sysdem_lang_t
+detect_lang(const char *str)
+{
+ size_t n = strlen(str);
+
+ if (n < 3 || str[0] != '_')
+ return (SYSDEM_LANG_AUTO);
+
+ switch (str[1]) {
+ case 'Z':
+ return (SYSDEM_LANG_CPP);
+
+ case '_':
+ break;
+
+ default:
+ return (SYSDEM_LANG_AUTO);
+ }
+
+ /* why they use ___Z sometimes is puzzling... *sigh* */
+ if (str[2] == '_' && str[3] == 'Z')
+ return (SYSDEM_LANG_CPP);
+
+ return (SYSDEM_LANG_AUTO);
+}
+
+static void
+check_debug(void)
+{
+ if (getenv(DEMANGLE_DEBUG))
+ demangle_debug = B_TRUE;
+}
+
+char *
+sysdemangle(const char *str, sysdem_lang_t lang, sysdem_ops_t *ops)
+{
+ VERIFY0(pthread_once(&debug_once, check_debug));
+
+ if (ops == NULL)
+ ops = sysdem_ops_default;
+
+ if (lang == SYSDEM_LANG_AUTO) {
+ lang = detect_lang(str);
+ if (lang == SYSDEM_LANG_AUTO) {
+ errno = ENOTSUP;
+ return (NULL);
+ }
+ }
+
+ switch (lang) {
+ case SYSDEM_LANG_AUTO:
+ break;
+ case SYSDEM_LANG_CPP:
+ return (cpp_demangle(str, ops));
+ }
+
+ errno = ENOTSUP;
+ return (NULL);
+}
diff --git a/usr/src/lib/libdemangle/common/demangle_int.h b/usr/src/lib/libdemangle/common/demangle_int.h
new file mode 100644
index 0000000000..9abb2cc295
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/demangle_int.h
@@ -0,0 +1,39 @@
+/*
+ * 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 2017 Jason King
+ */
+#ifndef _DEMANGLE_INT_H
+#define _DEMANGLE_INT_H
+
+#include <stdio.h>
+#include "demangle-sys.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern sysdem_ops_t *sysdem_ops_default;
+
+char *cpp_demangle(const char *, sysdem_ops_t *);
+
+void *zalloc(sysdem_ops_t *, size_t);
+void *xrealloc(sysdem_ops_t *, void *, size_t, size_t);
+void xfree(sysdem_ops_t *, void *, size_t);
+
+extern volatile boolean_t demangle_debug;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DEMANGLE_INT_H */
diff --git a/usr/src/lib/libdemangle/common/llib-ldemangle-sys b/usr/src/lib/libdemangle/common/llib-ldemangle-sys
new file mode 100644
index 0000000000..0f4c4bc081
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/llib-ldemangle-sys
@@ -0,0 +1,29 @@
+/*
+ * 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
+ */
+/* LINTLIBRARY */
+/* PROTOLIB1 */
+
+/*
+ * Copyright 2018 Jason King.
+ */
+
+#include "demangle-sys.h"
diff --git a/usr/src/lib/libdemangle/common/mapfile-vers b/usr/src/lib/libdemangle/common/mapfile-vers
new file mode 100644
index 0000000000..48c11ef0d7
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/mapfile-vers
@@ -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 2017 Jason King
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+$mapfile_version 2
+
+SYMBOL_VERSION ILLUMOSprivate {
+ global:
+ sysdemangle;
+ local:
+ *;
+};
diff --git a/usr/src/lib/libdemangle/common/str.c b/usr/src/lib/libdemangle/common/str.c
new file mode 100644
index 0000000000..014ce8a737
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/str.c
@@ -0,0 +1,313 @@
+/*
+ * 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 2017 Jason King
+ */
+#include <sys/debug.h>
+#include <sys/sysmacros.h>
+#include <string.h>
+#include "str.h"
+#include "demangle_int.h"
+
+#define STR_CHUNK_SZ (64U)
+
+/* are we storing a reference vs. a dynamically allocated copy? */
+#define IS_REF(s) ((s)->str_s != NULL && (s)->str_size == 0)
+
+/*
+ * Dynamically resizeable strings, with lazy allocation when initialized
+ * with a constant string value
+ *
+ * NOTE: these are not necessairly 0-terminated
+ *
+ * Additionally, these can store references instead of copies of strings
+ * (as indicated by the IS_REF() macro. However mutation may cause a
+ * string to convert from a refence to a dynamically allocated copy.
+ */
+
+void
+str_init(str_t *restrict s, sysdem_ops_t *restrict ops)
+{
+ (void) memset(s, 0, sizeof (*s));
+ s->str_ops = (ops != NULL) ? ops : sysdem_ops_default;
+}
+
+void
+str_fini(str_t *s)
+{
+ if (s == NULL)
+ return;
+ if (!IS_REF(s))
+ xfree(s->str_ops, s->str_s, s->str_size);
+ (void) memset(s, 0, sizeof (*s));
+}
+
+size_t
+str_length(const str_t *s)
+{
+ return (s->str_len);
+}
+
+/*
+ * store as a reference instead of a copy
+ * if len == 0, means store entire copy of 0 terminated string
+ */
+void
+str_set(str_t *s, const char *cstr, size_t len)
+{
+ sysdem_ops_t *ops = s->str_ops;
+
+ str_fini(s);
+ s->str_ops = ops;
+ s->str_s = (char *)cstr;
+ s->str_len = (len == 0 && cstr != NULL) ? strlen(cstr) : len;
+}
+
+boolean_t
+str_copy(const str_t *src, str_t *dest)
+{
+ str_fini(dest);
+ str_init(dest, src->str_ops);
+
+ if (src->str_len == 0)
+ return (B_TRUE);
+
+ size_t len = roundup(src->str_len, STR_CHUNK_SZ);
+ dest->str_s = zalloc(src->str_ops, len);
+ if (dest->str_s == NULL)
+ return (B_FALSE);
+
+ (void) memcpy(dest->str_s, src->str_s, src->str_len);
+ dest->str_len = src->str_len;
+ dest->str_size = len;
+
+ return (B_TRUE);
+}
+
+/*
+ * ensure s has at least amt bytes free, resizing if necessary
+ */
+static boolean_t
+str_reserve(str_t *s, size_t amt)
+{
+ size_t newlen = s->str_len + amt;
+
+ /* overflow check */
+ if (newlen < s->str_len || newlen < amt)
+ return (B_FALSE);
+
+ if ((amt > 0) && (s->str_len + amt <= s->str_size))
+ return (B_TRUE);
+
+ size_t newsize = roundup(newlen, STR_CHUNK_SZ);
+ void *temp;
+
+ if (IS_REF(s)) {
+ temp = zalloc(s->str_ops, newsize);
+ if (temp == NULL)
+ return (B_FALSE);
+
+ (void) memcpy(temp, s->str_s, s->str_len);
+ } else {
+ temp = xrealloc(s->str_ops, s->str_s, s->str_size, newsize);
+ if (temp == NULL)
+ return (B_FALSE);
+ }
+
+ s->str_s = temp;
+ s->str_size = newsize;
+
+ return (B_TRUE);
+}
+
+/* append to s, cstrlen == 0 means entire length of string */
+boolean_t
+str_append(str_t *s, const char *cstr, size_t cstrlen)
+{
+ if (cstr != NULL && cstrlen == 0)
+ cstrlen = strlen(cstr);
+
+ const str_t src = {
+ .str_s = (char *)cstr,
+ .str_len = cstrlen,
+ .str_ops = s->str_ops
+ };
+
+ return (str_append_str(s, &src));
+}
+
+boolean_t
+str_append_str(str_t *dest, const str_t *src)
+{
+ /* empty string is a noop */
+ if (src->str_s == NULL || src->str_len == 0)
+ return (B_TRUE);
+
+ /* if src is a reference, we can just copy that */
+ if (dest->str_s == NULL && IS_REF(src)) {
+ *dest = *src;
+ return (B_TRUE);
+ }
+
+ if (!str_reserve(dest, src->str_len))
+ return (B_FALSE);
+
+ (void) memcpy(dest->str_s + dest->str_len, src->str_s, src->str_len);
+ dest->str_len += src->str_len;
+ return (B_TRUE);
+}
+
+boolean_t
+str_append_c(str_t *s, char c)
+{
+ if (!str_reserve(s, 1))
+ return (B_FALSE);
+
+ s->str_s[s->str_len++] = c;
+ return (B_TRUE);
+}
+
+boolean_t
+str_insert(str_t *s, size_t idx, const char *cstr, size_t cstrlen)
+{
+ if (cstr == NULL)
+ return (B_TRUE);
+
+ if (cstrlen == 0)
+ cstrlen = strlen(cstr);
+
+ str_t src = {
+ .str_s = (char *)cstr,
+ .str_len = cstrlen,
+ .str_ops = s->str_ops,
+ .str_size = 0
+ };
+
+ return (str_insert_str(s, idx, &src));
+}
+
+boolean_t
+str_insert_str(str_t *dest, size_t idx, const str_t *src)
+{
+ ASSERT3U(idx, <=, dest->str_len);
+
+ if (idx == dest->str_len)
+ return (str_append_str(dest, src));
+
+ if (idx == 0 && dest->str_s == NULL && IS_REF(src)) {
+ sysdem_ops_t *ops = dest->str_ops;
+ *dest = *src;
+ dest->str_ops = ops;
+ return (B_TRUE);
+ }
+
+ if (!str_reserve(dest, src->str_len))
+ return (B_FALSE);
+
+ /*
+ * Shift the contents of dest over at the insertion point. Since
+ * src and dest ranges will overlap, and unlike some programmers,
+ * *I* can read man pages - memmove() is the appropriate function
+ * to this.
+ */
+ (void) memmove(dest->str_s + idx + src->str_len, dest->str_s + idx,
+ dest->str_len - idx);
+
+ /*
+ * However the content to insert does not overlap with the destination
+ * so memcpy() is fine here.
+ */
+ (void) memcpy(dest->str_s + idx, src->str_s, src->str_len);
+ dest->str_len += src->str_len;
+
+ return (B_TRUE);
+}
+
+boolean_t
+str_erase(str_t *s, size_t pos, size_t len)
+{
+ ASSERT3U(pos, <, s->str_len);
+ ASSERT3U(pos + len, <=, s->str_len);
+
+ if (IS_REF(s)) {
+ if (!str_reserve(s, 0))
+ return (B_FALSE);
+ }
+
+ (void) memmove(s->str_s + pos, s->str_s + pos + len, s->str_len - len);
+ s->str_len -= len;
+ return (B_TRUE);
+}
+
+str_pair_t *
+str_pair_init(str_pair_t *sp, sysdem_ops_t *ops)
+{
+ (void) memset(sp, 0, sizeof (*sp));
+ str_init(&sp->strp_l, ops);
+ str_init(&sp->strp_r, ops);
+ return (sp);
+}
+
+void
+str_pair_fini(str_pair_t *sp)
+{
+ str_fini(&sp->strp_l);
+ str_fini(&sp->strp_r);
+}
+
+/* combine left and right parts and put result into left part */
+boolean_t
+str_pair_merge(str_pair_t *sp)
+{
+ /* if right side is empty, don't need to do anything */
+ if (str_length(&sp->strp_r) == 0)
+ return (B_TRUE);
+
+ /* if left side is empty, just move right to left */
+ if (str_length(&sp->strp_l) == 0) {
+ str_fini(&sp->strp_l);
+ sp->strp_l = sp->strp_r;
+ sp->strp_r.str_s = NULL;
+ sp->strp_r.str_len = sp->strp_r.str_size = 0;
+ return (B_TRUE);
+ }
+
+ if (!str_append_str(&sp->strp_l, &sp->strp_r))
+ return (B_FALSE);
+
+ str_fini(&sp->strp_r);
+ str_init(&sp->strp_r, sp->strp_l.str_ops);
+ return (B_TRUE);
+}
+
+boolean_t
+str_pair_copy(const str_pair_t *src, str_pair_t *dest)
+{
+ boolean_t ok = B_TRUE;
+
+ ok &= str_copy(&src->strp_l, &dest->strp_l);
+ ok &= str_copy(&src->strp_r, &dest->strp_r);
+
+ if (!ok) {
+ str_fini(&dest->strp_l);
+ str_fini(&dest->strp_r);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+size_t
+str_pair_len(const str_pair_t *sp)
+{
+ return (str_length(&sp->strp_l) + str_length(&sp->strp_r));
+}
diff --git a/usr/src/lib/libdemangle/common/str.h b/usr/src/lib/libdemangle/common/str.h
new file mode 100644
index 0000000000..1d6ee9294c
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/str.h
@@ -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 2017 Jason King
+ */
+
+#ifndef _STR_H
+#define _STR_H
+
+#include <sys/types.h>
+#include "demangle-sys.h"
+#include "demangle_int.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sysdem_alloc_s;
+
+typedef struct str_s {
+ char *str_s;
+ sysdem_ops_t *str_ops;
+ size_t str_len;
+ size_t str_size;
+} str_t;
+
+typedef struct str_pair_s {
+ str_t strp_l;
+ str_t strp_r;
+} str_pair_t;
+
+void str_init(str_t *restrict, sysdem_ops_t *);
+void str_fini(str_t *);
+size_t str_length(const str_t *);
+boolean_t str_copy(const str_t *, str_t *);
+void str_set(str_t *, const char *, size_t);
+boolean_t str_append(str_t *, const char *, size_t);
+boolean_t str_append_str(str_t *, const str_t *);
+boolean_t str_append_c(str_t *, char);
+boolean_t str_insert(str_t *, size_t, const char *, size_t);
+boolean_t str_insert_str(str_t *, size_t, const str_t *);
+boolean_t str_erase(str_t *, size_t, size_t);
+
+str_pair_t *str_pair_init(str_pair_t *, sysdem_ops_t *);
+void str_pair_fini(str_pair_t *);
+boolean_t str_pair_merge(str_pair_t *);
+boolean_t str_pair_copy(const str_pair_t *, str_pair_t *);
+size_t str_pair_len(const str_pair_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _STR_H */
diff --git a/usr/src/lib/libdemangle/common/util.c b/usr/src/lib/libdemangle/common/util.c
new file mode 100644
index 0000000000..9ffb72c79b
--- /dev/null
+++ b/usr/src/lib/libdemangle/common/util.c
@@ -0,0 +1,85 @@
+/*
+ * 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 2017 Jason King
+ */
+
+#include <sys/debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include "demangle-sys.h"
+#include "demangle_int.h"
+
+void *
+zalloc(sysdem_ops_t *ops, size_t len)
+{
+ void *p = ops->alloc(len);
+
+ if (p != NULL)
+ (void) memset(p, 0, len);
+
+#ifdef DEBUG
+ /*
+ * In normal operation, we should never exhaust memory. Either
+ * something's wrong, or the system is so hosed that aborting
+ * shouldn't hurt anything, and it gives us a more useful stack
+ * trace.
+ */
+ if (p == NULL)
+ abort();
+#endif
+
+ return (p);
+}
+
+void
+xfree(sysdem_ops_t *ops, void *p, size_t len)
+{
+ if (p == NULL || len == 0)
+ return;
+
+ ops->free(p, len);
+}
+
+void *
+xrealloc(sysdem_ops_t *ops, void *p, size_t oldsz, size_t newsz)
+{
+ if (newsz == oldsz)
+ return (p);
+
+ VERIFY3U(newsz, >, oldsz);
+
+ void *temp = zalloc(ops, newsz);
+
+ if (temp == NULL)
+ return (NULL);
+
+ if (oldsz > 0) {
+ (void) memcpy(temp, p, oldsz);
+ xfree(ops, p, oldsz);
+ }
+
+ return (temp);
+}
+
+/*ARGSUSED*/
+static void
+def_free(void *p, size_t len)
+{
+ free(p);
+}
+
+static sysdem_ops_t i_sysdem_ops_default = {
+ .alloc = malloc,
+ .free = def_free
+};
+sysdem_ops_t *sysdem_ops_default = &i_sysdem_ops_default;
diff --git a/usr/src/lib/libdemangle/i386/Makefile b/usr/src/lib/libdemangle/i386/Makefile
new file mode 100644
index 0000000000..a91bb3aa20
--- /dev/null
+++ b/usr/src/lib/libdemangle/i386/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libdemangle/sparc/Makefile b/usr/src/lib/libdemangle/sparc/Makefile
new file mode 100644
index 0000000000..a91bb3aa20
--- /dev/null
+++ b/usr/src/lib/libdemangle/sparc/Makefile
@@ -0,0 +1,30 @@
+#
+# 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 2005 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
diff --git a/usr/src/lib/libdemangle/sparcv9/Makefile b/usr/src/lib/libdemangle/sparcv9/Makefile
new file mode 100644
index 0000000000..86609bbf96
--- /dev/null
+++ b/usr/src/lib/libdemangle/sparcv9/Makefile
@@ -0,0 +1,29 @@
+#
+# 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 2007 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
diff --git a/usr/src/lib/libdtrace/sparc/Makefile b/usr/src/lib/libdtrace/sparc/Makefile
index 6065e14810..4c4ad06f89 100644
--- a/usr/src/lib/libdtrace/sparc/Makefile
+++ b/usr/src/lib/libdtrace/sparc/Makefile
@@ -23,7 +23,7 @@
# Use is subject to license terms.
#
-ASFLAGS += -D_ASM -K PIC -P
+ASFLAGS += -D_ASM $(AS_BIGPICFLAGS) -P
include ../Makefile.com
diff --git a/usr/src/lib/libdtrace/sparcv9/Makefile b/usr/src/lib/libdtrace/sparcv9/Makefile
index a45f315e94..d22653cb31 100644
--- a/usr/src/lib/libdtrace/sparcv9/Makefile
+++ b/usr/src/lib/libdtrace/sparcv9/Makefile
@@ -23,7 +23,7 @@
# Use is subject to license terms.
#
-ASFLAGS += -D_ASM -K PIC -P
+ASFLAGS += -D_ASM $(AS_BIGPICFLAGS) -P
include ../Makefile.com
include ../../Makefile.lib.64
diff --git a/usr/src/lib/libdtrace_jni/Makefile.com b/usr/src/lib/libdtrace_jni/Makefile.com
index 9d605b3c59..471746866f 100644
--- a/usr/src/lib/libdtrace_jni/Makefile.com
+++ b/usr/src/lib/libdtrace_jni/Makefile.com
@@ -46,8 +46,8 @@ SRCDIR = ../common
CPPFLAGS += -I../common -I.
CPPFLAGS += -I$(JAVA_ROOT)/include -I$(JAVA_ROOT)/include/solaris
CPPFLAGS += -I../java/native
-CFLAGS += $(CCVERBOSE) -K PIC
-CFLAGS64 += $(CCVERBOSE) -K PIC
+CFLAGS += $(CCVERBOSE) $(C_BIGPICFLAGS)
+CFLAGS64 += $(CCVERBOSE) $(C_BIGPICFLAGS64)
CERRWARN += -_gcc=-Wno-uninitialized
diff --git a/usr/src/lib/libndmp/sparcv9/Makefile b/usr/src/lib/libndmp/sparcv9/Makefile
index b84fb15f9e..c0e1bf7d54 100644
--- a/usr/src/lib/libndmp/sparcv9/Makefile
+++ b/usr/src/lib/libndmp/sparcv9/Makefile
@@ -11,10 +11,10 @@
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
-# - Redistributions of source code must retain the above copyright
+# - Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
-# - Redistributions in binary form must reproduce the above copyright
+# - Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
@@ -39,6 +39,6 @@
include ../Makefile.com
include $(SRC)/lib/Makefile.lib.64
-sparcv9_C_PICFLAGS= -K PIC
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libnsl/sparcv9/Makefile b/usr/src/lib/libnsl/sparcv9/Makefile
index da1777943b..249857bc50 100644
--- a/usr/src/lib/libnsl/sparcv9/Makefile
+++ b/usr/src/lib/libnsl/sparcv9/Makefile
@@ -23,8 +23,6 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
include ../Makefile.com
include ../../Makefile.lib.64
@@ -33,7 +31,6 @@ include ../../Makefile.lib.64
# the whole 64-bit library with PIC instead of "generically" compiling
# large parts of the 32-bit library with PIC unnecessarily.
-sparcv9_C_PICFLAGS = -K PIC
-sparcv9_CC_PICFLAGS = -KPIC
+sparcv9_C_PICFLAGS = $(sparcv9_C_BIGPICFLAGS)
install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libresolv2/sparcv9/Makefile b/usr/src/lib/libresolv2/sparcv9/Makefile
index ceed393e0d..2095629575 100644
--- a/usr/src/lib/libresolv2/sparcv9/Makefile
+++ b/usr/src/lib/libresolv2/sparcv9/Makefile
@@ -22,17 +22,15 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
#
include ../Makefile.com
include ../../Makefile.lib.64
# With the adition of BIND 8.3.3, the symbol table for 64 bit went over
-# the limit for Kpic, so we've added -KPIC here, for just the 64 bit
+# the limit for Kpic, so we've added -KPIC here, for just the 64 bit
# library. This avoids compiling the 32-bit library with PIC unnecessarily.
-sparcv9_C_PICFLAGS = -K PIC
-sparcv9_CC_PICFLAGS = -KPIC
+sparcv9_C_PICFLAGS = $(sparcv9_C_BIGPICFLAGS)
install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c
index e68213b6ef..9455a92344 100644
--- a/usr/src/lib/libsmbfs/smb/ctx.c
+++ b/usr/src/lib/libsmbfs/smb/ctx.c
@@ -910,7 +910,7 @@ sectype_table[] = {
{ "ntlm", SMB_AT_NTLM1 },
{ "ntlm2", SMB_AT_NTLM2 },
{ "krb5", SMB_AT_KRB5 },
- { NULL, 0 },
+ { NULL, 0 },
};
int
smb_parse_secopts(struct smb_ctx *ctx, const char *arg)
@@ -1212,11 +1212,6 @@ smb_ctx_get_ssn(struct smb_ctx *ctx)
if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
return (EINVAL);
- if (ctx->ct_dev_fd < 0) {
- if ((err = smb_ctx_gethandle(ctx)))
- return (err);
- }
-
/*
* Check whether the driver already has a VC
* we can use. If so, we're done!
diff --git a/usr/src/lib/libsmbfs/smb/findvc.c b/usr/src/lib/libsmbfs/smb/findvc.c
index cfe2cad9e7..63c6cce242 100644
--- a/usr/src/lib/libsmbfs/smb/findvc.c
+++ b/usr/src/lib/libsmbfs/smb/findvc.c
@@ -96,6 +96,11 @@ smb_ctx_findvc(struct smb_ctx *ctx)
if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
return (EINVAL);
+ if (ctx->ct_dev_fd < 0) {
+ if ((err = smb_ctx_gethandle(ctx)))
+ return (err);
+ }
+
for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
switch (ai->ai_family) {
diff --git a/usr/src/lib/libsmbfs/smb/mapfile-vers b/usr/src/lib/libsmbfs/smb/mapfile-vers
index 68b38f46ed..8f0c3905c6 100644
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers
@@ -64,6 +64,7 @@ SYMBOL_VERSION SUNWprivate {
smb_ctx_alloc;
smb_ctx_done;
+ smb_ctx_findvc;
smb_ctx_flags2;
smb_ctx_free;
smb_ctx_get_ssn;
diff --git a/usr/src/lib/libtnfprobe/Makefile.com b/usr/src/lib/libtnfprobe/Makefile.com
index 9dd31dd6f6..f0fe5a2658 100644
--- a/usr/src/lib/libtnfprobe/Makefile.com
+++ b/usr/src/lib/libtnfprobe/Makefile.com
@@ -53,7 +53,7 @@ HDRS= com.h writer.h probe.h
ROOTHDRDIR= $(ROOT)/usr/include/tnf
ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%)
CHECKHDRS= $(HDRS:%.h=%.check)
-$(ROOTHDRS) := FILEMODE = 0644
+$(ROOTHDRS) := FILEMODE = 0644
CHECKHDRS = $(HDRS:%.h=%.check)
# Include .. first to pick up tnf_trace.h in current dir, Include UFSDIR to
@@ -87,7 +87,7 @@ $(ROOTLIBDIR) $(ROOTHDRDIR):
$(ROOTHDRDIR)/% : %
$(INS.file)
-#ASFLAGS= -K pic -P -D_SYS_SYS_S -D_LOCORE -D_ASM -DPIC -DLOCORE $(CPPFLAGS)
+#ASFLAGS= $(AS_PICFLAGS) -P -D_SYS_SYS_S -D_LOCORE -D_ASM -DPIC -DLOCORE $(CPPFLAGS)
ASFLAGS= -P -D_SYS_SYS_S -D_LOCORE -D_ASM -DPIC -DLOCORE $(CPPFLAGS)
BUILD.s= $(AS) $(ASFLAGS) $< -o $@
diff --git a/usr/src/lib/libzfs/sparcv9/Makefile b/usr/src/lib/libzfs/sparcv9/Makefile
index 24010f6fb4..fc812ba170 100644
--- a/usr/src/lib/libzfs/sparcv9/Makefile
+++ b/usr/src/lib/libzfs/sparcv9/Makefile
@@ -23,11 +23,10 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
include ../Makefile.com
include ../../Makefile.lib.64
-sparcv9_C_PICFLAGS= -K PIC
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/libzfs_core/sparcv9/Makefile b/usr/src/lib/libzfs_core/sparcv9/Makefile
index c5b6ca49b4..fc812ba170 100644
--- a/usr/src/lib/libzfs_core/sparcv9/Makefile
+++ b/usr/src/lib/libzfs_core/sparcv9/Makefile
@@ -27,6 +27,6 @@
include ../Makefile.com
include ../../Makefile.lib.64
-sparcv9_C_PICFLAGS= -K PIC
+sparcv9_C_PICFLAGS= $(sparcv9_C_BIGPICFLAGS)
install: all $(ROOTLIBS64) $(ROOTLINKS64)
diff --git a/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile b/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile
index afc42f3dbc..5f4cf20982 100644
--- a/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile
+++ b/usr/src/lib/smbsrv/libmlsvc/sparc/Makefile
@@ -26,8 +26,7 @@ include ../Makefile.com
# With compiling with gcc, the symbol table goes over
# the limit for Kpic, so we add -KPIC here.
-$(__GNUC)sparc_C_PICFLAGS = -K PIC
-$(__GNUC)sparc_CC_PICFLAGS = -KPIC
+$(__GNUC)sparc_C_PICFLAGS = $(sparc_C_BIGPICFLAGS)
DYNFLAGS += -R/usr/lib/smbsrv
diff --git a/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile b/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile
index e18b286b0a..745535f9a9 100644
--- a/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile
+++ b/usr/src/lib/smbsrv/libmlsvc/sparcv9/Makefile
@@ -22,8 +22,6 @@
# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
-#
MACH_LDLIBS += -L$(ROOT)/usr/lib/smbsrv/$(MACH64)
@@ -33,8 +31,7 @@ include ../../../Makefile.lib.64
# With the adition of BIND 8.3.3, the symbol table for 64 bit went over
# the limit for Kpic, so we add -KPIC here, for just the 64 bit SPARC
# library. This avoids compiling the 32-bit library with PIC unnecessarily.
-sparcv9_C_PICFLAGS = -K PIC
-sparcv9_CC_PICFLAGS = -KPIC
+sparcv9_C_PICFLAGS = $(sparcv9_C_BIGPICFLAGS)
DYNFLAGS += -R/usr/lib/smbsrv/$(MACH64)
diff --git a/usr/src/lib/smbsrv/libsmbrp/sparcv9/Makefile b/usr/src/lib/smbsrv/libsmbrp/sparcv9/Makefile
index d138cfc574..89460e9b3c 100644
--- a/usr/src/lib/smbsrv/libsmbrp/sparcv9/Makefile
+++ b/usr/src/lib/smbsrv/libsmbrp/sparcv9/Makefile
@@ -29,8 +29,7 @@ include ../../../Makefile.lib.64
# With the adition of BIND 8.3.3, the symbol table for 64 bit went over
# the limit for Kpic, so we add -KPIC here, for just the 64 bit SPARC
# library. This avoids compiling the 32-bit library with PIC unnecessarily.
-sparcv9_C_PICFLAGS = -K PIC
-sparcv9_CC_PICFLAGS = -KPIC
+sparcv9_C_PICFLAGS = $(sparcv9_C_BIGPICFLAGS)
$(ROOTLIBDIR64):
$(INS.dir)