From 44cb63a6ecea58dc21d20843f5af0a006f8b36cd Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 10 Jan 2014 17:32:51 +0700 Subject: Update to current libcxxabi for new exception code. --- system/lib/libcxxabi/CREDITS.TXT | 28 +- system/lib/libcxxabi/LICENSE.TXT | 4 +- system/lib/libcxxabi/include/cxa_demangle.h | 167 - system/lib/libcxxabi/include/libunwind.h | 486 + .../include/mach-o/compact_unwind_encoding.h | 487 + system/lib/libcxxabi/include/unwind.h | 217 + system/lib/libcxxabi/lib/buildit | 6 +- system/lib/libcxxabi/readme.txt | 2 +- system/lib/libcxxabi/src/Unwind/AddressSpace.hpp | 430 + .../lib/libcxxabi/src/Unwind/CompactUnwinder.hpp | 693 + .../lib/libcxxabi/src/Unwind/DwarfInstructions.hpp | 888 ++ system/lib/libcxxabi/src/Unwind/DwarfParser.hpp | 713 + system/lib/libcxxabi/src/Unwind/Registers.hpp | 1568 ++ system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c | 468 + system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp | 1063 ++ .../libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c | 268 + system/lib/libcxxabi/src/Unwind/UnwindLevel1.c | 495 + .../libcxxabi/src/Unwind/UnwindRegistersRestore.S | 329 + .../lib/libcxxabi/src/Unwind/UnwindRegistersSave.S | 301 + .../libcxxabi/src/Unwind/Unwind_AppleExtras.cpp | 205 + system/lib/libcxxabi/src/Unwind/assembly.h | 44 + system/lib/libcxxabi/src/Unwind/config.h | 108 + system/lib/libcxxabi/src/Unwind/dwarf2.h | 237 + system/lib/libcxxabi/src/Unwind/libunwind.cpp | 353 + system/lib/libcxxabi/src/Unwind/libunwind_ext.h | 38 + system/lib/libcxxabi/src/Unwind/unwind_ext.h | 37 + system/lib/libcxxabi/src/cxa_default_handlers.cpp | 120 + system/lib/libcxxabi/src/cxa_demangle.cpp | 14263 ++++++------------- system/lib/libcxxabi/src/cxa_exception.cpp | 2 +- system/lib/libcxxabi/src/cxa_exception.hpp | 18 +- system/lib/libcxxabi/src/cxa_new_delete.cpp | 36 +- system/lib/libcxxabi/src/private_typeinfo.cpp | 20 +- system/lib/libcxxabi/src/stdexcept.cpp | 16 +- system/lib/libcxxabi/symbols | 3 +- 34 files changed, 13718 insertions(+), 10395 deletions(-) delete mode 100644 system/lib/libcxxabi/include/cxa_demangle.h create mode 100644 system/lib/libcxxabi/include/libunwind.h create mode 100644 system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h create mode 100644 system/lib/libcxxabi/include/unwind.h create mode 100644 system/lib/libcxxabi/src/Unwind/AddressSpace.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/DwarfParser.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/Registers.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c create mode 100644 system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp create mode 100644 system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c create mode 100644 system/lib/libcxxabi/src/Unwind/UnwindLevel1.c create mode 100644 system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S create mode 100644 system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S create mode 100644 system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp create mode 100644 system/lib/libcxxabi/src/Unwind/assembly.h create mode 100644 system/lib/libcxxabi/src/Unwind/config.h create mode 100644 system/lib/libcxxabi/src/Unwind/dwarf2.h create mode 100644 system/lib/libcxxabi/src/Unwind/libunwind.cpp create mode 100644 system/lib/libcxxabi/src/Unwind/libunwind_ext.h create mode 100644 system/lib/libcxxabi/src/Unwind/unwind_ext.h create mode 100644 system/lib/libcxxabi/src/cxa_default_handlers.cpp (limited to 'system/lib') diff --git a/system/lib/libcxxabi/CREDITS.TXT b/system/lib/libcxxabi/CREDITS.TXT index 5446562a..bd54ba90 100644 --- a/system/lib/libcxxabi/CREDITS.TXT +++ b/system/lib/libcxxabi/CREDITS.TXT @@ -8,18 +8,30 @@ 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: mclow.lists@gmail.com E: marshall@idio.com D: Architect and primary coauthor of libc++abi +N: Matthew Dempsky +E: matthew@dempsky.org +D: Minor patches and bug fixes. + +N: Nowar Gu +E: wenhan.gu@gmail.com +D: Minor patches and fixes + +N: Howard Hinnant +E: hhinnant@apple.com +D: Architect and primary coauthor of libc++abi + N: Nick Kledzik E: kledzik@apple.com +N: Bruce Mitchener, Jr. +E: bruce.mitchener@gmail.com +D: Minor typo fixes + N: Andrew Morrow E: andrew.c.morrow@gmail.com D: Minor patches and fixes @@ -28,11 +40,3 @@ N: Erik Olofsson E: erik.olofsson@hansoft.se E: erik@olofsson.info D: Minor patches and fixes - -N: Nowar Gu -E: wenhan.gu@gmail.com -D: Minor patches and fixes - -N: Bruce Mitchener, Jr. -E: bruce.mitchener@gmail.com -D: Minor typo fixes diff --git a/system/lib/libcxxabi/LICENSE.TXT b/system/lib/libcxxabi/LICENSE.TXT index b04ba2c9..17969ae2 100644 --- a/system/lib/libcxxabi/LICENSE.TXT +++ b/system/lib/libcxxabi/LICENSE.TXT @@ -14,7 +14,7 @@ Full text of the relevant licenses is included below. University of Illinois/NCSA Open Source License -Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT All rights reserved. @@ -55,7 +55,7 @@ SOFTWARE. ============================================================================== -Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT +Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/system/lib/libcxxabi/include/cxa_demangle.h b/system/lib/libcxxabi/include/cxa_demangle.h deleted file mode 100644 index 46dc9821..00000000 --- a/system/lib/libcxxabi/include/cxa_demangle.h +++ /dev/null @@ -1,167 +0,0 @@ -//===-------------------------- 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 - -#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 bool __make(); - template bool __make(_A0 __a0); - template bool __make(_A0 __a0, _A1 __a1); - template - bool __make(_A0 __a0, _A1 __a1, _A2 __a2); - template - bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3); - template - bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4); - template - 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/libunwind.h b/system/lib/libcxxabi/include/libunwind.h new file mode 100644 index 00000000..eaeab39f --- /dev/null +++ b/system/lib/libcxxabi/include/libunwind.h @@ -0,0 +1,486 @@ +//===---------------------------- libunwind.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. +// +// +// Compatible with libuwind API documented at: +// http://www.nongnu.org/libunwind/man/libunwind(3).html +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBUNWIND__ +#define __LIBUNWIND__ + +#include +#include + +#if __APPLE__ + #include + #if __arm__ + #define LIBUNWIND_AVAIL __attribute__((unavailable)) + #else + #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0) + #endif +#else + #define LIBUNWIND_AVAIL +#endif + +/* error codes */ +enum { + UNW_ESUCCESS = 0, /* no error */ + UNW_EUNSPEC = -6540, /* unspecified (general) error */ + UNW_ENOMEM = -6541, /* out of memory */ + UNW_EBADREG = -6542, /* bad register number */ + UNW_EREADONLYREG = -6543, /* attempt to write read-only register */ + UNW_ESTOPUNWIND = -6544, /* stop unwinding */ + UNW_EINVALIDIP = -6545, /* invalid IP */ + UNW_EBADFRAME = -6546, /* bad frame */ + UNW_EINVAL = -6547, /* unsupported operation or bad value */ + UNW_EBADVERSION = -6548, /* unwind info has unsupported version */ + UNW_ENOINFO = -6549 /* no unwind info found */ +}; + +struct unw_context_t { + uint64_t data[128]; +}; +typedef struct unw_context_t unw_context_t; + +struct unw_cursor_t { + uint64_t data[140]; +}; +typedef struct unw_cursor_t unw_cursor_t; + +typedef struct unw_addr_space *unw_addr_space_t; + +typedef int unw_regnum_t; +typedef uint64_t unw_word_t; +typedef double unw_fpreg_t; + +struct unw_proc_info_t { + unw_word_t start_ip; /* start address of function */ + unw_word_t end_ip; /* address after end of function */ + unw_word_t lsda; /* address of language specific data area, */ + /* or zero if not used */ + unw_word_t handler; /* personality routine, or zero if not used */ + unw_word_t gp; /* not used */ + unw_word_t flags; /* not used */ + uint32_t format; /* compact unwind encoding, or zero if none */ + uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */ + unw_word_t unwind_info; /* address of dwarf unwind info, or zero */ + unw_word_t extra; /* mach_header of mach-o image containing func */ +}; +typedef struct unw_proc_info_t unw_proc_info_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL; +extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL; +extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL; +extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL; +extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL; +extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL; + +extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL; +extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL; +extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL; +extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL; +//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*); + +#if UNW_REMOTE +/* + * Mac OS X "remote" API for unwinding other processes on same machine + * + */ +extern unw_addr_space_t unw_local_addr_space; +extern unw_addr_space_t unw_create_addr_space_for_task(task_t); +extern void unw_destroy_addr_space(unw_addr_space_t); +extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *); +#endif + +/* + * traditional libuwind "remote" API + * NOT IMPLEMENTED on Mac OS X + * + * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t, + * thread_t*); + * extern unw_accessors_t unw_get_accessors(unw_addr_space_t); + * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int); + * extern void unw_flush_cache(unw_addr_space_t, unw_word_t, + * unw_word_t); + * extern int unw_set_caching_policy(unw_addr_space_t, + * unw_caching_policy_t); + * extern void _U_dyn_register(unw_dyn_info_t*); + * extern void _U_dyn_cancel(unw_dyn_info_t*); + */ + +#ifdef __cplusplus +} +#endif + +// architecture independent register numbers +enum { + UNW_REG_IP = -1, // instruction pointer + UNW_REG_SP = -2, // stack pointer +}; + +// 32-bit x86 registers +enum { + UNW_X86_EAX = 0, + UNW_X86_ECX = 1, + UNW_X86_EDX = 2, + UNW_X86_EBX = 3, + UNW_X86_EBP = 4, + UNW_X86_ESP = 5, + UNW_X86_ESI = 6, + UNW_X86_EDI = 7 +}; + +// 64-bit x86_64 registers +enum { + UNW_X86_64_RAX = 0, + UNW_X86_64_RDX = 1, + UNW_X86_64_RCX = 2, + UNW_X86_64_RBX = 3, + UNW_X86_64_RSI = 4, + UNW_X86_64_RDI = 5, + UNW_X86_64_RBP = 6, + UNW_X86_64_RSP = 7, + UNW_X86_64_R8 = 8, + UNW_X86_64_R9 = 9, + UNW_X86_64_R10 = 10, + UNW_X86_64_R11 = 11, + UNW_X86_64_R12 = 12, + UNW_X86_64_R13 = 13, + UNW_X86_64_R14 = 14, + UNW_X86_64_R15 = 15 +}; + + +// 32-bit ppc register numbers +enum { + UNW_PPC_R0 = 0, + UNW_PPC_R1 = 1, + UNW_PPC_R2 = 2, + UNW_PPC_R3 = 3, + UNW_PPC_R4 = 4, + UNW_PPC_R5 = 5, + UNW_PPC_R6 = 6, + UNW_PPC_R7 = 7, + UNW_PPC_R8 = 8, + UNW_PPC_R9 = 9, + UNW_PPC_R10 = 10, + UNW_PPC_R11 = 11, + UNW_PPC_R12 = 12, + UNW_PPC_R13 = 13, + UNW_PPC_R14 = 14, + UNW_PPC_R15 = 15, + UNW_PPC_R16 = 16, + UNW_PPC_R17 = 17, + UNW_PPC_R18 = 18, + UNW_PPC_R19 = 19, + UNW_PPC_R20 = 20, + UNW_PPC_R21 = 21, + UNW_PPC_R22 = 22, + UNW_PPC_R23 = 23, + UNW_PPC_R24 = 24, + UNW_PPC_R25 = 25, + UNW_PPC_R26 = 26, + UNW_PPC_R27 = 27, + UNW_PPC_R28 = 28, + UNW_PPC_R29 = 29, + UNW_PPC_R30 = 30, + UNW_PPC_R31 = 31, + UNW_PPC_F0 = 32, + UNW_PPC_F1 = 33, + UNW_PPC_F2 = 34, + UNW_PPC_F3 = 35, + UNW_PPC_F4 = 36, + UNW_PPC_F5 = 37, + UNW_PPC_F6 = 38, + UNW_PPC_F7 = 39, + UNW_PPC_F8 = 40, + UNW_PPC_F9 = 41, + UNW_PPC_F10 = 42, + UNW_PPC_F11 = 43, + UNW_PPC_F12 = 44, + UNW_PPC_F13 = 45, + UNW_PPC_F14 = 46, + UNW_PPC_F15 = 47, + UNW_PPC_F16 = 48, + UNW_PPC_F17 = 49, + UNW_PPC_F18 = 50, + UNW_PPC_F19 = 51, + UNW_PPC_F20 = 52, + UNW_PPC_F21 = 53, + UNW_PPC_F22 = 54, + UNW_PPC_F23 = 55, + UNW_PPC_F24 = 56, + UNW_PPC_F25 = 57, + UNW_PPC_F26 = 58, + UNW_PPC_F27 = 59, + UNW_PPC_F28 = 60, + UNW_PPC_F29 = 61, + UNW_PPC_F30 = 62, + UNW_PPC_F31 = 63, + UNW_PPC_MQ = 64, + UNW_PPC_LR = 65, + UNW_PPC_CTR = 66, + UNW_PPC_AP = 67, + UNW_PPC_CR0 = 68, + UNW_PPC_CR1 = 69, + UNW_PPC_CR2 = 70, + UNW_PPC_CR3 = 71, + UNW_PPC_CR4 = 72, + UNW_PPC_CR5 = 73, + UNW_PPC_CR6 = 74, + UNW_PPC_CR7 = 75, + UNW_PPC_XER = 76, + UNW_PPC_V0 = 77, + UNW_PPC_V1 = 78, + UNW_PPC_V2 = 79, + UNW_PPC_V3 = 80, + UNW_PPC_V4 = 81, + UNW_PPC_V5 = 82, + UNW_PPC_V6 = 83, + UNW_PPC_V7 = 84, + UNW_PPC_V8 = 85, + UNW_PPC_V9 = 86, + UNW_PPC_V10 = 87, + UNW_PPC_V11 = 88, + UNW_PPC_V12 = 89, + UNW_PPC_V13 = 90, + UNW_PPC_V14 = 91, + UNW_PPC_V15 = 92, + UNW_PPC_V16 = 93, + UNW_PPC_V17 = 94, + UNW_PPC_V18 = 95, + UNW_PPC_V19 = 96, + UNW_PPC_V20 = 97, + UNW_PPC_V21 = 98, + UNW_PPC_V22 = 99, + UNW_PPC_V23 = 100, + UNW_PPC_V24 = 101, + UNW_PPC_V25 = 102, + UNW_PPC_V26 = 103, + UNW_PPC_V27 = 104, + UNW_PPC_V28 = 105, + UNW_PPC_V29 = 106, + UNW_PPC_V30 = 107, + UNW_PPC_V31 = 108, + UNW_PPC_VRSAVE = 109, + UNW_PPC_VSCR = 110, + UNW_PPC_SPE_ACC = 111, + UNW_PPC_SPEFSCR = 112 +}; + +// 64-bit ARM64 registers +enum { + UNW_ARM64_X0 = 0, + UNW_ARM64_X1 = 1, + UNW_ARM64_X2 = 2, + UNW_ARM64_X3 = 3, + UNW_ARM64_X4 = 4, + UNW_ARM64_X5 = 5, + UNW_ARM64_X6 = 6, + UNW_ARM64_X7 = 7, + UNW_ARM64_X8 = 8, + UNW_ARM64_X9 = 9, + UNW_ARM64_X10 = 10, + UNW_ARM64_X11 = 11, + UNW_ARM64_X12 = 12, + UNW_ARM64_X13 = 13, + UNW_ARM64_X14 = 14, + UNW_ARM64_X15 = 15, + UNW_ARM64_X16 = 16, + UNW_ARM64_X17 = 17, + UNW_ARM64_X18 = 18, + UNW_ARM64_X19 = 19, + UNW_ARM64_X20 = 20, + UNW_ARM64_X21 = 21, + UNW_ARM64_X22 = 22, + UNW_ARM64_X23 = 23, + UNW_ARM64_X24 = 24, + UNW_ARM64_X25 = 25, + UNW_ARM64_X26 = 26, + UNW_ARM64_X27 = 27, + UNW_ARM64_X28 = 28, + UNW_ARM64_X29 = 29, + UNW_ARM64_FP = 29, + UNW_ARM64_X30 = 30, + UNW_ARM64_LR = 30, + UNW_ARM64_X31 = 31, + UNW_ARM64_SP = 31, + // reserved block + UNW_ARM64_D0 = 64, + UNW_ARM64_D1 = 65, + UNW_ARM64_D2 = 66, + UNW_ARM64_D3 = 67, + UNW_ARM64_D4 = 68, + UNW_ARM64_D5 = 69, + UNW_ARM64_D6 = 70, + UNW_ARM64_D7 = 71, + UNW_ARM64_D8 = 72, + UNW_ARM64_D9 = 73, + UNW_ARM64_D10 = 74, + UNW_ARM64_D11 = 75, + UNW_ARM64_D12 = 76, + UNW_ARM64_D13 = 77, + UNW_ARM64_D14 = 78, + UNW_ARM64_D15 = 79, + UNW_ARM64_D16 = 80, + UNW_ARM64_D17 = 81, + UNW_ARM64_D18 = 82, + UNW_ARM64_D19 = 83, + UNW_ARM64_D20 = 84, + UNW_ARM64_D21 = 85, + UNW_ARM64_D22 = 86, + UNW_ARM64_D23 = 87, + UNW_ARM64_D24 = 88, + UNW_ARM64_D25 = 89, + UNW_ARM64_D26 = 90, + UNW_ARM64_D27 = 91, + UNW_ARM64_D28 = 92, + UNW_ARM64_D29 = 93, + UNW_ARM64_D30 = 94, + UNW_ARM64_D31 = 95, +}; + +// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1. +// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3. +// In this scheme, even though the 64-bit floating point registers D0-D31 +// overlap physically with the 32-bit floating pointer registers S0-S31, +// they are given a non-overlapping range of register numbers. +// +// Commented out ranges are not preserved during unwinding. +enum { + UNW_ARM_R0 = 0, + UNW_ARM_R1 = 1, + UNW_ARM_R2 = 2, + UNW_ARM_R3 = 3, + UNW_ARM_R4 = 4, + UNW_ARM_R5 = 5, + UNW_ARM_R6 = 6, + UNW_ARM_R7 = 7, + UNW_ARM_R8 = 8, + UNW_ARM_R9 = 9, + UNW_ARM_R10 = 10, + UNW_ARM_R11 = 11, + UNW_ARM_R12 = 12, + UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP + UNW_ARM_R13 = 13, + UNW_ARM_LR = 14, + UNW_ARM_R14 = 14, + UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP + UNW_ARM_R15 = 15, + // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31. + UNW_ARM_S0 = 64, + UNW_ARM_S1 = 65, + UNW_ARM_S2 = 66, + UNW_ARM_S3 = 67, + UNW_ARM_S4 = 68, + UNW_ARM_S5 = 69, + UNW_ARM_S6 = 70, + UNW_ARM_S7 = 71, + UNW_ARM_S8 = 72, + UNW_ARM_S9 = 73, + UNW_ARM_S10 = 74, + UNW_ARM_S11 = 75, + UNW_ARM_S12 = 76, + UNW_ARM_S13 = 77, + UNW_ARM_S14 = 78, + UNW_ARM_S15 = 79, + UNW_ARM_S16 = 80, + UNW_ARM_S17 = 81, + UNW_ARM_S18 = 82, + UNW_ARM_S19 = 83, + UNW_ARM_S20 = 84, + UNW_ARM_S21 = 85, + UNW_ARM_S22 = 86, + UNW_ARM_S23 = 87, + UNW_ARM_S24 = 88, + UNW_ARM_S25 = 89, + UNW_ARM_S26 = 90, + UNW_ARM_S27 = 91, + UNW_ARM_S28 = 92, + UNW_ARM_S29 = 93, + UNW_ARM_S30 = 94, + UNW_ARM_S31 = 95, + // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP. + // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX) + UNW_ARM_WR0 = 112, + UNW_ARM_WR1 = 113, + UNW_ARM_WR2 = 114, + UNW_ARM_WR3 = 115, + UNW_ARM_WR4 = 116, + UNW_ARM_WR5 = 117, + UNW_ARM_WR6 = 118, + UNW_ARM_WR7 = 119, + UNW_ARM_WR8 = 120, + UNW_ARM_WR9 = 121, + UNW_ARM_WR10 = 122, + UNW_ARM_WR11 = 123, + UNW_ARM_WR12 = 124, + UNW_ARM_WR13 = 125, + UNW_ARM_WR14 = 126, + UNW_ARM_WR15 = 127, + // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC} + // 134-143 -- Reserved + // 144-150 -- R8_USR–R14_USR + // 151-157 -- R8_FIQ–R14_FIQ + // 158-159 -- R13_IRQ–R14_IRQ + // 160-161 -- R13_ABT–R14_ABT + // 162-163 -- R13_UND–R14_UND + // 164-165 -- R13_SVC–R14_SVC + // 166-191 -- Reserved + UNW_ARM_WC0 = 192, + UNW_ARM_WC1 = 193, + UNW_ARM_WC2 = 194, + UNW_ARM_WC3 = 195, + // 196-199 -- wC4-wC7 (Intel wireless MMX control) + // 200-255 -- Reserved + UNW_ARM_D0 = 256, + UNW_ARM_D1 = 257, + UNW_ARM_D2 = 258, + UNW_ARM_D3 = 259, + UNW_ARM_D4 = 260, + UNW_ARM_D5 = 261, + UNW_ARM_D6 = 262, + UNW_ARM_D7 = 263, + UNW_ARM_D8 = 264, + UNW_ARM_D9 = 265, + UNW_ARM_D10 = 266, + UNW_ARM_D11 = 267, + UNW_ARM_D12 = 268, + UNW_ARM_D13 = 269, + UNW_ARM_D14 = 270, + UNW_ARM_D15 = 271, + UNW_ARM_D16 = 272, + UNW_ARM_D17 = 273, + UNW_ARM_D18 = 274, + UNW_ARM_D19 = 275, + UNW_ARM_D20 = 276, + UNW_ARM_D21 = 277, + UNW_ARM_D22 = 278, + UNW_ARM_D23 = 279, + UNW_ARM_D24 = 280, + UNW_ARM_D25 = 281, + UNW_ARM_D26 = 282, + UNW_ARM_D27 = 283, + UNW_ARM_D28 = 284, + UNW_ARM_D29 = 285, + UNW_ARM_D30 = 286, + UNW_ARM_D31 = 287, + // 288-319 -- Reserved for VFP/Neon + // 320-8191 -- Reserved + // 8192-16383 -- Unspecified vendor co-processor register. +}; + +#endif diff --git a/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h b/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h new file mode 100644 index 00000000..61106880 --- /dev/null +++ b/system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h @@ -0,0 +1,487 @@ +//===------------------ mach-o/compact_unwind_encoding.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. +// +// +// Darwin's alternative to dwarf based unwind encodings. +// +//===----------------------------------------------------------------------===// + + +#ifndef __COMPACT_UNWIND_ENCODING__ +#define __COMPACT_UNWIND_ENCODING__ + +#include + +// +// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section +// of object files. Or compilers can emit compact unwind information in +// the __LD,__compact_unwind section. +// +// When the linker creates a final linked image, it will create a +// __TEXT,__unwind_info section. This section is a small and fast way for the +// runtime to access unwind info for any given function. If the compiler +// emitted compact unwind info for the function, that compact unwind info will +// be encoded in the __TEXT,__unwind_info section. If the compiler emitted +// dwarf unwind info, the __TEXT,__unwind_info section will contain the offset +// of the FDE in the __TEXT,__eh_frame section in the final linked image. +// +// Note: Previously, the linker would transform some dwarf unwind infos into +// compact unwind info. But that is fragile and no longer done. + + +// +// The compact unwind endoding is a 32-bit value which encoded in an +// architecture specific way, which registers to restore from where, and how +// to unwind out of the function. +// +typedef uint32_t compact_unwind_encoding_t; + + +// architecture independent bits +enum { + UNWIND_IS_NOT_FUNCTION_START = 0x80000000, + UNWIND_HAS_LSDA = 0x40000000, + UNWIND_PERSONALITY_MASK = 0x30000000, +}; + + + + +// +// x86 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// ebp based: +// 15-bits (5*3-bits per reg) register permutation +// 8-bits for stack offset +// frameless: +// 8-bits stack size +// 3-bits stack adjust +// 3-bits register count +// 10-bits register permutation +// +enum { + UNWIND_X86_MODE_MASK = 0x0F000000, + UNWIND_X86_MODE_EBP_FRAME = 0x01000000, + UNWIND_X86_MODE_STACK_IMMD = 0x02000000, + UNWIND_X86_MODE_STACK_IND = 0x03000000, + UNWIND_X86_MODE_DWARF = 0x04000000, + + UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF, + UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000, + + UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000, + UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000, + UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00, + UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, + + UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; + +enum { + UNWIND_X86_REG_NONE = 0, + UNWIND_X86_REG_EBX = 1, + UNWIND_X86_REG_ECX = 2, + UNWIND_X86_REG_EDX = 3, + UNWIND_X86_REG_EDI = 4, + UNWIND_X86_REG_ESI = 5, + UNWIND_X86_REG_EBP = 6, +}; + +// +// For x86 there are four modes for the compact unwind encoding: +// UNWIND_X86_MODE_EBP_FRAME: +// EBP based frame where EBP is push on stack immediately after return address, +// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current +// EPB value, then EBP is restored by popping off the stack, and the return +// is done by popping the stack once more into the pc. +// All non-volatile registers that need to be restored must have been saved +// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4 +// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved +// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries. +// Each entry contains which register to restore. +// UNWIND_X86_MODE_STACK_IMMD: +// A "frameless" (EBP not used as frame pointer) function with a small +// constant stack size. To return, a constant (encoded in the compact +// unwind encoding) is added to the ESP. Then the return is done by +// popping the stack into the pc. +// All non-volatile registers that need to be restored must have been saved +// on the stack immediately after the return address. The stack_size/4 is +// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024). +// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT. +// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were +// saved and their order. +// UNWIND_X86_MODE_STACK_IND: +// A "frameless" (EBP not used as frame pointer) function large constant +// stack size. This case is like the previous, except the stack size is too +// large to encode in the compact unwind encoding. Instead it requires that +// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact +// encoding contains the offset to the nnnnnnnn value in the function in +// UNWIND_X86_FRAMELESS_STACK_SIZE. +// UNWIND_X86_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only dwarf unwind info for a +// function. +// +// The following is the algorithm used to create the permutation encoding used +// with frameless stacks. It is passed the number of registers to be saved and +// an array of the register numbers saved. +// +//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6]) +//{ +// uint32_t renumregs[6]; +// for (int i=6-registerCount; i < 6; ++i) { +// int countless = 0; +// for (int j=6-registerCount; j < i; ++j) { +// if ( registers[j] < registers[i] ) +// ++countless; +// } +// renumregs[i] = registers[i] - countless -1; +// } +// uint32_t permutationEncoding = 0; +// switch ( registerCount ) { +// case 6: +// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1] +// + 6*renumregs[2] + 2*renumregs[3] +// + renumregs[4]); +// break; +// case 5: +// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2] +// + 6*renumregs[3] + 2*renumregs[4] +// + renumregs[5]); +// break; +// case 4: +// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3] +// + 3*renumregs[4] + renumregs[5]); +// break; +// case 3: +// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4] +// + renumregs[5]); +// break; +// case 2: +// permutationEncoding |= (5*renumregs[4] + renumregs[5]); +// break; +// case 1: +// permutationEncoding |= (renumregs[5]); +// break; +// } +// return permutationEncoding; +//} +// + + + + +// +// x86_64 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf +// rbp based: +// 15-bits (5*3-bits per reg) register permutation +// 8-bits for stack offset +// frameless: +// 8-bits stack size +// 3-bits stack adjust +// 3-bits register count +// 10-bits register permutation +// +enum { + UNWIND_X86_64_MODE_MASK = 0x0F000000, + UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000, + UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000, + UNWIND_X86_64_MODE_STACK_IND = 0x03000000, + UNWIND_X86_64_MODE_DWARF = 0x04000000, + + UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF, + UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000, + + UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000, + UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000, + UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00, + UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF, + + UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; + +enum { + UNWIND_X86_64_REG_NONE = 0, + UNWIND_X86_64_REG_RBX = 1, + UNWIND_X86_64_REG_R12 = 2, + UNWIND_X86_64_REG_R13 = 3, + UNWIND_X86_64_REG_R14 = 4, + UNWIND_X86_64_REG_R15 = 5, + UNWIND_X86_64_REG_RBP = 6, +}; +// +// For x86_64 there are four modes for the compact unwind encoding: +// UNWIND_X86_64_MODE_RBP_FRAME: +// RBP based frame where RBP is push on stack immediately after return address, +// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current +// EPB value, then RBP is restored by popping off the stack, and the return +// is done by popping the stack once more into the pc. +// All non-volatile registers that need to be restored must have been saved +// in a small range in the stack that starts RBP-8 to RBP-1020. The offset/4 +// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved +// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries. +// Each entry contains which register to restore. +// UNWIND_X86_64_MODE_STACK_IMMD: +// A "frameless" (RBP not used as frame pointer) function with a small +// constant stack size. To return, a constant (encoded in the compact +// unwind encoding) is added to the RSP. Then the return is done by +// popping the stack into the pc. +// All non-volatile registers that need to be restored must have been saved +// on the stack immediately after the return address. The stack_size/4 is +// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024). +// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT. +// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were +// saved and their order. +// UNWIND_X86_64_MODE_STACK_IND: +// A "frameless" (RBP not used as frame pointer) function large constant +// stack size. This case is like the previous, except the stack size is too +// large to encode in the compact unwind encoding. Instead it requires that +// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact +// encoding contains the offset to the nnnnnnnn value in the function in +// UNWIND_X86_64_FRAMELESS_STACK_SIZE. +// UNWIND_X86_64_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only dwarf unwind info for a +// function. +// + + +#ifndef __OPEN_SOURCE__ + +// ARM64 +// +// 1-bit: start +// 1-bit: has lsda +// 2-bit: personality index +// +// 4-bits: 4=frame-based, 2=frameless, 3=dwarf +// frameless: +// 12-bits of stack size +// frame-based: +// 4-bits D reg pairs saved +// 5-bits X reg pairs saved +// dwarf: +// 24-bits offset of dwarf FDE in __eh_frame section +// +enum { + UNWIND_ARM64_MODE_MASK = 0x0F000000, + UNWIND_ARM64_MODE_FRAMELESS = 0x02000000, + UNWIND_ARM64_MODE_DWARF = 0x03000000, + UNWIND_ARM64_MODE_FRAME = 0x04000000, + + UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001, + UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002, + UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004, + UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008, + UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010, + UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100, + UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200, + UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400, + UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800, + + UNWIND_ARM64_FRAME_X21_X22_PAIR_OLD = 0x00000001, + UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD = 0x00000002, + UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD = 0x00000004, + UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD = 0x00000008, + UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD = 0x00000010, + UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD = 0x00000020, + UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD = 0x00000040, + UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD = 0x00000080, + + UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000, + UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF, +}; +// For arm64 there are three modes for the compact unwind encoding: +// UNWIND_ARM64_MODE_FRAME: +// This is a standard arm64 prolog where FP/LR are immediately pushed on the +// stack, then SP is copied to FP. If there are any non-volatile registers +// saved, then are copied into the stack frame in pairs in a contiguous +// range right below the saved FP/LR pair. Any subset of the five X pairs +// and four D pairs can be saved, but the memory layout must be in register +// number order. +// UNWIND_ARM64_MODE_FRAMELESS: +// A "frameless" leaf function, where FP/LR are not saved. The return address +// remains in LR throughout the function. If any non-volatile registers +// are saved, they must be pushed onto the stack before any stack space is +// allocated for local variables. The stack sized (including any saved +// non-volatile registers) divided by 16 is encoded in the bits +// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. +// UNWIND_ARM64_MODE_DWARF: +// No compact unwind encoding is available. Instead the low 24-bits of the +// compact encoding is the offset of the dwarf FDE in the __eh_frame section. +// This mode is never used in object files. It is only generated by the +// linker in final linked images which have only dwarf unwind info for a +// function. +// + +#endif // __OPEN_SOURCE__ + + + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Relocatable Object Files: __LD,__compact_unwind +// +//////////////////////////////////////////////////////////////////////////////// + +// +// A compiler can generated compact unwind information for a function by adding +// a "row" to the __LD,__compact_unwind section. This section has the +// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers. +// It is removed by the new linker, so never ends up in final executables. +// This section is a table, initially with one row per function (that needs +// unwind info). The table columns and some conceptual entries are: +// +// range-start pointer to start of function/range +// range-length +// compact-unwind-encoding 32-bit encoding +// personality-function or zero if no personality function +// lsda or zero if no LSDA data +// +// The length and encoding fields are 32-bits. The other are all pointer sized. +// +// In x86_64 assembly, these entry would look like: +// +// .section __LD,__compact_unwind,regular,debug +// +// #compact unwind for _foo +// .quad _foo +// .set L1,LfooEnd-_foo +// .long L1 +// .long 0x01010001 +// .quad 0 +// .quad 0 +// +// #compact unwind for _bar +// .quad _bar +// .set L2,LbarEnd-_bar +// .long L2 +// .long 0x01020011 +// .quad __gxx_personality +// .quad except_tab1 +// +// +// Notes: There is no need for any labels in the the __compact_unwind section. +// The use of the .set directive is to force the evaluation of the +// range-length at assembly time, instead of generating relocations. +// +// To support future compiler optimizations where which non-volatile registers +// are saved changes within a function (e.g. delay saving non-volatiles until +// necessary), there can by multiple lines in the __compact_unwind table for one +// function, each with a different (non-overlapping) range and each with +// different compact unwind encodings that correspond to the non-volatiles +// saved at that range of the function. +// +// If a particular function is so wacky that there is no compact unwind way +// to encode it, then the compiler can emit traditional dwarf unwind info. +// The runtime will use which ever is available. +// +// Runtime support for compact unwind encodings are only available on 10.6 +// and later. So, the compiler should not generate it when targeting pre-10.6. + + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Final Linked Images: __TEXT,__unwind_info +// +//////////////////////////////////////////////////////////////////////////////// + +// +// The __TEXT,__unwind_info section is laid out for an efficient two level lookup. +// The header of the section contains a coarse index that maps function address +// to the page (4096 byte block) containing the unwind info for that function. +// + +#define UNWIND_SECTION_VERSION 1 +struct unwind_info_section_header +{ + uint32_t version; // UNWIND_SECTION_VERSION + uint32_t commonEncodingsArraySectionOffset; + uint32_t commonEncodingsArrayCount; + uint32_t personalityArraySectionOffset; + uint32_t personalityArrayCount; + uint32_t indexSectionOffset; + uint32_t indexCount; + // compact_unwind_encoding_t[] + // uintptr_t personalities[] + // unwind_info_section_header_index_entry[] + // unwind_info_section_header_lsda_index_entry[] +}; + +struct unwind_info_section_header_index_entry +{ + uint32_t functionOffset; + uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page + uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range +}; + +struct unwind_info_section_header_lsda_index_entry +{ + uint32_t functionOffset; + uint32_t lsdaOffset; +}; + +// +// There are two kinds of second level index pages: regular and compressed. +// A compressed page can hold up to 1021 entries, but it cannot be used +// if too many different encoding types are used. The regular page holds +// 511 entries. +// + +struct unwind_info_regular_second_level_entry +{ + uint32_t functionOffset; + compact_unwind_encoding_t encoding; +}; + +#define UNWIND_SECOND_LEVEL_REGULAR 2 +struct unwind_info_regular_second_level_page_header +{ + uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR + uint16_t entryPageOffset; + uint16_t entryCount; + // entry array +}; + +#define UNWIND_SECOND_LEVEL_COMPRESSED 3 +struct unwind_info_compressed_second_level_page_header +{ + uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED + uint16_t entryPageOffset; + uint16_t entryCount; + uint16_t encodingsPageOffset; + uint16_t encodingsCount; + // 32-bit entry array + // encodings array +}; + +#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF) +#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF) + + + +#endif + diff --git a/system/lib/libcxxabi/include/unwind.h b/system/lib/libcxxabi/include/unwind.h new file mode 100644 index 00000000..c5acd934 --- /dev/null +++ b/system/lib/libcxxabi/include/unwind.h @@ -0,0 +1,217 @@ +//===------------------------------- unwind.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. +// +// +// C++ ABI Level 1 ABI documented at: +// http://mentorembedded.github.io/cxx-abi/abi-eh.html +// +//===----------------------------------------------------------------------===// + +#ifndef __UNWIND_H__ +#define __UNWIND_H__ + +#include +#include + +#if defined(__APPLE__) +#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable )) +#else +#define LIBUNWIND_UNAVAIL +#endif + +typedef enum { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8 +} _Unwind_Reason_Code; + +typedef enum { + _UA_SEARCH_PHASE = 1, + _UA_CLEANUP_PHASE = 2, + _UA_HANDLER_FRAME = 4, + _UA_FORCE_UNWIND = 8, + _UA_END_OF_STACK = 16 // gcc extension to C++ ABI +} _Unwind_Action; + +struct _Unwind_Context; // opaque +struct _Unwind_Exception; // forward declaration + +struct _Unwind_Exception { + uint64_t exception_class; + void (*exception_cleanup)(_Unwind_Reason_Code reason, + struct _Unwind_Exception *exc); + uintptr_t private_1; // non-zero means forced unwind + uintptr_t private_2; // holds sp that phase1 found for phase2 to use +#if !__LP64__ + // The gcc implementation of _Unwind_Exception used attribute mode on the + // above fields which had the side effect of causing this whole struct to + // round up to 32 bytes in size. To be more explicit, we add pad fields + // added for binary compatibility. + uint32_t reserved[3]; +#endif +}; + +typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) + (int version, + _Unwind_Action actions, + uint64_t exceptionClass, + struct _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context, + void* stop_parameter ); + +typedef _Unwind_Reason_Code (*__personality_routine) + (int version, + _Unwind_Action actions, + uint64_t exceptionClass, + struct _Unwind_Exception* exceptionObject, + struct _Unwind_Context* context); + +#ifdef __cplusplus +extern "C" { +#endif + +// +// The following are the base functions documented by the C++ ABI +// +#if __arm__ +extern _Unwind_Reason_Code + _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object); +extern void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object); +#else +extern _Unwind_Reason_Code + _Unwind_RaiseException(struct _Unwind_Exception *exception_object); +extern void _Unwind_Resume(struct _Unwind_Exception *exception_object); +#endif +extern void _Unwind_DeleteException(struct _Unwind_Exception *exception_object); +extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index); +extern void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value); +extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); +extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value); +extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context); +extern uintptr_t + _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context); +#if __arm__ +extern _Unwind_Reason_Code + _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#else +extern _Unwind_Reason_Code + _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter); +#endif + +#if __arm__ +typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t; +extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc); +extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc); +#endif + +// +// The following are semi-suppoted extensions to the C++ ABI +// + +// +// called by __cxa_rethrow(). +// +#if __arm__ +extern _Unwind_Reason_Code + _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object); +#else +extern _Unwind_Reason_Code + _Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object); +#endif + +// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the +// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack +// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON. +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, + void *); +extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); + +// _Unwind_GetCFA is a gcc extension that can be called from within a +// personality handler to get the CFA (stack pointer before call) of +// current frame. +extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *); + + +// _Unwind_GetIPInfo is a gcc extension that can be called from within a +// personality handler. Similar to _Unwind_GetIP() but also returns in +// *ipBefore a non-zero value if the instruction pointer is at or before the +// instruction causing the unwind. Normally, in a function call, the IP returned +// is the return address which is after the call instruction and may be past the +// end of the function containing the call instruction. +extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore); + + +// __register_frame() is used with dynamically generated code to register the +// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point +// to its function and optional LSDA. +// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and +// 10.5 it was buggy and did not actually register the FDE with the unwinder. +// In 10.6 and later it does register properly. +extern void __register_frame(const void *fde); +extern void __deregister_frame(const void *fde); + +// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has +// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind +// info" which the runtime uses in preference to dwarf unwind info. This +// function will only work if the target function has an FDE but no compact +// unwind info. +struct dwarf_eh_bases { + uintptr_t tbase; + uintptr_t dbase; + uintptr_t func; +}; +extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *); + + +// This function attempts to find the start (address of first instruction) of +// a function given an address inside the function. It only works if the +// function has an FDE (dwarf unwind info). +// This function is unimplemented on Mac OS X 10.6 and later. Instead, use +// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result. +extern void *_Unwind_FindEnclosingFunction(void *pc); + +// Mac OS X does not support text-rel and data-rel addressing so these functions +// are unimplemented +extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; +extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context) + LIBUNWIND_UNAVAIL; + +// Mac OS X 10.4 and 10.5 had implementations of these functions in +// libgcc_s.dylib, but they never worked. +/// These functions are no longer available on Mac OS X. +extern void __register_frame_info_bases(const void *fde, void *ob, void *tb, + void *db) LIBUNWIND_UNAVAIL; +extern void __register_frame_info(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table_bases(const void *fde, void *ob, + void *tb, void *db) + LIBUNWIND_UNAVAIL; +extern void __register_frame_info_table(const void *fde, void *ob) + LIBUNWIND_UNAVAIL; +extern void __register_frame_table(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info(const void *fde) + LIBUNWIND_UNAVAIL; +extern void *__deregister_frame_info_bases(const void *fde) + LIBUNWIND_UNAVAIL; + +#ifdef __cplusplus +} +#endif + +#endif // __UNWIND_H__ diff --git a/system/lib/libcxxabi/lib/buildit b/system/lib/libcxxabi/lib/buildit index 75a7028a..5a4a7109 100755 --- a/system/lib/libcxxabi/lib/buildit +++ b/system/lib/libcxxabi/lib/buildit @@ -27,7 +27,7 @@ then RC_ProjectSourceVersion=1 fi -EXTRA_FLAGS="-std=c++0x -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \ +EXTRA_FLAGS="-std=c++11 -stdlib=libc++ -fstrict-aliasing -Wstrict-aliasing=2 \ -Wsign-conversion -Wshadow -Wconversion -Wunused-variable \ -Wmissing-field-initializers -Wchar-subscripts -Wmismatched-tags \ -Wmissing-braces -Wshorten-64-to-32 -Wsign-compare \ @@ -82,12 +82,12 @@ fi set -x for FILE in ../src/*.cpp; do - $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE + $CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $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 + $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE done ;; esac diff --git a/system/lib/libcxxabi/readme.txt b/system/lib/libcxxabi/readme.txt index f55da87c..700a2183 100644 --- a/system/lib/libcxxabi/readme.txt +++ b/system/lib/libcxxabi/readme.txt @@ -1 +1 @@ -These files are from libcxxabi, svn revision 175275, Feb 15, 2013. +These files are from libcxxabi, svn revision 198643, Jan 7, 2014. diff --git a/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp b/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp new file mode 100644 index 00000000..67b0973d --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/AddressSpace.hpp @@ -0,0 +1,430 @@ +//===------------------------- AddressSpace.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. +// +// +// Abstracts accessing local vs remote address spaces. +// +//===----------------------------------------------------------------------===// + +#ifndef __ADDRESSSPACE_HPP__ +#define __ADDRESSSPACE_HPP__ + +#include +#include +#include +#include + +#if __APPLE__ +#include +namespace libunwind { + bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde); +} +#endif + +#include "libunwind.h" +#include "config.h" +#include "dwarf2.h" +#include "Registers.hpp" + +namespace libunwind { + +/// Used by findUnwindSections() to return info about needed sections. +struct UnwindInfoSections { + uintptr_t dso_base; +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND + uintptr_t dwarf_section; + uintptr_t dwarf_section_length; +#endif +#if _LIBUNWIND_SUPPORT_DWARF_INDEX + uintptr_t dwarf_index_section; + uintptr_t dwarf_index_section_length; +#endif +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND + uintptr_t compact_unwind_section; + uintptr_t compact_unwind_section_length; +#endif +}; + + +/// LocalAddressSpace is used as a template parameter to UnwindCursor when +/// unwinding a thread in the same process. The wrappers compile away, +/// making local unwinds fast. +class __attribute__((visibility("hidden"))) LocalAddressSpace { +public: +#if __LP64__ + typedef uint64_t pint_t; + typedef int64_t sint_t; +#else + typedef uint32_t pint_t; + typedef int32_t sint_t; +#endif + uint8_t get8(pint_t addr) { return *((uint8_t *)addr); } + uint16_t get16(pint_t addr) { return *((uint16_t *)addr); } + uint32_t get32(pint_t addr) { return *((uint32_t *)addr); } + uint64_t get64(pint_t addr) { return *((uint64_t *)addr); } + double getDouble(pint_t addr) { return *((double *)addr); } + v128 getVector(pint_t addr) { return *((v128 *)addr); } + uintptr_t getP(pint_t addr); + static uint64_t getULEB128(pint_t &addr, pint_t end); + static int64_t getSLEB128(pint_t &addr, pint_t end); + + pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding); + bool findFunctionName(pint_t addr, char *buf, size_t bufLen, + unw_word_t *offset); + bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); + bool findOtherFDE(pint_t targetAddr, pint_t &fde); + + static LocalAddressSpace sThisAddressSpace; +}; + + +inline uintptr_t LocalAddressSpace::getP(pint_t addr) { +#if __LP64__ + return get64(addr); +#else + return get32(addr); +#endif +} + +/// Read a ULEB128 into a 64-bit word. +inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + uint64_t result = 0; + int bit = 0; + do { + uint64_t b; + + if (p == pend) + _LIBUNWIND_ABORT("truncated uleb128 expression"); + + b = *p & 0x7f; + + if (bit >= 64 || b << bit >> bit != b) { + _LIBUNWIND_ABORT("malformed uleb128 expression"); + } else { + result |= b << bit; + bit += 7; + } + } while (*p++ >= 0x80); + addr = (pint_t) p; + return result; +} + +/// Read a SLEB128 into a 64-bit word. +inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) { + const uint8_t *p = (uint8_t *)addr; + const uint8_t *pend = (uint8_t *)end; + int64_t result = 0; + int bit = 0; + uint8_t byte; + do { + if (p == pend) + _LIBUNWIND_ABORT("truncated sleb128 expression"); + byte = *p++; + result |= ((byte & 0x7f) << bit); + bit += 7; + } while (byte & 0x80); + // sign extend negative numbers + if ((byte & 0x40) != 0) + result |= (-1LL) << bit; + addr = (pint_t) p; + return result; +} + +inline LocalAddressSpace::pint_t LocalAddressSpace::getEncodedP(pint_t &addr, + pint_t end, + uint8_t encoding) { + pint_t startAddr = addr; + const uint8_t *p = (uint8_t *)addr; + pint_t result; + + // first get value + switch (encoding & 0x0F) { + case DW_EH_PE_ptr: + result = getP(addr); + p += sizeof(pint_t); + addr = (pint_t) p; + break; + case DW_EH_PE_uleb128: + result = (pint_t)getULEB128(addr, end); + break; + case DW_EH_PE_udata2: + result = get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_udata4: + result = get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_udata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + case DW_EH_PE_sleb128: + result = (pint_t)getSLEB128(addr, end); + break; + case DW_EH_PE_sdata2: + result = (uint16_t)get16(addr); + p += 2; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata4: + result = (uint32_t)get32(addr); + p += 4; + addr = (pint_t) p; + break; + case DW_EH_PE_sdata8: + result = (pint_t)get64(addr); + p += 8; + addr = (pint_t) p; + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + } + + // then add relative offset + switch (encoding & 0x70) { + case DW_EH_PE_absptr: + // do nothing + break; + case DW_EH_PE_pcrel: + result += startAddr; + break; + case DW_EH_PE_textrel: + _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported"); + break; + case DW_EH_PE_datarel: + _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported"); + break; + case DW_EH_PE_funcrel: + _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported"); + break; + case DW_EH_PE_aligned: + _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported"); + break; + default: + _LIBUNWIND_ABORT("unknown pointer encoding"); + break; + } + + if (encoding & DW_EH_PE_indirect) + result = getP(result); + + return result; +} + +#if __APPLE__ + struct dyld_unwind_sections + { + const struct mach_header* mh; + const void* dwarf_section; + uintptr_t dwarf_section_length; + const void* compact_unwind_section; + uintptr_t compact_unwind_section_length; + }; + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \ + && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) + // In 10.7.0 or later, libSystem.dylib implements this function. + extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *); + #else + // In 10.6.x and earlier, we need to implement this functionality. + static inline bool _dyld_find_unwind_sections(void* addr, + dyld_unwind_sections* info) { + // Find mach-o image containing address. + Dl_info dlinfo; + if (!dladdr(addr, &dlinfo)) + return false; + const mach_header *mh = (const mach_header *)dlinfo.dli_saddr; + + // Find dwarf unwind section in that image. + unsigned long size; + const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size); + if (!p) + return false; + + // Fill in return struct. + info->mh = mh; + info->dwarf_section = p; + info->dwarf_section_length = size; + info->compact_unwind_section = 0; + info->compact_unwind_section_length = 0; + + return true; + } + #endif +#endif + +inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr, + UnwindInfoSections &info) { +#if __APPLE__ + dyld_unwind_sections dyldInfo; + if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) { + info.dso_base = (uintptr_t)dyldInfo.mh; + #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section; + info.dwarf_section_length = dyldInfo.dwarf_section_length; + #endif + info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section; + info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length; + return true; + } +#else + // TO DO + +#endif + + return false; +} + + +inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) { +#if __APPLE__ + return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde)); +#else + // TO DO: if OS has way to dynamically register FDEs, check that. + return false; +#endif +} + +inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf, + size_t bufLen, + unw_word_t *offset) { + dl_info dyldInfo; + if (dladdr((void *)addr, &dyldInfo)) { + if (dyldInfo.dli_sname != NULL) { + strlcpy(buf, dyldInfo.dli_sname, bufLen); + *offset = (addr - (pint_t) dyldInfo.dli_saddr); + return true; + } + } + return false; +} + + + +#if UNW_REMOTE + +/// OtherAddressSpace is used as a template parameter to UnwindCursor when +/// unwinding a thread in the another process. The other process can be a +/// different endianness and a different pointer size which is handled by +/// the P template parameter. +template +class OtherAddressSpace { +public: + OtherAddressSpace(task_t task) : fTask(task) {} + + typedef typename P::uint_t pint_t; + + uint8_t get8(pint_t addr); + uint16_t get16(pint_t addr); + uint32_t get32(pint_t addr); + uint64_t get64(pint_t addr); + pint_t getP(pint_t addr); + uint64_t getULEB128(pint_t &addr, pint_t end); + int64_t getSLEB128(pint_t &addr, pint_t end); + pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding); + bool findFunctionName(pint_t addr, char *buf, size_t bufLen, + unw_word_t *offset); + bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info); + bool findOtherFDE(pint_t targetAddr, pint_t &fde); +private: + void *localCopy(pint_t addr); + + task_t fTask; +}; + +template uint8_t OtherAddressSpace

::get8(pint_t addr) { + return *((uint8_t *)localCopy(addr)); +} + +template uint16_t OtherAddressSpace

::get16(pint_t addr) { + return P::E::get16(*(uint16_t *)localCopy(addr)); +} + +template uint32_t OtherAddressSpace

::get32(pint_t addr) { + return P::E::get32(*(uint32_t *)localCopy(addr)); +} + +template uint64_t OtherAddressSpace

::get64(pint_t addr) { + return P::E::get64(*(uint64_t *)localCopy(addr)); +} + +template +typename P::uint_t OtherAddressSpace

::getP(pint_t addr) { + return P::getP(*(uint64_t *)localCopy(addr)); +} + +template +uint64_t OtherAddressSpace

::getULEB128(pint_t &addr, pint_t end) { + uintptr_t size = (end - addr); + LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); + LocalAddressSpace::pint_t sladdr = laddr; + uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size); + addr += (laddr - sladdr); + return result; +} + +template +int64_t OtherAddressSpace

::getSLEB128(pint_t &addr, pint_t end) { + uintptr_t size = (end - addr); + LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr); + LocalAddressSpace::pint_t sladdr = laddr; + uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size); + addr += (laddr - sladdr); + return result; +} + +template void *OtherAddressSpace

::localCopy(pint_t addr) { + // FIX ME +} + +template +bool OtherAddressSpace

::findFunctionName(pint_t addr, char *buf, + size_t bufLen, unw_word_t *offset) { + // FIX ME +} + +/// unw_addr_space is the base class that abstract unw_addr_space_t type in +/// libunwind.h points to. +struct unw_addr_space { + cpu_type_t cpuType; + task_t taskPort; +}; + +/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points +/// to when examining +/// a 32-bit intel process. +struct unw_addr_space_i386 : public unw_addr_space { + unw_addr_space_i386(task_t task) : oas(task) {} + OtherAddressSpace > oas; +}; + +/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t +/// points to when examining +/// a 64-bit intel process. +struct unw_addr_space_x86_64 : public unw_addr_space { + unw_addr_space_x86_64(task_t task) : oas(task) {} + OtherAddressSpace > oas; +}; + +/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points +/// to when examining +/// a 32-bit PowerPC process. +struct unw_addr_space_ppc : public unw_addr_space { + unw_addr_space_ppc(task_t task) : oas(task) {} + OtherAddressSpace > oas; +}; + +#endif // UNW_REMOTE + +} // namespace libunwind + +#endif // __ADDRESSSPACE_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp b/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp new file mode 100644 index 00000000..0dc187f1 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp @@ -0,0 +1,693 @@ +//===-------------------------- CompactUnwinder.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. +// +// +// Does runtime stack unwinding using compact unwind encodings. +// +//===----------------------------------------------------------------------===// + +#ifndef __COMPACT_UNWINDER_HPP__ +#define __COMPACT_UNWINDER_HPP__ + +#include +#include + +#include +#include + +#include "AddressSpace.hpp" +#include "Registers.hpp" + +#define EXTRACT_BITS(value, mask) \ + ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1)) + +namespace libunwind { + +/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86 register set +template +class CompactUnwinder_x86 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t info, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + +private: + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86 ®isters); + static void framelessUnwind(A &addressSpace, + typename A::pint_t returnAddressLocation, + Registers_x86 ®isters); + static int + stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding, + uint32_t functionStart, A &addressSpace, + Registers_x86 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize); +}; + +template +int CompactUnwinder_x86::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + switch (compactEncoding & UNWIND_X86_MODE_MASK) { + case UNWIND_X86_MODE_EBP_FRAME: + return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_x86::stepWithCompactEncodingEBPFrame( + compact_unwind_encoding_t compactEncoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS); + + uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for " + "function starting at 0x%X\n", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint32_t functionStart, + A &addressSpace, Registers_x86 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 4; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 4 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_REG_EBX: + registers.setEBX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ECX: + registers.setECX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDX: + registers.setEDX(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EDI: + registers.setEDI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_ESI: + registers.setESI(addressSpace.get32(savedRegisters)); + break; + case UNWIND_X86_REG_EBP: + registers.setEBP(addressSpace.get32(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%X\n", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 4; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; +} + + +template +void CompactUnwinder_x86::frameUnwind(A &addressSpace, + Registers_x86 ®isters) { + typename A::pint_t bp = registers.getEBP(); + // ebp points to old ebp + registers.setEBP(addressSpace.get32(bp)); + // old esp is ebp less saved ebp and return address + registers.setSP((uint32_t)bp + 8); + // pop return address into eip + registers.setIP(addressSpace.get32(bp + 4)); +} + +template +void CompactUnwinder_x86::framelessUnwind( + A &addressSpace, typename A::pint_t returnAddressLocation, + Registers_x86 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get32(returnAddressLocation)); + // old esp is before return address + registers.setSP((uint32_t)returnAddressLocation + 4); +} + + +/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_x86_64 register set +template +class CompactUnwinder_x86_64 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + +private: + typename A::pint_t pint_t; + + static void frameUnwind(A &addressSpace, Registers_x86_64 ®isters); + static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation, + Registers_x86_64 ®isters); + static int + stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters, bool indirectStackSize); +}; + +template +int CompactUnwinder_x86_64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + switch (compactEncoding & UNWIND_X86_64_MODE_MASK) { + case UNWIND_X86_64_MODE_RBP_FRAME: + return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_X86_64_MODE_STACK_IMMD: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, false); + case UNWIND_X86_64_MODE_STACK_IND: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers, true); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_x86_64::stepWithCompactEncodingRBPFrame( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_x86_64 ®isters) { + uint32_t savedRegistersOffset = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET); + uint32_t savedRegistersLocations = + EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); + + uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset; + for (int i = 0; i < 5; ++i) { + switch (savedRegistersLocations & 0x7) { + case UNWIND_X86_64_REG_NONE: + // no register saved in this slot + break; + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + default: + (void)functionStart; + _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for " + "function starting at 0x%llX\n", + compactEncoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + savedRegistersLocations = (savedRegistersLocations >> 3); + } + frameUnwind(addressSpace, registers); + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_x86_64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace, + Registers_x86_64 ®isters, bool indirectStackSize) { + uint32_t stackSizeEncoded = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE); + uint32_t stackAdjust = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST); + uint32_t regCount = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = + EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION); + uint32_t stackSize = stackSizeEncoded * 8; + if (indirectStackSize) { + // stack size is encoded in subl $xxx,%esp instruction + uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded); + stackSize = subl + 8 * stackAdjust; + } + // decompress permutation + uint32_t permunreg[6]; + switch (regCount) { + case 6: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + permunreg[5] = 0; + break; + case 5: + permunreg[0] = permutation / 120; + permutation -= (permunreg[0] * 120); + permunreg[1] = permutation / 24; + permutation -= (permunreg[1] * 24); + permunreg[2] = permutation / 6; + permutation -= (permunreg[2] * 6); + permunreg[3] = permutation / 2; + permutation -= (permunreg[3] * 2); + permunreg[4] = permutation; + break; + case 4: + permunreg[0] = permutation / 60; + permutation -= (permunreg[0] * 60); + permunreg[1] = permutation / 12; + permutation -= (permunreg[1] * 12); + permunreg[2] = permutation / 3; + permutation -= (permunreg[2] * 3); + permunreg[3] = permutation; + break; + case 3: + permunreg[0] = permutation / 20; + permutation -= (permunreg[0] * 20); + permunreg[1] = permutation / 4; + permutation -= (permunreg[1] * 4); + permunreg[2] = permutation; + break; + case 2: + permunreg[0] = permutation / 5; + permutation -= (permunreg[0] * 5); + permunreg[1] = permutation; + break; + case 1: + permunreg[0] = permutation; + break; + } + // re-number registers back to standard numbers + int registersSaved[6]; + bool used[7] = { false, false, false, false, false, false, false }; + for (uint32_t i = 0; i < regCount; ++i) { + uint32_t renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permunreg[i]) { + registersSaved[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount; + for (uint32_t i = 0; i < regCount; ++i) { + switch (registersSaved[i]) { + case UNWIND_X86_64_REG_RBX: + registers.setRBX(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R12: + registers.setR12(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R13: + registers.setR13(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R14: + registers.setR14(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_R15: + registers.setR15(addressSpace.get64(savedRegisters)); + break; + case UNWIND_X86_64_REG_RBP: + registers.setRBP(addressSpace.get64(savedRegisters)); + break; + default: + _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for " + "function starting at 0x%llX\n", + encoding, functionStart); + _LIBUNWIND_ABORT("invalid compact unwind encoding"); + } + savedRegisters += 8; + } + framelessUnwind(addressSpace, savedRegisters, registers); + return UNW_STEP_SUCCESS; +} + + +template +void CompactUnwinder_x86_64::frameUnwind(A &addressSpace, + Registers_x86_64 ®isters) { + uint64_t rbp = registers.getRBP(); + // ebp points to old ebp + registers.setRBP(addressSpace.get64(rbp)); + // old esp is ebp less saved ebp and return address + registers.setSP(rbp + 16); + // pop return address into eip + registers.setIP(addressSpace.get64(rbp + 8)); +} + +template +void CompactUnwinder_x86_64::framelessUnwind(A &addressSpace, + uint64_t returnAddressLocation, + Registers_x86_64 ®isters) { + // return address is on stack after last saved register + registers.setIP(addressSpace.get64(returnAddressLocation)); + // old esp is before return address + registers.setSP(returnAddressLocation + 8); +} + + + +/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka +/// unwind) by modifying a Registers_arm64 register set +template +class CompactUnwinder_arm64 { +public: + + static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm64 ®isters); + +private: + typename A::pint_t pint_t; + + static int + stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding, + uint64_t functionStart, A &addressSpace, + Registers_arm64 ®isters); + static int stepWithCompactEncodingFrameless( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_arm64 ®isters); +}; + +template +int CompactUnwinder_arm64::stepWithCompactEncoding( + compact_unwind_encoding_t compactEncoding, uint64_t functionStart, + A &addressSpace, Registers_arm64 ®isters) { + switch (compactEncoding & UNWIND_ARM64_MODE_MASK) { + case UNWIND_ARM64_MODE_FRAME: + return stepWithCompactEncodingFrame(compactEncoding, functionStart, + addressSpace, registers); + case UNWIND_ARM64_MODE_FRAMELESS: + return stepWithCompactEncodingFrameless(compactEncoding, functionStart, + addressSpace, registers); + } + _LIBUNWIND_ABORT("invalid compact unwind encoding"); +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrameless( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + Registers_arm64 ®isters) { + uint32_t stackSize = + 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK); + + uint64_t savedRegisterLoc = registers.getSP() + stackSize; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_ARM64_D8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_ARM64_D10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_ARM64_D12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_ARM64_D14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + // subtract stack size off of sp + registers.setSP(savedRegisterLoc); + + // set pc to be value in lr + registers.setIP(registers.getRegister(UNW_ARM64_LR)); + + return UNW_STEP_SUCCESS; +} + +template +int CompactUnwinder_arm64::stepWithCompactEncodingFrame( + compact_unwind_encoding_t encoding, uint64_t, A &addressSpace, + Registers_arm64 ®isters) { + uint64_t savedRegisterLoc = registers.getFP() - 8; + + if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) { + registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) { + registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) { + registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) { + registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) { + registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) { + registers.setFloatRegister(UNW_ARM64_D8, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D9, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) { + registers.setFloatRegister(UNW_ARM64_D10, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D11, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) { + registers.setFloatRegister(UNW_ARM64_D12, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D13, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) { + registers.setFloatRegister(UNW_ARM64_D14, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + registers.setFloatRegister(UNW_ARM64_D15, + addressSpace.getDouble(savedRegisterLoc)); + savedRegisterLoc -= 8; + } + + uint64_t fp = registers.getFP(); + // fp points to old fp + registers.setFP(addressSpace.get64(fp)); + // old sp is fp less saved fp and lr + registers.setSP(fp + 16); + // pop return address into pc + registers.setIP(addressSpace.get64(fp + 8)); + + return UNW_STEP_SUCCESS; +} + + +}; // namespace libunwind + +#endif // __COMPACT_UNWINDER_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp b/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp new file mode 100644 index 00000000..158bad87 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp @@ -0,0 +1,888 @@ +//===-------------------------- DwarfInstructions.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. +// +// +// Processor specific interpretation of dwarf unwind info. +// +//===----------------------------------------------------------------------===// + +#ifndef __DWARF_INSTRUCTIONS_HPP__ +#define __DWARF_INSTRUCTIONS_HPP__ + +#include +#include +#include + +#include "dwarf2.h" +#include "AddressSpace.hpp" +#include "Registers.hpp" +#include "DwarfParser.hpp" +#include "config.h" + + +namespace libunwind { + + +/// DwarfInstructions maps abtract dwarf unwind instructions to a particular +/// architecture +template +class DwarfInstructions { +public: + typedef typename A::pint_t pint_t; + typedef typename A::sint_t sint_t; + + static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart, + R ®isters); + +private: + + enum { + DW_X86_64_RET_ADDR = 16 + }; + + enum { + DW_X86_RET_ADDR = 8 + }; + + typedef typename CFI_Parser::RegisterLocation RegisterLocation; + typedef typename CFI_Parser::PrologInfo PrologInfo; + typedef typename CFI_Parser::FDE_Info FDE_Info; + typedef typename CFI_Parser::CIE_Info CIE_Info; + + static pint_t evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue); + static pint_t getSavedRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static double getSavedFloatRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + static v128 getSavedVectorRegister(A &addressSpace, const R ®isters, + pint_t cfa, const RegisterLocation &savedReg); + + // x86 specific variants + static int lastRestoreReg(const Registers_x86 &); + static bool isReturnAddressRegister(int regNum, const Registers_x86 &); + static pint_t getCFA(A &addressSpace, const PrologInfo &prolog, + const Registers_x86 &); + + // x86_64 specific variants + static int lastRestoreReg(const Registers_x86_64 &); + static bool isReturnAddressRegister(int regNum, const Registers_x86_64 &); + static pint_t getCFA(A &addressSpace, + const PrologInfo &prolog, + const Registers_x86_64 &); + + // ppc specific variants + static int lastRestoreReg(const Registers_ppc &); + static bool isReturnAddressRegister(int regNum, const Registers_ppc &); + static pint_t getCFA(A &addressSpace, + const PrologInfo &prolog, + const Registers_ppc &); + + // arm64 specific variants + static bool isReturnAddressRegister(int regNum, const Registers_arm64 &); + static int lastRestoreReg(const Registers_arm64 &); + static pint_t getCFA(A &addressSpace, + const PrologInfo &prolog, + const Registers_arm64 &); + +}; + + +template +typename A::pint_t DwarfInstructions::getSavedRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getP(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getP( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser::kRegisterIsExpression: + return evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa); + + case CFI_Parser::kRegisterInRegister: + return registers.getRegister((int)savedReg.value); + + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for register"); +} + +template +double DwarfInstructions::getSavedFloatRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getDouble(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getDouble( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + case CFI_Parser::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for float register"); +} + +template +v128 DwarfInstructions::getSavedVectorRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser::kRegisterInCFA: + return addressSpace.getVector(cfa + (pint_t)savedReg.value); + + case CFI_Parser::kRegisterAtExpression: + return addressSpace.getVector( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser::kRegisterIsExpression: + case CFI_Parser::kRegisterUnused: + case CFI_Parser::kRegisterOffsetFromCFA: + case CFI_Parser::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for vector register"); +} + +template +int DwarfInstructions::stepWithDwarf(A &addressSpace, pint_t pc, + pint_t fdeStart, R ®isters) { + FDE_Info fdeInfo; + CIE_Info cieInfo; + if (CFI_Parser::decodeFDE(addressSpace, fdeStart, + &fdeInfo, &cieInfo) == NULL) { + PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc, + &prolog)) { + R newRegisters = registers; + + // get pointer to cfa (architecture specific) + pint_t cfa = getCFA(addressSpace, prolog, registers); + + // restore registers that dwarf says were saved + pint_t returnAddress = 0; + for (int i = 0; i <= lastRestoreReg(newRegisters); ++i) { + if (prolog.savedRegisters[i].location != + CFI_Parser::kRegisterUnused) { + if (registers.validFloatRegister(i)) + newRegisters.setFloatRegister( + i, getSavedFloatRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (registers.validVectorRegister(i)) + newRegisters.setVectorRegister( + i, getSavedVectorRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else if (isReturnAddressRegister(i, registers)) + returnAddress = getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i]); + else if (registers.validRegister(i)) + newRegisters.setRegister( + i, getSavedRegister(addressSpace, registers, cfa, + prolog.savedRegisters[i])); + else + return UNW_EBADREG; + } + } + + // By definition, the CFA is the stack pointer at the call site, so + // restoring SP means setting it to CFA. + newRegisters.setSP(cfa); + + // Return address is address after call site instruction, so setting IP to + // that does simualates a return. + newRegisters.setIP(returnAddress); + + // Simulate the step by replacing the register set with the new ones. + registers = newRegisters; + + return UNW_STEP_SUCCESS; + } + } + return UNW_EBADFRAME; +} + +template +typename A::pint_t +DwarfInstructions::evaluateExpression(pint_t expression, A &addressSpace, + const R ®isters, + pint_t initialStackValue) { + const bool log = false; + pint_t p = expression; + pint_t expressionEnd = expression + 20; // temp, until len read + pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd); + expressionEnd = p + length; + if (log) + fprintf(stderr, "evaluateExpression(): length=%llu\n", (uint64_t)length); + pint_t stack[100]; + pint_t *sp = stack; + *(++sp) = initialStackValue; + + while (p < expressionEnd) { + if (log) { + for (pint_t *t = sp; t > stack; --t) { + fprintf(stderr, "sp[] = 0x%llX\n", (uint64_t)(*t)); + } + } + uint8_t opcode = addressSpace.get8(p++); + sint_t svalue, svalue2; + pint_t value; + uint32_t reg; + switch (opcode) { + case DW_OP_addr: + // push immediate address sized value + value = addressSpace.getP(p); + p += sizeof(pint_t); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_deref: + // pop stack, dereference, push result + value = *sp--; + *(++sp) = addressSpace.getP(value); + if (log) + fprintf(stderr, "dereference 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_const1u: + // push immediate 1 byte value + value = addressSpace.get8(p); + p += 1; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_const1s: + // push immediate 1 byte signed value + svalue = (int8_t) addressSpace.get8(p); + p += 1; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); + break; + + case DW_OP_const2u: + // push immediate 2 byte value + value = addressSpace.get16(p); + p += 2; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_const2s: + // push immediate 2 byte signed value + svalue = (int16_t) addressSpace.get16(p); + p += 2; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); + break; + + case DW_OP_const4u: + // push immediate 4 byte value + value = addressSpace.get32(p); + p += 4; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_const4s: + // push immediate 4 byte signed value + svalue = (int32_t)addressSpace.get32(p); + p += 4; + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); + break; + + case DW_OP_const8u: + // push immediate 8 byte value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_const8s: + // push immediate 8 byte signed value + value = (pint_t)addressSpace.get64(p); + p += 8; + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_constu: + // push immediate ULEB128 value + value = (pint_t)addressSpace.getULEB128(p, expressionEnd); + *(++sp) = value; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_consts: + // push immediate SLEB128 value + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + *(++sp) = (pint_t)svalue; + if (log) + fprintf(stderr, "push 0x%llX\n", (uint64_t) svalue); + break; + + case DW_OP_dup: + // push top of stack + value = *sp; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate top of stack\n"); + break; + + case DW_OP_drop: + // pop + --sp; + if (log) + fprintf(stderr, "pop top of stack\n"); + break; + + case DW_OP_over: + // dup second + value = sp[-1]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate second in stack\n"); + break; + + case DW_OP_pick: + // pick from + reg = addressSpace.get8(p); + p += 1; + value = sp[-reg]; + *(++sp) = value; + if (log) + fprintf(stderr, "duplicate %d in stack\n", reg); + break; + + case DW_OP_swap: + // swap top two + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = value; + if (log) + fprintf(stderr, "swap top of stack\n"); + break; + + case DW_OP_rot: + // rotate top three + value = sp[0]; + sp[0] = sp[-1]; + sp[-1] = sp[-2]; + sp[-2] = value; + if (log) + fprintf(stderr, "rotate top three of stack\n"); + break; + + case DW_OP_xderef: + // pop stack, dereference, push result + value = *sp--; + *sp = *((pint_t*)value); + if (log) + fprintf(stderr, "x-dereference 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_abs: + svalue = (sint_t)*sp; + if (svalue < 0) + *sp = (pint_t)(-svalue); + if (log) + fprintf(stderr, "abs\n"); + break; + + case DW_OP_and: + value = *sp--; + *sp &= value; + if (log) + fprintf(stderr, "and\n"); + break; + + case DW_OP_div: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 / svalue); + if (log) + fprintf(stderr, "div\n"); + break; + + case DW_OP_minus: + value = *sp--; + *sp = *sp - value; + if (log) + fprintf(stderr, "minus\n"); + break; + + case DW_OP_mod: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 % svalue); + if (log) + fprintf(stderr, "module\n"); + break; + + case DW_OP_mul: + svalue = (sint_t)(*sp--); + svalue2 = (sint_t)*sp; + *sp = (pint_t)(svalue2 * svalue); + if (log) + fprintf(stderr, "mul\n"); + break; + + case DW_OP_neg: + *sp = 0 - *sp; + if (log) + fprintf(stderr, "neg\n"); + break; + + case DW_OP_not: + svalue = (sint_t)(*sp); + *sp = (pint_t)(~svalue); + if (log) + fprintf(stderr, "not\n"); + break; + + case DW_OP_or: + value = *sp--; + *sp |= value; + if (log) + fprintf(stderr, "or\n"); + break; + + case DW_OP_plus: + value = *sp--; + *sp += value; + if (log) + fprintf(stderr, "plus\n"); + break; + + case DW_OP_plus_uconst: + // pop stack, add uelb128 constant, push result + *sp += addressSpace.getULEB128(p, expressionEnd); + if (log) + fprintf(stderr, "add constant\n"); + break; + + case DW_OP_shl: + value = *sp--; + *sp = *sp << value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shr: + value = *sp--; + *sp = *sp >> value; + if (log) + fprintf(stderr, "shift left\n"); + break; + + case DW_OP_shra: + value = *sp--; + svalue = (sint_t)*sp; + *sp = (pint_t)(svalue >> value); + if (log) + fprintf(stderr, "shift left arithmetric\n"); + break; + + case DW_OP_xor: + value = *sp--; + *sp ^= value; + if (log) + fprintf(stderr, "xor\n"); + break; + + case DW_OP_skip: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "skip %lld\n", (uint64_t) svalue); + break; + + case DW_OP_bra: + svalue = (int16_t) addressSpace.get16(p); + p += 2; + if (*sp--) + p = (pint_t)((sint_t)p + svalue); + if (log) + fprintf(stderr, "bra %lld\n", (uint64_t) svalue); + break; + + case DW_OP_eq: + value = *sp--; + *sp = (*sp == value); + if (log) + fprintf(stderr, "eq\n"); + break; + + case DW_OP_ge: + value = *sp--; + *sp = (*sp >= value); + if (log) + fprintf(stderr, "ge\n"); + break; + + case DW_OP_gt: + value = *sp--; + *sp = (*sp > value); + if (log) + fprintf(stderr, "gt\n"); + break; + + case DW_OP_le: + value = *sp--; + *sp = (*sp <= value); + if (log) + fprintf(stderr, "le\n"); + break; + + case DW_OP_lt: + value = *sp--; + *sp = (*sp < value); + if (log) + fprintf(stderr, "lt\n"); + break; + + case DW_OP_ne: + value = *sp--; + *sp = (*sp != value); + if (log) + fprintf(stderr, "ne\n"); + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + value = opcode - DW_OP_lit0; + *(++sp) = value; + if (log) + fprintf(stderr, "push literal 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + reg = opcode - DW_OP_reg0; + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d\n", reg); + break; + + case DW_OP_regx: + reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd); + *(++sp) = registers.getRegister((int)reg); + if (log) + fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + reg = opcode - DW_OP_breg0; + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += registers.getRegister((int)reg); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); + break; + + case DW_OP_bregx: + reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd); + svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd); + svalue += registers.getRegister((int)reg); + *(++sp) = (pint_t)(svalue); + if (log) + fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue); + break; + + case DW_OP_fbreg: + _LIBUNWIND_ABORT("DW_OP_fbreg not implemented"); + break; + + case DW_OP_piece: + _LIBUNWIND_ABORT("DW_OP_piece not implemented"); + break; + + case DW_OP_deref_size: + // pop stack, dereference, push result + value = *sp--; + switch (addressSpace.get8(p++)) { + case 1: + value = addressSpace.get8(value); + break; + case 2: + value = addressSpace.get16(value); + break; + case 4: + value = addressSpace.get32(value); + break; + case 8: + value = (pint_t)addressSpace.get64(value); + break; + default: + _LIBUNWIND_ABORT("DW_OP_deref_size with bad size"); + } + *(++sp) = value; + if (log) + fprintf(stderr, "sized dereference 0x%llX\n", (uint64_t) value); + break; + + case DW_OP_xderef_size: + case DW_OP_nop: + case DW_OP_push_object_addres: + case DW_OP_call2: + case DW_OP_call4: + case DW_OP_call_ref: + default: + _LIBUNWIND_ABORT("dwarf opcode not implemented"); + } + + } + if (log) + fprintf(stderr, "expression evaluates to 0x%llX\n", (uint64_t) * sp); + return *sp; +} + +// +// x86_64 specific functions +// +template +int DwarfInstructions::lastRestoreReg(const Registers_x86_64 &) { + static_assert((int)CFI_Parser::kMaxRegisterNumber + > (int)DW_X86_64_RET_ADDR, "register number out of range"); + return DW_X86_64_RET_ADDR; +} + +template +bool +DwarfInstructions::isReturnAddressRegister(int regNum, + const Registers_x86_64 &) { + return (regNum == DW_X86_64_RET_ADDR); +} + +template +typename A::pint_t DwarfInstructions::getCFA( + A &addressSpace, const PrologInfo &prolog, + const Registers_x86_64 ®isters) { + if (prolog.cfaRegister != 0) + return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + + prolog.cfaRegisterOffset); + else if (prolog.cfaExpression != 0) + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, registers, 0); + else + _LIBUNWIND_ABORT("getCFA(): unknown location for x86_64 cfa"); +} + + +// +// x86 specific functions +// +template +int DwarfInstructions::lastRestoreReg(const Registers_x86 &) { + static_assert((int)CFI_Parser::kMaxRegisterNumber + > (int)DW_X86_RET_ADDR, "register number out of range"); + return DW_X86_RET_ADDR; +} + +template +bool DwarfInstructions::isReturnAddressRegister(int regNum, + const Registers_x86 &) { + return (regNum == DW_X86_RET_ADDR); +} + +template +typename A::pint_t DwarfInstructions::getCFA( + A &addressSpace, const PrologInfo &prolog, + const Registers_x86 ®isters) { + if (prolog.cfaRegister != 0) + return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) + + prolog.cfaRegisterOffset); + else if (prolog.cfaExpression != 0) + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, + registers, 0); + else + _LIBUNWIND_ABORT("getCFA(): unknown location for x86 cfa"); +} + + +// +// ppc specific functions +// +template +int DwarfInstructions::lastRestoreReg(const Registers_ppc &) { + static_assert((int)CFI_Parser::kMaxRegisterNumber + > (int)UNW_PPC_SPEFSCR, "register number out of range"); + return UNW_PPC_SPEFSCR; +} + +template +bool DwarfInstructions::isReturnAddressRegister(int regNum, + const Registers_ppc &) { + return (regNum == UNW_PPC_LR); +} + +template +typename A::pint_t DwarfInstructions::getCFA( + A &addressSpace, const PrologInfo &prolog, + const Registers_ppc ®isters) { + if (prolog.cfaRegister != 0) + return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; + else if (prolog.cfaExpression != 0) + return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, + registers, 0); + else + _LIBUNWIND_ABORT("getCFA(): unknown location for ppc cfa"); +} + + + +// +// arm64 specific functions +// +template +bool DwarfInstructions::isReturnAddressRegister(int regNum, + const Registers_arm64 &) { + return (regNum == UNW_ARM64_LR); +} + +template +int DwarfInstructions::lastRestoreReg(const Registers_arm64 &) { + static_assert((int)CFI_Parser::kMaxRegisterNumber + > (int)UNW_ARM64_D31, "register number out of range"); + return UNW_ARM64_D31; +} + +template +typename A::pint_t DwarfInstructions::getCFA(A&, const PrologInfo &prolog, + const Registers_arm64 ®isters) { + if (prolog.cfaRegister != 0) + return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset; + else + _LIBUNWIND_ABORT("getCFA(): unsupported location for arm64 cfa"); +} + + +} // namespace libunwind + +#endif // __DWARF_INSTRUCTIONS_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp b/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp new file mode 100644 index 00000000..152baab9 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/DwarfParser.hpp @@ -0,0 +1,713 @@ +//===--------------------------- DwarfParser.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. +// +// +// Parses DWARF CFIs (FDEs and CIEs). +// +//===----------------------------------------------------------------------===// + +#ifndef __DWARF_PARSER_HPP__ +#define __DWARF_PARSER_HPP__ + +#include +#include +#include + +#include + +#include "libunwind.h" +#include "dwarf2.h" + +#include "AddressSpace.hpp" + +namespace libunwind { + +/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records. +/// See Dwarf Spec for details: +/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html +/// +template +class CFI_Parser { +public: + typedef typename A::pint_t pint_t; + + /// Information encoded in a CIE (Common Information Entry) + struct CIE_Info { + pint_t cieStart; + pint_t cieLength; + pint_t cieInstructions; + uint8_t pointerEncoding; + uint8_t lsdaEncoding; + uint8_t personalityEncoding; + uint8_t personalityOffsetInCIE; + pint_t personality; + uint32_t codeAlignFactor; + int dataAlignFactor; + bool isSignalFrame; + bool fdesHaveAugmentationData; + }; + + /// Information about an FDE (Frame Description Entry) + struct FDE_Info { + pint_t fdeStart; + pint_t fdeLength; + pint_t fdeInstructions; + pint_t pcStart; + pint_t pcEnd; + pint_t lsda; + }; + + enum { + kMaxRegisterNumber = 120 + }; + enum RegisterSavedWhere { + kRegisterUnused, + kRegisterInCFA, + kRegisterOffsetFromCFA, + kRegisterInRegister, + kRegisterAtExpression, + kRegisterIsExpression + }; + struct RegisterLocation { + RegisterSavedWhere location; + int64_t value; + }; + /// Information about a frame layout and registers saved determined + /// by "running" the dwarf FDE "instructions" + struct PrologInfo { + uint32_t cfaRegister; + int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset + int64_t cfaExpression; // CFA = expression + uint32_t spExtraArgSize; + uint32_t codeOffsetAtStackDecrement; + bool registersInOtherRegisters; + bool sameValueUsed; + RegisterLocation savedRegisters[kMaxRegisterNumber]; + }; + + struct PrologInfoStackEntry { + PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i) + : next(n), info(i) {} + PrologInfoStackEntry *next; + PrologInfo info; + }; + + static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo, + CIE_Info *cieInfo); + static const char *decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo); + static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + PrologInfo *results); + + static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo); + +private: + static bool parseInstructions(A &addressSpace, pint_t instructions, + pint_t instructionsEnd, const CIE_Info &cieInfo, + pint_t pcoffset, + PrologInfoStackEntry *&rememberStack, + PrologInfo *results); +}; + +/// Parse a FDE into a CIE_Info and an FDE_Info +template +const char *CFI_Parser::decodeFDE(A &addressSpace, pint_t fdeStart, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + pint_t p = fdeStart; + pint_t cfiLength = (pint_t)addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return "FDE has zero length"; // end marker + uint32_t ciePointer = addressSpace.get32(p); + if (ciePointer == 0) + return "FDE is really a CIE"; // this is a CIE not an FDE + pint_t nextCFI = p + cfiLength; + pint_t cieStart = p - ciePointer; + const char *err = parseCIE(addressSpace, cieStart, cieInfo); + if (err != NULL) + return err; + p += 4; + // parse pc begin and range + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // parse rest of info + fdeInfo->lsda = 0; + // check for augmentation length + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != 0) { + // peek at value (without indirection). Zero means no lsda + pint_t lsdaStart = p; + if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != + 0) { + // reset pointer and re-parse lsda address + p = lsdaStart; + fdeInfo->lsda = + addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = fdeStart; + fdeInfo->fdeLength = nextCFI - fdeStart; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return NULL; // success +} + +/// Scan an eh_frame section to find an FDE for a pc +template +bool CFI_Parser::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart, + uint32_t sectionLength, pint_t fdeHint, + FDE_Info *fdeInfo, CIE_Info *cieInfo) { + //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc); + pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart; + const pint_t ehSectionEnd = p + sectionLength; + while (p < ehSectionEnd) { + pint_t currentCFI = p; + //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p); + pint_t cfiLength = addressSpace.get32(p); + p += 4; + if (cfiLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cfiLength = (pint_t)addressSpace.get64(p); + p += 8; + } + if (cfiLength == 0) + return false; // end marker + uint32_t id = addressSpace.get32(p); + if (id == 0) { + // skip over CIEs + p += cfiLength; + } else { + // process FDE to see if it covers pc + pint_t nextCFI = p + cfiLength; + uint32_t ciePointer = addressSpace.get32(p); + pint_t cieStart = p - ciePointer; + // validate pointer to CIE is within section + if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) { + if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) { + p += 4; + // parse pc begin and range + pint_t pcStart = + addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding); + pint_t pcRange = addressSpace.getEncodedP( + p, nextCFI, cieInfo->pointerEncoding & 0x0F); + // test if pc is within the function this FDE covers + if ((pcStart < pc) && (pc <= pcStart + pcRange)) { + // parse rest of info + fdeInfo->lsda = 0; + // check for augmentation length + if (cieInfo->fdesHaveAugmentationData) { + pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI); + pint_t endOfAug = p + augLen; + if (cieInfo->lsdaEncoding != 0) { + // peek at value (without indirection). Zero means no lsda + pint_t lsdaStart = p; + if (addressSpace.getEncodedP( + p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) { + // reset pointer and re-parse lsda address + p = lsdaStart; + fdeInfo->lsda = addressSpace + .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding); + } + } + p = endOfAug; + } + fdeInfo->fdeStart = currentCFI; + fdeInfo->fdeLength = nextCFI - currentCFI; + fdeInfo->fdeInstructions = p; + fdeInfo->pcStart = pcStart; + fdeInfo->pcEnd = pcStart + pcRange; + return true; + } else { + // pc is not in begin/range, skip this FDE + } + } else { + // malformed CIE, now augmentation describing pc range encoding + } + } else { + // malformed FDE. CIE is bad + } + p = nextCFI; + } + } + return false; +} + +/// Extract info from a CIE +template +const char *CFI_Parser::parseCIE(A &addressSpace, pint_t cie, + CIE_Info *cieInfo) { + cieInfo->pointerEncoding = 0; + cieInfo->lsdaEncoding = 0; + cieInfo->personalityEncoding = 0; + cieInfo->personalityOffsetInCIE = 0; + cieInfo->personality = 0; + cieInfo->codeAlignFactor = 0; + cieInfo->dataAlignFactor = 0; + cieInfo->isSignalFrame = false; + cieInfo->fdesHaveAugmentationData = false; + cieInfo->cieStart = cie; + pint_t p = cie; + pint_t cieLength = (pint_t)addressSpace.get32(p); + p += 4; + pint_t cieContentEnd = p + cieLength; + if (cieLength == 0xffffffff) { + // 0xffffffff means length is really next 8 bytes + cieLength = (pint_t)addressSpace.get64(p); + p += 8; + cieContentEnd = p + cieLength; + } + if (cieLength == 0) + return NULL; + // CIE ID is always 0 + if (addressSpace.get32(p) != 0) + return "CIE ID is not zero"; + p += 4; + // Version is always 1 or 3 + uint8_t version = addressSpace.get8(p); + if ((version != 1) && (version != 3)) + return "CIE version is not 1 or 3"; + ++p; + // save start of augmentation string and find end + pint_t strStart = p; + while (addressSpace.get8(p) != 0) + ++p; + ++p; + // parse code aligment factor + cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd); + // parse data alignment factor + cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd); + // parse return address register + addressSpace.getULEB128(p, cieContentEnd); + // parse augmentation data based on augmentation string + const char *result = NULL; + if (addressSpace.get8(strStart) == 'z') { + // parse augmentation data length + addressSpace.getULEB128(p, cieContentEnd); + for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) { + switch (addressSpace.get8(s)) { + case 'z': + cieInfo->fdesHaveAugmentationData = true; + break; + case 'P': + cieInfo->personalityEncoding = addressSpace.get8(p); + ++p; + cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie); + cieInfo->personality = addressSpace + .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding); + break; + case 'L': + cieInfo->lsdaEncoding = addressSpace.get8(p); + ++p; + break; + case 'R': + cieInfo->pointerEncoding = addressSpace.get8(p); + ++p; + break; + case 'S': + cieInfo->isSignalFrame = true; + break; + default: + // ignore unknown letters + break; + } + } + } + cieInfo->cieLength = cieContentEnd - cieInfo->cieStart; + cieInfo->cieInstructions = p; + return result; +} + + +/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE +template +bool CFI_Parser::parseFDEInstructions(A &addressSpace, + const FDE_Info &fdeInfo, + const CIE_Info &cieInfo, pint_t upToPC, + PrologInfo *results) { + // clear results + bzero(results, sizeof(PrologInfo)); + PrologInfoStackEntry *rememberStack = NULL; + + // parse CIE then FDE instructions + return parseInstructions(addressSpace, cieInfo.cieInstructions, + cieInfo.cieStart + cieInfo.cieLength, cieInfo, + (pint_t)(-1), rememberStack, results) && + parseInstructions(addressSpace, fdeInfo.fdeInstructions, + fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo, + upToPC - fdeInfo.pcStart, rememberStack, results); +} + +/// "run" the dwarf instructions +template +bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, + pint_t instructionsEnd, + const CIE_Info &cieInfo, pint_t pcoffset, + PrologInfoStackEntry *&rememberStack, + PrologInfo *results) { + const bool logDwarf = false; + pint_t p = instructions; + pint_t codeOffset = 0; + PrologInfo initialState = *results; + if (logDwarf) + fprintf(stderr, "parseInstructions(instructions=0x%0llX)\n", + (uint64_t) instructionsEnd); + + // see Dwarf Spec, section 6.4.2 for details on unwind opcodes + while ((p < instructionsEnd) && (codeOffset < pcoffset)) { + uint64_t reg; + uint64_t reg2; + int64_t offset; + uint64_t length; + uint8_t opcode = addressSpace.get8(p); + uint8_t operand; + PrologInfoStackEntry *entry; + ++p; + switch (opcode) { + case DW_CFA_nop: + if (logDwarf) + fprintf(stderr, "DW_CFA_nop\n"); + break; + case DW_CFA_set_loc: + codeOffset = + addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding); + if (logDwarf) + fprintf(stderr, "DW_CFA_set_loc\n"); + break; + case DW_CFA_advance_loc1: + codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor); + p += 1; + if (logDwarf) + fprintf(stderr, "DW_CFA_advance_loc1: new offset=%llu\n", + (uint64_t)codeOffset); + break; + case DW_CFA_advance_loc2: + codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor); + p += 2; + if (logDwarf) + fprintf(stderr, "DW_CFA_advance_loc2: new offset=%llu\n", + (uint64_t)codeOffset); + break; + case DW_CFA_advance_loc4: + codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor); + p += 4; + if (logDwarf) + fprintf(stderr, "DW_CFA_advance_loc4: new offset=%llu\n", + (uint64_t)codeOffset); + break; + case DW_CFA_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n"); + return false; + } + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_offset_extended(reg=%lld, offset=%lld)\n", reg, + offset); + break; + case DW_CFA_restore_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + ; + if (reg > kMaxRegisterNumber) { + fprintf( + stderr, + "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n"); + return false; + } + results->savedRegisters[reg] = initialState.savedRegisters[reg]; + if (logDwarf) + fprintf(stderr, "DW_CFA_restore_extended(reg=%lld)\n", reg); + break; + case DW_CFA_undefined: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_undefined dwarf unwind, reg too big\n"); + return false; + } + results->savedRegisters[reg].location = kRegisterUnused; + if (logDwarf) + fprintf(stderr, "DW_CFA_undefined(reg=%lld)\n", reg); + break; + case DW_CFA_same_value: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_same_value dwarf unwind, reg too big\n"); + return false; + } + // DW_CFA_same_value unsupported + // "same value" means register was stored in frame, but its current + // value has not changed, so no need to restore from frame. + // We model this as if the register was never saved. + results->savedRegisters[reg].location = kRegisterUnused; + // set flag to disable conversion to compact unwind + results->sameValueUsed = true; + if (logDwarf) + fprintf(stderr, "DW_CFA_same_value(reg=%lld)\n", reg); + break; + case DW_CFA_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + reg2 = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_register dwarf unwind, reg too big\n"); + return false; + } + if (reg2 > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_register dwarf unwind, reg2 too big\n"); + return false; + } + results->savedRegisters[reg].location = kRegisterInRegister; + results->savedRegisters[reg].value = (int64_t)reg2; + // set flag to disable conversion to compact unwind + results->registersInOtherRegisters = true; + if (logDwarf) + fprintf(stderr, "DW_CFA_register(reg=%lld, reg2=%lld)\n", reg, reg2); + break; + case DW_CFA_remember_state: + // avoid operator new, because that would be an upward dependency + entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry)); + if (entry != NULL) { + entry->next = rememberStack; + entry->info = *results; + rememberStack = entry; + } else { + return false; + } + if (logDwarf) + fprintf(stderr, "DW_CFA_remember_state\n"); + break; + case DW_CFA_restore_state: + if (rememberStack != NULL) { + PrologInfoStackEntry *top = rememberStack; + *results = top->info; + rememberStack = top->next; + free((char *)top); + } else { + return false; + } + if (logDwarf) + fprintf(stderr, "DW_CFA_restore_state\n"); + break; + case DW_CFA_def_cfa: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_def_cfa(reg=%lld, offset=%lld)\n", reg, offset); + break; + case DW_CFA_def_cfa_register: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf( + stderr, + "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n"); + return false; + } + results->cfaRegister = (uint32_t)reg; + if (logDwarf) + fprintf(stderr, "DW_CFA_def_cfa_register(%lld)\n", reg); + break; + case DW_CFA_def_cfa_offset: + results->cfaRegisterOffset = (int32_t) + addressSpace.getULEB128(p, instructionsEnd); + results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; + if (logDwarf) + fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_def_cfa_expression: + results->cfaRegister = 0; + results->cfaExpression = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + p += length; + if (logDwarf) + fprintf(stderr, + "DW_CFA_def_cfa_expression(expression=0x%llX, length=%llu)\n", + results->cfaExpression, length); + break; + case DW_CFA_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_expression dwarf unwind, reg too big\n"); + return false; + } + results->savedRegisters[reg].location = kRegisterAtExpression; + results->savedRegisters[reg].value = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + p += length; + if (logDwarf) + fprintf(stderr, + "DW_CFA_expression(reg=%lld, expression=0x%llX, length=%llu)\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_offset_extended_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf( + stderr, + "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n"); + return false; + } + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%lld, offset=%lld)\n", + reg, offset); + break; + case DW_CFA_def_cfa_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n"); + return false; + } + results->cfaRegister = (uint32_t)reg; + results->cfaRegisterOffset = (int32_t)offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_def_cfa_sf(reg=%lld, offset=%lld)\n", reg, + offset); + break; + case DW_CFA_def_cfa_offset_sf: + results->cfaRegisterOffset = (int32_t) + (addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor); + results->codeOffsetAtStackDecrement = (uint32_t)codeOffset; + if (logDwarf) + fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n", + results->cfaRegisterOffset); + break; + case DW_CFA_val_offset: + reg = addressSpace.getULEB128(p, instructionsEnd); + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->savedRegisters[reg].location = kRegisterOffsetFromCFA; + results->savedRegisters[reg].value = offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_val_offset(reg=%lld, offset=%lld\n", reg, + offset); + break; + case DW_CFA_val_offset_sf: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n"); + return false; + } + offset = + addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor; + results->savedRegisters[reg].location = kRegisterOffsetFromCFA; + results->savedRegisters[reg].value = offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_val_offset_sf(reg=%lld, offset=%lld\n", reg, + offset); + break; + case DW_CFA_val_expression: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, + "malformed DW_CFA_val_expression dwarf unwind, reg too big\n"); + return false; + } + results->savedRegisters[reg].location = kRegisterIsExpression; + results->savedRegisters[reg].value = (int64_t)p; + length = addressSpace.getULEB128(p, instructionsEnd); + p += length; + if (logDwarf) + fprintf( + stderr, + "DW_CFA_val_expression(reg=%lld, expression=0x%llX, length=%lld)\n", + reg, results->savedRegisters[reg].value, length); + break; + case DW_CFA_GNU_args_size: + length = addressSpace.getULEB128(p, instructionsEnd); + results->spExtraArgSize = (uint32_t)length; + if (logDwarf) + fprintf(stderr, "DW_CFA_GNU_args_size(%lld)\n", length); + break; + case DW_CFA_GNU_negative_offset_extended: + reg = addressSpace.getULEB128(p, instructionsEnd); + if (reg > kMaxRegisterNumber) { + fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf " + "unwind, reg too big\n"); + return false; + } + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = -offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%lld)\n", offset); + break; + default: + operand = opcode & 0x3F; + switch (opcode & 0xC0) { + case DW_CFA_offset: + reg = operand; + offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd) + * cieInfo.dataAlignFactor; + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = offset; + if (logDwarf) + fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%lld)\n", operand, + offset); + break; + case DW_CFA_advance_loc: + codeOffset += operand * cieInfo.codeAlignFactor; + if (logDwarf) + fprintf(stderr, "DW_CFA_advance_loc: new offset=%llu\n", + (uint64_t)codeOffset); + break; + case DW_CFA_restore: + reg = operand; + results->savedRegisters[reg] = initialState.savedRegisters[reg]; + if (logDwarf) + fprintf(stderr, "DW_CFA_restore(reg=%lld)\n", reg); + break; + default: + if (logDwarf) + fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode); + return false; + } + } + } + + return true; +} + +} // namespace libunwind + +#endif // __DWARF_PARSER_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/Registers.hpp b/system/lib/libcxxabi/src/Unwind/Registers.hpp new file mode 100644 index 00000000..584e4492 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/Registers.hpp @@ -0,0 +1,1568 @@ +//===----------------------------- Registers.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. +// +// +// Models register sets for supported processors. +// +//===----------------------------------------------------------------------===// + +#ifndef __REGISTERS_HPP__ +#define __REGISTERS_HPP__ + +#include +#include + +#include "libunwind.h" +#include "config.h" + +namespace libunwind { + +// For emulating 128-bit registers +struct v128 { uint32_t vec[4]; }; + + +/// Registers_x86 holds the register state of a thread in a 32-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86 { +public: + Registers_x86(); + Registers_x86(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const { return false; } + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + + uint32_t getSP() const { return _registers.__esp; } + void setSP(uint32_t value) { _registers.__esp = value; } + uint32_t getIP() const { return _registers.__eip; } + void setIP(uint32_t value) { _registers.__eip = value; } + uint32_t getEBP() const { return _registers.__ebp; } + void setEBP(uint32_t value) { _registers.__ebp = value; } + uint32_t getEBX() const { return _registers.__ebx; } + void setEBX(uint32_t value) { _registers.__ebx = value; } + uint32_t getECX() const { return _registers.__ecx; } + void setECX(uint32_t value) { _registers.__ecx = value; } + uint32_t getEDX() const { return _registers.__edx; } + void setEDX(uint32_t value) { _registers.__edx = value; } + uint32_t getESI() const { return _registers.__esi; } + void setESI(uint32_t value) { _registers.__esi = value; } + uint32_t getEDI() const { return _registers.__edi; } + void setEDI(uint32_t value) { _registers.__edi = value; } + +private: + struct GPRs { + unsigned int __eax; + unsigned int __ebx; + unsigned int __ecx; + unsigned int __edx; + unsigned int __edi; + unsigned int __esi; + unsigned int __ebp; + unsigned int __esp; + unsigned int __ss; + unsigned int __eflags; + unsigned int __eip; + unsigned int __cs; + unsigned int __ds; + unsigned int __es; + unsigned int __fs; + unsigned int __gs; + }; + + GPRs _registers; +}; + +inline Registers_x86::Registers_x86(const void *registers) { + static_assert(sizeof(Registers_x86) < sizeof(unw_context_t), + "x86 registers do not fit into unw_context_t"); + _registers = *((GPRs *)registers); +} + +inline Registers_x86::Registers_x86() { + bzero(&_registers, sizeof(_registers)); +} + +inline bool Registers_x86::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 7) + return false; + return true; +} + +inline uint32_t Registers_x86::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__eip; + case UNW_REG_SP: + return _registers.__esp; + case UNW_X86_EAX: + return _registers.__eax; + case UNW_X86_ECX: + return _registers.__ecx; + case UNW_X86_EDX: + return _registers.__edx; + case UNW_X86_EBX: + return _registers.__ebx; + case UNW_X86_EBP: + return _registers.__ebp; + case UNW_X86_ESP: + return _registers.__esp; + case UNW_X86_ESI: + return _registers.__esi; + case UNW_X86_EDI: + return _registers.__edi; + } + _LIBUNWIND_ABORT("unsupported x86 register"); +} + +inline void Registers_x86::setRegister(int regNum, uint32_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__eip = value; + return; + case UNW_REG_SP: + _registers.__esp = value; + return; + case UNW_X86_EAX: + _registers.__eax = value; + return; + case UNW_X86_ECX: + _registers.__ecx = value; + return; + case UNW_X86_EDX: + _registers.__edx = value; + return; + case UNW_X86_EBX: + _registers.__ebx = value; + return; + case UNW_X86_EBP: + _registers.__ebp = value; + return; + case UNW_X86_ESP: + _registers.__esp = value; + return; + case UNW_X86_ESI: + _registers.__esi = value; + return; + case UNW_X86_EDI: + _registers.__edi = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86 register"); +} + +inline const char *Registers_x86::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "esp"; + case UNW_X86_EAX: + return "eax"; + case UNW_X86_ECX: + return "ecx"; + case UNW_X86_EDX: + return "edx"; + case UNW_X86_EBX: + return "ebx"; + case UNW_X86_EBP: + return "ebp"; + case UNW_X86_ESP: + return "esp"; + case UNW_X86_ESI: + return "esi"; + case UNW_X86_EDI: + return "edi"; + default: + return "unknown register"; + } +} + +inline double Registers_x86::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86 float registers"); +} + +inline void Registers_x86::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86 float registers"); +} + +inline v128 Registers_x86::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no x86 vector registers"); +} + +inline void Registers_x86::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no x86 vector registers"); +} + + +/// Registers_x86_64 holds the register state of a thread in a 64-bit intel +/// process. +class _LIBUNWIND_HIDDEN Registers_x86_64 { +public: + Registers_x86_64(); + Registers_x86_64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int) const { return false; } + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int) const { return false; } + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + + uint64_t getSP() const { return _registers.__rsp; } + void setSP(uint64_t value) { _registers.__rsp = value; } + uint64_t getIP() const { return _registers.__rip; } + void setIP(uint64_t value) { _registers.__rip = value; } + uint64_t getRBP() const { return _registers.__rbp; } + void setRBP(uint64_t value) { _registers.__rbp = value; } + uint64_t getRBX() const { return _registers.__rbx; } + void setRBX(uint64_t value) { _registers.__rbx = value; } + uint64_t getR12() const { return _registers.__r12; } + void setR12(uint64_t value) { _registers.__r12 = value; } + uint64_t getR13() const { return _registers.__r13; } + void setR13(uint64_t value) { _registers.__r13 = value; } + uint64_t getR14() const { return _registers.__r14; } + void setR14(uint64_t value) { _registers.__r14 = value; } + uint64_t getR15() const { return _registers.__r15; } + void setR15(uint64_t value) { _registers.__r15 = value; } + +private: + struct GPRs { + uint64_t __rax; + uint64_t __rbx; + uint64_t __rcx; + uint64_t __rdx; + uint64_t __rdi; + uint64_t __rsi; + uint64_t __rbp; + uint64_t __rsp; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __rip; + uint64_t __rflags; + uint64_t __cs; + uint64_t __fs; + uint64_t __gs; + }; + GPRs _registers; +}; + +inline Registers_x86_64::Registers_x86_64(const void *registers) { + static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t), + "x86_64 registers do not fit into unw_context_t"); + _registers = *((GPRs *)registers); +} + +inline Registers_x86_64::Registers_x86_64() { + bzero(&_registers, sizeof(_registers)); +} + +inline bool Registers_x86_64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 15) + return false; + return true; +} + +inline uint64_t Registers_x86_64::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__rip; + case UNW_REG_SP: + return _registers.__rsp; + case UNW_X86_64_RAX: + return _registers.__rax; + case UNW_X86_64_RDX: + return _registers.__rdx; + case UNW_X86_64_RCX: + return _registers.__rcx; + case UNW_X86_64_RBX: + return _registers.__rbx; + case UNW_X86_64_RSI: + return _registers.__rsi; + case UNW_X86_64_RDI: + return _registers.__rdi; + case UNW_X86_64_RBP: + return _registers.__rbp; + case UNW_X86_64_RSP: + return _registers.__rsp; + case UNW_X86_64_R8: + return _registers.__r8; + case UNW_X86_64_R9: + return _registers.__r9; + case UNW_X86_64_R10: + return _registers.__r10; + case UNW_X86_64_R11: + return _registers.__r11; + case UNW_X86_64_R12: + return _registers.__r12; + case UNW_X86_64_R13: + return _registers.__r13; + case UNW_X86_64_R14: + return _registers.__r14; + case UNW_X86_64_R15: + return _registers.__r15; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline void Registers_x86_64::setRegister(int regNum, uint64_t value) { + switch (regNum) { + case UNW_REG_IP: + _registers.__rip = value; + return; + case UNW_REG_SP: + _registers.__rsp = value; + return; + case UNW_X86_64_RAX: + _registers.__rax = value; + return; + case UNW_X86_64_RDX: + _registers.__rdx = value; + return; + case UNW_X86_64_RCX: + _registers.__rcx = value; + return; + case UNW_X86_64_RBX: + _registers.__rbx = value; + return; + case UNW_X86_64_RSI: + _registers.__rsi = value; + return; + case UNW_X86_64_RDI: + _registers.__rdi = value; + return; + case UNW_X86_64_RBP: + _registers.__rbp = value; + return; + case UNW_X86_64_RSP: + _registers.__rsp = value; + return; + case UNW_X86_64_R8: + _registers.__r8 = value; + return; + case UNW_X86_64_R9: + _registers.__r9 = value; + return; + case UNW_X86_64_R10: + _registers.__r10 = value; + return; + case UNW_X86_64_R11: + _registers.__r11 = value; + return; + case UNW_X86_64_R12: + _registers.__r12 = value; + return; + case UNW_X86_64_R13: + _registers.__r13 = value; + return; + case UNW_X86_64_R14: + _registers.__r14 = value; + return; + case UNW_X86_64_R15: + _registers.__r15 = value; + return; + } + _LIBUNWIND_ABORT("unsupported x86_64 register"); +} + +inline const char *Registers_x86_64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "rip"; + case UNW_REG_SP: + return "rsp"; + case UNW_X86_64_RAX: + return "rax"; + case UNW_X86_64_RDX: + return "rdx"; + case UNW_X86_64_RCX: + return "rcx"; + case UNW_X86_64_RBX: + return "rbx"; + case UNW_X86_64_RSI: + return "rsi"; + case UNW_X86_64_RDI: + return "rdi"; + case UNW_X86_64_RBP: + return "rbp"; + case UNW_X86_64_RSP: + return "rsp"; + case UNW_X86_64_R8: + return "r8"; + case UNW_X86_64_R9: + return "r9"; + case UNW_X86_64_R10: + return "r10"; + case UNW_X86_64_R11: + return "r11"; + case UNW_X86_64_R12: + return "r12"; + case UNW_X86_64_R13: + return "r13"; + case UNW_X86_64_R14: + return "r14"; + case UNW_X86_64_R15: + return "r15"; + default: + return "unknown register"; + } +} + +inline double Registers_x86_64::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline void Registers_x86_64::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no x86_64 float registers"); +} + +inline v128 Registers_x86_64::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no x86_64 vector registers"); +} + +inline void Registers_x86_64::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no x86_64 vector registers"); +} + + +/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC +/// process. +class _LIBUNWIND_HIDDEN Registers_ppc { +public: + Registers_ppc(); + Registers_ppc(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + + uint64_t getSP() const { return _registers.__r1; } + void setSP(uint32_t value) { _registers.__r1 = value; } + uint64_t getIP() const { return _registers.__srr0; } + void setIP(uint32_t value) { _registers.__srr0 = value; } + +private: + struct ppc_thread_state_t { + unsigned int __srr0; /* Instruction address register (PC) */ + unsigned int __srr1; /* Machine state register (supervisor) */ + unsigned int __r0; + unsigned int __r1; + unsigned int __r2; + unsigned int __r3; + unsigned int __r4; + unsigned int __r5; + unsigned int __r6; + unsigned int __r7; + unsigned int __r8; + unsigned int __r9; + unsigned int __r10; + unsigned int __r11; + unsigned int __r12; + unsigned int __r13; + unsigned int __r14; + unsigned int __r15; + unsigned int __r16; + unsigned int __r17; + unsigned int __r18; + unsigned int __r19; + unsigned int __r20; + unsigned int __r21; + unsigned int __r22; + unsigned int __r23; + unsigned int __r24; + unsigned int __r25; + unsigned int __r26; + unsigned int __r27; + unsigned int __r28; + unsigned int __r29; + unsigned int __r30; + unsigned int __r31; + unsigned int __cr; /* Condition register */ + unsigned int __xer; /* User's integer exception register */ + unsigned int __lr; /* Link register */ + unsigned int __ctr; /* Count register */ + unsigned int __mq; /* MQ register (601 only) */ + unsigned int __vrsave; /* Vector Save Register */ + }; + + struct ppc_float_state_t { + double __fpregs[32]; + + unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */ + unsigned int __fpscr; /* floating point status register */ + }; + + ppc_thread_state_t _registers; + ppc_float_state_t _floatRegisters; + v128 _vectorRegisters[32]; // offset 424 +}; + +inline Registers_ppc::Registers_ppc(const void *registers) { + static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t), + "ppc registers do not fit into unw_context_t"); + _registers = *((ppc_thread_state_t *)registers); + _floatRegisters = *((ppc_float_state_t *)((char *)registers + 160)); + memcpy(_vectorRegisters, ((char *)registers + 424), sizeof(_vectorRegisters)); +} + +inline Registers_ppc::Registers_ppc() { + bzero(&_registers, sizeof(_registers)); + bzero(&_floatRegisters, sizeof(_floatRegisters)); + bzero(&_vectorRegisters, sizeof(_vectorRegisters)); +} + +inline bool Registers_ppc::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum == UNW_PPC_VRSAVE) + return true; + if (regNum < 0) + return false; + if (regNum <= UNW_PPC_R31) + return true; + if (regNum == UNW_PPC_MQ) + return true; + if (regNum == UNW_PPC_LR) + return true; + if (regNum == UNW_PPC_CTR) + return true; + if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7)) + return true; + return false; +} + +inline uint32_t Registers_ppc::getRegister(int regNum) const { + switch (regNum) { + case UNW_REG_IP: + return _registers.__srr0; + case UNW_REG_SP: + return _registers.__r1; + case UNW_PPC_R0: + return _registers.__r0; + case UNW_PPC_R1: + return _registers.__r1; + case UNW_PPC_R2: + return _registers.__r2; + case UNW_PPC_R3: + return _registers.__r3; + case UNW_PPC_R4: + return _registers.__r4; + case UNW_PPC_R5: + return _registers.__r5; + case UNW_PPC_R6: + return _registers.__r6; + case UNW_PPC_R7: + return _registers.__r7; + case UNW_PPC_R8: + return _registers.__r8; + case UNW_PPC_R9: + return _registers.__r9; + case UNW_PPC_R10: + return _registers.__r10; + case UNW_PPC_R11: + return _registers.__r11; + case UNW_PPC_R12: + return _registers.__r12; + case UNW_PPC_R13: + return _registers.__r13; + case UNW_PPC_R14: + return _registers.__r14; + case UNW_PPC_R15: + return _registers.__r15; + case UNW_PPC_R16: + return _registers.__r16; + case UNW_PPC_R17: + return _registers.__r17; + case UNW_PPC_R18: + return _registers.__r18; + case UNW_PPC_R19: + return _registers.__r19; + case UNW_PPC_R20: + return _registers.__r20; + case UNW_PPC_R21: + return _registers.__r21; + case UNW_PPC_R22: + return _registers.__r22; + case UNW_PPC_R23: + return _registers.__r23; + case UNW_PPC_R24: + return _registers.__r24; + case UNW_PPC_R25: + return _registers.__r25; + case UNW_PPC_R26: + return _registers.__r26; + case UNW_PPC_R27: + return _registers.__r27; + case UNW_PPC_R28: + return _registers.__r28; + case UNW_PPC_R29: + return _registers.__r29; + case UNW_PPC_R30: + return _registers.__r30; + case UNW_PPC_R31: + return _registers.__r31; + case UNW_PPC_LR: + return _registers.__lr; + case UNW_PPC_CR0: + return (_registers.__cr & 0xF0000000); + case UNW_PPC_CR1: + return (_registers.__cr & 0x0F000000); + case UNW_PPC_CR2: + return (_registers.__cr & 0x00F00000); + case UNW_PPC_CR3: + return (_registers.__cr & 0x000F0000); + case UNW_PPC_CR4: + return (_registers.__cr & 0x0000F000); + case UNW_PPC_CR5: + return (_registers.__cr & 0x00000F00); + case UNW_PPC_CR6: + return (_registers.__cr & 0x000000F0); + case UNW_PPC_CR7: + return (_registers.__cr & 0x0000000F); + case UNW_PPC_VRSAVE: + return _registers.__vrsave; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline void Registers_ppc::setRegister(int regNum, uint32_t value) { + //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value); + switch (regNum) { + case UNW_REG_IP: + _registers.__srr0 = value; + return; + case UNW_REG_SP: + _registers.__r1 = value; + return; + case UNW_PPC_R0: + _registers.__r0 = value; + return; + case UNW_PPC_R1: + _registers.__r1 = value; + return; + case UNW_PPC_R2: + _registers.__r2 = value; + return; + case UNW_PPC_R3: + _registers.__r3 = value; + return; + case UNW_PPC_R4: + _registers.__r4 = value; + return; + case UNW_PPC_R5: + _registers.__r5 = value; + return; + case UNW_PPC_R6: + _registers.__r6 = value; + return; + case UNW_PPC_R7: + _registers.__r7 = value; + return; + case UNW_PPC_R8: + _registers.__r8 = value; + return; + case UNW_PPC_R9: + _registers.__r9 = value; + return; + case UNW_PPC_R10: + _registers.__r10 = value; + return; + case UNW_PPC_R11: + _registers.__r11 = value; + return; + case UNW_PPC_R12: + _registers.__r12 = value; + return; + case UNW_PPC_R13: + _registers.__r13 = value; + return; + case UNW_PPC_R14: + _registers.__r14 = value; + return; + case UNW_PPC_R15: + _registers.__r15 = value; + return; + case UNW_PPC_R16: + _registers.__r16 = value; + return; + case UNW_PPC_R17: + _registers.__r17 = value; + return; + case UNW_PPC_R18: + _registers.__r18 = value; + return; + case UNW_PPC_R19: + _registers.__r19 = value; + return; + case UNW_PPC_R20: + _registers.__r20 = value; + return; + case UNW_PPC_R21: + _registers.__r21 = value; + return; + case UNW_PPC_R22: + _registers.__r22 = value; + return; + case UNW_PPC_R23: + _registers.__r23 = value; + return; + case UNW_PPC_R24: + _registers.__r24 = value; + return; + case UNW_PPC_R25: + _registers.__r25 = value; + return; + case UNW_PPC_R26: + _registers.__r26 = value; + return; + case UNW_PPC_R27: + _registers.__r27 = value; + return; + case UNW_PPC_R28: + _registers.__r28 = value; + return; + case UNW_PPC_R29: + _registers.__r29 = value; + return; + case UNW_PPC_R30: + _registers.__r30 = value; + return; + case UNW_PPC_R31: + _registers.__r31 = value; + return; + case UNW_PPC_MQ: + _registers.__mq = value; + return; + case UNW_PPC_LR: + _registers.__lr = value; + return; + case UNW_PPC_CTR: + _registers.__ctr = value; + return; + case UNW_PPC_CR0: + _registers.__cr &= 0x0FFFFFFF; + _registers.__cr |= (value & 0xF0000000); + return; + case UNW_PPC_CR1: + _registers.__cr &= 0xF0FFFFFF; + _registers.__cr |= (value & 0x0F000000); + return; + case UNW_PPC_CR2: + _registers.__cr &= 0xFF0FFFFF; + _registers.__cr |= (value & 0x00F00000); + return; + case UNW_PPC_CR3: + _registers.__cr &= 0xFFF0FFFF; + _registers.__cr |= (value & 0x000F0000); + return; + case UNW_PPC_CR4: + _registers.__cr &= 0xFFFF0FFF; + _registers.__cr |= (value & 0x0000F000); + return; + case UNW_PPC_CR5: + _registers.__cr &= 0xFFFFF0FF; + _registers.__cr |= (value & 0x00000F00); + return; + case UNW_PPC_CR6: + _registers.__cr &= 0xFFFFFF0F; + _registers.__cr |= (value & 0x000000F0); + return; + case UNW_PPC_CR7: + _registers.__cr &= 0xFFFFFFF0; + _registers.__cr |= (value & 0x0000000F); + return; + case UNW_PPC_VRSAVE: + _registers.__vrsave = value; + return; + // not saved + return; + case UNW_PPC_XER: + _registers.__xer = value; + return; + case UNW_PPC_AP: + case UNW_PPC_VSCR: + case UNW_PPC_SPEFSCR: + // not saved + return; + } + _LIBUNWIND_ABORT("unsupported ppc register"); +} + +inline bool Registers_ppc::validFloatRegister(int regNum) const { + if (regNum < UNW_PPC_F0) + return false; + if (regNum > UNW_PPC_F31) + return false; + return true; +} + +inline double Registers_ppc::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _floatRegisters.__fpregs[regNum - UNW_PPC_F0]; +} + +inline void Registers_ppc::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value; +} + +inline bool Registers_ppc::validVectorRegister(int regNum) const { + if (regNum < UNW_PPC_V0) + return false; + if (regNum > UNW_PPC_V31) + return false; + return true; +} + +inline v128 Registers_ppc::getVectorRegister(int regNum) const { + assert(validVectorRegister(regNum)); + v128 result = _vectorRegisters[regNum - UNW_PPC_V0]; + return result; +} + +inline void Registers_ppc::setVectorRegister(int regNum, v128 value) { + assert(validVectorRegister(regNum)); + _vectorRegisters[regNum - UNW_PPC_V0] = value; +} + +inline const char *Registers_ppc::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "ip"; + case UNW_REG_SP: + return "sp"; + case UNW_PPC_R0: + return "r0"; + case UNW_PPC_R1: + return "r1"; + case UNW_PPC_R2: + return "r2"; + case UNW_PPC_R3: + return "r3"; + case UNW_PPC_R4: + return "r4"; + case UNW_PPC_R5: + return "r5"; + case UNW_PPC_R6: + return "r6"; + case UNW_PPC_R7: + return "r7"; + case UNW_PPC_R8: + return "r8"; + case UNW_PPC_R9: + return "r9"; + case UNW_PPC_R10: + return "r10"; + case UNW_PPC_R11: + return "r11"; + case UNW_PPC_R12: + return "r12"; + case UNW_PPC_R13: + return "r13"; + case UNW_PPC_R14: + return "r14"; + case UNW_PPC_R15: + return "r15"; + case UNW_PPC_R16: + return "r16"; + case UNW_PPC_R17: + return "r17"; + case UNW_PPC_R18: + return "r18"; + case UNW_PPC_R19: + return "r19"; + case UNW_PPC_R20: + return "r20"; + case UNW_PPC_R21: + return "r21"; + case UNW_PPC_R22: + return "r22"; + case UNW_PPC_R23: + return "r23"; + case UNW_PPC_R24: + return "r24"; + case UNW_PPC_R25: + return "r25"; + case UNW_PPC_R26: + return "r26"; + case UNW_PPC_R27: + return "r27"; + case UNW_PPC_R28: + return "r28"; + case UNW_PPC_R29: + return "r29"; + case UNW_PPC_R30: + return "r30"; + case UNW_PPC_R31: + return "r31"; + case UNW_PPC_F0: + return "fp0"; + case UNW_PPC_F1: + return "fp1"; + case UNW_PPC_F2: + return "fp2"; + case UNW_PPC_F3: + return "fp3"; + case UNW_PPC_F4: + return "fp4"; + case UNW_PPC_F5: + return "fp5"; + case UNW_PPC_F6: + return "fp6"; + case UNW_PPC_F7: + return "fp7"; + case UNW_PPC_F8: + return "fp8"; + case UNW_PPC_F9: + return "fp9"; + case UNW_PPC_F10: + return "fp10"; + case UNW_PPC_F11: + return "fp11"; + case UNW_PPC_F12: + return "fp12"; + case UNW_PPC_F13: + return "fp13"; + case UNW_PPC_F14: + return "fp14"; + case UNW_PPC_F15: + return "fp15"; + case UNW_PPC_F16: + return "fp16"; + case UNW_PPC_F17: + return "fp17"; + case UNW_PPC_F18: + return "fp18"; + case UNW_PPC_F19: + return "fp19"; + case UNW_PPC_F20: + return "fp20"; + case UNW_PPC_F21: + return "fp21"; + case UNW_PPC_F22: + return "fp22"; + case UNW_PPC_F23: + return "fp23"; + case UNW_PPC_F24: + return "fp24"; + case UNW_PPC_F25: + return "fp25"; + case UNW_PPC_F26: + return "fp26"; + case UNW_PPC_F27: + return "fp27"; + case UNW_PPC_F28: + return "fp28"; + case UNW_PPC_F29: + return "fp29"; + case UNW_PPC_F30: + return "fp30"; + case UNW_PPC_F31: + return "fp31"; + case UNW_PPC_LR: + return "lr"; + default: + return "unknown register"; + } + +} + + +/// Registers_arm64 holds the register state of a thread in a 64-bit arm +/// process. +class _LIBUNWIND_HIDDEN Registers_arm64 { +public: + Registers_arm64(); + Registers_arm64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + + uint64_t getSP() const { return _registers.__sp; } + void setSP(uint64_t value) { _registers.__sp = value; } + uint64_t getIP() const { return _registers.__pc; } + void setIP(uint64_t value) { _registers.__pc = value; } + uint64_t getFP() const { return _registers.__fp; } + void setFP(uint64_t value) { _registers.__fp = value; } + +private: + struct GPRs { + uint64_t __x[29]; // x0-x28 + uint64_t __fp; // Frame pointer x29 + uint64_t __lr; // Link register x30 + uint64_t __sp; // Stack pointer x31 + uint64_t __pc; // Program counter + uint64_t padding; // 16-byte align + }; + + GPRs _registers; + double _vectorHalfRegisters[32]; + // Currently only the lower double in 128-bit vectore registers + // is perserved during unwinding. We could define new register + // numbers (> 96) which mean whole vector registers, then this + // struct would need to change to contain whole vector registers. +}; + +inline Registers_arm64::Registers_arm64(const void *registers) { + static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t), + "arm64 registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); + memcpy(_vectorHalfRegisters, (((char *)registers) + 0x110), + sizeof(_vectorHalfRegisters)); +} + +inline Registers_arm64::Registers_arm64() { + bzero(&_registers, sizeof(_registers)); + bzero(&_vectorHalfRegisters, sizeof(_vectorHalfRegisters)); +} + +inline bool Registers_arm64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum > 95) + return false; + if ((regNum > 31) && (regNum < 64)) + return false; + return true; +} + +inline uint64_t Registers_arm64::getRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return _registers.__pc; + if (regNum == UNW_REG_SP) + return _registers.__sp; + if ((regNum >= 0) && (regNum < 32)) + return _registers.__x[regNum]; + _LIBUNWIND_ABORT("unsupported arm64 register"); +} + +inline void Registers_arm64::setRegister(int regNum, uint64_t value) { + if (regNum == UNW_REG_IP) + _registers.__pc = value; + else if (regNum == UNW_REG_SP) + _registers.__sp = value; + else if ((regNum >= 0) && (regNum < 32)) + _registers.__x[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported arm64 register"); +} + +inline const char *Registers_arm64::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + return "pc"; + case UNW_REG_SP: + return "sp"; + case UNW_ARM64_X0: + return "x0"; + case UNW_ARM64_X1: + return "x1"; + case UNW_ARM64_X2: + return "x2"; + case UNW_ARM64_X3: + return "x3"; + case UNW_ARM64_X4: + return "x4"; + case UNW_ARM64_X5: + return "x5"; + case UNW_ARM64_X6: + return "x6"; + case UNW_ARM64_X7: + return "x7"; + case UNW_ARM64_X8: + return "x8"; + case UNW_ARM64_X9: + return "x9"; + case UNW_ARM64_X10: + return "x10"; + case UNW_ARM64_X11: + return "x11"; + case UNW_ARM64_X12: + return "x12"; + case UNW_ARM64_X13: + return "x13"; + case UNW_ARM64_X14: + return "x14"; + case UNW_ARM64_X15: + return "x15"; + case UNW_ARM64_X16: + return "x16"; + case UNW_ARM64_X17: + return "x17"; + case UNW_ARM64_X18: + return "x18"; + case UNW_ARM64_X19: + return "x19"; + case UNW_ARM64_X20: + return "x20"; + case UNW_ARM64_X21: + return "x21"; + case UNW_ARM64_X22: + return "x22"; + case UNW_ARM64_X23: + return "x23"; + case UNW_ARM64_X24: + return "x24"; + case UNW_ARM64_X25: + return "x25"; + case UNW_ARM64_X26: + return "x26"; + case UNW_ARM64_X27: + return "x27"; + case UNW_ARM64_X28: + return "x28"; + case UNW_ARM64_X29: + return "fp"; + case UNW_ARM64_X30: + return "lr"; + case UNW_ARM64_X31: + return "sp"; + case UNW_ARM64_D0: + return "d0"; + case UNW_ARM64_D1: + return "d1"; + case UNW_ARM64_D2: + return "d2"; + case UNW_ARM64_D3: + return "d3"; + case UNW_ARM64_D4: + return "d4"; + case UNW_ARM64_D5: + return "d5"; + case UNW_ARM64_D6: + return "d6"; + case UNW_ARM64_D7: + return "d7"; + case UNW_ARM64_D8: + return "d8"; + case UNW_ARM64_D9: + return "d9"; + case UNW_ARM64_D10: + return "d10"; + case UNW_ARM64_D11: + return "d11"; + case UNW_ARM64_D12: + return "d12"; + case UNW_ARM64_D13: + return "d13"; + case UNW_ARM64_D14: + return "d14"; + case UNW_ARM64_D15: + return "d15"; + case UNW_ARM64_D16: + return "d16"; + case UNW_ARM64_D17: + return "d17"; + case UNW_ARM64_D18: + return "d18"; + case UNW_ARM64_D19: + return "d19"; + case UNW_ARM64_D20: + return "d20"; + case UNW_ARM64_D21: + return "d21"; + case UNW_ARM64_D22: + return "d22"; + case UNW_ARM64_D23: + return "d23"; + case UNW_ARM64_D24: + return "d24"; + case UNW_ARM64_D25: + return "d25"; + case UNW_ARM64_D26: + return "d26"; + case UNW_ARM64_D27: + return "d27"; + case UNW_ARM64_D28: + return "d28"; + case UNW_ARM64_D29: + return "d29"; + case UNW_ARM64_D30: + return "d30"; + case UNW_ARM64_D31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_arm64::validFloatRegister(int regNum) const { + if (regNum < UNW_ARM64_D0) + return false; + if (regNum > UNW_ARM64_D31) + return false; + return true; +} + +inline double Registers_arm64::getFloatRegister(int regNum) const { + assert(validFloatRegister(regNum)); + return _vectorHalfRegisters[regNum - UNW_ARM64_D0]; +} + +inline void Registers_arm64::setFloatRegister(int regNum, double value) { + assert(validFloatRegister(regNum)); + _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value; +} + +inline bool Registers_arm64::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm64::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} + +inline void Registers_arm64::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no arm64 vector register support yet"); +} + +/// Registers_arm holds the register state of a thread in a 32-bit arm +/// process. +/// +/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit, +/// this uses more memory than required. +/// +/// FIXME: Support MMX Data Registers, Control registers, and load/stores +/// for different representations in the VFP registers as listed in +/// Table 1 of EHABI #7.5.2 +class _LIBUNWIND_HIDDEN Registers_arm { +public: + Registers_arm(); + Registers_arm(const void *registers); + + bool validRegister(int num) const; + uint32_t getRegister(int num) const; + void setRegister(int num, uint32_t value); + // FIXME: Due to ARM VRS's support for reading/writing different + // representations into the VFP registers this set of accessors seem wrong. + // If {get,set}FloatRegister() is the backing store for + // _Unwind_VRS_{Get,Set} then it might be best to return a tagged union + // with types for each representation in _Unwind_VRS_DataRepresentation. + // Similarly, unw_{get,set}_fpreg in the public libunwind API may want to + // use a similar tagged union to back the unw_fpreg_t output parameter type. + bool validFloatRegister(int num) const; + unw_fpreg_t getFloatRegister(int num) const; + void setFloatRegister(int num, unw_fpreg_t value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + + uint32_t getSP() const { return _registers.__sp; } + void setSP(uint32_t value) { _registers.__sp = value; } + uint32_t getIP() const { return _registers.__pc; } + void setIP(uint32_t value) { _registers.__pc = value; } + +private: + struct GPRs { + uint32_t __r[13]; // r0-r12 + uint32_t __sp; // Stack pointer r13 + uint32_t __lr; // Link register r14 + uint32_t __pc; // Program counter r15 + }; + + GPRs _registers; +}; + +inline Registers_arm::Registers_arm(const void *registers) { + static_assert(sizeof(Registers_arm) < sizeof(unw_context_t), + "arm registers do not fit into unw_context_t"); + memcpy(&_registers, registers, sizeof(_registers)); +} + +inline Registers_arm::Registers_arm() { + bzero(&_registers, sizeof(_registers)); +} + +inline bool Registers_arm::validRegister(int regNum) const { + // Returns true for all non-VFP registers supported by the EHABI + // virtual register set (VRS). + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R15)) + return true; + return false; +} + +inline uint32_t Registers_arm::getRegister(int regNum) const { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + return _registers.__sp; + if (regNum == UNW_ARM_LR) + return _registers.__lr; + if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + return _registers.__pc; + if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12)) + return _registers.__r[regNum]; + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline void Registers_arm::setRegister(int regNum, uint32_t value) { + if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) + _registers.__sp = value; + else if (regNum == UNW_ARM_LR) + _registers.__lr = value; + else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) + _registers.__pc = value; + else if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12)) + _registers.__r[regNum] = value; + else + _LIBUNWIND_ABORT("unsupported arm register"); +} + +inline const char *Registers_arm::getRegisterName(int regNum) { + switch (regNum) { + case UNW_REG_IP: + case UNW_ARM_IP: // UNW_ARM_R15 is alias + return "pc"; + case UNW_ARM_LR: // UNW_ARM_R14 is alias + return "lr"; + case UNW_REG_SP: + case UNW_ARM_SP: // UNW_ARM_R13 is alias + return "sp"; + case UNW_ARM_R0: + return "r0"; + case UNW_ARM_R1: + return "r1"; + case UNW_ARM_R2: + return "r2"; + case UNW_ARM_R3: + return "r3"; + case UNW_ARM_R4: + return "r4"; + case UNW_ARM_R5: + return "r5"; + case UNW_ARM_R6: + return "r6"; + case UNW_ARM_R7: + return "r7"; + case UNW_ARM_R8: + return "r8"; + case UNW_ARM_R9: + return "r9"; + case UNW_ARM_R10: + return "r10"; + case UNW_ARM_R11: + return "r11"; + case UNW_ARM_R12: + return "r12"; + case UNW_ARM_S0: + return "s0"; + case UNW_ARM_S1: + return "s1"; + case UNW_ARM_S2: + return "s2"; + case UNW_ARM_S3: + return "s3"; + case UNW_ARM_S4: + return "s4"; + case UNW_ARM_S5: + return "s5"; + case UNW_ARM_S6: + return "s6"; + case UNW_ARM_S7: + return "s7"; + case UNW_ARM_S8: + return "s8"; + case UNW_ARM_S9: + return "s9"; + case UNW_ARM_S10: + return "s10"; + case UNW_ARM_S11: + return "s11"; + case UNW_ARM_S12: + return "s12"; + case UNW_ARM_S13: + return "s13"; + case UNW_ARM_S14: + return "s14"; + case UNW_ARM_S15: + return "s15"; + case UNW_ARM_S16: + return "s16"; + case UNW_ARM_S17: + return "s17"; + case UNW_ARM_S18: + return "s18"; + case UNW_ARM_S19: + return "s19"; + case UNW_ARM_S20: + return "s20"; + case UNW_ARM_S21: + return "s21"; + case UNW_ARM_S22: + return "s22"; + case UNW_ARM_S23: + return "s23"; + case UNW_ARM_S24: + return "s24"; + case UNW_ARM_S25: + return "s25"; + case UNW_ARM_S26: + return "s26"; + case UNW_ARM_S27: + return "s27"; + case UNW_ARM_S28: + return "s28"; + case UNW_ARM_S29: + return "s29"; + case UNW_ARM_S30: + return "s30"; + case UNW_ARM_S31: + return "s31"; + case UNW_ARM_D0: + return "d0"; + case UNW_ARM_D1: + return "d1"; + case UNW_ARM_D2: + return "d2"; + case UNW_ARM_D3: + return "d3"; + case UNW_ARM_D4: + return "d4"; + case UNW_ARM_D5: + return "d5"; + case UNW_ARM_D6: + return "d6"; + case UNW_ARM_D7: + return "d7"; + case UNW_ARM_D8: + return "d8"; + case UNW_ARM_D9: + return "d9"; + case UNW_ARM_D10: + return "d10"; + case UNW_ARM_D11: + return "d11"; + case UNW_ARM_D12: + return "d12"; + case UNW_ARM_D13: + return "d13"; + case UNW_ARM_D14: + return "d14"; + case UNW_ARM_D15: + return "d15"; + case UNW_ARM_D16: + return "d16"; + case UNW_ARM_D17: + return "d17"; + case UNW_ARM_D18: + return "d18"; + case UNW_ARM_D19: + return "d19"; + case UNW_ARM_D20: + return "d20"; + case UNW_ARM_D21: + return "d21"; + case UNW_ARM_D22: + return "d22"; + case UNW_ARM_D23: + return "d23"; + case UNW_ARM_D24: + return "d24"; + case UNW_ARM_D25: + return "d25"; + case UNW_ARM_D26: + return "d26"; + case UNW_ARM_D27: + return "d27"; + case UNW_ARM_D28: + return "d28"; + case UNW_ARM_D29: + return "d29"; + case UNW_ARM_D30: + return "d30"; + case UNW_ARM_D31: + return "d31"; + default: + return "unknown register"; + } +} + +inline bool Registers_arm::validFloatRegister(int) const { + // FIXME: Implement float register support. + return false; +} + +inline unw_fpreg_t Registers_arm::getFloatRegister(int) const { + _LIBUNWIND_ABORT("ARM float register support not yet implemented"); +} + +inline void Registers_arm::setFloatRegister(int, unw_fpreg_t) { + _LIBUNWIND_ABORT("ARM float register support not yet implemented"); +} + +inline bool Registers_arm::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_arm::getVectorRegister(int) const { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} + +inline void Registers_arm::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("ARM vector support not implemented"); +} + +} // namespace libunwind + +#endif // __REGISTERS_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c b/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c new file mode 100644 index 00000000..f9256b5a --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c @@ -0,0 +1,468 @@ +//===--------------------------- Unwind-sjlj.c ----------------------------===// +// +// 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. +// +// +// Implements setjump-longjump based C++ exceptions +// +//===----------------------------------------------------------------------===// + +#include + +#include +#include +#include + +#include "config.h" +#include "unwind_ext.h" + +// +// 32-bit iOS uses setjump/longjump based C++ exceptions. +// Other architectures use "zero cost" exceptions. +// +// With SJLJ based exceptions, any function that has a catch clause or needs to +// do any clean up when an exception propagates through it, needs to call +// _Unwind_SjLj_Register() at the start of the function and +// _Unwind_SjLj_Unregister() at the end. The register function is called with +// the address of a block of memory in the function's stack frame. The runtime +// keeps a linked list (stack) of these blocks - one per thread. The calling +// function also sets the personality and lsda fields of the block. +// + +#if _LIBUNWIND_BUILD_SJLJ_APIS + +struct _Unwind_FunctionContext { + // next function in stack of handlers + struct _Unwind_FunctionContext *prev; + + // set by calling function before registering to be the landing pad + uintptr_t resumeLocation; + + // set by personality handler to be parameters passed to landing pad function + uintptr_t resumeParameters[4]; + + // set by calling function before registering + __personality_routine personality; // arm offset=24 + uintptr_t lsda; // arm offset=28 + + // variable length array, contains registers to restore + // 0 = r7, 1 = pc, 2 = sp + void *jbuf[]; +}; + + +/// Called at start of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) { + fc->prev = __Unwind_SjLj_GetTopOfFunctionStack(); + __Unwind_SjLj_SetTopOfFunctionStack(fc); +} + + +/// Called at end of each function that catches exceptions +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) { + __Unwind_SjLj_SetTopOfFunctionStack(fc->prev); +} + + +static _Unwind_Reason_Code +unwind_phase1(struct _Unwind_Exception *exception_object) { + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p\n", c); + + // walk each frame looking for a place to stop + for (bool handlerNotFound = true; handlerNotFound; c = c->prev) { + + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p\n", c); + // if there is a personality routine, ask it if it will want to stop at this + // frame + if (c->personality != NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling " + "personality function %p\n", + exception_object, c->personality); + _Unwind_Reason_Code personalityResult = (*c->personality)( + 1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember function context + handlerNotFound = false; + exception_object->private_2 = (uintptr_t) c; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_HANDLER_FOUND\n", exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_CONTINUE_UNWIND\n", exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + + +static _Unwind_Reason_Code +unwind_phase2(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); + + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n", + exception_object, c); + + // check for no more frames + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + _Unwind_Action action = _UA_CLEANUP_PHASE; + if ((uintptr_t) c == exception_object->private_2) + action = (_Unwind_Action)( + _UA_CLEANUP_PHASE | + _UA_HANDLER_FRAME); // tell personality this was the frame it marked + // in phase 1 + _Unwind_Reason_Code personalityResult = + (*c->personality)(1, action, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + exception_object); + if ((uintptr_t) c == exception_object->private_2) { + // phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now if phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): " + "_URC_INSTALL_CONTEXT, will resume at " + "landing pad %p\n", + exception_object, c->jbuf[1]); + // personality routine says to transfer control to landing pad + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + // unw_resume() only returns if there was an error + return _URC_FATAL_PHASE2_ERROR; + default: + // something went wrong + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; +} + + +static _Unwind_Reason_Code +unwind_phase2_forced(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + // walk each frame until we reach where search phase said to stop + _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack(); + while (true) { + + // get next frame (skip over first which is _Unwind_RaiseException) + if (c == NULL) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } + + // call stop function at each frame + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stop function returned %d\n", + exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "stopped by stop function\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // if there is a personality routine, tell it we are unwinding + if (c->personality != NULL) { + __personality_routine p = (__personality_routine) c->personality; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "calling personality function %p\n", + exception_object, p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_CONTINUE_UNWIND\n", + exception_object); + // destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_INSTALL_CONTEXT\n", + exception_object); + // we may get control back if landing pad calls _Unwind_Resume() + __Unwind_SjLj_SetTopOfFunctionStack(c); + __builtin_longjmp(c->jbuf, 1); + break; + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR\n", + exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + c = c->prev; + } + + // call stop function one last time and tell it we've reached the end of the + // stack + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK\n", + exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)c, stop_parameter); + + // clean up phase did not resume at the frame that the search phase said it + // would + return _URC_FATAL_PHASE2_ERROR; +} + + +/// Called by __cxa_throw. Only returns if there is a fatal error +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object); + + // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right + // thing + exception_object->private_1 = 0; + exception_object->private_2 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(exception_object); +} + + + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Re-throwing an exception is implemented by having the code call +/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow() +_LIBUNWIND_EXPORT void +_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object); + + if (exception_object->private_1 != 0) + unwind_phase2_forced(exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(exception_object); + + // clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return"); +} + + +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), " + "private_1=%ld\n", + exception_object, exception_object->private_1); + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception. + if (exception_object->private_1 == 0) { + return _Unwind_SjLj_RaiseException(exception_object); + // should return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate() + } + + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_SjLj_Resume(exception_object); + _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called " + "_Unwind_SjLj_Resume() which unexpectedly returned"); +} + + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) " + "=> 0x%0lX\n", context, ufc->lsda); + return ufc->lsda; +} + + +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, + int index) { + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)\n", + context, index); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + return ufc->resumeParameters[index]; +} + + +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n" + , context, index, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeParameters[index] = new_value; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context, + ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + *ipBefore = 0; + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n", + context, ipBefore, ufc->resumeLocation + 1); + return ufc->resumeLocation + 1; +} + + +/// Called by personality handler during phase 2 to alter instruction pointer. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n", + context, new_value); + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + ufc->resumeLocation = new_value - 1; +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)\n", context); + return 0; +} + + +/// Called by personality handler during phase 2 if a foreign exception +/// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + + + +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); +} + + +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + // Not supported or needed for sjlj based unwinding + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); +} + + +/// Called by personality handler to get "Call Frame Area" for current frame. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)\n", context); + if (context != NULL) { + _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; + // Setjmp/longjmp based exceptions don't have a true CFA. + // Instead, the SP in the jmpbuf is the closest approximation. + return (uintptr_t) ufc->jbuf[2]; + } + return 0; +} + +#endif // _LIBUNWIND_BUILD_SJLJ_APIS diff --git a/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp b/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp new file mode 100644 index 00000000..256a72da --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp @@ -0,0 +1,1063 @@ +//===------------------------- UnwindCursor.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. +// +// +// C++ interface to lower levels of libuwind +//===----------------------------------------------------------------------===// + +#ifndef __UNWINDCURSOR_HPP__ +#define __UNWINDCURSOR_HPP__ + +#include +#include +#include +#include + +#if __APPLE__ + #include +#endif + +#include "libunwind.h" + +#include "AddressSpace.hpp" +#include "Registers.hpp" +#include "DwarfInstructions.hpp" +#include "CompactUnwinder.hpp" +#include "config.h" + +namespace libunwind { + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +/// Cache of recently found FDEs. +template +class _LIBUNWIND_HIDDEN DwarfFDECache { + typedef typename A::pint_t pint_t; +public: + static pint_t findFDE(pint_t mh, pint_t pc); + static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde); + static void removeAllIn(pint_t mh); + static void iterateCacheEntries(void (*func)(unw_word_t ip_start, + unw_word_t ip_end, + unw_word_t fde, unw_word_t mh)); + +private: + + struct entry { + pint_t mh; + pint_t ip_start; + pint_t ip_end; + pint_t fde; + }; + + // These fields are all static to avoid needing an initializer. + // There is only one instance of this class per process. + static pthread_rwlock_t _lock; +#if __APPLE__ + static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide); + static bool _registeredForDyldUnloads; +#endif + // Can't use std::vector<> here because this code is below libc++. + static entry *_buffer; + static entry *_bufferUsed; + static entry *_bufferEnd; + static entry _initialBuffer[64]; +}; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_buffer = _initialBuffer; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_bufferUsed = _initialBuffer; + +template +typename DwarfFDECache::entry * +DwarfFDECache::_bufferEnd = &_initialBuffer[64]; + +template +typename DwarfFDECache::entry DwarfFDECache::_initialBuffer[64]; + +template +pthread_rwlock_t DwarfFDECache::_lock = PTHREAD_RWLOCK_INITIALIZER; + +#if __APPLE__ +template +bool DwarfFDECache::_registeredForDyldUnloads = false; +#endif + +template +typename A::pint_t DwarfFDECache::findFDE(pint_t mh, pint_t pc) { + pint_t result = 0; + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock)); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + if ((mh == p->mh) || (mh == 0)) { + if ((p->ip_start <= pc) && (pc < p->ip_end)) { + result = p->fde; + break; + } + } + } + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); + return result; +} + +template +void DwarfFDECache::add(pint_t mh, pint_t ip_start, pint_t ip_end, + pint_t fde) { + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + if (_bufferUsed >= _bufferEnd) { + size_t oldSize = (size_t)(_bufferEnd - _buffer); + size_t newSize = oldSize * 4; + // Can't use operator new (we are below it). + entry *newBuffer = (entry *)malloc(newSize * sizeof(entry)); + memcpy(newBuffer, _buffer, oldSize * sizeof(entry)); + if (_buffer != _initialBuffer) + free(_buffer); + _buffer = newBuffer; + _bufferUsed = &newBuffer[oldSize]; + _bufferEnd = &newBuffer[newSize]; + } + _bufferUsed->mh = mh; + _bufferUsed->ip_start = ip_start; + _bufferUsed->ip_end = ip_end; + _bufferUsed->fde = fde; + ++_bufferUsed; +#if __APPLE__ + if (!_registeredForDyldUnloads) { + _dyld_register_func_for_remove_image(&dyldUnloadHook); + _registeredForDyldUnloads = true; + } +#endif + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); +} + +template +void DwarfFDECache::removeAllIn(pint_t mh) { + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + entry *d = _buffer; + for (const entry *s = _buffer; s < _bufferUsed; ++s) { + if (s->mh != mh) { + if (d != s) + *d = *s; + ++d; + } + } + _bufferUsed = d; + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); +} + +template +void DwarfFDECache::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { + removeAllIn((pint_t) mh); +} + +template +void DwarfFDECache::iterateCacheEntries(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock)); + for (entry *p = _buffer; p < _bufferUsed; ++p) { + (*func)(p->ip_start, p->ip_end, p->fde, p->mh); + } + _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock)); +} +#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND + + +#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field)) + +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +template class UnwindSectionHeader { +public: + UnwindSectionHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t version() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, version)); + } + uint32_t commonEncodingsArraySectionOffset() const { + return _addressSpace.get32(_addr + + offsetof(unwind_info_section_header, + commonEncodingsArraySectionOffset)); + } + uint32_t commonEncodingsArrayCount() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + commonEncodingsArrayCount)); + } + uint32_t personalityArraySectionOffset() const { + return _addressSpace.get32(_addr + offsetof(unwind_info_section_header, + personalityArraySectionOffset)); + } + uint32_t personalityArrayCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, personalityArrayCount)); + } + uint32_t indexSectionOffset() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexSectionOffset)); + } + uint32_t indexCount() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_section_header, indexCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionIndexArray { +public: + UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + functionOffset)); + } + uint32_t secondLevelPagesSectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + secondLevelPagesSectionOffset)); + } + uint32_t lsdaIndexArraySectionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_index_entry, index, + lsdaIndexArraySectionOffset)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionRegularPageHeader { +public: + UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + offsetof(unwind_info_regular_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_regular_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_regular_second_level_page_header, entryCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionRegularArray { +public: + UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index, + functionOffset)); + } + uint32_t encoding(uint32_t index) const { + return _addressSpace.get32( + _addr + + arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionCompressedPageHeader { +public: + UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t kind() const { + return _addressSpace.get32( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, kind)); + } + uint16_t entryPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + entryPageOffset)); + } + uint16_t entryCount() const { + return _addressSpace.get16( + _addr + + offsetof(unwind_info_compressed_second_level_page_header, entryCount)); + } + uint16_t encodingsPageOffset() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsPageOffset)); + } + uint16_t encodingsCount() const { + return _addressSpace.get16( + _addr + offsetof(unwind_info_compressed_second_level_page_header, + encodingsCount)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionCompressedArray { +public: + UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } + uint16_t encodingIndex(uint32_t index) const { + return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX( + _addressSpace.get32(_addr + index * sizeof(uint32_t))); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; + +template class UnwindSectionLsdaArray { +public: + UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr) + : _addressSpace(addressSpace), _addr(addr) {} + + uint32_t functionOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, functionOffset)); + } + uint32_t lsdaOffset(uint32_t index) const { + return _addressSpace.get32( + _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry, + index, lsdaOffset)); + } + +private: + A &_addressSpace; + typename A::pint_t _addr; +}; +#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND + + +class _LIBUNWIND_HIDDEN AbstractUnwindCursor { +public: + virtual bool validReg(int) = 0; + virtual unw_word_t getReg(int) = 0; + virtual void setReg(int, unw_word_t) = 0; + virtual bool validFloatReg(int) = 0; + virtual double getFloatReg(int) = 0; + virtual void setFloatReg(int, double) = 0; + virtual int step() = 0; + virtual void getInfo(unw_proc_info_t *) = 0; + virtual void jumpto() = 0; + virtual bool isSignalFrame() = 0; + virtual bool getFunctionName(char *bf, size_t ln, unw_word_t *off) = 0; + virtual void setInfoBasedOnIPRegister(bool isReturnAddr = false) = 0; + virtual const char *getRegisterName(int num) = 0; +}; + + +/// UnwindCursor contains all state (including all register values) during +/// an unwind. This is normally stack allocated inside a unw_cursor_t. +template +class UnwindCursor : public AbstractUnwindCursor{ + typedef typename A::pint_t pint_t; +public: + UnwindCursor(unw_context_t *context, A &as); + UnwindCursor(A &as, void *threadArg); + virtual ~UnwindCursor() {} + virtual bool validReg(int); + virtual unw_word_t getReg(int); + virtual void setReg(int, unw_word_t); + virtual bool validFloatReg(int); + virtual double getFloatReg(int); + virtual void setFloatReg(int, double); + virtual int step(); + virtual void getInfo(unw_proc_info_t *); + virtual void jumpto(); + virtual bool isSignalFrame(); + virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off); + virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false); + virtual const char *getRegisterName(int num); + + void operator delete(void *, size_t) {} + +private: + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND + bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint=0); + int stepWithDwarfFDE() { + return DwarfInstructions::stepWithDwarf(_addressSpace, + (pint_t)this->getReg(UNW_REG_IP), + (pint_t)_info.unwind_info, + _registers); + } +#endif + +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND + bool getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s); + int stepWithCompactEncoding() { + #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + if ( compactSaysUseDwarf() ) + return stepWithDwarfFDE(); + #endif + R dummy; + return stepWithCompactEncoding(dummy); + } + + int stepWithCompactEncoding(Registers_x86_64 &) { + return CompactUnwinder_x86_64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } + + int stepWithCompactEncoding(Registers_x86 &) { + return CompactUnwinder_x86::stepWithCompactEncoding( + _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); + } + + int stepWithCompactEncoding(Registers_ppc &) { + return UNW_EINVAL; + } + + int stepWithCompactEncoding(Registers_arm64 &) { + return CompactUnwinder_arm64::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } + + bool compactSaysUseDwarf(uint32_t *offset=NULL) const { + R dummy; + return compactSaysUseDwarf(dummy, offset); + } + + bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } + + bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const { + if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET); + return true; + } + return false; + } + + bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const { + return true; + } + + bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const { + if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) { + if (offset) + *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET); + return true; + } + return false; + } + + compact_unwind_encoding_t dwarfEncoding() const { + R dummy; + return dwarfEncoding(dummy); + } + + compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const { + return UNWIND_X86_64_MODE_DWARF; + } + + compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const { + return UNWIND_X86_MODE_DWARF; + } + + compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const { + return 0; + } + + compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const { + return UNWIND_ARM64_MODE_DWARF; + } +#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND + + + A &_addressSpace; + R _registers; + unw_proc_info_t _info; + bool _unwindInfoMissing; + bool _isSignalFrame; +}; + + +template +UnwindCursor::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _registers(context), _unwindInfoMissing(false), + _isSignalFrame(false) { + static_assert(sizeof(UnwindCursor) < sizeof(unw_cursor_t), + "UnwindCursor<> does not fit in unw_cursor_t"); + + bzero(&_info, sizeof(_info)); +} + +template +UnwindCursor::UnwindCursor(A &as, void *) + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + bzero(&_info, sizeof(_info)); + // FIXME + // fill in _registers from thread arg +} + + +template +bool UnwindCursor::validReg(int regNum) { + return _registers.validRegister(regNum); +} + +template +unw_word_t UnwindCursor::getReg(int regNum) { + return _registers.getRegister(regNum); +} + +template +void UnwindCursor::setReg(int regNum, unw_word_t value) { + _registers.setRegister(regNum, (typename A::pint_t)value); +} + +template +bool UnwindCursor::validFloatReg(int regNum) { + return _registers.validFloatRegister(regNum); +} + +template +double UnwindCursor::getFloatReg(int regNum) { + return _registers.getFloatRegister(regNum); +} + +template +void UnwindCursor::setFloatReg(int regNum, double value) { + _registers.setFloatRegister(regNum, value); +} + +template void UnwindCursor::jumpto() { + _registers.jumpto(); +} + +template +const char *UnwindCursor::getRegisterName(int regNum) { + return _registers.getRegisterName(regNum); +} + +template bool UnwindCursor::isSignalFrame() { + return _isSignalFrame; +} + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +template +bool UnwindCursor::getInfoFromDwarfSection(pint_t pc, + const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint) { + typename CFI_Parser::FDE_Info fdeInfo; + typename CFI_Parser::CIE_Info cieInfo; + bool foundFDE = false; + bool foundInCache = false; + // If compact encoding table gave offset into dwarf section, go directly there + if (fdeSectionOffsetHint != 0) { + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, + sects.dwarf_section + fdeSectionOffsetHint, + &fdeInfo, &cieInfo); + } +#if _LIBUNWIND_SUPPORT_DWARF_INDEX + if (!foundFDE && (sects.dwarf_index_section != 0)) { + // Have eh_frame_hdr section which is index into dwarf section. + // TO DO: implement index search + } +#endif + if (!foundFDE) { + // otherwise, search cache of previously found FDEs. + pint_t cachedFDE = DwarfFDECache::findFDE(sects.dso_base, pc); + if (cachedFDE != 0) { + foundFDE = + CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, + cachedFDE, &fdeInfo, &cieInfo); + foundInCache = foundFDE; + } + } + if (!foundFDE) { + // Still not found, do full scan of __eh_frame section. + foundFDE = CFI_Parser::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); + } + if (foundFDE) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc, + &prolog)) { + // Save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + _info.gp = prolog.spExtraArgSize; + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; + _info.extra = (unw_word_t) sects.dso_base; + + // Add to cache (to make next lookup faster) if we had no hint + // and there was no index. + if (!foundInCache && (fdeSectionOffsetHint == 0)) { + #if _LIBUNWIND_SUPPORT_DWARF_INDEX + if (sects.dwarf_index_section == 0) + #endif + DwarfFDECache::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } + return true; + } + } + //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc); + return false; +} +#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND + + +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND +template +bool UnwindCursor::getInfoFromCompactEncodingSection(pint_t pc, + const UnwindInfoSections §s) { + const bool log = false; + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n", + (uint64_t)pc, (uint64_t)sects.dso_base); + + const UnwindSectionHeader sectionHeader(_addressSpace, + sects.compact_unwind_section); + if (sectionHeader.version() != UNWIND_SECTION_VERSION) + return false; + + // do a binary search of top level index to find page with unwind info + pint_t targetFunctionOffset = pc - sects.dso_base; + const UnwindSectionIndexArray topIndex(_addressSpace, + sects.compact_unwind_section + + sectionHeader.indexSectionOffset()); + uint32_t low = 0; + uint32_t high = sectionHeader.indexCount(); + uint32_t last = high - 1; + while (low < high) { + uint32_t mid = (low + high) / 2; + //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n", + //mid, low, high, topIndex.functionOffset(mid)); + if (topIndex.functionOffset(mid) <= targetFunctionOffset) { + if ((mid == last) || + (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low); + const uint32_t firstLevelNextPageFunctionOffset = + topIndex.functionOffset(low + 1); + const pint_t secondLevelAddr = + sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low); + const pint_t lsdaArrayStartAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low); + const pint_t lsdaArrayEndAddr = + sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1); + if (log) + fprintf(stderr, "\tfirst level search for result index=%d " + "to secondLevelAddr=0x%llX\n", + low, (uint64_t) secondLevelAddr); + // do a binary search of second level page index + uint32_t encoding = 0; + pint_t funcStart = 0; + pint_t funcEnd = 0; + pint_t lsda = 0; + pint_t personality = 0; + uint32_t pageKind = _addressSpace.get32(secondLevelAddr); + if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) { + // regular page + UnwindSectionRegularPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionRegularArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in " + "regular page starting at secondLevelAddr=0x%llX\n", + (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr); + low = 0; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionOffset) { + if (mid == (uint32_t)(pageHeader.entryCount() - 1)) { + // at end of table + low = mid; + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + break; + } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) { + // next is too big, so we found it + low = mid; + funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + encoding = pageIndex.encoding(low); + funcStart = pageIndex.functionOffset(low) + sects.dso_base; + if (pc < funcStart) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + if (pc > funcEnd) { + if (log) + fprintf( + stderr, + "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd); + return false; + } + } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) { + // compressed page + UnwindSectionCompressedPageHeader pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionCompressedArray pageIndex( + _addressSpace, secondLevelAddr + pageHeader.entryPageOffset()); + const uint32_t targetFunctionPageOffset = + (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset); + // binary search looks for entry with e where index[e].offset <= pc < + // index[e+1].offset + if (log) + fprintf(stderr, "\tbinary search of compressed page starting at " + "secondLevelAddr=0x%llX\n", + (uint64_t) secondLevelAddr); + low = 0; + last = pageHeader.entryCount() - 1; + high = pageHeader.entryCount(); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) { + if ((mid == last) || + (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) { + low = mid; + break; + } else { + low = mid + 1; + } + } else { + high = mid; + } + } + funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset + + sects.dso_base; + if (low < last) + funcEnd = + pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset + + sects.dso_base; + else + funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base; + if (pc < funcStart) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " + "level compressed unwind table. funcStart=0x%llX\n", + (uint64_t) pc, (uint64_t) funcStart); + return false; + } + if (pc > funcEnd) { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second " + "level compressed unwind table. funcEnd=0x%llX\n", + (uint64_t) pc, (uint64_t) funcEnd); + return false; + } + uint16_t encodingIndex = pageIndex.encodingIndex(low); + if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) { + // encoding is in common table in section header + encoding = _addressSpace.get32( + sects.compact_unwind_section + + sectionHeader.commonEncodingsArraySectionOffset() + + encodingIndex * sizeof(uint32_t)); + } else { + // encoding is in page specific table + uint16_t pageEncodingIndex = + encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount(); + encoding = _addressSpace.get32(secondLevelAddr + + pageHeader.encodingsPageOffset() + + pageEncodingIndex * sizeof(uint32_t)); + } + } else { + _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second " + "level page\n", + (uint64_t) sects.compact_unwind_section); + return false; + } + + // look up LSDA, if encoding says function has one + if (encoding & UNWIND_HAS_LSDA) { + UnwindSectionLsdaArray lsdaIndex(_addressSpace, lsdaArrayStartAddr); + uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base); + low = 0; + high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) / + sizeof(unwind_info_section_header_lsda_index_entry); + // binary search looks for entry with exact match for functionOffset + if (log) + fprintf(stderr, + "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n", + funcStartOffset); + while (low < high) { + uint32_t mid = (low + high) / 2; + if (lsdaIndex.functionOffset(mid) == funcStartOffset) { + lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base; + break; + } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) { + low = mid + 1; + } else { + high = mid; + } + } + if (lsda == 0) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for " + "pc=0x%0llX, but lsda table has no entry\n", + encoding, (uint64_t) pc); + return false; + } + } + + // extact personality routine, if encoding says function has one + uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >> + (__builtin_ctz(UNWIND_PERSONALITY_MASK)); + if (personalityIndex != 0) { + --personalityIndex; // change 1-based to zero-based index + if (personalityIndex > sectionHeader.personalityArrayCount()) { + _LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, " + "but personality table has only %d entires\n", + encoding, personalityIndex, + sectionHeader.personalityArrayCount()); + return false; + } + uint32_t personalityDelta = _addressSpace.get32( + sects.compact_unwind_section + sectionHeader.personalityArraySectionOffset() + + personalityIndex * sizeof(uint32_t)); + pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta; + personality = _addressSpace.getP(personalityPointer); + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "personalityDelta=0x%08X, personality=0x%08llX\n", + (uint64_t) pc, personalityDelta, (uint64_t) personality); + } + + if (log) + fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), " + "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n", + (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart); + _info.start_ip = funcStart; + _info.end_ip = funcEnd; + _info.lsda = lsda; + _info.handler = personality; + _info.gp = 0; + _info.flags = 0; + _info.format = encoding; + _info.unwind_info = 0; + _info.unwind_info_size = 0; + _info.extra = sects.dso_base; + return true; +} +#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND + + +template +void UnwindCursor::setInfoBasedOnIPRegister(bool isReturnAddress) { + pint_t pc = (pint_t)this->getReg(UNW_REG_IP); + + // If the last line of a function is a "throw" the compiler sometimes + // emits no instructions after the call to __cxa_throw. This means + // the return address is actually the start of the next function. + // To disambiguate this, back up the pc when we know it is a return + // address. + if (isReturnAddress) + --pc; + + // Ask address space object to find unwind sections for this pc. + UnwindInfoSections sects; + if (_addressSpace.findUnwindSections(pc, sects)) { +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND + // If there is a compact unwind encoding table, look there first. + if (sects.compact_unwind_section != 0) { + if (this->getInfoFromCompactEncodingSection(pc, sects)) { + #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + // Found info in table, done unless encoding says to use dwarf. + uint32_t dwarfOffset; + if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) { + if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) { + // found info in dwarf, done + return; + } + } + #endif + // If unwind table has entry, but entry says there is no unwind info, + // record that we have no unwind info. + if (_info.format == 0) + _unwindInfoMissing = true; + return; + } + } +#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND + // If there is dwarf unwind info, look there next. + if (sects.dwarf_section != 0) { + if (this->getInfoFromDwarfSection(pc, sects)) { + // found info in dwarf, done + return; + } + } +#endif + } + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND + // There is no static unwind info for this pc. Look to see if an FDE was + // dynamically registered for it. + pint_t cachedFDE = DwarfFDECache::findFDE(0, pc); + if (cachedFDE != 0) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + const char *msg = CFI_Parser::decodeFDE(_addressSpace, + cachedFDE, &fdeInfo, &cieInfo); + if (msg == NULL) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, + pc, &prolog)) { + // save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + _info.gp = prolog.spExtraArgSize; + // Some frameless functions need SP + // altered when resuming in function. + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; + _info.extra = 0; + return; + } + } + } + + // Lastly, ask AddressSpace object about platform specific ways to locate + // other FDEs. + pint_t fde; + if (_addressSpace.findOtherFDE(pc, fde)) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + if (!CFI_Parser::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) { + // Double check this FDE is for a function that includes the pc. + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { + typename CFI_Parser::PrologInfo prolog; + if (CFI_Parser::parseFDEInstructions(_addressSpace, fdeInfo, + cieInfo, pc, &prolog)) { + // save off parsed FDE info + _info.start_ip = fdeInfo.pcStart; + _info.end_ip = fdeInfo.pcEnd; + _info.lsda = fdeInfo.lsda; + _info.handler = cieInfo.personality; + _info.gp = prolog.spExtraArgSize; + _info.flags = 0; + _info.format = dwarfEncoding(); + _info.unwind_info = fdeInfo.fdeStart; + _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength; + _info.extra = 0; + return; + } + } + } + } +#endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND + + // no unwind info, flag that we can't reliably unwind + _unwindInfoMissing = true; +} + +template +int UnwindCursor::step() { + // Bottom of stack is defined is when no unwind info cannot be found. + if (_unwindInfoMissing) + return UNW_STEP_END; + + // Use unwinding info to modify register set as if function returned. + int result; +#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND + result = this->stepWithCompactEncoding(); +#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND + result = this->stepWithDwarfFDE(); +#else + #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or _LIBUNWIND_SUPPORT_DWARF_UNWIND +#endif + + // update info based on new PC + if (result == UNW_STEP_SUCCESS) { + this->setInfoBasedOnIPRegister(true); + if (_unwindInfoMissing) + return UNW_STEP_END; + } + + return result; +} + +template +void UnwindCursor::getInfo(unw_proc_info_t *info) { + *info = _info; +} + +template +bool UnwindCursor::getFunctionName(char *buf, size_t bufLen, + unw_word_t *offset) { + return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP), + buf, bufLen, offset); +} + +}; // namespace libunwind + +#endif // __UNWINDCURSOR_HPP__ diff --git a/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c b/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c new file mode 100644 index 00000000..c84db76c --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c @@ -0,0 +1,268 @@ +//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===// +// +// 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. +// +// +// Implements gcc extensions to the C++ ABI Exception Handling Level 1. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#include "libunwind.h" +#include "unwind.h" +#include "libunwind_ext.h" +#include "config.h" + +#if _LIBUNWIND_BUILD_ZERO_COST_APIS + +/// Called by __cxa_rethrow(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), " + "private_1=%ld\n", + exception_object, exception_object->private_1); + // If this is non-forced and a stopping place was found, then this is a + // re-throw. + // Call _Unwind_RaiseException() as if this was a new exception + if (exception_object->private_1 == 0) { + return _Unwind_RaiseException(exception_object); + // Will return if there is no catch clause, so that __cxa_rethrow can call + // std::terminate(). + } + + // Call through to _Unwind_Resume() which distiguishes between forced and + // regular exceptions. + _Unwind_Resume(exception_object); + _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()" + " which unexpectedly returned"); +} + + +/// Called by personality handler during phase 2 to get base address for data +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetDataRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context); + _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented"); +} + + +/// Called by personality handler during phase 2 to get base address for text +/// relative encodings. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetTextRelBase(struct _Unwind_Context *context) { + (void)context; + _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context); + _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented"); +} + + +/// Scans unwind information to find the function that contains the +/// specified code address "pc". +_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) { + _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc); + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); + if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS) + return (void *)(long) info.start_ip; + else + return NULL; +} + + +/// Walk every frame and call trace function at each one. If trace function +/// returns anything other than _URC_NO_REASON, then walk is terminated. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) { + unw_cursor_t cursor; + unw_context_t uc; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + + _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n", callback); + + // walk each frame + while (true) { + + // ask libuwind to get next frame (skip over first frame which is + // _Unwind_Backtrace()) + if (unw_step(&cursor) <= 0) { + _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached " + "bottom of stack, returning %d\n", + _URC_END_OF_STACK); + return _URC_END_OF_STACK; + } + + // debugging + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_proc_info_t frameInfo; + unw_word_t offset; + unw_get_proc_name(&cursor, functionName, 512, &offset); + unw_get_proc_info(&cursor, &frameInfo); + _LIBUNWIND_TRACE_UNWINDING( + " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n", + frameInfo.start_ip, functionName, frameInfo.lsda, &cursor); + } + + // call trace function with this frame + _Unwind_Reason_Code result = + (*callback)((struct _Unwind_Context *)(&cursor), ref); + if (result != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because callback " + "returned %d\n", + result); + return result; + } + } +} + + +/// Find dwarf unwind info for an address 'pc' in some function. +_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc, + struct dwarf_eh_bases *bases) { + // This is slow, but works. + // We create an unwind cursor then alter the IP to be pc + unw_cursor_t cursor; + unw_context_t uc; + unw_proc_info_t info; + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc); + unw_get_proc_info(&cursor, &info); + bases->tbase = (uintptr_t)info.extra; + bases->dbase = 0; // dbase not used on Mac OS X + bases->func = (uintptr_t)info.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc, + (void *)(long) info.unwind_info); + return (void *)(long) info.unwind_info; +} + +/// Returns the CFA (call frame area, or stack pointer at start of function) +/// for the current context. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + unw_get_reg(cursor, UNW_REG_SP, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%llX\n", context, + (uint64_t) result); + return (uintptr_t)result; +} + + +/// Called by personality handler during phase 2 to get instruction pointer. +/// ipBefore is a boolean that says if IP is already adjusted to be the call +/// site address. Normally IP is the return address. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, + int *ipBefore) { + _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)\n", context); + *ipBefore = 0; + return _Unwind_GetIP(context); +} + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND + +/// Called by programs with dynamic code generators that want +/// to register a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __register_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__register_frame(%p)\n", fde); + _unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde); +} + + +/// Called by programs with dynamic code generators that want +/// to unregister a dynamically generated FDE. +/// This function has existed on Mac OS X since 10.4, but +/// was broken until 10.6. +_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) { + _LIBUNWIND_TRACE_API("__deregister_frame(%p)\n", fde); + _unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde); +} + + +// The following register/deregister functions are gcc extensions. +// They have existed on Mac OS X, but have never worked because Mac OS X +// before 10.6 used keymgr to track known FDEs, but these functions +// never got updated to use keymgr. +// For now, we implement these as do-nothing functions to keep any existing +// applications working. We also add the not in 10.6 symbol so that nwe +// application won't be able to use them. + +#if _LIBUNWIND_SUPPORT_FRAME_APIS +_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob, + void *tb, void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)\n", + fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)\n", fde, ob); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde, + void *ob, void *tb, + void *db) { + (void)fde; + (void)ob; + (void)tb; + (void)db; + _LIBUNWIND_TRACE_API("__register_frame_info_table_bases" + "(%p,%p, %p, %p)\n", fde, ob, tb, db); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) { + (void)fde; + (void)ob; + _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)\n", fde, ob); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__register_frame_table(%p)\n", fde); + // do nothing, this function never worked in Mac OS X +} + +_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)\n", fde); + // do nothing, this function never worked in Mac OS X + return NULL; +} + +_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) { + (void)fde; + _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)\n", fde); + // do nothing, this function never worked in Mac OS X + return NULL; +} +#endif // _LIBUNWIND_SUPPORT_FRAME_APIS + +#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND + +#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS diff --git a/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c b/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c new file mode 100644 index 00000000..b2e93c7e --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/UnwindLevel1.c @@ -0,0 +1,495 @@ +//===------------------------- UnwindLevel1.c -----------------------------===// +// +// 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. +// +// +// Implements C++ ABI Exception Handling Level 1 as documented at: +// http://mentorembedded.github.io/cxx-abi/abi-eh.html +// using libunwind +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + +#include "libunwind.h" +#include "unwind.h" +#include "config.h" + +#if _LIBUNWIND_BUILD_ZERO_COST_APIS + +static _Unwind_Reason_Code +unwind_phase1(unw_context_t *uc, struct _Unwind_Exception *exception_object) { + unw_cursor_t cursor1; + unw_init_local(&cursor1, uc); + + // Walk each frame looking for a place to stop. + for (bool handlerNotFound = true; handlerNotFound;) { + + // Ask libuwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = unw_step(&cursor1); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => " + "_URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // See if frame has code to run (has personality routine). + unw_proc_info_t frameInfo; + unw_word_t sp; + if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_word_t offset; + if ((unw_get_proc_name(&cursor1, functionName, 512, &offset) != + UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) + strcpy(functionName, ".anonymous."); + unw_word_t pc; + unw_get_reg(&cursor1, UNW_REG_IP, &pc); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, " + "lsda=0x%llX, personality=0x%llX\n", + exception_object, pc, frameInfo.start_ip, functionName, + frameInfo.lsda, frameInfo.handler); + } + + // If there is a personality routine, ask it if it will want to stop at + // this frame. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(long)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): calling personality function %p\n", + exception_object, p); + _Unwind_Reason_Code personalityResult = + (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class, + exception_object, (struct _Unwind_Context *)(&cursor1)); + switch (personalityResult) { + case _URC_HANDLER_FOUND: + // found a catch clause or locals that need destructing in this frame + // stop search and remember stack pointer at the frame + handlerNotFound = false; + unw_get_reg(&cursor1, UNW_REG_SP, &sp); + exception_object->private_2 = (uintptr_t)sp; + _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): " + "_URC_HANDLER_FOUND \n", + exception_object); + return _URC_NO_REASON; + + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + exception_object); + // continue unwinding + break; + + default: + // something went wrong + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + } + } + return _URC_NO_REASON; +} + + +static _Unwind_Reason_Code +unwind_phase2(unw_context_t *uc, struct _Unwind_Exception *exception_object) { + unw_cursor_t cursor2; + unw_init_local(&cursor2, uc); + + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object); + + // Walk each frame until we reach where search phase said to stop. + while (true) { + + // Ask libuwind to get next frame (skip over first which is + // _Unwind_RaiseException). + int stepResult = unw_step(&cursor2); + if (stepResult == 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached " + "bottom => _URC_END_OF_STACK\n", + exception_object); + return _URC_END_OF_STACK; + } else if (stepResult < 0) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => " + "_URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // Get info about this frame. + unw_word_t sp; + unw_proc_info_t frameInfo; + unw_get_reg(&cursor2, UNW_REG_SP, &sp); + if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info " + "failed => _URC_FATAL_PHASE1_ERROR\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_word_t offset; + if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != + UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) + strcpy(functionName, ".anonymous."); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, " + "lsda=0x%llX, personality=0x%llX\n", + exception_object, frameInfo.start_ip, functionName, sp, + frameInfo.lsda, frameInfo.handler); + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(long)(frameInfo.handler); + _Unwind_Action action = _UA_CLEANUP_PHASE; + if (sp == exception_object->private_2) { + // Tell personality this was the frame it marked in phase 1. + action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME); + } + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + // Continue unwinding + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n", + exception_object); + if (sp == exception_object->private_2) { + // Phase 1 said we would stop at this frame, but we did not... + _LIBUNWIND_ABORT("during phase1 personality function said it would " + "stop here, but now if phase2 it did not stop here"); + } + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n", + exception_object); + // Personality routine says to transfer control to landing pad. + // We may get control back if landing pad calls _Unwind_Resume(). + if (_LIBUNWIND_TRACING_UNWINDING) { + unw_word_t pc; + unw_get_reg(&cursor2, UNW_REG_IP, &pc); + unw_get_reg(&cursor2, UNW_REG_SP, &sp); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering " + "user code with ip=0x%llX, sp=0x%llX\n", + exception_object, pc, sp); + } + unw_resume(&cursor2); + // unw_resume() only returns if there was an error. + return _URC_FATAL_PHASE2_ERROR; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d", + personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Clean up phase did not resume at the frame that the search phase + // said it would... + return _URC_FATAL_PHASE2_ERROR; +} + +static _Unwind_Reason_Code +unwind_phase2_forced(unw_context_t *uc, + struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + unw_cursor_t cursor2; + unw_init_local(&cursor2, uc); + + // Walk each frame until we reach where search phase said to stop + while (unw_step(&cursor2) > 0) { + + // Update info about this frame. + unw_proc_info_t frameInfo; + if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) { + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step " + "failed => _URC_END_OF_STACK\n", + exception_object); + return _URC_FATAL_PHASE1_ERROR; + } + + // When tracing, print state information. + if (_LIBUNWIND_TRACING_UNWINDING) { + char functionName[512]; + unw_word_t offset; + if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) != + UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip)) + strcpy(functionName, ".anonymous."); + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "start_ip=0x%llX, func=%s, lsda=0x%llX, " + " personality=0x%llX\n", + exception_object, frameInfo.start_ip, + functionName, frameInfo.lsda, + frameInfo.handler); + } + + // Call stop function at each frame. + _Unwind_Action action = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE); + _Unwind_Reason_Code stopResult = + (*stop)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n", + exception_object, stopResult); + if (stopResult != _URC_NO_REASON) { + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n", + exception_object); + return _URC_FATAL_PHASE2_ERROR; + } + + // If there is a personality routine, tell it we are unwinding. + if (frameInfo.handler != 0) { + __personality_routine p = + (__personality_routine)(long)(frameInfo.handler); + _LIBUNWIND_TRACE_UNWINDING( + "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n", + exception_object, p); + _Unwind_Reason_Code personalityResult = + (*p)(1, action, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2)); + switch (personalityResult) { + case _URC_CONTINUE_UNWIND: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_CONTINUE_UNWIND\n", + exception_object); + // Destructors called, continue unwinding + break; + case _URC_INSTALL_CONTEXT: + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned _URC_INSTALL_CONTEXT\n", + exception_object); + // We may get control back if landing pad calls _Unwind_Resume(). + unw_resume(&cursor2); + break; + default: + // Personality routine returned an unknown result code. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): " + "personality returned %d, " + "_URC_FATAL_PHASE2_ERROR\n", + exception_object, personalityResult); + return _URC_FATAL_PHASE2_ERROR; + } + } + } + + // Call stop function one last time and tell it we've reached the end + // of the stack. + _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop " + "function with _UA_END_OF_STACK\n", + exception_object); + _Unwind_Action lastAction = + (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK); + (*stop)(1, lastAction, exception_object->exception_class, exception_object, + (struct _Unwind_Context *)(&cursor2), stop_parameter); + + // Clean up phase did not resume at the frame that the search phase said it + // would. + return _URC_FATAL_PHASE2_ERROR; +} + + +/// Called by __cxa_throw. Only returns if there is a fatal error. +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_RaiseException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n", + exception_object); + unw_context_t uc; + unw_getcontext(&uc); + + // Mark that this is a non-forced unwind, so _Unwind_Resume() + // can do the right thing. + exception_object->private_1 = 0; + exception_object->private_2 = 0; + + // phase 1: the search phase + _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object); + if (phase1 != _URC_NO_REASON) + return phase1; + + // phase 2: the clean up phase + return unwind_phase2(&uc, exception_object); +} + + + +/// When _Unwind_RaiseException() is in phase2, it hands control +/// to the personality function at each frame. The personality +/// may force a jump to a landing pad in that function, the landing +/// pad code may then call _Unwind_Resume() to continue with the +/// unwinding. Note: the call to _Unwind_Resume() is from compiler +/// geneated user code. All other _Unwind_* routines are called +/// by the C++ runtime __cxa_* routines. +/// +/// Note: re-throwing an exception (as opposed to continuing the unwind) +/// is implemented by having the code call __cxa_rethrow() which +/// in turn calls _Unwind_Resume_or_Rethrow(). +_LIBUNWIND_EXPORT void +_Unwind_Resume(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", exception_object); + unw_context_t uc; + unw_getcontext(&uc); + + if (exception_object->private_1 != 0) + unwind_phase2_forced(&uc, exception_object, + (_Unwind_Stop_Fn) exception_object->private_1, + (void *)exception_object->private_2); + else + unwind_phase2(&uc, exception_object); + + // Clients assume _Unwind_Resume() does not return, so all we can do is abort. + _LIBUNWIND_ABORT("_Unwind_Resume() can't return"); +} + + + +/// Not used by C++. +/// Unwinds stack, calling "stop" function at each frame. +/// Could be used to implement longjmp(). +_LIBUNWIND_EXPORT _Unwind_Reason_Code +_Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object, + _Unwind_Stop_Fn stop, void *stop_parameter) { + _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n", + exception_object, stop); + unw_context_t uc; + unw_getcontext(&uc); + + // Mark that this is a forced unwind, so _Unwind_Resume() can do + // the right thing. + exception_object->private_1 = (uintptr_t) stop; + exception_object->private_2 = (uintptr_t) stop_parameter; + + // do it + return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter); +} + + +/// Called by personality handler during phase 2 to get LSDA for current frame. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.lsda; + _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p)" + "=> 0x%lX\n", context, result); + if (result != 0) { + if (*((uint8_t *)result) != 0xFF) + _LIBUNWIND_DEBUG_LOG("lsda at 0x%lX does not start with 0xFF\n", result); + } + return result; +} + + + +/// Called by personality handler during phase 2 to get register values. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, + int index) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + unw_get_reg(cursor, index, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%llX\n", + context, + index, (uint64_t) result); + return (uintptr_t)result; +} + + + +/// Called by personality handler during phase 2 to alter register values. +_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, " + "value=0x%0llX)\n", context, + index, (uint64_t) new_value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_set_reg(cursor, index, new_value); +} + + + +/// Called by personality handler during phase 2 to get instruction pointer. +_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_word_t result; + unw_get_reg(cursor, UNW_REG_IP, &result); + _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%llX\n", context, + (uint64_t) result); + return (uintptr_t)result; +} + + + +/// Called by personality handler during phase 2 to alter instruction pointer, +/// such as setting where the landing pad is, so _Unwind_Resume() will +/// start executing in the landing pad. +_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, + uintptr_t new_value) { + _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n", + context, (uint64_t) new_value); + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_set_reg(cursor, UNW_REG_IP, new_value); +} + + +/// Called by personality handler during phase 2 to find the start of the +/// function. +_LIBUNWIND_EXPORT uintptr_t +_Unwind_GetRegionStart(struct _Unwind_Context *context) { + unw_cursor_t *cursor = (unw_cursor_t *)context; + unw_proc_info_t frameInfo; + uintptr_t result = 0; + if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS) + result = (uintptr_t)frameInfo.start_ip; + _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%lX\n", + context, result); + return result; +} + + +/// Called by personality handler during phase 2 if a foreign exception +// is caught. +_LIBUNWIND_EXPORT void +_Unwind_DeleteException(struct _Unwind_Exception *exception_object) { + _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n", + exception_object); + if (exception_object->exception_cleanup != NULL) + (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, + exception_object); +} + +#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS diff --git a/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S b/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S new file mode 100644 index 00000000..15e2072f --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S @@ -0,0 +1,329 @@ +//===-------------------- UnwindRegistersRestore.S ------------------------===// +// +// 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 "assembly.h" + + .text + +#if __i386__ +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv) +# +# void libunwind::Registers_x86::jumpto() +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + + movl 4(%esp), %eax + # set up eax and ret on new stack location + movl 28(%eax), %edx # edx holds new stack pointer + subl $8,%edx + movl %edx, 28(%eax) + movl 0(%eax), %ebx + movl %ebx, 0(%edx) + movl 40(%eax), %ebx + movl %ebx, 4(%edx) + # we now have ret and eax pushed onto where new stack will be + # restore all registers + movl 4(%eax), %ebx + movl 8(%eax), %ecx + movl 12(%eax), %edx + movl 16(%eax), %edi + movl 20(%eax), %esi + movl 24(%eax), %ebp + movl 28(%eax), %esp + # skip ss + # skip eflags + pop %eax # eax was already pushed on new stack + ret # eip was already pushed on new stack + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + +#elif __x86_64__ + +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv) +# +# void libunwind::Registers_x86_64::jumpto() +# +# On entry, thread_state pointer is in rdi + + movq 56(%rdi), %rax # rax holds new stack pointer + subq $16, %rax + movq %rax, 56(%rdi) + movq 32(%rdi), %rbx # store new rdi on new stack + movq %rbx, 0(%rax) + movq 128(%rdi), %rbx # store new rip on new stack + movq %rbx, 8(%rax) + # restore all registers + movq 0(%rdi), %rax + movq 8(%rdi), %rbx + movq 16(%rdi), %rcx + movq 24(%rdi), %rdx + # restore rdi later + movq 40(%rdi), %rsi + movq 48(%rdi), %rbp + # restore rsp later + movq 64(%rdi), %r8 + movq 72(%rdi), %r9 + movq 80(%rdi), %r10 + movq 88(%rdi), %r11 + movq 96(%rdi), %r12 + movq 104(%rdi), %r13 + movq 112(%rdi), %r14 + movq 120(%rdi), %r15 + # skip rflags + # skip cs + # skip fs + # skip gs + movq 56(%rdi), %rsp # cut back rsp to new location + pop %rdi # rdi was saved here earlier + ret # rip was saved here + + +#elif __ppc__ + +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv) +; +; void libunwind::Registers_ppc::jumpto() +; +; On entry: +; thread_state pointer is in r3 +; + + ; restore integral registerrs + ; skip r0 for now + ; skip r1 for now + lwz r2, 16(r3) + ; skip r3 for now + ; skip r4 for now + ; skip r5 for now + lwz r6, 32(r3) + lwz r7, 36(r3) + lwz r8, 40(r3) + lwz r9, 44(r3) + lwz r10, 48(r3) + lwz r11, 52(r3) + lwz r12, 56(r3) + lwz r13, 60(r3) + lwz r14, 64(r3) + lwz r15, 68(r3) + lwz r16, 72(r3) + lwz r17, 76(r3) + lwz r18, 80(r3) + lwz r19, 84(r3) + lwz r20, 88(r3) + lwz r21, 92(r3) + lwz r22, 96(r3) + lwz r23,100(r3) + lwz r24,104(r3) + lwz r25,108(r3) + lwz r26,112(r3) + lwz r27,116(r3) + lwz r28,120(r3) + lwz r29,124(r3) + lwz r30,128(r3) + lwz r31,132(r3) + + ; restore float registers + lfd f0, 160(r3) + lfd f1, 168(r3) + lfd f2, 176(r3) + lfd f3, 184(r3) + lfd f4, 192(r3) + lfd f5, 200(r3) + lfd f6, 208(r3) + lfd f7, 216(r3) + lfd f8, 224(r3) + lfd f9, 232(r3) + lfd f10,240(r3) + lfd f11,248(r3) + lfd f12,256(r3) + lfd f13,264(r3) + lfd f14,272(r3) + lfd f15,280(r3) + lfd f16,288(r3) + lfd f17,296(r3) + lfd f18,304(r3) + lfd f19,312(r3) + lfd f20,320(r3) + lfd f21,328(r3) + lfd f22,336(r3) + lfd f23,344(r3) + lfd f24,352(r3) + lfd f25,360(r3) + lfd f26,368(r3) + lfd f27,376(r3) + lfd f28,384(r3) + lfd f29,392(r3) + lfd f30,400(r3) + lfd f31,408(r3) + + ; restore vector registers if any are in use + lwz r5,156(r3) ; test VRsave + cmpwi r5,0 + beq Lnovec + + subi r4,r1,16 + rlwinm r4,r4,0,0,27 ; mask low 4-bits + ; r4 is now a 16-byte aligned pointer into the red zone + ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer + + +#define LOAD_VECTOR_UNALIGNEDl(_index) \ + andis. r0,r5,(1<<(15-_index)) @\ + beq Ldone ## _index @\ + lwz r0, 424+_index*16(r3) @\ + stw r0, 0(r4) @\ + lwz r0, 424+_index*16+4(r3) @\ + stw r0, 4(r4) @\ + lwz r0, 424+_index*16+8(r3) @\ + stw r0, 8(r4) @\ + lwz r0, 424+_index*16+12(r3)@\ + stw r0, 12(r4) @\ + lvx v ## _index,0,r4 @\ +Ldone ## _index: + +#define LOAD_VECTOR_UNALIGNEDh(_index) \ + andi. r0,r5,(1<<(31-_index)) @\ + beq Ldone ## _index @\ + lwz r0, 424+_index*16(r3) @\ + stw r0, 0(r4) @\ + lwz r0, 424+_index*16+4(r3) @\ + stw r0, 4(r4) @\ + lwz r0, 424+_index*16+8(r3) @\ + stw r0, 8(r4) @\ + lwz r0, 424+_index*16+12(r3)@\ + stw r0, 12(r4) @\ + lvx v ## _index,0,r4 @\ + Ldone ## _index: + + + LOAD_VECTOR_UNALIGNEDl(0) + LOAD_VECTOR_UNALIGNEDl(1) + LOAD_VECTOR_UNALIGNEDl(2) + LOAD_VECTOR_UNALIGNEDl(3) + LOAD_VECTOR_UNALIGNEDl(4) + LOAD_VECTOR_UNALIGNEDl(5) + LOAD_VECTOR_UNALIGNEDl(6) + LOAD_VECTOR_UNALIGNEDl(7) + LOAD_VECTOR_UNALIGNEDl(8) + LOAD_VECTOR_UNALIGNEDl(9) + LOAD_VECTOR_UNALIGNEDl(10) + LOAD_VECTOR_UNALIGNEDl(11) + LOAD_VECTOR_UNALIGNEDl(12) + LOAD_VECTOR_UNALIGNEDl(13) + LOAD_VECTOR_UNALIGNEDl(14) + LOAD_VECTOR_UNALIGNEDl(15) + LOAD_VECTOR_UNALIGNEDh(16) + LOAD_VECTOR_UNALIGNEDh(17) + LOAD_VECTOR_UNALIGNEDh(18) + LOAD_VECTOR_UNALIGNEDh(19) + LOAD_VECTOR_UNALIGNEDh(20) + LOAD_VECTOR_UNALIGNEDh(21) + LOAD_VECTOR_UNALIGNEDh(22) + LOAD_VECTOR_UNALIGNEDh(23) + LOAD_VECTOR_UNALIGNEDh(24) + LOAD_VECTOR_UNALIGNEDh(25) + LOAD_VECTOR_UNALIGNEDh(26) + LOAD_VECTOR_UNALIGNEDh(27) + LOAD_VECTOR_UNALIGNEDh(28) + LOAD_VECTOR_UNALIGNEDh(29) + LOAD_VECTOR_UNALIGNEDh(30) + LOAD_VECTOR_UNALIGNEDh(31) + +Lnovec: + lwz r0, 136(r3) ; __cr + mtocrf 255,r0 + lwz r0, 148(r3) ; __ctr + mtctr r0 + lwz r0, 0(r3) ; __ssr0 + mtctr r0 + lwz r0, 8(r3) ; do r0 now + lwz r5,28(r3) ; do r5 now + lwz r4,24(r3) ; do r4 now + lwz r1,12(r3) ; do sp now + lwz r3,20(r3) ; do r3 last + bctr + +#elif __arm64__ + +; +; void libunwind::Registers_arm64::jumpto() +; +; On entry: +; thread_state pointer is in x0 +; +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv) + ; skip restore of x0,x1 for now + ldp x2, x3, [x0, #0x010] + ldp x4, x5, [x0, #0x020] + ldp x6, x7, [x0, #0x030] + ldp x8, x9, [x0, #0x040] + ldp x10,x11, [x0, #0x050] + ldp x12,x13, [x0, #0x060] + ldp x14,x15, [x0, #0x070] + ldp x16,x17, [x0, #0x080] + ldp x18,x19, [x0, #0x090] + ldp x20,x21, [x0, #0x0A0] + ldp x22,x23, [x0, #0x0B0] + ldp x24,x25, [x0, #0x0C0] + ldp x26,x27, [x0, #0x0D0] + ldp x28,fp, [x0, #0x0E0] + ldr lr, [x0, #0x100] ; restore pc into lr + ldr x1, [x0, #0x0F8] + mov sp,x1 ; restore sp + + ldp d0, d1, [x0, #0x110] + ldp d2, d3, [x0, #0x120] + ldp d4, d5, [x0, #0x130] + ldp d6, d7, [x0, #0x140] + ldp d8, d9, [x0, #0x150] + ldp d10,d11, [x0, #0x160] + ldp d12,d13, [x0, #0x170] + ldp d14,d15, [x0, #0x180] + ldp d16,d17, [x0, #0x190] + ldp d18,d19, [x0, #0x1A0] + ldp d20,d21, [x0, #0x1B0] + ldp d22,d23, [x0, #0x1C0] + ldp d24,d25, [x0, #0x1D0] + ldp d26,d27, [x0, #0x1E0] + ldp d28,d29, [x0, #0x1F0] + ldr d30, [x0, #0x200] + ldr d31, [x0, #0x208] + + ldp x0, x1, [x0, #0x000] ; restore x0,x1 + ret lr ; jump to pc + +#elif __arm__ + +@ +@ void libunwind::Registers_arm::jumpto() +@ +@ On entry: +@ thread_state pointer is in r0 +@ +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm6jumptoEv) + @ Use lr as base so that r0 can be restored. + mov lr, r0 + @ 32bit thumb-2 restrictions for ldm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction + ldm lr, {r0-r12} + ldr sp, [lr, #52] + ldr lr, [lr, #60] @ restore pc into lr + mov pc, lr + +#endif diff --git a/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S b/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S new file mode 100644 index 00000000..6f19f6c6 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S @@ -0,0 +1,301 @@ +//===------------------------ UnwindRegistersSave.S -----------------------===// +// +// 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 "assembly.h" + + .text + +#if __i386__ + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# + + +# +-----------------------+ +# + thread_state pointer + +# +-----------------------+ +# + return address + +# +-----------------------+ <-- SP +# + + +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + push %eax + movl 8(%esp), %eax + movl %ebx, 4(%eax) + movl %ecx, 8(%eax) + movl %edx, 12(%eax) + movl %edi, 16(%eax) + movl %esi, 20(%eax) + movl %ebp, 24(%eax) + movl %esp, %edx + addl $8, %edx + movl %edx, 28(%eax) # store what sp was at call site as esp + # skip ss + # skip eflags + movl 4(%esp), %edx + movl %edx, 40(%eax) # store return address as eip + # skip cs + # skip ds + # skip es + # skip fs + # skip gs + movl (%esp), %edx + movl %edx, (%eax) # store original eax + popl %eax + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif __x86_64__ + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in rdi +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + movq %rax, (%rdi) + movq %rbx, 8(%rdi) + movq %rcx, 16(%rdi) + movq %rdx, 24(%rdi) + movq %rdi, 32(%rdi) + movq %rsi, 40(%rdi) + movq %rbp, 48(%rdi) + movq %rsp, 56(%rdi) + addq $8, 56(%rdi) + movq %r8, 64(%rdi) + movq %r9, 72(%rdi) + movq %r10, 80(%rdi) + movq %r11, 88(%rdi) + movq %r12, 96(%rdi) + movq %r13,104(%rdi) + movq %r14,112(%rdi) + movq %r15,120(%rdi) + movq (%rsp),%rsi + movq %rsi,128(%rdi) # store return address as rip + # skip rflags + # skip cs + # skip fs + # skip gs + xorl %eax, %eax # return UNW_ESUCCESS + ret + +#elif __ppc__ + +; +; extern int unw_getcontext(unw_context_t* thread_state) +; +; On entry: +; thread_state pointer is in r3 +; +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + stw r0, 8(r3) + mflr r0 + stw r0, 0(r3) ; store lr as ssr0 + stw r1, 12(r3) + stw r2, 16(r3) + stw r3, 20(r3) + stw r4, 24(r3) + stw r5, 28(r3) + stw r6, 32(r3) + stw r7, 36(r3) + stw r8, 40(r3) + stw r9, 44(r3) + stw r10, 48(r3) + stw r11, 52(r3) + stw r12, 56(r3) + stw r13, 60(r3) + stw r14, 64(r3) + stw r15, 68(r3) + stw r16, 72(r3) + stw r17, 76(r3) + stw r18, 80(r3) + stw r19, 84(r3) + stw r20, 88(r3) + stw r21, 92(r3) + stw r22, 96(r3) + stw r23,100(r3) + stw r24,104(r3) + stw r25,108(r3) + stw r26,112(r3) + stw r27,116(r3) + stw r28,120(r3) + stw r29,124(r3) + stw r30,128(r3) + stw r31,132(r3) + + ; save VRSave register + mfspr r0,256 + stw r0,156(r3) + ; save CR registers + mfcr r0 + stw r0,136(r3) + ; save CTR register + mfctr r0 + stw r0,148(r3) + + ; save float registers + stfd f0, 160(r3) + stfd f1, 168(r3) + stfd f2, 176(r3) + stfd f3, 184(r3) + stfd f4, 192(r3) + stfd f5, 200(r3) + stfd f6, 208(r3) + stfd f7, 216(r3) + stfd f8, 224(r3) + stfd f9, 232(r3) + stfd f10,240(r3) + stfd f11,248(r3) + stfd f12,256(r3) + stfd f13,264(r3) + stfd f14,272(r3) + stfd f15,280(r3) + stfd f16,288(r3) + stfd f17,296(r3) + stfd f18,304(r3) + stfd f19,312(r3) + stfd f20,320(r3) + stfd f21,328(r3) + stfd f22,336(r3) + stfd f23,344(r3) + stfd f24,352(r3) + stfd f25,360(r3) + stfd f26,368(r3) + stfd f27,376(r3) + stfd f28,384(r3) + stfd f29,392(r3) + stfd f30,400(r3) + stfd f31,408(r3) + + + ; save vector registers + + subi r4,r1,16 + rlwinm r4,r4,0,0,27 ; mask low 4-bits + ; r4 is now a 16-byte aligned pointer into the red zone + +#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \ + stvx _vec,0,r4 @\ + lwz r5, 0(r4) @\ + stw r5, _offset(r3) @\ + lwz r5, 4(r4) @\ + stw r5, _offset+4(r3) @\ + lwz r5, 8(r4) @\ + stw r5, _offset+8(r3) @\ + lwz r5, 12(r4) @\ + stw r5, _offset+12(r3) + + SAVE_VECTOR_UNALIGNED( v0, 424+0x000) + SAVE_VECTOR_UNALIGNED( v1, 424+0x010) + SAVE_VECTOR_UNALIGNED( v2, 424+0x020) + SAVE_VECTOR_UNALIGNED( v3, 424+0x030) + SAVE_VECTOR_UNALIGNED( v4, 424+0x040) + SAVE_VECTOR_UNALIGNED( v5, 424+0x050) + SAVE_VECTOR_UNALIGNED( v6, 424+0x060) + SAVE_VECTOR_UNALIGNED( v7, 424+0x070) + SAVE_VECTOR_UNALIGNED( v8, 424+0x080) + SAVE_VECTOR_UNALIGNED( v9, 424+0x090) + SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0) + SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0) + SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0) + SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0) + SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0) + SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0) + SAVE_VECTOR_UNALIGNED(v16, 424+0x100) + SAVE_VECTOR_UNALIGNED(v17, 424+0x110) + SAVE_VECTOR_UNALIGNED(v18, 424+0x120) + SAVE_VECTOR_UNALIGNED(v19, 424+0x130) + SAVE_VECTOR_UNALIGNED(v20, 424+0x140) + SAVE_VECTOR_UNALIGNED(v21, 424+0x150) + SAVE_VECTOR_UNALIGNED(v22, 424+0x160) + SAVE_VECTOR_UNALIGNED(v23, 424+0x170) + SAVE_VECTOR_UNALIGNED(v24, 424+0x180) + SAVE_VECTOR_UNALIGNED(v25, 424+0x190) + SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0) + SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0) + SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0) + SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0) + SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0) + SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0) + + li r3, 0 ; return UNW_ESUCCESS + blr + + +#elif __arm64__ + +; +; extern int unw_getcontext(unw_context_t* thread_state) +; +; On entry: +; thread_state pointer is in x0 +; +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + stp x0, x1, [x0, #0x000] + stp x2, x3, [x0, #0x010] + stp x4, x5, [x0, #0x020] + stp x6, x7, [x0, #0x030] + stp x8, x9, [x0, #0x040] + stp x10,x11, [x0, #0x050] + stp x12,x13, [x0, #0x060] + stp x14,x15, [x0, #0x070] + stp x16,x17, [x0, #0x080] + stp x18,x19, [x0, #0x090] + stp x20,x21, [x0, #0x0A0] + stp x22,x23, [x0, #0x0B0] + stp x24,x25, [x0, #0x0C0] + stp x26,x27, [x0, #0x0D0] + stp x28,fp, [x0, #0x0E0] + str lr, [x0, #0x0F0] + mov x1,sp + str x1, [x0, #0x0F8] + str lr, [x0, #0x100] ; store return address as pc + ; skip cpsr + stp d0, d1, [x0, #0x110] + stp d2, d3, [x0, #0x120] + stp d4, d5, [x0, #0x130] + stp d6, d7, [x0, #0x140] + stp d8, d9, [x0, #0x150] + stp d10,d11, [x0, #0x160] + stp d12,d13, [x0, #0x170] + stp d14,d15, [x0, #0x180] + stp d16,d17, [x0, #0x190] + stp d18,d19, [x0, #0x1A0] + stp d20,d21, [x0, #0x1B0] + stp d22,d23, [x0, #0x1C0] + stp d24,d25, [x0, #0x1D0] + stp d26,d27, [x0, #0x1E0] + stp d28,d29, [x0, #0x1F0] + str d30, [x0, #0x200] + str d31, [x0, #0x208] + ldr x0, #0 ; return UNW_ESUCCESS + ret + +#elif __arm__ && !__APPLE__ + +@ +@ extern int unw_getcontext(unw_context_t* thread_state) +@ +@ On entry: +@ thread_state pointer is in r0 +@ +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + @ 32bit thumb-2 restrictions for stm: + @ . the sp (r13) cannot be in the list + @ . the pc (r15) cannot be in the list in an STM instruction + stm r0, {r0-r12} + str sp, [r0, #52] + str lr, [r0, #56] + str lr, [r0, #60] @ store return address as pc + mov r0, #0 @ return UNW_ESUCCESS + mov pc, lr + +#endif diff --git a/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp b/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp new file mode 100644 index 00000000..6d02a66b --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp @@ -0,0 +1,205 @@ +//===--------------------- Unwind_AppleExtras.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 "config.h" +#include "DwarfParser.hpp" +#include "unwind_ext.h" + + +// private keymgr stuff +#define KEYMGR_GCC3_DW2_OBJ_LIST 302 +extern "C" { + extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr); + extern void *_keymgr_get_and_lock_processwide_ptr(int key); +} + +// undocumented libgcc "struct object" +struct libgcc_object { + void *start; + void *unused1; + void *unused2; + void *fde; + unsigned long encoding; + void *fde_end; + libgcc_object *next; +}; + +// undocumented libgcc "struct km_object_info" referenced by +// KEYMGR_GCC3_DW2_OBJ_LIST +struct libgcc_object_info { + libgcc_object *seen_objects; + libgcc_object *unseen_objects; + unsigned spare[2]; +}; + + +// static linker symbols to prevent wrong two level namespace for _Unwind symbols +#if __arm__ + #define NOT_HERE_BEFORE_5_0(sym) \ + extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \ + extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \ + extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\ + __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \ + extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \ + extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \ + extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \ + extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp43 = 0; +#elif __arm64__ + #define NOT_HERE_BEFORE_10_6(sym) + #define NEVER_HERE(sym) +#else + #define NOT_HERE_BEFORE_10_6(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; + #define NEVER_HERE(sym) \ + extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \ + extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \ + extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \ + __attribute__((visibility("default"))) const char sym##_tmp6 = 0; +#endif + + +#if _LIBUNWIND_BUILD_ZERO_COST_APIS + +// +// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_10_6(_Unwind_DeleteException) +NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE) +NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind) +NOT_HERE_BEFORE_10_6(_Unwind_GetGR) +NOT_HERE_BEFORE_10_6(_Unwind_GetIP) +NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_10_6(_Unwind_RaiseException) +NOT_HERE_BEFORE_10_6(_Unwind_Resume) +NOT_HERE_BEFORE_10_6(_Unwind_SetGR) +NOT_HERE_BEFORE_10_6(_Unwind_SetIP) +NOT_HERE_BEFORE_10_6(_Unwind_Backtrace) +NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction) +NOT_HERE_BEFORE_10_6(_Unwind_GetCFA) +NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase) +NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow) +NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_10_6(__register_frame) +NOT_HERE_BEFORE_10_6(__deregister_frame) + +// +// symbols in libSystem.dylib for compatibility, but we don't want any new code +// using them +// +NEVER_HERE(__register_frame_info_bases) +NEVER_HERE(__register_frame_info) +NEVER_HERE(__register_frame_info_table_bases) +NEVER_HERE(__register_frame_info_table) +NEVER_HERE(__register_frame_table) +NEVER_HERE(__deregister_frame_info) +NEVER_HERE(__deregister_frame_info_bases) + +#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS + + + + +#if _LIBUNWIND_BUILD_SJLJ_APIS +// +// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in +// earlier versions +// +NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData) +NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart) +NOT_HERE_BEFORE_5_0(_Unwind_GetIP) +NOT_HERE_BEFORE_5_0(_Unwind_SetGR) +NOT_HERE_BEFORE_5_0(_Unwind_SetIP) +NOT_HERE_BEFORE_5_0(_Unwind_DeleteException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register) +NOT_HERE_BEFORE_5_0(_Unwind_GetGR) +NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo) +NOT_HERE_BEFORE_5_0(_Unwind_GetCFA) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow) +NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister) + +#endif // _LIBUNWIND_BUILD_SJLJ_APIS + + +namespace libunwind { + +_LIBUNWIND_HIDDEN +bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) { +#if __MAC_OS_X_VERSION_MIN_REQUIRED + // lastly check for old style keymgr registration of dynamically generated + // FDEs acquire exclusive access to libgcc_object_info + libgcc_object_info *head = (libgcc_object_info *) + _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST); + if (head != NULL) { + // look at each FDE in keymgr + for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + const char *msg = CFI_Parser::decodeFDE( + LocalAddressSpace::sThisAddressSpace, + (uintptr_t)ob->fde, &fdeInfo, &cieInfo); + if (msg == NULL) { + // Check if this FDE is for a function that includes the pc + if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) { + fde = (void*)fdeInfo.pcStart; + _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, + head); + return true; + } + } + } + } + // release libgcc_object_info + _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head); +#else + (void)pc; + (void)fde; +#endif + return false; +} + +} + + +#if !FOR_DYLD && _LIBUNWIND_BUILD_SJLJ_APIS + +#include + +// Accessors to get get/set linked list of frames for sjlj based execeptions. +_LIBUNWIND_HIDDEN +struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() { + return (struct _Unwind_FunctionContext *) + _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key); +} + +_LIBUNWIND_HIDDEN +void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) { + _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc); +} +#endif + + + + diff --git a/system/lib/libcxxabi/src/Unwind/assembly.h b/system/lib/libcxxabi/src/Unwind/assembly.h new file mode 100644 index 00000000..d282de8c --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/assembly.h @@ -0,0 +1,44 @@ +/* ===-- assembly.h - libUnwind assembler support macros -------------------=== + * + * 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 defines macros for use in libUnwind assembler source. + * This file is not part of the interface of this library. + * + * ===----------------------------------------------------------------------=== + */ + +#ifndef UNWIND_ASSEMBLY_H +#define UNWIND_ASSEMBLY_H + +#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) +#define SEPARATOR @ +#else +#define SEPARATOR ; +#endif + +#if defined(__APPLE__) +#define HIDDEN_DIRECTIVE .private_extern +#else +#define HIDDEN_DIRECTIVE .hidden +#endif + +#define GLUE2(a, b) a ## b +#define GLUE(a, b) GLUE2(a, b) +#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) + +#define DEFINE_LIBUNWIND_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): + +#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \ + .globl SYMBOL_NAME(name) SEPARATOR \ + HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \ + SYMBOL_NAME(name): + +#endif /* UNWIND_ASSEMBLY_H */ diff --git a/system/lib/libcxxabi/src/Unwind/config.h b/system/lib/libcxxabi/src/Unwind/config.h new file mode 100644 index 00000000..2b924641 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/config.h @@ -0,0 +1,108 @@ +//===----------------------------- config.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. +// +// +// Defines macros used within libuwind project. +// +//===----------------------------------------------------------------------===// + + +#ifndef LIBUNWIND_CONFIG_H +#define LIBUNWIND_CONFIG_H + +#include + +// Define static_assert() unless already defined by compiler. +#ifndef __has_feature + #define __has_feature(__x) 0 +#endif +#if !(__has_feature(cxx_static_assert)) + #define static_assert(__b, __m) \ + extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \ + __attribute__( ( unused ) ); +#endif + +// Platform specific configuration defines. +#if __APPLE__ + #include + #ifdef __cplusplus + extern "C" { + #endif + void __assert_rtn(const char *, const char *, int, const char *) + __attribute__((noreturn)); + #ifdef __cplusplus + } + #endif + + #define _LIBUNWIND_BUILD_ZERO_COST_APIS (__i386__ || __x86_64__ || __arm64__) + #define _LIBUNWIND_BUILD_SJLJ_APIS (__arm__) + #define _LIBUNWIND_SUPPORT_FRAME_APIS (__i386__ || __x86_64__) + #define _LIBUNWIND_EXPORT __attribute__((visibility("default"))) + #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden"))) + #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__) + #define _LIBUNWIND_ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg) + + #if FOR_DYLD + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 + #else + #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1 + #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0 + #endif + +#else + // #define _LIBUNWIND_BUILD_ZERO_COST_APIS + // #define _LIBUNWIND_BUILD_SJLJ_APIS + // #define _LIBUNWIND_SUPPORT_FRAME_APIS + // #define _LIBUNWIND_EXPORT + // #define _LIBUNWIND_HIDDEN + // #define _LIBUNWIND_LOG() + // #define _LIBUNWIND_ABORT() + // #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND + // #define _LIBUNWIND_SUPPORT_DWARF_UNWIND + // #define _LIBUNWIND_SUPPORT_DWARF_INDEX +#endif + + +// Macros that define away in non-Debug builds +#ifdef NDEBUG + #define _LIBUNWIND_DEBUG_LOG(msg, ...) + #define _LIBUNWIND_TRACE_API(msg, ...) + #define _LIBUNWIND_TRACING_UNWINDING 0 + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) + #define _LIBUNWIND_LOG_NON_ZERO(x) x +#else + #ifdef __cplusplus + extern "C" { + #endif + extern bool logAPIs(); + extern bool logUnwinding(); + #ifdef __cplusplus + } + #endif + #define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__) + #define _LIBUNWIND_LOG_NON_ZERO(x) \ + do { \ + int _err = x; \ + if ( _err != 0 ) \ + _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \ + } while (0) + #define _LIBUNWIND_TRACE_API(msg, ...) \ + do { \ + if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while(0) + #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \ + do { \ + if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \ + } while(0) + #define _LIBUNWIND_TRACING_UNWINDING logUnwinding() +#endif + + +#endif // LIBUNWIND_CONFIG_H diff --git a/system/lib/libcxxabi/src/Unwind/dwarf2.h b/system/lib/libcxxabi/src/Unwind/dwarf2.h new file mode 100644 index 00000000..0dcd2ca9 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/dwarf2.h @@ -0,0 +1,237 @@ +//===------------------------------- dwarf2.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. +// +//===----------------------------------------------------------------------===// + + +/* + These constants were taken from version 3 of the DWARF standard, + which is Copyright (c) 2005 Free Standards Group, and + Copyright (c) 1992, 1993 UNIX International, Inc. +*/ + +#ifndef __DWARF2__ +#define __DWARF2__ + +// DWARF unwind instructions +enum { + DW_CFA_nop = 0x0, + DW_CFA_set_loc = 0x1, + DW_CFA_advance_loc1 = 0x2, + DW_CFA_advance_loc2 = 0x3, + DW_CFA_advance_loc4 = 0x4, + DW_CFA_offset_extended = 0x5, + DW_CFA_restore_extended = 0x6, + DW_CFA_undefined = 0x7, + DW_CFA_same_value = 0x8, + DW_CFA_register = 0x9, + DW_CFA_remember_state = 0xA, + DW_CFA_restore_state = 0xB, + DW_CFA_def_cfa = 0xC, + DW_CFA_def_cfa_register = 0xD, + DW_CFA_def_cfa_offset = 0xE, + DW_CFA_def_cfa_expression = 0xF, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta + DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register + DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register + + // GNU extensions + DW_CFA_GNU_window_save = 0x2D, + DW_CFA_GNU_args_size = 0x2E, + DW_CFA_GNU_negative_offset_extended = 0x2F +}; + + +// FSF exception handling Pointer-Encoding constants +// Used in CFI augmentation by GCC +enum { + DW_EH_PE_ptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + DW_EH_PE_absptr = 0x00, + 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 +}; + + +// DWARF expressions +enum { + DW_OP_addr = 0x03, // constant address (size target specific) + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, // 1-byte constant + DW_OP_const1s = 0x09, // 1-byte constant + DW_OP_const2u = 0x0A, // 2-byte constant + DW_OP_const2s = 0x0B, // 2-byte constant + DW_OP_const4u = 0x0C, // 4-byte constant + DW_OP_const4s = 0x0D, // 4-byte constant + DW_OP_const8u = 0x0E, // 8-byte constant + DW_OP_const8s = 0x0F, // 8-byte constant + DW_OP_constu = 0x10, // ULEB128 constant + DW_OP_consts = 0x11, // SLEB128 constant + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, // 1-byte stack index + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1A, + DW_OP_div = 0x1B, + DW_OP_minus = 0x1C, + DW_OP_mod = 0x1D, + DW_OP_mul = 0x1E, + DW_OP_neg = 0x1F, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, // ULEB128 addend + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2F, // signed 2-byte constant + DW_OP_bra = 0x28, // signed 2-byte constant + DW_OP_eq = 0x29, + DW_OP_ge = 0x2A, + DW_OP_gt = 0x2B, + DW_OP_le = 0x2C, + DW_OP_lt = 0x2D, + DW_OP_ne = 0x2E, + DW_OP_lit0 = 0x30, // Literal 0 + DW_OP_lit1 = 0x31, // Literal 1 + DW_OP_lit2 = 0x32, // Literal 2 + DW_OP_lit3 = 0x33, // Literal 3 + DW_OP_lit4 = 0x34, // Literal 4 + DW_OP_lit5 = 0x35, // Literal 5 + DW_OP_lit6 = 0x36, // Literal 6 + DW_OP_lit7 = 0x37, // Literal 7 + DW_OP_lit8 = 0x38, // Literal 8 + DW_OP_lit9 = 0x39, // Literal 9 + DW_OP_lit10 = 0x3A, // Literal 10 + DW_OP_lit11 = 0x3B, // Literal 11 + DW_OP_lit12 = 0x3C, // Literal 12 + DW_OP_lit13 = 0x3D, // Literal 13 + DW_OP_lit14 = 0x3E, // Literal 14 + DW_OP_lit15 = 0x3F, // Literal 15 + DW_OP_lit16 = 0x40, // Literal 16 + DW_OP_lit17 = 0x41, // Literal 17 + DW_OP_lit18 = 0x42, // Literal 18 + DW_OP_lit19 = 0x43, // Literal 19 + DW_OP_lit20 = 0x44, // Literal 20 + DW_OP_lit21 = 0x45, // Literal 21 + DW_OP_lit22 = 0x46, // Literal 22 + DW_OP_lit23 = 0x47, // Literal 23 + DW_OP_lit24 = 0x48, // Literal 24 + DW_OP_lit25 = 0x49, // Literal 25 + DW_OP_lit26 = 0x4A, // Literal 26 + DW_OP_lit27 = 0x4B, // Literal 27 + DW_OP_lit28 = 0x4C, // Literal 28 + DW_OP_lit29 = 0x4D, // Literal 29 + DW_OP_lit30 = 0x4E, // Literal 30 + DW_OP_lit31 = 0x4F, // Literal 31 + DW_OP_reg0 = 0x50, // Contents of reg0 + DW_OP_reg1 = 0x51, // Contents of reg1 + DW_OP_reg2 = 0x52, // Contents of reg2 + DW_OP_reg3 = 0x53, // Contents of reg3 + DW_OP_reg4 = 0x54, // Contents of reg4 + DW_OP_reg5 = 0x55, // Contents of reg5 + DW_OP_reg6 = 0x56, // Contents of reg6 + DW_OP_reg7 = 0x57, // Contents of reg7 + DW_OP_reg8 = 0x58, // Contents of reg8 + DW_OP_reg9 = 0x59, // Contents of reg9 + DW_OP_reg10 = 0x5A, // Contents of reg10 + DW_OP_reg11 = 0x5B, // Contents of reg11 + DW_OP_reg12 = 0x5C, // Contents of reg12 + DW_OP_reg13 = 0x5D, // Contents of reg13 + DW_OP_reg14 = 0x5E, // Contents of reg14 + DW_OP_reg15 = 0x5F, // Contents of reg15 + DW_OP_reg16 = 0x60, // Contents of reg16 + DW_OP_reg17 = 0x61, // Contents of reg17 + DW_OP_reg18 = 0x62, // Contents of reg18 + DW_OP_reg19 = 0x63, // Contents of reg19 + DW_OP_reg20 = 0x64, // Contents of reg20 + DW_OP_reg21 = 0x65, // Contents of reg21 + DW_OP_reg22 = 0x66, // Contents of reg22 + DW_OP_reg23 = 0x67, // Contents of reg23 + DW_OP_reg24 = 0x68, // Contents of reg24 + DW_OP_reg25 = 0x69, // Contents of reg25 + DW_OP_reg26 = 0x6A, // Contents of reg26 + DW_OP_reg27 = 0x6B, // Contents of reg27 + DW_OP_reg28 = 0x6C, // Contents of reg28 + DW_OP_reg29 = 0x6D, // Contents of reg29 + DW_OP_reg30 = 0x6E, // Contents of reg30 + DW_OP_reg31 = 0x6F, // Contents of reg31 + DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset + DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset + DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset + DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset + DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset + DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset + DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset + DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset + DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset + DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset + DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset + DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset + DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset + DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset + DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset + DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset + DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset + DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset + DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset + DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset + DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset + DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset + DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset + DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset + DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset + DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset + DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset + DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset + DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset + DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset + DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset + DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset + DW_OP_regx = 0x90, // ULEB128 register + DW_OP_fbreg = 0x91, // SLEB128 offset + DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset + DW_OP_piece = 0x93, // ULEB128 size of piece addressed + DW_OP_deref_size = 0x94, // 1-byte size of data retrieved + DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved + DW_OP_nop = 0x96, + DW_OP_push_object_addres = 0x97, + DW_OP_call2 = 0x98, // 2-byte offset of DIE + DW_OP_call4 = 0x99, // 4-byte offset of DIE + DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE + DW_OP_lo_user = 0xE0, + DW_OP_APPLE_uninit = 0xF0, + DW_OP_hi_user = 0xFF +}; + + +#endif diff --git a/system/lib/libcxxabi/src/Unwind/libunwind.cpp b/system/lib/libcxxabi/src/Unwind/libunwind.cpp new file mode 100644 index 00000000..2043ac23 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/libunwind.cpp @@ -0,0 +1,353 @@ +//===--------------------------- libuwind.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. +// +// +// Implements unw_* functions from +// +//===----------------------------------------------------------------------===// + +#include + +#include + +#include "libunwind_ext.h" +#include "config.h" + + +#if _LIBUNWIND_BUILD_ZERO_COST_APIS + +#include "UnwindCursor.hpp" + +using namespace libunwind; + +/// internal object to represent this processes address space +LocalAddressSpace LocalAddressSpace::sThisAddressSpace; + +/// record the registers and stack position of the caller +extern int unw_getcontext(unw_context_t *); +// note: unw_getcontext() implemented in assembly + +/// Create a cursor of a thread in this process given 'context' recorded by +/// unw_getcontext(). +_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, + unw_context_t *context) { + _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n", + cursor, context); + // Use "placement new" to allocate UnwindCursor in the cursor buffer. +#if __i386__ + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#elif __x86_64__ + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#elif __ppc__ + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#elif __arm64__ + new ((void *)cursor) UnwindCursor( + context, LocalAddressSpace::sThisAddressSpace); +#endif + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->setInfoBasedOnIPRegister(); + + return UNW_ESUCCESS; +} + +#if UNW_REMOTE + +_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space = + (unw_addr_space_t) & sThisAddressSpace; + +/// Create a cursor into a thread in another process. +_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor, + unw_addr_space_t as, + void *arg) { + // special case: unw_init_remote(xx, unw_local_addr_space, xx) + if (as == (unw_addr_space_t) & sThisAddressSpace) + return unw_init_local(cursor, NULL); //FIXME + + // use "placement new" to allocate UnwindCursor in the cursor buffer + switch (as->cpuType) { + case CPU_TYPE_I386: + new ((void *)cursor) + UnwindCursor >, + Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); + break; + case CPU_TYPE_X86_64: + new ((void *)cursor) UnwindCursor< + OtherAddressSpace >, Registers_x86_64>( + ((unw_addr_space_x86_64 *)as)->oas, arg); + break; + case CPU_TYPE_POWERPC: + new ((void *)cursor) + UnwindCursor >, Registers_ppc>( + ((unw_addr_space_ppc *)as)->oas, arg); + break; + default: + return UNW_EUNSPEC; + } + return UNW_ESUCCESS; +} + + +static bool is64bit(task_t task) { + return false; // FIXME +} + +/// Create an address_space object for use in examining another task. +_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) { +#if __i386__ + if (is64bit(task)) { + unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task); + as->taskPort = task; + as->cpuType = CPU_TYPE_X86_64; + //as->oas + } else { + unw_addr_space_i386 *as = new unw_addr_space_i386(task); + as->taskPort = task; + as->cpuType = CPU_TYPE_I386; + //as->oas + } +#else +// FIXME +#endif +} + + +/// Delete an address_space object. +_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) { + switch (asp->cpuType) { +#if __i386__ || __x86_64__ + case CPU_TYPE_I386: { + unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp; + delete as; + } + break; + case CPU_TYPE_X86_64: { + unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp; + delete as; + } + break; +#endif + case CPU_TYPE_POWERPC: { + unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp; + delete as; + } + break; + } +} +#endif // UNW_REMOTE + + +/// Get value of specified register at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t *value) { + _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n", + cursor, regNum, value); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + *value = co->getReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} + + +/// Set value of specified register at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_word_t value) { + _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n", + cursor, regNum, value); + typedef LocalAddressSpace::pint_t pint_t; + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validReg(regNum)) { + co->setReg(regNum, (pint_t)value); + // specical case altering IP to re-find info (being called by personality + // function) + if (regNum == UNW_REG_IP) { + unw_proc_info_t info; + co->getInfo(&info); + pint_t orgArgSize = (pint_t)info.gp; + uint64_t orgFuncStart = info.start_ip; + co->setInfoBasedOnIPRegister(false); + // and adjust REG_SP if there was a DW_CFA_GNU_args_size + if ((orgFuncStart == info.start_ip) && (orgArgSize != 0)) + co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize); + } + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} + + +/// Get value of specified float register at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t *value) { + _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n", + cursor, regNum, value); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + *value = co->getFloatReg(regNum); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} + + +/// Set value of specified float register at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum, + unw_fpreg_t value) { + _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n", + cursor, regNum, value); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->validFloatReg(regNum)) { + co->setFloatReg(regNum, value); + return UNW_ESUCCESS; + } + return UNW_EBADREG; +} + + +/// Move cursor to next frame. +_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", cursor); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->step(); +} + + +/// Get unwind info at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor, + unw_proc_info_t *info) { + _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n", + cursor, info); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->getInfo(info); + if (info->end_ip == 0) + return UNW_ENOINFO; + else + return UNW_ESUCCESS; +} + + +/// Resume execution at cursor position (aka longjump). +_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", cursor); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + co->jumpto(); + return UNW_EUNSPEC; +} + + +/// Get name of function at cursor position in stack frame. +_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf, + size_t bufLen, unw_word_t *offset) { + _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p," + "bufLen=%ld)\n", cursor, buf, bufLen); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + if (co->getFunctionName(buf, bufLen, offset)) + return UNW_ESUCCESS; + else + return UNW_EUNSPEC; +} + + +/// Checks if a register is a floating-point register. +_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n", + cursor, regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->validFloatReg(regNum); +} + + +/// Checks if a register is a floating-point register. +_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor, + unw_regnum_t regNum) { + _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n", + cursor, regNum); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->getRegisterName(regNum); +} + + +/// Checks if current frame is signal trampoline. +_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) { + _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", cursor); + AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor; + return co->isSignalFrame(); +} + + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +/// SPI: walks cached dwarf entries +_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)( + unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) { + _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func); + DwarfFDECache::iterateCacheEntries(func); +} + + +/// IPI: for __register_frame() +void _unw_add_dynamic_fde(unw_word_t fde) { + CFI_Parser::FDE_Info fdeInfo; + CFI_Parser::CIE_Info cieInfo; + const char *message = CFI_Parser::decodeFDE( + LocalAddressSpace::sThisAddressSpace, + (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo); + if (message == NULL) { + // dynamically registered FDEs don't have a mach_header group they are in. + // Use fde as mh_group + unw_word_t mh_group = fdeInfo.fdeStart; + DwarfFDECache::add((LocalAddressSpace::pint_t)mh_group, + fdeInfo.pcStart, fdeInfo.pcEnd, + fdeInfo.fdeStart); + } else { + _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message); + } +} + +/// IPI: for __deregister_frame() +void _unw_remove_dynamic_fde(unw_word_t fde) { + // fde is own mh_group + DwarfFDECache::removeAllIn((LocalAddressSpace::pint_t)fde); +} +#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND + +#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS + + + +// Add logging hooks in Debug builds only +#ifndef NDEBUG + +_LIBUNWIND_HIDDEN +bool logAPIs() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_APIS") != NULL); + checked = true; + } + return log; +} + +_LIBUNWIND_HIDDEN +bool logUnwinding() { + // do manual lock to avoid use of _cxa_guard_acquire or initializers + static bool checked = false; + static bool log = false; + if (!checked) { + log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL); + checked = true; + } + return log; +} + +#endif // NDEBUG + diff --git a/system/lib/libcxxabi/src/Unwind/libunwind_ext.h b/system/lib/libcxxabi/src/Unwind/libunwind_ext.h new file mode 100644 index 00000000..38d71cce --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/libunwind_ext.h @@ -0,0 +1,38 @@ +//===------------------------ libunwind_ext.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. +// +// +// Extensions to libunwind API. +// +//===----------------------------------------------------------------------===// + +#ifndef __LIBUNWIND_EXT__ +#define __LIBUNWIND_EXT__ + +#include + +#define UNW_STEP_SUCCESS 1 +#define UNW_STEP_END 0 + +#ifdef __cplusplus +extern "C" { +#endif +// SPI +extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start, + unw_word_t ip_end, + unw_word_t fde, + unw_word_t mh)); + +// IPI +extern void _unw_add_dynamic_fde(unw_word_t fde); +extern void _unw_remove_dynamic_fde(unw_word_t fde); + +#ifdef __cplusplus +} +#endif + +#endif // __LIBUNWIND_EXT__ diff --git a/system/lib/libcxxabi/src/Unwind/unwind_ext.h b/system/lib/libcxxabi/src/Unwind/unwind_ext.h new file mode 100644 index 00000000..c40ce6a1 --- /dev/null +++ b/system/lib/libcxxabi/src/Unwind/unwind_ext.h @@ -0,0 +1,37 @@ +//===-------------------------- unwind_ext.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. +// +// +// Extensions to unwind API. +// +//===----------------------------------------------------------------------===// + +#ifndef __UNWIND_EXT__ +#define __UNWIND_EXT__ + +#include "unwind.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// These platform specific functions to get and set the top context are +// implemented elsewhere. + +extern struct _Unwind_FunctionContext * +__Unwind_SjLj_GetTopOfFunctionStack(); + +extern void +__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc); + +#ifdef __cplusplus +} +#endif + +#endif // __UNWIND_EXT__ + + diff --git a/system/lib/libcxxabi/src/cxa_default_handlers.cpp b/system/lib/libcxxabi/src/cxa_default_handlers.cpp new file mode 100644 index 00000000..27ffb719 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_default_handlers.cpp @@ -0,0 +1,120 @@ +//===------------------------- cxa_default_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 default terminate_handler and unexpected_handler. +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include "abort_message.h" +#include "cxxabi.h" +#include "cxa_handlers.hpp" +#include "cxa_exception.hpp" +#include "private_typeinfo.h" + +static const char* cause = "uncaught"; + +__attribute__((noreturn)) +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(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(&typeid(std::exception)); + if (catch_type->can_catch(thrown_type, thrown_object)) + { + // Include the what() message from the exception + const std::exception* e = static_cast(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"); +} + +__attribute__((noreturn)) +static void default_unexpected_handler() +{ + cause = "unexpected"; + std::terminate(); +} + + +// +// Global variables that hold the pointers to the current handler +// +std::terminate_handler __cxa_terminate_handler = default_terminate_handler; +std::unexpected_handler __cxa_unexpected_handler = default_unexpected_handler; + +// In the future these will become: +// std::atomic __cxa_terminate_handler(default_terminate_handler); +// std::atomic __cxa_unexpected_handler(default_unexpected_handler); + +namespace std +{ + +unexpected_handler +set_unexpected(unexpected_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_unexpected_handler; + return __sync_swap(&__cxa_unexpected_handler, func); +// Using of C++11 atomics this should be rewritten +// return __cxa_unexpected_handler.exchange(func, memory_order_acq_rel); +} + +terminate_handler +set_terminate(terminate_handler func) _NOEXCEPT +{ + if (func == 0) + func = default_terminate_handler; + return __sync_swap(&__cxa_terminate_handler, func); +// Using of C++11 atomics this should be rewritten +// return __cxa_terminate_handler.exchange(func, memory_order_acq_rel); +} + +} diff --git a/system/lib/libcxxabi/src/cxa_demangle.cpp b/system/lib/libcxxabi/src/cxa_demangle.cpp index c1e12603..839aebec 100644 --- a/system/lib/libcxxabi/src/cxa_demangle.cpp +++ b/system/lib/libcxxabi/src/cxa_demangle.cpp @@ -7,10305 +7,3871 @@ // //===----------------------------------------------------------------------===// -#include "cxa_demangle.h" +#define _LIBCPP_EXTERN_TEMPLATE(...) +#define _LIBCPP_NO_EXCEPTIONS -#include -#include -#include -#include -#include +#include #include -#include - -#ifdef DEBUGGING - #include -#include - -#endif +#include +#include +#include +#include namespace __cxxabiv1 { -namespace __libcxxabi +namespace { -#pragma GCC visibility push(hidden) - -class __node +enum { - __node(const __node&); - __node& operator=(const __node&); -public: - const char* __name_; - size_t __size_; - __node* __left_; - __node* __right_; - long __cached_size_; - long double __value_; -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(__cached_size_) = static_cast(first_size() + second_size()); - return static_cast(__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; - } + unknown_error = -4, + invalid_args = -3, + invalid_mangled_name, + memory_alloc_failure, + success }; -#ifdef DEBUGGING +template + const char* parse_type(const char* first, const char* last, C& db); +template + const char* parse_encoding(const char* first, const char* last, C& db); +template + const char* parse_name(const char* first, const char* last, C& db); +template + const char* parse_expression(const char* first, const char* last, C& db); +template + const char* parse_template_args(const char* first, const char* last, C& db); +template + const char* parse_operator_name(const char* first, const char* last, C& db); +template + const char* parse_unqualified_name(const char* first, const char* last, C& db); +template + const char* parse_decltype(const char* first, const char* last, C& db); -void display(__node* x, int indent = 0) -{ - if (x) +template +void +print_stack(const C& db) +{ + printf("---------\n"); + printf("names:\n"); + for (auto& s : db.names) + printf("{%s#%s}\n", s.first.c_str(), s.second.c_str()); + int i = -1; + printf("subs:\n"); + for (auto& v : db.subs) + { + if (i >= 0) + printf("S%i_ = {", i); + else + printf("S_ = {"); + for (auto& s : v) + printf("{%s#%s}", s.first.c_str(), s.second.c_str()); + printf("}\n"); + ++i; + } + printf("template_param:\n"); + for (auto& t : db.template_param) { - for (int i = 0; i < 2*indent; ++i) - printf(" "); - size_t sz = x->size(); - char* buf = (char*)calloc(sz+10, 1); - x->get_demangled_name(buf); - printf("%s [%ld] %s, %p\n", typeid(*x).name(), sz, buf, x); - if (strlen(buf) != sz) + printf("--\n"); + i = -1; + for (auto& v : t) { - printf("strlen(buf) = %ld and size = %ld\n", strlen(buf), sz); + if (i >= 0) + printf("T%i_ = {", i); + else + printf("T_ = {"); + for (auto& s : v) + printf("{%s#%s}", s.first.c_str(), s.second.c_str()); + printf("}\n"); + ++i; } - free(buf); - display(x->__left_, indent+1); - display(x->__right_, indent+1); } + printf("---------\n\n"); } -#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(__cached_size_) = n + static_cast(__right_->size()); - return static_cast(__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 +template +void +print_state(const char* msg, const char* first, const char* last, const C& db) { - static const ptrdiff_t n = sizeof("VTT for ") - 1; -public: - __VTT(__node* type) - { - __right_ = type; - } + printf("%s: ", msg); + for (; first != last; ++first) + printf("%c", *first); + printf("\n"); + print_stack(db); +} - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast(__cached_size_) = n + static_cast(__right_->size()); - return static_cast(__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); - } -}; +// ::= [n] -class __construction_vtable - : public __node +const char* +parse_number(const char* first, const char* last) { - static const ptrdiff_t n = sizeof("construction vtable for ") - 1 + 4; -public: - __construction_vtable(__node* left, __node* right) + if (first != last) { - __left_ = left; - __right_ = right; + 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 && std::isdigit(*first)) + ++first; + } + } } + return first; +} - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast(__cached_size_) = n + static_cast(__left_->size() - + __right_->size()); - return static_cast(__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); - } -}; +template +struct float_data; -class __typeinfo - : public __node +template <> +struct float_data { - 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(__cached_size_) = n + static_cast(__right_->size()); - return static_cast(__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); - } + static const size_t mangled_size = 8; + static const size_t max_demangled_size = 24; + static constexpr const char* spec = "%af"; }; -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(__cached_size_) = n + static_cast(__right_->size()); - return static_cast(__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); - } -}; +constexpr const char* float_data::spec; -class __covariant_return_thunk - : public __node +template <> +struct float_data { - 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(__cached_size_) = n + static_cast(__right_->size()); - return static_cast(__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); - } + static const size_t mangled_size = 16; + static const size_t max_demangled_size = 32; + static constexpr const char* spec = "%a"; }; -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(__cached_size_) = static_cast(n + __right_->size()); - return static_cast(__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); - } -}; +constexpr const char* float_data::spec; -class __non_virtual_thunk - : public __node +template <> +struct float_data { - 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(__cached_size_) = static_cast(n + __right_->size()); - return static_cast(__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); - } + static const size_t mangled_size = 20; // May need to be adjusted to 16 or 24 on other platforms + static const size_t max_demangled_size = 40; + static constexpr const char* spec = "%LaL"; }; -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(__cached_size_) = static_cast(n + __right_->size()); - return static_cast(__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); - } -}; +constexpr const char* float_data::spec; -class __reference_temporary - : public __node +template +const char* +parse_floating_number(const char* first, const char* last, C& db) { - static const size_t n = sizeof("reference temporary for ") - 1; -public: - __reference_temporary(__node* type) + const size_t N = float_data::mangled_size; + if (static_cast(last - first) > N) { - __right_ = type; + last = first + N; + union + { + Float value; + char buf[sizeof(Float)]; + }; + const char* t = first; + char* e = buf; + for (; t != last; ++t, ++e) + { + if (!isxdigit(*t)) + return first; + unsigned d1 = isdigit(*t) ? static_cast(*t - '0') : + static_cast(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast(*t - '0') : + static_cast(*t - 'a' + 10); + *e = static_cast((d1 << 4) + d0); + } + if (*t == 'E') + { +#if __LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[float_data::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), float_data::spec, value); + if (static_cast(n) >= sizeof(num)) + return first; + db.names.push_back(typename C::String(num, static_cast(n))); + first = t+1; + } } + return first; +} - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast(__cached_size_) = static_cast(n + __right_->size()); - return static_cast(__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 +template +const char* +parse_source_name(const char* first, const char* last, C& db) { -public: - __source_name(const char* __name, size_t __size) - { - __name_ = __name; - __size_ = __size; - } - - virtual size_t first_size() const + if (first != last) { - if (__cached_size_ == -1) + char c = *first; + if (isdigit(c) && first+1 != last) { - if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0) - const_cast(__cached_size_) = 21; - else - const_cast(__cached_size_) = static_cast(__size_); + const char* t = first+1; + size_t n = static_cast(c - '0'); + for (c = *t; isdigit(c); c = *t) + { + n = n * 10 + static_cast(c - '0'); + if (++t == last) + return first; + } + if (static_cast(last - t) >= n) + { + typename C::String r(t, n); + if (r.substr(0, 10) == "_GLOBAL__N") + db.names.push_back("(anonymous namespace)"); + else + db.names.push_back(std::move(r)); + first = t + n; + } } - return static_cast(__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: + return first; +} - 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; - } -}; +// ::= S _ +// ::= S_ +// ::= Sa # ::std::allocator +// ::= Sb # ::std::basic_string +// ::= Ss # ::std::basic_string < char, +// ::std::char_traits, +// ::std::allocator > +// ::= Si # ::std::basic_istream > +// ::= So # ::std::basic_ostream > +// ::= Sd # ::std::basic_iostream > -class __operator_new_array - : public __node +template +const char* +parse_substitution(const char* first, const char* last, C& db) { -public: - - virtual size_t first_size() const {return sizeof("operator new[]") - 1;} - virtual char* first_demangled_name(char* buf) const + if (last - first >= 2) { - 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; + if (*first == 'S') + { + switch (first[1]) + { + case 'a': + db.names.push_back("std::allocator"); + first += 2; + break; + case 'b': + db.names.push_back("std::basic_string"); + first += 2; + break; + case 's': + db.names.push_back("std::string"); + first += 2; + break; + case 'i': + db.names.push_back("std::istream"); + first += 2; + break; + case 'o': + db.names.push_back("std::ostream"); + first += 2; + break; + case 'd': + db.names.push_back("std::iostream"); + first += 2; + break; + case '_': + if (!db.subs.empty()) + { + for (const auto& n : db.subs.front()) + db.names.push_back(n); + first += 2; + } + break; + default: + if (std::isdigit(first[1]) || std::isupper(first[1])) + { + size_t sub = 0; + const char* t = first+1; + if (std::isdigit(*t)) + sub = static_cast(*t - '0'); + else + sub = static_cast(*t - 'A') + 10; + for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) + { + sub *= 36; + if (std::isdigit(*t)) + sub += static_cast(*t - '0'); + else + sub += static_cast(*t - 'A') + 10; + } + if (t == last || *t != '_') + return first; + ++sub; + if (sub < db.subs.size()) + { + for (const auto& n : db.subs[sub]) + db.names.push_back(n); + first = t+1; + } + } + break; + } + } } -}; - -class __operator_delete_array - : public __node -{ -public: + return first; +} - 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; - } -}; +// ::= 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 # vendor extended type -class __operator_logical_and - : public __node +template +const char* +parse_builtin_type(const char* first, const char* last, C& db) { -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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator&&") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const + if (first != last) { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") && (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + switch (*first) { - strncpy(buf, "operator&&", sizeof("operator&&") - 1); - buf += sizeof("operator&&") - 1; + case 'v': + db.names.push_back("void"); + ++first; + break; + case 'w': + db.names.push_back("wchar_t"); + ++first; + break; + case 'b': + db.names.push_back("bool"); + ++first; + break; + case 'c': + db.names.push_back("char"); + ++first; + break; + case 'a': + db.names.push_back("signed char"); + ++first; + break; + case 'h': + db.names.push_back("unsigned char"); + ++first; + break; + case 's': + db.names.push_back("short"); + ++first; + break; + case 't': + db.names.push_back("unsigned short"); + ++first; + break; + case 'i': + db.names.push_back("int"); + ++first; + break; + case 'j': + db.names.push_back("unsigned int"); + ++first; + break; + case 'l': + db.names.push_back("long"); + ++first; + break; + case 'm': + db.names.push_back("unsigned long"); + ++first; + break; + case 'x': + db.names.push_back("long long"); + ++first; + break; + case 'y': + db.names.push_back("unsigned long long"); + ++first; + break; + case 'n': + db.names.push_back("__int128"); + ++first; + break; + case 'o': + db.names.push_back("unsigned __int128"); + ++first; + break; + case 'f': + db.names.push_back("float"); + ++first; + break; + case 'd': + db.names.push_back("double"); + ++first; + break; + case 'e': + db.names.push_back("long double"); + ++first; + break; + case 'g': + db.names.push_back("__float128"); + ++first; + break; + case 'z': + db.names.push_back("..."); + ++first; + break; + case 'u': + { + const char*t = parse_source_name(first+1, last, db); + if (t != first+1) + first = t; + } + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'd': + db.names.push_back("decimal64"); + first += 2; + break; + case 'e': + db.names.push_back("decimal128"); + first += 2; + break; + case 'f': + db.names.push_back("decimal32"); + first += 2; + break; + case 'h': + db.names.push_back("decimal16"); + first += 2; + break; + case 'i': + db.names.push_back("char32_t"); + first += 2; + break; + case 's': + db.names.push_back("char16_t"); + first += 2; + break; + case 'a': + db.names.push_back("auto"); + first += 2; + break; + case 'n': + db.names.push_back("std::nullptr_t"); + first += 2; + break; + } + } + break; } - 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; - } -}; + return first; +} -class __operator_addressof - : public __node -{ -public: +// ::= [r] [V] [K] - __operator_addressof() {} - explicit __operator_addressof(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const +const char* +parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) +{ + cv = 0; + if (first != last) { - if (__cached_size_ == -1) + if (*first == 'r') { - if (__left_) - const_cast(__cached_size_) = static_cast(3 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator&") - 1; + cv |= 4; + ++first; } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) + if (*first == 'V') { - *buf++ = '&'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; + cv |= 2; + ++first; } - else + if (*first == 'K') { - strncpy(buf, "operator&", sizeof("operator&") - 1); - buf += sizeof("operator&") - 1; + cv |= 1; + ++first; } - 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; } -}; + return first; +} -class __operator_bit_and - : public __node -{ -public: +// ::= T_ # first template parameter +// ::= T _ - __operator_bit_and() {} - __operator_bit_and(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_template_param(const char* first, const char* last, C& db) +{ + if (last - first >= 2) { - if (__cached_size_ == -1) + if (*first == 'T') { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator&") - 1; + if (first[1] == '_') + { + if (db.template_param.empty()) + return first; + if (!db.template_param.back().empty()) + { + for (auto& t : db.template_param.back().front()) + db.names.push_back(t); + first += 2; + } + else + { + db.names.push_back("T_"); + first += 2; + db.fix_forward_references = true; + } + } + else if (isdigit(first[1])) + { + const char* t = first+1; + size_t sub = static_cast(*t - '0'); + for (++t; t != last && isdigit(*t); ++t) + { + sub *= 10; + sub += static_cast(*t - '0'); + } + if (t == last || *t != '_' || db.template_param.empty()) + return first; + ++sub; + if (sub < db.template_param.back().size()) + { + for (auto& temp : db.template_param.back()[sub]) + db.names.push_back(temp); + first = t+1; + } + else + { + db.names.push_back(typename C::String(first, t+1)); + first = t+1; + db.fix_forward_references = true; + } + } } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// cc # const_cast (expression) + +template +const char* +parse_const_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') { - if (__left_) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - *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; + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } } - 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; - } -}; + return first; +} -class __operator_and_equal - : public __node -{ -public: +// dc # dynamic_cast (expression) - __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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator&=") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const +template +const char* +parse_dynamic_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") &= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator&=", sizeof("operator&=") - 1); - buf += sizeof("operator&=") - 1; + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } } - 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; - } -}; + return first; +} -class __operator_equal - : public __node -{ -public: +// rc # reinterpret_cast (expression) - __operator_equal() {} - __operator_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_reinterpret_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') { - if (__cached_size_ == -1) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator=") - 1; + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// sc # static_cast (expression) + +template +const char* +parse_static_cast_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'c') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") = (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator=", sizeof("operator=") - 1); - buf += sizeof("operator=") - 1; + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")"; + first = t1; + } } - 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; } -}; + return first; +} -class __operator_alignof_type - : public __node -{ -public: +// sp # pack expansion - __operator_alignof_type() {} - __operator_alignof_type(__node* op) +template +const char* +parse_pack_expansion(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { - __right_ = op; + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + first = t; } - virtual size_t first_size() const + return first; +} + +// st # sizeof (a type) + +template +const char* +parse_sizeof_type_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 't') { - if (__cached_size_ == -1) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - if (__right_) - const_cast(__cached_size_) = static_cast(__right_->size() + 10); - else - const_cast(__cached_size_) = sizeof("operator alignof") - 1; + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + first = t; } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// sz # sizeof (a expression) + +template +const char* +parse_sizeof_expr_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'z') { - if (__right_) - { - strncpy(buf, "alignof (", 9); - buf += 9; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); - buf += sizeof("operator alignof") - 1; + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + first = t; } - 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; - } -}; + return first; +} -class __operator_alignof_expression - : public __node -{ -public: +// sZ # size of a parameter pack - __operator_alignof_expression() {} - __operator_alignof_expression(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const +template +const char* +parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') { - if (__cached_size_ == -1) + size_t k0 = db.names.size(); + const char* t = parse_template_param(first+2, last, db); + size_t k1 = db.names.size(); + if (t != first+2) { - if (__right_) - const_cast(__cached_size_) = static_cast(__right_->size() + 10); - else - const_cast(__cached_size_) = sizeof("operator alignof") - 1; + typename C::String tmp("sizeof...("); + size_t k = k0; + if (k != k1) + { + tmp += db.names[k].move_full(); + for (++k; k != k1; ++k) + tmp += ", " + db.names[k].move_full(); + } + tmp += ")"; + for (; k1 != k0; --k1) + db.names.pop_back(); + db.names.push_back(std::move(tmp)); + first = t; } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// ::= fp _ # L == 0, first parameter +// ::= fp _ # L == 0, second and later parameters +// ::= fL p _ # L > 0, first parameter +// ::= fL p _ # L > 0, second and later parameters + +template +const char* +parse_function_param(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && *first == 'f') { - if (__right_) + if (first[1] == 'p') { - strncpy(buf, "alignof (", 9); - buf += 9; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; + unsigned cv; + const char* t = parse_cv_qualifiers(first+2, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+1; + } } - else + else if (first[1] == 'L') { - strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); - buf += sizeof("operator alignof") - 1; + unsigned cv; + const char* t0 = parse_number(first+2, last); + if (t0 != last && *t0 == 'p') + { + ++t0; + const char* t = parse_cv_qualifiers(t0, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+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: + return first; +} - 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; - } -}; +// sZ # size of a function parameter pack -class __operator_comma - : public __node +template +const char* +parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) { -public: - - __operator_comma() {} - __operator_comma(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') { - if (__cached_size_ == -1) + const char* t = parse_function_param(first+2, last, db); + if (t != first+2) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator,") - 1; + if (db.names.empty()) + return first; + db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + first = t; } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// te # typeid (expression) +// ti # typeid (type) + +template +const char* +parse_typeid_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") , (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } + const char* t; + if (first[1] == 'e') + t = parse_expression(first+2, last, db); else + t = parse_type(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator,", sizeof("operator,") - 1); - buf += sizeof("operator,") - 1; + if (db.names.empty()) + return first; + db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + first = t; } - 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; } -}; + return first; +} -class __operator_tilda - : public __node -{ -public: +// tw # throw expression - __operator_tilda() {} - explicit __operator_tilda(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast(__cached_size_) = static_cast(3 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator~") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const +template +const char* +parse_throw_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 't' && first[1] == 'w') { - if (__left_) - { - *buf++ = '~'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator~", sizeof("operator~") - 1); - buf += sizeof("operator~") - 1; + if (db.names.empty()) + return first; + db.names.back() = "throw " + db.names.back().move_full(); + first = t; } - 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; } -}; + return first; +} -class __operator_cast - : public __node -{ - static const size_t n = sizeof("operator ") - 1; -public: +// ds # expr.*expr - 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 +template +const char* +parse_dot_star_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 's') { - if (__cached_size_ == -1) + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - size_t off; - if (__size_) + const char* t1 = parse_expression(t, last, db); + if (t1 != t) { - off = 4; - off += __right_->size(); - if (__left_) - off += __left_->size(); + if (db.names.size() < 2) + return first; + auto expr = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += ".*" + expr; + first = t1; } - else - off = n + __right_->size();; - const_cast(__cached_size_) = static_cast(off); } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// ::= [ ] + +template +const char* +parse_simple_id(const char* first, const char* last, C& db) +{ + if (first != last) { - if (__size_) + const char* t = parse_source_name(first, last, db); + if (t != first) { - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - *buf++ = '('; - if (__left_) - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; + const char* t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + first = t1; } 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; + first = t; } - virtual bool is_ctor_dtor_conv() const - { - return true; - } -}; - -class __cast_literal - : public __node -{ -public: + return first; +} - __cast_literal(__node* type, const char* f, const char* l) - { - __left_ = type; - __name_ = f; - __size_ = static_cast(l - f); - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast(__cached_size_) = static_cast(2 + - __left_->size() + __size_); - return static_cast(__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 +template +const char* +parse_unresolved_type(const char* first, const char* last, C& db) { -public: - - __operator_dereference() {} - explicit __operator_dereference(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const + if (first != last) { - if (__cached_size_ == -1) + const char* t = first; + switch (*first) { - if (__left_) - const_cast(__cached_size_) = static_cast(3 + __left_->size()); + case 'T': + { + size_t k0 = db.names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.names.size(); + if (t != first && k1 == k0 + 1) + { + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } else - const_cast(__cached_size_) = sizeof("operator*") - 1; - } - return static_cast(__cached_size_); + { + for (; k1 != k0; --k1) + db.names.pop_back(); + } + break; + } + case 'D': + t = parse_decltype(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + break; + case 'S': + t = parse_substitution(first, last, db); + if (t != first) + first = t; + else + { + if (last - first > 2 && first[1] == 't') + { + t = parse_unqualified_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "std::"); + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + } + break; + } } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// ::= # e.g., ~T or ~decltype(f()) +// ::= # e.g., ~A<2*N> + +template +const char* +parse_destructor_name(const char* first, const char* last, C& db) +{ + if (first != last) { - if (__left_) - { - *buf++ = '*'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_unresolved_type(first, last, db); + if (t == first) + t = parse_simple_id(first, last, db); + if (t != first) { - strncpy(buf, "operator*", sizeof("operator*") - 1); - buf += sizeof("operator*") - 1; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "~"); + first = t; } - 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; - } -}; + return first; +} -class __operator_divide - : public __node -{ -public: +// ::= # unresolved name +// extension ::= # unresolved operator-function-id +// extension ::= # unresolved operator template-id +// ::= on # unresolved operator-function-id +// ::= on # unresolved operator template-id +// ::= dn # destructor or pseudo-destructor; +// # e.g. ~X or ~X - __operator_divide() {} - __operator_divide(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_base_unresolved_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) { - if (__cached_size_ == -1) + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); + if (first[0] == 'o') + { + const char* t = parse_operator_name(first+2, last, db); + if (t != first+2) + { + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + } + } else - const_cast(__cached_size_) = sizeof("operator/") - 1; - } - return static_cast(__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++ = ')'; + { + const char* t = parse_destructor_name(first+2, last, db); + if (t != first+2) + first = t; + } } else { - strncpy(buf, "operator/", sizeof("operator/") - 1); - buf += sizeof("operator/") - 1; + const char* t = parse_simple_id(first, last, db); + if (t == first) + { + t = parse_operator_name(first, last, db); + if (t != first) + { + first = parse_template_args(t, last, db); + if (first != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + } + } + } + else + first = t; } - 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; - } -}; + return first; +} -class __operator_divide_equal - : public __node +// ::= + +template +const char* +parse_unresolved_qualifier_level(const char* first, const char* last, C& db) { -public: + return parse_simple_id(first, last, db); +} - __operator_divide_equal() {} - __operator_divide_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +// +// extension ::= srN [] * E +// ::= [gs] # x or (with "gs") ::x +// ::= [gs] sr + E +// # A::x, N::y, A::z; "gs" means leading "::" +// ::= sr # T::x / decltype(p)::x +// extension ::= sr +// # T::N::x /decltype(p)::N::x +// (ignored) ::= srN + E + +template +const char* +parse_unresolved_name(const char* first, const char* last, C& db) +{ + if (last - first > 2) { - if (__cached_size_ == -1) + const char* t = first; + bool global = false; + if (t[0] == 'g' && t[1] == 's') { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator/=") - 1; + global = true; + t += 2; } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) + const char* t2 = parse_base_unresolved_name(t, last, db); + if (t2 != t) { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") /= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; + if (global) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "::"); + } + first = t2; } - else + else if (last - t > 2 && t[0] == 's' && t[1] == 'r') { - strncpy(buf, "operator/=", sizeof("operator/=") - 1); - buf += sizeof("operator/=") - 1; + if (t[2] == 'N') + { + t += 3; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + t = t1; + if (t == last) + { + db.names.pop_back(); + return first; + } + } + while (*t != 'E') + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + t = t1; + } + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + else + { + t += 2; + const char* t1 = parse_unresolved_type(t, last, db); + if (t1 != t) + { + t = t1; + t1 = parse_template_args(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + t = t1; + } + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + else + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + if (global) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "::"); + } + while (*t != 'E') + { + t1 = parse_unresolved_qualifier_level(t, last, db); + if (t1 == t || t1 == last || db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + t = t1; + } + ++t; + t1 = parse_base_unresolved_name(t, last, db); + if (t1 == t) + { + if (!db.names.empty()) + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto s = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "::" + std::move(s); + first = t1; + } + } } - 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; - } -}; + return first; +} -class __operator_xor - : public __node -{ -public: +// dt # expr.name - __operator_xor() {} - __operator_xor(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_dot_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'd' && first[1] == 't') { - if (__cached_size_ == -1) + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator^") - 1; + const char* t1 = parse_unresolved_name(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "." + name; + first = t1; + } } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// cl + E # call + +template +const char* +parse_call_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") ^ (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - 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; + if (t == last) + return first; + if (db.names.empty()) + return first; + db.names.back().first += db.names.back().second; + db.names.back().second = typename C::String(); + db.names.back().first.append("("); + bool first_expr = true; + while (*t != 'E') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + if (!first_expr) + { + db.names.back().first.append(", "); + first_expr = false; + } + db.names.back().first.append(tmp); + } + t = t1; + } + ++t; + if (db.names.empty()) + return first; + db.names.back().first.append(")"); + first = t; + } } -}; + return first; +} -class __operator_xor_equal - : public __node -{ -public: +// [gs] nw * _ E # new (expr-list) type +// [gs] nw * _ # new (expr-list) type (init) +// [gs] na * _ E # new[] (expr-list) type +// [gs] na * _ # new[] (expr-list) type (init) +// ::= pi * E # parenthesized initialization - __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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator^=") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const +template +const char* +parse_new_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 4) { - if (__left_) + const char* t = first; + bool parsed_gs = false; + if (t[0] == 'g' && t[1] == 's') { - *buf++ = '('; // strncpy(buf, "(", 1); - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") ^= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; + t += 2; + parsed_gs = true; } - else + if (t[0] == 'n' && (t[1] == 'w' || t[1] == 'a')) { - strncpy(buf, "operator^=", sizeof("operator^=") - 1); - buf += sizeof("operator^=") - 1; + bool is_array = t[1] == 'a'; + t += 2; + if (t == last) + return first; + bool has_expr_list = false; + bool first_expr = true; + while (*t != '_') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + has_expr_list = true; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + ++t; + const char* t1 = parse_type(t, last, db); + if (t1 == t || t1 == last) + return first; + t = t1; + bool has_init = false; + if (last - t >= 3 && t[0] == 'p' && t[1] == 'i') + { + t += 2; + has_init = true; + first_expr = true; + while (*t != 'E') + { + t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + } + if (*t != 'E') + return first; + typename C::String init_list; + if (has_init) + { + if (db.names.empty()) + return first; + init_list = db.names.back().move_full(); + db.names.pop_back(); + } + if (db.names.empty()) + return first; + auto type = db.names.back().move_full(); + db.names.pop_back(); + typename C::String expr_list; + if (has_expr_list) + { + if (db.names.empty()) + return first; + expr_list = db.names.back().move_full(); + db.names.pop_back(); + } + typename C::String r; + if (parsed_gs) + r = "::"; + if (is_array) + r += "[] "; + else + r += " "; + if (has_expr_list) + r += "(" + expr_list + ") "; + r += type; + if (has_init) + r += " (" + init_list + ")"; + db.names.push_back(std::move(r)); + first = t+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; } -}; + return first; +} -class __operator_equality - : public __node -{ -public: +// cv # conversion with one argument +// cv _ * E # conversion with a different number of arguments - __operator_equality() {} - __operator_equality(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_conversion_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { - if (__cached_size_ == -1) + bool try_to_parse_template_args = db.try_to_parse_template_args; + db.try_to_parse_template_args = false; + const char* t = parse_type(first+2, last, db); + db.try_to_parse_template_args = try_to_parse_template_args; + if (t != first+2 && t != last) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); + if (*t != '_') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t) + return first; + t = t1; + } else - const_cast(__cached_size_) = sizeof("operator==") - 1; + { + ++t; + if (t == last) + return first; + if (*t == 'E') + db.names.emplace_back(); + else + { + bool first_expr = true; + while (*t != 'E') + { + const char* t1 = parse_expression(t, last, db); + if (t1 == t || t1 == last) + return first; + if (!first_expr) + { + if (db.names.empty()) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + first_expr = false; + } + } + t = t1; + } + } + ++t; + } + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")"; + first = t; } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// pt # expr->name + +template +const char* +parse_arrow_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'p' && first[1] == 't') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") == (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - strncpy(buf, "operator==", sizeof("operator==") - 1); - buf += sizeof("operator==") - 1; + const char* t1 = parse_expression(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += "->"; + db.names.back().first += tmp; + first = t1; + } } - 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; - } -}; + return first; +} -class __operator_greater_equal - : public __node -{ -public: +// ::= R # & ref-qualifier +// ::= O # && ref-qualifier - __operator_greater_equal() {} - __operator_greater_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +// ::= F [Y] [] E + +template +const char* +parse_function_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'F') { - if (__cached_size_ == -1) + const char* t = first+1; + if (t != last) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator>=") - 1; + bool externC = false; + if (*t == 'Y') + { + externC = true; + if (++t == last) + return first; + } + const char* t1 = parse_type(t, last, db); + if (t1 != t) + { + t = t1; + typename C::String sig("("); + int ref_qual = 0; + while (true) + { + if (t == last) + { + db.names.pop_back(); + return first; + } + if (*t == 'E') + { + ++t; + break; + } + if (*t == 'v') + { + ++t; + continue; + } + if (*t == 'R' && t+1 != last && t[1] == 'E') + { + ref_qual = 1; + ++t; + continue; + } + if (*t == 'O' && t+1 != last && t[1] == 'E') + { + ref_qual = 2; + ++t; + continue; + } + size_t k0 = db.names.size(); + t1 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t1 == t || t1 == last) + return first; + for (size_t k = k0; k < k1; ++k) + { + if (sig.size() > 1) + sig += ", "; + sig += db.names[k].move_full(); + } + for (size_t k = k0; k < k1; ++k) + db.names.pop_back(); + t = t1; + } + sig += ")"; + switch (ref_qual) + { + case 1: + sig += " &"; + break; + case 2: + sig += " &&"; + break; + } + if (db.names.empty()) + return first; + db.names.back().first += " "; + db.names.back().second.insert(0, sig); + first = t; + } } - return static_cast(__cached_size_); } - virtual char* first_demangled_name(char* buf) const + return first; +} + +// ::= M + +template +const char* +parse_pointer_to_member_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'M') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") >= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + const char* t = parse_type(first+1, last, db); + if (t != first+1) { - strncpy(buf, "operator>=", sizeof("operator>=") - 1); - buf += sizeof("operator>=") - 1; + const char* t2 = parse_type(t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto func = std::move(db.names.back()); + db.names.pop_back(); + auto class_type = std::move(db.names.back()); + if (func.second.front() == '(') + { + db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; + db.names.back().second = ")" + std::move(func.second); + } + else + { + db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; + db.names.back().second = std::move(func.second); + } + first = t2; + } } - 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; - } -}; + return first; +} -class __operator_greater - : public __node -{ -public: +// ::= A _ +// ::= A [] _ - __operator_greater() {} - __operator_greater(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const +template +const char* +parse_array_type(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'A' && first+1 != last) { - if (__cached_size_ == -1) + if (first[1] == '_') { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 9 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator>") - 1; + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + if (db.names.back().second.substr(0, 2) == " [") + db.names.back().second.erase(0, 1); + db.names.back().second.insert(0, " []"); + first = t; + } } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator<=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator<") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) + else if ('1' <= first[1] && first[1] <= '9') { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") < (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; + const char* t = parse_number(first+1, last); + if (t != last && *t == '_') + { + const char* t2 = parse_type(t+1, last, db); + if (t2 != t+1) + { + if (db.names.empty()) + return first; + if (db.names.back().second.substr(0, 2) == " [") + db.names.back().second.erase(0, 1); + db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]"); + first = t2; + } + } } else { - strncpy(buf, "operator<", sizeof("operator<") - 1); - buf += sizeof("operator<") - 1; + const char* t = parse_expression(first+1, last, db); + if (t != first+1 && t != last && *t == '_') + { + const char* t2 = parse_type(++t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto type = std::move(db.names.back()); + db.names.pop_back(); + auto expr = std::move(db.names.back()); + db.names.back().first = std::move(type.first); + if (type.second.substr(0, 2) == " [") + type.second.erase(0, 1); + db.names.back().second = " [" + expr.move_full() + "]" + std::move(type.second); + first = t2; + } + } } - 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: + return first; +} - __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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator<<") - 1; - } - return static_cast(__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; - } -}; +// ::= Dt E # decltype of an id-expression or class member access (C++0x) +// ::= DT E # decltype of an expression (C++0x) -class __operator_left_shift_equal - : public __node +template +const char* +parse_decltype(const char* first, const char* last, C& db) { -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(__cached_size_) = static_cast( - __left_->size() + 9 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator<<=") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const + if (last - first >= 4 && first[0] == 'D') { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") <<= (", 7); - buf += 7; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else + switch (first[1]) { - strncpy(buf, "operator<<=", sizeof("operator<<=") - 1); - buf += sizeof("operator<<=") - 1; + case 't': + case 'T': + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2 && t != last && *t == 'E') + { + if (db.names.empty()) + return first; + db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + first = t+1; + } + } + break; } - 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: + return first; +} - __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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator-") - 1; - } - return static_cast(__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; - } -}; +// extension: +// ::= Dv _ +// +// ::= Dv [] _ +// ::= +// ::= p # AltiVec vector pixel -class __operator_minus_equal - : public __node +template +const char* +parse_vector_type(const char* first, const char* last, C& db) { -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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator-=") - 1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const + if (last - first > 3 && first[0] == 'D' && first[1] == 'v') { - if (__left_) + if ('1' <= first[2] && first[2] <= '9') { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") -= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; + const char* t = parse_number(first+2, last); + if (t == last || *t != '_') + return first; + const char* num = first + 2; + size_t sz = static_cast(t - num); + if (++t != last) + { + if (*t != 'p') + { + const char* t1 = parse_type(t, last, db); + if (t1 != t) + { + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + first = t1; + } + } + else + { + ++t; + db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + first = t; + } + } } else { - strncpy(buf, "operator-=", sizeof("operator-=") - 1); - buf += sizeof("operator-=") - 1; + typename C::String num; + const char* t1 = first+2; + if (*t1 != '_') + { + const char* t = parse_expression(t1, last, db); + if (t != t1) + { + if (db.names.empty()) + return first; + num = db.names.back().move_full(); + db.names.pop_back(); + t1 = t; + } + } + if (t1 != last && *t1 == '_' && ++t1 != last) + { + const char* t = parse_type(t1, last, db); + if (t != t1) + { + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + num + "]"; + first = t; + } + } } - 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; } -}; + return first; +} -class __operator_times - : public __node -{ -public: +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= +// ::= P # pointer-to +// ::= R # reference-to +// ::= O # rvalue reference-to (C++0x) +// ::= C # complex pair (C 2000) +// ::= G # imaginary (C 2000) +// ::= Dp # pack expansion (C++0x) +// ::= U # vendor extended type qualifier +// extension := U # objc-type +// extension := # starts with Dv - __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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator*") - 1; - } - return static_cast(__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; - } -}; +// ::= objcproto # k0 = 9 + + k1 +// := # PU<11+>objcproto 11objc_object 11objc_object -> id -class __operator_times_equal - : public __node +template +const char* +parse_type(const char* first, const char* last, C& db) { -public: - - __operator_times_equal() {} - __operator_times_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const + if (first != last) { - if (__cached_size_ == -1) + switch (*first) { - if (__left_) - const_cast(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator*=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(4 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator--") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator!=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(3 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator-") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(3 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator!") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator||") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator|") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator|=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 9 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator->*") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator+") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator+=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(4 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator++") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(3 + __left_->size()); - else - const_cast(__cached_size_) = sizeof("operator+") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator->") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - op1->size() + - __left_->size() + 12 + - __right_->size()); - } - else - const_cast(__cached_size_) = sizeof("operator?") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 7 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator%") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator%=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 8 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator>>") - 1; - } - return static_cast(__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(__cached_size_) = static_cast( - __left_->size() + 9 + - __right_->size()); - else - const_cast(__cached_size_) = sizeof("operator>>=") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(__right_->size() + 9); - else - const_cast(__cached_size_) = sizeof("operator sizeof") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(__right_->size() + 9); - else - const_cast(__cached_size_) = sizeof("operator sizeof") - 1; - } - return static_cast(__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(__cached_size_) = static_cast(__right_->size() + 8); - return static_cast(__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(__cached_size_) = static_cast(__right_->size() + 6); - return static_cast(__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(__cached_size_) = static_cast(__right_->size() + 11); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 14 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 16 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 20 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 15 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(off); - } - return static_cast(__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(__cached_size_) = static_cast((__size_ ? 2 : 0) + - 9 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast((__size_ ? 2 : 0) + - 7 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(off); - } - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 2 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 1 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - 2 + __right_->size()); - return static_cast(__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, std::allocator >") - 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, std::allocator >", 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_) = true; - return const_cast<__node*>(static_cast(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 - { - if (__left_ == 0) - return false; - 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_ < static_cast(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(__cached_size_) = static_cast(__left_->size() + - __right_->size()); - return static_cast(__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(__cached_size_) = 0; - else if (__right_ == NULL) - const_cast(__cached_size_) = static_cast(__left_->size()); - else - { - size_t off = __right_->size(); - if (off > 0) - off += 2; - const_cast(__cached_size_) = static_cast(__left_->size() + off); - } - } - return static_cast(__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_ && __right_->size() > 0) - { - return __right_->ends_with_template(parsing); - } - else if (__left_ && __left_->size() > 0) - { - 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(__cached_size_) = static_cast(__left_->size() + off); - } - return static_cast(__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(__cached_size_) = static_cast(2 + __right_->size()); - return static_cast(__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 ___lambda_node - : public __node -{ -public: - ___lambda_node(__node* params, const char *number, size_t number_size) - { - __right_ = params; - __name_ = number; - __size_ = number_size; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - size_t r = 2; - r += sizeof("'lambda'")-1; - if (__right_) - r += __right_->size(); - r += __size_; - const_cast(__cached_size_) = static_cast(r); - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - size_t n = sizeof("'lambda") - 1; - strncpy(buf, "'lambda", n); - buf += n; - if (__size_) - { - strncpy(buf, __name_, __size_); - buf += __size_; - } - *buf++ = '\''; - *buf++ = '('; - if (__right_) - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - 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 __unnamed - : public __node -{ -public: - __unnamed(const char *number, size_t number_size) - { - __name_ = number; - __size_ = number_size; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - size_t r = 0; - r += sizeof("'unnamed'")-1; - r += __size_; - const_cast(__cached_size_) = static_cast(r); - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - size_t n = sizeof("'unnamed") - 1; - strncpy(buf, "'unnamed", n); - buf += n; - if (__size_) - { - strncpy(buf, __name_, __size_); - buf += __size_; - } - *buf++ = '\''; - return buf; - } -}; - -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(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(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(__cached_size_) = static_cast(off); - } - return static_cast(__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(__cached_size_) = static_cast(n + __left_->size()); - return static_cast(__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(__cached_size_) = static_cast(n + __left_->size()); - return static_cast(__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(__cached_size_) = static_cast(off); - } - return static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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_ = static_cast(__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 __signed_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_ = static_cast(__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_ = static_cast(__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(__value_); - const_cast(__cached_size_) = sprintf(num, "%a", v)+1; - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - char num[20] = {0}; - float v = static_cast(__value_); - int n = sprintf(num, "%a", v); - strncpy(buf, num, static_cast(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(__value_); - const_cast(__cached_size_) = sprintf(num, "%a", v); - } - return static_cast(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - char num[30] = {0}; - double v = static_cast(__value_); - int n = sprintf(num, "%a", v); - strncpy(buf, num, static_cast(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 += static_cast(snprintf(0, 0, "%ld", __size_)); - const_cast(__cached_size_) = static_cast(r); - } - return static_cast(__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) - { - int 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 += static_cast(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) - { - int 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(__cached_size_) = static_cast(__left_->size() + 3 - + __right_->first_size() - + __right_->second_size()); - return static_cast(__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(__cached_size_) = static_cast(10 + __right_->size()); - return static_cast(__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(__cached_size_) = static_cast(__left_->size() + - __right_->size() + 2); - return static_cast(__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*&) 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(__cached_size_) = static_cast((__left_ ? - __left_->size() + 2 : 0) + - __right_->size() + __size_ * 2); - return static_cast(__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*&) 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(__cached_size_) = static_cast(__right_->base_size()); - return static_cast(__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(__cached_size_) = static_cast(__right_->base_size() + 1); - return static_cast(__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, size_t 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(__cached_size_) = static_cast(off); - } - return static_cast(__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(__cached_size_) = static_cast(off); - } - return static_cast(__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(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(__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 -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 -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 -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 -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 -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 -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 -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; -} - -// ::= [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; -} - -// ::= 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 # 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<__signed_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; -} - -// ::= + -// # 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) - { - bool prev_tag_templates = __tag_templates_; - __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_ = prev_tag_templates; - } - return first; -} - -// ::= F [Y] 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 + static_cast(*t - '0'); - else if (isupper(*t)) - n = n * 16 + static_cast(*t - 'A') + 10; - else - n = n * 16 + static_cast(*t - 'a') + 10; - } - first = t; - return first; -} - -// ::= L E # integer literal -// ::= L E # floating literal -// ::= L E # string literal -// ::= L E # nullptr literal (i.e., "LDnE") -// ::= L _ E # complex floating point literal (C 2000) -// ::= L 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", 5u)) - first += 4; - break; - case '1': - if (__make<__bool_literal>("true", 4u)) - 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(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; - case 'T': - // Invalid mangled name per - // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html - 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; -} - -// ::= Ut [ ] _ -// ::= -// -// ::= Ul E [ ] _ -// -// ::= + # 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') - { - char type = first[1]; - switch (type) - { - case 't': - case 'l': - { - const char* t = first + 2; - __node* params = 0; - if (type == 'l') - { - if (*t == 'v') - { - // void lambda - ++t; - if (t != last && *t == 'E') - ++t; - else - return first; - } - else - { - const char* t1 = __parse_type(t, last); - if (t1 == t || !__make<__list>(__root_)) - return first; - params = __root_; - __node* prev = params; - t = t1; - while (true) - { - t1 = __parse_type(t, last); - if (t1 == t) - break; - if (!__make<__list>(__root_)) - return first; - t = t1; - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; - prev = __root_; - } - if (t == last || *t != 'E') - return first; - ++t; - } - } - const char* number_start = t; - const char* number_end = __parse_number(t, last); - if (number_end == last || *number_end != '_') - return first; - t = number_end + 1; - if (type == 'l') - { - if (!__make<___lambda_node>(params, number_start, static_cast(number_end - number_start))) - return first; - } - else - { - if (!__make<__unnamed>(number_start, static_cast(number_end - number_start))) - return first; - } - first = t; - } - break; - } - } - return first; -} - -// ::= 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 && __root_) - { - 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*) -{ -// assert(!"__parse_unscoped_template_name not implemented"); - __status_ = not_yet_implemented; - return first; -} - -// := _ # when number < 10 -// := __ _ # 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; -} - -// := Z E [] -// := Z E s [] -// := Z Ed [ ] _ - -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; -} - -// ::= # e.g., ~T or ~decltype(f()) -// ::= # 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; -} - -// ::= [ ] - -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; -} - -// ::= # unresolved name -// extension ::= # unresolved operator-function-id -// extension ::= # unresolved operator template-id -// ::= on # unresolved operator-function-id -// ::= on # unresolved operator template-id -// ::= dn # destructor or pseudo-destructor; -// # e.g. ~X or ~X - -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; -} - -// ::= -// ::= -// ::= - -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; -} - -// ::= [ ] - -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; -} - -// -// extension ::= srN [] * E -// ::= [gs] # x or (with "gs") ::x -// ::= [gs] sr + E -// # A::x, N::y, A::z; "gs" means leading "::" -// ::= sr # T::x / decltype(p)::x -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN + E - -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; -} - -// ::= fp _ # L == 0, first parameter -// ::= fp _ # L == 0, second and later parameters -// ::= fL p _ # L > 0, first parameter -// ::= fL p - -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 # 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 # const_cast (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 + 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 # conversion with one argument -// cv _ * 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 # 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 # dynamic_cast (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 # 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 # 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 # 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_ # 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_ # 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 * _ E # new (expr-list) type -// [gs] nw * _ # new (expr-list) type (init) -// [gs] na * _ E # new[] (expr-list) type -// [gs] na * _ # new[] (expr-list) type (init) -// ::= pi * 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') + case 'r': + case 'V': + case 'K': + { + unsigned cv = 0; + const char* t = parse_cv_qualifiers(first, last, cv); + if (t != first) { - 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) + bool is_function = *t == 'F'; + size_t k0 = db.names.size(); + const char* t1 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t1 != t) { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; + if (is_function) + db.subs.pop_back(); + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (is_function) + { + size_t p = db.names[k].second.size(); + if (db.names[k].second[p-2] == '&') + p -= 3; + else if (db.names[k].second.back() == '&') + p -= 2; + if (cv & 1) + { + db.names[k].second.insert(p, " const"); + p += 6; + } + if (cv & 2) + { + db.names[k].second.insert(p, " volatile"); + p += 9; + } + if (cv & 4) + db.names[k].second.insert(p, " restrict"); + } + else + { + if (cv & 1) + db.names[k].first.append(" const"); + if (cv & 2) + db.names[k].first.append(" volatile"); + if (cv & 4) + db.names[k].first.append(" restrict"); + } + db.subs.back().push_back(db.names[k]); + } + first = t1; } - 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 # 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 # reinterpret_cast (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 # static_cast (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 # 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 # 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 # 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 # 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 # typeid (expression) -// ti # 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 # 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; + } + break; + default: + { + const char* t = parse_builtin_type(first, last, db); + if (t != first) + { + first = t; + } + else + { + switch (*first) + { + case 'A': + t = parse_array_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'C': + t = parse_type(first+1, last, db); + if (t != first+1) + { + if (db.names.empty()) + return first; + db.names.back().first.append(" complex"); + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'F': + t = parse_function_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'G': + t = parse_type(first+1, last, db); + if (t != first+1) + { + if (db.names.empty()) + return first; + db.names.back().first.append(" imaginary"); + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'M': + t = parse_pointer_to_member_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + first = t; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + } + break; + case 'O': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + db.names[k].first.append("&&"); + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'P': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + if (first[1] != 'U' || db.names[k].first.substr(0, 12) != "objc_object<") + { + db.names[k].first.append("*"); + } + else + { + db.names[k].first.replace(0, 11, "id"); + } + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'R': + { + size_t k0 = db.names.size(); + t = parse_type(first+1, last, db); + size_t k1 = db.names.size(); + if (t != first+1) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + { + if (db.names[k].second.substr(0, 2) == " [") + { + db.names[k].first += " ("; + db.names[k].second.insert(0, ")"); + } + else if (db.names[k].second.front() == '(') + { + db.names[k].first += "("; + db.names[k].second.insert(0, ")"); + } + db.names[k].first.append("&"); + db.subs.back().push_back(db.names[k]); + } + first = t; + } + break; + } + case 'T': + { + size_t k0 = db.names.size(); + t = parse_template_param(first, last, db); + size_t k1 = db.names.size(); + if (t != first) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.subs.back().push_back(db.names[k]); + if (db.try_to_parse_template_args && k1 == k0+1) + { + const char* t1 = parse_template_args(t, last, db); + if (t1 != t) + { + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t = t1; + } + } + first = t; + } + break; + } + case 'U': + if (first+1 != last) + { + t = parse_source_name(first+1, last, db); + if (t != first+1) + { + const char* t2 = parse_type(t, last, db); + if (t2 != t) + { + if (db.names.size() < 2) + return first; + auto type = db.names.back().move_full(); + db.names.pop_back(); + if (db.names.back().first.substr(0, 9) != "objcproto") + { + db.names.back() = type + " " + db.names.back().move_full(); + } + else + { + auto proto = db.names.back().move_full(); + db.names.pop_back(); + t = parse_source_name(proto.data() + 9, proto.data() + proto.size(), db); + if (t != proto.data() + 9) + { + db.names.back() = type + "<" + db.names.back().move_full() + ">"; + } + else + { + db.names.push_back(type + " " + proto); + } + } + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t2; + } + } + } + break; + case 'S': + if (first+1 != last && first[1] == 't') + { + t = parse_name(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + else + { + t = parse_substitution(first, last, db); + if (t != first) + { + first = t; + // Parsed a substitution. If the substitution is a + // it might be followed by . + t = parse_template_args(first, last, db); + if (t != first) + { + if (db.names.size() < 2) + return first; + auto template_args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += template_args; + // Need to create substitution for + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + } + break; + case 'D': + if (first+1 != last) + { + switch (first[1]) + { + case 'p': + { + size_t k0 = db.names.size(); + t = parse_type(first+2, last, db); + size_t k1 = db.names.size(); + if (t != first+2) + { + db.subs.emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.subs.back().push_back(db.names[k]); + first = t; + return first; + } + break; + } + case 't': + case 'T': + t = parse_decltype(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + return first; + } + break; + case 'v': + t = parse_vector_type(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + 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, db); + if (t != first) + { + first = t; + } + else + { + t = parse_name(first, last, db); + if (t != first) + { + if (db.names.empty()) + return first; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; + } + } + break; + } + } + break; + } } } return first; } -// ::= -// ::= -// ::= -// ::= cl + E # call -// ::= cv # conversion with one argument -// ::= cv _ * E # conversion with a different number of arguments -// ::= [gs] nw * _ E # new (expr-list) type -// ::= [gs] nw * _ # new (expr-list) type (init) -// ::= [gs] na * _ E # new[] (expr-list) type -// ::= [gs] na * _ # new[] (expr-list) type (init) -// ::= [gs] dl # delete expression -// ::= [gs] da # delete[] expression -// ::= pp_ # prefix ++ -// ::= mm_ # prefix -- -// ::= ti # typeid (type) -// ::= te # typeid (expression) -// ::= dc # dynamic_cast (expression) -// ::= sc # static_cast (expression) -// ::= cc # const_cast (expression) -// ::= rc # reinterpret_cast (expression) -// ::= st # sizeof (a type) -// ::= at # alignof (a type) -// ::= -// ::= -// ::= dt # expr.name -// ::= pt # expr->name -// ::= ds # expr.*expr -// ::= sZ # size of a parameter pack -// ::= sZ # size of a function parameter pack -// ::= sp # pack expansion -// ::= tw # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= - +// +// ::= aa # && +// ::= ad # & (unary) +// ::= an # & +// ::= aN # &= +// ::= aS # = +// ::= cl # () +// ::= cm # , +// ::= co # ~ +// ::= cv # (cast) +// ::= da # delete[] +// ::= de # * (unary) +// ::= dl # delete +// ::= dv # / +// ::= dV # /= +// ::= eo # ^ +// ::= eO # ^= +// ::= eq # == +// ::= ge # >= +// ::= gt # > +// ::= ix # [] +// ::= le # <= +// ::= li # operator "" +// ::= ls # << +// ::= lS # <<= +// ::= lt # < +// ::= mi # - +// ::= mI # -= +// ::= ml # * +// ::= mL # *= +// ::= mm # -- (postfix in context) +// ::= na # new[] +// ::= ne # != +// ::= ng # - (unary) +// ::= nt # ! +// ::= nw # new +// ::= oo # || +// ::= or # | +// ::= oR # |= +// ::= pm # ->* +// ::= pl # + +// ::= pL # += +// ::= pp # ++ (postfix in context) +// ::= ps # + (unary) +// ::= pt # -> +// ::= qu # ? +// ::= rm # % +// ::= rM # %= +// ::= rs # >> +// ::= rS # >>= +// ::= v # vendor extended operator + +template const char* -__demangle_tree::__parse_expression(const char* first, const char* last) +parse_operator_name(const char* first, const char* last, C& db) { 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) + switch (first[0]) { - 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); + switch (first[1]) + { + case 'a': + db.names.push_back("operator&&"); + first += 2; + break; + case 'd': + case 'n': + db.names.push_back("operator&"); + first += 2; + break; + case 'N': + db.names.push_back("operator&="); + first += 2; + break; + case 'S': + db.names.push_back("operator="); + first += 2; + break; + } break; case 'c': - switch (t[1]) + switch (first[1]) { - case 'c': - t = __parse_const_cast_expr(first, last); - break; case 'l': - t = __parse_call_expr(first, last); + db.names.push_back("operator()"); + first += 2; + break; + case 'm': + db.names.push_back("operator,"); + first += 2; + break; + case 'o': + db.names.push_back("operator~"); + first += 2; break; case 'v': - t = __parse_conversion_expr(first, last); + { + bool try_to_parse_template_args = db.try_to_parse_template_args; + db.try_to_parse_template_args = false; + const char* t = parse_type(first+2, last, db); + db.try_to_parse_template_args = try_to_parse_template_args; + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator "); + db.parsed_ctor_dtor_cv = true; + first = t; + } + } break; } break; case 'd': - switch (t[1]) + switch (first[1]) { case 'a': - t = __parse_delete_array_expr(first, last); + db.names.push_back("operator delete[]"); + first += 2; break; - case 'c': - t = __parse_dynamic_cast_expr(first, last); + case 'e': + db.names.push_back("operator*"); + first += 2; break; case 'l': - t = __parse_delete_expr(first, last); + db.names.push_back("operator delete"); + first += 2; break; - case 's': - t = __parse_dot_star_expr(first, last); + case 'v': + db.names.push_back("operator/"); + first += 2; break; - case 't': - t = __parse_dot_expr(first, last); + case 'V': + db.names.push_back("operator/="); + first += 2; break; } break; - case 'm': - t = __parse_decrement_expr(first, last); + case 'e': + switch (first[1]) + { + case 'o': + db.names.push_back("operator^"); + first += 2; + break; + case 'O': + db.names.push_back("operator^="); + first += 2; + break; + case 'q': + db.names.push_back("operator=="); + first += 2; + break; + } break; - case 'n': - switch (t[1]) + case 'g': + switch (first[1]) { - case 'a': - case 'w': - t = __parse_new_expr(first, last); + case 'e': + db.names.push_back("operator>="); + first += 2; + break; + case 't': + db.names.push_back("operator>"); + first += 2; break; } break; - case 'p': - switch (t[1]) + case 'i': + if (first[1] == 'x') { - case 'p': - t = __parse_increment_expr(first, last); + db.names.push_back("operator[]"); + first += 2; + } + break; + case 'l': + switch (first[1]) + { + case 'e': + db.names.push_back("operator<="); + first += 2; + break; + case 'i': + { + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator\"\" "); + first = t; + } + } + break; + case 's': + db.names.push_back("operator<<"); + first += 2; + break; + case 'S': + db.names.push_back("operator<<="); + first += 2; break; case 't': - t = __parse_arrow_expr(first, last); + db.names.push_back("operator<"); + first += 2; + break; + } + break; + case 'm': + switch (first[1]) + { + case 'i': + db.names.push_back("operator-"); + first += 2; + break; + case 'I': + db.names.push_back("operator-="); + first += 2; + break; + case 'l': + db.names.push_back("operator*"); + first += 2; + break; + case 'L': + db.names.push_back("operator*="); + first += 2; + break; + case 'm': + db.names.push_back("operator--"); + first += 2; break; } break; - case 'r': - t = __parse_reinterpret_cast_expr(first, last); - break; - case 's': - switch (t[1]) + case 'n': + switch (first[1]) { - case 'c': - t = __parse_static_cast_expr(first, last); + case 'a': + db.names.push_back("operator new[]"); + first += 2; break; - case 'p': - t = __parse_pack_expansion(first, last); + case 'e': + db.names.push_back("operator!="); + first += 2; + break; + case 'g': + db.names.push_back("operator-"); + first += 2; break; case 't': - t = __parse_sizeof_type_expr(first, last); + db.names.push_back("operator!"); + first += 2; 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; - } - } + case 'w': + db.names.push_back("operator new"); + first += 2; break; } break; - case 't': - switch (t[1]) + case 'o': + switch (first[1]) { - case 'e': - case 'i': - t = __parse_typeid_expr(first, last); + case 'o': + db.names.push_back("operator||"); + first += 2; break; case 'r': - if (__make<__rethrow>()) - t = first +2; + db.names.push_back("operator|"); + first += 2; break; - case 'w': - t = __parse_throw_expr(first, last); + case 'R': + db.names.push_back("operator|="); + first += 2; 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; -} - -// ::= A _ -// ::= A [] _ - -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 = static_cast(first[1] - '0'); - const char* t = first+2; - for (; t != last && isdigit(*t); ++t) - dim = dim * 10 + static_cast(*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; -} - -// ::= - -const char* -__demangle_tree::__parse_class_enum_type(const char* first, const char* last) -{ - return __parse_name(first, last); -} - -// ::= M - -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; -} - -// ::= Dt E # decltype of an id-expression or class member access (C++0x) -// ::= DT 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': + case 'p': + switch (first[1]) { - const char* t = __parse_expression(first+2, last); - if (t != first+2 && t != last && *t == 'E') - { - if (__make<__decltype_node>(__root_)) - first = t+1; - } + case 'm': + db.names.push_back("operator->*"); + first += 2; + break; + case 'l': + db.names.push_back("operator+"); + first += 2; + break; + case 'L': + db.names.push_back("operator+="); + first += 2; + break; + case 'p': + db.names.push_back("operator++"); + first += 2; + break; + case 's': + db.names.push_back("operator+"); + first += 2; + break; + case 't': + db.names.push_back("operator->"); + first += 2; + break; } break; - } - } - return first; -} - -// ::= T_ # first template parameter -// ::= T _ - -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 = static_cast(*t - '0'); - for (++t; t != last && isdigit(*t); ++t) - { - sub *= 10; - sub += static_cast(*t - '0'); - } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < static_cast(__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: -// ::= Dv _ -// -// ::= Dv [] _ -// ::= -// ::= 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 = static_cast(t - num); - if (++t != last) + case 'q': + if (first[1] == 'u') { - 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; - } + db.names.push_back("operator?"); + first += 2; } - } - else - { - __node* num = 0; - const char* t1 = first+2; - if (*t1 != '_') + break; + case 'r': + switch (first[1]) { - const char* t = __parse_expression(t1, last); - if (t != t1) - num = __root_; - t1 = t; + case 'm': + db.names.push_back("operator%"); + first += 2; + break; + case 'M': + db.names.push_back("operator%="); + first += 2; + break; + case 's': + db.names.push_back("operator>>"); + first += 2; + break; + case 'S': + db.names.push_back("operator>>="); + first += 2; + break; } - if (t1 != last && *t1 == '_' && ++t1 != last) + break; + case 'v': + if (std::isdigit(first[1])) { - const char* t = __parse_type(t1, last); - if (t != t1) + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) { - if (__make<__vector_type>(__root_, num)) - first = t; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator "); + first = t; } } + break; } } return first; } -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= -// ::= P # pointer-to -// ::= R # reference-to -// ::= O # rvalue reference-to (C++0x) -// ::= C # complex pair (C 2000) -// ::= G # imaginary (C 2000) -// ::= Dp # pack expansion (C++0x) -// ::= U # vendor extended type qualifier -// extension := # starts with Dv - +template const char* -__demangle_tree::__parse_type(const char* first, const char* last, - bool try_to_parse_template_args, - bool look_for_ref_quals) +parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) { - unsigned cv = 0; - const char* t = __parse_cv_qualifiers(first, last, cv, look_for_ref_quals); - if (t != first) + const char* t = parse_number(first, last); + if (t != first && t != last && *t == 'E') { - const char* t2 = __parse_type(t, last, try_to_parse_template_args); - if (t2 != t) + if (lit.size() > 3) + db.names.push_back("(" + lit + ")"); + else + db.names.emplace_back(); + if (*first == 'n') { - if (__make<__cv_qualifiers>(cv, __root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t2; - } - } + db.names.back().first += '-'; + ++first; } - return first; + db.names.back().first.append(first, t); + if (lit.size() <= 3) + db.names.back().first += lit; + first = t+1; } - if (first != last) + return first; +} + +// ::= L E # integer literal +// ::= L E # floating literal +// ::= L E # string literal +// ::= L E # nullptr literal (i.e., "LDnE") +// ::= L _ E # complex floating point literal (C 2000) +// ::= L E # external name + +template +const char* +parse_expr_primary(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && *first == 'L') { - switch (*first) + switch (first[1]) { - case 'A': - t = __parse_array_type(first, last); - if (t != first) + case 'w': { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + const char* t = parse_integer_literal(first+2, last, "wchar_t", db); + if (t != first+2) + first = t; } break; - case 'C': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'b': + if (first[3] == 'E') { - if (__make<__d_complex>(__root_)) + switch (first[2]) { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + case '0': + db.names.push_back("false"); + first += 4; + break; + case '1': + db.names.push_back("true"); + first += 4; + break; } - return first; } break; - case 'F': - t = __parse_function_type(first, last); - if (t != first) + case 'c': { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + const char* t = parse_integer_literal(first+2, last, "char", db); + if (t != first+2) + first = t; } break; - case 'G': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'a': { - if (__make<__imaginary>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + const char* t = parse_integer_literal(first+2, last, "signed char", db); + if (t != first+2) + first = t; } break; - case 'M': - t = __parse_pointer_to_member_type(first, last); - if (t != first) + case 'h': { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + const char* t = parse_integer_literal(first+2, last, "unsigned char", db); + if (t != first+2) + first = t; } break; - case 'O': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 's': { - if (__make<__rvalue_reference_to>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + const char* t = parse_integer_literal(first+2, last, "short", db); + if (t != first+2) + first = t; } break; - case 'P': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 't': { - if (__make<__pointer_to>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + const char* t = parse_integer_literal(first+2, last, "unsigned short", db); + if (t != first+2) + first = t; } break; - case 'R': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'i': { - if (__make<__lvalue_reference_to>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + const char* t = parse_integer_literal(first+2, last, "", db); + if (t != first+2) + first = t; } break; - case 'T': - t = __parse_template_param(first, last); - if (t != first) + case 'j': { - 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; - } - } + const char* t = parse_integer_literal(first+2, last, "u", db); + if (t != first+2) + first = t; } break; - case 'U': - if (first+1 != last) + case 'l': { - 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; - } - } + const char* t = parse_integer_literal(first+2, last, "l", db); + if (t != first+2) + first = t; } break; - case 'S': - if (first+1 != last && first[1] == 't') + case 'm': { - 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; - } - } + const char* t = parse_integer_literal(first+2, last, "ul", db); + if (t != first+2) + first = t; } - else + break; + case 'x': { - t = __parse_substitution(first, last); - if (t != first) - { - first = t; - // Parsed a substitution. If the substitution is a - // it might be followed by . - t = __parse_template_args(first, last); - if (t != first) - { - // Need to create substitution for - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - } + const char* t = parse_integer_literal(first+2, last, "ll", db); + if (t != first+2) + first = t; } break; - case 'D': - if (first+1 != last) + case 'y': { - 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) + const char* t = parse_integer_literal(first+2, last, "ull", db); + if (t != first+2) + first = t; + } + break; + case 'n': + { + const char* t = parse_integer_literal(first+2, last, "__int128", db); + if (t != first+2) + first = t; + } + break; + case 'o': + { + const char* t = parse_integer_literal(first+2, last, "unsigned __int128", db); + if (t != first+2) + first = t; + } + break; + case 'f': + { + const char* t = parse_floating_number(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'd': + { + const char* t = parse_floating_number(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'e': + { + const char* t = parse_floating_number(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case '_': + if (first[2] == 'Z') + { + const char* t = parse_encoding(first+3, last, db); + if (t != first+3 && t != last && *t == 'E') + first = t+1; + } + break; + case 'T': + // Invalid mangled name per + // http://sourcerytools.com/pipermail/cxx-abi-dev/2011-August/002422.html + break; + default: + { + // might be named type + const char* t = parse_type(first+1, last, db); + if (t != first+1 && t != last) + { + if (*t != 'E') { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else + const char* n = t; + for (; n != last && isdigit(*n); ++n) + ; + if (n != t && n != last && *n == 'E') { - *__sub_end_++ = __root_; - first = t; + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + first = n+1; + break; } - return first; } - break; - case 'v': - t = __parse_vector_type(first, last); - if (t != first) + else { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - return first; + first = t+1; + break; } - 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 + } + } + return first; +} + +template +String +base_name(String& s) +{ + if (s.empty()) + return s; + if (s == "std::string") + { + s = "std::basic_string, std::allocator >"; + return "basic_string"; + } + if (s == "std::istream") + { + s = "std::basic_istream >"; + return "basic_istream"; + } + if (s == "std::ostream") + { + s = "std::basic_ostream >"; + return "basic_ostream"; + } + if (s == "std::iostream") + { + s = "std::basic_iostream >"; + return "basic_iostream"; + } + const char* const pf = s.data(); + const char* pe = pf + s.size(); + if (pe[-1] == '>') + { + unsigned c = 1; + while (true) + { + if (--pe == pf) + return String(); + if (pe[-1] == '<') { - t = __parse_class_enum_type(first, last); - if (t != first) + if (--c == 0) { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + --pe; + break; } } + else if (pe[-1] == '>') + ++c; + } + } + const char* p0 = pe - 1; + for (; p0 != pf; --p0) + { + if (*p0 == ':') + { + ++p0; break; } } - return first; + return String(p0, pe); } -// ::= [n] +// ::= C1 # complete object constructor +// ::= C2 # base object constructor +// ::= C3 # complete object allocating constructor +// extension ::= C5 # ? +// ::= D0 # deleting destructor +// ::= D1 # complete object destructor +// ::= D2 # base object destructor +// extension ::= D5 # ? +template const char* -__demangle_tree::__parse_number(const char* first, const char* last) +parse_ctor_dtor_name(const char* first, const char* last, C& db) { - if (first != last) + if (last-first >= 2 && !db.names.empty()) { - const char* t = first; - if (*t == 'n') - ++t; - if (t != last) + switch (first[0]) { - if (*t == '0') + case 'C': + switch (first[1]) { - first = t+1; + case '1': + case '2': + case '3': + case '5': + if (db.names.empty()) + return first; + db.names.push_back(base_name(db.names.back().first)); + first += 2; + db.parsed_ctor_dtor_cv = true; + break; } - else if ('1' <= *t && *t <= '9') + break; + case 'D': + switch (first[1]) { - first = t+1; - while (first != last && isdigit(*first)) - ++first; + case '0': + case '1': + case '2': + case '5': + if (db.names.empty()) + return first; + db.names.push_back("~" + base_name(db.names.back().first)); + first += 2; + db.parsed_ctor_dtor_cv = true; + break; } + break; } } return first; } -// ::= h _ -// ::= v _ +// ::= Ut [ ] _ +// ::= // -// ::= -// # non-virtual base override +// ::= Ul E [ ] _ // -// ::= _ -// # virtual base override, with vcall offset +// ::= + # Parameter types or "v" if the lambda has no parameters +template const char* -__demangle_tree::__parse_call_offset(const char* first, const char* last) +parse_unnamed_type_name(const char* first, const char* last, C& db) { - if (first != last) + if (last - first > 2 && first[0] == 'U') { - switch (*first) + char type = first[1]; + switch (type) { - case 'h': + case 't': + { + db.names.push_back(typename C::String("'unnamed")); + const char* t0 = first+2; + if (t0 == last) { - const char* t = __parse_number(first + 1, last); - if (t != first + 1 && t != last && *t == '_') - first = t + 1; + db.names.pop_back(); + return first; + } + if (std::isdigit(*t0)) + { + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + db.names.back().first.append(t0, t1); + t0 = t1; + } + db.names.back().first.push_back('\''); + if (t0 == last || *t0 != '_') + { + db.names.pop_back(); + return first; } + first = t0 + 1; + } break; - case 'v': + case 'l': + { + db.names.push_back(typename C::String("'lambda'(")); + const char* t0 = first+2; + if (first[2] == 'v') { - const char* t = __parse_number(first + 1, last); - if (t != first + 1 && t != last && *t == '_') + db.names.back().first += ')'; + ++t0; + } + else { - const char* t2 = __parse_number(++t, last); - if (t2 != t && t2 != last && *t2 == '_') - first = t2 + 1; + const char* t1 = parse_type(t0, last, db); + if (t1 == t0) + { + db.names.pop_back(); + return first; + } + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append(tmp); + t0 = t1; + while (true) + { + t1 = parse_type(t0, last, db); + if (t1 == t0) + break; + if (db.names.size() < 2) + return first; + tmp = db.names.back().move_full(); + db.names.pop_back(); + if (!tmp.empty()) + { + db.names.back().first.append(", "); + db.names.back().first.append(tmp); + } + t0 = t1; + } + db.names.back().first.append(")"); + } + if (t0 == last || *t0 != 'E') + { + db.names.pop_back(); + return first; + } + ++t0; + if (t0 == last) + { + db.names.pop_back(); + return first; + } + if (std::isdigit(*t0)) + { + const char* t1 = t0 + 1; + while (t1 != last && std::isdigit(*t1)) + ++t1; + db.names.back().first.insert(db.names.back().first.begin()+7, t0, t1); + t0 = t1; } + if (t0 == last || *t0 != '_') + { + db.names.pop_back(); + return first; } + first = t0 + 1; + } break; } } return first; } -// ::= TV # virtual table -// ::= TT # VTT structure (construction vtable index) -// ::= TI # typeinfo structure -// ::= TS # typeinfo name (null-terminated byte string) -// ::= Tc -// # base is the nominal target function of thunk -// # first call-offset is 'this' adjustment -// # second call-offset is result adjustment -// ::= T -// # base is the nominal target function of thunk -// ::= GV # Guard variable for one-time initialization -// # No -// extension ::= TC _ # construction vtable for second-in-first -// extension ::= GR # reference temporary for object +// ::= +// ::= +// ::= +// ::= +template const char* -__demangle_tree::__parse_special_name(const char* first, const char* last) +parse_unqualified_name(const char* first, const char* last, C& db) { - if (last - first > 2) + if (first != last) { const char* t; switch (*first) { - case 'T': - switch (first[1]) - { - case 'V': - // TV # virtual table - t = __parse_type(first+2, last); - if (t != first+2 && __make<__vtable>(__root_)) - first = t; - break; - case 'T': - // TT # VTT structure (construction vtable index) - t = __parse_type(first+2, last); - if (t != first+2 && __make<__VTT>(__root_)) - first = t; - break; - case 'I': - // TI # typeinfo structure - t = __parse_type(first+2, last); - if (t != first+2 && __make<__typeinfo>(__root_)) - first = t; - break; - case 'S': - // TS # 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 - { - 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 _ # 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 - { - 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; - } + case 'C': + case 'D': + t = parse_ctor_dtor_name(first, last, db); + if (t != first) + first = t; break; - case 'G': - switch (first[1]) + case 'U': + t = parse_unnamed_type_name(first, last, db); + if (t != first) + first = t; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + t = parse_source_name(first, last, db); + if (t != first) + first = t; + break; + default: + t = parse_operator_name(first, last, db); + if (t != first) + first = t; + break; + }; + } + return first; +} + +// ::= +// ::= St # ::std:: +// extension ::= StL + +template +const char* +parse_unscoped_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) + { + const char* t0 = first; + bool St = false; + if (first[0] == 'S' && first[1] == 't') + { + t0 += 2; + St = true; + if (t0 != last && *t0 == 'L') + ++t0; + } + const char* t1 = parse_unqualified_name(t0, last, db); + if (t1 != t0) + { + if (St) { - case 'V': - // GV # 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 # reference temporary for object - t = __parse_name(first+2, last); - if (t != first+2 && __make<__reference_temporary>(__root_)) - first = t; - break; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "std::"); } - break; + first = t1; + } + } + return first; +} + +// at # alignof (a type) + +template +const char* +parse_alignof_type(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'a' && first[1] == 't') + { + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +// az # alignof (a expression) + +template +const char* +parse_alignof_expr(const char* first, const char* last, C& db) +{ + if (last - first >= 3 && first[0] == 'a' && first[1] == 'z') + { + const char* t = parse_expression(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first = "alignof (" + db.names.back().move_full() + ")"; + first = t; + } + } + return first; +} + +template +const char* +parse_noexcept_expression(const char* first, const char* last, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + if (db.names.empty()) + return first; + db.names.back().first = "noexcept (" + db.names.back().move_full() + ")"; + first = t1; + } + return first; +} + +template +const char* +parse_prefix_expression(const char* first, const char* last, const typename C::String& op, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + if (db.names.empty()) + return first; + db.names.back().first = op + "(" + db.names.back().move_full() + ")"; + first = t1; + } + return first; +} + +template +const char* +parse_binary_expression(const char* first, const char* last, const typename C::String& op, C& db) +{ + const char* t1 = parse_expression(first, last, db); + if (t1 != first) + { + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) + { + if (db.names.size() < 2) + return first; + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + auto& nm = db.names.back().first; + nm.clear(); + if (op == ">") + nm += '('; + nm += "(" + op1 + ") " + op + " (" + op2 + ")"; + if (op == ">") + nm += ')'; + first = t2; } + else + db.names.pop_back(); } return first; } -// -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv # (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 context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= v # vendor extended operator +// ::= +// ::= +// ::= +// ::= cl + E # call +// ::= cv # conversion with one argument +// ::= cv _ * E # conversion with a different number of arguments +// ::= [gs] nw * _ E # new (expr-list) type +// ::= [gs] nw * _ # new (expr-list) type (init) +// ::= [gs] na * _ E # new[] (expr-list) type +// ::= [gs] na * _ # new[] (expr-list) type (init) +// ::= [gs] dl # delete expression +// ::= [gs] da # delete[] expression +// ::= pp_ # prefix ++ +// ::= mm_ # prefix -- +// ::= ti # typeid (type) +// ::= te # typeid (expression) +// ::= dc # dynamic_cast (expression) +// ::= sc # static_cast (expression) +// ::= cc # const_cast (expression) +// ::= rc # reinterpret_cast (expression) +// ::= st # sizeof (a type) +// ::= sz # sizeof (an expression) +// ::= at # alignof (a type) +// ::= az # alignof (an expression) +// ::= nx # noexcept (expression) +// ::= +// ::= +// ::= dt # expr.name +// ::= pt # expr->name +// ::= ds # expr.*expr +// ::= sZ # size of a parameter pack +// ::= sZ # size of a function parameter pack +// ::= sp # pack expansion +// ::= tw # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= +template const char* -__demangle_tree::__parse_operator_name(const char* first, const char* last, int* type) +parse_expression(const char* first, const char* last, C& db) { if (last - first >= 2) { - switch (*first) + 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': + first = parse_expr_primary(first, last, db); + break; + case 'T': + first = parse_template_param(first, last, db); + break; + case 'f': + first = parse_function_param(first, last, db); + break; case 'a': - switch (first[1]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, "&&", db); + if (t != first+2) + first = t; 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; - } + t = parse_prefix_expression(first+2, last, "&", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "&", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "&=", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "=", db); + if (t != first+2) + first = t; 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; - } + first = parse_alignof_type(first, last, db); 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; - } + first = parse_alignof_expr(first, last, db); break; } break; case 'c': - switch (first[1]) + switch (t[1]) { + case 'c': + first = parse_const_cast_expr(first, last, db); + break; case 'l': - // () - if (__make<__operator_paren>()) - { - first += 2; - if (type) - *type = -1; - } + first = parse_call_expr(first, last, db); 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; - } + t = parse_binary_expression(first+2, last, ",", db); + if (t != first+2) + first = t; 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; - } + t = parse_prefix_expression(first+2, last, "~", db); + if (t != first+2) + first = t; break; case 'v': - // cast - { - const char* t = __parse_type(first+2, last, false, true); - 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; - } - } - } + first = parse_conversion_expr(first, last, db); break; } break; case 'd': - switch (first[1]) + switch (t[1]) { case 'a': - // delete[] - if (__make<__operator_delete_array>()) { - first += 2; - if (type) - *type = -1; + const char* t1 = parse_expression(t+2, last, db); + if (t1 != t+2) + { + if (db.names.empty()) + return first; + db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + + "delete[] " + db.names.back().move_full(); + first = t1; + } } break; + case 'c': + first = parse_dynamic_cast_expr(first, last, db); + break; case 'e': - // * (unary) - if (type) + t = parse_prefix_expression(first+2, last, "*", db); + if (t != first+2) + first = t; + break; + case 'l': { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + const char* t1 = parse_expression(t+2, last, db); + if (t1 != t+2) { - if (__make<__operator_dereference>(__root_)) - { - *type = 1; - first = t; - } + if (db.names.empty()) + return first; + db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) + + "delete " + db.names.back().move_full(); + first = t1; } } - else - { - if (__make<__operator_dereference>()) - first += 2; - } break; - case 'l': - // delete - if (__make<__operator_delete>()) - { - first += 2; - if (type) - *type = -1; - } + case 'n': + return parse_unresolved_name(first, last, db); + case 's': + first = parse_dot_star_expr(first, last, db); + break; + case 't': + first = parse_dot_expr(first, last, db); 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; - } + t = parse_binary_expression(first+2, last, "/", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "/=", db); + if (t != first+2) + first = t; break; } break; case 'e': - switch (first[1]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, "^", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "^=", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "==", db); + if (t != first+2) + first = t; break; } break; case 'g': - switch (first[1]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, ">=", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, ">", db); + if (t != first+2) + first = t; break; } break; case 'i': - // [] - if (first[1] == 'x' && __make<__operator_brackets>()) + if (t[1] == 'x') + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) { - first += 2; - if (type) - *type = -1; + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) + { + if (db.names.size() < 2) + return first; + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + db.names.back() = "(" + op1 + ")[" + op2 + "]"; + first = t2; + } + else + db.names.pop_back(); } + } break; case 'l': - switch (first[1]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, "<=", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "<<", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "<<=", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "<", db); + if (t != first+2) + first = t; 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; - } + switch (t[1]) + { + case 'i': + t = parse_binary_expression(first+2, last, "-", db); + if (t != first+2) + first = t; + break; + case 'I': + t = parse_binary_expression(first+2, last, "-=", db); + if (t != first+2) + first = t; + break; + case 'l': + t = parse_binary_expression(first+2, last, "*", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "*=", db); + if (t != first+2) + first = t; break; case 'm': - // -- (postfix in context) - if (type) + if (first+2 != last && first[2] == '_') { - const char* t = __parse_expression(first+2, last); - if (t != first+2) - { - if (__make<__operator_decrement>(false, __root_)) - { - *type = 1; - first = t; - } - } + t = parse_prefix_expression(first+3, last, "--", db); + if (t != first+3) + first = t; } else { - if (__make<__operator_decrement>()) - first += 2; + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")--"; + first = t1; + } } break; } break; case 'n': - switch (first[1]) + switch (t[1]) { case 'a': - // new[] - if (__make<__operator_new_array>()) - { - first += 2; - if (type) - *type = -1; - } + case 'w': + first = parse_new_expr(first, last, db); 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; - } + t = parse_binary_expression(first+2, last, "!=", db); + if (t != first+2) + first = t; 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; - } + t = parse_prefix_expression(first+2, last, "-", db); + if (t != first+2) + first = t; 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; - } + t = parse_prefix_expression(first+2, last, "!", db); + if (t != first+2) + first = t; break; - case 'w': - // new - if (__make<__operator_new>()) - { - first += 2; - if (type) - *type = -1; - } + case 'x': + t = parse_noexcept_expression(first+2, last, db); + if (t != first+2) + first = t; break; } break; case 'o': - switch (first[1]) + switch (t[1]) { + case 'n': + return parse_unresolved_name(first, last, db); 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; - } + t = parse_binary_expression(first+2, last, "||", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "|", db); + if (t != first+2) + first = t; 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; - } + t = parse_binary_expression(first+2, last, "|=", db); + if (t != first+2) + first = t; break; } break; case 'p': - switch (first[1]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, "->*", db); + if (t != first+2) + first = t; 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 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; - } + t = parse_binary_expression(first+2, last, "+", db); + if (t != first+2) + first = t; break; - case 'M': - // %= - if (type) + case 'L': + t = parse_binary_expression(first+2, last, "+=", db); + if (t != first+2) + first = t; + break; + case 'p': + if (first+2 != last && first[2] == '_') { - 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; - } - } - } + t = parse_prefix_expression(first+3, last, "++", db); + if (t != first+3) + first = t; } else { - if (__make<__operator_mod_equal>()) - first += 2; + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")++"; + first = t1; + } } break; case 's': - // >> - if (type) + t = parse_prefix_expression(first+2, last, "+", db); + if (t != first+2) + first = t; + break; + case 't': + first = parse_arrow_expr(first, last, db); + break; + } + break; + case 'q': + if (t[1] == 'u') + { + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + const char* t2 = parse_expression(t1, last, db); + if (t2 != t1) { - __node* op1 = __root_; - const char* t2 = __parse_expression(t, last); - if (t != t2) + const char* t3 = parse_expression(t2, last, db); + if (t3 != t2) { - if (__make<__operator_right_shift>(op1, __root_)) - { - *type = 2; - first = t2; - } + if (db.names.size() < 3) + return first; + auto op3 = db.names.back().move_full(); + db.names.pop_back(); + auto op2 = db.names.back().move_full(); + db.names.pop_back(); + auto op1 = db.names.back().move_full(); + db.names.back() = "(" + op1 + ") ? (" + op2 + ") : (" + op3 + ")"; + first = t3; } - } - } - 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) + else { - if (__make<__operator_right_shift_equal>(op1, __root_)) - { - *type = 2; - first = t2; - } + db.names.pop_back(); + db.names.pop_back(); } } + else + db.names.pop_back(); } - else - { - if (__make<__operator_right_shift_equal>()) - first += 2; - } + } + break; + case 'r': + switch (t[1]) + { + case 'c': + first = parse_reinterpret_cast_expr(first, last, db); + break; + case 'm': + t = parse_binary_expression(first+2, last, "%", db); + if (t != first+2) + first = t; + break; + case 'M': + t = parse_binary_expression(first+2, last, "%=", db); + if (t != first+2) + first = t; + break; + case 's': + t = parse_binary_expression(first+2, last, ">>", db); + if (t != first+2) + first = t; + break; + case 'S': + t = parse_binary_expression(first+2, last, ">>=", db); + if (t != first+2) + first = t; break; } break; case 's': - switch (first[1]) + switch (t[1]) { + case 'c': + first = parse_static_cast_expr(first, last, db); + break; + case 'p': + first = parse_pack_expansion(first, last, db); + break; + case 'r': + return parse_unresolved_name(first, last, db); 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; - } + first = parse_sizeof_type_expr(first, last, db); break; case 'z': - // sizeof (an expression) - if (type) + first = parse_sizeof_expr_expr(first, last, db); + break; + case 'Z': + if (last - t >= 3) { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + switch (t[2]) { - if (__make<__operator_sizeof_expression>(__root_)) - { - *type = -1; - first = t; - } + case 'T': + first = parse_sizeof_param_pack_expr(first, last, db); + break; + case 'f': + first = parse_sizeof_function_param_pack_expr(first, last, db); + break; } } - else - { - if (__make<__operator_sizeof_expression>()) - first += 2; - } break; } break; + case 't': + switch (t[1]) + { + case 'e': + case 'i': + first = parse_typeid_expr(first, last, db); + break; + case 'r': + db.names.push_back("throw"); + first += 2; + break; + case 'w': + first = parse_throw_expr(first, last, db); + break; + } + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return parse_unresolved_name(first, last, db); } } return first; } -// ::= +// ::= # type or template +// ::= X E # expression +// ::= # simple expressions +// ::= J * E # argument pack +// ::= LZ E # extension +template const char* -__demangle_tree::__parse_source_name(const char* first, const char* last) +parse_template_arg(const char* first, const char* last, C& db) { if (first != last) { - char c = *first; - if ('1' <= c && c <= '9' && first+1 != last) + const char* t; + switch (*first) { - const char* t = first+1; - size_t n = static_cast(c - '0'); - for (c = *t; '0' <= c && c <= '9'; c = *t) + case 'X': + t = parse_expression(first+1, last, db); + if (t != first+1) { - n = n * 10 + static_cast(c - '0'); - if (++t == last) + if (t != last && *t == 'E') + first = t+1; + } + break; + case 'J': + t = first+1; + if (t == last) + return first; + while (*t != 'E') + { + const char* t1 = parse_template_arg(t, last, db); + if (t1 == t) return first; + t = t1; + } + first = t+1; + break; + case 'L': + // or LZ E + if (first+1 != last && first[1] == 'Z') + { + t = parse_encoding(first+2, last, db); + if (t != first+2 && t != last && *t == 'E') + first = t+1; } - if (static_cast(last - t) >= n && __make<__source_name>(t, n)) - first = t + n; - } - } - return first; -} - -// ::= -// ::= -// ::= -// ::= - -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; + first = parse_expr_primary(first, last, db); + break; + default: + // + first = parse_type(first, last, db); + break; } - else - first = t; } - else - first = t; return first; } -// ::= -// ::= St # ::std:: -// extension ::= StL +// ::= I * E +// extension, the abi says + +template const char* -__demangle_tree::__parse_unscoped_name(const char* first, const char* last) +parse_template_args(const char* first, const char* last, C& db) { - if (last - first >= 2) + if (last - first >= 2 && *first == 'I') { - 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 (db.tag_templates) + db.template_param.back().clear(); + const char* t = first+1; + typename C::String args("<"); + while (*t != 'E') { - if (t0 != first) + if (db.tag_templates) + db.template_param.emplace_back(db.names.get_allocator()); + size_t k0 = db.names.size(); + const char* t1 = parse_template_arg(t, last, db); + size_t k1 = db.names.size(); + if (db.tag_templates) + db.template_param.pop_back(); + if (t1 == t || t1 == last) + return first; + if (db.tag_templates) { - __node* name = __root_; - if (__make<__std_qualified_name>()) - { - if (__make<__nested_delimeter>(__root_, name)) - first = t1; - } + db.template_param.back().emplace_back(db.names.get_allocator()); + for (size_t k = k0; k < k1; ++k) + db.template_param.back().back().push_back(db.names[k]); } - else - first = t1; + for (size_t k = k0; k < k1; ++k) + { + if (args.size() > 1) + args += ", "; + args += db.names[k].move_full(); + } + for (; k1 != k0; --k1) + db.names.pop_back(); + t = t1; } + first = t + 1; + if (args.back() != '>') + args += ">"; + else + args += " >"; + db.names.push_back(std::move(args)); + } return first; } -// ::= N [] E -// ::= N [] E +// ::= N [] [] E +// ::= N [] [] E // // ::= // ::= @@ -10320,717 +3886,1052 @@ __demangle_tree::__parse_unscoped_name(const char* first, const char* last) // ::= // ::= +template const char* -__demangle_tree::__parse_nested_name(const char* first, const char* last) +parse_nested_name(const char* first, const char* last, C& db) { if (first != last && *first == 'N') { - unsigned cv = 0; - const char* t0 = __parse_cv_qualifiers(first+1, last, cv, true); - __node* prev = NULL; + unsigned cv; + const char* t0 = parse_cv_qualifiers(first+1, last, cv); + if (t0 == last) + return first; + db.ref = 0; + if (*t0 == 'R') + { + db.ref = 1; + ++t0; + } + else if (*t0 == 'O') + { + db.ref = 2; + ++t0; + } + db.names.emplace_back(); if (last - t0 >= 2 && t0[0] == 'S' && t0[1] == 't') { t0 += 2; - if (!__make<__std_qualified_name>()) - return first; - prev = __root_; + db.names.back().first = "std"; } - while (t0 != last) + if (t0 == last) { - bool can_sub = true; - bool make_nested = true; - const char* t1 = NULL; + db.names.pop_back(); + return first; + } + bool pop_subs = false; + while (*t0 != 'E') + { + 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 - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) + case 'S': + if (t0 + 1 != last && t0[1] == 't') + goto do_parse_unqualified_name; + t1 = parse_substitution(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) { - __status_ = memory_alloc_failure; - return first; + db.names.back().first += "::" + name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); } 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; + db.names.back().first = name; + pop_subs = true; + t0 = t1; } - // check for Dt, DT here, else drop through - case 'C': - t1 = __parse_ctor_dtor_name(t0, last); - if (t1 == t0 || t1 == last) + else return first; - if (*t1 == 'I') - { - // has following - 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': - t1 = __parse_unnamed_type_name(t0, last); - if (t1 == t0 || t1 == last) - return first; - break; - case 'T': - t1 = __parse_template_param(t0, last); - if (t1 == t0 || t1 == last) - return first; - if (*t1 == 'I') - { - // has following - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __status_ = memory_alloc_failure; - return first; - } + case 'T': + t1 = parse_template_param(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; else - *__sub_end_++ = __root_; - const char* t2 = __parse_template_args(t1, last); - if (t2 == t1) - return first; - t1 = t2; + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; } + else + return first; break; - case 'S': - t1 = __parse_substitution(t0, last); - if (t1 == t0 || t1 == last) + case 'D': + if (t0 + 1 != last && t0[1] != 't' && t0[1] != 'T') + goto do_parse_unqualified_name; + t1 = parse_decltype(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; + else + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; + } + else return first; - if (*t1 == 'I') + break; + case 'I': + t1 = parse_template_args(t0, last, db); + if (t1 != t0 && t1 != last) { - const char* t2 = __parse_template_args(t1, last); - if (t2 == t1) - return first; - t1 = t2; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t0 = t1; } else - can_sub = false; + return first; break; case 'L': - // extension: ignore L here - ++t0; - continue; - default: - t1 = __parse_operator_name(t0, last); - if (t1 == t0 || t1 == last) + if (++t0 == last) return first; - if (*t1 == 'I') - { - // has following - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __status_ = memory_alloc_failure; - return first; - } + break; + default: + do_parse_unqualified_name: + t1 = parse_unqualified_name(t0, last, db); + if (t1 != t0 && t1 != last) + { + auto name = db.names.back().move_full(); + db.names.pop_back(); + if (!db.names.back().first.empty()) + db.names.back().first += "::" + name; else - *__sub_end_++ = __root_; - const char* t2 = __parse_template_args(t1, last); - if (t2 == t1) - return first; - t1 = t2; + db.names.back().first = name; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + pop_subs = true; + t0 = t1; } - break; - } - if (t1 == t0 || t1 == last) - return first; - if (prev && make_nested) - { - if (!__make<__nested_delimeter>(prev, __root_)) + else return first; - can_sub = true; } - if (can_sub && *t1 != 'E') + } + first = t0 + 1; + db.cv = cv; + if (pop_subs && !db.subs.empty()) + db.subs.pop_back(); + } + return first; +} + +// := _ # when number < 10 +// := __ _ # when number >= 10 +// extension := decimal-digit+ + +const char* +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 (__sub_end_ == __sub_cap_) + if (std::isdigit(*t1)) + first = t1+1; + else if (*t1 == '_') { - __status_ = memory_alloc_failure; - return first; + for (++t1; t1 != last && std::isdigit(*t1); ++t1) + ; + if (t1 != last && *t1 == '_') + first = t1 + 1; } - else - *__sub_end_++ = __root_; } - if (*t1 == 'E') + } + else if (std::isdigit(*first)) + { + const char* t1 = first+1; + for (; t1 != last && std::isdigit(*t1); ++t1) + ; + first = t1; + } + } + return first; +} + +// := Z E [] +// := Z E s [] +// := Z Ed [ ] _ + +template +const char* +parse_local_name(const char* first, const char* last, C& db) +{ + if (first != last && *first == 'Z') + { + const char* t = parse_encoding(first+1, last, db); + if (t != first+1 && t != last && *t == 'E' && ++t != last) + { + switch (*t) { - if (cv != 0) + case 's': + first = parse_discriminator(t+1, last); + if (db.names.empty()) + return first; + db.names.back().first.append("::string literal"); + break; + case 'd': + if (++t != last) { - if (!__make<__cv_qualifiers>(cv, __root_)) - return first; + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') + { + t = t1 + 1; + t1 = parse_name(t, last, db); + if (t1 != t) + { + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append("::"); + db.names.back().first.append(name); + first = t1; + } + else + db.names.pop_back(); + } + } + break; + default: + { + const char* t1 = parse_name(t, last, db); + if (t1 != t) + { + // parse but ignore discriminator + first = parse_discriminator(t1, last); + if (db.names.size() < 2) + return first; + auto name = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first.append("::"); + db.names.back().first.append(name); + } + else + db.names.pop_back(); } - first = t1+1; break; } - prev = __root_; - t0 = t1; } } return first; } -// ::= # type or template -// ::= X E # expression -// ::= # simple expressions -// ::= J * E # argument pack -// ::= LZ E # extension +// ::= // N +// ::= # See Scope Encoding below // Z +// ::= +// ::= + +// ::= +// ::= +template const char* -__demangle_tree::__parse_template_arg(const char* first, const char* last) +parse_name(const char* first, const char* last, C& db) { - if (first != last) + if (last - first >= 2) { - const char* t; - switch (*first) + const char* t0 = first; + // extension: ignore L here + if (*t0 == 'L') + ++t0; + switch (*t0) { - case 'X': - t = __parse_expression(first+1, last); - if (t != first+1) - { - if (t != last && *t == 'E') - first = t+1; - } + case 'N': + { + const char* t1 = parse_nested_name(t0, last, db); + if (t1 != t0) + first = t1; break; - case 'J': - t = first+1; - if (t == last) - return first; - if (*t == 'E') - { - if (__make<__list>((__node*)0)) - first = t+1; - } - else + } + case 'Z': + { + const char* t1 = parse_local_name(t0, last, db); + if (t1 != t0) + first = t1; + break; + } + default: + { + const char* t1 = parse_unscoped_name(t0, last, db); + if (t1 != t0) { - __node* list = NULL; - __node* prev = NULL; - do + if (t1 != last && *t1 == 'I') // { - const char* t2 = __parse_template_arg(t, last); - if (t2 == t || !__make<__list>(__root_)) + if (db.names.empty()) return first; - if (list == 0) - list = __root_; - if (prev) + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + t0 = t1; + t1 = parse_template_args(t0, last, db); + if (t1 != t0) { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += tmp; + first = t1; } - prev = __root_; - t = t2; - } while (t != last && *t != 'E'); - first = t+1; - __root_ = list; - } - break; - case 'L': - // or LZ 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 = t1; } else - first = __parse_expr_primary(first, last); - break; - default: - // - first = __parse_type(first, last); + { // try + t1 = parse_substitution(t0, last, db); + if (t1 != t0 && t1 != last && *t1 == 'I') + { + t0 = t1; + t1 = parse_template_args(t0, last, db); + if (t1 != t0) + { + if (db.names.size() < 2) + return first; + auto tmp = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += tmp; + first = t1; + } + } + } break; + } } } return first; } -// ::= I * E -// extension, the abi says + +// ::= h _ +// ::= v _ +// +// ::= +// # non-virtual base override +// +// ::= _ +// # virtual base override, with vcall offset const char* -__demangle_tree::__parse_template_args(const char* first, const char* last) +parse_call_offset(const char* first, const char* last) { - if (last - first >= 2 && *first == 'I') + if (first != last) { - __node* args = NULL; - __node* prev = NULL; - __node* name = __root_; - if (__tag_templates_) - __t_end_ = __t_begin_; - const char* t = first+1; - while (*t != 'E') + switch (*first) { - 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) + case 'h': { - __tag_templates_ = prev_tag_templates; - __t_begin_ = prev_t_begin; - __t_end_ = prev_t_end; + const char* t = parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') + first = t + 1; } - if (t2 == t || t2 == last) - break; - if (!__make<__list>(__root_)) - return first; - if (args == 0) - args = __root_; - if (prev) + break; + case 'v': { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; - } - prev = __root_; - if (__tag_templates_) + const char* t = parse_number(first + 1, last); + if (t != first + 1 && t != last && *t == '_') { - if (__t_end_ == __t_cap_) - { - __status_ = memory_alloc_failure; - return first; - } - if (__root_->__left_) - *__t_end_++ = __root_->__left_; - else - *__t_end_++ = __root_; + const char* t2 = parse_number(++t, last); + if (t2 != t && t2 != last && *t2 == '_') + first = t2 + 1; } - t = t2; - } - if (t != last && *t == 'E') - { - if (__make<__template_args>(name, args)) - first = t+1; + } + break; } } return first; } -// ::= S _ -// ::= S_ -// ::= Sa # ::std::allocator -// ::= Sb # ::std::basic_string -// ::= Ss # ::std::basic_string < char, -// ::std::char_traits, -// ::std::allocator > -// ::= Si # ::std::basic_istream > -// ::= So # ::std::basic_ostream > -// ::= Sd # ::std::basic_iostream > +// ::= TV # virtual table +// ::= TT # VTT structure (construction vtable index) +// ::= TI # typeinfo structure +// ::= TS # typeinfo name (null-terminated byte string) +// ::= Tc +// # base is the nominal target function of thunk +// # first call-offset is 'this' adjustment +// # second call-offset is result adjustment +// ::= T +// # base is the nominal target function of thunk +// ::= GV # Guard variable for one-time initialization +// # No +// extension ::= TC _ # construction vtable for second-in-first +// extension ::= GR # reference temporary for object +template const char* -__demangle_tree::__parse_substitution(const char* first, const char* last) +parse_special_name(const char* first, const char* last, C& db) { - if (last - first >= 2) + if (last - first > 2) { - if (*first == 'S') + const char* t; + switch (*first) { + case 'T': switch (first[1]) { - case 'a': - if (__make<__sub_allocator>()) - first += 2; - break; - case 'b': - if (__make<__sub_basic_string>()) - first += 2; + case 'V': + // TV # virtual table + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "vtable for "); + first = t; + } break; - case 's': - if (__make<__sub_string>()) - first += 2; + case 'T': + // TT # VTT structure (construction vtable index) + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "VTT for "); + first = t; + } break; - case 'i': - if (__make<__sub_istream>()) - first += 2; + case 'I': + // TI # typeinfo structure + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "typeinfo for "); + first = t; + } break; - case 'o': - if (__make<__sub_ostream>()) - first += 2; + case 'S': + // TS # typeinfo name (null-terminated byte string) + t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "typeinfo name for "); + first = t; + } break; - case 'd': - if (__make<__sub_iostream>()) - first += 2; + case 'c': + // Tc + { + 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, db); + if (t != t1) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "covariant return thunk to "); + first = t; + } + } break; - case '_': - if (__sub_begin_ != __sub_end_) + case 'C': + // extension ::= TC _ # construction vtable for second-in-first + t = parse_type(first+2, last, db); + if (t != first+2) { - if (__make<__sub>(*__sub_begin_)) - first += 2; + const char* t0 = parse_number(t, last); + if (t0 != t && t0 != last && *t0 == '_') + { + const char* t1 = parse_type(++t0, last, db); + if (t1 != t0) + { + if (db.names.size() < 2) + return first; + auto left = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first = "construction vtable for " + + std::move(left) + "-in-" + + db.names.back().move_full(); + first = t1; + } + } } break; default: - if (isdigit(first[1]) || isupper(first[1])) + // T { - size_t sub = 0; - const char* t = first+1; - if (isdigit(*t)) - sub = static_cast(*t - '0'); - else - sub = static_cast(*t - 'A') + 10; - for (++t; t != last && (isdigit(*t) || isupper(*t)); ++t) + const char* t0 = parse_call_offset(first+1, last); + if (t0 == first+1) + break; + t = parse_encoding(t0, last, db); + if (t != t0) + { + if (db.names.empty()) + return first; + if (first[2] == 'v') { - sub *= 36; - if (isdigit(*t)) - sub += static_cast(*t - '0'); - else - sub += static_cast(*t - 'A') + 10; + db.names.back().first.insert(0, "virtual thunk to "); + first = t; } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < static_cast(__sub_end_ - __sub_begin_)) + else { - if (__make<__sub>(__sub_begin_[sub])) - first = t+1; + db.names.back().first.insert(0, "non-virtual thunk to "); + first = t; } } + } + break; + } + break; + case 'G': + switch (first[1]) + { + case 'V': + // GV # Guard variable for one-time initialization + t = parse_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "guard variable for "); + first = t; + } + break; + case 'R': + // extension ::= GR # reference temporary for object + t = parse_name(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "reference temporary for "); + first = t; + } break; } + break; } } return first; } -// ::= -// ::= # See Scope Encoding below -// ::= -// ::= +template +class save_value +{ + T& restore_; + T original_value_; +public: + save_value(T& restore) + : restore_(restore), + original_value_(restore) + {} + + ~save_value() + { + restore_ = std::move(original_value_); + } + + save_value(const save_value&) = delete; + save_value& operator=(const save_value&) = delete; +}; + +// ::= +// ::= +// ::= +template const char* -__demangle_tree::__parse_name(const char* first, const char* last) +parse_encoding(const char* first, const char* last, C& db) { 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) + save_value su(db.encoding_depth); + ++db.encoding_depth; + save_value sb(db.tag_templates); + if (db.encoding_depth > 1) + db.tag_templates = true; + switch (*first) { - t = __parse_local_name(t0, last); - if (t == t0) - { - // not nor - // Try to parse or - // which are nearly ambiguous. - // This logic occurs nowhere else. - if (last - t0 >= 2) + case 'G': + case 'T': + first = parse_special_name(first, last, db); + break; + default: + { + const char* t = parse_name(first, last, db); + unsigned cv = db.cv; + unsigned ref = db.ref; + if (t != first) + { + if (t != last && *t != 'E' && *t != '.') { - if (t0[0] == 'S' && (t0[1] == '_' || - isdigit(t0[1]) || - isupper(t0[1]) || - t0[1] == 'a' || - t0[1] == 'b')) + save_value sb2(db.tag_templates); + db.tag_templates = false; + const char* t2; + typename C::String ret2; + if (db.names.empty()) + return first; + const typename C::String& nm = db.names.back().first; + if (nm.empty()) + return first; + if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-' + && nm[nm.size()-2] != '>') { - t = __parse_substitution(t0, last); - if (t != t0) - { - const char* t2 = __parse_template_args(t, last); - if (t2 != t) - first = t2; - } + t2 = parse_type(t, last, db); + if (t2 == t) + return first; + if (db.names.size() < 2) + return first; + auto ret1 = std::move(db.names.back().first); + ret2 = std::move(db.names.back().second); + if (ret2.empty()) + ret1 += ' '; + db.names.pop_back(); + db.names.back().first.insert(0, ret1); + t = t2; } - else // Not a substitution, except maybe St + db.names.back().first += '('; + if (t != last && *t == 'v') + { + ++t; + } + else { - t = __parse_unscoped_name(t0, last); - if (t != t0) + bool first_arg = true; + while (true) { - // unscoped-name might be - if (t != last && *t == 'I') + size_t k0 = db.names.size(); + t2 = parse_type(t, last, db); + size_t k1 = db.names.size(); + if (t2 == t) + break; + if (k1 > k0) { - if (__sub_end_ == __sub_cap_) + typename C::String tmp; + for (size_t k = k0; k < k1; ++k) { - __status_ = memory_alloc_failure; - return first; + if (!tmp.empty()) + tmp += ", "; + tmp += db.names[k].move_full(); + } + for (size_t k = k0; k < k1; ++k) + db.names.pop_back(); + if (!tmp.empty()) + { + if (db.names.empty()) + return first; + if (!first_arg) + db.names.back().first += ", "; + else + first_arg = false; + db.names.back().first += tmp; } - *__sub_end_++ = __root_; - const char* t2 = __parse_template_args(t, last); - if (t2 != t) - first = t2; - } - else - { - // - first = t; } + t = t2; } } + if (db.names.empty()) + return first; + db.names.back().first += ')'; + if (cv & 1) + db.names.back().first.append(" const"); + if (cv & 2) + db.names.back().first.append(" volatile"); + if (cv & 4) + db.names.back().first.append(" restrict"); + if (ref == 1) + db.names.back().first.append(" &"); + else if (ref == 2) + db.names.back().first.append(" &&"); + db.names.back().first += ret2; + first = t; } + else + first = t; } - else - first = t; + break; + } } - else - first = t; } return first; } -// extension -// := . +// _block_invoke +// _block_invoke+ +// _block_invoke_+ +template const char* -__demangle_tree::__parse_dot_suffix(const char* first, const char* last) +parse_block_invoke(const char* first, const char* last, C& db) { - if (first != last && *first == '.') + if (last - first >= 13) { - if (__make<__dot_suffix>(__root_, first, static_cast(last-first))) - first = last; + const char test[] = "_block_invoke"; + const char* t = first; + for (int i = 0; i < 13; ++i, ++t) + { + if (*t != test[i]) + return first; + } + if (t != last) + { + if (*t == '_') + { + // must have at least 1 decimal digit + if (++t == last || !std::isdigit(*t)) + return first; + ++t; + } + // parse zero or more digits + while (t != last && isdigit(*t)) + ++t; + } + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "invocation function for block in "); + first = t; } return first; } -// ::= -// ::= -// ::= +// extension +// := . +template const char* -__demangle_tree::__parse_encoding(const char* first, const char* last) +parse_dot_suffix(const char* first, const char* last, C& db) { - const char* t = __parse_name(first, last); - if (t != first) + if (first != last && *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; - bool prev_tag_templates = __tag_templates_; - __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_ = prev_tag_templates; - } - else - first = t; + if (db.names.empty()) + return first; + db.names.back().first += " (" + typename C::String(first, last) + ")"; + first = last; } - else - first = __parse_special_name(first, last); return first; } +// ___Z_block_invoke +// ___Z_block_invoke+ +// ___Z_block_invoke_+ // ::= _Z // ::= +template void -__demangle_tree::__parse() +demangle(const char* first, const char* last, C& db, int& status) { - if (__mangled_name_begin_ == __mangled_name_end_) + if (first >= last) { - __status_ = invalid_mangled_name; + 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 (*first == '_') { - if (__fix_forward_references_) + if (last - first >= 4) { - if (__root_->fix_forward_references(__t_begin_, __t_end_)) - __status_ = success; + if (first[1] == 'Z') + { + const char* t = parse_encoding(first+2, last, db); + if (t != first+2 && t != last && *t == '.') + t = parse_dot_suffix(t, last, db); + if (t != last) + status = invalid_mangled_name; + } + else if (first[1] == '_' && first[2] == '_' && first[3] == 'Z') + { + const char* t = parse_encoding(first+4, last, db); + if (t != first+4 && t != last) + { + const char* t1 = parse_block_invoke(t, last, db); + if (t1 != last) + status = invalid_mangled_name; + } + else + status = invalid_mangled_name; + } + else + status = invalid_mangled_name; } else - __status_ = success; + status = invalid_mangled_name; + } + else + { + const char* t = parse_type(first, last, db); + if (t != last) + status = invalid_mangled_name; } + if (status == success && db.names.empty()) + status = invalid_mangled_name; } -__demangle_tree -__demangle(const char* mangled_name, char* buf, size_t bs) +template +class arena { - __demangle_tree t(mangled_name, buf, bs); - if (t.__status() == invalid_mangled_name) - t.__parse(); - return t; -} + static const std::size_t alignment = 16; + alignas(alignment) char buf_[N]; + char* ptr_; + + std::size_t + align_up(std::size_t n) noexcept + {return n + (alignment-1) & ~(alignment-1);} + + bool + pointer_in_buffer(char* p) noexcept + {return buf_ <= p && p <= buf_ + N;} -__demangle_tree -__demangle(const char* mangled_name) +public: + arena() noexcept : ptr_(buf_) {} + ~arena() {ptr_ = nullptr;} + arena(const arena&) = delete; + arena& operator=(const arena&) = delete; + + char* allocate(std::size_t n); + void deallocate(char* p, std::size_t n) noexcept; + + static constexpr std::size_t size() {return N;} + std::size_t used() const {return static_cast(ptr_ - buf_);} + void reset() {ptr_ = buf_;} +}; + +template +char* +arena::allocate(std::size_t n) { - return __demangle(mangled_name, 0, 0); + n = align_up(n); + if (static_cast(buf_ + N - ptr_) >= n) + { + char* r = ptr_; + ptr_ += n; + return r; + } + return static_cast(std::malloc(n)); } -char* -__demangle(__demangle_tree dmg_tree, char* buf, size_t* n, int* status) +template +void +arena::deallocate(char* p, std::size_t n) noexcept { - if (dmg_tree.__status() != success) + if (pointer_in_buffer(p)) { - if (status) - *status = dmg_tree.__status(); - return NULL; + n = align_up(n); + if (p + n == ptr_) + ptr_ = p; } -#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 (static_cast(est) <= bs) + else + std::free(p); +} + +template +class short_alloc +{ + arena& a_; +public: + typedef T value_type; + +public: + template struct rebind {typedef short_alloc<_Up, N> other;}; + + short_alloc(arena& a) noexcept : a_(a) {} + template + short_alloc(const short_alloc& a) noexcept + : a_(a.a_) {} + short_alloc(const short_alloc&) = default; + short_alloc& operator=(const short_alloc&) = delete; + + T* allocate(std::size_t n) { - char* e = dmg_tree.__get_demangled_name(buf); - *e++ = '\0'; - s = e - buf; + return reinterpret_cast(a_.allocate(n*sizeof(T))); } - else if (static_cast(est) <= N) + void deallocate(T* p, std::size_t n) noexcept { - char* e = dmg_tree.__get_demangled_name(tmp); - *e++ = '\0'; - s = e - tmp; + a_.deallocate(reinterpret_cast(p), n*sizeof(T)); } - else - s = static_cast(dmg_tree.size() + 1); - if (static_cast(s) > bs) + + template + friend + bool + operator==(const short_alloc& x, const short_alloc& y) noexcept; + + template friend class short_alloc; +}; + +template +inline +bool +operator==(const short_alloc& x, const short_alloc& y) noexcept +{ + return N == M && &x.a_ == &y.a_; +} + +template +inline +bool +operator!=(const short_alloc& x, const short_alloc& y) noexcept +{ + return !(x == y); +} + +template +class malloc_alloc +{ +public: + typedef T value_type; + + malloc_alloc() = default; + template malloc_alloc(const malloc_alloc&) noexcept {} + + T* allocate(std::size_t n) { - buf = static_cast(realloc(buf, static_cast(s))); - if (buf == NULL) - { - if (status) - *status = memory_alloc_failure; - return NULL; - } - if (n) - *n = static_cast(s); + return static_cast(std::malloc(n*sizeof(T))); } - if (static_cast(est) > bs) + void deallocate(T* p, std::size_t) noexcept { - if (static_cast(est) <= N) - strncpy(buf, tmp, static_cast(s)); - else - *dmg_tree.__get_demangled_name(buf) = '\0'; + std::free(p); } - if (status) - *status = success; - return buf; +}; + +template +inline +bool +operator==(const malloc_alloc&, const malloc_alloc&) noexcept +{ + return true; } -} // __libcxxabi +template +inline +bool +operator!=(const malloc_alloc& x, const malloc_alloc& y) noexcept +{ + return !(x == y); +} -#pragma GCC visibility pop -#pragma GCC visibility push(default) +const size_t bs = 4 * 1024; +template using Alloc = short_alloc; +template using Vector = std::vector>; +using String = std::basic_string, malloc_alloc>; -extern "C" +struct string_pair +{ + String first; + String second; + + string_pair() = default; + string_pair(String f) : first(std::move(f)) {} + string_pair(String f, String s) + : first(std::move(f)), second(std::move(s)) {} + template + string_pair(const char (&s)[N]) : first(s, N-1) {} + + size_t size() const {return first.size() + second.size();} + String full() const {return first + second;} + String move_full() {return std::move(first) + std::move(second);} +}; + +struct Db { + typedef String String; + typedef Vector sub_type; + typedef Vector template_param_type; + Vector names; + Vector subs; + Vector template_param; + unsigned cv; + unsigned ref; + unsigned encoding_depth; + bool parsed_ctor_dtor_cv; + bool tag_templates; + bool fix_forward_references; + bool try_to_parse_template_args; + + template + Db(arena& ar) : + names(ar), + subs(0, names, ar), + template_param(0, subs, ar) + {} +}; + +} // unnamed namespace +__attribute__ ((__visibility__("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 (mangled_name == nullptr || (buf != nullptr && n == nullptr)) { if (status) - *status = __libcxxabi::invalid_args; - return NULL; + *status = invalid_args; + return nullptr; + } + size_t internal_size = buf != nullptr ? *n : 0; + arena a; + Db db(a); + db.cv = 0; + db.ref = 0; + db.encoding_depth = 0; + db.parsed_ctor_dtor_cv = false; + db.tag_templates = true; + db.template_param.emplace_back(a); + db.fix_forward_references = false; + db.try_to_parse_template_args = true; + int internal_status = success; + size_t len = std::strlen(mangled_name); + demangle(mangled_name, mangled_name + len, db, + internal_status); + if (internal_status == success && db.fix_forward_references && + !db.template_param.empty() && !db.template_param.front().empty()) + { + db.fix_forward_references = false; + db.tag_templates = false; + db.names.clear(); + db.subs.clear(); + demangle(mangled_name, mangled_name + len, db, internal_status); + if (db.fix_forward_references) + internal_status = invalid_mangled_name; + } + if (internal_status == success) + { + size_t sz = db.names.back().size() + 1; + if (sz > internal_size) + { + char* newbuf = static_cast(std::realloc(buf, sz)); + if (newbuf == nullptr) + { + internal_status = memory_alloc_failure; + buf = nullptr; + } + else + { + buf = newbuf; + if (n != nullptr) + *n = sz; + } + } + if (buf != nullptr) + { + db.names.back().first += db.names.back().second; + std::memcpy(buf, db.names.back().first.data(), sz-1); + buf[sz-1] = char(0); + } } - const size_t bs = 4 * 1024; - __attribute((aligned(16))) char static_buf[bs]; - - buf = __libcxxabi::__demangle(__libcxxabi::__demangle(mangled_name, - static_buf, bs), - buf, n, status); + else + buf = nullptr; + if (status) + *status = internal_status; return buf; } -} // extern "C" - -} // abi +} // __cxxabiv1 diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp index f8c38c07..c43777c2 100644 --- a/system/lib/libcxxabi/src/cxa_exception.cpp +++ b/system/lib/libcxxabi/src/cxa_exception.cpp @@ -15,7 +15,7 @@ #include // for std::terminate #include // for malloc, free -#include // for memset +#include // for memset #include #include "cxa_exception.hpp" diff --git a/system/lib/libcxxabi/src/cxa_exception.hpp b/system/lib/libcxxabi/src/cxa_exception.hpp index 66f05c45..22c4da38 100644 --- a/system/lib/libcxxabi/src/cxa_exception.hpp +++ b/system/lib/libcxxabi/src/cxa_exception.hpp @@ -41,19 +41,19 @@ static const uint64_t get_vendor_and_language = 0xFFFFFFFFFFFFFF00; // mask std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; - __cxa_exception *nextException; + __cxa_exception *nextException; - int handlerCount; + int handlerCount; #ifdef __ARM_EABI_UNWINDER__ - __cxa_exception* nextPropagatingException; - int propagationCount; + __cxa_exception* nextPropagatingException; + int propagationCount; #else - int handlerSwitchValue; - const unsigned char *actionRecord; - const unsigned char *languageSpecificData; - void *catchTemp; - void *adjustedPtr; + int handlerSwitchValue; + const unsigned char *actionRecord; + const unsigned char *languageSpecificData; + void *catchTemp; + void *adjustedPtr; #endif #if !__LP64__ diff --git a/system/lib/libcxxabi/src/cxa_new_delete.cpp b/system/lib/libcxxabi/src/cxa_new_delete.cpp index 7fd0b3b7..25a5454e 100644 --- a/system/lib/libcxxabi/src/cxa_new_delete.cpp +++ b/system/lib/libcxxabi/src/cxa_new_delete.cpp @@ -9,6 +9,8 @@ // This file implements the new and delete operators. //===----------------------------------------------------------------------===// +#define _LIBCPP_BUILDING_NEW + #include #include @@ -228,15 +230,33 @@ bad_array_new_length::what() const _NOEXCEPT return "bad_array_new_length"; } -#ifdef __EMSCRIPTEN__ -// We don't build the new.cpp from libcxx, so we need to define this. -void -__throw_bad_alloc() +// bad_array_length + +#ifndef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED + +class _LIBCPP_EXCEPTION_ABI bad_array_length + : public bad_alloc +{ +public: + bad_array_length() _NOEXCEPT; + virtual ~bad_array_length() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +#endif // _LIBCPP_BAD_ARRAY_LENGTH_DEFINED + +bad_array_length::bad_array_length() _NOEXCEPT { -#ifndef _LIBCPP_NO_EXCEPTIONS - throw bad_alloc(); -#endif } -#endif + +bad_array_length::~bad_array_length() _NOEXCEPT +{ +} + +const char* +bad_array_length::what() const _NOEXCEPT +{ + return "bad_array_length"; +} } // std diff --git a/system/lib/libcxxabi/src/private_typeinfo.cpp b/system/lib/libcxxabi/src/private_typeinfo.cpp index 216f796d..52326a3e 100644 --- a/system/lib/libcxxabi/src/private_typeinfo.cpp +++ b/system/lib/libcxxabi/src/private_typeinfo.cpp @@ -27,7 +27,7 @@ // The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a // printf-like function called syslog: // -// void syslog(const char* format, ...); +// void syslog(int facility_priority, const char* format, ...); // // If you want this functionality but your platform doesn't have syslog, // just implement it in terms of fprintf(stderr, ...). @@ -40,6 +40,18 @@ #include #endif +// On Windows, typeids are different between DLLs and EXEs, so comparing +// type_info* will work for typeids from the same compiled file but fail +// for typeids from a DLL and an executable. Among other things, exceptions +// are not caught by handlers since can_catch() returns false. +// +// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls +// is_equal() with use_strcmp=false so the string names are not compared. + +#ifdef _WIN32 +#include +#endif + namespace __cxxabiv1 { @@ -62,7 +74,11 @@ inline bool is_equal(const std::type_info* x, const std::type_info* y, bool) { +#ifndef _WIN32 return x == y; +#else + return (x == y) || (strcmp(x->name(), y->name()) == 0); +#endif } #endif // _LIBCXX_DYNAMIC_FALLBACK @@ -498,7 +514,7 @@ __dynamic_cast(const void* static_ptr, // We get here only if there is some kind of visibility problem // in client code. syslog(LOG_ERR, "dynamic_cast error 1: Both of the following type_info's " - "should have public visibility. At least of of them is hidden. %s" + "should have public visibility. At least one of them is hidden. %s" ", %s.\n", static_type->name(), dynamic_type->name()); // Redo the search comparing type_info's using strcmp info = {dst_type, static_ptr, static_type, src2dst_offset, 0}; diff --git a/system/lib/libcxxabi/src/stdexcept.cpp b/system/lib/libcxxabi/src/stdexcept.cpp index de859db4..246eea4b 100644 --- a/system/lib/libcxxabi/src/stdexcept.cpp +++ b/system/lib/libcxxabi/src/stdexcept.cpp @@ -47,7 +47,7 @@ private: #if __APPLE__ static const void* - compute_gcc_empty_string_storage() _LIBCPP_CANTTHROW + compute_gcc_empty_string_storage() _NOEXCEPT { void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD); if (handle == 0) @@ -57,7 +57,7 @@ private: static const void* - get_gcc_empty_string_storage() _LIBCPP_CANTTHROW + get_gcc_empty_string_storage() _NOEXCEPT { static const void* p = compute_gcc_empty_string_storage(); return p; @@ -66,9 +66,9 @@ private: 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; + __libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT; + __libcpp_nmstr& operator=(const __libcpp_nmstr& s) _NOEXCEPT; + ~__libcpp_nmstr(); const char* c_str() const _NOEXCEPT {return str_;} }; @@ -80,11 +80,11 @@ __libcpp_nmstr::__libcpp_nmstr(const char* msg) c->len = c->cap = len; str_ += offset; count() = 0; - std::strcpy(const_cast(c_str()), msg); + std::memcpy(const_cast(c_str()), msg, len + 1); } inline -__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) +__libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) _NOEXCEPT : str_(s.str_) { #if __APPLE__ @@ -94,7 +94,7 @@ __libcpp_nmstr::__libcpp_nmstr(const __libcpp_nmstr& s) } __libcpp_nmstr& -__libcpp_nmstr::operator=(const __libcpp_nmstr& s) +__libcpp_nmstr::operator=(const __libcpp_nmstr& s) _NOEXCEPT { const char* p = str_; str_ = s.str_; diff --git a/system/lib/libcxxabi/symbols b/system/lib/libcxxabi/symbols index a02a6411..f2925e4c 100644 --- a/system/lib/libcxxabi/symbols +++ b/system/lib/libcxxabi/symbols @@ -31,7 +31,6 @@ T _ZN10__cxxabiv129__pointer_to_member_type_infoD0Ev T _ZN10__cxxabiv129__pointer_to_member_type_infoD1Ev T _ZN10__cxxabiv129__pointer_to_member_type_infoD2Ev - C _ZN10__cxxabiv18is_equalEPKSt9type_infoS2_b T _ZNK10__cxxabiv116__enum_type_info9can_catchEPKNS_16__shim_type_infoERPv T _ZNK10__cxxabiv116__shim_type_info5noop1Ev T _ZNK10__cxxabiv116__shim_type_info5noop2Ev @@ -127,6 +126,7 @@ D _ZTIPy D _ZTISt10bad_typeid D _ZTISt8bad_cast + C _ZTISt9exception D _ZTISt9type_info D _ZTIa D _ZTIb @@ -201,6 +201,7 @@ D _ZTSPy D _ZTSSt10bad_typeid D _ZTSSt8bad_cast + C _ZTSSt9exception D _ZTSSt9type_info D _ZTSa D _ZTSb -- cgit v1.2.3-18-g5258