[rtems-tools commit] elftoolchain: Add libelftc.

Chris Johns chrisj at rtems.org
Tue Jun 19 03:44:14 UTC 2018


Module:    rtems-tools
Branch:    master
Commit:    1f1a10f4716e8d9b166f9c4741554fbbfa26fe66
Changeset: http://git.rtems.org/rtems-tools/commit/?id=1f1a10f4716e8d9b166f9c4741554fbbfa26fe66

Author:    Chris Johns <chrisj at rtems.org>
Date:      Wed May 23 20:39:54 2018 +1200

elftoolchain: Add libelftc.

---

 rtemstoolkit/elftoolchain/libelftc/Makefile        |   60 +
 rtemstoolkit/elftoolchain/libelftc/_libelftc.h     |   95 +
 rtemstoolkit/elftoolchain/libelftc/elftc.3         |   83 +
 .../elftoolchain/libelftc/elftc_bfd_find_target.3  |  200 +
 .../elftoolchain/libelftc/elftc_bfdtarget.c        |   73 +
 .../elftoolchain/libelftc/elftc_copyfile.3         |   73 +
 .../elftoolchain/libelftc/elftc_copyfile.c         |  113 +
 .../elftoolchain/libelftc/elftc_demangle.3         |  116 +
 .../elftoolchain/libelftc/elftc_demangle.c         |  107 +
 .../elftoolchain/libelftc/elftc_reloc_type_str.3   |   72 +
 .../elftoolchain/libelftc/elftc_reloc_type_str.c   |  832 ++++
 .../elftoolchain/libelftc/elftc_set_timestamps.3   |   84 +
 .../elftoolchain/libelftc/elftc_set_timestamps.c   |   85 +
 .../elftoolchain/libelftc/elftc_string_table.c     |  392 ++
 .../libelftc/elftc_string_table_create.3           |  227 ++
 .../elftoolchain/libelftc/elftc_timestamp.3        |   79 +
 .../elftoolchain/libelftc/elftc_timestamp.c        |   55 +
 rtemstoolkit/elftoolchain/libelftc/elftc_version.3 |   79 +
 rtemstoolkit/elftoolchain/libelftc/elftc_version.c |   10 +
 rtemstoolkit/elftoolchain/libelftc/libelftc.h      |  100 +
 .../elftoolchain/libelftc/libelftc_bfdtarget.c     |  463 +++
 .../elftoolchain/libelftc/libelftc_dem_arm.c       | 1216 ++++++
 .../elftoolchain/libelftc/libelftc_dem_gnu2.c      | 1365 +++++++
 .../elftoolchain/libelftc/libelftc_dem_gnu3.c      | 3991 ++++++++++++++++++++
 rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c |   70 +
 rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c |  359 ++
 .../elftoolchain/libelftc/make-toolchain-version   |  110 +
 rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk   |    7 +
 rtemstoolkit/elftoolchain/libelftc/os.Linux.mk     |    3 +
 rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk    |    2 +
 rtemstoolkit/wscript                               |   24 +
 31 files changed, 10545 insertions(+)

diff --git a/rtemstoolkit/elftoolchain/libelftc/Makefile b/rtemstoolkit/elftoolchain/libelftc/Makefile
new file mode 100644
index 0000000..cf4efc0
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/Makefile
@@ -0,0 +1,60 @@
+# $Id: Makefile 3601 2018-04-12 16:58:53Z jkoshy $
+
+TOP=	..
+
+LIB=	elftc
+
+SRCS=	elftc_bfdtarget.c			\
+	elftc_copyfile.c			\
+	elftc_demangle.c			\
+	elftc_reloc_type_str.c			\
+	elftc_set_timestamps.c			\
+	elftc_string_table.c			\
+	elftc_timestamp.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
+
+ELFTC_VERSION_FILE=	${.OBJDIR}/elftc_version.c
+CLEANFILES+=		${ELFTC_VERSION_FILE}
+
+LDADD+=	-lelf
+
+MAN=	elftc.3 \
+	elftc_bfd_find_target.3 \
+	elftc_copyfile.3 \
+	elftc_demangle.3 \
+	elftc_reloc_type_str.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
+
+.if	!make(clean) && !make(clobber) && !make(obj)
+.BEGIN:	.SILENT
+	${.CURDIR}/make-toolchain-version -t ${.CURDIR}/${TOP} \
+	    -r ${RELEASE} -h ${OS_HOST} -o ${ELFTC_VERSION_FILE}
+.endif
+
+.include "${TOP}/mk/elftoolchain.lib.mk"
diff --git a/rtemstoolkit/elftoolchain/libelftc/_libelftc.h b/rtemstoolkit/elftoolchain/libelftc/_libelftc.h
new file mode 100644
index 0000000..a56e29e
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/_libelftc.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2009 Kai Wang
+ * Copyright (c) 2007,2008 Hyogeol Lee <hyogeollee at 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 3531 2017-06-05 05:08:43Z kaiwang27 $
+ */
+
+#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
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+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(struct vector_str *_dst,
+    struct vector_str *_org);
+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);
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __LIBELFTC_H */
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc.3 b/rtemstoolkit/elftoolchain/libelftc/elftc.3
new file mode 100644
index 0000000..bbf5173
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3
new file mode 100644
index 0000000..302c319
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_bfd_find_target.3
@@ -0,0 +1,200 @@
+.\" 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 3516 2017-02-10 02:33:08Z emaste $
+.\"
+.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" "Bit Width"
+.It Em Name Ta Em "Object Format" Ta Em "Byte Order" Ta Em "Bit Width"
+.It Li binary Ta Binary Ta - Ta -
+.It Li efi-app-ia32 Ta PE Ta LSB Ta 32
+.It Li efi-app-x86_64 Ta PE Ta LSB Ta 64
+.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-powerpc-freebsd 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 elf32-tradbigmips Ta ELF Ta MSB Ta 32
+.It Li elf32-tradlittlemips Ta ELF Ta LSB 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-littleaarch64 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-powerpc-freebsd 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-tradbigmips Ta ELF Ta MSB Ta 64
+.It Li elf64-tradlittlemips Ta ELF Ta LSB 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 pei-i386 Ta PE Ta LSB Ta 32
+.It Li pei-x86-64 Ta PE Ta LSB Ta 64
+.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/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c b/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c
new file mode 100644
index 0000000..a5ae1a6
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_bfdtarget.c
@@ -0,0 +1,73 @@
+/*-
+ * 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/param.h>
+#include <string.h>
+#include <libelftc.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: elftc_bfdtarget.c 3174 2015-03-27 17:13:41Z emaste $");
+
+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/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.3
new file mode 100644
index 0000000..4520433
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c
new file mode 100644
index 0000000..dac9c14
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_copyfile.c
@@ -0,0 +1,113 @@
+/*-
+ * 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 3297 2016-01-09 15:26:34Z jkoshy $");
+
+/*
+ * Copy the contents referenced by 'ifd' to 'ofd'.  Returns 0 on
+ * success and -1 on error.
+ */
+
+int
+elftc_copyfile(int ifd, int ofd)
+{
+	size_t file_size, n;
+	int buf_mmapped;
+	struct stat sb;
+	char *b, *buf;
+	ssize_t nr, nw;
+
+	/* 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;
+	file_size = (size_t) sb.st_size;
+
+#if	ELFTC_HAVE_MMAP
+	/*
+	 * Prefer mmap() if it is available.
+	 */
+	buf = mmap(NULL, file_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_mmapped == false) {
+		if ((buf = malloc(file_size)) == NULL)
+			return (-1);
+		b = buf;
+		for (n = file_size; n > 0; n -= (size_t) nr, b += nr) {
+			if ((nr = read(ifd, b, n)) < 0) {
+				free(buf);
+				return (-1);
+			}
+		}
+	}
+
+	/*
+	 * Write data to the output file descriptor.
+	 */
+	for (n = file_size, b = buf; n > 0; n -= (size_t) nw, b += nw)
+		if ((nw = write(ofd, b, n)) <= 0)
+			break;
+
+	/* Release the input buffer. */
+#if	ELFTC_HAVE_MMAP
+	if (buf_mmapped && munmap(buf, file_size) < 0)
+		return (-1);
+#endif
+
+	if (!buf_mmapped)
+		free(buf);
+
+	return (n > 0 ? -1 : 0);
+}
+
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.3
new file mode 100644
index 0000000..44cf007
--- /dev/null
+++ b/rtemstoolkit/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 3182 2015-04-10 16:08:10Z emaste $
+.\"
+.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/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c
new file mode 100644
index 0000000..945f777
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_demangle.c
@@ -0,0 +1,107 @@
+/*-
+ * 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/param.h>
+#include <assert.h>
+#include <errno.h>
+#include <libelftc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: elftc_demangle.c 3296 2016-01-09 14:17:28Z jkoshy $");
+
+static unsigned int
+is_mangled(const char *s, unsigned 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, unsigned int style, unsigned 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)
+{
+	unsigned 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/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3
new file mode 100644
index 0000000..5cd08a6
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.3
@@ -0,0 +1,72 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation.  All rights reserved.
+.\"
+.\" This documentation was written by Ed Maste under sponsorship of
+.\" the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" $Id$
+.\"
+.Dd February 19, 2016
+.Os
+.Dt ELFTC_RELOC_TYPE_STR 3
+.Sh NAME
+.Nm elftc_reloc_type_str
+.Nd return the type name for an ELF relocation
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft const char *
+.Fo elftc_reloc_type_str
+.Fa "unsigned int mach"
+.Fa "unsigned int type"
+.Fc
+.Sh DESCRIPTION
+Function
+.Fn elftc_reloc_type_str
+returns the name for specified relocation type.
+.Pp
+Argument
+.Ar mach
+specifies the machine (architecture) type.
+Argument
+.Ar type
+specifies the relocation value.
+.Sh RETURN VALUE
+Function
+.Fn elftc_program_version
+returns a pointer to a string constant, or to an internal character buffer
+if the relocation type is unknown.
+.Sh EXAMPLES
+To print ARM relocation type 7, use:
+.Bd -literal -offset indent
+#include <sys/types.h>
+#include <libelftc.h>
+#include <stdio.h>
+
+(void) printf("%s\en", elftc_reloc_type_str(EM_ARM, 7));
+.Ed
+.Sh ERRORS
+Function
+.Fn elftc_reloc_type_str
+always succeeds.
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c
new file mode 100644
index 0000000..fdad9a6
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_reloc_type_str.c
@@ -0,0 +1,832 @@
+/*-
+ * Copyright (c) 2009-2015 Kai Wang
+ * Copyright (c) 2016 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * Portions of this software were developed by Ed Maste under sponsorship
+ * of the FreeBSD Foundation.
+ *
+ * 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 <libelftc.h>
+#include <stdio.h>
+
+const char *
+elftc_reloc_type_str(unsigned int mach, unsigned int type)
+{
+	static char s_type[32];
+
+	switch(mach) {
+	case EM_386:
+	case EM_IAMCU:
+		switch(type) {
+		case 0: return "R_386_NONE";
+		case 1: return "R_386_32";
+		case 2: return "R_386_PC32";
+		case 3: return "R_386_GOT32";
+		case 4: return "R_386_PLT32";
+		case 5: return "R_386_COPY";
+		case 6: return "R_386_GLOB_DAT";
+		case 7: return "R_386_JUMP_SLOT";
+		case 8: return "R_386_RELATIVE";
+		case 9: return "R_386_GOTOFF";
+		case 10: return "R_386_GOTPC";
+		case 11: return "R_386_32PLT"; /* Not in psabi */
+		case 14: return "R_386_TLS_TPOFF";
+		case 15: return "R_386_TLS_IE";
+		case 16: return "R_386_TLS_GOTIE";
+		case 17: return "R_386_TLS_LE";
+		case 18: return "R_386_TLS_GD";
+		case 19: return "R_386_TLS_LDM";
+		case 20: return "R_386_16";
+		case 21: return "R_386_PC16";
+		case 22: return "R_386_8";
+		case 23: return "R_386_PC8";
+		case 24: return "R_386_TLS_GD_32";
+		case 25: return "R_386_TLS_GD_PUSH";
+		case 26: return "R_386_TLS_GD_CALL";
+		case 27: return "R_386_TLS_GD_POP";
+		case 28: return "R_386_TLS_LDM_32";
+		case 29: return "R_386_TLS_LDM_PUSH";
+		case 30: return "R_386_TLS_LDM_CALL";
+		case 31: return "R_386_TLS_LDM_POP";
+		case 32: return "R_386_TLS_LDO_32";
+		case 33: return "R_386_TLS_IE_32";
+		case 34: return "R_386_TLS_LE_32";
+		case 35: return "R_386_TLS_DTPMOD32";
+		case 36: return "R_386_TLS_DTPOFF32";
+		case 37: return "R_386_TLS_TPOFF32";
+		case 38: return "R_386_SIZE32";
+		case 39: return "R_386_TLS_GOTDESC";
+		case 40: return "R_386_TLS_DESC_CALL";
+		case 41: return "R_386_TLS_DESC";
+		case 42: return "R_386_IRELATIVE";
+		case 43: return "R_386_GOT32X";
+		}
+		break;
+	case EM_AARCH64:
+		switch(type) {
+		case 0: return "R_AARCH64_NONE";
+		case 257: return "R_AARCH64_ABS64";
+		case 258: return "R_AARCH64_ABS32";
+		case 259: return "R_AARCH64_ABS16";
+		case 260: return "R_AARCH64_PREL64";
+		case 261: return "R_AARCH64_PREL32";
+		case 262: return "R_AARCH64_PREL16";
+		case 263: return "R_AARCH64_MOVW_UABS_G0";
+		case 264: return "R_AARCH64_MOVW_UABS_G0_NC";
+		case 265: return "R_AARCH64_MOVW_UABS_G1";
+		case 266: return "R_AARCH64_MOVW_UABS_G1_NC";
+		case 267: return "R_AARCH64_MOVW_UABS_G2";
+		case 268: return "R_AARCH64_MOVW_UABS_G2_NC";
+		case 269: return "R_AARCH64_MOVW_UABS_G3";
+		case 270: return "R_AARCH64_MOVW_SABS_G0";
+		case 271: return "R_AARCH64_MOVW_SABS_G1";
+		case 272: return "R_AARCH64_MOVW_SABS_G2";
+		case 273: return "R_AARCH64_LD_PREL_LO19";
+		case 274: return "R_AARCH64_ADR_PREL_LO21";
+		case 275: return "R_AARCH64_ADR_PREL_PG_HI21";
+		case 276: return "R_AARCH64_ADR_PREL_PG_HI21_NC";
+		case 277: return "R_AARCH64_ADD_ABS_LO12_NC";
+		case 278: return "R_AARCH64_LDST8_ABS_LO12_NC";
+		case 279: return "R_AARCH64_TSTBR14";
+		case 280: return "R_AARCH64_CONDBR19";
+		case 282: return "R_AARCH64_JUMP26";
+		case 283: return "R_AARCH64_CALL26";
+		case 284: return "R_AARCH64_LDST16_ABS_LO12_NC";
+		case 285: return "R_AARCH64_LDST32_ABS_LO12_NC";
+		case 286: return "R_AARCH64_LDST64_ABS_LO12_NC";
+		case 287: return "R_AARCH64_MOVW_PREL_G0";
+		case 288: return "R_AARCH64_MOVW_PREL_G0_NC";
+		case 289: return "R_AARCH64_MOVW_PREL_G1";
+		case 290: return "R_AARCH64_MOVW_PREL_G1_NC";
+		case 291: return "R_AARCH64_MOVW_PREL_G2";
+		case 292: return "R_AARCH64_MOVW_PREL_G2_NC";
+		case 293: return "R_AARCH64_MOVW_PREL_G3";
+		case 299: return "R_AARCH64_LDST128_ABS_LO12_NC";
+		case 300: return "R_AARCH64_MOVW_GOTOFF_G0";
+		case 301: return "R_AARCH64_MOVW_GOTOFF_G0_NC";
+		case 302: return "R_AARCH64_MOVW_GOTOFF_G1";
+		case 303: return "R_AARCH64_MOVW_GOTOFF_G1_NC";
+		case 304: return "R_AARCH64_MOVW_GOTOFF_G2";
+		case 305: return "R_AARCH64_MOVW_GOTOFF_G2_NC";
+		case 306: return "R_AARCH64_MOVW_GOTOFF_G3";
+		case 307: return "R_AARCH64_GOTREL64";
+		case 308: return "R_AARCH64_GOTREL32";
+		case 309: return "R_AARCH64_GOT_LD_PREL19";
+		case 310: return "R_AARCH64_LD64_GOTOFF_LO15";
+		case 311: return "R_AARCH64_ADR_GOT_PAGE";
+		case 312: return "R_AARCH64_LD64_GOT_LO12_NC";
+		case 313: return "R_AARCH64_LD64_GOTPAGE_LO15";
+		case 560: return "R_AARCH64_TLSDESC_LD_PREL19";
+		case 561: return "R_AARCH64_TLSDESC_ADR_PREL21";
+		case 562: return "R_AARCH64_TLSDESC_ADR_PAGE21";
+		case 563: return "R_AARCH64_TLSDESC_LD64_LO12";
+		case 564: return "R_AARCH64_TLSDESC_ADD_LO12";
+		case 565: return "R_AARCH64_TLSDESC_OFF_G1";
+		case 566: return "R_AARCH64_TLSDESC_OFF_G0_NC";
+		case 567: return "R_AARCH64_TLSDESC_LDR";
+		case 568: return "R_AARCH64_TLSDESC_ADD";
+		case 569: return "R_AARCH64_TLSDESC_CALL";
+		case 1024: return "R_AARCH64_COPY";
+		case 1025: return "R_AARCH64_GLOB_DAT";
+		case 1026: return "R_AARCH64_JUMP_SLOT";
+		case 1027: return "R_AARCH64_RELATIVE";
+		case 1028: return "R_AARCH64_TLS_DTPREL64";
+		case 1029: return "R_AARCH64_TLS_DTPMOD64";
+		case 1030: return "R_AARCH64_TLS_TPREL64";
+		case 1031: return "R_AARCH64_TLSDESC";
+		case 1032: return "R_AARCH64_IRELATIVE";
+		}
+		break;
+	case EM_ARM:
+		switch(type) {
+		case 0: return "R_ARM_NONE";
+		case 1: return "R_ARM_PC24"; /* Deprecated */
+		case 2: return "R_ARM_ABS32";
+		case 3: return "R_ARM_REL32";
+		case 4: return "R_ARM_LDR_PC_G0"; /* Also R_ARM_PC13 */
+		case 5: return "R_ARM_ABS16";
+		case 6: return "R_ARM_ABS12";
+		case 7: return "R_ARM_THM_ABS5";
+		case 8: return "R_ARM_ABS8";
+		case 9: return "R_ARM_SBREL32";
+		case 10: return "R_ARM_THM_CALL"; /* Also R_ARM_THM_PC22 */
+		case 11: return "R_ARM_THM_PC8";
+		case 12: return "R_ARM_BREL_ADJ"; /* Also R_ARM_AMP_VCALL9 */
+		case 13: return "R_ARM_TLS_DESC"; /* Also R_ARM_SWI24 */
+		case 14: return "R_ARM_THM_SWI8"; /* Obsolete */
+		case 15: return "R_ARM_XPC25"; /* Obsolete */
+		case 16: return "R_ARM_THM_XPC22"; /* Obsolete */
+		case 17: return "R_ARM_TLS_DTPMOD32";
+		case 18: return "R_ARM_TLS_DTPOFF32";
+		case 19: return "R_ARM_TLS_TPOFF32";
+		case 20: return "R_ARM_COPY";
+		case 21: return "R_ARM_GLOB_DAT";
+		case 22: return "R_ARM_JUMP_SLOT";
+		case 23: return "R_ARM_RELATIVE";
+		case 24: return "R_ARM_GOTOFF32"; /* Also R_ARM_GOTOFF */
+		case 25: return "R_ARM_BASE_PREL"; /* GNU R_ARM_GOTPC */
+		case 26: return "R_ARM_GOT_BREL"; /* GNU R_ARM_GOT32 */
+		case 27: return "R_ARM_PLT32"; /* Deprecated */
+		case 28: return "R_ARM_CALL";
+		case 29: return "R_ARM_JUMP24";
+		case 30: return "R_ARM_THM_JUMP24";
+		case 31: return "R_ARM_BASE_ABS";
+		case 32: return "R_ARM_ALU_PCREL_7_0"; /* Obsolete */
+		case 33: return "R_ARM_ALU_PCREL_15_8"; /* Obsolete */
+		case 34: return "R_ARM_ALU_PCREL_23_15"; /* Obsolete */
+		case 35: return "R_ARM_LDR_SBREL_11_0_NC"; /* Deprecated */
+		case 36: return "R_ARM_ALU_SBREL_19_12_NC"; /* Deprecated */
+		case 37: return "R_ARM_ALU_SBREL_27_20_CK"; /* Deprecated */
+		case 38: return "R_ARM_TARGET1";
+		case 39: return "R_ARM_SBREL31"; /* Deprecated. */
+		case 40: return "R_ARM_V4BX";
+		case 41: return "R_ARM_TARGET2";
+		case 42: return "R_ARM_PREL31";
+		case 43: return "R_ARM_MOVW_ABS_NC";
+		case 44: return "R_ARM_MOVT_ABS";
+		case 45: return "R_ARM_MOVW_PREL_NC";
+		case 46: return "R_ARM_MOVT_PREL";
+		case 47: return "R_ARM_THM_MOVW_ABS_NC";
+		case 48: return "R_ARM_THM_MOVT_ABS";
+		case 49: return "R_ARM_THM_MOVW_PREL_NC";
+		case 50: return "R_ARM_THM_MOVT_PREL";
+		case 51: return "R_ARM_THM_JUMP19";
+		case 52: return "R_ARM_THM_JUMP6";
+		case 53: return "R_ARM_THM_ALU_PREL_11_0";
+		case 54: return "R_ARM_THM_PC12";
+		case 55: return "R_ARM_ABS32_NOI";
+		case 56: return "R_ARM_REL32_NOI";
+		case 57: return "R_ARM_ALU_PC_G0_NC";
+		case 58: return "R_ARM_ALU_PC_G0";
+		case 59: return "R_ARM_ALU_PC_G1_NC";
+		case 60: return "R_ARM_ALU_PC_G1";
+		case 61: return "R_ARM_ALU_PC_G2";
+		case 62: return "R_ARM_LDR_PC_G1";
+		case 63: return "R_ARM_LDR_PC_G2";
+		case 64: return "R_ARM_LDRS_PC_G0";
+		case 65: return "R_ARM_LDRS_PC_G1";
+		case 66: return "R_ARM_LDRS_PC_G2";
+		case 67: return "R_ARM_LDC_PC_G0";
+		case 68: return "R_ARM_LDC_PC_G1";
+		case 69: return "R_ARM_LDC_PC_G2";
+		case 70: return "R_ARM_ALU_SB_G0_NC";
+		case 71: return "R_ARM_ALU_SB_G0";
+		case 72: return "R_ARM_ALU_SB_G1_NC";
+		case 73: return "R_ARM_ALU_SB_G1";
+		case 74: return "R_ARM_ALU_SB_G2";
+		case 75: return "R_ARM_LDR_SB_G0";
+		case 76: return "R_ARM_LDR_SB_G1";
+		case 77: return "R_ARM_LDR_SB_G2";
+		case 78: return "R_ARM_LDRS_SB_G0";
+		case 79: return "R_ARM_LDRS_SB_G1";
+		case 80: return "R_ARM_LDRS_SB_G2";
+		case 81: return "R_ARM_LDC_SB_G0";
+		case 82: return "R_ARM_LDC_SB_G1";
+		case 83: return "R_ARM_LDC_SB_G2";
+		case 84: return "R_ARM_MOVW_BREL_NC";
+		case 85: return "R_ARM_MOVT_BREL";
+		case 86: return "R_ARM_MOVW_BREL";
+		case 87: return "R_ARM_THM_MOVW_BREL_NC";
+		case 88: return "R_ARM_THM_MOVT_BREL";
+		case 89: return "R_ARM_THM_MOVW_BREL";
+		case 90: return "R_ARM_TLS_GOTDESC";
+		case 91: return "R_ARM_TLS_CALL";
+		case 92: return "R_ARM_TLS_DESCSEQ";
+		case 93: return "R_ARM_THM_TLS_CALL";
+		case 94: return "R_ARM_PLT32_ABS";
+		case 95: return "R_ARM_GOT_ABS";
+		case 96: return "R_ARM_GOT_PREL";
+		case 97: return "R_ARM_GOT_BREL12";
+		case 98: return "R_ARM_GOTOFF12";
+		case 99: return "R_ARM_GOTRELAX";
+		case 100: return "R_ARM_GNU_VTENTRY";
+		case 101: return "R_ARM_GNU_VTINHERIT";
+		case 102: return "R_ARM_THM_JUMP11"; /* Also R_ARM_THM_PC11 */
+		case 103: return "R_ARM_THM_JUMP8"; /* Also R_ARM_THM_PC9 */
+		case 104: return "R_ARM_TLS_GD32";
+		case 105: return "R_ARM_TLS_LDM32";
+		case 106: return "R_ARM_TLS_LDO32";
+		case 107: return "R_ARM_TLS_IE32";
+		case 108: return "R_ARM_TLS_LE32";
+		case 109: return "R_ARM_TLS_LDO12";
+		case 110: return "R_ARM_TLS_LE12";
+		case 111: return "R_ARM_TLS_IE12GP";
+		/* 112-127 R_ARM_PRIVATE_<n> */
+		case 128: return "R_ARM_ME_TOO"; /* Obsolete */
+		case 129: return "R_ARM_THM_TLS_DESCSEQ16";
+		case 130: return "R_ARM_THM_TLS_DESCSEQ32";
+		case 131: return "R_ARM_THM_GOT_BREL12";
+		case 132: return "R_ARM_THM_ALU_ABS_G0_NC";
+		case 133: return "R_ARM_THM_ALU_ABS_G1_NC";
+		case 134: return "R_ARM_THM_ALU_ABS_G2_NC";
+		case 135: return "R_ARM_THM_ALU_ABS_G3";
+		/* 136-159 Reserved for future allocation. */
+		case 160: return "R_ARM_IRELATIVE";
+		/* 161-255 Reserved for future allocation. */
+		case 249: return "R_ARM_RXPC25";
+		case 250: return "R_ARM_RSBREL32";
+		case 251: return "R_ARM_THM_RPC22";
+		case 252: return "R_ARM_RREL32";
+		case 253: return "R_ARM_RABS32";
+		case 254: return "R_ARM_RPC24";
+		case 255: return "R_ARM_RBASE";
+		}
+		break;
+	case EM_IA_64:
+		switch(type) {
+		case 0: return "R_IA_64_NONE";
+		case 33: return "R_IA_64_IMM14";
+		case 34: return "R_IA_64_IMM22";
+		case 35: return "R_IA_64_IMM64";
+		case 36: return "R_IA_64_DIR32MSB";
+		case 37: return "R_IA_64_DIR32LSB";
+		case 38: return "R_IA_64_DIR64MSB";
+		case 39: return "R_IA_64_DIR64LSB";
+		case 42: return "R_IA_64_GPREL22";
+		case 43: return "R_IA_64_GPREL64I";
+		case 44: return "R_IA_64_GPREL32MSB";
+		case 45: return "R_IA_64_GPREL32LSB";
+		case 46: return "R_IA_64_GPREL64MSB";
+		case 47: return "R_IA_64_GPREL64LSB";
+		case 50: return "R_IA_64_LTOFF22";
+		case 51: return "R_IA_64_LTOFF64I";
+		case 58: return "R_IA_64_PLTOFF22";
+		case 59: return "R_IA_64_PLTOFF64I";
+		case 62: return "R_IA_64_PLTOFF64MSB";
+		case 63: return "R_IA_64_PLTOFF64LSB";
+		case 67: return "R_IA_64_FPTR64I";
+		case 68: return "R_IA_64_FPTR32MSB";
+		case 69: return "R_IA_64_FPTR32LSB";
+		case 70: return "R_IA_64_FPTR64MSB";
+		case 71: return "R_IA_64_FPTR64LSB";
+		case 72: return "R_IA_64_PCREL60B";
+		case 73: return "R_IA_64_PCREL21B";
+		case 74: return "R_IA_64_PCREL21M";
+		case 75: return "R_IA_64_PCREL21F";
+		case 76: return "R_IA_64_PCREL32MSB";
+		case 77: return "R_IA_64_PCREL32LSB";
+		case 78: return "R_IA_64_PCREL64MSB";
+		case 79: return "R_IA_64_PCREL64LSB";
+		case 82: return "R_IA_64_LTOFF_FPTR22";
+		case 83: return "R_IA_64_LTOFF_FPTR64I";
+		case 84: return "R_IA_64_LTOFF_FPTR32MSB";
+		case 85: return "R_IA_64_LTOFF_FPTR32LSB";
+		case 86: return "R_IA_64_LTOFF_FPTR64MSB";
+		case 87: return "R_IA_64_LTOFF_FPTR64LSB";
+		case 92: return "R_IA_64_SEGREL32MSB";
+		case 93: return "R_IA_64_SEGREL32LSB";
+		case 94: return "R_IA_64_SEGREL64MSB";
+		case 95: return "R_IA_64_SEGREL64LSB";
+		case 100: return "R_IA_64_SECREL32MSB";
+		case 101: return "R_IA_64_SECREL32LSB";
+		case 102: return "R_IA_64_SECREL64MSB";
+		case 103: return "R_IA_64_SECREL64LSB";
+		case 108: return "R_IA_64_REL32MSB";
+		case 109: return "R_IA_64_REL32LSB";
+		case 110: return "R_IA_64_REL64MSB";
+		case 111: return "R_IA_64_REL64LSB";
+		case 116: return "R_IA_64_LTV32MSB";
+		case 117: return "R_IA_64_LTV32LSB";
+		case 118: return "R_IA_64_LTV64MSB";
+		case 119: return "R_IA_64_LTV64LSB";
+		case 121: return "R_IA_64_PCREL21BI";
+		case 122: return "R_IA_64_PCREL22";
+		case 123: return "R_IA_64_PCREL64I";
+		case 128: return "R_IA_64_IPLTMSB";
+		case 129: return "R_IA_64_IPLTLSB";
+		case 133: return "R_IA_64_SUB";
+		case 134: return "R_IA_64_LTOFF22X";
+		case 135: return "R_IA_64_LDXMOV";
+		case 145: return "R_IA_64_TPREL14";
+		case 146: return "R_IA_64_TPREL22";
+		case 147: return "R_IA_64_TPREL64I";
+		case 150: return "R_IA_64_TPREL64MSB";
+		case 151: return "R_IA_64_TPREL64LSB";
+		case 154: return "R_IA_64_LTOFF_TPREL22";
+		case 166: return "R_IA_64_DTPMOD64MSB";
+		case 167: return "R_IA_64_DTPMOD64LSB";
+		case 170: return "R_IA_64_LTOFF_DTPMOD22";
+		case 177: return "R_IA_64_DTPREL14";
+		case 178: return "R_IA_64_DTPREL22";
+		case 179: return "R_IA_64_DTPREL64I";
+		case 180: return "R_IA_64_DTPREL32MSB";
+		case 181: return "R_IA_64_DTPREL32LSB";
+		case 182: return "R_IA_64_DTPREL64MSB";
+		case 183: return "R_IA_64_DTPREL64LSB";
+		case 186: return "R_IA_64_LTOFF_DTPREL22";
+		}
+		break;
+	case EM_MIPS:
+		switch(type) {
+		case 0: return "R_MIPS_NONE";
+		case 1: return "R_MIPS_16";
+		case 2: return "R_MIPS_32";
+		case 3: return "R_MIPS_REL32";
+		case 4: return "R_MIPS_26";
+		case 5: return "R_MIPS_HI16";
+		case 6: return "R_MIPS_LO16";
+		case 7: return "R_MIPS_GPREL16";
+		case 8: return "R_MIPS_LITERAL";
+		case 9: return "R_MIPS_GOT16";
+		case 10: return "R_MIPS_PC16";
+		case 11: return "R_MIPS_CALL16";
+		case 12: return "R_MIPS_GPREL32";
+		case 16: return "R_MIPS_SHIFT5";
+		case 17: return "R_MIPS_SHIFT6";
+		case 18: return "R_MIPS_64";
+		case 19: return "R_MIPS_GOT_DISP";
+		case 20: return "R_MIPS_GOT_PAGE";
+		case 21: return "R_MIPS_GOT_OFST";
+		case 22: return "R_MIPS_GOT_HI16";
+		case 23: return "R_MIPS_GOT_LO16";
+		case 24: return "R_MIPS_SUB";
+		case 30: return "R_MIPS_CALLHI16";
+		case 31: return "R_MIPS_CALLLO16";
+		case 37: return "R_MIPS_JALR";
+		case 38: return "R_MIPS_TLS_DTPMOD32";
+		case 39: return "R_MIPS_TLS_DTPREL32";
+		case 40: return "R_MIPS_TLS_DTPMOD64";
+		case 41: return "R_MIPS_TLS_DTPREL64";
+		case 42: return "R_MIPS_TLS_GD";
+		case 43: return "R_MIPS_TLS_LDM";
+		case 44: return "R_MIPS_TLS_DTPREL_HI16";
+		case 45: return "R_MIPS_TLS_DTPREL_LO16";
+		case 46: return "R_MIPS_TLS_GOTTPREL";
+		case 47: return "R_MIPS_TLS_TPREL32";
+		case 48: return "R_MIPS_TLS_TPREL64";
+		case 49: return "R_MIPS_TLS_TPREL_HI16";
+		case 50: return "R_MIPS_TLS_TPREL_LO16";
+		}
+		break;
+	case EM_PPC:
+		switch(type) {
+		case 0: return "R_PPC_NONE";
+		case 1: return "R_PPC_ADDR32";
+		case 2: return "R_PPC_ADDR24";
+		case 3: return "R_PPC_ADDR16";
+		case 4: return "R_PPC_ADDR16_LO";
+		case 5: return "R_PPC_ADDR16_HI";
+		case 6: return "R_PPC_ADDR16_HA";
+		case 7: return "R_PPC_ADDR14";
+		case 8: return "R_PPC_ADDR14_BRTAKEN";
+		case 9: return "R_PPC_ADDR14_BRNTAKEN";
+		case 10: return "R_PPC_REL24";
+		case 11: return "R_PPC_REL14";
+		case 12: return "R_PPC_REL14_BRTAKEN";
+		case 13: return "R_PPC_REL14_BRNTAKEN";
+		case 14: return "R_PPC_GOT16";
+		case 15: return "R_PPC_GOT16_LO";
+		case 16: return "R_PPC_GOT16_HI";
+		case 17: return "R_PPC_GOT16_HA";
+		case 18: return "R_PPC_PLTREL24";
+		case 19: return "R_PPC_COPY";
+		case 20: return "R_PPC_GLOB_DAT";
+		case 21: return "R_PPC_JMP_SLOT";
+		case 22: return "R_PPC_RELATIVE";
+		case 23: return "R_PPC_LOCAL24PC";
+		case 24: return "R_PPC_UADDR32";
+		case 25: return "R_PPC_UADDR16";
+		case 26: return "R_PPC_REL32";
+		case 27: return "R_PPC_PLT32";
+		case 28: return "R_PPC_PLTREL32";
+		case 29: return "R_PPC_PLT16_LO";
+		case 30: return "R_PPC_PLT16_HI";
+		case 31: return "R_PPC_PLT16_HA";
+		case 32: return "R_PPC_SDAREL16";
+		case 33: return "R_PPC_SECTOFF";
+		case 34: return "R_PPC_SECTOFF_LO";
+		case 35: return "R_PPC_SECTOFF_HI";
+		case 36: return "R_PPC_SECTOFF_HA";
+		case 67: return "R_PPC_TLS";
+		case 68: return "R_PPC_DTPMOD32";
+		case 69: return "R_PPC_TPREL16";
+		case 70: return "R_PPC_TPREL16_LO";
+		case 71: return "R_PPC_TPREL16_HI";
+		case 72: return "R_PPC_TPREL16_HA";
+		case 73: return "R_PPC_TPREL32";
+		case 74: return "R_PPC_DTPREL16";
+		case 75: return "R_PPC_DTPREL16_LO";
+		case 76: return "R_PPC_DTPREL16_HI";
+		case 77: return "R_PPC_DTPREL16_HA";
+		case 78: return "R_PPC_DTPREL32";
+		case 79: return "R_PPC_GOT_TLSGD16";
+		case 80: return "R_PPC_GOT_TLSGD16_LO";
+		case 81: return "R_PPC_GOT_TLSGD16_HI";
+		case 82: return "R_PPC_GOT_TLSGD16_HA";
+		case 83: return "R_PPC_GOT_TLSLD16";
+		case 84: return "R_PPC_GOT_TLSLD16_LO";
+		case 85: return "R_PPC_GOT_TLSLD16_HI";
+		case 86: return "R_PPC_GOT_TLSLD16_HA";
+		case 87: return "R_PPC_GOT_TPREL16";
+		case 88: return "R_PPC_GOT_TPREL16_LO";
+		case 89: return "R_PPC_GOT_TPREL16_HI";
+		case 90: return "R_PPC_GOT_TPREL16_HA";
+		case 101: return "R_PPC_EMB_NADDR32";
+		case 102: return "R_PPC_EMB_NADDR16";
+		case 103: return "R_PPC_EMB_NADDR16_LO";
+		case 104: return "R_PPC_EMB_NADDR16_HI";
+		case 105: return "R_PPC_EMB_NADDR16_HA";
+		case 106: return "R_PPC_EMB_SDAI16";
+		case 107: return "R_PPC_EMB_SDA2I16";
+		case 108: return "R_PPC_EMB_SDA2REL";
+		case 109: return "R_PPC_EMB_SDA21";
+		case 110: return "R_PPC_EMB_MRKREF";
+		case 111: return "R_PPC_EMB_RELSEC16";
+		case 112: return "R_PPC_EMB_RELST_LO";
+		case 113: return "R_PPC_EMB_RELST_HI";
+		case 114: return "R_PPC_EMB_RELST_HA";
+		case 115: return "R_PPC_EMB_BIT_FLD";
+		case 116: return "R_PPC_EMB_RELSDA";
+		}
+		break;
+	case EM_PPC64:
+		switch(type) {
+		case 0: return "R_PPC64_NONE";
+		case 1: return "R_PPC64_ADDR32";
+		case 2: return "R_PPC64_ADDR24";
+		case 3: return "R_PPC64_ADDR16";
+		case 4: return "R_PPC64_ADDR16_LO";
+		case 5: return "R_PPC64_ADDR16_HI";
+		case 6: return "R_PPC64_ADDR16_HA";
+		case 7: return "R_PPC64_ADDR14";
+		case 8: return "R_PPC64_ADDR14_BRTAKEN";
+		case 9: return "R_PPC64_ADDR14_BRNTAKEN";
+		case 10: return "R_PPC64_REL24";
+		case 11: return "R_PPC64_REL14";
+		case 12: return "R_PPC64_REL14_BRTAKEN";
+		case 13: return "R_PPC64_REL14_BRNTAKEN";
+		case 14: return "R_PPC64_GOT16";
+		case 15: return "R_PPC64_GOT16_LO";
+		case 16: return "R_PPC64_GOT16_HI";
+		case 17: return "R_PPC64_GOT16_HA";
+		case 19: return "R_PPC64_COPY";
+		case 20: return "R_PPC64_GLOB_DAT";
+		case 21: return "R_PPC64_JMP_SLOT";
+		case 22: return "R_PPC64_RELATIVE";
+		case 24: return "R_PPC64_UADDR32";
+		case 25: return "R_PPC64_UADDR16";
+		case 26: return "R_PPC64_REL32";
+		case 27: return "R_PPC64_PLT32";
+		case 28: return "R_PPC64_PLTREL32";
+		case 29: return "R_PPC64_PLT16_LO";
+		case 30: return "R_PPC64_PLT16_HI";
+		case 31: return "R_PPC64_PLT16_HA";
+		case 33: return "R_PPC64_SECTOFF";
+		case 34: return "R_PPC64_SECTOFF_LO";
+		case 35: return "R_PPC64_SECTOFF_HI";
+		case 36: return "R_PPC64_SECTOFF_HA";
+		case 37: return "R_PPC64_ADDR30";
+		case 38: return "R_PPC64_ADDR64";
+		case 39: return "R_PPC64_ADDR16_HIGHER";
+		case 40: return "R_PPC64_ADDR16_HIGHERA";
+		case 41: return "R_PPC64_ADDR16_HIGHEST";
+		case 42: return "R_PPC64_ADDR16_HIGHESTA";
+		case 43: return "R_PPC64_UADDR64";
+		case 44: return "R_PPC64_REL64";
+		case 45: return "R_PPC64_PLT64";
+		case 46: return "R_PPC64_PLTREL64";
+		case 47: return "R_PPC64_TOC16";
+		case 48: return "R_PPC64_TOC16_LO";
+		case 49: return "R_PPC64_TOC16_HI";
+		case 50: return "R_PPC64_TOC16_HA";
+		case 51: return "R_PPC64_TOC";
+		case 52: return "R_PPC64_PLTGOT16";
+		case 53: return "R_PPC64_PLTGOT16_LO";
+		case 54: return "R_PPC64_PLTGOT16_HI";
+		case 55: return "R_PPC64_PLTGOT16_HA";
+		case 56: return "R_PPC64_ADDR16_DS";
+		case 57: return "R_PPC64_ADDR16_LO_DS";
+		case 58: return "R_PPC64_GOT16_DS";
+		case 59: return "R_PPC64_GOT16_LO_DS";
+		case 60: return "R_PPC64_PLT16_LO_DS";
+		case 61: return "R_PPC64_SECTOFF_DS";
+		case 62: return "R_PPC64_SECTOFF_LO_DS";
+		case 63: return "R_PPC64_TOC16_DS";
+		case 64: return "R_PPC64_TOC16_LO_DS";
+		case 65: return "R_PPC64_PLTGOT16_DS";
+		case 66: return "R_PPC64_PLTGOT16_LO_DS";
+		case 67: return "R_PPC64_TLS";
+		case 68: return "R_PPC64_DTPMOD64";
+		case 69: return "R_PPC64_TPREL16";
+		case 70: return "R_PPC64_TPREL16_LO";
+		case 71: return "R_PPC64_TPREL16_HI";
+		case 72: return "R_PPC64_TPREL16_HA";
+		case 73: return "R_PPC64_TPREL64";
+		case 74: return "R_PPC64_DTPREL16";
+		case 75: return "R_PPC64_DTPREL16_LO";
+		case 76: return "R_PPC64_DTPREL16_HI";
+		case 77: return "R_PPC64_DTPREL16_HA";
+		case 78: return "R_PPC64_DTPREL64";
+		case 79: return "R_PPC64_GOT_TLSGD16";
+		case 80: return "R_PPC64_GOT_TLSGD16_LO";
+		case 81: return "R_PPC64_GOT_TLSGD16_HI";
+		case 82: return "R_PPC64_GOT_TLSGD16_HA";
+		case 83: return "R_PPC64_GOT_TLSLD16";
+		case 84: return "R_PPC64_GOT_TLSLD16_LO";
+		case 85: return "R_PPC64_GOT_TLSLD16_HI";
+		case 86: return "R_PPC64_GOT_TLSLD16_HA";
+		case 87: return "R_PPC64_GOT_TPREL16_DS";
+		case 88: return "R_PPC64_GOT_TPREL16_LO_DS";
+		case 89: return "R_PPC64_GOT_TPREL16_HI";
+		case 90: return "R_PPC64_GOT_TPREL16_HA";
+		case 91: return "R_PPC64_GOT_DTPREL16_DS";
+		case 92: return "R_PPC64_GOT_DTPREL16_LO_DS";
+		case 93: return "R_PPC64_GOT_DTPREL16_HI";
+		case 94: return "R_PPC64_GOT_DTPREL16_HA";
+		case 95: return "R_PPC64_TPREL16_DS";
+		case 96: return "R_PPC64_TPREL16_LO_DS";
+		case 97: return "R_PPC64_TPREL16_HIGHER";
+		case 98: return "R_PPC64_TPREL16_HIGHERA";
+		case 99: return "R_PPC64_TPREL16_HIGHEST";
+		case 100: return "R_PPC64_TPREL16_HIGHESTA";
+		case 101: return "R_PPC64_DTPREL16_DS";
+		case 102: return "R_PPC64_DTPREL16_LO_DS";
+		case 103: return "R_PPC64_DTPREL16_HIGHER";
+		case 104: return "R_PPC64_DTPREL16_HIGHERA";
+		case 105: return "R_PPC64_DTPREL16_HIGHEST";
+		case 106: return "R_PPC64_DTPREL16_HIGHESTA";
+		case 107: return "R_PPC64_TLSGD";
+		case 108: return "R_PPC64_TLSLD";
+		case 249: return "R_PPC64_REL16";
+		case 250: return "R_PPC64_REL16_LO";
+		case 251: return "R_PPC64_REL16_HI";
+		case 252: return "R_PPC64_REL16_HA";
+		}
+		break;
+	case EM_RISCV:
+		switch(type) {
+		case 0: return "R_RISCV_NONE";
+		case 1: return "R_RISCV_32";
+		case 2: return "R_RISCV_64";
+		case 3: return "R_RISCV_RELATIVE";
+		case 4: return "R_RISCV_COPY";
+		case 5: return "R_RISCV_JUMP_SLOT";
+		case 6: return "R_RISCV_TLS_DTPMOD32";
+		case 7: return "R_RISCV_TLS_DTPMOD64";
+		case 8: return "R_RISCV_TLS_DTPREL32";
+		case 9: return "R_RISCV_TLS_DTPREL64";
+		case 10: return "R_RISCV_TLS_TPREL32";
+		case 11: return "R_RISCV_TLS_TPREL64";
+		case 16: return "R_RISCV_BRANCH";
+		case 17: return "R_RISCV_JAL";
+		case 18: return "R_RISCV_CALL";
+		case 19: return "R_RISCV_CALL_PLT";
+		case 20: return "R_RISCV_GOT_HI20";
+		case 21: return "R_RISCV_TLS_GOT_HI20";
+		case 22: return "R_RISCV_TLS_GD_HI20";
+		case 23: return "R_RISCV_PCREL_HI20";
+		case 24: return "R_RISCV_PCREL_LO12_I";
+		case 25: return "R_RISCV_PCREL_LO12_S";
+		case 26: return "R_RISCV_HI20";
+		case 27: return "R_RISCV_LO12_I";
+		case 28: return "R_RISCV_LO12_S";
+		case 29: return "R_RISCV_TPREL_HI20";
+		case 30: return "R_RISCV_TPREL_LO12_I";
+		case 31: return "R_RISCV_TPREL_LO12_S";
+		case 32: return "R_RISCV_TPREL_ADD";
+		case 33: return "R_RISCV_ADD8";
+		case 34: return "R_RISCV_ADD16";
+		case 35: return "R_RISCV_ADD32";
+		case 36: return "R_RISCV_ADD64";
+		case 37: return "R_RISCV_SUB8";
+		case 38: return "R_RISCV_SUB16";
+		case 39: return "R_RISCV_SUB32";
+		case 40: return "R_RISCV_SUB64";
+		case 41: return "R_RISCV_GNU_VTINHERIT";
+		case 42: return "R_RISCV_GNU_VTENTRY";
+		case 43: return "R_RISCV_ALIGN";
+		case 44: return "R_RISCV_RVC_BRANCH";
+		case 45: return "R_RISCV_RVC_JUMP";
+		case 46: return "R_RISCV_RVC_LUI";
+		case 47: return "R_RISCV_GPREL_I";
+		case 48: return "R_RISCV_GPREL_S";
+		}
+		break;
+	case EM_S390:
+		switch (type) {
+		case 0: return "R_390_NONE";
+		case 1: return "R_390_8";
+		case 2: return "R_390_12";
+		case 3: return "R_390_16";
+		case 4: return "R_390_32";
+		case 5: return "R_390_PC32";
+		case 6: return "R_390_GOT12";
+		case 7: return "R_390_GOT32";
+		case 8: return "R_390_PLT32";
+		case 9: return "R_390_COPY";
+		case 10: return "R_390_GLOB_DAT";
+		case 11: return "R_390_JMP_SLOT";
+		case 12: return "R_390_RELATIVE";
+		case 13: return "R_390_GOTOFF";
+		case 14: return "R_390_GOTPC";
+		case 15: return "R_390_GOT16";
+		case 16: return "R_390_PC16";
+		case 17: return "R_390_PC16DBL";
+		case 18: return "R_390_PLT16DBL";
+		case 19: return "R_390_PC32DBL";
+		case 20: return "R_390_PLT32DBL";
+		case 21: return "R_390_GOTPCDBL";
+		case 22: return "R_390_64";
+		case 23: return "R_390_PC64";
+		case 24: return "R_390_GOT64";
+		case 25: return "R_390_PLT64";
+		case 26: return "R_390_GOTENT";
+		}
+		break;
+	case EM_SPARC:
+	case EM_SPARCV9:
+		switch(type) {
+		case 0: return "R_SPARC_NONE";
+		case 1: return "R_SPARC_8";
+		case 2: return "R_SPARC_16";
+		case 3: return "R_SPARC_32";
+		case 4: return "R_SPARC_DISP8";
+		case 5: return "R_SPARC_DISP16";
+		case 6: return "R_SPARC_DISP32";
+		case 7: return "R_SPARC_WDISP30";
+		case 8: return "R_SPARC_WDISP22";
+		case 9: return "R_SPARC_HI22";
+		case 10: return "R_SPARC_22";
+		case 11: return "R_SPARC_13";
+		case 12: return "R_SPARC_LO10";
+		case 13: return "R_SPARC_GOT10";
+		case 14: return "R_SPARC_GOT13";
+		case 15: return "R_SPARC_GOT22";
+		case 16: return "R_SPARC_PC10";
+		case 17: return "R_SPARC_PC22";
+		case 18: return "R_SPARC_WPLT30";
+		case 19: return "R_SPARC_COPY";
+		case 20: return "R_SPARC_GLOB_DAT";
+		case 21: return "R_SPARC_JMP_SLOT";
+		case 22: return "R_SPARC_RELATIVE";
+		case 23: return "R_SPARC_UA32";
+		case 24: return "R_SPARC_PLT32";
+		case 25: return "R_SPARC_HIPLT22";
+		case 26: return "R_SPARC_LOPLT10";
+		case 27: return "R_SPARC_PCPLT32";
+		case 28: return "R_SPARC_PCPLT22";
+		case 29: return "R_SPARC_PCPLT10";
+		case 30: return "R_SPARC_10";
+		case 31: return "R_SPARC_11";
+		case 32: return "R_SPARC_64";
+		case 33: return "R_SPARC_OLO10";
+		case 34: return "R_SPARC_HH22";
+		case 35: return "R_SPARC_HM10";
+		case 36: return "R_SPARC_LM22";
+		case 37: return "R_SPARC_PC_HH22";
+		case 38: return "R_SPARC_PC_HM10";
+		case 39: return "R_SPARC_PC_LM22";
+		case 40: return "R_SPARC_WDISP16";
+		case 41: return "R_SPARC_WDISP19";
+		case 42: return "R_SPARC_GLOB_JMP";
+		case 43: return "R_SPARC_7";
+		case 44: return "R_SPARC_5";
+		case 45: return "R_SPARC_6";
+		case 46: return "R_SPARC_DISP64";
+		case 47: return "R_SPARC_PLT64";
+		case 48: return "R_SPARC_HIX22";
+		case 49: return "R_SPARC_LOX10";
+		case 50: return "R_SPARC_H44";
+		case 51: return "R_SPARC_M44";
+		case 52: return "R_SPARC_L44";
+		case 53: return "R_SPARC_REGISTER";
+		case 54: return "R_SPARC_UA64";
+		case 55: return "R_SPARC_UA16";
+		case 56: return "R_SPARC_TLS_GD_HI22";
+		case 57: return "R_SPARC_TLS_GD_LO10";
+		case 58: return "R_SPARC_TLS_GD_ADD";
+		case 59: return "R_SPARC_TLS_GD_CALL";
+		case 60: return "R_SPARC_TLS_LDM_HI22";
+		case 61: return "R_SPARC_TLS_LDM_LO10";
+		case 62: return "R_SPARC_TLS_LDM_ADD";
+		case 63: return "R_SPARC_TLS_LDM_CALL";
+		case 64: return "R_SPARC_TLS_LDO_HIX22";
+		case 65: return "R_SPARC_TLS_LDO_LOX10";
+		case 66: return "R_SPARC_TLS_LDO_ADD";
+		case 67: return "R_SPARC_TLS_IE_HI22";
+		case 68: return "R_SPARC_TLS_IE_LO10";
+		case 69: return "R_SPARC_TLS_IE_LD";
+		case 70: return "R_SPARC_TLS_IE_LDX";
+		case 71: return "R_SPARC_TLS_IE_ADD";
+		case 72: return "R_SPARC_TLS_LE_HIX22";
+		case 73: return "R_SPARC_TLS_LE_LOX10";
+		case 74: return "R_SPARC_TLS_DTPMOD32";
+		case 75: return "R_SPARC_TLS_DTPMOD64";
+		case 76: return "R_SPARC_TLS_DTPOFF32";
+		case 77: return "R_SPARC_TLS_DTPOFF64";
+		case 78: return "R_SPARC_TLS_TPOFF32";
+		case 79: return "R_SPARC_TLS_TPOFF64";
+		}
+		break;
+	case EM_X86_64:
+		switch(type) {
+		case 0: return "R_X86_64_NONE";
+		case 1: return "R_X86_64_64";
+		case 2: return "R_X86_64_PC32";
+		case 3: return "R_X86_64_GOT32";
+		case 4: return "R_X86_64_PLT32";
+		case 5: return "R_X86_64_COPY";
+		case 6: return "R_X86_64_GLOB_DAT";
+		case 7: return "R_X86_64_JUMP_SLOT";
+		case 8: return "R_X86_64_RELATIVE";
+		case 9: return "R_X86_64_GOTPCREL";
+		case 10: return "R_X86_64_32";
+		case 11: return "R_X86_64_32S";
+		case 12: return "R_X86_64_16";
+		case 13: return "R_X86_64_PC16";
+		case 14: return "R_X86_64_8";
+		case 15: return "R_X86_64_PC8";
+		case 16: return "R_X86_64_DTPMOD64";
+		case 17: return "R_X86_64_DTPOFF64";
+		case 18: return "R_X86_64_TPOFF64";
+		case 19: return "R_X86_64_TLSGD";
+		case 20: return "R_X86_64_TLSLD";
+		case 21: return "R_X86_64_DTPOFF32";
+		case 22: return "R_X86_64_GOTTPOFF";
+		case 23: return "R_X86_64_TPOFF32";
+		case 24: return "R_X86_64_PC64";
+		case 25: return "R_X86_64_GOTOFF64";
+		case 26: return "R_X86_64_GOTPC32";
+		case 27: return "R_X86_64_GOT64";
+		case 28: return "R_X86_64_GOTPCREL64";
+		case 29: return "R_X86_64_GOTPC64";
+		case 30: return "R_X86_64_GOTPLT64";
+		case 31: return "R_X86_64_PLTOFF64";
+		case 32: return "R_X86_64_SIZE32";
+		case 33: return "R_X86_64_SIZE64";
+		case 34: return "R_X86_64_GOTPC32_TLSDESC";
+		case 35: return "R_X86_64_TLSDESC_CALL";
+		case 36: return "R_X86_64_TLSDESC";
+		case 37: return "R_X86_64_IRELATIVE";
+		case 38: return "R_X86_64_RELATIVE64";
+		case 41: return "R_X86_64_GOTPCRELX";
+		case 42: return "R_X86_64_REX_GOTPCRELX";
+		}
+		break;
+	}
+
+	snprintf(s_type, sizeof(s_type), "<unknown: %#x>", type);
+	return (s_type);
+}
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.3
new file mode 100644
index 0000000..115fe92
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c b/rtemstoolkit/elftoolchain/libelftc/elftc_set_timestamps.c
new file mode 100644
index 0000000..cb28c35
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table.c
new file mode 100644
index 0000000..bba9ac6
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_string_table_create.3
new file mode 100644
index 0000000..e11e73c
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3
new file mode 100644
index 0000000..3c56f2f
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.3
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2016 The FreeBSD Foundation.  All rights reserved.
+.\"
+.\" This documentation was written by Ed Maste under sponsorship of
+.\" the FreeBSD Foundation.
+.\"
+.\" 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.
+.\"
+.\" $Id$
+.\"
+.Dd August 24, 2016
+.Os
+.Dt ELFTC_TIMESTAMP 3
+.Sh NAME
+.Nm elftc_timestamp
+.Nd return the current or environment-provided timestamp
+.Sh LIBRARY
+.Lb libelftc
+.Sh SYNOPSIS
+.In libelftc.h
+.Ft int
+.Fo elftc_timestamp
+.Fa "time_t *timestamp"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn elftc_timestamp
+function returns a timestamp supplied by the
+.Ev SOURCE_DATE_EPOCH
+environment variable, or the current time provided by
+.Xr time 3
+if the environment variable is not set.
+.Pp
+The
+.Ar timestamp
+argument specifies a pointer to the location where the timestamp will be
+stored.
+.Sh RETURN VALUE
+Function
+.Fn elftc_timestamp
+returns 0 on success, and -1 in the event of an error.
+.Sh ERRORS
+The
+.Fn elftc_timestamp
+function may fail with the following errors:
+.Bl -tag -width ".Bq Er ERANGE"
+.It Bq Er EINVAL
+.Ev SOURCE_DATE_EPOCH
+contains invalid characters.
+.It Bq Er ERANGE
+.Ev SOURCE_DATE_EPOCH
+specifies a negative value or a value that cannot be stored in a
+time_t.
+.El
+The
+.Fn elftc_timestamp
+function may also fail for any of the reasons described in
+.Xr strtoll 3 .
+.Sh SEE ALSO
+.Xr strtoll 3 ,
+.Xr time 3
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c
new file mode 100644
index 0000000..ccf482f
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_timestamp.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2016 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Ed Maste under sponsorship
+ * of the FreeBSD Foundation.
+ *
+ * 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 <errno.h>
+#include <stdlib.h>
+#include <time.h>
+#include <libelftc.h>
+
+int
+elftc_timestamp(time_t *timestamp)
+{
+	long long source_date_epoch;
+	char *env, *eptr;
+
+	if ((env = getenv("SOURCE_DATE_EPOCH")) != NULL) {
+		errno = 0;
+		source_date_epoch = strtoll(env, &eptr, 10);
+		if (*eptr != '\0')
+			errno = EINVAL;
+		if (source_date_epoch < 0)
+			errno = ERANGE;
+		if (errno != 0)
+			return (-1);
+		*timestamp = source_date_epoch;
+		return (0);
+	}
+	*timestamp = time(NULL);
+	return (0);
+}
diff --git a/rtemstoolkit/elftoolchain/libelftc/elftc_version.3 b/rtemstoolkit/elftoolchain/libelftc/elftc_version.3
new file mode 100644
index 0000000..f7018a5
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/elftc_version.c b/rtemstoolkit/elftoolchain/libelftc/elftc_version.c
new file mode 100644
index 0000000..5c41c1b
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/elftc_version.c
@@ -0,0 +1,10 @@
+/* WARNING: Generated by "make-toolchain-version". */
+
+#include <sys/types.h>
+#include <libelftc.h>
+
+const char *
+elftc_version(void)
+{
+	return "elftoolchain HEAD RTEMS git:heads/covoar-dwarf-0-g9b49665-dirty";
+}
diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc.h b/rtemstoolkit/elftoolchain/libelftc/libelftc.h
new file mode 100644
index 0000000..a235097
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc.h
@@ -0,0 +1,100 @@
+/*-
+ * 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 3489 2016-08-31 00:12:15Z emaste $
+ */
+
+#ifndef	_LIBELFTC_H_
+#define	_LIBELFTC_H_
+
+#include <sys/stat.h>
+
+#include <libelf.h>
+
+/*
+ * Types meant to be opaque to the consumers of these APIs.
+ */
+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,
+	ETF_PE,
+	ETF_EFI,
+} 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
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+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);
+const char	*elftc_reloc_type_str(unsigned int mach, unsigned int type);
+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);
+int		elftc_timestamp(time_t *_timestamp);
+const char	*elftc_version(void);
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _LIBELFTC_H_ */
diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c
new file mode 100644
index 0000000..48b67a0
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_bfdtarget.c
@@ -0,0 +1,463 @@
+/*-
+ * 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/param.h>
+#include <libelf.h>
+#include <libelftc.h>
+
+#include "_libelftc.h"
+
+ELFTC_VCSID("$Id: libelftc_bfdtarget.c 3516 2017-02-10 02:33:08Z emaste $");
+
+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-powerpc-freebsd",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2MSB,
+		.bt_elfclass  = ELFCLASS32,
+		.bt_machine   = EM_PPC,
+		.bt_osabi     = ELFOSABI_FREEBSD,
+	},
+
+	{
+		.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      = "elf32-tradbigmips",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2MSB,
+		.bt_elfclass  = ELFCLASS32,
+		.bt_machine   = EM_MIPS,
+	},
+
+	{
+		.bt_name      = "elf32-tradlittlemips",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2LSB,
+		.bt_elfclass  = ELFCLASS32,
+		.bt_machine   = EM_MIPS,
+	},
+
+	{
+		.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-littleaarch64",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2LSB,
+		.bt_elfclass  = ELFCLASS64,
+		.bt_machine   = EM_AARCH64,
+	},
+
+	{
+		.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-powerpc-freebsd",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2MSB,
+		.bt_elfclass  = ELFCLASS64,
+		.bt_machine   = EM_PPC64,
+		.bt_osabi     = ELFOSABI_FREEBSD,
+	},
+
+	{
+		.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-tradbigmips",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2MSB,
+		.bt_elfclass  = ELFCLASS64,
+		.bt_machine   = EM_MIPS,
+	},
+
+	{
+		.bt_name      = "elf64-tradlittlemips",
+		.bt_type      = ETF_ELF,
+		.bt_byteorder = ELFDATA2LSB,
+		.bt_elfclass  = ELFCLASS64,
+		.bt_machine   = EM_MIPS,
+	},
+
+	{
+		.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    = "efi-app-ia32",
+		.bt_type    = ETF_EFI,
+		.bt_machine = EM_386,
+	},
+
+	{
+		.bt_name    = "efi-app-x86_64",
+		.bt_type    = ETF_EFI,
+		.bt_machine = EM_X86_64,
+	},
+
+	{
+		.bt_name    = "pei-i386",
+		.bt_type    = ETF_PE,
+		.bt_machine = EM_386,
+	},
+
+	{
+		.bt_name    = "pei-x86-64",
+		.bt_type    = ETF_PE,
+		.bt_machine = EM_X86_64,
+	},
+
+	{
+		.bt_name = NULL,
+		.bt_type = ETF_NONE,
+	},
+};
diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c
new file mode 100644
index 0000000..5550505
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_arm.c
@@ -0,0 +1,1216 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee at 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 3513 2016-12-29 07:04:22Z kaiwang27 $");
+
+/**
+ * @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 VEC_PUSH_STR(d,s)	vector_str_push((d), (s), strlen((s)))
+#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 (VEC_PUSH_STR(&d.vec, "(") == 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 (VEC_PUSH_STR(&d.vec, "*") == false)
+				goto clean;
+
+			d.ptr = false;
+		}
+
+		if (d.ref == true) {
+			if (VEC_PUSH_STR(&d.vec, "&") == false)
+				goto clean;
+
+			d.ref = false;
+		}
+
+		if (d.cnst == true) {
+			if (VEC_PUSH_STR(&d.vec, " const") == 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 (VEC_PUSH_STR(&d.vec, ", ") == false)
+			goto clean;
+
+		if (++try > CPP_DEMANGLE_ARM_TRY)
+			goto clean;
+	}
+
+	/* end argument types */
+	if (VEC_PUSH_STR(&d.vec, ")") == 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 (VEC_PUSH_STR(v, v->container[v->size - 2]) == false)
+		return (false);
+
+	if (VEC_PUSH_STR(v, "()") == 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&fptr.vec, "*") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.ptr = false;
+		}
+
+		if (fptr.ref == true) {
+			if (VEC_PUSH_STR(&fptr.vec, "&") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.ref = false;
+		}
+
+		if (fptr.cnst == true) {
+			if (VEC_PUSH_STR(&fptr.vec, " const") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.cnst = false;
+		}
+
+		if (*fptr.p == '_')
+			break;
+
+		if (VEC_PUSH_STR(&fptr.vec, ", ") == 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 (VEC_PUSH_STR(&d->vec, " (*)(") == 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 (VEC_PUSH_STR(&d->vec, ")"));
+}
+
+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 (VEC_PUSH_STR(&d->vec, "::*") == 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 (VEC_PUSH_STR(&d->vec, "operator*"));
+	case SIMPLE_HASH('d', 'v') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator/"));
+	case SIMPLE_HASH('m', 'd') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator%"));
+	case SIMPLE_HASH('p', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator+"));
+	case SIMPLE_HASH('m', 'i') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator-"));
+	case SIMPLE_HASH('l', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<<"));
+	case SIMPLE_HASH('r', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>>"));
+	case SIMPLE_HASH('e', 'q') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator=="));
+	case SIMPLE_HASH('n', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator!="));
+	case SIMPLE_HASH('l', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<"));
+	case SIMPLE_HASH('g', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>"));
+	case SIMPLE_HASH('l', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<="));
+	case SIMPLE_HASH('g', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>="));
+	case SIMPLE_HASH('a', 'd') :
+		d->p += 2;
+		if (*d->p == 'v') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator/="));
+		} else
+			return (VEC_PUSH_STR(&d->vec, "operator&"));
+	case SIMPLE_HASH('o', 'r') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator|"));
+	case SIMPLE_HASH('e', 'r') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator^"));
+	case SIMPLE_HASH('a', 'a') :
+		d->p += 2;
+		if (*d->p == 'd') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator&="));
+		} else
+			return (VEC_PUSH_STR(&d->vec, "operator&&"));
+	case SIMPLE_HASH('o', 'o') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator||"));
+	case SIMPLE_HASH('n', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator!"));
+	case SIMPLE_HASH('c', 'o') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator~"));
+	case SIMPLE_HASH('p', 'p') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator++"));
+	case SIMPLE_HASH('m', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator--"));
+	case SIMPLE_HASH('a', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator="));
+	case SIMPLE_HASH('r', 'f') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator->"));
+	case SIMPLE_HASH('a', 'p') :
+		/* apl */
+		if (*(d->p + 2) != 'l')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator+="));
+	case SIMPLE_HASH('a', 'm') :
+		d->p += 2;
+		if (*d->p == 'i') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator-="));
+		} else if (*d->p == 'u') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator*="));
+		} else if (*d->p == 'd') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator%="));
+		}
+
+		return (false);
+	case SIMPLE_HASH('a', 'l') :
+		/* als */
+		if (*(d->p + 2) != 's')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator<<="));
+	case SIMPLE_HASH('a', 'r') :
+		/* ars */
+		if (*(d->p + 2) != 's')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator>>="));
+	case SIMPLE_HASH('a', 'o') :
+		/* aor */
+		if (*(d->p + 2) != 'r')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator|="));
+	case SIMPLE_HASH('a', 'e') :
+		/* aer */
+		if (*(d->p + 2) != 'r')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator^="));
+	case SIMPLE_HASH('c', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator,"));
+	case SIMPLE_HASH('r', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator->*"));
+	case SIMPLE_HASH('c', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "()"));
+	case SIMPLE_HASH('v', 'c') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "[]"));
+	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 (VEC_PUSH_STR(&d->vec, "operator new()"));
+	case SIMPLE_HASH('d', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator delete()"));
+	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 (VEC_PUSH_STR(&d->vec, "::operator ") == false)
+		return (false);
+
+	if (vector_str_push(&d->vec, to_str, to_len) == false)
+		goto clean;
+
+	rtn = VEC_PUSH_STR(&d->vec, "()");
+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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
+		return (-1);
+
+	if (VEC_PUSH_STR(&d->arg, 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 (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
+			return (-1);
+
+		if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false)
+			return (-1);
+
+		if (i != repeat - 1 &&
+		    VEC_PUSH_STR(&d->vec, ", ") == 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 (VEC_PUSH_STR(&d->vec, "unsigned ") == false)
+				return (false);
+
+			break;
+		case 'C' :
+			++d->p;
+
+			if (*d->p == 'P')
+				d->cnst = true;
+			else {
+				if (VEC_PUSH_STR(&d->vec, "const ") ==
+				    false)
+					return (false);
+			}
+
+			break;
+		case 'V' :
+			++d->p;
+
+			if (VEC_PUSH_STR(&d->vec, "volatile ") == false)
+				return (false);
+
+			break;
+		case 'S' :
+			++d->p;
+
+			if (VEC_PUSH_STR(&d->vec, "signed ") == 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 (VEC_PUSH_STR(&d->vec, "void"));
+	case 'c' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "char"));
+	case 's' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "short"));
+	case 'i' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "int"));
+	case 'l' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "long"));
+	case 'f' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "float"));
+	case 'd':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "double"));
+	case 'r':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "long double"));
+	case 'e':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "..."));
+	default:
+		return (false);
+	};
+
+	/* NOTREACHED */
+	return (false);
+}
diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c
new file mode 100644
index 0000000..5c77b67
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu2.c
@@ -0,0 +1,1365 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee at 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 3513 2016-12-29 07:04:22Z kaiwang27 $");
+
+/**
+ * @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 VEC_PUSH_STR(d,s)	vector_str_push((d), (s), strlen((s)))
+#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 (VEC_PUSH_STR(&d.vec, "(void)") == 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 (VEC_PUSH_STR(&d.vec, "(void)") == false)
+				goto clean;
+
+			goto flat;
+		} else
+			goto clean;
+	}
+
+	/* start argument types */
+	if (VEC_PUSH_STR(&d.vec, "(") == 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 (VEC_PUSH_STR(&d.vec, "*") == false)
+				goto clean;
+
+			d.ptr = false;
+		}
+
+		if (d.ref == true) {
+			if (VEC_PUSH_STR(&d.vec, "&") == false)
+				goto clean;
+
+			d.ref = false;
+		}
+
+		if (d.cnst == true) {
+			if (VEC_PUSH_STR(&d.vec, " const") == 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 (VEC_PUSH_STR(&d.vec, ", ") == false)
+			goto clean;
+
+		if (++try > CPP_DEMANGLE_GNU2_TRY)
+			goto clean;
+	}
+
+	/* end argument types */
+	if (VEC_PUSH_STR(&d.vec, ")") == false)
+		goto clean;
+flat:
+	if (d.cnst_fn == true && VEC_PUSH_STR(&d.vec, " const") == 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 (VEC_PUSH_STR(v, 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, "__") == 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, " virtual table"));
+	} 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 (VEC_PUSH_STR(&fptr.vec, "*") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.ptr = false;
+		}
+
+		if (fptr.ref == true) {
+			if (VEC_PUSH_STR(&fptr.vec, "&") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.ref = false;
+		}
+
+		if (fptr.cnst == true) {
+			if (VEC_PUSH_STR(&fptr.vec, " const") == false) {
+				dest_demangle_data(&fptr);
+
+				return (false);
+			}
+
+			fptr.cnst = false;
+		}
+
+		if (*fptr.p == '_')
+			break;
+
+		if (VEC_PUSH_STR(&fptr.vec, ", ") == 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 (VEC_PUSH_STR(&d->vec, " (*)(") == 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 (VEC_PUSH_STR(&d->vec, ")"));
+}
+
+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 (VEC_PUSH_STR(&d->vec, "::*") == 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 (VEC_PUSH_STR(&d->vec, "operator*"));
+	case SIMPLE_HASH('d', 'v') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator/"));
+	case SIMPLE_HASH('m', 'd') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator%"));
+	case SIMPLE_HASH('p', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator+"));
+	case SIMPLE_HASH('m', 'i') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator-"));
+	case SIMPLE_HASH('l', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<<"));
+	case SIMPLE_HASH('r', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>>"));
+	case SIMPLE_HASH('e', 'q') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator=="));
+	case SIMPLE_HASH('n', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator!="));
+	case SIMPLE_HASH('l', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<"));
+	case SIMPLE_HASH('g', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>"));
+	case SIMPLE_HASH('l', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator<="));
+	case SIMPLE_HASH('g', 'e') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator>="));
+	case SIMPLE_HASH('a', 'd') :
+		d->p += 2;
+		if (*d->p == 'v') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator/="));
+		} else
+			return (VEC_PUSH_STR(&d->vec, "operator&"));
+	case SIMPLE_HASH('o', 'r') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator|"));
+	case SIMPLE_HASH('e', 'r') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator^"));
+	case SIMPLE_HASH('a', 'a') :
+		d->p += 2;
+		if (*d->p == 'd') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator&="));
+		} else
+			return (VEC_PUSH_STR(&d->vec, "operator&&"));
+	case SIMPLE_HASH('o', 'o') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator||"));
+	case SIMPLE_HASH('n', 't') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator!"));
+	case SIMPLE_HASH('c', 'o') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator~"));
+	case SIMPLE_HASH('p', 'p') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator++"));
+	case SIMPLE_HASH('m', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator--"));
+	case SIMPLE_HASH('a', 's') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator="));
+	case SIMPLE_HASH('r', 'f') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator->"));
+	case SIMPLE_HASH('a', 'p') :
+		/* apl */
+		if (*(d->p + 2) != 'l')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator+="));
+	case SIMPLE_HASH('a', 'm') :
+		d->p += 2;
+		if (*d->p == 'i') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator-="));
+		} else if (*d->p == 'u') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator*="));
+		} else if (*d->p == 'd') {
+			++d->p;
+			return (VEC_PUSH_STR(&d->vec, "operator%="));
+		}
+
+		return (false);
+	case SIMPLE_HASH('a', 'l') :
+		/* als */
+		if (*(d->p + 2) != 's')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator<<="));
+	case SIMPLE_HASH('a', 'r') :
+		/* ars */
+		if (*(d->p + 2) != 's')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator>>="));
+	case SIMPLE_HASH('a', 'o') :
+		/* aor */
+		if (*(d->p + 2) != 'r')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator|="));
+	case SIMPLE_HASH('a', 'e') :
+		/* aer */
+		if (*(d->p + 2) != 'r')
+			return (false);
+
+		d->p += 3;
+		return (VEC_PUSH_STR(&d->vec, "operator^="));
+	case SIMPLE_HASH('c', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator,"));
+	case SIMPLE_HASH('r', 'm') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator->*"));
+	case SIMPLE_HASH('c', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "()"));
+	case SIMPLE_HASH('v', 'c') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "[]"));
+	case SIMPLE_HASH('n', 'w') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator new()"));
+	case SIMPLE_HASH('d', 'l') :
+		d->p += 2;
+		return (VEC_PUSH_STR(&d->vec, "operator delete()"));
+	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 (VEC_PUSH_STR(&d->vec, " type_info function"));
+	case SIMPLE_HASH('t', 'i') :
+		d->p += 2;
+		d->type = ENCODE_OP_TI;
+
+		if (read_type(d) == false)
+			return (false);
+
+		return (VEC_PUSH_STR(&d->vec, " type_info node"));
+	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 (VEC_PUSH_STR(&d->vec, "::operator ") == false)
+		goto clean;
+
+	if (vector_str_push(&d->vec, to_str, to_len) == false)
+		goto clean;
+
+	rtn = VEC_PUSH_STR(&d->vec, "()");
+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 (VEC_PUSH_STR(&d->vec, "::") == 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 (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
+		return (-1);
+
+	if (VEC_PUSH_STR(&d->arg, 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 (VEC_PUSH_STR(&d->vec, d->arg.container[idx - 1]) == false)
+			return (-1);
+
+		if (VEC_PUSH_STR(&d->arg, d->arg.container[idx - 1]) == false)
+			return (-1);
+
+		if (i != repeat - 1 &&
+		    VEC_PUSH_STR(&d->vec, ", ") == 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 (VEC_PUSH_STR(&d->vec, "unsigned ") == false)
+				return (false);
+
+			break;
+		case 'C' :
+			++d->p;
+
+			if (*d->p == 'P')
+				d->cnst = true;
+			else {
+				if (VEC_PUSH_STR(&d->vec, "const ") ==
+				    false)
+					return (false);
+			}
+
+			break;
+		case 'V' :
+			++d->p;
+
+			if (VEC_PUSH_STR(&d->vec, "volatile ") == false)
+				return (false);
+
+			break;
+		case 'S' :
+			++d->p;
+
+			if (VEC_PUSH_STR(&d->vec, "signed ") == 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 (VEC_PUSH_STR(&d->vec, "void"));
+	case 'b':
+		++d->p;
+
+		return(VEC_PUSH_STR(&d->vec, "bool"));
+	case 'c' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "char"));
+	case 's' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "short"));
+	case 'i' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "int"));
+	case 'l' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "long"));
+	case 'f' :
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "float"));
+	case 'd':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "double"));
+	case 'r':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "long double"));
+	case 'e':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "..."));
+	case 'w':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "wchar_t"));
+	case 'x':
+		++d->p;
+
+		return (VEC_PUSH_STR(&d->vec, "long long"));
+	default:
+		return (false);
+	};
+
+	/* NOTREACHED */
+	return (false);
+}
diff --git a/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c
new file mode 100644
index 0000000..73ed371
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_dem_gnu3.c
@@ -0,0 +1,3991 @@
+/*-
+ * Copyright (c) 2007 Hyogeol Lee <hyogeollee at gmail.com>
+ * Copyright (c) 2015-2017 Kai Wang <kaiwang27 at 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 3583 2017-10-15 15:38:47Z emaste $");
+
+/**
+ * @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, TYPE_VEC, TYPE_RREF
+};
+
+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 read_cmd_item {
+	enum read_cmd cmd;
+	void *data;
+};
+
+struct vector_read_cmd {
+	size_t size, capacity;
+	struct read_cmd_item *r_container;
+};
+
+enum push_qualifier {
+	PUSH_ALL_QUALIFIER,
+	PUSH_CV_QUALIFIER,
+	PUSH_NON_CV_QUALIFIER,
+};
+
+struct cpp_demangle_data {
+	struct vector_str	 output;	/* output string vector */
+	struct vector_str	 subst;		/* substitution string vector */
+	struct vector_str	 tmpl;
+	struct vector_str	 class_type;
+	struct vector_str	*cur_output;	/* ptr to current output vec */
+	struct vector_read_cmd	 cmd;
+	bool			 mem_rst;	/* restrict member function */
+	bool			 mem_vat;	/* volatile member function */
+	bool			 mem_cst;	/* const member function */
+	bool			 mem_ref;	/* lvalue-ref member func */
+	bool			 mem_rref;	/* rvalue-ref member func */
+	bool			 is_tmpl;	/* template args */
+	bool			 is_functype;	/* function type */
+	bool			 ref_qualifier; /* ref qualifier */
+	enum type_qualifier	 ref_qualifier_type; /* ref qualifier type */
+	enum push_qualifier	 push_qualifier; /* which qualifiers to push */
+	int			 func_type;
+	const char		*cur;		/* current mangled name ptr */
+	const char		*last_sname;	/* last source name */
+};
+
+struct type_delimit {
+	bool paren;
+	bool firstp;
+};
+
+#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)
+#define DEM_PUSH_STR(d,s)	cpp_demangle_push_str((d), (s), strlen((s)))
+#define VEC_PUSH_STR(d,s)	vector_str_push((d), (s), strlen((s)))
+
+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_pop_str(struct cpp_demangle_data *);
+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_flat(struct cpp_demangle_data *,
+		    char **);
+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_name_flat(struct cpp_demangle_data *,
+		    char**);
+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_number_as_string(struct cpp_demangle_data *,
+		    char **);
+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 *,
+		    struct vector_type_qualifier *);
+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 *);
+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 *,
+		    struct type_delimit *);
+static int	cpp_demangle_read_type_flat(struct cpp_demangle_data *,
+		    char **);
+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 struct read_cmd_item *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,
+		    void *);
+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);
+
+/**
+ * @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;
+	struct vector_str ret_type;
+	struct type_delimit td;
+	ssize_t org_len;
+	unsigned int limit;
+	char *rtn;
+	bool has_ret, more_type;
+
+	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);
+
+	rtn = NULL;
+	has_ret = more_type = false;
+
+	if (!cpp_demangle_read_encoding(&ddata))
+		goto clean;
+
+	/*
+	 * Pop function name from substitution candidate list.
+	 */
+	if (*ddata.cur != 0 && ddata.subst.size >= 1) {
+		if (!vector_str_pop(&ddata.subst))
+			goto clean;
+	}
+
+	td.paren = false;
+	td.firstp = true;
+	limit = 0;
+
+	/*
+	 * The first type is a return type if we just demangled template
+	 * args. (the template args is right next to the function name,
+	 * which means it's a template function)
+	 */
+	if (ddata.is_tmpl) {
+		ddata.is_tmpl = false;
+		if (!vector_str_init(&ret_type))
+			goto clean;
+		ddata.cur_output = &ret_type;
+		has_ret = true;
+	}
+
+	while (*ddata.cur != '\0') {
+		/*
+		 * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4
+		 */
+		if (*ddata.cur == '@' && *(ddata.cur + 1) == '@')
+			break;
+
+		if (has_ret) {
+			/* Read return type */
+			if (!cpp_demangle_read_type(&ddata, NULL))
+				goto clean;
+		} else {
+			/* Read function arg type */
+			if (!cpp_demangle_read_type(&ddata, &td))
+				goto clean;
+		}
+
+		if (has_ret) {
+			/* Push return type to the beginning */
+			if (!VEC_PUSH_STR(&ret_type, " "))
+				goto clean;
+			if (!vector_str_push_vector_head(&ddata.output,
+			    &ret_type))
+				goto clean;
+			ddata.cur_output = &ddata.output;
+			vector_str_dest(&ret_type);
+			has_ret = false;
+			more_type = true;
+		} else if (more_type)
+			more_type = false;
+		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+			goto clean;
+	}
+	if (more_type)
+		goto clean;
+
+	if (ddata.output.size == 0)
+		goto clean;
+	if (td.paren && !VEC_PUSH_STR(&ddata.output, ")"))
+		goto clean;
+	if (ddata.mem_vat && !VEC_PUSH_STR(&ddata.output, " volatile"))
+		goto clean;
+	if (ddata.mem_cst && !VEC_PUSH_STR(&ddata.output, " const"))
+		goto clean;
+	if (ddata.mem_rst && !VEC_PUSH_STR(&ddata.output, " restrict"))
+		goto clean;
+	if (ddata.mem_ref && !VEC_PUSH_STR(&ddata.output, " &"))
+		goto clean;
+	if (ddata.mem_rref && !VEC_PUSH_STR(&ddata.output, " &&"))
+		goto clean;
+
+	rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
+
+clean:
+	if (has_ret)
+		vector_str_dest(&ret_type);
+
+	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);
+}
+
+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->subst))
+		goto clean1;
+	if (!vector_str_init(&d->tmpl))
+		goto clean2;
+	if (!vector_str_init(&d->class_type))
+		goto clean3;
+	if (!vector_read_cmd_init(&d->cmd))
+		goto clean4;
+
+	assert(d->output.container != NULL);
+	assert(d->subst.container != NULL);
+	assert(d->tmpl.container != NULL);
+	assert(d->class_type.container != NULL);
+
+	d->mem_rst = false;
+	d->mem_vat = false;
+	d->mem_cst = false;
+	d->mem_ref = false;
+	d->mem_rref = false;
+	d->is_tmpl = false;
+	d->is_functype = false;
+	d->ref_qualifier = false;
+	d->push_qualifier = PUSH_ALL_QUALIFIER;
+	d->func_type = 0;
+	d->cur = cur;
+	d->cur_output = &d->output;
+	d->last_sname = NULL;
+
+	return (1);
+
+clean4:
+	vector_str_dest(&d->class_type);
+clean3:
+	vector_str_dest(&d->tmpl);
+clean2:
+	vector_str_dest(&d->subst);
+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;
+
+	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);
+
+	++ddata->cur;
+
+	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);
+
+	/*
+	 * is_tmpl is used to check if the type (function arg) is right next
+	 * to template args, and should always be cleared whenever new string
+	 * pushed.
+	 */
+	ddata->is_tmpl = false;
+
+	return (vector_str_push(ddata->cur_output, str, len));
+}
+
+static int
+cpp_demangle_pop_str(struct cpp_demangle_data *ddata)
+{
+
+	if (ddata == NULL)
+		return (0);
+
+	return (vector_str_pop(ddata->cur_output));
+}
+
+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;
+	enum type_qualifier t;
+	size_t idx, e_idx, e_len;
+	char *buf;
+	int rtn;
+	bool cv;
+
+	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 (!VEC_PUSH_STR(&subst_v, type_str))
+			goto clean;
+	}
+
+	cv = true;
+	e_idx = 0;
+	while (idx > 0) {
+		switch (v->q_container[idx - 1]) {
+		case TYPE_PTR:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "*"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, "*"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_REF:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "&"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, "&"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_RREF:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, "&&"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, "&&"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_CMX:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, " complex"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, " complex"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_IMG:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (!DEM_PUSH_STR(ddata, " imaginary"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, " imaginary"))
+					goto clean;
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_EXT:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (v->ext_name.size == 0 ||
+			    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(e_len + 2)) == NULL)
+				goto clean;
+			snprintf(buf, e_len + 2, " %s",
+			    v->ext_name.container[e_idx]);
+
+			if (!DEM_PUSH_STR(ddata, buf)) {
+				free(buf);
+				goto clean;
+			}
+
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, buf)) {
+					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 (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " restrict"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, " restrict"))
+					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_VAT:
+			if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " volatile"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, " volatile"))
+					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_CST:
+			if (ddata->push_qualifier == PUSH_NON_CV_QUALIFIER &&
+			    cv)
+				break;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER && !cv)
+				break;
+			if (!DEM_PUSH_STR(ddata, " const"))
+				goto clean;
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, " const"))
+					goto clean;
+				if (idx - 1 > 0) {
+					t = v->q_container[idx - 2];
+					if (t == TYPE_RST || t == TYPE_VAT ||
+					    t == TYPE_CST)
+						break;
+				}
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v))
+					goto clean;
+			}
+			break;
+
+		case TYPE_VEC:
+			cv = false;
+			if (ddata->push_qualifier == PUSH_CV_QUALIFIER)
+				break;
+			if (v->ext_name.size == 0 ||
+			    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(e_len + 12)) == NULL)
+				goto clean;
+			snprintf(buf, e_len + 12, " __vector(%s)",
+			    v->ext_name.container[e_idx]);
+			if (!DEM_PUSH_STR(ddata, buf)) {
+				free(buf);
+				goto clean;
+			}
+			if (type_str != NULL) {
+				if (!VEC_PUSH_STR(&subst_v, buf)) {
+					free(buf);
+					goto clean;
+				}
+				if (!cpp_demangle_push_subst_v(ddata,
+				    &subst_v)) {
+					free(buf);
+					goto clean;
+				}
+			}
+			free(buf);
+			++e_idx;
+			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, NULL))
+			return (0);
+
+		if (!DEM_PUSH_STR(ddata, "[]"))
+			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, NULL))
+				return (0);
+			if (!DEM_PUSH_STR(ddata, "["))
+				return (0);
+			if (!cpp_demangle_push_str(ddata, num, num_len))
+				return (0);
+			if (!DEM_PUSH_STR(ddata, "]"))
+				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, NULL)) {
+				free(exp);
+				return (0);
+			}
+			if (!DEM_PUSH_STR(ddata, "[")) {
+				free(exp);
+				return (0);
+			}
+			if (!cpp_demangle_push_str(ddata, exp, exp_len)) {
+				free(exp);
+				return (0);
+			}
+			if (!DEM_PUSH_STR(ddata, "]")) {
+				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':
+		if (*(ddata->cur + 2) != 'E')
+			return (0);
+		switch (*(++ddata->cur)) {
+		case '0':
+			ddata->cur += 2;
+			return (DEM_PUSH_STR(ddata, "false"));
+		case '1':
+			ddata->cur += 2;
+			return (DEM_PUSH_STR(ddata, "true"));
+		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 (!DEM_PUSH_STR(ddata, "-"))
+				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 - 1));
+
+	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, NULL));
+
+	case SIMPLE_HASH('s', 'r'):
+		ddata->cur += 2;
+		if (!cpp_demangle_read_type(ddata, NULL))
+			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_flat(struct cpp_demangle_data *ddata, char **str)
+{
+	struct vector_str *output;
+	size_t i, p_idx, idx, exp_len;
+	char *exp;
+
+	output = &ddata->output;
+
+	p_idx = output->size;
+
+	if (!cpp_demangle_read_expression(ddata))
+		return (0);
+
+	if ((exp = vector_str_substr(output, p_idx, output->size - 1,
+	    &exp_len)) == NULL)
+		return (0);
+
+	idx = output->size;
+	for (i = p_idx; i < idx; ++i) {
+		if (!vector_str_pop(output)) {
+			free(exp);
+			return (0);
+		}
+	}
+
+	*str = exp;
+
+	return (1);
+}
+
+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)
+{
+	struct type_delimit td;
+	struct read_cmd_item *rc;
+	size_t class_type_size, class_type_len, limit;
+	const char *class_type;
+	int i;
+	bool paren, non_cv_qualifier;
+
+	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;
+	}
+
+	/* Return type */
+	if (!cpp_demangle_read_type(ddata, NULL))
+		return (0);
+
+	if (*ddata->cur != 'E') {
+		if (!DEM_PUSH_STR(ddata, " "))
+			return (0);
+
+		non_cv_qualifier = false;
+		if (v->size > 0) {
+			for (i = 0; (size_t) i < v->size; i++) {
+				if (v->q_container[i] != TYPE_RST &&
+				    v->q_container[i] != TYPE_VAT &&
+				    v->q_container[i] != TYPE_CST) {
+					non_cv_qualifier = true;
+					break;
+				}
+			}
+		}
+
+		paren = false;
+		rc = vector_read_cmd_find(&ddata->cmd, READ_PTRMEM);
+		if (non_cv_qualifier || rc != NULL) {
+			if (!DEM_PUSH_STR(ddata, "("))
+				return (0);
+			paren = true;
+		}
+
+		/* Push non-cv qualifiers. */
+		ddata->push_qualifier = PUSH_NON_CV_QUALIFIER;
+		if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
+			return (0);
+
+		if (rc) {
+			if (non_cv_qualifier && !DEM_PUSH_STR(ddata, " "))
+				return (0);
+			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 (!DEM_PUSH_STR(ddata, "::*"))
+				return (0);
+			/* Push pointer-to-member qualifiers. */
+			ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+			if (!cpp_demangle_push_type_qualifier(ddata, rc->data,
+			    NULL))
+				return (0);
+			++ddata->func_type;
+		}
+
+		if (paren) {
+			if (!DEM_PUSH_STR(ddata, ")"))
+				return (0);
+			paren = false;
+		}
+
+		td.paren = false;
+		td.firstp = true;
+		limit = 0;
+		ddata->is_functype = true;
+		for (;;) {
+			if (!cpp_demangle_read_type(ddata, &td))
+				return (0);
+			if (*ddata->cur == 'E')
+				break;
+			if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+				return (0);
+		}
+		ddata->is_functype = false;
+		if (td.paren) {
+			if (!DEM_PUSH_STR(ddata, ")"))
+				return (0);
+			td.paren = false;
+		}
+
+		/* Push CV qualifiers. */
+		ddata->push_qualifier = PUSH_CV_QUALIFIER;
+		if (!cpp_demangle_push_type_qualifier(ddata, v, NULL))
+			return (0);
+
+		ddata->push_qualifier = PUSH_ALL_QUALIFIER;
+
+		/* Release type qualifier vector. */
+		vector_type_qualifier_dest(v);
+		if (!vector_type_qualifier_init(v))
+			return (0);
+
+		/* Push ref-qualifiers. */
+		if (ddata->ref_qualifier) {
+			switch (ddata->ref_qualifier_type) {
+			case TYPE_REF:
+				if (!DEM_PUSH_STR(ddata, " &"))
+					return (0);
+				break;
+			case TYPE_RREF:
+				if (!DEM_PUSH_STR(ddata, " &&"))
+					return (0);
+				break;
+			default:
+				return (0);
+			}
+			ddata->ref_qualifier = false;
+		}
+	}
+
+	++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)
+{
+	char *name, *type, *num_str;
+	long offset;
+	int rtn;
+
+	if (ddata == NULL || *ddata->cur == '\0')
+		return (0);
+
+	/* special name */
+	switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+	case SIMPLE_HASH('G', 'A'):
+		if (!DEM_PUSH_STR(ddata, "hidden alias for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_encoding(ddata));
+
+	case SIMPLE_HASH('G', 'R'):
+		if (!DEM_PUSH_STR(ddata, "reference temporary #"))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		if (!cpp_demangle_read_name_flat(ddata, &name))
+			return (0);
+		rtn = 0;
+		if (!cpp_demangle_read_number_as_string(ddata, &num_str))
+			goto clean1;
+		if (!DEM_PUSH_STR(ddata, num_str))
+			goto clean2;
+		if (!DEM_PUSH_STR(ddata, " for "))
+			goto clean2;
+		if (!DEM_PUSH_STR(ddata, name))
+			goto clean2;
+		rtn = 1;
+	clean2:
+		free(num_str);
+	clean1:
+		free(name);
+		return (rtn);
+
+	case SIMPLE_HASH('G', 'T'):
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		switch (*ddata->cur) {
+		case 'n':
+			if (!DEM_PUSH_STR(ddata, "non-transaction clone for "))
+				return (0);
+			break;
+		case 't':
+		default:
+			if (!DEM_PUSH_STR(ddata, "transaction clone for "))
+				return (0);
+			break;
+		}
+		++ddata->cur;
+		return (cpp_demangle_read_encoding(ddata));
+
+	case SIMPLE_HASH('G', 'V'):
+		/* sentry object for 1 time init */
+		if (!DEM_PUSH_STR(ddata, "guard variable for "))
+			return (0);
+		ddata->cur += 2;
+		break;
+
+	case SIMPLE_HASH('T', 'c'):
+		/* virtual function covariant override thunk */
+		if (!DEM_PUSH_STR(ddata,
+		    "virtual function covariant override "))
+			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', 'C'):
+		/* construction vtable */
+		if (!DEM_PUSH_STR(ddata, "construction vtable for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		if (!cpp_demangle_read_type_flat(ddata, &type))
+			return (0);
+		rtn = 0;
+		if (!cpp_demangle_read_number(ddata, &offset))
+			goto clean3;
+		if (*ddata->cur++ != '_')
+			goto clean3;
+		if (!cpp_demangle_read_type(ddata, NULL))
+			goto clean3;
+		if (!DEM_PUSH_STR(ddata, "-in-"))
+			goto clean3;
+		if (!DEM_PUSH_STR(ddata, type))
+			goto clean3;
+		rtn = 1;
+	clean3:
+		free(type);
+		return (rtn);
+
+	case SIMPLE_HASH('T', 'D'):
+		/* typeinfo common proxy */
+		break;
+
+	case SIMPLE_HASH('T', 'F'):
+		/* typeinfo fn */
+		if (!DEM_PUSH_STR(ddata, "typeinfo fn for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'h'):
+		/* virtual function non-virtual override thunk */
+		if (!DEM_PUSH_STR(ddata,
+		    "virtual function non-virtual override "))
+			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', 'H'):
+		/* TLS init function */
+		if (!DEM_PUSH_STR(ddata, "TLS init function for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		break;
+
+	case SIMPLE_HASH('T', 'I'):
+		/* typeinfo structure */
+		if (!DEM_PUSH_STR(ddata, "typeinfo for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'J'):
+		/* java class */
+		if (!DEM_PUSH_STR(ddata, "java Class for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'S'):
+		/* RTTI name (NTBS) */
+		if (!DEM_PUSH_STR(ddata, "typeinfo name for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'T'):
+		/* VTT table */
+		if (!DEM_PUSH_STR(ddata, "VTT for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'v'):
+		/* virtual function virtual override thunk */
+		if (!DEM_PUSH_STR(ddata, "virtual function virtual override "))
+			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 (!DEM_PUSH_STR(ddata, "vtable for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('T', 'W'):
+		/* TLS wrapper function */
+		if (!DEM_PUSH_STR(ddata, "TLS wrapper function for "))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == '\0')
+			return (0);
+		break;
+	}
+
+	return (cpp_demangle_read_name(ddata));
+}
+
+static int
+cpp_demangle_read_local_name(struct cpp_demangle_data *ddata)
+{
+	struct vector_str local_name;
+	struct type_delimit td;
+	size_t limit;
+	bool  more_type;
+
+	if (ddata == NULL)
+		return (0);
+	if (*(++ddata->cur) == '\0')
+		return (0);
+
+	vector_str_init(&local_name);
+	ddata->cur_output = &local_name;
+
+	if (!cpp_demangle_read_encoding(ddata)) {
+		vector_str_dest(&local_name);
+		return (0);
+	}
+
+	ddata->cur_output = &ddata->output;
+
+	td.paren = false;
+	td.firstp = true;
+	more_type = false;
+	limit = 0;
+
+	/*
+	 * The first type is a return type if we just demangled template
+	 * args. (the template args is right next to the function name,
+	 * which means it's a template function)
+	 */
+	if (ddata->is_tmpl) {
+		ddata->is_tmpl = false;
+
+		/* Read return type */
+		if (!cpp_demangle_read_type(ddata, NULL)) {
+			vector_str_dest(&local_name);
+			return (0);
+		}
+
+		more_type = true;
+	}
+
+	/* Now we can push the name after possible return type is handled. */
+	if (!vector_str_push_vector(&ddata->output, &local_name)) {
+		vector_str_dest(&local_name);
+		return (0);
+	}
+	vector_str_dest(&local_name);
+
+	while (*ddata->cur != '\0') {
+		if (!cpp_demangle_read_type(ddata, &td))
+			return (0);
+		if (more_type)
+			more_type = false;
+		if (*ddata->cur == 'E')
+			break;
+		if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+			return (0);
+	}
+	if (more_type)
+		return (0);
+
+	if (*(++ddata->cur) == '\0')
+		return (0);
+	if (td.paren == true) {
+		if (!DEM_PUSH_STR(ddata, ")"))
+			return (0);
+		td.paren = false;
+	}
+	if (*ddata->cur == 's')
+		++ddata->cur;
+	else {
+		if (!DEM_PUSH_STR(ddata, "::"))
+			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 = ddata->cur_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_name_flat(struct cpp_demangle_data *ddata, char **str)
+{
+	struct vector_str *output;
+	size_t i, p_idx, idx, name_len;
+	char *name;
+
+	output = ddata->cur_output;
+
+	p_idx = output->size;
+
+	if (!cpp_demangle_read_name(ddata))
+		return (0);
+
+	if ((name = vector_str_substr(output, p_idx, output->size - 1,
+	    &name_len)) == NULL)
+		return (0);
+
+	idx = output->size;
+	for (i = p_idx; i < idx; ++i) {
+		if (!vector_str_pop(output)) {
+			free(name);
+			return (0);
+		}
+	}
+
+	*str = name;
+
+	return (1);
+}
+
+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);
+
+	do {
+		switch (*ddata->cur) {
+		case 'r':
+			ddata->mem_rst = true;
+			break;
+		case 'V':
+			ddata->mem_vat = true;
+			break;
+		case 'K':
+			ddata->mem_cst = true;
+			break;
+		case 'R':
+			ddata->mem_ref = true;
+			break;
+		case 'O':
+			ddata->mem_rref = true;
+			break;
+		default:
+			goto next;
+		}
+	} while (*(++ddata->cur));
+
+next:
+	output = ddata->cur_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 (p_idx == output->size)
+			goto next_comp;
+		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;
+
+	next_comp:
+		if (*ddata->cur == 'E')
+			break;
+		else if (*ddata->cur != 'I' && *ddata->cur != 'C' &&
+		    *ddata->cur != 'D' && p_idx != output->size) {
+			if (!DEM_PUSH_STR(ddata, "::"))
+				goto clean;
+			if (!VEC_PUSH_STR(&v, "::"))
+				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_number_as_string(struct cpp_demangle_data *ddata, char **str)
+{
+	long n;
+
+	if (!cpp_demangle_read_number(ddata, &n)) {
+		*str = NULL;
+		return (0);
+	}
+
+	if (asprintf(str, "%ld", n) < 0) {
+		*str = NULL;
+		return (0);
+	}
+
+	return (1);
+}
+
+static int
+cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata)
+{
+
+	if (ddata == NULL)
+		return (0);
+
+	if (!DEM_PUSH_STR(ddata, "offset : "))
+		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 && !DEM_PUSH_STR(ddata, "-"))
+		return (0);
+
+	assert(start != NULL);
+
+	if (!cpp_demangle_push_str(ddata, start, ddata->cur - start))
+		return (0);
+	if (!DEM_PUSH_STR(ddata, " "))
+		return (0);
+
+	++ddata->cur;
+
+	return (1);
+}
+
+static int
+cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata,
+    struct vector_type_qualifier *v)
+{
+	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, NULL))
+		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, v))
+		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, NULL))
+		goto clean3;
+
+	if (p_func_type == ddata->func_type) {
+		if (!DEM_PUSH_STR(ddata, " "))
+			goto clean3;
+		if (!cpp_demangle_push_str(ddata, class_type, class_type_len))
+			goto clean3;
+		if (!DEM_PUSH_STR(ddata, "::*"))
+			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);
+
+	vector_type_qualifier_dest(v);
+	if (!vector_type_qualifier_init(v))
+		return (0);
+
+	return (rtn);
+}
+
+/* read source-name, source-name is <len> <ID> */
+static int
+cpp_demangle_read_sname(struct cpp_demangle_data *ddata)
+{
+	long len;
+	int err;
+
+	if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 ||
+	    len <= 0)
+		return (0);
+
+	if (len == 12 && (memcmp("_GLOBAL__N_1", ddata->cur, 12) == 0))
+		err = DEM_PUSH_STR(ddata, "(anonymous namespace)");
+	else
+		err = cpp_demangle_push_str(ddata, ddata->cur, len);
+
+	if (err == 0)
+		return (0);
+
+	assert(ddata->output.size > 0);
+	if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == NULL)
+		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 (!DEM_PUSH_STR(ddata, "std::allocator"))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::allocator"));
+		return (1);
+
+	case SIMPLE_HASH('S', 'b'):
+		/* std::basic_string */
+		if (!DEM_PUSH_STR(ddata, "std::basic_string"))
+			return (0);
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::basic_string"));
+		return (1);
+
+	case SIMPLE_HASH('S', 'd'):
+		/* std::basic_iostream<char, std::char_traits<char> > */
+		if (!DEM_PUSH_STR(ddata, "std::basic_iostream<char, "
+		    "std::char_traits<char> >"))
+			return (0);
+		ddata->last_sname = "basic_iostream";
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::basic_iostream<char, std::char_traits"
+				"<char> >"));
+		return (1);
+
+	case SIMPLE_HASH('S', 'i'):
+		/* std::basic_istream<char, std::char_traits<char> > */
+		if (!DEM_PUSH_STR(ddata, "std::basic_istream<char, "
+		    "std::char_traits<char> >"))
+			return (0);
+		ddata->last_sname = "basic_istream";
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::basic_istream<char, std::char_traits"
+				"<char> >"));
+		return (1);
+
+	case SIMPLE_HASH('S', 'o'):
+		/* std::basic_ostream<char, std::char_traits<char> > */
+		if (!DEM_PUSH_STR(ddata, "std::basic_ostream<char, "
+		    "std::char_traits<char> >"))
+			return (0);
+		ddata->last_sname = "basic_ostream";
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::basic_ostream<char, std::char_traits"
+				"<char> >"));
+		return (1);
+
+	case SIMPLE_HASH('S', 's'):
+		/*
+		 * std::basic_string<char, std::char_traits<char>,
+		 * std::allocator<char> >
+		 *
+		 * a.k.a std::string
+		 */
+		if (!DEM_PUSH_STR(ddata, "std::basic_string<char, "
+		    "std::char_traits<char>, std::allocator<char> >"))
+			return (0);
+		ddata->last_sname = "string";
+		ddata->cur += 2;
+		if (*ddata->cur == 'I')
+			return (cpp_demangle_read_subst_stdtmpl(ddata,
+			    "std::basic_string<char, std::char_traits<char>,"
+				" std::allocator<char> >"));
+		return (1);
+
+	case SIMPLE_HASH('S', 't'):
+		/* std:: */
+		return (cpp_demangle_read_subst_std(ddata));
+	}
+
+	if (*(++ddata->cur) == '\0')
+		return (0);
+
+	/* Skip unknown substitution abbreviations. */
+	if (!(*ddata->cur >= '0' && *ddata->cur <= '9') &&
+	    !(*ddata->cur >= 'A' && *ddata->cur <= 'Z') &&
+	    *ddata->cur != '_') {
+		++ddata->cur;
+		return (1);
+	}
+
+	/* 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 (!DEM_PUSH_STR(ddata, "std::"))
+		goto clean;
+
+	if (!VEC_PUSH_STR(&v, "std::"))
+		goto clean;
+
+	ddata->cur += 2;
+
+	output = ddata->cur_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)
+{
+	struct vector_str *output;
+	size_t p_idx, substr_len, len;
+	int rtn;
+	char *subst_str, *substr;
+
+	if (ddata == NULL || str == NULL)
+		return (0);
+
+	if ((len = strlen(str)) == 0)
+		return (0);
+
+	output = ddata->cur_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':
+		++ddata->cur;
+		if (!cpp_demangle_read_expression(ddata))
+			return (0);
+		return (*ddata->cur++ == 'E');
+	}
+
+	return (cpp_demangle_read_type(ddata, NULL));
+}
+
+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, NULL))
+		return (0);
+
+	if (!DEM_PUSH_STR(ddata, "<"))
+		return (0);
+
+	limit = 0;
+	v = &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 (!DEM_PUSH_STR(ddata, " >"))
+					return (0);
+			} else if (!DEM_PUSH_STR(ddata, ">"))
+				return (0);
+			ddata->is_tmpl = true;
+			break;
+		} else if (*ddata->cur != 'I' &&
+		    !DEM_PUSH_STR(ddata, ", "))
+			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,
+    struct type_delimit *td)
+{
+	struct vector_type_qualifier v;
+	struct vector_str *output, sv;
+	size_t p_idx, type_str_len, subst_str_len;
+	int extern_c, is_builtin;
+	long len;
+	const char *p;
+	char *type_str, *exp_str, *num_str, *subst_str;
+	bool skip_ref_qualifier, omit_void;
+
+	if (ddata == NULL)
+		return (0);
+
+	output = ddata->cur_output;
+	if (td) {
+		if (td->paren == false) {
+			if (!DEM_PUSH_STR(ddata, "("))
+				return (0);
+			if (ddata->output.size < 2)
+				return (0);
+			td->paren = true;
+		}
+
+		if (!td->firstp) {
+			if (*ddata->cur != 'I') {
+				if (!DEM_PUSH_STR(ddata, ", "))
+					return (0);
+			}
+		}
+	}
+
+	assert(output != NULL);
+	/*
+	 * [r, V, K] [P, R, O, 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 = exp_str = num_str = NULL;
+	skip_ref_qualifier = false;
+
+again:
+
+	/* Clear ref-qualifier flag */
+	if (*ddata->cur != 'R' && *ddata->cur != 'O' && *ddata->cur != 'E')
+		ddata->ref_qualifier = false;
+
+	/* builtin type */
+	switch (*ddata->cur) {
+	case 'a':
+		/* signed char */
+		if (!DEM_PUSH_STR(ddata, "signed char"))
+			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 (!DEM_PUSH_STR(ddata, "bool"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'C':
+		/* complex pair */
+		if (!vector_type_qualifier_push(&v, TYPE_CMX))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'c':
+		/* char */
+		if (!DEM_PUSH_STR(ddata, "char"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'd':
+		/* double */
+		if (!DEM_PUSH_STR(ddata, "double"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'D':
+		++ddata->cur;
+		switch (*ddata->cur) {
+		case 'a':
+			/* auto */
+			if (!DEM_PUSH_STR(ddata, "auto"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'c':
+			/* decltype(auto) */
+			if (!DEM_PUSH_STR(ddata, "decltype(auto)"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'd':
+			/* IEEE 754r decimal floating point (64 bits) */
+			if (!DEM_PUSH_STR(ddata, "decimal64"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'e':
+			/* IEEE 754r decimal floating point (128 bits) */
+			if (!DEM_PUSH_STR(ddata, "decimal128"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'f':
+			/* IEEE 754r decimal floating point (32 bits) */
+			if (!DEM_PUSH_STR(ddata, "decimal32"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'h':
+			/* IEEE 754r half-precision floating point (16 bits) */
+			if (!DEM_PUSH_STR(ddata, "half"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'i':
+			/* char32_t */
+			if (!DEM_PUSH_STR(ddata, "char32_t"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'n':
+			/* std::nullptr_t (i.e., decltype(nullptr)) */
+			if (!DEM_PUSH_STR(ddata, "decltype(nullptr)"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 's':
+			/* char16_t */
+			if (!DEM_PUSH_STR(ddata, "char16_t"))
+				goto clean;
+			++ddata->cur;
+			break;
+		case 'v':
+			/* gcc vector_size extension. */
+			++ddata->cur;
+			if (*ddata->cur == '_') {
+				++ddata->cur;
+				if (!cpp_demangle_read_expression_flat(ddata,
+				    &exp_str))
+					goto clean;
+				if (!VEC_PUSH_STR(&v.ext_name, exp_str))
+					goto clean;
+			} else {
+				if (!cpp_demangle_read_number_as_string(ddata,
+				    &num_str))
+					goto clean;
+				if (!VEC_PUSH_STR(&v.ext_name, num_str))
+					goto clean;
+			}
+			if (*ddata->cur != '_')
+				goto clean;
+			++ddata->cur;
+			if (!vector_type_qualifier_push(&v, TYPE_VEC))
+				goto clean;
+			if (td)
+				td->firstp = false;
+			goto again;
+		default:
+			goto clean;
+		}
+		goto rtn;
+
+	case 'e':
+		/* long double */
+		if (!DEM_PUSH_STR(ddata, "long double"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'E':
+		/* unexpected end except ref-qualifiers */
+		if (ddata->ref_qualifier && ddata->is_functype) {
+			skip_ref_qualifier = true;
+			/* Pop the delimiter. */
+			cpp_demangle_pop_str(ddata);
+			goto rtn;
+		}
+		goto clean;
+
+	case 'f':
+		/* float */
+		if (!DEM_PUSH_STR(ddata, "float"))
+			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 (!DEM_PUSH_STR(ddata, "__float128"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'G':
+		/* imaginary */
+		if (!vector_type_qualifier_push(&v, TYPE_IMG))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'h':
+		/* unsigned char */
+		if (!DEM_PUSH_STR(ddata, "unsigned char"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'i':
+		/* int */
+		if (!DEM_PUSH_STR(ddata, "int"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'I':
+		/* template args. */
+		/* handles <substitute><template-args> */
+		p_idx = output->size;
+		if (!cpp_demangle_read_tmpl_args(ddata))
+			goto clean;
+		if ((subst_str = vector_str_substr(output, p_idx,
+		    output->size - 1, &subst_str_len)) == NULL)
+			goto clean;
+		if (!vector_str_init(&sv)) {
+			free(subst_str);
+			goto clean;
+		}
+		if (!vector_str_push(&sv, subst_str, subst_str_len)) {
+			free(subst_str);
+			vector_str_dest(&sv);
+			goto clean;
+		}
+		free(subst_str);
+		if (!cpp_demangle_push_subst_v(ddata, &sv)) {
+			vector_str_dest(&sv);
+			goto clean;
+		}
+		vector_str_dest(&sv);
+		goto rtn;
+
+	case 'j':
+		/* unsigned int */
+		if (!DEM_PUSH_STR(ddata, "unsigned int"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'K':
+		/* const */
+		if (!vector_type_qualifier_push(&v, TYPE_CST))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'l':
+		/* long */
+		if (!DEM_PUSH_STR(ddata, "long"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'm':
+		/* unsigned long */
+		if (!DEM_PUSH_STR(ddata, "unsigned long"))
+			goto clean;
+
+		++ddata->cur;
+
+		goto rtn;
+	case 'M':
+		/* pointer to member */
+		if (!cpp_demangle_read_pointer_to_member(ddata, &v))
+			goto clean;
+		is_builtin = 0;
+		goto rtn;
+
+	case 'n':
+		/* __int128 */
+		if (!DEM_PUSH_STR(ddata, "__int128"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'o':
+		/* unsigned __int128 */
+		if (!DEM_PUSH_STR(ddata, "unsigned __int128"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'O':
+		/* rvalue reference */
+		if (ddata->ref_qualifier)
+			goto clean;
+		if (!vector_type_qualifier_push(&v, TYPE_RREF))
+			goto clean;
+		ddata->ref_qualifier = true;
+		ddata->ref_qualifier_type = TYPE_RREF;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'P':
+		/* pointer */
+		if (!vector_type_qualifier_push(&v, TYPE_PTR))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'r':
+		/* restrict */
+		if (!vector_type_qualifier_push(&v, TYPE_RST))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'R':
+		/* reference */
+		if (ddata->ref_qualifier)
+			goto clean;
+		if (!vector_type_qualifier_push(&v, TYPE_REF))
+			goto clean;
+		ddata->ref_qualifier = true;
+		ddata->ref_qualifier_type = TYPE_REF;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 's':
+		/* short, local string */
+		if (!DEM_PUSH_STR(ddata, "short"))
+			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 (!DEM_PUSH_STR(ddata, "unsigned short"))
+			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 */
+		++ddata->cur;
+		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;
+		if (!vector_type_qualifier_push(&v, TYPE_EXT))
+			goto clean;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'v':
+		/* void */
+		omit_void = false;
+		if (td && td->firstp) {
+			/*
+			 * peek into next bytes and see if we should omit
+			 * the "void".
+			 */
+			omit_void = true;
+			for (p = ddata->cur + 1; *p != '\0'; p++) {
+				if (*p == 'E')
+					break;
+				if (*p != 'R' && *p != 'O') {
+					omit_void = false;
+					break;
+				}
+			}
+		}
+		if (!omit_void && !DEM_PUSH_STR(ddata, "void"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'V':
+		/* volatile */
+		if (!vector_type_qualifier_push(&v, TYPE_VAT))
+			goto clean;
+		++ddata->cur;
+		if (td)
+			td->firstp = false;
+		goto again;
+
+	case 'w':
+		/* wchar_t */
+		if (!DEM_PUSH_STR(ddata, "wchar_t"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'x':
+		/* long long */
+		if (!DEM_PUSH_STR(ddata, "long long"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'y':
+		/* unsigned long long */
+		if (!DEM_PUSH_STR(ddata, "unsigned long long"))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+
+	case 'z':
+		/* ellipsis */
+		if (!DEM_PUSH_STR(ddata, "..."))
+			goto clean;
+		++ddata->cur;
+		goto rtn;
+	}
+
+	if (!cpp_demangle_read_name(ddata))
+		goto clean;
+
+	is_builtin = 0;
+rtn:
+
+	type_str = vector_str_substr(output, p_idx, output->size - 1,
+	    &type_str_len);
+
+	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 (!skip_ref_qualifier &&
+	    !cpp_demangle_push_type_qualifier(ddata, &v, type_str))
+		goto clean;
+
+	if (td)
+		td->firstp = false;
+
+	free(type_str);
+	free(exp_str);
+	free(num_str);
+	vector_type_qualifier_dest(&v);
+
+	return (1);
+clean:
+	free(type_str);
+	free(exp_str);
+	free(num_str);
+	vector_type_qualifier_dest(&v);
+
+	return (0);
+}
+
+static int
+cpp_demangle_read_type_flat(struct cpp_demangle_data *ddata, char **str)
+{
+	struct vector_str *output;
+	size_t i, p_idx, idx, type_len;
+	char *type;
+
+	output = ddata->cur_output;
+
+	p_idx = output->size;
+
+	if (!cpp_demangle_read_type(ddata, NULL))
+		return (0);
+
+	if ((type = vector_str_substr(output, p_idx, output->size - 1,
+	    &type_len)) == NULL)
+		return (0);
+
+	idx = output->size;
+	for (i = p_idx; i < idx; ++i) {
+		if (!vector_str_pop(output)) {
+			free(type);
+			return (0);
+		}
+	}
+
+	*str = type;
+
+	return (1);
+}
+
+/*
+ * 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 (!DEM_PUSH_STR(ddata, "operator&&"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('a', 'd'):
+		/* operator & (unary) */
+		if (!DEM_PUSH_STR(ddata, "operator&"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('a', 'n'):
+		/* operator & */
+		if (!DEM_PUSH_STR(ddata, "operator&"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('a', 'N'):
+		/* operator &= */
+		if (!DEM_PUSH_STR(ddata, "operator&="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('a', 'S'):
+		/* operator = */
+		if (!DEM_PUSH_STR(ddata, "operator="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('c', 'l'):
+		/* operator () */
+		if (!DEM_PUSH_STR(ddata, "operator()"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('c', 'm'):
+		/* operator , */
+		if (!DEM_PUSH_STR(ddata, "operator,"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('c', 'o'):
+		/* operator ~ */
+		if (!DEM_PUSH_STR(ddata, "operator~"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('c', 'v'):
+		/* operator (cast) */
+		if (!DEM_PUSH_STR(ddata, "operator(cast)"))
+			return (0);
+		ddata->cur += 2;
+		return (cpp_demangle_read_type(ddata, NULL));
+
+	case SIMPLE_HASH('d', 'a'):
+		/* operator delete [] */
+		if (!DEM_PUSH_STR(ddata, "operator delete []"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('d', 'e'):
+		/* operator * (unary) */
+		if (!DEM_PUSH_STR(ddata, "operator*"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('d', 'l'):
+		/* operator delete */
+		if (!DEM_PUSH_STR(ddata, "operator delete"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('d', 'v'):
+		/* operator / */
+		if (!DEM_PUSH_STR(ddata, "operator/"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('d', 'V'):
+		/* operator /= */
+		if (!DEM_PUSH_STR(ddata, "operator/="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('e', 'o'):
+		/* operator ^ */
+		if (!DEM_PUSH_STR(ddata, "operator^"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('e', 'O'):
+		/* operator ^= */
+		if (!DEM_PUSH_STR(ddata, "operator^="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('e', 'q'):
+		/* operator == */
+		if (!DEM_PUSH_STR(ddata, "operator=="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('g', 'e'):
+		/* operator >= */
+		if (!DEM_PUSH_STR(ddata, "operator>="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('g', 't'):
+		/* operator > */
+		if (!DEM_PUSH_STR(ddata, "operator>"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('i', 'x'):
+		/* operator [] */
+		if (!DEM_PUSH_STR(ddata, "operator[]"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('l', 'e'):
+		/* operator <= */
+		if (!DEM_PUSH_STR(ddata, "operator<="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('l', 's'):
+		/* operator << */
+		if (!DEM_PUSH_STR(ddata, "operator<<"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('l', 'S'):
+		/* operator <<= */
+		if (!DEM_PUSH_STR(ddata, "operator<<="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('l', 't'):
+		/* operator < */
+		if (!DEM_PUSH_STR(ddata, "operator<"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('m', 'i'):
+		/* operator - */
+		if (!DEM_PUSH_STR(ddata, "operator-"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('m', 'I'):
+		/* operator -= */
+		if (!DEM_PUSH_STR(ddata, "operator-="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('m', 'l'):
+		/* operator * */
+		if (!DEM_PUSH_STR(ddata, "operator*"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('m', 'L'):
+		/* operator *= */
+		if (!DEM_PUSH_STR(ddata, "operator*="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('m', 'm'):
+		/* operator -- */
+		if (!DEM_PUSH_STR(ddata, "operator--"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('n', 'a'):
+		/* operator new[] */
+		if (!DEM_PUSH_STR(ddata, "operator new []"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('n', 'e'):
+		/* operator != */
+		if (!DEM_PUSH_STR(ddata, "operator!="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('n', 'g'):
+		/* operator - (unary) */
+		if (!DEM_PUSH_STR(ddata, "operator-"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('n', 't'):
+		/* operator ! */
+		if (!DEM_PUSH_STR(ddata, "operator!"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('n', 'w'):
+		/* operator new */
+		if (!DEM_PUSH_STR(ddata, "operator new"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('o', 'o'):
+		/* operator || */
+		if (!DEM_PUSH_STR(ddata, "operator||"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('o', 'r'):
+		/* operator | */
+		if (!DEM_PUSH_STR(ddata, "operator|"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('o', 'R'):
+		/* operator |= */
+		if (!DEM_PUSH_STR(ddata, "operator|="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 'l'):
+		/* operator + */
+		if (!DEM_PUSH_STR(ddata, "operator+"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 'L'):
+		/* operator += */
+		if (!DEM_PUSH_STR(ddata, "operator+="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 'm'):
+		/* operator ->* */
+		if (!DEM_PUSH_STR(ddata, "operator->*"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 'p'):
+		/* operator ++ */
+		if (!DEM_PUSH_STR(ddata, "operator++"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 's'):
+		/* operator + (unary) */
+		if (!DEM_PUSH_STR(ddata, "operator+"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('p', 't'):
+		/* operator -> */
+		if (!DEM_PUSH_STR(ddata, "operator->"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('q', 'u'):
+		/* operator ? */
+		if (!DEM_PUSH_STR(ddata, "operator?"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('r', 'm'):
+		/* operator % */
+		if (!DEM_PUSH_STR(ddata, "operator%"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('r', 'M'):
+		/* operator %= */
+		if (!DEM_PUSH_STR(ddata, "operator%="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('r', 's'):
+		/* operator >> */
+		if (!DEM_PUSH_STR(ddata, "operator>>"))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('r', 'S'):
+		/* operator >>= */
+		if (!DEM_PUSH_STR(ddata, "operator>>="))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('r', 'z'):
+		/* operator sizeof */
+		if (!DEM_PUSH_STR(ddata, "operator sizeof "))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('s', 'r'):
+		/* scope resolution operator */
+		if (!DEM_PUSH_STR(ddata, "scope resolution operator "))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+
+	case SIMPLE_HASH('s', 'v'):
+		/* operator sizeof */
+		if (!DEM_PUSH_STR(ddata, "operator sizeof "))
+			return (0);
+		ddata->cur += 2;
+		return (1);
+	}
+
+	/* vendor extened operator */
+	if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) {
+		if (!DEM_PUSH_STR(ddata, "vendor extened operator "))
+			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'):
+	case SIMPLE_HASH('C', '2'):
+	case SIMPLE_HASH('C', '3'):
+		if (ddata->last_sname == NULL)
+			return (0);
+		if ((len = strlen(ddata->last_sname)) == 0)
+			return (0);
+		if (!DEM_PUSH_STR(ddata, "::"))
+			return (0);
+		if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
+			return (0);
+		ddata->cur +=2;
+		return (1);
+
+	case SIMPLE_HASH('D', '0'):
+	case SIMPLE_HASH('D', '1'):
+	case SIMPLE_HASH('D', '2'):
+		if (ddata->last_sname == NULL)
+			return (0);
+		if ((len = strlen(ddata->last_sname)) == 0)
+			return (0);
+		if (!DEM_PUSH_STR(ddata, "::~"))
+			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 (!DEM_PUSH_STR(ddata, "offset : "))
+		return (0);
+
+	if (!cpp_demangle_read_offset_number(ddata))
+		return (0);
+
+	if (!DEM_PUSH_STR(ddata, "virtual offset : "))
+		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);
+}
+
+static struct read_cmd_item *
+vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
+{
+	int i;
+
+	if (v == NULL || dst == READ_FAIL)
+		return (NULL);
+
+	for (i = (int) v->size - 1; i >= 0; i--)
+		if (v->r_container[i].cmd == dst)
+			return (&v->r_container[i]);
+
+	return (NULL);
+}
+
+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(*v->r_container) * 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].cmd = READ_FAIL;
+	v->r_container[v->size].data = NULL;
+
+	return (1);
+}
+
+static int
+vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd, void *data)
+{
+	struct read_cmd_item *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(*tmp_r_ctn) * 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 = cmd;
+	v->r_container[v->size].data = data;
+	++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/rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_hash.c
new file mode 100644
index 0000000..6cc54b9
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c b/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c
new file mode 100644
index 0000000..934b5db
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/libelftc_vstr.c
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 2008 Hyogeol Lee <hyogeollee at 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 3531 2017-06-05 05:08:43Z kaiwang27 $");
+
+/**
+ * @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 Push org vector to the tail of det vector.
+ * @return false at failed, true at success.
+ */
+bool
+vector_str_push_vector(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 < dst->size; ++i)
+		tmp_ctn[i] = dst->container[i];
+
+	for (i = 0; i < org->size; ++i)
+		if ((tmp_ctn[i + dst->size] = strdup(org->container[i])) ==
+		    NULL) {
+			for (j = 0; j < i + dst->size; ++j)
+				free(tmp_ctn[j]);
+
+			free(tmp_ctn);
+
+			return (false);
+		}
+
+	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/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version b/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version
new file mode 100755
index 0000000..0cdf370
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/make-toolchain-version
@@ -0,0 +1,110 @@
+#!/bin/sh
+#
+# This script generates a project-wide version identifier for use by
+# the `elftc_version()' API.
+#
+# $Id: make-toolchain-version 3414 2016-02-16 22:55:28Z 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 CVS ]; then		# Look for CVS (NetBSD).
+    versionstring=" cvs:unknown"
+else				# Try git (DragonFlyBSD).
+    gitversion="$(git describe --all --dirty --long 2> /dev/null)"
+    if [ -n "${gitversion}" ]; then
+        versionstring=" git:${gitversion}"
+    else   # Assume an SVN checkout (SourceForge or FreeBSD).
+        svnversion="$(svnversion)"
+        if [ -n "${svnversion}" ]; then
+	    versionstring=" svn:$(svnversion)"
+        fi
+    fi
+fi
+
+if [ -z "${versionstring}" ]; then
+    echo "ERROR: cannot determine a revision number." 1>&2
+    exit 1
+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/rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk b/rtemstoolkit/elftoolchain/libelftc/os.FreeBSD.mk
new file mode 100644
index 0000000..8079a5b
--- /dev/null
+++ b/rtemstoolkit/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/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk b/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk
new file mode 100644
index 0000000..d99117d
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/os.Linux.mk
@@ -0,0 +1,3 @@
+# $Id: os.Linux.mk 3210 2015-05-17 13:40:49Z kaiwang27 $
+
+CFLAGS+=	-Wall -D_GNU_SOURCE
diff --git a/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk b/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk
new file mode 100644
index 0000000..ae214e3
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libelftc/os.NetBSD.mk
@@ -0,0 +1,2 @@
+# TODO(#511): Revert after the source tree is -Wconversion clean.
+WARNS=5
diff --git a/rtemstoolkit/wscript b/rtemstoolkit/wscript
index 4c30935..4b5fa34 100644
--- a/rtemstoolkit/wscript
+++ b/rtemstoolkit/wscript
@@ -170,6 +170,7 @@ def conf_elftoolchain(conf):
 
 def bld_elftoolchain(bld, conf):
     libelf = 'elftoolchain/libelf/'
+    libelftc = 'elftoolchain/libelftc/'
     libdwarf = 'elftoolchain/libdwarf/'
     libelf_m4_rule = '${M4} -D SRCDIR=../rtemstoolkit/' + libelf[:-1] + ' ${SRC} > ${TGT}'
     libdwarf_m4_rule = '${M4} -D SRCDIR=../rtemstoolkit/' + libdwarf[:-1] + ' ${SRC} > ${TGT}'
@@ -334,6 +335,29 @@ def bld_elftoolchain(bld, conf):
                        libdwarf + 'libdwarf_sections.c',
                        libdwarf + 'libdwarf_str.c'] + libdwarf_m4_source)
 
+    bld.stlib(target = 'elftc',
+              features = 'c',
+              install_path = None,
+              includes = [bld.bldnode.abspath(),
+                          'elftoolchain/libelf',
+                          'elftoolchain/libelftc',
+                          'elftoolchain/common'] + includes,
+              cflags = conf['cflags'],
+              source =[libelftc + 'elftc_bfdtarget.c',
+                       libelftc + 'elftc_copyfile.c',
+                       libelftc + 'elftc_demangle.c',
+                       libelftc + 'elftc_reloc_type_str.c',
+                       libelftc + 'elftc_set_timestamps.c',
+                       libelftc + 'elftc_string_table.c',
+                       libelftc + 'elftc_timestamp.c',
+                       libelftc + 'elftc_version.c',
+                       libelftc + 'libelftc_bfdtarget.c',
+                       libelftc + 'libelftc_dem_arm.c',
+                       libelftc + 'libelftc_dem_gnu2.c',
+                       libelftc + 'libelftc_dem_gnu3.c',
+                       libelftc + 'libelftc_hash.c',
+                       libelftc + 'libelftc_vstr.c'])
+
 #
 # Libiberty module.
 #



More information about the vc mailing list