diff options
Diffstat (limited to 'usr/src/lib')
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(©, n->nm_ops); + if (!str_pair_copy(src_sp, ©)) { + str_pair_fini(©); + name_fini(dest); + return (B_FALSE); + } + + VERIFY(name_add_str(dest, ©.strp_l, ©.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, ©)) + goto fail; + + if (!name_add_str(n, ©.strp_l, ©.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) |