diff options
author | Alon Zakai <alonzakai@gmail.com> | 2012-02-22 11:23:32 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2012-02-22 11:23:32 -0800 |
commit | dd979ed995ce4a82b505fba2f29a8f32dc900bdd (patch) | |
tree | a6f11f4ad5d17bfcfbcc53b0f477b60e7dff2dd7 | |
parent | f53e69d92372020949c5ac0ca8f5ffdc67fb42fb (diff) |
bundle libcxxabi
29 files changed, 16123 insertions, 0 deletions
diff --git a/system/lib/libcxxabi/CREDITS.TXT b/system/lib/libcxxabi/CREDITS.TXT new file mode 100644 index 00000000..a99245f7 --- /dev/null +++ b/system/lib/libcxxabi/CREDITS.TXT @@ -0,0 +1,22 @@ +This file is a partial list of people who have contributed to the LLVM/libc++abi +project. If you have contributed a patch or made some other contribution to +LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be +done! + +The list is sorted by surname and formatted to allow easy grepping and +beautification by scripts. The fields are: name (N), email (E), web-address +(W), PGP key ID and fingerprint (P), description (D), and snail-mail address +(S). + +N: Howard Hinnant +E: hhinnant@apple.com +D: Architect and primary coauthor of libc++abi + +N: Marshall Clow +E: marshall@idio.com +E: mclow.lists@gmail.com +E: mclow@qualcomm.com +D: Architect and primary coauthor of libc++abi + +N: Nick Kledzik +E: kledzik@apple.com diff --git a/system/lib/libcxxabi/LICENSE.TXT b/system/lib/libcxxabi/LICENSE.TXT new file mode 100644 index 00000000..40ce7c7d --- /dev/null +++ b/system/lib/libcxxabi/LICENSE.TXT @@ -0,0 +1,76 @@ +============================================================================== +libc++abi License +============================================================================== + +The libc++abi library is dual licensed under both the University of Illinois +"BSD-Like" license and the MIT license. As a user of this code you may choose +to use it under either license. As a contributor, you agree to allow your code +to be used under both. + +Full text of the relevant licenses is included below. + +============================================================================== + +University of Illinois/NCSA +Open Source License + +Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT + +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== + +Copyright (c) 2009-2010 by the contributors listed in CREDITS.TXT + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/system/lib/libcxxabi/Makefile b/system/lib/libcxxabi/Makefile new file mode 100644 index 00000000..86d88976 --- /dev/null +++ b/system/lib/libcxxabi/Makefile @@ -0,0 +1,27 @@ +OBJECTS = \ + cxa_vector.bc \ + private_typeinfo.bc \ + cxa_virtual.bc \ + temporary.bc \ + cxa_guard.bc \ + cxa_unexpected.bc \ + cxa_exception.bc \ + cxa_aux_runtime.bc \ + exception.bc \ + stdexcept.bc \ + abort_message.bc \ + cxa_personality.bc \ + cxa_new_delete.bc \ + cxa_handlers.bc \ + cxa_exception_storage.bc \ + typeinfo.bc \ + cxa_demangle.bc + +all: libcxx.bc + +%.bc: %.cpp + $(CXX) $< -o $@ + +libcxx.bc: $(OBJECTS) + $(CXX) $(OBJECTS) -o libcxxabi.bc + diff --git a/system/lib/libcxxabi/include/cxa_demangle.h b/system/lib/libcxxabi/include/cxa_demangle.h new file mode 100644 index 00000000..46dc9821 --- /dev/null +++ b/system/lib/libcxxabi/include/cxa_demangle.h @@ -0,0 +1,167 @@ +//===-------------------------- cxa_demangle.h ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _CXA_DEMANGLE_H +#define _CXA_DEMANGLE_H + +#include <cxxabi.h> + +#pragma GCC visibility push(hidden) + +namespace __cxxabiv1 +{ + +namespace __libcxxabi +{ + +class __demangle_tree; +class __node; + +char* +__demangle(__demangle_tree, char*, size_t*, int*); + +struct __demangle_tree_rv +{ + __demangle_tree* ptr_; + + explicit __demangle_tree_rv(__demangle_tree* ptr) + : ptr_(ptr) {} +}; + +class __demangle_tree +{ + const char* __mangled_name_begin_; + const char* __mangled_name_end_; + int __status_; + __node* __root_; + __node* __node_begin_; + __node* __node_end_; + __node* __node_cap_; + __node** __sub_begin_; + __node** __sub_end_; + __node** __sub_cap_; + __node** __t_begin_; + __node** __t_end_; + __node** __t_cap_; + bool __tag_templates_; + bool __fix_forward_references_; + bool __owns_buf_; + + __demangle_tree& operator=(const __demangle_tree&); +public: + __demangle_tree(const char*, char*, size_t); + ~__demangle_tree(); + + __demangle_tree(__demangle_tree&); + __demangle_tree(__demangle_tree_rv); + operator __demangle_tree_rv() {return __demangle_tree_rv(this);} + + int __status() const; + size_t size() const; + char* __get_demangled_name(char*) const; + + void __parse(); + +private: + const char* __parse_encoding(const char*, const char*); + const char* __parse_type(const char*, const char*, + bool = true, bool = false); + const char* __parse_special_name(const char*, const char*); + const char* __parse_name(const char*, const char*); + const char* __parse_bare_function_type(const char*, const char*); + const char* __parse_call_offset(const char*, const char*); + const char* __parse_number(const char*, const char*); + const char* __parse_cv_qualifiers(const char* first, const char* last, + unsigned& cv, bool = false); + const char* __parse_nested_name(const char*, const char*); + const char* __parse_discriminator(const char*, const char*); + const char* __parse_local_name(const char*, const char*); + const char* __parse_unscoped_template_name(const char*, const char*); + const char* __parse_unscoped_name(const char*, const char*); + const char* __parse_operator_name(const char*, const char*, int* = 0); + const char* __parse_unqualified_name(const char*, const char*); + const char* __parse_source_name(const char*, const char*); + const char* __parse_ctor_dtor_name(const char*, const char*); + const char* __parse_unnamed_type_name(const char*, const char*); + const char* __parse_template_args(const char*, const char*); + const char* __parse_template_arg(const char*, const char*); + const char* __parse_expression(const char*, const char*); + const char* __parse_expr_primary(const char*, const char*); + const char* __parse_substitution(const char*, const char*); + const char* __parse_builtin_type(const char*, const char*); + const char* __parse_function_type(const char*, const char*); + const char* __parse_class_enum_type(const char*, const char*); + const char* __parse_array_type(const char*, const char*); + const char* __parse_pointer_to_member_type(const char*, const char*); + const char* __parse_decltype(const char*, const char*); + const char* __parse_template_param(const char*, const char*); + const char* __parse_unresolved_name(const char*, const char*); + const char* __parse_unresolved_type(const char*, const char*); + const char* __parse_base_unresolved_name(const char*, const char*); + const char* __parse_simple_id(const char*, const char*); + const char* __parse_destructor_name(const char*, const char*); + const char* __parse_function_param(const char*, const char*); + const char* __parse_const_cast_expr(const char*, const char*); + const char* __parse_alignof_expr(const char*, const char*); + const char* __parse_call_expr(const char*, const char*); + const char* __parse_conversion_expr(const char*, const char*); + const char* __parse_delete_array_expr(const char*, const char*); + const char* __parse_delete_expr(const char*, const char*); + const char* __parse_dynamic_cast_expr(const char*, const char*); + const char* __parse_dot_star_expr(const char*, const char*); + const char* __parse_dot_expr(const char*, const char*); + const char* __parse_decrement_expr(const char*, const char*); + const char* __parse_new_expr(const char*, const char*); + const char* __parse_increment_expr(const char*, const char*); + const char* __parse_arrow_expr(const char*, const char*); + const char* __parse_reinterpret_cast_expr(const char*, const char*); + const char* __parse_static_cast_expr(const char*, const char*); + const char* __parse_sizeof_type_expr(const char*, const char*); + const char* __parse_sizeof_param_pack_expr(const char*, const char*); + const char* __parse_typeid_expr(const char*, const char*); + const char* __parse_throw_expr(const char*, const char*); + const char* __parse_pack_expansion(const char*, const char*); + const char* __parse_sizeof_function_param_pack_expr(const char*, const char*); + const char* __parse_dot_suffix(const char*, const char*); + const char* __parse_unresolved_qualifier_level(const char*, const char*); + const char* __parse_vector_type(const char*, const char*); + const char* __parse_hex_number(const char*, const char*, unsigned long long&); + + template <class _Tp> bool __make(); + template <class _Tp, class _A0> bool __make(_A0 __a0); + template <class _Tp, class _A0, class _A1> bool __make(_A0 __a0, _A1 __a1); + template <class _Tp, class _A0, class _A1, class _A2> + bool __make(_A0 __a0, _A1 __a1, _A2 __a2); + template <class _Tp, class _A0, class _A1, class _A2, class _A3> + bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3); + template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4> + bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4); + template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4, + class _A5> + bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, _A5 __a5); + + friend + char* + __demangle(__demangle_tree, char*, size_t*, int*); + +}; + +__demangle_tree +__demangle(const char*); + +__demangle_tree +__demangle(const char*, char*, size_t); + +} // __libcxxabi +} // __cxxabiv1 + +#pragma GCC visibility pop + + +#endif // _CXA_DEMANGLE_H diff --git a/system/lib/libcxxabi/include/cxxabi.h b/system/lib/libcxxabi/include/cxxabi.h new file mode 100644 index 00000000..b08fba0e --- /dev/null +++ b/system/lib/libcxxabi/include/cxxabi.h @@ -0,0 +1,175 @@ +//===--------------------------- cxxabi.h ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __CXXABI_H +#define __CXXABI_H + +/* + * This header provides the interface to the C++ ABI as defined at: + * http://www.codesourcery.com/cxx-abi/ + */ + +#include <stddef.h> +#include <stdint.h> + +#define _LIBCPPABI_VERSION 1001 +#define LIBCXXABI_NORETURN __attribute__((noreturn)) + +#ifdef __cplusplus + +namespace std { + class type_info; // forward declaration +} + + +// runtime routines use C calling conventions, but are in __cxxabiv1 namespace +namespace __cxxabiv1 { + extern "C" { + +// 2.4.2 Allocating the Exception Object +extern void * __cxa_allocate_exception(size_t thrown_size) throw(); +extern void __cxa_free_exception(void * thrown_exception) throw(); + +// 2.4.3 Throwing the Exception Object +extern LIBCXXABI_NORETURN void __cxa_throw(void * thrown_exception, + std::type_info * tinfo, void (*dest)(void *)); + +// 2.5.3 Exception Handlers +extern void * __cxa_get_exception_ptr(void * exceptionObject) throw(); +extern void * __cxa_begin_catch(void * exceptionObject) throw(); +extern void __cxa_end_catch(); +extern std::type_info * __cxa_current_exception_type(); + +// 2.5.4 Rethrowing Exceptions +extern LIBCXXABI_NORETURN void __cxa_rethrow(); + + + +// 2.6 Auxiliary Runtime APIs +extern LIBCXXABI_NORETURN void __cxa_bad_cast(void); +extern LIBCXXABI_NORETURN void __cxa_bad_typeid(void); + + + +// 3.2.6 Pure Virtual Function API +extern LIBCXXABI_NORETURN void __cxa_pure_virtual(void); + +// 3.2.7 Deleted Virtual Function API +extern LIBCXXABI_NORETURN void __cxa_deleted_virtual(void); + +// 3.3.2 One-time Construction API +#ifdef LIBCXXABI_ARMEABI +extern int __cxa_guard_acquire(uint32_t*); +extern void __cxa_guard_release(uint32_t*); +extern void __cxa_guard_abort(uint32_t*); +#else +extern int __cxa_guard_acquire(uint64_t*); +extern void __cxa_guard_release(uint64_t*); +extern void __cxa_guard_abort(uint64_t*); +#endif + +// 3.3.3 Array Construction and Destruction API +extern void* __cxa_vec_new(size_t element_count, + size_t element_size, + size_t padding_size, + void (*constructor)(void*), + void (*destructor)(void*) ); + +extern void* __cxa_vec_new2(size_t element_count, + size_t element_size, + size_t padding_size, + void (*constructor)(void*), + void (*destructor)(void*), + void* (*alloc)(size_t), + void (*dealloc)(void*) ); + +extern void* __cxa_vec_new3(size_t element_count, + size_t element_size, + size_t padding_size, + void (*constructor)(void*), + void (*destructor)(void*), + void* (*alloc)(size_t), + void (*dealloc)(void*, size_t) ); + +extern void __cxa_vec_ctor(void* array_address, + size_t element_count, + size_t element_size, + void (*constructor)(void*), + void (*destructor)(void*) ); + + +extern void __cxa_vec_dtor(void* array_address, + size_t element_count, + size_t element_size, + void (*destructor)(void*) ); + + +extern void __cxa_vec_cleanup(void* array_address, + size_t element_count, + size_t element_size, + void (*destructor)(void*) ); + + +extern void __cxa_vec_delete(void* array_address, + size_t element_size, + size_t padding_size, + void (*destructor)(void*) ); + + +extern void __cxa_vec_delete2(void* array_address, + size_t element_size, + size_t padding_size, + void (*destructor)(void*), + void (*dealloc)(void*) ); + + +extern void __cxa_vec_delete3(void* __array_address, + size_t element_size, + size_t padding_size, + void (*destructor)(void*), + void (*dealloc) (void*, size_t)); + + +extern void __cxa_vec_cctor(void* dest_array, + void* src_array, + size_t element_count, + size_t element_size, + void (*constructor) (void*, void*), + void (*destructor)(void*) ); + + +// 3.3.5.3 Runtime API +extern int __cxa_atexit(void (*f)(void*), void* p, void* d); +extern int __cxa_finalize(void*); + + +// 3.4 Demangler API +extern char* __cxa_demangle(const char* mangled_name, + char* output_buffer, + size_t* length, + int* status); + +// Apple additions to support C++ 0x exception_ptr class +// These are primitives to wrap a smart pointer around an exception object +extern void * __cxa_current_primary_exception() throw(); +extern void __cxa_rethrow_primary_exception(void* primary_exception); +extern void __cxa_increment_exception_refcount(void* primary_exception) throw(); +extern void __cxa_decrement_exception_refcount(void* primary_exception) throw(); + +// Apple addition to support std::uncaught_exception() +extern bool __cxa_uncaught_exception() throw(); + + } // extern "C" +} // namespace __cxxabiv1 + +#endif // __cplusplus + +namespace abi = __cxxabiv1; + +#endif // __CXXABI_H diff --git a/system/lib/libcxxabi/lib/buildit b/system/lib/libcxxabi/lib/buildit new file mode 100755 index 00000000..d1d2acda --- /dev/null +++ b/system/lib/libcxxabi/lib/buildit @@ -0,0 +1,90 @@ +#! /bin/sh +# +# Set the $TRIPLE environment variable to your system's triple before +# running this script. If you set $CXX, that will be used to compile +# the library. Otherwise we'll use clang++. + +set -e + +if [ `basename $(pwd)` != "lib" ] +then + echo "current directory must be lib" + exit 1 +fi + +if [ -z "$CXX" ] +then + CXX=clang++ +fi + +if [ -z "$CC" ] +then + CC=clang +fi + +if [ -z $RC_ProjectSourceVersion ] +then + RC_ProjectSourceVersion=1 +fi + +EXTRA_FLAGS="-std=c++0x -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 -Wnewline-eof" + +case $TRIPLE in + *-apple-*) + if [ -z $RC_XBS ] + then + RC_CFLAGS="-arch i386 -arch x86_64" + fi + SOEXT=dylib + if [ -n "$SDKROOT" ] + then + EXTRA_FLAGS+="-isysroot ${SDKROOT}" + CXX=`xcrun -sdk "${SDKROOT}" -find clang++` + CC=`xcrun -sdk "${SDKROOT}" -find clang` + fi + LDSHARED_FLAGS="-o libc++abi.dylib \ + -dynamiclib -nodefaultlibs \ + -current_version ${RC_ProjectSourceVersion} \ + -compatibility_version 1 \ + -install_name /usr/lib/libc++abi.dylib \ + -lSystem" + ;; + *-*-mingw*) + # FIXME: removing libgcc and libsupc++ dependencies means porting libcxxrt and LLVM/compiler-rt + SOEXT=dll + LDSHARED_FLAGS="-o libc++abi.dll \ + -shared -nodefaultlibs -Wl,--export-all-symbols -Wl,--allow-multiple-definition -Wl,--out-implib,libc++abi.dll.a \ + -lsupc++ -lpthread -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcr100 -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt" + ;; + *) + RC_CFLAGS="-fPIC" + SOEXT=so + LDSHARED_FLAGS="-o libc++abi.so.1.0 \ + -shared -nodefaultlibs -Wl,-soname,libc++abi.so.1 \ + -lpthread -lrt -lc -lstdc++" + ;; +esac + +if [ -z $RC_XBS ] +then + rm -f libc++abi.1.$SOEXT* +fi + +set -x + +for FILE in ../src/*.cpp; do + $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE +done +case $TRIPLE in + *-*-mingw*) + for FILE in ../src/support/win32/*.cpp; do + $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE + done + ;; +esac +$CC *.o $RC_CFLAGS $LDSHARED_FLAGS $EXTRA_FLAGS + +if [ -z $RC_XBS ] +then + rm *.o +fi diff --git a/system/lib/libcxxabi/readme.txt b/system/lib/libcxxabi/readme.txt new file mode 100644 index 00000000..0be9a318 --- /dev/null +++ b/system/lib/libcxxabi/readme.txt @@ -0,0 +1 @@ +These files are from libcxxabi, svn revision 151132, Feb 22 2012 diff --git a/system/lib/libcxxabi/src/abort_message.cpp b/system/lib/libcxxabi/src/abort_message.cpp new file mode 100644 index 00000000..7beb86b5 --- /dev/null +++ b/system/lib/libcxxabi/src/abort_message.cpp @@ -0,0 +1,60 @@ +//===------------------------- abort_message.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include "abort_message.h" + +#pragma GCC visibility push(hidden) + +#if __APPLE__ +# if defined(__has_include) && __has_include(<CrashReporterClient.h>) +# define HAVE_CRASHREPORTERCLIENT_H 1 +# include <CrashReporterClient.h> + + // If any clients of llvm try to link to libCrashReporterClient.a themselves, + // only one crash info struct will be used. + extern "C" { + CRASH_REPORTER_CLIENT_HIDDEN + struct crashreporter_annotations_t gCRAnnotations + __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) + = { CRASHREPORTER_ANNOTATIONS_VERSION, 0, 0, 0, 0, 0, 0 }; + } + +# endif +#endif + +__attribute__((visibility("hidden"), noreturn)) +void abort_message(const char* format, ...) +{ + // write message to stderr +#if __APPLE__ + fprintf(stderr, "libc++abi.dylib: "); +#endif + va_list list; + va_start(list, format); + vfprintf(stderr, format, list); + va_end(list); + fprintf(stderr, "\n"); + +#if __APPLE__ && HAVE_CRASHREPORTERCLIENT_H + // record message in crash report + char* buffer; + va_list list2; + va_start(list2, format); + vasprintf(&buffer, format, list2); + va_end(list2); + CRSetCrashLogMessage(buffer); +#endif + + abort(); +} + +#pragma GCC visibility pop diff --git a/system/lib/libcxxabi/src/abort_message.h b/system/lib/libcxxabi/src/abort_message.h new file mode 100644 index 00000000..2c5cb204 --- /dev/null +++ b/system/lib/libcxxabi/src/abort_message.h @@ -0,0 +1,33 @@ +//===-------------------------- abort_message.h-----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __ABORT_MESSAGE_H_ +#define __ABORT_MESSAGE_H_ + +#include <stdio.h> + +#pragma GCC visibility push(hidden) + +#ifdef __cplusplus +extern "C" { +#endif + +__attribute__((visibility("hidden"), noreturn)) + void abort_message(const char* format, ...) + __attribute__((format(printf, 1, 2))); + + +#ifdef __cplusplus +} +#endif + +#pragma GCC visibility pop + +#endif + diff --git a/system/lib/libcxxabi/src/cxa_aux_runtime.cpp b/system/lib/libcxxabi/src/cxa_aux_runtime.cpp new file mode 100644 index 00000000..abd8091c --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_aux_runtime.cpp @@ -0,0 +1,34 @@ +//===------------------------ cxa_aux_runtime.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Auxiliary Runtime APIs" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html#cxx-aux +//===----------------------------------------------------------------------===// + +#include "cxxabi.h" +#include <typeinfo> + +namespace __cxxabiv1 +{ + +extern "C" +{ + +LIBCXXABI_NORETURN +void __cxa_bad_cast (void) { + throw std::bad_cast(); +} + +LIBCXXABI_NORETURN +void __cxa_bad_typeid(void) { + throw std::bad_typeid(); +} + +} // extern "C" + +} // abi diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp new file mode 100644 index 00000000..1135c99b --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_demangle.cpp @@ -0,0 +1,10798 @@ +//===-------------------------- cxa_demangle.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "cxa_demangle.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <new> +#include <algorithm> +#include <assert.h> + + +#ifdef DEBUGGING + +#include <string> +#include <typeinfo> + +#endif + +namespace __cxxabiv1 +{ + +namespace __libcxxabi +{ + +#pragma GCC visibility push(hidden) + +class __node +{ + __node(const __node&); + __node& operator=(const __node&); +public: + const char* __name_; + size_t __size_; + __node* __left_; + __node* __right_; + long double __value_; + long __cached_size_; +public: + __node() + : __name_(0), __size_(0), __left_(0), __right_(0), __cached_size_(-1) + {} + virtual ~__node() {}; + + void reset_cached_size() + { + __cached_size_ = -1; + if (__left_) + __left_->reset_cached_size(); + if (__right_) + __right_->reset_cached_size(); + } + + virtual size_t first_size() const {return 0;} + virtual size_t second_size() const {return 0;} + virtual size_t size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = first_size() + second_size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const {return buf;} + virtual char* second_demangled_name(char* buf) const {return buf;} + virtual char* get_demangled_name(char* buf) const + { + return second_demangled_name(first_demangled_name(buf)); + } + virtual size_t base_size() const {return size();} + virtual char* get_base_name(char* buf) const + { + return get_demangled_name(buf); + } + + virtual bool ends_with_template(bool parsing = false) const + { + return false; + } + virtual bool is_ctor_dtor_conv() const + { + return false; + } + virtual __node* base_name() const + { + return const_cast<__node*>(this); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return false; + } + virtual bool is_function() const + { + return false; + } + virtual bool is_cv_qualifer() const + { + return false; + } + virtual bool is_array() const + { + return false; + } + + virtual bool fix_forward_references(__node**, __node**) + { + return true; + } + virtual __node* extract_cv(__node*&) const + { + return 0; + } + virtual size_t list_len() const + { + return 0; + } + virtual bool is_sub() const + { + return false; + } +}; + +#ifdef DEBUGGING + +void display(__node* x, int indent = 0) +{ + if (x) + { + for (int i = 0; i < 2*indent; ++i) + printf(" "); + std::string buf(x->size(), '\0'); + x->get_demangled_name(&buf.front()); + printf("%s %s, %p\n", typeid(*x).name(), buf.c_str(), x); + display(x->__left_, indent+1); + display(x->__right_, indent+1); + } +} + +#endif + +class __vtable + : public __node +{ + static const ptrdiff_t n = sizeof("vtable for ") - 1; +public: + __vtable(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "vtable for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __VTT + : public __node +{ + static const ptrdiff_t n = sizeof("VTT for ") - 1; +public: + __VTT(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "VTT for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __construction_vtable + : public __node +{ + static const ptrdiff_t n = sizeof("construction vtable for ") - 1 + 4; +public: + __construction_vtable(__node* left, __node* right) + { + __left_ = left; + __right_ = right; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __left_->size() + + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "construction vtable for ", n-4); + buf = __left_->get_demangled_name(buf+n-4); + *buf++ = '-'; + *buf++ = 'i'; + *buf++ = 'n'; + *buf++ = '-'; + return __right_->get_demangled_name(buf); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = __left_->fix_forward_references(t_begin, t_end); + return r && __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __typeinfo + : public __node +{ + static const ptrdiff_t n = sizeof("typeinfo for ") - 1; +public: + __typeinfo(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "typeinfo for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __typeinfo_name + : public __node +{ + static const ptrdiff_t n = sizeof("typeinfo name for ") - 1; +public: + __typeinfo_name(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "typeinfo name for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __covariant_return_thunk + : public __node +{ + static const ptrdiff_t n = sizeof("covariant return thunk to ") - 1; +public: + __covariant_return_thunk(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "covariant return thunk to ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __virtual_thunk + : public __node +{ + static const size_t n = sizeof("virtual thunk to ") - 1; +public: + __virtual_thunk(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "virtual thunk to ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __non_virtual_thunk + : public __node +{ + static const size_t n = sizeof("non-virtual thunk to ") - 1; +public: + __non_virtual_thunk(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "non-virtual thunk to ", n); + return __right_->get_demangled_name(buf+n); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __guard_variable + : public __node +{ + static const size_t n = sizeof("guard variable for ") - 1; +public: + __guard_variable(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "guard variable for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __reference_temporary + : public __node +{ + static const size_t n = sizeof("reference temporary for ") - 1; +public: + __reference_temporary(__node* type) + { + __right_ = type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "reference temporary for ", n); + return __right_->get_demangled_name(buf+n); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __source_name + : public __node +{ +public: + __source_name(const char* __name, unsigned __size) + { + __name_ = __name; + __size_ = __size; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0) + const_cast<long&>(__cached_size_) = 21; + else + const_cast<long&>(__cached_size_) = __size_; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0) + return strncpy(buf, "(anonymous namespace)", 21) + 21; + return strncpy(buf, __name_, __size_) + __size_; + } +}; + +class __operator_new + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator new") - 1;} + virtual char* first_demangled_name(char* buf) const + { + return strncpy(buf, "operator new", sizeof("operator new") - 1) + + sizeof("operator new") - 1; + } +}; + +class __operator_new_array + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator new[]") - 1;} + virtual char* first_demangled_name(char* buf) const + { + return strncpy(buf, "operator new[]", sizeof("operator new[]") - 1) + + sizeof("operator new[]") - 1; + } +}; + +class __operator_delete + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator delete") - 1;} + virtual char* first_demangled_name(char* buf) const + { + return strncpy(buf, "operator delete", sizeof("operator delete") - 1) + + sizeof("operator delete") - 1; + } +}; + +class __operator_delete_array + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator delete[]") - 1;} + virtual char* first_demangled_name(char* buf) const + { + return strncpy(buf, "operator delete[]", sizeof("operator delete[]") - 1) + + sizeof("operator delete[]") - 1; + } +}; + +class __operator_logical_and + : public __node +{ +public: + + __operator_logical_and() {} + __operator_logical_and(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator&&") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") && (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator&&", sizeof("operator&&") - 1); + buf += sizeof("operator&&") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_addressof + : public __node +{ +public: + + __operator_addressof() {} + explicit __operator_addressof(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator&") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '&'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator&", sizeof("operator&") - 1); + buf += sizeof("operator&") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_bit_and + : public __node +{ +public: + + __operator_bit_and() {} + __operator_bit_and(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator&") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") & (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator&", sizeof("operator&") - 1); + buf += sizeof("operator&") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_and_equal + : public __node +{ +public: + + __operator_and_equal() {} + __operator_and_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator&=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") &= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator&=", sizeof("operator&=") - 1); + buf += sizeof("operator&=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_equal + : public __node +{ +public: + + __operator_equal() {} + __operator_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") = (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator=", sizeof("operator=") - 1); + buf += sizeof("operator=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_alignof_type + : public __node +{ +public: + + __operator_alignof_type() {} + __operator_alignof_type(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__right_) + const_cast<long&>(__cached_size_) = __right_->size() + 10; + else + const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__right_) + { + strncpy(buf, "alignof (", 9); + buf += 9; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); + buf += sizeof("operator alignof") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__right_) + return __right_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_alignof_expression + : public __node +{ +public: + + __operator_alignof_expression() {} + __operator_alignof_expression(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__right_) + const_cast<long&>(__cached_size_) = __right_->size() + 10; + else + const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__right_) + { + strncpy(buf, "alignof (", 9); + buf += 9; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); + buf += sizeof("operator alignof") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__right_) + return __right_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_paren + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator()") - 1;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "operator()", sizeof("operator()") - 1); + return buf + sizeof("operator()") - 1; + } +}; + +class __operator_comma + : public __node +{ +public: + + __operator_comma() {} + __operator_comma(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator,") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") , (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator,", sizeof("operator,") - 1); + buf += sizeof("operator,") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_tilda + : public __node +{ +public: + + __operator_tilda() {} + explicit __operator_tilda(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator~") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '~'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator~", sizeof("operator~") - 1); + buf += sizeof("operator~") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_cast + : public __node +{ + static const size_t n = sizeof("operator ") - 1; +public: + + explicit __operator_cast(__node* type) + { + __right_ = type; + } + __operator_cast(__node* type, __node* arg) + { + __size_ = 1; + __right_ = type; + __left_ = arg; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off; + if (__size_) + { + off = 4; + off += __right_->size(); + if (__left_) + off += __left_->size(); + } + else + off = n + __right_->size();; + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + *buf++ = '('; + if (__left_) + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator ", n); + buf = __right_->get_demangled_name(buf+n); + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } + virtual bool is_ctor_dtor_conv() const + { + return true; + } +}; + +class __cast_literal + : public __node +{ +public: + + __cast_literal(__node* type, const char* f, const char* l) + { + __left_ = type; + __name_ = f; + __size_ = l - f; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = 2 + __left_->size() + __size_; + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + strncpy(buf, __name_, __size_); + return buf + __size_; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } +}; + +class __operator_dereference + : public __node +{ +public: + + __operator_dereference() {} + explicit __operator_dereference(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator*") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '*'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator*", sizeof("operator*") - 1); + buf += sizeof("operator*") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_divide + : public __node +{ +public: + + __operator_divide() {} + __operator_divide(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator/") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") / (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator/", sizeof("operator/") - 1); + buf += sizeof("operator/") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_divide_equal + : public __node +{ +public: + + __operator_divide_equal() {} + __operator_divide_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator/=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") /= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator/=", sizeof("operator/=") - 1); + buf += sizeof("operator/=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_xor + : public __node +{ +public: + + __operator_xor() {} + __operator_xor(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator^") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") ^ (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator^", sizeof("operator^") - 1); + buf += sizeof("operator^") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_xor_equal + : public __node +{ +public: + + __operator_xor_equal() {} + __operator_xor_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator^=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; // strncpy(buf, "(", 1); + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") ^= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator^=", sizeof("operator^=") - 1); + buf += sizeof("operator^=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_equality + : public __node +{ +public: + + __operator_equality() {} + __operator_equality(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator==") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") == (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator==", sizeof("operator==") - 1); + buf += sizeof("operator==") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_greater_equal + : public __node +{ +public: + + __operator_greater_equal() {} + __operator_greater_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator>=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") >= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator>=", sizeof("operator>=") - 1); + buf += sizeof("operator>=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_greater + : public __node +{ +public: + + __operator_greater() {} + __operator_greater(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator>") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") > (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + *buf++ = ')'; + } + else + { + strncpy(buf, "operator>", sizeof("operator>") - 1); + buf += sizeof("operator>") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_brackets + : public __node +{ +public: + + virtual size_t first_size() const {return sizeof("operator[]") - 1;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "operator[]", sizeof("operator[]") - 1); + return buf + sizeof("operator[]") - 1; + } +}; + +class __operator_less_equal + : public __node +{ +public: + + __operator_less_equal() {} + __operator_less_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator<=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") <= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator<=", sizeof("operator<=") - 1); + buf += sizeof("operator<=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_less + : public __node +{ +public: + + __operator_less() {} + __operator_less(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator<") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") < (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator<", sizeof("operator<") - 1); + buf += sizeof("operator<") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_left_shift + : public __node +{ +public: + + __operator_left_shift() {} + __operator_left_shift(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator<<") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") << (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator<<", sizeof("operator<<") - 1); + buf += sizeof("operator<<") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_left_shift_equal + : public __node +{ +public: + + __operator_left_shift_equal() {} + __operator_left_shift_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator<<=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") <<= (", 7); + buf += 7; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator<<=", sizeof("operator<<=") - 1); + buf += sizeof("operator<<=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_minus + : public __node +{ +public: + + __operator_minus() {} + __operator_minus(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator-") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") - (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator-", sizeof("operator-") - 1); + buf += sizeof("operator-") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_minus_equal + : public __node +{ +public: + + __operator_minus_equal() {} + __operator_minus_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator-=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") -= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator-=", sizeof("operator-=") - 1); + buf += sizeof("operator-=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_times + : public __node +{ +public: + + __operator_times() {} + __operator_times(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator*") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") * (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator*", sizeof("operator*") - 1); + buf += sizeof("operator*") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_times_equal + : public __node +{ +public: + + __operator_times_equal() {} + __operator_times_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator*=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") *= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator*=", sizeof("operator*=") - 1); + buf += sizeof("operator*=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_decrement + : public __node +{ +public: + + __operator_decrement() {} + explicit __operator_decrement(bool prefix, __node* op) + { + __size_ = prefix; + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 4+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator--") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + if (__size_) + { + *buf++ = '-'; + *buf++ = '-'; + *buf++ = '('; + } + else + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + if (__size_) + *buf++ = ')'; + else + { + *buf++ = ')'; + *buf++ = '-'; + *buf++ = '-'; + } + } + else + { + strncpy(buf, "operator--", sizeof("operator--") - 1); + buf += sizeof("operator--") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_not_equal + : public __node +{ +public: + + __operator_not_equal() {} + __operator_not_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator!=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") != (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator!=", sizeof("operator!=") - 1); + buf += sizeof("operator!=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_negate + : public __node +{ +public: + + __operator_negate() {} + explicit __operator_negate(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator-") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '-'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator-", sizeof("operator-") - 1); + buf += sizeof("operator-") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_logical_not + : public __node +{ +public: + + __operator_logical_not() {} + explicit __operator_logical_not(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator!") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '!'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator!", sizeof("operator!") - 1); + buf += sizeof("operator!") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_logical_or + : public __node +{ +public: + + __operator_logical_or() {} + __operator_logical_or(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator||") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") || (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator||", sizeof("operator||") - 1); + buf += sizeof("operator||") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_bit_or + : public __node +{ +public: + + __operator_bit_or() {} + __operator_bit_or(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator|") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") | (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator|", sizeof("operator|") - 1); + buf += sizeof("operator|") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_or_equal + : public __node +{ +public: + + __operator_or_equal() {} + __operator_or_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator|=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") |= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator|=", sizeof("operator|=") - 1); + buf += sizeof("operator|=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_pointer_to_member + : public __node +{ +public: + + __operator_pointer_to_member() {} + __operator_pointer_to_member(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator->*") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") ->* (", 7); + buf += 7; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator->*", sizeof("operator->*") - 1); + buf += sizeof("operator->*") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_plus + : public __node +{ +public: + + __operator_plus() {} + __operator_plus(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator+") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") + (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator+", sizeof("operator+") - 1); + buf += sizeof("operator+") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_plus_equal + : public __node +{ +public: + + __operator_plus_equal() {} + __operator_plus_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator+=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") += (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator+=", sizeof("operator+=") - 1); + buf += sizeof("operator+=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_increment + : public __node +{ +public: + + __operator_increment() {} + explicit __operator_increment(bool prefix, __node* op) + { + __size_ = prefix; + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 4+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator++") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + if (__size_) + { + *buf++ = '+'; + *buf++ = '+'; + *buf++ = '('; + } + else + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + if (__size_) + *buf++ = ')'; + else + { + *buf++ = ')'; + *buf++ = '+'; + *buf++ = '+'; + } + } + else + { + strncpy(buf, "operator++", sizeof("operator++") - 1); + buf += sizeof("operator++") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_unary_plus + : public __node +{ +public: + + __operator_unary_plus() {} + explicit __operator_unary_plus(__node* op) + { + __left_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = 3+__left_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator+") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '+'; + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator+", sizeof("operator+") - 1); + buf += sizeof("operator+") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_) + return __left_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_arrow + : public __node +{ +public: + + __operator_arrow() {} + __operator_arrow(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator->") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") -> (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator->", sizeof("operator->") - 1); + buf += sizeof("operator->") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_conditional + : public __node +{ +public: + + __operator_conditional() {} + __operator_conditional(__node* op1, __node* op2, __node* op3) + { + __name_ = (const char*)op1; + __left_ = op2; + __right_ = op3; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + { + __node* op1 = (__node*)__name_; + const_cast<long&>(__cached_size_) = op1->size() + __left_->size() + 12 + __right_->size(); + } + else + const_cast<long&>(__cached_size_) = sizeof("operator?") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + __node* op1 = (__node*)__name_; + *buf++ = '('; + buf = op1->get_demangled_name(buf); + strncpy(buf, ") ? (", 5); + buf += 5; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") : (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator?", sizeof("operator?") - 1); + buf += sizeof("operator?") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__name_) + r = r && ((__node*)__name_)->fix_forward_references(t_begin, t_end); + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_mod + : public __node +{ +public: + + __operator_mod() {} + __operator_mod(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 7 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator%") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") % (", 5); + buf += 5; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator%", sizeof("operator%") - 1); + buf += sizeof("operator%") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_mod_equal + : public __node +{ +public: + + __operator_mod_equal() {} + __operator_mod_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator%=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") %= (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator%=", sizeof("operator%=") - 1); + buf += sizeof("operator%=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_right_shift + : public __node +{ +public: + + __operator_right_shift() {} + __operator_right_shift(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 8 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator>>") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") >> (", 6); + buf += 6; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator>>", sizeof("operator>>") - 1); + buf += sizeof("operator>>") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_right_shift_equal + : public __node +{ +public: + + __operator_right_shift_equal() {} + __operator_right_shift_equal(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_) + const_cast<long&>(__cached_size_) = __left_->size() + 9 + __right_->size(); + else + const_cast<long&>(__cached_size_) = sizeof("operator>>=") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + strncpy(buf, ") >>= (", 7); + buf += 7; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator>>=", sizeof("operator>>=") - 1); + buf += sizeof("operator>>=") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __operator_sizeof_type + : public __node +{ +public: + + __operator_sizeof_type() {} + __operator_sizeof_type(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__right_) + const_cast<long&>(__cached_size_) = __right_->size() + 9; + else + const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__right_) + { + strncpy(buf, "sizeof (", 8); + buf += 8; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1); + buf += sizeof("operator sizeof") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__right_) + return __right_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __operator_sizeof_expression + : public __node +{ +public: + + __operator_sizeof_expression() {} + __operator_sizeof_expression(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__right_) + const_cast<long&>(__cached_size_) = __right_->size() + 9; + else + const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__right_) + { + strncpy(buf, "sizeof (", 8); + buf += 8; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + else + { + strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1); + buf += sizeof("operator sizeof") - 1; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__right_) + return __right_->fix_forward_references(t_begin, t_end); + return true; + } +}; + +class __typeid + : public __node +{ +public: + + __typeid(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __right_->size() + 8; + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "typeid(", 7); + buf += 7; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __throw + : public __node +{ +public: + + __throw(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __right_->size() + 6; + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "throw ", 6); + return __right_->get_demangled_name(buf+6); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __rethrow + : public __node +{ + static const ptrdiff_t n = sizeof("throw") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "throw", n); + return buf+n; + } +}; + +class __operator_sizeof_param_pack + : public __node +{ +public: + + __operator_sizeof_param_pack(__node* op) + { + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __right_->size() + 11; + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "sizeof...(", 10); + buf += 10; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __const_cast + : public __node +{ +public: + + __const_cast(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 14 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "const_cast<", 11); + buf += 11; + buf = __left_->get_demangled_name(buf); + *buf++ = '>'; + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __dynamic_cast + : public __node +{ +public: + + __dynamic_cast(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 16 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "dynamic_cast<", 13); + buf += 13; + buf = __left_->get_demangled_name(buf); + *buf++ = '>'; + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __reinterpret_cast + : public __node +{ +public: + + __reinterpret_cast(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 20 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "reinterpret_cast<", 17); + buf += 17; + buf = __left_->get_demangled_name(buf); + *buf++ = '>'; + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __static_cast + : public __node +{ +public: + + __static_cast(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 15 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "static_cast<", 12); + buf += 12; + buf = __left_->get_demangled_name(buf); + *buf++ = '>'; + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __call_expr + : public __node +{ +public: + + __call_expr(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off = __left_->size() + 2; + if (__right_) + off += __right_->size(); + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = '('; + if (__right_) + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __delete_array_expr + : public __node +{ +public: + + __delete_array_expr(bool global, __node* op) + { + __size_ = global; + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = (__size_ ? 2 : 0) + 9 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + *buf++ = ':'; + *buf++ = ':'; + } + strncpy(buf, "delete[] ", 9); + return __right_->get_demangled_name(buf+9); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __delete_expr + : public __node +{ +public: + + __delete_expr(bool global, __node* op) + { + __size_ = global; + __right_ = op; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = (__size_ ? 2 : 0) + 7 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + *buf++ = ':'; + *buf++ = ':'; + } + strncpy(buf, "delete ", 7); + return __right_->get_demangled_name(buf+7); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __new_expr + : public __node +{ +public: + + __new_expr(bool global, bool is_array, bool has_init, + __node* expr, __node* type, __node* init) + { + __size_ = (unsigned)global | + ((unsigned)is_array << 1) | + ((unsigned)has_init << 2); + __left_ = expr; + __name_ = (const char*)type; + __right_ = init; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off = 4; + if (__size_ & 1) + off += 2; + if (__size_ & 2) + off += 2; + if (__left_) + { + off += 2; + off += __left_->size(); + } + __node* type = (__node*)__name_; + off += type->size(); + if (__size_ & 4) + { + off += 2; + if (__right_) + off += __right_->size(); + } + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_ & 1) + { + *buf++ = ':'; + *buf++ = ':'; + } + *buf++ = 'n'; + *buf++ = 'e'; + *buf++ = 'w'; + if (__size_ & 2) + { + *buf++ = '['; + *buf++ = ']'; + } + if (__left_) + { + *buf++ = '('; + buf = __left_->get_demangled_name(buf); + *buf++ = ')'; + } + *buf++ = ' '; + __node* type = (__node*)__name_; + buf = type->get_demangled_name(buf); + if (__size_ & 4) + { + *buf++ = '('; + if (__right_) + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + __node* type = (__node*)__name_; + bool r = type->fix_forward_references(t_begin, t_end); + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end);; + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end);; + return r; + } +}; + +class __dot_star_expr + : public __node +{ +public: + + __dot_star_expr(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 2 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = '.'; + *buf++ = '*'; + return __right_->get_demangled_name(buf); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __dot_expr + : public __node +{ +public: + + __dot_expr(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 1 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = '.'; + return __right_->get_demangled_name(buf); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __arrow_expr + : public __node +{ +public: + + __arrow_expr(__node* op1, __node* op2) + { + __left_ = op1; + __right_ = op2; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 2 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = '-'; + *buf++ = '>'; + return __right_->get_demangled_name(buf); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __std_qualified_name + : public __node +{ + static const ptrdiff_t n = sizeof("std") - 1; +public: + + __std_qualified_name() + { + } + virtual size_t first_size() const + { + return n; + } + + virtual char* first_demangled_name(char* buf) const + { + *buf++ = 's'; + *buf++ = 't'; + *buf++ = 'd'; + return buf; + } +}; + +class __sub_allocator + : public __node +{ + static const ptrdiff_t n = sizeof("std::allocator") - 1; +public: + + virtual size_t first_size() const + { + return n; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::allocator", n); + return buf + n; + } +}; + +class __sub_basic_string + : public __node +{ + static const ptrdiff_t n = sizeof("std::basic_string") - 1; +public: + + virtual size_t first_size() const + { + return n; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::basic_string", n); + return buf + n; + } +}; + +class __sub_string + : public __node +{ + static const size_t n = sizeof("std::string") - 1; + static const size_t ne = sizeof("std::basic_string<char, std::char_traits<char>, std::allocator<char> >") - 1; +public: + + virtual size_t first_size() const + { + if (__size_) + return ne; + return n; + } + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + strncpy(buf, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", ne); + buf += ne; + } + else + { + strncpy(buf, "std::string", n); + buf += n; + } + return buf; + } + + virtual size_t base_size() const + { + return 12; + } + virtual char* get_base_name(char* buf) const + { + strncpy(buf, "basic_string", 12); + return buf + 12; + } + + virtual __node* base_name() const + { + const_cast<size_t&>(__size_) = true; + return const_cast<__node*>(static_cast<const __node*>(this)); + } +}; + +class __sub_istream + : public __node +{ + static const ptrdiff_t n = sizeof("std::istream") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::istream", n); + return buf + n; + } +}; + +class __sub_ostream + : public __node +{ + static const ptrdiff_t n = sizeof("std::ostream") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::ostream", n); + return buf + n; + } +}; + +class __sub_iostream + : public __node +{ + static const ptrdiff_t n = sizeof("std::iostream") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::iostream", n); + return buf + n; + } +}; + +class __sub + : public __node +{ +public: + + explicit __sub(__node* arg) + { + __left_ = arg; + } + explicit __sub(size_t arg) + { + __size_ = arg; + } + virtual size_t first_size() const + { + return __left_->first_size(); + } + virtual char* first_demangled_name(char* buf) const + { + return __left_->first_demangled_name(buf); + } + virtual size_t second_size() const + { + return __left_->second_size(); + } + virtual char* second_demangled_name(char* buf) const + { + return __left_->second_demangled_name(buf); + } + virtual bool ends_with_template(bool parsing = false) const + { + return __left_->ends_with_template(parsing); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_reference_or_pointer_to_function_or_array(); + } + virtual bool is_function() const + { + return __left_->is_function(); + } + virtual bool is_cv_qualifer() const + { + return __left_->is_cv_qualifer(); + } + virtual bool is_ctor_dtor_conv() const + { + return __left_->is_ctor_dtor_conv(); + } + virtual bool is_array() const + { + return __left_->is_array(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + if (__left_ == 0) + { + if (__size_ < t_end - t_begin) + { + __left_ = t_begin[__size_]; + __size_ = 0; + } + else + return false; + } + return true; + } + virtual size_t list_len() const + { + return __left_->list_len(); + } + virtual bool is_sub() const + { + return true; + } +}; + +class __unscoped_template_name + : public __node +{ +public: + __unscoped_template_name(__node* name, __node* args) + {__left_ = name; __right_ = args;} + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + return __right_->get_demangled_name(buf); + } + virtual bool ends_with_template(bool parsing = false) const + { + return __right_->ends_with_template(parsing); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +// length == 0: __left_ == NULL +// length == 1: __left_ != NULL, __right_ == NULL +// length > 1: __left_ != NULL, __right_ != NULL +class __list + : public __node +{ +public: + explicit __list(__node* type) + {__left_ = type;} + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + if (__left_ == NULL) + const_cast<long&>(__cached_size_) = 0; + else if (__right_ == NULL) + const_cast<long&>(__cached_size_) = __left_->size(); + else + { + size_t off = __right_->size(); + if (off > 0) + off += 2; + const_cast<long&>(__cached_size_) = __left_->size() + off; + } + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_ != NULL) + { + char* t = __left_->get_demangled_name(buf + (__size_ ? 2 : 0)); + if (__size_ == 0) + buf = t; + else if (t != buf+2) + { + *buf++ = ','; + *buf++ = ' '; + buf = t; + } + if (__right_) + buf = __right_->get_demangled_name(buf); + } + return buf; + } + virtual bool ends_with_template(bool parsing = false) const + { + if (__right_ != NULL) + return __right_->ends_with_template(parsing); + if (__left_ != NULL) + return __left_->ends_with_template(parsing); + return false; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } + virtual size_t list_len() const + { + if (!__left_) + return 0; + if (!__right_) + return 1; + return 1 + __right_->list_len(); + } +}; + +class __template_args + : public __node +{ +public: + __template_args(__node* name, __node* list) + { + __left_ = name; + __right_ = list; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off = 2; + if (__right_) + { + if (__right_->ends_with_template()) + ++off; + off += __right_->size(); + } + const_cast<long&>(__cached_size_) = __left_->size() + off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = '<'; + if (__right_) + { + buf = __right_->get_demangled_name(buf); + if (buf[-1] == '>') + *buf++ = ' '; + } + *buf++ = '>'; + return buf; + } + virtual bool ends_with_template(bool parsing = false) const + { + return true; + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_ctor_dtor_conv() const + { + return __left_->is_ctor_dtor_conv(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __function_args + : public __node +{ +public: + __function_args(__node* list) + {__right_ = list;} + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = 2 + __right_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + *buf++ = '('; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __cv_qualifiers + : public __node +{ +public: + __cv_qualifiers(size_t cv, __node* type) + { + __left_ = type; + __size_ = __left_->is_function() ? cv << 5 : cv; + } + + virtual size_t first_size() const + { + size_t s = __left_->first_size(); + if (__size_ & 4) + s += sizeof(" restrict")-1; + if (__size_ & 2) + s += sizeof(" volatile")-1; + if (__size_ & 1) + s += sizeof(" const")-1; + if (__size_ & 8) + s += sizeof(" &")-1; + if (__size_ & 16) + s += sizeof(" &&")-1; + return s; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->first_demangled_name(buf); + if (__size_ & 1) + { + const size_t n = sizeof(" const")-1; + strncpy(buf, " const", n); + buf += n; + } + if (__size_ & 2) + { + const size_t n = sizeof(" volatile")-1; + strncpy(buf, " volatile", n); + buf += n; + } + if (__size_ & 4) + { + const size_t n = sizeof(" restrict")-1; + strncpy(buf, " restrict", n); + buf += n; + } + if (__size_ & 8) + { + *buf++ = ' '; + *buf++ = '&'; + } + if (__size_ & 16) + { + *buf++ = ' '; + *buf++ = '&'; + *buf++ = '&'; + } + return buf; + } + virtual size_t second_size() const + { + size_t s = __left_->second_size(); + if (__size_ & 128) + s += sizeof(" restrict")-1; + if (__size_ & 64) + s += sizeof(" volatile")-1; + if (__size_ & 32) + s += sizeof(" const")-1; + if (__size_ & 256) + s += sizeof(" &")-1; + if (__size_ & 512) + s += sizeof(" &&")-1; + return s; + } + virtual char* second_demangled_name(char* buf) const + { + buf = __left_->second_demangled_name(buf); + if (__size_ & 32) + { + const size_t n = sizeof(" const")-1; + strncpy(buf, " const", n); + buf += n; + } + if (__size_ & 64) + { + const size_t n = sizeof(" volatile")-1; + strncpy(buf, " volatile", n); + buf += n; + } + if (__size_ & 128) + { + const size_t n = sizeof(" restrict")-1; + strncpy(buf, " restrict", n); + buf += n; + } + if (__size_ & 256) + { + *buf++ = ' '; + *buf++ = '&'; + } + if (__size_ & 512) + { + *buf++ = ' '; + *buf++ = '&'; + *buf++ = '&'; + } + return buf; + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_reference_or_pointer_to_function_or_array(); + } + virtual bool is_function() const + { + return __left_->is_function(); + } + virtual bool is_cv_qualifer() const + { + return true; + } + virtual __node* extract_cv(__node*& rt) const + { + if (rt == this) + { + rt = __left_; + return const_cast<__node*>(static_cast<const __node*>(this)); + } + return 0; + } + virtual bool ends_with_template(bool parsing = false) const + { + if (parsing) + return __left_->ends_with_template(parsing); + return false; + } + virtual bool is_ctor_dtor_conv() const + { + return __left_->is_ctor_dtor_conv(); + } + virtual bool is_array() const + { + return __left_->is_array(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } + virtual size_t list_len() const + { + return __left_->list_len(); + } +}; + +class __extended_qualifier + : public __node +{ +public: + __extended_qualifier(__node* name, __node* type) + { + __left_ = type; + __right_ = name; + __size_ = __left_->is_function() ? 1 : 0; + } + + virtual size_t first_size() const + { + size_t s = __left_->first_size(); + if (__size_ == 0) + s += __right_->size() + 1; + return s; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->first_demangled_name(buf); + if (__size_ == 0) + { + *buf++ = ' '; + buf = __right_->get_demangled_name(buf); + } + return buf; + } + virtual size_t second_size() const + { + size_t s = __left_->second_size(); + if (__size_ == 1) + s += __right_->size() + 1; + return s; + } + virtual char* second_demangled_name(char* buf) const + { + buf = __left_->second_demangled_name(buf); + if (__size_ == 1) + { + *buf++ = ' '; + buf = __right_->get_demangled_name(buf); + } + return buf; + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_reference_or_pointer_to_function_or_array(); + } + virtual bool is_function() const + { + return __left_->is_function(); + } + virtual bool is_cv_qualifer() const + { + return true; + } + virtual __node* extract_cv(__node*& rt) const + { + if (rt == this) + { + rt = __left_; + return const_cast<__node*>(static_cast<const __node*>(this)); + } + return 0; + } + virtual bool ends_with_template(bool parsing = false) const + { + return __left_->ends_with_template(parsing); + } + virtual bool is_ctor_dtor_conv() const + { + return __left_->is_ctor_dtor_conv(); + } + virtual bool is_array() const + { + return __left_->is_array(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } + virtual size_t list_len() const + { + return __left_->list_len(); + } +}; + +class __function + : public __node +{ +public: + + __function(__node* name, __node* signature, size_t ret_goes_first = true) + { + __size_ = ret_goes_first; + __left_ = name; + __right_ = signature; + } + + virtual size_t first_size() const + { + size_t off = 0; + if (__size_) + { + off = __right_->first_size(); + if (off > 0 && (__left_ == NULL || + !__right_->__left_->is_reference_or_pointer_to_function_or_array())) + ++off; + } + else + off = 5; + if (__left_) + off += __left_->first_size(); + else + ++off; + return off; + } + + virtual size_t second_size() const + { + size_t off = 0; + if (__left_ == NULL) + off = 1; + off += __right_->second_size(); + if (!__size_) + { + off += 2; + off += __right_->first_size(); + } + return off; + } + + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + const char* t = buf; + buf = __right_->first_demangled_name(buf); + if (buf != t && (__left_ == NULL || + !__right_->__left_->is_reference_or_pointer_to_function_or_array())) + *buf++ = ' '; + } + else + { + strncpy(buf, "auto ", 5); + buf += 5; + } + if (__left_) + buf = __left_->first_demangled_name(buf); + else + *buf++ = '('; + return buf; + } + virtual char* second_demangled_name(char* buf) const + { + if (__left_ == NULL) + *buf++ = ')'; + buf = __right_->second_demangled_name(buf); + if (!__size_) + { + *buf++ = '-'; + *buf++ = '>'; + buf = __right_->first_demangled_name(buf); + } + return buf; + } + virtual char* get_demangled_name(char* buf) const + { + if (__size_) + { + const char* t = buf; + buf = __right_->first_demangled_name(buf); + if (buf != t && (__left_ == NULL || + !__right_->__left_->is_reference_or_pointer_to_function_or_array())) + *buf++ = ' '; + } + else + { + strncpy(buf, "auto ", 5); + buf += 5; + } + if (__left_) + buf = __left_->first_demangled_name(buf); + buf = __right_->second_demangled_name(buf); + if (!__size_) + { + *buf++ = '-'; + *buf++ = '>'; + buf = __right_->first_demangled_name(buf); + } + return buf; + } + + virtual size_t size() const + { + if (__cached_size_ == -1) + { + size_t off = 0; + if (__size_) + { + off = __right_->first_size(); + if (off > 0 && (__left_ == NULL || + !__right_->__left_->is_reference_or_pointer_to_function_or_array())) + ++off; + } + else + off = 5; + if (__left_) + off += __left_->first_size(); + off += __right_->second_size(); + if (!__size_) + { + off += 2; + off += __right_->first_size(); + } + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + + virtual bool is_function() const + { + return true; + } + virtual bool is_ctor_dtor_conv() const + { + return __left_->is_ctor_dtor_conv(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __function_signature + : public __node +{ +public: + __function_signature(__node* ret, __node* args) + { + __left_ = ret; + __right_ = args; + } + virtual size_t first_size() const + { + return __left_ ? __left_->first_size() : 0; + } + + virtual size_t second_size() const + { + return 2 + (__right_ ? __right_->size() : 0) + + (__left_ ? __left_->second_size() : 0); + } + + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + buf = __left_->first_demangled_name(buf); + return buf; + } + + virtual char* second_demangled_name(char* buf) const + { + *buf++ = '('; + if (__right_) + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + if (__left_) + buf = __left_->second_demangled_name(buf); + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = r && __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __pointer_to + : public __node +{ +public: + + explicit __pointer_to(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + return __left_->first_size() + (__left_->is_array() ? 3 : 1); + } + virtual size_t second_size() const + { + return __left_->second_size() + (__left_->is_array() ? 1 : 0); + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->first_demangled_name(buf); + if (__left_->is_array()) + { + *buf++ = ' '; + *buf++ = '('; + *buf++ = '*'; + } + else + *buf++ = '*'; + return buf; + } + virtual char* second_demangled_name(char* buf) const + { + if (__left_->is_array()) + *buf++ = ')'; + return __left_->second_demangled_name(buf); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_function() || + __left_->is_reference_or_pointer_to_function_or_array(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } + virtual size_t list_len() const + { + return __left_->list_len(); + } +}; + +class __lvalue_reference_to + : public __node +{ +public: + + explicit __lvalue_reference_to(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + return __left_->first_size() + (__left_->is_array() ? 3 : 1); + } + virtual size_t second_size() const + { + return __left_->second_size() + (__left_->is_array() ? 1 : 0); + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->first_demangled_name(buf); + if (__left_->is_array()) + { + *buf++ = ' '; + *buf++ = '('; + *buf++ = '&'; + } + else + *buf++ = '&'; + return buf; + } + virtual char* second_demangled_name(char* buf) const + { + if (__left_->is_array()) + *buf++ = ')'; + return __left_->second_demangled_name(buf); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_function(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } + virtual size_t list_len() const + { + return __left_->list_len(); + } +}; + +class __rvalue_reference_to + : public __node +{ +public: + + explicit __rvalue_reference_to(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + return __left_->first_size() + (__left_->is_array() ? 4 : 2); + } + virtual size_t second_size() const + { + return __left_->second_size() + (__left_->is_array() ? 1 : 0); + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->first_demangled_name(buf); + if (__left_->is_array()) + { + strncpy(buf, " (&&", 4); + buf += 4; + } + else + { + *buf++ = '&'; + *buf++ = '&'; + } + return buf; + } + virtual char* second_demangled_name(char* buf) const + { + if (__left_->is_array()) + *buf++ = ')'; + return __left_->second_demangled_name(buf); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __left_->is_function(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } + virtual size_t list_len() const + { + return __left_->list_len(); + } +}; + +class __d_complex + : public __node +{ + static const size_t n = sizeof(" complex") - 1; +public: + + explicit __d_complex(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __left_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + strncpy(buf, " complex", n); + return buf + n; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } +}; + +class __imaginary + : public __node +{ + static const size_t n = sizeof(" imaginary") - 1; +public: + + explicit __imaginary(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = n + __left_->size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + strncpy(buf, " imaginary", n); + return buf + n; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } +}; + +class __pack_expansion + : public __node +{ +public: + + explicit __pack_expansion(__node* type) + { + __left_ = type; + } + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t len = __left_->list_len(); + size_t off = 0; + if (len != 0) + { + if (__left_->is_sub() || len == 1) + off = __left_->size(); + else + { + __node* top = __left_; + __node* bottom = top; + while (!bottom->__left_->is_sub()) + bottom = bottom->__left_; + __node* sub = bottom->__left_; + __node* i = sub->__left_; + bool first = true; + top->reset_cached_size(); + while (i) + { + if (!first) + off += 2; + bottom->__left_ = i->__left_; + off += top->size(); + top->reset_cached_size(); + i = i->__right_; + first = false; + } + bottom->__left_ = sub; + } + } + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + size_t len = __left_->list_len(); + if (len != 0) + { + if (__left_->is_sub() || len == 1) + buf = __left_->get_demangled_name(buf); + else + { + __node* top = __left_; + __node* bottom = top; + while (!bottom->__left_->is_sub()) + bottom = bottom->__left_; + __node* sub = bottom->__left_; + __node* i = sub->__left_; + bool first = true; + top->reset_cached_size(); + while (i) + { + if (!first) + { + *buf++ = ','; + *buf++ = ' '; + } + bottom->__left_ = i->__left_; + buf = top->get_demangled_name(buf); + top->reset_cached_size(); + i = i->__right_; + first = false; + } + bottom->__left_ = sub; + } + } + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } +}; + +class __void + : public __node +{ + static const size_t n = sizeof("void") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "void", n); + return buf + n; + } +}; + +class __wchar_t + : public __node +{ + static const size_t n = sizeof("wchar_t") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "wchar_t", n); + return buf + n; + } +}; + +class __wchar_t_literal + : public __node +{ +public: + explicit __wchar_t_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+9; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(wchar_t)", 9); + buf += 9; + strncpy(buf, __name_, __size_); + return buf + __size_; + } +}; + +class __bool + : public __node +{ + static const size_t n = sizeof("bool") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "bool", n); + return buf + n; + } +}; + +class __bool_literal + : public __node +{ +public: + explicit __bool_literal(const char* __name, unsigned __size) + { + __name_ = __name; + __size_ = __size; + } + + virtual size_t first_size() const + { + return __size_; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, __name_, __size_); + return buf + __size_; + } +}; + +class __char + : public __node +{ + static const size_t n = sizeof("char") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "char", n); + return buf + n; + } +}; + +class __char_literal + : public __node +{ +public: + explicit __char_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+6; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(char)", 6); + buf += 6; + if (*__name_ == 'n') + { + *buf++ = '-'; // strncpy(buf+6, "-", 1); + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + return buf; + } +}; + +class __signed_char + : public __node +{ + static const size_t n = sizeof("signed char") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "signed char", n); + return buf + n; + } +}; + +class __signed_char_literal + : public __node +{ +public: + explicit __signed_char_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+13; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(signed char)", 13); + buf += 13; + if (*__name_ == 'n') + { + *buf++ = '-'; + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + return buf; + } +}; + +class __unsigned_char + : public __node +{ + static const size_t n = sizeof("unsigned char") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned char", n); + return buf + n; + } +}; + +class __unsigned_char_literal + : public __node +{ +public: + explicit __unsigned_char_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+15; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(unsigned char)", 15); + buf += 15; + strncpy(buf, __name_, __size_); + return buf + __size_; + } +}; + +class __short + : public __node +{ + static const size_t n = sizeof("short") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "short", n); + return buf + n; + } +}; + +class __short_literal + : public __node +{ +public: + explicit __short_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+7; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(short)", 7); + buf += 7; + if (*__name_ == 'n') + { + *buf++ = '-'; + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + return buf; + } +}; + +class __unsigned_short + : public __node +{ + static const size_t n = sizeof("unsigned short") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned short", n); + return buf + n; + } +}; + +class __unsigned_short_literal + : public __node +{ +public: + explicit __unsigned_short_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+16; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(unsigned short)", 16); + buf += 16; + strncpy(buf, __name_, __size_); + return buf + __size_; + } +}; + +class __int + : public __node +{ + static const size_t n = sizeof("int") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + *buf++ = 'i'; + *buf++ = 'n'; + *buf++ = 't'; + return buf; + } +}; + +class __int_literal + : public __node +{ +public: + explicit __int_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (*__name_ == 'n') + { + *buf++ = '-'; + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + return buf; + } +}; + +class __unsigned_int + : public __node +{ + static const size_t n = sizeof("unsigned int") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned int", n); + return buf + n; + } +}; + +class __unsigned_int_literal + : public __node +{ +public: + explicit __unsigned_int_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+1; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, __name_, __size_); + buf += __size_; + *buf++ = 'u'; + return buf; + } +}; + +class __long + : public __node +{ + static const size_t n = sizeof("long") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "long", n); + return buf + n; + } +}; + +class __long_literal + : public __node +{ +public: + explicit __long_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+1; + } + virtual char* first_demangled_name(char* buf) const + { + if (*__name_ == 'n') + { + *buf++ = '-'; // strncpy(buf, "-", 1); + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + *buf++ = 'l'; + return buf; + } +}; + +class __unsigned_long + : public __node +{ + static const size_t n = sizeof("unsigned long") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned long", n); + return buf + n; + } +}; + +class __unsigned_long_literal + : public __node +{ +public: + explicit __unsigned_long_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+2; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, __name_, __size_); + buf += __size_; + *buf++ = 'u'; + *buf++ = 'l'; + return buf; + } +}; + +class __long_long + : public __node +{ + static const size_t n = sizeof("long long") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "long long", n); + return buf + n; + } +}; + +class __long_long_literal + : public __node +{ +public: + explicit __long_long_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+2; + } + virtual char* first_demangled_name(char* buf) const + { + if (*__name_ == 'n') + { + *buf++ = '-'; + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + *buf++ = 'l'; + *buf++ = 'l'; + return buf; + } +}; + +class __unsigned_long_long + : public __node +{ + static const size_t n = sizeof("unsigned long long") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned long long", n); + return buf + n; + } +}; + +class __unsigned_long_long_literal + : public __node +{ +public: + explicit __unsigned_long_long_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+3; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, __name_, __size_); + buf += __size_; + *buf++ = 'u'; + *buf++ = 'l'; + *buf++ = 'l'; + return buf; + } +}; + +class __int128 + : public __node +{ + static const size_t n = sizeof("__int128") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "__int128", n); + return buf + n; + } +}; + +class __int128_literal + : public __node +{ +public: + explicit __int128_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+10; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(__int128)", 10); + buf += 10; + if (*__name_ == 'n') + { + *buf++ = '-'; + strncpy(buf, __name_+1, __size_-1); + buf += __size_ - 1; + } + else + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + return buf; + } +}; + +class __unsigned_int128 + : public __node +{ + static const size_t n = sizeof("unsigned __int128") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "unsigned __int128", n); + return buf + n; + } +}; + +class __unsigned_int128_literal + : public __node +{ +public: + explicit __unsigned_int128_literal(const char* __first, const char* __last) + { + __name_ = __first; + __size_ = __last - __first; + } + + virtual size_t first_size() const + { + return __size_+19; + } + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "(unsigned __int128)", 19); + buf += 19; + strncpy(buf, __name_, __size_); + return buf + __size_; + } +}; + +class __float_literal + : public __node +{ +public: + explicit __float_literal(float value) + { + __value_ = value; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + char num[20] = {0}; + float v = static_cast<float>(__value_); + const_cast<long&>(__cached_size_) = sprintf(num, "%a", v)+1; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + char num[20] = {0}; + float v = static_cast<float>(__value_); + int n = sprintf(num, "%a", v); + strncpy(buf, num, n); + buf += n; + *buf++ = 'f'; + return buf; + } +}; + +class __float + : public __node +{ + static const size_t n = sizeof("float") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "float", n); + return buf + n; + } +}; + +class __double_literal + : public __node +{ +public: + explicit __double_literal(double value) + { + __value_ = value; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + char num[30] = {0}; + double v = static_cast<double>(__value_); + const_cast<long&>(__cached_size_) = sprintf(num, "%a", v); + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + char num[30] = {0}; + double v = static_cast<double>(__value_); + int n = sprintf(num, "%a", v); + strncpy(buf, num, n); + return buf + n; + } +}; + +class __double + : public __node +{ + static const size_t n = sizeof("double") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "double", n); + return buf + n; + } +}; + +class __long_double + : public __node +{ + static const size_t n = sizeof("long double") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "long double", n); + return buf + n; + } +}; + +class __float128 + : public __node +{ + static const size_t n = sizeof("__float128") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "__float128", n); + return buf + n; + } +}; + +class __ellipsis + : public __node +{ + static const size_t n = sizeof("...") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + *buf++ = '.'; + *buf++ = '.'; + *buf++ = '.'; + return buf; + } +}; + +class __decimal64 + : public __node +{ + static const size_t n = sizeof("decimal64") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "decimal64", n); + return buf + n; + } +}; + +class __decimal128 + : public __node +{ + static const size_t n = sizeof("decimal128") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "decimal128", n); + return buf + n; + } +}; + +class __decimal32 + : public __node +{ + static const size_t n = sizeof("decimal32") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "decimal32", n); + return buf + n; + } +}; + +class __decimal16 + : public __node +{ + static const size_t n = sizeof("decimal16") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "decimal16", n); + return buf + n; + } +}; + +class __d_char32_t + : public __node +{ + static const size_t n = sizeof("char32_t") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "char32_t", n); + return buf + n; + } +}; + +class __d_char16_t + : public __node +{ + static const size_t n = sizeof("char16_t") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "char16_t", n); + return buf + n; + } +}; + +class __auto + : public __node +{ + static const size_t n = sizeof("auto") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "auto", n); + return buf + n; + } +}; + +class __nullptr_t + : public __node +{ + static const size_t n = sizeof("std::nullptr_t") - 1; +public: + + virtual size_t first_size() const {return n;} + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "std::nullptr_t", n); + return buf + n; + } +}; + +class __array + : public __node +{ +public: + + explicit __array(__node* type) + { + __left_ = type; + } + + __array(__node* type, size_t dim) + { + __left_ = type; + __size_ = dim; + } + + __array(__node* type, __node* dim) + { + __left_ = type; + __right_ = dim; + } + + virtual size_t size() const + { + if (__cached_size_ == -1) + { + size_t r = __left_->size() + 3; + if (__right_ != 0) + r += __right_->size(); + else if (__size_ != 0) + r += snprintf(0, 0, "%ld", __size_); + const_cast<long&>(__cached_size_) = r; + } + return __cached_size_; + } + + virtual char* get_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = ' '; + *buf++ = '['; + if (__right_ != 0) + buf = __right_->get_demangled_name(buf); + else if (__size_ != 0) + { + size_t rs = sprintf(buf, "%ld", __size_); + buf += rs; + } + *buf++ = ']'; + return buf; + } + + virtual size_t first_size() const + { + return __left_->first_size(); + } + + virtual char* first_demangled_name(char* buf) const + { + return __left_->first_demangled_name(buf); + } + + virtual size_t second_size() const + { + size_t r = 2 + __left_->second_size(); + if (!__left_->is_array()) + ++r; + if (__right_ != 0) + r += __right_->size(); + else if (__size_ != 0) + r += snprintf(0, 0, "%ld", __size_); + return r; + } + + virtual char* second_demangled_name(char* buf) const + { + *buf++ = ' '; + *buf++ = '['; + if (__right_ != 0) + buf = __right_->get_demangled_name(buf); + else if (__size_ != 0) + { + size_t off = sprintf(buf, "%ld", __size_); + buf += off; + } + char* t = buf; + buf = __left_->second_demangled_name(buf); + *t = ']'; + if (buf == t) + ++buf; + return buf; + } + virtual bool is_array() const + { + return true; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + +class __pointer_to_member_type + : public __node +{ +public: + + __pointer_to_member_type(__node* class_type, __node* member_type) + { + __left_ = class_type; + __right_ = member_type; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + 3 + + __right_->first_size() + + __right_->second_size(); + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __right_->first_demangled_name(buf); + buf = __left_->get_demangled_name(buf); + *buf++ = ':'; + *buf++ = ':'; + *buf++ = '*'; + return __right_->second_demangled_name(buf); + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool is_reference_or_pointer_to_function_or_array() const + { + return __right_->is_function(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __decltype_node + : public __node +{ +public: + + explicit __decltype_node(__node* expr) + { + __right_ = expr; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = 10 + __right_->size(); + return __cached_size_; + } + + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "decltype(", 9); + buf += 9; + buf = __right_->get_demangled_name(buf); + *buf++ = ')'; + return buf; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __nested_delimeter + : public __node +{ +public: + + explicit __nested_delimeter(__node* prev, __node* arg) + { + __left_ = prev; + __right_ = arg; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __left_->size() + __right_->size() + 2; + return __cached_size_; + } + + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = ':'; + *buf++ = ':'; + return __right_->get_demangled_name(buf); + } + + virtual bool ends_with_template(bool parsing = false) const + { + return __right_->ends_with_template(parsing); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool is_ctor_dtor_conv() const + { + return __right_->is_ctor_dtor_conv(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end) && + __right_->fix_forward_references(t_begin, t_end); + } + virtual __node* extract_cv(__node*& rt) const + { + return __right_->extract_cv(const_cast<__node*&>(__right_)); + } +}; + +class __unresolved_name + : public __node +{ +public: + + __unresolved_name(__node* prev, __node* arg) + { + __left_ = prev; + __right_ = arg; + } + + __unresolved_name(bool global, __node* prev, __node* arg) + { + __size_ = global; + __left_ = prev; + __right_ = arg; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = (__left_ ? __left_->size() + 2 : 0) + + __right_->size() + __size_ * 2; + return __cached_size_; + } + + virtual char* first_demangled_name(char* buf) const + { + if (__size_) + { + *buf++ = ':'; + *buf++ = ':'; + } + if (__left_) + { + buf = __left_->get_demangled_name(buf); + *buf++ = ':'; + *buf++ = ':'; + } + return __right_->get_demangled_name(buf); + } + + virtual bool ends_with_template(bool parsing = false) const + { + return __right_->ends_with_template(parsing); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool is_ctor_dtor_conv() const + { + return __right_->is_ctor_dtor_conv(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = __left_->fix_forward_references(t_begin, t_end); + return r && __right_->fix_forward_references(t_begin, t_end); + } + virtual __node* extract_cv(__node*& rt) const + { + return __right_->extract_cv(const_cast<__node*&>(__right_)); + } +}; + +class __string_literal + : public __node +{ +public: + + virtual size_t first_size() const + { + return 14; + } + + virtual char* first_demangled_name(char* buf) const + { + strncpy(buf, "string literal", 14); + return buf + 14; + } +}; + +class __constructor + : public __node +{ +public: + + explicit __constructor(__node* name) + { + __right_ = name; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __right_->base_size(); + return __cached_size_; + } + + virtual char* first_demangled_name(char* buf) const + { + return __right_->get_base_name(buf); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool ends_with_template(bool parsing = false) const + { + return __right_->ends_with_template(parsing); + } + virtual bool is_ctor_dtor_conv() const + { + return true; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __destructor + : public __node +{ +public: + + explicit __destructor(__node* name) + { + __right_ = name; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + const_cast<long&>(__cached_size_) = __right_->base_size() + 1; + return __cached_size_; + } + + virtual char* first_demangled_name(char* buf) const + { + *buf++ = '~'; + return __right_->get_base_name(buf); + } + virtual __node* base_name() const + { + return __right_->base_name(); + } + virtual bool is_ctor_dtor_conv() const + { + return true; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __right_->fix_forward_references(t_begin, t_end); + } +}; + +class __dot_suffix + : public __node +{ +public: + __dot_suffix(__node* name, const char* suffix, unsigned sz) + { + __left_ = name; + __name_ = suffix; + __size_ = sz; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off = __left_->size(); + off += __size_ + 3; + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + buf = __left_->get_demangled_name(buf); + *buf++ = ' '; + *buf++ = '('; + strncpy(buf, __name_, __size_); + buf += __size_; + *buf++ = ')'; + return buf; + } + virtual __node* base_name() const + { + return __left_->base_name(); + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + return __left_->fix_forward_references(t_begin, t_end); + } +}; + +class __vector_type + : public __node +{ +public: + __vector_type(__node* type, const char* num, size_t sz) + { + __left_ = type; + __name_ = num; + __size_ = sz; + } + + __vector_type(__node* type, __node* num) + { + __left_ = type; + __right_ = num; + } + + virtual size_t first_size() const + { + if (__cached_size_ == -1) + { + size_t off = 5; + if (__left_) + off = __left_->size(); + off += 9; + if (__right_) + off += __right_->size(); + else if (__size_ > 0) + off += __size_; + const_cast<long&>(__cached_size_) = off; + } + return __cached_size_; + } + virtual char* first_demangled_name(char* buf) const + { + if (__left_) + buf = __left_->get_demangled_name(buf); + else + { + strncpy(buf, "pixel", 5); + buf += 5; + } + strncpy(buf, " vector[", 8); + buf += 8; + if (__right_) + buf = __right_->get_demangled_name(buf); + else if (__size_ > 0) + { + strncpy(buf, __name_, __size_); + buf += __size_; + } + *buf++ = ']'; + return buf; + } + virtual __node* base_name() const + { + if (__left_) + return __left_->base_name(); + return __left_; + } + virtual bool fix_forward_references(__node** t_begin, __node** t_end) + { + bool r = true; + if (__left_) + r = __left_->fix_forward_references(t_begin, t_end); + if (__right_) + r = r && __right_->fix_forward_references(t_begin, t_end); + return r; + } +}; + + +enum {invalid_args = -3, invalid_mangled_name, memory_alloc_failure, success, + not_yet_implemented}; + +__demangle_tree::__demangle_tree(const char* mangled_name, char* buf, size_t bs) + : __mangled_name_begin_(0), __mangled_name_end_(0), + __status_(invalid_mangled_name), __root_(0), + __node_begin_(0), __node_end_(0), __node_cap_(0), + __sub_begin_(0), __sub_end_(0), __sub_cap_(0), + __t_begin_(0), __t_end_(0), __t_cap_(0), + __tag_templates_(true), + __fix_forward_references_(false) +{ + size_t n = strlen(mangled_name); + size_t ms = n + 2*n*sizeof(__node) + 2*n*sizeof(__node*); + char* m; + if (ms <= bs) + { + m = buf; + __owns_buf_ = false; + } + else + { + m = static_cast<char*>(malloc(ms)); + __owns_buf_ = true; + } + if (m == NULL) + { + __status_ = memory_alloc_failure; + return; + } + __node_begin_ = __node_end_ = (__node*)(m); + __node_cap_ = __node_begin_ + 2*n; + __sub_begin_ = __sub_end_ = (__node**)(__node_cap_); + __sub_cap_ = __sub_begin_ + n; + __t_begin_ = __t_end_ = (__node**)(__sub_cap_); + __t_cap_ = __t_begin_ + n; + __mangled_name_begin_ = (const char*)(__t_cap_); + __mangled_name_end_ = __mangled_name_begin_ + n; + strncpy(const_cast<char*>(__mangled_name_begin_), mangled_name, n); +} + +__demangle_tree::~__demangle_tree() +{ + if (__owns_buf_) + free(__node_begin_); +} + +__demangle_tree::__demangle_tree(__demangle_tree& t) + : __mangled_name_begin_(t.__mangled_name_begin_), + __mangled_name_end_(t.__mangled_name_end_), + __status_(t.__status_), __root_(t.__root_), + __node_begin_(t.__node_begin_), __node_end_(t.__node_end_), + __node_cap_(t.__node_cap_), + __sub_begin_(t.__sub_begin_), __sub_end_(t.__sub_end_), + __sub_cap_(t.__sub_cap_), + __t_begin_(t.__t_begin_), __t_end_(t.__t_end_), + __t_cap_(t.__t_cap_), + __tag_templates_(t.__tag_templates_), + __fix_forward_references_(t.__fix_forward_references_), + __owns_buf_(t.__owns_buf_) +{ + t.__mangled_name_begin_ = 0; + t.__mangled_name_end_ = 0; + t.__status_ = invalid_mangled_name; + t.__root_ = 0; + t.__node_begin_ = t.__node_end_ = t.__node_cap_ = 0; + t.__sub_begin_ = t.__sub_end_ = t.__sub_cap_ = 0; + t.__t_begin_ = t.__t_end_ = t.__t_cap_ = 0; + t.__owns_buf_ = false; +} + +__demangle_tree::__demangle_tree(__demangle_tree_rv rv) + : __mangled_name_begin_(rv.ptr_->__mangled_name_begin_), + __mangled_name_end_(rv.ptr_->__mangled_name_end_), + __status_(rv.ptr_->__status_), __root_(rv.ptr_->__root_), + __node_begin_(rv.ptr_->__node_begin_), __node_end_(rv.ptr_->__node_end_), + __node_cap_(rv.ptr_->__node_cap_), + __sub_begin_(rv.ptr_->__sub_begin_), __sub_end_(rv.ptr_->__sub_end_), + __sub_cap_(rv.ptr_->__sub_cap_), + __t_begin_(rv.ptr_->__t_begin_), __t_end_(rv.ptr_->__t_end_), + __t_cap_(rv.ptr_->__t_cap_), + __tag_templates_(rv.ptr_->__tag_templates_), + __fix_forward_references_(rv.ptr_->__fix_forward_references_), + __owns_buf_(rv.ptr_->__owns_buf_) +{ + rv.ptr_->__mangled_name_begin_ = 0; + rv.ptr_->__mangled_name_end_ = 0; + rv.ptr_->__status_ = invalid_mangled_name; + rv.ptr_->__root_ = 0; + rv.ptr_->__node_begin_ = rv.ptr_->__node_end_ = rv.ptr_->__node_cap_ = 0; + rv.ptr_->__sub_begin_ = rv.ptr_->__sub_end_ = rv.ptr_->__sub_cap_ = 0; + rv.ptr_->__t_begin_ = rv.ptr_->__t_end_ = rv.ptr_->__t_cap_ = 0; + rv.ptr_->__owns_buf_ = false; +} + +int +__demangle_tree::__status() const +{ + return __status_; +} + +size_t +__demangle_tree::size() const +{ + return __status_ == success ? __root_->size() : 0; +} + +char* +__demangle_tree::__get_demangled_name(char* buf) const +{ + if (__status_ == success) + return __root_->get_demangled_name(buf); + return 0; +} + +template <class _Tp> +bool +__demangle_tree::__make() +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0> +bool +__demangle_tree::__make(_A0 __a0) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0, class _A1> +bool +__demangle_tree::__make(_A0 __a0, _A1 __a1) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0, __a1); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0, class _A1, class _A2> +bool +__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0, __a1, __a2); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0, class _A1, class _A2, class _A3> +bool +__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4> +bool +__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4, + class _A5> +bool +__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, + _A5 __a5) +{ + if (__node_end_ < __node_cap_) + { + ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4, __a5); + __root_ = __node_end_; + ++__node_end_; + return true; + } + __status_ = memory_alloc_failure; + return false; +} + +// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const +// [R | O] # & or && + +const char* +__demangle_tree::__parse_cv_qualifiers(const char* first, const char* last, + unsigned& cv, bool look_for_ref_quals) +{ + if (look_for_ref_quals) + { + for (; first != last; ++first) + { + switch (*first) + { + case 'r': + cv |= 4; + break; + case 'V': + cv |= 2; + break; + case 'K': + cv |= 1; + break; + case 'R': + cv |= 8; + break; + case 'O': + cv |= 16; + break; + default: + return first; + } + } + } + else + { + for (; first != last; ++first) + { + switch (*first) + { + case 'r': + cv |= 4; + break; + case 'V': + cv |= 2; + break; + case 'K': + cv |= 1; + break; + default: + return first; + } + } + } + return first; +} + +// <builtin-type> ::= v # void +// ::= w # wchar_t +// ::= b # bool +// ::= c # char +// ::= a # signed char +// ::= h # unsigned char +// ::= s # short +// ::= t # unsigned short +// ::= i # int +// ::= j # unsigned int +// ::= l # long +// ::= m # unsigned long +// ::= x # long long, __int64 +// ::= y # unsigned long long, __int64 +// ::= n # __int128 +// ::= o # unsigned __int128 +// ::= f # float +// ::= d # double +// ::= e # long double, __float80 +// ::= g # __float128 +// ::= z # ellipsis +// ::= Dd # IEEE 754r decimal floating point (64 bits) +// ::= De # IEEE 754r decimal floating point (128 bits) +// ::= Df # IEEE 754r decimal floating point (32 bits) +// ::= Dh # IEEE 754r half-precision floating point (16 bits) +// ::= Di # char32_t +// ::= Ds # char16_t +// ::= Da # auto (in dependent new-expressions) +// ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) +// ::= u <source-name> # vendor extended type + +const char* +__demangle_tree::__parse_builtin_type(const char* first, const char* last) +{ + if (first != last) + { + switch (*first) + { + case 'v': + if (__make<__void>()) + ++first; + break; + case 'w': + if (__make<__wchar_t>()) + ++first; + break; + case 'b': + if (__make<__bool>()) + ++first; + break; + case 'c': + if (__make<__char>()) + ++first; + break; + case 'a': + if (__make<__signed_char>()) + ++first; + break; + case 'h': + if (__make<__unsigned_char>()) + ++first; + break; + case 's': + if (__make<__short>()) + ++first; + break; + case 't': + if (__make<__unsigned_short>()) + ++first; + break; + case 'i': + if (__make<__int>()) + ++first; + break; + case 'j': + if (__make<__unsigned_int>()) + ++first; + break; + case 'l': + if (__make<__long>()) + ++first; + break; + case 'm': + if (__make<__unsigned_long>()) + ++first; + break; + case 'x': + if (__make<__long_long>()) + ++first; + break; + case 'y': + if (__make<__unsigned_long_long>()) + ++first; + break; + case 'n': + if (__make<__int128>()) + ++first; + break; + case 'o': + if (__make<__unsigned_int128>()) + ++first; + break; + case 'f': + if (__make<__float>()) + ++first; + break; + case 'd': + if (__make<__double>()) + ++first; + break; + case 'e': + if (__make<__long_double>()) + ++first; + break; + case 'g': + if (__make<__float128>()) + ++first; + break; + case 'z': + if (__make<__ellipsis>()) + ++first; + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'd': + if (__make<__decimal64>()) + first += 2; + break; + case 'e': + if (__make<__decimal128>()) + first += 2; + break; + case 'f': + if (__make<__decimal32>()) + first += 2; + break; + case 'h': + if (__make<__decimal16>()) + first += 2; + break; + case 'i': + if (__make<__d_char32_t>()) + first += 2; + break; + case 's': + if (__make<__d_char16_t>()) + first += 2; + break; + case 'a': + if (__make<__auto>()) + first += 2; + break; + case 'n': + if (__make<__nullptr_t>()) + first += 2; + break; + } + } + break; + } + } + return first; +} + +// <bare-function-type> ::= <signature type>+ +// # types are possible return type, then parameter types + +const char* +__demangle_tree::__parse_bare_function_type(const char* first, const char* last) +{ + if (first != last) + { + __tag_templates_ = false; + const char* t = __parse_type(first, last); + if (t != first && __make<__list>(__root_)) + { + const char* t0 = t; + __node* head = __root_; + __node* prev = head; + while (true) + { + t = __parse_type(t0, last); + if (t != t0) + { + if (__make<__list>(__root_)) + { + t0 = t; + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + prev = __root_; + } + else + break; + } + else + { + first = t; + __root_ = head; + break; + } + } + } + __tag_templates_ = true; + } + return first; +} + +// <function-type> ::= F [Y] <bare-function-type> E + +const char* +__demangle_tree::__parse_function_type(const char* first, const char* last) +{ + if (first != last && *first == 'F') + { + const char* t = first+1; + if (t != last) + { + bool externC = false; + if (*t == 'Y') + { + externC = true; + if (++t == last) + return first; + } + const char* t1 = __parse_type(t, last); + if (t1 != t) + { + __node* ret = __root_; + t = t1; + t1 = __parse_bare_function_type(t, last); + if (t1 != t && t1 != last && *t1 == 'E') + { + if (dynamic_cast<__void*>(__root_->__left_) != NULL) + __root_->__left_ = NULL; + if (__make<__function_signature>(ret, __root_)) + { + if (__make<__function>((__node*)0, __root_)) + first = t1+1; + } + } + } + } + } + return first; +} + +const char* +__demangle_tree::__parse_hex_number(const char* first, const char* last, unsigned long long& n) +{ + const char* t = first; + for (; t != last && isxdigit(*t); ++t) + { + if (t == first) + n = 0; + if (isdigit(*t)) + n = n * 16 + *t - '0'; + else if (isupper(*t)) + n = n * 16 + *t - 'A' + 10; + else + n = n * 16 + *t - 'a' + 10; + } + first = t; + return first; +} + +// <expr-primary> ::= L <type> <value number> E # integer literal +// ::= L <type> <value float> E # floating literal +// ::= L <string type> E # string literal +// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") +// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) +// ::= L <mangled-name> E # external name + +const char* +__demangle_tree::__parse_expr_primary(const char* first, const char* last) +{ + if (last - first >= 4 && *first == 'L') + { + switch (first[1]) + { + case 'w': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__wchar_t_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'b': + if (first[3] == 'E') + { + switch (first[2]) + { + case '0': + if (__make<__bool_literal>("false", 5)) + first += 4; + break; + case '1': + if (__make<__bool_literal>("true", 4)) + first += 4; + break; + } + } + break; + case 'c': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__char_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'a': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__signed_char_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'h': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_char_literal>(first+2, t)) + first = t+1; + } + } + break; + case 's': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__short_literal>(first+2, t)) + first = t+1; + } + } + break; + case 't': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_short_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'i': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__int_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'j': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_int_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'l': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__long_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'm': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_long_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'x': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__long_long_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'y': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_long_long_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'n': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__int128_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'o': + { + const char* t = __parse_number(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__unsigned_int128_literal>(first+2, t)) + first = t+1; + } + } + break; + case 'f': + { + if (last - (first+2) <= 8) + return first; + unsigned long long j; + const char* t = __parse_hex_number(first+2, first+10, j); + if (t != first+2 && t != last && *t == 'E') + { + unsigned i = static_cast<unsigned>(j); + float value = *(float*)&i; + if (__make<__float_literal>(value)) + first = t+1; + } + } + break; + case 'd': + { + if (last - (first+2) <= 16) + return first; + unsigned long long j; + const char* t = __parse_hex_number(first+2, first+18, j); + if (t != first+2 && t != last && *t == 'E') + { + double value = *(double*)&j; + if (__make<__double_literal>(value)) + first = t+1; + } + } + break; + case 'e': + break; + case '_': + if (first[2] == 'Z') + { + const char* t = __parse_encoding(first+3, last); + if (t != first+3 && t != last && *t == 'E') + first = t+1; + } + break; + default: + { + // might be named type + const char* t = __parse_type(first+1, last); + if (t != first+1 && t != last) + { + if (*t != 'E') + { + const char* n = t; + for (; n != last && isdigit(*n); ++n) + ; + if (n != t && n != last && *n == 'E') + { + if (__make<__cast_literal>(__root_, t, n)) + { + first = n+1; + break; + } + } + } + else + { + first = t+1; + break; + } + } + } +// assert(!"case in __parse_expr_primary not implemented"); + __status_ = not_yet_implemented; + } + } + return first; +} + +// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ +// ::= <closure-type-name> +// +// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ +// +// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters + +const char* +__demangle_tree::__parse_unnamed_type_name(const char* first, const char* last) +{ + if (last - first > 2 && first[0] == 'U') + { + switch (first[1]) + { + case 't': + case 'l': + first += 2; + __status_ = not_yet_implemented; + break; + } + } + return first; +} + +// <ctor-dtor-name> ::= C1 # complete object constructor +// ::= C2 # base object constructor +// ::= C3 # complete object allocating constructor +// ::= D0 # deleting destructor +// ::= D1 # complete object destructor +// ::= D2 # base object destructor + +const char* +__demangle_tree::__parse_ctor_dtor_name(const char* first, const char* last) +{ + if (last-first >= 2) + { + switch (first[0]) + { + case 'C': + switch (first[1]) + { + case '1': + case '2': + case '3': + if (__make<__constructor>(__root_->base_name())) + first += 2; + break; + } + break; + case 'D': + switch (first[1]) + { + case '0': + case '1': + case '2': + if (__make<__destructor>(__root_->base_name())) + first += 2; + break; + } + break; + } + } + return first; +} + +const char* +__demangle_tree::__parse_unscoped_template_name(const char* first, const char* last) +{ +// assert(!"__parse_unscoped_template_name not implemented"); + __status_ = not_yet_implemented; + return first; +} + +// <discriminator> := _ <non-negative number> # when number < 10 +// := __ <non-negative number> _ # when number >= 10 +// extension := decimal-digit+ + +const char* +__demangle_tree::__parse_discriminator(const char* first, const char* last) +{ + // parse but ignore discriminator + if (first != last) + { + if (*first == '_') + { + const char* t1 = first+1; + if (t1 != last) + { + if (isdigit(*t1)) + first = t1+1; + else if (*t1 == '_') + { + for (++t1; t1 != last && isdigit(*t1); ++t1) + ; + if (t1 != last && *t1 == '_') + first = t1 + 1; + } + } + } + else if (isdigit(*first)) + { + const char* t1 = first+1; + for (; t1 != last && isdigit(*t1); ++t1) + ; + first = t1; + } + } + return first; +} + +// <local-name> := Z <function encoding> E <entity name> [<discriminator>] +// := Z <function encoding> E s [<discriminator>] +// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> + +const char* +__demangle_tree::__parse_local_name(const char* first, const char* last) +{ + if (first != last && *first == 'Z') + { + const char* t = __parse_encoding(first+1, last); + if (t != first+1 && t != last && *t == 'E' && ++t != last) + { + __node* encoding = __root_; + switch (*t) + { + case 's': + { + const char*t1 = __parse_discriminator(t+1, last); + if (__make<__string_literal>()) + { + if (__make<__nested_delimeter>(encoding, __root_)) + first = t1; + } + } + break; + case 'd': +// assert(!"__parse_local_name d not implemented"); + __status_ = not_yet_implemented; + break; + default: + { + const char*t1 = __parse_name(t, last); + if (t1 != t) + { + // parse but ignore discriminator + t1 = __parse_discriminator(t1, last); + if (__make<__nested_delimeter>(encoding, __root_)) + first = t1; + } + } + break; + } + } + } + return first; +} + +// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) +// ::= <simple-id> # e.g., ~A<2*N> + +const char* +__demangle_tree::__parse_destructor_name(const char* first, const char* last) +{ + if (first != last) + { + const char* t = __parse_unresolved_type(first, last); + if (t == first) + t = __parse_simple_id(first, last); + if (t != first && __make<__destructor>(__root_)) + first = t; + } + return first; +} + +// <simple-id> ::= <source-name> [ <template-args> ] + +const char* +__demangle_tree::__parse_simple_id(const char* first, const char* last) +{ + if (first != last) + { + const char* t = __parse_source_name(first, last); + if (t != first) + first = __parse_template_args(t, last); + else + first = t; + } + return first; +} + +// <base-unresolved-name> ::= <simple-id> # unresolved name +// extension ::= <operator-name> # unresolved operator-function-id +// extension ::= <operator-name> <template-args> # unresolved operator template-id +// ::= on <operator-name> # unresolved operator-function-id +// ::= on <operator-name> <template-args> # unresolved operator template-id +// ::= dn <destructor-name> # destructor or pseudo-destructor; +// # e.g. ~X or ~X<N-1> + +const char* +__demangle_tree::__parse_base_unresolved_name(const char* first, const char* last) +{ + if (last - first >= 2) + { + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') + { + if (first[0] == 'o') + { + const char* t = __parse_operator_name(first+2, last); + if (t != first+2) + first = __parse_template_args(t, last); + else + first = t; + } + else + { + const char* t = __parse_destructor_name(first+2, last); + if (t != first+2) + first = t; + } + } + else + { + const char* t = __parse_simple_id(first, last); + if (t == first) + { + t = __parse_operator_name(first, last); + if (t != first) + t = __parse_template_args(t, last); + } + if (t != first) + first = t; + } + } + return first; +} + +// <unresolved-type> ::= <template-param> +// ::= <decltype> +// ::= <substitution> + +const char* +__demangle_tree::__parse_unresolved_type(const char* first, const char* last) +{ + if (first != last) + { + const char* t; + switch (*first) + { + case 'T': + t = __parse_template_param(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + break; + case 'D': + t = __parse_decltype(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + break; + case 'S': + t = __parse_substitution(first, last); + if (t != first) + first = t; + break; + } + } + return first; +} + +// <unresolved-qualifier-level> ::= <source-name> [ <template-args> ] + +const char* +__demangle_tree::__parse_unresolved_qualifier_level(const char* first, const char* last) +{ + if (first != last) + { + const char* t = __parse_source_name(first, last); + if (t != first) + first = __parse_template_args(t, last); + } + return first; +} + +// <unresolved-name> +// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x +// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> +// # A::x, N::y, A<T>::z; "gs" means leading "::" +// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x +// # T::N::x /decltype(p)::N::x +// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> + +const char* +__demangle_tree::__parse_unresolved_name(const char* first, const char* last) +{ + if (last - first > 2) + { + const char* t = first; + bool global = false; + if (t[0] == 'g' && t[1] == 's') + { + global = true; + t += 2; + } + const char* t2 = __parse_base_unresolved_name(t, last); + if (t2 != t) + { + if (__make<__unresolved_name>(global, (__node*)0, __root_)) + first = t2; + } + else if (last - t > 2 && t[0] == 's' && t[1] == 'r') + { + if (!global && t[2] == 'N') + { + t2 = __parse_unresolved_type(t+3, last); + if (t2 != t+3 && t2 != last) + { + t = __parse_template_args(t2, last); + if (t == last) + return first; + __node* name = __root_; + while (*t != 'E') + { + t2 = __parse_unresolved_qualifier_level(t, last); + if (t2 == t || t2 == last) + return first; + if (!__make<__nested_delimeter>(name, __root_)) + return first; + name = __root_; + t = t2; + } + t2 = __parse_base_unresolved_name(++t, last); + if (t2 != t && __make<__unresolved_name>(false, name, __root_)) + first = t2; + } + } + else + { + if (!global) + { + t2 = __parse_unresolved_type(t+2, last); + if (t2 != t+2) + { + t = t2; + __node* name = __root_; + t2 = __parse_base_unresolved_name(t, last); + if (t2 != t && __make<__unresolved_name>(false, name, __root_)) + return t2; + return first; + } + } + t2 = __parse_unresolved_qualifier_level(t+2, last); + if (t2 != t+2 && t2 != last) + { + __node* name = __root_; + t = t2; + while (*t != 'E') + { + t2 = __parse_unresolved_qualifier_level(t, last); + if (t2 == t || t2 == last) + return first; + if (!__make<__nested_delimeter>(name, __root_)) + return first; + name = __root_; + t = t2; + } + t2 = __parse_base_unresolved_name(++t, last); + if (t2 != t && __make<__unresolved_name>(global, name, __root_)) + first = t2; + } + } + } + } + return first; +} + +// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> + +const char* +__demangle_tree::__parse_function_param(const char* first, const char* last) +{ + if (last - first >= 3 && *first == 'f') + { + if (first[1] == 'p') + { +// assert(!"__parse_function_param not implemented"); + __status_ = not_yet_implemented; + } + else if (first[1] == 'L') + { +// assert(!"__parse_function_param not implemented"); + __status_ = not_yet_implemented; + } + } + return first; +} + +// at <type> # alignof (a type) + +const char* +__demangle_tree::__parse_alignof_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'a' && first[1] == 't') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + if (__make<__operator_alignof_expression>(__root_)) + first = t; + } + } + return first; +} + +// cc <type> <expression> # const_cast<type> (expression) + +const char* +__demangle_tree::__parse_const_cast_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + __node* type = __root_; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__const_cast>(type, __root_)) + first = t1; + } + } + } + return first; +} + +// cl <expression>+ E # call + +const char* +__demangle_tree::__parse_call_expr(const char* first, const char* last) +{ + if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (t == last) + return first; + __node* name = __root_; + __node* args = 0; + __node* prev = 0; + while (*t != 'E') + { + const char* t1 = __parse_expression(t, last); + if (t1 == t || t1 == last) + return first; + if (!__make<__list>(__root_)) + return first; + if (args == 0) + args = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + t = t1; + } + ++t; + if (__make<__call_expr>(name, args)) + first = t; + } + } + return first; +} + +// cv <type> <expression> # conversion with one argument +// cv <type> _ <expression>* E # conversion with a different number of arguments + +const char* +__demangle_tree::__parse_conversion_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') + { + const char* t = __parse_type(first+2, last); + if (t != first+2 && t != last) + { + __node* type = __root_; + __node* args = 0; + if (*t != '_') + { + const char* t1 = __parse_expression(t, last); + if (t1 == t) + return first; + args = __root_; + t = t1; + } + else + { + ++t; + if (t == last) + return first; + __node* prev = 0; + while (*t != 'E') + { + const char* t1 = __parse_expression(t, last); + if (t1 == t || t1 == last) + return first; + if (!__make<__list>(__root_)) + return first; + if (args == 0) + args = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + t = t1; + } + ++t; + } + if (__make<__operator_cast>(type, args)) + first = t; + } + } + return first; +} + +// [gs] da <expression> # delete[] expression + +const char* +__demangle_tree::__parse_delete_array_expr(const char* first, const char* last) +{ + if (last - first >= 4) + { + const char* t = first; + bool parsed_gs = false; + if (t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + if (t[0] == 'd' && t[1] == 'a') + { + t += 2; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__delete_array_expr>(parsed_gs, __root_)) + first = t1; + } + } + } + return first; +} + +// dc <type> <expression> # dynamic_cast<type> (expression) + +const char* +__demangle_tree::__parse_dynamic_cast_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + __node* type = __root_; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__dynamic_cast>(type, __root_)) + first = t1; + } + } + } + return first; +} + +// [gs] dl <expression> # delete expression + +const char* +__demangle_tree::__parse_delete_expr(const char* first, const char* last) +{ + if (last - first >= 4) + { + const char* t = first; + bool parsed_gs = false; + if (t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + if (t[0] == 'd' && t[1] == 'l') + { + t += 2; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__delete_expr>(parsed_gs, __root_)) + first = t1; + } + } + } + return first; +} + +// ds <expression> <expression> # expr.*expr + +const char* +__demangle_tree::__parse_dot_star_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 's') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* expr = __root_; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__dot_star_expr>(expr, __root_)) + first = t1; + } + } + } + return first; +} + +// dt <expression> <unresolved-name> # expr.name + +const char* +__demangle_tree::__parse_dot_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 't') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* expr = __root_; + const char* t1 = __parse_unresolved_name(t, last); + if (t1 != t) + { + if (__make<__dot_expr>(expr, __root_)) + first = t1; + } + } + } + return first; +} + +// mm_ <expression> # prefix -- + +const char* +__demangle_tree::__parse_decrement_expr(const char* first, const char* last) +{ + if (last - first > 3 && first[0] == 'm' && first[1] == 'm' && first[2] == '_') + { + const char* t = __parse_expression(first+3, last); + if (t != first+3) + { + if (__make<__operator_decrement>(true, __root_)) + first = t; + } + } + return first; +} + +// pp_ <expression> # prefix ++ + +const char* +__demangle_tree::__parse_increment_expr(const char* first, const char* last) +{ + if (last - first > 3 && first[0] == 'p' && first[1] == 'p' && first[2] == '_') + { + const char* t = __parse_expression(first+3, last); + if (t != first+3) + { + if (__make<__operator_increment>(true, __root_)) + first = t; + } + } + return first; +} + +// [gs] nw <expression>* _ <type> E # new (expr-list) type +// [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// [gs] na <expression>* _ <type> E # new[] (expr-list) type +// [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// <initializer> ::= pi <expression>* E # parenthesized initialization + +const char* +__demangle_tree::__parse_new_expr(const char* first, const char* last) +{ + if (last - first >= 4) + { + const char* t = first; + bool parsed_gs = false; + if (t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) + { + bool is_array = t[1] == 'a'; + t += 2; + if (t == last) + return first; + __node* expr = 0; + __node* prev = 0; + while (*t != '_') + { + const char* t1 = __parse_expression(t, last); + if (t1 == t || t1 == last) + return first; + if (!__make<__list>(__root_)) + return first; + if (expr == 0) + expr = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + t = t1; + } + ++t; + const char* t1 = __parse_type(t, last); + if (t1 == t || t1 == last) + return first; + t = t1; + __node* type = __root_; + __node* init = 0; + prev = 0; + bool has_init = false; + if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') + { + t += 2; + has_init = true; + while (*t != 'E') + { + t1 = __parse_expression(t, last); + if (t1 == t || t1 == last) + return first; + if (!__make<__list>(__root_)) + return first; + if (init == 0) + init = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + t = t1; + } + } + if (*t != 'E') + return first; + if (__make<__new_expr>(parsed_gs, is_array, has_init, + expr, type, init)) + first = t; + } + } + return first; +} + +// pt <expression> <unresolved-name> # expr->name + +const char* +__demangle_tree::__parse_arrow_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'p' && first[1] == 't') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* expr = __root_; + const char* t1 = __parse_unresolved_name(t, last); + if (t1 != t) + { + if (__make<__arrow_expr>(expr, __root_)) + first = t1; + } + } + } + return first; +} + +// rc <type> <expression> # reinterpret_cast<type> (expression) + +const char* +__demangle_tree::__parse_reinterpret_cast_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + __node* type = __root_; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__reinterpret_cast>(type, __root_)) + first = t1; + } + } + } + return first; +} + +// sc <type> <expression> # static_cast<type> (expression) + +const char* +__demangle_tree::__parse_static_cast_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'c') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + __node* type = __root_; + const char* t1 = __parse_expression(t, last); + if (t1 != t) + { + if (__make<__static_cast>(type, __root_)) + first = t1; + } + } + } + return first; +} + +// st <type> # sizeof (a type) + +const char* +__demangle_tree::__parse_sizeof_type_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 't') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + if (__make<__operator_sizeof_expression>(__root_)) + first = t; + } + } + return first; +} + +// sZ <template-param> # size of a parameter pack + +const char* +__demangle_tree::__parse_sizeof_param_pack_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') + { + const char* t = __parse_template_param(first+2, last); + if (t != first+2) + { + if (__make<__operator_sizeof_param_pack>(__root_)) + first = t; + } + } + return first; +} + +// sZ <function-param> # size of a function parameter pack + +const char* +__demangle_tree::__parse_sizeof_function_param_pack_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') + { + const char* t = __parse_function_param(first+2, last); + if (t != first+2) + { + if (__make<__operator_sizeof_param_pack>(__root_)) + first = t; + } + } + return first; +} + +// sp <expression> # pack expansion + +const char* +__demangle_tree::__parse_pack_expansion(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'p') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__pack_expansion>(__root_)) + first = t; + } + } + return first; +} + +// te <expression> # typeid (expression) +// ti <type> # typeid (type) + +const char* +__demangle_tree::__parse_typeid_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) + { + const char* t; + if (first[1] == 'e') + t = __parse_expression(first+2, last); + else + t = __parse_type(first+2, last); + if (t != first+2) + { + if (__make<__typeid>(__root_)) + first = t; + } + } + return first; +} + +// tw <expression> # throw expression + +const char* +__demangle_tree::__parse_throw_expr(const char* first, const char* last) +{ + if (last - first >= 3 && first[0] == 't' && first[1] == 'w') + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__throw>(__root_)) + first = t; + } + } + return first; +} + +// <expression> ::= <unary operator-name> <expression> +// ::= <binary operator-name> <expression> <expression> +// ::= <ternary operator-name> <expression> <expression> <expression> +// ::= cl <expression>+ E # call +// ::= cv <type> <expression> # conversion with one argument +// ::= cv <type> _ <expression>* E # conversion with a different number of arguments +// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type +// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type +// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// ::= [gs] dl <expression> # delete expression +// ::= [gs] da <expression> # delete[] expression +// ::= pp_ <expression> # prefix ++ +// ::= mm_ <expression> # prefix -- +// ::= ti <type> # typeid (type) +// ::= te <expression> # typeid (expression) +// ::= dc <type> <expression> # dynamic_cast<type> (expression) +// ::= sc <type> <expression> # static_cast<type> (expression) +// ::= cc <type> <expression> # const_cast<type> (expression) +// ::= rc <type> <expression> # reinterpret_cast<type> (expression) +// ::= st <type> # sizeof (a type) +// ::= at <type> # alignof (a type) +// ::= <template-param> +// ::= <function-param> +// ::= dt <expression> <unresolved-name> # expr.name +// ::= pt <expression> <unresolved-name> # expr->name +// ::= ds <expression> <expression> # expr.*expr +// ::= sZ <template-param> # size of a parameter pack +// ::= sZ <function-param> # size of a function parameter pack +// ::= sp <expression> # pack expansion +// ::= tw <expression> # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= <unresolved-name> # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= <expr-primary> + +const char* +__demangle_tree::__parse_expression(const char* first, const char* last) +{ + if (last - first >= 2) + { + const char* t = first; + bool parsed_gs = false; + if (last - first >= 4 && t[0] == 'g' && t[1] == 's') + { + t += 2; + parsed_gs = true; + } + switch (*t) + { + case 'L': + t = __parse_expr_primary(first, last); + break; + case 'T': + t = __parse_template_param(first, last); + break; + case 'f': + t = __parse_function_param(first, last); + break; + case 'a': + if (t[1] == 't') + t = __parse_alignof_expr(first, last); + break; + case 'c': + switch (t[1]) + { + case 'c': + t = __parse_const_cast_expr(first, last); + break; + case 'l': + t = __parse_call_expr(first, last); + break; + case 'v': + t = __parse_conversion_expr(first, last); + break; + } + break; + case 'd': + switch (t[1]) + { + case 'a': + t = __parse_delete_array_expr(first, last); + break; + case 'c': + t = __parse_dynamic_cast_expr(first, last); + break; + case 'l': + t = __parse_delete_expr(first, last); + break; + case 's': + t = __parse_dot_star_expr(first, last); + break; + case 't': + t = __parse_dot_expr(first, last); + break; + } + break; + case 'm': + t = __parse_decrement_expr(first, last); + break; + case 'n': + switch (t[1]) + { + case 'a': + case 'w': + t = __parse_new_expr(first, last); + break; + } + break; + case 'p': + switch (t[1]) + { + case 'p': + t = __parse_increment_expr(first, last); + break; + case 't': + t = __parse_arrow_expr(first, last); + break; + } + break; + case 'r': + t = __parse_reinterpret_cast_expr(first, last); + break; + case 's': + switch (t[1]) + { + case 'c': + t = __parse_static_cast_expr(first, last); + break; + case 'p': + t = __parse_pack_expansion(first, last); + break; + case 't': + t = __parse_sizeof_type_expr(first, last); + break; + case 'Z': + if (last - t >= 3) + { + switch (t[2]) + { + case 'T': + t = __parse_sizeof_param_pack_expr(first, last); + break; + case 'f': + t = __parse_sizeof_function_param_pack_expr(first, last); + break; + } + } + break; + } + break; + case 't': + switch (t[1]) + { + case 'e': + case 'i': + t = __parse_typeid_expr(first, last); + break; + case 'r': + if (__make<__rethrow>()) + t = first +2; + break; + case 'w': + t = __parse_throw_expr(first, last); + break; + } + break; + } + if ((!parsed_gs && t == first) || (parsed_gs && t == first+2)) + { + int op; + t = __parse_operator_name(first, last, &op); + if (t == first) + first = __parse_unresolved_name(first, last); + else + first = t; + } + else + first = t; + } + return first; +} + +// <array-type> ::= A <positive dimension number> _ <element type> +// ::= A [<dimension expression>] _ <element type> + +const char* +__demangle_tree::__parse_array_type(const char* first, const char* last) +{ + if (first != last && *first == 'A' && first+1 != last) + { + if (first[1] == '_') + { + const char* t = __parse_type(first+2, last); + if (t != first+2) + { + if (__make<__array>(__root_)) + first = t; + } + } + else if ('1' <= first[1] && first[1] <= '9') + { + size_t dim = first[1] - '0'; + const char* t = first+2; + for (; t != last && isdigit(*t); ++t) + dim = dim * 10 + *t - '0'; + if (t != last && *t == '_') + { + const char* t2 = __parse_type(t+1, last); + if (t2 != t+1) + { + if (__make<__array>(__root_, dim)) + first = t2; + } + } + } + else + { + const char* t = __parse_expression(first+1, last); + if (t != first+1 && t != last && *t == '_') + { + __node* dim = __root_; + const char* t2 = __parse_type(++t, last); + if (t2 != t) + { + if (__make<__array>(__root_, dim)) + first = t2; + } + } + } + } + return first; +} + +// <class-enum-type> ::= <name> + +const char* +__demangle_tree::__parse_class_enum_type(const char* first, const char* last) +{ + return __parse_name(first, last); +} + +// <pointer-to-member-type> ::= M <class type> <member type> + +const char* +__demangle_tree::__parse_pointer_to_member_type(const char* first, const char* last) +{ + if (first != last && *first == 'M') + { + const char* t = __parse_type(first+1, last); + if (t != first+1) + { + __node* class_type = __root_; + const char* t2 = __parse_type(t, last, true, true); + if (t2 != t) + { + if (__make<__pointer_to_member_type>(class_type, __root_)) + first = t2; + } + } + } + return first; +} + +// <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) +// ::= DT <expression> E # decltype of an expression (C++0x) + +const char* +__demangle_tree::__parse_decltype(const char* first, const char* last) +{ + if (last - first >= 4 && first[0] == 'D') + { + switch (first[1]) + { + case 't': + case 'T': + { + const char* t = __parse_expression(first+2, last); + if (t != first+2 && t != last && *t == 'E') + { + if (__make<__decltype_node>(__root_)) + first = t+1; + } + } + break; + } + } + return first; +} + +// <template-param> ::= T_ # first template parameter +// ::= T <parameter-2 non-negative number> _ + +const char* +__demangle_tree::__parse_template_param(const char* first, const char* last) +{ + if (last - first >= 2) + { + if (*first == 'T') + { + if (first[1] == '_') + { + if (__t_begin_ != __t_end_) + { + if (__make<__sub>(*__t_begin_)) + first += 2; + } + else + { + if (__make<__sub>(size_t(0))) + { + first += 2; + __fix_forward_references_ = true; + } + } + } + else if (isdigit(first[1])) + { + const char* t = first+1; + size_t sub = *t - '0'; + for (++t; t != last && isdigit(*t); ++t) + { + sub *= 10; + sub += *t - '0'; + } + if (t == last || *t != '_') + return first; + ++sub; + if (sub < __t_end_ - __t_begin_) + { + if (__make<__sub>(__t_begin_[sub])) + first = t+1; + } + else + { + if (__make<__sub>(sub)) + { + first = t+1; + __fix_forward_references_ = true; + } + } + } + } + } + return first; +} + +// extension: +// <vector-type> ::= Dv <positive dimension number> _ +// <extended element type> +// ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +// ::= p # AltiVec vector pixel + +const char* +__demangle_tree::__parse_vector_type(const char* first, const char* last) +{ + if (last - first > 3 && first[0] == 'D' && first[1] == 'v') + { + if ('1' <= first[2] && first[2] <= '9') + { + const char* t = first+3; + while (*t != '_') + { + if (!isdigit(*t) || ++t == last) + return first; + } + const char* num = first + 2; + size_t sz = t - num; + if (++t != last) + { + if (*t != 'p') + { + const char* t1 = __parse_type(t, last); + if (t1 != t) + { + if (__make<__vector_type>(__root_, num, sz)) + first = t1; + } + } + else + { + ++t; + if (__make<__vector_type>((__node*)0, num, sz)) + first = t; + } + } + } + else + { + __node* num = 0; + const char* t1 = first+2; + if (*t1 != '_') + { + const char* t = __parse_expression(t1, last); + if (t != t1) + num = __root_; + t1 = t; + } + if (t1 != last && *t1 == '_' && ++t1 != last) + { + const char* t = __parse_type(t1, last); + if (t != t1) + { + if (__make<__vector_type>(__root_, num)) + first = t; + } + } + } + } + return first; +} + +// <type> ::= <builtin-type> +// ::= <function-type> +// ::= <class-enum-type> +// ::= <array-type> +// ::= <pointer-to-member-type> +// ::= <template-param> +// ::= <template-template-param> <template-args> +// ::= <decltype> +// ::= <substitution> +// ::= <CV-qualifiers> <type> +// ::= P <type> # pointer-to +// ::= R <type> # reference-to +// ::= O <type> # rvalue reference-to (C++0x) +// ::= C <type> # complex pair (C 2000) +// ::= G <type> # imaginary (C 2000) +// ::= Dp <type> # pack expansion (C++0x) +// ::= U <source-name> <type> # vendor extended type qualifier +// extension := <vector-type> # <vector-type> starts with Dv + +const char* +__demangle_tree::__parse_type(const char* first, const char* last, + bool try_to_parse_template_args, + bool look_for_ref_quals) +{ + unsigned cv = 0; + const char* t = __parse_cv_qualifiers(first, last, cv, look_for_ref_quals); + if (t != first) + { + const char* t2 = __parse_type(t, last, try_to_parse_template_args); + if (t2 != t) + { + if (__make<__cv_qualifiers>(cv, __root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t2; + } + } + } + return first; + } + if (first != last) + { + switch (*first) + { + case 'A': + t = __parse_array_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + break; + case 'C': + t = __parse_type(first+1, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__d_complex>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 'F': + t = __parse_function_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + break; + case 'G': + t = __parse_type(first+1, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__imaginary>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 'M': + t = __parse_pointer_to_member_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + break; + case 'O': + t = __parse_type(first+1, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__rvalue_reference_to>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 'P': + t = __parse_type(first+1, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__pointer_to>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 'R': + t = __parse_type(first+1, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__lvalue_reference_to>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 'T': + t = __parse_template_param(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + if (try_to_parse_template_args) + { + const char* t2 = __parse_template_args(t, last); + if (t2 != t) + { + if (__sub_end_ < __sub_cap_) + { + *__sub_end_++ = __root_; + first = t2; + } + else + __status_ = memory_alloc_failure; + } + else + { + first = t; + } + } + else + { + first = t; + } + } + } + break; + case 'U': + if (first+1 != last) + { + t = __parse_source_name(first+1, last); + if (t != first+1) + { + __node* name = __root_; + const char* t2 = __parse_type(t, last, try_to_parse_template_args); + if (t2 != t) + { + if (__make<__extended_qualifier>(name, __root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t2; + } + } + return first; + } + } + } + break; + case 'S': + if (first+1 != last && first[1] == 't') + { + t = __parse_class_enum_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + } + else + { + t = __parse_substitution(first, last); + if (t != first) + { + first = t; + // Parsed a substitution. If the substitution is a + // <template-param> it might be followed by <template-args>. + t = __parse_template_args(first, last); + if (t != first) + { + // Need to create substitution for <template-template-param> <template-args> + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + } + } + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'p': + t = __parse_type(first+2, last, try_to_parse_template_args); + if (t != first+1) + { + if (__make<__pack_expansion>(__root_)) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + return first; + } + break; + case 't': + case 'T': + t = __parse_decltype(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + return first; + } + break; + case 'v': + t = __parse_vector_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + return first; + } + break; + } + } + // drop through + default: + // must check for builtin-types before class-enum-types to avoid + // ambiguities with operator-names + t = __parse_builtin_type(first, last); + if (t != first) + { + first = t; + } + else + { + t = __parse_class_enum_type(first, last); + if (t != first) + { + if (__sub_end_ == __sub_cap_) + __status_ = memory_alloc_failure; + else + { + *__sub_end_++ = __root_; + first = t; + } + } + } + break; + } + } + return first; +} + +// <number> ::= [n] <non-negative decimal integer> + +const char* +__demangle_tree::__parse_number(const char* first, const char* last) +{ + if (first != last) + { + const char* t = first; + if (*t == 'n') + ++t; + if (t != last) + { + if (*t == '0') + { + first = t+1; + } + else if ('1' <= *t && *t <= '9') + { + first = t+1; + while (first != last && isdigit(*first)) + ++first; + } + } + } + return first; +} + +// <call-offset> ::= h <nv-offset> _ +// ::= v <v-offset> _ +// +// <nv-offset> ::= <offset number> +// # non-virtual base override +// +// <v-offset> ::= <offset number> _ <virtual offset number> +// # virtual base override, with vcall offset + +const char* +__demangle_tree::__parse_call_offset(const char* first, const char* last) +{ + if (first != last) + { + switch (*first) + { + case 'h': + { + const char* t = __parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') + first = t + 1; + } + break; + case 'v': + { + const char* t = __parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') + { + const char* t2 = __parse_number(++t, last); + if (t2 != t && t2 != last && *t2 == '_') + first = t2 + 1; + } + } + break; + } + } + return first; +} + +// <special-name> ::= TV <type> # virtual table +// ::= TT <type> # VTT structure (construction vtable index) +// ::= TI <type> # typeinfo structure +// ::= TS <type> # typeinfo name (null-terminated byte string) +// ::= Tc <call-offset> <call-offset> <base encoding> +// # base is the nominal target function of thunk +// # first call-offset is 'this' adjustment +// # second call-offset is result adjustment +// ::= T <call-offset> <base encoding> +// # base is the nominal target function of thunk +// ::= GV <object name> # Guard variable for one-time initialization +// # No <type> +// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first +// extension ::= GR <object name> # reference temporary for object + +const char* +__demangle_tree::__parse_special_name(const char* first, const char* last) +{ + if (last - first > 2) + { + const char* t; + switch (*first) + { + case 'T': + switch (first[1]) + { + case 'V': + // TV <type> # virtual table + t = __parse_type(first+2, last); + if (t != first+2 && __make<__vtable>(__root_)) + first = t; + break; + case 'T': + // TT <type> # VTT structure (construction vtable index) + t = __parse_type(first+2, last); + if (t != first+2 && __make<__VTT>(__root_)) + first = t; + break; + case 'I': + // TI <type> # typeinfo structure + t = __parse_type(first+2, last); + if (t != first+2 && __make<__typeinfo>(__root_)) + first = t; + break; + case 'S': + // TS <type> # typeinfo name (null-terminated byte string) + t = __parse_type(first+2, last); + if (t != first+2 && __make<__typeinfo_name>(__root_)) + first = t; + break; + case 'c': + // Tc <call-offset> <call-offset> <base encoding> + { + const char* t0 = __parse_call_offset(first+2, last); + if (t0 == first+2) + break; + const char* t1 = __parse_call_offset(t0, last); + if (t1 == t0) + break; + t = __parse_encoding(t1, last); + if (t != t1 && __make<__covariant_return_thunk>(__root_)) + first = t; + } + break; + case 'C': + // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first + t = __parse_type(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t0 = __parse_number(t, last); + if (t0 != t && t0 != last && *t0 == '_') + { + const char* t1 = __parse_type(++t0, last); + if (t1 != t0) + { + if (__make<__construction_vtable>(__root_, op1)) + first = t1; + } + } + } + break; + default: + // T <call-offset> <base encoding> + { + const char* t0 = __parse_call_offset(first+1, last); + if (t0 == first+1) + break; + t = __parse_encoding(t0, last); + if (t != t0) + { + if (first[2] == 'v') + { + if (__make<__virtual_thunk>(__root_)) + first = t; + } + else + { + if (__make<__non_virtual_thunk>(__root_)) + first = t; + } + } + } + break; + } + break; + case 'G': + switch (first[1]) + { + case 'V': + // GV <object name> # Guard variable for one-time initialization + t = __parse_name(first+2, last); + if (t != first+2 && __make<__guard_variable>(__root_)) + first = t; + break; + case 'R': + // extension ::= GR <object name> # reference temporary for object + t = __parse_name(first+2, last); + if (t != first+2 && __make<__reference_temporary>(__root_)) + first = t; + break; + } + break; + } + } + return first; +} + +// <operator-name> +// ::= aa # && +// ::= ad # & (unary) +// ::= an # & +// ::= aN # &= +// ::= aS # = +// ::= at # alignof (a type) +// ::= az # alignof (an expression) +// ::= cl # () +// ::= cm # , +// ::= co # ~ +// ::= cv <type> # (cast) +// ::= da # delete[] +// ::= de # * (unary) +// ::= dl # delete +// ::= dv # / +// ::= dV # /= +// ::= eo # ^ +// ::= eO # ^= +// ::= eq # == +// ::= ge # >= +// ::= gt # > +// ::= ix # [] +// ::= le # <= +// ::= ls # << +// ::= lS # <<= +// ::= lt # < +// ::= mi # - +// ::= mI # -= +// ::= ml # * +// ::= mL # *= +// ::= mm # -- (postfix in <expression> context) +// ::= na # new[] +// ::= ne # != +// ::= ng # - (unary) +// ::= nt # ! +// ::= nw # new +// ::= oo # || +// ::= or # | +// ::= oR # |= +// ::= pm # ->* +// ::= pl # + +// ::= pL # += +// ::= pp # ++ (postfix in <expression> context) +// ::= ps # + (unary) +// ::= pt # -> +// ::= qu # ? +// ::= rm # % +// ::= rM # %= +// ::= rs # >> +// ::= rS # >>= +// ::= st # sizeof (a type) +// ::= sz # sizeof (an expression) +// ::= v <digit> <source-name> # vendor extended operator + +const char* +__demangle_tree::__parse_operator_name(const char* first, const char* last, int* type) +{ + if (last - first >= 2) + { + switch (*first) + { + case 'a': + switch (first[1]) + { + case 'a': + // && + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_logical_and>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_logical_and>()) + first += 2; + } + break; + case 'd': + // & (unary) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_addressof>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_addressof>()) + first += 2; + } + break; + case 'n': + // & + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_bit_and>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_bit_and>()) + first += 2; + } + break; + case 'N': + // &= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_and_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_and_equal>()) + first += 2; + } + break; + case 'S': + // = + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_equal>()) + first += 2; + } + break; + case 't': + // alignof (a type) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_alignof_type>(__root_)) + { + *type = -1; + first = t; + } + } + } + else + { + if (__make<__operator_alignof_type>()) + first += 2; + } + break; + case 'z': + // alignof (an expression) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_alignof_expression>(__root_)) + { + *type = -1; + first = t; + } + } + } + else + { + if (__make<__operator_alignof_expression>()) + first += 2; + } + break; + } + break; + case 'c': + switch (first[1]) + { + case 'l': + // () + if (__make<__operator_paren>()) + { + first += 2; + if (type) + *type = -1; + } + break; + case 'm': + // , + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_comma>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_comma>()) + first += 2; + } + break; + case 'o': + // ~ + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_tilda>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_tilda>()) + first += 2; + } + break; + case 'v': + // cast <type> + { + const char* t = __parse_type(first+2, last, false); + if (t != first+2) + { + __node* cast_type = __root_; + if (type) + { + const char* t2 = __parse_expression(t, last); + if (t2 != t) + { + if (__make<__operator_cast>(cast_type, __root_)) + { + *type = -1; + first = t2; + } + } + } + else + { + if (__make<__operator_cast>(cast_type)) + first = t; + } + } + } + break; + } + break; + case 'd': + switch (first[1]) + { + case 'a': + // delete[] + if (__make<__operator_delete_array>()) + { + first += 2; + if (type) + *type = -1; + } + break; + case 'e': + // * (unary) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_dereference>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_dereference>()) + first += 2; + } + break; + case 'l': + // delete + if (__make<__operator_delete>()) + { + first += 2; + if (type) + *type = -1; + } + break; + case 'v': + // / + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_divide>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_divide>()) + first += 2; + } + break; + case 'V': + // /= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_divide_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_divide_equal>()) + first += 2; + } + break; + } + break; + case 'e': + switch (first[1]) + { + case 'o': + // ^ + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_xor>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_xor>()) + first += 2; + } + break; + case 'O': + // ^= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_xor_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_xor_equal>()) + first += 2; + } + break; + case 'q': + // == + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_equality>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_equality>()) + first += 2; + } + break; + } + break; + case 'g': + switch (first[1]) + { + case 'e': + // >= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_greater_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_greater_equal>()) + first += 2; + } + break; + case 't': + // > + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_greater>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_greater>()) + first += 2; + } + break; + } + break; + case 'i': + // [] + if (first[1] == 'x' && __make<__operator_brackets>()) + { + first += 2; + if (type) + *type = -1; + } + break; + case 'l': + switch (first[1]) + { + case 'e': + // <= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_less_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_less_equal>()) + first += 2; + } + break; + case 's': + // << + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_left_shift>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_left_shift>()) + first += 2; + } + break; + case 'S': + // <<= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_left_shift_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_left_shift_equal>()) + first += 2; + } + break; + case 't': + // < + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_less>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_less>()) + first += 2; + } + break; + } + break; + case 'm': + switch (first[1]) + { + case 'i': + // - + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_minus>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_minus>()) + first += 2; + } + break; + case 'I': + // -= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_minus_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_minus_equal>()) + first += 2; + } + break; + case 'l': + // * + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_times>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_times>()) + first += 2; + } + break; + case 'L': + // *= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_times_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_times_equal>()) + first += 2; + } + break; + case 'm': + // -- (postfix in <expression> context) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_decrement>(false, __root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_decrement>()) + first += 2; + } + break; + } + break; + case 'n': + switch (first[1]) + { + case 'a': + // new[] + if (__make<__operator_new_array>()) + { + first += 2; + if (type) + *type = -1; + } + break; + case 'e': + // != + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_not_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_not_equal>()) + first += 2; + } + break; + case 'g': + // - (unary) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_negate>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_negate>()) + first += 2; + } + break; + case 't': + // ! + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_logical_not>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_logical_not>()) + first += 2; + } + break; + case 'w': + // new + if (__make<__operator_new>()) + { + first += 2; + if (type) + *type = -1; + } + break; + } + break; + case 'o': + switch (first[1]) + { + case 'o': + // || + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_logical_or>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_logical_or>()) + first += 2; + } + break; + case 'r': + // | + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_bit_or>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_bit_or>()) + first += 2; + } + break; + case 'R': + // |= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_or_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_or_equal>()) + first += 2; + } + break; + } + break; + case 'p': + switch (first[1]) + { + case 'm': + // ->* + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_pointer_to_member>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_pointer_to_member>()) + first += 2; + } + break; + case 'l': + // + + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_plus>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_plus>()) + first += 2; + } + break; + case 'L': + // += + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_plus_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_plus_equal>()) + first += 2; + } + break; + case 'p': + // ++ (postfix in <expression> context) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_increment>(false, __root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_increment>()) + first += 2; + } + break; + case 's': + // + (unary) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_unary_plus>(__root_)) + { + *type = 1; + first = t; + } + } + } + else + { + if (__make<__operator_unary_plus>()) + first += 2; + } + break; + case 't': + // -> + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_arrow>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_arrow>()) + first += 2; + } + break; + } + break; + case 'q': + // ? + if (first[1] == 'u') + { + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + __node* op2 = __root_; + const char* t3 = __parse_expression(t2, last); + if (t3 != t2) + { + if (__make<__operator_conditional>(op1, op2, __root_)) + { + *type = 3; + first = t3; + } + } + } + } + } + else + { + if (__make<__operator_conditional>()) + first += 2; + } + } + break; + case 'r': + switch (first[1]) + { + case 'm': + // % + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_mod>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_mod>()) + first += 2; + } + break; + case 'M': + // %= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_mod_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_mod_equal>()) + first += 2; + } + break; + case 's': + // >> + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_right_shift>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_right_shift>()) + first += 2; + } + break; + case 'S': + // >>= + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + __node* op1 = __root_; + const char* t2 = __parse_expression(t, last); + if (t != t2) + { + if (__make<__operator_right_shift_equal>(op1, __root_)) + { + *type = 2; + first = t2; + } + } + } + } + else + { + if (__make<__operator_right_shift_equal>()) + first += 2; + } + break; + } + break; + case 's': + switch (first[1]) + { + case 't': + // sizeof (a type) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_sizeof_type>(__root_)) + { + *type = -1; + first = t; + } + } + } + else + { + if (__make<__operator_sizeof_type>()) + first += 2; + } + break; + case 'z': + // sizeof (an expression) + if (type) + { + const char* t = __parse_expression(first+2, last); + if (t != first+2) + { + if (__make<__operator_sizeof_expression>(__root_)) + { + *type = -1; + first = t; + } + } + } + else + { + if (__make<__operator_sizeof_expression>()) + first += 2; + } + break; + } + break; + } + } + return first; +} + +// <source-name> ::= <positive length number> <identifier> + +const char* +__demangle_tree::__parse_source_name(const char* first, const char* last) +{ + if (first != last) + { + char c = *first; + if ('1' <= c && c <= '9' && first+1 != last) + { + const char* t = first+1; + size_t n = c - '0'; + for (c = *t; '0' <= c && c <= '9'; c = *t) + { + n = n * 10 + c - '0'; + if (++t == last) + return first; + } + if (last - t >= n && __make<__source_name>(t, n)) + first = t + n; + } + } + return first; +} + +// <unqualified-name> ::= <operator-name> +// ::= <ctor-dtor-name> +// ::= <source-name> +// ::= <unnamed-type-name> + +const char* +__demangle_tree::__parse_unqualified_name(const char* first, const char* last) +{ + const char* t = __parse_source_name(first, last); + if (t == first) + { + t = __parse_ctor_dtor_name(first, last); + if (t == first) + { + t = __parse_operator_name(first, last); + if (t == first) + first = __parse_unnamed_type_name(first, last); + else + first = t; + } + else + first = t; + } + else + first = t; + return first; +} + +// <unscoped-name> ::= <unqualified-name> +// ::= St <unqualified-name> # ::std:: +// extension ::= StL<unqualified-name> + +const char* +__demangle_tree::__parse_unscoped_name(const char* first, const char* last) +{ + if (last - first >= 2) + { + const char* t0 = first; + if (first[0] == 'S' && first[1] == 't') + { + t0 += 2; + if (t0 != last && *t0 == 'L') + ++t0; + } + const char* t1 = __parse_unqualified_name(t0, last); + if (t1 != t0) + { + if (t0 != first) + { + __node* name = __root_; + if (__make<__std_qualified_name>()) + { + if (__make<__nested_delimeter>(__root_, name)) + first = t1; + } + } + else + first = t1; + } + } + return first; +} + +// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E +// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E +// +// <prefix> ::= <prefix> <unqualified-name> +// ::= <template-prefix> <template-args> +// ::= <template-param> +// ::= <decltype> +// ::= # empty +// ::= <substitution> +// ::= <prefix> <data-member-prefix> +// extension ::= L +// +// <template-prefix> ::= <prefix> <template unqualified-name> +// ::= <template-param> +// ::= <substitution> + +const char* +__demangle_tree::__parse_nested_name(const char* first, const char* last) +{ + if (first != last && *first == 'N') + { + unsigned cv = 0; + const char* t0 = __parse_cv_qualifiers(first+1, last, cv, true); + __node* prev = NULL; + if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') + { + t0 += 2; + if (!__make<__std_qualified_name>()) + return first; + prev = __root_; + } + while (t0 != last) + { + bool can_sub = true; + bool make_nested = true; + const char* t1; + switch (*t0) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + t1 = __parse_source_name(t0, last); + if (t1 == t0 || t1 == last) + return first; + if (*t1 == 'M') + { + // This is a data-member-prefix + ++t1; + } + else if (*t1 == 'I') + { + // has following <template-args> + if (prev) + { + if (!__make<__nested_delimeter>(prev, __root_)) + return first; + make_nested = false; + } + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + else + *__sub_end_++ = __root_; + const char* t2 = __parse_template_args(t1, last); + if (t2 == t1) + return first; + t1 = t2; + } + break; + case 'D': + if (t0+1 != last && (t0[1] == 't' || t0[1] == 'T')) + { + t1 = __parse_decltype(t0, last); + break; + } + // check for Dt, DT here, else drop through + case 'C': + t1 = __parse_ctor_dtor_name(t0, last); + if (t1 == t0 || t1 == last) + return first; + if (*t1 == 'I') + { + // has following <template-args> + if (prev) + { + if (!__make<__nested_delimeter>(prev, __root_)) + return first; + make_nested = false; + } + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + else + *__sub_end_++ = __root_; + const char* t2 = __parse_template_args(t1, last); + if (t2 == t1) + return first; + t1 = t2; + } + break; + case 'U': + assert(!"__parse_nested_name U"); + // could have following <template-args> + break; + case 'T': + t1 = __parse_template_param(t0, last); + if (t1 == t0 || t1 == last) + return first; + if (*t1 == 'I') + { + // has following <template-args> + if (prev) + { + if (!__make<__nested_delimeter>(prev, __root_)) + return first; + make_nested = false; + } + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + else + *__sub_end_++ = __root_; + const char* t2 = __parse_template_args(t1, last); + if (t2 == t1) + return first; + t1 = t2; + } + break; + case 'S': + t1 = __parse_substitution(t0, last); + if (t1 == t0 || t1 == last) + return first; + if (*t1 == 'I') + { + const char* t2 = __parse_template_args(t1, last); + if (t2 == t1) + return first; + t1 = t2; + } + else + can_sub = false; + break; + case 'L': + // extension: ignore L here + ++t0; + continue; + default: + t1 = __parse_operator_name(t0, last); + if (t1 == t0 || t1 == last) + return first; + if (*t1 == 'I') + { + // has following <template-args> + if (prev) + { + if (!__make<__nested_delimeter>(prev, __root_)) + return first; + make_nested = false; + } + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + else + *__sub_end_++ = __root_; + const char* t2 = __parse_template_args(t1, last); + if (t2 == t1) + return first; + t1 = t2; + } + break; + } + if (t1 == t0 || t1 == last) + return first; + if (prev && make_nested) + { + if (!__make<__nested_delimeter>(prev, __root_)) + return first; + can_sub = true; + } + if (can_sub && *t1 != 'E') + { + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + else + *__sub_end_++ = __root_; + } + if (*t1 == 'E') + { + if (cv != 0) + { + if (!__make<__cv_qualifiers>(cv, __root_)) + return first; + } + first = t1+1; + break; + } + prev = __root_; + t0 = t1; + } + } + return first; +} + +// <template-arg> ::= <type> # type or template +// ::= X <expression> E # expression +// ::= <expr-primary> # simple expressions +// ::= J <template-arg>* E # argument pack +// ::= LZ <encoding> E # extension + +const char* +__demangle_tree::__parse_template_arg(const char* first, const char* last) +{ + if (first != last) + { + const char* t; + switch (*first) + { + case 'X': + t = __parse_expression(first+1, last); + if (t != first+1) + { + if (t != last && *t == 'E') + first = t+1; + } + break; + case 'J': + t = first+1; + if (t == last) + return first; + if (*t == 'E') + { + if (__make<__list>((__node*)0)) + first = t+1; + } + else + { + __node* list = NULL; + __node* prev = NULL; + do + { + const char* t2 = __parse_template_arg(t, last); + if (t2 == t || !__make<__list>(__root_)) + return first; + if (list == 0) + list = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + t = t2; + } while (t != last && *t != 'E'); + first = t+1; + __root_ = list; + } + break; + case 'L': + // <expr-primary> or LZ <encoding> E + if (first+1 != last && first[1] == 'Z') + { + t = __parse_encoding(first+2, last); + if (t != first+2 && t != last && *t == 'E') + first = t+1; + } + else + first = __parse_expr_primary(first, last); + break; + default: + // <type> + first = __parse_type(first, last); + break; + } + } + return first; +} + +// <template-args> ::= I <template-arg>* E +// extension, the abi says <template-arg>+ + +const char* +__demangle_tree::__parse_template_args(const char* first, const char* last) +{ + if (last - first >= 2 && *first == 'I') + { + __node* args = NULL; + __node* prev = NULL; + __node* name = __root_; + if (__tag_templates_) + __t_end_ = __t_begin_; + const char* t = first+1; + while (*t != 'E') + { + bool prev_tag_templates = __tag_templates_; + __node** prev_t_begin = __t_begin_; + __node** prev_t_end = __t_end_; + if (__tag_templates_) + __t_begin_ = __t_end_; + const char* t2 = __parse_template_arg(t, last); + if (prev_tag_templates) + { + __tag_templates_ = prev_tag_templates; + __t_begin_ = prev_t_begin; + __t_end_ = prev_t_end; + } + if (t2 == t || t2 == last) + break; + if (!__make<__list>(__root_)) + return first; + if (args == 0) + args = __root_; + if (prev) + { + prev->__right_ = __root_; + __root_->__size_ = prev->__size_ + 1; + } + prev = __root_; + if (__tag_templates_) + { + if (__t_end_ == __t_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + if (__root_->__left_) + *__t_end_++ = __root_->__left_; + else + *__t_end_++ = __root_; + } + t = t2; + } + if (t != last && *t == 'E') + { + if (__make<__template_args>(name, args)) + first = t+1; + } + } + return first; +} + +// <substitution> ::= S <seq-id> _ +// ::= S_ +// <substitution> ::= Sa # ::std::allocator +// <substitution> ::= Sb # ::std::basic_string +// <substitution> ::= Ss # ::std::basic_string < char, +// ::std::char_traits<char>, +// ::std::allocator<char> > +// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > +// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > +// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > + +const char* +__demangle_tree::__parse_substitution(const char* first, const char* last) +{ + if (last - first >= 2) + { + if (*first == 'S') + { + switch (first[1]) + { + case 'a': + if (__make<__sub_allocator>()) + first += 2; + break; + case 'b': + if (__make<__sub_basic_string>()) + first += 2; + break; + case 's': + if (__make<__sub_string>()) + first += 2; + break; + case 'i': + if (__make<__sub_istream>()) + first += 2; + break; + case 'o': + if (__make<__sub_ostream>()) + first += 2; + break; + case 'd': + if (__make<__sub_iostream>()) + first += 2; + break; + case '_': + if (__sub_begin_ != __sub_end_) + { + if (__make<__sub>(*__sub_begin_)) + first += 2; + } + break; + default: + if (isdigit(first[1]) || isupper(first[1])) + { + size_t sub = 0; + const char* t = first+1; + if (isdigit(*t)) + sub = *t - '0'; + else + sub = *t - 'A' + 10; + for (++t; t != last && (isdigit(*t) || isupper(*t)); ++t) + { + sub *= 36; + if (isdigit(*t)) + sub += *t - '0'; + else + sub += *t - 'A' + 10; + } + if (t == last || *t != '_') + return first; + ++sub; + if (sub < __sub_end_ - __sub_begin_) + { + if (__make<__sub>(__sub_begin_[sub])) + first = t+1; + } + } + break; + } + } + } + return first; +} + +// <name> ::= <nested-name> +// ::= <local-name> # See Scope Encoding below +// ::= <unscoped-template-name> <template-args> +// ::= <unscoped-name> + +const char* +__demangle_tree::__parse_name(const char* first, const char* last) +{ + if (first != last) + { + const char* t0 = first; + // extension: ignore L here + if (*t0 == 'L') + ++t0; + const char* t = __parse_nested_name(t0, last); + if (t == t0) + { + t = __parse_local_name(t0, last); + if (t == t0) + { + // not <nested-name> nor <local-name> + // Try to parse <unscoped-template-name> <template-args> or + // <unscoped-name> which are nearly ambiguous. + // This logic occurs nowhere else. + if (last - t0 >= 2) + { + if (t0[0] == 'S' && (t0[1] == '_' || + isdigit(t0[1]) || + isupper(t0[1]) || + t0[1] == 'a' || + t0[1] == 'b')) + { + t = __parse_substitution(t0, last); + if (t != t0) + { + const char* t2 = __parse_template_args(t, last); + if (t2 != t) + first = t2; + } + } + else // Not a substitution, except maybe St + { + t = __parse_unscoped_name(t0, last); + if (t != t0) + { + // unscoped-name might be <unscoped-template-name> + if (t != last && *t == 'I') + { + if (__sub_end_ == __sub_cap_) + { + __status_ = memory_alloc_failure; + return first; + } + *__sub_end_++ = __root_; + const char* t2 = __parse_template_args(t, last); + if (t2 != t) + first = t2; + } + else + { + // <unscoped-name> + first = t; + } + } + } + } + } + else + first = t; + } + else + first = t; + } + return first; +} + +// extension +// <dot-suffix> := .<anything and everything> + +const char* +__demangle_tree::__parse_dot_suffix(const char* first, const char* last) +{ + if (first != last && *first == '.') + { + if (__make<__dot_suffix>(__root_, first, last-first)) + first = last; + } + return first; +} + +// <encoding> ::= <function name> <bare-function-type> +// ::= <data name> +// ::= <special-name> + +const char* +__demangle_tree::__parse_encoding(const char* first, const char* last) +{ + const char* t = __parse_name(first, last); + if (t != first) + { + if (t != last && *t != 'E' && *t != '.') + { + __node* name = __root_; + bool has_return = name->ends_with_template(true) && + !name->is_ctor_dtor_conv(); + __node* ret = NULL; + const char* t2; + __tag_templates_ = false; + if (has_return) + { + t2 = __parse_type(t, last); + if (t2 != t) + { + ret = __root_; + t = t2; + } + else + return first; + } + t2 = __parse_bare_function_type(t, last); + if (t2 != t) + { + if (dynamic_cast<__void*>(__root_->__left_) != NULL) + __root_->__left_ = NULL; + if (__make<__function_signature>(ret, __root_)) + { + __node* cv = name->extract_cv(name); + if (__make<__function>(name, __root_)) + { + if (cv) + { + cv->__left_ = __root_; + cv->__size_ <<= 5; + __root_ = cv; + } + first = t2; + } + } + } + __tag_templates_ = true; + } + else + first = t; + } + else + first = __parse_special_name(first, last); + return first; +} + +// <mangled-name> ::= _Z<encoding> +// ::= <type> + +void +__demangle_tree::__parse() +{ + if (__mangled_name_begin_ == __mangled_name_end_) + { + __status_ = invalid_mangled_name; + return; + } + const char* t = NULL; + if (__mangled_name_end_ - __mangled_name_begin_ >= 2 && + __mangled_name_begin_[0] == '_' && + __mangled_name_begin_[1] == 'Z') + { + t = __parse_encoding(__mangled_name_begin_+2, __mangled_name_end_); + if (t != __mangled_name_begin_+2 && t != __mangled_name_end_ && *t == '.') + t = __parse_dot_suffix(t, __mangled_name_end_); + } + else + t = __parse_type(__mangled_name_begin_, __mangled_name_end_); + if (t == __mangled_name_end_ && __root_) + { + if (__fix_forward_references_) + { + if (__root_->fix_forward_references(__t_begin_, __t_end_)) + __status_ = success; + } + else + __status_ = success; + } +} + +__demangle_tree +__demangle(const char* mangled_name, char* buf, size_t bs) +{ + __demangle_tree t(mangled_name, buf, bs); + if (t.__status() == invalid_mangled_name) + t.__parse(); + return t; +} + +__demangle_tree +__demangle(const char* mangled_name) +{ + return __demangle(mangled_name, 0, 0); +} + +char* +__demangle(__demangle_tree dmg_tree, char* buf, size_t* n, int* status) +{ + if (dmg_tree.__status() != success) + { + if (status) + *status = dmg_tree.__status(); + return NULL; + } +#ifdef DEBUGGING +display(dmg_tree.__root_); +printf("\n"); +#endif + const size_t bs = buf == NULL ? 0 : *n; + ptrdiff_t sm = dmg_tree.__mangled_name_end_ - dmg_tree.__mangled_name_begin_; + ptrdiff_t est = sm + 60 * ( + (dmg_tree.__node_end_ - dmg_tree.__node_begin_) + + (dmg_tree.__sub_end_ - dmg_tree.__sub_begin_) + + (dmg_tree.__t_end_ - dmg_tree.__t_begin_)); + const unsigned N = 4096; + char tmp[N]; + ptrdiff_t s; + if (est <= bs) + { + char* e = dmg_tree.__get_demangled_name(buf); + *e++ = '\0'; + s = e - buf; + } + else if (est <= N) + { + char* e = dmg_tree.__get_demangled_name(tmp); + *e++ = '\0'; + s = e - tmp; + } + else + s = dmg_tree.size() + 1; + if (s > bs) + { + buf = static_cast<char*>(realloc(buf, s)); + if (buf == NULL) + { + if (status) + *status = memory_alloc_failure; + return NULL; + } + if (n) + *n = s; + } + if (est > bs) + { + if (est <= N) + strncpy(buf, tmp, s); + else + *dmg_tree.__get_demangled_name(buf) = '\0'; + } + if (status) + *status = success; + return buf; +} + +} // __libcxxabi + +#pragma GCC visibility pop +#pragma GCC visibility push(default) + +extern "C" +{ + +char* +__cxa_demangle(const char* mangled_name, char* buf, size_t* n, int* status) +{ + if (mangled_name == NULL || (buf != NULL && n == NULL)) + { + if (status) + *status = __libcxxabi::invalid_args; + return NULL; + } + const size_t bs = 64 * 1024; + __attribute((aligned(16))) char static_buf[bs]; + + buf = __libcxxabi::__demangle(__libcxxabi::__demangle(mangled_name, + static_buf, bs), + buf, n, status); + return buf; +} + +} // extern "C" + +} // abi diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp new file mode 100644 index 00000000..b866f9e4 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception.cpp @@ -0,0 +1,622 @@ +//===------------------------- cxa_exception.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Exception Handling APIs" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +#include "cxxabi.h" + +#include <exception> // for std::terminate +#include <cstdlib> // for malloc, free +#include <string> // for memset +#include <pthread.h> + +#include "cxa_exception.hpp" +#include "cxa_handlers.hpp" + +// +---------------------------+-----------------------------+---------------+ +// | __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | +// +---------------------------+-----------------------------+---------------+ +// ^ +// | +// +-------------------------------------------------------+ +// | +// +---------------------------+-----------------------------+ +// | __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | +// +---------------------------+-----------------------------+ + +namespace __cxxabiv1 { + +#pragma GCC visibility push(default) + +// Utility routines +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +// Note: This is never called when exception_header is masquerading as a +// __cxa_dependent_exception. +static +inline +void* +thrown_object_from_cxa_exception(__cxa_exception* exception_header) +{ + return static_cast<void*>(exception_header + 1); +} + +// Get the exception object from the unwind pointer. +// Relies on the structure layout, where the unwind pointer is right in +// front of the user's exception object +static +inline +__cxa_exception* +cxa_exception_from_exception_unwind_exception(_Unwind_Exception* unwind_exception) +{ + return cxa_exception_from_thrown_object(unwind_exception + 1 ); +} + +static +inline +size_t +cxa_exception_size_from_exception_thrown_size(size_t size) +{ + return size + sizeof (__cxa_exception); +} + +static void setExceptionClass(_Unwind_Exception* unwind_exception) { + unwind_exception->exception_class = kOurExceptionClass; +} + +static void setDependentExceptionClass(_Unwind_Exception* unwind_exception) { + unwind_exception->exception_class = kOurDependentExceptionClass; +} + +// Is it one of ours? +static bool isOurExceptionClass(const _Unwind_Exception* unwind_exception) { + return (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); +} + +static bool isDependentException(_Unwind_Exception* unwind_exception) { + return (unwind_exception->exception_class & 0xFF) == 0x01; +} + +// This does not need to be atomic +static inline int incrementHandlerCount(__cxa_exception *exception) { + return ++exception->handlerCount; +} + +// This does not need to be atomic +static inline int decrementHandlerCount(__cxa_exception *exception) { + return --exception->handlerCount; +} + +#include "fallback_malloc.ipp" + +// Allocate some memory from _somewhere_ +static void *do_malloc(size_t size) { + void *ptr = std::malloc(size); + if (NULL == ptr) // if malloc fails, fall back to emergency stash + ptr = fallback_malloc(size); + return ptr; +} + +static void do_free(void *ptr) { + is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr); +} + +/* + If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler + stored in exc is called. Otherwise the exceptionDestructor stored in + exc is called, and then the memory for the exception is deallocated. + + This is never called for a __cxa_dependent_exception. +*/ +static +void +exception_cleanup_func(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) +{ + __cxa_exception* exception_header = cxa_exception_from_exception_unwind_exception(unwind_exception); + if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) + std::__terminate(exception_header->terminateHandler); + // Just in case there exists a dependent exception that is pointing to this, + // check the reference count and only destroy this if that count goes to zero. + __cxa_decrement_exception_refcount(unwind_exception + 1); +} + +static LIBCXXABI_NORETURN void failed_throw(__cxa_exception* exception_header) { +// Section 2.5.3 says: +// * For purposes of this ABI, several things are considered exception handlers: +// ** A terminate() call due to a throw. +// and +// * Upon entry, Following initialization of the catch parameter, +// a handler must call: +// * void *__cxa_begin_catch(void *exceptionObject ); + (void) __cxa_begin_catch(&exception_header->unwindHeader); + std::__terminate(exception_header->terminateHandler); +} + +extern "C" { + +// Allocate a __cxa_exception object, and zero-fill it. +// Reserve "thrown_size" bytes on the end for the user's exception +// object. Zero-fill the object. If memory can't be allocated, call +// std::terminate. Return a pointer to the memory to be used for the +// user's exception object. +void * __cxa_allocate_exception (size_t thrown_size) throw() { + size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); + __cxa_exception* exception_header = static_cast<__cxa_exception*>(do_malloc(actual_size)); + if (NULL == exception_header) + std::terminate(); + std::memset(exception_header, 0, actual_size); + return thrown_object_from_cxa_exception(exception_header); +} + + +// Free a __cxa_exception object allocated with __cxa_allocate_exception. +void __cxa_free_exception (void * thrown_object) throw() { + do_free(cxa_exception_from_thrown_object(thrown_object)); +} + + +// This function shall allocate a __cxa_dependent_exception and +// return a pointer to it. (Really to the object, not past its' end). +// Otherwise, it will work like __cxa_allocate_exception. +void * __cxa_allocate_dependent_exception () { + size_t actual_size = sizeof(__cxa_dependent_exception); + void *ptr = do_malloc(actual_size); + if (NULL == ptr) + std::terminate(); + std::memset(ptr, 0, actual_size); + return ptr; +} + + +// This function shall free a dependent_exception. +// It does not affect the reference count of the primary exception. +void __cxa_free_dependent_exception (void * dependent_exception) { + do_free(dependent_exception); +} + + +// 2.4.3 Throwing the Exception Object +/* +After constructing the exception object with the throw argument value, +the generated code calls the __cxa_throw runtime library routine. This +routine never returns. + +The __cxa_throw routine will do the following: + +* Obtain the __cxa_exception header from the thrown exception object address, +which can be computed as follows: + __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); +* Save the current unexpected_handler and terminate_handler in the __cxa_exception header. +* Save the tinfo and dest arguments in the __cxa_exception header. +* Set the exception_class field in the unwind header. This is a 64-bit value +representing the ASCII string "XXXXC++\0", where "XXXX" is a +vendor-dependent string. That is, for implementations conforming to this +ABI, the low-order 4 bytes of this 64-bit value will be "C++\0". +* Increment the uncaught_exception flag. +* Call _Unwind_RaiseException in the system unwind library, Its argument is the +pointer to the thrown exception, which __cxa_throw itself received as an argument. +__Unwind_RaiseException begins the process of stack unwinding, described +in Section 2.5. In special cases, such as an inability to find a +handler, _Unwind_RaiseException may return. In that case, __cxa_throw +will call terminate, assuming that there was no handler for the +exception. +*/ +LIBCXXABI_NORETURN +void +__cxa_throw(void* thrown_object, std::type_info* tinfo, void (*dest)(void*)) +{ + __cxa_eh_globals *globals = __cxa_get_globals(); + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + + exception_header->unexpectedHandler = std::get_unexpected(); + exception_header->terminateHandler = std::get_terminate(); + exception_header->exceptionType = tinfo; + exception_header->exceptionDestructor = dest; + setExceptionClass(&exception_header->unwindHeader); + exception_header->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. + globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local + + exception_header->unwindHeader.exception_cleanup = exception_cleanup_func; +#if __arm__ + _Unwind_SjLj_RaiseException(&exception_header->unwindHeader); +#else + _Unwind_RaiseException(&exception_header->unwindHeader); +#endif + // This only happens when there is no handler, or some unexpected unwinding + // error happens. + failed_throw(exception_header); +} + + +// 2.5.3 Exception Handlers +/* +The adjusted pointer is computed by the personality routine during phase 1 + and saved in the exception header (either __cxa_exception or + __cxa_dependent_exception). + + Requires: exception is native +*/ +void* +__cxa_get_exception_ptr(void* unwind_exception) throw() +{ + return cxa_exception_from_exception_unwind_exception + ( + static_cast<_Unwind_Exception*>(unwind_exception) + )->adjustedPtr; +} + +/* +This routine can catch foreign or native exceptions. If native, the exception +can be a primary or dependent variety. This routine may remain blissfully +ignorant of whether the native exception is primary or dependent. + +If the exception is native: +* Increment's the exception's handler count. +* Push the exception on the stack of currently-caught exceptions if it is not + already there (from a rethrow). +* Decrements the uncaught_exception count. +* Returns the adjusted pointer to the exception object, which is stored in + the __cxa_exception by the personality routine. + +If the exception is foreign, this means it did not originate from one of throw +routines. The foreign exception does not necessarily have a __cxa_exception +header. However we can catch it here with a catch (...), or with a call +to terminate or unexpected during unwinding. +* Do not try to increment the exception's handler count, we don't know where + it is. +* Push the exception on the stack of currently-caught exceptions only if the + stack is empty. The foreign exception has no way to link to the current + top of stack. If the stack is not empty, call terminate. Even with an + empty stack, this is hacked in by pushing a pointer to an imaginary + __cxa_exception block in front of the foreign exception. It would be better + if the __cxa_eh_globals structure had a stack of _Unwind_Exception, but it + doesn't. It has a stack of __cxa_exception (which has a next* in it). +* Do not decrement the uncaught_exception count because we didn't increment it + in __cxa_throw (or one of our rethrow functions). +* If we haven't terminated, assume the exception object is just past the + _Unwind_Exception and return a pointer to that. +*/ +void* +__cxa_begin_catch(void* unwind_arg) throw() +{ + _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); + bool native_exception = isOurExceptionClass(unwind_exception); + __cxa_eh_globals* globals = __cxa_get_globals(); + // exception_header is a hackish offset from a foreign exception, but it + // works as long as we're careful not to try to access any __cxa_exception + // parts. + __cxa_exception* exception_header = + cxa_exception_from_exception_unwind_exception + ( + static_cast<_Unwind_Exception*>(unwind_exception) + ); + if (native_exception) + { + // Increment the handler count, removing the flag about being rethrown + exception_header->handlerCount = exception_header->handlerCount < 0 ? + -exception_header->handlerCount + 1 : exception_header->handlerCount + 1; + // place the exception on the top of the stack if it's not already + // there by a previous rethrow + if (exception_header != globals->caughtExceptions) + { + exception_header->nextException = globals->caughtExceptions; + globals->caughtExceptions = exception_header; + } + globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local + return exception_header->adjustedPtr; + } + // Else this is a foreign exception + // If the caughtExceptions stack is not empty, terminate + if (globals->caughtExceptions != 0) + std::terminate(); + // Push the foreign exception on to the stack + globals->caughtExceptions = exception_header; + return unwind_exception + 1; +} + + +/* +Upon exit for any reason, a handler must call: + void __cxa_end_catch (); + +This routine can be called for either a native or foreign exception. +For a native exception: +* Locates the most recently caught exception and decrements its handler count. +* Removes the exception from the caught exception stack, if the handler count goes to zero. +* If the handler count goes down to zero, and the exception was not re-thrown + by throw, it locates the primary exception (which may be the same as the one + it's handling) and decrements its reference count. If that reference count + goes to zero, the function destroys the exception. In any case, if the current + exception is a dependent exception, it destroys that. + +For a foreign exception: +* If it has been rethrown, there is nothing to do. +* Otherwise delete the exception and pop the catch stack to empty. +*/ +void __cxa_end_catch() +{ + static_assert(sizeof(__cxa_exception) == sizeof(__cxa_dependent_exception), + "sizeof(__cxa_exception) must be equal to sizeof(__cxa_dependent_exception)"); + __cxa_eh_globals* globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch + __cxa_exception* exception_header = globals->caughtExceptions; + // If we've rethrown a foreign exception, then globals->caughtExceptions + // will have been made an empty stack by __cxa_rethrow() and there is + // nothing more to be done. Do nothing! + if (NULL != exception_header) + { + bool native_exception = isOurExceptionClass(&exception_header->unwindHeader); + if (native_exception) + { + // This is a native exception + if (exception_header->handlerCount < 0) + { + // The exception has been rethrown by __cxa_rethrow, so don't delete it + if (0 == incrementHandlerCount(exception_header)) + { + // Remove from the chain of uncaught exceptions + globals->caughtExceptions = exception_header->nextException; + // but don't destroy + } + // Keep handlerCount negative in case there are nested catch's + // that need to be told that this exception is rethrown. Don't + // erase this rethrow flag until the exception is recaught. + } + else + { + // The native exception has not been rethrown + if (0 == decrementHandlerCount(exception_header)) + { + // Remove from the chain of uncaught exceptions + globals->caughtExceptions = exception_header->nextException; + // Destroy this exception, being careful to distinguish + // between dependent and primary exceptions + if (isDependentException(&exception_header->unwindHeader)) + { + // Reset exception_header to primaryException and deallocate the dependent exception + __cxa_dependent_exception* dep_exception_header = + reinterpret_cast<__cxa_dependent_exception*>(exception_header); + exception_header = + cxa_exception_from_thrown_object(dep_exception_header->primaryException); + __cxa_free_dependent_exception(dep_exception_header); + } + // Destroy the primary exception only if its referenceCount goes to 0 + // (this decrement must be atomic) + __cxa_decrement_exception_refcount(thrown_object_from_cxa_exception(exception_header)); + } + } + } + else + { + // The foreign exception has not been rethrown. Pop the stack + // and delete it. If there are nested catch's and they try + // to touch a foreign exception in any way, that is undefined + // behavior. They likely can't since the only way to catch + // a foreign exception is with catch (...)! + _Unwind_DeleteException(&globals->caughtExceptions->unwindHeader); + globals->caughtExceptions = 0; + } + } +} + +// Note: exception_header may be masquerading as a __cxa_dependent_exception +// and that's ok. exceptionType is there too. +// However watch out for foreign exceptions. Return null for them. +std::type_info * __cxa_current_exception_type() { +// get the current exception + __cxa_eh_globals *globals = __cxa_get_globals_fast(); + if (NULL == globals) + return NULL; // If there have never been any exceptions, there are none now. + __cxa_exception *exception_header = globals->caughtExceptions; + if (NULL == exception_header) + return NULL; // No current exception + if (!isOurExceptionClass(&exception_header->unwindHeader)) + return NULL; + return exception_header->exceptionType; +} + +// 2.5.4 Rethrowing Exceptions +/* This routine can rethrow native or foreign exceptions. +If the exception is native: +* marks the exception object on top of the caughtExceptions stack + (in an implementation-defined way) as being rethrown. +* If the caughtExceptions stack is empty, it calls terminate() + (see [C++FDIS] [except.throw], 15.1.8). +* It then calls _Unwind_RaiseException which should not return + (terminate if it does). + Note: exception_header may be masquerading as a __cxa_dependent_exception + and that's ok. +*/ +LIBCXXABI_NORETURN +void +__cxa_rethrow() +{ + __cxa_eh_globals* globals = __cxa_get_globals(); + __cxa_exception* exception_header = globals->caughtExceptions; + if (NULL == exception_header) + std::terminate(); // throw; called outside of a exception handler + bool native_exception = isOurExceptionClass(&exception_header->unwindHeader); + if (native_exception) + { + // Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) + exception_header->handlerCount = -exception_header->handlerCount; + globals->uncaughtExceptions += 1; + // __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary + } + else // this is a foreign exception + { + // The only way to communicate to __cxa_end_catch that we've rethrown + // a foreign exception, so don't delete us, is to pop the stack here + // which must be empty afterwards. Then __cxa_end_catch will do + // nothing + globals->caughtExceptions = 0; + } +#if __arm__ + (void) _Unwind_SjLj_Resume_or_Rethrow(&exception_header->unwindHeader); +#else + (void)_Unwind_RaiseException(&exception_header->unwindHeader); +#endif + + // If we get here, some kind of unwinding error has occurred. + // There is some weird code generation bug happening with + // Apple clang version 4.0 (tags/Apple/clang-418.0.2) (based on LLVM 3.1svn) + // If we call failed_throw here. Turns up with -O2 or higher, and -Os. + __cxa_begin_catch(&exception_header->unwindHeader); + if (native_exception) + std::__terminate(exception_header->terminateHandler); + // Foreign exception: can't get exception_header->terminateHandler + std::terminate(); +} + +/* + If thrown_object is not null, atomically increment the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +void +__cxa_increment_exception_refcount(void* thrown_object) throw() +{ + if (thrown_object != NULL ) + { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + __sync_add_and_fetch(&exception_header->referenceCount, 1); + } +} + +/* + If thrown_object is not null, atomically decrement the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. If the referenceCount drops to zero, destroy and + deallocate the exception. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +void +__cxa_decrement_exception_refcount(void* thrown_object) throw() +{ + if (thrown_object != NULL ) + { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + if (__sync_sub_and_fetch(&exception_header->referenceCount, size_t(1)) == 0) + { + if (NULL != exception_header->exceptionDestructor) + exception_header->exceptionDestructor(thrown_object); + __cxa_free_exception(thrown_object); + } + } +} + +/* + Returns a pointer to the thrown object (if any) at the top of the + caughtExceptions stack. Atommically increment the exception's referenceCount. + If there is no such thrown object or if the thrown object is foreign, + returns null. + + We can use __cxa_get_globals_fast here to get the globals because if there have + been no exceptions thrown, ever, on this thread, we can return NULL without + the need to allocate the exception-handling globals. +*/ +void* +__cxa_current_primary_exception() throw() +{ +// get the current exception + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (NULL == globals) + return NULL; // If there are no globals, there is no exception + __cxa_exception* exception_header = globals->caughtExceptions; + if (NULL == exception_header) + return NULL; // No current exception + if (!isOurExceptionClass(&exception_header->unwindHeader)) + return NULL; // Can't capture a foreign exception (no way to refcount it) + if (isDependentException(&exception_header->unwindHeader)) { + __cxa_dependent_exception* dep_exception_header = + reinterpret_cast<__cxa_dependent_exception*>(exception_header); + exception_header = cxa_exception_from_thrown_object(dep_exception_header->primaryException); + } + void* thrown_object = thrown_object_from_cxa_exception(exception_header); + __cxa_increment_exception_refcount(thrown_object); + return thrown_object; +} + +/* + If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler + stored in exc is called. Otherwise the referenceCount stored in the + primary exception is decremented, destroying the primary if necessary. + Finally the dependent exception is destroyed. +*/ +static +void +dependent_exception_cleanup(_Unwind_Reason_Code reason, _Unwind_Exception* unwind_exception) +{ + __cxa_dependent_exception* dep_exception_header = + reinterpret_cast<__cxa_dependent_exception*>(unwind_exception + 1) - 1; + if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) + std::__terminate(dep_exception_header->terminateHandler); + __cxa_decrement_exception_refcount(dep_exception_header->primaryException); + __cxa_free_dependent_exception(dep_exception_header); +} + +/* + If thrown_object is not null, allocate, initialize and thow a dependent + exception. +*/ +void +__cxa_rethrow_primary_exception(void* thrown_object) +{ + if ( thrown_object != NULL ) + { + // thrown_object guaranteed to be native because + // __cxa_current_primary_exception returns NULL for foreign exceptions + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + __cxa_dependent_exception* dep_exception_header = + static_cast<__cxa_dependent_exception*>(__cxa_allocate_dependent_exception()); + dep_exception_header->primaryException = thrown_object; + __cxa_increment_exception_refcount(thrown_object); + dep_exception_header->exceptionType = exception_header->exceptionType; + dep_exception_header->unexpectedHandler = std::get_unexpected(); + dep_exception_header->terminateHandler = std::get_terminate(); + setDependentExceptionClass(&dep_exception_header->unwindHeader); + __cxa_get_globals()->uncaughtExceptions += 1; + dep_exception_header->unwindHeader.exception_cleanup = dependent_exception_cleanup; +#if __arm__ + _Unwind_SjLj_RaiseException(&dep_exception_header->unwindHeader); +#else + _Unwind_RaiseException(&dep_exception_header->unwindHeader); +#endif + // Some sort of unwinding error. Note that terminate is a handler. + __cxa_begin_catch(&dep_exception_header->unwindHeader); + } + // If we return client will call terminate() +} + +bool +__cxa_uncaught_exception() throw() +{ + // This does not report foreign exceptions in flight + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (globals == 0) + return false; + return globals->uncaughtExceptions != 0; +} + +} // extern "C" + +#pragma GCC visibility pop + +} // abi diff --git a/system/lib/libcxxabi/src/cxa_exception.hpp b/system/lib/libcxxabi/src/cxa_exception.hpp new file mode 100644 index 00000000..cf019d4c --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception.hpp @@ -0,0 +1,118 @@ +//===------------------------- cxa_exception.hpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Exception Handling APIs" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +#include <exception> // for std::unexpected_handler and std::terminate_handler +#include <cxxabi.h> +#include "unwind.h" + +namespace __cxxabiv1 { + +#pragma GCC visibility push(hidden) + +static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 +static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 +static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask for CLNGC++ + + struct __cxa_exception { +#if __LP64__ + // This is a new field to support C++ 0x exception_ptr. + // For binary compatibility it is at the start of this + // struct which is prepended to the object thrown in + // __cxa_allocate_exception. + size_t referenceCount; +#endif + + // Manage the exception object itself. + std::type_info *exceptionType; + void (*exceptionDestructor)(void *); + std::unexpected_handler unexpectedHandler; + std::terminate_handler terminateHandler; + + __cxa_exception *nextException; + + int handlerCount; + +#ifdef __ARM_EABI_UNWINDER__ + __cxa_exception* nextPropagatingException; + int propagationCount; +#else + int handlerSwitchValue; + const unsigned char *actionRecord; + const unsigned char *languageSpecificData; + void *catchTemp; + void *adjustedPtr; +#endif + +#if !__LP64__ + // This is a new field to support C++ 0x exception_ptr. + // For binary compatibility it is placed where the compiler + // previously adding padded to 64-bit align unwindHeader. + size_t referenceCount; +#endif + + _Unwind_Exception unwindHeader; + }; + +// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html + + struct __cxa_dependent_exception { +#if __LP64__ + void* primaryException; +#endif + + std::type_info *exceptionType; + void (*exceptionDestructor)(void *); + std::unexpected_handler unexpectedHandler; + std::terminate_handler terminateHandler; + + __cxa_exception *nextException; + + int handlerCount; + +#ifdef __ARM_EABI_UNWINDER__ + __cxa_exception* nextPropagatingException; + int propagationCount; +#else + int handlerSwitchValue; + const unsigned char *actionRecord; + const unsigned char *languageSpecificData; + void * catchTemp; + void *adjustedPtr; +#endif + +#if !__LP64__ + void* primaryException; +#endif + + _Unwind_Exception unwindHeader; + }; + + struct __cxa_eh_globals { + __cxa_exception * caughtExceptions; + unsigned int uncaughtExceptions; +#ifdef __ARM_EABI_UNWINDER__ + __cxa_exception* propagatingExceptions; +#endif + }; + +#pragma GCC visibility pop +#pragma GCC visibility push(default) + + extern "C" __cxa_eh_globals * __cxa_get_globals (); + extern "C" __cxa_eh_globals * __cxa_get_globals_fast (); + + extern "C" void * __cxa_allocate_dependent_exception (); + extern "C" void __cxa_free_dependent_exception (void * dependent_exception); + +#pragma GCC visibility pop +} diff --git a/system/lib/libcxxabi/src/cxa_exception_storage.cpp b/system/lib/libcxxabi/src/cxa_exception_storage.cpp new file mode 100644 index 00000000..2c269c7f --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception_storage.cpp @@ -0,0 +1,91 @@ +//===--------------------- cxa_exception_storage.cpp ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the storage for the "Caught Exception Stack" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html (section 2.2.2) +// +//===----------------------------------------------------------------------===// + +#include "cxa_exception.hpp" + +#ifdef HAS_THREAD_LOCAL + +namespace __cxxabiv1 { + +namespace { + __cxa_eh_globals * __globals () { + static thread_local __cxa_eh_globals eh_globals; + return &eh_globals; + } + } + +extern "C" { + __cxa_eh_globals * __cxa_get_globals () { return __globals (); } + __cxa_eh_globals * __cxa_get_globals_fast () { return __globals (); } + } +} + +#else + +#include <pthread.h> +#include <cstdlib> // for calloc, free +#include "abort_message.h" + +// In general, we treat all pthread errors as fatal. +// We cannot call std::terminate() because that will in turn +// call __cxa_get_globals() and cause infinite recursion. + +namespace __cxxabiv1 { +namespace { + pthread_key_t key_; + pthread_once_t flag_ = PTHREAD_ONCE_INIT; + + void destruct_ (void *p) { + std::free ( p ); + if ( 0 != ::pthread_setspecific ( key_, NULL ) ) + abort_message("cannot zero out thread value for __cxa_get_globals()"); + } + + void construct_ () { + if ( 0 != pthread_key_create ( &key_, destruct_ ) ) + abort_message("cannot create pthread key for __cxa_get_globals()"); + } +} + +extern "C" { + __cxa_eh_globals * __cxa_get_globals () { + // Try to get the globals for this thread + __cxa_eh_globals* retVal = __cxa_get_globals_fast (); + + // If this is the first time we've been asked for these globals, create them + if ( NULL == retVal ) { + retVal = static_cast<__cxa_eh_globals*> + (std::calloc (1, sizeof (__cxa_eh_globals))); + if ( NULL == retVal ) + abort_message("cannot allocate __cxa_eh_globals"); + if ( 0 != pthread_setspecific ( key_, retVal ) ) + abort_message("pthread_setspecific failure in __cxa_get_globals()"); + } + return retVal; + } + + // Note that this implementation will reliably return NULL if not + // preceeded by a call to __cxa_get_globals(). This is an extension + // to the Itanium ABI and is taken advantage of in several places in + // libc++abi. + __cxa_eh_globals * __cxa_get_globals_fast () { + // First time through, create the key. + if (0 != pthread_once(&flag_, construct_)) + abort_message("pthread_once failure in __cxa_get_globals_fast()"); +// static int init = construct_(); + return static_cast<__cxa_eh_globals*>(::pthread_getspecific(key_)); + } + +} +} +#endif diff --git a/system/lib/libcxxabi/src/cxa_guard.cpp b/system/lib/libcxxabi/src/cxa_guard.cpp new file mode 100644 index 00000000..814aaeb1 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_guard.cpp @@ -0,0 +1,231 @@ +//===---------------------------- cxa_guard.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "abort_message.h" + +#include <pthread.h> +#include <stdint.h> + +/* + This implementation must be careful to not call code external to this file + which will turn around and try to call __cxa_guard_acquire reentrantly. + For this reason, the headers of this file are as restricted as possible. + Previous implementations of this code for __APPLE__ have used + pthread_mutex_lock and the abort_message utility without problem. This + implementation also uses pthread_cond_wait which has tested to not be a + problem. +*/ + +namespace __cxxabiv1 +{ + +namespace +{ + +#if LIBCXXABI_ARMEABI + +// A 32-bit, 4-byte-aligned static data value. The least significant 2 bits must +// be statically initialized to 0. +typedef uint32_t guard_type; + +// Test the lowest bit. +inline bool is_initialized(guard_type* guard_object) { + return (*guard_object) & 1; +} + +inline void set_initialized(guard_type* guard_object) { + *guard_object |= 1; +} + +#else + +typedef uint64_t guard_type; + +bool is_initialized(guard_type* guard_object) { + char* initialized = (char*)guard_object; + return *initialized; +} + +void set_initialized(guard_type* guard_object) { + char* initialized = (char*)guard_object; + *initialized = 1; +} + +#endif + +pthread_mutex_t guard_mut = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t guard_cv = PTHREAD_COND_INITIALIZER; + +#if __APPLE__ + +typedef uint32_t lock_type; + +#if __LITTLE_ENDIAN__ + +inline +lock_type +get_lock(uint64_t x) +{ + return static_cast<lock_type>(x >> 32); +} + +inline +void +set_lock(uint64_t& x, lock_type y) +{ + x = static_cast<uint64_t>(y) << 32; +} + +#else // __LITTLE_ENDIAN__ + +inline +lock_type +get_lock(uint64_t x) +{ + return static_cast<lock_type>(x); +} + +inline +void +set_lock(uint64_t& x, lock_type y) +{ + x = y; +} + +#endif // __LITTLE_ENDIAN__ + +#else // __APPLE__ + +typedef bool lock_type; + +inline +lock_type +get_lock(uint64_t x) +{ + union + { + uint64_t guard; + uint8_t lock[2]; + } f = {x}; + return f.lock[1] != 0; +} + +inline +void +set_lock(uint64_t& x, lock_type y) +{ + union + { + uint64_t guard; + uint8_t lock[2]; + } f = {0}; + f.lock[1] = y; + x = f.guard; +} + +inline +lock_type +get_lock(uint32_t x) +{ + union + { + uint32_t guard; + uint8_t lock[2]; + } f = {x}; + return f.lock[1] != 0; +} + +inline +void +set_lock(uint32_t& x, lock_type y) +{ + union + { + uint32_t guard; + uint8_t lock[2]; + } f = {0}; + f.lock[1] = y; + x = f.guard; +} + +#endif // __APPLE__ + +} // unnamed namespace + +extern "C" +{ + +int __cxa_guard_acquire(guard_type* guard_object) +{ + char* initialized = (char*)guard_object; + if (pthread_mutex_lock(&guard_mut)) + abort_message("__cxa_guard_acquire failed to acquire mutex"); + int result = *initialized == 0; + if (result) + { +#if __APPLE__ + const lock_type id = pthread_mach_thread_np(pthread_self()); + lock_type lock = get_lock(*guard_object); + if (lock) + { + // if this thread set lock for this same guard_object, abort + if (lock == id) + abort_message("__cxa_guard_acquire detected deadlock"); + do + { + if (pthread_cond_wait(&guard_cv, &guard_mut)) + abort_message("__cxa_guard_acquire condition variable wait failed"); + lock = get_lock(*guard_object); + } while (lock); + result = !is_initialized(guard_object); + if (result) + set_lock(*guard_object, id); + } + else + set_lock(*guard_object, id); +#else // __APPLE__ + while (get_lock(*guard_object)) + if (pthread_cond_wait(&guard_cv, &guard_mut)) + abort_message("__cxa_guard_acquire condition variable wait failed"); + result = *initialized == 0; + if (result) + set_lock(*guard_object, true); +#endif // __APPLE__ + } + if (pthread_mutex_unlock(&guard_mut)) + abort_message("__cxa_guard_acquire failed to release mutex"); + return result; +} + +void __cxa_guard_release(guard_type* guard_object) +{ + if (pthread_mutex_lock(&guard_mut)) + abort_message("__cxa_guard_release failed to acquire mutex"); + *guard_object = 0; + set_initialized(guard_object); + if (pthread_mutex_unlock(&guard_mut)) + abort_message("__cxa_guard_release failed to release mutex"); + if (pthread_cond_broadcast(&guard_cv)) + abort_message("__cxa_guard_release failed to broadcast condition variable"); +} + +void __cxa_guard_abort(guard_type* guard_object) +{ + if (pthread_mutex_lock(&guard_mut)) + abort_message("__cxa_guard_abort failed to acquire mutex"); + *guard_object = 0; + if (pthread_mutex_unlock(&guard_mut)) + abort_message("__cxa_guard_abort failed to release mutex"); + if (pthread_cond_broadcast(&guard_cv)) + abort_message("__cxa_guard_abort failed to broadcast condition variable"); +} + +} // extern "C" + +} // __cxxabiv1 diff --git a/system/lib/libcxxabi/src/cxa_handlers.cpp b/system/lib/libcxxabi/src/cxa_handlers.cpp new file mode 100644 index 00000000..be43181c --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_handlers.cpp @@ -0,0 +1,196 @@ +//===------------------------- cxa_handlers.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the functionality associated with the terminate_handler, +// unexpected_handler, and new_handler. +//===----------------------------------------------------------------------===// + +#include <stdexcept> +#include <new> +#include <exception> +#include "abort_message.h" +#include "cxxabi.h" +#include "cxa_handlers.hpp" +#include "cxa_exception.hpp" +#include "private_typeinfo.h" + +namespace std +{ + +static const char* cause = "uncaught"; + +static void default_terminate_handler() +{ + // If there might be an uncaught exception + using namespace __cxxabiv1; + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (globals) + { + __cxa_exception* exception_header = globals->caughtExceptions; + // If there is an uncaught exception + if (exception_header) + { + _Unwind_Exception* unwind_exception = + reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; + bool native_exception = + (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + if (native_exception) + { + void* thrown_object = + unwind_exception->exception_class == kOurDependentExceptionClass ? + ((__cxa_dependent_exception*)exception_header)->primaryException : + exception_header + 1; + const __shim_type_info* thrown_type = + static_cast<const __shim_type_info*>(exception_header->exceptionType); + // Try to get demangled name of thrown_type + int status; + char buf[1024]; + size_t len = sizeof(buf); + const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); + if (status != 0) + name = thrown_type->name(); + // If the uncaught exception can be caught with std::exception& + const __shim_type_info* catch_type = + static_cast<const __shim_type_info*>(&typeid(exception)); + if (catch_type->can_catch(thrown_type, thrown_object)) + { + // Include the what() message from the exception + const exception* e = static_cast<const exception*>(thrown_object); + abort_message("terminating with %s exception of type %s: %s", + cause, name, e->what()); + } + else + // Else just note that we're terminating with an exception + abort_message("terminating with %s exception of type %s", + cause, name); + } + else + // Else we're terminating with a foreign exception + abort_message("terminating with %s foreign exception", cause); + } + } + // Else just note that we're terminating + abort_message("terminating"); +} + +static void default_unexpected_handler() +{ + cause = "unexpected"; + terminate(); +} + +static terminate_handler __terminate_handler = default_terminate_handler; +static unexpected_handler __unexpected_handler = default_unexpected_handler; +static new_handler __new_handler = 0; + +unexpected_handler +set_unexpected(unexpected_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_unexpected_handler; + return __sync_lock_test_and_set(&__unexpected_handler, func); +} + +unexpected_handler +get_unexpected() _NOEXCEPT +{ + return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0); +} + +__attribute__((visibility("hidden"), noreturn)) +void +__unexpected(unexpected_handler func) +{ + func(); + // unexpected handler should not return + abort_message("unexpected_handler unexpectedly returned"); +} + +__attribute__((noreturn)) +void +unexpected() +{ + __unexpected(get_unexpected()); +} + +terminate_handler +set_terminate(terminate_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_terminate_handler; + return __sync_lock_test_and_set(&__terminate_handler, func); +} + +terminate_handler +get_terminate() _NOEXCEPT +{ + return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0); +} + +__attribute__((visibility("hidden"), noreturn)) +void +__terminate(terminate_handler func) _NOEXCEPT +{ +#if __has_feature(cxx_exceptions) + try + { +#endif // __has_feature(cxx_exceptions) + func(); + // handler should not return + abort_message("terminate_handler unexpectedly returned"); +#if __has_feature(cxx_exceptions) + } + catch (...) + { + // handler should not throw exception + abort_message("terminate_handler unexpectedly threw an exception"); + } +#endif // #if __has_feature(cxx_exceptions) +} + +__attribute__((noreturn)) +void +terminate() _NOEXCEPT +{ + // If there might be an uncaught exception + using namespace __cxxabiv1; + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + if (globals) + { + __cxa_exception* exception_header = globals->caughtExceptions; + if (exception_header) + { + _Unwind_Exception* unwind_exception = + reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1; + bool native_exception = + (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + if (native_exception) + { + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + __terminate(exception_header->terminateHandler); + } + } + } + __terminate(get_terminate()); +} + +new_handler +set_new_handler(new_handler handler) _NOEXCEPT +{ + return __sync_lock_test_and_set(&__new_handler, handler); +} + +new_handler +get_new_handler() _NOEXCEPT +{ + return __sync_fetch_and_add(&__new_handler, (new_handler)0); +} + +} // std diff --git a/system/lib/libcxxabi/src/cxa_handlers.hpp b/system/lib/libcxxabi/src/cxa_handlers.hpp new file mode 100644 index 00000000..a7f582c0 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_handlers.hpp @@ -0,0 +1,26 @@ +//===------------------------- cxa_handlers.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the functionality associated with the terminate_handler, +// unexpected_handler, and new_handler. +//===----------------------------------------------------------------------===// + +#include <exception> + +namespace std +{ + +__attribute__((visibility("hidden"), noreturn)) +void +__unexpected(unexpected_handler func); + +__attribute__((visibility("hidden"), noreturn)) +void +__terminate(terminate_handler func) _NOEXCEPT; + +} // std diff --git a/system/lib/libcxxabi/src/cxa_new_delete.cpp b/system/lib/libcxxabi/src/cxa_new_delete.cpp new file mode 100644 index 00000000..6352001b --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_new_delete.cpp @@ -0,0 +1,231 @@ +//===------------------------ cxa_new_delete.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the new and delete operators. +//===----------------------------------------------------------------------===// + +#include <new> +#include <cstdlib> + +/* +[new.delete.single] + +* Executes a loop: Within the loop, the function first attempts to allocate + the requested storage. Whether the attempt involves a call to the Standard C + library function malloc is unspecified. + +* Returns a pointer to the allocated storage if the attempt is successful. + Otherwise, if the current new_handler (18.6.2.5) is a null pointer value, + throws bad_alloc. + +* Otherwise, the function calls the current new_handler function (18.6.2.3). + If the called function returns, the loop repeats. + +* The loop terminates when an attempt to allocate the requested storage is + successful or when a called new_handler function does not return. +*/ +__attribute__((__weak__, __visibility__("default"))) +void * +operator new(std::size_t size) +#if !__has_feature(cxx_noexcept) + throw(std::bad_alloc) +#endif +{ + if (size == 0) + size = 1; + void* p; + while ((p = std::malloc(size)) == 0) + { + std::new_handler nh = std::get_new_handler(); + if (nh) + nh(); + else + throw std::bad_alloc(); + } + return p; +} + +/* +Note: The relationships among these operators is both carefully considered +and standard in C++11. Please do not change them without fully understanding +the consequences of doing so. Reference: +http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2158.html +*/ +/* +[new.delete.single] + +Calls operator new(size). If the call returns normally, returns the result of +that call. Otherwise, returns a null pointer. +*/ +__attribute__((__weak__, __visibility__("default"))) +void* +operator new(size_t size, const std::nothrow_t&) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + void* p = 0; + try + { + p = ::operator new(size); + } + catch (...) + { + } + return p; +} + +/* +[new.delete.array] + +Returns operator new(size). +*/ +__attribute__((__weak__, __visibility__("default"))) +void* +operator new[](size_t size) +#if !__has_feature(cxx_noexcept) + throw(std::bad_alloc) +#endif +{ + return ::operator new(size); +} + +/* +[new.delete.array] + +Calls operator new[](size). If the call returns normally, returns the result +of that call. Otherwise, returns a null pointer. +*/ +__attribute__((__weak__, __visibility__("default"))) +void* +operator new[](size_t size, const std::nothrow_t&) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + void* p = 0; + try + { + p = ::operator new[](size); + } + catch (...) + { + } + return p; +} + +/* +[new.delete.single] + +If ptr is null, does nothing. Otherwise, reclaims the storage allocated by the +earlier call to operator new. +*/ +__attribute__((__weak__, __visibility__("default"))) +void +operator delete(void* ptr) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + if (ptr) + std::free(ptr); +} + +/* +[new.delete.single] + +calls operator delete(ptr) +*/ +__attribute__((__weak__, __visibility__("default"))) +void +operator delete(void* ptr, const std::nothrow_t&) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + ::operator delete(ptr); +} + +/* +[new.delete.array] + +Calls operator delete(ptr) +*/ +__attribute__((__weak__, __visibility__("default"))) +void +operator delete[] (void* ptr) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + ::operator delete(ptr); +} + +/* +[new.delete.array] + +calls operator delete[](ptr) +*/ +__attribute__((__weak__, __visibility__("default"))) +void +operator delete[] (void* ptr, const std::nothrow_t&) +#if __has_feature(cxx_noexcept) + noexcept +#else + throw() +#endif +{ + ::operator delete[](ptr); +} + +namespace std +{ + +// bad_alloc + +bad_alloc::bad_alloc() _NOEXCEPT +{ +} + +bad_alloc::~bad_alloc() _NOEXCEPT +{ +} + +const char* +bad_alloc::what() const _NOEXCEPT +{ + return "std::bad_alloc"; +} + +// bad_array_new_length + +bad_array_new_length::bad_array_new_length() _NOEXCEPT +{ +} + +bad_array_new_length::~bad_array_new_length() _NOEXCEPT +{ +} + +const char* +bad_array_new_length::what() const _NOEXCEPT +{ + return "bad_array_new_length"; +} + +} // std diff --git a/system/lib/libcxxabi/src/cxa_personality.cpp b/system/lib/libcxxabi/src/cxa_personality.cpp new file mode 100644 index 00000000..e49278c0 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_personality.cpp @@ -0,0 +1,987 @@ +//===------------------------- cxa_exception.cpp --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Exception Handling APIs" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// http://www.intel.com/design/itanium/downloads/245358.htm +// +//===----------------------------------------------------------------------===// + +#include "unwind.h" +#include "cxa_exception.hpp" +#include "cxa_handlers.hpp" +#include "private_typeinfo.h" +#include <typeinfo> +#include <stdlib.h> +#include <assert.h> + +/* + Exception Header Layout: + ++---------------------------+-----------------------------+---------------+ +| __cxa_exception | _Unwind_Exception CLNGC++\0 | thrown object | ++---------------------------+-----------------------------+---------------+ + ^ + | + +-------------------------------------------------------+ + | ++---------------------------+-----------------------------+ +| __cxa_dependent_exception | _Unwind_Exception CLNGC++\1 | ++---------------------------+-----------------------------+ + + Exception Handling Table Layout: + ++-----------------+--------+ +| lpStartEncoding | (char) | ++---------+-------+--------+---------------+-----------------------+ +| lpStart | (encoded wtih lpStartEncoding) | defaults to funcStart | ++---------+-----+--------+-----------------+---------------+-------+ +| ttypeEncoding | (char) | Encoding of the type_info table | ++---------------+-+------+----+----------------------------+----------------+ +| classInfoOffset | (ULEB128) | Offset to type_info table, defaults to null | ++-----------------++--------+-+----------------------------+----------------+ +| callSiteEncoding | (char) | Encoding for Call Site Table | ++------------------+--+-----+-----+------------------------+--------------------------+ +| callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | ++---------------------+-----------+------------------------------------------------+--+ +| Beginning of Call Site Table If the current ip lies within the | +| ... (start, length) range of one of these | +| call sites, there may be action needed. | +| +-------------+---------------------------------+------------------------------+ | +| | start | (encoded with callSiteEncoding) | offset relative to funcStart | | +| | length | (encoded with callSiteEncoding) | lenght of code fragment | | +| | landingPad | (encoded with callSiteEncoding) | offset relative to lpStart | | +| | actionEntry | (ULEB128) | Action Table Index 1-based | | +| | | | actionEntry == 0 -> cleanup | | +| +-------------+---------------------------------+------------------------------+ | +| ... | ++---------------------------------------------------------------------+------------+ +| Beginning of Action Table ttypeIndex == 0 : cleanup | +| ... ttypeIndex > 0 : catch | +| ttypeIndex < 0 : exception spec | +| +--------------+-----------+--------------------------------------+ | +| | ttypeIndex | (SLEB128) | Index into type_info Table (1-based) | | +| | actionOffset | (SLEB128) | Offset into next Action Table entry | | +| +--------------+-----------+--------------------------------------+ | +| ... | ++---------------------------------------------------------------------+-----------------+ +| type_info Table, but classInfoOffset does *not* point here! | +| +----------------+------------------------------------------------+-----------------+ | +| | Nth type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == N | | +| +----------------+------------------------------------------------+-----------------+ | +| ... | +| +----------------+------------------------------------------------+-----------------+ | +| | 1st type_info* | Encoded with ttypeEncoding, 0 means catch(...) | ttypeIndex == 1 | | +| +----------------+------------------------------------------------+-----------------+ | +| +---------------------------------------+-----------+------------------------------+ | +| | 1st ttypeIndex for 1st exception spec | (ULEB128) | classInfoOffset points here! | | +| | ... | (ULEB128) | | | +| | Mth ttypeIndex for 1st exception spec | (ULEB128) | | | +| | 0 | (ULEB128) | | | +| +---------------------------------------+------------------------------------------+ | +| ... | +| +---------------------------------------+------------------------------------------+ | +| | 0 | (ULEB128) | throw() | | +| +---------------------------------------+------------------------------------------+ | +| ... | +| +---------------------------------------+------------------------------------------+ | +| | 1st ttypeIndex for Nth exception spec | (ULEB128) | | | +| | ... | (ULEB128) | | | +| | Mth ttypeIndex for Nth exception spec | (ULEB128) | | | +| | 0 | (ULEB128) | | | +| +---------------------------------------+------------------------------------------+ | ++---------------------------------------------------------------------------------------+ + +Notes: + +* ttypeIndex in the Action Table, and in the exception spec table, is an index, + not a byte count, if positive. It is a negative index offset of + classInfoOffset and the sizeof entry depends on ttypeEncoding. + But if ttypeIndex is negative, it is a positive 1-based byte offset into the + type_info Table. + And if ttypeIndex is zero, it refers to a catch (...). + +* landingPad can be 0, this implies there is nothing to be done. + +* landingPad != 0 and actionEntry == 0 implies a cleanup needs to be done + @landingPad. + +* A cleanup can also be found under landingPad != 0 and actionEntry != 0 in + the Action Table with ttypeIndex == 0. +*/ + +namespace __cxxabiv1 +{ + +extern "C" +{ + +// private API + +// Heavily borrowed from llvm/examples/ExceptionDemo/ExceptionDemo.cpp + +// DWARF Constants +enum +{ + DW_EH_PE_absptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + DW_EH_PE_indirect = 0x80, + DW_EH_PE_omit = 0xFF +}; + +/// Read a uleb128 encoded value and advance pointer +/// See Variable Length Data Appendix C in: +/// @link http://dwarfstd.org/Dwarf4.pdf @unlink +/// @param data reference variable holding memory pointer to decode from +/// @returns decoded value +static +uintptr_t +readULEB128(const uint8_t** data) +{ + uintptr_t result = 0; + uintptr_t shift = 0; + unsigned char byte; + const uint8_t *p = *data; + do + { + byte = *p++; + result |= static_cast<uintptr_t>(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + *data = p; + return result; +} + +/// Read a sleb128 encoded value and advance pointer +/// See Variable Length Data Applendix C in: +/// @link http://dwarfstd.org/Dwarf4.pdf @unlink +/// @param data reference variable holding memory pointer to decode from +/// @returns decoded value +static +uintptr_t +readSLEB128(const uint8_t** data) +{ + uintptr_t result = 0; + uintptr_t shift = 0; + unsigned char byte; + const uint8_t *p = *data; + do + { + byte = *p++; + result |= static_cast<uintptr_t>(byte & 0x7F) << shift; + shift += 7; + } while (byte & 0x80); + *data = p; + if ((byte & 0x40) && (shift < (sizeof(result) << 3))) + result |= static_cast<uintptr_t>(~0) << shift; + return result; +} + +/// Read a pointer encoded value and advance pointer +/// See Variable Length Data in: +/// @link http://dwarfstd.org/Dwarf3.pdf @unlink +/// @param data reference variable holding memory pointer to decode from +/// @param encoding dwarf encoding type +/// @returns decoded value +static +uintptr_t +readEncodedPointer(const uint8_t** data, uint8_t encoding) +{ + uintptr_t result = 0; + if (encoding == DW_EH_PE_omit) + return result; + const uint8_t* p = *data; + // first get value + switch (encoding & 0x0F) + { + case DW_EH_PE_absptr: + result = *((uintptr_t*)p); + p += sizeof(uintptr_t); + break; + case DW_EH_PE_uleb128: + result = readULEB128(&p); + break; + case DW_EH_PE_sleb128: + result = readSLEB128(&p); + break; + case DW_EH_PE_udata2: + result = *((uint16_t*)p); + p += sizeof(uint16_t); + break; + case DW_EH_PE_udata4: + result = *((uint32_t*)p); + p += sizeof(uint32_t); + break; + case DW_EH_PE_udata8: + result = *((uint64_t*)p); + p += sizeof(uint64_t); + break; + case DW_EH_PE_sdata2: + result = *((int16_t*)p); + p += sizeof(int16_t); + break; + case DW_EH_PE_sdata4: + result = *((int32_t*)p); + p += sizeof(int32_t); + break; + case DW_EH_PE_sdata8: + result = *((int64_t*)p); + p += sizeof(int64_t); + break; + default: + // not supported + abort(); + break; + } + // then add relative offset + switch (encoding & 0x70) + { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + if (result) + result += (uintptr_t)(*data); + break; + case DW_EH_PE_textrel: + case DW_EH_PE_datarel: + case DW_EH_PE_funcrel: + case DW_EH_PE_aligned: + default: + // not supported + abort(); + break; + } + // then apply indirection + if (result && (encoding & DW_EH_PE_indirect)) + result = *((uintptr_t*)result); + *data = p; + return result; +} + +static +void +call_terminate(bool native_exception, _Unwind_Exception* unwind_exception) +{ + __cxa_begin_catch(unwind_exception); + if (native_exception) + { + // Use the stored terminate_handler if possible + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + std::__terminate(exception_header->terminateHandler); + } + std::terminate(); +} + +static +const __shim_type_info* +get_shim_type_info(int64_t ttypeIndex, const uint8_t* classInfo, + uint8_t ttypeEncoding, bool native_exception, + _Unwind_Exception* unwind_exception) +{ + if (classInfo == 0) + { + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + switch (ttypeEncoding & 0x0F) + { + case DW_EH_PE_absptr: + ttypeIndex *= sizeof(void*); + break; + case DW_EH_PE_udata2: + case DW_EH_PE_sdata2: + ttypeIndex *= 2; + break; + case DW_EH_PE_udata4: + case DW_EH_PE_sdata4: + ttypeIndex *= 4; + break; + case DW_EH_PE_udata8: + case DW_EH_PE_sdata8: + ttypeIndex *= 8; + break; + default: + // this should not happen. Indicates corrupted eh_table. + call_terminate(native_exception, unwind_exception); + } + classInfo -= ttypeIndex; + return (const __shim_type_info*)readEncodedPointer(&classInfo, ttypeEncoding); +} + +/* + This is checking a thrown exception type, excpType, against a posibly empty + list of catchType's which make up an exception spec. + + An exception spec acts like a catch handler, but in reverse. This "catch + handler" will catch an excpType if and only if none of the catchType's in + the list will catch a excpType. If any catchType in the list can catch an + excpType, then this exception spec does not catch the excpType. +*/ +static +bool +exception_spec_can_catch(int64_t specIndex, const uint8_t* classInfo, + uint8_t ttypeEncoding, const __shim_type_info* excpType, + void* adjustedPtr, _Unwind_Exception* unwind_exception) +{ + if (classInfo == 0) + { + // this should not happen. Indicates corrupted eh_table. + call_terminate(false, unwind_exception); + } + // specIndex is negative of 1-based byte offset into classInfo; + specIndex = -specIndex; + --specIndex; + const uint8_t* temp = classInfo + specIndex; + // If any type in the spec list can catch excpType, return false, else return true + // adjustments to adjustedPtr are ignored. + while (true) + { + uint64_t ttypeIndex = readULEB128(&temp); + if (ttypeIndex == 0) + break; + const __shim_type_info* catchType = get_shim_type_info(ttypeIndex, + classInfo, + ttypeEncoding, + true, + unwind_exception); + void* tempPtr = adjustedPtr; + if (catchType->can_catch(excpType, tempPtr)) + return false; + } + return true; +} + +static +void* +get_thrown_object_ptr(_Unwind_Exception* unwind_exception) +{ + // Even for foreign exceptions, the exception object is *probably* at unwind_exception + 1 + // Regardless, this library is prohibited from touching a foreign exception + void* adjustedPtr = unwind_exception + 1; + if (unwind_exception->exception_class == kOurDependentExceptionClass) + adjustedPtr = ((__cxa_dependent_exception*)adjustedPtr - 1)->primaryException; + return adjustedPtr; +} + +/* + There are 3 types of scans needed: + + 1. Scan for handler with native or foreign exception. If handler found, + save state and return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. + May also report an error on invalid input. + May terminate for invalid exception table. + _UA_SEARCH_PHASE + + 2. Scan for handler with foreign exception. Must return _URC_HANDLER_FOUND, + or call terminate. + _UA_CLEANUP_PHASE && _UA_HANDLER_FRAME && !native_exception + + 3. Scan for cleanups. If a handler is found and this isn't forced unwind, + then terminate, otherwise ignore the handler and keep looking for cleanup. + If a cleanup is found, return _URC_HANDLER_FOUND, else return _URC_CONTINUE_UNWIND. + May also report an error on invalid input. + May terminate for invalid exception table. + _UA_CLEANUP_PHASE && !_UA_HANDLER_FRAME +*/ + +namespace +{ + +struct scan_results +{ + int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup + const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance. + const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected + uintptr_t landingPad; // null -> nothing found, else something found + void* adjustedPtr; // Used in cxa_exception.cpp + _Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR, + // _URC_FATAL_PHASE2_ERROR, + // _URC_CONTINUE_UNWIND, + // _URC_HANDLER_FOUND +}; + +} // unnamed namespace + +static +void +scan_eh_tab(scan_results& results, _Unwind_Action actions, bool native_exception, + _Unwind_Exception* unwind_exception, _Unwind_Context* context) +{ + // Initialize results to found nothing but an error + results.ttypeIndex = 0; + results.actionRecord = 0; + results.languageSpecificData = 0; + results.landingPad = 0; + results.adjustedPtr = 0; + results.reason = _URC_FATAL_PHASE1_ERROR; + // Check for consistent actions + if (actions & _UA_SEARCH_PHASE) + { + // Do Phase 1 + if (actions & (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME | _UA_FORCE_UNWIND)) + { + // None of these flags should be set during Phase 1 + // Client error + results.reason = _URC_FATAL_PHASE1_ERROR; + return; + } + } + else if (actions & _UA_CLEANUP_PHASE) + { + if ((actions & _UA_HANDLER_FRAME) && (actions & _UA_FORCE_UNWIND)) + { + // _UA_HANDLER_FRAME should only be set if phase 1 found a handler. + // If _UA_FORCE_UNWIND is set, phase 1 shouldn't have happened. + // Client error + results.reason = _URC_FATAL_PHASE2_ERROR; + return; + } + } + else // Niether _UA_SEARCH_PHASE nor _UA_CLEANUP_PHASE is set + { + // One of these should be set. + // Client error + results.reason = _URC_FATAL_PHASE1_ERROR; + return; + } + // Start scan by getting exception table address + const uint8_t* lsda = (const uint8_t*)_Unwind_GetLanguageSpecificData(context); + if (lsda == 0) + { + // There is no exception table + results.reason = _URC_CONTINUE_UNWIND; + return; + } + results.languageSpecificData = lsda; + // Get the current instruction pointer and offset it before next + // instruction in the current frame which threw the exception. + uintptr_t ip = _Unwind_GetIP(context) - 1; + // Get beginning current frame's code (as defined by the + // emitted dwarf code) + uintptr_t funcStart = _Unwind_GetRegionStart(context); + uintptr_t ipOffset = ip - funcStart; + const uint8_t* classInfo = NULL; + // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding + // dwarf emission + // Parse LSDA header. + uint8_t lpStartEncoding = *lsda++; + const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); + if (lpStart == 0) + lpStart = (const uint8_t*)funcStart; + uint8_t ttypeEncoding = *lsda++; + if (ttypeEncoding != DW_EH_PE_omit) + { + // Calculate type info locations in emitted dwarf code which + // were flagged by type info arguments to llvm.eh.selector + // intrinsic + uintptr_t classInfoOffset = readULEB128(&lsda); + classInfo = lsda + classInfoOffset; + } + // Walk call-site table looking for range that + // includes current PC. + uint8_t callSiteEncoding = *lsda++; + uint32_t callSiteTableLength = readULEB128(&lsda); + const uint8_t* callSiteTableStart = lsda; + const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength; + const uint8_t* actionTableStart = callSiteTableEnd; + const uint8_t* callSitePtr = callSiteTableStart; + while (true) + { + // There is one entry per call site. + // The call sites are non-overlapping in [start, start+length) + // The call sites are ordered in increasing value of start + uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); + uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding); + uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); + uintptr_t actionEntry = readULEB128(&callSitePtr); + if ((start <= ipOffset) && (ipOffset < (start + length))) + { + // Found the call site containing ip. + if (landingPad == 0) + { + // No handler here + results.reason = _URC_CONTINUE_UNWIND; + return; + } + landingPad = (uintptr_t)lpStart + landingPad; + if (actionEntry == 0) + { + // Found a cleanup + // If this is a type 1 or type 2 search, there are no handlers + // If this is a type 3 search, you want to install the cleanup. + if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) + { + results.ttypeIndex = 0; // Redundant but clarifying + results.landingPad = landingPad; + results.reason = _URC_HANDLER_FOUND; + return; + } + // No handler here + results.reason = _URC_CONTINUE_UNWIND; + return; + } + // Convert 1-based byte offset into + const uint8_t* action = actionTableStart + (actionEntry - 1); + // Scan action entries until you find a matching handler, cleanup, or the end of action list + while (true) + { + const uint8_t* actionRecord = action; + int64_t ttypeIndex = readSLEB128(&action); + if (ttypeIndex > 0) + { + // Found a catch, does it actually catch? + // First check for catch (...) + const __shim_type_info* catchType = + get_shim_type_info(ttypeIndex, classInfo, + ttypeEncoding, native_exception, + unwind_exception); + if (catchType == 0) + { + // Found catch (...) catches everything, including foreign exceptions + // If this is a type 1 search save state and return _URC_HANDLER_FOUND + // If this is a type 2 search save state and return _URC_HANDLER_FOUND + // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! + // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan + if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) + { + // Save state and return _URC_HANDLER_FOUND + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.landingPad = landingPad; + results.adjustedPtr = get_thrown_object_ptr(unwind_exception); + results.reason = _URC_HANDLER_FOUND; + return; + } + else if (!(actions & _UA_FORCE_UNWIND)) + { + // It looks like the exception table has changed + // on us. Likely stack corruption! + call_terminate(native_exception, unwind_exception); + } + } + // Else this is a catch (T) clause and will never + // catch a foreign exception + else if (native_exception) + { + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + void* adjustedPtr = get_thrown_object_ptr(unwind_exception); + const __shim_type_info* excpType = + static_cast<const __shim_type_info*>(exception_header->exceptionType); + if (adjustedPtr == 0 || excpType == 0) + { + // Something very bad happened + call_terminate(native_exception, unwind_exception); + } + if (catchType->can_catch(excpType, adjustedPtr)) + { + // Found a matching handler + // If this is a type 1 search save state and return _URC_HANDLER_FOUND + // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! + // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan + if (actions & _UA_SEARCH_PHASE) + { + // Save state and return _URC_HANDLER_FOUND + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.landingPad = landingPad; + results.adjustedPtr = adjustedPtr; + results.reason = _URC_HANDLER_FOUND; + return; + } + else if (!(actions & _UA_FORCE_UNWIND)) + { + // It looks like the exception table has changed + // on us. Likely stack corruption! + call_terminate(native_exception, unwind_exception); + } + } + } + // Scan next action ... + } + else if (ttypeIndex < 0) + { + // Found an exception spec. If this is a foreign exception, + // it is always caught. + if (native_exception) + { + // Does the exception spec catch this native exception? + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + void* adjustedPtr = get_thrown_object_ptr(unwind_exception); + const __shim_type_info* excpType = + static_cast<const __shim_type_info*>(exception_header->exceptionType); + if (adjustedPtr == 0 || excpType == 0) + { + // Something very bad happened + call_terminate(native_exception, unwind_exception); + } + if (exception_spec_can_catch(ttypeIndex, classInfo, + ttypeEncoding, excpType, + adjustedPtr, unwind_exception)) + { + // native exception caught by exception spec + // If this is a type 1 search, save state and return _URC_HANDLER_FOUND + // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! + // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan + if (actions & _UA_SEARCH_PHASE) + { + // Save state and return _URC_HANDLER_FOUND + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.landingPad = landingPad; + results.adjustedPtr = adjustedPtr; + results.reason = _URC_HANDLER_FOUND; + return; + } + else if (!(actions & _UA_FORCE_UNWIND)) + { + // It looks like the exception table has changed + // on us. Likely stack corruption! + call_terminate(native_exception, unwind_exception); + } + } + } + else + { + // foreign exception caught by exception spec + // If this is a type 1 search, save state and return _URC_HANDLER_FOUND + // If this is a type 2 search, save state and return _URC_HANDLER_FOUND + // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! + // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan + if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) + { + // Save state and return _URC_HANDLER_FOUND + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.landingPad = landingPad; + results.adjustedPtr = get_thrown_object_ptr(unwind_exception); + results.reason = _URC_HANDLER_FOUND; + return; + } + else if (!(actions & _UA_FORCE_UNWIND)) + { + // It looks like the exception table has changed + // on us. Likely stack corruption! + call_terminate(native_exception, unwind_exception); + } + } + // Scan next action ... + } + else // ttypeIndex == 0 + { + // Found a cleanup + // If this is a type 1 search, ignore it and continue scan + // If this is a type 2 search, ignore it and continue scan + // If this is a type 3 search, save state and return _URC_HANDLER_FOUND + if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) + { + // Save state and return _URC_HANDLER_FOUND + results.ttypeIndex = ttypeIndex; + results.actionRecord = actionRecord; + results.landingPad = landingPad; + results.adjustedPtr = get_thrown_object_ptr(unwind_exception); + results.reason = _URC_HANDLER_FOUND; + return; + } + } + const uint8_t* temp = action; + int64_t actionOffset = readSLEB128(&temp); + if (actionOffset == 0) + { + // End of action list, no matching handler or cleanup found + results.reason = _URC_CONTINUE_UNWIND; + return; + } + // Go to next action + action += actionOffset; + } // there is no break out of this loop, only return + } + else if (ipOffset < start) + { + // There is no call site for this ip + // Something bad has happened. We should never get here. + // Possible stack corruption. + call_terminate(native_exception, unwind_exception); + } + } // there is no break out of this loop, only return +} + +// public API + +/* +The personality function branches on actions like so: + +_UA_SEARCH_PHASE + + If _UA_CLEANUP_PHASE or _UA_HANDLER_FRAME or _UA_FORCE_UNWIND there's + an error from above, return _URC_FATAL_PHASE1_ERROR. + + Scan for anything that could stop unwinding: + + 1. A catch clause that will catch this exception + (will never catch foreign). + 2. A catch (...) (will always catch foreign). + 3. An exception spec that will catch this exception + (will always catch foreign). + If a handler is found + If not foreign + Save state in header + return _URC_HANDLER_FOUND + Else a handler not found + return _URC_CONTINUE_UNWIND + +_UA_CLEANUP_PHASE + + If _UA_HANDLER_FRAME + If _UA_FORCE_UNWIND + How did this happen? return _URC_FATAL_PHASE2_ERROR + If foreign + Do _UA_SEARCH_PHASE to recover state + else + Recover state from header + Transfer control to landing pad. return _URC_INSTALL_CONTEXT + + Else + + This branch handles both normal C++ non-catching handlers (cleanups) + and forced unwinding. + Scan for anything that can not stop unwinding: + + 1. A cleanup. + + If a cleanup is found + transfer control to it. return _URC_INSTALL_CONTEXT + Else a cleanup is not found: return _URC_CONTINUE_UNWIND +*/ + +_Unwind_Reason_Code +__gxx_personality_v0(int version, _Unwind_Action actions, uint64_t exceptionClass, + _Unwind_Exception* unwind_exception, _Unwind_Context* context) +{ + if (version != 1 || unwind_exception == 0 || context == 0) + return _URC_FATAL_PHASE1_ERROR; + bool native_exception = (exceptionClass & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + scan_results results; + if (actions & _UA_SEARCH_PHASE) + { + // Phase 1 search: All we're looking for in phase 1 is a handler that + // halts unwinding + scan_eh_tab(results, actions, native_exception, unwind_exception, context); + if (results.reason == _URC_HANDLER_FOUND) + { + // Found one. Can we cache the results somewhere to optimize phase 2? + if (native_exception) + { + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + exception_header->handlerSwitchValue = static_cast<int>(results.ttypeIndex); + exception_header->actionRecord = results.actionRecord; + exception_header->languageSpecificData = results.languageSpecificData; + exception_header->catchTemp = reinterpret_cast<void*>(results.landingPad); + exception_header->adjustedPtr = results.adjustedPtr; + } + return _URC_HANDLER_FOUND; + } + // Did not find a catching-handler. Return the results of the scan + // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE1_ERROR + // if we were called improperly). + return results.reason; + } + if (actions & _UA_CLEANUP_PHASE) + { + // Phase 2 search: + // Did we find a catching handler in phase 1? + if (actions & _UA_HANDLER_FRAME) + { + // Yes, phase 1 said we have a catching handler here. + // Did we cache the results of the scan? + if (native_exception) + { + // Yes, reload the results from the cache. + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + results.ttypeIndex = exception_header->handlerSwitchValue; + results.actionRecord = exception_header->actionRecord; + results.languageSpecificData = exception_header->languageSpecificData; + results.landingPad = reinterpret_cast<uintptr_t>(exception_header->catchTemp); + results.adjustedPtr = exception_header->adjustedPtr; + } + else + { + // No, do the scan again to reload the results. + scan_eh_tab(results, actions, native_exception, unwind_exception, context); + // Phase 1 told us we would find a handler. Now in Phase 2 we + // didn't find a handler. The eh table should not be changing! + if (results.reason != _URC_HANDLER_FOUND) + call_terminate(native_exception, unwind_exception); + } + // Jump to the handler + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), results.ttypeIndex); + _Unwind_SetIP(context, results.landingPad); + return _URC_INSTALL_CONTEXT; + } + // Either we didn't do a phase 1 search (due to forced unwinding), or + // phase 1 reported no catching-handlers. + // Search for a (non-catching) cleanup + scan_eh_tab(results, actions, native_exception, unwind_exception, context); + if (results.reason == _URC_HANDLER_FOUND) + { + // Found a non-catching handler. Jump to it: + _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), (uintptr_t)unwind_exception); + _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), results.ttypeIndex); + _Unwind_SetIP(context, results.landingPad); + return _URC_INSTALL_CONTEXT; + } + // Did not find a cleanup. Return the results of the scan + // (normally _URC_CONTINUE_UNWIND, but could have been _URC_FATAL_PHASE2_ERROR + // if we were called improperly). + return results.reason; + } + // We were called improperly: neither a phase 1 or phase 2 search + return _URC_FATAL_PHASE1_ERROR; +} + +__attribute__((noreturn)) +void +__cxa_call_unexpected(void* arg) +{ + _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(arg); + if (unwind_exception == 0) + call_terminate(false, unwind_exception); + __cxa_begin_catch(unwind_exception); + bool native_old_exception = + (unwind_exception->exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + std::unexpected_handler u_handler; + std::terminate_handler t_handler; + __cxa_exception* old_exception_header = 0; + int64_t ttypeIndex; + const uint8_t* lsda; + if (native_old_exception) + { + old_exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + t_handler = old_exception_header->terminateHandler; + u_handler = old_exception_header->unexpectedHandler; + // If std::__unexpected(u_handler) rethrows the same exception, + // these values get overwritten by the rethrow. So save them now: + ttypeIndex = old_exception_header->handlerSwitchValue; + lsda = old_exception_header->languageSpecificData; + } + else + { + t_handler = std::get_terminate(); + u_handler = std::get_unexpected(); + } + try + { + std::__unexpected(u_handler); + } + catch (...) + { + // If the old exception is foreign, then all we can do is terminate. + // We have no way to recover the needed old exception spec. There's + // no way to pass that information here. And the personality routine + // can't call us directly and do anything but terminate() if we throw + // from here. + if (native_old_exception) + { + // Have: + // old_exception_header->languageSpecificData + // old_exception_header->actionRecord + // Need + // const uint8_t* classInfo + // uint8_t ttypeEncoding + uint8_t lpStartEncoding = *lsda++; + const uint8_t* lpStart = (const uint8_t*)readEncodedPointer(&lsda, lpStartEncoding); + uint8_t ttypeEncoding = *lsda++; + if (ttypeEncoding == DW_EH_PE_omit) + std::__terminate(t_handler); + uintptr_t classInfoOffset = readULEB128(&lsda); + const uint8_t* classInfo = lsda + classInfoOffset; + // Is this new exception catchable by the exception spec at ttypeIndex? + // The answer is obviously yes if the new and old exceptions are the same exception + // If no + // throw; + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + __cxa_exception* new_exception_header = globals->caughtExceptions; + if (new_exception_header == 0) + // This shouldn't be able to happen! + std::__terminate(t_handler); + bool native_new_exception = + (new_exception_header->unwindHeader.exception_class & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); + void* adjustedPtr; + if (native_new_exception && (new_exception_header != old_exception_header)) + { + const __shim_type_info* excpType = + static_cast<const __shim_type_info*>(new_exception_header->exceptionType); + adjustedPtr = + new_exception_header->unwindHeader.exception_class == kOurDependentExceptionClass ? + ((__cxa_dependent_exception*)new_exception_header)->primaryException : + new_exception_header + 1; + if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, + excpType, adjustedPtr, unwind_exception)) + { + // We need to __cxa_end_catch, but for the old exception, + // not the new one. This is a little tricky ... + // Disguise new_exception_header as a rethrown exception, but + // don't actually rethrow it. This means you can temporarily + // end the catch clause enclosing new_exception_header without + // __cxa_end_catch destroying new_exception_header. + new_exception_header->handlerCount = -new_exception_header->handlerCount; + globals->uncaughtExceptions += 1; + // Call __cxa_end_catch for new_exception_header + __cxa_end_catch(); + // Call __cxa_end_catch for old_exception_header + __cxa_end_catch(); + // Renter this catch clause with new_exception_header + __cxa_begin_catch(&new_exception_header->unwindHeader); + // Rethrow new_exception_header + throw; + } + } + // Will a std::bad_exception be catchable by the exception spec at + // ttypeIndex? + // If no + // throw std::bad_exception(); + const __shim_type_info* excpType = + static_cast<const __shim_type_info*>(&typeid(std::bad_exception)); + std::bad_exception be; + adjustedPtr = &be; + if (!exception_spec_can_catch(ttypeIndex, classInfo, ttypeEncoding, + excpType, adjustedPtr, unwind_exception)) + { + // We need to __cxa_end_catch for both the old exception and the + // new exception. Technically we should do it in that order. + // But it is expedent to do it in the opposite order: + // Call __cxa_end_catch for new_exception_header + __cxa_end_catch(); + // Throw std::bad_exception will __cxa_end_catch for + // old_exception_header + throw be; + } + } + } + std::__terminate(t_handler); +} + +} // extern "C" + +} // __cxxabiv1 diff --git a/system/lib/libcxxabi/src/cxa_unexpected.cpp b/system/lib/libcxxabi/src/cxa_unexpected.cpp new file mode 100644 index 00000000..f6e6b6ab --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_unexpected.cpp @@ -0,0 +1,27 @@ +//===------------------------- cxa_unexpected.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <exception> +#include <cxxabi.h> +#include "cxa_exception.hpp" + +namespace __cxxabiv1 +{ + +#pragma GCC visibility push(default) + +extern "C" +{ + +} + +#pragma GCC visibility pop + +} // namespace __cxxabiv1 + diff --git a/system/lib/libcxxabi/src/cxa_vector.cpp b/system/lib/libcxxabi/src/cxa_vector.cpp new file mode 100644 index 00000000..926c01dd --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_vector.cpp @@ -0,0 +1,367 @@ +//===-------------------------- cxa_vector.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Array Construction and Destruction APIs" +// http://www.codesourcery.com/public/cxx-abi/abi.html#array-ctor +// +//===----------------------------------------------------------------------===// + +#include "cxxabi.h" + +#include <exception> // for std::terminate + +namespace __cxxabiv1 { + +#pragma mark --Helper routines and classes -- + +namespace { + inline static size_t __get_element_count ( void *p ) { + return static_cast <size_t *> (p)[-1]; + } + + inline static void __set_element_count ( void *p, size_t element_count ) { + static_cast <size_t *> (p)[-1] = element_count; + } + + +// A pair of classes to simplify exception handling and control flow. +// They get passed a block of memory in the constructor, and unless the +// 'release' method is called, they deallocate the memory in the destructor. +// Prefered usage is to allocate some memory, attach it to one of these objects, +// and then, when all the operations to set up the memory block have succeeded, +// call 'release'. If any of the setup operations fail, or an exception is +// thrown, then the block is automatically deallocated. +// +// The only difference between these two classes is the signature for the +// deallocation function (to match new2/new3 and delete2/delete3. + class st_heap_block2 { + public: + typedef void (*dealloc_f)(void *); + + st_heap_block2 ( dealloc_f dealloc, void *ptr ) + : dealloc_ ( dealloc ), ptr_ ( ptr ), enabled_ ( true ) {} + ~st_heap_block2 () { if ( enabled_ ) dealloc_ ( ptr_ ) ; } + void release () { enabled_ = false; } + + private: + dealloc_f dealloc_; + void *ptr_; + bool enabled_; + }; + + class st_heap_block3 { + public: + typedef void (*dealloc_f)(void *, size_t); + + st_heap_block3 ( dealloc_f dealloc, void *ptr, size_t size ) + : dealloc_ ( dealloc ), ptr_ ( ptr ), size_ ( size ), enabled_ ( true ) {} + ~st_heap_block3 () { if ( enabled_ ) dealloc_ ( ptr_, size_ ) ; } + void release () { enabled_ = false; } + + private: + dealloc_f dealloc_; + void *ptr_; + size_t size_; + bool enabled_; + }; + + class st_cxa_cleanup { + public: + typedef void (*destruct_f)(void *); + + st_cxa_cleanup ( void *ptr, size_t &idx, size_t element_size, destruct_f destructor ) + : ptr_ ( ptr ), idx_ ( idx ), element_size_ ( element_size ), + destructor_ ( destructor ), enabled_ ( true ) {} + ~st_cxa_cleanup () { + if ( enabled_ ) + __cxa_vec_cleanup ( ptr_, idx_, element_size_, destructor_ ); + } + + void release () { enabled_ = false; } + + private: + void *ptr_; + size_t &idx_; + size_t element_size_; + destruct_f destructor_; + bool enabled_; + }; + + class st_terminate { + public: + st_terminate ( bool enabled = true ) : enabled_ ( enabled ) {} + ~st_terminate () { if ( enabled_ ) std::terminate (); } + void release () { enabled_ = false; } + private: + bool enabled_ ; + }; +} + +#pragma mark --Externally visible routines-- + +extern "C" { + +// Equivalent to +// +// __cxa_vec_new2(element_count, element_size, padding_size, constructor, +// destructor, &::operator new[], &::operator delete[]) +void* __cxa_vec_new( + size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*) ) { + + return __cxa_vec_new2 ( element_count, element_size, padding_size, + constructor, destructor, &::operator new [], &::operator delete [] ); +} + + + +// Given the number and size of elements for an array and the non-negative +// size of prefix padding for a cookie, allocate space (using alloc) for +// the array preceded by the specified padding, initialize the cookie if +// the padding is non-zero, and call the given constructor on each element. +// Return the address of the array proper, after the padding. +// +// If alloc throws an exception, rethrow the exception. If alloc returns +// NULL, return NULL. If the constructor throws an exception, call +// destructor for any already constructed elements, and rethrow the +// exception. If the destructor throws an exception, call std::terminate. +// +// The constructor may be NULL, in which case it must not be called. If the +// padding_size is zero, the destructor may be NULL; in that case it must +// not be called. +// +// Neither alloc nor dealloc may be NULL. +void* __cxa_vec_new2( + size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*), + void* (*alloc)(size_t), void (*dealloc)(void*) ) { + + const size_t heap_size = element_count * element_size + padding_size; + char * const heap_block = static_cast<char *> ( alloc ( heap_size )); + char *vec_base = heap_block; + + if ( NULL != vec_base ) { + st_heap_block2 heap ( dealloc, heap_block ); + + // put the padding before the array elements + if ( 0 != padding_size ) { + vec_base += padding_size; + __set_element_count ( vec_base, element_count ); + } + + // Construct the elements + __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); + heap.release (); // We're good! + } + + return vec_base; +} + + +// Same as __cxa_vec_new2 except that the deallocation function takes both +// the object address and its size. +void* __cxa_vec_new3( + size_t element_count, size_t element_size, size_t padding_size, + void (*constructor)(void*), void (*destructor)(void*), + void* (*alloc)(size_t), void (*dealloc)(void*, size_t) ) { + + const size_t heap_size = element_count * element_size + padding_size; + char * const heap_block = static_cast<char *> ( alloc ( heap_size )); + char *vec_base = heap_block; + + if ( NULL != vec_base ) { + st_heap_block3 heap ( dealloc, heap_block, heap_size ); + + // put the padding before the array elements + if ( 0 != padding_size ) { + vec_base += padding_size; + __set_element_count ( vec_base, element_count ); + } + + // Construct the elements + __cxa_vec_ctor ( vec_base, element_count, element_size, constructor, destructor ); + heap.release (); // We're good! + } + + return vec_base; +} + + +// Given the (data) addresses of a destination and a source array, an +// element count and an element size, call the given copy constructor to +// copy each element from the source array to the destination array. The +// copy constructor's arguments are the destination address and source +// address, respectively. If an exception occurs, call the given destructor +// (if non-NULL) on each copied element and rethrow. If the destructor +// throws an exception, call terminate(). The constructor and or destructor +// pointers may be NULL. If either is NULL, no action is taken when it +// would have been called. + +void __cxa_vec_cctor( void* dest_array, void* src_array, + size_t element_count, size_t element_size, + void (*constructor) (void*, void*), void (*destructor)(void*) ) { + + if ( NULL != constructor ) { + size_t idx = 0; + char *src_ptr = static_cast<char *>(src_array); + char *dest_ptr = static_cast<char *>(dest_array); + st_cxa_cleanup cleanup ( dest_array, idx, element_size, destructor ); + + for ( idx = 0; idx < element_count; + ++idx, src_ptr += element_size, dest_ptr += element_size ) + constructor ( dest_ptr, src_ptr ); + cleanup.release (); // We're good! + } +} + + +// Given the (data) address of an array, not including any cookie padding, +// and the number and size of its elements, call the given constructor on +// each element. If the constructor throws an exception, call the given +// destructor for any already-constructed elements, and rethrow the +// exception. If the destructor throws an exception, call terminate(). The +// constructor and/or destructor pointers may be NULL. If either is NULL, +// no action is taken when it would have been called. +void __cxa_vec_ctor( + void* array_address, size_t element_count, size_t element_size, + void (*constructor)(void*), void (*destructor)(void*) ) { + + if ( NULL != constructor ) { + size_t idx; + char *ptr = static_cast <char *> ( array_address ); + st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); + + // Construct the elements + for ( idx = 0; idx < element_count; ++idx, ptr += element_size ) + constructor ( ptr ); + cleanup.release (); // We're good! + } +} + +// Given the (data) address of an array, the number of elements, and the +// size of its elements, call the given destructor on each element. If the +// destructor throws an exception, rethrow after destroying the remaining +// elements if possible. If the destructor throws a second exception, call +// terminate(). The destructor pointer may be NULL, in which case this +// routine does nothing. +void __cxa_vec_dtor( + void* array_address, size_t element_count, size_t element_size, + void (*destructor)(void*) ) { + + if ( NULL != destructor ) { + char *ptr = static_cast <char *> (array_address); + size_t idx = element_count; + st_cxa_cleanup cleanup ( array_address, idx, element_size, destructor ); + { + st_terminate exception_guard (__cxa_uncaught_exception ()); + ptr += element_count * element_size; // one past the last element + + while ( idx-- > 0 ) { + ptr -= element_size; + destructor ( ptr ); + } + exception_guard.release (); // We're good ! + } + cleanup.release (); // We're still good! + } +} + +// Given the (data) address of an array, the number of elements, and the +// size of its elements, call the given destructor on each element. If the +// destructor throws an exception, call terminate(). The destructor pointer +// may be NULL, in which case this routine does nothing. +void __cxa_vec_cleanup( void* array_address, size_t element_count, + size_t element_size, void (*destructor)(void*) ) { + + if ( NULL != destructor ) { + char *ptr = static_cast <char *> (array_address); + size_t idx = element_count; + st_terminate exception_guard; + + ptr += element_count * element_size; // one past the last element + while ( idx-- > 0 ) { + ptr -= element_size; + destructor ( ptr ); + } + exception_guard.release (); // We're done! + } +} + + +// If the array_address is NULL, return immediately. Otherwise, given the +// (data) address of an array, the non-negative size of prefix padding for +// the cookie, and the size of its elements, call the given destructor on +// each element, using the cookie to determine the number of elements, and +// then delete the space by calling ::operator delete[](void *). If the +// destructor throws an exception, rethrow after (a) destroying the +// remaining elements, and (b) deallocating the storage. If the destructor +// throws a second exception, call terminate(). If padding_size is 0, the +// destructor pointer must be NULL. If the destructor pointer is NULL, no +// destructor call is to be made. +// +// The intent of this function is to permit an implementation to call this +// function when confronted with an expression of the form delete[] p in +// the source code, provided that the default deallocation function can be +// used. Therefore, the semantics of this function are consistent with +// those required by the standard. The requirement that the deallocation +// function be called even if the destructor throws an exception derives +// from the resolution to DR 353 to the C++ standard, which was adopted in +// April, 2003. +void __cxa_vec_delete( void* array_address, + size_t element_size, size_t padding_size, void (*destructor)(void*) ) { + + __cxa_vec_delete2 ( array_address, element_size, padding_size, + destructor, &::operator delete [] ); +} + + +// Same as __cxa_vec_delete, except that the given function is used for +// deallocation instead of the default delete function. If dealloc throws +// an exception, the result is undefined. The dealloc pointer may not be +// NULL. +void __cxa_vec_delete2( void* array_address, + size_t element_size, size_t padding_size, + void (*destructor)(void*), void (*dealloc)(void*) ) { + + if ( NULL != array_address ) { + char *vec_base = static_cast <char *> (array_address); + char *heap_block = vec_base - padding_size; + st_heap_block2 heap ( dealloc, heap_block ); + + if ( 0 != padding_size && NULL != destructor ) // call the destructors + __cxa_vec_dtor ( array_address, __get_element_count ( vec_base ), + element_size, destructor ); + } +} + + +// Same as __cxa_vec_delete, except that the given function is used for +// deallocation instead of the default delete function. The deallocation +// function takes both the object address and its size. If dealloc throws +// an exception, the result is undefined. The dealloc pointer may not be +// NULL. +void __cxa_vec_delete3( void* array_address, + size_t element_size, size_t padding_size, + void (*destructor)(void*), void (*dealloc) (void*, size_t)) { + + if ( NULL != array_address ) { + char *vec_base = static_cast <char *> (array_address); + char *heap_block = vec_base - padding_size; + const size_t element_count = padding_size ? __get_element_count ( vec_base ) : 0; + const size_t heap_block_size = element_size * element_count + padding_size; + st_heap_block3 heap ( dealloc, heap_block, heap_block_size ); + + if ( 0 != padding_size && NULL != destructor ) // call the destructors + __cxa_vec_dtor ( array_address, element_count, element_size, destructor ); + } +} + + +} // extern "C" + +} // abi diff --git a/system/lib/libcxxabi/src/cxa_virtual.cpp b/system/lib/libcxxabi/src/cxa_virtual.cpp new file mode 100644 index 00000000..437b6016 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_virtual.cpp @@ -0,0 +1,31 @@ +//===-------------------------- cxa_virtual.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "cxxabi.h" +#include "abort_message.h" + +namespace __cxxabiv1 +{ + +extern "C" +{ + +LIBCXXABI_NORETURN +void __cxa_pure_virtual(void) { + abort_message("Pure virtual function called!"); +} + +LIBCXXABI_NORETURN +void __cxa_deleted_virtual(void) { + abort_message("Deleted virtual function called!"); +} + +} // extern "C" + +} // abi diff --git a/system/lib/libcxxabi/src/exception.cpp b/system/lib/libcxxabi/src/exception.cpp new file mode 100644 index 00000000..c47a9b76 --- /dev/null +++ b/system/lib/libcxxabi/src/exception.cpp @@ -0,0 +1,41 @@ +//===---------------------------- exception.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <exception> + +#pragma GCC visibility push(default) + +namespace std +{ + +// exception + +exception::~exception() _NOEXCEPT +{ +} + +const char* exception::what() const _NOEXCEPT +{ + return "std::exception"; +} + +// bad_exception + +bad_exception::~bad_exception() _NOEXCEPT +{ +} + +const char* bad_exception::what() const _NOEXCEPT +{ + return "std::bad_exception"; +} + +} // std + +#pragma GCC visibility pop diff --git a/system/lib/libcxxabi/src/fallback_malloc.ipp b/system/lib/libcxxabi/src/fallback_malloc.ipp new file mode 100644 index 00000000..979f0bbd --- /dev/null +++ b/system/lib/libcxxabi/src/fallback_malloc.ipp @@ -0,0 +1,174 @@ +//===------------------------ fallback_malloc.ipp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// +// This file implements the "Exception Handling APIs" +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +// A small, simple heap manager based (loosely) on +// the startup heap manager from FreeBSD, optimized for space. +// +// Manages a fixed-size memory pool, supports malloc and free only. +// No support for realloc. +// +// Allocates chunks in multiples of four bytes, with a four byte header +// for each chunk. The overhead of each chunk is kept low by keeping pointers +// as two byte offsets within the heap, rather than (4 or 8 byte) pointers. + +namespace { + +static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER; + +class mutexor { +public: + mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); } + ~mutexor () { pthread_mutex_unlock ( mtx_ ); } +private: + mutexor ( const mutexor &rhs ); + mutexor & operator = ( const mutexor &rhs ); + pthread_mutex_t *mtx_; + }; + + +#define HEAP_SIZE 512 +char heap [ HEAP_SIZE ]; + +typedef unsigned short heap_offset; +typedef unsigned short heap_size; + +struct heap_node { + heap_offset next_node; // offset into heap + heap_size len; // size in units of "sizeof(heap_node)" +}; + +static const heap_node *list_end = (heap_node *) ( &heap [ HEAP_SIZE ] ); // one past the end of the heap +static heap_node *freelist = NULL; + +heap_node *node_from_offset ( const heap_offset offset ) + { return (heap_node *) ( heap + ( offset * sizeof (heap_node))); } + +heap_offset offset_from_node ( const heap_node *ptr ) + { return (((char *) ptr ) - heap) / sizeof (heap_node); } + +void init_heap () { + freelist = (heap_node *) heap; + freelist->next_node = offset_from_node ( list_end ); + freelist->len = HEAP_SIZE / sizeof (heap_node); + } + +// How big a chunk we allocate +size_t alloc_size (size_t len) + { return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; } + +bool is_fallback_ptr ( void *ptr ) + { return ptr >= heap && ptr < ( heap + HEAP_SIZE ); } + +void *fallback_malloc(size_t len) { + heap_node *p, *prev; + const size_t nelems = alloc_size ( len ); + mutexor mtx ( &heap_mutex ); + + if ( NULL == freelist ) + init_heap (); + +// Walk the free list, looking for a "big enough" chunk + for (p = freelist, prev = 0; + p && p != list_end; prev = p, p = node_from_offset ( p->next_node)) { + + if (p->len > nelems) { // chunk is larger, shorten, and return the tail + heap_node *q; + + p->len -= nelems; + q = p + p->len; + q->next_node = 0; + q->len = nelems; + return (void *) (q + 1); + } + + if (p->len == nelems) { // exact size match + if (prev == 0) + freelist = node_from_offset(p->next_node); + else + prev->next_node = p->next_node; + p->next_node = 0; + return (void *) (p + 1); + } + } + return NULL; // couldn't find a spot big enough +} + +// Return the start of the next block +heap_node *after ( struct heap_node *p ) { return p + p->len; } + +void fallback_free (void *ptr) { + struct heap_node *cp = ((struct heap_node *) ptr) - 1; // retrieve the chunk + struct heap_node *p, *prev; + + mutexor mtx ( &heap_mutex ); + +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << "Freeing item at " << offset_from_node ( cp ) << " of size " << cp->len << std::endl; +#endif + + for (p = freelist, prev = 0; + p && p != list_end; prev = p, p = node_from_offset (p->next_node)) { +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " p, cp, after (p), after(cp) " + << offset_from_node ( p ) << ' ' + << offset_from_node ( cp ) << ' ' + << offset_from_node ( after ( p )) << ' ' + << offset_from_node ( after ( cp )) << std::endl; +#endif + if ( after ( p ) == cp ) { +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Appending onto chunk at " << offset_from_node ( p ) << std::endl; +#endif + p->len += cp->len; // make the free heap_node larger + return; + } + else if ( after ( cp ) == p ) { // there's a free heap_node right after +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Appending free chunk at " << offset_from_node ( p ) << std::endl; +#endif + cp->len += p->len; + if ( prev == 0 ) { + freelist = cp; + cp->next_node = p->next_node; + } + else + prev->next_node = offset_from_node(cp); + return; + } + } +// Nothing to merge with, add it to the start of the free list +#ifdef DEBUG_FALLBACK_MALLOC + std::cout << " Making new free list entry " << offset_from_node ( cp ) << std::endl; +#endif + cp->next_node = offset_from_node ( freelist ); + freelist = cp; +} + +#ifdef INSTRUMENT_FALLBACK_MALLOC +size_t print_free_list () { + struct heap_node *p, *prev; + heap_size total_free = 0; + if ( NULL == freelist ) + init_heap (); + + for (p = freelist, prev = 0; + p && p != list_end; prev = p, p = node_from_offset (p->next_node)) { + std::cout << ( prev == 0 ? "" : " ") << "Offset: " << offset_from_node ( p ) + << "\tsize: " << p->len << " Next: " << p->next_node << std::endl; + total_free += p->len; + } + std::cout << "Total Free space: " << total_free << std::endl; + return total_free; + } +#endif +} // end unnamed namespace diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp new file mode 100644 index 00000000..269116b6 --- /dev/null +++ b/system/lib/libcxxabi/src/private_typeinfo.cpp @@ -0,0 +1,1036 @@ +//===----------------------- private_typeinfo.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "private_typeinfo.h" + +namespace __cxxabiv1 +{ + +#pragma GCC visibility push(hidden) + +// __shim_type_info + +__shim_type_info::~__shim_type_info() +{ +} + +// __fundamental_type_info + +// This miraculously (compiler magic) emits the type_info's for: +// 1. all of the fundamental types +// 2. pointers to all of the fundamental types +// 3. pointers to all of the const fundamental types +__fundamental_type_info::~__fundamental_type_info() +{ +} + +// __array_type_info + +__array_type_info::~__array_type_info() +{ +} + +// __function_type_info + +__function_type_info::~__function_type_info() +{ +} + +// __enum_type_info + +__enum_type_info::~__enum_type_info() +{ +} + +// __class_type_info + +__class_type_info::~__class_type_info() +{ +} + +// __si_class_type_info + +__si_class_type_info::~__si_class_type_info() +{ +} + +// __vmi_class_type_info + +__vmi_class_type_info::~__vmi_class_type_info() +{ +} + +// __pbase_type_info + +__pbase_type_info::~__pbase_type_info() +{ +} + +// __pointer_type_info + +__pointer_type_info::~__pointer_type_info() +{ +} + +// __pointer_to_member_type_info + +__pointer_to_member_type_info::~__pointer_to_member_type_info() +{ +} + +// can_catch + +// A handler is a match for an exception object of type E if +// 1. The handler is of type cv T or cv T& and E and T are the same type +// (ignoring the top-level cv-qualifiers), or +// 2. the handler is of type cv T or cv T& and T is an unambiguous public +// base class of E, or +// 3. the handler is of type cv1 T* cv2 and E is a pointer type that can be +// converted to the type of the handler by either or both of +// A. a standard pointer conversion (4.10) not involving conversions to +// pointers to private or protected or ambiguous classes +// B. a qualification conversion +// 4. the handler is a pointer or pointer to member type and E is +// std::nullptr_t. + +// adjustedPtr: +// +// catch (A& a) : adjustedPtr == &a +// catch (A* a) : adjustedPtr == a +// catch (A** a) : adjustedPtr == a +// +// catch (D2& d2) : adjustedPtr == &d2 (d2 is base class of thrown object) +// catch (D2* d2) : adjustedPtr == d2 +// catch (D2*& d2) : adjustedPtr == d2 +// +// catch (...) : adjustedPtr == & of the exception + +// Handles bullet 1 +bool +__fundamental_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + return this == thrown_type; +} + +bool +__array_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + // We can get here if someone tries to catch an array by reference. + // However if someone tries to throw an array, it immediately gets + // converted to a pointer, which will not convert back to an array + // at the catch clause. So this can never catch anything. + return false; +} + +bool +__function_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + // We can get here if someone tries to catch a function by reference. + // However if someone tries to throw a function, it immediately gets + // converted to a pointer, which will not convert back to a function + // at the catch clause. So this can never catch anything. + return false; +} + +// Handles bullet 1 +bool +__enum_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + return this == thrown_type; +} + +// Handles bullets 1 and 2 +bool +__class_type_info::can_catch(const __shim_type_info* thrown_type, + void*& adjustedPtr) const +{ + // bullet 1 + if (this == thrown_type) + return true; + const __class_type_info* thrown_class_type = + dynamic_cast<const __class_type_info*>(thrown_type); + if (thrown_class_type == 0) + return false; + // bullet 2 + __dynamic_cast_info info = {thrown_class_type, 0, this, -1, 0}; + info.number_of_dst_type = 1; + thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); + if (info.path_dst_ptr_to_static_ptr == public_path) + { + adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); + return true; + } + return false; +} + +void +__class_type_info::process_found_base_class(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (info->dst_ptr_leading_to_static_ptr == 0) + { + // First time here + info->dst_ptr_leading_to_static_ptr = adjustedPtr; + info->path_dst_ptr_to_static_ptr = path_below; + info->number_to_static_ptr = 1; + } + else if (info->dst_ptr_leading_to_static_ptr == adjustedPtr) + { + // We've been here before. Update path to "most public" + if (info->path_dst_ptr_to_static_ptr == not_public_path) + info->path_dst_ptr_to_static_ptr = path_below; + } + else + { + // We've detected an ambiguous cast from (thrown_class_type, adjustedPtr) + // to a static_type + info->number_to_static_ptr += 1; + info->path_dst_ptr_to_static_ptr = not_public_path; + info->search_done = true; + } +} + +void +__class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); +} + +void +__si_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); + else + __base_type->has_unambiguous_public_base(info, adjustedPtr, path_below); +} + +void +__base_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; + if (__offset_flags & __virtual_mask) + { + const char* vtable = *static_cast<const char*const*>(adjustedPtr); + offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); + } + __base_type->has_unambiguous_public_base(info, + static_cast<char*>(adjustedPtr) + offset_to_base, + (__offset_flags & __public_mask) ? + path_below : + not_public_path); +} + +void +__vmi_class_type_info::has_unambiguous_public_base(__dynamic_cast_info* info, + void* adjustedPtr, + int path_below) const +{ + if (this == info->static_type) + process_found_base_class(info, adjustedPtr, path_below); + else + { + typedef const __base_class_type_info* Iter; + const Iter e = __base_info + __base_count; + Iter p = __base_info; + p->has_unambiguous_public_base(info, adjustedPtr, path_below); + if (++p < e) + { + do + { + p->has_unambiguous_public_base(info, adjustedPtr, path_below); + if (info->search_done) + break; + } while (++p < e); + } + } +} + +// Handles bullets 1 and 4 for both pointers and member pointers +bool +__pbase_type_info::can_catch(const __shim_type_info* thrown_type, + void*&) const +{ + if (this == thrown_type) + return true; + return thrown_type == &typeid(std::nullptr_t); +} + +// Handles bullets 1, 3 and 4 +bool +__pointer_type_info::can_catch(const __shim_type_info* thrown_type, + void*& adjustedPtr) const +{ + // Do the dereference adjustment + adjustedPtr = *static_cast<void**>(adjustedPtr); + // bullets 1 and 4 + if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) + return true; + // bullet 3 + const __pointer_type_info* thrown_pointer_type = + dynamic_cast<const __pointer_type_info*>(thrown_type); + if (thrown_pointer_type == 0) + return false; + // bullet 3B + if (thrown_pointer_type->__flags & ~__flags) + return false; + if (__pointee == thrown_pointer_type->__pointee) + return true; + // bullet 3A + if (__pointee == &typeid(void)) + return true; + const __class_type_info* catch_class_type = + dynamic_cast<const __class_type_info*>(__pointee); + if (catch_class_type == 0) + return false; + const __class_type_info* thrown_class_type = + dynamic_cast<const __class_type_info*>(thrown_pointer_type->__pointee); + if (thrown_class_type == 0) + return false; + __dynamic_cast_info info = {thrown_class_type, 0, catch_class_type, -1, 0}; + info.number_of_dst_type = 1; + thrown_class_type->has_unambiguous_public_base(&info, adjustedPtr, public_path); + if (info.path_dst_ptr_to_static_ptr == public_path) + { + adjustedPtr = const_cast<void*>(info.dst_ptr_leading_to_static_ptr); + return true; + } + return false; +} + +#pragma GCC visibility pop +#pragma GCC visibility push(default) + +// __dynamic_cast + +// static_ptr: pointer to an object of type static_type; nonnull, and since the +// object is polymorphic, *(void**)static_ptr is a virtual table pointer. +// static_ptr is &v in the expression dynamic_cast<T>(v). +// static_type: static type of the object pointed to by static_ptr. +// dst_type: destination type of the cast (the "T" in "dynamic_cast<T>(v)"). +// src2dst_offset: a static hint about the location of the +// source subobject with respect to the complete object; +// special negative values are: +// -1: no hint +// -2: static_type is not a public base of dst_type +// -3: static_type is a multiple public base type but never a +// virtual base type +// otherwise, the static_type type is a unique public nonvirtual +// base type of dst_type at offset src2dst_offset from the +// origin of dst_type. +// +// (dynamic_ptr, dynamic_type) are the run time type of the complete object +// referred to by static_ptr and a pointer to it. These can be found from +// static_ptr for polymorphic types. +// static_type is guaranteed to be a polymorphic type. +// +// (dynamic_ptr, dynamic_type) is the root of a DAG that grows upward. Each +// node of the tree represents a base class/object of its parent (or parents) below. +// Each node is uniquely represented by a pointer to the object, and a pointer +// to a type_info - its type. Different nodes may have the same pointer and +// different nodes may have the same type. But only one node has a specific +// (pointer-value, type) pair. In C++ two objects of the same type can not +// share the same address. +// +// There are two flavors of nodes which have the type dst_type: +// 1. Those that are derived from (below) (static_ptr, static_type). +// 2. Those that are not derived from (below) (static_ptr, static_type). +// +// Invariants of the DAG: +// +// There is at least one path from the root (dynamic_ptr, dynamic_type) to +// the node (static_ptr, static_type). This path may or may not be public. +// There may be more than one such path (some public some not). Such a path may +// or may not go through a node having type dst_type. +// +// No node of type T appears above a node of the same type. That means that +// there is only one node with dynamic_type. And if dynamic_type == dst_type, +// then there is only one dst_type in the DAG. +// +// No node of type dst_type appears above a node of type static_type. Such +// DAG's are possible in C++, but the compiler computes those dynamic_casts at +// compile time, and only calls __dynamic_cast when dst_type lies below +// static_type in the DAG. +// +// dst_type != static_type: The compiler computes the dynamic_cast in this case too. +// dynamic_type != static_type: The compiler computes the dynamic_cast in this case too. +// +// Returns: +// +// If there is exactly one dst_type of flavor 1, and +// If there is a public path from that dst_type to (static_ptr, static_type), or +// If there are 0 dst_types of flavor 2, and there is a public path from +// (dynamic_ptr, dynamic_type) to (static_ptr, static_type) and a public +// path from (dynamic_ptr, dynamic_type) to the one dst_type, then return +// a pointer to that dst_type. +// Else if there are 0 dst_types of flavor 1 and exactly 1 dst_type of flavor 2, and +// if there is a public path from (dynamic_ptr, dynamic_type) to +// (static_ptr, static_type) and a public path from (dynamic_ptr, dynamic_type) +// to the one dst_type, then return a pointer to that one dst_type. +// Else return nullptr. +// +// If dynamic_type == dst_type, then the above algorithm collapses to the +// following cheaper algorithm: +// +// If there is a public path from (dynamic_ptr, dynamic_type) to +// (static_ptr, static_type), then return dynamic_ptr. +// Else return nullptr. +extern "C" +void* +__dynamic_cast(const void* static_ptr, + const __class_type_info* static_type, + const __class_type_info* dst_type, + std::ptrdiff_t src2dst_offset) +{ + // Possible future optimization: Take advantage of src2dst_offset + // Currently clang always sets src2dst_offset to -1 (no hint). + + // Get (dynamic_ptr, dynamic_type) from static_ptr + void** vtable = *(void***)static_ptr; + ptrdiff_t offset_to_derived = reinterpret_cast<ptrdiff_t>(vtable[-2]); + const void* dynamic_ptr = static_cast<const char*>(static_ptr) + offset_to_derived; + const __class_type_info* dynamic_type = static_cast<const __class_type_info*>(vtable[-1]); + + // Initialize answer to nullptr. This will be changed from the search + // results if a non-null answer is found. Regardless, this is what will + // be returned. + const void* dst_ptr = 0; + // Initialize info struct for this search. + __dynamic_cast_info info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; + + // Find out if we can use a giant short cut in the search + if (dynamic_type == dst_type) + { + // Using giant short cut. Add that information to info. + info.number_of_dst_type = 1; + // Do the search + dynamic_type->search_above_dst(&info, dynamic_ptr, dynamic_ptr, public_path); + // Query the search. + if (info.path_dst_ptr_to_static_ptr == public_path) + dst_ptr = dynamic_ptr; + } + else + { + // Not using giant short cut. Do the search + dynamic_type->search_below_dst(&info, dynamic_ptr, public_path); + // Query the search. + switch (info.number_to_static_ptr) + { + case 0: + if (info.number_to_dst_ptr == 1 && + info.path_dynamic_ptr_to_static_ptr == public_path && + info.path_dynamic_ptr_to_dst_ptr == public_path) + dst_ptr = info.dst_ptr_not_leading_to_static_ptr; + break; + case 1: + if (info.path_dst_ptr_to_static_ptr == public_path || + ( + info.number_to_dst_ptr == 0 && + info.path_dynamic_ptr_to_static_ptr == public_path && + info.path_dynamic_ptr_to_dst_ptr == public_path + ) + ) + dst_ptr = info.dst_ptr_leading_to_static_ptr; + break; + } + } + return const_cast<void*>(dst_ptr); +} + +#pragma GCC visibility pop +#pragma GCC visibility push(hidden) + +// Call this function when you hit a static_type which is a base (above) a dst_type. +// Let caller know you hit a static_type. But only start recording details if +// this is (static_ptr, static_type) -- the node we are casting from. +// If this is (static_ptr, static_type) +// Record the path (public or not) from the dst_type to here. There may be +// multiple paths from the same dst_type to here, record the "most public" one. +// Record the dst_ptr as pointing to (static_ptr, static_type). +// If more than one (dst_ptr, dst_type) points to (static_ptr, static_type), +// then mark this dyanmic_cast as ambiguous and stop the search. +void +__class_type_info::process_static_type_above_dst(__dynamic_cast_info* info, + const void* dst_ptr, + const void* current_ptr, + int path_below) const +{ + // Record that we found a static_type + info->found_any_static_type = true; + if (current_ptr == info->static_ptr) + { + // Record that we found (static_ptr, static_type) + info->found_our_static_ptr = true; + if (info->dst_ptr_leading_to_static_ptr == 0) + { + // First time here + info->dst_ptr_leading_to_static_ptr = dst_ptr; + info->path_dst_ptr_to_static_ptr = path_below; + info->number_to_static_ptr = 1; + // If there is only one dst_type in the entire tree and the path from + // there to here is public then we are done! + if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) + info->search_done = true; + } + else if (info->dst_ptr_leading_to_static_ptr == dst_ptr) + { + // We've been here before. Update path to "most public" + if (info->path_dst_ptr_to_static_ptr == not_public_path) + info->path_dst_ptr_to_static_ptr = path_below; + // If there is only one dst_type in the entire tree and the path from + // there to here is public then we are done! + if (info->number_of_dst_type == 1 && info->path_dst_ptr_to_static_ptr == public_path) + info->search_done = true; + } + else + { + // We've detected an ambiguous cast from (static_ptr, static_type) + // to a dst_type + info->number_to_static_ptr += 1; + info->search_done = true; + } + } +} + +// Call this function when you hit a static_type which is not a base (above) a dst_type. +// If this is (static_ptr, static_type) +// Record the path (public or not) from (dynamic_ptr, dynamic_type) to here. There may be +// multiple paths from (dynamic_ptr, dynamic_type) to here, record the "most public" one. +void +__class_type_info::process_static_type_below_dst(__dynamic_cast_info* info, + const void* current_ptr, + int path_below) const +{ + if (current_ptr == info->static_ptr) + { + // Record the most public path from (dynamic_ptr, dynamic_type) to + // (static_ptr, static_type) + if (info->path_dynamic_ptr_to_static_ptr != public_path) + info->path_dynamic_ptr_to_static_ptr = path_below; + } +} + +// Call this function when searching below a dst_type node. This function searches +// for a path to (static_ptr, static_type) and for paths to one or more dst_type nodes. +// If it finds a static_type node, there is no need to further search base classes +// above. +// If it finds a dst_type node it should search base classes using search_above_dst +// to find out if this dst_type points to (static_ptr, static_type) or not. +// Either way, the dst_type is recorded as one of two "flavors": one that does +// or does not point to (static_ptr, static_type). +// If this is neither a static_type nor a dst_type node, continue searching +// base classes above. +// All the hoopla surrounding the search code is doing nothing but looking for +// excuses to stop the search prematurely (break out of the for-loop). That is, +// the algorithm below is simply an optimization of this: +// void +// __vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, +// const void* current_ptr, +// int path_below) const +// { +// typedef const __base_class_type_info* Iter; +// if (this == info->static_type) +// process_static_type_below_dst(info, current_ptr, path_below); +// else if (this == info->dst_type) +// { +// // Record the most public access path that got us here +// if (info->path_dynamic_ptr_to_dst_ptr != public_path) +// info->path_dynamic_ptr_to_dst_ptr = path_below; +// bool does_dst_type_point_to_our_static_type = false; +// for (Iter p = __base_info, e= __base_info + __base_count; p < e; ++p) +// { +// p->search_above_dst(info, current_ptr, current_ptr, public_path); +// if (info->found_our_static_ptr) +// does_dst_type_point_to_our_static_type = true; +// // break out early here if you can detect it doesn't matter if you do +// } +// if (!does_dst_type_point_to_our_static_type) +// { +// // We found a dst_type that doesn't point to (static_ptr, static_type) +// // So record the address of this dst_ptr and increment the +// // count of the number of such dst_types found in the tree. +// info->dst_ptr_not_leading_to_static_ptr = current_ptr; +// info->number_to_dst_ptr += 1; +// } +// } +// else +// { +// // This is not a static_type and not a dst_type. +// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) +// { +// p->search_below_dst(info, current_ptr, public_path); +// // break out early here if you can detect it doesn't matter if you do +// } +// } +// } +void +__vmi_class_type_info::search_below_dst(__dynamic_cast_info* info, + const void* current_ptr, + int path_below) const +{ + typedef const __base_class_type_info* Iter; + if (this == info->static_type) + process_static_type_below_dst(info, current_ptr, path_below); + else if (this == info->dst_type) + { + // We've been here before if we've recorded current_ptr in one of these + // two places: + if (current_ptr == info->dst_ptr_leading_to_static_ptr || + current_ptr == info->dst_ptr_not_leading_to_static_ptr) + { + // We've seen this node before, and therefore have already searched + // its base classes above. + // Update path to here that is "most public". + if (path_below == public_path) + info->path_dynamic_ptr_to_dst_ptr = public_path; + } + else // We have haven't been here before + { + // Record the access path that got us here + // If there is more than one dst_type this path doesn't matter. + info->path_dynamic_ptr_to_dst_ptr = path_below; + // Only search above here if dst_type derives from static_type, or + // if it is unknown if dst_type derives from static_type. + if (info->is_dst_type_derived_from_static_type != no) + { + // Set up flags to record results from all base classes + bool is_dst_type_derived_from_static_type = false; + bool does_dst_type_point_to_our_static_type = false; + // We've found a dst_type with a potentially public path to here. + // We have to assume the path is public because it may become + // public later (if we get back to here with a public path). + // We can stop looking above if: + // 1. We've found a public path to (static_ptr, static_type). + // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. + // This is detected at the (static_ptr, static_type). + // 3. We can prove that there is no public path to (static_ptr, static_type) + // above here. + const Iter e = __base_info + __base_count; + for (Iter p = __base_info; p < e; ++p) + { + // Zero out found flags + info->found_our_static_ptr = false; + info->found_any_static_type = false; + p->search_above_dst(info, current_ptr, current_ptr, public_path); + if (info->search_done) + break; + if (info->found_any_static_type) + { + is_dst_type_derived_from_static_type = true; + if (info->found_our_static_ptr) + { + does_dst_type_point_to_our_static_type = true; + // If we found what we're looking for, stop looking above. + if (info->path_dst_ptr_to_static_ptr == public_path) + break; + // We found a private path to (static_ptr, static_type) + // If there is no diamond then there is only one path + // to (static_ptr, static_type) and we just found it. + if (!(__flags & __diamond_shaped_mask)) + break; + } + else + { + // If we found a static_type that isn't the one we're looking + // for, and if there are no repeated types above here, + // then stop looking. + if (!(__flags & __non_diamond_repeat_mask)) + break; + } + } + } + if (!does_dst_type_point_to_our_static_type) + { + // We found a dst_type that doesn't point to (static_ptr, static_type) + // So record the address of this dst_ptr and increment the + // count of the number of such dst_types found in the tree. + info->dst_ptr_not_leading_to_static_ptr = current_ptr; + info->number_to_dst_ptr += 1; + // If there exists another dst with a private path to + // (static_ptr, static_type), then the cast from + // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous, + // so stop search. + if (info->number_to_static_ptr == 1 && + info->path_dst_ptr_to_static_ptr == not_public_path) + info->search_done = true; + } + // If we found no static_type,s then dst_type doesn't derive + // from static_type, else it does. Record this result so that + // next time we hit a dst_type we will know not to search above + // it if it doesn't derive from static_type. + if (is_dst_type_derived_from_static_type) + info->is_dst_type_derived_from_static_type = yes; + else + info->is_dst_type_derived_from_static_type = no; + } + } + } + else + { + // This is not a static_type and not a dst_type. + const Iter e = __base_info + __base_count; + Iter p = __base_info; + p->search_below_dst(info, current_ptr, path_below); + if (++p < e) + { + if ((__flags & __diamond_shaped_mask) || info->number_to_static_ptr == 1) + { + // If there are multiple paths to a base above from here, or if + // a dst_type pointing to (static_ptr, static_type) has been found, + // then there is no way to break out of this loop early unless + // something below detects the search is done. + do + { + if (info->search_done) + break; + p->search_below_dst(info, current_ptr, path_below); + } while (++p < e); + } + else if (__flags & __non_diamond_repeat_mask) + { + // There are not multiple paths to any base class from here and a + // dst_type pointing to (static_ptr, static_type) has not yet been + // found. + do + { + if (info->search_done) + break; + // If we just found a dst_type with a public path to (static_ptr, static_type), + // then the only reason to continue the search is to make sure + // no other dst_type points to (static_ptr, static_type). + // If !diamond, then we don't need to search here. + if (info->number_to_static_ptr == 1 && + info->path_dst_ptr_to_static_ptr == public_path) + break; + p->search_below_dst(info, current_ptr, path_below); + } while (++p < e); + } + else + { + // There are no repeated types above this node. + // There are no nodes with multiple parents above this node. + // no dst_type has been found to (static_ptr, static_type) + do + { + if (info->search_done) + break; + // If we just found a dst_type with a public path to (static_ptr, static_type), + // then the only reason to continue the search is to make sure sure + // no other dst_type points to (static_ptr, static_type). + // If !diamond, then we don't need to search here. + // if we just found a dst_type with a private path to (static_ptr, static_type), + // then we're only looking for a public path to (static_ptr, static_type) + // and to check for other dst_types. + // If !diamond & !repeat, then there is not a pointer to (static_ptr, static_type) + // and not a dst_type under here. + if (info->number_to_static_ptr == 1) + break; + p->search_below_dst(info, current_ptr, path_below); + } while (++p < e); + } + } + } +} + +// This is the same algorithm as __vmi_class_type_info::search_below_dst but +// simplified to the case that there is only a single base class. +void +__si_class_type_info::search_below_dst(__dynamic_cast_info* info, + const void* current_ptr, + int path_below) const +{ + if (this == info->static_type) + process_static_type_below_dst(info, current_ptr, path_below); + else if (this == info->dst_type) + { + // We've been here before if we've recorded current_ptr in one of these + // two places: + if (current_ptr == info->dst_ptr_leading_to_static_ptr || + current_ptr == info->dst_ptr_not_leading_to_static_ptr) + { + // We've seen this node before, and therefore have already searched + // its base classes above. + // Update path to here that is "most public". + if (path_below == public_path) + info->path_dynamic_ptr_to_dst_ptr = public_path; + } + else // We have haven't been here before + { + // Record the access path that got us here + // If there is more than one dst_type this path doesn't matter. + info->path_dynamic_ptr_to_dst_ptr = path_below; + // Only search above here if dst_type derives from static_type, or + // if it is unknown if dst_type derives from static_type. + if (info->is_dst_type_derived_from_static_type != no) + { + // Set up flags to record results from all base classes + bool is_dst_type_derived_from_static_type = false; + bool does_dst_type_point_to_our_static_type = false; + // Zero out found flags + info->found_our_static_ptr = false; + info->found_any_static_type = false; + __base_type->search_above_dst(info, current_ptr, current_ptr, public_path); + if (info->found_any_static_type) + { + is_dst_type_derived_from_static_type = true; + if (info->found_our_static_ptr) + does_dst_type_point_to_our_static_type = true; + } + if (!does_dst_type_point_to_our_static_type) + { + // We found a dst_type that doesn't point to (static_ptr, static_type) + // So record the address of this dst_ptr and increment the + // count of the number of such dst_types found in the tree. + info->dst_ptr_not_leading_to_static_ptr = current_ptr; + info->number_to_dst_ptr += 1; + // If there exists another dst with a private path to + // (static_ptr, static_type), then the cast from + // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. + if (info->number_to_static_ptr == 1 && + info->path_dst_ptr_to_static_ptr == not_public_path) + info->search_done = true; + } + // If we found no static_type,s then dst_type doesn't derive + // from static_type, else it does. Record this result so that + // next time we hit a dst_type we will know not to search above + // it if it doesn't derive from static_type. + if (is_dst_type_derived_from_static_type) + info->is_dst_type_derived_from_static_type = yes; + else + info->is_dst_type_derived_from_static_type = no; + } + } + } + else + { + // This is not a static_type and not a dst_type + __base_type->search_below_dst(info, current_ptr, path_below); + } +} + +// This is the same algorithm as __vmi_class_type_info::search_below_dst but +// simplified to the case that there is no base class. +void +__class_type_info::search_below_dst(__dynamic_cast_info* info, + const void* current_ptr, + int path_below) const +{ + typedef const __base_class_type_info* Iter; + if (this == info->static_type) + process_static_type_below_dst(info, current_ptr, path_below); + else if (this == info->dst_type) + { + // We've been here before if we've recorded current_ptr in one of these + // two places: + if (current_ptr == info->dst_ptr_leading_to_static_ptr || + current_ptr == info->dst_ptr_not_leading_to_static_ptr) + { + // We've seen this node before, and therefore have already searched + // its base classes above. + // Update path to here that is "most public". + if (path_below == public_path) + info->path_dynamic_ptr_to_dst_ptr = public_path; + } + else // We have haven't been here before + { + // Record the access path that got us here + // If there is more than one dst_type this path doesn't matter. + info->path_dynamic_ptr_to_dst_ptr = path_below; + // We found a dst_type that doesn't point to (static_ptr, static_type) + // So record the address of this dst_ptr and increment the + // count of the number of such dst_types found in the tree. + info->dst_ptr_not_leading_to_static_ptr = current_ptr; + info->number_to_dst_ptr += 1; + // If there exists another dst with a private path to + // (static_ptr, static_type), then the cast from + // (dynamic_ptr, dynamic_type) to dst_type is now ambiguous. + if (info->number_to_static_ptr == 1 && + info->path_dst_ptr_to_static_ptr == not_public_path) + info->search_done = true; + // We found that dst_type does not derive from static_type + info->is_dst_type_derived_from_static_type = no; + } + } +} + +// Call this function when searching above a dst_type node. This function searches +// for a public path to (static_ptr, static_type). +// This function is guaranteed not to find a node of type dst_type. +// Theoretically this is a very simple function which just stops if it finds a +// static_type node: All the hoopla surrounding the search code is doing +// nothing but looking for excuses to stop the search prematurely (break out of +// the for-loop). That is, the algorithm below is simply an optimization of this: +// void +// __vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, +// const void* dst_ptr, +// const void* current_ptr, +// int path_below) const +// { +// if (this == info->static_type) +// process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); +// else +// { +// typedef const __base_class_type_info* Iter; +// // This is not a static_type and not a dst_type +// for (Iter p = __base_info, e = __base_info + __base_count; p < e; ++p) +// { +// p->search_above_dst(info, dst_ptr, current_ptr, public_path); +// // break out early here if you can detect it doesn't matter if you do +// } +// } +// } +void +__vmi_class_type_info::search_above_dst(__dynamic_cast_info* info, + const void* dst_ptr, + const void* current_ptr, + int path_below) const +{ + if (this == info->static_type) + process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); + else + { + typedef const __base_class_type_info* Iter; + // This is not a static_type and not a dst_type + // Save flags so they can be restored when returning to nodes below. + bool found_our_static_ptr = info->found_our_static_ptr; + bool found_any_static_type = info->found_any_static_type; + // We've found a dst_type below with a path to here. If the path + // to here is not public, there may be another path to here that + // is public. So we have to assume that the path to here is public. + // We can stop looking above if: + // 1. We've found a public path to (static_ptr, static_type). + // 2. We've found an ambiguous cast from (static_ptr, static_type) to a dst_type. + // This is detected at the (static_ptr, static_type). + // 3. We can prove that there is no public path to (static_ptr, static_type) + // above here. + const Iter e = __base_info + __base_count; + Iter p = __base_info; + // Zero out found flags + info->found_our_static_ptr = false; + info->found_any_static_type = false; + p->search_above_dst(info, dst_ptr, current_ptr, path_below); + if (++p < e) + { + do + { + if (info->search_done) + break; + if (info->found_our_static_ptr) + { + // If we found what we're looking for, stop looking above. + if (info->path_dst_ptr_to_static_ptr == public_path) + break; + // We found a private path to (static_ptr, static_type) + // If there is no diamond then there is only one path + // to (static_ptr, static_type) from here and we just found it. + if (!(__flags & __diamond_shaped_mask)) + break; + } + else if (info->found_any_static_type) + { + // If we found a static_type that isn't the one we're looking + // for, and if there are no repeated types above here, + // then stop looking. + if (!(__flags & __non_diamond_repeat_mask)) + break; + } + // Zero out found flags + info->found_our_static_ptr = false; + info->found_any_static_type = false; + p->search_above_dst(info, dst_ptr, current_ptr, path_below); + } while (++p < e); + } + // Restore flags + info->found_our_static_ptr = found_our_static_ptr; + info->found_any_static_type = found_any_static_type; + } +} + +// This is the same algorithm as __vmi_class_type_info::search_above_dst but +// simplified to the case that there is only a single base class. +void +__si_class_type_info::search_above_dst(__dynamic_cast_info* info, + const void* dst_ptr, + const void* current_ptr, + int path_below) const +{ + if (this == info->static_type) + process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); + else + __base_type->search_above_dst(info, dst_ptr, current_ptr, path_below); +} + +// This is the same algorithm as __vmi_class_type_info::search_above_dst but +// simplified to the case that there is no base class. +void +__class_type_info::search_above_dst(__dynamic_cast_info* info, + const void* dst_ptr, + const void* current_ptr, + int path_below) const +{ + if (this == info->static_type) + process_static_type_above_dst(info, dst_ptr, current_ptr, path_below); +} + +// The search functions for __base_class_type_info are simply convenience +// functions for adjusting the current_ptr and path_below as the search is +// passed up to the base class node. + +void +__base_class_type_info::search_above_dst(__dynamic_cast_info* info, + const void* dst_ptr, + const void* current_ptr, + int path_below) const +{ + ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; + if (__offset_flags & __virtual_mask) + { + const char* vtable = *static_cast<const char*const*>(current_ptr); + offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); + } + __base_type->search_above_dst(info, dst_ptr, + static_cast<const char*>(current_ptr) + offset_to_base, + (__offset_flags & __public_mask) ? + path_below : + not_public_path); +} + +void +__base_class_type_info::search_below_dst(__dynamic_cast_info* info, + const void* current_ptr, + int path_below) const +{ + ptrdiff_t offset_to_base = __offset_flags >> __offset_shift; + if (__offset_flags & __virtual_mask) + { + const char* vtable = *static_cast<const char*const*>(current_ptr); + offset_to_base = *reinterpret_cast<const ptrdiff_t*>(vtable + offset_to_base); + } + __base_type->search_below_dst(info, + static_cast<const char*>(current_ptr) + offset_to_base, + (__offset_flags & __public_mask) ? + path_below : + not_public_path); +} + +#pragma GCC visibility pop + +} // __cxxabiv1 diff --git a/system/lib/libcxxabi/src/private_typeinfo.h b/system/lib/libcxxabi/src/private_typeinfo.h new file mode 100644 index 00000000..fec081ab --- /dev/null +++ b/system/lib/libcxxabi/src/private_typeinfo.h @@ -0,0 +1,246 @@ +//===------------------------ private_typeinfo.h --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PRIVATE_TYPEINFO_H_ +#define __PRIVATE_TYPEINFO_H_ + +#include <typeinfo> +#include <cstddef> + +namespace __cxxabiv1 +{ + +#pragma GCC visibility push(hidden) + +class __attribute__ ((__visibility__("hidden"))) __shim_type_info + : public std::type_info +{ +public: + virtual ~__shim_type_info(); + + virtual bool can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const = 0; +}; + +class __attribute__ ((__visibility__("default"))) __fundamental_type_info + : public __shim_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__fundamental_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +class __attribute__ ((__visibility__("default"))) __array_type_info + : public __shim_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__array_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +class __attribute__ ((__visibility__("default"))) __function_type_info + : public __shim_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__function_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +class __attribute__ ((__visibility__("default"))) __enum_type_info + : public __shim_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__enum_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +enum +{ + unknown = 0, + public_path, + not_public_path, + yes, + no +}; + +class __class_type_info; + +struct __dynamic_cast_info +{ +// const data supplied to the search: + + const __class_type_info* const dst_type; + const void* const static_ptr; + const __class_type_info* const static_type; + const std::ptrdiff_t src2dst_offset; + +// Data that represents the answer: + + // pointer to a dst_type which has (static_ptr, static_type) above it + const void* dst_ptr_leading_to_static_ptr; + // pointer to a dst_type which does not have (static_ptr, static_type) above it + const void* dst_ptr_not_leading_to_static_ptr; + + // The following three paths are either unknown, public_path or not_public_path. + // access of path from dst_ptr_leading_to_static_ptr to (static_ptr, static_type) + int path_dst_ptr_to_static_ptr; + // access of path from (dynamic_ptr, dynamic_type) to (static_ptr, static_type) + // when there is no dst_type along the path + int path_dynamic_ptr_to_static_ptr; + // access of path from (dynamic_ptr, dynamic_type) to dst_type + // (not used if there is a (static_ptr, static_type) above a dst_type). + int path_dynamic_ptr_to_dst_ptr; + + // Number of dst_types below (static_ptr, static_type) + int number_to_static_ptr; + // Number of dst_types not below (static_ptr, static_type) + int number_to_dst_ptr; + +// Data that helps stop the search before the entire tree is searched: + + // is_dst_type_derived_from_static_type is either unknown, yes or no. + int is_dst_type_derived_from_static_type; + // Number of dst_type in tree. If 0, then that means unknown. + int number_of_dst_type; + // communicates to a dst_type node that (static_ptr, static_type) was found + // above it. + bool found_our_static_ptr; + // communicates to a dst_type node that a static_type was found + // above it, but it wasn't (static_ptr, static_type) + bool found_any_static_type; + // Set whenever a search can be stopped + bool search_done; +}; + +// Has no base class +class __attribute__ ((__visibility__("default"))) __class_type_info + : public __shim_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__class_type_info(); + + __attribute__ ((__visibility__("hidden"))) + void process_static_type_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + void process_static_type_below_dst(__dynamic_cast_info*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + void process_found_base_class(__dynamic_cast_info*, void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual bool can_catch(const __shim_type_info*, void*&) const; + __attribute__ ((__visibility__("hidden"))) + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; +}; + +// Has one non-virtual public base class at offset zero +class __attribute__ ((__visibility__("default"))) __si_class_type_info + : public __class_type_info +{ +public: + const __class_type_info* __base_type; + + __attribute__ ((__visibility__("hidden"))) virtual ~__si_class_type_info(); + + __attribute__ ((__visibility__("hidden"))) + virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; +}; + +struct __base_class_type_info +{ +public: + const __class_type_info* __base_type; + long __offset_flags; + + enum __offset_flags_masks + { + __virtual_mask = 0x1, + __public_mask = 0x2, // base is public + __offset_shift = 8 + }; + + void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; + void search_below_dst(__dynamic_cast_info*, const void*, int) const; + void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; +}; + +// Has one or more base classes +class __attribute__ ((__visibility__("default"))) __vmi_class_type_info + : public __class_type_info +{ +public: + unsigned int __flags; + unsigned int __base_count; + __base_class_type_info __base_info[1]; + + enum __flags_masks + { + __non_diamond_repeat_mask = 0x1, // has two or more distinct base class + // objects of the same type + __diamond_shaped_mask = 0x2 // has base class object with two or + // more derived objects + }; + + __attribute__ ((__visibility__("hidden"))) virtual ~__vmi_class_type_info(); + + __attribute__ ((__visibility__("hidden"))) + virtual void search_above_dst(__dynamic_cast_info*, const void*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void search_below_dst(__dynamic_cast_info*, const void*, int) const; + __attribute__ ((__visibility__("hidden"))) + virtual void has_unambiguous_public_base(__dynamic_cast_info*, void*, int) const; +}; + +class __attribute__ ((__visibility__("default"))) __pbase_type_info + : public __shim_type_info +{ +public: + unsigned int __flags; + const __shim_type_info* __pointee; + + enum __masks + { + __const_mask = 0x1, + __volatile_mask = 0x2, + __restrict_mask = 0x4, + __incomplete_mask = 0x8, + __incomplete_class_mask = 0x10 + }; + + __attribute__ ((__visibility__("hidden"))) virtual ~__pbase_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +class __attribute__ ((__visibility__("default"))) __pointer_type_info + : public __pbase_type_info +{ +public: + __attribute__ ((__visibility__("hidden"))) virtual ~__pointer_type_info(); + __attribute__ ((__visibility__("hidden"))) virtual bool can_catch(const __shim_type_info*, void*&) const; +}; + +class __attribute__ ((__visibility__("default"))) __pointer_to_member_type_info + : public __pbase_type_info +{ +public: + const __class_type_info* __context; + + __attribute__ ((__visibility__("hidden"))) virtual ~__pointer_to_member_type_info(); +}; + +#pragma GCC visibility pop + +} // __cxxabiv1 + +#endif // __PRIVATE_TYPEINFO_H_ diff --git a/system/lib/libcxxabi/src/stdexcept.cpp b/system/lib/libcxxabi/src/stdexcept.cpp new file mode 100644 index 00000000..4aa962d0 --- /dev/null +++ b/system/lib/libcxxabi/src/stdexcept.cpp @@ -0,0 +1,122 @@ +//===------------------------ stdexcept.cpp -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "stdexcept" +#include "new" +#include <cstdlib> +#include <cstring> +#include <cstdint> +#include <cstddef> + +// Note: optimize for size + +#pragma GCC visibility push(hidden) + +namespace +{ + +class __libcpp_nmstr +{ +private: + const char* str_; + + typedef std::size_t unused_t; + typedef std::int32_t count_t; + + static const std::ptrdiff_t offset = static_cast<std::ptrdiff_t>(2*sizeof(unused_t) + + sizeof(count_t)); + + count_t& count() const _NOEXCEPT {return (count_t&)(*(str_ - sizeof(count_t)));} +public: + explicit __libcpp_nmstr(const char* msg); + __libcpp_nmstr(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW; + __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _LIBCPP_CANTTHROW; + ~__libcpp_nmstr() _LIBCPP_CANTTHROW; + const char* c_str() const _NOEXCEPT {return str_;} +}; + +__libcpp_nmstr::__libcpp_nmstr(const char* msg) +{ + std::size_t len = strlen(msg); + str_ = new char[len + 1 + offset]; + unused_t* c = (unused_t*)str_; + c[0] = c[1] = len; + str_ += offset; + count() = 0; + std::strcpy(const_cast<char*>(c_str()), msg); +} + +inline +__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) + : str_(s.str_) +{ + __sync_add_and_fetch(&count(), 1); +} + +__libcpp_nmstr& +__libcpp_nmstr::operator=(const __libcpp_nmstr& s) +{ + const char* p = str_; + str_ = s.str_; + __sync_add_and_fetch(&count(), 1); + if (__sync_add_and_fetch((count_t*)(p-sizeof(count_t)), -1) < 0) + delete [] (p-offset); + return *this; +} + +inline +__libcpp_nmstr::~__libcpp_nmstr() +{ + if (__sync_add_and_fetch(&count(), -1) < 0) + delete [] (str_ - offset); +} + +} + +#pragma GCC visibility pop + +namespace std // purposefully not using versioning namespace +{ + +logic_error::~logic_error() _NOEXCEPT +{ + __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_; + s.~__libcpp_nmstr(); +} + +const char* +logic_error::what() const _NOEXCEPT +{ + __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_; + return s.c_str(); +} + +runtime_error::~runtime_error() _NOEXCEPT +{ + __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_; + s.~__libcpp_nmstr(); +} + +const char* +runtime_error::what() const _NOEXCEPT +{ + __libcpp_nmstr& s = (__libcpp_nmstr&)__imp_; + return s.c_str(); +} + +domain_error::~domain_error() _NOEXCEPT {} +invalid_argument::~invalid_argument() _NOEXCEPT {} +length_error::~length_error() _NOEXCEPT {} +out_of_range::~out_of_range() _NOEXCEPT {} + +range_error::~range_error() _NOEXCEPT {} +overflow_error::~overflow_error() _NOEXCEPT {} +underflow_error::~underflow_error() _NOEXCEPT {} + +} // std diff --git a/system/lib/libcxxabi/src/temporary.cpp b/system/lib/libcxxabi/src/temporary.cpp new file mode 100644 index 00000000..5facf39d --- /dev/null +++ b/system/lib/libcxxabi/src/temporary.cpp @@ -0,0 +1,41 @@ +//===---------------------------- temporary.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "abort_message.h" + +#pragma GCC visibility push(default) + +extern "C" +{ + +static +void f1() +{ + abort_message("__cxa_new_handler shouldn't be called"); +} + +static +void f2() +{ + abort_message("__cxa_terminate_handler shouldn't be called"); +} + +static +void f3() +{ + abort_message("__cxa_unexpected_handler shouldn't be called"); +} + +void (*__cxa_new_handler)() = f1; +void (*__cxa_terminate_handler)() = f2; +void (*__cxa_unexpected_handler)() = f3; + +} + +#pragma GCC visibility pop diff --git a/system/lib/libcxxabi/src/typeinfo.cpp b/system/lib/libcxxabi/src/typeinfo.cpp new file mode 100644 index 00000000..9313be04 --- /dev/null +++ b/system/lib/libcxxabi/src/typeinfo.cpp @@ -0,0 +1,53 @@ +//===----------------------------- typeinfo.cpp ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include <typeinfo> + +namespace std +{ + +// type_info + +type_info::~type_info() +{ +} + +// bad_cast + +bad_cast::bad_cast() _NOEXCEPT +{ +} + +bad_cast::~bad_cast() _NOEXCEPT +{ +} + +const char* +bad_cast::what() const _NOEXCEPT +{ + return "std::bad_cast"; +} + +// bad_typeid + +bad_typeid::bad_typeid() _NOEXCEPT +{ +} + +bad_typeid::~bad_typeid() _NOEXCEPT +{ +} + +const char* +bad_typeid::what() const _NOEXCEPT +{ + return "std::bad_typeid"; +} + +} // std |