summaryrefslogtreecommitdiffstats
path: root/contrib/libcxxrt
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libcxxrt')
-rw-r--r--contrib/libcxxrt/FREEBSD-upgrade6
-rw-r--r--contrib/libcxxrt/LICENSE14
-rw-r--r--contrib/libcxxrt/abi_namespace.h5
-rw-r--r--contrib/libcxxrt/auxhelper.cc41
-rw-r--r--contrib/libcxxrt/cxxabi.h219
-rw-r--r--contrib/libcxxrt/dwarf_eh.h454
-rw-r--r--contrib/libcxxrt/dynamic_cast.cc133
-rw-r--r--contrib/libcxxrt/exception.cc1483
-rw-r--r--contrib/libcxxrt/guard.cc134
-rw-r--r--contrib/libcxxrt/libelftc_dem_gnu3.c3473
-rw-r--r--contrib/libcxxrt/memory.cc115
-rw-r--r--contrib/libcxxrt/stdexcept.cc60
-rw-r--r--contrib/libcxxrt/stdexcept.h61
-rw-r--r--contrib/libcxxrt/terminate.cc14
-rw-r--r--contrib/libcxxrt/typeinfo26
-rw-r--r--contrib/libcxxrt/typeinfo.cc83
-rw-r--r--contrib/libcxxrt/typeinfo.h200
-rw-r--r--contrib/libcxxrt/unwind-arm.h201
-rw-r--r--contrib/libcxxrt/unwind-itanium.h170
-rw-r--r--contrib/libcxxrt/unwind.h18
20 files changed, 6910 insertions, 0 deletions
diff --git a/contrib/libcxxrt/FREEBSD-upgrade b/contrib/libcxxrt/FREEBSD-upgrade
new file mode 100644
index 0000000..ac62556
--- /dev/null
+++ b/contrib/libcxxrt/FREEBSD-upgrade
@@ -0,0 +1,6 @@
+$FreeBSD$
+
+This is the FreeBSD copy of libcxxrt. It contains the src directory from the
+upstream repository.
+
+When updating, copy *.{c,cc,h} and typeinfo from the upstream src/.
diff --git a/contrib/libcxxrt/LICENSE b/contrib/libcxxrt/LICENSE
new file mode 100644
index 0000000..cda1ea2
--- /dev/null
+++ b/contrib/libcxxrt/LICENSE
@@ -0,0 +1,14 @@
+The BSD License
+
+Copyright 2010-2011 PathScale, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
+
+The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of PathScale, Inc.
diff --git a/contrib/libcxxrt/abi_namespace.h b/contrib/libcxxrt/abi_namespace.h
new file mode 100644
index 0000000..dda788d
--- /dev/null
+++ b/contrib/libcxxrt/abi_namespace.h
@@ -0,0 +1,5 @@
+/**
+ * The namespace used for the ABI declarations. This is currently defined to
+ * be the same as GNU libsupc++, however this may change in the future.
+ */
+#define ABI_NAMESPACE __cxxabiv1
diff --git a/contrib/libcxxrt/auxhelper.cc b/contrib/libcxxrt/auxhelper.cc
new file mode 100644
index 0000000..e8ce6e7
--- /dev/null
+++ b/contrib/libcxxrt/auxhelper.cc
@@ -0,0 +1,41 @@
+/**
+ * aux.cc - Compiler helper functions.
+ *
+ * The functions declared in this file are intended to be called only by code
+ * that is automatically generated by C++ compilers for some common cases.
+ */
+
+#include <stdlib.h>
+#include "stdexcept.h"
+
+/**
+ * Called to generate a bad cast exception. This function is intended to allow
+ * compilers to insert code generating this exception without needing to
+ * duplicate the code for throwing the exception in every call site.
+ */
+extern "C" void __cxa_bad_cast()
+{
+ throw std::bad_cast();
+}
+
+/**
+ * Called to generate a bad typeid exception. This function is intended to
+ * allow compilers to insert code generating this exception without needing to
+ * duplicate the code for throwing the exception in every call site.
+ */
+extern "C" void __cxa_bad_typeid()
+{
+ throw std::bad_typeid();
+}
+
+/**
+ * Compilers may (but are not required to) set any pure-virtual function's
+ * vtable entry to this function. This makes debugging slightly easier, as
+ * users can add a breakpoint on this function to tell if they've accidentally
+ * called a pure-virtual function.
+ */
+extern "C" void __cxa_pure_virtual()
+{
+ abort();
+}
+
diff --git a/contrib/libcxxrt/cxxabi.h b/contrib/libcxxrt/cxxabi.h
new file mode 100644
index 0000000..040d28d
--- /dev/null
+++ b/contrib/libcxxrt/cxxabi.h
@@ -0,0 +1,219 @@
+#ifndef __CXXABI_H_
+#define __CXXABI_H_
+#include <stdint.h>
+#include "unwind.h"
+namespace std
+{
+ class type_info;
+}
+/*
+ * The cxxabi.h header provides a set of public definitions for types and
+ * functions defined by the Itanium C++ ABI specification. For reference, see
+ * the ABI specification here:
+ *
+ * http://sourcery.mentor.com/public/cxx-abi/abi.html
+ *
+ * All deviations from this specification, unless otherwise noted, are
+ * accidental.
+ */
+
+#ifdef __cplusplus
+namespace __cxxabiv1 {
+extern "C" {
+#endif
+/**
+ * Function type to call when an unexpected exception is encountered.
+ */
+typedef void (*unexpected_handler)();
+/**
+ * Function type to call when an unrecoverable condition is encountered.
+ */
+typedef void (*terminate_handler)();
+
+
+/**
+ * Structure used as a header on thrown exceptions. This is the same layout as
+ * defined by the Itanium ABI spec, so should be interoperable with any other
+ * implementation of this spec, such as GNU libsupc++.
+ *
+ * This structure is allocated when an exception is thrown. Unwinding happens
+ * in two phases, the first looks for a handler and the second installs the
+ * context. This structure stores a cache of the handler location between
+ * phase 1 and phase 2. Unfortunately, cleanup information is not cached, so
+ * must be looked up in both phases. This happens for two reasons. The first
+ * is that we don't know how many frames containing cleanups there will be, and
+ * we should avoid dynamic allocation during unwinding (the exception may be
+ * reporting that we've run out of memory). The second is that finding
+ * cleanups is much cheaper than finding handlers, because we don't have to
+ * look at the type table at all.
+ *
+ * Note: Several fields of this structure have not-very-informative names.
+ * These are taken from the ABI spec and have not been changed to make it
+ * easier for people referring to to the spec while reading this code.
+ */
+struct __cxa_exception
+{
+#if __LP64__
+ /**
+ * Reference count. Used to support the C++11 exception_ptr class. This
+ * is prepended to the structure in 64-bit mode and squeezed in to the
+ * padding left before the 64-bit aligned _Unwind_Exception at the end in
+ * 32-bit mode.
+ *
+ * Note that it is safe to extend this structure at the beginning, rather
+ * than the end, because the public API for creating it returns the address
+ * of the end (where the exception object can be stored).
+ */
+ uintptr_t referenceCount;
+#endif
+ /** Type info for the thrown object. */
+ std::type_info *exceptionType;
+ /** Destructor for the object, if one exists. */
+ void (*exceptionDestructor) (void *);
+ /** Handler called when an exception specification is violated. */
+ unexpected_handler unexpectedHandler;
+ /** Hander called to terminate. */
+ terminate_handler terminateHandler;
+ /**
+ * Next exception in the list. If an exception is thrown inside a catch
+ * block and caught in a nested catch, this points to the exception that
+ * will be handled after the inner catch block completes.
+ */
+ __cxa_exception *nextException;
+ /**
+ * The number of handlers that currently have references to this
+ * exception. The top (non-sign) bit of this is used as a flag to indicate
+ * that the exception is being rethrown, so should not be deleted when its
+ * handler count reaches 0 (which it doesn't with the top bit set).
+ */
+ int handlerCount;
+#ifdef __arm__
+ /**
+ * The ARM EH ABI requires the unwind library to keep track of exceptions
+ * during cleanups. These support nesting, so we need to keep a list of
+ * them.
+ */
+ _Unwind_Exception *nextCleanup;
+ /**
+ * The number of cleanups that are currently being run on this exception.
+ */
+ int cleanupCount;
+#endif
+ /**
+ * The selector value to be returned when installing the catch handler.
+ * Used at the call site to determine which catch() block should execute.
+ * This is found in phase 1 of unwinding then installed in phase 2.
+ */
+ int handlerSwitchValue;
+ /**
+ * The action record for the catch. This is cached during phase 1
+ * unwinding.
+ */
+ const char *actionRecord;
+ /**
+ * Pointer to the language-specific data area (LSDA) for the handler
+ * frame. This is unused in this implementation, but set for ABI
+ * compatibility in case we want to mix code in very weird ways.
+ */
+ const char *languageSpecificData;
+ /** The cached landing pad for the catch handler.*/
+ void *catchTemp;
+ /**
+ * The pointer that will be returned as the pointer to the object. When
+ * throwing a class and catching a virtual superclass (for example), we
+ * need to adjust the thrown pointer to make it all work correctly.
+ */
+ void *adjustedPtr;
+#if !__LP64__
+ /**
+ * Reference count. Used to support the C++11 exception_ptr class. This
+ * is prepended to the structure in 64-bit mode and squeezed in to the
+ * padding left before the 64-bit aligned _Unwind_Exception at the end in
+ * 32-bit mode.
+ *
+ * Note that it is safe to extend this structure at the beginning, rather
+ * than the end, because the public API for creating it returns the address
+ * of the end (where the exception object can be stored)
+ */
+ uintptr_t referenceCount;
+#endif
+ /** The language-agnostic part of the exception header. */
+ _Unwind_Exception unwindHeader;
+};
+
+/**
+ * ABI-specified globals structure. Returned by the __cxa_get_globals()
+ * function and its fast variant. This is a per-thread structure - every
+ * thread will have one lazily allocated.
+ *
+ * This structure is defined by the ABI, so may be used outside of this
+ * library.
+ */
+struct __cxa_eh_globals
+{
+ /**
+ * A linked list of exceptions that are currently caught. There may be
+ * several of these in nested catch() blocks.
+ */
+ __cxa_exception *caughtExceptions;
+ /**
+ * The number of uncaught exceptions.
+ */
+ unsigned int uncaughtExceptions;
+};
+/**
+ * ABI function returning the __cxa_eh_globals structure.
+ */
+__cxa_eh_globals *__cxa_get_globals(void);
+/**
+ * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already
+ * been called at least once by this thread.
+ */
+__cxa_eh_globals *__cxa_get_globals_fast(void);
+
+/**
+ * Throws an exception returned by __cxa_current_primary_exception(). This
+ * exception may have been caught in another thread.
+ */
+void __cxa_rethrow_primary_exception(void* thrown_exception);
+/**
+ * Returns the current exception in a form that can be stored in an
+ * exception_ptr object and then rethrown by a call to
+ * __cxa_rethrow_primary_exception().
+ */
+void *__cxa_current_primary_exception(void);
+/**
+ * Increments the reference count of an exception. Called when an
+ * exception_ptr is copied.
+ */
+void __cxa_increment_exception_refcount(void* thrown_exception);
+/**
+ * Decrements the reference count of an exception. Called when an
+ * exception_ptr is deleted.
+ */
+void __cxa_decrement_exception_refcount(void* thrown_exception);
+/**
+ * Demangles a C++ symbol or type name. The buffer, if non-NULL, must be
+ * allocated with malloc() and must be *n bytes or more long. This function
+ * may call realloc() on the value pointed to by buf, and will return the
+ * length of the string via *n.
+ *
+ * The value pointed to by status is set to one of the following:
+ *
+ * 0: success
+ * -1: memory allocation failure
+ * -2: invalid mangled name
+ * -3: invalid arguments
+ */
+char* __cxa_demangle(const char* mangled_name,
+ char* buf,
+ size_t* n,
+ int* status);
+#ifdef __cplusplus
+} // extern "C"
+} // namespace
+
+namespace abi = __cxxabiv1;
+
+#endif /* __cplusplus */
+#endif /* __CXXABI_H_ */
diff --git a/contrib/libcxxrt/dwarf_eh.h b/contrib/libcxxrt/dwarf_eh.h
new file mode 100644
index 0000000..52e6369
--- /dev/null
+++ b/contrib/libcxxrt/dwarf_eh.h
@@ -0,0 +1,454 @@
+/**
+ * dwarf_eh.h - Defines some helper functions for parsing DWARF exception
+ * handling tables.
+ *
+ * This file contains various helper functions that are independent of the
+ * language-specific code. It can be used in any personality function for the
+ * Itanium ABI.
+ */
+#include <assert.h>
+
+// TODO: Factor out Itanium / ARM differences. We probably want an itanium.h
+// and arm.h that can be included by this file depending on the target ABI.
+
+// _GNU_SOURCE must be defined for unwind.h to expose some of the functions
+// that we want. If it isn't, then we define it and undefine it to make sure
+// that it doesn't impact the rest of the program.
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+# include "unwind.h"
+# undef _GNU_SOURCE
+#else
+# include "unwind.h"
+#endif
+
+#include <stdint.h>
+
+/// Type used for pointers into DWARF data
+typedef unsigned char *dw_eh_ptr_t;
+
+// Flag indicating a signed quantity
+#define DW_EH_PE_signed 0x08
+/// DWARF data encoding types.
+enum dwarf_data_encoding
+{
+ /// Unsigned, little-endian, base 128-encoded (variable length).
+ DW_EH_PE_uleb128 = 0x01,
+ /// Unsigned 16-bit integer.
+ DW_EH_PE_udata2 = 0x02,
+ /// Unsigned 32-bit integer.
+ DW_EH_PE_udata4 = 0x03,
+ /// Unsigned 64-bit integer.
+ DW_EH_PE_udata8 = 0x04,
+ /// Signed, little-endian, base 128-encoded (variable length)
+ DW_EH_PE_sleb128 = DW_EH_PE_uleb128 | DW_EH_PE_signed,
+ /// Signed 16-bit integer.
+ DW_EH_PE_sdata2 = DW_EH_PE_udata2 | DW_EH_PE_signed,
+ /// Signed 32-bit integer.
+ DW_EH_PE_sdata4 = DW_EH_PE_udata4 | DW_EH_PE_signed,
+ /// Signed 32-bit integer.
+ DW_EH_PE_sdata8 = DW_EH_PE_udata8 | DW_EH_PE_signed
+};
+
+/**
+ * Returns the encoding for a DWARF EH table entry. The encoding is stored in
+ * the low four of an octet. The high four bits store the addressing mode.
+ */
+static inline enum dwarf_data_encoding get_encoding(unsigned char x)
+{
+ return (enum dwarf_data_encoding)(x & 0xf);
+}
+
+/**
+ * DWARF addressing mode constants. When reading a pointer value from a DWARF
+ * exception table, you must know how it is stored and what the addressing mode
+ * is. The low four bits tell you the encoding, allowing you to decode a
+ * number. The high four bits tell you the addressing mode, allowing you to
+ * turn that number into an address in memory.
+ */
+enum dwarf_data_relative
+{
+ /// Value is omitted
+ DW_EH_PE_omit = 0xff,
+ /// Absolute pointer value
+ DW_EH_PE_absptr = 0x00,
+ /// Value relative to program counter
+ DW_EH_PE_pcrel = 0x10,
+ /// Value relative to the text segment
+ DW_EH_PE_textrel = 0x20,
+ /// Value relative to the data segment
+ DW_EH_PE_datarel = 0x30,
+ /// Value relative to the start of the function
+ DW_EH_PE_funcrel = 0x40,
+ /// Aligned pointer (Not supported yet - are they actually used?)
+ DW_EH_PE_aligned = 0x50,
+ /// Pointer points to address of real value
+ DW_EH_PE_indirect = 0x80
+};
+/**
+ * Returns the addressing mode component of this encoding.
+ */
+static inline enum dwarf_data_relative get_base(unsigned char x)
+{
+ return (enum dwarf_data_relative)(x & 0x70);
+}
+/**
+ * Returns whether an encoding represents an indirect address.
+ */
+static int is_indirect(unsigned char x)
+{
+ return ((x & DW_EH_PE_indirect) == DW_EH_PE_indirect);
+}
+
+/**
+ * Returns the size of a fixed-size encoding. This function will abort if
+ * called with a value that is not a fixed-size encoding.
+ */
+static inline int dwarf_size_of_fixed_size_field(unsigned char type)
+{
+ switch (get_encoding(type))
+ {
+ default: abort();
+ case DW_EH_PE_sdata2:
+ case DW_EH_PE_udata2: return 2;
+ case DW_EH_PE_sdata4:
+ case DW_EH_PE_udata4: return 4;
+ case DW_EH_PE_sdata8:
+ case DW_EH_PE_udata8: return 8;
+ case DW_EH_PE_absptr: return sizeof(void*);
+ }
+}
+
+/**
+ * Read an unsigned, little-endian, base-128, DWARF value. Updates *data to
+ * point to the end of the value. Stores the number of bits read in the value
+ * pointed to by b, allowing you to determine the value of the highest bit, and
+ * therefore the sign of a signed value.
+ *
+ * This function is not intended to be called directly. Use read_sleb128() or
+ * read_uleb128() for reading signed and unsigned versions, respectively.
+ */
+static uint64_t read_leb128(dw_eh_ptr_t *data, int *b)
+{
+ uint64_t uleb = 0;
+ unsigned int bit = 0;
+ unsigned char digit = 0;
+ // We have to read at least one octet, and keep reading until we get to one
+ // with the high bit unset
+ do
+ {
+ // This check is a bit too strict - we should also check the highest
+ // bit of the digit.
+ assert(bit < sizeof(uint64_t) * 8);
+ // Get the base 128 digit
+ digit = (**data) & 0x7f;
+ // Add it to the current value
+ uleb += digit << bit;
+ // Increase the shift value
+ bit += 7;
+ // Proceed to the next octet
+ (*data)++;
+ // Terminate when we reach a value that does not have the high bit set
+ // (i.e. which was not modified when we mask it with 0x7f)
+ } while ((*(*data - 1)) != digit);
+ *b = bit;
+
+ return uleb;
+}
+
+/**
+ * Reads an unsigned little-endian base-128 value starting at the address
+ * pointed to by *data. Updates *data to point to the next byte after the end
+ * of the variable-length value.
+ */
+static int64_t read_uleb128(dw_eh_ptr_t *data)
+{
+ int b;
+ return read_leb128(data, &b);
+}
+
+/**
+ * Reads a signed little-endian base-128 value starting at the address pointed
+ * to by *data. Updates *data to point to the next byte after the end of the
+ * variable-length value.
+ */
+static int64_t read_sleb128(dw_eh_ptr_t *data)
+{
+ int bits;
+ // Read as if it's signed
+ uint64_t uleb = read_leb128(data, &bits);
+ // If the most significant bit read is 1, then we need to sign extend it
+ if ((uleb >> (bits-1)) == 1)
+ {
+ // Sign extend by setting all bits in front of it to 1
+ uleb |= ((int64_t)-1) << bits;
+ }
+ return (int64_t)uleb;
+}
+/**
+ * Reads a value using the specified encoding from the address pointed to by
+ * *data. Updates the value of *data to point to the next byte after the end
+ * of the data.
+ */
+static uint64_t read_value(char encoding, dw_eh_ptr_t *data)
+{
+ enum dwarf_data_encoding type = get_encoding(encoding);
+ uint64_t v;
+ switch (type)
+ {
+ // Read fixed-length types
+#define READ(dwarf, type) \
+ case dwarf:\
+ v = (uint64_t)(*(type*)(*data));\
+ *data += sizeof(type);\
+ break;
+ READ(DW_EH_PE_udata2, uint16_t)
+ READ(DW_EH_PE_udata4, uint32_t)
+ READ(DW_EH_PE_udata8, uint64_t)
+ READ(DW_EH_PE_sdata2, int16_t)
+ READ(DW_EH_PE_sdata4, int32_t)
+ READ(DW_EH_PE_sdata8, int64_t)
+ READ(DW_EH_PE_absptr, intptr_t)
+#undef READ
+ // Read variable-length types
+ case DW_EH_PE_sleb128:
+ v = read_sleb128(data);
+ break;
+ case DW_EH_PE_uleb128:
+ v = read_uleb128(data);
+ break;
+ default: abort();
+ }
+
+ return v;
+}
+
+/**
+ * Resolves an indirect value. This expects an unwind context, an encoding, a
+ * decoded value, and the start of the region as arguments. The returned value
+ * is a pointer to the address identified by the encoded value.
+ *
+ * If the encoding does not specify an indirect value, then this returns v.
+ */
+static uint64_t resolve_indirect_value(_Unwind_Context *c,
+ unsigned char encoding,
+ int64_t v,
+ dw_eh_ptr_t start)
+{
+ switch (get_base(encoding))
+ {
+ case DW_EH_PE_pcrel:
+ v += (uint64_t)start;
+ break;
+ case DW_EH_PE_textrel:
+ v += (uint64_t)_Unwind_GetTextRelBase(c);
+ break;
+ case DW_EH_PE_datarel:
+ v += (uint64_t)_Unwind_GetDataRelBase(c);
+ break;
+ case DW_EH_PE_funcrel:
+ v += (uint64_t)_Unwind_GetRegionStart(c);
+ default:
+ break;
+ }
+ // If this is an indirect value, then it is really the address of the real
+ // value
+ // TODO: Check whether this should really always be a pointer - it seems to
+ // be a GCC extensions, so not properly documented...
+ if (is_indirect(encoding))
+ {
+ v = (uint64_t)(uintptr_t)*(void**)v;
+ }
+ return v;
+}
+
+
+/**
+ * Reads an encoding and a value, updating *data to point to the next byte.
+ */
+static inline void read_value_with_encoding(_Unwind_Context *context,
+ dw_eh_ptr_t *data,
+ uint64_t *out)
+{
+ dw_eh_ptr_t start = *data;
+ unsigned char encoding = *((*data)++);
+ // If this value is omitted, skip it and don't touch the output value
+ if (encoding == DW_EH_PE_omit) { return; }
+
+ *out = read_value(encoding, data);
+ *out = resolve_indirect_value(context, encoding, *out, start);
+}
+
+/**
+ * Structure storing a decoded language-specific data area. Use parse_lsda()
+ * to generate an instance of this structure from the address returned by the
+ * generic unwind library.
+ *
+ * You should not need to inspect the fields of this structure directly if you
+ * are just using this header. The structure stores the locations of the
+ * various tables used for unwinding exceptions and is used by the functions
+ * for reading values from these tables.
+ */
+struct dwarf_eh_lsda
+{
+ /// The start of the region. This is a cache of the value returned by
+ /// _Unwind_GetRegionStart().
+ dw_eh_ptr_t region_start;
+ /// The start of the landing pads table.
+ dw_eh_ptr_t landing_pads;
+ /// The start of the type table.
+ dw_eh_ptr_t type_table;
+ /// The encoding used for entries in the type tables.
+ unsigned char type_table_encoding;
+ /// The location of the call-site table.
+ dw_eh_ptr_t call_site_table;
+ /// The location of the action table.
+ dw_eh_ptr_t action_table;
+ /// The encoding used for entries in the call-site table.
+ unsigned char callsite_encoding;
+};
+
+/**
+ * Parse the header on the language-specific data area and return a structure
+ * containing the addresses and encodings of the various tables.
+ */
+static inline struct dwarf_eh_lsda parse_lsda(_Unwind_Context *context,
+ unsigned char *data)
+{
+ struct dwarf_eh_lsda lsda;
+
+ lsda.region_start = (dw_eh_ptr_t)(uintptr_t)_Unwind_GetRegionStart(context);
+
+ // If the landing pads are relative to anything other than the start of
+ // this region, find out where. This is @LPStart in the spec, although the
+ // encoding that GCC uses does not quite match the spec.
+ uint64_t v = (uint64_t)(uintptr_t)lsda.region_start;
+ read_value_with_encoding(context, &data, &v);
+ lsda.landing_pads = (dw_eh_ptr_t)(uintptr_t)v;
+
+ // If there is a type table, find out where it is. This is @TTBase in the
+ // spec. Note: we find whether there is a type table pointer by checking
+ // whether the leading byte is DW_EH_PE_omit (0xff), which is not what the
+ // spec says, but does seem to be how G++ indicates this.
+ lsda.type_table = 0;
+ lsda.type_table_encoding = *data++;
+ if (lsda.type_table_encoding != DW_EH_PE_omit)
+ {
+ v = read_uleb128(&data);
+ dw_eh_ptr_t type_table = data;
+ type_table += v;
+ lsda.type_table = type_table;
+ //lsda.type_table = (uintptr_t*)(data + v);
+ }
+#if __arm__
+ lsda.type_table_encoding = (DW_EH_PE_pcrel | DW_EH_PE_indirect);
+#endif
+
+ lsda.callsite_encoding = (enum dwarf_data_encoding)(*(data++));
+
+ // Action table is immediately after the call site table
+ lsda.action_table = data;
+ uintptr_t callsite_size = (uintptr_t)read_uleb128(&data);
+ lsda.action_table = data + callsite_size;
+ // Call site table is immediately after the header
+ lsda.call_site_table = (dw_eh_ptr_t)data;
+
+
+ return lsda;
+}
+
+/**
+ * Structure representing an action to be performed while unwinding. This
+ * contains the address that should be unwound to and the action record that
+ * provoked this action.
+ */
+struct dwarf_eh_action
+{
+ /**
+ * The address that this action directs should be the new program counter
+ * value after unwinding.
+ */
+ dw_eh_ptr_t landing_pad;
+ /// The address of the action record.
+ dw_eh_ptr_t action_record;
+};
+
+/**
+ * Look up the landing pad that corresponds to the current invoke.
+ * Returns true if record exists. The context is provided by the generic
+ * unwind library and the lsda should be the result of a call to parse_lsda().
+ *
+ * The action record is returned via the result parameter.
+ */
+static bool dwarf_eh_find_callsite(struct _Unwind_Context *context,
+ struct dwarf_eh_lsda *lsda,
+ struct dwarf_eh_action *result)
+{
+ result->action_record = 0;
+ result->landing_pad = 0;
+ // The current instruction pointer offset within the region
+ uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context);
+ unsigned char *callsite_table = (unsigned char*)lsda->call_site_table;
+
+ while (callsite_table <= lsda->action_table)
+ {
+ // Once again, the layout deviates from the spec.
+ uint64_t call_site_start, call_site_size, landing_pad, action;
+ call_site_start = read_value(lsda->callsite_encoding, &callsite_table);
+ call_site_size = read_value(lsda->callsite_encoding, &callsite_table);
+
+ // Call site entries are sorted, so if we find a call site that's after
+ // the current instruction pointer then there is no action associated
+ // with this call and we should unwind straight through this frame
+ // without doing anything.
+ if (call_site_start > ip) { break; }
+
+ // Read the address of the landing pad and the action from the call
+ // site table.
+ landing_pad = read_value(lsda->callsite_encoding, &callsite_table);
+ action = read_uleb128(&callsite_table);
+
+ // We should not include the call_site_start (beginning of the region)
+ // address in the ip range. For each call site:
+ //
+ // address1: call proc
+ // address2: next instruction
+ //
+ // The call stack contains address2 and not address1, address1 can be
+ // at the end of another EH region.
+ if (call_site_start < ip && ip <= call_site_start + call_site_size)
+ {
+ if (action)
+ {
+ // Action records are 1-biased so both no-record and zeroth
+ // record can be stored.
+ result->action_record = lsda->action_table + action - 1;
+ }
+ // No landing pad means keep unwinding.
+ if (landing_pad)
+ {
+ // Landing pad is the offset from the value in the header
+ result->landing_pad = lsda->landing_pads + landing_pad;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+/// Defines an exception class from 8 bytes (endian independent)
+#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) \
+ (((uint64_t)a << 56) +\
+ ((uint64_t)b << 48) +\
+ ((uint64_t)c << 40) +\
+ ((uint64_t)d << 32) +\
+ ((uint64_t)e << 24) +\
+ ((uint64_t)f << 16) +\
+ ((uint64_t)g << 8) +\
+ ((uint64_t)h))
+
+#define GENERIC_EXCEPTION_CLASS(e,f,g,h) \
+ ((uint32_t)e << 24) +\
+ ((uint32_t)f << 16) +\
+ ((uint32_t)g << 8) +\
+ ((uint32_t)h)
diff --git a/contrib/libcxxrt/dynamic_cast.cc b/contrib/libcxxrt/dynamic_cast.cc
new file mode 100644
index 0000000..043796f
--- /dev/null
+++ b/contrib/libcxxrt/dynamic_cast.cc
@@ -0,0 +1,133 @@
+#include "typeinfo.h"
+#include <stdio.h>
+
+using namespace ABI_NAMESPACE;
+
+/**
+ * Vtable header.
+ */
+struct vtable_header
+{
+ /** Offset of the leaf object. */
+ ptrdiff_t leaf_offset;
+ /** Type of the object. */
+ const __class_type_info *type;
+};
+
+/**
+ * Simple macro that does pointer arithmetic in bytes but returns a value of
+ * the same type as the original.
+ */
+#define ADD_TO_PTR(x, off) (__typeof__(x))(((char*)x) + off)
+
+bool __class_type_info::can_cast_to(const struct __class_type_info *other) const
+{
+ return this == other;
+}
+
+void *__class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
+{
+ if (this == other)
+ {
+ return obj;
+ }
+ return 0;
+}
+
+
+bool __si_class_type_info::can_cast_to(const struct __class_type_info *other) const
+{
+ return this == other || __base_type->can_cast_to(other);
+}
+
+void *__si_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
+{
+ if (this == other)
+ {
+ return obj;
+ }
+ return __base_type->cast_to(obj, other);
+}
+
+
+bool __vmi_class_type_info::can_cast_to(const struct __class_type_info *other) const
+{
+ if (this == other)
+ {
+ return true;
+ }
+ for (unsigned int i=0 ; i<__base_count ; i++)
+ {
+ const __base_class_type_info *info = &__base_info[i];
+ if(info->isPublic() && info->__base_type->can_cast_to(other))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void *__vmi_class_type_info::cast_to(void *obj, const struct __class_type_info *other) const
+{
+ if (this == other)
+ {
+ return obj;
+ }
+ for (unsigned int i=0 ; i<__base_count ; i++)
+ {
+ const __base_class_type_info *info = &__base_info[i];
+ ptrdiff_t offset = info->offset();
+ // If this is a virtual superclass, the offset is stored in the
+ // object's vtable at the offset requested; 2.9.5.6.c:
+ //
+ // 'For a non-virtual base, this is the offset in the object of the
+ // base subobject. For a virtual base, this is the offset in the
+ // virtual table of the virtual base offset for the virtual base
+ // referenced (negative).'
+
+ if (info->isVirtual())
+ {
+ // Object's vtable
+ ptrdiff_t *off = *(ptrdiff_t**)obj;
+ // Offset location in vtable
+ off = ADD_TO_PTR(off, offset);
+ offset = *off;
+ }
+ void *cast = ADD_TO_PTR(obj, offset);
+
+ if (info->__base_type == other)
+ {
+ return cast;
+ }
+ if ((cast = info->__base_type->cast_to(cast, other)))
+ {
+ return cast;
+ }
+ }
+ return 0;
+}
+
+/**
+ * ABI function used to implement the dynamic_cast<> operator. Some cases of
+ * this operator are implemented entirely in the compiler (e.g. to void*).
+ * This function implements the dynamic casts of the form dynamic_cast<T>(v).
+ * This will be translated to a call to this function with the value v as the
+ * first argument. The type id of the static type of v is the second argument
+ * and the type id of the destination type (T) is the third argument.
+ *
+ * The third argument is a hint about the compiler's guess at the correct
+ * pointer offset. If this value is negative, then -1 indicates no hint, -2
+ * that src is not a public base of dst, and -3 that src is a multiple public
+ * base type but never a virtual base type
+ */
+extern "C" void* __dynamic_cast(const void *sub,
+ const __class_type_info *src,
+ const __class_type_info *dst,
+ ptrdiff_t src2dst_offset)
+{
+ char *vtable_location = *(char**)sub;
+ const vtable_header *header =
+ (const vtable_header*)(vtable_location - sizeof(vtable_header));
+ void *leaf = ADD_TO_PTR((void*)sub, header->leaf_offset);
+ return header->type->cast_to(leaf, dst);
+}
diff --git a/contrib/libcxxrt/exception.cc b/contrib/libcxxrt/exception.cc
new file mode 100644
index 0000000..2da7454
--- /dev/null
+++ b/contrib/libcxxrt/exception.cc
@@ -0,0 +1,1483 @@
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <pthread.h>
+#include "typeinfo.h"
+#include "dwarf_eh.h"
+#include "cxxabi.h"
+
+#pragma weak pthread_key_create
+#pragma weak pthread_setspecific
+#pragma weak pthread_getspecific
+#pragma weak pthread_once
+#pragma weak pthread_once
+#pragma weak pthread_cond_signal
+#pragma weak pthread_cond_wait
+#pragma weak pthread_mutex_lock
+#pragma weak pthread_mutex_unlock
+
+
+using namespace ABI_NAMESPACE;
+
+/**
+ * Saves the result of the landing pad that we have found. For ARM, this is
+ * stored in the generic unwind structure, while on other platforms it is
+ * stored in the C++ exception.
+ */
+static void saveLandingPad(struct _Unwind_Context *context,
+ struct _Unwind_Exception *ucb,
+ struct __cxa_exception *ex,
+ int selector,
+ dw_eh_ptr_t landingPad)
+{
+#ifdef __arm__
+ // On ARM, we store the saved exception in the generic part of the structure
+ ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
+ ucb->barrier_cache.bitpattern[1] = (uint32_t)selector;
+ ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad;
+#endif
+ // Cache the results for the phase 2 unwind, if we found a handler
+ // and this is not a foreign exception.
+ if (ex)
+ {
+ ex->handlerSwitchValue = selector;
+ ex->catchTemp = landingPad;
+ }
+}
+
+/**
+ * Loads the saved landing pad. Returns 1 on success, 0 on failure.
+ */
+static int loadLandingPad(struct _Unwind_Context *context,
+ struct _Unwind_Exception *ucb,
+ struct __cxa_exception *ex,
+ unsigned long *selector,
+ dw_eh_ptr_t *landingPad)
+{
+#ifdef __arm__
+ *selector = ucb->barrier_cache.bitpattern[1];
+ *landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3];
+ return 1;
+#else
+ if (ex)
+ {
+ *selector = ex->handlerSwitchValue;
+ *landingPad = (dw_eh_ptr_t)ex->catchTemp;
+ return 0;
+ }
+ return 0;
+#endif
+}
+
+static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
+ struct _Unwind_Context *context)
+{
+#ifdef __arm__
+ if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
+#endif
+ return _URC_CONTINUE_UNWIND;
+}
+
+
+extern "C" void __cxa_free_exception(void *thrown_exception);
+extern "C" void __cxa_free_dependent_exception(void *thrown_exception);
+extern "C" void* __dynamic_cast(const void *sub,
+ const __class_type_info *src,
+ const __class_type_info *dst,
+ ptrdiff_t src2dst_offset);
+
+/**
+ * The type of a handler that has been found.
+ */
+typedef enum
+{
+ /** No handler. */
+ handler_none,
+ /**
+ * A cleanup - the exception will propagate through this frame, but code
+ * must be run when this happens.
+ */
+ handler_cleanup,
+ /**
+ * A catch statement. The exception will not propagate past this frame
+ * (without an explicit rethrow).
+ */
+ handler_catch
+} handler_type;
+
+/**
+ * Per-thread info required by the runtime. We store a single structure
+ * pointer in thread-local storage, because this tends to be a scarce resource
+ * and it's impolite to steal all of it and not leave any for the rest of the
+ * program.
+ *
+ * Instances of this structure are allocated lazily - at most one per thread -
+ * and are destroyed on thread termination.
+ */
+struct __cxa_thread_info
+{
+ /** The termination handler for this thread. */
+ terminate_handler terminateHandler;
+ /** The unexpected exception handler for this thread. */
+ unexpected_handler unexpectedHandler;
+ /**
+ * The number of emergency buffers held by this thread. This is 0 in
+ * normal operation - the emergency buffers are only used when malloc()
+ * fails to return memory for allocating an exception. Threads are not
+ * permitted to hold more than 4 emergency buffers (as per recommendation
+ * in ABI spec [3.3.1]).
+ */
+ int emergencyBuffersHeld;
+ /**
+ * The exception currently running in a cleanup.
+ */
+ _Unwind_Exception *currentCleanup;
+ /**
+ * The public part of this structure, accessible from outside of this
+ * module.
+ */
+ __cxa_eh_globals globals;
+};
+/**
+ * Dependent exception. This
+ */
+struct __cxa_dependent_exception
+{
+#if __LP64__
+ void *primaryException;
+#endif
+ std::type_info *exceptionType;
+ void (*exceptionDestructor) (void *);
+ unexpected_handler unexpectedHandler;
+ terminate_handler terminateHandler;
+ __cxa_exception *nextException;
+ int handlerCount;
+#ifdef __arm__
+ _Unwind_Exception *nextCleanup;
+ int cleanupCount;
+#endif
+ int handlerSwitchValue;
+ const char *actionRecord;
+ const char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+#if !__LP64__
+ void *primaryException;
+#endif
+ _Unwind_Exception unwindHeader;
+};
+
+
+namespace std
+{
+ void unexpected();
+ class exception
+ {
+ public:
+ virtual ~exception() throw();
+ virtual const char* what() const throw();
+ };
+
+}
+
+extern "C" std::type_info *__cxa_current_exception_type();
+
+/**
+ * Class of exceptions to distinguish between this and other exception types.
+ *
+ * The first four characters are the vendor ID. Currently, we use GNUC,
+ * because we aim for ABI-compatibility with the GNU implementation, and
+ * various checks may test for equality of the class, which is incorrect.
+ */
+static const uint64_t exception_class =
+ EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\0');
+/**
+ * Class used for dependent exceptions.
+ */
+static const uint64_t dependent_exception_class =
+ EXCEPTION_CLASS('G', 'N', 'U', 'C', 'C', '+', '+', '\x01');
+/**
+ * The low four bytes of the exception class, indicating that we conform to the
+ * Itanium C++ ABI. This is currently unused, but should be used in the future
+ * if we change our exception class, to allow this library and libsupc++ to be
+ * linked to the same executable and both to interoperate.
+ */
+static const uint32_t abi_exception_class =
+ GENERIC_EXCEPTION_CLASS('C', '+', '+', '\0');
+
+static bool isCXXException(uint64_t cls)
+{
+ return (cls == exception_class) || (cls == dependent_exception_class);
+}
+
+static bool isDependentException(uint64_t cls)
+{
+ return cls == dependent_exception_class;
+}
+
+static __cxa_exception *exceptionFromPointer(void *ex)
+{
+ return (__cxa_exception*)((char*)ex -
+ offsetof(struct __cxa_exception, unwindHeader));
+}
+static __cxa_exception *realExceptionFromException(__cxa_exception *ex)
+{
+ if (!isDependentException(ex->unwindHeader.exception_class)) { return ex; }
+ return ((__cxa_exception*)(((__cxa_dependent_exception*)ex)->primaryException))-1;
+}
+
+
+namespace std
+{
+ // Forward declaration of standard library terminate() function used to
+ // abort execution.
+ void terminate(void);
+}
+
+using namespace ABI_NAMESPACE;
+
+
+
+/** The global termination handler. */
+static terminate_handler terminateHandler = abort;
+/** The global unexpected exception handler. */
+static unexpected_handler unexpectedHandler = std::terminate;
+
+/** Key used for thread-local data. */
+static pthread_key_t eh_key;
+
+
+/**
+ * Cleanup function, allowing foreign exception handlers to correctly destroy
+ * this exception if they catch it.
+ */
+static void exception_cleanup(_Unwind_Reason_Code reason,
+ struct _Unwind_Exception *ex)
+{
+ __cxa_free_exception((void*)ex);
+}
+static void dependent_exception_cleanup(_Unwind_Reason_Code reason,
+ struct _Unwind_Exception *ex)
+{
+
+ __cxa_free_dependent_exception((void*)ex);
+}
+
+/**
+ * Recursively walk a list of exceptions and delete them all in post-order.
+ */
+static void free_exception_list(__cxa_exception *ex)
+{
+ if (0 != ex->nextException)
+ {
+ free_exception_list(ex->nextException);
+ }
+ // __cxa_free_exception() expects to be passed the thrown object, which
+ // immediately follows the exception, not the exception itself
+ __cxa_free_exception(ex+1);
+}
+
+/**
+ * Cleanup function called when a thread exists to make certain that all of the
+ * per-thread data is deleted.
+ */
+static void thread_cleanup(void* thread_info)
+{
+ __cxa_thread_info *info = (__cxa_thread_info*)thread_info;
+ if (info->globals.caughtExceptions)
+ {
+ free_exception_list(info->globals.caughtExceptions);
+ }
+ free(thread_info);
+}
+
+
+/**
+ * Once control used to protect the key creation.
+ */
+static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
+/**
+ * We may not be linked against a full pthread implementation. If we're not,
+ * then we need to fake the thread-local storage by storing 'thread-local'
+ * things in a global.
+ */
+static bool fakeTLS;
+/**
+ * Thread-local storage for a single-threaded program.
+ */
+static __cxa_thread_info singleThreadInfo;
+/**
+ * Initialise eh_key.
+ */
+static void init_key(void)
+{
+ if ((0 == pthread_key_create) ||
+ (0 == pthread_setspecific) ||
+ (0 == pthread_getspecific))
+ {
+ fakeTLS = true;
+ return;
+ }
+ pthread_key_create(&eh_key, thread_cleanup);
+ pthread_setspecific(eh_key, (void*)0x42);
+ fakeTLS = (pthread_getspecific(eh_key) != (void*)0x42);
+ pthread_setspecific(eh_key, 0);
+}
+
+/**
+ * Returns the thread info structure, creating it if it is not already created.
+ */
+static __cxa_thread_info *thread_info()
+{
+ if ((0 == pthread_once) || pthread_once(&once_control, init_key))
+ {
+ fakeTLS = true;
+ }
+ if (fakeTLS) { return &singleThreadInfo; }
+ __cxa_thread_info *info = (__cxa_thread_info*)pthread_getspecific(eh_key);
+ if (0 == info)
+ {
+ info = (__cxa_thread_info*)calloc(1, sizeof(__cxa_thread_info));
+ pthread_setspecific(eh_key, info);
+ }
+ return info;
+}
+/**
+ * Fast version of thread_info(). May fail if thread_info() is not called on
+ * this thread at least once already.
+ */
+static __cxa_thread_info *thread_info_fast()
+{
+ if (fakeTLS) { return &singleThreadInfo; }
+ return (__cxa_thread_info*)pthread_getspecific(eh_key);
+}
+/**
+ * ABI function returning the __cxa_eh_globals structure.
+ */
+extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void)
+{
+ return &(thread_info()->globals);
+}
+/**
+ * Version of __cxa_get_globals() assuming that __cxa_get_globals() has already
+ * been called at least once by this thread.
+ */
+extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals_fast(void)
+{
+ return &(thread_info_fast()->globals);
+}
+
+/**
+ * An emergency allocation reserved for when malloc fails. This is treated as
+ * 16 buffers of 1KB each.
+ */
+static char emergency_buffer[16384];
+/**
+ * Flag indicating whether each buffer is allocated.
+ */
+static bool buffer_allocated[16];
+/**
+ * Lock used to protect emergency allocation.
+ */
+static pthread_mutex_t emergency_malloc_lock = PTHREAD_MUTEX_INITIALIZER;
+/**
+ * Condition variable used to wait when two threads are both trying to use the
+ * emergency malloc() buffer at once.
+ */
+static pthread_cond_t emergency_malloc_wait = PTHREAD_COND_INITIALIZER;
+
+/**
+ * Allocates size bytes from the emergency allocation mechanism, if possible.
+ * This function will fail if size is over 1KB or if this thread already has 4
+ * emergency buffers. If all emergency buffers are allocated, it will sleep
+ * until one becomes available.
+ */
+static char *emergency_malloc(size_t size)
+{
+ if (size > 1024) { return 0; }
+
+ __cxa_thread_info *info = thread_info();
+ // Only 4 emergency buffers allowed per thread!
+ if (info->emergencyBuffersHeld > 3) { return 0; }
+
+ if (pthread_mutex_lock)
+ {
+ pthread_mutex_lock(&emergency_malloc_lock);
+ }
+ int buffer = -1;
+ while (buffer < 0)
+ {
+ // While we were sleeping on the lock, another thread might have free'd
+ // enough memory for us to use, so try the allocation again - no point
+ // using the emergency buffer if there is some real memory that we can
+ // use...
+ void *m = calloc(1, size);
+ if (0 != m)
+ {
+ if (pthread_mutex_unlock)
+ {
+ pthread_mutex_unlock(&emergency_malloc_lock);
+ }
+ return (char*)m;
+ }
+ for (int i=0 ; i<16 ; i++)
+ {
+ if (!buffer_allocated[i])
+ {
+ buffer = i;
+ buffer_allocated[i] = true;
+ break;
+ }
+ }
+ // If there still isn't a buffer available, then sleep on the condition
+ // variable. This will be signalled when another thread releases one
+ // of the emergency buffers.
+ if (buffer < 0)
+ {
+ // If we don't have pthread_cond_wait, then there is only one
+ // thread and it's already used all of the emergency buffers, so we
+ // have no alternative but to die. Calling abort() instead of
+ // terminate, because terminate can throw exceptions, which can
+ // bring us back here and infinite loop.
+ if (!pthread_cond_wait)
+ {
+ fputs("Terminating while out of memory trying to throw an exception",
+ stderr);
+ abort();
+ }
+ pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock);
+ }
+ }
+ if (pthread_mutex_unlock)
+ {
+ pthread_mutex_unlock(&emergency_malloc_lock);
+ }
+ info->emergencyBuffersHeld++;
+ return emergency_buffer + (1024 * buffer);
+}
+
+/**
+ * Frees a buffer returned by emergency_malloc().
+ *
+ * Note: Neither this nor emergency_malloc() is particularly efficient. This
+ * should not matter, because neither will be called in normal operation - they
+ * are only used when the program runs out of memory, which should not happen
+ * often.
+ */
+static void emergency_malloc_free(char *ptr)
+{
+ int buffer = -1;
+ // Find the buffer corresponding to this pointer.
+ for (int i=0 ; i<16 ; i++)
+ {
+ if (ptr == (void*)(emergency_buffer + (1024 * i)))
+ {
+ buffer = i;
+ break;
+ }
+ }
+ assert(buffer > 0 &&
+ "Trying to free something that is not an emergency buffer!");
+ // emergency_malloc() is expected to return 0-initialized data. We don't
+ // zero the buffer when allocating it, because the static buffers will
+ // begin life containing 0 values.
+ memset((void*)ptr, 0, 1024);
+ // Signal the condition variable to wake up any threads that are blocking
+ // waiting for some space in the emergency buffer
+ if (pthread_mutex_lock)
+ {
+ pthread_mutex_lock(&emergency_malloc_lock);
+ }
+ // In theory, we don't need to do this with the lock held. In practice,
+ // our array of bools will probably be updated using 32-bit or 64-bit
+ // memory operations, so this update may clobber adjacent values.
+ buffer_allocated[buffer] = false;
+ if (pthread_cond_signal && pthread_mutex_unlock)
+ {
+ pthread_cond_signal(&emergency_malloc_wait);
+ pthread_mutex_unlock(&emergency_malloc_lock);
+ }
+}
+
+static char *alloc_or_die(size_t size)
+{
+ char *buffer = (char*)calloc(1, size);
+
+ // If calloc() doesn't want to give us any memory, try using an emergency
+ // buffer.
+ if (0 == buffer)
+ {
+ buffer = emergency_malloc(size);
+ // This is only reached if the allocation is greater than 1KB, and
+ // anyone throwing objects that big really should know better.
+ if (0 == buffer)
+ {
+ fprintf(stderr, "Out of memory attempting to allocate exception\n");
+ std::terminate();
+ }
+ }
+ return buffer;
+}
+static void free_exception(char *e)
+{
+ // If this allocation is within the address range of the emergency buffer,
+ // don't call free() because it was not allocated with malloc()
+ if ((e > emergency_buffer) &&
+ (e < (emergency_buffer + sizeof(emergency_buffer))))
+ {
+ emergency_malloc_free(e);
+ }
+ else
+ {
+ free(e);
+ }
+}
+
+/**
+ * Allocates an exception structure. Returns a pointer to the space that can
+ * be used to store an object of thrown_size bytes. This function will use an
+ * emergency buffer if malloc() fails, and may block if there are no such
+ * buffers available.
+ */
+extern "C" void *__cxa_allocate_exception(size_t thrown_size)
+{
+ size_t size = thrown_size + sizeof(__cxa_exception);
+ char *buffer = alloc_or_die(size);
+ return buffer+sizeof(__cxa_exception);
+}
+
+extern "C" void *__cxa_allocate_dependent_exception(void)
+{
+ size_t size = sizeof(__cxa_dependent_exception);
+ char *buffer = alloc_or_die(size);
+ return buffer+sizeof(__cxa_dependent_exception);
+}
+
+/**
+ * __cxa_free_exception() is called when an exception was thrown in between
+ * calling __cxa_allocate_exception() and actually throwing the exception.
+ * This happens when the object's copy constructor throws an exception.
+ *
+ * In this implementation, it is also called by __cxa_end_catch() and during
+ * thread cleanup.
+ */
+extern "C" void __cxa_free_exception(void *thrown_exception)
+{
+ __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1;
+ // Free the object that was thrown, calling its destructor
+ if (0 != ex->exceptionDestructor)
+ {
+ try
+ {
+ ex->exceptionDestructor(thrown_exception);
+ }
+ catch(...)
+ {
+ // FIXME: Check that this is really what the spec says to do.
+ std::terminate();
+ }
+ }
+
+ free_exception((char*)ex);
+}
+
+static void releaseException(__cxa_exception *exception)
+{
+ if (isDependentException(exception->unwindHeader.exception_class))
+ {
+ __cxa_free_dependent_exception(exception+1);
+ return;
+ }
+ if (__sync_sub_and_fetch(&exception->referenceCount, 1) == 0)
+ {
+ // __cxa_free_exception() expects to be passed the thrown object,
+ // which immediately follows the exception, not the exception
+ // itself
+ __cxa_free_exception(exception+1);
+ }
+}
+
+void __cxa_free_dependent_exception(void *thrown_exception)
+{
+ __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)thrown_exception) - 1;
+ assert(isDependentException(ex->unwindHeader.exception_class));
+ if (ex->primaryException)
+ {
+ releaseException(realExceptionFromException((__cxa_exception*)ex));
+ }
+ free_exception((char*)ex);
+}
+
+/**
+ * Callback function used with _Unwind_Backtrace().
+ *
+ * Prints a stack trace. Used only for debugging help.
+ *
+ * Note: As of FreeBSD 8.1, dladd() still doesn't work properly, so this only
+ * correctly prints function names from public, relocatable, symbols.
+ */
+static _Unwind_Reason_Code trace(struct _Unwind_Context *context, void *c)
+{
+ Dl_info myinfo;
+ int mylookup =
+ dladdr((void*)(uintptr_t)__cxa_current_exception_type, &myinfo);
+ void *ip = (void*)_Unwind_GetIP(context);
+ Dl_info info;
+ if (dladdr(ip, &info) != 0)
+ {
+ if (mylookup == 0 || strcmp(info.dli_fname, myinfo.dli_fname) != 0)
+ {
+ printf("%p:%s() in %s\n", ip, info.dli_sname, info.dli_fname);
+ }
+ }
+ return _URC_CONTINUE_UNWIND;
+}
+
+/**
+ * Report a failure that occurred when attempting to throw an exception.
+ *
+ * If the failure happened by falling off the end of the stack without finding
+ * a handler, prints a back trace before aborting.
+ */
+static void report_failure(_Unwind_Reason_Code err, __cxa_exception *thrown_exception)
+{
+ switch (err)
+ {
+ default: break;
+ case _URC_FATAL_PHASE1_ERROR:
+ fprintf(stderr, "Fatal error during phase 1 unwinding\n");
+ break;
+#ifndef __arm__
+ case _URC_FATAL_PHASE2_ERROR:
+ fprintf(stderr, "Fatal error during phase 2 unwinding\n");
+ break;
+#endif
+ case _URC_END_OF_STACK:
+ fprintf(stderr, "Terminating due to uncaught exception %p",
+ (void*)thrown_exception);
+ thrown_exception = realExceptionFromException(thrown_exception);
+ static const __class_type_info *e_ti =
+ static_cast<const __class_type_info*>(&typeid(std::exception));
+ const __class_type_info *throw_ti =
+ dynamic_cast<const __class_type_info*>(thrown_exception->exceptionType);
+ if (throw_ti)
+ {
+ std::exception *e =
+ (std::exception*)e_ti->cast_to((void*)(thrown_exception+1),
+ throw_ti);
+ if (e)
+ {
+ fprintf(stderr, " '%s'", e->what());
+ }
+ }
+
+ size_t bufferSize = 128;
+ char *demangled = (char*)malloc(bufferSize);
+ const char *mangled = thrown_exception->exceptionType->name();
+ int status;
+ demangled = __cxa_demangle(mangled, demangled, &bufferSize, &status);
+ fprintf(stderr, " of type %s\n",
+ status == 0 ? (const char*)demangled : mangled);
+ if (status == 0) { free(demangled); }
+ // Print a back trace if no handler is found.
+ // TODO: Make this optional
+ _Unwind_Backtrace(trace, 0);
+ break;
+ }
+ std::terminate();
+}
+
+static void throw_exception(__cxa_exception *ex)
+{
+ __cxa_thread_info *info = thread_info();
+ ex->unexpectedHandler = info->unexpectedHandler;
+ if (0 == ex->unexpectedHandler)
+ {
+ ex->unexpectedHandler = unexpectedHandler;
+ }
+ ex->terminateHandler = info->terminateHandler;
+ if (0 == ex->terminateHandler)
+ {
+ ex->terminateHandler = terminateHandler;
+ }
+ info->globals.uncaughtExceptions++;
+
+ _Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
+ // The _Unwind_RaiseException() function should not return, it should
+ // unwind the stack past this function. If it does return, then something
+ // has gone wrong.
+ report_failure(err, ex);
+}
+
+
+/**
+ * ABI function for throwing an exception. Takes the object to be thrown (the
+ * pointer returned by __cxa_allocate_exception()), the type info for the
+ * pointee, and the destructor (if there is one) as arguments.
+ */
+extern "C" void __cxa_throw(void *thrown_exception,
+ std::type_info *tinfo,
+ void(*dest)(void*))
+{
+ __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1;
+
+ ex->referenceCount = 1;
+ ex->exceptionType = tinfo;
+
+ ex->exceptionDestructor = dest;
+
+ ex->unwindHeader.exception_class = exception_class;
+ ex->unwindHeader.exception_cleanup = exception_cleanup;
+
+ throw_exception(ex);
+}
+
+extern "C" void __cxa_rethrow_primary_exception(void* thrown_exception)
+{
+ if (NULL == thrown_exception) { return; }
+
+ __cxa_exception *original = exceptionFromPointer(thrown_exception);
+ __cxa_dependent_exception *ex = ((__cxa_dependent_exception*)__cxa_allocate_dependent_exception())-1;
+
+ ex->primaryException = thrown_exception;
+ __cxa_increment_exception_refcount(thrown_exception);
+
+ ex->exceptionType = original->exceptionType;
+ ex->unwindHeader.exception_class = dependent_exception_class;
+ ex->unwindHeader.exception_cleanup = dependent_exception_cleanup;
+
+ throw_exception((__cxa_exception*)ex);
+}
+
+extern "C" void *__cxa_current_primary_exception(void)
+{
+ __cxa_eh_globals* globals = __cxa_get_globals();
+ __cxa_exception *ex = globals->caughtExceptions;
+
+ if (0 == ex) { return NULL; }
+ ex = realExceptionFromException(ex);
+ __sync_fetch_and_add(&ex->referenceCount, 1);
+ return ex + 1;
+}
+
+extern "C" void __cxa_increment_exception_refcount(void* thrown_exception)
+{
+ if (NULL == thrown_exception) { return; }
+ __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1;
+ if (isDependentException(ex->unwindHeader.exception_class)) { return; }
+ __sync_fetch_and_add(&ex->referenceCount, 1);
+}
+extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
+{
+ if (NULL == thrown_exception) { return; }
+ __cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1;
+ releaseException(ex);
+}
+
+/**
+ * ABI function. Rethrows the current exception. Does not remove the
+ * exception from the stack or decrement its handler count - the compiler is
+ * expected to set the landing pad for this function to the end of the catch
+ * block, and then call _Unwind_Resume() to continue unwinding once
+ * __cxa_end_catch() has been called and any cleanup code has been run.
+ */
+extern "C" void __cxa_rethrow()
+{
+ __cxa_eh_globals *globals = __cxa_get_globals();
+ // Note: We don't remove this from the caught list here, because
+ // __cxa_end_catch will be called when we unwind out of the try block. We
+ // could probably make this faster by providing an alternative rethrow
+ // function and ensuring that all cleanup code is run before calling it, so
+ // we can skip the top stack frame when unwinding.
+ __cxa_exception *ex = globals->caughtExceptions;
+
+ if (0 == ex)
+ {
+ fprintf(stderr,
+ "Attempting to rethrow an exception that doesn't exist!\n");
+ std::terminate();
+ }
+
+ assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
+
+ // ex->handlerCount will be decremented in __cxa_end_catch in enclosing
+ // catch block
+
+ // Make handler count negative. This will tell __cxa_end_catch that
+ // exception was rethrown and exception object should not be destroyed
+ // when handler count become zero
+ ex->handlerCount = -ex->handlerCount;
+
+ // Continue unwinding the stack with this exception. This should unwind to
+ // the place in the caller where __cxa_end_catch() is called. The caller
+ // will then run cleanup code and bounce the exception back with
+ // _Unwind_Resume().
+ _Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(&ex->unwindHeader);
+ report_failure(err, ex);
+}
+
+/**
+ * Returns the type_info object corresponding to the filter.
+ */
+static std::type_info *get_type_info_entry(_Unwind_Context *context,
+ dwarf_eh_lsda *lsda,
+ int filter)
+{
+ // Get the address of the record in the table.
+ dw_eh_ptr_t record = lsda->type_table -
+ dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter;
+ //record -= 4;
+ dw_eh_ptr_t start = record;
+ // Read the value, but it's probably an indirect reference...
+ int64_t offset = read_value(lsda->type_table_encoding, &record);
+
+ // (If the entry is 0, don't try to dereference it. That would be bad.)
+ if (offset == 0) { return 0; }
+
+ // ...so we need to resolve it
+ return (std::type_info*)resolve_indirect_value(context,
+ lsda->type_table_encoding, offset, start);
+}
+
+
+
+/**
+ * Checks the type signature found in a handler against the type of the thrown
+ * object. If ex is 0 then it is assumed to be a foreign exception and only
+ * matches cleanups.
+ */
+static bool check_type_signature(__cxa_exception *ex,
+ const std::type_info *type,
+ void *&adjustedPtr)
+{
+ // TODO: For compatibility with the GNU implementation, we should move this
+ // out into a __do_catch() virtual function in std::type_info
+ void *exception_ptr = (void*)(ex+1);
+ const std::type_info *ex_type = ex->exceptionType;
+
+ const __pointer_type_info *ptr_type =
+ dynamic_cast<const __pointer_type_info*>(ex_type);
+ if (0 != ptr_type)
+ {
+ exception_ptr = *(void**)exception_ptr;
+ }
+ // Always match a catchall, even with a foreign exception
+ //
+ // Note: A 0 here is a catchall, not a cleanup, so we return true to
+ // indicate that we found a catch.
+ //
+ // TODO: Provide a class for matching against foreign exceptions. This is
+ // already done in libobjc2, allowing C++ exceptions to be boxed as
+ // Objective-C objects. We should do something similar, allowing foreign
+ // exceptions to be wrapped in a C++ exception and delivered.
+ if (0 == type)
+ {
+ if (ex)
+ {
+ adjustedPtr = exception_ptr;
+ }
+ return true;
+ }
+
+ if (0 == ex) { return false; }
+
+ const __pointer_type_info *target_ptr_type =
+ dynamic_cast<const __pointer_type_info*>(type);
+
+ if (0 != ptr_type && 0 != target_ptr_type)
+ {
+ if (ptr_type->__flags & ~target_ptr_type->__flags)
+ {
+ // Handler pointer is less qualified
+ return false;
+ }
+
+ // Special case for void* handler.
+ if(*target_ptr_type->__pointee == typeid(void))
+ {
+ adjustedPtr = exception_ptr;
+ return true;
+ }
+
+ ex_type = ptr_type->__pointee;
+ type = target_ptr_type->__pointee;
+ }
+
+ // If the types are the same, no casting is needed.
+ if (*type == *ex_type)
+ {
+ adjustedPtr = exception_ptr;
+ return true;
+ }
+
+ const __class_type_info *cls_type =
+ dynamic_cast<const __class_type_info*>(ex_type);
+ const __class_type_info *target_cls_type =
+ dynamic_cast<const __class_type_info*>(type);
+
+ if (0 != cls_type &&
+ 0 != target_cls_type &&
+ cls_type->can_cast_to(target_cls_type))
+ {
+ adjustedPtr = cls_type->cast_to(exception_ptr, target_cls_type);
+ return true;
+ }
+ return false;
+}
+/**
+ * Checks whether the exception matches the type specifiers in this action
+ * record. If the exception only matches cleanups, then this returns false.
+ * If it matches a catch (including a catchall) then it returns true.
+ *
+ * The selector argument is used to return the selector that is passed in the
+ * second exception register when installing the context.
+ */
+static handler_type check_action_record(_Unwind_Context *context,
+ dwarf_eh_lsda *lsda,
+ dw_eh_ptr_t action_record,
+ __cxa_exception *ex,
+ unsigned long *selector,
+ void *&adjustedPtr)
+{
+ if (!action_record) { return handler_cleanup; }
+ handler_type found = handler_none;
+ while (action_record)
+ {
+ int filter = read_sleb128(&action_record);
+ dw_eh_ptr_t action_record_offset_base = action_record;
+ int displacement = read_sleb128(&action_record);
+ action_record = displacement ?
+ action_record_offset_base + displacement : 0;
+ // We only check handler types for C++ exceptions - foreign exceptions
+ // are only allowed for cleanup.
+ if (filter > 0 && 0 != ex)
+ {
+ std::type_info *handler_type = get_type_info_entry(context, lsda, filter);
+ if (check_type_signature(ex, handler_type, adjustedPtr))
+ {
+ *selector = filter;
+ return handler_catch;
+ }
+ }
+ else if (filter < 0 && 0 != ex)
+ {
+ bool matched = false;
+ *selector = filter;
+#ifdef __arm__
+ filter++;
+ std::type_info *handler_type = get_type_info_entry(context, lsda, filter--);
+ while (handler_type)
+ {
+ if (check_type_signature(ex, handler_type, adjustedPtr))
+ {
+ matched = true;
+ break;
+ }
+ handler_type = get_type_info_entry(context, lsda, filter--);
+ }
+#else
+ unsigned char *type_index = ((unsigned char*)lsda->type_table - filter - 1);
+ while (*type_index)
+ {
+ std::type_info *handler_type = get_type_info_entry(context, lsda, *(type_index++));
+ // If the exception spec matches a permitted throw type for
+ // this function, don't report a handler - we are allowed to
+ // propagate this exception out.
+ if (check_type_signature(ex, handler_type, adjustedPtr))
+ {
+ matched = true;
+ break;
+ }
+ }
+#endif
+ if (matched) { continue; }
+ // If we don't find an allowed exception spec, we need to install
+ // the context for this action. The landing pad will then call the
+ // unexpected exception function. Treat this as a catch
+ return handler_catch;
+ }
+ else if (filter == 0)
+ {
+ *selector = filter;
+ found = handler_cleanup;
+ }
+ }
+ return found;
+}
+
+static void pushCleanupException(_Unwind_Exception *exceptionObject,
+ __cxa_exception *ex)
+{
+#ifdef __arm__
+ __cxa_thread_info *info = thread_info_fast();
+ if (ex)
+ {
+ ex->cleanupCount++;
+ if (ex->cleanupCount > 1)
+ {
+ assert(exceptionObject == info->currentCleanup);
+ return;
+ }
+ ex->nextCleanup = info->currentCleanup;
+ }
+ info->currentCleanup = exceptionObject;
+#endif
+}
+
+/**
+ * The exception personality function. This is referenced in the unwinding
+ * DWARF metadata and is called by the unwind library for each C++ stack frame
+ * containing catch or cleanup code.
+ */
+extern "C"
+BEGIN_PERSONALITY_FUNCTION(__gxx_personality_v0)
+ // This personality function is for version 1 of the ABI. If you use it
+ // with a future version of the ABI, it won't know what to do, so it
+ // reports a fatal error and give up before it breaks anything.
+ if (1 != version)
+ {
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ __cxa_exception *ex = 0;
+ __cxa_exception *realEx = 0;
+
+ // If this exception is throw by something else then we can't make any
+ // assumptions about its layout beyond the fields declared in
+ // _Unwind_Exception.
+ bool foreignException = !isCXXException(exceptionClass);
+
+ // If this isn't a foreign exception, then we have a C++ exception structure
+ if (!foreignException)
+ {
+ ex = exceptionFromPointer(exceptionObject);
+ realEx = realExceptionFromException(ex);
+ }
+
+ unsigned char *lsda_addr =
+ (unsigned char*)_Unwind_GetLanguageSpecificData(context);
+
+ // No LSDA implies no landing pads - try the next frame
+ if (0 == lsda_addr) { return continueUnwinding(exceptionObject, context); }
+
+ // These two variables define how the exception will be handled.
+ dwarf_eh_action action = {0};
+ unsigned long selector = 0;
+
+ // During the search phase, we do a complete lookup. If we return
+ // _URC_HANDLER_FOUND, then the phase 2 unwind will call this function with
+ // a _UA_HANDLER_FRAME action, telling us to install the handler frame. If
+ // we return _URC_CONTINUE_UNWIND, we may be called again later with a
+ // _UA_CLEANUP_PHASE action for this frame.
+ //
+ // The point of the two-stage unwind allows us to entirely avoid any stack
+ // unwinding if there is no handler. If there are just cleanups found,
+ // then we can just panic call an abort function.
+ //
+ // Matching a handler is much more expensive than matching a cleanup,
+ // because we don't need to bother doing type comparisons (or looking at
+ // the type table at all) for a cleanup. This means that there is no need
+ // to cache the result of finding a cleanup, because it's (quite) quick to
+ // look it up again from the action table.
+ if (actions & _UA_SEARCH_PHASE)
+ {
+ struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+
+ if (!dwarf_eh_find_callsite(context, &lsda, &action))
+ {
+ // EH range not found. This happens if exception is thrown and not
+ // caught inside a cleanup (destructor). We should call
+ // terminate() in this case. The catchTemp (landing pad) field of
+ // exception object will contain null when personality function is
+ // called with _UA_HANDLER_FRAME action for phase 2 unwinding.
+ return _URC_HANDLER_FOUND;
+ }
+
+ handler_type found_handler = check_action_record(context, &lsda,
+ action.action_record, realEx, &selector, ex->adjustedPtr);
+ // If there's no action record, we've only found a cleanup, so keep
+ // searching for something real
+ if (found_handler == handler_catch)
+ {
+ // Cache the results for the phase 2 unwind, if we found a handler
+ // and this is not a foreign exception.
+ if (ex)
+ {
+ saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
+ ex->languageSpecificData = (const char*)lsda_addr;
+ ex->actionRecord = (const char*)action.action_record;
+ // ex->adjustedPtr is set when finding the action record.
+ }
+ return _URC_HANDLER_FOUND;
+ }
+ return continueUnwinding(exceptionObject, context);
+ }
+
+
+ // If this is a foreign exception, we didn't have anywhere to cache the
+ // lookup stuff, so we need to do it again. If this is either a forced
+ // unwind, a foreign exception, or a cleanup, then we just install the
+ // context for a cleanup.
+ if (!(actions & _UA_HANDLER_FRAME))
+ {
+ // cleanup
+ struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+ dwarf_eh_find_callsite(context, &lsda, &action);
+ if (0 == action.landing_pad) { return continueUnwinding(exceptionObject, context); }
+ handler_type found_handler = check_action_record(context, &lsda,
+ action.action_record, realEx, &selector, ex->adjustedPtr);
+ // Ignore handlers this time.
+ if (found_handler != handler_cleanup) { return continueUnwinding(exceptionObject, context); }
+ pushCleanupException(exceptionObject, ex);
+ }
+ else if (foreignException)
+ {
+ struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+ dwarf_eh_find_callsite(context, &lsda, &action);
+ check_action_record(context, &lsda, action.action_record, realEx,
+ &selector, ex->adjustedPtr);
+ }
+ else if (ex->catchTemp == 0)
+ {
+ // Uncaught exception in cleanup, calling terminate
+ std::terminate();
+ }
+ else
+ {
+ // Restore the saved info if we saved some last time.
+ loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
+ ex->catchTemp = 0;
+ ex->handlerSwitchValue = 0;
+ }
+
+
+ _Unwind_SetIP(context, (unsigned long)action.landing_pad);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
+ (unsigned long)exceptionObject);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
+
+ return _URC_INSTALL_CONTEXT;
+}
+
+/**
+ * ABI function called when entering a catch statement. The argument is the
+ * pointer passed out of the personality function. This is always the start of
+ * the _Unwind_Exception object. The return value for this function is the
+ * pointer to the caught exception, which is either the adjusted pointer (for
+ * C++ exceptions) of the unadjusted pointer (for foreign exceptions).
+ */
+#if __GNUC__ > 3 && __GNUC_MINOR__ > 2
+extern "C" void *__cxa_begin_catch(void *e) throw()
+#else
+extern "C" void *__cxa_begin_catch(void *e)
+#endif
+{
+ // Decrement the uncaught exceptions count
+ __cxa_eh_globals *globals = __cxa_get_globals();
+ globals->uncaughtExceptions--;
+ _Unwind_Exception *exceptionObject = (_Unwind_Exception*)e;
+
+ if (isCXXException(exceptionObject->exception_class))
+ {
+ __cxa_exception *ex = exceptionFromPointer(exceptionObject);
+
+ if (ex->handlerCount == 0)
+ {
+ // Add this to the front of the list of exceptions being handled
+ // and increment its handler count so that it won't be deleted
+ // prematurely.
+ ex->nextException = globals->caughtExceptions;
+ globals->caughtExceptions = ex;
+ }
+
+ if (ex->handlerCount < 0)
+ {
+ // Rethrown exception is catched before end of catch block.
+ // Clear the rethrow flag (make value positive) - we are allowed
+ // to delete this exception at the end of the catch block, as long
+ // as it isn't thrown again later.
+
+ // Code pattern:
+ //
+ // try {
+ // throw x;
+ // }
+ // catch() {
+ // try {
+ // throw;
+ // }
+ // catch() {
+ // __cxa_begin_catch() <- we are here
+ // }
+ // }
+ ex->handlerCount = -ex->handlerCount + 1;
+ }
+ else
+ {
+ ex->handlerCount++;
+ }
+
+ return ex->adjustedPtr;
+ }
+ // exceptionObject is the pointer to the _Unwind_Exception within the
+ // __cxa_exception. The throw object is after this
+ return ((char*)exceptionObject + sizeof(_Unwind_Exception));
+}
+
+
+
+/**
+ * ABI function called when exiting a catch block. This will free the current
+ * exception if it is no longer referenced in other catch blocks.
+ */
+extern "C" void __cxa_end_catch()
+{
+ // We can call the fast version here because the slow version is called in
+ // __cxa_throw(), which must have been called before we end a catch block
+ __cxa_eh_globals *globals = __cxa_get_globals_fast();
+ __cxa_exception *ex = globals->caughtExceptions;
+
+ assert(0 != ex && "Ending catch when no exception is on the stack!");
+
+ bool deleteException = true;
+
+ if (ex->handlerCount < 0)
+ {
+ // exception was rethrown. Exception should not be deleted even if
+ // handlerCount become zero.
+ // Code pattern:
+ // try {
+ // throw x;
+ // }
+ // catch() {
+ // {
+ // throw;
+ // }
+ // cleanup {
+ // __cxa_end_catch(); <- we are here
+ // }
+ // }
+ //
+
+ ex->handlerCount++;
+ deleteException = false;
+ }
+ else
+ {
+ ex->handlerCount--;
+ }
+
+ if (ex->handlerCount == 0)
+ {
+ globals->caughtExceptions = ex->nextException;
+ if (deleteException)
+ {
+ releaseException(ex);
+ }
+ }
+}
+
+/**
+ * ABI function. Returns the type of the current exception.
+ */
+extern "C" std::type_info *__cxa_current_exception_type()
+{
+ __cxa_eh_globals *globals = __cxa_get_globals();
+ __cxa_exception *ex = globals->caughtExceptions;
+ return ex ? ex->exceptionType : 0;
+}
+
+/**
+ * ABI function, called when an exception specification is violated.
+ *
+ * This function does not return.
+ */
+extern "C" void __cxa_call_unexpected(void*exception)
+{
+ _Unwind_Exception *exceptionObject = (_Unwind_Exception*)exception;
+ if (exceptionObject->exception_class == exception_class)
+ {
+ __cxa_exception *ex = exceptionFromPointer(exceptionObject);
+ if (ex->unexpectedHandler)
+ {
+ ex->unexpectedHandler();
+ // Should not be reached.
+ abort();
+ }
+ }
+ std::unexpected();
+ // Should not be reached.
+ abort();
+}
+
+/**
+ * ABI function, returns the adjusted pointer to the exception object.
+ */
+extern "C" void *__cxa_get_exception_ptr(void *exceptionObject)
+{
+ return exceptionFromPointer(exceptionObject)->adjustedPtr;
+}
+
+/**
+ * As an extension, we provide the ability for the unexpected and terminate
+ * handlers to be thread-local. We default to the standards-compliant
+ * behaviour where they are global.
+ */
+static bool thread_local_handlers = false;
+
+
+namespace pathscale
+{
+ /**
+ * Sets whether unexpected and terminate handlers should be thread-local.
+ */
+ void set_use_thread_local_handlers(bool flag) throw()
+ {
+ thread_local_handlers = flag;
+ }
+ /**
+ * Sets a thread-local unexpected handler.
+ */
+ unexpected_handler set_unexpected(unexpected_handler f) throw()
+ {
+ static __cxa_thread_info *info = thread_info();
+ unexpected_handler old = info->unexpectedHandler;
+ info->unexpectedHandler = f;
+ return old;
+ }
+ /**
+ * Sets a thread-local terminate handler.
+ */
+ terminate_handler set_terminate(terminate_handler f) throw()
+ {
+ static __cxa_thread_info *info = thread_info();
+ terminate_handler old = info->terminateHandler;
+ info->terminateHandler = f;
+ return old;
+ }
+}
+
+namespace std
+{
+ /**
+ * Sets the function that will be called when an exception specification is
+ * violated.
+ */
+ unexpected_handler set_unexpected(unexpected_handler f) throw()
+ {
+ if (thread_local_handlers) { return pathscale::set_unexpected(f); }
+
+ return __sync_lock_test_and_set(&unexpectedHandler, f);
+ }
+ /**
+ * Sets the function that is called to terminate the program.
+ */
+ terminate_handler set_terminate(terminate_handler f) throw()
+ {
+ if (thread_local_handlers) { return pathscale::set_terminate(f); }
+ return __sync_lock_test_and_set(&terminateHandler, f);
+ }
+ /**
+ * Terminates the program, calling a custom terminate implementation if
+ * required.
+ */
+ void terminate()
+ {
+ static __cxa_thread_info *info = thread_info_fast();
+ if (0 != info && 0 != info->terminateHandler)
+ {
+ info->terminateHandler();
+ // Should not be reached - a terminate handler is not expected to
+ // return.
+ abort();
+ }
+ terminateHandler();
+ }
+ /**
+ * Called when an unexpected exception is encountered (i.e. an exception
+ * violates an exception specification). This calls abort() unless a
+ * custom handler has been set..
+ */
+ void unexpected()
+ {
+ static __cxa_thread_info *info = thread_info_fast();
+ if (0 != info && 0 != info->unexpectedHandler)
+ {
+ info->unexpectedHandler();
+ // Should not be reached - a terminate handler is not expected to
+ // return.
+ abort();
+ }
+ unexpectedHandler();
+ }
+ /**
+ * Returns whether there are any exceptions currently being thrown that
+ * have not been caught. This can occur inside a nested catch statement.
+ */
+ bool uncaught_exception() throw()
+ {
+ __cxa_thread_info *info = thread_info();
+ return info->globals.uncaughtExceptions != 0;
+ }
+ /**
+ * Returns the current unexpected handler.
+ */
+ unexpected_handler get_unexpected() throw()
+ {
+ __cxa_thread_info *info = thread_info();
+ if (info->unexpectedHandler)
+ {
+ return info->unexpectedHandler;
+ }
+ return unexpectedHandler;
+ }
+ /**
+ * Returns the current terminate handler.
+ */
+ terminate_handler get_terminate() throw()
+ {
+ __cxa_thread_info *info = thread_info();
+ if (info->terminateHandler)
+ {
+ return info->terminateHandler;
+ }
+ return terminateHandler;
+ }
+}
+#ifdef __arm__
+extern "C" _Unwind_Exception *__cxa_get_cleanup(void)
+{
+ __cxa_thread_info *info = thread_info_fast();
+ _Unwind_Exception *exceptionObject = info->currentCleanup;
+ if (isCXXException(exceptionObject->exception_class))
+ {
+ __cxa_exception *ex = exceptionFromPointer(exceptionObject);
+ ex->cleanupCount--;
+ if (ex->cleanupCount == 0)
+ {
+ info->currentCleanup = ex->nextCleanup;
+ ex->nextCleanup = 0;
+ }
+ }
+ else
+ {
+ info->currentCleanup = 0;
+ }
+ return exceptionObject;
+}
+
+asm (
+".pushsection .text.__cxa_end_cleanup \n"
+".global __cxa_end_cleanup \n"
+".type __cxa_end_cleanup, \"function\" \n"
+"__cxa_end_cleanup: \n"
+" push {r1, r2, r3, r4} \n"
+" bl __cxa_get_cleanup \n"
+" push {r1, r2, r3, r4} \n"
+" b _Unwind_Resume \n"
+" bl abort \n"
+".popsection \n"
+);
+#endif
diff --git a/contrib/libcxxrt/guard.cc b/contrib/libcxxrt/guard.cc
new file mode 100644
index 0000000..f236053
--- /dev/null
+++ b/contrib/libcxxrt/guard.cc
@@ -0,0 +1,134 @@
+/**
+ * guard.cc: Functions for thread-safe static initialisation.
+ *
+ * Static values in C++ can be initialised lazily their first use. This file
+ * contains functions that are used to ensure that two threads attempting to
+ * initialize the same static do not call the constructor twice. This is
+ * important because constructors can have side effects, so calling the
+ * constructor twice may be very bad.
+ *
+ * Statics that require initialisation are protected by a 64-bit value. Any
+ * platform that can do 32-bit atomic test and set operations can use this
+ * value as a low-overhead lock. Because statics (in most sane code) are
+ * accessed far more times than they are initialised, this lock implementation
+ * is heavily optimised towards the case where the static has already been
+ * initialised.
+ */
+#include <stdint.h>
+#include <pthread.h>
+#include <assert.h>
+
+#ifdef __arm__
+// ARM ABI - 32-bit guards.
+
+/**
+ * Acquires a lock on a guard, returning 0 if the object has already been
+ * initialised, and 1 if it has not. If the object is already constructed then
+ * this function just needs to read a byte from memory and return.
+ */
+extern "C" int __cxa_guard_acquire(volatile int32_t *guard_object)
+{
+ if ((1<<31) == *guard_object) { return 0; }
+ // If we can atomically move the value from 0 -> 1, then this is
+ // uninitialised.
+ if (__sync_bool_compare_and_swap(guard_object, 0, 1))
+ {
+ return 1;
+ }
+ // If the value is not 0, some other thread was initialising this. Spin
+ // until it's finished.
+ while (__sync_bool_compare_and_swap(guard_object, (1<<31), (1<<31)))
+ {
+ // If the other thread aborted, then we grab the lock
+ if (__sync_bool_compare_and_swap(guard_object, 0, 1))
+ {
+ return 1;
+ }
+ sched_yield();
+ }
+ return 0;
+}
+
+/**
+ * Releases the lock without marking the object as initialised. This function
+ * is called if initialising a static causes an exception to be thrown.
+ */
+extern "C" void __cxa_guard_abort(int32_t *guard_object)
+{
+ assert(__sync_bool_compare_and_swap(guard_object, 1, 0));
+}
+/**
+ * Releases the guard and marks the object as initialised. This function is
+ * called after successful initialisation of a static.
+ */
+extern "C" void __cxa_guard_release(int32_t *guard_object)
+{
+ assert(__sync_bool_compare_and_swap(guard_object, 1, (1<<31)));
+}
+
+
+#else
+// Itanium ABI: 64-bit guards
+
+/**
+ * Returns a pointer to the low 32 bits in a 64-bit value, respecting the
+ * platform's byte order.
+ */
+static int32_t *low_32_bits(volatile int64_t *ptr)
+{
+ int32_t *low= (int32_t*)ptr;
+ // Test if the machine is big endian - constant propagation at compile time
+ // should eliminate this completely.
+ int one = 1;
+ if (*(char*)&one != 1)
+ {
+ low++;
+ }
+ return low;
+}
+
+/**
+ * Acquires a lock on a guard, returning 0 if the object has already been
+ * initialised, and 1 if it has not. If the object is already constructed then
+ * this function just needs to read a byte from memory and return.
+ */
+extern "C" int __cxa_guard_acquire(volatile int64_t *guard_object)
+{
+ char first_byte = (*guard_object) >> 56;
+ if (1 == first_byte) { return 0; }
+ int32_t *lock = low_32_bits(guard_object);
+ // Simple spin lock using the low 32 bits. We assume that concurrent
+ // attempts to initialize statics are very rare, so we don't need to
+ // optimise for the case where we have lots of threads trying to acquire
+ // the lock at the same time.
+ while (!__sync_bool_compare_and_swap_4(lock, 0, 1))
+ {
+ sched_yield();
+ }
+ // We have to test the guard again, in case another thread has performed
+ // the initialisation while we were trying to acquire the lock.
+ first_byte = (*guard_object) >> 56;
+ return (1 != first_byte);
+}
+
+/**
+ * Releases the lock without marking the object as initialised. This function
+ * is called if initialising a static causes an exception to be thrown.
+ */
+extern "C" void __cxa_guard_abort(int64_t *guard_object)
+{
+ int32_t *lock = low_32_bits(guard_object);
+ *lock = 0;
+}
+/**
+ * Releases the guard and marks the object as initialised. This function is
+ * called after successful initialisation of a static.
+ */
+extern "C" void __cxa_guard_release(int64_t *guard_object)
+{
+ // Set the first byte to 1
+ *guard_object |= ((int64_t)1) << 56;
+ __cxa_guard_abort(guard_object);
+}
+
+#endif
diff --git a/contrib/libcxxrt/libelftc_dem_gnu3.c b/contrib/libcxxrt/libelftc_dem_gnu3.c
new file mode 100644
index 0000000..b0428c9
--- /dev/null
+++ b/contrib/libcxxrt/libelftc_dem_gnu3.c
@@ -0,0 +1,3473 @@
+/*-
+ * Copyright (c) 2007, 2008 Hyogeol Lee <hyogeollee@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <sys/types.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * @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
+ */
+
+/** @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 VECTOR_DEF_CAPACITY 8
+#define ELFTC_ISDIGIT(C) (isdigit((C) & 0xFF))
+
+enum type_qualifier {
+ TYPE_PTR, TYPE_REF, TYPE_CMX, TYPE_IMG, TYPE_EXT, TYPE_RST, TYPE_VAT,
+ TYPE_CST
+};
+
+struct vector_type_qualifier {
+ size_t size, capacity;
+ enum type_qualifier *q_container;
+ struct vector_str ext_name;
+};
+
+enum read_cmd {
+ READ_FAIL, READ_NEST, READ_TMPL, READ_EXPR, READ_EXPL, READ_LOCAL,
+ READ_TYPE, READ_FUNC, READ_PTRMEM
+};
+
+struct vector_read_cmd {
+ size_t size, capacity;
+ enum read_cmd *r_container;
+};
+
+struct cpp_demangle_data {
+ struct vector_str output; /* output string vector */
+ struct vector_str output_tmp;
+ struct vector_str subst; /* substitution string vector */
+ struct vector_str tmpl;
+ struct vector_str class_type;
+ struct vector_read_cmd cmd;
+ bool paren; /* parenthesis opened */
+ bool pfirst; /* first element of parameter */
+ bool mem_rst; /* restrict member function */
+ bool mem_vat; /* volatile member function */
+ bool mem_cst; /* const member function */
+ int func_type;
+ const char *cur; /* current mangled name ptr */
+ const char *last_sname; /* last source name */
+ int push_head;
+};
+
+#define CPP_DEMANGLE_TRY_LIMIT 128
+#define FLOAT_SPRINTF_TRY_LIMIT 5
+#define FLOAT_QUADRUPLE_BYTES 16
+#define FLOAT_EXTENED_BYTES 10
+
+#define SIMPLE_HASH(x,y) (64 * x + y)
+
+static 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static 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.
+ */
+static bool
+vector_str_push_vector_head(struct vector_str *dst, struct vector_str *org)
+{
+ size_t i, j, tmp_cap;
+ char **tmp_ctn;
+
+ if (dst == NULL || org == NULL)
+ return (false);
+
+ tmp_cap = (dst->size + org->size) * BUFFER_GROWFACTOR;
+
+ if ((tmp_ctn = malloc(sizeof(char *) * tmp_cap)) == NULL)
+ return (false);
+
+ for (i = 0; i < org->size; ++i)
+ if ((tmp_ctn[i] = strdup(org->container[i])) == NULL) {
+ for (j = 0; j < i; ++j)
+ free(tmp_ctn[j]);
+
+ free(tmp_ctn);
+
+ return (false);
+ }
+
+ for (i = 0; i < dst->size; ++i)
+ tmp_ctn[i + org->size] = dst->container[i];
+
+ free(dst->container);
+
+ dst->container = tmp_ctn;
+ dst->capacity = tmp_cap;
+ dst->size += org->size;
+
+ return (true);
+}
+
+/**
+ * @brief Get new allocated flat string from vector between begin and end.
+ *
+ * If r_len is not NULL, string length will be returned.
+ * @return NULL at failed or NUL terminated new allocated string.
+ */
+static 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);
+}
+
+static void cpp_demangle_data_dest(struct cpp_demangle_data *);
+static int cpp_demangle_data_init(struct cpp_demangle_data *,
+ const char *);
+static int cpp_demangle_get_subst(struct cpp_demangle_data *, size_t);
+static int cpp_demangle_get_tmpl_param(struct cpp_demangle_data *, size_t);
+static int cpp_demangle_push_fp(struct cpp_demangle_data *,
+ char *(*)(const char *, size_t));
+static int cpp_demangle_push_str(struct cpp_demangle_data *, const char *,
+ size_t);
+static int cpp_demangle_push_subst(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_push_subst_v(struct cpp_demangle_data *,
+ struct vector_str *);
+static int cpp_demangle_push_type_qualifier(struct cpp_demangle_data *,
+ struct vector_type_qualifier *, const char *);
+static int cpp_demangle_read_array(struct cpp_demangle_data *);
+static int cpp_demangle_read_encoding(struct cpp_demangle_data *);
+static int cpp_demangle_read_expr_primary(struct cpp_demangle_data *);
+static int cpp_demangle_read_expression(struct cpp_demangle_data *);
+static int cpp_demangle_read_expression_binary(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_expression_unary(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_expression_trinary(struct cpp_demangle_data *,
+ const char *, size_t, const char *, size_t);
+static int cpp_demangle_read_function(struct cpp_demangle_data *, int *,
+ struct vector_type_qualifier *);
+static int cpp_demangle_read_local_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_nested_name(struct cpp_demangle_data *);
+static int cpp_demangle_read_number(struct cpp_demangle_data *, long *);
+static int cpp_demangle_read_nv_offset(struct cpp_demangle_data *);
+static int cpp_demangle_read_offset(struct cpp_demangle_data *);
+static int cpp_demangle_read_offset_number(struct cpp_demangle_data *);
+static int cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *);
+static int cpp_demangle_read_sname(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst_std(struct cpp_demangle_data *);
+static int cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *,
+ const char *, size_t);
+static int cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *);
+static int cpp_demangle_read_tmpl_args(struct cpp_demangle_data *);
+static int cpp_demangle_read_tmpl_param(struct cpp_demangle_data *);
+static int cpp_demangle_read_type(struct cpp_demangle_data *, int);
+static int cpp_demangle_read_uqname(struct cpp_demangle_data *);
+static int cpp_demangle_read_v_offset(struct cpp_demangle_data *);
+static char *decode_fp_to_double(const char *, size_t);
+static char *decode_fp_to_float(const char *, size_t);
+static char *decode_fp_to_float128(const char *, size_t);
+static char *decode_fp_to_float80(const char *, size_t);
+static char *decode_fp_to_long_double(const char *, size_t);
+static int hex_to_dec(char);
+static void vector_read_cmd_dest(struct vector_read_cmd *);
+static int vector_read_cmd_find(struct vector_read_cmd *, enum read_cmd);
+static int vector_read_cmd_init(struct vector_read_cmd *);
+static int vector_read_cmd_pop(struct vector_read_cmd *);
+static int vector_read_cmd_push(struct vector_read_cmd *, enum read_cmd);
+static void vector_type_qualifier_dest(struct vector_type_qualifier *);
+static int vector_type_qualifier_init(struct vector_type_qualifier *);
+static int vector_type_qualifier_push(struct vector_type_qualifier *,
+ enum type_qualifier);
+
+/**
+ * @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 *
+__cxa_demangle_gnu3(const char *org)
+{
+ struct cpp_demangle_data ddata;
+ ssize_t org_len;
+ unsigned int limit;
+ char *rtn;
+
+ if (org == NULL)
+ return (NULL);
+
+ // Try demangling as a type for short encodings
+ if (((org_len = strlen(org)) < 2) || (org[0] != '_' || org[1] != 'Z' )) {
+ if (!cpp_demangle_data_init(&ddata, org))
+ return (NULL);
+ if (!cpp_demangle_read_type(&ddata, 0))
+ goto clean;
+ rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
+ goto clean;
+ }
+ 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 (!cpp_demangle_data_init(&ddata, org + 2))
+ return (NULL);
+
+ rtn = NULL;
+
+ if (!cpp_demangle_read_encoding(&ddata))
+ goto clean;
+
+ limit = 0;
+ while (*ddata.cur != '\0') {
+ /*
+ * Breaking at some gcc info at tail. e.g) @@GLIBCXX_3.4
+ */
+ if (*ddata.cur == '@' && *(ddata.cur + 1) == '@')
+ break;
+ if (!cpp_demangle_read_type(&ddata, 1))
+ goto clean;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ goto clean;
+ }
+
+ if (ddata.output.size == 0)
+ goto clean;
+ if (ddata.paren && !vector_str_push(&ddata.output, ")", 1))
+ goto clean;
+ if (ddata.mem_vat && !vector_str_push(&ddata.output, " volatile", 9))
+ goto clean;
+ if (ddata.mem_cst && !vector_str_push(&ddata.output, " const", 6))
+ goto clean;
+ if (ddata.mem_rst && !vector_str_push(&ddata.output, " restrict", 9))
+ goto clean;
+
+ rtn = vector_str_get_flat(&ddata.output, (size_t *) NULL);
+
+clean:
+ cpp_demangle_data_dest(&ddata);
+
+ return (rtn);
+}
+
+static void
+cpp_demangle_data_dest(struct cpp_demangle_data *d)
+{
+
+ if (d == NULL)
+ return;
+
+ vector_read_cmd_dest(&d->cmd);
+ vector_str_dest(&d->class_type);
+ vector_str_dest(&d->tmpl);
+ vector_str_dest(&d->subst);
+ vector_str_dest(&d->output_tmp);
+ vector_str_dest(&d->output);
+}
+
+static int
+cpp_demangle_data_init(struct cpp_demangle_data *d, const char *cur)
+{
+
+ if (d == NULL || cur == NULL)
+ return (0);
+
+ if (!vector_str_init(&d->output))
+ return (0);
+ if (!vector_str_init(&d->output_tmp))
+ goto clean1;
+ if (!vector_str_init(&d->subst))
+ goto clean2;
+ if (!vector_str_init(&d->tmpl))
+ goto clean3;
+ if (!vector_str_init(&d->class_type))
+ goto clean4;
+ if (!vector_read_cmd_init(&d->cmd))
+ goto clean5;
+
+ assert(d->output.container != NULL);
+ assert(d->output_tmp.container != NULL);
+ assert(d->subst.container != NULL);
+ assert(d->tmpl.container != NULL);
+ assert(d->class_type.container != NULL);
+
+ d->paren = false;
+ d->pfirst = false;
+ d->mem_rst = false;
+ d->mem_vat = false;
+ d->mem_cst = false;
+ d->func_type = 0;
+ d->cur = cur;
+ d->last_sname = NULL;
+ d->push_head = 0;
+
+ return (1);
+
+clean5:
+ vector_str_dest(&d->class_type);
+clean4:
+ vector_str_dest(&d->tmpl);
+clean3:
+ vector_str_dest(&d->subst);
+clean2:
+ vector_str_dest(&d->output_tmp);
+clean1:
+ vector_str_dest(&d->output);
+
+ return (0);
+}
+
+static int
+cpp_demangle_push_fp(struct cpp_demangle_data *ddata,
+ char *(*decoder)(const char *, size_t))
+{
+ size_t len;
+ int rtn;
+ const char *fp;
+ char *f;
+
+ if (ddata == NULL || decoder == NULL)
+ return (0);
+
+ fp = ddata->cur;
+ while (*ddata->cur != 'E')
+ ++ddata->cur;
+ ++ddata->cur;
+
+ if ((f = decoder(fp, ddata->cur - fp)) == NULL)
+ return (0);
+
+ rtn = 0;
+ if ((len = strlen(f)) > 0 &&
+ cpp_demangle_push_str(ddata, f, len))
+ rtn = 1;
+
+ free(f);
+
+ return (0);
+}
+
+static int
+cpp_demangle_push_str(struct cpp_demangle_data *ddata, const char *str,
+ size_t len)
+{
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ if (ddata->push_head > 0)
+ return (vector_str_push(&ddata->output_tmp, str, len));
+
+ return (vector_str_push(&ddata->output, str, len));
+}
+
+static int
+cpp_demangle_push_subst(struct cpp_demangle_data *ddata, const char *str,
+ size_t len)
+{
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ if (!vector_str_find(&ddata->subst, str, len))
+ return (vector_str_push(&ddata->subst, str, len));
+
+ return (1);
+}
+
+static int
+cpp_demangle_push_subst_v(struct cpp_demangle_data *ddata, struct vector_str *v)
+{
+ size_t str_len;
+ int rtn;
+ char *str;
+
+ if (ddata == NULL || v == NULL)
+ return (0);
+
+ if ((str = vector_str_get_flat(v, &str_len)) == NULL)
+ return (0);
+
+ rtn = cpp_demangle_push_subst(ddata, str, str_len);
+ free(str);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_push_type_qualifier(struct cpp_demangle_data *ddata,
+ struct vector_type_qualifier *v, const char *type_str)
+{
+ struct vector_str subst_v;
+ size_t idx, e_idx, e_len;
+ int rtn;
+ char *buf;
+
+ if (ddata == NULL || v == NULL)
+ return (0);
+
+ if ((idx = v->size) == 0)
+ return (1);
+
+ rtn = 0;
+ if (type_str != NULL) {
+ if (!vector_str_init(&subst_v))
+ return (0);
+ if (!vector_str_push(&subst_v, type_str, strlen(type_str)))
+ goto clean;
+ }
+
+ e_idx = 0;
+ while (idx > 0) {
+ switch (v->q_container[idx - 1]) {
+ case TYPE_PTR:
+ if (!cpp_demangle_push_str(ddata, "*", 1))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, "*", 1))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_REF:
+ if (!cpp_demangle_push_str(ddata, "&", 1))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, "&", 1))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_CMX:
+ if (!cpp_demangle_push_str(ddata, " complex", 8))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " complex", 8))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_IMG:
+ if (!cpp_demangle_push_str(ddata, " imaginary", 10))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " imaginary", 10))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_EXT:
+ if (e_idx > v->ext_name.size - 1)
+ goto clean;
+ if ((e_len = strlen(v->ext_name.container[e_idx])) == 0)
+ goto clean;
+ if ((buf = malloc(sizeof(char) * (e_len + 1))) == NULL)
+ goto clean;
+
+ memcpy(buf, " ", 1);
+ memcpy(buf + 1, v->ext_name.container[e_idx], e_len);
+
+ if (!cpp_demangle_push_str(ddata, buf, e_len + 1)) {
+ free(buf);
+ goto clean;
+ }
+
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, buf,
+ e_len + 1)) {
+ free(buf);
+ goto clean;
+ }
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v)) {
+ free(buf);
+ goto clean;
+ }
+ }
+ free(buf);
+ ++e_idx;
+ break;
+
+ case TYPE_RST:
+ if (!cpp_demangle_push_str(ddata, " restrict", 9))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " restrict", 9))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_VAT:
+ if (!cpp_demangle_push_str(ddata, " volatile", 9))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " volatile", 9))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ case TYPE_CST:
+ if (!cpp_demangle_push_str(ddata, " const", 6))
+ goto clean;
+ if (type_str != NULL) {
+ if (!vector_str_push(&subst_v, " const", 6))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &subst_v))
+ goto clean;
+ }
+ break;
+
+ };
+ --idx;
+ }
+
+ rtn = 1;
+clean:
+ if (type_str != NULL)
+ vector_str_dest(&subst_v);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_get_subst(struct cpp_demangle_data *ddata, size_t idx)
+{
+ size_t len;
+
+ if (ddata == NULL || ddata->subst.size <= idx)
+ return (0);
+ if ((len = strlen(ddata->subst.container[idx])) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->subst.container[idx], len))
+ return (0);
+
+ /* skip '_' */
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_get_tmpl_param(struct cpp_demangle_data *ddata, size_t idx)
+{
+ size_t len;
+
+ if (ddata == NULL || ddata->tmpl.size <= idx)
+ return (0);
+ if ((len = strlen(ddata->tmpl.container[idx])) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->tmpl.container[idx], len))
+ return (0);
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_array(struct cpp_demangle_data *ddata)
+{
+ size_t i, num_len, exp_len, p_idx, idx;
+ const char *num;
+ char *exp;
+
+ if (ddata == NULL || *(++ddata->cur) == '\0')
+ return (0);
+
+ if (*ddata->cur == '_') {
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "[]", 2))
+ return (0);
+ } else {
+ if (ELFTC_ISDIGIT(*ddata->cur) != 0) {
+ num = ddata->cur;
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+ if (*ddata->cur != '_')
+ return (0);
+ num_len = ddata->cur - num;
+ assert(num_len > 0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "[", 1))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, num, num_len))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "]", 1))
+ return (0);
+ } else {
+ p_idx = ddata->output.size;
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if ((exp = vector_str_substr(&ddata->output, p_idx,
+ ddata->output.size - 1, &exp_len)) == NULL)
+ return (0);
+ idx = ddata->output.size;
+ for (i = p_idx; i < idx; ++i)
+ if (!vector_str_pop(&ddata->output)) {
+ free(exp);
+ return (0);
+ }
+ if (*ddata->cur != '_') {
+ free(exp);
+ return (0);
+ }
+ ++ddata->cur;
+ if (*ddata->cur == '\0') {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_read_type(ddata, 0)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, "[", 1)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, exp, exp_len)) {
+ free(exp);
+ return (0);
+ }
+ if (!cpp_demangle_push_str(ddata, "]", 1)) {
+ free(exp);
+ return (0);
+ }
+ free(exp);
+ }
+ }
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_expr_primary(struct cpp_demangle_data *ddata)
+{
+ const char *num;
+
+ if (ddata == NULL || *(++ddata->cur) == '\0')
+ return (0);
+
+ if (*ddata->cur == '_' && *(ddata->cur + 1) == 'Z') {
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_encoding(ddata))
+ return (0);
+ ++ddata->cur;
+ return (1);
+ }
+
+ switch (*ddata->cur) {
+ case 'b':
+ switch (*(++ddata->cur)) {
+ case '0':
+ return (cpp_demangle_push_str(ddata, "false", 5));
+ case '1':
+ return (cpp_demangle_push_str(ddata, "true", 4));
+ default:
+ return (0);
+ };
+
+ case 'd':
+ ++ddata->cur;
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_double));
+
+ case 'e':
+ ++ddata->cur;
+ if (sizeof(long double) == 10)
+ return (cpp_demangle_push_fp(ddata,
+ decode_fp_to_double));
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float80));
+
+ case 'f':
+ ++ddata->cur;
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float));
+
+ case 'g':
+ ++ddata->cur;
+ if (sizeof(long double) == 16)
+ return (cpp_demangle_push_fp(ddata,
+ decode_fp_to_double));
+ return (cpp_demangle_push_fp(ddata, decode_fp_to_float128));
+
+ case 'i':
+ case 'j':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 's':
+ case 't':
+ case 'x':
+ case 'y':
+ if (*(++ddata->cur) == 'n') {
+ if (!cpp_demangle_push_str(ddata, "-", 1))
+ return (0);
+ ++ddata->cur;
+ }
+ num = ddata->cur;
+ while (*ddata->cur != 'E') {
+ if (!ELFTC_ISDIGIT(*ddata->cur))
+ return (0);
+ ++ddata->cur;
+ }
+ ++ddata->cur;
+ return (cpp_demangle_push_str(ddata, num, ddata->cur - num));
+
+ default:
+ return (0);
+ };
+}
+
+static int
+cpp_demangle_read_expression(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('s', 't'):
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 0));
+
+ case SIMPLE_HASH('s', 'r'):
+ ddata->cur += 2;
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (!cpp_demangle_read_uqname(ddata))
+ return (0);
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_tmpl_args(ddata));
+ return (1);
+
+ case SIMPLE_HASH('a', 'a'):
+ /* operator && */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&&", 2));
+
+ case SIMPLE_HASH('a', 'd'):
+ /* operator & (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "&", 1));
+
+ case SIMPLE_HASH('a', 'n'):
+ /* operator & */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&", 1));
+
+ case SIMPLE_HASH('a', 'N'):
+ /* operator &= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "&=", 2));
+
+ case SIMPLE_HASH('a', 'S'):
+ /* operator = */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "=", 1));
+
+ case SIMPLE_HASH('c', 'l'):
+ /* operator () */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "()", 2));
+
+ case SIMPLE_HASH('c', 'm'):
+ /* operator , */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ",", 1));
+
+ case SIMPLE_HASH('c', 'o'):
+ /* operator ~ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "~", 1));
+
+ case SIMPLE_HASH('c', 'v'):
+ /* operator (cast) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "(cast)", 6));
+
+ case SIMPLE_HASH('d', 'a'):
+ /* operator delete [] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "delete []", 9));
+
+ case SIMPLE_HASH('d', 'e'):
+ /* operator * (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "*", 1));
+
+ case SIMPLE_HASH('d', 'l'):
+ /* operator delete */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "delete", 6));
+
+ case SIMPLE_HASH('d', 'v'):
+ /* operator / */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "/", 1));
+
+ case SIMPLE_HASH('d', 'V'):
+ /* operator /= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "/=", 2));
+
+ case SIMPLE_HASH('e', 'o'):
+ /* operator ^ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "^", 1));
+
+ case SIMPLE_HASH('e', 'O'):
+ /* operator ^= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "^=", 2));
+
+ case SIMPLE_HASH('e', 'q'):
+ /* operator == */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "==", 2));
+
+ case SIMPLE_HASH('g', 'e'):
+ /* operator >= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">=", 2));
+
+ case SIMPLE_HASH('g', 't'):
+ /* operator > */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">", 1));
+
+ case SIMPLE_HASH('i', 'x'):
+ /* operator [] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "[]", 2));
+
+ case SIMPLE_HASH('l', 'e'):
+ /* operator <= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<=", 2));
+
+ case SIMPLE_HASH('l', 's'):
+ /* operator << */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<<", 2));
+
+ case SIMPLE_HASH('l', 'S'):
+ /* operator <<= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<<=", 3));
+
+ case SIMPLE_HASH('l', 't'):
+ /* operator < */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "<", 1));
+
+ case SIMPLE_HASH('m', 'i'):
+ /* operator - */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "-", 1));
+
+ case SIMPLE_HASH('m', 'I'):
+ /* operator -= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "-=", 2));
+
+ case SIMPLE_HASH('m', 'l'):
+ /* operator * */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "*", 1));
+
+ case SIMPLE_HASH('m', 'L'):
+ /* operator *= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "*=", 2));
+
+ case SIMPLE_HASH('m', 'm'):
+ /* operator -- */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "--", 2));
+
+ case SIMPLE_HASH('n', 'a'):
+ /* operator new[] */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "new []", 6));
+
+ case SIMPLE_HASH('n', 'e'):
+ /* operator != */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "!=", 2));
+
+ case SIMPLE_HASH('n', 'g'):
+ /* operator - (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "-", 1));
+
+ case SIMPLE_HASH('n', 't'):
+ /* operator ! */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "!", 1));
+
+ case SIMPLE_HASH('n', 'w'):
+ /* operator new */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "new", 3));
+
+ case SIMPLE_HASH('o', 'o'):
+ /* operator || */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "||", 2));
+
+ case SIMPLE_HASH('o', 'r'):
+ /* operator | */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "|", 1));
+
+ case SIMPLE_HASH('o', 'R'):
+ /* operator |= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "|=", 2));
+
+ case SIMPLE_HASH('p', 'l'):
+ /* operator + */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "+", 1));
+
+ case SIMPLE_HASH('p', 'L'):
+ /* operator += */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "+=", 2));
+
+ case SIMPLE_HASH('p', 'm'):
+ /* operator ->* */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "->*", 3));
+
+ case SIMPLE_HASH('p', 'p'):
+ /* operator ++ */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "++", 2));
+
+ case SIMPLE_HASH('p', 's'):
+ /* operator + (unary) */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "+", 1));
+
+ case SIMPLE_HASH('p', 't'):
+ /* operator -> */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "->", 2));
+
+ case SIMPLE_HASH('q', 'u'):
+ /* operator ? */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_trinary(ddata, "?", 1,
+ ":", 1));
+
+ case SIMPLE_HASH('r', 'm'):
+ /* operator % */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "%", 1));
+
+ case SIMPLE_HASH('r', 'M'):
+ /* operator %= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, "%=", 2));
+
+ case SIMPLE_HASH('r', 's'):
+ /* operator >> */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">>", 2));
+
+ case SIMPLE_HASH('r', 'S'):
+ /* operator >>= */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_binary(ddata, ">>=", 3));
+
+ case SIMPLE_HASH('r', 'z'):
+ /* operator sizeof */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6));
+
+ case SIMPLE_HASH('s', 'v'):
+ /* operator sizeof */
+ ddata->cur += 2;
+ return (cpp_demangle_read_expression_unary(ddata, "sizeof", 6));
+ };
+
+ switch (*ddata->cur) {
+ case 'L':
+ return (cpp_demangle_read_expr_primary(ddata));
+ case 'T':
+ return (cpp_demangle_read_tmpl_param(ddata));
+ };
+
+ return (0);
+}
+
+static int
+cpp_demangle_read_expression_binary(struct cpp_demangle_data *ddata,
+ const char *name, size_t len)
+{
+
+ if (ddata == NULL || name == NULL || len == 0)
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name, len))
+ return (0);
+
+ return (cpp_demangle_read_expression(ddata));
+}
+
+static int
+cpp_demangle_read_expression_unary(struct cpp_demangle_data *ddata,
+ const char *name, size_t len)
+{
+
+ if (ddata == NULL || name == NULL || len == 0)
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+
+ return (cpp_demangle_push_str(ddata, name, len));
+}
+
+static int
+cpp_demangle_read_expression_trinary(struct cpp_demangle_data *ddata,
+ const char *name1, size_t len1, const char *name2, size_t len2)
+{
+
+ if (ddata == NULL || name1 == NULL || len1 == 0 || name2 == NULL ||
+ len2 == 0)
+ return (0);
+
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name1, len1))
+ return (0);
+ if (!cpp_demangle_read_expression(ddata))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, name2, len2))
+ return (0);
+
+ return (cpp_demangle_read_expression(ddata));
+}
+
+static int
+cpp_demangle_read_function(struct cpp_demangle_data *ddata, int *ext_c,
+ struct vector_type_qualifier *v)
+{
+ size_t class_type_size, class_type_len, limit;
+ const char *class_type;
+
+ if (ddata == NULL || *ddata->cur != 'F' || v == NULL)
+ return (0);
+
+ ++ddata->cur;
+ if (*ddata->cur == 'Y') {
+ if (ext_c != NULL)
+ *ext_c = 1;
+ ++ddata->cur;
+ }
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (*ddata->cur != 'E') {
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+ if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM)) {
+ if ((class_type_size = ddata->class_type.size) == 0)
+ return (0);
+ class_type =
+ ddata->class_type.container[class_type_size - 1];
+ if (class_type == NULL)
+ return (0);
+ if ((class_type_len = strlen(class_type)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, class_type,
+ class_type_len))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::*", 3))
+ return (0);
+ ++ddata->func_type;
+ } else {
+ if (!cpp_demangle_push_type_qualifier(ddata, v,
+ (const char *) NULL))
+ return (0);
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+ }
+
+ if (!cpp_demangle_push_str(ddata, ")(", 2))
+ return (0);
+
+ limit = 0;
+ for (;;) {
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+ if (*ddata->cur == 'E')
+ break;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+
+ if (vector_read_cmd_find(&ddata->cmd, READ_PTRMEM) == 1) {
+ if (!cpp_demangle_push_type_qualifier(ddata, v,
+ (const char *) NULL))
+ return (0);
+ vector_type_qualifier_dest(v);
+ if (!vector_type_qualifier_init(v))
+ return (0);
+ }
+
+ if (!cpp_demangle_push_str(ddata, ")", 1))
+ return (0);
+ }
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+/* read encoding, encoding are function name, data name, special-name */
+static int
+cpp_demangle_read_encoding(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* special name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('G', 'V'):
+ /* sentry object for 1 time init */
+ if (!cpp_demangle_push_str(ddata, "guard variable for ", 20))
+ return (0);
+ ddata->cur += 2;
+ break;
+
+ case SIMPLE_HASH('T', 'c'):
+ /* virtual function covariant override thunk */
+ if (!cpp_demangle_push_str(ddata,
+ "virtual function covariant override ", 36))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_offset(ddata))
+ return (0);
+ if (!cpp_demangle_read_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'D'):
+ /* typeinfo common proxy */
+ break;
+
+ case SIMPLE_HASH('T', 'h'):
+ /* virtual function non-virtual override thunk */
+ if (cpp_demangle_push_str(ddata,
+ "virtual function non-virtual override ", 38) == 0)
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_nv_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'I'):
+ /* typeinfo structure */
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('T', 'S'):
+ /* RTTI name (NTBS) */
+ if (!cpp_demangle_push_str(ddata, "typeinfo for ", 14))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('T', 'T'):
+ /* VTT table */
+ if (!cpp_demangle_push_str(ddata, "VTT for ", 8))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('T', 'v'):
+ /* virtual function virtual override thunk */
+ if (!cpp_demangle_push_str(ddata,
+ "virtual function virtual override ", 34))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ if (!cpp_demangle_read_v_offset(ddata))
+ return (0);
+ return (cpp_demangle_read_encoding(ddata));
+
+ case SIMPLE_HASH('T', 'V'):
+ /* virtual table */
+ if (!cpp_demangle_push_str(ddata, "vtable for ", 12))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == '\0')
+ return (0);
+ return (cpp_demangle_read_type(ddata, 1));
+ };
+
+ return (cpp_demangle_read_name(ddata));
+}
+
+static int
+cpp_demangle_read_local_name(struct cpp_demangle_data *ddata)
+{
+ size_t limit;
+
+ if (ddata == NULL)
+ return (0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (!cpp_demangle_read_encoding(ddata))
+ return (0);
+
+ limit = 0;
+ for (;;) {
+ if (!cpp_demangle_read_type(ddata, 1))
+ return (0);
+ if (*ddata->cur == 'E')
+ break;
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+ if (*(++ddata->cur) == '\0')
+ return (0);
+ if (ddata->paren == true) {
+ if (!cpp_demangle_push_str(ddata, ")", 1))
+ return (0);
+ ddata->paren = false;
+ }
+ if (*ddata->cur == 's')
+ ++ddata->cur;
+ else {
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ return (0);
+ if (!cpp_demangle_read_name(ddata))
+ return (0);
+ }
+ if (*ddata->cur == '_') {
+ ++ddata->cur;
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+ }
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_name(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+
+ subst_str = NULL;
+
+ switch (*ddata->cur) {
+ case 'S':
+ return (cpp_demangle_read_subst(ddata));
+ case 'N':
+ return (cpp_demangle_read_nested_name(ddata));
+ case 'Z':
+ return (cpp_demangle_read_local_name(ddata));
+ };
+
+ if (!vector_str_init(&v))
+ return (0);
+
+ p_idx = output->size;
+ rtn = 0;
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+ if ((subst_str = vector_str_substr(output, p_idx, output->size - 1,
+ &subst_str_len)) == NULL)
+ goto clean;
+ if (subst_str_len > 8 && strstr(subst_str, "operator") != NULL) {
+ rtn = 1;
+ goto clean;
+ }
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+
+ if (*ddata->cur == 'I') {
+ p_idx = output->size;
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ free(subst_str);
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ }
+
+ rtn = 1;
+
+clean:
+ free(subst_str);
+ vector_str_dest(&v);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_read_nested_name(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t limit, p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL || *ddata->cur != 'N')
+ return (0);
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ while (*ddata->cur == 'r' || *ddata->cur == 'V' ||
+ *ddata->cur == 'K') {
+ switch (*ddata->cur) {
+ case 'r':
+ ddata->mem_rst = true;
+ break;
+ case 'V':
+ ddata->mem_vat = true;
+ break;
+ case 'K':
+ ddata->mem_cst = true;
+ break;
+ };
+ ++ddata->cur;
+ }
+
+ output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ if (!vector_str_init(&v))
+ return (0);
+
+ rtn = 0;
+ limit = 0;
+ for (;;) {
+ p_idx = output->size;
+ switch (*ddata->cur) {
+ case 'I':
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ break;
+ case 'S':
+ if (!cpp_demangle_read_subst(ddata))
+ goto clean;
+ break;
+ case 'T':
+ if (!cpp_demangle_read_tmpl_param(ddata))
+ goto clean;
+ break;
+ default:
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+ };
+
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len)) {
+ free(subst_str);
+ goto clean;
+ }
+ free(subst_str);
+
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ if (*ddata->cur == 'E')
+ break;
+ else if (*ddata->cur != 'I' &&
+ *ddata->cur != 'C' && *ddata->cur != 'D') {
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ goto clean;
+ if (!vector_str_push(&v, "::", 2))
+ goto clean;
+ }
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ goto clean;
+ }
+
+ ++ddata->cur;
+ rtn = 1;
+
+clean:
+ vector_str_dest(&v);
+
+ return (rtn);
+}
+
+/*
+ * read number
+ * number ::= [n] <decimal>
+ */
+static int
+cpp_demangle_read_number(struct cpp_demangle_data *ddata, long *rtn)
+{
+ long len, negative_factor;
+
+ if (ddata == NULL || rtn == NULL)
+ return (0);
+
+ negative_factor = 1;
+ if (*ddata->cur == 'n') {
+ negative_factor = -1;
+
+ ++ddata->cur;
+ }
+ if (ELFTC_ISDIGIT(*ddata->cur) == 0)
+ return (0);
+
+ errno = 0;
+ if ((len = strtol(ddata->cur, (char **) NULL, 10)) == 0 &&
+ errno != 0)
+ return (0);
+
+ while (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ ++ddata->cur;
+
+ assert(len >= 0);
+ assert(negative_factor == 1 || negative_factor == -1);
+
+ *rtn = len * negative_factor;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_nv_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+ return (0);
+
+ return (cpp_demangle_read_offset_number(ddata));
+}
+
+/* read offset, offset are nv-offset, v-offset */
+static int
+cpp_demangle_read_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (*ddata->cur == 'h') {
+ ++ddata->cur;
+ return (cpp_demangle_read_nv_offset(ddata));
+ } else if (*ddata->cur == 'v') {
+ ++ddata->cur;
+ return (cpp_demangle_read_v_offset(ddata));
+ }
+
+ return (0);
+}
+
+static int
+cpp_demangle_read_offset_number(struct cpp_demangle_data *ddata)
+{
+ bool negative;
+ const char *start;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* offset could be negative */
+ if (*ddata->cur == 'n') {
+ negative = true;
+ start = ddata->cur + 1;
+ } else {
+ negative = false;
+ start = ddata->cur;
+ }
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ if (negative && !cpp_demangle_push_str(ddata, "-", 1))
+ return (0);
+
+ assert(start != NULL);
+
+ if (!cpp_demangle_push_str(ddata, start, ddata->cur - start))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, " ", 1))
+ return (0);
+
+ ++ddata->cur;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_pointer_to_member(struct cpp_demangle_data *ddata)
+{
+ size_t class_type_len, i, idx, p_idx;
+ int p_func_type, rtn;
+ char *class_type;
+
+ if (ddata == NULL || *ddata->cur != 'M' || *(++ddata->cur) == '\0')
+ return (0);
+
+ p_idx = ddata->output.size;
+ if (!cpp_demangle_read_type(ddata, 0))
+ return (0);
+
+ if ((class_type = vector_str_substr(&ddata->output, p_idx,
+ ddata->output.size - 1, &class_type_len)) == NULL)
+ return (0);
+
+ rtn = 0;
+ idx = ddata->output.size;
+ for (i = p_idx; i < idx; ++i)
+ if (!vector_str_pop(&ddata->output))
+ goto clean1;
+
+ if (!vector_read_cmd_push(&ddata->cmd, READ_PTRMEM))
+ goto clean1;
+
+ if (!vector_str_push(&ddata->class_type, class_type, class_type_len))
+ goto clean2;
+
+ p_func_type = ddata->func_type;
+ if (!cpp_demangle_read_type(ddata, 0))
+ goto clean3;
+
+ if (p_func_type == ddata->func_type) {
+ if (!cpp_demangle_push_str(ddata, " ", 1))
+ goto clean3;
+ if (!cpp_demangle_push_str(ddata, class_type, class_type_len))
+ goto clean3;
+ if (!cpp_demangle_push_str(ddata, "::*", 3))
+ goto clean3;
+ }
+
+ rtn = 1;
+clean3:
+ if (!vector_str_pop(&ddata->class_type))
+ rtn = 0;
+clean2:
+ if (!vector_read_cmd_pop(&ddata->cmd))
+ rtn = 0;
+clean1:
+ free(class_type);
+
+ return (rtn);
+}
+
+/* read source-name, source-name is <len> <ID> */
+static int
+cpp_demangle_read_sname(struct cpp_demangle_data *ddata)
+{
+ long len;
+
+ if (ddata == NULL || cpp_demangle_read_number(ddata, &len) == 0 ||
+ len <= 0 || cpp_demangle_push_str(ddata, ddata->cur, len) == 0)
+ return (0);
+
+ assert(ddata->output.size > 0);
+ if (vector_read_cmd_find(&ddata->cmd, READ_TMPL) == 0)
+ ddata->last_sname =
+ ddata->output.container[ddata->output.size - 1];
+
+ ddata->cur += len;
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_subst(struct cpp_demangle_data *ddata)
+{
+ long nth;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* abbreviations of the form Sx */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('S', 'a'):
+ /* std::allocator */
+ if (cpp_demangle_push_str(ddata, "std::allocator", 14) == 0)
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::allocator", 14));
+ return (1);
+
+ case SIMPLE_HASH('S', 'b'):
+ /* std::basic_string */
+ if (!cpp_demangle_push_str(ddata, "std::basic_string", 17))
+ return (0);
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::basic_string", 17));
+ return (1);
+
+ case SIMPLE_HASH('S', 'd'):
+ /* std::basic_iostream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::iostream", 19))
+ return (0);
+ ddata->last_sname = "iostream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::iostream", 19));
+ return (1);
+
+ case SIMPLE_HASH('S', 'i'):
+ /* std::basic_istream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::istream", 18))
+ return (0);
+ ddata->last_sname = "istream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::istream", 18));
+ return (1);
+
+ case SIMPLE_HASH('S', 'o'):
+ /* std::basic_ostream<char, std::char_traits<char> > */
+ if (!cpp_demangle_push_str(ddata, "std::ostream", 18))
+ return (0);
+ ddata->last_sname = "istream";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::ostream", 18));
+ return (1);
+
+ case SIMPLE_HASH('S', 's'):
+ /*
+ * std::basic_string<char, std::char_traits<char>,
+ * std::allocator<char> >
+ *
+ * a.k.a std::string
+ */
+ if (!cpp_demangle_push_str(ddata, "std::string", 11))
+ return (0);
+ ddata->last_sname = "string";
+ ddata->cur += 2;
+ if (*ddata->cur == 'I')
+ return (cpp_demangle_read_subst_stdtmpl(ddata,
+ "std::string", 11));
+ return (1);
+
+ case SIMPLE_HASH('S', 't'):
+ /* std:: */
+ return (cpp_demangle_read_subst_std(ddata));
+ };
+
+ if (*(++ddata->cur) == '\0')
+ return (0);
+
+ /* substitution */
+ if (*ddata->cur == '_')
+ return (cpp_demangle_get_subst(ddata, 0));
+ else {
+ errno = 0;
+ /* substitution number is base 36 */
+ if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 &&
+ errno != 0)
+ return (0);
+
+ /* first was '_', so increase one */
+ ++nth;
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ assert(nth > 0);
+
+ return (cpp_demangle_get_subst(ddata, nth));
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+cpp_demangle_read_subst_std(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *output, v;
+ size_t p_idx, subst_str_len;
+ int rtn;
+ char *subst_str;
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!vector_str_init(&v))
+ return (0);
+
+ subst_str = NULL;
+ rtn = 0;
+ if (!cpp_demangle_push_str(ddata, "std::", 5))
+ goto clean;
+
+ if (!vector_str_push(&v, "std::", 5))
+ goto clean;
+
+ ddata->cur += 2;
+
+ output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+
+ p_idx = output->size;
+ if (!cpp_demangle_read_uqname(ddata))
+ goto clean;
+
+ if ((subst_str = vector_str_substr(output, p_idx, output->size - 1,
+ &subst_str_len)) == NULL)
+ goto clean;
+
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+
+ if (*ddata->cur == 'I') {
+ p_idx = output->size;
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ goto clean;
+ free(subst_str);
+ if ((subst_str = vector_str_substr(output, p_idx,
+ output->size - 1, &subst_str_len)) == NULL)
+ goto clean;
+ if (!vector_str_push(&v, subst_str, subst_str_len))
+ goto clean;
+ if (!cpp_demangle_push_subst_v(ddata, &v))
+ goto clean;
+ }
+
+ rtn = 1;
+clean:
+ free(subst_str);
+ vector_str_dest(&v);
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_subst_stdtmpl(struct cpp_demangle_data *ddata,
+ const char *str, size_t len)
+{
+ struct vector_str *output;
+ size_t p_idx, substr_len;
+ int rtn;
+ char *subst_str, *substr;
+
+ if (ddata == NULL || str == NULL || len == 0)
+ return (0);
+
+ output = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+
+ p_idx = output->size;
+ substr = NULL;
+ subst_str = NULL;
+
+ if (!cpp_demangle_read_tmpl_args(ddata))
+ return (0);
+ if ((substr = vector_str_substr(output, p_idx, output->size - 1,
+ &substr_len)) == NULL)
+ return (0);
+
+ rtn = 0;
+ if ((subst_str = malloc(sizeof(char) * (substr_len + len + 1))) ==
+ NULL)
+ goto clean;
+
+ memcpy(subst_str, str, len);
+ memcpy(subst_str + len, substr, substr_len);
+ subst_str[substr_len + len] = '\0';
+
+ if (!cpp_demangle_push_subst(ddata, subst_str, substr_len + len))
+ goto clean;
+
+ rtn = 1;
+clean:
+ free(subst_str);
+ free(substr);
+
+ return (rtn);
+}
+
+static int
+cpp_demangle_read_tmpl_arg(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ switch (*ddata->cur) {
+ case 'L':
+ return (cpp_demangle_read_expr_primary(ddata));
+ case 'X':
+ return (cpp_demangle_read_expression(ddata));
+ };
+
+ return (cpp_demangle_read_type(ddata, 0));
+}
+
+static int
+cpp_demangle_read_tmpl_args(struct cpp_demangle_data *ddata)
+{
+ struct vector_str *v;
+ size_t arg_len, idx, limit, size;
+ char *arg;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ ++ddata->cur;
+
+ if (!vector_read_cmd_push(&ddata->cmd, READ_TMPL))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "<", 1))
+ return (0);
+
+ limit = 0;
+ v = ddata->push_head > 0 ? &ddata->output_tmp : &ddata->output;
+ for (;;) {
+ idx = v->size;
+ if (!cpp_demangle_read_tmpl_arg(ddata))
+ return (0);
+ if ((arg = vector_str_substr(v, idx, v->size - 1, &arg_len)) ==
+ NULL)
+ return (0);
+ if (!vector_str_find(&ddata->tmpl, arg, arg_len) &&
+ !vector_str_push(&ddata->tmpl, arg, arg_len)) {
+ free(arg);
+ return (0);
+ }
+
+ free(arg);
+
+ if (*ddata->cur == 'E') {
+ ++ddata->cur;
+ size = v->size;
+ assert(size > 0);
+ if (!strncmp(v->container[size - 1], ">", 1)) {
+ if (!cpp_demangle_push_str(ddata, " >", 2))
+ return (0);
+ } else if (!cpp_demangle_push_str(ddata, ">", 1))
+ return (0);
+ break;
+ } else if (*ddata->cur != 'I' &&
+ !cpp_demangle_push_str(ddata, ", ", 2))
+ return (0);
+
+ if (limit++ > CPP_DEMANGLE_TRY_LIMIT)
+ return (0);
+ }
+
+ return (vector_read_cmd_pop(&ddata->cmd));
+}
+
+/*
+ * Read template parameter that forms in 'T[number]_'.
+ * This function much like to read_subst but only for types.
+ */
+static int
+cpp_demangle_read_tmpl_param(struct cpp_demangle_data *ddata)
+{
+ long nth;
+
+ if (ddata == NULL || *ddata->cur != 'T')
+ return (0);
+
+ ++ddata->cur;
+
+ if (*ddata->cur == '_')
+ return (cpp_demangle_get_tmpl_param(ddata, 0));
+ else {
+
+ errno = 0;
+ if ((nth = strtol(ddata->cur, (char **) NULL, 36)) == 0 &&
+ errno != 0)
+ return (0);
+
+ /* T_ is first */
+ ++nth;
+
+ while (*ddata->cur != '_')
+ ++ddata->cur;
+
+ assert(nth > 0);
+
+ return (cpp_demangle_get_tmpl_param(ddata, nth));
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+cpp_demangle_read_type(struct cpp_demangle_data *ddata, int delimit)
+{
+ struct vector_type_qualifier v;
+ struct vector_str *output;
+ size_t p_idx, type_str_len;
+ int extern_c, is_builtin;
+ long len;
+ char *type_str;
+
+ if (ddata == NULL)
+ return (0);
+
+ output = &ddata->output;
+ if (ddata->output.size > 0 && !strncmp(ddata->output.container[ddata->output.size - 1], ">", 1)) {
+ ddata->push_head++;
+ output = &ddata->output_tmp;
+ } else if (delimit == 1) {
+ if (ddata->paren == false) {
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+ if (ddata->output.size < 2)
+ return (0);
+ ddata->paren = true;
+ ddata->pfirst = true;
+ /* Need pop function name */
+ if (ddata->subst.size == 1 &&
+ !vector_str_pop(&ddata->subst))
+ return (0);
+ }
+
+ if (ddata->pfirst)
+ ddata->pfirst = false;
+ else if (*ddata->cur != 'I' &&
+ !cpp_demangle_push_str(ddata, ", ", 2))
+ return (0);
+ }
+
+ assert(output != NULL);
+ /*
+ * [r, V, K] [P, R, C, G, U] builtin, function, class-enum, array
+ * pointer-to-member, template-param, template-template-param, subst
+ */
+
+ if (!vector_type_qualifier_init(&v))
+ return (0);
+
+ extern_c = 0;
+ is_builtin = 1;
+ p_idx = output->size;
+ type_str = NULL;
+again:
+ /* builtin type */
+ switch (*ddata->cur) {
+ case 'a':
+ /* signed char */
+ if (!cpp_demangle_push_str(ddata, "signed char", 11))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'A':
+ /* array type */
+ if (!cpp_demangle_read_array(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'b':
+ /* bool */
+ if (!cpp_demangle_push_str(ddata, "bool", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'C':
+ /* complex pair */
+ if (!vector_type_qualifier_push(&v, TYPE_CMX))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'c':
+ /* char */
+ if (!cpp_demangle_push_str(ddata, "char", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'd':
+ /* double */
+ if (!cpp_demangle_push_str(ddata, "double", 6))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'e':
+ /* long double */
+ if (!cpp_demangle_push_str(ddata, "long double", 11))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'f':
+ /* float */
+ if (!cpp_demangle_push_str(ddata, "float", 5))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'F':
+ /* function */
+ if (!cpp_demangle_read_function(ddata, &extern_c, &v))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'g':
+ /* __float128 */
+ if (!cpp_demangle_push_str(ddata, "__float128", 10))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'G':
+ /* imaginary */
+ if (!vector_type_qualifier_push(&v, TYPE_IMG))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'h':
+ /* unsigned char */
+ if (!cpp_demangle_push_str(ddata, "unsigned char", 13))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'i':
+ /* int */
+ if (!cpp_demangle_push_str(ddata, "int", 3))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'j':
+ /* unsigned int */
+ if (!cpp_demangle_push_str(ddata, "unsigned int", 12))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'K':
+ /* const */
+ if (!vector_type_qualifier_push(&v, TYPE_CST))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'l':
+ /* long */
+ if (!cpp_demangle_push_str(ddata, "long", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'm':
+ /* unsigned long */
+ if (!cpp_demangle_push_str(ddata, "unsigned long", 13))
+ goto clean;
+
+ ++ddata->cur;
+
+ goto rtn;
+ case 'M':
+ /* pointer to member */
+ if (!cpp_demangle_read_pointer_to_member(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'n':
+ /* __int128 */
+ if (!cpp_demangle_push_str(ddata, "__int128", 8))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'o':
+ /* unsigned __int128 */
+ if (!cpp_demangle_push_str(ddata, "unsigned _;int128", 17))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'P':
+ /* pointer */
+ if (!vector_type_qualifier_push(&v, TYPE_PTR))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'r':
+ /* restrict */
+ if (!vector_type_qualifier_push(&v, TYPE_RST))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'R':
+ /* reference */
+ if (!vector_type_qualifier_push(&v, TYPE_REF))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 's':
+ /* short, local string */
+ if (!cpp_demangle_push_str(ddata, "short", 5))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'S':
+ /* substitution */
+ if (!cpp_demangle_read_subst(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 't':
+ /* unsigned short */
+ if (!cpp_demangle_push_str(ddata, "unsigned short", 14))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'T':
+ /* template parameter */
+ if (!cpp_demangle_read_tmpl_param(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'u':
+ /* vendor extended builtin */
+ ++ddata->cur;
+ if (!cpp_demangle_read_sname(ddata))
+ goto clean;
+ is_builtin = 0;
+ goto rtn;
+
+ case 'U':
+ /* vendor extended type qualifier */
+ if (!cpp_demangle_read_number(ddata, &len))
+ goto clean;
+ if (len <= 0)
+ goto clean;
+ if (!vector_str_push(&v.ext_name, ddata->cur, len))
+ return (0);
+ ddata->cur += len;
+ goto again;
+
+ case 'v':
+ /* void */
+ if (!cpp_demangle_push_str(ddata, "void", 4))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'V':
+ /* volatile */
+ if (!vector_type_qualifier_push(&v, TYPE_VAT))
+ goto clean;
+ ++ddata->cur;
+ goto again;
+
+ case 'w':
+ /* wchar_t */
+ if (!cpp_demangle_push_str(ddata, "wchar_t", 6))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'x':
+ /* long long */
+ if (!cpp_demangle_push_str(ddata, "long long", 9))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'y':
+ /* unsigned long long */
+ if (!cpp_demangle_push_str(ddata, "unsigned long long", 18))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+
+ case 'z':
+ /* ellipsis */
+ if (!cpp_demangle_push_str(ddata, "ellipsis", 8))
+ goto clean;
+ ++ddata->cur;
+ goto rtn;
+ };
+
+ if (!cpp_demangle_read_name(ddata))
+ goto clean;
+
+ is_builtin = 0;
+rtn:
+ if ((type_str = vector_str_substr(output, p_idx, output->size - 1,
+ &type_str_len)) == NULL)
+ goto clean;
+
+ if (is_builtin == 0) {
+ if (!vector_str_find(&ddata->subst, type_str, type_str_len) &&
+ !vector_str_push(&ddata->subst, type_str, type_str_len))
+ goto clean;
+ }
+
+ if (!cpp_demangle_push_type_qualifier(ddata, &v, type_str))
+ goto clean;
+
+ free(type_str);
+ vector_type_qualifier_dest(&v);
+
+ if (ddata->push_head > 0) {
+ if (*ddata->cur == 'I' && cpp_demangle_read_tmpl_args(ddata)
+ == 0)
+ return (0);
+
+ if (--ddata->push_head > 0)
+ return (1);
+
+ if (!vector_str_push(&ddata->output_tmp, " ", 1))
+ return (0);
+
+ if (!vector_str_push_vector_head(&ddata->output,
+ &ddata->output_tmp))
+ return (0);
+
+ vector_str_dest(&ddata->output_tmp);
+ if (!vector_str_init(&ddata->output_tmp))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "(", 1))
+ return (0);
+
+ ddata->paren = true;
+ ddata->pfirst = true;
+ }
+
+ return (1);
+clean:
+ free(type_str);
+ vector_type_qualifier_dest(&v);
+
+ return (0);
+}
+
+/*
+ * read unqualified-name, unqualified name are operator-name, ctor-dtor-name,
+ * source-name
+ */
+static int
+cpp_demangle_read_uqname(struct cpp_demangle_data *ddata)
+{
+ size_t len;
+
+ if (ddata == NULL || *ddata->cur == '\0')
+ return (0);
+
+ /* operator name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('a', 'a'):
+ /* operator && */
+ if (!cpp_demangle_push_str(ddata, "operator&&", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'd'):
+ /* operator & (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator&", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'n'):
+ /* operator & */
+ if (!cpp_demangle_push_str(ddata, "operator&", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'N'):
+ /* operator &= */
+ if (!cpp_demangle_push_str(ddata, "operator&=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('a', 'S'):
+ /* operator = */
+ if (!cpp_demangle_push_str(ddata, "operator=", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'l'):
+ /* operator () */
+ if (!cpp_demangle_push_str(ddata, "operator()", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'm'):
+ /* operator , */
+ if (!cpp_demangle_push_str(ddata, "operator,", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'o'):
+ /* operator ~ */
+ if (!cpp_demangle_push_str(ddata, "operator~", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('c', 'v'):
+ /* operator (cast) */
+ if (!cpp_demangle_push_str(ddata, "operator(cast)", 14))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_type(ddata, 1));
+
+ case SIMPLE_HASH('d', 'a'):
+ /* operator delete [] */
+ if (!cpp_demangle_push_str(ddata, "operator delete []", 18))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'e'):
+ /* operator * (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator*", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'l'):
+ /* operator delete */
+ if (!cpp_demangle_push_str(ddata, "operator delete", 15))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'v'):
+ /* operator / */
+ if (!cpp_demangle_push_str(ddata, "operator/", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('d', 'V'):
+ /* operator /= */
+ if (!cpp_demangle_push_str(ddata, "operator/=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'o'):
+ /* operator ^ */
+ if (!cpp_demangle_push_str(ddata, "operator^", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'O'):
+ /* operator ^= */
+ if (!cpp_demangle_push_str(ddata, "operator^=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('e', 'q'):
+ /* operator == */
+ if (!cpp_demangle_push_str(ddata, "operator==", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('g', 'e'):
+ /* operator >= */
+ if (!cpp_demangle_push_str(ddata, "operator>=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('g', 't'):
+ /* operator > */
+ if (!cpp_demangle_push_str(ddata, "operator>", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('i', 'x'):
+ /* operator [] */
+ if (!cpp_demangle_push_str(ddata, "operator[]", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 'e'):
+ /* operator <= */
+ if (!cpp_demangle_push_str(ddata, "operator<=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 's'):
+ /* operator << */
+ if (!cpp_demangle_push_str(ddata, "operator<<", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 'S'):
+ /* operator <<= */
+ if (!cpp_demangle_push_str(ddata, "operator<<=", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('l', 't'):
+ /* operator < */
+ if (!cpp_demangle_push_str(ddata, "operator<", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'i'):
+ /* operator - */
+ if (!cpp_demangle_push_str(ddata, "operator-", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'I'):
+ /* operator -= */
+ if (!cpp_demangle_push_str(ddata, "operator-=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'l'):
+ /* operator * */
+ if (!cpp_demangle_push_str(ddata, "operator*", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'L'):
+ /* operator *= */
+ if (!cpp_demangle_push_str(ddata, "operator*=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('m', 'm'):
+ /* operator -- */
+ if (!cpp_demangle_push_str(ddata, "operator--", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'a'):
+ /* operator new[] */
+ if (!cpp_demangle_push_str(ddata, "operator new []", 15))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'e'):
+ /* operator != */
+ if (!cpp_demangle_push_str(ddata, "operator!=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'g'):
+ /* operator - (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator-", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 't'):
+ /* operator ! */
+ if (!cpp_demangle_push_str(ddata, "operator!", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('n', 'w'):
+ /* operator new */
+ if (!cpp_demangle_push_str(ddata, "operator new", 12))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'o'):
+ /* operator || */
+ if (!cpp_demangle_push_str(ddata, "operator||", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'r'):
+ /* operator | */
+ if (!cpp_demangle_push_str(ddata, "operator|", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('o', 'R'):
+ /* operator |= */
+ if (!cpp_demangle_push_str(ddata, "operator|=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'l'):
+ /* operator + */
+ if (!cpp_demangle_push_str(ddata, "operator+", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'L'):
+ /* operator += */
+ if (!cpp_demangle_push_str(ddata, "operator+=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'm'):
+ /* operator ->* */
+ if (!cpp_demangle_push_str(ddata, "operator->*", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 'p'):
+ /* operator ++ */
+ if (!cpp_demangle_push_str(ddata, "operator++", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 's'):
+ /* operator + (unary) */
+ if (!cpp_demangle_push_str(ddata, "operator+", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('p', 't'):
+ /* operator -> */
+ if (!cpp_demangle_push_str(ddata, "operator->", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('q', 'u'):
+ /* operator ? */
+ if (!cpp_demangle_push_str(ddata, "operator?", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'm'):
+ /* operator % */
+ if (!cpp_demangle_push_str(ddata, "operator%", 9))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'M'):
+ /* operator %= */
+ if (!cpp_demangle_push_str(ddata, "operator%=", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 's'):
+ /* operator >> */
+ if (!cpp_demangle_push_str(ddata, "operator>>", 10))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'S'):
+ /* operator >>= */
+ if (!cpp_demangle_push_str(ddata, "operator>>=", 11))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('r', 'z'):
+ /* operator sizeof */
+ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('s', 'r'):
+ /* scope resolution operator */
+ if (!cpp_demangle_push_str(ddata, "scope resolution operator ",
+ 26))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+
+ case SIMPLE_HASH('s', 'v'):
+ /* operator sizeof */
+ if (!cpp_demangle_push_str(ddata, "operator sizeof ", 16))
+ return (0);
+ ddata->cur += 2;
+ return (1);
+ };
+
+ /* vendor extened operator */
+ if (*ddata->cur == 'v' && ELFTC_ISDIGIT(*(ddata->cur + 1))) {
+ if (!cpp_demangle_push_str(ddata, "vendor extened operator ",
+ 24))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->cur + 1, 1))
+ return (0);
+ ddata->cur += 2;
+ return (cpp_demangle_read_sname(ddata));
+ }
+
+ /* ctor-dtor-name */
+ switch (SIMPLE_HASH(*ddata->cur, *(ddata->cur + 1))) {
+ case SIMPLE_HASH('C', '1'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('C', '2'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('C', '3'):
+ if (ddata->last_sname == NULL)
+ return (0);
+ if ((len = strlen(ddata->last_sname)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::", 2))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
+ return (0);
+ ddata->cur +=2;
+ return (1);
+
+ case SIMPLE_HASH('D', '0'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('D', '1'):
+ /* FALLTHROUGH */
+ case SIMPLE_HASH('D', '2'):
+ if (ddata->last_sname == NULL)
+ return (0);
+ if ((len = strlen(ddata->last_sname)) == 0)
+ return (0);
+ if (!cpp_demangle_push_str(ddata, "::~", 3))
+ return (0);
+ if (!cpp_demangle_push_str(ddata, ddata->last_sname, len))
+ return (0);
+ ddata->cur +=2;
+ return (1);
+ };
+
+ /* source name */
+ if (ELFTC_ISDIGIT(*ddata->cur) != 0)
+ return (cpp_demangle_read_sname(ddata));
+
+ return (1);
+}
+
+static int
+cpp_demangle_read_v_offset(struct cpp_demangle_data *ddata)
+{
+
+ if (ddata == NULL)
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "offset : ", 9))
+ return (0);
+
+ if (!cpp_demangle_read_offset_number(ddata))
+ return (0);
+
+ if (!cpp_demangle_push_str(ddata, "virtual offset : ", 17))
+ return (0);
+
+ return (!cpp_demangle_read_offset_number(ddata));
+}
+
+/*
+ * Decode floating point representation to string
+ * Return new allocated string or NULL
+ *
+ * Todo
+ * Replace these functions to macro.
+ */
+static char *
+decode_fp_to_double(const char *p, size_t len)
+{
+ double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(double))
+ return (NULL);
+
+ memset(&f, 0, sizeof(double));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(double) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 64;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%fld", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return rtn;
+}
+
+static char *
+decode_fp_to_float(const char *p, size_t len)
+{
+ size_t i, rtn_len, limit;
+ float f;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 || len / 2 > sizeof(float))
+ return (NULL);
+
+ memset(&f, 0, sizeof(float));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+ if (byte < 0 || byte > 255)
+ return (NULL);
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(float) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 64;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%ff", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return rtn;
+}
+
+static char *
+decode_fp_to_float128(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ unsigned char buf[FLOAT_QUADRUPLE_BYTES];
+ char *rtn;
+
+ switch(sizeof(long double)) {
+ case FLOAT_QUADRUPLE_BYTES:
+ return (decode_fp_to_long_double(p, len));
+ case FLOAT_EXTENED_BYTES:
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > FLOAT_QUADRUPLE_BYTES)
+ return (NULL);
+
+ memset(buf, 0, FLOAT_QUADRUPLE_BYTES);
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+ if (byte < 0 || byte > 255)
+ return (NULL);
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ buf[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ buf[FLOAT_QUADRUPLE_BYTES - i -1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+ memset(&f, 0, FLOAT_EXTENED_BYTES);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ memcpy(&f, buf, FLOAT_EXTENED_BYTES);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ memcpy(&f, buf + 6, FLOAT_EXTENED_BYTES);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+ default:
+ return (NULL);
+ }
+}
+
+static char *
+decode_fp_to_float80(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ unsigned char buf[FLOAT_EXTENED_BYTES];
+ char *rtn;
+
+ switch(sizeof(long double)) {
+ case FLOAT_QUADRUPLE_BYTES:
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > FLOAT_EXTENED_BYTES)
+ return (NULL);
+
+ memset(buf, 0, FLOAT_EXTENED_BYTES);
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ buf[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ buf[FLOAT_EXTENED_BYTES - i -1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ memset(&f, 0, FLOAT_QUADRUPLE_BYTES);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ memcpy(&f, buf, FLOAT_EXTENED_BYTES);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ memcpy((unsigned char *)(&f) + 6, buf, FLOAT_EXTENED_BYTES);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+ case FLOAT_EXTENED_BYTES:
+ return (decode_fp_to_long_double(p, len));
+ default:
+ return (NULL);
+ }
+}
+
+static char *
+decode_fp_to_long_double(const char *p, size_t len)
+{
+ long double f;
+ size_t rtn_len, limit, i;
+ int byte;
+ char *rtn;
+
+ if (p == NULL || len == 0 || len % 2 != 0 ||
+ len / 2 > sizeof(long double))
+ return (NULL);
+
+ memset(&f, 0, sizeof(long double));
+
+ for (i = 0; i < len / 2; ++i) {
+ byte = hex_to_dec(p[len - i * 2 - 1]) +
+ hex_to_dec(p[len - i * 2 - 2]) * 16;
+
+ if (byte < 0 || byte > 255)
+ return (NULL);
+
+#if ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN
+ ((unsigned char *)&f)[i] = (unsigned char)(byte);
+#else /* ELFTC_BYTE_ORDER != ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ ((unsigned char *)&f)[sizeof(long double) - i - 1] =
+ (unsigned char)(byte);
+#endif /* ELFTC_BYTE_ORDER == ELFTC_BYTE_ORDER_LITTLE_ENDIAN */
+ }
+
+ rtn_len = 256;
+ limit = 0;
+again:
+ if ((rtn = malloc(sizeof(char) * rtn_len)) == NULL)
+ return (NULL);
+
+ if (snprintf(rtn, rtn_len, "%Lfd", f) >= (int)rtn_len) {
+ free(rtn);
+ if (limit++ > FLOAT_SPRINTF_TRY_LIMIT)
+ return (NULL);
+ rtn_len *= BUFFER_GROWFACTOR;
+ goto again;
+ }
+
+ return (rtn);
+}
+
+/* Simple hex to integer function used by decode_to_* function. */
+static int
+hex_to_dec(char c)
+{
+
+ switch (c) {
+ case '0':
+ return (0);
+ case '1':
+ return (1);
+ case '2':
+ return (2);
+ case '3':
+ return (3);
+ case '4':
+ return (4);
+ case '5':
+ return (5);
+ case '6':
+ return (6);
+ case '7':
+ return (7);
+ case '8':
+ return (8);
+ case '9':
+ return (9);
+ case 'a':
+ return (10);
+ case 'b':
+ return (11);
+ case 'c':
+ return (12);
+ case 'd':
+ return (13);
+ case 'e':
+ return (14);
+ case 'f':
+ return (15);
+ default:
+ return (-1);
+ };
+}
+
+static void
+vector_read_cmd_dest(struct vector_read_cmd *v)
+{
+
+ if (v == NULL)
+ return;
+
+ free(v->r_container);
+}
+
+/* return -1 at failed, 0 at not found, 1 at found. */
+static int
+vector_read_cmd_find(struct vector_read_cmd *v, enum read_cmd dst)
+{
+ size_t i;
+
+ if (v == NULL || dst == READ_FAIL)
+ return (-1);
+
+ for (i = 0; i < v->size; ++i)
+ if (v->r_container[i] == dst)
+ return (1);
+
+ return (0);
+}
+
+static int
+vector_read_cmd_init(struct vector_read_cmd *v)
+{
+
+ if (v == NULL)
+ return (0);
+
+ v->size = 0;
+ v->capacity = VECTOR_DEF_CAPACITY;
+
+ if ((v->r_container = malloc(sizeof(enum read_cmd) * v->capacity))
+ == NULL)
+ return (0);
+
+ return (1);
+}
+
+static int
+vector_read_cmd_pop(struct vector_read_cmd *v)
+{
+
+ if (v == NULL || v->size == 0)
+ return (0);
+
+ --v->size;
+ v->r_container[v->size] = READ_FAIL;
+
+ return (1);
+}
+
+static int
+vector_read_cmd_push(struct vector_read_cmd *v, enum read_cmd cmd)
+{
+ enum read_cmd *tmp_r_ctn;
+ size_t tmp_cap;
+ size_t i;
+
+ if (v == NULL)
+ return (0);
+
+ if (v->size == v->capacity) {
+ tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+ if ((tmp_r_ctn = malloc(sizeof(enum read_cmd) * tmp_cap))
+ == NULL)
+ return (0);
+ for (i = 0; i < v->size; ++i)
+ tmp_r_ctn[i] = v->r_container[i];
+ free(v->r_container);
+ v->r_container = tmp_r_ctn;
+ v->capacity = tmp_cap;
+ }
+
+ v->r_container[v->size] = cmd;
+ ++v->size;
+
+ return (1);
+}
+
+static void
+vector_type_qualifier_dest(struct vector_type_qualifier *v)
+{
+
+ if (v == NULL)
+ return;
+
+ free(v->q_container);
+ vector_str_dest(&v->ext_name);
+}
+
+/* size, capacity, ext_name */
+static int
+vector_type_qualifier_init(struct vector_type_qualifier *v)
+{
+
+ if (v == NULL)
+ return (0);
+
+ v->size = 0;
+ v->capacity = VECTOR_DEF_CAPACITY;
+
+ if ((v->q_container = malloc(sizeof(enum type_qualifier) * v->capacity))
+ == NULL)
+ return (0);
+
+ assert(v->q_container != NULL);
+
+ if (vector_str_init(&v->ext_name) == false) {
+ free(v->q_container);
+ return (0);
+ }
+
+ return (1);
+}
+
+static int
+vector_type_qualifier_push(struct vector_type_qualifier *v,
+ enum type_qualifier t)
+{
+ enum type_qualifier *tmp_ctn;
+ size_t tmp_cap;
+ size_t i;
+
+ if (v == NULL)
+ return (0);
+
+ if (v->size == v->capacity) {
+ tmp_cap = v->capacity * BUFFER_GROWFACTOR;
+ if ((tmp_ctn = malloc(sizeof(enum type_qualifier) * tmp_cap))
+ == NULL)
+ return (0);
+ for (i = 0; i < v->size; ++i)
+ tmp_ctn[i] = v->q_container[i];
+ free(v->q_container);
+ v->q_container = tmp_ctn;
+ v->capacity = tmp_cap;
+ }
+
+ v->q_container[v->size] = t;
+ ++v->size;
+
+ return (1);
+}
diff --git a/contrib/libcxxrt/memory.cc b/contrib/libcxxrt/memory.cc
new file mode 100644
index 0000000..027bc3f
--- /dev/null
+++ b/contrib/libcxxrt/memory.cc
@@ -0,0 +1,115 @@
+/**
+ * memory.cc - Contains stub definition of C++ new/delete operators.
+ *
+ * These definitions are intended to be used for testing and are weak symbols
+ * to allow them to be replaced by definitions from a STL implementation.
+ * These versions simply wrap malloc() and free(), they do not provide a
+ * C++-specific allocator.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "stdexcept.h"
+
+#if !__has_builtin(__sync_swap)
+#define __sync_swap __sync_lock_test_and_set
+#endif
+
+namespace std
+{
+ struct nothrow_t {};
+}
+
+
+/// The type of the function called when allocation fails.
+typedef void (*new_handler)();
+/**
+ * The function to call when allocation fails. By default, there is no
+ * handler and a bad allocation exception is thrown if an allocation fails.
+ */
+static new_handler new_handl;
+
+namespace std
+{
+ /**
+ * Sets a function to be called when there is a failure in new.
+ */
+ __attribute__((weak))
+ new_handler set_new_handler(new_handler handler)
+ {
+ return __sync_swap(&new_handl, handler);
+ }
+}
+
+
+__attribute__((weak))
+void* operator new(size_t size)
+{
+ void * mem = malloc(size);
+ while (0 == mem)
+ {
+ if (0 != new_handl)
+ {
+ new_handl();
+ }
+ else
+ {
+ throw std::bad_alloc();
+ }
+ mem = malloc(size);
+ }
+
+ return mem;
+}
+
+__attribute__((weak))
+void* operator new(size_t size, const std::nothrow_t &) throw()
+{
+ void *mem = malloc(size);
+ while (0 == mem)
+ {
+ if (0 != new_handl)
+ {
+ try
+ {
+ new_handl();
+ }
+ catch (...)
+ {
+ // nothrow operator new should return NULL in case of
+ // std::bad_alloc exception in new handler
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ mem = malloc(size);
+ }
+
+ return mem;
+}
+
+
+__attribute__((weak))
+void operator delete(void * ptr)
+{
+ free(ptr);
+}
+
+
+__attribute__((weak))
+void * operator new[](size_t size)
+{
+ return ::operator new(size);
+}
+
+
+__attribute__((weak))
+void operator delete[](void * ptr) throw()
+{
+ ::operator delete(ptr);
+}
+
+
diff --git a/contrib/libcxxrt/stdexcept.cc b/contrib/libcxxrt/stdexcept.cc
new file mode 100644
index 0000000..ba74240
--- /dev/null
+++ b/contrib/libcxxrt/stdexcept.cc
@@ -0,0 +1,60 @@
+/**
+ * stdexcept.cc - provides stub implementations of the exceptions required by the runtime.
+ */
+#include "stdexcept.h"
+
+namespace std {
+
+exception::exception() throw() {}
+exception::~exception() {}
+exception::exception(const exception&) throw() {}
+exception& exception::operator=(const exception&) throw()
+{
+ return *this;
+}
+const char* exception::what() const throw()
+{
+ return "std::exception";
+}
+
+bad_alloc::bad_alloc() throw() {}
+bad_alloc::~bad_alloc() {}
+bad_alloc::bad_alloc(const bad_alloc&) throw() {}
+bad_alloc& bad_alloc::operator=(const bad_alloc&) throw()
+{
+ return *this;
+}
+const char* bad_alloc::what() const throw()
+{
+ return "cxxrt::bad_alloc";
+}
+
+
+
+bad_cast::bad_cast() throw() {}
+bad_cast::~bad_cast() {}
+bad_cast::bad_cast(const bad_cast&) throw() {}
+bad_cast& bad_cast::operator=(const bad_cast&) throw()
+{
+ return *this;
+}
+const char* bad_cast::what() const throw()
+{
+ return "std::bad_cast";
+}
+
+bad_typeid::bad_typeid() throw() {}
+bad_typeid::~bad_typeid() {}
+bad_typeid::bad_typeid(const bad_typeid &__rhs) throw() {}
+bad_typeid& bad_typeid::operator=(const bad_typeid &__rhs) throw()
+{
+ return *this;
+}
+
+const char* bad_typeid::what() const throw()
+{
+ return "std::bad_typeid";
+}
+
+} // namespace std
+
diff --git a/contrib/libcxxrt/stdexcept.h b/contrib/libcxxrt/stdexcept.h
new file mode 100644
index 0000000..718f810
--- /dev/null
+++ b/contrib/libcxxrt/stdexcept.h
@@ -0,0 +1,61 @@
+/**
+ * stdexcept.h - provides a stub version of <stdexcept>, which defines enough
+ * of the exceptions for the runtime to use.
+ */
+
+namespace std
+{
+
+ class exception
+ {
+ public:
+ exception() throw();
+ exception(const exception&) throw();
+ exception& operator=(const exception&) throw();
+ virtual ~exception();
+ virtual const char* what() const throw();
+ };
+
+
+ /**
+ * Bad allocation exception. Thrown by ::operator new() if it fails.
+ */
+ class bad_alloc: public exception
+ {
+ public:
+ bad_alloc() throw();
+ bad_alloc(const bad_alloc&) throw();
+ bad_alloc& operator=(const bad_alloc&) throw();
+ ~bad_alloc();
+ virtual const char* what() const throw();
+ };
+
+ /**
+ * Bad cast exception. Thrown by the __cxa_bad_cast() helper function.
+ */
+ class bad_cast: public exception {
+ public:
+ bad_cast() throw();
+ bad_cast(const bad_cast&) throw();
+ bad_cast& operator=(const bad_cast&) throw();
+ virtual ~bad_cast();
+ virtual const char* what() const throw();
+ };
+
+ /**
+ * Bad typeidexception. Thrown by the __cxa_bad_typeid() helper function.
+ */
+ class bad_typeid: public exception
+ {
+ public:
+ bad_typeid() throw();
+ bad_typeid(const bad_typeid &__rhs) throw();
+ virtual ~bad_typeid();
+ bad_typeid& operator=(const bad_typeid &__rhs) throw();
+ virtual const char* what() const throw();
+ };
+
+
+
+} // namespace std
+
diff --git a/contrib/libcxxrt/terminate.cc b/contrib/libcxxrt/terminate.cc
new file mode 100644
index 0000000..663fe52
--- /dev/null
+++ b/contrib/libcxxrt/terminate.cc
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+
+namespace std
+{
+ /**
+ * Stub implementation of std::terminate. Used when the STL implementation
+ * doesn't provide one.
+ */
+ __attribute__((weak))
+ void terminate()
+ {
+ abort();
+ }
+}
diff --git a/contrib/libcxxrt/typeinfo b/contrib/libcxxrt/typeinfo
new file mode 100644
index 0000000..74e77ae
--- /dev/null
+++ b/contrib/libcxxrt/typeinfo
@@ -0,0 +1,26 @@
+namespace std
+{
+ /**
+ * Standard type info class. The layout of this class is specified by the
+ * ABI.
+ */
+ class type_info
+ {
+ public:
+ /**
+ * Virtual destructor. This class must have one virtual function to
+ * ensure that it has a vtable.
+ */
+ virtual ~type_info();
+ bool operator==(const type_info &) const;
+ bool operator!=(const type_info &) const;
+ bool before(const type_info &) const;
+ const char* name() const;
+ type_info();
+ private:
+ type_info(const type_info& rhs);
+ type_info& operator= (const type_info& rhs);
+ const char *__type_name;
+ };
+}
+
diff --git a/contrib/libcxxrt/typeinfo.cc b/contrib/libcxxrt/typeinfo.cc
new file mode 100644
index 0000000..fab4015
--- /dev/null
+++ b/contrib/libcxxrt/typeinfo.cc
@@ -0,0 +1,83 @@
+#include "typeinfo.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+using std::type_info;
+
+type_info::~type_info() {}
+
+bool type_info::operator==(const type_info &other) const
+{
+ return __type_name == other.__type_name;
+}
+bool type_info::operator!=(const type_info &other) const
+{
+ return __type_name != other.__type_name;
+}
+bool type_info::before(const type_info &other) const
+{
+ return __type_name < other.__type_name;
+}
+const char* type_info::name() const
+{
+ return __type_name;
+}
+type_info::type_info (const type_info& rhs)
+{
+ __type_name = rhs.__type_name;
+}
+type_info& type_info::operator= (const type_info& rhs)
+{
+ return *new type_info(rhs);
+}
+
+ABI_NAMESPACE::__fundamental_type_info::~__fundamental_type_info() {}
+ABI_NAMESPACE::__array_type_info::~__array_type_info() {}
+ABI_NAMESPACE::__function_type_info::~__function_type_info() {}
+ABI_NAMESPACE::__enum_type_info::~__enum_type_info() {}
+ABI_NAMESPACE::__class_type_info::~__class_type_info() {}
+ABI_NAMESPACE::__si_class_type_info::~__si_class_type_info() {}
+ABI_NAMESPACE::__vmi_class_type_info::~__vmi_class_type_info() {}
+ABI_NAMESPACE::__pbase_type_info::~__pbase_type_info() {}
+ABI_NAMESPACE::__pointer_type_info::~__pointer_type_info() {}
+ABI_NAMESPACE::__pointer_to_member_type_info::~__pointer_to_member_type_info() {}
+
+// From libelftc
+extern "C" char *__cxa_demangle_gnu3(const char *);
+
+extern "C" char* __cxa_demangle(const char* mangled_name,
+ char* buf,
+ size_t* n,
+ int* status)
+{
+ // TODO: We should probably just be linking against libelf-tc, rather than
+ // copying their code. This requires them to do an actual release,
+ // however, and for our changes to be pushed upstream. We also need to
+ // call a different demangling function here depending on the ABI (e.g.
+ // ARM).
+ char *demangled = __cxa_demangle_gnu3(mangled_name);
+ if (NULL != demangled)
+ {
+ size_t len = strlen(demangled);
+ buf = (char*)realloc(buf, len+1);
+ if (0 != buf)
+ {
+ memcpy(buf, demangled, len);
+ buf[len] = 0;
+ *n = len;
+ *status = 0;
+ }
+ else
+ {
+ *status = -1;
+ }
+ free(demangled);
+ }
+ else
+ {
+ *status = -2;
+ return NULL;
+ }
+ return buf;
+}
diff --git a/contrib/libcxxrt/typeinfo.h b/contrib/libcxxrt/typeinfo.h
new file mode 100644
index 0000000..1ee1fe5
--- /dev/null
+++ b/contrib/libcxxrt/typeinfo.h
@@ -0,0 +1,200 @@
+#include <stddef.h>
+#include "abi_namespace.h"
+#include "typeinfo"
+
+namespace ABI_NAMESPACE
+{
+ /**
+ * Primitive type info, for intrinsic types.
+ */
+ struct __fundamental_type_info : public std::type_info
+ {
+ virtual ~__fundamental_type_info();
+ };
+ /**
+ * Type info for arrays.
+ */
+ struct __array_type_info : public std::type_info
+ {
+ virtual ~__array_type_info();
+ };
+ /**
+ * Type info for functions.
+ */
+ struct __function_type_info : public std::type_info
+ {
+ virtual ~__function_type_info();
+ };
+ /**
+ * Type info for enums.
+ */
+ struct __enum_type_info : public std::type_info
+ {
+ virtual ~__enum_type_info();
+ };
+
+ /**
+ * Base class for class type info. Used only for tentative definitions.
+ */
+ struct __class_type_info : public std::type_info
+ {
+ virtual ~__class_type_info();
+ /**
+ * Function implementing dynamic casts.
+ */
+ virtual void *cast_to(void *obj,
+ const struct __class_type_info *other) const;
+ /**
+ * Function returning whether a cast from this type to another type is
+ * possible.
+ */
+ virtual bool can_cast_to(const struct __class_type_info *other) const;
+ };
+
+ /**
+ * Single-inheritance class type info. This is used for classes containing
+ * a single non-virtual base class at offset 0.
+ */
+ struct __si_class_type_info : public __class_type_info
+ {
+ virtual ~__si_class_type_info();
+ const __class_type_info *__base_type;
+ virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
+ virtual bool can_cast_to(const struct __class_type_info *other) const;
+ };
+
+ /**
+ * Type info for base classes. Classes with multiple bases store an array
+ * of these, one for each superclass.
+ */
+ struct __base_class_type_info
+ {
+ const __class_type_info *__base_type;
+ private:
+ /**
+ * The high __offset_shift bits of this store the (signed) offset
+ * of the base class. The low bits store flags from
+ * __offset_flags_masks.
+ */
+ long __offset_flags;
+ /**
+ * Flags used in the low bits of __offset_flags.
+ */
+ enum __offset_flags_masks
+ {
+ /** This base class is virtual. */
+ __virtual_mask = 0x1,
+ /** This base class is public. */
+ __public_mask = 0x2,
+ /** The number of bits reserved for flags. */
+ __offset_shift = 8
+ };
+ public:
+ /**
+ * Returns the offset of the base class.
+ */
+ long offset() const
+ {
+ return __offset_flags >> __offset_shift;
+ }
+ /**
+ * Returns the flags.
+ */
+ long flags() const
+ {
+ return __offset_flags & ((1 << __offset_shift) - 1);
+ }
+ /**
+ * Returns whether this is a public base class.
+ */
+ bool isPublic() const { return flags() & __public_mask; }
+ /**
+ * Returns whether this is a virtual base class.
+ */
+ bool isVirtual() const { return flags() & __virtual_mask; }
+ };
+
+ /**
+ * Type info for classes with virtual bases or multiple superclasses.
+ */
+ struct __vmi_class_type_info : public __class_type_info
+ {
+ virtual ~__vmi_class_type_info();
+ /** Flags describing this class. Contains values from __flags_masks. */
+ unsigned int __flags;
+ /** The number of base classes. */
+ unsigned int __base_count;
+ /**
+ * Array of base classes - this actually has __base_count elements, not
+ * 1.
+ */
+ __base_class_type_info __base_info[1];
+
+ /**
+ * Flags used in the __flags field.
+ */
+ enum __flags_masks
+ {
+ /** The class has non-diamond repeated inheritance. */
+ __non_diamond_repeat_mask = 0x1,
+ /** The class is diamond shaped. */
+ __diamond_shaped_mask = 0x2
+ };
+ virtual void *cast_to(void *obj, const struct __class_type_info *other) const;
+ virtual bool can_cast_to(const struct __class_type_info *other) const;
+ };
+
+ /**
+ * Base class used for both pointer and pointer-to-member type info.
+ */
+ struct __pbase_type_info : public std::type_info
+ {
+ virtual ~__pbase_type_info();
+ /**
+ * Flags. Values from __masks.
+ */
+ unsigned int __flags;
+ /**
+ * The type info for the pointee.
+ */
+ const std::type_info *__pointee;
+
+ /**
+ * Masks used for qualifiers on the pointer.
+ */
+ enum __masks
+ {
+ /** Pointer has const qualifier. */
+ __const_mask = 0x1,
+ /** Pointer has volatile qualifier. */
+ __volatile_mask = 0x2,
+ /** Pointer has restrict qualifier. */
+ __restrict_mask = 0x4,
+ /** Pointer points to an incomplete type. */
+ __incomplete_mask = 0x8,
+ /** Pointer is a pointer to a member of an incomplete class. */
+ __incomplete_class_mask = 0x10
+ };
+ };
+
+ /**
+ * Pointer type info.
+ */
+ struct __pointer_type_info : public __pbase_type_info
+ {
+ virtual ~__pointer_type_info();
+ };
+
+ /**
+ * Pointer to member type info.
+ */
+ struct __pointer_to_member_type_info : public __pbase_type_info
+ {
+ virtual ~__pointer_to_member_type_info();
+ /**
+ * Pointer to the class containing this member.
+ */
+ const __class_type_info *__context;
+ };
+
+}
diff --git a/contrib/libcxxrt/unwind-arm.h b/contrib/libcxxrt/unwind-arm.h
new file mode 100644
index 0000000..f9ed429
--- /dev/null
+++ b/contrib/libcxxrt/unwind-arm.h
@@ -0,0 +1,201 @@
+/**
+ * ARM-specific unwind definitions. These are taken from the ARM EHABI
+ * specification.
+ */
+ typedef enum
+{
+ _URC_OK = 0, /* operation completed successfully */
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8,
+ _URC_FAILURE = 9, /* unspecified failure of some kind */
+ _URC_FATAL_PHASE1_ERROR = _URC_FAILURE
+} _Unwind_Reason_Code;
+
+typedef uint32_t _Unwind_State;
+#ifdef __clang__
+static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
+static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
+static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
+#else // GCC fails at knowing what a constant expression is
+# define _US_VIRTUAL_UNWIND_FRAME 0
+# define _US_UNWIND_FRAME_STARTING 1
+# define _US_UNWIND_FRAME_RESUME 2
+#endif
+
+typedef struct _Unwind_Context _Unwind_Context;
+
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Exception
+{
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
+ /* Unwinder cache, private fields for the unwinder's use */
+ struct
+ {
+ uint32_t reserved1;
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint32_t reserved4;
+ uint32_t reserved5;
+ /* init reserved1 to 0, then don't touch */
+ } unwinder_cache;
+ /* Propagation barrier cache (valid after phase 1): */
+ struct
+ {
+ uint32_t sp;
+ uint32_t bitpattern[5];
+ } barrier_cache;
+ /* Cleanup cache (preserved over cleanup): */
+ struct
+ {
+ uint32_t bitpattern[4];
+ } cleanup_cache;
+ /* Pr cache (for pr's benefit): */
+ struct
+ {
+ /** function start address */
+ uint32_t fnstart;
+ /** pointer to EHT entry header word */
+ _Unwind_EHT_Header *ehtp;
+ /** additional data */
+ uint32_t additional;
+ uint32_t reserved1;
+ } pr_cache;
+ /** Force alignment of next item to 8-byte boundary */
+ long long int :0;
+};
+
+/* Unwinding functions */
+_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
+void _Unwind_Resume(struct _Unwind_Exception *ucbp);
+void _Unwind_Complete(struct _Unwind_Exception *ucbp);
+void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
+void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
+
+typedef enum
+{
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+typedef enum
+{
+ _UVRSC_CORE = 0,
+ _UVRSC_VFP = 1,
+ _UVRSC_WMMXD = 3,
+ _UVRSC_WMMXC = 4
+} _Unwind_VRS_RegClass;
+typedef enum
+{
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ uint32_t regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass,
+ uint32_t regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+
+/* Return the base-address for data references. */
+extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);
+
+/* Return the base-address for text references. */
+extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
+extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);
+
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
+ void *);
+extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+extern _Unwind_Reason_Code
+ _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
+
+/**
+ * The next set of functions are compatibility extensions, implementing Itanium
+ * ABI functions on top of ARM ones.
+ */
+
+#define _UA_SEARCH_PHASE 1
+#define _UA_CLEANUP_PHASE 2
+#define _UA_HANDLER_FRAME 4
+#define _UA_FORCE_UNWIND 8
+
+static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
+{
+ unsigned long val;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
+ return val;
+}
+static inline void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
+{
+ _Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
+}
+static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
+{
+ // Low bit store the thumb state - discard it
+ return _Unwind_GetGR(context, 15) & ~1;
+}
+static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
+{
+ // The lowest bit of the instruction pointer indicates whether we're in
+ // thumb or ARM mode. This is assumed to be fixed throughout a function,
+ // so must be propagated when setting the program counter.
+ unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
+ _Unwind_SetGR(context, 15, (val | thumbState));
+}
+
+/** GNU API function that unwinds the frame */
+_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);
+
+
+#define DECLARE_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(_Unwind_State state,\
+ struct _Unwind_Exception *exceptionObject,\
+ struct _Unwind_Context *context);
+
+#define BEGIN_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(_Unwind_State state,\
+ struct _Unwind_Exception *exceptionObject,\
+ struct _Unwind_Context *context)\
+{\
+ int version = 1;\
+ uint64_t exceptionClass = exceptionObject->exception_class;\
+ int actions;\
+ switch (state)\
+ {\
+ default: return _URC_FAILURE;\
+ case _US_VIRTUAL_UNWIND_FRAME:\
+ {\
+ actions = _UA_SEARCH_PHASE;\
+ break;\
+ }\
+ case _US_UNWIND_FRAME_STARTING:\
+ {\
+ actions = _UA_CLEANUP_PHASE;\
+ if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
+ {\
+ actions |= _UA_HANDLER_FRAME;\
+ }\
+ break;\
+ }\
+ case _US_UNWIND_FRAME_RESUME:\
+ {\
+ return continueUnwinding(exceptionObject, context);\
+ break;\
+ }\
+ }\
+ _Unwind_SetGR (context, 12, (unsigned long)exceptionObject);\
+
+#define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)
diff --git a/contrib/libcxxrt/unwind-itanium.h b/contrib/libcxxrt/unwind-itanium.h
new file mode 100644
index 0000000..16b3eed
--- /dev/null
+++ b/contrib/libcxxrt/unwind-itanium.h
@@ -0,0 +1,170 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+
+#ifndef _UNWIND_H
+#define _UNWIND_H
+
+/* For uint64_t */
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Minimal interface as per C++ ABI draft standard:
+
+ http://www.codesourcery.com/cxx-abi/abi-eh.html */
+
+typedef enum
+ {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8
+ }
+_Unwind_Reason_Code;
+
+typedef int _Unwind_Action;
+
+#define _UA_SEARCH_PHASE 1
+#define _UA_CLEANUP_PHASE 2
+#define _UA_HANDLER_FRAME 4
+#define _UA_FORCE_UNWIND 8
+
+struct _Unwind_Context; /* opaque data-structure */
+struct _Unwind_Exception; /* forward-declaration */
+
+typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
+ struct _Unwind_Exception *);
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action,
+ uint64_t,
+ struct _Unwind_Exception *,
+ struct _Unwind_Context *,
+ void *);
+
+/* The C++ ABI requires exception_class, private_1, and private_2 to
+ be of type uint64 and the entire structure to be
+ double-word-aligned. Please note that exception_class stays 64-bit
+ even on 32-bit machines for gcc compatibility. */
+struct _Unwind_Exception
+ {
+ uint64_t exception_class;
+ _Unwind_Exception_Cleanup_Fn exception_cleanup;
+ unsigned long private_1;
+ unsigned long private_2;
+ } __attribute__((__aligned__));
+
+extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
+extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
+ _Unwind_Stop_Fn, void *);
+extern void _Unwind_Resume (struct _Unwind_Exception *);
+extern void _Unwind_DeleteException (struct _Unwind_Exception *);
+extern unsigned long _Unwind_GetGR (struct _Unwind_Context *, int);
+extern void _Unwind_SetGR (struct _Unwind_Context *, int, unsigned long);
+extern unsigned long _Unwind_GetIP (struct _Unwind_Context *);
+extern unsigned long _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
+extern void _Unwind_SetIP (struct _Unwind_Context *, unsigned long);
+extern unsigned long _Unwind_GetLanguageSpecificData (struct _Unwind_Context*);
+extern unsigned long _Unwind_GetRegionStart (struct _Unwind_Context *);
+
+#ifdef _GNU_SOURCE
+
+/* Callback for _Unwind_Backtrace(). The backtrace stops immediately
+ if the callback returns any value other than _URC_NO_REASON. */
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
+ void *);
+
+/* See http://gcc.gnu.org/ml/gcc-patches/2001-09/msg00082.html for why
+ _UA_END_OF_STACK exists. */
+# define _UA_END_OF_STACK 16
+
+/* If the unwind was initiated due to a forced unwind, resume that
+ operation, else re-raise the exception. This is used by
+ __cxa_rethrow(). */
+extern _Unwind_Reason_Code
+ _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
+
+/* See http://gcc.gnu.org/ml/gcc-patches/2003-09/msg00154.html for why
+ _Unwind_GetBSP() exists. */
+extern unsigned long _Unwind_GetBSP (struct _Unwind_Context *);
+
+/* Return the "canonical frame address" for the given context.
+ This is used by NPTL... */
+extern unsigned long _Unwind_GetCFA (struct _Unwind_Context *);
+
+/* Return the base-address for data references. */
+extern unsigned long _Unwind_GetDataRelBase (struct _Unwind_Context *);
+
+/* Return the base-address for text references. */
+extern unsigned long _Unwind_GetTextRelBase (struct _Unwind_Context *);
+
+/* Call _Unwind_Trace_Fn once for each stack-frame, without doing any
+ cleanup. The first frame for which the callback is invoked is the
+ one for the caller of _Unwind_Backtrace(). _Unwind_Backtrace()
+ returns _URC_END_OF_STACK when the backtrace stopped due to
+ reaching the end of the call-chain or _URC_FATAL_PHASE1_ERROR if it
+ stops for any other reason. */
+extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+
+/* Find the start-address of the procedure containing the specified IP
+ or NULL if it cannot be found (e.g., because the function has no
+ unwind info). Note: there is not necessarily a one-to-one
+ correspondence between source-level functions and procedures: some
+ functions don't have unwind-info and others are split into multiple
+ procedures. */
+extern void *_Unwind_FindEnclosingFunction (void *);
+
+/* See also Linux Standard Base Spec:
+ http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/libgcc-s.html */
+
+#endif /* _GNU_SOURCE */
+
+#define DECLARE_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(int version,\
+ _Unwind_Action actions,\
+ uint64_t exceptionClass,\
+ struct _Unwind_Exception *exceptionObject,\
+ struct _Unwind_Context *context);
+#define BEGIN_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(int version,\
+ _Unwind_Action actions,\
+ uint64_t exceptionClass,\
+ struct _Unwind_Exception *exceptionObject,\
+ struct _Unwind_Context *context)\
+{
+
+#define CALL_PERSONALITY_FUNCTION(name) name(version, actions, exceptionClass, exceptionObject, context)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNWIND_H */
diff --git a/contrib/libcxxrt/unwind.h b/contrib/libcxxrt/unwind.h
new file mode 100644
index 0000000..5089491
--- /dev/null
+++ b/contrib/libcxxrt/unwind.h
@@ -0,0 +1,18 @@
+#ifndef UNWIND_H_INCLUDED
+#define UNWIND_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __arm__
+#include "unwind-arm.h"
+#else
+#include "unwind-itanium.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
OpenPOWER on IntegriCloud