summaryrefslogtreecommitdiffstats
path: root/contrib/elftoolchain/libelftc
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2014-11-27 20:12:13 +0000
committeremaste <emaste@FreeBSD.org>2014-11-27 20:12:13 +0000
commitb09a2340ee89cb9c8c414aaf7b8b267bfc5653ae (patch)
tree49421ff690e54a53267da358fb3f85c8e1600eb5 /contrib/elftoolchain/libelftc
parent50fd85b21cc1520575b04bfc8a5671fe07072c53 (diff)
parent9ee78763690833f42af4a97b77baf30edbca5314 (diff)
downloadFreeBSD-src-b09a2340ee89cb9c8c414aaf7b8b267bfc5653ae.zip
FreeBSD-src-b09a2340ee89cb9c8c414aaf7b8b267bfc5653ae.tar.gz
Copy elftoolchain binutils replacements from vendor branch
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'contrib/elftoolchain/libelftc')
-rw-r--r--contrib/elftoolchain/libelftc/Makefile65
-rw-r--r--contrib/elftoolchain/libelftc/Version.map18
-rw-r--r--contrib/elftoolchain/libelftc/_libelftc.h89
-rw-r--r--contrib/elftoolchain/libelftc/elftc.383
-rw-r--r--contrib/elftoolchain/libelftc/elftc_bfd_find_target.3189
-rw-r--r--contrib/elftoolchain/libelftc/elftc_bfdtarget.c75
-rw-r--r--contrib/elftoolchain/libelftc/elftc_copyfile.373
-rw-r--r--contrib/elftoolchain/libelftc/elftc_copyfile.c107
-rw-r--r--contrib/elftoolchain/libelftc/elftc_demangle.3116
-rw-r--r--contrib/elftoolchain/libelftc/elftc_demangle.c110
-rw-r--r--contrib/elftoolchain/libelftc/elftc_set_timestamps.384
-rw-r--r--contrib/elftoolchain/libelftc/elftc_set_timestamps.c85
-rw-r--r--contrib/elftoolchain/libelftc/elftc_string_table.c392
-rw-r--r--contrib/elftoolchain/libelftc/elftc_string_table_create.3227
-rw-r--r--contrib/elftoolchain/libelftc/elftc_symbol_table_create.3529
-rw-r--r--contrib/elftoolchain/libelftc/elftc_version.379
-rw-r--r--contrib/elftoolchain/libelftc/libelftc.h89
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_bfdtarget.c383
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_dem_arm.c1227
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c1376
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c3238
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_hash.c70
-rw-r--r--contrib/elftoolchain/libelftc/libelftc_vstr.c318
-rwxr-xr-xcontrib/elftoolchain/libelftc/make-toolchain-version104
-rw-r--r--contrib/elftoolchain/libelftc/os.FreeBSD.mk7
-rw-r--r--contrib/elftoolchain/libelftc/os.Linux.mk3
26 files changed, 9136 insertions, 0 deletions
diff --git a/contrib/elftoolchain/libelftc/Makefile b/contrib/elftoolchain/libelftc/Makefile
new file mode 100644
index 0000000..a5fc297
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/Makefile
@@ -0,0 +1,65 @@
+# $Id: Makefile 2859 2013-01-05 09:21:54Z jkoshy $
+
+TOP= ${.CURDIR}/..
+
+LIB= elftc
+
+SRCS= elftc_bfdtarget.c \
+ elftc_copyfile.c \
+ elftc_demangle.c \
+ elftc_set_timestamps.c \
+ elftc_string_table.c \
+ elftc_version.c \
+ libelftc_bfdtarget.c \
+ libelftc_dem_arm.c \
+ libelftc_dem_gnu2.c \
+ libelftc_dem_gnu3.c \
+ libelftc_hash.c \
+ libelftc_vstr.c
+
+INCS= libelftc.h
+INCSDIR= /usr/include
+
+RELEASE= HEAD # Change this on release branches.
+
+SHLIB_MAJOR= 1
+
+WARNS?= 6
+
+CLEANFILES+= elftc_version.c
+
+LDADD+= -lelf
+
+MAN= elftc.3 \
+ elftc_bfd_find_target.3 \
+ elftc_copyfile.3 \
+ elftc_demangle.3 \
+ elftc_set_timestamps.3 \
+ elftc_string_table_create.3 \
+ elftc_version.3
+
+MLINKS= elftc_bfd_find_target.3 elftc_bfd_target_byteorder.3 \
+ elftc_bfd_find_target.3 elftc_bfd_target_class.3 \
+ elftc_bfd_find_target.3 elftc_bfd_target_flavor.3 \
+ elftc_string_table_create.3 elftc_string_table_from_section.3 \
+ elftc_string_table_create.3 elftc_string_table_destroy.3 \
+ elftc_string_table_create.3 elftc_string_table_image.3 \
+ elftc_string_table_create.3 elftc_string_table_insert.3 \
+ elftc_string_table_create.3 elftc_string_table_lookup.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_create_nested.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_delete_name.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_delete_entry.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_destroy.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_from_section.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_insert.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_iterate.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_lookup.3 \
+ elftc_symbol_table_create.3 elftc_symbol_table_to_image.3
+
+.if !make(clean) && !make(clobber)
+.BEGIN: .SILENT
+ ${.CURDIR}/make-toolchain-version -t ${TOP} -r ${RELEASE} \
+ -h ${OS_HOST}
+.endif
+
+.include "${TOP}/mk/elftoolchain.lib.mk"
diff --git a/contrib/elftoolchain/libelftc/Version.map b/contrib/elftoolchain/libelftc/Version.map
new file mode 100644
index 0000000..43f9e82
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/Version.map
@@ -0,0 +1,18 @@
+/*
+ * $Id: Version.map 2574 2012-09-11 15:11:59Z jkoshy $
+ */
+
+R1.0 {
+global:
+ elftc_bfd_find_target;
+ elftc_bfd_target_byteorder;
+ elftc_bfd_target_class;
+ elftc_bfd_target_flavor;
+ elftc_bfd_target_machine;
+ elftc_copyfile;
+ elftc_demangle;
+ elftc_set_timestamps;
+ elftc_version;
+local:
+ *;
+};
diff --git a/contrib/elftoolchain/libelftc/_libelftc.h b/contrib/elftoolchain/libelftc/_libelftc.h
new file mode 100644
index 0000000..c300f91
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/_libelftc.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2009 Kai Wang
+ * Copyright (c) 2007,2008 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $Id: _libelftc.h 2856 2013-01-04 16:00:26Z jkoshy $
+ */
+
+#ifndef __LIBELFTC_H_
+#define __LIBELFTC_H_
+
+#include <stdbool.h>
+
+#include "_elftc.h"
+
+struct _Elftc_Bfd_Target {
+ const char *bt_name; /* target name. */
+ unsigned int bt_type; /* target type. */
+ unsigned int bt_byteorder; /* elf target byteorder. */
+ unsigned int bt_elfclass; /* elf target class (32/64bit). */
+ unsigned int bt_machine; /* elf target arch. */
+ unsigned int bt_osabi; /* elf target abi. */
+};
+
+extern struct _Elftc_Bfd_Target _libelftc_targets[];
+
+/** @brief Dynamic vector data for string. */
+struct vector_str {
+ /** Current size */
+ size_t size;
+ /** Total capacity */
+ size_t capacity;
+ /** String array */
+ char **container;
+};
+
+#define BUFFER_GROWFACTOR 1.618
+
+#define ELFTC_FAILURE 0
+#define ELFTC_ISDIGIT(C) (isdigit((C) & 0xFF))
+#define ELFTC_SUCCESS 1
+
+#define VECTOR_DEF_CAPACITY 8
+
+
+__BEGIN_DECLS
+char *cpp_demangle_ARM(const char *_org);
+char *cpp_demangle_gnu2(const char *_org);
+char *cpp_demangle_gnu3(const char *_org);
+bool is_cpp_mangled_ARM(const char *_org);
+bool is_cpp_mangled_gnu2(const char *_org);
+bool is_cpp_mangled_gnu3(const char *_org);
+unsigned int libelftc_hash_string(const char *);
+void vector_str_dest(struct vector_str *_vec);
+int vector_str_find(const struct vector_str *_vs, const char *_str,
+ size_t _len);
+char *vector_str_get_flat(const struct vector_str *_vs, size_t *_len);
+bool vector_str_init(struct vector_str *_vs);
+bool vector_str_pop(struct vector_str *_vs);
+bool vector_str_push(struct vector_str *_vs, const char *_str,
+ size_t _len);
+bool vector_str_push_vector_head(struct vector_str *_dst,
+ struct vector_str *_org);
+char *vector_str_substr(const struct vector_str *_vs, size_t _begin,
+ size_t _end, size_t *_rlen);
+__END_DECLS
+
+#endif /* __LIBELFTC_H */
diff --git a/contrib/elftoolchain/libelftc/elftc.3 b/contrib/elftoolchain/libelftc/elftc.3
new file mode 100644
index 0000000..bbf5173
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc.3
@@ -0,0 +1,83 @@
+.\" Copyright (c) 2012 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc.3 2818 2012-12-24 12:32:48Z jkoshy $
+.\"
+.Dd December 24, 2012
+.Os
+.Dt ELFTC 3
+.Sh NAME
+.Nm elftc
+.Nd support routines used in the Elftoolchain project
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Sh DESCRIPTION
+The
+.Lb libelftc
+provides support routines used for developing the utilities in the
+Elftoolchain source tree.
+.Pp
+This manual page serves as an overview of the functionality in this
+library.
+Additional reference information may be found in the individual
+manual pages for the functions listed below.
+.Ss Functional Grouping
+.Bl -tag -width indent
+.It "Binary Object Handling"
+.Bl -tag -compact
+.It Fn elftc_bfd_find_target
+Locate a binary object descriptor.
+.It Fn elftc_bfd_target_class
+Query the ELF class for a binary object descriptor.
+.It Fn elftc_bfd_target_byteorder
+Query the byte order for a binary object descriptor.
+.It Fn elftc_bfd_target_flavor
+Query the object format for a binary object descriptor.
+.It Fn elftc_bfd_target_machine
+Query the target machine for a binary object descriptor.
+.El
+.It "C++ support"
+.Bl -tag -compact
+.It Fn elftc_demangle
+Decodes a symbol name encoded according to the encoding rules for the
+C++ language.
+.El
+.It "Programming conveniences"
+.Bl -tag -compact
+.It Fn elftc_copyfile
+Copies the contents of a file to another.
+.It Fn elftc_set_timestamp
+Portably set the time stamps on a file.
+.El
+.It "Project Configuration"
+.Bl -tag -compact
+.It Fn elftc_version
+Returns a project-wide identifier string that encodes the source
+revision of the source tree.
+.El
+.El
+.Sh SEE ALSO
+.Xr dwarf 3 ,
+.Xr elf 3
diff --git a/contrib/elftoolchain/libelftc/elftc_bfd_find_target.3 b/contrib/elftoolchain/libelftc/elftc_bfd_find_target.3
new file mode 100644
index 0000000..851ae31
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_bfd_find_target.3
@@ -0,0 +1,189 @@
+.\" Copyright (c) 2010-2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_bfd_find_target.3 2251 2011-11-30 16:50:06Z jkoshy $
+.\"
+.Dd November 30, 2011
+.Os
+.Dt ELFTC_BFD_FIND_TARGET
+.Sh NAME
+.Nm elftc_bfd_find_target ,
+.Nm elftc_bfd_target_byteorder ,
+.Nm elftc_bfd_target_class ,
+.Nm elftc_bfd_target_flavor ,
+.Nm elftc_bfd_target_machine
+.Nd binary object descriptor handling
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Vt struct Elftc_Bfd_Target;
+.Ft "Elftc_Bfd_Target *"
+.Fn elftc_bfd_find_target "const char *target_name"
+.Ft "unsigned int"
+.Fn elftc_bfd_target_class "Elftc_Bfd_Target *target"
+.Ft "unsigned int"
+.Fn elftc_bfd_target_byteorder "Elftc_Bfd_Target *target"
+.Ft Elftc_Bfd_Target_Flavor
+.Fn elftc_bfd_target_flavor "Elftc_Bfd_Target *target"
+.Ft "unsigned int"
+.Fn elftc_bfd_target_machine "Elftc_Bfd_Target *target"
+.Sh DESCRIPTION
+Function
+.Fn elftc_bfd_find_target
+locates a binary object descriptor corresponding to the descriptor
+name in argument
+.Ar "target_name" .
+Binary object descriptors encapsulate properties of an object format
+such as its file representation, ELF class, and byte endianness.
+.Pp
+Known descriptor names and their properties include:
+.Bl -column -offset "XXXX" ".Li elf32-x86-64-freebsd" "Object format" "Byte Order" "ELF Class"
+.It Em Name Ta Em "Object Format" Ta Em "Byte Order" Ta Em "ELF Class"
+.It Li binary Ta Binary Ta - Ta -
+.It Li elf32-avr Ta ELF Ta LSB Ta 32
+.It Li elf32-big Ta ELF Ta MSB Ta 32
+.It Li elf32-bigarm Ta ELF Ta MSB Ta 32
+.It Li elf32-bigmips Ta ELF Ta MSB Ta 32
+.It Li elf32-i386 Ta ELF Ta LSB Ta 32
+.It Li elf32-i386-freebsd Ta ELF Ta LSB Ta 32
+.It Li elf32-ia64-big Ta ELF Ta MSB Ta 32
+.It Li elf32-little Ta ELF Ta LSB Ta 32
+.It Li elf32-littlearm Ta ELF Ta LSB Ta 32
+.It Li elf32-littlemips Ta ELF Ta LSB Ta 32
+.It Li elf32-powerpc Ta ELF Ta MSB Ta 32
+.It Li elf32-powerpcle Ta ELF Ta LSB Ta 32
+.It Li elf32-sh Ta ELF Ta MSB Ta 32
+.It Li elf32-shl Ta ELF Ta LSB Ta 32
+.It Li elf32-sh-nbsd Ta ELF Ta MSB Ta 32
+.It Li elf32-shl-nbsd Ta ELF Ta LSB Ta 32
+.It Li elf32-shbig-linux Ta ELF Ta MSB Ta 32
+.It Li elf32-shl-linux Ta ELF Ta LSB Ta 32
+.It Li elf32-sparc Ta ELF Ta MSB Ta 32
+.It Li elf64-alpha Ta ELF Ta LSB Ta 64
+.It Li elf64-alpha-freebsd Ta ELF Ta LSB Ta 64
+.It Li elf64-big Ta ELF Ta MSB Ta 64
+.It Li elf64-bigmips Ta ELF Ta MSB Ta 64
+.It Li elf64-ia64-big Ta ELF Ta MSB Ta 64
+.It Li elf64-ia64-little Ta ELF Ta LSB Ta 64
+.It Li elf64-little Ta ELF Ta LSB Ta 64
+.It Li elf64-littlemips Ta ELF Ta LSB Ta 64
+.It Li elf64-powerpc Ta ELF Ta MSB Ta 64
+.It Li elf64-powerpcle Ta ELF Ta LSB Ta 64
+.It Li elf64-sh64 Ta ELF Ta MSB Ta 64
+.It Li elf64-sh64l Ta ELF Ta LSB Ta 64
+.It Li elf64-sh64-nbsd Ta ELF Ta MSB Ta 64
+.It Li elf64-sh64l-nbsd Ta ELF Ta LSB Ta 64
+.It Li elf64-sh64big-linux Ta ELF Ta MSB Ta 64
+.It Li elf64-sh64-linux Ta ELF Ta LSB Ta 64
+.It Li elf64-sparc Ta ELF Ta MSB Ta 64
+.It Li elf64-sparc-freebsd Ta ELF Ta MSB Ta 64
+.It Li elf64-x86-64 Ta ELF Ta LSB Ta 64
+.It Li elf64-x86-64-freebsd Ta ELF Ta LSB Ta 64
+.It Li ihex Ta IHEX Ta - Ta -
+.It Li srec Ta SREC Ta - Ta -
+.It Li symbolsrec Ta SREC Ta - Ta -
+.El
+.Pp
+Function
+.Fn elftc_bfd_target_byteorder
+returns the ELF byte order associated with target descriptor
+.Ar target .
+.Pp
+Function
+.Fn elftc_bfd_target_class
+returns the ELF class associated with target descriptor
+.Ar target .
+.Pp
+Function
+.Fn elftc_bfd_target_flavor
+returns the object format associated with target descriptor
+.Ar target .
+The known object formats are:
+.Bl -tag -offset "XXXX" -width ".Dv ETF_BINARY" -compact
+.It Dv ETF_ELF
+An ELF object.
+.It Dv ETF_BINARY
+Raw binary.
+.It Dv ETF_IHEX
+An object encoded in
+.Tn Intel
+hex format.
+.It Dv ETF_NONE
+An unknown object format.
+.It Dv ETF_SREC
+An object encoded as S-records.
+.El
+.Sh RETURN VALUES
+Function
+.Fn elftc_bfd_find_target
+returns a valid pointer to an opaque binary target descriptor if
+successful, or NULL in case of an error.
+.Pp
+Function
+.Fn elftc_bfd_target_byteorder
+returns the ELF byte order associated with the target descriptor; one of
+.Dv ELFDATA2MSB
+or
+.Dv ELFDATA2LSB .
+.Pp
+Function
+.Fn elftc_bfd_target_class
+returns the ELF class associated with the target descriptor; one of
+.Dv ELFCLASS32
+or
+.Dv ELFCLASS64 .
+.Pp
+Function
+.Fn elftc_bfd_target_machine
+returns the ELF architecture associated with the target descriptor.
+.Pp
+Function
+.Fn elftc_bfd_target_flavor
+returns one of
+.Dv ETF_BINARY ,
+.Dv ETF_ELF ,
+.Dv ETF_IHEX
+or
+.Dv ETF_SREC
+if successful or
+.Dv ETF_NONE
+in case of error.
+.Sh EXAMPLES
+To return descriptor information associated with target name
+.Dq elf64-big
+use:
+.Bd -literal -offset indent
+struct Elftc_Bfd_Target *t;
+
+if ((t = elftc_bfd_find_target("elf64-big")) == NULL)
+ errx(EXIT_FAILURE, "Cannot find target descriptor");
+
+printf("Class: %s\\n", elftc_bfd_target_class(t) == ELFCLASS32 ?
+ "ELFCLASS32" : "ELFCLASS64");
+printf("Byteorder: %s\\n",
+ elftc_bfd_target_byteorder(t) == ELFDATA2LSB ? "LSB" : "MSB");
+printf("Flavor: %d\\n", elftc_bfd_target_flavor(t));
+.Ed
+.Sh SEE ALSO
+.Xr elf 3
diff --git a/contrib/elftoolchain/libelftc/elftc_bfdtarget.c b/contrib/elftoolchain/libelftc/elftc_bfdtarget.c
new file mode 100644
index 0000000..351e5e4
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_bfdtarget.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2008,2009 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <string.h>
+#include <libelftc.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: elftc_bfdtarget.c 2251 2011-11-30 16:50:06Z jkoshy $");
+
+Elftc_Bfd_Target *
+elftc_bfd_find_target(const char *tgt_name)
+{
+ Elftc_Bfd_Target *tgt;
+
+ for (tgt = _libelftc_targets; tgt->bt_name; tgt++)
+ if (!strcmp(tgt_name, tgt->bt_name))
+ return (tgt);
+
+ return (NULL); /* not found */
+}
+
+Elftc_Bfd_Target_Flavor
+elftc_bfd_target_flavor(Elftc_Bfd_Target *tgt)
+{
+
+ return (tgt->bt_type);
+}
+
+unsigned int
+elftc_bfd_target_byteorder(Elftc_Bfd_Target *tgt)
+{
+
+ return (tgt->bt_byteorder);
+}
+
+unsigned int
+elftc_bfd_target_class(Elftc_Bfd_Target *tgt)
+{
+
+ return (tgt->bt_elfclass);
+}
+
+unsigned int
+elftc_bfd_target_machine(Elftc_Bfd_Target *tgt)
+{
+
+ return (tgt->bt_machine);
+}
diff --git a/contrib/elftoolchain/libelftc/elftc_copyfile.3 b/contrib/elftoolchain/libelftc/elftc_copyfile.3
new file mode 100644
index 0000000..4520433
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_copyfile.3
@@ -0,0 +1,73 @@
+.\" Copyright (c) 2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_copyfile.3 2315 2011-12-11 09:28:55Z jkoshy $
+.\"
+.Dd December 11, 2011
+.Os
+.Dt ELFTC_COPYFILE 3
+.Sh NAME
+.Nm elftc_copyfile
+.Nd convenience function to copy data
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft in
+.Fn elftc_copyfile "int ifd" "int ofd"
+.Sh DESCRIPTION
+The function
+.Fn elftc_copyfile
+copies the contents of the file referenced by argument
+.Ar ifd
+to the file referenced by argument
+.Ar ofd .
+.Pp
+The argument
+.Ar ifd
+should contain a file descriptor opened for reading, with its file
+offset at the beginning of the file.
+.Pp
+The argument
+.Ar ofd
+should contain a file descriptor opened for writing.
+.Sh RETURN VALUE
+.Rv -std
+.Sh ERRORS
+The function
+.Fn elftc_copyfile
+may fail with any of the errors returned by
+.Xr fstat 2 ,
+.Xr malloc 3 ,
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr read 2
+or
+.Xr write 2 .
+.Sh SEE ALSO
+.Xr fstat 2 ,
+.Xr malloc 3 ,
+.Xr mmap 2 ,
+.Xr munmap 2 ,
+.Xr read 2 ,
+.Xr write 2
diff --git a/contrib/elftoolchain/libelftc/elftc_copyfile.c b/contrib/elftoolchain/libelftc/elftc_copyfile.c
new file mode 100644
index 0000000..0bacaf4
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_copyfile.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2011, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "libelftc.h"
+#include "_libelftc.h"
+
+#if ELFTC_HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+ELFTC_VCSID("$Id: elftc_copyfile.c 2318 2011-12-11 10:54:27Z jkoshy $");
+
+/*
+ * Copy the contents referenced by 'ifd' to 'ofd'. Returns 0 on
+ * success and -1 on error.
+ */
+
+int
+elftc_copyfile(int ifd, int ofd)
+{
+ int buf_mmapped;
+ struct stat sb;
+ char *b, *buf;
+ ssize_t nw;
+ size_t n;
+
+ /* Determine the input file's size. */
+ if (fstat(ifd, &sb) < 0)
+ return (-1);
+
+ /* Skip files without content. */
+ if (sb.st_size == 0)
+ return (0);
+
+ buf = NULL;
+ buf_mmapped = 0;
+
+#if ELFTC_HAVE_MMAP
+ /*
+ * Prefer mmap() if it is available.
+ */
+ buf = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, ifd, (off_t) 0);
+ if (buf != MAP_FAILED)
+ buf_mmapped = 1;
+ else
+ buf = NULL;
+#endif
+
+ /*
+ * If mmap() is not available, or if the mmap() operation
+ * failed, allocate a buffer, and read in input data.
+ */
+ if (buf == NULL) {
+ if ((buf = malloc(sb.st_size)) == NULL)
+ return (-1);
+ if (read(ifd, buf, sb.st_size) != sb.st_size)
+ return (-1);
+ }
+
+ /*
+ * Write data to the output file descriptor.
+ */
+ for (n = sb.st_size, b = buf; n > 0; n -= nw, b += nw)
+ if ((nw = write(ofd, b, n)) <= 0)
+ break;
+
+ /* Release the input buffer. */
+#if ELFTC_HAVE_MMAP
+ if (buf_mmapped && munmap(buf, sb.st_size) < 0)
+ return (-1);
+#endif
+
+ if (!buf_mmapped)
+ free(buf);
+
+ return (n > 0 ? -1 : 0);
+}
+
diff --git a/contrib/elftoolchain/libelftc/elftc_demangle.3 b/contrib/elftoolchain/libelftc/elftc_demangle.3
new file mode 100644
index 0000000..bbe67e5
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_demangle.3
@@ -0,0 +1,116 @@
+.\" Copyright (c) 2009,2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_demangle.3 2065 2011-10-26 15:24:47Z jkoshy $
+.\"
+.Dd August 24, 2011
+.Os
+.Dt ELFTC_DEMANGLE 3
+.Sh NAME
+.Nm elftc_demangle
+.Nd demangle a C++ name
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft int
+.Fo elftc_demangle
+.Fa "const char *encodedname"
+.Fa "char *buffer"
+.Fa "size_t bufsize"
+.Fa "unsigned int flags"
+.Fc
+.Sh DESCRIPTION
+Function
+.Fn elftc_demangle
+decodes a symbol name encoded according to the type encoding rules
+for the C++ language and returns a string denoting an equivalent
+C++ prototype.
+.Pp
+Argument
+.Ar encodedname
+specifies the encoded symbol name.
+Argument
+.Ar buffer
+denotes a programmer-specified area to place the prototype string in.
+Argument
+.Ar bufsize
+specifies the size of the programmer-specified area.
+Argument
+.Ar flags
+specifies the encoding style in use for argument
+.Ar encodedname .
+Supported encoding styles are:
+.Bl -tag -width ".Dv ELFTC_DEM_GNU3"
+.It Dv ELFTC_DEM_ARM
+The encoding style used by compilers adhering to the conventions of the
+C++ Annotated Reference Manual.
+.It Dv ELFTC_DEM_GNU2
+The encoding style by GNU C++ version 2.
+.It Dv ELFTC_DEM_GNU3
+The encoding style by GNU C++ version 3 and later.
+.El
+.Pp
+Argument
+.Ar flags
+may be zero, in which case the function will attempt to guess the
+encoding scheme from the contents of
+.Ar encodedname .
+.Sh RETURN VALUE
+Function
+.Fn elftc_demangle
+returns 0 on success.
+In case of an error it returns -1 and sets the
+.Va errno
+variable.
+.Sh EXAMPLES
+To decode a name that uses an unknown encoding style use:
+.Bd -literal -offset indent
+char buffer[1024];
+const char *funcname;
+
+funcname = ...; /* points to string to be demangled */
+if (elftc_demangle(funcname, buffer, sizeof(buffer), 0) == 0)
+ printf("Demangled name: %\\n", buffer);
+else
+ perror("Cannot demangle %s", funcname);
+.Ed
+.Sh ERRORS
+Function
+.Fn elftc_demangle
+may fail with the following errors:
+.Bl -tag -width ".Bq Er ENAMETOOLONG"
+.It Bq Er EINVAL
+Argument
+.Ar encodedname
+was not a valid encoded name.
+.It Bq Er ENAMETOOLONG
+The output buffer specified by arguments
+.Ar buffer
+and
+.Ar bufsize
+was too small to hold the decoded function prototype.
+.El
+.Sh SEE ALSO
+.Xr elf 3 ,
+.Xr elf_strptr 3
diff --git a/contrib/elftoolchain/libelftc/elftc_demangle.c b/contrib/elftoolchain/libelftc/elftc_demangle.c
new file mode 100644
index 0000000..c55564e
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_demangle.c
@@ -0,0 +1,110 @@
+/*-
+ * Copyright (c) 2009 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <libelf.h>
+#include <libelftc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: elftc_demangle.c 2065 2011-10-26 15:24:47Z jkoshy $");
+
+static int
+is_mangled(const char *s, int style)
+{
+
+ switch (style) {
+ case ELFTC_DEM_ARM: return (is_cpp_mangled_ARM(s) ? style : 0);
+ case ELFTC_DEM_GNU2: return (is_cpp_mangled_gnu2(s) ? style : 0);
+ case ELFTC_DEM_GNU3: return (is_cpp_mangled_gnu3(s) ? style : 0);
+ }
+
+ /* No style or invalid style spcified, try to guess. */
+ if (is_cpp_mangled_gnu3(s))
+ return (ELFTC_DEM_GNU3);
+ if (is_cpp_mangled_gnu2(s))
+ return (ELFTC_DEM_GNU2);
+ if (is_cpp_mangled_ARM(s))
+ return (ELFTC_DEM_ARM);
+
+ /* Cannot be demangled. */
+ return (0);
+}
+
+static char *
+demangle(const char *s, int style, int rc)
+{
+
+ (void) rc; /* XXX */
+ switch (style) {
+ case ELFTC_DEM_ARM: return (cpp_demangle_ARM(s));
+ case ELFTC_DEM_GNU2: return (cpp_demangle_gnu2(s));
+ case ELFTC_DEM_GNU3: return (cpp_demangle_gnu3(s));
+ default:
+ assert(0);
+ return (NULL);
+ }
+}
+
+int
+elftc_demangle(const char *mangledname, char *buffer, size_t bufsize,
+ unsigned int flags)
+{
+ int style, rc;
+ char *rlt;
+
+ style = flags & 0xFFFF;
+ rc = flags >> 16;
+
+ if (mangledname == NULL ||
+ ((style = is_mangled(mangledname, style)) == 0)) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((rlt = demangle(mangledname, style, rc)) == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (buffer == NULL || bufsize < strlen(rlt) + 1) {
+ free(rlt);
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ strncpy(buffer, rlt, bufsize);
+ buffer[bufsize - 1] = '\0';
+ free(rlt);
+
+ return (0);
+}
diff --git a/contrib/elftoolchain/libelftc/elftc_set_timestamps.3 b/contrib/elftoolchain/libelftc/elftc_set_timestamps.3
new file mode 100644
index 0000000..115fe92
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_set_timestamps.3
@@ -0,0 +1,84 @@
+.\" Copyright (c) 2011 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id$
+.\"
+.Dd December 15, 2011
+.Os
+.Dt ELFTC_SET_TIMESTAMPS 3
+.Sh NAME
+.Nm elftc_set_timestamps
+.Nd set file timestamps
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft int
+.Fn elftc_set_timestamps "const char *filename" "struct stat *sb"
+.Sh DESCRIPTION
+The
+.Fn elftc_set_timestamps
+function is used to set the access and modified time stamps on a file
+based on the contents of a
+.Vt "struct stat"
+descriptor.
+.Pp
+Argument
+.Ar filename
+names an existing file in the file system.
+.Pp
+Argument
+.Ar sb
+points to structure of type
+.Vt "struct stat"
+populated by a prior call to
+.Xr fstat 2
+or
+.Xr stat 2 .
+.Sh IMPLEMENTATION NOTES
+This function will invoke the high-resolution
+.Xr utimes 2
+system call if the underlying operating system supports it.
+On operating systems lacking support for
+.Xr utimes 2 ,
+the function will use lower resolution
+.Xr utime 2
+system call.
+.Sh EXAMPLES
+To set the access and modified times for a new file to those of an
+existing file, use:
+.Bd -literal -offset indent
+struct stat sb;
+const char *existing_filename, *new_filename;
+
+if (stat(existing_filename, &sb) < 0)
+ err(EXIT_FAILURE, "stat failed");
+
+if (elftc_set_timestamps(new_filename, &sb) < 0)
+ err(EXIT_FAILURE, "timestamps could not be set");
+.Ed
+.Sh SEE ALSO
+.Xr fstat 2 ,
+.Xr stat 2 ,
+.Xr utime 2 ,
+.Xr utimes 2 .
diff --git a/contrib/elftoolchain/libelftc/elftc_set_timestamps.c b/contrib/elftoolchain/libelftc/elftc_set_timestamps.c
new file mode 100644
index 0000000..cb28c35
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_set_timestamps.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2011 Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include "libelftc.h"
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id$");
+
+/*
+ * Determine the field name for the timestamp fields inside a 'struct
+ * stat'.
+ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+#define ATIME st_atimespec
+#define MTIME st_mtimespec
+#define LIBELFTC_HAVE_UTIMES 1
+#endif
+
+#if defined(__DragonFly__) || defined(__linux__) || defined(__OpenBSD__)
+#define ATIME st_atim
+#define MTIME st_mtim
+#define LIBELFTC_HAVE_UTIMES 1
+#endif
+
+#if LIBELFTC_HAVE_UTIMES
+#include <sys/time.h>
+#else
+#include <utime.h>
+#endif
+
+int
+elftc_set_timestamps(const char *fn, struct stat *sb)
+{
+#if LIBELFTC_HAVE_UTIMES
+ /*
+ * The BSD utimes() system call offers timestamps
+ * 1-microsecond granularity.
+ */
+ struct timeval tv[2];
+
+ tv[0].tv_sec = sb->ATIME.tv_sec;
+ tv[0].tv_usec = sb->ATIME.tv_nsec / 1000;
+ tv[1].tv_sec = sb->MTIME.tv_sec;
+ tv[1].tv_usec = sb->MTIME.tv_nsec / 1000;
+
+ return (utimes(fn, tv));
+#else
+ /*
+ * On OSes without utimes(), fall back to the POSIX utime()
+ * call, which offers 1-second granularity.
+ */
+ struct utimbuf utb;
+
+ utb.actime = sb->st_atime;
+ utb.modtime = sb->st_mtime;
+ return (utime(fn, &utb));
+#endif
+}
diff --git a/contrib/elftoolchain/libelftc/elftc_string_table.c b/contrib/elftoolchain/libelftc/elftc_string_table.c
new file mode 100644
index 0000000..bba9ac6
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_string_table.c
@@ -0,0 +1,392 @@
+/*-
+ * Copyright (c) 2013, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <gelf.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "libelftc.h"
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: elftc_string_table.c 2869 2013-01-06 13:29:18Z jkoshy $");
+
+#define ELFTC_STRING_TABLE_DEFAULT_SIZE (4*1024)
+#define ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE 16
+#define ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH 8
+#define ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT (4*1024)
+
+struct _Elftc_String_Table_Entry {
+ int ste_idx;
+ SLIST_ENTRY(_Elftc_String_Table_Entry) ste_next;
+};
+
+#define ELFTC_STRING_TABLE_COMPACTION_FLAG 0x1
+#define ELFTC_STRING_TABLE_LENGTH(st) ((st)->st_len >> 1)
+#define ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st) do { \
+ (st)->st_len &= ~ELFTC_STRING_TABLE_COMPACTION_FLAG; \
+ } while (0)
+#define ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st) do { \
+ (st)->st_len |= ELFTC_STRING_TABLE_COMPACTION_FLAG; \
+ } while (0)
+#define ELFTC_STRING_TABLE_UPDATE_LENGTH(st, len) do { \
+ (st)->st_len = \
+ ((st)->st_len & \
+ ELFTC_STRING_TABLE_COMPACTION_FLAG) | \
+ ((len) << 1); \
+ } while (0)
+
+struct _Elftc_String_Table {
+ unsigned int st_len; /* length and flags */
+ int st_nbuckets;
+ int st_string_pool_size;
+ char *st_string_pool;
+ SLIST_HEAD(_Elftc_String_Table_Bucket,
+ _Elftc_String_Table_Entry) st_buckets[];
+};
+
+static struct _Elftc_String_Table_Entry *
+elftc_string_table_find_hash_entry(Elftc_String_Table *st, const char *string,
+ int *rhashindex)
+{
+ struct _Elftc_String_Table_Entry *ste;
+ int hashindex;
+ char *s;
+
+ hashindex = libelftc_hash_string(string) % st->st_nbuckets;
+
+ if (rhashindex)
+ *rhashindex = hashindex;
+
+ SLIST_FOREACH(ste, &st->st_buckets[hashindex], ste_next) {
+ s = st->st_string_pool + abs(ste->ste_idx);
+
+ assert(s > st->st_string_pool &&
+ s < st->st_string_pool + st->st_string_pool_size);
+
+ if (strcmp(s, string) == 0)
+ return (ste);
+ }
+
+ return (NULL);
+}
+
+static int
+elftc_string_table_add_to_pool(Elftc_String_Table *st, const char *string)
+{
+ char *newpool;
+ int len, newsize, stlen;
+
+ len = strlen(string) + 1; /* length, including the trailing NUL */
+ stlen = ELFTC_STRING_TABLE_LENGTH(st);
+
+ /* Resize the pool, if needed. */
+ if (stlen + len >= st->st_string_pool_size) {
+ newsize = roundup(st->st_string_pool_size +
+ ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT,
+ ELFTC_STRING_TABLE_POOL_SIZE_INCREMENT);
+ if ((newpool = realloc(st->st_string_pool, newsize)) ==
+ NULL)
+ return (0);
+ st->st_string_pool = newpool;
+ st->st_string_pool_size = newsize;
+ }
+
+ strcpy(st->st_string_pool + stlen, string);
+ ELFTC_STRING_TABLE_UPDATE_LENGTH(st, stlen + len);
+
+ return (stlen);
+}
+
+Elftc_String_Table *
+elftc_string_table_create(int sizehint)
+{
+ int n, nbuckets, tablesize;
+ struct _Elftc_String_Table *st;
+
+ if (sizehint < ELFTC_STRING_TABLE_DEFAULT_SIZE)
+ sizehint = ELFTC_STRING_TABLE_DEFAULT_SIZE;
+
+ nbuckets = sizehint / (ELFTC_STRING_TABLE_EXPECTED_CHAIN_LENGTH *
+ ELFTC_STRING_TABLE_EXPECTED_STRING_SIZE);
+
+ tablesize = sizeof(struct _Elftc_String_Table) +
+ nbuckets * sizeof(struct _Elftc_String_Table_Bucket);
+
+ if ((st = malloc(tablesize)) == NULL)
+ return (NULL);
+ if ((st->st_string_pool = malloc(sizehint)) == NULL) {
+ free(st);
+ return (NULL);
+ }
+
+ for (n = 0; n < nbuckets; n++)
+ SLIST_INIT(&st->st_buckets[n]);
+
+ st->st_len = 0;
+ st->st_nbuckets = nbuckets;
+ st->st_string_pool_size = sizehint;
+ *st->st_string_pool = '\0';
+ ELFTC_STRING_TABLE_UPDATE_LENGTH(st, 1);
+
+ return (st);
+}
+
+void
+elftc_string_table_destroy(Elftc_String_Table *st)
+{
+ int n;
+ struct _Elftc_String_Table_Entry *s, *t;
+
+ for (n = 0; n < st->st_nbuckets; n++)
+ SLIST_FOREACH_SAFE(s, &st->st_buckets[n], ste_next, t)
+ free(s);
+ free(st->st_string_pool);
+ free(st);
+
+ return;
+}
+
+Elftc_String_Table *
+elftc_string_table_from_section(Elf_Scn *scn, int sizehint)
+{
+ int len;
+ Elf_Data *d;
+ GElf_Shdr sh;
+ const char *s, *end;
+ Elftc_String_Table *st;
+
+ /* Verify the type of the section passed in. */
+ if (gelf_getshdr(scn, &sh) == NULL ||
+ sh.sh_type != SHT_STRTAB) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((d = elf_getdata(scn, NULL)) == NULL ||
+ d->d_size == 0) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((st = elftc_string_table_create(sizehint)) == NULL)
+ return (NULL);
+
+ s = d->d_buf;
+
+ /*
+ * Verify that the first byte of the data buffer is '\0'.
+ */
+ if (*s != '\0') {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ end = s + d->d_size;
+
+ /*
+ * Skip the first '\0' and insert the strings in the buffer,
+ * in order.
+ */
+ for (s += 1; s < end; s += len) {
+ if (elftc_string_table_insert(st, s) == 0)
+ goto fail;
+
+ len = strlen(s) + 1; /* Include space for the trailing NUL. */
+ }
+
+ return (st);
+
+fail:
+ if (st)
+ (void) elftc_string_table_destroy(st);
+
+ return (NULL);
+}
+
+const char *
+elftc_string_table_image(Elftc_String_Table *st, size_t *size)
+{
+ char *r, *s, *end;
+ struct _Elftc_String_Table_Entry *ste;
+ struct _Elftc_String_Table_Bucket *head;
+ int copied, hashindex, offset, length, newsize;
+
+ /*
+ * For the common case of a string table has not seen
+ * a string deletion, we can just export the current
+ * pool.
+ */
+ if ((st->st_len & ELFTC_STRING_TABLE_COMPACTION_FLAG) == 0) {
+ if (size)
+ *size = ELFTC_STRING_TABLE_LENGTH(st);
+ return (st->st_string_pool);
+ }
+
+ /*
+ * Otherwise, compact the string table in-place.
+ */
+ assert(*st->st_string_pool == '\0');
+
+ newsize = 1;
+ end = st->st_string_pool + ELFTC_STRING_TABLE_LENGTH(st);
+
+ for (r = s = st->st_string_pool + 1;
+ s < end;
+ s += length, r += copied) {
+
+ copied = 0;
+ length = strlen(s) + 1;
+
+ ste = elftc_string_table_find_hash_entry(st, s,
+ &hashindex);
+ head = &st->st_buckets[hashindex];
+
+ assert(ste != NULL);
+
+ /* Ignore deleted strings. */
+ if (ste->ste_idx < 0) {
+ SLIST_REMOVE(head, ste, _Elftc_String_Table_Entry,
+ ste_next);
+ free(ste);
+ continue;
+ }
+
+ /* Move 'live' strings up. */
+ offset = newsize;
+ newsize += length;
+ copied = length;
+
+ if (r == s) /* Nothing removed yet. */
+ continue;
+
+ memmove(r, s, copied);
+
+ /* Update the index for this entry. */
+ ste->ste_idx = offset;
+ }
+
+ ELFTC_STRING_TABLE_CLEAR_COMPACTION_FLAG(st);
+ ELFTC_STRING_TABLE_UPDATE_LENGTH(st, newsize);
+
+ if (size)
+ *size = newsize;
+
+ return (st->st_string_pool);
+}
+
+size_t
+elftc_string_table_insert(Elftc_String_Table *st, const char *string)
+{
+ int hashindex, idx;
+ struct _Elftc_String_Table_Entry *ste;
+
+ hashindex = 0;
+
+ ste = elftc_string_table_find_hash_entry(st, string, &hashindex);
+
+ assert(hashindex >= 0 && hashindex < st->st_nbuckets);
+
+ if (ste == NULL) {
+ if ((ste = malloc(sizeof(*ste))) == NULL)
+ return (0);
+ if ((ste->ste_idx = elftc_string_table_add_to_pool(st,
+ string)) == 0) {
+ free(ste);
+ return (0);
+ }
+
+ SLIST_INSERT_HEAD(&st->st_buckets[hashindex], ste, ste_next);
+ }
+
+ idx = ste->ste_idx;
+ if (idx < 0) /* Undelete. */
+ ste->ste_idx = idx = (- idx);
+
+ return (idx);
+}
+
+size_t
+elftc_string_table_lookup(Elftc_String_Table *st, const char *string)
+{
+ int hashindex, idx;
+ struct _Elftc_String_Table_Entry *ste;
+
+ ste = elftc_string_table_find_hash_entry(st, string, &hashindex);
+
+ assert(hashindex >= 0 && hashindex < st->st_nbuckets);
+
+ if (ste == NULL || (idx = ste->ste_idx) < 0)
+ return (0);
+
+ return (idx);
+}
+
+int
+elftc_string_table_remove(Elftc_String_Table *st, const char *string)
+{
+ int idx;
+ struct _Elftc_String_Table_Entry *ste;
+
+ ste = elftc_string_table_find_hash_entry(st, string, NULL);
+
+ if (ste == NULL || (idx = ste->ste_idx) < 0)
+ return (ELFTC_FAILURE);
+
+ assert(idx > 0 && idx < (int) ELFTC_STRING_TABLE_LENGTH(st));
+
+ ste->ste_idx = (- idx);
+
+ ELFTC_STRING_TABLE_SET_COMPACTION_FLAG(st);
+
+ return (ELFTC_SUCCESS);
+}
+
+const char *
+elftc_string_table_to_string(Elftc_String_Table *st, size_t offset)
+{
+ const char *s;
+
+ s = st->st_string_pool + offset;
+
+ /*
+ * Check for:
+ * - An offset value within pool bounds.
+ * - A non-NUL byte at the specified offset.
+ * - The end of the prior string at offset - 1.
+ */
+ if (offset == 0 || offset >= ELFTC_STRING_TABLE_LENGTH(st) ||
+ *s == '\0' || *(s - 1) != '\0') {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (s);
+}
diff --git a/contrib/elftoolchain/libelftc/elftc_string_table_create.3 b/contrib/elftoolchain/libelftc/elftc_string_table_create.3
new file mode 100644
index 0000000..e11e73c
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_string_table_create.3
@@ -0,0 +1,227 @@
+.\" Copyright (c) 2012-2013 Joseph Koshy.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_string_table_create.3 2866 2013-01-06 03:20:14Z jkoshy $
+.\"
+.Dd January 5, 2013
+.Os
+.Dt ELFTC_STRING_TABLE_CREATE 3
+.Sh NAME
+.Nm elftc_string_table_create ,
+.Nm elftc_string_table_destroy ,
+.Nm elftc_string_table_from_section ,
+.Nm elftc_string_table_image ,
+.Nm elftc_string_table_insert ,
+.Nm elftc_string_table_lookup ,
+.Nm elftc_string_table_remove ,
+.Nm elftc_string_table_to_string
+.Nd convenience routines for handling ELF string tables
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft "Elftc_String_Table *"
+.Fn elftc_string_table_create "int sizehint"
+.Ft int
+.Fn elftc_string_table_destroy "Elftc_String_Table *table"
+.Ft "Elftc_String_Table *"
+.Fn elftc_string_table_from_section "Elf_Scn *scn" "int sizehint"
+.Ft "const char *"
+.Fo elftc_string_table_image
+.Fa "Elftc_String_Table *table"
+.Fa "size_t *size"
+.Fc
+.Ft size_t
+.Fo elftc_string_table_insert
+.Fa "Elftc_String_Table *table"
+.Fa "const char *string"
+.Fc
+.Ft size_t
+.Fo elftc_string_table_lookup
+.Fa "Elftc_String_Table *table"
+.Fa "const char *string"
+.Fc
+.Ft int
+.Fo elftc_string_table_remove
+.Fa "Elftc_String_Table *table"
+.Fa "const char *string"
+.Fc
+.Ft "const char *"
+.Fo elftc_string_table_to_string
+.Fa "Elftc_String_Table *table"
+.Fa "size_t offset"
+.Fc
+.Sh DESCRIPTION
+This manual page documents convenience routines for handling ELF
+string tables.
+.Pp
+Function
+.Fn elftc_string_table_create
+creates a new, empty string table.
+The argument
+.Ar sizehint
+provides a hint about the expected number of bytes of string data in
+the table.
+If the argument
+.Ar sizehint
+is zero, an implementation-defined default will be used instead.
+.Pp
+Function
+.Fn elftc_string_table_destroy
+destroys the previously allocated string table specified by
+argument
+.Ar table ,
+and frees the internal resources allocated for it.
+.Pp
+Function
+.Fn elftc_string_table_from_section
+creates a new string table and initializes it based on the
+contents of the section specified by argument
+.Ar scn .
+This section must be of type
+.Dv SHT_STRTAB .
+The argument
+.Ar sizehint
+provides a hint about expected number of bytes of string data in the
+table.
+If the value of
+.Ar sizehint
+is zero, an implementation-default will be used instead.
+.Pp
+Function
+.Fn elftc_string_table_image
+returns a pointer to the ELF representation of the contents of the
+string table specified by argument
+.Ar table .
+If argument
+.Ar size
+is not NULL, the size of the ELF representation of the string table is
+stored in the location pointed to by argument
+.Ar size .
+The function
+.Fn elftc_string_table_image
+will compact the string table if the table contains deleted strings.
+The string offsets returned by prior calls to
+.Fn elftc_string_table_insert
+and
+.Fn elftc_string_table_lookup
+should be treated as invalid after a call to this function.
+.Pp
+Function
+.Fn elftc_string_table_insert
+inserts the NUL-terminated string pointed to by argument
+.Ar string
+into the string table specified by argument
+.Ar table ,
+and returns an offset value usable in ELF data structures.
+Multiple insertions of the same content will return the same offset.
+The offset returned will remain valid until the next call to
+.Fn elftc_string_table_image .
+.Pp
+Function
+.Fn elftc_string_table_lookup
+looks up the string referenced by argument
+.Ar string
+in the string table specified by argument
+.Ar table ,
+and if found, returns the offset associated with the string.
+The returned offset will be valid till the next call to function
+.Fn elftc_string_table_image .
+.Pp
+Function
+.Fn elftc_string_table_remove
+removes the string pointed by argument
+.Ar string
+from the string table referenced by argument
+.Ar table ,
+if it is present in the string table.
+.Pp
+Function
+.Fn elftc_string_table_to_string
+returns a pointer to the NUL-terminated string residing at argument
+.Ar offset
+in the string table specified by argument
+.Ar table .
+The value of argument
+.Ar offset
+should be one returned by a prior call to
+.Fn elftc_string_table_insert
+or
+.Fn elftc_string_table_lookup .
+The returned pointer will remain valid until the next call to
+.Fn elftc_string_table_insert
+or
+.Fn elftc_string_table_image .
+.Ss Memory Management
+The
+.Lb libelftc
+library manages its own memory allocations.
+The application should not free the pointers returned by the string
+table functions.
+.El
+.Sh IMPLEMENTATION NOTES
+The current implementation is optimized for the case where strings are
+added to a string table, but rarely removed from it.
+.Pp
+The functions
+.Fn elftc_string_table_insert ,
+.Fn elftc_string_table_lookup ,
+.Fn elftc_string_table_remove
+and
+.Fn elftc_string_table_to_string
+have O(1) asymptotic behavior.
+The function
+.Fn elftc_string_table_image
+can have O(size) asymptotic behavior, where
+.Ar size
+denotes the size of the string table.
+.Sh RETURN VALUES
+Functions
+.Fn elftc_string_table_create
+and
+.Fn elftc_string_table_from_section
+return a valid pointer to an opaque structure of type
+.Vt Elftc_String_Table
+on success, or NULL in case of an error.
+.Pp
+The function
+.Fn elftc_string_table_image
+returns a pointer to an in-memory representation of an ELF string
+table on success, or NULL in case of an error.
+.Pp
+Functions
+.Fn elftc_string_table_insert
+and
+.Fn elftc_string_table_lookup
+return a non-zero offset on success, or zero in case of an error.
+.Pp
+Function
+.Fn elftc_string_table_remove
+returns a positive value on success, or zero in case of an error.
+.Pp
+Function
+.Fn elftc_string_table_to_string
+returns a valid pointer on success, or NULL in case of an error.
+.Sh SEE ALSO
+.Xr dwarf 3 ,
+.Xr elf 3 ,
+.Xr elftc 3
diff --git a/contrib/elftoolchain/libelftc/elftc_symbol_table_create.3 b/contrib/elftoolchain/libelftc/elftc_symbol_table_create.3
new file mode 100644
index 0000000..3ff2c35
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_symbol_table_create.3
@@ -0,0 +1,529 @@
+.\" Copyright (c) 2012 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_symbol_table_create.3 2825 2012-12-29 14:25:33Z jkoshy $
+.\"
+.Dd December 29, 2012
+.Os
+.Dt ELFTC_SYMBOL_TABLE_CREATE 3
+.Sh NAME
+.Nm elftc_elf_symbol_table_from_section ,
+.Nm elftc_symbol_table_count ,
+.Nm elftc_symbol_table_create ,
+.Nm elftc_symbol_table_create_nested ,
+.Nm elftc_symbol_table_delete_name ,
+.Nm elftc_symbol_table_delete_entry ,
+.Nm elftc_symbol_table_destroy ,
+.Nm elftc_symbol_table_insert ,
+.Nm elftc_symbol_table_iterate ,
+.Nm elftc_symbol_table_lookup ,
+.Nm elftc_symbol_table_lookup_value ,
+.Nm elftc_symbol_table_replace ,
+.Nm elftc_symbol_table_sort ,
+.Nm elftc_symbol_table_step
+.Nd symbol table management routines
+.Sh SYNOPSIS
+.In libelftc.h
+.Bd -literal
+typedef struct _Elftc_Symbol_Table Elftc_Symbol_Table;
+
+typedef struct _Elftc_Symbol {
+ ... library private fields ...
+ const char *sym_name;
+ uintptr_t sym_value;
+} Elftc_Symbol;
+.Ed
+.Ft size_t
+.Fn elftc_symbol_table_count "Elftc_Symbol_Table *table"
+.Ft "Elftc_Symbol_Table *"
+.Fo elftc_symbol_table_create
+.Fa "size_t entrysize"
+.Fa "int sizehint"
+.Fc
+.Ft "Elftc_Symbol_Table *"
+.Fo elftc_symbol_table_create_nested
+.Fa "Elftc_Symbol_Table *table"
+.Fa "int sizehint"
+.Fc
+.Ft int
+.Fo elftc_symbol_table_delete_name
+.Fa "Elftc_Symbol_Table *table"
+.Fa "const char *name"
+.Fc
+.Ft int
+.Fo elftc_symbol_table_delete_entry
+.Fa "Elftc_Symbol_Table *table"
+.Fa "Elftc_Symbol *entry"
+.Fc
+.Ft int
+.Fn elftc_symbol_table_destroy "Elftc_Symbol_Table *table"
+.Ft "Elftc_Symbol *entry"
+.Fo elftc_symbol_table_insert
+.Fa "Elftc_Symbol_Table *table"
+.Fa "const char *symbolname"
+.Fa "int *status"
+.Fc
+.Ft int
+.Fo elftc_symbol_table_iterate
+.Fa "Elftc_Symbol_Table *table"
+.Fa "int (*iterfn)(Elftc_Symbol *entry, void *cookie)"
+.Fa "void *cookie"
+.Fc
+.Ft "Elftc_Symbol *"
+.Fo elftc_symbol_table_lookup
+.Fa "Elftc_Symbol_Table *table"
+.Fa "const char *symbolname"
+.Fc
+.Ft "Elftc_Elf_Symbol *"
+.Fo elftc_symbol_table_lookup_value
+.Fa "Elftc_Symbol_Table *table"
+.Fa "uintptr_t value"
+.Fa "int searchflags"
+.Fc
+.Ft int
+.Fo elftc_symbol_table_replace
+.Fa "Elftc_Symbol_Table *table"
+.Fa "Elftc_Symbol *sym1"
+.Fa "Elftc_Symbol *sym2"
+.Fc
+.Ft int
+.Fo elftc_symbol_table_sort
+.Fa "Elftc_Symbol_Table *table"
+.Fa "int (*cmpfn)(Elftc_Symbol *s1, Elftc_Symbol *s2)"
+.Fc
+.Ft "Elftc_Symbol *"
+.Fo elftc_symbol_table_step
+.Fa "Elftc_Symbol_Table *table"
+.Fa "Elftc_Symbol *cursym"
+.Fa "int direction"
+.Fc
+.Bd -literal
+typedef struct _Elftc_Elf_Symbol {
+ ... library private fields ...
+ const char *sym_name;
+ Gelf_Sym sym_elf;
+} Elftc_Elf_Symbol;
+.Ed
+.Ft "Elftc_Symbol_Table *"
+.Fo elftc_elf_symbol_table_from_section
+.Fa "Elf_Scn *symscn"
+.Fa "Elf_Scn *strscn"
+.Fc
+.Sh DESCRIPTION
+This manual page documents convenience routines for handling symbol
+tables.
+Two flavors of symbol tables are supported:
+.Bl -bullet -compact
+.It
+.Dq Regular
+symbol tables supporting insertion, deletion and lookup of entries by
+name or by value, sorting of entries, and stepping through entries in
+the table's current traversal order.
+.It
+.Dq ELF-centric
+symbol tables support additional operations for conversions to and
+from the symbol table format understood by
+.Lb libelf .
+.El
+The default traversal order for a symbol table is the order in which
+entries were inserted into it.
+This traversal order may be changed using function
+.Fn elftc_symbol_table_sort .
+.Ss Operations on Regular Symbol Tables
+Regular symbol tables use symbols that are subtypes of
+.Vt Elftc_Symbol ,
+as described in the section
+.Sx "Structure of a Symbol Table Entry"
+below.
+.Pp
+Function
+.Fn elftc_symbol_table_count
+returns the number of entries currently in the symbol table.
+.Pp
+Function
+.Fn elftc_symbol_table_create
+creates a new, empty symbol table.
+The argument
+.Ar entrysize
+specifies the size of each symbol table entry, as described
+in the section
+.Sx "Structure of a Symbol Table Entry"
+below.
+The argument
+.Ar sizehint
+specifies the expected number of symbol table entries.
+If
+.Ar sizehint
+is zero, an implementation-defined default will be used.
+.Pp
+Function
+.Fn elftc_symbol_table_create_nested
+creates a symbol table whose search scope nests inside that of a
+parent symbol table.
+The argument
+.Ar parent
+specifies the parent symbol table to nest under.
+The argument
+.Ar sizehint
+specifies the expected number of symbol table entries.
+If
+.Ar sizehint
+is zero, an implementation-defined default will be used instead.
+.Pp
+The function
+.Fn elftc_symbol_table_delete_name
+removes the symbol entry named by the argument
+.Ar name
+from the symbol table specified by argument
+.Ar table ,
+according to the rules described in section
+.Sx "Symbol Search Rules" .
+.Pp
+The function
+.Fn elftc_symbol_table_delete_entry
+removes the symbol table entry specified by argument
+.Ar entry
+from the symbol table specified by argument
+.Ar table .
+.Pp
+Function
+.Fn elftc_symbol_table_destroy
+is used to destroy a symbol table and free up its internal
+resources.
+.Pp
+The function
+.Fn elftc_symbol_table_insert
+inserts a symbol entry for the name specified by argument
+.Ar symbolname
+into the symbol table specified by argument
+.Ar table ,
+returning a pointer to a symbol table entry.
+The argument
+.Ar status
+should point to a location that will be updated with one of
+the following values:
+.Bl -tag -width indent -compact -offset indent
+.It Dv ELFTC_INSERT_ERROR
+An error occured during insertion of the symbol.
+.It Dv ELFTC_INSERT_EXISTING
+The name in argument
+.Ar symbolname
+was already in the symbol table, and a pointer to the existing
+symbol table entry is being returned.
+.It Dv ELFTC_INSERT_NEW
+A new symbol table entry was allocated for the symbol name
+in
+.Ar symbolname .
+The application will need to initialize the application-specific
+fields of the symbol table entry.
+.El
+Insertion obeys the scoping rules described in section
+.Sx "Symbol Search Rules" .
+.Pp
+The function
+.Fn elftc_symbol_table_iterate
+iterates over the symbol table specifed by argument
+.Ar table ,
+applying the function pointed to by argument
+.Ar iterfn
+to each symbol table entry.
+The return value from the function
+.Ar iterfn
+controls progress of the iteration:
+.Bl -tag -width indent -compact -offset indent
+.It Dv ELFTC_ITERATE_ABORT
+Terminates the iteration.
+.It Dv ELFTC_ITERATE_CONTINUE
+Iteration will continue on to the next element in the symbol table.
+.El
+Argument
+.Ar cookie
+will be passed to each invocation of
+.Ar iterfn ,
+and may be used to track persistent state.
+The ordering of symbol table entries presented to function
+.Ar iterfn
+is not defined.
+The behavior of the iteration is undefined if
+.Ar iterfn
+adds or deletes symbol entries from a symbol table that currently
+being iterated through.
+.Pp
+Function
+.Fn elftc_symbol_table_lookup
+returns the symbol entry corresponding to the name of the symbol
+in argument
+.Ar symbolname .
+.Pp
+Function
+.Fn elftc_symbol_table_lookup_value
+returns the symbol entry that has a
+.Va sym_value
+field that is closest to the value specified in argument
+.Ar value .
+The argument
+.Ar table
+should point to a symbol table, that has been sorted
+by a prior call to
+.Fn elftc_symbol_table_sort .
+The argument
+.Ar searchflags
+can be a combination of the following flags:
+.Bl -tag -width indent -compact -offset indent
+.It Dv ELFTC_SEARCH_FORWARD
+Find the symbol entry with the next higher value in its
+.Va sym_value
+field.
+.It Dv ELFTC_SEARCH_BACKWARD
+Find the symbol entry with next lower value in its
+.Va sym_value
+field.
+.El
+If both
+.Dv ELFTC_SEARCH_FORWARD
+and
+.Dv ELFTC_SEARCH_BACKWARD
+are specified, then this function will return the symbol that is
+closest to the argument
+.Ar value .
+.Pp
+Function
+.Fn elftc_symbol_table_replace
+moves the symbol table entry pointed to by argument
+.Ar sym2
+into the traversal position for the entry pointed to by
+.Ar sym1 ,
+and implicitly deletes the entry pointed to by argument
+.Ar sym1 .
+Argument
+.Ar table
+should point to a valid symbol table.
+.Pp
+Function
+.Fn elftc_symbol_table_sort
+is used to define an ordering of symbol entries in a symbol
+table.
+This ordering will be associated with the symbol table till the next
+call to function
+.Fn elftc_symbol_table_insert ,
+.Fn elftc_symbol_table_delete_name
+or
+.Fn elftc_symbol_table_delete_entry .
+The argument
+.Ar cmpfn
+should point to a function that compares two symbol entries pointed
+to by
+.Ar s1
+and
+.Ar s2
+and returns -1, 0, or 1, depending whether
+.Ar s1
+is less, equal to, or greater than
+.Ar s2
+respectively.
+.Pp
+Function
+.Fn elftc_symbol_table_step
+is used to step to the next symbol in a sorted symbol table.
+Argument
+.Ar table
+should point to a symbol table.
+The argument
+.Ar cursym
+specifies the current symbol.
+The argument
+.Ar direction
+specifies the direction to step:
+.Bl -tag -width indent -compact -offset ident
+.It Dv ELFTC_STEP_NEXT
+Return the symbol which follows the argument
+.Ar cursym
+in the current traversal order.
+If argument
+.Ar cursym
+is NULL, return the first symbol in the current
+traversal order.
+.It Dv ELFTC_STEP_PREVIOUS
+Return the symbol which precedes the argument
+.Ar cursym
+in the current traversal order.
+If argument
+.Ar cursym
+is NULL, return the last symbol in the current
+traversal order.
+.El
+.Ss Operations on ELF-centric symbol tables
+ELF-centric symbol tables use symbols that are subtypes of
+.Vt Elftc_Elf_Symbol ,
+as described in the section
+.Sx "Structure of a Symbol Table Entry"
+below.
+.Pp
+In addition to the operations on regular symbol tables listed above,
+these symbol tables may be used with the following additional
+functions.
+.Pp
+The function
+.Fn elftc_elf_symbol_table_from_section
+builds a symbol table from the contents of an ELF section.
+The argument
+.Ar symscn
+should reference an ELF section of type
+.Dv SHT_SYMTAB
+or
+.Dv SHT_DYNSYM .
+The argument
+.Ar strscn
+should reference an ELF section of type
+.Dv SHT_STRTAB
+containing the string table associated wit section
+.Ar symscn .
+.Ss Structure of a Symbol Table Entry
+The symbol tables managed by
+.Lb libelftc
+are collections of symbol table entries.
+Each entry should be a subtype of one of the
+.Vt Elftc_Symbol
+or
+.Vt Elftc_Elf_Symbol
+types.
+In other words, each entry should have an
+.Vt Elftc_Symbol
+or
+.Vt Elftc_Elf_Symbol
+structure as its first member, before any application specific
+fields.
+For example:
+.Bd -literal -offset indent
+struct _MySymbol {
+ Elftc_Symbol sym_base;
+ ... other application-specific fields ...
+};
+.Ed
+.Pp
+The size of the combined entry is indicated to the library
+at the time of creating a new symbol table.
+Applications may then cast the returned pointers from these
+routines to the appropriate type:
+.Bd -literal -offset indent
+struct _MySymbol *mysym;
+
+mysym = (struct _MySymbol *) elftc_symbol_table_lookup(table,
+ name);
+.Ed
+.Pp
+The
+.Vt Elftc_Symbol
+type has two public fields:
+.Bl -tag -width ".Va sym_value" -compact -offset indent
+.It Va sym_name
+Points to a NUL-terminated string containing the symbol's name.
+The application should not change the value of this field.
+.It Va sym_value
+The value associated with this symbol.
+This field is entirely under the application's control.
+.El
+.Pp
+The
+.Vt Elftc_Elf_Symbol
+type has two public fields:
+.Bl -tag -width ".Va sym_value" -compact -offset indent
+.It Va sym_name
+Points to a NUL-terminated string containing the symbol's name.
+The application should not change the value of this field.
+.It Va sym_elf
+A structure of type
+.Vt Gelf_Sym
+containing ELF symbol information.
+This field is entirely under the application's control.
+.El
+.Ss Symbol Search Rules
+During lookups, symbols are looked up first in the symbol table passed in
+to the
+.Fn elftc_symbol_table_lookup
+function.
+If the specified symbol is not found, and if the symbol table has a
+parent, then the search continues recursively up the chain of parent
+symbol tables till either a matching symbol is found or till there are
+no more parent symbol tables to search in.
+.Pp
+Insertions and deletion only work on the specified symbol table and
+do not recurse into parent symbol tables.
+.Ss Memory Management
+The
+.Lb libelftc
+manages its memory allocations.
+Applications should not free the pointers returned by the
+API documented in this manual page.
+.Sh RETURN VALUES
+Function
+.Fn elftc_symbol_table_count
+returns a count of the number of symbol table entries as an unsigned
+value.
+.Pp
+Functions
+.Fn elftc_symbol_table_create ,
+.Fn elftc_symbol_table_create_nested
+and
+.Fn elftc_symbol_table_from_section
+return a pointer to an opaque structure of type
+.Vt Elftc_Symbol_Table
+on success, or return NULL in case of an error.
+.Pp
+Functions
+.Fn elftc_symbol_table_delete_name ,
+.Fn elftc_symbol_table_delete_name
+.Fn elftc_symbol_table_destroy ,
+.Fn elftc_symbol_table_replace
+and
+.Fn elftc_symbol_table_sort
+return a non-zero value on success, or return zero in case of an error.
+.Pp
+Functions
+.Fn elftc_symbol_table_insert ,
+.Fn elftc_symbol_table_lookup
+and
+.Fn elftc_symbol_table_lookup_value
+return a pointer to a structure that is a subtype of
+.Vt Elftc_Symbol
+on success, or return NULL in case of an error.
+.Pp
+The function
+.Fn elftc_symbol_table_step
+return a pointer to a structure that is a subtype of
+.Vt Elftc_Symbol
+on success.
+The function returns NULL if there are no more elements in the
+specified traversal direction.
+.Pp
+The function
+.Fn elftc_symbol_table_iterate
+returns
+.Dv ELFTC_ITERATE_SUCCESS
+if the symbol table was successfully traversed, or
+.Dv ELFTC_ITERATE_ABORT
+in case the iteration function aborted the traversal.
+.Sh SEE ALSO
+.Xr dwarf 3 ,
+.Xr elf 3 ,
+.Xr elftc 3
diff --git a/contrib/elftoolchain/libelftc/elftc_version.3 b/contrib/elftoolchain/libelftc/elftc_version.3
new file mode 100644
index 0000000..f7018a5
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/elftc_version.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2011,2012 Joseph Koshy. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. 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.
+.\"
+.\" This software is provided by Joseph Koshy ``as is'' and
+.\" any express or implied warranties, including, but not limited to, the
+.\" implied warranties of merchantability and fitness for a particular purpose
+.\" are disclaimed. in no event shall Joseph Koshy be liable
+.\" for any direct, indirect, incidental, special, exemplary, or consequential
+.\" damages (including, but not limited to, procurement of substitute goods
+.\" or services; loss of use, data, or profits; or business interruption)
+.\" however caused and on any theory of liability, whether in contract, strict
+.\" liability, or tort (including negligence or otherwise) arising in any way
+.\" out of the use of this software, even if advised of the possibility of
+.\" such damage.
+.\"
+.\" $Id: elftc_version.3 2828 2012-12-30 04:41:27Z jkoshy $
+.\"
+.Dd December 30, 2012
+.Os
+.Dt ELFTC_VERSION 3
+.Sh NAME
+.Nm elftc_version
+.Nd return a project-wide version identifier string
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft const char *
+.Fn elftc_version void
+.Sh DESCRIPTION
+Function
+.Fn elftc_version
+returns a project-wide identifier string that encodes the source
+revision of the project source tree.
+.Pp
+The returned identifier has four space-separated fields:
+.Bl -tag -width ".Em Project Branch"
+.It Em "Project-Name"
+This is always
+.Dq elftoolchain .
+.It Em "Project-Branch"
+The branch name for the project source tree.
+.It Em "Build-OS"
+The operating system that the tool chain was compiled for.
+.It Em "Version-Number"
+A tree-wide version number extracted from the version control
+system in use.
+.El
+.Sh RETURN VALUE
+Function
+.Fn elftc_program_version
+returns a pointer to an internal character buffer.
+.Sh EXAMPLES
+To retrieve and print the current toolchain version identifier, use:
+.Bd -literal -offset indent
+#include <sys/types.h>
+#include <libelftc.h>
+
+(void) printf("%s\en", elftc_version());
+.Ed
+.Pp
+On the HEAD branch of the project's sources, when checked out using
+Subversion and compiled on a NetBSD host, this would print:
+.D1 Dq elftoolchain HEAD NetBSD svn: Ns Em REVINFO
+where
+.Em REVINFO
+would be the current revision information for the project source tree.
+.Sh ERRORS
+Function
+.Fn elftc_program_version
+always succeeds.
diff --git a/contrib/elftoolchain/libelftc/libelftc.h b/contrib/elftoolchain/libelftc/libelftc.h
new file mode 100644
index 0000000..aa6b0b6
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc.h
@@ -0,0 +1,89 @@
+/*-
+ * Copyright (c) 2009 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: users/kaiwang27/elftc/libelftc.h 392 2009-05-31 19:17:46Z kaiwang27 $
+ * $Id: libelftc.h 2863 2013-01-06 03:18:32Z jkoshy $
+ */
+
+#ifndef _LIBELFTC_H_
+#define _LIBELFTC_H_
+
+#include <sys/stat.h>
+
+#include <libelf.h>
+
+typedef struct _Elftc_Bfd_Target Elftc_Bfd_Target;
+typedef struct _Elftc_String_Table Elftc_String_Table;
+
+/* Target types. */
+typedef enum {
+ ETF_NONE,
+ ETF_ELF,
+ ETF_BINARY,
+ ETF_SREC,
+ ETF_IHEX
+} Elftc_Bfd_Target_Flavor;
+
+/*
+ * Demangler flags.
+ */
+
+/* Name mangling style. */
+#define ELFTC_DEM_UNKNOWN 0x00000000U /* Not specified. */
+#define ELFTC_DEM_ARM 0x00000001U /* C++ Ann. Ref. Manual. */
+#define ELFTC_DEM_GNU2 0x00000002U /* GNU version 2. */
+#define ELFTC_DEM_GNU3 0x00000004U /* GNU version 3. */
+
+/* Demangling behaviour control. */
+#define ELFTC_DEM_NOPARAM 0x00010000U
+
+__BEGIN_DECLS
+Elftc_Bfd_Target *elftc_bfd_find_target(const char *_tgt_name);
+Elftc_Bfd_Target_Flavor elftc_bfd_target_flavor(Elftc_Bfd_Target *_tgt);
+unsigned int elftc_bfd_target_byteorder(Elftc_Bfd_Target *_tgt);
+unsigned int elftc_bfd_target_class(Elftc_Bfd_Target *_tgt);
+unsigned int elftc_bfd_target_machine(Elftc_Bfd_Target *_tgt);
+int elftc_copyfile(int _srcfd, int _dstfd);
+int elftc_demangle(const char *_mangledname, char *_buffer,
+ size_t _bufsize, unsigned int _flags);
+int elftc_set_timestamps(const char *_filename, struct stat *_sb);
+Elftc_String_Table *elftc_string_table_create(int _hint);
+void elftc_string_table_destroy(Elftc_String_Table *_table);
+Elftc_String_Table *elftc_string_table_from_section(Elf_Scn *_scn,
+ int _hint);
+const char *elftc_string_table_image(Elftc_String_Table *_table,
+ size_t *_sz);
+size_t elftc_string_table_insert(Elftc_String_Table *_table,
+ const char *_string);
+size_t elftc_string_table_lookup(Elftc_String_Table *_table,
+ const char *_string);
+int elftc_string_table_remove(Elftc_String_Table *_table,
+ const char *_string);
+const char *elftc_string_table_to_string(Elftc_String_Table *_table,
+ size_t offset);
+const char *elftc_version(void);
+__END_DECLS
+
+#endif /* _LIBELFTC_H_ */
diff --git a/contrib/elftoolchain/libelftc/libelftc_bfdtarget.c b/contrib/elftoolchain/libelftc/libelftc_bfdtarget.c
new file mode 100644
index 0000000..31c89b7
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_bfdtarget.c
@@ -0,0 +1,383 @@
+/*-
+ * Copyright (c) 2008,2009 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <libelf.h>
+#include <libelftc.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_bfdtarget.c 2251 2011-11-30 16:50:06Z jkoshy $");
+
+struct _Elftc_Bfd_Target _libelftc_targets[] = {
+
+ {
+ .bt_name = "binary",
+ .bt_type = ETF_BINARY,
+ },
+
+ {
+ .bt_name = "elf32-avr",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_AVR,
+ },
+
+ {
+ .bt_name = "elf32-big",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ },
+
+ {
+ .bt_name = "elf32-bigarm",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_ARM,
+ },
+
+ {
+ .bt_name = "elf32-bigmips",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_MIPS,
+ },
+
+ {
+ .bt_name = "elf32-i386",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_386,
+ },
+
+ {
+ .bt_name = "elf32-i386-freebsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_386,
+ .bt_osabi = ELFOSABI_FREEBSD,
+ },
+
+ {
+ .bt_name = "elf32-ia64-big",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_IA_64,
+ },
+
+ {
+ .bt_name = "elf32-little",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ },
+
+ {
+ .bt_name = "elf32-littlearm",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_ARM,
+ },
+
+ {
+ .bt_name = "elf32-littlemips",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_MIPS,
+ },
+
+ {
+ .bt_name = "elf32-powerpc",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_PPC,
+ },
+
+ {
+ .bt_name = "elf32-powerpcle",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_PPC,
+ },
+
+ {
+ .bt_name = "elf32-sh",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ },
+
+ {
+ .bt_name = "elf32-shl",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ },
+
+ {
+ .bt_name = "elf32-sh-nbsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_NETBSD,
+ },
+
+ {
+ .bt_name = "elf32-shl-nbsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_NETBSD,
+ },
+
+ {
+ .bt_name = "elf32-shbig-linux",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_LINUX,
+ },
+
+ {
+ .bt_name = "elf32-sh-linux",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_LINUX,
+ },
+
+ {
+ .bt_name = "elf32-sparc",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS32,
+ .bt_machine = EM_SPARC,
+ },
+
+ {
+ .bt_name = "elf64-alpha",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_ALPHA,
+ },
+
+ {
+ .bt_name = "elf64-alpha-freebsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_ALPHA,
+ .bt_osabi = ELFOSABI_FREEBSD
+ },
+
+ {
+ .bt_name = "elf64-big",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ },
+
+ {
+ .bt_name = "elf64-bigmips",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_MIPS,
+ },
+
+ {
+ .bt_name = "elf64-ia64-big",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_IA_64,
+ },
+
+ {
+ .bt_name = "elf64-ia64-little",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_IA_64,
+ },
+
+ {
+ .bt_name = "elf64-little",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ },
+
+ {
+ .bt_name = "elf64-littlemips",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_MIPS,
+ },
+
+ {
+ .bt_name = "elf64-powerpc",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_PPC64,
+ },
+
+ {
+ .bt_name = "elf64-powerpcle",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_PPC64,
+ },
+
+ {
+ .bt_name = "elf64-sh64",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ },
+
+ {
+ .bt_name = "elf64-sh64l",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ },
+
+ {
+ .bt_name = "elf64-sh64-nbsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_NETBSD,
+ },
+
+ {
+ .bt_name = "elf64-sh64l-nbsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_NETBSD,
+ },
+
+ {
+ .bt_name = "elf64-sh64big-linux",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_LINUX,
+ },
+
+ {
+ .bt_name = "elf64-sh64-linux",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SH,
+ .bt_osabi = ELFOSABI_LINUX,
+ },
+
+ {
+ .bt_name = "elf64-sparc",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SPARCV9,
+ },
+
+ {
+ .bt_name = "elf64-sparc-freebsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2MSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_SPARCV9,
+ .bt_osabi = ELFOSABI_FREEBSD
+ },
+
+ {
+ .bt_name = "elf64-x86-64",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_X86_64,
+ },
+
+ {
+ .bt_name = "elf64-x86-64-freebsd",
+ .bt_type = ETF_ELF,
+ .bt_byteorder = ELFDATA2LSB,
+ .bt_elfclass = ELFCLASS64,
+ .bt_machine = EM_X86_64,
+ .bt_osabi = ELFOSABI_FREEBSD
+ },
+
+ {
+ .bt_name = "ihex",
+ .bt_type = ETF_IHEX,
+ },
+
+ {
+ .bt_name = "srec",
+ .bt_type = ETF_SREC,
+ },
+
+ {
+ .bt_name = "symbolsrec",
+ .bt_type = ETF_SREC,
+ },
+
+ {
+ .bt_name = NULL,
+ .bt_type = ETF_NONE,
+ },
+};
diff --git a/contrib/elftoolchain/libelftc/libelftc_dem_arm.c b/contrib/elftoolchain/libelftc/libelftc_dem_arm.c
new file mode 100644
index 0000000..e850b8b
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_dem_arm.c
@@ -0,0 +1,1227 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libelftc.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_dem_arm.c 2065 2011-10-26 15:24:47Z jkoshy $");
+
+/**
+ * @file cpp_demangle_arm.c
+ * @brief Decode function name encoding in ARM.
+ *
+ * Function name encoding in "The Annotated C++ Reference Manual".
+ *
+ * Ref : "The Annotated C++ Reference Manual", Margaet A.Ellis,
+ * Bjarne Stroustrup, AT&T Bell Laboratories 1990, pp 122-126.
+ */
+
+enum encode_type {
+ ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER
+};
+
+struct cstring {
+ char *buf;
+ size_t size;
+};
+
+struct demangle_data {
+ bool ptr, ref, cnst, array;
+ struct cstring array_str;
+ const char *p;
+ enum encode_type type;
+ struct vector_str vec;
+ struct vector_str arg;
+};
+
+#define SIMPLE_HASH(x,y) (64 * x + y)
+#define CPP_DEMANGLE_ARM_TRY 128
+
+static void dest_cstring(struct cstring *);
+static void dest_demangle_data(struct demangle_data *);
+static bool init_cstring(struct cstring *, size_t);
+static bool init_demangle_data(struct demangle_data *);
+static bool push_CTDT(const char *, size_t, struct vector_str *);
+static bool read_array(struct demangle_data *);
+static bool read_class(struct demangle_data *);
+static bool read_func(struct demangle_data *);
+static bool read_func_name(struct demangle_data *);
+static bool read_func_ptr(struct demangle_data *);
+static bool read_memptr(struct demangle_data *);
+static bool read_op(struct demangle_data *);
+static bool read_op_user(struct demangle_data *);
+static bool read_qual_name(struct demangle_data *);
+static int read_subst(struct demangle_data *);
+static int read_subst_iter(struct demangle_data *);
+static bool read_type(struct demangle_data *);
+
+/**
+ * @brief Decode the input string by the ARM style.
+ *
+ * @return New allocated demangled string or NULL if failed.
+ */
+char *
+cpp_demangle_ARM(const char *org)
+{
+ struct demangle_data d;
+ size_t arg_begin, arg_len;
+ unsigned int try;
+ char *rtn, *arg;
+
+ if (org == NULL)
+ return (NULL);
+
+ if (init_demangle_data(&d) == false)
+ return (NULL);
+
+ try = 0;
+ rtn = NULL;
+
+ d.p = org;
+ if (read_func_name(&d) == false)
+ goto clean;
+
+ if (d.type == ENCODE_OP_CT) {
+ if (push_CTDT("::", 2, &d.vec) == false)
+ goto clean;
+
+ goto flat;
+ }
+
+ if (d.type == ENCODE_OP_DT) {
+ if (push_CTDT("::~", 3, &d.vec) == false)
+ goto clean;
+
+ goto flat;
+ }
+
+ if (d.type == ENCODE_OP_USER)
+ goto flat;
+
+ /* function type */
+ if (*d.p != 'F')
+ goto clean;
+ ++d.p;
+
+ /* start argument types */
+ if (vector_str_push(&d.vec, "(", 1) == false)
+ goto clean;
+
+ for (;;) {
+ if (*d.p == 'T') {
+ const int rtn_subst = read_subst(&d);
+
+ if (rtn_subst == -1)
+ goto clean;
+ else if (rtn_subst == 1)
+ break;
+
+ continue;
+ }
+
+ if (*d.p == 'N') {
+ const int rtn_subst_iter = read_subst_iter(&d);
+
+ if (rtn_subst_iter == -1)
+ goto clean;
+ else if(rtn_subst_iter == 1)
+ break;
+
+ continue;
+ }
+
+ arg_begin = d.vec.size;
+
+ if (read_type(&d) == false)
+ goto clean;
+
+ if (d.ptr == true) {
+ if (vector_str_push(&d.vec, "*", 1) == false)
+ goto clean;
+
+ d.ptr = false;
+ }
+
+ if (d.ref == true) {
+ if (vector_str_push(&d.vec, "&", 1) == false)
+ goto clean;
+
+ d.ref = false;
+ }
+
+ if (d.cnst == true) {
+ if (vector_str_push(&d.vec, " const", 6) == false)
+ goto clean;
+
+ d.cnst = false;
+ }
+
+ if (d.array == true) {
+ if (vector_str_push(&d.vec, d.array_str.buf,
+ d.array_str.size) == false)
+ goto clean;
+
+ dest_cstring(&d.array_str);
+ d.array = false;
+ }
+
+ if (*d.p == '\0')
+ break;
+
+ if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1,
+ &arg_len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d.arg, arg, arg_len) == false)
+ goto clean;
+
+ free(arg);
+
+ if (vector_str_push(&d.vec, ", ", 2) == false)
+ goto clean;
+
+ if (++try > CPP_DEMANGLE_ARM_TRY)
+ goto clean;
+ }
+
+ /* end argument types */
+ if (vector_str_push(&d.vec, ")", 1) == false)
+ goto clean;
+
+flat:
+ rtn = vector_str_get_flat(&d.vec, NULL);
+clean:
+ dest_demangle_data(&d);
+
+ return (rtn);
+}
+
+/**
+ * @brief Test input string is encoded by the ARM style.
+ *
+ * @return True if input string is encoded by the ARM style.
+ */
+bool
+is_cpp_mangled_ARM(const char *org)
+{
+
+ if (org == NULL)
+ return (false);
+
+ return (strstr(org, "__") != NULL);
+}
+
+static void
+dest_cstring(struct cstring *s)
+{
+
+ if (s == NULL)
+ return;
+
+ free(s->buf);
+ s->buf = NULL;
+ s->size = 0;
+}
+
+static void
+dest_demangle_data(struct demangle_data *d)
+{
+
+ if (d != NULL) {
+ vector_str_dest(&d->arg);
+ vector_str_dest(&d->vec);
+
+ dest_cstring(&d->array_str);
+ }
+}
+
+static bool
+init_cstring(struct cstring *s, size_t len)
+{
+
+ if (s == NULL || len <= 1)
+ return (false);
+
+ if ((s->buf = malloc(sizeof(char) * len)) == NULL)
+ return (false);
+
+ s->size = len - 1;
+
+ return (true);
+}
+
+static bool
+init_demangle_data(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ d->ptr = false;
+ d->ref = false;
+ d->cnst = false;
+ d->array = false;
+
+ d->array_str.buf = NULL;
+ d->array_str.size = 0;
+
+ d->type = ENCODE_FUNC;
+
+ if (vector_str_init(&d->vec) == false)
+ return (false);
+
+ if (vector_str_init(&d->arg) == false) {
+ vector_str_dest(&d->vec);
+
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+push_CTDT(const char *s, size_t l, struct vector_str *v)
+{
+
+ if (s == NULL || l == 0 || v == NULL)
+ return (false);
+
+ if (vector_str_push(v, s, l) == false)
+ return (false);
+
+ assert(v->size > 1);
+ if (vector_str_push(v, v->container[v->size - 2],
+ strlen(v->container[v->size - 2])) == false)
+ return (false);
+
+ if (vector_str_push(v, "()", 2) == false)
+ return (false);
+
+ return (true);
+}
+
+static bool
+read_array(struct demangle_data *d)
+{
+ size_t len;
+ const char *end;
+
+ if (d == NULL || d->p == NULL)
+ return (false);
+
+ end = d->p;
+ assert(end != NULL);
+
+ for (;;) {
+ if (*end == '\0')
+ return (false);
+
+ if (ELFTC_ISDIGIT(*end) == 0)
+ break;
+
+ ++end;
+ }
+
+ if (*end != '_')
+ return (false);
+
+ len = end - d->p;
+ assert(len > 0);
+
+ dest_cstring(&d->array_str);
+ if (init_cstring(&d->array_str, len + 3) == false)
+ return (false);
+
+ strncpy(d->array_str.buf + 1, d->p, len);
+ *d->array_str.buf = '[';
+ *(d->array_str.buf + len + 1) = ']';
+
+ d->array = true;
+ d->p = end + 1;
+
+ return (true);
+}
+
+static bool
+read_class(struct demangle_data *d)
+{
+ size_t len;
+ char *str;
+
+ if (d == NULL)
+ return (false);
+
+ len = strtol(d->p, &str, 10);
+ if (len == 0 && (errno == EINVAL || errno == ERANGE))
+ return (false);
+
+ assert(len > 0);
+ assert(str != NULL);
+
+ if (vector_str_push(&d->vec, str, len) == false)
+ return (false);
+
+ d->p = str + len;
+
+ return (true);
+}
+
+static bool
+read_func(struct demangle_data *d)
+{
+ size_t len;
+ const char *name;
+ char *delim;
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+ if ((delim = strstr(d->p, "__")) == NULL)
+ return (false);
+
+ len = delim - d->p;
+ assert(len != 0);
+
+ name = d->p;
+
+ d->p = delim + 2;
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ if (read_qual_name(d) == false)
+ return (false);
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ if (read_class(d) == false)
+ return (false);
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ return (false);
+ }
+
+ if (vector_str_push(&d->vec, name, len) == false)
+ return (false);
+
+ return (true);
+}
+
+static bool
+read_func_name(struct demangle_data *d)
+{
+ size_t len;
+ bool rtn;
+ char *op_name;
+
+ if (d == NULL)
+ return (false);
+
+ rtn = false;
+ op_name = NULL;
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ if (*d->p == '_' && *(d->p + 1) == '_') {
+ d->p += 2;
+
+ d->type = ENCODE_OP;
+ if (read_op(d) == false)
+ return (false);
+
+ if (d->type == ENCODE_OP_CT || d->type == ENCODE_OP_DT ||
+ d->type == ENCODE_OP_USER)
+ return (true);
+
+ /* skip "__" */
+ d->p += 2;
+
+ /* assume delimiter is removed */
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ assert(d->vec.size > 0);
+
+ len = strlen(d->vec.container[d->vec.size - 1]);
+ if ((op_name = malloc(sizeof(char) * (len + 1)))
+ == NULL)
+ return (false);
+
+ snprintf(op_name, len + 1, "%s",
+ d->vec.container[d->vec.size - 1]);
+ vector_str_pop(&d->vec);
+
+ if (read_qual_name(d) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, op_name, len) == false)
+ goto clean;
+
+ rtn = true;
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ assert(d->vec.size > 0);
+
+ len = strlen(d->vec.container[d->vec.size - 1]);
+ if ((op_name = malloc(sizeof(char) * (len + 1)))
+ == NULL)
+ return (false);
+
+ snprintf(op_name, len + 1, "%s",
+ d->vec.container[d->vec.size - 1]);
+ vector_str_pop(&d->vec);
+
+ if (read_class(d) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, op_name, len) == false)
+ goto clean;
+
+ rtn = true;
+ }
+ } else
+ return (read_func(d));
+
+clean:
+ free(op_name);
+
+ return (rtn);
+}
+
+/* Read function ptr type */
+static bool
+read_func_ptr(struct demangle_data *d)
+{
+ struct demangle_data fptr;
+ size_t arg_len, rtn_len;
+ char *arg_type, *rtn_type;
+ int lim;
+
+ if (d == NULL)
+ return (false);
+
+ if (init_demangle_data(&fptr) == false)
+ return (false);
+
+ fptr.p = d->p + 1;
+ lim = 0;
+ arg_type = NULL;
+ rtn_type = NULL;
+
+ for (;;) {
+ if (read_type(&fptr) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ if (fptr.ptr == true) {
+ if (vector_str_push(&fptr.vec, "*", 1) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.ptr = false;
+ }
+
+ if (fptr.ref == true) {
+ if (vector_str_push(&fptr.vec, "&", 1) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.ref = false;
+ }
+
+ if (fptr.cnst == true) {
+ if (vector_str_push(&fptr.vec, " const", 6) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.cnst = false;
+ }
+
+ if (*fptr.p == '_')
+ break;
+
+ if (vector_str_push(&fptr.vec, ", ", 2) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ if (++lim > CPP_DEMANGLE_ARM_TRY) {
+
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+ }
+
+ arg_type = vector_str_get_flat(&fptr.vec, &arg_len);
+ /* skip '_' */
+ d->p = fptr.p + 1;
+
+ dest_demangle_data(&fptr);
+
+ if (init_demangle_data(&fptr) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ fptr.p = d->p;
+ lim = 0;
+
+ if (read_type(&fptr) == false) {
+ free(arg_type);
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len);
+ d->p = fptr.p;
+
+
+ dest_demangle_data(&fptr);
+
+ if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) {
+ free(rtn_type);
+ free(arg_type);
+
+ return (false);
+ }
+
+ free(rtn_type);
+
+ if (vector_str_push(&d->vec, " (*)(", 5) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ if (vector_str_push(&d->vec, arg_type, arg_len) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ free(arg_type);
+
+ return (vector_str_push(&d->vec, ")", 1));
+}
+
+static bool
+read_memptr(struct demangle_data *d)
+{
+ struct demangle_data mptr;
+ size_t len;
+ bool rtn;
+ char *mptr_str;
+
+ if (d == NULL || d->p == NULL)
+ return (false);
+
+ if (init_demangle_data(&mptr) == false)
+ return (false);
+
+ rtn = false;
+ mptr_str = NULL;
+
+ mptr.p = d->p;
+ if (*mptr.p == 'Q') {
+ ++mptr.p;
+
+ if (read_qual_name(&mptr) == false)
+ goto clean;
+ } else {
+ if (read_class(&mptr) == false)
+ goto clean;
+ }
+
+ d->p = mptr.p;
+
+ if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d->vec, mptr_str, len) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::*", 3) == false)
+ goto clean;
+
+ rtn = true;
+clean:
+ free(mptr_str);
+ dest_demangle_data(&mptr);
+
+ return (rtn);
+}
+
+static bool
+read_op(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ switch (SIMPLE_HASH(*(d->p), *(d->p+1))) {
+ case SIMPLE_HASH('m', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator*", 9));
+ case SIMPLE_HASH('d', 'v') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator/", 9));
+ case SIMPLE_HASH('m', 'd') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator%", 9));
+ case SIMPLE_HASH('p', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator+", 9));
+ case SIMPLE_HASH('m', 'i') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator-", 9));
+ case SIMPLE_HASH('l', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<<", 10));
+ case SIMPLE_HASH('r', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>>", 10));
+ case SIMPLE_HASH('e', 'q') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator==", 10));
+ case SIMPLE_HASH('n', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator!=", 10));
+ case SIMPLE_HASH('l', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<", 9));
+ case SIMPLE_HASH('g', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>", 9));
+ case SIMPLE_HASH('l', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<=", 10));
+ case SIMPLE_HASH('g', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>=", 10));
+ case SIMPLE_HASH('a', 'd') :
+ d->p += 2;
+ if (*d->p == 'v') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator/=",
+ 10));
+ } else
+ return (vector_str_push(&d->vec, "operator&", 9));
+ case SIMPLE_HASH('o', 'r') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator|", 9));
+ case SIMPLE_HASH('e', 'r') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator^", 9));
+ case SIMPLE_HASH('a', 'a') :
+ d->p += 2;
+ if (*d->p == 'd') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator&=",
+ 10));
+ } else
+ return (vector_str_push(&d->vec, "operator&&",
+ 10));
+ case SIMPLE_HASH('o', 'o') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator||", 10));
+ case SIMPLE_HASH('n', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator!", 9));
+ case SIMPLE_HASH('c', 'o') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator~", 9));
+ case SIMPLE_HASH('p', 'p') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator++", 10));
+ case SIMPLE_HASH('m', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator--", 10));
+ case SIMPLE_HASH('a', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator=", 9));
+ case SIMPLE_HASH('r', 'f') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator->", 10));
+ case SIMPLE_HASH('a', 'p') :
+ /* apl */
+ if (*(d->p + 2) != 'l')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator+=", 10));
+ case SIMPLE_HASH('a', 'm') :
+ d->p += 2;
+ if (*d->p == 'i') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator-=",
+ 10));
+ } else if (*d->p == 'u') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator*=",
+ 10));
+ } else if (*d->p == 'd') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator%=",
+ 10));
+ }
+
+ return (false);
+ case SIMPLE_HASH('a', 'l') :
+ /* als */
+ if (*(d->p + 2) != 's')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator<<=", 11));
+ case SIMPLE_HASH('a', 'r') :
+ /* ars */
+ if (*(d->p + 2) != 's')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator>>=", 11));
+ case SIMPLE_HASH('a', 'o') :
+ /* aor */
+ if (*(d->p + 2) != 'r')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator|=", 10));
+ case SIMPLE_HASH('a', 'e') :
+ /* aer */
+ if (*(d->p + 2) != 'r')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator^=", 10));
+ case SIMPLE_HASH('c', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator,", 9));
+ case SIMPLE_HASH('r', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator->*", 11));
+ case SIMPLE_HASH('c', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "()", 2));
+ case SIMPLE_HASH('v', 'c') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "[]", 2));
+ case SIMPLE_HASH('c', 't') :
+ d->p += 4;
+ d->type = ENCODE_OP_CT;
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ return (read_qual_name(d));
+ } else if (ELFTC_ISDIGIT(*d->p))
+ return (read_class(d));
+
+ return (false);
+ case SIMPLE_HASH('d', 't') :
+ d->p += 4;
+ d->type = ENCODE_OP_DT;
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ return (read_qual_name(d));
+ } else if (ELFTC_ISDIGIT(*d->p))
+ return (read_class(d));
+
+ return (false);
+ case SIMPLE_HASH('n', 'w') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator new()", 14));
+ case SIMPLE_HASH('d', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator delete()",
+ 17));
+ case SIMPLE_HASH('o', 'p') :
+ /* __op<TO_TYPE>__<FROM_TYPE> */
+ d->p += 2;
+
+ d->type = ENCODE_OP_USER;
+
+ return (read_op_user(d));
+ default :
+ return (false);
+ };
+}
+
+static bool
+read_op_user(struct demangle_data *d)
+{
+ struct demangle_data from, to;
+ size_t from_len, to_len;
+ bool rtn;
+ char *from_str, *to_str;
+
+ if (d == NULL)
+ return (false);
+
+ if (init_demangle_data(&from) == false)
+ return (false);
+
+ rtn = false;
+ from_str = NULL;
+ to_str = NULL;
+ if (init_demangle_data(&to) == false)
+ goto clean;
+
+ to.p = d->p;
+ if (*to.p == 'Q') {
+ ++to.p;
+
+ if (read_qual_name(&to) == false)
+ goto clean;
+
+ /* pop last '::' */
+ if (vector_str_pop(&to.vec) == false)
+ goto clean;
+ } else {
+ if (read_class(&to) == false)
+ goto clean;
+
+ /* skip '__' */
+ to.p += 2;
+ }
+
+ if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL)
+ goto clean;
+
+ from.p = to.p;
+ if (*from.p == 'Q') {
+ ++from.p;
+
+ if (read_qual_name(&from) == false)
+ goto clean;
+
+ /* pop last '::' */
+ if (vector_str_pop(&from.vec) == false)
+ goto clean;
+ } else {
+ if (read_class(&from) == false)
+ goto clean;
+ }
+
+ if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d->vec, from_str, from_len) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::operator ", 11) == false)
+ return (false);
+
+ if (vector_str_push(&d->vec, to_str, to_len) == false)
+ goto clean;
+
+ rtn = vector_str_push(&d->vec, "()", 2);
+clean:
+ free(to_str);
+ free(from_str);
+ dest_demangle_data(&to);
+ dest_demangle_data(&from);
+
+ return (rtn);
+}
+
+/* single digit + class names */
+static bool
+read_qual_name(struct demangle_data *d)
+{
+ int i;
+ char num;
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+ assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
+
+ num = *d->p - 48;
+
+ assert(num > 0);
+
+ ++d->p;
+ for (i = 0; i < num ; ++i) {
+ if (read_class(d) == false)
+ return (false);
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ return (false);
+ }
+
+ if (*d->p != '\0')
+ d->p = d->p + 2;
+
+ return (true);
+}
+
+/* Return -1 at fail, 0 at success, and 1 at end */
+static int
+read_subst(struct demangle_data *d)
+{
+ size_t idx;
+ char *str;
+
+ if (d == NULL)
+ return (-1);
+
+ idx = strtol(d->p + 1, &str, 10);
+ if (idx == 0 && (errno == EINVAL || errno == ERANGE))
+ return (-1);
+
+ assert(idx > 0);
+ assert(str != NULL);
+
+ d->p = str;
+
+ if (vector_str_push(&d->vec, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (vector_str_push(&d->arg, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (*d->p == '\0')
+ return (1);
+
+ return (0);
+}
+
+static int
+read_subst_iter(struct demangle_data *d)
+{
+ int i;
+ size_t idx;
+ char repeat;
+ char *str;
+
+ if (d == NULL)
+ return (-1);
+
+ ++d->p;
+ assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
+
+ repeat = *d->p - 48;
+
+ assert(repeat > 1);
+
+ ++d->p;
+
+ idx = strtol(d->p, &str, 10);
+ if (idx == 0 && (errno == EINVAL || errno == ERANGE))
+ return (-1);
+
+ assert(idx > 0);
+ assert(str != NULL);
+
+ d->p = str;
+
+ for (i = 0; i < repeat ; ++i) {
+ if (vector_str_push(&d->vec, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (vector_str_push(&d->arg, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (i != repeat - 1 &&
+ vector_str_push(&d->vec, ", ", 2) == false)
+ return (-1);
+ }
+
+ if (*d->p == '\0')
+ return (1);
+
+ return (0);
+}
+
+static bool
+read_type(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' ||
+ *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' ||
+ *d->p == 'M') {
+ switch (*d->p) {
+ case 'U' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "unsigned ", 9) == false)
+ return (false);
+
+ break;
+ case 'C' :
+ ++d->p;
+
+ if (*d->p == 'P')
+ d->cnst = true;
+ else {
+ if (vector_str_push(&d->vec, "const ", 6) ==
+ false)
+ return (false);
+ }
+
+ break;
+ case 'V' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "volatile ", 9) == false)
+ return (false);
+
+ break;
+ case 'S' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "signed ", 7) == false)
+ return (false);
+
+ break;
+ case 'P' :
+ ++d->p;
+
+ if (*d->p == 'F')
+ return (read_func_ptr(d));
+ else
+ d->ptr = true;
+
+ break;
+ case 'R' :
+ ++d->p;
+
+ d->ref = true;
+
+ break;
+ case 'F' :
+ break;
+ case 'A' :
+ ++d->p;
+
+ if (read_array(d) == false)
+ return (false);
+
+ break;
+ case 'M' :
+ ++d->p;
+
+ if (read_memptr(d) == false)
+ return (false);
+
+ break;
+ default :
+ break;
+ };
+ };
+
+ if (ELFTC_ISDIGIT(*d->p))
+ return (read_class(d));
+
+ switch (*d->p) {
+ case 'Q' :
+ ++d->p;
+
+ return (read_qual_name(d));
+ case 'v' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "void", 4));
+ case 'c' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "char", 4));
+ case 's' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "short", 5));
+ case 'i' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "int", 3));
+ case 'l' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "long", 4));
+ case 'f' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "float", 5));
+ case 'd':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "double", 6));
+ case 'r':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "long double", 11));
+ case 'e':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "...", 3));
+ default:
+ return (false);
+ };
+
+ /* NOTREACHED */
+ return (false);
+}
diff --git a/contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c b/contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c
new file mode 100644
index 0000000..4fe141b
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_dem_gnu2.c
@@ -0,0 +1,1376 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libelftc.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_dem_gnu2.c 2065 2011-10-26 15:24:47Z jkoshy $");
+
+/**
+ * @file cpp_demangle_gnu2.c
+ * @brief Decode function name encoding in GNU 2.
+ *
+ * Function name encoding in GNU 2 based on ARM style.
+ */
+
+enum encode_type {
+ ENCODE_FUNC, ENCODE_OP, ENCODE_OP_CT, ENCODE_OP_DT, ENCODE_OP_USER,
+ ENCODE_OP_TF, ENCODE_OP_TI, ENCODE_OP_VT
+};
+
+struct cstring {
+ char *buf;
+ size_t size;
+};
+
+struct demangle_data {
+ bool ptr, ref, cnst, array, cnst_fn, class_name;
+ struct cstring array_str;
+ const char *p;
+ enum encode_type type;
+ struct vector_str vec;
+ struct vector_str arg;
+};
+
+#define SIMPLE_HASH(x,y) (64 * x + y)
+#define CPP_DEMANGLE_GNU2_TRY 128
+
+static void dest_cstring(struct cstring *);
+static void dest_demangle_data(struct demangle_data *);
+static bool init_cstring(struct cstring *, size_t);
+static bool init_demangle_data(struct demangle_data *);
+static bool push_CTDT(const char *, size_t, struct vector_str *);
+static bool read_array(struct demangle_data *);
+static bool read_class(struct demangle_data *);
+static bool read_func(struct demangle_data *);
+static bool read_func_name(struct demangle_data *);
+static bool read_func_ptr(struct demangle_data *);
+static bool read_memptr(struct demangle_data *);
+static bool read_op(struct demangle_data *);
+static bool read_op_user(struct demangle_data *);
+static bool read_qual_name(struct demangle_data *);
+static int read_subst(struct demangle_data *);
+static int read_subst_iter(struct demangle_data *);
+static bool read_type(struct demangle_data *);
+
+/**
+ * @brief Decode the input string by the GNU 2 style.
+ *
+ * @return New allocated demangled string or NULL if failed.
+ */
+char *
+cpp_demangle_gnu2(const char *org)
+{
+ struct demangle_data d;
+ size_t arg_begin, arg_len;
+ unsigned int try;
+ char *rtn, *arg;
+
+ if (org == NULL)
+ return (NULL);
+
+ if (init_demangle_data(&d) == false)
+ return (NULL);
+
+ try = 0;
+ rtn = NULL;
+
+ d.p = org;
+ if (read_func_name(&d) == false)
+ goto clean;
+
+ switch (d.type) {
+ case ENCODE_FUNC :
+ case ENCODE_OP :
+ break;
+
+ case ENCODE_OP_CT :
+ if (push_CTDT("::", 2, &d.vec) == false)
+ goto clean;
+
+ break;
+ case ENCODE_OP_DT :
+ if (push_CTDT("::~", 3, &d.vec) == false)
+ goto clean;
+
+ if (vector_str_push(&d.vec, "(void)", 6) == false)
+ goto clean;
+
+ goto flat;
+ case ENCODE_OP_USER :
+ case ENCODE_OP_TF :
+ case ENCODE_OP_TI :
+ case ENCODE_OP_VT :
+ goto flat;
+ };
+
+ if (*d.p == 'F')
+ ++d.p;
+ else if (*d.p == '\0') {
+ if (d.class_name == true) {
+ if (vector_str_push(&d.vec, "(void)", 6) == false)
+ goto clean;
+
+ goto flat;
+ } else
+ goto clean;
+ }
+
+ /* start argument types */
+ if (vector_str_push(&d.vec, "(", 1) == false)
+ goto clean;
+
+ for (;;) {
+ if (*d.p == 'T') {
+ const int rtn_subst = read_subst(&d);
+
+ if (rtn_subst == -1)
+ goto clean;
+ else if (rtn_subst == 1)
+ break;
+
+ continue;
+ }
+
+ if (*d.p == 'N') {
+ const int rtn_subst_iter = read_subst_iter(&d);
+
+ if (rtn_subst_iter == -1)
+ goto clean;
+ else if(rtn_subst_iter == 1)
+ break;
+
+ continue;
+ }
+
+ arg_begin = d.vec.size;
+
+ if (read_type(&d) == false)
+ goto clean;
+
+ if (d.ptr == true) {
+ if (vector_str_push(&d.vec, "*", 1) == false)
+ goto clean;
+
+ d.ptr = false;
+ }
+
+ if (d.ref == true) {
+ if (vector_str_push(&d.vec, "&", 1) == false)
+ goto clean;
+
+ d.ref = false;
+ }
+
+ if (d.cnst == true) {
+ if (vector_str_push(&d.vec, " const", 6) == false)
+ goto clean;
+
+ d.cnst = false;
+ }
+
+ if (d.array == true) {
+ if (vector_str_push(&d.vec, d.array_str.buf,
+ d.array_str.size) == false)
+ goto clean;
+
+ dest_cstring(&d.array_str);
+ d.array = false;
+ }
+
+ if (*d.p == '\0')
+ break;
+
+ if ((arg = vector_str_substr(&d.vec, arg_begin, d.vec.size - 1,
+ &arg_len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d.arg, arg, arg_len) == false)
+ goto clean;
+
+ free(arg);
+
+ if (vector_str_push(&d.vec, ", ", 2) == false)
+ goto clean;
+
+ if (++try > CPP_DEMANGLE_GNU2_TRY)
+ goto clean;
+ }
+
+ /* end argument types */
+ if (vector_str_push(&d.vec, ")", 1) == false)
+ goto clean;
+flat:
+ if (d.cnst_fn == true && vector_str_push(&d.vec, " const", 6) == false)
+ goto clean;
+
+ rtn = vector_str_get_flat(&d.vec, NULL);
+clean:
+ dest_demangle_data(&d);
+
+ return (rtn);
+}
+
+/**
+ * @brief Test input string is encoded by the GNU 2 style.
+ *
+ * @return True if input string is encoded by the GNU 2 style.
+ */
+bool
+is_cpp_mangled_gnu2(const char *org)
+{
+ char *str;
+ bool rtn = false;
+
+ if (org == NULL)
+ return (false);
+
+ /* search valid text to end */
+ str = strstr(org, "__");
+ while (str != NULL) {
+ if (*(str + 2) != '\0') {
+ if (*(str + 2) == 'C' ||
+ *(str + 2) == 'F' ||
+ *(str + 2) == 'Q' ||
+ ELFTC_ISDIGIT(*(str + 2))) {
+ rtn |= true;
+
+ break;
+ }
+
+ if (*(str + 3) != '\0') {
+ switch (SIMPLE_HASH(*(str + 2), *(str + 3))) {
+ case SIMPLE_HASH('m', 'l') :
+ case SIMPLE_HASH('d', 'v') :
+ case SIMPLE_HASH('m', 'd') :
+ case SIMPLE_HASH('p', 'l') :
+ case SIMPLE_HASH('m', 'i') :
+ case SIMPLE_HASH('l', 's') :
+ case SIMPLE_HASH('r', 's') :
+ case SIMPLE_HASH('e', 'q') :
+ case SIMPLE_HASH('n', 'e') :
+ case SIMPLE_HASH('l', 't') :
+ case SIMPLE_HASH('g', 't') :
+ case SIMPLE_HASH('l', 'e') :
+ case SIMPLE_HASH('g', 'e') :
+ case SIMPLE_HASH('a', 'd') :
+ case SIMPLE_HASH('o', 'r') :
+ case SIMPLE_HASH('e', 'r') :
+ case SIMPLE_HASH('a', 'a') :
+ case SIMPLE_HASH('o', 'o') :
+ case SIMPLE_HASH('n', 't') :
+ case SIMPLE_HASH('c', 'o') :
+ case SIMPLE_HASH('p', 'p') :
+ case SIMPLE_HASH('m', 'm') :
+ case SIMPLE_HASH('a', 's') :
+ case SIMPLE_HASH('r', 'f') :
+ case SIMPLE_HASH('a', 'p') :
+ case SIMPLE_HASH('a', 'm') :
+ case SIMPLE_HASH('a', 'l') :
+ case SIMPLE_HASH('a', 'r') :
+ case SIMPLE_HASH('a', 'o') :
+ case SIMPLE_HASH('a', 'e') :
+ case SIMPLE_HASH('c', 'm') :
+ case SIMPLE_HASH('r', 'm') :
+ case SIMPLE_HASH('c', 'l') :
+ case SIMPLE_HASH('v', 'c') :
+ case SIMPLE_HASH('n', 'w') :
+ case SIMPLE_HASH('d', 'l') :
+ case SIMPLE_HASH('o', 'p') :
+ case SIMPLE_HASH('t', 'f') :
+ case SIMPLE_HASH('t', 'i') :
+ rtn |= true;
+
+ break;
+ };
+ }
+ }
+
+ str = strstr(str + 2, "__");
+ }
+
+ rtn |= strstr(org, "_$_") != NULL;
+ rtn |= strstr(org, "_vt$") != NULL;
+
+ return (rtn);
+}
+
+static void
+dest_cstring(struct cstring *s)
+{
+
+ if (s == NULL)
+ return;
+
+ free(s->buf);
+ s->buf = NULL;
+ s->size = 0;
+}
+
+static void
+dest_demangle_data(struct demangle_data *d)
+{
+
+ if (d != NULL) {
+ vector_str_dest(&d->arg);
+ vector_str_dest(&d->vec);
+
+ dest_cstring(&d->array_str);
+ }
+}
+
+static bool
+init_cstring(struct cstring *s, size_t len)
+{
+
+ if (s == NULL || len <= 1)
+ return (false);
+
+ if ((s->buf = malloc(sizeof(char) * len)) == NULL)
+ return (false);
+
+ s->size = len - 1;
+
+ return (true);
+}
+
+static bool
+init_demangle_data(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ d->ptr = false;
+ d->ref = false;
+ d->cnst = false;
+ d->array = false;
+ d->cnst_fn = false;
+ d->class_name = false;
+
+ d->array_str.buf = NULL;
+ d->array_str.size = 0;
+
+ d->type = ENCODE_FUNC;
+
+ if (vector_str_init(&d->vec) == false)
+ return (false);
+
+ if (vector_str_init(&d->arg) == false) {
+ vector_str_dest(&d->vec);
+
+ return (false);
+ }
+
+ return (true);
+}
+
+static bool
+push_CTDT(const char *s, size_t l, struct vector_str *v)
+{
+
+ if (s == NULL || l == 0 || v == NULL)
+ return (false);
+
+ if (vector_str_push(v, s, l) == false)
+ return (false);
+
+ assert(v->size > 1);
+
+ return (vector_str_push(v, v->container[v->size - 2],
+ strlen(v->container[v->size - 2])));
+}
+
+static bool
+read_array(struct demangle_data *d)
+{
+ size_t len;
+ const char *end;
+
+ if (d == NULL || d->p == NULL)
+ return (false);
+
+ end = d->p;
+ assert(end != NULL);
+
+ for (;;) {
+ if (*end == '\0')
+ return (false);
+
+ if (ELFTC_ISDIGIT(*end) == 0)
+ break;
+
+ ++end;
+ }
+
+ if (*end != '_')
+ return (false);
+
+ len = end - d->p;
+ assert(len > 0);
+
+ dest_cstring(&d->array_str);
+ if (init_cstring(&d->array_str, len + 3) == false)
+ return (false);
+
+ strncpy(d->array_str.buf + 1, d->p, len);
+ *d->array_str.buf = '[';
+ *(d->array_str.buf + len + 1) = ']';
+
+ d->array = true;
+ d->p = end + 1;
+
+ return (true);
+}
+
+static bool
+read_class(struct demangle_data *d)
+{
+ size_t len;
+ char *str;
+
+ if (d == NULL)
+ return (false);
+
+ len = strtol(d->p, &str, 10);
+ if (len == 0 && (errno == EINVAL || errno == ERANGE))
+ return (false);
+
+ assert(len > 0);
+ assert(str != NULL);
+
+ if (vector_str_push(&d->vec, str, len) == false)
+ return (false);
+
+ d->p = str + len;
+
+ d->class_name = true;
+
+ return (true);
+}
+
+static bool
+read_func(struct demangle_data *d)
+{
+ size_t len;
+ const char *name;
+ char *delim;
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+ if ((delim = strstr(d->p, "__")) == NULL)
+ return (false);
+
+ len = delim - d->p;
+ assert(len != 0);
+
+ name = d->p;
+
+ d->p = delim + 2;
+
+ if (*d->p == 'C') {
+ ++d->p;
+
+ d->cnst_fn = true;
+ }
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ if (read_qual_name(d) == false)
+ return (false);
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ if (read_class(d) == false)
+ return (false);
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ return (false);
+ }
+
+ return (vector_str_push(&d->vec, name, len));
+}
+
+static bool
+read_func_name(struct demangle_data *d)
+{
+ size_t len;
+ bool rtn;
+ char *op_name;
+
+ if (d == NULL)
+ return (false);
+
+ rtn = false;
+ op_name = NULL;
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ if (*d->p == '_' && *(d->p + 1) == '_') {
+ d->p += 2;
+
+ /* CTOR */
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+ d->type = ENCODE_OP_CT;
+
+ if (read_qual_name(d) == false)
+ return (false);
+
+ return (vector_str_pop(&d->vec));
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ d->type = ENCODE_OP_CT;
+
+ return (read_class(d));
+ }
+
+ d->type = ENCODE_OP;
+ if (read_op(d) == false) {
+ /* not good condition, start function name with '__' */
+ d->type = ENCODE_FUNC;
+
+ if (vector_str_push(&d->vec, "__", 2) == false)
+ return (false);
+
+ return (read_func(d));
+ }
+
+ if (d->type == ENCODE_OP_USER ||
+ d->type == ENCODE_OP_TF ||
+ d->type == ENCODE_OP_TI)
+ return (true);
+
+ /* skip "__" */
+ d->p += 2;
+
+ if (*d->p == 'C') {
+ ++d->p;
+
+ d->cnst_fn = true;
+ }
+
+ /* assume delimiter is removed */
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ assert(d->vec.size > 0);
+
+ len = strlen(d->vec.container[d->vec.size - 1]);
+ if ((op_name = malloc(sizeof(char) * (len + 1)))
+ == NULL)
+ return (false);
+
+ snprintf(op_name, len + 1, "%s",
+ d->vec.container[d->vec.size - 1]);
+ vector_str_pop(&d->vec);
+
+ if (read_qual_name(d) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, op_name, len) == false)
+ goto clean;
+
+ rtn = true;
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ assert(d->vec.size > 0);
+
+ len = strlen(d->vec.container[d->vec.size - 1]);
+ if ((op_name = malloc(sizeof(char) * (len + 1)))
+ == NULL)
+ return (false);
+
+ snprintf(op_name, len + 1, "%s",
+ d->vec.container[d->vec.size - 1]);
+ vector_str_pop(&d->vec);
+
+ if (read_class(d) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, op_name, len) == false)
+ goto clean;
+
+ rtn = true;
+ }
+ } else if (memcmp(d->p, "_$_", 3) == 0) {
+ /* DTOR */
+ d->p += 3;
+ d->type = ENCODE_OP_DT;
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ if (read_qual_name(d) == false)
+ return (false);
+
+ return (vector_str_pop(&d->vec));
+ } else if (ELFTC_ISDIGIT(*d->p))
+ return (read_class(d));
+
+ return (false);
+ } else if (memcmp(d->p, "_vt$", 4) == 0) {
+ /* vtable */
+ d->p += 4;
+ d->type = ENCODE_OP_VT;
+
+ if (*d->p == 'Q' && ELFTC_ISDIGIT(*(d->p + 1))) {
+ ++d->p;
+
+ if (read_qual_name(d) == false)
+ return (false);
+
+ if (vector_str_pop(&d->vec) == false)
+ return (false);
+ } else if (ELFTC_ISDIGIT(*d->p)) {
+ if (read_class(d) == false)
+ return (false);
+ }
+
+ return (vector_str_push(&d->vec, " virtual table", 14));
+ } else
+ return (read_func(d));
+clean:
+ free(op_name);
+
+ return (rtn);
+}
+
+/* Read function ptr type */
+static bool
+read_func_ptr(struct demangle_data *d)
+{
+ struct demangle_data fptr;
+ size_t arg_len, rtn_len;
+ char *arg_type, *rtn_type;
+ int lim;
+
+ if (d == NULL)
+ return (false);
+
+ if (init_demangle_data(&fptr) == false)
+ return (false);
+
+ fptr.p = d->p + 1;
+ lim = 0;
+ arg_type = NULL;
+ rtn_type = NULL;
+
+ for (;;) {
+ if (read_type(&fptr) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ if (fptr.ptr == true) {
+ if (vector_str_push(&fptr.vec, "*", 1) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.ptr = false;
+ }
+
+ if (fptr.ref == true) {
+ if (vector_str_push(&fptr.vec, "&", 1) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.ref = false;
+ }
+
+ if (fptr.cnst == true) {
+ if (vector_str_push(&fptr.vec, " const", 6) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ fptr.cnst = false;
+ }
+
+ if (*fptr.p == '_')
+ break;
+
+ if (vector_str_push(&fptr.vec, ", ", 2) == false) {
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ if (++lim > CPP_DEMANGLE_GNU2_TRY) {
+
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+ }
+
+ arg_type = vector_str_get_flat(&fptr.vec, &arg_len);
+ /* skip '_' */
+ d->p = fptr.p + 1;
+
+ dest_demangle_data(&fptr);
+
+ if (init_demangle_data(&fptr) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ fptr.p = d->p;
+ lim = 0;
+
+ if (read_type(&fptr) == false) {
+ free(arg_type);
+ dest_demangle_data(&fptr);
+
+ return (false);
+ }
+
+ rtn_type = vector_str_get_flat(&fptr.vec, &rtn_len);
+ d->p = fptr.p;
+
+
+ dest_demangle_data(&fptr);
+
+ if (vector_str_push(&d->vec, rtn_type, rtn_len) == false) {
+ free(rtn_type);
+ free(arg_type);
+
+ return (false);
+ }
+
+ free(rtn_type);
+
+ if (vector_str_push(&d->vec, " (*)(", 5) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ if (vector_str_push(&d->vec, arg_type, arg_len) == false) {
+ free(arg_type);
+
+ return (false);
+ }
+
+ free(arg_type);
+
+ return (vector_str_push(&d->vec, ")", 1));
+}
+
+static bool
+read_memptr(struct demangle_data *d)
+{
+ struct demangle_data mptr;
+ size_t len;
+ bool rtn;
+ char *mptr_str;
+
+ if (d == NULL || d->p == NULL)
+ return (false);
+
+ if (init_demangle_data(&mptr) == false)
+ return (false);
+
+ rtn = false;
+ mptr_str = NULL;
+
+ mptr.p = d->p;
+ if (*mptr.p == 'Q') {
+ ++mptr.p;
+
+ if (read_qual_name(&mptr) == false)
+ goto clean;
+ } else if (read_class(&mptr) == false)
+ goto clean;
+
+ d->p = mptr.p;
+
+ if ((mptr_str = vector_str_get_flat(&mptr.vec, &len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d->vec, mptr_str, len) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::*", 3) == false)
+ goto clean;
+
+ rtn = true;
+clean:
+ free(mptr_str);
+ dest_demangle_data(&mptr);
+
+ return (rtn);
+}
+
+static bool
+read_op(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ switch (SIMPLE_HASH(*(d->p), *(d->p+1))) {
+ case SIMPLE_HASH('m', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator*", 9));
+ case SIMPLE_HASH('d', 'v') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator/", 9));
+ case SIMPLE_HASH('m', 'd') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator%", 9));
+ case SIMPLE_HASH('p', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator+", 9));
+ case SIMPLE_HASH('m', 'i') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator-", 9));
+ case SIMPLE_HASH('l', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<<", 10));
+ case SIMPLE_HASH('r', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>>", 10));
+ case SIMPLE_HASH('e', 'q') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator==", 10));
+ case SIMPLE_HASH('n', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator!=", 10));
+ case SIMPLE_HASH('l', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<", 9));
+ case SIMPLE_HASH('g', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>", 9));
+ case SIMPLE_HASH('l', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator<=", 10));
+ case SIMPLE_HASH('g', 'e') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator>=", 10));
+ case SIMPLE_HASH('a', 'd') :
+ d->p += 2;
+ if (*d->p == 'v') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator/=",
+ 10));
+ } else
+ return (vector_str_push(&d->vec, "operator&", 9));
+ case SIMPLE_HASH('o', 'r') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator|", 9));
+ case SIMPLE_HASH('e', 'r') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator^", 9));
+ case SIMPLE_HASH('a', 'a') :
+ d->p += 2;
+ if (*d->p == 'd') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator&=",
+ 10));
+ } else
+ return (vector_str_push(&d->vec, "operator&&",
+ 10));
+ case SIMPLE_HASH('o', 'o') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator||", 10));
+ case SIMPLE_HASH('n', 't') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator!", 9));
+ case SIMPLE_HASH('c', 'o') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator~", 9));
+ case SIMPLE_HASH('p', 'p') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator++", 10));
+ case SIMPLE_HASH('m', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator--", 10));
+ case SIMPLE_HASH('a', 's') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator=", 9));
+ case SIMPLE_HASH('r', 'f') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator->", 10));
+ case SIMPLE_HASH('a', 'p') :
+ /* apl */
+ if (*(d->p + 2) != 'l')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator+=", 10));
+ case SIMPLE_HASH('a', 'm') :
+ d->p += 2;
+ if (*d->p == 'i') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator-=",
+ 10));
+ } else if (*d->p == 'u') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator*=",
+ 10));
+ } else if (*d->p == 'd') {
+ ++d->p;
+ return (vector_str_push(&d->vec, "operator%=",
+ 10));
+ }
+
+ return (false);
+ case SIMPLE_HASH('a', 'l') :
+ /* als */
+ if (*(d->p + 2) != 's')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator<<=", 11));
+ case SIMPLE_HASH('a', 'r') :
+ /* ars */
+ if (*(d->p + 2) != 's')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator>>=", 11));
+ case SIMPLE_HASH('a', 'o') :
+ /* aor */
+ if (*(d->p + 2) != 'r')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator|=", 10));
+ case SIMPLE_HASH('a', 'e') :
+ /* aer */
+ if (*(d->p + 2) != 'r')
+ return (false);
+
+ d->p += 3;
+ return (vector_str_push(&d->vec, "operator^=", 10));
+ case SIMPLE_HASH('c', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator,", 9));
+ case SIMPLE_HASH('r', 'm') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator->*", 11));
+ case SIMPLE_HASH('c', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "()", 2));
+ case SIMPLE_HASH('v', 'c') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "[]", 2));
+ case SIMPLE_HASH('n', 'w') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator new()", 14));
+ case SIMPLE_HASH('d', 'l') :
+ d->p += 2;
+ return (vector_str_push(&d->vec, "operator delete()",
+ 17));
+ case SIMPLE_HASH('o', 'p') :
+ /* __op<TO_TYPE>__<FROM_TYPE> */
+ d->p += 2;
+
+ d->type = ENCODE_OP_USER;
+
+ return (read_op_user(d));
+ case SIMPLE_HASH('t', 'f') :
+ d->p += 2;
+ d->type = ENCODE_OP_TF;
+
+ if (read_type(d) == false)
+ return (false);
+
+ return (vector_str_push(&d->vec, " type_info function", 19));
+ case SIMPLE_HASH('t', 'i') :
+ d->p += 2;
+ d->type = ENCODE_OP_TI;
+
+ if (read_type(d) == false)
+ return (false);
+
+ return (vector_str_push(&d->vec, " type_info node", 15));
+ default :
+ return (false);
+ };
+}
+
+static bool
+read_op_user(struct demangle_data *d)
+{
+ struct demangle_data from, to;
+ size_t from_len, to_len;
+ bool rtn;
+ char *from_str, *to_str;
+
+ if (d == NULL)
+ return (false);
+
+ if (init_demangle_data(&from) == false)
+ return (false);
+
+ rtn = false;
+ from_str = NULL;
+ to_str = NULL;
+ if (init_demangle_data(&to) == false)
+ goto clean;
+
+ to.p = d->p;
+ if (*to.p == 'Q') {
+ ++to.p;
+
+ if (read_qual_name(&to) == false)
+ goto clean;
+
+ /* pop last '::' */
+ if (vector_str_pop(&to.vec) == false)
+ goto clean;
+ } else {
+ if (read_class(&to) == false)
+ goto clean;
+
+ /* skip '__' */
+ to.p += 2;
+ }
+
+ if ((to_str = vector_str_get_flat(&to.vec, &to_len)) == NULL)
+ goto clean;
+
+ from.p = to.p;
+ if (*from.p == 'Q') {
+ ++from.p;
+
+ if (read_qual_name(&from) == false)
+ goto clean;
+
+ /* pop last '::' */
+ if (vector_str_pop(&from.vec) == false)
+ goto clean;
+ } else if (read_class(&from) == false)
+ goto clean;
+
+ if ((from_str = vector_str_get_flat(&from.vec, &from_len)) == NULL)
+ goto clean;
+
+ if (vector_str_push(&d->vec, from_str, from_len) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, "::operator ", 11) == false)
+ goto clean;
+
+ if (vector_str_push(&d->vec, to_str, to_len) == false)
+ goto clean;
+
+ rtn = vector_str_push(&d->vec, "()", 2);
+clean:
+ free(to_str);
+ free(from_str);
+ dest_demangle_data(&to);
+ dest_demangle_data(&from);
+
+ return (rtn);
+}
+
+/* single digit + class names */
+static bool
+read_qual_name(struct demangle_data *d)
+{
+ int i;
+ char num;
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+ assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
+
+ num = *d->p - 48;
+
+ assert(num > 0);
+
+ ++d->p;
+ for (i = 0; i < num ; ++i) {
+ if (read_class(d) == false)
+ return (false);
+
+ if (vector_str_push(&d->vec, "::", 2) == false)
+ return (false);
+ }
+
+ if (*d->p != '\0')
+ d->p = d->p + 2;
+
+ return (true);
+}
+
+/* Return -1 at fail, 0 at success, and 1 at end */
+static int
+read_subst(struct demangle_data *d)
+{
+ size_t idx;
+ char *str;
+
+ if (d == NULL)
+ return (-1);
+
+ idx = strtol(d->p + 1, &str, 10);
+ if (idx == 0 && (errno == EINVAL || errno == ERANGE))
+ return (-1);
+
+ assert(idx > 0);
+ assert(str != NULL);
+
+ d->p = str;
+
+ if (vector_str_push(&d->vec, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (vector_str_push(&d->arg, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (*d->p == '\0')
+ return (1);
+
+ return (0);
+}
+
+static int
+read_subst_iter(struct demangle_data *d)
+{
+ int i;
+ size_t idx;
+ char repeat;
+ char *str;
+
+ if (d == NULL)
+ return (-1);
+
+ ++d->p;
+ assert(*d->p > 48 && *d->p < 58 && "*d->p not in ASCII numeric range");
+
+ repeat = *d->p - 48;
+
+ assert(repeat > 1);
+
+ ++d->p;
+
+ idx = strtol(d->p, &str, 10);
+ if (idx == 0 && (errno == EINVAL || errno == ERANGE))
+ return (-1);
+
+ assert(idx > 0);
+ assert(str != NULL);
+
+ d->p = str;
+
+ for (i = 0; i < repeat ; ++i) {
+ if (vector_str_push(&d->vec, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (vector_str_push(&d->arg, d->arg.container[idx - 1],
+ strlen(d->arg.container[idx - 1])) == false)
+ return (-1);
+
+ if (i != repeat - 1 &&
+ vector_str_push(&d->vec, ", ", 2) == false)
+ return (-1);
+ }
+
+ if (*d->p == '\0')
+ return (1);
+
+ return (0);
+}
+
+static bool
+read_type(struct demangle_data *d)
+{
+
+ if (d == NULL)
+ return (false);
+
+ assert(d->p != NULL && "d->p (org str) is NULL");
+
+ while (*d->p == 'U' || *d->p == 'C' || *d->p == 'V' || *d->p == 'S' ||
+ *d->p == 'P' || *d->p == 'R' || *d->p == 'A' || *d->p == 'F' ||
+ *d->p == 'M') {
+ switch (*d->p) {
+ case 'U' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "unsigned ", 9) == false)
+ return (false);
+
+ break;
+ case 'C' :
+ ++d->p;
+
+ if (*d->p == 'P')
+ d->cnst = true;
+ else {
+ if (vector_str_push(&d->vec, "const ", 6) ==
+ false)
+ return (false);
+ }
+
+ break;
+ case 'V' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "volatile ", 9) == false)
+ return (false);
+
+ break;
+ case 'S' :
+ ++d->p;
+
+ if (vector_str_push(&d->vec, "signed ", 7) == false)
+ return (false);
+
+ break;
+ case 'P' :
+ ++d->p;
+
+ if (*d->p == 'F')
+ return (read_func_ptr(d));
+ else
+ d->ptr = true;
+
+ break;
+ case 'R' :
+ ++d->p;
+
+ d->ref = true;
+
+ break;
+ case 'F' :
+ break;
+ case 'A' :
+ ++d->p;
+
+ if (read_array(d) == false)
+ return (false);
+
+ break;
+ case 'M' :
+ ++d->p;
+
+ if (read_memptr(d) == false)
+ return (false);
+
+ break;
+ default :
+ break;
+ };
+ };
+
+ if (ELFTC_ISDIGIT(*d->p))
+ return (read_class(d));
+
+ switch (*d->p) {
+ case 'Q' :
+ ++d->p;
+
+ return (read_qual_name(d));
+ case 'v' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "void", 4));
+ case 'b':
+ ++d->p;
+
+ return(vector_str_push(&d->vec, "bool", 4));
+ case 'c' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "char", 4));
+ case 's' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "short", 5));
+ case 'i' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "int", 3));
+ case 'l' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "long", 4));
+ case 'f' :
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "float", 5));
+ case 'd':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "double", 6));
+ case 'r':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "long double", 11));
+ case 'e':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "...", 3));
+ case 'w':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "wchar_t", 7));
+ case 'x':
+ ++d->p;
+
+ return (vector_str_push(&d->vec, "long long", 9));
+ default:
+ return (false);
+ };
+
+ /* NOTREACHED */
+ return (false);
+}
diff --git a/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c b/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c
new file mode 100644
index 0000000..bd54f54
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_dem_gnu3.c
@@ -0,0 +1,3238 @@
+/*-
+ * Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <libelftc.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_dem_gnu3.c 2179 2011-11-18 03:05:47Z jkoshy $");
+
+/**
+ * @file cpp_demangle.c
+ * @brief Decode IA-64 C++ ABI style implementation.
+ *
+ * IA-64 standard ABI(Itanium C++ ABI) references.
+ *
+ * http://www.codesourcery.com/cxx-abi/abi.html#mangling \n
+ * http://www.codesourcery.com/cxx-abi/abi-mangling.html
+ */
+
+enum type_qualifier {
+ TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT,
+ TYPE_CST
+};
+
+struct vector_type_qualifier {
+ size_t size, capacity;
+ enum type_qualifier *q_container;
+ struct vector_str ext_name;
+};
+
+enum read_cmd {
+ READ_FAIL, READ_NEST, READ_TMPL, READ_EXPR, READ_EXPL, READ_LOCAL,
+ READ_TYPE, READ_FUNC, READ_PTRMEM
+};
+
+struct vector_read_cmd {
+ size_t size, capacity;
+ enum read_cmd *r_container;
+};
+
+struct cpp_demangle_data {
+ struct vector_str output; /* output string vector */
+ struct vector_str output_tmp;
+ struct vector_str subst; /* substitution string vector */
+ struct vector_str tmpl;
+ struct vector_str class_type;
+ struct vector_read_cmd cmd;
+ bool paren; /* parenthesis opened */
+ bool pfirst; /* first element of parameter */
+ bool mem_rst; /* restrict member function */
+ bool mem_vat; /* volatile member function */
+ bool mem_cst; /* const member function */
+ int func_type;
+ const char *cur; /* current mangled name ptr */
+ const char *last_sname; /* last source name */
+};
+
+#define CPP_DEMANGLE_TRY_LIMIT 128
+#define FLOAT_SPRINTF_TRY_LIMIT 5
+#define FLOAT_QUADRUPLE_BYTES 16
+#define FLOAT_EXTENED_BYTES 10
+
+#define SIMPLE_HASH(x,y) (64 * x + y)
+
+static void cpp_demangle_data_dest(struct cpp_demangle_data *);
+static int cpp_demangle_data_init(struct cpp_demangle_data *,
+ const char *);
+static int cpp_demangle_get_subst(struct cpp_demangle_data *, size_t);
+static int cpp_demangle_get_tmpl_param(struct cpp_demangle_data *, size_t);
+static int cpp_demangle_push_fp(struct cpp_demangle_data *,
+ char *(*)(const char *, size_t));
+static int cpp_demangle_push_str(struct cpp_demangle_data *, const char *,
+ size_t);
+static int cpp_demangle_push_subst(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_push_subst_v(struct cpp_demangle_data *,
+ struct vector_str *);
+static int cpp_demangle_push_type_qualifier(struct cpp_demangle_data *,
+ struct vector_type_qualifier *, const char *);
+static int cpp_demangle_read_array(struct cpp_demangle_data *);
+static int cpp_demangle_read_encoding(struct cpp_demangle_data *);
+static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *);
+static int cpp_demangle_read_expression(struct cpp_demangle_data *);
+static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_expression_trinary(struct cpp_demangle_data *,
+ const char *, size_t, const char *, size_t);
+static int cpp_demangle_read_function(struct cpp_demangle_data *, int *,
+ struct vector_type_qualifier *);
+static int cpp_demangle_local_source_name(struct cpp_demangle_data *ddata);
+static int cpp_demangle_read_local_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_nested_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_number(struct cpp_demangle_data *, long *);
+static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *);
+static int cpp_demangle_read_offset(struct cpp_demangle_data *);
+static int cpp_demangle_read_offset_number(struct cpp_demangle_data *);
+static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *);
+static int cpp_demangle_read_sname(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst_std(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *);
+static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *);
+static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *);
+static int cpp_demangle_read_type(struct cpp_demangle_data *, int);
+static int cpp_demangle_read_uqname(struct cpp_demangle_data *);
+static int cpp_demangle_read_v_offset(struct cpp_demangle_data *);
+static char *decode_fp_to_double(const char *, size_t);
+static char *decode_fp_to_float(const char *, size_t);
+static char *decode_fp_to_float128(const char *, size_t);
+static char *decode_fp_to_float80(const char *, size_t);
+static char *decode_fp_to_long_double(const char *, size_t);
+static int hex_to_dec(char);
+static void vector_read_cmd_dest(struct vector_read_cmd *);
+static int vector_read_cmd_find(struct vector_read_cmd *, enum read_cmd);
+static int vector_read_cmd_init(struct vector_read_cmd *);
+static int vector_read_cmd_pop(struct vector_read_cmd *);
+static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd);
+static void vector_type_qualifier_dest(struct vector_type_qualifier *);
+static int vector_type_qualifier_init(struct vector_type_qualifier *);
+static int vector_type_qualifier_push(struct vector_type_qualifier *,
+ enum type_qualifier);
+
+int cpp_demangle_gnu3_push_head;
+
+/**
+ * @brief Decode the input string by IA-64 C++ ABI style.
+ *
+ * GNU GCC v3 use IA-64 standard ABI.
+ * @return New allocated demangled string or NULL if failed.
+ * @todo 1. Testing and more test case. 2. Code cleaning.
+ */
+char *
+cpp_demangle_gnu3(const char *org)
+{
+ struct cpp_demangle_data ddata;
+ ssize_t org_len;
+ unsigned int limit;
+ char *rtn;
+
+ if (org == NULL || (org_len = strlen(org)) < 2)
+ return (NULL);
+
+ if (org_len > 11 && !strncmp(org, "_GLOBAL__I_", 11)) {
+ if ((rtn = malloc(org_len + 19)) == NULL)
+ return (NULL);
+ snprintf(rtn, org_len + 19,
+ "global constructors keyed to %s", org + 11);
+ return (rtn);
+ }
+
+ if (org[0] != '_' || org[1] != 'Z')
+ return (NULL);
+
+ if (!cpp_demangle_data_init(&ddata, org + 2))
+ return (NULL);
+
+ cpp_demangle_gnu3_push_head = 0;
+ rtn = NULL;
+
+ if (!cpp_demangle_read_encoding(&ddata))
+ goto clean;
+
+ limit = 0;
+ while (*ddata.cur != '\0') {
+ /*
+ * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4
+ */
+ if (*ddata.cur == '@' && *(ddata.cur + 1) == '@')
+ break;
+ if (!cpp_demangle_read_type(&ddata, 1))
+ goto clean;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ goto clean;
+ }
+
+ if (ddata.output.size == 0)
+ goto clean;
+ if (ddata.paren && !vector_str_push(&ddata.output, ")", 1))
+ goto clean;
+ if (ddata.mem_vat && !vector_str_push(&ddata.output, " volatile", 9))
+ goto clean;
+ if (ddata.mem_cst && !vector_str_push(&ddata.output, " const", 6))
+ goto clean;
+ if (ddata.mem_rst && !vector_str_push(&ddata.output, " restrict", 9))
+ goto clean;
+
+ rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
+
+clean:
+ cpp_demangle_data_dest(&ddata);
+
+ return (rtn);
+}
+
+static void
+cpp_demangle_data_dest(struct cpp_demangle_data *d)
+{
+
+ if (d == NULL)
+ return;
+
+ vector_read_cmd_dest(&d->cmd);
+ vector_str_dest(&d->class_type);
+ vector_str_dest(&d->tmpl);
+ vector_str_dest(&d->subst);
+ vector_str_dest(&d->output_tmp);
+ vector_str_dest(&d->output);
+}
+
+static int
+cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur)
+{
+
+ if (d == NULL || cur == NULL)
+ return (0);
+
+ if (!vector_str_init(&d->output))
+ return (0);
+ if (!vector_str_init(&d->output_tmp))
+ goto clean1;
+ if (!vector_str_init(&d->subst))
+ goto clean2;
+ if (!vector_str_init(&d->tmpl))
+ goto clean3;
+ if (!vector_str_init(&d->class_type))
+ goto clean4;
+ if (!vector_read_cmd_init(&d->cmd))
+ goto clean5;
+
+ assert(d->output.container != NULL);
+ assert(d->output_tmp.container != NULL);
+ assert(d->subst.container != NULL);
+ assert(d->tmpl.container != NULL);
+ assert(d->class_type.container != NULL);
+
+ d->paren = false;
+ d->pfirst = false;
+ d->mem_rst = false;
+ d->mem_vat = false;
+ d->mem_cst = false;
+ d->func_type = 0;
+ d->cur = cur;
+ d->last_sname = NULL;
+
+ return (1);
+
+clean5:
+ vector_str_dest(&d->class_type);
+clean4:
+ vector_str_dest(&d->tmpl);
+clean3:
+ vector_str_dest(&d->subst);
+clean2:
+ vector_str_dest(&d->output_tmp);
+clean1:
+ vector_str_dest(&d->output);
+
+ return (0);
+}
+
+static int
+cpp_demangle_push_fp(struct cpp_demangle_data *ddata,
+ char *(*decoder)(const char *, size_t))
+{
+ size_t len;
+ int rtn;
+ const char *fp;
+ char *f;
+
+ if (ddata == NULL || decoder == NULL)
+ return (0);
+
+ fp = ddata->cur;
+ while (*ddata->cur != 'E')
+ ++ddata->cur;
+ ++ddata->cur;
+
+ if ((f = decoder(fp, ddata->cur - fp)) == NULL)
+ return (0);
+
+ rtn = 0;
+ if ((len = strlen(f)) > 0)
+ rtn = cpp_demangle_push_str(ddata, f, len);
+
+ free(f);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str,
+ size_t len)
+{
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ if (cpp_demangle_gnu3_push_head > 0)
+ return (vector_str_push(&ddata->output_tmp, str, len));
+
+ return (vector_str_push(&ddata->output, str, len));
+}
+
+static int
+cpp_demangle_push_subst(struct cpp_demangle_data *ddata, const char *str,
+ size_t len)
+{
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ if (!vector_str_find(&ddata->subst, str, len))
+ return (vector_str_push(&ddata->subst, str, len));
+
+ return (1);
+}
+
+static int
+cpp_demangle_push_subst_v(struct cpp_demangle_data *ddata, struct vector_str *v)
+{
+ size_t str_len;
+ int rtn;
+ char *str;
+
+ if (ddata == NULL || v == NULL)
+ return (0);
+
+ if ((str = vector_str_get_flat(v, &str_len)) == NULL)
+ return (0);
+
+ rtn = cpp_demangle_push_subst(ddata, str, str_len);
+
+ free(str);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
+ struct vector_type_qualifier *v, const char *type_str)
+{
+ struct vector_str subst_v;
+ size_t idx, e_idx, e_len;
+ int rtn;
+ char *buf;
+
+ if (ddata == NULL || v == NULL)
+ return (0);
+
+ if ((idx = v->size) == 0)
+ return (1);
+
+ rtn = 0;
+ if (type_str != NULL) {
+ if (!vector_str_init(&subst_v))
+ return (0);
+ if (!vector_str_push(&subst_v, type_str, strlen(type_str)))
+ goto clean;
+ }
+
+ e_idx = 0;
+ while (idx > 0) {
+ switch (v->q_container[idx - 1]) {
+ case TYPE_PTR:
+ if (!cpp_demangle_push_str(ddata, "*", 1))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, "*", 1))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_REF:
+ if (!cpp_demangle_push_str(ddata, "&", 1))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, "&", 1))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_CMX:
+ if (!cpp_demangle_push_str(ddata, " complex", 8))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " complex", 8))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_IMG:
+ if (!cpp_demangle_push_str(ddata, " imaginary", 10))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " imaginary", 10))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_EXT:
+ if (e_idx > v->ext_name.size - 1)
+ goto clean;
+ if ((e_len = strlen(v->ext_name.container[e_idx])) == 0)
+ goto clean;
+ if ((buf = malloc(sizeof(char) * (e_len + 1))) == NULL)
+ goto clean;
+
+ memcpy(buf, " ", 1);
+ memcpy(buf + 1, v->ext_name.container[e_idx], e_len);
+
+ if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) {
+ free(buf);
+ goto clean;
+ }
+
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, buf,
+ e_len + 1)) {
+ free(buf);
+ goto clean;
+ }
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v)) {
+ free(buf);
+ goto clean;
+ }
+ }
+ free(buf);
+ ++e_idx;
+ break;
+
+ case TYPE_RST:
+ if (!cpp_demangle_push_str(ddata, " restrict", 9))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " restrict", 9))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_VAT:
+ if (!cpp_demangle_push_str(ddata, " volatile", 9))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " volatile", 9))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_CST:
+ if (!cpp_demangle_push_str(ddata, " const", 6))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " const", 6))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ };
+ --idx;
+ }
+
+ rtn = 1;
+clean:
+ if (type_str != NULL)
+ vector_str_dest(&subst_v);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_get_subst(struct cpp_demangle_data *ddata, size_t idx)
+{
+ size_t len;
+
+ if (ddata == NULL || ddata->subst.size <= idx)
+ return (0);
+ if ((len = strlen(ddata->subst.container[idx])) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->subst.container[idx], len))
+ return (0);
+
+ /* skip '_' */
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_get_tmpl_param(struct cpp_demangle_data *ddata, size_t idx)
+{
+ size_t len;
+
+ if (ddata == NULL || ddata->tmpl.size <= idx)
+ return (0);
+ if ((len = strlen(ddata->tmpl.container[idx])) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->tmpl.container[idx], len))
+ return (0);
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_array(struct cpp_demangle_data *ddata)
+{
+ size_t i, num_len, exp_len, p_idx, idx;
+ const char *num;
+ char *exp;
+
+ if (ddata == NULL || *(++ddata->cur) == '\0')
+ return (0);
+
+ if (*ddata->cur == '_') {
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "[]", 2))
+ return (0);
+ } else {
+ if (ELFTC_ISDIGIT(*ddata->cur) != 0) {
+ num = ddata->cur;
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+ if (*ddata->cur != '_')
+ return (0);
+ num_len = ddata->cur - num;
+ assert(num_len > 0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "[", 1))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, num, num_len))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "]", 1))
+ return (0);
+ } else {
+ p_idx = ddata->output.size;
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if ((exp = vector_str_substr(&ddata->output, p_idx,
+ ddata->output.size - 1, &exp_len)) == NULL)
+ return (0);
+ idx = ddata->output.size;
+ for (i = p_idx; i < idx; ++i)
+ if (!vector_str_pop(&ddata->output)) {
+ free(exp);
+ return (0);
+ }
+ if (*ddata->cur != '_') {
+ free(exp);
+ return (0);
+ }
+ ++ddata->cur;
+ if (*ddata->cur == '\0') {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_read_type(ddata, 0)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, "[", 1)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, exp, exp_len)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, "]", 1)) {
+ free(exp);
+ return (0);
+ }
+ free(exp);
+ }
+ }
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata)
+{
+ const char *num;
+
+ if (ddata == NULL || *(++ddata->cur) == '\0')
+ return (0);
+
+ if (*ddata->cur == '_' && *(ddata->cur + 1) == 'Z') {
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_encoding(ddata))
+ return (0);
+ ++ddata->cur;
+ return (1);
+ }
+
+ switch (*ddata->cur) {
+ case 'b':
+ switch (*(++ddata->cur)) {
+ case '0':
+ return (cpp_demangle_push_str(ddata, "false", 5));
+ case '1':
+ return (cpp_demangle_push_str(ddata, "true", 4));
+ default:
+ return (0);
+ };
+
+ case 'd':
+ ++ddata->cur;
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_double));
+
+ case 'e':
+ ++ddata->cur;
+ if (sizeof(long double) == 10)
+ return (cpp_demangle_push_fp(ddata,
+ decode_fp_to_double));
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float80));
+
+ case 'f':
+ ++ddata->cur;
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float));
+
+ case 'g':
+ ++ddata->cur;
+ if (sizeof(long double) == 16)
+ return (cpp_demangle_push_fp(ddata,
+ decode_fp_to_double));
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float128));
+
+ case 'i':
+ case 'j':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 's':
+ case 't':
+ case 'x':
+ case 'y':
+ if (*(++ddata->cur) == 'n') {
+ if (!cpp_demangle_push_str(ddata, "-", 1))
+ return (0);
+ ++ddata->cur;
+ }
+ num = ddata->cur;
+ while (*ddata->cur != 'E') {
+ if (!ELFTC_ISDIGIT(*ddata->cur))
+ return (0);
+ ++ddata->cur;
+ }
+ ++ddata->cur;
+ return (cpp_demangle_push_str(ddata, num, ddata->cur - num));
+
+ default:
+ return (0);
+ };
+}
+
+static int
+cpp_demangle_read_expression(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('s', 't'):
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 0));
+
+ case SIMPLE_HASH('s', 'r'):
+ ddata->cur += 2;
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (!cpp_demangle_read_uqname(ddata))
+ return (0);
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_tmpl_args(ddata));
+ return (1);
+
+ case SIMPLE_HASH('a', 'a'):
+ /* operator && */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&&", 2));
+
+ case SIMPLE_HASH('a', 'd'):
+ /* operator & (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "&", 1));
+
+ case SIMPLE_HASH('a', 'n'):
+ /* operator & */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&", 1));
+
+ case SIMPLE_HASH('a', 'N'):
+ /* operator &= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&=", 2));
+
+ case SIMPLE_HASH('a', 'S'):
+ /* operator = */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "=", 1));
+
+ case SIMPLE_HASH('c', 'l'):
+ /* operator () */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "()", 2));
+
+ case SIMPLE_HASH('c', 'm'):
+ /* operator , */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ",", 1));
+
+ case SIMPLE_HASH('c', 'o'):
+ /* operator ~ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "~", 1));
+
+ case SIMPLE_HASH('c', 'v'):
+ /* operator (cast) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "(cast)", 6));
+
+ case SIMPLE_HASH('d', 'a'):
+ /* operator delete [] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "delete []", 9));
+
+ case SIMPLE_HASH('d', 'e'):
+ /* operator * (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "*", 1));
+
+ case SIMPLE_HASH('d', 'l'):
+ /* operator delete */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "delete", 6));
+
+ case SIMPLE_HASH('d', 'v'):
+ /* operator / */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "/", 1));
+
+ case SIMPLE_HASH('d', 'V'):
+ /* operator /= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "/=", 2));
+
+ case SIMPLE_HASH('e', 'o'):
+ /* operator ^ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "^", 1));
+
+ case SIMPLE_HASH('e', 'O'):
+ /* operator ^= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "^=", 2));
+
+ case SIMPLE_HASH('e', 'q'):
+ /* operator == */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "==", 2));
+
+ case SIMPLE_HASH('g', 'e'):
+ /* operator >= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">=", 2));
+
+ case SIMPLE_HASH('g', 't'):
+ /* operator > */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">", 1));
+
+ case SIMPLE_HASH('i', 'x'):
+ /* operator [] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "[]", 2));
+
+ case SIMPLE_HASH('l', 'e'):
+ /* operator <= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<=", 2));
+
+ case SIMPLE_HASH('l', 's'):
+ /* operator << */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<<", 2));
+
+ case SIMPLE_HASH('l', 'S'):
+ /* operator <<= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<<=", 3));
+
+ case SIMPLE_HASH('l', 't'):
+ /* operator < */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<", 1));
+
+ case SIMPLE_HASH('m', 'i'):
+ /* operator - */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "-", 1));
+
+ case SIMPLE_HASH('m', 'I'):
+ /* operator -= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "-=", 2));
+
+ case SIMPLE_HASH('m', 'l'):
+ /* operator * */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "*", 1));
+
+ case SIMPLE_HASH('m', 'L'):
+ /* operator *= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "*=", 2));
+
+ case SIMPLE_HASH('m', 'm'):
+ /* operator -- */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "--", 2));
+
+ case SIMPLE_HASH('n', 'a'):
+ /* operator new[] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "new []", 6));
+
+ case SIMPLE_HASH('n', 'e'):
+ /* operator != */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "!=", 2));
+
+ case SIMPLE_HASH('n', 'g'):
+ /* operator - (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "-", 1));
+
+ case SIMPLE_HASH('n', 't'):
+ /* operator ! */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "!", 1));
+
+ case SIMPLE_HASH('n', 'w'):
+ /* operator new */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "new", 3));
+
+ case SIMPLE_HASH('o', 'o'):
+ /* operator || */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "||", 2));
+
+ case SIMPLE_HASH('o', 'r'):
+ /* operator | */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "|", 1));
+
+ case SIMPLE_HASH('o', 'R'):
+ /* operator |= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "|=", 2));
+
+ case SIMPLE_HASH('p', 'l'):
+ /* operator + */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "+", 1));
+
+ case SIMPLE_HASH('p', 'L'):
+ /* operator += */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "+=", 2));
+
+ case SIMPLE_HASH('p', 'm'):
+ /* operator ->* */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "->*", 3));
+
+ case SIMPLE_HASH('p', 'p'):
+ /* operator ++ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "++", 2));
+
+ case SIMPLE_HASH('p', 's'):
+ /* operator + (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "+", 1));
+
+ case SIMPLE_HASH('p', 't'):
+ /* operator -> */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "->", 2));
+
+ case SIMPLE_HASH('q', 'u'):
+ /* operator ? */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_trinary(ddata, "?", 1,
+ ":", 1));
+
+ case SIMPLE_HASH('r', 'm'):
+ /* operator % */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "%", 1));
+
+ case SIMPLE_HASH('r', 'M'):
+ /* operator %= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "%=", 2));
+
+ case SIMPLE_HASH('r', 's'):
+ /* operator >> */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">>", 2));
+
+ case SIMPLE_HASH('r', 'S'):
+ /* operator >>= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">>=", 3));
+
+ case SIMPLE_HASH('r', 'z'):
+ /* operator sizeof */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6));
+
+ case SIMPLE_HASH('s', 'v'):
+ /* operator sizeof */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6));
+ };
+
+ switch (*ddata->cur) {
+ case 'L':
+ return (cpp_demangle_read_expr_primary(ddata));
+ case 'T':
+ return (cpp_demangle_read_tmpl_param(ddata));
+ };
+
+ return (0);
+}
+
+static int
+cpp_demangle_read_expression_binary(struct cpp_demangle_data *ddata,
+ const char *name, size_t len)
+{
+
+ if (ddata == NULL || name == NULL || len == 0)
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name, len))
+ return (0);
+
+ return (cpp_demangle_read_expression(ddata));
+}
+
+static int
+cpp_demangle_read_expression_unary(struct cpp_demangle_data *ddata,
+ const char *name, size_t len)
+{
+
+ if (ddata == NULL || name == NULL || len == 0)
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+
+ return (cpp_demangle_push_str(ddata, name, len));
+}
+
+static int
+cpp_demangle_read_expression_trinary(struct cpp_demangle_data *ddata,
+ const char *name1, size_t len1, const char *name2, size_t len2)
+{
+
+ if (ddata == NULL || name1 == NULL || len1 == 0 || name2 == NULL ||
+ len2 == 0)
+ return (0);
+
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name1, len1))
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name2, len2))
+ return (0);
+
+ return (cpp_demangle_read_expression(ddata));
+}
+
+static int
+cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
+ struct vector_type_qualifier *v)
+{
+ size_t class_type_size, class_type_len, limit;
+ const char *class_type;
+
+ if (ddata == NULL || *ddata->cur != 'F' || v == NULL)
+ return (0);
+
+ ++ddata->cur;
+ if (*ddata->cur == 'Y') {
+ if (ext_c != NULL)
+ *ext_c = 1;
+ ++ddata->cur;
+ }
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (*ddata->cur != 'E') {
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+ if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM)) {
+ if ((class_type_size = ddata->class_type.size) == 0)
+ return (0);
+ class_type =
+ ddata->class_type.container[class_type_size - 1];
+ if (class_type == NULL)
+ return (0);
+ if ((class_type_len = strlen(class_type)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, class_type,
+ class_type_len))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::*", 3))
+ return (0);
+ ++ddata->func_type;
+ } else {
+ if (!cpp_demangle_push_type_qualifier(ddata, v,
+ (const char *) NULL))
+ return (0);
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+ }
+
+ if (!cpp_demangle_push_str(ddata, ")(", 2))
+ return (0);
+
+ limit = 0;
+ for (;;) {
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (*ddata->cur == 'E')
+ break;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+
+ if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM) == 1) {
+ if (!cpp_demangle_push_type_qualifier(ddata, v,
+ (const char *) NULL))
+ return (0);
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+ }
+
+ if (!cpp_demangle_push_str(ddata, ")", 1))
+ return (0);
+ }
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+/* read encoding, encoding are function name, data name, special-name */
+static int
+cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* special name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('G', 'V'):
+ /* sentry object for 1 time init */
+ if (!cpp_demangle_push_str(ddata, "guard variable for ", 20))
+ return (0);
+ ddata->cur += 2;
+ break;
+
+ case SIMPLE_HASH('T', 'c'):
+ /* virtual function covariant override thunk */
+ if (!cpp_demangle_push_str(ddata,
+ "virtual function covariant override ", 36))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_offset(ddata))
+ return (0);
+ if (!cpp_demangle_read_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'D'):
+ /* typeinfo common proxy */
+ break;
+
+ case SIMPLE_HASH('T', 'h'):
+ /* virtual function non-virtual override thunk */
+ if (cpp_demangle_push_str(ddata,
+ "virtual function non-virtual override ", 38) == 0)
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_nv_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'I'):
+ /* typeinfo structure */
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('T', 'S'):
+ /* RTTI name (NTBS) */
+ if (!cpp_demangle_push_str(ddata, "typeinfo for ", 14))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('T', 'T'):
+ /* VTT table */
+ if (!cpp_demangle_push_str(ddata, "VTT for ", 8))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('T', 'v'):
+ /* virtual function virtual override thunk */
+ if (!cpp_demangle_push_str(ddata,
+ "virtual function virtual override ", 34))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_v_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'V'):
+ /* virtual table */
+ if (!cpp_demangle_push_str(ddata, "vtable for ", 12))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ return (cpp_demangle_read_type(ddata, 1));
+ };
+
+ return (cpp_demangle_read_name(ddata));
+}
+
+static int
+cpp_demangle_read_local_name(struct cpp_demangle_data *ddata)
+{
+ size_t limit;
+
+ if (ddata == NULL)
+ return (0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (!cpp_demangle_read_encoding(ddata))
+ return (0);
+
+ limit = 0;
+ for (;;) {
+ if (!cpp_demangle_read_type(ddata, 1))
+ return (0);
+ if (*ddata->cur == 'E')
+ break;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (ddata->paren == true) {
+ if (!cpp_demangle_push_str(ddata, ")", 1))
+ return (0);
+ ddata->paren = false;
+ }
+ if (*ddata->cur == 's')
+ ++ddata->cur;
+ else {
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ return (0);
+ if (!cpp_demangle_read_name(ddata))
+ return (0);
+ }
+ if (*ddata->cur == '_') {
+ ++ddata->cur;
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+ }
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_name(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ output = cpp_demangle_gnu3_push_head > 0 ?
+ &ddata->output_tmp : &ddata->output;
+
+ subst_str = NULL;
+
+ switch (*ddata->cur) {
+ case 'S':
+ return (cpp_demangle_read_subst(ddata));
+ case 'N':
+ return (cpp_demangle_read_nested_name(ddata));
+ case 'Z':
+ return (cpp_demangle_read_local_name(ddata));
+ };
+
+ if (!vector_str_init(&v))
+ return (0);
+
+ p_idx = output->size;
+ rtn = 0;
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+ if ((subst_str = vector_str_substr(output, p_idx, output->size - 1,
+ &subst_str_len)) == NULL)
+ goto clean;
+ if (subst_str_len > 8 && strstr(subst_str, "operator") != NULL) {
+ rtn = 1;
+ goto clean;
+ }
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+
+ if (*ddata->cur == 'I') {
+ p_idx = output->size;
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ free(subst_str);
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ }
+
+ rtn = 1;
+
+clean:
+ free(subst_str);
+ vector_str_dest(&v);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t limit, p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL || *ddata->cur != 'N')
+ return (0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ while (*ddata->cur == 'r' || *ddata->cur == 'V' ||
+ *ddata->cur == 'K') {
+ switch (*ddata->cur) {
+ case 'r':
+ ddata->mem_rst = true;
+ break;
+ case 'V':
+ ddata->mem_vat = true;
+ break;
+ case 'K':
+ ddata->mem_cst = true;
+ break;
+ };
+ ++ddata->cur;
+ }
+
+ output = cpp_demangle_gnu3_push_head > 0 ?
+ &ddata->output_tmp : &ddata->output;
+ if (!vector_str_init(&v))
+ return (0);
+
+ rtn = 0;
+ limit = 0;
+ for (;;) {
+ p_idx = output->size;
+ switch (*ddata->cur) {
+ case 'I':
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ break;
+ case 'S':
+ if (!cpp_demangle_read_subst(ddata))
+ goto clean;
+ break;
+ case 'T':
+ if (!cpp_demangle_read_tmpl_param(ddata))
+ goto clean;
+ break;
+ default:
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+ };
+
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len)) {
+ free(subst_str);
+ goto clean;
+ }
+ free(subst_str);
+
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ if (*ddata->cur == 'E')
+ break;
+ else if (*ddata->cur != 'I' &&
+ *ddata->cur != 'C' && *ddata->cur != 'D') {
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ goto clean;
+ if (!vector_str_push(&v, "::", 2))
+ goto clean;
+ }
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ goto clean;
+ }
+
+ ++ddata->cur;
+ rtn = 1;
+
+clean:
+ vector_str_dest(&v);
+
+ return (rtn);
+}
+
+/*
+ * read number
+ * number ::= [n] <decimal>
+ */
+static int
+cpp_demangle_read_number(struct cpp_demangle_data *ddata, long *rtn)
+{
+ long len, negative_factor;
+
+ if (ddata == NULL || rtn == NULL)
+ return (0);
+
+ negative_factor = 1;
+ if (*ddata->cur == 'n') {
+ negative_factor = -1;
+
+ ++ddata->cur;
+ }
+ if (ELFTC_ISDIGIT(*ddata->cur) == 0)
+ return (0);
+
+ errno = 0;
+ if ((len = strtol(ddata->cur, (char **) NULL, 10)) == 0 &&
+ errno != 0)
+ return (0);
+
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+
+ assert(len >= 0);
+ assert(negative_factor == 1 || negative_factor == -1);
+
+ *rtn = len * negative_factor;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+ return (0);
+
+ return (cpp_demangle_read_offset_number(ddata));
+}
+
+/* read offset, offset are nv-offset, v-offset */
+static int
+cpp_demangle_read_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (*ddata->cur == 'h') {
+ ++ddata->cur;
+ return (cpp_demangle_read_nv_offset(ddata));
+ } else if (*ddata->cur == 'v') {
+ ++ddata->cur;
+ return (cpp_demangle_read_v_offset(ddata));
+ }
+
+ return (0);
+}
+
+static int
+cpp_demangle_read_offset_number(struct cpp_demangle_data *ddata)
+{
+ bool negative;
+ const char *start;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* offset could be negative */
+ if (*ddata->cur == 'n') {
+ negative = true;
+ start = ddata->cur + 1;
+ } else {
+ negative = false;
+ start = ddata->cur;
+ }
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ if (negative && !cpp_demangle_push_str(ddata, "-", 1))
+ return (0);
+
+ assert(start != NULL);
+
+ if (!cpp_demangle_push_str(ddata, start, ddata->cur - start))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, " ", 1))
+ return (0);
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
+{
+ size_t class_type_len, i, idx, p_idx;
+ int p_func_type, rtn;
+ char *class_type;
+
+ if (ddata == NULL || *ddata->cur != 'M' || *(++ddata->cur) == '\0')
+ return (0);
+
+ p_idx = ddata->output.size;
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+
+ if ((class_type = vector_str_substr(&ddata->output, p_idx,
+ ddata->output.size - 1, &class_type_len)) == NULL)
+ return (0);
+
+ rtn = 0;
+ idx = ddata->output.size;
+ for (i = p_idx; i < idx; ++i)
+ if (!vector_str_pop(&ddata->output))
+ goto clean1;
+
+ if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM))
+ goto clean1;
+
+ if (!vector_str_push(&ddata->class_type, class_type, class_type_len))
+ goto clean2;
+
+ p_func_type = ddata->func_type;
+ if (!cpp_demangle_read_type(ddata, 0))
+ goto clean3;
+
+ if (p_func_type == ddata->func_type) {
+ if (!cpp_demangle_push_str(ddata, " ", 1))
+ goto clean3;
+ if (!cpp_demangle_push_str(ddata, class_type, class_type_len))
+ goto clean3;
+ if (!cpp_demangle_push_str(ddata, "::*", 3))
+ goto clean3;
+ }
+
+ rtn = 1;
+clean3:
+ if (!vector_str_pop(&ddata->class_type))
+ rtn = 0;
+clean2:
+ if (!vector_read_cmd_pop(&ddata->cmd))
+ rtn = 0;
+clean1:
+ free(class_type);
+
+ return (rtn);
+}
+
+/* read source-name, source-name is <len> <ID> */
+static int
+cpp_demangle_read_sname(struct cpp_demangle_data *ddata)
+{
+ long len;
+
+ if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 ||
+ len <= 0 || cpp_demangle_push_str(ddata, ddata->cur, len) == 0)
+ return (0);
+
+ assert(ddata->output.size > 0);
+ if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == 0)
+ ddata->last_sname =
+ ddata->output.container[ddata->output.size - 1];
+
+ ddata->cur += len;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
+{
+ long nth;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* abbreviations of the form Sx */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('S', 'a'):
+ /* std::allocator */
+ if (cpp_demangle_push_str(ddata, "std::allocator", 14) == 0)
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::allocator", 14));
+ return (1);
+
+ case SIMPLE_HASH('S', 'b'):
+ /* std::basic_string */
+ if (!cpp_demangle_push_str(ddata, "std::basic_string", 17))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::basic_string", 17));
+ return (1);
+
+ case SIMPLE_HASH('S', 'd'):
+ /* std::basic_iostream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::iostream", 19))
+ return (0);
+ ddata->last_sname = "iostream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::iostream", 19));
+ return (1);
+
+ case SIMPLE_HASH('S', 'i'):
+ /* std::basic_istream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::istream", 18))
+ return (0);
+ ddata->last_sname = "istream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::istream", 18));
+ return (1);
+
+ case SIMPLE_HASH('S', 'o'):
+ /* std::basic_ostream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::ostream", 18))
+ return (0);
+ ddata->last_sname = "istream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::ostream", 18));
+ return (1);
+
+ case SIMPLE_HASH('S', 's'):
+ /*
+ * std::basic_string<char, std::char_traits<char>,
+ * std::allocator<char> >
+ *
+ * a.k.a std::string
+ */
+ if (!cpp_demangle_push_str(ddata, "std::string", 11))
+ return (0);
+ ddata->last_sname = "string";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::string", 11));
+ return (1);
+
+ case SIMPLE_HASH('S', 't'):
+ /* std:: */
+ return (cpp_demangle_read_subst_std(ddata));
+ };
+
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ /* substitution */
+ if (*ddata->cur == '_')
+ return (cpp_demangle_get_subst(ddata, 0));
+ else {
+ errno = 0;
+ /* substitution number is base 36 */
+ if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 &&
+ errno != 0)
+ return (0);
+
+ /* first was '_', so increase one */
+ ++nth;
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ assert(nth > 0);
+
+ return (cpp_demangle_get_subst(ddata, nth));
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!vector_str_init(&v))
+ return (0);
+
+ subst_str = NULL;
+ rtn = 0;
+ if (!cpp_demangle_push_str(ddata, "std::", 5))
+ goto clean;
+
+ if (!vector_str_push(&v, "std::", 5))
+ goto clean;
+
+ ddata->cur += 2;
+
+ output = cpp_demangle_gnu3_push_head > 0 ?
+ &ddata->output_tmp : &ddata->output;
+
+ p_idx = output->size;
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+
+ if ((subst_str = vector_str_substr(output, p_idx, output->size - 1,
+ &subst_str_len)) == NULL)
+ goto clean;
+
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+
+ if (*ddata->cur == 'I') {
+ p_idx = output->size;
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ free(subst_str);
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ }
+
+ rtn = 1;
+clean:
+ free(subst_str);
+ vector_str_dest(&v);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata,
+ const char *str, size_t len)
+{
+ struct vector_str *output;
+ size_t p_idx, substr_len;
+ int rtn;
+ char *subst_str, *substr;
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ output = cpp_demangle_gnu3_push_head > 0 ? &ddata->output_tmp :
+ &ddata->output;
+
+ p_idx = output->size;
+ substr = NULL;
+ subst_str = NULL;
+
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ return (0);
+ if ((substr = vector_str_substr(output, p_idx, output->size - 1,
+ &substr_len)) == NULL)
+ return (0);
+
+ rtn = 0;
+ if ((subst_str = malloc(sizeof(char) * (substr_len + len + 1))) ==
+ NULL)
+ goto clean;
+
+ memcpy(subst_str, str, len);
+ memcpy(subst_str + len, substr, substr_len);
+ subst_str[substr_len + len] = '\0';
+
+ if (!cpp_demangle_push_subst(ddata, subst_str, substr_len + len))
+ goto clean;
+
+ rtn = 1;
+clean:
+ free(subst_str);
+ free(substr);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ switch (*ddata->cur) {
+ case 'L':
+ return (cpp_demangle_read_expr_primary(ddata));
+ case 'X':
+ return (cpp_demangle_read_expression(ddata));
+ };
+
+ return (cpp_demangle_read_type(ddata, 0));
+}
+
+static int
+cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *v;
+ size_t arg_len, idx, limit, size;
+ char *arg;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ ++ddata->cur;
+
+ if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "<", 1))
+ return (0);
+
+ limit = 0;
+ v = cpp_demangle_gnu3_push_head > 0 ?
+ &ddata->output_tmp : &ddata->output;
+ for (;;) {
+ idx = v->size;
+ if (!cpp_demangle_read_tmpl_arg(ddata))
+ return (0);
+ if ((arg = vector_str_substr(v, idx, v->size - 1, &arg_len)) ==
+ NULL)
+ return (0);
+ if (!vector_str_find(&ddata->tmpl, arg, arg_len) &&
+ !vector_str_push(&ddata->tmpl, arg, arg_len)) {
+ free(arg);
+ return (0);
+ }
+
+ free(arg);
+
+ if (*ddata->cur == 'E') {
+ ++ddata->cur;
+ size = v->size;
+ assert(size > 0);
+ if (!strncmp(v->container[size - 1], ">", 1)) {
+ if (!cpp_demangle_push_str(ddata, " >", 2))
+ return (0);
+ } else if (!cpp_demangle_push_str(ddata, ">", 1))
+ return (0);
+ break;
+ } else if (*ddata->cur != 'I' &&
+ !cpp_demangle_push_str(ddata, ", ", 2))
+ return (0);
+
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+
+ return (vector_read_cmd_pop(&ddata->cmd));
+}
+
+/*
+ * Read template parameter that forms in 'T[number]_'.
+ * This function much like to read_subst but only for types.
+ */
+static int
+cpp_demangle_read_tmpl_param(struct cpp_demangle_data *ddata)
+{
+ long nth;
+
+ if (ddata == NULL || *ddata->cur != 'T')
+ return (0);
+
+ ++ddata->cur;
+
+ if (*ddata->cur == '_')
+ return (cpp_demangle_get_tmpl_param(ddata, 0));
+ else {
+
+ errno = 0;
+ if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 &&
+ errno != 0)
+ return (0);
+
+ /* T_ is first */
+ ++nth;
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ assert(nth > 0);
+
+ return (cpp_demangle_get_tmpl_param(ddata, nth));
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit)
+{
+ struct vector_type_qualifier v;
+ struct vector_str *output;
+ size_t p_idx, type_str_len;
+ int extern_c, is_builtin;
+ long len;
+ char *type_str;
+
+ if (ddata == NULL)
+ return (0);
+
+ output = &ddata->output;
+ if (!strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) {
+ cpp_demangle_gnu3_push_head++;
+ output = &ddata->output_tmp;
+ } else if (delimit == 1) {
+ if (ddata->paren == false) {
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+ if (ddata->output.size < 2)
+ return (0);
+ ddata->paren = true;
+ ddata->pfirst = true;
+ /* Need pop function name */
+ if (ddata->subst.size == 1 &&
+ !vector_str_pop(&ddata->subst))
+ return (0);
+ }
+
+ if (ddata->pfirst)
+ ddata->pfirst = false;
+ else if (*ddata->cur != 'I' &&
+ !cpp_demangle_push_str(ddata, ", ", 2))
+ return (0);
+ }
+
+ assert(output != NULL);
+ /*
+ * [r, V, K] [P, R, C, G, U] builtin, function, class-enum, array
+ * pointer-to-member, template-param, template-template-param, subst
+ */
+
+ if (!vector_type_qualifier_init(&v))
+ return (0);
+
+ extern_c = 0;
+ is_builtin = 1;
+ p_idx = output->size;
+ type_str = NULL;
+again:
+ /* builtin type */
+ switch (*ddata->cur) {
+ case 'a':
+ /* signed char */
+ if (!cpp_demangle_push_str(ddata, "signed char", 11))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'A':
+ /* array type */
+ if (!cpp_demangle_read_array(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'b':
+ /* bool */
+ if (!cpp_demangle_push_str(ddata, "bool", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'C':
+ /* complex pair */
+ if (!vector_type_qualifier_push(&v, TYPE_CMX))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'c':
+ /* char */
+ if (!cpp_demangle_push_str(ddata, "char", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'd':
+ /* double */
+ if (!cpp_demangle_push_str(ddata, "double", 6))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'e':
+ /* long double */
+ if (!cpp_demangle_push_str(ddata, "long double", 11))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'f':
+ /* float */
+ if (!cpp_demangle_push_str(ddata, "float", 5))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'F':
+ /* function */
+ if (!cpp_demangle_read_function(ddata, &extern_c, &v))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'g':
+ /* __float128 */
+ if (!cpp_demangle_push_str(ddata, "__float128", 10))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'G':
+ /* imaginary */
+ if (!vector_type_qualifier_push(&v, TYPE_IMG))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'h':
+ /* unsigned char */
+ if (!cpp_demangle_push_str(ddata, "unsigned char", 13))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'i':
+ /* int */
+ if (!cpp_demangle_push_str(ddata, "int", 3))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'j':
+ /* unsigned int */
+ if (!cpp_demangle_push_str(ddata, "unsigned int", 12))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'K':
+ /* const */
+ if (!vector_type_qualifier_push(&v, TYPE_CST))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'l':
+ /* long */
+ if (!cpp_demangle_push_str(ddata, "long", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'm':
+ /* unsigned long */
+ if (!cpp_demangle_push_str(ddata, "unsigned long", 13))
+ goto clean;
+
+ ++ddata->cur;
+
+ goto rtn;
+ case 'M':
+ /* pointer to member */
+ if (!cpp_demangle_read_pointer_to_member(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'n':
+ /* __int128 */
+ if (!cpp_demangle_push_str(ddata, "__int128", 8))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'o':
+ /* unsigned __int128 */
+ if (!cpp_demangle_push_str(ddata, "unsigned _;int128", 17))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'P':
+ /* pointer */
+ if (!vector_type_qualifier_push(&v, TYPE_PTR))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'r':
+ /* restrict */
+ if (!vector_type_qualifier_push(&v, TYPE_RST))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'R':
+ /* reference */
+ if (!vector_type_qualifier_push(&v, TYPE_REF))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 's':
+ /* short, local string */
+ if (!cpp_demangle_push_str(ddata, "short", 5))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'S':
+ /* substitution */
+ if (!cpp_demangle_read_subst(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 't':
+ /* unsigned short */
+ if (!cpp_demangle_push_str(ddata, "unsigned short", 14))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'T':
+ /* template parameter */
+ if (!cpp_demangle_read_tmpl_param(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'u':
+ /* vendor extended builtin */
+ ++ddata->cur;
+ if (!cpp_demangle_read_sname(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'U':
+ /* vendor extended type qualifier */
+ if (!cpp_demangle_read_number(ddata, &len))
+ goto clean;
+ if (len <= 0)
+ goto clean;
+ if (!vector_str_push(&v.ext_name, ddata->cur, len))
+ return (0);
+ ddata->cur += len;
+ goto again;
+
+ case 'v':
+ /* void */
+ if (!cpp_demangle_push_str(ddata, "void", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'V':
+ /* volatile */
+ if (!vector_type_qualifier_push(&v, TYPE_VAT))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'w':
+ /* wchar_t */
+ if (!cpp_demangle_push_str(ddata, "wchar_t", 6))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'x':
+ /* long long */
+ if (!cpp_demangle_push_str(ddata, "long long", 9))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'y':
+ /* unsigned long long */
+ if (!cpp_demangle_push_str(ddata, "unsigned long long", 18))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'z':
+ /* ellipsis */
+ if (!cpp_demangle_push_str(ddata, "ellipsis", 8))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+ };
+
+ if (!cpp_demangle_read_name(ddata))
+ goto clean;
+
+ is_builtin = 0;
+rtn:
+ if ((type_str = vector_str_substr(output, p_idx, output->size - 1,
+ &type_str_len)) == NULL)
+ goto clean;
+
+ if (is_builtin == 0) {
+ if (!vector_str_find(&ddata->subst, type_str, type_str_len) &&
+ !vector_str_push(&ddata->subst, type_str, type_str_len))
+ goto clean;
+ }
+
+ if (!cpp_demangle_push_type_qualifier(ddata, &v, type_str))
+ goto clean;
+
+ free(type_str);
+ vector_type_qualifier_dest(&v);
+
+ if (cpp_demangle_gnu3_push_head > 0) {
+ if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata)
+ == 0)
+ return (0);
+
+ if (--cpp_demangle_gnu3_push_head > 0)
+ return (1);
+
+ if (!vector_str_push(&ddata->output_tmp, " ", 1))
+ return (0);
+
+ if (!vector_str_push_vector_head(&ddata->output,
+ &ddata->output_tmp))
+ return (0);
+
+ vector_str_dest(&ddata->output_tmp);
+ if (!vector_str_init(&ddata->output_tmp))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+
+ ddata->paren = true;
+ ddata->pfirst = true;
+ }
+
+ return (1);
+clean:
+ free(type_str);
+ vector_type_qualifier_dest(&v);
+
+ return (0);
+}
+
+/*
+ * read unqualified-name, unqualified name are operator-name, ctor-dtor-name,
+ * source-name
+ */
+static int
+cpp_demangle_read_uqname(struct cpp_demangle_data *ddata)
+{
+ size_t len;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* operator name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('a', 'a'):
+ /* operator && */
+ if (!cpp_demangle_push_str(ddata, "operator&&", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'd'):
+ /* operator & (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator&", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'n'):
+ /* operator & */
+ if (!cpp_demangle_push_str(ddata, "operator&", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'N'):
+ /* operator &= */
+ if (!cpp_demangle_push_str(ddata, "operator&=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'S'):
+ /* operator = */
+ if (!cpp_demangle_push_str(ddata, "operator=", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'l'):
+ /* operator () */
+ if (!cpp_demangle_push_str(ddata, "operator()", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'm'):
+ /* operator , */
+ if (!cpp_demangle_push_str(ddata, "operator,", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'o'):
+ /* operator ~ */
+ if (!cpp_demangle_push_str(ddata, "operator~", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'v'):
+ /* operator (cast) */
+ if (!cpp_demangle_push_str(ddata, "operator(cast)", 14))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('d', 'a'):
+ /* operator delete [] */
+ if (!cpp_demangle_push_str(ddata, "operator delete []", 18))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'e'):
+ /* operator * (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator*", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'l'):
+ /* operator delete */
+ if (!cpp_demangle_push_str(ddata, "operator delete", 15))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'v'):
+ /* operator / */
+ if (!cpp_demangle_push_str(ddata, "operator/", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'V'):
+ /* operator /= */
+ if (!cpp_demangle_push_str(ddata, "operator/=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'o'):
+ /* operator ^ */
+ if (!cpp_demangle_push_str(ddata, "operator^", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'O'):
+ /* operator ^= */
+ if (!cpp_demangle_push_str(ddata, "operator^=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'q'):
+ /* operator == */
+ if (!cpp_demangle_push_str(ddata, "operator==", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('g', 'e'):
+ /* operator >= */
+ if (!cpp_demangle_push_str(ddata, "operator>=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('g', 't'):
+ /* operator > */
+ if (!cpp_demangle_push_str(ddata, "operator>", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('i', 'x'):
+ /* operator [] */
+ if (!cpp_demangle_push_str(ddata, "operator[]", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 'e'):
+ /* operator <= */
+ if (!cpp_demangle_push_str(ddata, "operator<=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 's'):
+ /* operator << */
+ if (!cpp_demangle_push_str(ddata, "operator<<", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 'S'):
+ /* operator <<= */
+ if (!cpp_demangle_push_str(ddata, "operator<<=", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 't'):
+ /* operator < */
+ if (!cpp_demangle_push_str(ddata, "operator<", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'i'):
+ /* operator - */
+ if (!cpp_demangle_push_str(ddata, "operator-", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'I'):
+ /* operator -= */
+ if (!cpp_demangle_push_str(ddata, "operator-=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'l'):
+ /* operator * */
+ if (!cpp_demangle_push_str(ddata, "operator*", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'L'):
+ /* operator *= */
+ if (!cpp_demangle_push_str(ddata, "operator*=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'm'):
+ /* operator -- */
+ if (!cpp_demangle_push_str(ddata, "operator--", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'a'):
+ /* operator new[] */
+ if (!cpp_demangle_push_str(ddata, "operator new []", 15))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'e'):
+ /* operator != */
+ if (!cpp_demangle_push_str(ddata, "operator!=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'g'):
+ /* operator - (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator-", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 't'):
+ /* operator ! */
+ if (!cpp_demangle_push_str(ddata, "operator!", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'w'):
+ /* operator new */
+ if (!cpp_demangle_push_str(ddata, "operator new", 12))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'o'):
+ /* operator || */
+ if (!cpp_demangle_push_str(ddata, "operator||", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'r'):
+ /* operator | */
+ if (!cpp_demangle_push_str(ddata, "operator|", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'R'):
+ /* operator |= */
+ if (!cpp_demangle_push_str(ddata, "operator|=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'l'):
+ /* operator + */
+ if (!cpp_demangle_push_str(ddata, "operator+", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'L'):
+ /* operator += */
+ if (!cpp_demangle_push_str(ddata, "operator+=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'm'):
+ /* operator ->* */
+ if (!cpp_demangle_push_str(ddata, "operator->*", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'p'):
+ /* operator ++ */
+ if (!cpp_demangle_push_str(ddata, "operator++", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 's'):
+ /* operator + (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator+", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 't'):
+ /* operator -> */
+ if (!cpp_demangle_push_str(ddata, "operator->", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('q', 'u'):
+ /* operator ? */
+ if (!cpp_demangle_push_str(ddata, "operator?", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'm'):
+ /* operator % */
+ if (!cpp_demangle_push_str(ddata, "operator%", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'M'):
+ /* operator %= */
+ if (!cpp_demangle_push_str(ddata, "operator%=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 's'):
+ /* operator >> */
+ if (!cpp_demangle_push_str(ddata, "operator>>", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'S'):
+ /* operator >>= */
+ if (!cpp_demangle_push_str(ddata, "operator>>=", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'z'):
+ /* operator sizeof */
+ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('s', 'r'):
+ /* scope resolution operator */
+ if (!cpp_demangle_push_str(ddata, "scope resolution operator ",
+ 26))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('s', 'v'):
+ /* operator sizeof */
+ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+ };
+
+ /* vendor extened operator */
+ if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) {
+ if (!cpp_demangle_push_str(ddata, "vendor extened operator ",
+ 24))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->cur + 1, 1))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_sname(ddata));
+ }
+
+ /* ctor-dtor-name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('C', '1'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('C', '2'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('C', '3'):
+ if (ddata->last_sname == NULL)
+ return (0);
+ if ((len = strlen(ddata->last_sname)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
+ return (0);
+ ddata->cur +=2;
+ return (1);
+
+ case SIMPLE_HASH('D', '0'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('D', '1'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('D', '2'):
+ if (ddata->last_sname == NULL)
+ return (0);
+ if ((len = strlen(ddata->last_sname)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::~", 3))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
+ return (0);
+ ddata->cur +=2;
+ return (1);
+ };
+
+ /* source name */
+ if (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ return (cpp_demangle_read_sname(ddata));
+
+ /* local source name */
+ if (*ddata->cur == 'L')
+ return (cpp_demangle_local_source_name(ddata));
+
+ return (1);
+}
+
+/*
+ * Read local source name.
+ *
+ * References:
+ * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+ * http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+ */
+static int
+cpp_demangle_local_source_name(struct cpp_demangle_data *ddata)
+{
+ /* L */
+ if (ddata == NULL || *ddata->cur != 'L')
+ return (0);
+ ++ddata->cur;
+
+ /* source name */
+ if (!cpp_demangle_read_sname(ddata))
+ return (0);
+
+ /* discriminator */
+ if (*ddata->cur == '_') {
+ ++ddata->cur;
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+ }
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_v_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+ return (0);
+
+ if (!cpp_demangle_read_offset_number(ddata))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "virtual offset : ", 17))
+ return (0);
+
+ return (!cpp_demangle_read_offset_number(ddata));
+}
+
+/*
+ * Decode floating point representation to string
+ * Return new allocated string or NULL
+ *
+ * Todo
+ * Replace these functions to macro.
+ */
+static char *
+decode_fp_to_double(const char *p, size_t len)
+{
+ double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(double))
+ return (NULL);
+
+ memset(&f, 0, sizeof(double));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(double) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 64;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%fld", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return rtn;
+}
+
+static char *
+decode_fp_to_float(const char *p, size_t len)
+{
+ size_t i, rtn_len, limit;
+ float f;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(float))
+ return (NULL);
+
+ memset(&f, 0, sizeof(float));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+ if (byte < 0 || byte > 255)
+ return (NULL);
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(float) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 64;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%ff", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return rtn;
+}
+
+static char *
+decode_fp_to_float128(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ unsigned char buf[FLOAT_QUADRUPLE_BYTES];
+ char *rtn;
+
+ switch(sizeof(long double)) {
+ case FLOAT_QUADRUPLE_BYTES:
+ return (decode_fp_to_long_double(p, len));
+ case FLOAT_EXTENED_BYTES:
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > FLOAT_QUADRUPLE_BYTES)
+ return (NULL);
+
+ memset(buf, 0, FLOAT_QUADRUPLE_BYTES);
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+ if (byte < 0 || byte > 255)
+ return (NULL);
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ buf[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ buf[FLOAT_QUADRUPLE_BYTES - i -1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+ memset(&f, 0, FLOAT_EXTENED_BYTES);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ memcpy(&f, buf, FLOAT_EXTENED_BYTES);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ memcpy(&f, buf + 6, FLOAT_EXTENED_BYTES);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+ default:
+ return (NULL);
+ }
+}
+
+static char *
+decode_fp_to_float80(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ unsigned char buf[FLOAT_EXTENED_BYTES];
+ char *rtn;
+
+ switch(sizeof(long double)) {
+ case FLOAT_QUADRUPLE_BYTES:
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > FLOAT_EXTENED_BYTES)
+ return (NULL);
+
+ memset(buf, 0, FLOAT_EXTENED_BYTES);
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ buf[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ buf[FLOAT_EXTENED_BYTES - i -1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ memset(&f, 0, FLOAT_QUADRUPLE_BYTES);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ memcpy(&f, buf, FLOAT_EXTENED_BYTES);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ memcpy((unsigned char *)(&f) + 6, buf, FLOAT_EXTENED_BYTES);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+ case FLOAT_EXTENED_BYTES:
+ return (decode_fp_to_long_double(p, len));
+ default:
+ return (NULL);
+ }
+}
+
+static char *
+decode_fp_to_long_double(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > sizeof(long double))
+ return (NULL);
+
+ memset(&f, 0, sizeof(long double));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(long double) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+}
+
+/* Simple hex to integer function used by decode_to_* function. */
+static int
+hex_to_dec(char c)
+{
+
+ switch (c) {
+ case '0':
+ return (0);
+ case '1':
+ return (1);
+ case '2':
+ return (2);
+ case '3':
+ return (3);
+ case '4':
+ return (4);
+ case '5':
+ return (5);
+ case '6':
+ return (6);
+ case '7':
+ return (7);
+ case '8':
+ return (8);
+ case '9':
+ return (9);
+ case 'a':
+ return (10);
+ case 'b':
+ return (11);
+ case 'c':
+ return (12);
+ case 'd':
+ return (13);
+ case 'e':
+ return (14);
+ case 'f':
+ return (15);
+ default:
+ return (-1);
+ };
+}
+
+/**
+ * @brief Test input string is mangled by IA-64 C++ ABI style.
+ *
+ * Test string heads with "_Z" or "_GLOBAL__I_".
+ * @return Return 0 at false.
+ */
+bool
+is_cpp_mangled_gnu3(const char *org)
+{
+ size_t len;
+
+ len = strlen(org);
+ return ((len > 2 && *org == '_' && *(org + 1) == 'Z') ||
+ (len > 11 && !strncmp(org, "_GLOBAL__I_", 11)));
+}
+
+static void
+vector_read_cmd_dest(struct vector_read_cmd *v)
+{
+
+ if (v == NULL)
+ return;
+
+ free(v->r_container);
+}
+
+/* return -1 at failed, 0 at not found, 1 at found. */
+static int
+vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
+{
+ size_t i;
+
+ if (v == NULL || dst == READ_FAIL)
+ return (-1);
+
+ for (i = 0; i < v->size; ++i)
+ if (v->r_container[i] == dst)
+ return (1);
+
+ return (0);
+}
+
+static int
+vector_read_cmd_init(struct vector_read_cmd *v)
+{
+
+ if (v == NULL)
+ return (0);
+
+ v->size = 0;
+ v->capacity = VECTOR_DEF_CAPACITY;
+
+ if ((v->r_container = malloc(sizeof(enum read_cmd) * v->capacity))
+ == NULL)
+ return (0);
+
+ return (1);
+}
+
+static int
+vector_read_cmd_pop(struct vector_read_cmd *v)
+{
+
+ if (v == NULL || v->size == 0)
+ return (0);
+
+ --v->size;
+ v->r_container[v->size] = READ_FAIL;
+
+ return (1);
+}
+
+static int
+vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
+{
+ enum read_cmd *tmp_r_ctn;
+ size_t tmp_cap;
+ size_t i;
+
+ if (v == NULL)
+ return (0);
+
+ if (v->size == v->capacity) {
+ tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+ if ((tmp_r_ctn = malloc(sizeof(enum read_cmd) * tmp_cap))
+ == NULL)
+ return (0);
+ for (i = 0; i < v->size; ++i)
+ tmp_r_ctn[i] = v->r_container[i];
+ free(v->r_container);
+ v->r_container = tmp_r_ctn;
+ v->capacity = tmp_cap;
+ }
+
+ v->r_container[v->size] = cmd;
+ ++v->size;
+
+ return (1);
+}
+
+static void
+vector_type_qualifier_dest(struct vector_type_qualifier *v)
+{
+
+ if (v == NULL)
+ return;
+
+ free(v->q_container);
+ vector_str_dest(&v->ext_name);
+}
+
+/* size, capacity, ext_name */
+static int
+vector_type_qualifier_init(struct vector_type_qualifier *v)
+{
+
+ if (v == NULL)
+ return (0);
+
+ v->size = 0;
+ v->capacity = VECTOR_DEF_CAPACITY;
+
+ if ((v->q_container = malloc(sizeof(enum type_qualifier) * v->capacity))
+ == NULL)
+ return (0);
+
+ assert(v->q_container != NULL);
+
+ if (vector_str_init(&v->ext_name) == false) {
+ free(v->q_container);
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+vector_type_qualifier_push(struct vector_type_qualifier *v,
+ enum type_qualifier t)
+{
+ enum type_qualifier *tmp_ctn;
+ size_t tmp_cap;
+ size_t i;
+
+ if (v == NULL)
+ return (0);
+
+ if (v->size == v->capacity) {
+ tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+ if ((tmp_ctn = malloc(sizeof(enum type_qualifier) * tmp_cap))
+ == NULL)
+ return (0);
+ for (i = 0; i < v->size; ++i)
+ tmp_ctn[i] = v->q_container[i];
+ free(v->q_container);
+ v->q_container = tmp_ctn;
+ v->capacity = tmp_cap;
+ }
+
+ v->q_container[v->size] = t;
+ ++v->size;
+
+ return (1);
+}
diff --git a/contrib/elftoolchain/libelftc/libelftc_hash.c b/contrib/elftoolchain/libelftc/libelftc_hash.c
new file mode 100644
index 0000000..6cc54b9
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_hash.c
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 2013, Joseph Koshy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * An implementation of the Fowler-Noll-Vo hash function.
+ *
+ * References:
+ * - http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+ * - http://www.isthe.com/chongo/tech/comp/fnv/
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_hash.c 2870 2013-01-07 10:38:43Z jkoshy $");
+
+/*
+ * Use the size of an 'int' to determine the magic numbers used by the
+ * hash function.
+ */
+
+#if INT_MAX == 2147483647UL
+#define FNV_PRIME 16777619UL
+#define FNV_OFFSET 2166136261UL
+#elif INT_MAX == 18446744073709551615ULL
+#define FNV_PRIME 1099511628211ULL
+#define FNV_OFFSET 14695981039346656037ULL
+#else
+#error sizeof(int) is unknown.
+#endif
+
+unsigned int
+libelftc_hash_string(const char *s)
+{
+ char c;
+ unsigned int hash;
+
+ for (hash = FNV_OFFSET; (c = *s) != '\0'; s++) {
+ hash ^= c;
+ hash *= FNV_PRIME;
+ }
+
+ return (hash);
+}
diff --git a/contrib/elftoolchain/libelftc/libelftc_vstr.c b/contrib/elftoolchain/libelftc/libelftc_vstr.c
new file mode 100644
index 0000000..4b0977e
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/libelftc_vstr.c
@@ -0,0 +1,318 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <assert.h>
+#include <libelftc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_vstr.c 2065 2011-10-26 15:24:47Z jkoshy $");
+
+/**
+ * @file vector_str.c
+ * @brief Dynamic vector data for string implementation.
+ *
+ * Resemble to std::vector<std::string> in C++.
+ */
+
+static size_t get_strlen_sum(const struct vector_str *v);
+static bool vector_str_grow(struct vector_str *v);
+
+static size_t
+get_strlen_sum(const struct vector_str *v)
+{
+ size_t i, len = 0;
+
+ if (v == NULL)
+ return (0);
+
+ assert(v->size > 0);
+
+ for (i = 0; i < v->size; ++i)
+ len += strlen(v->container[i]);
+
+ return (len);
+}
+
+/**
+ * @brief Deallocate resource in vector_str.
+ */
+void
+vector_str_dest(struct vector_str *v)
+{
+ size_t i;
+
+ if (v == NULL)
+ return;
+
+ for (i = 0; i < v->size; ++i)
+ free(v->container[i]);
+
+ free(v->container);
+}
+
+/**
+ * @brief Find string in vector_str.
+ * @param v Destination vector.
+ * @param o String to find.
+ * @param l Length of the string.
+ * @return -1 at failed, 0 at not found, 1 at found.
+ */
+int
+vector_str_find(const struct vector_str *v, const char *o, size_t l)
+{
+ size_t i;
+
+ if (v == NULL || o == NULL)
+ return (-1);
+
+ for (i = 0; i < v->size; ++i)
+ if (strncmp(v->container[i], o, l) == 0)
+ return (1);
+
+ return (0);
+}
+
+/**
+ * @brief Get new allocated flat string from vector.
+ *
+ * If l is not NULL, return length of the string.
+ * @param v Destination vector.
+ * @param l Length of the string.
+ * @return NULL at failed or NUL terminated new allocated string.
+ */
+char *
+vector_str_get_flat(const struct vector_str *v, size_t *l)
+{
+ ssize_t elem_pos, elem_size, rtn_size;
+ size_t i;
+ char *rtn;
+
+ if (v == NULL || v->size == 0)
+ return (NULL);
+
+ if ((rtn_size = get_strlen_sum(v)) == 0)
+ return (NULL);
+
+ if ((rtn = malloc(sizeof(char) * (rtn_size + 1))) == NULL)
+ return (NULL);
+
+ elem_pos = 0;
+ for (i = 0; i < v->size; ++i) {
+ elem_size = strlen(v->container[i]);
+
+ memcpy(rtn + elem_pos, v->container[i], elem_size);
+
+ elem_pos += elem_size;
+ }
+
+ rtn[rtn_size] = '\0';
+
+ if (l != NULL)
+ *l = rtn_size;
+
+ return (rtn);
+}
+
+static bool
+vector_str_grow(struct vector_str *v)
+{
+ size_t i, tmp_cap;
+ char **tmp_ctn;
+
+ if (v == NULL)
+ return (false);
+
+ assert(v->capacity > 0);
+
+ tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+
+ assert(tmp_cap > v->capacity);
+
+ if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
+ return (false);
+
+ for (i = 0; i < v->size; ++i)
+ tmp_ctn[i] = v->container[i];
+
+ free(v->container);
+
+ v->container = tmp_ctn;
+ v->capacity = tmp_cap;
+
+ return (true);
+}
+
+/**
+ * @brief Initialize vector_str.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_init(struct vector_str *v)
+{
+
+ if (v == NULL)
+ return (false);
+
+ v->size = 0;
+ v->capacity = VECTOR_DEF_CAPACITY;
+
+ assert(v->capacity > 0);
+
+ if ((v->container = malloc(sizeof(char *) * v->capacity)) == NULL)
+ return (false);
+
+ assert(v->container != NULL);
+
+ return (true);
+}
+
+/**
+ * @brief Remove last element in vector_str.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_pop(struct vector_str *v)
+{
+
+ if (v == NULL)
+ return (false);
+
+ if (v->size == 0)
+ return (true);
+
+ --v->size;
+
+ free(v->container[v->size]);
+ v->container[v->size] = NULL;
+
+ return (true);
+}
+
+/**
+ * @brief Push back string to vector.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_push(struct vector_str *v, const char *str, size_t len)
+{
+
+ if (v == NULL || str == NULL)
+ return (false);
+
+ if (v->size == v->capacity && vector_str_grow(v) == false)
+ return (false);
+
+ if ((v->container[v->size] = malloc(sizeof(char) * (len + 1))) == NULL)
+ return (false);
+
+ snprintf(v->container[v->size], len + 1, "%s", str);
+
+ ++v->size;
+
+ return (true);
+}
+
+/**
+ * @brief Push front org vector to det vector.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org)
+{
+ size_t i, j, tmp_cap;
+ char **tmp_ctn;
+
+ if (dst == NULL || org == NULL)
+ return (false);
+
+ tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR;
+
+ if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
+ return (false);
+
+ for (i = 0; i < org->size; ++i)
+ if ((tmp_ctn[i] = strdup(org->container[i])) == NULL) {
+ for (j = 0; j < i; ++j)
+ free(tmp_ctn[j]);
+
+ free(tmp_ctn);
+
+ return (false);
+ }
+
+ for (i = 0; i < dst->size; ++i)
+ tmp_ctn[i + org->size] = dst->container[i];
+
+ free(dst->container);
+
+ dst->container = tmp_ctn;
+ dst->capacity = tmp_cap;
+ dst->size += org->size;
+
+ return (true);
+}
+
+/**
+ * @brief Get new allocated flat string from vector between begin and end.
+ *
+ * If r_len is not NULL, string length will be returned.
+ * @return NULL at failed or NUL terminated new allocated string.
+ */
+char *
+vector_str_substr(const struct vector_str *v, size_t begin, size_t end,
+ size_t *r_len)
+{
+ size_t cur, i, len;
+ char *rtn;
+
+ if (v == NULL || begin > end)
+ return (NULL);
+
+ len = 0;
+ for (i = begin; i < end + 1; ++i)
+ len += strlen(v->container[i]);
+
+ if ((rtn = malloc(sizeof(char) * (len + 1))) == NULL)
+ return (NULL);
+
+ if (r_len != NULL)
+ *r_len = len;
+
+ cur = 0;
+ for (i = begin; i < end + 1; ++i) {
+ len = strlen(v->container[i]);
+ memcpy(rtn + cur, v->container[i], len);
+ cur += len;
+ }
+ rtn[cur] = '\0';
+
+ return (rtn);
+}
diff --git a/contrib/elftoolchain/libelftc/make-toolchain-version b/contrib/elftoolchain/libelftc/make-toolchain-version
new file mode 100755
index 0000000..ac6155a
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/make-toolchain-version
@@ -0,0 +1,104 @@
+#!/bin/sh
+#
+# This script generates a project-wide version identifier for use by
+# the `elftc_version()' API.
+#
+# $Id: make-toolchain-version 2583 2012-09-14 09:49:25Z jkoshy $
+
+#
+# Defaults.
+#
+buildhost=`uname -s`
+elftcname="elftoolchain"
+options="e:h:o:r:t:"
+top=""
+version="HEAD"
+versionfile="elftc_version.c"
+progname=`basename ${0}`
+
+usage()
+{
+ exec >&2
+
+ # Print a message, if supplied.
+ if [ -n "${*}" ]; then echo "##${@}"; fi
+
+ echo "Usage: ${progname} [options]"
+ echo " Generate a toolchain-wide version number"
+ echo " -e PROJECTNAME Set the project name [default: ${elftcname}]."
+ echo " -h HOSTOS Set the build OS [default: ${buildhost}]."
+ echo " -o OUTPUT Set the output file [default: ${versionfile}]."
+ echo " -r VERSION Set the version string [default: ${version}]."
+ echo " -t TOPDIR Set the top-of-tree directory [required]."
+ exit 1
+}
+
+#
+# Parse options.
+#
+
+while getopts ${options} option
+do
+ case ${option} in
+ 'e') elftcname="${OPTARG}" ;;
+ 'h') buildhost="${OPTARG}" ;;
+ 'o') versionfile="${OPTARG}" ;;
+ 'r') version="${OPTARG}" ;;
+ 't') top="${OPTARG}" ;;
+ '?') usage ;;
+ esac
+done
+
+[ -n "${top}" ] || usage
+
+# Try to determine the in-tree revision number.
+#
+# This script attempts to handle the case where our sources have been
+# incorporated into an operating system's base sources.
+#
+# - If SVN is detected, we use the `svninfo' tool to determine the
+# in-tree revision number.
+# - If CVS is detected, we use the string `unknown'.
+# - Otherwise, we use `git --describe'.
+
+curdir=`pwd`
+cd ${top} || usage "ERROR: Cannot change directory to \"${top}\"."
+
+if [ -d .svn ]; then # FreeBSD and SF.Net sources.
+ versionstring=" svn:"$(svnversion)
+elif [ -d CVS ]; then # NetBSD.
+ versionstring=" cvs:unknown"
+else # DragonFlyBSD.
+ versionstring=" git:"$(git describe --all --dirty --long 2> /dev/null)
+
+ # Cannot determine an in-tree version number.
+ if [ $? -ne 0 ]; then
+ versionstring=""
+ fi
+fi
+
+cd ${curdir} || usage "Cannot change back to ${curdir}."
+
+#
+# Only replace the source file if its content has changed.
+#
+tmpfile=`mktemp ${TMPDIR:-/tmp}/MV.XXXXXXX`
+trap "rm -f ${tmpfile};" 0 1 2 3 15
+
+cat > ${tmpfile} <<EOF
+/* WARNING: Generated by "${progname}". */
+
+#include <sys/types.h>
+#include <libelftc.h>
+
+const char *
+elftc_version(void)
+{
+ return "${elftcname} ${version} ${buildhost}${versionstring}";
+}
+EOF
+
+if ! cmp -s ${tmpfile} ${versionfile}; then
+ echo "@ ${progname}: building \"${versionfile}\"."
+ cp ${tmpfile} ${versionfile} || exit ${?}
+fi
diff --git a/contrib/elftoolchain/libelftc/os.FreeBSD.mk b/contrib/elftoolchain/libelftc/os.FreeBSD.mk
new file mode 100644
index 0000000..8079a5b
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/os.FreeBSD.mk
@@ -0,0 +1,7 @@
+#
+# Building for a FreeBSD target.
+#
+# $Id: os.freebsd.mk 189 2008-07-20 10:38:08Z jkoshy $
+
+# Symbol versioning support [FreeBSD 7.X and later]
+VERSION_MAP= ${.CURDIR}/Version.map
diff --git a/contrib/elftoolchain/libelftc/os.Linux.mk b/contrib/elftoolchain/libelftc/os.Linux.mk
new file mode 100644
index 0000000..9730bf6
--- /dev/null
+++ b/contrib/elftoolchain/libelftc/os.Linux.mk
@@ -0,0 +1,3 @@
+# $Id: os.Linux.mk 994 2010-06-13 10:39:19Z jkoshy $
+
+CFLAGS+= -Wall
OpenPOWER on IntegriCloud