diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-01-13 16:55:19 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-01-13 16:56:03 -0800 |
commit | cd1edebb5034ea52396a5b68304e84ae80878740 (patch) | |
tree | 6a6f8364ea74985d11c4f6ff74e5b80e08dc849d | |
parent | af59788f8b7b76515e36bee1bf66edf497b801db (diff) | |
parent | 2914deb17f3857bb02eeec87a58a3ed6d4a8853a (diff) |
Merge branch 'incoming' of github.com:kripken/emscripten into incoming1.8.8
conflicts: tests/test_core.py tools/shared.py
117 files changed, 16913 insertions, 10057 deletions
@@ -1449,9 +1449,25 @@ try: os.path.join('libc', 'gen', 'verrx.c'), os.path.join('libc', 'gen', 'vwarn.c'), os.path.join('libc', 'gen', 'vwarnx.c'), - os.path.join('libc', 'stdlib', 'strtod.c'), ] musl_files = [ + ['internal', [ + 'floatscan.c', + 'shgetc.c', + ]], + ['math', [ + 'scalbn.c', + 'scalbnl.c', + ]], + ['stdio', [ + '__overflow.c', + '__toread.c', + '__uflow.c', + ]], + ['stdlib', [ + 'atof.c', + 'strtod.c', + ]] ] for directory, sources in musl_files: libc_files += [os.path.join('libc', 'musl', 'src', directory, source) for source in sources] @@ -1492,6 +1508,9 @@ try: 'wctrans.c', 'wcwidth.c', ]], + ['internal', [ + 'intscan.c', + ]], ['locale', [ 'iconv.c', 'iswalnum_l.c', @@ -1507,7 +1526,9 @@ try: 'iswspace_l.c', 'iswupper_l.c', 'iswxdigit_l.c', + 'strcasecmp_l.c', 'strfmon.c', + 'strncasecmp_l.c', 'strxfrm.c', 'towctrans_l.c', 'towlower_l.c', @@ -1519,6 +1540,29 @@ try: 'wctrans_l.c', 'wctype_l.c', ]], + ['math', [ + '__cosdf.c', + '__sindf.c', + 'ilogb.c', + 'ilogbf.c', + 'ilogbl.c', + 'ldexp.c', + 'ldexpf.c', + 'ldexpl.c', + 'logb.c', + 'logbf.c', + 'logbl.c', + 'lgamma.c', + 'lgamma_r.c', + 'lgammaf.c', + 'lgammaf_r.c', + 'lgammal.c', + 'scalbnf.c', + 'signgam.c', + 'tgamma.c', + 'tgammaf.c', + 'tgammal.c' + ]], ['multibyte', [ 'btowc.c', 'mblen.c', @@ -1554,8 +1598,20 @@ try: 'ecvt.c', 'fcvt.c', 'gcvt.c', + 'wcstod.c', + 'wcstol.c', ]], ['string', [ + 'memccpy.c', + 'memmem.c', + 'mempcpy.c', + 'memrchr.c', + 'strcasestr.c', + 'strchrnul.c', + 'strlcat.c', + 'strlcpy.c', + 'strsep.c', + 'strverscmp.c', 'wcpcpy.c', 'wcpncpy.c', 'wcscasecmp.c', diff --git a/src/jsifier.js b/src/jsifier.js index a503e90d..726a5eda 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -215,6 +215,9 @@ function JSify(data, functionsOnly) { function parseConst(value, type, ident) { var constant = makeConst(value, type); + // Sadly, we've thrown away type information in makeConst, so we're not + // passing correct type info to parseNumerical which works around this + // lack. constant = flatten(constant).map(function(x) { return parseNumerical(x) }) return constant; } diff --git a/src/library.js b/src/library.js index b1eb0be3..c41a8cda 100644 --- a/src/library.js +++ b/src/library.js @@ -4830,15 +4830,6 @@ LibraryManager.library = { llvm_log_f64: 'Math_log', llvm_exp_f32: 'Math_exp', llvm_exp_f64: 'Math_exp', - ldexp: function(x, exp_) { - return x * Math.pow(2, exp_); - }, - ldexpf: 'ldexp', - scalb: 'ldexp', - scalbn: 'ldexp', - scalbnf: 'ldexp', - scalbln: 'ldexp', - scalblnf: 'ldexp', cbrt: function(x) { return Math.pow(x, 1/3); }, @@ -9193,7 +9184,7 @@ function autoAddDeps(object, name) { } // Add aborting stubs for various libc stuff needed by libc++ -['pthread_cond_signal', 'pthread_equal', 'wcstol', 'wcstoll', 'wcstoul', 'wcstoull', 'wcstof', 'wcstod', 'wcstold', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose', 'fputwc', '__lockfile', '__unlockfile'].forEach(function(aborter) { +['pthread_cond_signal', 'pthread_equal', 'pthread_join', 'pthread_detach', 'catgets', 'catopen', 'catclose', 'fputwc', '__lockfile', '__unlockfile'].forEach(function(aborter) { LibraryManager.library[aborter] = function aborting_stub() { throw 'TODO: ' + aborter }; }); diff --git a/src/parseTools.js b/src/parseTools.js index 4d6d7bd3..b7f97a40 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -962,8 +962,13 @@ function parseNumerical(value, type) { } if (isNumber(value)) { var ret = parseFloat(value); // will change e.g. 5.000000e+01 to 50 + // type may be undefined here, like when this is called from makeConst with a single argument. + // but if it is a number, then we can safely assume that this should handle negative zeros + // correctly. + if (type === undefined || type === 'double' || type === 'float') { + if (value[0] === '-' && ret === 0) { return '-.0'; } // fix negative 0, toString makes it 0 + } if (type === 'double' || type === 'float') { - if (value[0] === '-' && ret === 0) return '-.0'; // fix negative 0, toString makes it 0 if (!RUNNING_JS_OPTS) ret = asmEnsureFloat(ret, type); } return ret.toString(); diff --git a/system/include/libcxx/__config b/system/include/libcxx/__config index a45b02de..45207392 100644 --- a/system/include/libcxx/__config +++ b/system/include/libcxx/__config @@ -174,7 +174,7 @@ #endif #ifndef _LIBCPP_TYPE_VIS -# if __has_attribute(type_visibility) +# if __has_attribute(__type_visibility__) # define _LIBCPP_TYPE_VIS __attribute__ ((__type_visibility__("default"))) # else # define _LIBCPP_TYPE_VIS __attribute__ ((__visibility__("default"))) @@ -389,9 +389,7 @@ namespace std { #endif #if _GNUC_VER < 404 -#define _LIBCPP_HAS_NO_ADVANCED_SFINAE #define _LIBCPP_HAS_NO_DECLTYPE -#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS #define _LIBCPP_HAS_NO_DELETED_FUNCTIONS #define _LIBCPP_HAS_NO_UNICODE_CHARS #define _LIBCPP_HAS_NO_VARIADICS @@ -402,6 +400,11 @@ namespace std { #define _LIBCPP_HAS_NO_NULLPTR #endif +#if _GNUC_VER < 407 +#define _LIBCPP_HAS_NO_ADVANCED_SFINAE +#define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif + #endif // __GXX_EXPERIMENTAL_CXX0X__ #define _LIBCPP_BEGIN_NAMESPACE_STD namespace std { namespace _LIBCPP_NAMESPACE { @@ -454,7 +457,6 @@ namespace std { #define _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS #define _LIBCPP_HAS_NO_NULLPTR #define _LIBCPP_HAS_NO_UNICODE_CHARS -#define _LIBCPP_HAS_NO_STRONG_ENUMS #define _LIBCPP_HAS_IS_BASE_OF #if defined(_AIX) @@ -514,7 +516,7 @@ template <unsigned> struct __static_assert_check {}; #define __has_feature(__x) 0 #endif -#if __has_feature(cxx_explicit_conversions) +#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) # define _LIBCPP_EXPLICIT explicit #else # define _LIBCPP_EXPLICIT @@ -567,6 +569,16 @@ template <unsigned> struct __static_assert_check {}; #define _LIBCPP_WCTYPE_IS_MASK #endif +#if defined(__APPLE__) +#ifndef _LIBCPP_TRIVIAL_PAIR_COPY_CTOR +# define _LIBCPP_TRIVIAL_PAIR_COPY_CTOR 0 +#endif +#endif + +#ifndef _LIBCPP_TRIVIAL_PAIR_COPY_CTOR +# define _LIBCPP_TRIVIAL_PAIR_COPY_CTOR 1 +#endif + #ifndef _LIBCPP_STD_VER # if __cplusplus <= 201103L # define _LIBCPP_STD_VER 11 diff --git a/system/include/libcxx/__undef_min_max b/system/include/libcxx/__undef_min_max index 2b6bc90a..5df9412c 100644 --- a/system/include/libcxx/__undef_min_max +++ b/system/include/libcxx/__undef_min_max @@ -10,7 +10,8 @@ #ifdef min #if defined(_MSC_VER) && ! defined(__clang__) -_LIBCPP_WARNING("macro min is incompatible with C++. #undefing min") +_LIBCPP_WARNING("macro min is incompatible with C++. Try #define NOMINMAX " + "before any Windows header. #undefing min") #else #warning: macro min is incompatible with C++. #undefing min #endif @@ -19,7 +20,8 @@ _LIBCPP_WARNING("macro min is incompatible with C++. #undefing min") #ifdef max #if defined(_MSC_VER) && ! defined(__clang__) -_LIBCPP_WARNING("macro max is incompatible with C++. #undefing max") +_LIBCPP_WARNING("macro max is incompatible with C++. Try #define NOMINMAX " + "before any Windows header. #undefing max") #else #warning: macro max is incompatible with C++. #undefing max #endif diff --git a/system/include/libcxx/dynarray b/system/include/libcxx/experimental/dynarray index b0d04f91..7c5c9b3f 100644 --- a/system/include/libcxx/dynarray +++ b/system/include/libcxx/experimental/dynarray @@ -17,7 +17,7 @@ /* dynarray synopsis -namespace std { +namespace std { namespace experimental { template< typename T > class dynarray @@ -93,7 +93,7 @@ public: void fill(const T& v); }; -} // std +}} // std::experimental */ @@ -112,7 +112,7 @@ public: #pragma GCC system_header #endif -_LIBCPP_BEGIN_NAMESPACE_STD +namespace std { namespace experimental { inline namespace __array_extensions_v1 { template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY dynarray @@ -302,9 +302,12 @@ dynarray<_Tp>::at(size_type __n) const return data()[__n]; } -template <class _Tp, class _Alloc> -struct _LIBCPP_TYPE_VIS_ONLY uses_allocator<dynarray<_Tp>, _Alloc> : true_type {}; +}}} + +_LIBCPP_BEGIN_NAMESPACE_STD +template <class _Tp, class _Alloc> +struct _LIBCPP_TYPE_VIS_ONLY uses_allocator<std::experimental::dynarray<_Tp>, _Alloc> : true_type {}; _LIBCPP_END_NAMESPACE_STD #endif // if _LIBCPP_STD_VER > 11 diff --git a/system/include/libcxx/optional b/system/include/libcxx/experimental/optional index a8e6a991..3848da87 100644 --- a/system/include/libcxx/optional +++ b/system/include/libcxx/experimental/optional @@ -18,8 +18,7 @@ #include <initializer_list> -namespace std -{ +namespace std { namespace experimental { // optional for object types template <class T> @@ -110,7 +109,7 @@ template <class T> constexpr optional<typename decay<T>::type> make_optional(T&& template <class T> struct hash; template <class T> struct hash<optional<T>>; -} // std +}} // std::experimental */ @@ -118,8 +117,7 @@ template <class T> struct hash<optional<T>>; #include <functional> #include <stdexcept> -namespace std // purposefully not using versioning namespace -{ +namespace std { namespace experimental { class _LIBCPP_EXCEPTION_ABI bad_optional_access : public logic_error @@ -142,7 +140,7 @@ public: virtual ~bad_optional_access() _NOEXCEPT; }; -} // std +}} // std::experimental #if _LIBCPP_STD_VER > 11 @@ -163,7 +161,7 @@ public: #pragma GCC system_header #endif -_LIBCPP_BEGIN_NAMESPACE_STD +namespace std { namespace experimental { inline namespace __library_fundamentals_v1 { struct in_place_t {}; constexpr in_place_t in_place{}; @@ -677,10 +675,14 @@ make_optional(_Tp&& __v) return optional<typename decay<_Tp>::type>(_VSTD::forward<_Tp>(__v)); } +}}} // namespace std::experimental::__library_fundamentals_v1 + +_LIBCPP_BEGIN_NAMESPACE_STD + template <class _Tp> -struct _LIBCPP_TYPE_VIS_ONLY hash<optional<_Tp> > +struct _LIBCPP_TYPE_VIS_ONLY hash<std::experimental::optional<_Tp> > { - typedef optional<_Tp> argument_type; + typedef std::experimental::optional<_Tp> argument_type; typedef size_t result_type; _LIBCPP_INLINE_VISIBILITY diff --git a/system/include/libcxx/ext/__hash b/system/include/libcxx/ext/__hash index 04975bfd..c0523cce 100644 --- a/system/include/libcxx/ext/__hash +++ b/system/include/libcxx/ext/__hash @@ -19,7 +19,7 @@ namespace __gnu_cxx { using namespace std; -template <typename T> struct _LIBCPP_TYPE_VIS_ONLY hash : public std::hash<T> +template <typename _Tp> struct _LIBCPP_TYPE_VIS_ONLY hash : public std::hash<_Tp> { }; template <> struct _LIBCPP_TYPE_VIS_ONLY hash<const char*> diff --git a/system/include/libcxx/iomanip b/system/include/libcxx/iomanip index cdb0d5f0..e334c7de 100644 --- a/system/include/libcxx/iomanip +++ b/system/include/libcxx/iomanip @@ -14,6 +14,8 @@ /* iomanip synopsis +namespace std { + // types T1, T2, ... are unspecified implementation types T1 resetiosflags(ios_base::fmtflags mask); T2 setiosflags (ios_base::fmtflags mask); @@ -604,7 +606,7 @@ basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& __os, const __quoted_proxy<_CharT, _Traits, _Allocator> & __proxy) { - return __quoted_output (__os, __proxy.string.cbegin (), __proxy.string.cend (), __proxy.__delim, __proxy.__escape); + return __quoted_output (__os, __proxy.__string.cbegin (), __proxy.__string.cend (), __proxy.__delim, __proxy.__escape); } // extractor for non-const basic_string& proxies diff --git a/system/include/libcxx/memory b/system/include/libcxx/memory index bf44837f..b382f70b 100644 --- a/system/include/libcxx/memory +++ b/system/include/libcxx/memory @@ -1954,7 +1954,7 @@ public: _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : __first_(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) @@ -1973,8 +1973,6 @@ public: return *this; } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && @@ -1992,9 +1990,7 @@ public: return *this; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -2051,7 +2047,7 @@ public: _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : _T1(_VSTD::forward<_T1_param>(__t1)), __second_(_VSTD::forward<_T2_param>(__t2)) {} -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) @@ -2069,8 +2065,6 @@ public: return *this; } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && @@ -2087,9 +2081,7 @@ public: return *this; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -2147,7 +2139,7 @@ public: is_nothrow_move_constructible<_T2>::value) : _T2(_VSTD::forward<_T2_param>(__t2)), __first_(_VSTD::forward<_T1_param>(__t1)) {} -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) @@ -2165,8 +2157,6 @@ public: return *this; } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && @@ -2183,9 +2173,7 @@ public: return *this; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -2241,7 +2229,7 @@ public: _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(_T1_param __t1, _T2_param __t2) : _T1(_VSTD::forward<_T1_param>(__t1)), _T2(_VSTD::forward<_T2_param>(__t2)) {} -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(const __libcpp_compressed_pair_imp& __p) @@ -2259,8 +2247,6 @@ public: return *this; } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY __libcpp_compressed_pair_imp(__libcpp_compressed_pair_imp&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && @@ -2277,9 +2263,7 @@ public: return *this; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS @@ -2332,7 +2316,7 @@ public: _LIBCPP_INLINE_VISIBILITY __compressed_pair(_T1_param __t1, _T2_param __t2) : base(_VSTD::forward<_T1_param>(__t1), _VSTD::forward<_T2_param>(__t2)) {} -#ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) _LIBCPP_INLINE_VISIBILITY __compressed_pair(const __compressed_pair& __p) @@ -2349,7 +2333,6 @@ public: return *this; } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES _LIBCPP_INLINE_VISIBILITY __compressed_pair(__compressed_pair&& __p) _NOEXCEPT_(is_nothrow_move_constructible<_T1>::value && @@ -2365,9 +2348,7 @@ public: return *this; } -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#endif // defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) #ifndef _LIBCPP_HAS_NO_VARIADICS diff --git a/system/include/libcxx/new b/system/include/libcxx/new index 31bb5982..ea4a4a01 100644 --- a/system/include/libcxx/new +++ b/system/include/libcxx/new @@ -94,6 +94,7 @@ public: }; #if defined(_LIBCPP_BUILDING_NEW) || (_LIBCPP_STD_VER > 11) + class _LIBCPP_EXCEPTION_ABI bad_array_length : public bad_alloc { @@ -102,7 +103,10 @@ public: virtual ~bad_array_length() _NOEXCEPT; virtual const char* what() const _NOEXCEPT; }; -#endif + +#define _LIBCPP_BAD_ARRAY_LENGTH_DEFINED + +#endif // defined(_LIBCPP_BUILDING_NEW) || (_LIBCPP_STD_VER > 11) _LIBCPP_FUNC_VIS void __throw_bad_alloc(); // not in C++ spec diff --git a/system/include/libcxx/readme.txt b/system/include/libcxx/readme.txt index ae8090fd..ccac2fcd 100644 --- a/system/include/libcxx/readme.txt +++ b/system/include/libcxx/readme.txt @@ -1 +1 @@ -These files are from libc++, svn revision 194185, 2013-11-07. +These files are from libc++, svn revision 195693, 2013-11-26. diff --git a/system/include/libcxx/support/ibm/support.h b/system/include/libcxx/support/ibm/support.h index 3effbaed..0abfa7f9 100644 --- a/system/include/libcxx/support/ibm/support.h +++ b/system/include/libcxx/support/ibm/support.h @@ -15,7 +15,7 @@ extern "builtin" int __popcnt4(unsigned int); extern "builtin" int __popcnt8(unsigned long long); extern "builtin" unsigned int __cnttz4(unsigned int); extern "builtin" unsigned int __cnttz8(unsigned long long); -extern "builtin" unsigned int __cntlz4(unsigned long long); +extern "builtin" unsigned int __cntlz4(unsigned int); extern "builtin" unsigned int __cntlz8(unsigned long long); // Builtin functions for counting population diff --git a/system/include/libcxx/support/win32/locale_win32.h b/system/include/libcxx/support/win32/locale_win32.h index e768af50..f728d234 100644 --- a/system/include/libcxx/support/win32/locale_win32.h +++ b/system/include/libcxx/support/win32/locale_win32.h @@ -103,9 +103,9 @@ isupper_l(int c, _locale_t loc) #define sscanf_l( __s, __l, __f, ...) _sscanf_l( __s, __f, __l, __VA_ARGS__ ) #define vsscanf_l( __s, __l, __f, ...) _sscanf_l( __s, __f, __l, __VA_ARGS__ ) #define sprintf_l( __s, __l, __f, ... ) _sprintf_l( __s, __f, __l, __VA_ARGS__ ) -#define snprintf_l( __s, __n, __l, __f, ... ) _snprintf_l( __s, __n, __f, __l, __VA_ARGS__ ) #define vsprintf_l( __s, __l, __f, ... ) _vsprintf_l( __s, __f, __l, __VA_ARGS__ ) #define vsnprintf_l( __s, __n, __l, __f, ... ) _vsnprintf_l( __s, __n, __f, __l, __VA_ARGS__ ) +int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...); int asprintf_l( char **ret, locale_t loc, const char *format, ... ); int vasprintf_l( char **ret, locale_t loc, const char *format, va_list ap ); diff --git a/system/include/libcxx/support/win32/support.h b/system/include/libcxx/support/win32/support.h index b953ab77..ed1986e6 100644 --- a/system/include/libcxx/support/win32/support.h +++ b/system/include/libcxx/support/win32/support.h @@ -23,7 +23,6 @@ #ifndef NOMINMAX #define NOMINMAX #endif -#include <Windows.h> extern "C" { diff --git a/system/include/libcxx/type_traits b/system/include/libcxx/type_traits index b6430fbb..0ad7b7f2 100644 --- a/system/include/libcxx/type_traits +++ b/system/include/libcxx/type_traits @@ -1409,7 +1409,7 @@ template <class ..._Tp> using common_type_t = typename common_type<_Tp...>::type // is_assignable -template<typename, typename T> struct __select_2nd { typedef T type; }; +template<typename, typename _Tp> struct __select_2nd { typedef _Tp type; }; template <class _Tp, class _Arg> typename __select_2nd<decltype((_VSTD::declval<_Tp>() = _VSTD::declval<_Arg>())), true_type>::type @@ -2437,7 +2437,7 @@ template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY is_trivially_default_construct // is_trivially_copy_constructible template <class _Tp> struct _LIBCPP_TYPE_VIS_ONLY is_trivially_copy_constructible - : public is_trivially_constructible<_Tp, const typename add_lvalue_reference<_Tp>::type> + : public is_trivially_constructible<_Tp, typename add_lvalue_reference<const _Tp>::type> {}; // is_trivially_move_constructible diff --git a/system/include/libcxx/utility b/system/include/libcxx/utility index 5fc2cf20..2c1f62cc 100644 --- a/system/include/libcxx/utility +++ b/system/include/libcxx/utility @@ -272,10 +272,10 @@ struct _LIBCPP_TYPE_VIS_ONLY pair ) : first(__p.first), second(__p.second) {} -#ifndef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS +#if !defined(_LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS) && _LIBCPP_TRIVIAL_PAIR_COPY_CTOR _LIBCPP_INLINE_VISIBILITY pair(const pair& __p) = default; -#else +#elif !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) || !_LIBCPP_TRIVIAL_PAIR_COPY_CTOR _LIBCPP_INLINE_VISIBILITY pair(const pair& __p) _NOEXCEPT_(is_nothrow_copy_constructible<first_type>::value && diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols index 561f01c1..04fb40d6 100644 --- a/system/lib/libc.symbols +++ b/system/lib/libc.symbols @@ -1,9 +1,15 @@ + T _ZNKSt16bad_array_length4whatEv T _ZNKSt20bad_array_new_length4whatEv T _ZNKSt9bad_alloc4whatEv + T _ZNSt16bad_array_lengthC1Ev + T _ZNSt16bad_array_lengthC2Ev + T _ZNSt16bad_array_lengthD0Ev + T _ZNSt16bad_array_lengthD1Ev + T _ZNSt16bad_array_lengthD2Ev T _ZNSt20bad_array_new_lengthC1Ev T _ZNSt20bad_array_new_lengthC2Ev T _ZNSt20bad_array_new_lengthD0Ev - ? _ZNSt20bad_array_new_lengthD1Ev + T _ZNSt20bad_array_new_lengthD1Ev T _ZNSt20bad_array_new_lengthD2Ev T _ZNSt9bad_allocC1Ev T _ZNSt9bad_allocC2Ev @@ -14,10 +20,15 @@ T _ZSt15set_new_handlerPFvvE T _ZSt17__throw_bad_allocv D _ZSt7nothrow + D _ZTISt16bad_array_length D _ZTISt20bad_array_new_length D _ZTISt9bad_alloc + C _ZTISt9exception + D _ZTSSt16bad_array_length D _ZTSSt20bad_array_new_length D _ZTSSt9bad_alloc + C _ZTSSt9exception + D _ZTVSt16bad_array_length D _ZTVSt20bad_array_new_length D _ZTVSt9bad_alloc W _ZdaPv @@ -28,6 +39,17 @@ W _ZnajRKSt9nothrow_t W _Znwj W _ZnwjRKSt9nothrow_t + T __floatscan + T __overflow + T __seek_on_exit + T __shgetc + T __shlim + W __strtod_l + W __strtof_l + W __strtold_l + T __toread + W __towrite_used + T __uflow T _err T _errx T _verr @@ -67,11 +89,14 @@ W pvalloc W realloc W realloc_in_place + T scalbn + T scalbnl T strtod - T strtod_l + W strtod_l T strtof + W strtof_l T strtold - T strtold_l + W strtold_l W valloc W verr W verrx diff --git a/system/lib/libc/musl/src/internal/floatscan.c b/system/lib/libc/musl/src/internal/floatscan.c new file mode 100644 index 00000000..f6e331d4 --- /dev/null +++ b/system/lib/libc/musl/src/internal/floatscan.c @@ -0,0 +1,496 @@ +#include <stdint.h> +#include <stdio.h> +#include <math.h> +#include <float.h> +#include <limits.h> +#include <errno.h> +#include <ctype.h> + +#include "shgetc.h" +#include "floatscan.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 + +#define LD_B1B_DIG 2 +#define LD_B1B_MAX 9007199, 254740991 +#define KMAX 128 + +#else /* LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 */ + +#define LD_B1B_DIG 3 +#define LD_B1B_MAX 18, 446744073, 709551615 +#define KMAX 2048 + +#endif + +#define MASK (KMAX-1) + +#define CONCAT2(x,y) x ## y +#define CONCAT(x,y) CONCAT2(x,y) + +static long long scanexp(FILE *f, int pok) +{ + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c=='+' || c=='-') { + neg = (c=='-'); + c = shgetc(f); + if (c-'0'>=10U && pok) shunget(f); + } + if (c-'0'>=10U) { + shunget(f); + return LLONG_MIN; + } + for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f)) + x = 10*x + c-'0'; + for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f)) + y = 10*y + c-'0'; + for (; c-'0'<10U; c = shgetc(f)); + shunget(f); + return neg ? -y : y; +} + + +static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok) +{ + uint32_t x[KMAX]; + static const uint32_t th[] = { LD_B1B_MAX }; + int i, j, k, a, z; + long long lrp=0, dc=0; + long long e10=0; + int lnz = 0; + int gotdig = 0, gotrad = 0; + int rp; + int e2; + int emax = -emin-bits+3; + int denormal = 0; + long double y; + long double frac=0; + long double bias=0; + static const int p10s[] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; + + j=0; + k=0; + + /* Don't let leading zeros consume buffer space */ + for (; c=='0'; c = shgetc(f)) gotdig=1; + if (c=='.') { + gotrad = 1; + for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--; + } + + x[0] = 0; + for (; c-'0'<10U || c=='.'; c = shgetc(f)) { + if (c == '.') { + if (gotrad) break; + gotrad = 1; + lrp = dc; + } else if (k < KMAX-3) { + dc++; + if (c!='0') lnz = dc; + if (j) x[k] = x[k]*10 + c-'0'; + else x[k] = c-'0'; + if (++j==9) { + k++; + j=0; + } + gotdig=1; + } else { + dc++; + if (c!='0') x[KMAX-4] |= 1; + } + } + if (!gotrad) lrp=dc; + + if (gotdig && (c|32)=='e') { + e10 = scanexp(f, pok); + if (e10 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e10 = 0; + } + lrp += e10; + } else if (c>=0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) + return sign * (long double)x[0]; + if (lrp > -emin/2) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (lrp < emin-2*LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j<9; j++) x[k]*=10; + k++; + j=0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz<9 && lnz<=rp && rp < 18) { + if (rp == 9) return sign * (long double)x[0]; + if (rp < 9) return sign * (long double)x[0] / p10s[8-rp]; + int bitlim = bits-3*(int)(rp-9); + if (bitlim>30 || x[0]>>bitlim==0) + return sign * (long double)x[0] * p10s[rp-10]; + } + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp>=0 ? rp%9 : rp%9+9; + int p10 = p10s[8-rpm9]; + uint32_t carry = 0; + for (k=a; k!=z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k]/p10 + carry; + carry = 1000000000/p10 * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9-rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) { + uint32_t carry = 0; + e2 -= 29; + for (k=(z-1 & MASK); ; k=(k-1 & MASK)) { + uint64_t tmp = ((uint64_t)x[k] << 29) + carry; + if (tmp > 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; + if (k==a) break; + } + if (carry) { + rp += 9; + a = (a-1 & MASK); + if (a == z) { + z = (z-1 & MASK); + x[z-1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i=0; i<LD_B1B_DIG; i++) { + k = (a+i & MASK); + if (k == z || x[k] < th[i]) { + i=LD_B1B_DIG; + break; + } + if (x[a+i & MASK] > th[i]) break; + } + if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9+9*LD_B1B_DIG) sh = 9; + e2 += sh; + for (k=a; k!=z; k=(k+1 & MASK)) { + uint32_t tmp = x[k] & (1<<sh)-1; + x[k] = (x[k]>>sh) + carry; + carry = (1000000000>>sh) * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z+1 & MASK) != a) { + x[z] = carry; + z = (z+1 & MASK); + } else x[z-1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y=i=0; i<LD_B1B_DIG; i++) { + if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0; + y = 1000000000.0L * y + x[a+i & MASK]; + } + + y *= sign; + + /* Limit precision for denormal results */ + if (bits > LDBL_MANT_DIG+e2-emin) { + bits = LDBL_MANT_DIG+e2-emin; + if (bits<0) bits=0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < LDBL_MANT_DIG) { + bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y); + frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a+i & MASK) != z) { + uint32_t t = x[a+i & MASK]; + if (t < 500000000 && (t || (a+i+1 & MASK) != z)) + frac += 0.25*sign; + else if (t > 500000000) + frac += 0.75*sign; + else if (t == 500000000) { + if ((a+i+1 & MASK) == z) + frac += 0.5*sign; + else + frac += 0.75*sign; + } + if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1)) + frac++; + } + + y += frac; + y -= bias; + + if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) { + if (fabs(y) >= CONCAT(0x1p, LDBL_MANT_DIG)) { + if (denormal && bits==LDBL_MANT_DIG+e2-emin) + denormal = 0; + y *= 0.5; + e2++; + } + if (e2+LDBL_MANT_DIG>emax || (denormal && frac)) + errno = ERANGE; + } + + return scalbnl(y, e2); +} + +static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok) +{ + uint32_t x = 0; + long double y = 0; + long double scale = 1; + long double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c=='0'; c = shgetc(f)) gotdig = 1; + + if (c=='.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1; + } + + for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) { + if (c=='.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') d = (c|32)+10-'a'; + else d = c-'0'; + if (dc<8) { + x = x*16 + d; + } else if (dc < LDBL_MANT_DIG/4+1) { + y += d*(scale/=16); + } else if (d && !gottail) { + y += 0.5*scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc<8) x *= 16, dc++; + if ((c|32)=='p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4*rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * LDBL_MAX * LDBL_MAX; + } + if (e2 < emin-2*LDBL_MANT_DIG) { + errno = ERANGE; + return sign * LDBL_MIN * LDBL_MIN; + } + + while (x < 0x80000000) { + if (y>=0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32+e2-emin) { + bits = 32+e2-emin; + if (bits<0) bits=0; + } + + if (bits < LDBL_MANT_DIG) + bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign); + + if (bits<32 && y && !(x&1)) x++, y=0; + + y = bias + sign*(long double)x + sign*y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbnl(y, e2); +} + +long double __floatscan(FILE *f, int prec, int pok) +{ + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + case 2: + bits = LDBL_MANT_DIG; + emin = LDBL_MIN_EXP-bits; + break; + default: + return 0; + } + + while (isspace((c=shgetc(f)))); + + if (c=='+' || c=='-') { + sign -= 2*(c=='-'); + c = shgetc(f); + } + + for (i=0; i<8 && (c|32)=="infinity"[i]; i++) + if (i<7) c = shgetc(f); + if (i==3 || i==8 || (i>3 && pok)) { + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } + return sign * INFINITY; + } + if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) + if (i<2) c = shgetc(f); + if (i==3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i=1; ; i++) { + c = shgetc(f); + if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') + continue; + if (c==')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) shunget(f); + return NAN; + } + return NAN; + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c=='0') { + c = shgetc(f); + if ((c|32) == 'x') + return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} diff --git a/system/lib/libc/musl/src/internal/floatscan.h b/system/lib/libc/musl/src/internal/floatscan.h new file mode 100644 index 00000000..e027fa08 --- /dev/null +++ b/system/lib/libc/musl/src/internal/floatscan.h @@ -0,0 +1,8 @@ +#ifndef FLOATSCAN_H +#define FLOATSCAN_H + +#include <stdio.h> + +long double __floatscan(FILE *, int, int); + +#endif diff --git a/system/lib/libc/musl/src/internal/intscan.c b/system/lib/libc/musl/src/internal/intscan.c new file mode 100644 index 00000000..69350efa --- /dev/null +++ b/system/lib/libc/musl/src/internal/intscan.c @@ -0,0 +1,99 @@ +#include <limits.h> +#include <errno.h> +#include <ctype.h> +#include "shgetc.h" + +/* Lookup table for digit values. -1==255>=36 -> invalid */ +static const unsigned char table[] = { -1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, +25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +unsigned long long __intscan(FILE *f, unsigned base, int pok, unsigned long long lim) +{ + const unsigned char *val = table+1; + int c, neg=0; + unsigned x; + unsigned long long y; + if (base > 36) { + errno = EINVAL; + return 0; + } + while (isspace((c=shgetc(f)))); + if (c=='+' || c=='-') { + neg = -(c=='-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c=='0') { + c = shgetc(f); + if ((c|32)=='x') { + c = shgetc(f); + if (val[c]>=16) { + shunget(f); + if (pok) shunget(f); + else shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f)) + x = x*10 + (c-'0'); + for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f)) + y = y*10 + (c-'0'); + if (c-'0'>=10U) goto done; + } else if (!(base & base-1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7]; + for (x=0; val[c]<base && x<=UINT_MAX/32; c=shgetc(f)) + x = x<<bs | val[c]; + for (y=x; val[c]<base && y<=ULLONG_MAX>>bs; c=shgetc(f)) + y = y<<bs | val[c]; + } else { + for (x=0; val[c]<base && x<=UINT_MAX/36-1; c=shgetc(f)) + x = x*base + val[c]; + for (y=x; val[c]<base && y<=ULLONG_MAX/base && base*y<=ULLONG_MAX-val[c]; c=shgetc(f)) + y = y*base + val[c]; + } + if (val[c]<base) { + for (; val[c]<base; c=shgetc(f)); + errno = ERANGE; + y = lim; + } +done: + shunget(f); + if (y>=lim) { + if (!(lim&1) && !neg) { + errno = ERANGE; + return lim-1; + } else if (y>lim) { + errno = ERANGE; + return lim; + } + } + return (y^neg)-neg; +} diff --git a/system/lib/libc/musl/src/internal/intscan.h b/system/lib/libc/musl/src/internal/intscan.h new file mode 100644 index 00000000..994c5e7d --- /dev/null +++ b/system/lib/libc/musl/src/internal/intscan.h @@ -0,0 +1,8 @@ +#ifndef INTSCAN_H +#define INTSCAN_H + +#include <stdio.h> + +unsigned long long __intscan(FILE *, unsigned, int, unsigned long long); + +#endif diff --git a/system/lib/libc/musl/src/internal/libm.h b/system/lib/libc/musl/src/internal/libm.h new file mode 100644 index 00000000..9f0d3bc8 --- /dev/null +++ b/system/lib/libc/musl/src/internal/libm.h @@ -0,0 +1,169 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#ifndef _LIBM_H +#define _LIBM_H + +#include <stdint.h> +#include <float.h> +#include <math.h> +#include <complex.h> +#include <endian.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t m; + uint16_t se; + } i; +}; +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN +union ldshape { + long double f; + struct { + uint64_t lo; + uint32_t mid; + uint16_t top; + uint16_t se; + } i; + struct { + uint64_t lo; + uint64_t hi; + } i2; +}; +#else +#error Unsupported long double representation +#endif + +#define FORCE_EVAL(x) do { \ + if (sizeof(x) == sizeof(float)) { \ + volatile float __x; \ + __x = (x); \ + } else if (sizeof(x) == sizeof(double)) { \ + volatile double __x; \ + __x = (x); \ + } else { \ + volatile long double __x; \ + __x = (x); \ + } \ +} while(0) + +/* Get two 32 bit ints from a double. */ +#define EXTRACT_WORDS(hi,lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ +#define GET_HIGH_WORD(hi,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (hi) = __u.i >> 32; \ +} while (0) + +/* Get the less significant 32 bit int from a double. */ +#define GET_LOW_WORD(lo,d) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + (lo) = (uint32_t)__u.i; \ +} while (0) + +/* Set a double from two 32 bit ints. */ +#define INSERT_WORDS(d,hi,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Set the more significant 32 bits of a double from an int. */ +#define SET_HIGH_WORD(d,hi) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff; \ + __u.i |= (uint64_t)(hi) << 32; \ + (d) = __u.f; \ +} while (0) + +/* Set the less significant 32 bits of a double from an int. */ +#define SET_LOW_WORD(d,lo) \ +do { \ + union {double f; uint64_t i;} __u; \ + __u.f = (d); \ + __u.i &= 0xffffffff00000000ull; \ + __u.i |= (uint32_t)(lo); \ + (d) = __u.f; \ +} while (0) + +/* Get a 32 bit int from a float. */ +#define GET_FLOAT_WORD(w,d) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.f = (d); \ + (w) = __u.i; \ +} while (0) + +/* Set a float from a 32 bit int. */ +#define SET_FLOAT_WORD(d,w) \ +do { \ + union {float f; uint32_t i;} __u; \ + __u.i = (w); \ + (d) = __u.f; \ +} while (0) + +/* fdlibm kernel functions */ + +int __rem_pio2_large(double*,double*,int,int,int); + +int __rem_pio2(double,double*); +double __sin(double,double,int); +double __cos(double,double); +double __tan(double,double,int); +double __expo2(double); +double complex __ldexp_cexp(double complex,int); + +int __rem_pio2f(float,double*); +float __sindf(double); +float __cosdf(double); +float __tandf(double,int); +float __expo2f(float); +float complex __ldexp_cexpf(float complex,int); + +int __rem_pio2l(long double, long double *); +long double __sinl(long double, long double, int); +long double __cosl(long double, long double); +long double __tanl(long double, long double, int); + +/* polynomial evaluation */ +long double __polevll(long double, const long double *, int); +long double __p1evll(long double, const long double *, int); + +#if 0 +/* Attempt to get strict C99 semantics for assignment with non-C99 compilers. */ +#define STRICT_ASSIGN(type, lval, rval) do { \ + volatile type __v = (rval); \ + (lval) = __v; \ +} while (0) +#else +/* Should work with -fexcess-precision=standard (>=gcc-4.5) or -ffloat-store */ +#define STRICT_ASSIGN(type, lval, rval) ((lval) = (type)(rval)) +#endif + +#endif diff --git a/system/lib/libc/musl/src/internal/shgetc.c b/system/lib/libc/musl/src/internal/shgetc.c new file mode 100644 index 00000000..e878b00a --- /dev/null +++ b/system/lib/libc/musl/src/internal/shgetc.c @@ -0,0 +1,27 @@ +#include "shgetc.h" + +void __shlim(FILE *f, off_t lim) +{ + f->shlim = lim; + f->shcnt = f->rend - f->rpos; + if (lim && f->shcnt > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +int __shgetc(FILE *f) +{ + int c; + if (f->shlim && f->shcnt >= f->shlim || (c=__uflow(f)) < 0) { + f->shend = 0; + return EOF; + } + if (f->shlim && f->rend - f->rpos > f->shlim - f->shcnt - 1) + f->shend = f->rpos + (f->shlim - f->shcnt - 1); + else + f->shend = f->rend; + if (f->rend) f->shcnt += f->rend - f->rpos + 1; + if (f->rpos[-1] != c) f->rpos[-1] = c; + return c; +} diff --git a/system/lib/libc/musl/src/internal/shgetc.h b/system/lib/libc/musl/src/internal/shgetc.h new file mode 100644 index 00000000..7beb8ce6 --- /dev/null +++ b/system/lib/libc/musl/src/internal/shgetc.h @@ -0,0 +1,9 @@ +#include "stdio_impl.h" + +void __shlim(FILE *, off_t); +int __shgetc(FILE *); + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->rend)) +#define shlim(f, lim) __shlim((f), (lim)) +#define shgetc(f) (((f)->rpos < (f)->shend) ? *(f)->rpos++ : __shgetc(f)) +#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0) diff --git a/system/lib/libc/musl/src/locale/strcasecmp_l.c b/system/lib/libc/musl/src/locale/strcasecmp_l.c new file mode 100644 index 00000000..eea2f80b --- /dev/null +++ b/system/lib/libc/musl/src/locale/strcasecmp_l.c @@ -0,0 +1,7 @@ +#include <strings.h> +#include <ctype.h> + +int strcasecmp_l(const char *l, const char *r, locale_t loc) +{ + return strcasecmp(l, r); +} diff --git a/system/lib/libc/musl/src/locale/strncasecmp_l.c b/system/lib/libc/musl/src/locale/strncasecmp_l.c new file mode 100644 index 00000000..af33ada6 --- /dev/null +++ b/system/lib/libc/musl/src/locale/strncasecmp_l.c @@ -0,0 +1,7 @@ +#include <strings.h> +#include <locale.h> + +int strncasecmp_l(const char *l, const char *r, size_t n, locale_t loc) +{ + return strncasecmp(l, r, n); +} diff --git a/system/lib/libc/musl/src/math/__cosdf.c b/system/lib/libc/musl/src/math/__cosdf.c new file mode 100644 index 00000000..2124989b --- /dev/null +++ b/system/lib/libc/musl/src/math/__cosdf.c @@ -0,0 +1,35 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |cos(x) - c(x)| < 2**-34.1 (~[-5.37e-11, 5.295e-11]). */ +static const double +C0 = -0x1ffffffd0c5e81.0p-54, /* -0.499999997251031003120 */ +C1 = 0x155553e1053a42.0p-57, /* 0.0416666233237390631894 */ +C2 = -0x16c087e80f1e27.0p-62, /* -0.00138867637746099294692 */ +C3 = 0x199342e0ee5069.0p-68; /* 0.0000243904487962774090654 */ + +float __cosdf(double x) +{ + double_t r, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = C2+z*C3; + return ((1.0+z*C0) + w*C1) + (w*z)*r; +} diff --git a/system/lib/libc/musl/src/math/__sindf.c b/system/lib/libc/musl/src/math/__sindf.c new file mode 100644 index 00000000..8fec2a3f --- /dev/null +++ b/system/lib/libc/musl/src/math/__sindf.c @@ -0,0 +1,36 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +/* |sin(x)/x - s(x)| < 2**-37.5 (~[-4.89e-12, 4.824e-12]). */ +static const double +S1 = -0x15555554cbac77.0p-55, /* -0.166666666416265235595 */ +S2 = 0x111110896efbb2.0p-59, /* 0.0083333293858894631756 */ +S3 = -0x1a00f9e2cae774.0p-65, /* -0.000198393348360966317347 */ +S4 = 0x16cd878c3b46a7.0p-71; /* 0.0000027183114939898219064 */ + +float __sindf(double x) +{ + double_t r, s, w, z; + + /* Try to optimize for parallel evaluation as in __tandf.c. */ + z = x*x; + w = z*z; + r = S3 + z*S4; + s = z*x; + return (x + s*(S1 + z*S2)) + s*w*r; +} diff --git a/system/lib/libc/musl/src/math/ilogb.c b/system/lib/libc/musl/src/math/ilogb.c new file mode 100644 index 00000000..64d40154 --- /dev/null +++ b/system/lib/libc/musl/src/math/ilogb.c @@ -0,0 +1,26 @@ +#include <limits.h> +#include "libm.h" + +int ilogb(double x) +{ + #pragma STDC FENV_ACCESS ON + union {double f; uint64_t i;} u = {x}; + uint64_t i = u.i; + int e = i>>52 & 0x7ff; + + if (!e) { + i <<= 12; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3ff; i>>63 == 0; e--, i<<=1); + return e; + } + if (e == 0x7ff) { + FORCE_EVAL(0/0.0f); + return i<<12 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3ff; +} diff --git a/system/lib/libc/musl/src/math/ilogbf.c b/system/lib/libc/musl/src/math/ilogbf.c new file mode 100644 index 00000000..e23ba209 --- /dev/null +++ b/system/lib/libc/musl/src/math/ilogbf.c @@ -0,0 +1,26 @@ +#include <limits.h> +#include "libm.h" + +int ilogbf(float x) +{ + #pragma STDC FENV_ACCESS ON + union {float f; uint32_t i;} u = {x}; + uint32_t i = u.i; + int e = i>>23 & 0xff; + + if (!e) { + i <<= 9; + if (i == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x7f; i>>31 == 0; e--, i<<=1); + return e; + } + if (e == 0xff) { + FORCE_EVAL(0/0.0f); + return i<<9 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x7f; +} diff --git a/system/lib/libc/musl/src/math/ilogbl.c b/system/lib/libc/musl/src/math/ilogbl.c new file mode 100644 index 00000000..7b1a9cf8 --- /dev/null +++ b/system/lib/libc/musl/src/math/ilogbl.c @@ -0,0 +1,55 @@ +#include <limits.h> +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +int ilogbl(long double x) +{ + return ilogb(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + uint64_t m = u.i.m; + int e = u.i.se & 0x7fff; + + if (!e) { + if (m == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + for (e = -0x3fff+1; m>>63 == 0; e--, m<<=1); + return e; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + return m<<1 ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int ilogbl(long double x) +{ + #pragma STDC FENV_ACCESS ON + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (!e) { + if (x == 0) { + FORCE_EVAL(0/0.0f); + return FP_ILOGB0; + } + /* subnormal x */ + x *= 0x1p120; + return ilogbl(x) - 120; + } + if (e == 0x7fff) { + FORCE_EVAL(0/0.0f); + u.i.se = 0; + return u.f ? FP_ILOGBNAN : INT_MAX; + } + return e - 0x3fff; +} +#endif diff --git a/system/lib/libc/musl/src/math/ldexp.c b/system/lib/libc/musl/src/math/ldexp.c new file mode 100644 index 00000000..f4d1cd6a --- /dev/null +++ b/system/lib/libc/musl/src/math/ldexp.c @@ -0,0 +1,6 @@ +#include <math.h> + +double ldexp(double x, int n) +{ + return scalbn(x, n); +} diff --git a/system/lib/libc/musl/src/math/ldexpf.c b/system/lib/libc/musl/src/math/ldexpf.c new file mode 100644 index 00000000..3bad5f39 --- /dev/null +++ b/system/lib/libc/musl/src/math/ldexpf.c @@ -0,0 +1,6 @@ +#include <math.h> + +float ldexpf(float x, int n) +{ + return scalbnf(x, n); +} diff --git a/system/lib/libc/musl/src/math/ldexpl.c b/system/lib/libc/musl/src/math/ldexpl.c new file mode 100644 index 00000000..fd145ccc --- /dev/null +++ b/system/lib/libc/musl/src/math/ldexpl.c @@ -0,0 +1,6 @@ +#include <math.h> + +long double ldexpl(long double x, int n) +{ + return scalbnl(x, n); +} diff --git a/system/lib/libc/musl/src/math/lgamma.c b/system/lib/libc/musl/src/math/lgamma.c new file mode 100644 index 00000000..36006682 --- /dev/null +++ b/system/lib/libc/musl/src/math/lgamma.c @@ -0,0 +1,9 @@ +#include <math.h> + +extern int signgam; +double __lgamma_r(double, int *); + +double lgamma(double x) +{ + return __lgamma_r(x, &signgam); +} diff --git a/system/lib/libc/musl/src/math/lgamma_r.c b/system/lib/libc/musl/src/math/lgamma_r.c new file mode 100644 index 00000000..82e296f5 --- /dev/null +++ b/system/lib/libc/musl/src/math/lgamma_r.c @@ -0,0 +1,314 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgamma_r.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + */ +/* lgamma_r(x, signgamp) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * where + * poly(z) is a 14 degree polynomial. + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * with accuracy + * |P/Q - (lgamma(x)-0.5s)| < 2**-61.71 + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * where + * |w - f(z)| < 2**-58.74 + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1) = lgamma(2) = 0 + * lgamma(x) ~ -log(|x|) for tiny x + * lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero + * lgamma(inf) = inf + * lgamma(-inf) = inf (bug for bug compatible with C99!?) + * + */ + +#include "libm.h" +#include "libc.h" + +static const double +two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */ +pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */ +a0 = 7.72156649015328655494e-02, /* 0x3FB3C467, 0xE37DB0C8 */ +a1 = 3.22467033424113591611e-01, /* 0x3FD4A34C, 0xC4A60FAD */ +a2 = 6.73523010531292681824e-02, /* 0x3FB13E00, 0x1A5562A7 */ +a3 = 2.05808084325167332806e-02, /* 0x3F951322, 0xAC92547B */ +a4 = 7.38555086081402883957e-03, /* 0x3F7E404F, 0xB68FEFE8 */ +a5 = 2.89051383673415629091e-03, /* 0x3F67ADD8, 0xCCB7926B */ +a6 = 1.19270763183362067845e-03, /* 0x3F538A94, 0x116F3F5D */ +a7 = 5.10069792153511336608e-04, /* 0x3F40B6C6, 0x89B99C00 */ +a8 = 2.20862790713908385557e-04, /* 0x3F2CF2EC, 0xED10E54D */ +a9 = 1.08011567247583939954e-04, /* 0x3F1C5088, 0x987DFB07 */ +a10 = 2.52144565451257326939e-05, /* 0x3EFA7074, 0x428CFA52 */ +a11 = 4.48640949618915160150e-05, /* 0x3F07858E, 0x90A45837 */ +tc = 1.46163214496836224576e+00, /* 0x3FF762D8, 0x6356BE3F */ +tf = -1.21486290535849611461e-01, /* 0xBFBF19B9, 0xBCC38A42 */ +/* tt = -(tail of tf) */ +tt = -3.63867699703950536541e-18, /* 0xBC50C7CA, 0xA48A971F */ +t0 = 4.83836122723810047042e-01, /* 0x3FDEF72B, 0xC8EE38A2 */ +t1 = -1.47587722994593911752e-01, /* 0xBFC2E427, 0x8DC6C509 */ +t2 = 6.46249402391333854778e-02, /* 0x3FB08B42, 0x94D5419B */ +t3 = -3.27885410759859649565e-02, /* 0xBFA0C9A8, 0xDF35B713 */ +t4 = 1.79706750811820387126e-02, /* 0x3F9266E7, 0x970AF9EC */ +t5 = -1.03142241298341437450e-02, /* 0xBF851F9F, 0xBA91EC6A */ +t6 = 6.10053870246291332635e-03, /* 0x3F78FCE0, 0xE370E344 */ +t7 = -3.68452016781138256760e-03, /* 0xBF6E2EFF, 0xB3E914D7 */ +t8 = 2.25964780900612472250e-03, /* 0x3F6282D3, 0x2E15C915 */ +t9 = -1.40346469989232843813e-03, /* 0xBF56FE8E, 0xBF2D1AF1 */ +t10 = 8.81081882437654011382e-04, /* 0x3F4CDF0C, 0xEF61A8E9 */ +t11 = -5.38595305356740546715e-04, /* 0xBF41A610, 0x9C73E0EC */ +t12 = 3.15632070903625950361e-04, /* 0x3F34AF6D, 0x6C0EBBF7 */ +t13 = -3.12754168375120860518e-04, /* 0xBF347F24, 0xECC38C38 */ +t14 = 3.35529192635519073543e-04, /* 0x3F35FD3E, 0xE8C2D3F4 */ +u0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +u1 = 6.32827064025093366517e-01, /* 0x3FE4401E, 0x8B005DFF */ +u2 = 1.45492250137234768737e+00, /* 0x3FF7475C, 0xD119BD6F */ +u3 = 9.77717527963372745603e-01, /* 0x3FEF4976, 0x44EA8450 */ +u4 = 2.28963728064692451092e-01, /* 0x3FCD4EAE, 0xF6010924 */ +u5 = 1.33810918536787660377e-02, /* 0x3F8B678B, 0xBF2BAB09 */ +v1 = 2.45597793713041134822e+00, /* 0x4003A5D7, 0xC2BD619C */ +v2 = 2.12848976379893395361e+00, /* 0x40010725, 0xA42B18F5 */ +v3 = 7.69285150456672783825e-01, /* 0x3FE89DFB, 0xE45050AF */ +v4 = 1.04222645593369134254e-01, /* 0x3FBAAE55, 0xD6537C88 */ +v5 = 3.21709242282423911810e-03, /* 0x3F6A5ABB, 0x57D0CF61 */ +s0 = -7.72156649015328655494e-02, /* 0xBFB3C467, 0xE37DB0C8 */ +s1 = 2.14982415960608852501e-01, /* 0x3FCB848B, 0x36E20878 */ +s2 = 3.25778796408930981787e-01, /* 0x3FD4D98F, 0x4F139F59 */ +s3 = 1.46350472652464452805e-01, /* 0x3FC2BB9C, 0xBEE5F2F7 */ +s4 = 2.66422703033638609560e-02, /* 0x3F9B481C, 0x7E939961 */ +s5 = 1.84028451407337715652e-03, /* 0x3F5E26B6, 0x7368F239 */ +s6 = 3.19475326584100867617e-05, /* 0x3F00BFEC, 0xDD17E945 */ +r1 = 1.39200533467621045958e+00, /* 0x3FF645A7, 0x62C4AB74 */ +r2 = 7.21935547567138069525e-01, /* 0x3FE71A18, 0x93D3DCDC */ +r3 = 1.71933865632803078993e-01, /* 0x3FC601ED, 0xCCFBDF27 */ +r4 = 1.86459191715652901344e-02, /* 0x3F9317EA, 0x742ED475 */ +r5 = 7.77942496381893596434e-04, /* 0x3F497DDA, 0xCA41A95B */ +r6 = 7.32668430744625636189e-06, /* 0x3EDEBAF7, 0xA5B38140 */ +w0 = 4.18938533204672725052e-01, /* 0x3FDACFE3, 0x90C97D69 */ +w1 = 8.33333333333329678849e-02, /* 0x3FB55555, 0x5555553B */ +w2 = -2.77777777728775536470e-03, /* 0xBF66C16C, 0x16B02E5C */ +w3 = 7.93650558643019558500e-04, /* 0x3F4A019F, 0x98CF38B6 */ +w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */ +w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */ +w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */ + +static double sin_pi(double x) +{ + double y,z; + int n,ix; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + if (ix < 0x3fd00000) + return __sin(pi*x, 0.0, 0); + + y = -x; /* negative x is assumed */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floor(y); + if (z != y) { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */ + n = (int)(y*4.0); + } else { + if (ix >= 0x43400000) { + y = 0.0; /* y must be even */ + n = 0; + } else { + if (ix < 0x43300000) + z = y + two52; /* exact */ + GET_LOW_WORD(n, z); + n &= 1; + y = n; + n <<= 2; + } + } + switch (n) { + case 0: y = __sin(pi*y, 0.0, 0); break; + case 1: + case 2: y = __cos(pi*(0.5-y), 0.0); break; + case 3: + case 4: y = __sin(pi*(1.0-y), 0.0, 0); break; + case 5: + case 6: y = -__cos(pi*(y-1.5), 0.0); break; + default: y = __sin(pi*(y-2.0), 0.0, 0); break; + } + return -y; +} + + +double __lgamma_r(double x, int *signgamp) +{ + double t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,lx,ix; + + EXTRACT_WORDS(hx, lx, x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx & 0x7fffffff; + if (ix >= 0x7ff00000) + return x*x; + if ((ix|lx) == 0) + return 1.0/0.0; + if (ix < 0x3b900000) { /* |x|<2**-70, return -log(|x|) */ + if(hx < 0) { + *signgamp = -1; + return -log(-x); + } + return -log(x); + } + if (hx < 0) { + if (ix >= 0x43300000) /* |x|>=2**52, must be -integer */ + return 1.0/0.0; + t = sin_pi(x); + if (t == 0.0) /* -integer */ + return 1.0/0.0; + nadj = log(pi/fabs(t*x)); + if (t < 0.0) + *signgamp = -1; + x = -x; + } + + /* purge off 1 and 2 */ + if (((ix - 0x3ff00000)|lx) == 0 || ((ix - 0x40000000)|lx) == 0) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3feccccc) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -log(x); + if (ix >= 0x3FE76944) { + y = 1.0 - x; + i = 0; + } else if (ix >= 0x3FCDA661) { + y = x - (tc-1.0); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3FFBB4C3) { /* [1.7316,2] */ + y = 2.0 - x; + i = 0; + } else if(ix >= 0x3FF3B4C4) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += (p-0.5*y); + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += tf + p; + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5*y + p1/p2; + } + } else if (ix < 0x40200000) { /* x < 8.0 */ + i = (int)x; + y = x - (double)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5*y+p/q; + z = 1.0; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0; /* FALLTHRU */ + case 6: z *= y + 5.0; /* FALLTHRU */ + case 5: z *= y + 4.0; /* FALLTHRU */ + case 4: z *= y + 3.0; /* FALLTHRU */ + case 3: z *= y + 2.0; /* FALLTHRU */ + r += log(z); + break; + } + } else if (ix < 0x43900000) { /* 8.0 <= x < 2**58 */ + t = log(x); + z = 1.0/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5)*(t-1.0)+w; + } else /* 2**58 <= x <= inf */ + r = x*(log(x)-1.0); + if (hx < 0) + r = nadj - r; + return r; +} + +weak_alias(__lgamma_r, lgamma_r); diff --git a/system/lib/libc/musl/src/math/lgammaf.c b/system/lib/libc/musl/src/math/lgammaf.c new file mode 100644 index 00000000..628e6ade --- /dev/null +++ b/system/lib/libc/musl/src/math/lgammaf.c @@ -0,0 +1,9 @@ +#include <math.h> + +extern int signgam; +float __lgammaf_r(float, int *); + +float lgammaf(float x) +{ + return __lgammaf_r(x, &signgam); +} diff --git a/system/lib/libc/musl/src/math/lgammaf_r.c b/system/lib/libc/musl/src/math/lgammaf_r.c new file mode 100644 index 00000000..dc65bace --- /dev/null +++ b/system/lib/libc/musl/src/math/lgammaf_r.c @@ -0,0 +1,249 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_lgammaf_r.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" +#include "libc.h" + +static const float +two23= 8.3886080000e+06, /* 0x4b000000 */ +pi = 3.1415927410e+00, /* 0x40490fdb */ +a0 = 7.7215664089e-02, /* 0x3d9e233f */ +a1 = 3.2246702909e-01, /* 0x3ea51a66 */ +a2 = 6.7352302372e-02, /* 0x3d89f001 */ +a3 = 2.0580807701e-02, /* 0x3ca89915 */ +a4 = 7.3855509982e-03, /* 0x3bf2027e */ +a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */ +a6 = 1.1927076848e-03, /* 0x3a9c54a1 */ +a7 = 5.1006977446e-04, /* 0x3a05b634 */ +a8 = 2.2086278477e-04, /* 0x39679767 */ +a9 = 1.0801156895e-04, /* 0x38e28445 */ +a10 = 2.5214456400e-05, /* 0x37d383a2 */ +a11 = 4.4864096708e-05, /* 0x383c2c75 */ +tc = 1.4616321325e+00, /* 0x3fbb16c3 */ +tf = -1.2148628384e-01, /* 0xbdf8cdcd */ +/* tt = -(tail of tf) */ +tt = 6.6971006518e-09, /* 0x31e61c52 */ +t0 = 4.8383611441e-01, /* 0x3ef7b95e */ +t1 = -1.4758771658e-01, /* 0xbe17213c */ +t2 = 6.4624942839e-02, /* 0x3d845a15 */ +t3 = -3.2788541168e-02, /* 0xbd064d47 */ +t4 = 1.7970675603e-02, /* 0x3c93373d */ +t5 = -1.0314224288e-02, /* 0xbc28fcfe */ +t6 = 6.1005386524e-03, /* 0x3bc7e707 */ +t7 = -3.6845202558e-03, /* 0xbb7177fe */ +t8 = 2.2596477065e-03, /* 0x3b141699 */ +t9 = -1.4034647029e-03, /* 0xbab7f476 */ +t10 = 8.8108185446e-04, /* 0x3a66f867 */ +t11 = -5.3859531181e-04, /* 0xba0d3085 */ +t12 = 3.1563205994e-04, /* 0x39a57b6b */ +t13 = -3.1275415677e-04, /* 0xb9a3f927 */ +t14 = 3.3552918467e-04, /* 0x39afe9f7 */ +u0 = -7.7215664089e-02, /* 0xbd9e233f */ +u1 = 6.3282704353e-01, /* 0x3f2200f4 */ +u2 = 1.4549225569e+00, /* 0x3fba3ae7 */ +u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */ +u4 = 2.2896373272e-01, /* 0x3e6a7578 */ +u5 = 1.3381091878e-02, /* 0x3c5b3c5e */ +v1 = 2.4559779167e+00, /* 0x401d2ebe */ +v2 = 2.1284897327e+00, /* 0x4008392d */ +v3 = 7.6928514242e-01, /* 0x3f44efdf */ +v4 = 1.0422264785e-01, /* 0x3dd572af */ +v5 = 3.2170924824e-03, /* 0x3b52d5db */ +s0 = -7.7215664089e-02, /* 0xbd9e233f */ +s1 = 2.1498242021e-01, /* 0x3e5c245a */ +s2 = 3.2577878237e-01, /* 0x3ea6cc7a */ +s3 = 1.4635047317e-01, /* 0x3e15dce6 */ +s4 = 2.6642270386e-02, /* 0x3cda40e4 */ +s5 = 1.8402845599e-03, /* 0x3af135b4 */ +s6 = 3.1947532989e-05, /* 0x3805ff67 */ +r1 = 1.3920053244e+00, /* 0x3fb22d3b */ +r2 = 7.2193557024e-01, /* 0x3f38d0c5 */ +r3 = 1.7193385959e-01, /* 0x3e300f6e */ +r4 = 1.8645919859e-02, /* 0x3c98bf54 */ +r5 = 7.7794247773e-04, /* 0x3a4beed6 */ +r6 = 7.3266842264e-06, /* 0x36f5d7bd */ +w0 = 4.1893854737e-01, /* 0x3ed67f1d */ +w1 = 8.3333335817e-02, /* 0x3daaaaab */ +w2 = -2.7777778450e-03, /* 0xbb360b61 */ +w3 = 7.9365057172e-04, /* 0x3a500cfd */ +w4 = -5.9518753551e-04, /* 0xba1c065c */ +w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */ +w6 = -1.6309292987e-03; /* 0xbad5c4e8 */ + +static float sin_pif(float x) +{ + float y,z; + int n,ix; + + GET_FLOAT_WORD(ix, x); + ix &= 0x7fffffff; + + if(ix < 0x3e800000) + return __sindf(pi*x); + + y = -x; /* negative x is assumed */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorf(y); + if (z != y) { /* inexact anyway */ + y *= 0.5f; + y = 2.0f*(y - floorf(y)); /* y = |x| mod 2.0 */ + n = (int)(y*4.0f); + } else { + if (ix >= 0x4b800000) { + y = 0.0f; /* y must be even */ + n = 0; + } else { + if (ix < 0x4b000000) + z = y + two23; /* exact */ + GET_FLOAT_WORD(n, z); + n &= 1; + y = n; + n <<= 2; + } + } + switch (n) { + case 0: y = __sindf(pi*y); break; + case 1: + case 2: y = __cosdf(pi*(0.5f - y)); break; + case 3: + case 4: y = __sindf(pi*(1.0f - y)); break; + case 5: + case 6: y = -__cosdf(pi*(y - 1.5f)); break; + default: y = __sindf(pi*(y - 2.0f)); break; + } + return -y; +} + + +float __lgammaf_r(float x, int *signgamp) +{ + float t,y,z,nadj,p,p1,p2,p3,q,r,w; + int32_t hx; + int i,ix; + + GET_FLOAT_WORD(hx, x); + + /* purge off +-inf, NaN, +-0, tiny and negative arguments */ + *signgamp = 1; + ix = hx & 0x7fffffff; + if (ix >= 0x7f800000) + return x*x; + if (ix == 0) + return 1.0f/0.0f; + if (ix < 0x35000000) { /* |x| < 2**-21, return -log(|x|) */ + if (hx < 0) { + *signgamp = -1; + return -logf(-x); + } + return -logf(x); + } + if (hx < 0) { + if (ix >= 0x4b000000) /* |x| >= 2**23, must be -integer */ + return 1.0f/0.0f; + t = sin_pif(x); + if (t == 0.0f) /* -integer */ + return 1.0f/0.0f; + nadj = logf(pi/fabsf(t*x)); + if (t < 0.0f) + *signgamp = -1; + x = -x; + } + + /* purge off 1 and 2 */ + if (ix == 0x3f800000 || ix == 0x40000000) + r = 0; + /* for x < 2.0 */ + else if (ix < 0x40000000) { + if (ix <= 0x3f666666) { /* lgamma(x) = lgamma(x+1)-log(x) */ + r = -logf(x); + if (ix >= 0x3f3b4a20) { + y = 1.0f - x; + i = 0; + } else if (ix >= 0x3e6d3308) { + y = x - (tc-1.0f); + i = 1; + } else { + y = x; + i = 2; + } + } else { + r = 0.0f; + if (ix >= 0x3fdda618) { /* [1.7316,2] */ + y = 2.0f - x; + i = 0; + } else if (ix >= 0x3F9da620) { /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + y = x - 1.0f; + i = 2; + } + } + switch(i) { + case 0: + z = y*y; + p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10)))); + p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11))))); + p = y*p1+p2; + r += p - 0.5f*y; + break; + case 1: + z = y*y; + w = z*y; + p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */ + p2 = t1+w*(t4+w*(t7+w*(t10+w*t13))); + p3 = t2+w*(t5+w*(t8+w*(t11+w*t14))); + p = z*p1-(tt-w*(p2+y*p3)); + r += (tf + p); + break; + case 2: + p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5))))); + p2 = 1.0f+y*(v1+y*(v2+y*(v3+y*(v4+y*v5)))); + r += -0.5f*y + p1/p2; + } + } else if (ix < 0x41000000) { /* x < 8.0 */ + i = (int)x; + y = x - (float)i; + p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6)))))); + q = 1.0f+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6))))); + r = 0.5f*y+p/q; + z = 1.0f; /* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: z *= y + 6.0f; /* FALLTHRU */ + case 6: z *= y + 5.0f; /* FALLTHRU */ + case 5: z *= y + 4.0f; /* FALLTHRU */ + case 4: z *= y + 3.0f; /* FALLTHRU */ + case 3: z *= y + 2.0f; /* FALLTHRU */ + r += logf(z); + break; + } + } else if (ix < 0x5c800000) { /* 8.0 <= x < 2**58 */ + t = logf(x); + z = 1.0f/x; + y = z*z; + w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6))))); + r = (x-0.5f)*(t-1.0f)+w; + } else /* 2**58 <= x <= inf */ + r = x*(logf(x)-1.0f); + if (hx < 0) + r = nadj - r; + return r; +} + +weak_alias(__lgammaf_r, lgammaf_r); diff --git a/system/lib/libc/musl/src/math/lgammal.c b/system/lib/libc/musl/src/math/lgammal.c new file mode 100644 index 00000000..9686d9ee --- /dev/null +++ b/system/lib/libc/musl/src/math/lgammal.c @@ -0,0 +1,386 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_lgammal.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* lgammal(x) + * Reentrant version of the logarithm of the Gamma function + * with user provide pointer for the sign of Gamma(x). + * + * Method: + * 1. Argument Reduction for 0 < x <= 8 + * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may + * reduce x to a number in [1.5,2.5] by + * lgamma(1+s) = log(s) + lgamma(s) + * for example, + * lgamma(7.3) = log(6.3) + lgamma(6.3) + * = log(6.3*5.3) + lgamma(5.3) + * = log(6.3*5.3*4.3*3.3*2.3) + lgamma(2.3) + * 2. Polynomial approximation of lgamma around its + * minimun ymin=1.461632144968362245 to maintain monotonicity. + * On [ymin-0.23, ymin+0.27] (i.e., [1.23164,1.73163]), use + * Let z = x-ymin; + * lgamma(x) = -1.214862905358496078218 + z^2*poly(z) + * 2. Rational approximation in the primary interval [2,3] + * We use the following approximation: + * s = x-2.0; + * lgamma(x) = 0.5*s + s*P(s)/Q(s) + * Our algorithms are based on the following observation + * + * zeta(2)-1 2 zeta(3)-1 3 + * lgamma(2+s) = s*(1-Euler) + --------- * s - --------- * s + ... + * 2 3 + * + * where Euler = 0.5771... is the Euler constant, which is very + * close to 0.5. + * + * 3. For x>=8, we have + * lgamma(x)~(x-0.5)log(x)-x+0.5*log(2pi)+1/(12x)-1/(360x**3)+.... + * (better formula: + * lgamma(x)~(x-0.5)*(log(x)-1)-.5*(log(2pi)-1) + ...) + * Let z = 1/x, then we approximation + * f(z) = lgamma(x) - (x-0.5)(log(x)-1) + * by + * 3 5 11 + * w = w0 + w1*z + w2*z + w3*z + ... + w6*z + * + * 4. For negative x, since (G is gamma function) + * -x*G(-x)*G(x) = pi/sin(pi*x), + * we have + * G(x) = pi/(sin(pi*x)*(-x)*G(-x)) + * since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0 + * Hence, for x<0, signgam = sign(sin(pi*x)) and + * lgamma(x) = log(|Gamma(x)|) + * = log(pi/(|x*sin(pi*x)|)) - lgamma(-x); + * Note: one should avoid compute pi*(-x) directly in the + * computation of sin(pi*(-x)). + * + * 5. Special Cases + * lgamma(2+s) ~ s*(1-Euler) for tiny s + * lgamma(1)=lgamma(2)=0 + * lgamma(x) ~ -log(x) for tiny x + * lgamma(0) = lgamma(inf) = inf + * lgamma(-integer) = +-inf + * + */ + +#define _GNU_SOURCE +#include "libm.h" +#include "libc.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +double __lgamma_r(double x, int *sg); + +long double __lgammal_r(long double x, int *sg) +{ + return __lgamma_r(x, sg); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +static const long double +pi = 3.14159265358979323846264L, +two63 = 9.223372036854775808e18L, + +/* lgam(1+x) = 0.5 x + x a(x)/b(x) + -0.268402099609375 <= x <= 0 + peak relative error 6.6e-22 */ +a0 = -6.343246574721079391729402781192128239938E2L, +a1 = 1.856560238672465796768677717168371401378E3L, +a2 = 2.404733102163746263689288466865843408429E3L, +a3 = 8.804188795790383497379532868917517596322E2L, +a4 = 1.135361354097447729740103745999661157426E2L, +a5 = 3.766956539107615557608581581190400021285E0L, + +b0 = 8.214973713960928795704317259806842490498E3L, +b1 = 1.026343508841367384879065363925870888012E4L, +b2 = 4.553337477045763320522762343132210919277E3L, +b3 = 8.506975785032585797446253359230031874803E2L, +b4 = 6.042447899703295436820744186992189445813E1L, +/* b5 = 1.000000000000000000000000000000000000000E0 */ + + +tc = 1.4616321449683623412626595423257213284682E0L, +tf = -1.2148629053584961146050602565082954242826E-1, /* double precision */ +/* tt = (tail of tf), i.e. tf + tt has extended precision. */ +tt = 3.3649914684731379602768989080467587736363E-18L, +/* lgam ( 1.4616321449683623412626595423257213284682E0 ) = +-1.2148629053584960809551455717769158215135617312999903886372437313313530E-1 */ + +/* lgam (x + tc) = tf + tt + x g(x)/h(x) + -0.230003726999612341262659542325721328468 <= x + <= 0.2699962730003876587373404576742786715318 + peak relative error 2.1e-21 */ +g0 = 3.645529916721223331888305293534095553827E-18L, +g1 = 5.126654642791082497002594216163574795690E3L, +g2 = 8.828603575854624811911631336122070070327E3L, +g3 = 5.464186426932117031234820886525701595203E3L, +g4 = 1.455427403530884193180776558102868592293E3L, +g5 = 1.541735456969245924860307497029155838446E2L, +g6 = 4.335498275274822298341872707453445815118E0L, + +h0 = 1.059584930106085509696730443974495979641E4L, +h1 = 2.147921653490043010629481226937850618860E4L, +h2 = 1.643014770044524804175197151958100656728E4L, +h3 = 5.869021995186925517228323497501767586078E3L, +h4 = 9.764244777714344488787381271643502742293E2L, +h5 = 6.442485441570592541741092969581997002349E1L, +/* h6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+1) = -0.5 x + x u(x)/v(x) + -0.100006103515625 <= x <= 0.231639862060546875 + peak relative error 1.3e-21 */ +u0 = -8.886217500092090678492242071879342025627E1L, +u1 = 6.840109978129177639438792958320783599310E2L, +u2 = 2.042626104514127267855588786511809932433E3L, +u3 = 1.911723903442667422201651063009856064275E3L, +u4 = 7.447065275665887457628865263491667767695E2L, +u5 = 1.132256494121790736268471016493103952637E2L, +u6 = 4.484398885516614191003094714505960972894E0L, + +v0 = 1.150830924194461522996462401210374632929E3L, +v1 = 3.399692260848747447377972081399737098610E3L, +v2 = 3.786631705644460255229513563657226008015E3L, +v3 = 1.966450123004478374557778781564114347876E3L, +v4 = 4.741359068914069299837355438370682773122E2L, +v5 = 4.508989649747184050907206782117647852364E1L, +/* v6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam (x+2) = .5 x + x s(x)/r(x) + 0 <= x <= 1 + peak relative error 7.2e-22 */ +s0 = 1.454726263410661942989109455292824853344E6L, +s1 = -3.901428390086348447890408306153378922752E6L, +s2 = -6.573568698209374121847873064292963089438E6L, +s3 = -3.319055881485044417245964508099095984643E6L, +s4 = -7.094891568758439227560184618114707107977E5L, +s5 = -6.263426646464505837422314539808112478303E4L, +s6 = -1.684926520999477529949915657519454051529E3L, + +r0 = -1.883978160734303518163008696712983134698E7L, +r1 = -2.815206082812062064902202753264922306830E7L, +r2 = -1.600245495251915899081846093343626358398E7L, +r3 = -4.310526301881305003489257052083370058799E6L, +r4 = -5.563807682263923279438235987186184968542E5L, +r5 = -3.027734654434169996032905158145259713083E4L, +r6 = -4.501995652861105629217250715790764371267E2L, +/* r6 = 1.000000000000000000000000000000000000000E0 */ + + +/* lgam(x) = ( x - 0.5 ) * log(x) - x + LS2PI + 1/x w(1/x^2) + x >= 8 + Peak relative error 1.51e-21 +w0 = LS2PI - 0.5 */ +w0 = 4.189385332046727417803e-1L, +w1 = 8.333333333333331447505E-2L, +w2 = -2.777777777750349603440E-3L, +w3 = 7.936507795855070755671E-4L, +w4 = -5.952345851765688514613E-4L, +w5 = 8.412723297322498080632E-4L, +w6 = -1.880801938119376907179E-3L, +w7 = 4.885026142432270781165E-3L; + +static long double sin_pi(long double x) +{ + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + long double y, z; + int n; + + if (ix < 0x3ffd8000) /* 0.25 */ + return sinl(pi * x); + y = -x; /* x is assume negative */ + + /* + * argument reduction, make sure inexact flag not raised if input + * is an integer + */ + z = floorl(y); + if (z != y) { /* inexact anyway */ + y *= 0.5; + y = 2.0*(y - floorl(y));/* y = |x| mod 2.0 */ + n = (int) (y*4.0); + } else { + if (ix >= 0x403f8000) { /* 2^64 */ + y = 0.0; /* y must be even */ + n = 0; + } else { + if (ix < 0x403e8000) /* 2^63 */ + z = y + two63; /* exact */ + u.f = z; + n = u.i.m & 1; + y = n; + n <<= 2; + } + } + + switch (n) { + case 0: + y = sinl(pi * y); + break; + case 1: + case 2: + y = cosl(pi * (0.5 - y)); + break; + case 3: + case 4: + y = sinl(pi * (1.0 - y)); + break; + case 5: + case 6: + y = -cosl(pi * (y - 1.5)); + break; + default: + y = sinl(pi * (y - 2.0)); + break; + } + return -y; +} + +long double __lgammal_r(long double x, int *sg) { + long double t, y, z, nadj, p, p1, p2, q, r, w; + union ldshape u = {x}; + uint32_t ix = (u.i.se & 0x7fffU)<<16 | u.i.m>>48; + int sign = u.i.se >> 15; + int i; + + *sg = 1; + + /* purge off +-inf, NaN, +-0, and negative arguments */ + if (ix >= 0x7fff0000) + return x * x; + if (x == 0) { + *sg -= 2*sign; + return 1.0 / fabsl(x); + } + if (ix < 0x3fc08000) { /* |x|<2**-63, return -log(|x|) */ + if (sign) { + *sg = -1; + return -logl(-x); + } + return -logl(x); + } + if (sign) { + t = sin_pi (x); + if (t == 0.0) + return 1.0 / fabsl(t); /* -integer */ + nadj = logl(pi / fabsl(t * x)); + if (t < 0.0) + *sg = -1; + x = -x; + } + + if (ix < 0x40008000) { /* x < 2.0 */ + if (ix <= 0x3ffee666) { /* 8.99993896484375e-1 */ + /* lgamma(x) = lgamma(x+1) - log(x) */ + r = -logl(x); + if (ix >= 0x3ffebb4a) { /* 7.31597900390625e-1 */ + y = x - 1.0; + i = 0; + } else if (ix >= 0x3ffced33) { /* 2.31639862060546875e-1 */ + y = x - (tc - 1.0); + i = 1; + } else { /* x < 0.23 */ + y = x; + i = 2; + } + } else { + r = 0.0; + if (ix >= 0x3fffdda6) { /* 1.73162841796875 */ + /* [1.7316,2] */ + y = x - 2.0; + i = 0; + } else if (ix >= 0x3fff9da6) { /* 1.23162841796875 */ + /* [1.23,1.73] */ + y = x - tc; + i = 1; + } else { + /* [0.9, 1.23] */ + y = x - 1.0; + i = 2; + } + } + switch (i) { + case 0: + p1 = a0 + y * (a1 + y * (a2 + y * (a3 + y * (a4 + y * a5)))); + p2 = b0 + y * (b1 + y * (b2 + y * (b3 + y * (b4 + y)))); + r += 0.5 * y + y * p1/p2; + break; + case 1: + p1 = g0 + y * (g1 + y * (g2 + y * (g3 + y * (g4 + y * (g5 + y * g6))))); + p2 = h0 + y * (h1 + y * (h2 + y * (h3 + y * (h4 + y * (h5 + y))))); + p = tt + y * p1/p2; + r += (tf + p); + break; + case 2: + p1 = y * (u0 + y * (u1 + y * (u2 + y * (u3 + y * (u4 + y * (u5 + y * u6)))))); + p2 = v0 + y * (v1 + y * (v2 + y * (v3 + y * (v4 + y * (v5 + y))))); + r += (-0.5 * y + p1 / p2); + } + } else if (ix < 0x40028000) { /* 8.0 */ + /* x < 8.0 */ + i = (int)x; + t = 0.0; + y = x - (double)i; + p = y * (s0 + y * (s1 + y * (s2 + y * (s3 + y * (s4 + y * (s5 + y * s6)))))); + q = r0 + y * (r1 + y * (r2 + y * (r3 + y * (r4 + y * (r5 + y * (r6 + y)))))); + r = 0.5 * y + p / q; + z = 1.0;/* lgamma(1+s) = log(s) + lgamma(s) */ + switch (i) { + case 7: + z *= (y + 6.0); /* FALLTHRU */ + case 6: + z *= (y + 5.0); /* FALLTHRU */ + case 5: + z *= (y + 4.0); /* FALLTHRU */ + case 4: + z *= (y + 3.0); /* FALLTHRU */ + case 3: + z *= (y + 2.0); /* FALLTHRU */ + r += logl(z); + break; + } + } else if (ix < 0x40418000) { /* 2^66 */ + /* 8.0 <= x < 2**66 */ + t = logl(x); + z = 1.0 / x; + y = z * z; + w = w0 + z * (w1 + y * (w2 + y * (w3 + y * (w4 + y * (w5 + y * (w6 + y * w7)))))); + r = (x - 0.5) * (t - 1.0) + w; + } else /* 2**66 <= x <= inf */ + r = x * (logl(x) - 1.0); + if (sign) + r = nadj - r; + return r; +} +#endif + +extern int signgam; + +long double lgammal(long double x) +{ + return __lgammal_r(x, &signgam); +} + +weak_alias(__lgammal_r, lgammal_r); diff --git a/system/lib/libc/musl/src/math/logb.c b/system/lib/libc/musl/src/math/logb.c new file mode 100644 index 00000000..7f8bdfae --- /dev/null +++ b/system/lib/libc/musl/src/math/logb.c @@ -0,0 +1,17 @@ +#include <math.h> + +/* +special cases: + logb(+-0) = -inf, and raise divbyzero + logb(+-inf) = +inf + logb(nan) = nan +*/ + +double logb(double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogb(x); +} diff --git a/system/lib/libc/musl/src/math/logbf.c b/system/lib/libc/musl/src/math/logbf.c new file mode 100644 index 00000000..a0a0b5ed --- /dev/null +++ b/system/lib/libc/musl/src/math/logbf.c @@ -0,0 +1,10 @@ +#include <math.h> + +float logbf(float x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbf(x); +} diff --git a/system/lib/libc/musl/src/math/logbl.c b/system/lib/libc/musl/src/math/logbl.c new file mode 100644 index 00000000..962973a7 --- /dev/null +++ b/system/lib/libc/musl/src/math/logbl.c @@ -0,0 +1,16 @@ +#include <math.h> +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double logbl(long double x) +{ + return logb(x); +} +#else +long double logbl(long double x) +{ + if (!isfinite(x)) + return x * x; + if (x == 0) + return -1/(x*x); + return ilogbl(x); +} +#endif diff --git a/system/lib/libc/musl/src/math/scalbn.c b/system/lib/libc/musl/src/math/scalbn.c new file mode 100644 index 00000000..530e07c7 --- /dev/null +++ b/system/lib/libc/musl/src/math/scalbn.c @@ -0,0 +1,31 @@ +#include <math.h> +#include <stdint.h> + +double scalbn(double x, int n) +{ + union {double f; uint64_t i;} u; + double_t y = x; + + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) { + y *= 0x1p1023; + n -= 1023; + if (n > 1023) + n = 1023; + } + } else if (n < -1022) { + y *= 0x1p-1022; + n += 1022; + if (n < -1022) { + y *= 0x1p-1022; + n += 1022; + if (n < -1022) + n = -1022; + } + } + u.i = (uint64_t)(0x3ff+n)<<52; + x = y * u.f; + return x; +} diff --git a/system/lib/libc/musl/src/math/scalbnf.c b/system/lib/libc/musl/src/math/scalbnf.c new file mode 100644 index 00000000..0b62c3c7 --- /dev/null +++ b/system/lib/libc/musl/src/math/scalbnf.c @@ -0,0 +1,31 @@ +#include <math.h> +#include <stdint.h> + +float scalbnf(float x, int n) +{ + union {float f; uint32_t i;} u; + float_t y = x; + + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) { + y *= 0x1p127f; + n -= 127; + if (n > 127) + n = 127; + } + } else if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) { + y *= 0x1p-126f; + n += 126; + if (n < -126) + n = -126; + } + } + u.i = (uint32_t)(0x7f+n)<<23; + x = y * u.f; + return x; +} diff --git a/system/lib/libc/musl/src/math/scalbnl.c b/system/lib/libc/musl/src/math/scalbnl.c new file mode 100644 index 00000000..08a4c587 --- /dev/null +++ b/system/lib/libc/musl/src/math/scalbnl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double scalbnl(long double x, int n) +{ + return scalbn(x, n); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double scalbnl(long double x, int n) +{ + union ldshape u; + + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) { + x *= 0x1p16383L; + n -= 16383; + if (n > 16383) + n = 16383; + } + } else if (n < -16382) { + x *= 0x1p-16382L; + n += 16382; + if (n < -16382) { + x *= 0x1p-16382L; + n += 16382; + if (n < -16382) + n = -16382; + } + } + u.f = 1.0; + u.i.se = 0x3fff + n; + return x * u.f; +} +#endif diff --git a/system/lib/libc/musl/src/math/signgam.c b/system/lib/libc/musl/src/math/signgam.c new file mode 100644 index 00000000..ee5d70f1 --- /dev/null +++ b/system/lib/libc/musl/src/math/signgam.c @@ -0,0 +1,4 @@ +#include <math.h> +#include "libc.h" + +int signgam = 0; diff --git a/system/lib/libc/musl/src/math/tgamma.c b/system/lib/libc/musl/src/math/tgamma.c new file mode 100644 index 00000000..f91af735 --- /dev/null +++ b/system/lib/libc/musl/src/math/tgamma.c @@ -0,0 +1,222 @@ +/* +"A Precision Approximation of the Gamma Function" - Cornelius Lanczos (1964) +"Lanczos Implementation of the Gamma Function" - Paul Godfrey (2001) +"An Analysis of the Lanczos Gamma Approximation" - Glendon Ralph Pugh (2004) + +approximation method: + + (x - 0.5) S(x) +Gamma(x) = (x + g - 0.5) * ---------------- + exp(x + g - 0.5) + +with + a1 a2 a3 aN +S(x) ~= [ a0 + ----- + ----- + ----- + ... + ----- ] + x + 1 x + 2 x + 3 x + N + +with a0, a1, a2, a3,.. aN constants which depend on g. + +for x < 0 the following reflection formula is used: + +Gamma(x)*Gamma(-x) = -pi/(x sin(pi x)) + +most ideas and constants are from boost and python +*/ +#include "libm.h" + +static const double pi = 3.141592653589793238462643383279502884; + +/* sin(pi x) with x > 0 && isnormal(x) assumption */ +static double sinpi(double x) +{ + int n; + + /* argument reduction: x = |x| mod 2 */ + /* spurious inexact when x is odd int */ + x = x * 0.5; + x = 2 * (x - floor(x)); + + /* reduce x into [-.25,.25] */ + n = 4 * x; + n = (n+1)/2; + x -= n * 0.5; + + x *= pi; + switch (n) { + default: /* case 4 */ + case 0: + return __sin(x, 0, 0); + case 1: + return __cos(x, 0); + case 2: + /* sin(0-x) and -sin(x) have different sign at 0 */ + return __sin(0-x, 0, 0); + case 3: + return -__cos(x, 0); + } +} + +#define N 12 +//static const double g = 6.024680040776729583740234375; +static const double gmhalf = 5.524680040776729583740234375; +static const double Snum[N+1] = { + 23531376880.410759688572007674451636754734846804940, + 42919803642.649098768957899047001988850926355848959, + 35711959237.355668049440185451547166705960488635843, + 17921034426.037209699919755754458931112671403265390, + 6039542586.3520280050642916443072979210699388420708, + 1439720407.3117216736632230727949123939715485786772, + 248874557.86205415651146038641322942321632125127801, + 31426415.585400194380614231628318205362874684987640, + 2876370.6289353724412254090516208496135991145378768, + 186056.26539522349504029498971604569928220784236328, + 8071.6720023658162106380029022722506138218516325024, + 210.82427775157934587250973392071336271166969580291, + 2.5066282746310002701649081771338373386264310793408, +}; +static const double Sden[N+1] = { + 0, 39916800, 120543840, 150917976, 105258076, 45995730, 13339535, + 2637558, 357423, 32670, 1925, 66, 1, +}; +/* n! for small integer n */ +static const double fact[] = { + 1, 1, 2, 6, 24, 120, 720, 5040.0, 40320.0, 362880.0, 3628800.0, 39916800.0, + 479001600.0, 6227020800.0, 87178291200.0, 1307674368000.0, 20922789888000.0, + 355687428096000.0, 6402373705728000.0, 121645100408832000.0, + 2432902008176640000.0, 51090942171709440000.0, 1124000727777607680000.0, +}; + +/* S(x) rational function for positive x */ +static double S(double x) +{ + double_t num = 0, den = 0; + int i; + + /* to avoid overflow handle large x differently */ + if (x < 8) + for (i = N; i >= 0; i--) { + num = num * x + Snum[i]; + den = den * x + Sden[i]; + } + else + for (i = 0; i <= N; i++) { + num = num / x + Snum[i]; + den = den / x + Sden[i]; + } + return num/den; +} + +double tgamma(double x) +{ + double absx, y, dy, z, r; + + /* special cases */ + if (!isfinite(x)) + /* tgamma(nan)=nan, tgamma(inf)=inf, tgamma(-inf)=nan with invalid */ + return x + INFINITY; + + /* integer arguments */ + /* raise inexact when non-integer */ + if (x == floor(x)) { + if (x == 0) + /* tgamma(+-0)=+-inf with divide-by-zero */ + return 1/x; + if (x < 0) + return 0/0.0; + if (x <= sizeof fact/sizeof *fact) + return fact[(int)x - 1]; + } + + absx = fabs(x); + + /* x ~ 0: tgamma(x) ~ 1/x */ + if (absx < 0x1p-54) + return 1/x; + + /* x >= 172: tgamma(x)=inf with overflow */ + /* x =< -184: tgamma(x)=+-0 with underflow */ + if (absx >= 184) { + if (x < 0) { + FORCE_EVAL((float)(0x1p-126/x)); + if (floor(x) * 0.5 == floor(x * 0.5)) + return 0; + return -0.0; + } + x *= 0x1p1023; + return x; + } + + /* handle the error of x + g - 0.5 */ + y = absx + gmhalf; + if (absx > gmhalf) { + dy = y - absx; + dy -= gmhalf; + } else { + dy = y - gmhalf; + dy -= absx; + } + + z = absx - 0.5; + r = S(absx) * exp(-y); + if (x < 0) { + /* reflection formula for negative x */ + r = -pi / (sinpi(absx) * absx * r); + dy = -dy; + z = -z; + } + r += dy * (gmhalf+0.5) * r / y; + z = pow(y, 0.5*z); + r = r * z * z; + return r; +} + +#if 0 +double __lgamma_r(double x, int *sign) +{ + double r, absx, z, zz, w; + + *sign = 1; + + /* special cases */ + if (!isfinite(x)) + /* lgamma(nan)=nan, lgamma(+-inf)=inf */ + return x*x; + + /* integer arguments */ + if (x == floor(x) && x <= 2) { + /* n <= 0: lgamma(n)=inf with divbyzero */ + /* n == 1,2: lgamma(n)=0 */ + if (x <= 0) + return 1/0.0; + return 0; + } + + absx = fabs(x); + + /* lgamma(x) ~ -log(|x|) for tiny |x| */ + if (absx < 0x1p-54) { + *sign = 1 - 2*!!signbit(x); + return -log(absx); + } + + /* use tgamma for smaller |x| */ + if (absx < 128) { + x = tgamma(x); + *sign = 1 - 2*!!signbit(x); + return log(fabs(x)); + } + + /* second term (log(S)-g) could be more precise here.. */ + /* or with stirling: (|x|-0.5)*(log(|x|)-1) + poly(1/|x|) */ + r = (absx-0.5)*(log(absx+gmhalf)-1) + (log(S(absx)) - (gmhalf+0.5)); + if (x < 0) { + /* reflection formula for negative x */ + x = sinpi(absx); + *sign = 2*!!signbit(x) - 1; + r = log(pi/(fabs(x)*absx)) - r; + } + return r; +} + +weak_alias(__lgamma_r, lgamma_r); +#endif diff --git a/system/lib/libc/musl/src/math/tgammaf.c b/system/lib/libc/musl/src/math/tgammaf.c new file mode 100644 index 00000000..b4ca51c9 --- /dev/null +++ b/system/lib/libc/musl/src/math/tgammaf.c @@ -0,0 +1,6 @@ +#include <math.h> + +float tgammaf(float x) +{ + return tgamma(x); +} diff --git a/system/lib/libc/musl/src/math/tgammal.c b/system/lib/libc/musl/src/math/tgammal.c new file mode 100644 index 00000000..5c1a02a6 --- /dev/null +++ b/system/lib/libc/musl/src/math/tgammal.c @@ -0,0 +1,275 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_tgammal.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Gamma function + * + * + * SYNOPSIS: + * + * long double x, y, tgammal(); + * + * y = tgammal( x ); + * + * + * DESCRIPTION: + * + * Returns gamma function of the argument. The result is + * correctly signed. + * + * Arguments |x| <= 13 are reduced by recurrence and the function + * approximated by a rational function of degree 7/8 in the + * interval (2,3). Large arguments are handled by Stirling's + * formula. Large negative arguments are made positive using + * a reflection formula. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -40,+40 10000 3.6e-19 7.9e-20 + * IEEE -1755,+1755 10000 4.8e-18 6.5e-19 + * + * Accuracy for large arguments is dominated by error in powl(). + * + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tgammal(long double x) +{ + return tgamma(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* +tgamma(x+2) = tgamma(x+2) P(x)/Q(x) +0 <= x <= 1 +Relative error +n=7, d=8 +Peak error = 1.83e-20 +Relative error spread = 8.4e-23 +*/ +static const long double P[8] = { + 4.212760487471622013093E-5L, + 4.542931960608009155600E-4L, + 4.092666828394035500949E-3L, + 2.385363243461108252554E-2L, + 1.113062816019361559013E-1L, + 3.629515436640239168939E-1L, + 8.378004301573126728826E-1L, + 1.000000000000000000009E0L, +}; +static const long double Q[9] = { +-1.397148517476170440917E-5L, + 2.346584059160635244282E-4L, +-1.237799246653152231188E-3L, +-7.955933682494738320586E-4L, + 2.773706565840072979165E-2L, +-4.633887671244534213831E-2L, +-2.243510905670329164562E-1L, + 4.150160950588455434583E-1L, + 9.999999999999999999908E-1L, +}; + +/* +static const long double P[] = { +-3.01525602666895735709e0L, +-3.25157411956062339893e1L, +-2.92929976820724030353e2L, +-1.70730828800510297666e3L, +-7.96667499622741999770e3L, +-2.59780216007146401957e4L, +-5.99650230220855581642e4L, +-7.15743521530849602425e4L +}; +static const long double Q[] = { + 1.00000000000000000000e0L, +-1.67955233807178858919e1L, + 8.85946791747759881659e1L, + 5.69440799097468430177e1L, +-1.98526250512761318471e3L, + 3.31667508019495079814e3L, + 1.60577839621734713377e4L, +-2.97045081369399940529e4L, +-7.15743521530849602412e4L +}; +*/ +#define MAXGAML 1755.455L +/*static const long double LOGPI = 1.14472988584940017414L;*/ + +/* Stirling's formula for the gamma function +tgamma(x) = sqrt(2 pi) x^(x-.5) exp(-x) (1 + 1/x P(1/x)) +z(x) = x +13 <= x <= 1024 +Relative error +n=8, d=0 +Peak error = 9.44e-21 +Relative error spread = 8.8e-4 +*/ +static const long double STIR[9] = { + 7.147391378143610789273E-4L, +-2.363848809501759061727E-5L, +-5.950237554056330156018E-4L, + 6.989332260623193171870E-5L, + 7.840334842744753003862E-4L, +-2.294719747873185405699E-4L, +-2.681327161876304418288E-3L, + 3.472222222230075327854E-3L, + 8.333333333333331800504E-2L, +}; + +#define MAXSTIR 1024.0L +static const long double SQTPI = 2.50662827463100050242E0L; + +/* 1/tgamma(x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 4.2e-23 + */ +static const long double S[9] = { +-1.193945051381510095614E-3L, + 7.220599478036909672331E-3L, +-9.622023360406271645744E-3L, +-4.219773360705915470089E-2L, + 1.665386113720805206758E-1L, +-4.200263503403344054473E-2L, +-6.558780715202540684668E-1L, + 5.772156649015328608253E-1L, + 1.000000000000000000000E0L, +}; + +/* 1/tgamma(-x) = z P(z) + * z(x) = 1/x + * 0 < x < 0.03125 + * Peak relative error 5.16e-23 + * Relative error spread = 2.5e-24 + */ +static const long double SN[9] = { + 1.133374167243894382010E-3L, + 7.220837261893170325704E-3L, + 9.621911155035976733706E-3L, +-4.219773343731191721664E-2L, +-1.665386113944413519335E-1L, +-4.200263503402112910504E-2L, + 6.558780715202536547116E-1L, + 5.772156649015328608727E-1L, +-1.000000000000000000000E0L, +}; + +static const long double PIL = 3.1415926535897932384626L; + +/* Gamma function computed by Stirling's formula. + */ +static long double stirf(long double x) +{ + long double y, w, v; + + w = 1.0/x; + /* For large x, use rational coefficients from the analytical expansion. */ + if (x > 1024.0) + w = (((((6.97281375836585777429E-5L * w + + 7.84039221720066627474E-4L) * w + - 2.29472093621399176955E-4L) * w + - 2.68132716049382716049E-3L) * w + + 3.47222222222222222222E-3L) * w + + 8.33333333333333333333E-2L) * w + + 1.0; + else + w = 1.0 + w * __polevll(w, STIR, 8); + y = expl(x); + if (x > MAXSTIR) { /* Avoid overflow in pow() */ + v = powl(x, 0.5L * x - 0.25L); + y = v * (v / y); + } else { + y = powl(x, x - 0.5L) / y; + } + y = SQTPI * y * w; + return y; +} + +long double tgammal(long double x) +{ + long double p, q, z; + + if (!isfinite(x)) + return x + INFINITY; + + q = fabsl(x); + if (q > 13.0) { + if (x < 0.0) { + p = floorl(q); + z = q - p; + if (z == 0) + return 0 / z; + if (q > MAXGAML) { + z = 0; + } else { + if (z > 0.5) { + p += 1.0; + z = q - p; + } + z = q * sinl(PIL * z); + z = fabsl(z) * stirf(q); + z = PIL/z; + } + if (0.5 * p == floorl(q * 0.5)) + z = -z; + } else if (x > MAXGAML) { + z = x * 0x1p16383L; + } else { + z = stirf(x); + } + return z; + } + + z = 1.0; + while (x >= 3.0) { + x -= 1.0; + z *= x; + } + while (x < -0.03125L) { + z /= x; + x += 1.0; + } + if (x <= 0.03125L) + goto small; + while (x < 2.0) { + z /= x; + x += 1.0; + } + if (x == 2.0) + return z; + + x -= 2.0; + p = __polevll(x, P, 7); + q = __polevll(x, Q, 8); + z = z * p / q; + return z; + +small: + /* z==1 if x was originally +-0 */ + if (x == 0 && z != 1) + return x / x; + if (x < 0.0) { + x = -x; + q = z / (x * __polevll(x, SN, 8)); + } else + q = z / (x * __polevll(x, S, 8)); + return q; +} +#endif diff --git a/system/lib/libc/musl/src/stdio/__overflow.c b/system/lib/libc/musl/src/stdio/__overflow.c new file mode 100644 index 00000000..3bb37923 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/__overflow.c @@ -0,0 +1,10 @@ +#include "stdio_impl.h" + +int __overflow(FILE *f, int _c) +{ + unsigned char c = _c; + if (!f->wend && __towrite(f)) return EOF; + if (f->wpos < f->wend && c != f->lbf) return *f->wpos++ = c; + if (f->write(f, &c, 1)!=1) return EOF; + return c; +} diff --git a/system/lib/libc/musl/src/stdio/__toread.c b/system/lib/libc/musl/src/stdio/__toread.c new file mode 100644 index 00000000..2e804f64 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/__toread.c @@ -0,0 +1,24 @@ +#include <stdio_impl.h> + +int __toread(FILE *f) +{ + f->mode |= f->mode-1; + if (f->wpos > f->buf) f->write(f, 0, 0); + f->wpos = f->wbase = f->wend = 0; + if (f->flags & (F_EOF|F_NORD)) { + if (f->flags & F_NORD) f->flags |= F_ERR; + return EOF; + } + f->rpos = f->rend = f->buf; + return 0; +} + +static const int dummy = 0; +weak_alias(dummy, __towrite_used); + +void __stdio_exit(void); + +void __seek_on_exit() +{ + if (!__towrite_used) __stdio_exit(); +} diff --git a/system/lib/libc/musl/src/stdio/__uflow.c b/system/lib/libc/musl/src/stdio/__uflow.c new file mode 100644 index 00000000..e28922c2 --- /dev/null +++ b/system/lib/libc/musl/src/stdio/__uflow.c @@ -0,0 +1,11 @@ +#include "stdio_impl.h" + +/* This function will never be called if there is already data + * buffered for reading. Thus we can get by with very few branches. */ + +int __uflow(FILE *f) +{ + unsigned char c; + if ((f->rend || !__toread(f)) && f->read(f, &c, 1)==1) return c; + return EOF; +} diff --git a/system/lib/libc/musl/src/stdlib/atof.c b/system/lib/libc/musl/src/stdlib/atof.c new file mode 100644 index 00000000..f7fcd826 --- /dev/null +++ b/system/lib/libc/musl/src/stdlib/atof.c @@ -0,0 +1,6 @@ +#include <stdlib.h> + +double atof(const char *s) +{ + return strtod(s, 0); +} diff --git a/system/lib/libc/musl/src/stdlib/strtod.c b/system/lib/libc/musl/src/stdlib/strtod.c new file mode 100644 index 00000000..461dcf85 --- /dev/null +++ b/system/lib/libc/musl/src/stdlib/strtod.c @@ -0,0 +1,40 @@ +#include <stdlib.h> +#include "shgetc.h" +#include "floatscan.h" +#include "stdio_impl.h" +#include "libc.h" + +static long double strtox(const char *s, char **p, int prec) +{ + FILE f = { + .buf = (void *)s, .rpos = (void *)s, + .rend = (void *)-1, .lock = -1 + }; + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + off_t cnt = shcnt(&f); + if (p) *p = cnt ? (char *)s + cnt : (char *)s; + return y; +} + +float strtof(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 0); +} + +double strtod(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 1); +} + +long double strtold(const char *restrict s, char **restrict p) +{ + return strtox(s, p, 2); +} + +weak_alias(strtof, strtof_l); +weak_alias(strtod, strtod_l); +weak_alias(strtold, strtold_l); +weak_alias(strtof, __strtof_l); +weak_alias(strtod, __strtod_l); +weak_alias(strtold, __strtold_l); diff --git a/system/lib/libc/musl/src/stdlib/wcstod.c b/system/lib/libc/musl/src/stdlib/wcstod.c new file mode 100644 index 00000000..83f308d3 --- /dev/null +++ b/system/lib/libc/musl/src/stdlib/wcstod.c @@ -0,0 +1,64 @@ +#include "shgetc.h" +#include "floatscan.h" +#include "stdio_impl.h" +#include <wctype.h> + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE *f, unsigned char *buf, size_t len) +{ + size_t i; + const wchar_t *wcs = f->cookie; + + if (!wcs[0]) wcs=L"@"; + for (i=0; i<f->buf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void *)(wcs+i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static long double wcstox(const wchar_t *s, wchar_t **p, int prec) +{ + wchar_t *t = (wchar_t *)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = 0; + f.buf = buf + 4; + f.buf_size = sizeof buf - 4; + f.lock = -1; + f.read = do_read; + while (iswspace(*t)) t++; + f.cookie = (void *)t; + shlim(&f, 0); + long double y = __floatscan(&f, prec, 1); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t *)s; + } + return y; +} + +float wcstof(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 0); +} + +double wcstod(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 1); +} + +long double wcstold(const wchar_t *restrict s, wchar_t **restrict p) +{ + return wcstox(s, p, 2); +} diff --git a/system/lib/libc/musl/src/stdlib/wcstol.c b/system/lib/libc/musl/src/stdlib/wcstol.c new file mode 100644 index 00000000..4443f577 --- /dev/null +++ b/system/lib/libc/musl/src/stdlib/wcstol.c @@ -0,0 +1,82 @@ +#include "stdio_impl.h" +#include "intscan.h" +#include "shgetc.h" +#include <inttypes.h> +#include <limits.h> +#include <wctype.h> +#include <wchar.h> + +/* This read function heavily cheats. It knows: + * (1) len will always be 1 + * (2) non-ascii characters don't matter */ + +static size_t do_read(FILE *f, unsigned char *buf, size_t len) +{ + size_t i; + const wchar_t *wcs = f->cookie; + + if (!wcs[0]) wcs=L"@"; + for (i=0; i<f->buf_size && wcs[i]; i++) + f->buf[i] = wcs[i] < 128 ? wcs[i] : '@'; + f->rpos = f->buf; + f->rend = f->buf + i; + f->cookie = (void *)(wcs+i); + + if (i && len) { + *buf = *f->rpos++; + return 1; + } + return 0; +} + +static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsigned long long lim) +{ + wchar_t *t = (wchar_t *)s; + unsigned char buf[64]; + FILE f = {0}; + f.flags = 0; + f.rpos = f.rend = 0; + f.buf = buf + 4; + f.buf_size = sizeof buf - 4; + f.lock = -1; + f.read = do_read; + while (iswspace(*t)) t++; + f.cookie = (void *)t; + shlim(&f, 0); + unsigned long long y = __intscan(&f, base, 1, lim); + if (p) { + size_t cnt = shcnt(&f); + *p = cnt ? t + cnt : (wchar_t *)s; + } + return y; +} + +unsigned long long wcstoull(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, ULLONG_MAX); +} + +long long wcstoll(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, LLONG_MIN); +} + +unsigned long wcstoul(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, ULONG_MAX); +} + +long wcstol(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstox(s, p, base, 0UL+LONG_MIN); +} + +intmax_t wcstoimax(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstoll(s, p, base); +} + +uintmax_t wcstoumax(const wchar_t *restrict s, wchar_t **restrict p, int base) +{ + return wcstoull(s, p, base); +} diff --git a/system/lib/libc/musl/src/string/memccpy.c b/system/lib/libc/musl/src/string/memccpy.c new file mode 100644 index 00000000..b85009c8 --- /dev/null +++ b/system/lib/libc/musl/src/string/memccpy.c @@ -0,0 +1,32 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + size_t *wd, k; + const size_t *ws; + + c = (unsigned char)c; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d=*s)!=c; n--, s++, d++); + if ((uintptr_t)s & ALIGN) goto tail; + k = ONES * c; + wd=(void *)d; ws=(const void *)s; + for (; n>=sizeof(size_t) && !HASZERO(*ws^k); + n-=sizeof(size_t), ws++, wd++) *wd = *ws; + d=(void *)wd; s=(const void *)ws; + } + for (; n && (*d=*s)!=c; n--, s++, d++); +tail: + if (*s==c) return d+1; + return 0; +} diff --git a/system/lib/libc/musl/src/string/memmem.c b/system/lib/libc/musl/src/string/memmem.c new file mode 100644 index 00000000..861fef2f --- /dev/null +++ b/system/lib/libc/musl/src/string/memmem.c @@ -0,0 +1,148 @@ +#define _GNU_SOURCE +#include <string.h> +#include <stdlib.h> +#include <stdint.h> + +static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1]; + for (h++, k--; k; k--, hw = hw<<8 | *++h) + if (hw == nw) return (char *)h-1; + return 0; +} + +static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8; + uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8; + for (h+=2, k-=2; k; k--, hw = (hw|*++h)<<8) + if (hw == nw) return (char *)h-2; + return 0; +} + +static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) +{ + uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; + uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; + for (h+=3, k-=3; k; k--, hw = hw<<8 | *++h) + if (hw == nw) return (char *)h-3; + return 0; +} + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) + +#define BITOP(a,b,op) \ + ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a)))) + +static char *twoway_memmem(const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l) +{ + size_t i, ip, jp, k, p, ms, p0, mem, mem0; + size_t byteset[32 / sizeof(size_t)] = { 0 }; + size_t shift[256]; + + /* Computing length of needle and fill shift table */ + for (i=0; i<l; i++) + BITOP(byteset, n[i], |=), shift[n[i]] = i+1; + + /* Compute maximal suffix */ + ip = -1; jp = 0; k = p = 1; + while (jp+k<l) { + if (n[ip+k] == n[jp+k]) { + if (k == p) { + jp += p; + k = 1; + } else k++; + } else if (n[ip+k] > n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + ms = ip; + p0 = p; + + /* And with the opposite comparison */ + ip = -1; jp = 0; k = p = 1; + while (jp+k<l) { + if (n[ip+k] == n[jp+k]) { + if (k == p) { + jp += p; + k = 1; + } else k++; + } else if (n[ip+k] < n[jp+k]) { + jp += k; + k = 1; + p = jp - ip; + } else { + ip = jp++; + k = p = 1; + } + } + if (ip+1 > ms+1) ms = ip; + else p = p0; + + /* Periodic needle? */ + if (memcmp(n, n+p, ms+1)) { + mem0 = 0; + p = MAX(ms, l-ms-1) + 1; + } else mem0 = l-p; + mem = 0; + + /* Search loop */ + for (;;) { + /* If remainder of haystack is shorter than needle, done */ + if (z-h < l) return 0; + + /* Check last byte first; advance by shift on mismatch */ + if (BITOP(byteset, h[l-1], &)) { + k = l-shift[h[l-1]]; + if (k) { + if (mem0 && mem && k < p) k = l-p; + h += k; + mem = 0; + continue; + } + } else { + h += l; + mem = 0; + continue; + } + + /* Compare right half */ + for (k=MAX(ms+1,mem); n[k] && n[k] == h[k]; k++); + if (n[k]) { + h += k-ms; + mem = 0; + continue; + } + /* Compare left half */ + for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--); + if (k == mem) return (char *)h; + h += p; + mem = mem0; + } +} + +void *memmem(const void *h0, size_t k, const void *n0, size_t l) +{ + const unsigned char *h = h0, *n = n0; + + /* Return immediately on empty needle */ + if (!l) return (void *)h; + + /* Return immediately when needle is longer than haystack */ + if (k<l) return 0; + + /* Use faster algorithms for short needles */ + h = memchr(h0, *n, k); + if (!h || l==1) return (void *)h; + if (l==2) return twobyte_memmem(h, k, n); + if (l==3) return threebyte_memmem(h, k, n); + if (l==4) return fourbyte_memmem(h, k, n); + + return twoway_memmem(h, h+k, n, l); +} diff --git a/system/lib/libc/musl/src/string/mempcpy.c b/system/lib/libc/musl/src/string/mempcpy.c new file mode 100644 index 00000000..c23ca69e --- /dev/null +++ b/system/lib/libc/musl/src/string/mempcpy.c @@ -0,0 +1,6 @@ +#include <string.h> + +void *mempcpy(void *dest, const void *src, size_t n) +{ + return (char *)memcpy(dest, src, n) + n; +} diff --git a/system/lib/libc/musl/src/string/memrchr.c b/system/lib/libc/musl/src/string/memrchr.c new file mode 100644 index 00000000..a78e9d6c --- /dev/null +++ b/system/lib/libc/musl/src/string/memrchr.c @@ -0,0 +1,12 @@ +#include <string.h> +#include "libc.h" + +void *__memrchr(const void *m, int c, size_t n) +{ + const unsigned char *s = m; + c = (unsigned char)c; + while (n--) if (s[n]==c) return (void *)(s+n); + return 0; +} + +weak_alias(__memrchr, memrchr); diff --git a/system/lib/libc/musl/src/string/strcasestr.c b/system/lib/libc/musl/src/string/strcasestr.c new file mode 100644 index 00000000..af109f36 --- /dev/null +++ b/system/lib/libc/musl/src/string/strcasestr.c @@ -0,0 +1,9 @@ +#define _GNU_SOURCE +#include <string.h> + +char *strcasestr(const char *h, const char *n) +{ + size_t l = strlen(n); + for (; *h; h++) if (!strncasecmp(h, n, l)) return (char *)h; + return 0; +} diff --git a/system/lib/libc/musl/src/string/strchrnul.c b/system/lib/libc/musl/src/string/strchrnul.c new file mode 100644 index 00000000..ceae4d45 --- /dev/null +++ b/system/lib/libc/musl/src/string/strchrnul.c @@ -0,0 +1,27 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "libc.h" + +#define ALIGN (sizeof(size_t)) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +char *__strchrnul(const char *s, int c) +{ + size_t *w, k; + + c = (unsigned char)c; + if (!c) return (char *)s + strlen(s); + + for (; (uintptr_t)s % ALIGN; s++) + if (!*s || *(unsigned char *)s == c) return (char *)s; + k = ONES * c; + for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w^k); w++); + for (s = (void *)w; *s && *(unsigned char *)s != c; s++); + return (char *)s; +} + +weak_alias(__strchrnul, strchrnul); diff --git a/system/lib/libc/musl/src/string/strlcat.c b/system/lib/libc/musl/src/string/strlcat.c new file mode 100644 index 00000000..ef81209e --- /dev/null +++ b/system/lib/libc/musl/src/string/strlcat.c @@ -0,0 +1,9 @@ +#define _BSD_SOURCE +#include <string.h> + +size_t strlcat(char *d, const char *s, size_t n) +{ + size_t l = strnlen(d, n); + if (l == n) return l + strlen(s); + return l + strlcpy(d+l, s, n-l); +} diff --git a/system/lib/libc/musl/src/string/strlcpy.c b/system/lib/libc/musl/src/string/strlcpy.c new file mode 100644 index 00000000..4d3ff92a --- /dev/null +++ b/system/lib/libc/musl/src/string/strlcpy.c @@ -0,0 +1,32 @@ +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "libc.h" + +#define ALIGN (sizeof(size_t)-1) +#define ONES ((size_t)-1/UCHAR_MAX) +#define HIGHS (ONES * (UCHAR_MAX/2+1)) +#define HASZERO(x) ((x)-ONES & ~(x) & HIGHS) + +size_t strlcpy(char *d, const char *s, size_t n) +{ + char *d0 = d; + size_t *wd; + const size_t *ws; + + if (!n--) goto finish; + if (((uintptr_t)s & ALIGN) == ((uintptr_t)d & ALIGN)) { + for (; ((uintptr_t)s & ALIGN) && n && (*d=*s); n--, s++, d++); + if (n && *s) { + wd=(void *)d; ws=(const void *)s; + for (; n>=sizeof(size_t) && !HASZERO(*ws); + n-=sizeof(size_t), ws++, wd++) *wd = *ws; + d=(void *)wd; s=(const void *)ws; + } + } + for (; n && (*d=*s); n--, s++, d++); + *d = 0; +finish: + return d-d0 + strlen(s); +} diff --git a/system/lib/libc/musl/src/string/strsep.c b/system/lib/libc/musl/src/string/strsep.c new file mode 100644 index 00000000..cb37c32e --- /dev/null +++ b/system/lib/libc/musl/src/string/strsep.c @@ -0,0 +1,13 @@ +#define _GNU_SOURCE +#include <string.h> + +char *strsep(char **str, const char *sep) +{ + char *s = *str, *end; + if (!s) return NULL; + end = s + strcspn(s, sep); + if (*end) *end++ = 0; + else end = 0; + *str = end; + return s; +} diff --git a/system/lib/libc/musl/src/string/strverscmp.c b/system/lib/libc/musl/src/string/strverscmp.c new file mode 100644 index 00000000..94d2e15c --- /dev/null +++ b/system/lib/libc/musl/src/string/strverscmp.c @@ -0,0 +1,42 @@ +#define _GNU_SOURCE +#include <ctype.h> +#include <string.h> +#include <sys/types.h> + +int strverscmp(const char *l, const char *r) +{ + int haszero=1; + while (*l==*r) { + if (!*l) return 0; + + if (*l=='0') { + if (haszero==1) { + haszero=0; + } + } else if (isdigit(*l)) { + if (haszero==1) { + haszero=2; + } + } else { + haszero=1; + } + l++; r++; + } + if (haszero==1 && (*l=='0' || *r=='0')) { + haszero=0; + } + if ((isdigit(*l) && isdigit(*r) ) && haszero) { + size_t lenl=0, lenr=0; + while (isdigit(l[lenl]) ) lenl++; + while (isdigit(r[lenr]) ) lenr++; + if (lenl==lenr) { + return (*l - *r); + } else if (lenl>lenr) { + return 1; + } else { + return -1; + } + } else { + return (*l - *r); + } +} diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index d169ead6..c3475e1c 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -1,4 +1,12 @@ + T __cosdf + T __intscan W __iswctype_l + T __lgamma_r + T __lgammaf_r + T __lgammal_r + T __memrchr + T __sindf + T __strchrnul T __strxfrm_l W __towlower_l W __towupper_l @@ -16,6 +24,9 @@ T iconv T iconv_close T iconv_open + T ilogb + T ilogbf + T ilogbl T iswalnum T iswalnum_l T iswalpha @@ -42,6 +53,18 @@ T iswupper_l T iswxdigit T iswxdigit_l + T ldexp + T ldexpf + T ldexpl + T lgamma + W lgamma_r + T lgammaf + W lgammaf_r + T lgammal + W lgammal_r + T logb + T logbf + T logbl T mblen T mbrlen T mbrtowc @@ -50,15 +73,32 @@ T mbsrtowcs T mbstowcs T mbtowc + T memccpy + T memmem + T mempcpy + W memrchr T regcomp T regerror T regexec T regfree + T scalbnf + D signgam + T strcasecmp_l + T strcasestr + W strchrnul T strfmon T strfmon_l + T strlcat + T strlcpy + T strncasecmp_l + T strsep + T strverscmp T strxfrm W strxfrm_l T swprintf + T tgamma + T tgammaf + T tgammal T towctrans T towctrans_l T towlower @@ -94,8 +134,17 @@ T wcsrtombs T wcsspn T wcsstr + T wcstod + T wcstof + T wcstoimax T wcstok + T wcstol + T wcstold + T wcstoll T wcstombs + T wcstoul + T wcstoull + T wcstoumax T wcswcs T wcswidth T wcsxfrm diff --git a/system/lib/libcxx/exception.cpp b/system/lib/libcxx/exception.cpp index 83f6fd19..3ce6f2e1 100644 --- a/system/lib/libcxx/exception.cpp +++ b/system/lib/libcxx/exception.cpp @@ -24,7 +24,7 @@ #ifndef _LIBCPPABI_VERSION using namespace __cxxabiapple; // On Darwin, there are two STL shared libraries and a lower level ABI - // shared libray. The globals holding the current terminate handler and + // shared library. The globals holding the current terminate handler and // current unexpected handler are in the ABI library. #define __terminate_handler __cxxabiapple::__cxa_terminate_handler #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp index a326323a..8e7fdb43 100644 --- a/system/lib/libcxx/locale.cpp +++ b/system/lib/libcxx/locale.cpp @@ -1036,7 +1036,7 @@ ctype<char>::classic_table() _NOEXCEPT #elif defined(__EMSCRIPTEN__) return *__ctype_b_loc(); #elif defined(_AIX) - return (const unsigned long *)__lc_ctype_ptr->obj->mask; + return (const unsigned int *)__lc_ctype_ptr->obj->mask; #else // Platform not supported: abort so the person doing the port knows what to // fix diff --git a/system/lib/libcxx/new.cpp b/system/lib/libcxx/new.cpp index fa0331a8..f4998cfb 100644 --- a/system/lib/libcxx/new.cpp +++ b/system/lib/libcxx/new.cpp @@ -22,7 +22,7 @@ #ifndef _LIBCPPABI_VERSION // On Darwin, there are two STL shared libraries and a lower level ABI - // shared libray. The global holding the current new handler is + // shared library. The global holding the current new handler is // in the ABI library and named __cxa_new_handler. #define __new_handler __cxxabiapple::__cxa_new_handler #endif diff --git a/system/lib/libcxx/optional.cpp b/system/lib/libcxx/optional.cpp index fde071c9..b614d811 100644 --- a/system/lib/libcxx/optional.cpp +++ b/system/lib/libcxx/optional.cpp @@ -7,10 +7,10 @@ // //===----------------------------------------------------------------------===// -#include "optional" +#include "experimental/optional" namespace std // purposefully not using versioning namespace -{ +{ namespace experimental { #ifdef _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS @@ -22,4 +22,4 @@ bad_optional_access::~bad_optional_access() _NOEXCEPT = default; #endif -} // std +}} // std::experimental diff --git a/system/lib/libcxx/random.cpp b/system/lib/libcxx/random.cpp index 47cdee40..bd24f2e5 100644 --- a/system/lib/libcxx/random.cpp +++ b/system/lib/libcxx/random.cpp @@ -19,8 +19,10 @@ #ifdef __sun__ #define rename solaris_headers_are_broken #endif +#if !defined(_WIN32) #include <fcntl.h> #include <unistd.h> +#endif // defined(_WIN32) #include <errno.h> _LIBCPP_BEGIN_NAMESPACE_STD diff --git a/system/lib/libcxx/readme.txt b/system/lib/libcxx/readme.txt index ae8090fd..ccac2fcd 100644 --- a/system/lib/libcxx/readme.txt +++ b/system/lib/libcxx/readme.txt @@ -1 +1 @@ -These files are from libc++, svn revision 194185, 2013-11-07. +These files are from libc++, svn revision 195693, 2013-11-26. diff --git a/system/lib/libcxx/support/win32/locale_win32.cpp b/system/lib/libcxx/support/win32/locale_win32.cpp index 1729d84a..5a437434 100644 --- a/system/lib/libcxx/support/win32/locale_win32.cpp +++ b/system/lib/libcxx/support/win32/locale_win32.cpp @@ -80,6 +80,16 @@ int wctob_l( wint_t c, locale_t loc ) return wctob( c ); } +int snprintf_l(char *ret, size_t n, locale_t loc, const char *format, ...) +{ + __locale_raii __current( uselocale(loc), uselocale ); + va_list ap; + va_start( ap, format ); + int result = vsnprintf( ret, n, format, ap ); + va_end(ap); + return result; +} + int asprintf_l( char **ret, locale_t loc, const char *format, ... ) { va_list ap; diff --git a/system/lib/libcxx/symbols b/system/lib/libcxx/symbols index 51368bce..2c026b0f 100644 --- a/system/lib/libcxx/symbols +++ b/system/lib/libcxx/symbols @@ -2408,7 +2408,6 @@ D _ZTISt15underflow_error D _ZTISt16invalid_argument D _ZTISt16nested_exception - C _ZTISt9exception C _ZTSNSt3__110__stdinbufIcEE C _ZTSNSt3__110__stdinbufIwEE C _ZTSNSt3__110__time_getE @@ -2542,7 +2541,6 @@ D _ZTSSt15underflow_error D _ZTSSt16invalid_argument D _ZTSSt16nested_exception - C _ZTSSt9exception D _ZTTNSt3__110istrstreamE D _ZTTNSt3__110ostrstreamE W _ZTTNSt3__113basic_istreamIcNS_11char_traitsIcEEEE 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 <cxxabi.h> - -#pragma GCC visibility push(hidden) - -namespace __cxxabiv1 -{ - -namespace __libcxxabi -{ - -class __demangle_tree; -class __node; - -char* -__demangle(__demangle_tree, char*, size_t*, int*); - -struct __demangle_tree_rv -{ - __demangle_tree* ptr_; - - explicit __demangle_tree_rv(__demangle_tree* ptr) - : ptr_(ptr) {} -}; - -class __demangle_tree -{ - const char* __mangled_name_begin_; - const char* __mangled_name_end_; - int __status_; - __node* __root_; - __node* __node_begin_; - __node* __node_end_; - __node* __node_cap_; - __node** __sub_begin_; - __node** __sub_end_; - __node** __sub_cap_; - __node** __t_begin_; - __node** __t_end_; - __node** __t_cap_; - bool __tag_templates_; - bool __fix_forward_references_; - bool __owns_buf_; - - __demangle_tree& operator=(const __demangle_tree&); -public: - __demangle_tree(const char*, char*, size_t); - ~__demangle_tree(); - - __demangle_tree(__demangle_tree&); - __demangle_tree(__demangle_tree_rv); - operator __demangle_tree_rv() {return __demangle_tree_rv(this);} - - int __status() const; - size_t size() const; - char* __get_demangled_name(char*) const; - - void __parse(); - -private: - const char* __parse_encoding(const char*, const char*); - const char* __parse_type(const char*, const char*, - bool = true, bool = false); - const char* __parse_special_name(const char*, const char*); - const char* __parse_name(const char*, const char*); - const char* __parse_bare_function_type(const char*, const char*); - const char* __parse_call_offset(const char*, const char*); - const char* __parse_number(const char*, const char*); - const char* __parse_cv_qualifiers(const char* first, const char* last, - unsigned& cv, bool = false); - const char* __parse_nested_name(const char*, const char*); - const char* __parse_discriminator(const char*, const char*); - const char* __parse_local_name(const char*, const char*); - const char* __parse_unscoped_template_name(const char*, const char*); - const char* __parse_unscoped_name(const char*, const char*); - const char* __parse_operator_name(const char*, const char*, int* = 0); - const char* __parse_unqualified_name(const char*, const char*); - const char* __parse_source_name(const char*, const char*); - const char* __parse_ctor_dtor_name(const char*, const char*); - const char* __parse_unnamed_type_name(const char*, const char*); - const char* __parse_template_args(const char*, const char*); - const char* __parse_template_arg(const char*, const char*); - const char* __parse_expression(const char*, const char*); - const char* __parse_expr_primary(const char*, const char*); - const char* __parse_substitution(const char*, const char*); - const char* __parse_builtin_type(const char*, const char*); - const char* __parse_function_type(const char*, const char*); - const char* __parse_class_enum_type(const char*, const char*); - const char* __parse_array_type(const char*, const char*); - const char* __parse_pointer_to_member_type(const char*, const char*); - const char* __parse_decltype(const char*, const char*); - const char* __parse_template_param(const char*, const char*); - const char* __parse_unresolved_name(const char*, const char*); - const char* __parse_unresolved_type(const char*, const char*); - const char* __parse_base_unresolved_name(const char*, const char*); - const char* __parse_simple_id(const char*, const char*); - const char* __parse_destructor_name(const char*, const char*); - const char* __parse_function_param(const char*, const char*); - const char* __parse_const_cast_expr(const char*, const char*); - const char* __parse_alignof_expr(const char*, const char*); - const char* __parse_call_expr(const char*, const char*); - const char* __parse_conversion_expr(const char*, const char*); - const char* __parse_delete_array_expr(const char*, const char*); - const char* __parse_delete_expr(const char*, const char*); - const char* __parse_dynamic_cast_expr(const char*, const char*); - const char* __parse_dot_star_expr(const char*, const char*); - const char* __parse_dot_expr(const char*, const char*); - const char* __parse_decrement_expr(const char*, const char*); - const char* __parse_new_expr(const char*, const char*); - const char* __parse_increment_expr(const char*, const char*); - const char* __parse_arrow_expr(const char*, const char*); - const char* __parse_reinterpret_cast_expr(const char*, const char*); - const char* __parse_static_cast_expr(const char*, const char*); - const char* __parse_sizeof_type_expr(const char*, const char*); - const char* __parse_sizeof_param_pack_expr(const char*, const char*); - const char* __parse_typeid_expr(const char*, const char*); - const char* __parse_throw_expr(const char*, const char*); - const char* __parse_pack_expansion(const char*, const char*); - const char* __parse_sizeof_function_param_pack_expr(const char*, const char*); - const char* __parse_dot_suffix(const char*, const char*); - const char* __parse_unresolved_qualifier_level(const char*, const char*); - const char* __parse_vector_type(const char*, const char*); - const char* __parse_hex_number(const char*, const char*, unsigned long long&); - - template <class _Tp> bool __make(); - template <class _Tp, class _A0> bool __make(_A0 __a0); - template <class _Tp, class _A0, class _A1> bool __make(_A0 __a0, _A1 __a1); - template <class _Tp, class _A0, class _A1, class _A2> - bool __make(_A0 __a0, _A1 __a1, _A2 __a2); - template <class _Tp, class _A0, class _A1, class _A2, class _A3> - bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3); - template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4> - bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4); - template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4, - class _A5> - bool __make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, _A5 __a5); - - friend - char* - __demangle(__demangle_tree, char*, size_t*, int*); - -}; - -__demangle_tree -__demangle(const char*); - -__demangle_tree -__demangle(const char*, char*, size_t); - -} // __libcxxabi -} // __cxxabiv1 - -#pragma GCC visibility pop - - -#endif // _CXA_DEMANGLE_H diff --git a/system/lib/libcxxabi/include/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 <stdint.h> +#include <stddef.h> + +#if __APPLE__ + #include <Availability.h> + #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 <stdint.h> + +// +// 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 <stdint.h> +#include <stddef.h> + +#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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <dlfcn.h> + +#if __APPLE__ +#include <mach-o/getsect.h> +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 <typename P> +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 <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) { + return *((uint8_t *)localCopy(addr)); +} + +template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) { + return P::E::get16(*(uint16_t *)localCopy(addr)); +} + +template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) { + return P::E::get32(*(uint32_t *)localCopy(addr)); +} + +template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) { + return P::E::get64(*(uint64_t *)localCopy(addr)); +} + +template <typename P> +typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) { + return P::getP(*(uint64_t *)localCopy(addr)); +} + +template <typename P> +uint64_t OtherAddressSpace<P>::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 <typename P> +int64_t OtherAddressSpace<P>::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 <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) { + // FIX ME +} + +template <typename P> +bool OtherAddressSpace<P>::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<Pointer32<LittleEndian> > 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<Pointer64<LittleEndian> > 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<Pointer32<BigEndian> > 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 <stdint.h> +#include <stdlib.h> + +#include <libunwind.h> +#include <mach-o/compact_unwind_encoding.h> + +#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 <typename A> +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 <typename A> +int CompactUnwinder_x86<A>::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 <typename A> +int CompactUnwinder_x86<A>::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 <typename A> +int CompactUnwinder_x86<A>::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 <typename A> +void CompactUnwinder_x86<A>::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 <typename A> +void CompactUnwinder_x86<A>::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 <typename A> +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 <typename A> +int CompactUnwinder_x86_64<A>::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 <typename A> +int CompactUnwinder_x86_64<A>::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 <typename A> +int CompactUnwinder_x86_64<A>::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 <typename A> +void CompactUnwinder_x86_64<A>::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 <typename A> +void CompactUnwinder_x86_64<A>::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 <typename A> +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 <typename A> +int CompactUnwinder_arm64<A>::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 <typename A> +int CompactUnwinder_arm64<A>::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 <typename A> +int CompactUnwinder_arm64<A>::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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#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 <typename A, typename R> +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<A>::RegisterLocation RegisterLocation; + typedef typename CFI_Parser<A>::PrologInfo PrologInfo; + typedef typename CFI_Parser<A>::FDE_Info FDE_Info; + typedef typename CFI_Parser<A>::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, typename R> +typename A::pint_t DwarfInstructions<A, R>::getSavedRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser<A>::kRegisterInCFA: + return addressSpace.getP(cfa + (pint_t)savedReg.value); + + case CFI_Parser<A>::kRegisterAtExpression: + return addressSpace.getP( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser<A>::kRegisterIsExpression: + return evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa); + + case CFI_Parser<A>::kRegisterInRegister: + return registers.getRegister((int)savedReg.value); + + case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterOffsetFromCFA: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for register"); +} + +template <typename A, typename R> +double DwarfInstructions<A, R>::getSavedFloatRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser<A>::kRegisterInCFA: + return addressSpace.getDouble(cfa + (pint_t)savedReg.value); + + case CFI_Parser<A>::kRegisterAtExpression: + return addressSpace.getDouble( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser<A>::kRegisterIsExpression: + case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterOffsetFromCFA: + case CFI_Parser<A>::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for float register"); +} + +template <typename A, typename R> +v128 DwarfInstructions<A, R>::getSavedVectorRegister( + A &addressSpace, const R ®isters, pint_t cfa, + const RegisterLocation &savedReg) { + switch (savedReg.location) { + case CFI_Parser<A>::kRegisterInCFA: + return addressSpace.getVector(cfa + (pint_t)savedReg.value); + + case CFI_Parser<A>::kRegisterAtExpression: + return addressSpace.getVector( + evaluateExpression((pint_t)savedReg.value, addressSpace, + registers, cfa)); + + case CFI_Parser<A>::kRegisterIsExpression: + case CFI_Parser<A>::kRegisterUnused: + case CFI_Parser<A>::kRegisterOffsetFromCFA: + case CFI_Parser<A>::kRegisterInRegister: + // FIX ME + break; + } + _LIBUNWIND_ABORT("unsupported restore location for vector register"); +} + +template <typename A, typename R> +int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc, + pint_t fdeStart, R ®isters) { + FDE_Info fdeInfo; + CIE_Info cieInfo; + if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, + &fdeInfo, &cieInfo) == NULL) { + PrologInfo prolog; + if (CFI_Parser<A>::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<A>::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, typename R> +typename A::pint_t +DwarfInstructions<A, R>::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 <typename A, typename R> +int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86_64 &) { + static_assert((int)CFI_Parser<A>::kMaxRegisterNumber + > (int)DW_X86_64_RET_ADDR, "register number out of range"); + return DW_X86_64_RET_ADDR; +} + +template <typename A, typename R> +bool +DwarfInstructions<A, R>::isReturnAddressRegister(int regNum, + const Registers_x86_64 &) { + return (regNum == DW_X86_64_RET_ADDR); +} + +template <typename A, typename R> +typename A::pint_t DwarfInstructions<A, R>::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 <typename A, typename R> +int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86 &) { + static_assert((int)CFI_Parser<A>::kMaxRegisterNumber + > (int)DW_X86_RET_ADDR, "register number out of range"); + return DW_X86_RET_ADDR; +} + +template <typename A, typename R> +bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum, + const Registers_x86 &) { + return (regNum == DW_X86_RET_ADDR); +} + +template <typename A, typename R> +typename A::pint_t DwarfInstructions<A, R>::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 <typename A, typename R> +int DwarfInstructions<A, R>::lastRestoreReg(const Registers_ppc &) { + static_assert((int)CFI_Parser<A>::kMaxRegisterNumber + > (int)UNW_PPC_SPEFSCR, "register number out of range"); + return UNW_PPC_SPEFSCR; +} + +template <typename A, typename R> +bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum, + const Registers_ppc &) { + return (regNum == UNW_PPC_LR); +} + +template <typename A, typename R> +typename A::pint_t DwarfInstructions<A, R>::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 <typename A, typename R> +bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum, + const Registers_arm64 &) { + return (regNum == UNW_ARM64_LR); +} + +template <typename A, typename R> +int DwarfInstructions<A, R>::lastRestoreReg(const Registers_arm64 &) { + static_assert((int)CFI_Parser<A>::kMaxRegisterNumber + > (int)UNW_ARM64_D31, "register number out of range"); + return UNW_ARM64_D31; +} + +template <typename A, typename R> +typename A::pint_t DwarfInstructions<A, R>::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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <vector> + +#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 <typename A> +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 <typename A> +const char *CFI_Parser<A>::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 <typename A> +bool CFI_Parser<A>::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 <typename A> +const char *CFI_Parser<A>::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 <typename A> +bool CFI_Parser<A>::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 <typename A> +bool CFI_Parser<A>::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; + } + // <rdar://problem/8456377> 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 <stdint.h> +#include <strings.h> + +#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 <unwind.h> + +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> + +#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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> + +#if __APPLE__ + #include <mach-o/dyld.h> +#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 <typename A> +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 A> +typename DwarfFDECache<A>::entry * +DwarfFDECache<A>::_buffer = _initialBuffer; + +template <typename A> +typename DwarfFDECache<A>::entry * +DwarfFDECache<A>::_bufferUsed = _initialBuffer; + +template <typename A> +typename DwarfFDECache<A>::entry * +DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64]; + +template <typename A> +typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64]; + +template <typename A> +pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER; + +#if __APPLE__ +template <typename A> +bool DwarfFDECache<A>::_registeredForDyldUnloads = false; +#endif + +template <typename A> +typename A::pint_t DwarfFDECache<A>::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 <typename A> +void DwarfFDECache<A>::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 <typename A> +void DwarfFDECache<A>::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 <typename A> +void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) { + removeAllIn((pint_t) mh); +} + +template <typename A> +void DwarfFDECache<A>::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 <typename A> 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 <typename A> 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 <typename A> 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 <typename A> 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 <typename A> 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 <typename A> 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 <typename A> 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 <typename A, typename R> +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<A, R>::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<A>::stepWithCompactEncoding( + _info.format, _info.start_ip, _addressSpace, _registers); + } + + int stepWithCompactEncoding(Registers_x86 &) { + return CompactUnwinder_x86<A>::stepWithCompactEncoding( + _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers); + } + + int stepWithCompactEncoding(Registers_ppc &) { + return UNW_EINVAL; + } + + int stepWithCompactEncoding(Registers_arm64 &) { + return CompactUnwinder_arm64<A>::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 <typename A, typename R> +UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as) + : _addressSpace(as), _registers(context), _unwindInfoMissing(false), + _isSignalFrame(false) { + static_assert(sizeof(UnwindCursor<A, R>) < sizeof(unw_cursor_t), + "UnwindCursor<> does not fit in unw_cursor_t"); + + bzero(&_info, sizeof(_info)); +} + +template <typename A, typename R> +UnwindCursor<A, R>::UnwindCursor(A &as, void *) + : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) { + bzero(&_info, sizeof(_info)); + // FIXME + // fill in _registers from thread arg +} + + +template <typename A, typename R> +bool UnwindCursor<A, R>::validReg(int regNum) { + return _registers.validRegister(regNum); +} + +template <typename A, typename R> +unw_word_t UnwindCursor<A, R>::getReg(int regNum) { + return _registers.getRegister(regNum); +} + +template <typename A, typename R> +void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) { + _registers.setRegister(regNum, (typename A::pint_t)value); +} + +template <typename A, typename R> +bool UnwindCursor<A, R>::validFloatReg(int regNum) { + return _registers.validFloatRegister(regNum); +} + +template <typename A, typename R> +double UnwindCursor<A, R>::getFloatReg(int regNum) { + return _registers.getFloatRegister(regNum); +} + +template <typename A, typename R> +void UnwindCursor<A, R>::setFloatReg(int regNum, double value) { + _registers.setFloatRegister(regNum, value); +} + +template <typename A, typename R> void UnwindCursor<A, R>::jumpto() { + _registers.jumpto(); +} + +template <typename A, typename R> +const char *UnwindCursor<A, R>::getRegisterName(int regNum) { + return _registers.getRegisterName(regNum); +} + +template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() { + return _isSignalFrame; +} + +#if _LIBUNWIND_SUPPORT_DWARF_UNWIND +template <typename A, typename R> +bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc, + const UnwindInfoSections §s, + uint32_t fdeSectionOffsetHint) { + typename CFI_Parser<A>::FDE_Info fdeInfo; + typename CFI_Parser<A>::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<A>::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<A>::findFDE(sects.dso_base, pc); + if (cachedFDE != 0) { + foundFDE = + CFI_Parser<A>::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<A>::findFDE(_addressSpace, pc, sects.dwarf_section, + (uint32_t)sects.dwarf_section_length, 0, + &fdeInfo, &cieInfo); + } + if (foundFDE) { + typename CFI_Parser<A>::PrologInfo prolog; + if (CFI_Parser<A>::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<A>::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 <typename A, typename R> +bool UnwindCursor<A, R>::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<A> 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<A> 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<A> pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionRegularArray<A> 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<A> pageHeader(_addressSpace, + secondLevelAddr); + UnwindSectionCompressedArray<A> 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<A> 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 <typename A, typename R> +void UnwindCursor<A, R>::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<A>::findFDE(0, pc); + if (cachedFDE != 0) { + CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace, + cachedFDE, &fdeInfo, &cieInfo); + if (msg == NULL) { + typename CFI_Parser<A>::PrologInfo prolog; + if (CFI_Parser<A>::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<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + if (!CFI_Parser<A>::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<A>::PrologInfo prolog; + if (CFI_Parser<A>::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 <typename A, typename R> +int UnwindCursor<A, R>::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 <typename A, typename R> +void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) { + *info = _info; +} + +template <typename A, typename R> +bool UnwindCursor<A, R>::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 <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> + +#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 <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#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<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + const char *msg = CFI_Parser<LocalAddressSpace>::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 <System/pthread_machdep.h> + +// 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 <assert.h> + +// 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 <Availability.h> + #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 <libunwind.h> +// +//===----------------------------------------------------------------------===// + +#include <libunwind.h> + +#include <new> + +#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<LocalAddressSpace, Registers_x86>( + context, LocalAddressSpace::sThisAddressSpace); +#elif __x86_64__ + new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>( + context, LocalAddressSpace::sThisAddressSpace); +#elif __ppc__ + new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>( + context, LocalAddressSpace::sThisAddressSpace); +#elif __arm64__ + new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>( + 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<OtherAddressSpace<Pointer32<LittleEndian> >, + Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg); + break; + case CPU_TYPE_X86_64: + new ((void *)cursor) UnwindCursor< + OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>( + ((unw_addr_space_x86_64 *)as)->oas, arg); + break; + case CPU_TYPE_POWERPC: + new ((void *)cursor) + UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, 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<LocalAddressSpace>::iterateCacheEntries(func); +} + + +/// IPI: for __register_frame() +void _unw_add_dynamic_fde(unw_word_t fde) { + CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo; + CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo; + const char *message = CFI_Parser<LocalAddressSpace>::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<LocalAddressSpace>::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<LocalAddressSpace>::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 <libunwind.h> + +#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 <stdexcept> +#include <new> +#include <exception> +#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<const __shim_type_info*>(exception_header->exceptionType); + // Try to get demangled name of thrown_type + int status; + char buf[1024]; + size_t len = sizeof(buf); + const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); + if (status != 0) + name = thrown_type->name(); + // If the uncaught exception can be caught with std::exception& + const __shim_type_info* catch_type = + static_cast<const __shim_type_info*>(&typeid(std::exception)); + if (catch_type->can_catch(thrown_type, thrown_object)) + { + // Include the what() message from the exception + const std::exception* e = static_cast<const std::exception*>(thrown_object); + abort_message("terminating with %s exception of type %s: %s", + cause, name, e->what()); + } + else + // Else just note that we're terminating with an exception + abort_message("terminating with %s exception of type %s", + cause, name); + } + else + // Else we're terminating with a foreign exception + abort_message("terminating with %s foreign exception", cause); + } + } + // Else just note that we're terminating + abort_message("terminating"); +} + +__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<std::terminate_handler> __cxa_terminate_handler(default_terminate_handler); +// std::atomic<std::unexpected_handler> __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,6438 +7,317 @@ // //===----------------------------------------------------------------------===// -#include "cxa_demangle.h" +#define _LIBCPP_EXTERN_TEMPLATE(...) +#define _LIBCPP_NO_EXCEPTIONS -#include <stdlib.h> -#include <string.h> -#include <ctype.h> -#include <stdio.h> -#include <new> +#include <vector> #include <algorithm> -#include <assert.h> - -#ifdef DEBUGGING - #include <string> -#include <typeinfo> - -#endif +#include <numeric> +#include <cstdlib> +#include <cstring> +#include <cctype> namespace __cxxabiv1 { -namespace __libcxxabi -{ - -#pragma GCC visibility push(hidden) - -class __node -{ - __node(const __node&); - __node& operator=(const __node&); -public: - const char* __name_; - size_t __size_; - __node* __left_; - __node* __right_; - long __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<long&>(__cached_size_) = static_cast<long>(first_size() + second_size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const {return buf;} - virtual char* second_demangled_name(char* buf) const {return buf;} - virtual char* get_demangled_name(char* buf) const - { - return second_demangled_name(first_demangled_name(buf)); - } - virtual size_t base_size() const {return size();} - virtual char* get_base_name(char* buf) const - { - return get_demangled_name(buf); - } - - virtual bool ends_with_template(bool /*parsing*/ = false) const - { - return false; - } - virtual bool is_ctor_dtor_conv() const - { - return false; - } - virtual __node* base_name() const - { - return const_cast<__node*>(this); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return false; - } - virtual bool is_function() const - { - return false; - } - virtual bool is_cv_qualifer() const - { - return false; - } - virtual bool is_array() const - { - return false; - } - - virtual bool fix_forward_references(__node**, __node**) - { - return true; - } - virtual __node* extract_cv(__node*&) const - { - return 0; - } - virtual size_t list_len() const - { - return 0; - } - virtual bool is_sub() const - { - return false; - } -}; - -#ifdef DEBUGGING - -void display(__node* x, int indent = 0) -{ - if (x) - { - for (int i = 0; i < 2*indent; ++i) - printf(" "); - 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("strlen(buf) = %ld and size = %ld\n", strlen(buf), sz); - } - free(buf); - display(x->__left_, indent+1); - display(x->__right_, indent+1); - } -} - -#endif - -class __vtable - : public __node -{ - static const ptrdiff_t n = sizeof("vtable for ") - 1; -public: - __vtable(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "vtable for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __VTT - : public __node -{ - static const ptrdiff_t n = sizeof("VTT for ") - 1; -public: - __VTT(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "VTT for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __construction_vtable - : public __node -{ - static const ptrdiff_t n = sizeof("construction vtable for ") - 1 + 4; -public: - __construction_vtable(__node* left, __node* right) - { - __left_ = left; - __right_ = right; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__left_->size() - + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "construction vtable for ", n-4); - buf = __left_->get_demangled_name(buf+n-4); - *buf++ = '-'; - *buf++ = 'i'; - *buf++ = 'n'; - *buf++ = '-'; - return __right_->get_demangled_name(buf); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = __left_->fix_forward_references(t_begin, t_end); - return r && __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __typeinfo - : public __node -{ - static const ptrdiff_t n = sizeof("typeinfo for ") - 1; -public: - __typeinfo(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "typeinfo for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __typeinfo_name - : public __node -{ - static const ptrdiff_t n = sizeof("typeinfo name for ") - 1; -public: - __typeinfo_name(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "typeinfo name for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __covariant_return_thunk - : public __node -{ - static const ptrdiff_t n = sizeof("covariant return thunk to ") - 1; -public: - __covariant_return_thunk(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = n + static_cast<long>(__right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "covariant return thunk to ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __virtual_thunk - : public __node -{ - static const size_t n = sizeof("virtual thunk to ") - 1; -public: - __virtual_thunk(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "virtual thunk to ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __non_virtual_thunk - : public __node -{ - static const size_t n = sizeof("non-virtual thunk to ") - 1; -public: - __non_virtual_thunk(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "non-virtual thunk to ", n); - return __right_->get_demangled_name(buf+n); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __guard_variable - : public __node -{ - static const size_t n = sizeof("guard variable for ") - 1; -public: - __guard_variable(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "guard variable for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __reference_temporary - : public __node -{ - static const size_t n = sizeof("reference temporary for ") - 1; -public: - __reference_temporary(__node* type) - { - __right_ = type; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "reference temporary for ", n); - return __right_->get_demangled_name(buf+n); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __source_name - : public __node -{ -public: - __source_name(const char* __name, size_t __size) - { - __name_ = __name; - __size_ = __size; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0) - const_cast<long&>(__cached_size_) = 21; - else - const_cast<long&>(__cached_size_) = static_cast<long>(__size_); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__size_ >= 10 && strncmp(__name_, "_GLOBAL__N", 10) == 0) - return strncpy(buf, "(anonymous namespace)", 21) + 21; - return strncpy(buf, __name_, __size_) + __size_; - } -}; - -class __operator_new - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator new") - 1;} - virtual char* first_demangled_name(char* buf) const - { - return strncpy(buf, "operator new", sizeof("operator new") - 1) + - sizeof("operator new") - 1; - } -}; - -class __operator_new_array - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator new[]") - 1;} - virtual char* first_demangled_name(char* buf) const - { - return strncpy(buf, "operator new[]", sizeof("operator new[]") - 1) + - sizeof("operator new[]") - 1; - } -}; - -class __operator_delete - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator delete") - 1;} - virtual char* first_demangled_name(char* buf) const - { - return strncpy(buf, "operator delete", sizeof("operator delete") - 1) + - sizeof("operator delete") - 1; - } -}; - -class __operator_delete_array - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator delete[]") - 1;} - virtual char* first_demangled_name(char* buf) const - { - return strncpy(buf, "operator delete[]", sizeof("operator delete[]") - 1) + - sizeof("operator delete[]") - 1; - } -}; - -class __operator_logical_and - : public __node -{ -public: - - __operator_logical_and() {} - __operator_logical_and(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator&&") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") && (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator&&", sizeof("operator&&") - 1); - buf += sizeof("operator&&") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_addressof - : public __node -{ -public: - - __operator_addressof() {} - explicit __operator_addressof(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator&") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '&'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator&", sizeof("operator&") - 1); - buf += sizeof("operator&") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_bit_and - : public __node -{ -public: - - __operator_bit_and() {} - __operator_bit_and(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator&") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") & (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator&", sizeof("operator&") - 1); - buf += sizeof("operator&") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_and_equal - : public __node -{ -public: - - __operator_and_equal() {} - __operator_and_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator&=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") &= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator&=", sizeof("operator&=") - 1); - buf += sizeof("operator&=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_equal - : public __node -{ -public: - - __operator_equal() {} - __operator_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") = (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator=", sizeof("operator=") - 1); - buf += sizeof("operator=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_alignof_type - : public __node -{ -public: - - __operator_alignof_type() {} - __operator_alignof_type(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__right_) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 10); - else - const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__right_) - { - strncpy(buf, "alignof (", 9); - buf += 9; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); - buf += sizeof("operator alignof") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__right_) - return __right_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_alignof_expression - : public __node -{ -public: - - __operator_alignof_expression() {} - __operator_alignof_expression(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__right_) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 10); - else - const_cast<long&>(__cached_size_) = sizeof("operator alignof") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__right_) - { - strncpy(buf, "alignof (", 9); - buf += 9; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator alignof", sizeof("operator alignof") - 1); - buf += sizeof("operator alignof") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__right_) - return __right_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_paren - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator()") - 1;} - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "operator()", sizeof("operator()") - 1); - return buf + sizeof("operator()") - 1; - } -}; - -class __operator_comma - : public __node -{ -public: - - __operator_comma() {} - __operator_comma(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator,") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") , (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator,", sizeof("operator,") - 1); - buf += sizeof("operator,") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_tilda - : public __node +namespace { -public: - __operator_tilda() {} - explicit __operator_tilda(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator~") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '~'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator~", sizeof("operator~") - 1); - buf += sizeof("operator~") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_cast - : public __node +enum { - static const size_t n = sizeof("operator ") - 1; -public: - - explicit __operator_cast(__node* type) - { - __right_ = type; - } - __operator_cast(__node* type, __node* arg) - { - __size_ = 1; - __right_ = type; - __left_ = arg; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - size_t off; - if (__size_) - { - off = 4; - off += __right_->size(); - if (__left_) - off += __left_->size(); - } - else - off = n + __right_->size();; - const_cast<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__size_) - { - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - *buf++ = '('; - if (__left_) - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator ", n); - buf = __right_->get_demangled_name(buf+n); - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } - virtual bool is_ctor_dtor_conv() const - { - return true; - } -}; - -class __cast_literal - : public __node -{ -public: - - __cast_literal(__node* type, const char* f, const char* l) - { - __left_ = type; - __name_ = f; - __size_ = static_cast<size_t>(l - f); - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(2 + - __left_->size() + __size_); - return static_cast<size_t>(__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); - } + unknown_error = -4, + invalid_args = -3, + invalid_mangled_name, + memory_alloc_failure, + success }; -class __operator_dereference - : public __node -{ -public: - - __operator_dereference() {} - explicit __operator_dereference(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator*") - 1; - } - return static_cast<size_t>(__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; - } -}; +template <class C> + const char* parse_type(const char* first, const char* last, C& db); +template <class C> + const char* parse_encoding(const char* first, const char* last, C& db); +template <class C> + const char* parse_name(const char* first, const char* last, C& db); +template <class C> + const char* parse_expression(const char* first, const char* last, C& db); +template <class C> + const char* parse_template_args(const char* first, const char* last, C& db); +template <class C> + const char* parse_operator_name(const char* first, const char* last, C& db); +template <class C> + const char* parse_unqualified_name(const char* first, const char* last, C& db); +template <class C> + const char* parse_decltype(const char* first, const char* last, C& db); -class __operator_divide - : public __node -{ -public: - - __operator_divide() {} - __operator_divide(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator/") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") / (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator/", sizeof("operator/") - 1); - buf += sizeof("operator/") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_divide_equal - : public __node -{ -public: - - __operator_divide_equal() {} - __operator_divide_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator/=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") /= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator/=", sizeof("operator/=") - 1); - buf += sizeof("operator/=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_xor - : public __node -{ -public: - - __operator_xor() {} - __operator_xor(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator^") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") ^ (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator^", sizeof("operator^") - 1); - buf += sizeof("operator^") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_xor_equal - : public __node -{ -public: - - __operator_xor_equal() {} - __operator_xor_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator^=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; // strncpy(buf, "(", 1); - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") ^= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator^=", sizeof("operator^=") - 1); - buf += sizeof("operator^=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_equality - : public __node -{ -public: - - __operator_equality() {} - __operator_equality(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator==") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") == (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator==", sizeof("operator==") - 1); - buf += sizeof("operator==") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_greater_equal - : public __node -{ -public: - - __operator_greater_equal() {} - __operator_greater_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator>=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") >= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator>=", sizeof("operator>=") - 1); - buf += sizeof("operator>=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_greater - : public __node -{ -public: - - __operator_greater() {} - __operator_greater(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 9 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator>") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") > (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - *buf++ = ')'; - } - else - { - strncpy(buf, "operator>", sizeof("operator>") - 1); - buf += sizeof("operator>") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_brackets - : public __node -{ -public: - - virtual size_t first_size() const {return sizeof("operator[]") - 1;} - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "operator[]", sizeof("operator[]") - 1); - return buf + sizeof("operator[]") - 1; - } -}; - -class __operator_less_equal - : public __node -{ -public: - - __operator_less_equal() {} - __operator_less_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator<=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") <= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator<=", sizeof("operator<=") - 1); - buf += sizeof("operator<=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_less - : public __node -{ -public: - - __operator_less() {} - __operator_less(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator<") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") < (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator<", sizeof("operator<") - 1); - buf += sizeof("operator<") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_left_shift - : public __node -{ -public: - - __operator_left_shift() {} - __operator_left_shift(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator<<") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") << (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator<<", sizeof("operator<<") - 1); - buf += sizeof("operator<<") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_left_shift_equal - : public __node -{ -public: - - __operator_left_shift_equal() {} - __operator_left_shift_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 9 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator<<=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") <<= (", 7); - buf += 7; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator<<=", sizeof("operator<<=") - 1); - buf += sizeof("operator<<=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_minus - : public __node -{ -public: - - __operator_minus() {} - __operator_minus(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator-") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") - (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator-", sizeof("operator-") - 1); - buf += sizeof("operator-") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_minus_equal - : public __node -{ -public: - - __operator_minus_equal() {} - __operator_minus_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator-=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") -= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator-=", sizeof("operator-=") - 1); - buf += sizeof("operator-=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_times - : public __node -{ -public: - - __operator_times() {} - __operator_times(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator*") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") * (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator*", sizeof("operator*") - 1); - buf += sizeof("operator*") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_times_equal - : public __node -{ -public: - - __operator_times_equal() {} - __operator_times_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator*=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") *= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator*=", sizeof("operator*=") - 1); - buf += sizeof("operator*=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_decrement - : public __node -{ -public: - - __operator_decrement() {} - explicit __operator_decrement(bool prefix, __node* op) - { - __size_ = prefix; - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(4 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator--") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - if (__size_) - { - *buf++ = '-'; - *buf++ = '-'; - *buf++ = '('; - } - else - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - if (__size_) - *buf++ = ')'; - else - { - *buf++ = ')'; - *buf++ = '-'; - *buf++ = '-'; - } - } - else - { - strncpy(buf, "operator--", sizeof("operator--") - 1); - buf += sizeof("operator--") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_not_equal - : public __node -{ -public: - - __operator_not_equal() {} - __operator_not_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator!=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") != (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator!=", sizeof("operator!=") - 1); - buf += sizeof("operator!=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_negate - : public __node -{ -public: - - __operator_negate() {} - explicit __operator_negate(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator-") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '-'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator-", sizeof("operator-") - 1); - buf += sizeof("operator-") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_logical_not - : public __node -{ -public: - - __operator_logical_not() {} - explicit __operator_logical_not(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator!") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '!'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator!", sizeof("operator!") - 1); - buf += sizeof("operator!") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_logical_or - : public __node -{ -public: - - __operator_logical_or() {} - __operator_logical_or(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator||") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") || (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator||", sizeof("operator||") - 1); - buf += sizeof("operator||") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_bit_or - : public __node -{ -public: - - __operator_bit_or() {} - __operator_bit_or(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator|") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") | (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator|", sizeof("operator|") - 1); - buf += sizeof("operator|") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_or_equal - : public __node -{ -public: - - __operator_or_equal() {} - __operator_or_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator|=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") |= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator|=", sizeof("operator|=") - 1); - buf += sizeof("operator|=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_pointer_to_member - : public __node -{ -public: - - __operator_pointer_to_member() {} - __operator_pointer_to_member(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 9 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator->*") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") ->* (", 7); - buf += 7; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator->*", sizeof("operator->*") - 1); - buf += sizeof("operator->*") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_plus - : public __node -{ -public: - - __operator_plus() {} - __operator_plus(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator+") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") + (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator+", sizeof("operator+") - 1); - buf += sizeof("operator+") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_plus_equal - : public __node -{ -public: - - __operator_plus_equal() {} - __operator_plus_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator+=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") += (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator+=", sizeof("operator+=") - 1); - buf += sizeof("operator+=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_increment - : public __node -{ -public: - - __operator_increment() {} - explicit __operator_increment(bool prefix, __node* op) - { - __size_ = prefix; - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(4 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator++") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - if (__size_) - { - *buf++ = '+'; - *buf++ = '+'; - *buf++ = '('; - } - else - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - if (__size_) - *buf++ = ')'; - else - { - *buf++ = ')'; - *buf++ = '+'; - *buf++ = '+'; - } - } - else - { - strncpy(buf, "operator++", sizeof("operator++") - 1); - buf += sizeof("operator++") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_unary_plus - : public __node -{ -public: - - __operator_unary_plus() {} - explicit __operator_unary_plus(__node* op) - { - __left_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>(3 + __left_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator+") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '+'; - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator+", sizeof("operator+") - 1); - buf += sizeof("operator+") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__left_) - return __left_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __operator_arrow - : public __node -{ -public: - - __operator_arrow() {} - __operator_arrow(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator->") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") -> (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator->", sizeof("operator->") - 1); - buf += sizeof("operator->") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_conditional - : public __node -{ -public: - - __operator_conditional() {} - __operator_conditional(__node* op1, __node* op2, __node* op3) - { - __name_ = (const char*)op1; - __left_ = op2; - __right_ = op3; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - { - __node* op1 = (__node*)__name_; - const_cast<long&>(__cached_size_) = static_cast<long>( - op1->size() + - __left_->size() + 12 + - __right_->size()); - } - else - const_cast<long&>(__cached_size_) = sizeof("operator?") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - __node* op1 = (__node*)__name_; - *buf++ = '('; - buf = op1->get_demangled_name(buf); - strncpy(buf, ") ? (", 5); - buf += 5; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") : (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator?", sizeof("operator?") - 1); - buf += sizeof("operator?") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__name_) - r = r && ((__node*)__name_)->fix_forward_references(t_begin, t_end); - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_mod - : public __node -{ -public: - - __operator_mod() {} - __operator_mod(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 7 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator%") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") % (", 5); - buf += 5; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator%", sizeof("operator%") - 1); - buf += sizeof("operator%") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_mod_equal - : public __node -{ -public: - - __operator_mod_equal() {} - __operator_mod_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator%=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") %= (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator%=", sizeof("operator%=") - 1); - buf += sizeof("operator%=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_right_shift - : public __node -{ -public: - - __operator_right_shift() {} - __operator_right_shift(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 8 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator>>") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") >> (", 6); - buf += 6; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator>>", sizeof("operator>>") - 1); - buf += sizeof("operator>>") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_right_shift_equal - : public __node -{ -public: - - __operator_right_shift_equal() {} - __operator_right_shift_equal(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_) - const_cast<long&>(__cached_size_) = static_cast<long>( - __left_->size() + 9 + - __right_->size()); - else - const_cast<long&>(__cached_size_) = sizeof("operator>>=") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - strncpy(buf, ") >>= (", 7); - buf += 7; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator>>=", sizeof("operator>>=") - 1); - buf += sizeof("operator>>=") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __operator_sizeof_type - : public __node -{ -public: - - __operator_sizeof_type() {} - __operator_sizeof_type(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__right_) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 9); - else - const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1; - } - return static_cast<size_t>(__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++ = ')'; - } +template <class C> +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 - { - strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1); - buf += sizeof("operator sizeof") - 1; - } - return buf; + printf("S_ = {"); + for (auto& s : v) + printf("{%s#%s}", s.first.c_str(), s.second.c_str()); + printf("}\n"); + ++i; } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) + printf("template_param:\n"); + for (auto& t : db.template_param) { - 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) + printf("--\n"); + i = -1; + for (auto& v : t) { - if (__right_) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 9); + if (i >= 0) + printf("T%i_ = {", i); else - const_cast<long&>(__cached_size_) = sizeof("operator sizeof") - 1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__right_) - { - strncpy(buf, "sizeof (", 8); - buf += 8; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - else - { - strncpy(buf, "operator sizeof", sizeof("operator sizeof") - 1); - buf += sizeof("operator sizeof") - 1; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - if (__right_) - return __right_->fix_forward_references(t_begin, t_end); - return true; - } -}; - -class __typeid - : public __node -{ -public: - - __typeid(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 8); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "typeid(", 7); - buf += 7; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __throw - : public __node -{ -public: - - __throw(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 6); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "throw ", 6); - return __right_->get_demangled_name(buf+6); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __rethrow - : public __node -{ - static const ptrdiff_t n = sizeof("throw") - 1; -public: - - virtual size_t first_size() const {return n;} - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "throw", n); - return buf+n; - } -}; - -class __operator_sizeof_param_pack - : public __node -{ -public: - - __operator_sizeof_param_pack(__node* op) - { - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->size() + 11); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "sizeof...(", 10); - buf += 10; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __const_cast - : public __node -{ -public: - - __const_cast(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 14 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "const_cast<", 11); - buf += 11; - buf = __left_->get_demangled_name(buf); - *buf++ = '>'; - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __dynamic_cast - : public __node -{ -public: - - __dynamic_cast(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 16 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "dynamic_cast<", 13); - buf += 13; - buf = __left_->get_demangled_name(buf); - *buf++ = '>'; - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __reinterpret_cast - : public __node -{ -public: - - __reinterpret_cast(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 20 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "reinterpret_cast<", 17); - buf += 17; - buf = __left_->get_demangled_name(buf); - *buf++ = '>'; - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __static_cast - : public __node -{ -public: - - __static_cast(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 15 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "static_cast<", 12); - buf += 12; - buf = __left_->get_demangled_name(buf); - *buf++ = '>'; - *buf++ = '('; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __call_expr - : public __node -{ -public: - - __call_expr(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - size_t off = __left_->size() + 2; - if (__right_) - off += __right_->size(); - const_cast<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - *buf++ = '('; - if (__right_) - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __delete_array_expr - : public __node -{ -public: - - __delete_array_expr(bool global, __node* op) - { - __size_ = global; - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>((__size_ ? 2 : 0) + - 9 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__size_) - { - *buf++ = ':'; - *buf++ = ':'; + printf("T_ = {"); + for (auto& s : v) + printf("{%s#%s}", s.first.c_str(), s.second.c_str()); + printf("}\n"); + ++i; } - 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); } -}; + printf("---------\n\n"); +} -class __delete_expr - : public __node +template <class C> +void +print_state(const char* msg, const char* first, const char* last, const C& db) { -public: + printf("%s: ", msg); + for (; first != last; ++first) + printf("%c", *first); + printf("\n"); + print_stack(db); +} - __delete_expr(bool global, __node* op) - { - __size_ = global; - __right_ = op; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>((__size_ ? 2 : 0) + - 7 + __right_->size()); - return static_cast<size_t>(__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); - } -}; +// <number> ::= [n] <non-negative decimal integer> -class __new_expr - : public __node +const char* +parse_number(const char* first, const char* last) { -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 (first != last) { - if (__cached_size_ == -1) + const char* t = first; + if (*t == 'n') + ++t; + if (t != last) { - size_t off = 4; - if (__size_ & 1) - off += 2; - if (__size_ & 2) - off += 2; - if (__left_) + if (*t == '0') { - off += 2; - off += __left_->size(); + first = t+1; } - __node* type = (__node*)__name_; - off += type->size(); - if (__size_ & 4) + else if ('1' <= *t && *t <= '9') { - off += 2; - if (__right_) - off += __right_->size(); + first = t+1; + while (first != last && std::isdigit(*first)) + ++first; } - const_cast<long&>(__cached_size_) = static_cast<long>(off); } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__size_ & 1) - { - *buf++ = ':'; - *buf++ = ':'; - } - *buf++ = 'n'; - *buf++ = 'e'; - *buf++ = 'w'; - if (__size_ & 2) - { - *buf++ = '['; - *buf++ = ']'; - } - if (__left_) - { - *buf++ = '('; - buf = __left_->get_demangled_name(buf); - *buf++ = ')'; - } - *buf++ = ' '; - __node* type = (__node*)__name_; - buf = type->get_demangled_name(buf); - if (__size_ & 4) - { - *buf++ = '('; - if (__right_) - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - } - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - __node* type = (__node*)__name_; - bool r = type->fix_forward_references(t_begin, t_end); - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end);; - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end);; - return r; - } -}; - -class __dot_star_expr - : public __node -{ -public: - - __dot_star_expr(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 2 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - *buf++ = '.'; - *buf++ = '*'; - return __right_->get_demangled_name(buf); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __dot_expr - : public __node -{ -public: - - __dot_expr(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 1 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - *buf++ = '.'; - return __right_->get_demangled_name(buf); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __arrow_expr - : public __node -{ -public: - - __arrow_expr(__node* op1, __node* op2) - { - __left_ = op1; - __right_ = op2; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - 2 + __right_->size()); - return static_cast<size_t>(__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: + return first; +} - 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; - } -}; +template <class Float> +struct float_data; -class __sub_string - : public __node +template <> +struct float_data<float> { - static const size_t n = sizeof("std::string") - 1; - static const size_t ne = sizeof("std::basic_string<char, std::char_traits<char>, std::allocator<char> >") - 1; -public: - - virtual size_t first_size() const - { - if (__size_) - return ne; - return n; - } - virtual char* first_demangled_name(char* buf) const - { - if (__size_) - { - strncpy(buf, "std::basic_string<char, std::char_traits<char>, std::allocator<char> >", ne); - buf += ne; - } - else - { - strncpy(buf, "std::string", n); - buf += n; - } - return buf; - } - - virtual size_t base_size() const - { - return 12; - } - virtual char* get_base_name(char* buf) const - { - strncpy(buf, "basic_string", 12); - return buf + 12; - } - - virtual __node* base_name() const - { - const_cast<size_t&>(__size_) = true; - return const_cast<__node*>(static_cast<const __node*>(this)); - } + static const size_t mangled_size = 8; + static const size_t max_demangled_size = 24; + static constexpr const char* spec = "%af"; }; -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; - } -}; +constexpr const char* float_data<float>::spec; -class __sub_ostream - : public __node +template <> +struct float_data<double> { - 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; - } + static const size_t mangled_size = 16; + static const size_t max_demangled_size = 32; + static constexpr const char* spec = "%a"; }; -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; - } -}; +constexpr const char* float_data<double>::spec; -class __sub - : public __node +template <> +struct float_data<long double> { -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<size_t>(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; - } + 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 __unscoped_template_name - : public __node -{ -public: - __unscoped_template_name(__node* name, __node* args) - {__left_ = name; __right_ = args;} +constexpr const char* float_data<long double>::spec; - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - __right_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - return __right_->get_demangled_name(buf); - } - virtual bool ends_with_template(bool parsing = false) const - { - return __right_->ends_with_template(parsing); - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -// length == 0: __left_ == NULL -// length == 1: __left_ != NULL, __right_ == NULL -// length > 1: __left_ != NULL, __right_ != NULL -class __list - : public __node -{ -public: - explicit __list(__node* type) - {__left_ = type;} - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - if (__left_ == NULL) - const_cast<long&>(__cached_size_) = 0; - else if (__right_ == NULL) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size()); - else - { - size_t off = __right_->size(); - if (off > 0) - off += 2; - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + off); - } - } - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>(__left_->size() + off); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - *buf++ = '<'; - if (__right_) - { - buf = __right_->get_demangled_name(buf); - if (buf[-1] == '>') - *buf++ = ' '; - } - *buf++ = '>'; - return buf; - } - virtual bool ends_with_template(bool /*parsing*/ = false) const - { - return true; - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_ctor_dtor_conv() const - { - return __left_->is_ctor_dtor_conv(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __function_args - : public __node -{ -public: - __function_args(__node* list) - {__right_ = list;} - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(2 + __right_->size()); - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>(r); - } - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>(r); - } - return static_cast<size_t>(__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 +template <class Float, class C> +const char* +parse_floating_number(const char* first, const char* last, C& db) { -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 + const size_t N = float_data<Float>::mangled_size; + if (static_cast<std::size_t>(last - first) > N) { - 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) + last = first + N; + union { - 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) + Float value; + char buf[sizeof(Float)]; + }; + const char* t = first; + char* e = buf; + for (; t != last; ++t, ++e) { - *buf++ = ' '; - *buf++ = '&'; + if (!isxdigit(*t)) + return first; + unsigned d1 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : + static_cast<unsigned>(*t - 'a' + 10); + ++t; + unsigned d0 = isdigit(*t) ? static_cast<unsigned>(*t - '0') : + static_cast<unsigned>(*t - 'a' + 10); + *e = static_cast<char>((d1 << 4) + d0); } - if (__size_ & 512) + if (*t == 'E') { - *buf++ = ' '; - *buf++ = '&'; - *buf++ = '&'; - } - return buf; - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __left_->is_reference_or_pointer_to_function_or_array(); - } - virtual bool is_function() const - { - return __left_->is_function(); - } - virtual bool is_cv_qualifer() const - { - return true; - } - virtual __node* extract_cv(__node*& rt) const - { - if (rt == this) - { - rt = __left_; - return const_cast<__node*>(static_cast<const __node*>(this)); +#if __LITTLE_ENDIAN__ + std::reverse(buf, e); +#endif + char num[float_data<Float>::max_demangled_size] = {0}; + int n = snprintf(num, sizeof(num), float_data<Float>::spec, value); + if (static_cast<std::size_t>(n) >= sizeof(num)) + return first; + db.names.push_back(typename C::String(num, static_cast<std::size_t>(n))); + first = t+1; } - 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; } + return first; +} - virtual size_t first_size() const - { - size_t s = __left_->first_size(); - if (__size_ == 0) - s += __right_->size() + 1; - return s; - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->first_demangled_name(buf); - if (__size_ == 0) - { - *buf++ = ' '; - buf = __right_->get_demangled_name(buf); - } - return buf; - } - virtual size_t second_size() const - { - size_t s = __left_->second_size(); - if (__size_ == 1) - s += __right_->size() + 1; - return s; - } - virtual char* second_demangled_name(char* buf) const - { - buf = __left_->second_demangled_name(buf); - if (__size_ == 1) - { - *buf++ = ' '; - buf = __right_->get_demangled_name(buf); - } - return buf; - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __left_->is_reference_or_pointer_to_function_or_array(); - } - virtual bool is_function() const - { - return __left_->is_function(); - } - virtual bool is_cv_qualifer() const - { - return true; - } - virtual __node* extract_cv(__node*& rt) const - { - if (rt == this) - { - rt = __left_; - return const_cast<__node*>(static_cast<const __node*>(this)); - } - return 0; - } - virtual bool ends_with_template(bool parsing = false) const - { - return __left_->ends_with_template(parsing); - } - virtual bool is_ctor_dtor_conv() const - { - return __left_->is_ctor_dtor_conv(); - } - virtual bool is_array() const - { - return __left_->is_array(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } - virtual size_t list_len() const - { - return __left_->list_len(); - } -}; +// <source-name> ::= <positive length number> <identifier> -class __function - : public __node +template <class C> +const char* +parse_source_name(const char* first, const char* last, C& db) { -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 (first != last) { - if (__cached_size_ == -1) + char c = *first; + if (isdigit(c) && first+1 != last) { - 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_) + const char* t = first+1; + size_t n = static_cast<size_t>(c - '0'); + for (c = *t; isdigit(c); c = *t) { - off += 2; - off += __right_->first_size(); + n = n * 10 + static_cast<size_t>(c - '0'); + if (++t == last) + return first; } - const_cast<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__cached_size_); - } - - virtual bool is_function() const - { - return true; - } - virtual bool is_ctor_dtor_conv() const - { - return __left_->is_ctor_dtor_conv(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __function_signature - : public __node -{ -public: - __function_signature(__node* ret, __node* args) - { - __left_ = ret; - __right_ = args; - } - virtual size_t first_size() const - { - return __left_ ? __left_->first_size() : 0; - } - - virtual size_t second_size() const - { - return 2 + (__right_ ? __right_->size() : 0) - + (__left_ ? __left_->second_size() : 0); - } - - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - buf = __left_->first_demangled_name(buf); - return buf; - } - - virtual char* second_demangled_name(char* buf) const - { - *buf++ = '('; - if (__right_) - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - if (__left_) - buf = __left_->second_demangled_name(buf); - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = r && __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - -class __pointer_to - : public __node -{ -public: - - explicit __pointer_to(__node* type) - { - __left_ = type; - } - virtual size_t first_size() const - { - return __left_->first_size() + (__left_->is_array() ? 3 : 1); - } - virtual size_t second_size() const - { - return __left_->second_size() + (__left_->is_array() ? 1 : 0); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->first_demangled_name(buf); - if (__left_->is_array()) - { - *buf++ = ' '; - *buf++ = '('; - *buf++ = '*'; - } - else - *buf++ = '*'; - return buf; - } - virtual char* second_demangled_name(char* buf) const - { - if (__left_->is_array()) - *buf++ = ')'; - return __left_->second_demangled_name(buf); - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __left_->is_function() || - __left_->is_reference_or_pointer_to_function_or_array(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } - virtual size_t list_len() const - { - return __left_->list_len(); - } -}; - -class __lvalue_reference_to - : public __node -{ -public: - - explicit __lvalue_reference_to(__node* type) - { - __left_ = type; - } - virtual size_t first_size() const - { - return __left_->first_size() + (__left_->is_array() ? 3 : 1); - } - virtual size_t second_size() const - { - return __left_->second_size() + (__left_->is_array() ? 1 : 0); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->first_demangled_name(buf); - if (__left_->is_array()) - { - *buf++ = ' '; - *buf++ = '('; - *buf++ = '&'; - } - else - *buf++ = '&'; - return buf; - } - virtual char* second_demangled_name(char* buf) const - { - if (__left_->is_array()) - *buf++ = ')'; - return __left_->second_demangled_name(buf); - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __left_->is_function(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } - virtual size_t list_len() const - { - return __left_->list_len(); - } -}; - -class __rvalue_reference_to - : public __node -{ -public: - - explicit __rvalue_reference_to(__node* type) - { - __left_ = type; - } - virtual size_t first_size() const - { - return __left_->first_size() + (__left_->is_array() ? 4 : 2); - } - virtual size_t second_size() const - { - return __left_->second_size() + (__left_->is_array() ? 1 : 0); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->first_demangled_name(buf); - if (__left_->is_array()) - { - strncpy(buf, " (&&", 4); - buf += 4; - } - else - { - *buf++ = '&'; - *buf++ = '&'; - } - return buf; - } - virtual char* second_demangled_name(char* buf) const - { - if (__left_->is_array()) - *buf++ = ')'; - return __left_->second_demangled_name(buf); - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __left_->is_function(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } - virtual size_t list_len() const - { - return __left_->list_len(); - } -}; - -class __d_complex - : public __node -{ - static const size_t n = sizeof(" complex") - 1; -public: - - explicit __d_complex(__node* type) - { - __left_ = type; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __left_->size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - strncpy(buf, " complex", n); - return buf + n; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } -}; - -class __imaginary - : public __node -{ - static const size_t n = sizeof(" imaginary") - 1; -public: - - explicit __imaginary(__node* type) - { - __left_ = type; - } - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(n + __left_->size()); - return static_cast<size_t>(__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 (static_cast<size_t>(last - t) >= n) { - if (__left_->is_sub() || len == 1) - off = __left_->size(); + typename C::String r(t, n); + if (r.substr(0, 10) == "_GLOBAL__N") + db.names.push_back("(anonymous namespace)"); else - { - __node* top = __left_; - __node* bottom = top; - while (!bottom->__left_->is_sub()) - bottom = bottom->__left_; - __node* sub = bottom->__left_; - __node* i = sub->__left_; - bool first = true; - top->reset_cached_size(); - while (i) - { - if (!first) - off += 2; - bottom->__left_ = i->__left_; - off += top->size(); - top->reset_cached_size(); - i = i->__right_; - first = false; - } - bottom->__left_ = sub; - } - } - const_cast<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__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; + db.names.push_back(std::move(r)); + first = t + n; } } - 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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__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<size_t>(__last - __first); - } - - virtual size_t first_size() const - { - return __size_+19; - } - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "(unsigned __int128)", 19); - buf += 19; - strncpy(buf, __name_, __size_); - return buf + __size_; - } -}; - -class __float_literal - : public __node -{ -public: - explicit __float_literal(float value) - { - __value_ = value; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - char num[20] = {0}; - float v = static_cast<float>(__value_); - const_cast<long&>(__cached_size_) = sprintf(num, "%a", v)+1; - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - char num[20] = {0}; - float v = static_cast<float>(__value_); - int n = sprintf(num, "%a", v); - strncpy(buf, num, static_cast<size_t>(n)); - buf += n; - *buf++ = 'f'; - return buf; - } -}; - -class __float - : public __node -{ - static const size_t n = sizeof("float") - 1; -public: - - virtual size_t first_size() const {return n;} - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "float", n); - return buf + n; - } -}; - -class __double_literal - : public __node -{ -public: - explicit __double_literal(double value) - { - __value_ = value; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - char num[30] = {0}; - double v = static_cast<double>(__value_); - const_cast<long&>(__cached_size_) = sprintf(num, "%a", v); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - char num[30] = {0}; - double v = static_cast<double>(__value_); - int n = sprintf(num, "%a", v); - strncpy(buf, num, static_cast<size_t>(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<size_t>(snprintf(0, 0, "%ld", __size_)); - const_cast<long&>(__cached_size_) = static_cast<long>(r); - } - return static_cast<size_t>(__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<size_t>(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<long&>(__cached_size_) = static_cast<long>(__left_->size() + 3 - + __right_->first_size() - + __right_->second_size()); - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __right_->first_demangled_name(buf); - buf = __left_->get_demangled_name(buf); - *buf++ = ':'; - *buf++ = ':'; - *buf++ = '*'; - return __right_->second_demangled_name(buf); } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool is_reference_or_pointer_to_function_or_array() const - { - return __right_->is_function(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end) && - __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __decltype_node - : public __node -{ -public: - - explicit __decltype_node(__node* expr) - { - __right_ = expr; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(10 + __right_->size()); - return static_cast<size_t>(__cached_size_); - } - - virtual char* first_demangled_name(char* buf) const - { - strncpy(buf, "decltype(", 9); - buf += 9; - buf = __right_->get_demangled_name(buf); - *buf++ = ')'; - return buf; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __nested_delimeter - : public __node -{ -public: - - explicit __nested_delimeter(__node* prev, __node* arg) - { - __left_ = prev; - __right_ = arg; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__left_->size() + - __right_->size() + 2); - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>((__left_ ? - __left_->size() + 2 : 0) + - __right_->size() + __size_ * 2); - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>(__right_->base_size()); - return static_cast<size_t>(__cached_size_); - } - - virtual char* first_demangled_name(char* buf) const - { - return __right_->get_base_name(buf); - } - virtual __node* base_name() const - { - return __right_->base_name(); - } - virtual bool ends_with_template(bool parsing = false) const - { - return __right_->ends_with_template(parsing); - } - virtual bool is_ctor_dtor_conv() const - { - return true; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __right_->fix_forward_references(t_begin, t_end); - } -}; - -class __destructor - : public __node -{ -public: - - explicit __destructor(__node* name) - { - __right_ = name; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - const_cast<long&>(__cached_size_) = static_cast<long>(__right_->base_size() + 1); - return static_cast<size_t>(__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<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - buf = __left_->get_demangled_name(buf); - *buf++ = ' '; - *buf++ = '('; - strncpy(buf, __name_, __size_); - buf += __size_; - *buf++ = ')'; - return buf; - } - virtual __node* base_name() const - { - return __left_->base_name(); - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - return __left_->fix_forward_references(t_begin, t_end); - } -}; - -class __vector_type - : public __node -{ -public: - __vector_type(__node* type, const char* num, size_t sz) - { - __left_ = type; - __name_ = num; - __size_ = sz; - } - - __vector_type(__node* type, __node* num) - { - __left_ = type; - __right_ = num; - } - - virtual size_t first_size() const - { - if (__cached_size_ == -1) - { - size_t off = 5; - if (__left_) - off = __left_->size(); - off += 9; - if (__right_) - off += __right_->size(); - else if (__size_ > 0) - off += __size_; - const_cast<long&>(__cached_size_) = static_cast<long>(off); - } - return static_cast<size_t>(__cached_size_); - } - virtual char* first_demangled_name(char* buf) const - { - if (__left_) - buf = __left_->get_demangled_name(buf); - else - { - strncpy(buf, "pixel", 5); - buf += 5; - } - strncpy(buf, " vector[", 8); - buf += 8; - if (__right_) - buf = __right_->get_demangled_name(buf); - else if (__size_ > 0) - { - strncpy(buf, __name_, __size_); - buf += __size_; - } - *buf++ = ']'; - return buf; - } - virtual __node* base_name() const - { - if (__left_) - return __left_->base_name(); - return __left_; - } - virtual bool fix_forward_references(__node** t_begin, __node** t_end) - { - bool r = true; - if (__left_) - r = __left_->fix_forward_references(t_begin, t_end); - if (__right_) - r = r && __right_->fix_forward_references(t_begin, t_end); - return r; - } -}; - - -enum {invalid_args = -3, invalid_mangled_name, memory_alloc_failure, success, - not_yet_implemented}; - -__demangle_tree::__demangle_tree(const char* mangled_name, char* buf, size_t bs) - : __mangled_name_begin_(0), __mangled_name_end_(0), - __status_(invalid_mangled_name), __root_(0), - __node_begin_(0), __node_end_(0), __node_cap_(0), - __sub_begin_(0), __sub_end_(0), __sub_cap_(0), - __t_begin_(0), __t_end_(0), __t_cap_(0), - __tag_templates_(true), - __fix_forward_references_(false) -{ - size_t n = strlen(mangled_name); - size_t ms = n + 2*n*sizeof(__node) + 2*n*sizeof(__node*); - char* m; - if (ms <= bs) - { - m = buf; - __owns_buf_ = false; - } - else - { - m = static_cast<char*>(malloc(ms)); - __owns_buf_ = true; - } - if (m == NULL) - { - __status_ = memory_alloc_failure; - return; - } - __node_begin_ = __node_end_ = (__node*)(m); - __node_cap_ = __node_begin_ + 2*n; - __sub_begin_ = __sub_end_ = (__node**)(__node_cap_); - __sub_cap_ = __sub_begin_ + n; - __t_begin_ = __t_end_ = (__node**)(__sub_cap_); - __t_cap_ = __t_begin_ + n; - __mangled_name_begin_ = (const char*)(__t_cap_); - __mangled_name_end_ = __mangled_name_begin_ + n; - strncpy(const_cast<char*>(__mangled_name_begin_), mangled_name, n); -} - -__demangle_tree::~__demangle_tree() -{ - if (__owns_buf_) - free(__node_begin_); -} - -__demangle_tree::__demangle_tree(__demangle_tree& t) - : __mangled_name_begin_(t.__mangled_name_begin_), - __mangled_name_end_(t.__mangled_name_end_), - __status_(t.__status_), __root_(t.__root_), - __node_begin_(t.__node_begin_), __node_end_(t.__node_end_), - __node_cap_(t.__node_cap_), - __sub_begin_(t.__sub_begin_), __sub_end_(t.__sub_end_), - __sub_cap_(t.__sub_cap_), - __t_begin_(t.__t_begin_), __t_end_(t.__t_end_), - __t_cap_(t.__t_cap_), - __tag_templates_(t.__tag_templates_), - __fix_forward_references_(t.__fix_forward_references_), - __owns_buf_(t.__owns_buf_) -{ - t.__mangled_name_begin_ = 0; - t.__mangled_name_end_ = 0; - t.__status_ = invalid_mangled_name; - t.__root_ = 0; - t.__node_begin_ = t.__node_end_ = t.__node_cap_ = 0; - t.__sub_begin_ = t.__sub_end_ = t.__sub_cap_ = 0; - t.__t_begin_ = t.__t_end_ = t.__t_cap_ = 0; - t.__owns_buf_ = false; -} - -__demangle_tree::__demangle_tree(__demangle_tree_rv rv) - : __mangled_name_begin_(rv.ptr_->__mangled_name_begin_), - __mangled_name_end_(rv.ptr_->__mangled_name_end_), - __status_(rv.ptr_->__status_), __root_(rv.ptr_->__root_), - __node_begin_(rv.ptr_->__node_begin_), __node_end_(rv.ptr_->__node_end_), - __node_cap_(rv.ptr_->__node_cap_), - __sub_begin_(rv.ptr_->__sub_begin_), __sub_end_(rv.ptr_->__sub_end_), - __sub_cap_(rv.ptr_->__sub_cap_), - __t_begin_(rv.ptr_->__t_begin_), __t_end_(rv.ptr_->__t_end_), - __t_cap_(rv.ptr_->__t_cap_), - __tag_templates_(rv.ptr_->__tag_templates_), - __fix_forward_references_(rv.ptr_->__fix_forward_references_), - __owns_buf_(rv.ptr_->__owns_buf_) -{ - rv.ptr_->__mangled_name_begin_ = 0; - rv.ptr_->__mangled_name_end_ = 0; - rv.ptr_->__status_ = invalid_mangled_name; - rv.ptr_->__root_ = 0; - rv.ptr_->__node_begin_ = rv.ptr_->__node_end_ = rv.ptr_->__node_cap_ = 0; - rv.ptr_->__sub_begin_ = rv.ptr_->__sub_end_ = rv.ptr_->__sub_cap_ = 0; - rv.ptr_->__t_begin_ = rv.ptr_->__t_end_ = rv.ptr_->__t_cap_ = 0; - rv.ptr_->__owns_buf_ = false; -} - -int -__demangle_tree::__status() const -{ - return __status_; -} - -size_t -__demangle_tree::size() const -{ - return __status_ == success ? __root_->size() : 0; -} - -char* -__demangle_tree::__get_demangled_name(char* buf) const -{ - if (__status_ == success) - return __root_->get_demangled_name(buf); - return 0; -} - -template <class _Tp> -bool -__demangle_tree::__make() -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0> -bool -__demangle_tree::__make(_A0 __a0) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0, class _A1> -bool -__demangle_tree::__make(_A0 __a0, _A1 __a1) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0, __a1); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0, class _A1, class _A2> -bool -__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0, __a1, __a2); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0, class _A1, class _A2, class _A3> -bool -__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4> -bool -__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; -} - -template <class _Tp, class _A0, class _A1, class _A2, class _A3, class _A4, - class _A5> -bool -__demangle_tree::__make(_A0 __a0, _A1 __a1, _A2 __a2, _A3 __a3, _A4 __a4, - _A5 __a5) -{ - if (__node_end_ < __node_cap_) - { - ::new (__node_end_) _Tp(__a0, __a1, __a2, __a3, __a4, __a5); - __root_ = __node_end_; - ++__node_end_; - return true; - } - __status_ = memory_alloc_failure; - return false; + return first; } -// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const -// [R | O] # & or && +// <substitution> ::= S <seq-id> _ +// ::= S_ +// <substitution> ::= Sa # ::std::allocator +// <substitution> ::= Sb # ::std::basic_string +// <substitution> ::= Ss # ::std::basic_string < char, +// ::std::char_traits<char>, +// ::std::allocator<char> > +// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > +// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > +// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > +template <class C> const char* -__demangle_tree::__parse_cv_qualifiers(const char* first, const char* last, - unsigned& cv, bool look_for_ref_quals) +parse_substitution(const char* first, const char* last, C& db) { - if (look_for_ref_quals) + if (last - first >= 2) { - for (; first != last; ++first) + if (*first == 'S') { - switch (*first) + switch (first[1]) { - case 'r': - cv |= 4; - break; - case 'V': - cv |= 2; + case 'a': + db.names.push_back("std::allocator"); + first += 2; break; - case 'K': - cv |= 1; + case 'b': + db.names.push_back("std::basic_string"); + first += 2; break; - case 'R': - cv |= 8; + case 's': + db.names.push_back("std::string"); + first += 2; break; - case 'O': - cv |= 16; + case 'i': + db.names.push_back("std::istream"); + first += 2; break; - default: - return first; - } - } - } - else - { - for (; first != last; ++first) - { - switch (*first) - { - case 'r': - cv |= 4; + case 'o': + db.names.push_back("std::ostream"); + first += 2; break; - case 'V': - cv |= 2; + case 'd': + db.names.push_back("std::iostream"); + first += 2; break; - case 'K': - cv |= 1; + case '_': + if (!db.subs.empty()) + { + for (const auto& n : db.subs.front()) + db.names.push_back(n); + first += 2; + } break; default: - return first; + 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<size_t>(*t - '0'); + else + sub = static_cast<size_t>(*t - 'A') + 10; + for (++t; t != last && (std::isdigit(*t) || std::isupper(*t)); ++t) + { + sub *= 36; + if (std::isdigit(*t)) + sub += static_cast<size_t>(*t - '0'); + else + sub += static_cast<size_t>(*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; } } } @@ -6476,96 +355,104 @@ __demangle_tree::__parse_cv_qualifiers(const char* first, const char* last, // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) // ::= u <source-name> # vendor extended type +template <class C> const char* -__demangle_tree::__parse_builtin_type(const char* first, const char* last) +parse_builtin_type(const char* first, const char* last, C& db) { if (first != last) { switch (*first) { case 'v': - if (__make<__void>()) - ++first; + db.names.push_back("void"); + ++first; break; case 'w': - if (__make<__wchar_t>()) - ++first; + db.names.push_back("wchar_t"); + ++first; break; case 'b': - if (__make<__bool>()) - ++first; + db.names.push_back("bool"); + ++first; break; case 'c': - if (__make<__char>()) - ++first; + db.names.push_back("char"); + ++first; break; case 'a': - if (__make<__signed_char>()) - ++first; + db.names.push_back("signed char"); + ++first; break; case 'h': - if (__make<__unsigned_char>()) - ++first; + db.names.push_back("unsigned char"); + ++first; break; case 's': - if (__make<__short>()) - ++first; + db.names.push_back("short"); + ++first; break; case 't': - if (__make<__unsigned_short>()) - ++first; + db.names.push_back("unsigned short"); + ++first; break; case 'i': - if (__make<__int>()) - ++first; + db.names.push_back("int"); + ++first; break; case 'j': - if (__make<__unsigned_int>()) - ++first; + db.names.push_back("unsigned int"); + ++first; break; case 'l': - if (__make<__long>()) - ++first; + db.names.push_back("long"); + ++first; break; case 'm': - if (__make<__unsigned_long>()) - ++first; + db.names.push_back("unsigned long"); + ++first; break; case 'x': - if (__make<__long_long>()) - ++first; + db.names.push_back("long long"); + ++first; break; case 'y': - if (__make<__unsigned_long_long>()) - ++first; + db.names.push_back("unsigned long long"); + ++first; break; case 'n': - if (__make<__signed_int128>()) - ++first; + db.names.push_back("__int128"); + ++first; break; case 'o': - if (__make<__unsigned_int128>()) - ++first; + db.names.push_back("unsigned __int128"); + ++first; break; case 'f': - if (__make<__float>()) - ++first; + db.names.push_back("float"); + ++first; break; case 'd': - if (__make<__double>()) - ++first; + db.names.push_back("double"); + ++first; break; case 'e': - if (__make<__long_double>()) - ++first; + db.names.push_back("long double"); + ++first; break; case 'g': - if (__make<__float128>()) - ++first; + db.names.push_back("__float128"); + ++first; break; case 'z': - if (__make<__ellipsis>()) - ++first; + 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) @@ -6573,36 +460,36 @@ __demangle_tree::__parse_builtin_type(const char* first, const char* last) switch (first[1]) { case 'd': - if (__make<__decimal64>()) - first += 2; + db.names.push_back("decimal64"); + first += 2; break; case 'e': - if (__make<__decimal128>()) - first += 2; + db.names.push_back("decimal128"); + first += 2; break; case 'f': - if (__make<__decimal32>()) - first += 2; + db.names.push_back("decimal32"); + first += 2; break; case 'h': - if (__make<__decimal16>()) - first += 2; + db.names.push_back("decimal16"); + first += 2; break; case 'i': - if (__make<__d_char32_t>()) - first += 2; + db.names.push_back("char32_t"); + first += 2; break; case 's': - if (__make<__d_char16_t>()) - first += 2; + db.names.push_back("char16_t"); + first += 2; break; case 'a': - if (__make<__auto>()) - first += 2; + db.names.push_back("auto"); + first += 2; break; case 'n': - if (__make<__nullptr_t>()) - first += 2; + db.names.push_back("std::nullptr_t"); + first += 2; break; } } @@ -6612,794 +499,316 @@ __demangle_tree::__parse_builtin_type(const char* first, const char* last) return first; } -// <bare-function-type> ::= <signature type>+ -// # types are possible return type, then parameter types +// <CV-qualifiers> ::= [r] [V] [K] const char* -__demangle_tree::__parse_bare_function_type(const char* first, const char* last) +parse_cv_qualifiers(const char* first, const char* last, unsigned& cv) { + cv = 0; 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_)) + if (*first == 'r') { - 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; - } - } + cv |= 4; + ++first; } - __tag_templates_ = prev_tag_templates; - } - return first; -} - -// <function-type> ::= F [Y] <bare-function-type> E - -const char* -__demangle_tree::__parse_function_type(const char* first, const char* last) -{ - if (first != last && *first == 'F') - { - const char* t = first+1; - if (t != last) + if (*first == 'V') { - 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; - } - } - } + cv |= 2; + ++first; + } + if (*first == 'K') + { + cv |= 1; + ++first; } } 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<unsigned long long>(*t - '0'); - else if (isupper(*t)) - n = n * 16 + static_cast<unsigned long long>(*t - 'A') + 10; - else - n = n * 16 + static_cast<unsigned long long>(*t - 'a') + 10; - } - first = t; - return first; -} - -// <expr-primary> ::= L <type> <value number> E # integer literal -// ::= L <type> <value float> E # floating literal -// ::= L <string type> E # string literal -// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") -// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) -// ::= L <mangled-name> E # external name +// <template-param> ::= T_ # first template parameter +// ::= T <parameter-2 non-negative number> _ +template <class C> const char* -__demangle_tree::__parse_expr_primary(const char* first, const char* last) +parse_template_param(const char* first, const char* last, C& db) { - if (last - first >= 4 && *first == 'L') + if (last - first >= 2) { - switch (first[1]) + if (*first == 'T') { - 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': + if (first[1] == '_') { - const char* t = __parse_number(first+2, last); - if (t != first+2 && t != last && *t == 'E') + if (db.template_param.empty()) + return first; + if (!db.template_param.back().empty()) { - if (__make<__unsigned_long_long_literal>(first+2, t)) - first = t+1; + for (auto& t : db.template_param.back().front()) + db.names.push_back(t); + first += 2; } - } - break; - case 'n': - { - const char* t = __parse_number(first+2, last); - if (t != first+2 && t != last && *t == 'E') + else { - if (__make<__int128_literal>(first+2, t)) - first = t+1; + db.names.push_back("T_"); + first += 2; + db.fix_forward_references = true; } } - break; - case 'o': + else if (isdigit(first[1])) { - const char* t = __parse_number(first+2, last); - if (t != first+2 && t != last && *t == 'E') + const char* t = first+1; + size_t sub = static_cast<size_t>(*t - '0'); + for (++t; t != last && isdigit(*t); ++t) { - if (__make<__unsigned_int128_literal>(first+2, t)) - first = t+1; + sub *= 10; + sub += static_cast<size_t>(*t - '0'); } - } - break; - case 'f': - { - if (last - (first+2) <= 8) + if (t == last || *t != '_' || db.template_param.empty()) 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') + ++sub; + if (sub < db.template_param.back().size()) { - unsigned i = static_cast<unsigned>(j); - float value = *(float*)&i; - if (__make<__float_literal>(value)) - first = t+1; + for (auto& temp : db.template_param.back()[sub]) + db.names.push_back(temp); + 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') + else { - 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') + db.names.push_back(typename C::String(first, t+1)); 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; - } + db.fix_forward_references = true; } } -// assert(!"case in __parse_expr_primary not implemented"); - __status_ = not_yet_implemented; } } return first; } -// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ -// ::= <closure-type-name> -// -// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ -// -// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters +// cc <type> <expression> # const_cast<type> (expression) +template <class C> const char* -__demangle_tree::__parse_unnamed_type_name(const char* first, const char* last) +parse_const_cast_expr(const char* first, const char* last, C& db) { - if (last - first > 2 && first[0] == 'U') + if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') { - char type = first[1]; - switch (type) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - 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<size_t>(number_end - number_start))) - return first; - } - else + const char* t1 = parse_expression(t, last, db); + if (t1 != t) { - if (!__make<__unnamed>(number_start, static_cast<size_t>(number_end - number_start))) + 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; } - first = t; - } - break; } } return first; } -// <ctor-dtor-name> ::= C1 # complete object constructor -// ::= C2 # base object constructor -// ::= C3 # complete object allocating constructor -// ::= D0 # deleting destructor -// ::= D1 # complete object destructor -// ::= D2 # base object destructor +// dc <type> <expression> # dynamic_cast<type> (expression) +template <class C> const char* -__demangle_tree::__parse_ctor_dtor_name(const char* first, const char* last) +parse_dynamic_cast_expr(const char* first, const char* last, C& db) { - if (last-first >= 2 && __root_) + if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') { - switch (first[0]) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - 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]) + const char* t1 = parse_expression(t, last, db); + if (t1 != t) { - case '0': - case '1': - case '2': - if (__make<__destructor>(__root_->base_name())) - first += 2; - break; + 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; } - 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; -} - -// <discriminator> := _ <non-negative number> # when number < 10 -// := __ <non-negative number> _ # when number >= 10 -// extension := decimal-digit+ +// rc <type> <expression> # reinterpret_cast<type> (expression) +template <class C> const char* -__demangle_tree::__parse_discriminator(const char* first, const char* last) +parse_reinterpret_cast_expr(const char* first, const char* last, C& db) { - // parse but ignore discriminator - if (first != last) + if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') { - if (*first == '_') + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - const char* t1 = first+1; - if (t1 != last) + const char* t1 = parse_expression(t, last, db); + if (t1 != t) { - if (isdigit(*t1)) - first = t1+1; - else if (*t1 == '_') - { - for (++t1; t1 != last && isdigit(*t1); ++t1) - ; - if (t1 != last && *t1 == '_') - first = t1 + 1; - } + 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; } } - else if (isdigit(*first)) - { - const char* t1 = first+1; - for (; t1 != last && isdigit(*t1); ++t1) - ; - first = t1; - } } return first; } -// <local-name> := Z <function encoding> E <entity name> [<discriminator>] -// := Z <function encoding> E s [<discriminator>] -// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> +// sc <type> <expression> # static_cast<type> (expression) +template <class C> const char* -__demangle_tree::__parse_local_name(const char* first, const char* last) +parse_static_cast_expr(const char* first, const char* last, C& db) { - if (first != last && *first == 'Z') + if (last - first >= 3 && first[0] == 's' && first[1] == 'c') { - const char* t = __parse_encoding(first+1, last); - if (t != first+1 && t != last && *t == 'E' && ++t != last) + const char* t = parse_type(first+2, last, db); + if (t != first+2) { - __node* encoding = __root_; - switch (*t) + const char* t1 = parse_expression(t, last, db); + if (t1 != 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; + 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 first; } -// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) -// ::= <simple-id> # e.g., ~A<2*N> +// sp <expression> # pack expansion +template <class C> const char* -__demangle_tree::__parse_destructor_name(const char* first, const char* last) +parse_pack_expansion(const char* first, const char* last, C& db) { - if (first != last) + if (last - first >= 3 && first[0] == 's' && first[1] == 'p') { - const char* t = __parse_unresolved_type(first, last); - if (t == first) - t = __parse_simple_id(first, last); - if (t != first && __make<__destructor>(__root_)) + const char* t = parse_expression(first+2, last, db); + if (t != first+2) first = t; } return first; } -// <simple-id> ::= <source-name> [ <template-args> ] +// st <type> # sizeof (a type) +template <class C> const char* -__demangle_tree::__parse_simple_id(const char* first, const char* last) +parse_sizeof_type_expr(const char* first, const char* last, C& db) { - if (first != last) + if (last - first >= 3 && first[0] == 's' && first[1] == 't') { - const char* t = __parse_source_name(first, last); - if (t != first) - first = __parse_template_args(t, last); - else + const char* t = parse_type(first+2, last, db); + if (t != first+2) + { + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; first = t; + } } return first; } -// <base-unresolved-name> ::= <simple-id> # unresolved name -// extension ::= <operator-name> # unresolved operator-function-id -// extension ::= <operator-name> <template-args> # unresolved operator template-id -// ::= on <operator-name> # unresolved operator-function-id -// ::= on <operator-name> <template-args> # unresolved operator template-id -// ::= dn <destructor-name> # destructor or pseudo-destructor; -// # e.g. ~X or ~X<N-1> +// sz <expr> # sizeof (a expression) +template <class C> const char* -__demangle_tree::__parse_base_unresolved_name(const char* first, const char* last) +parse_sizeof_expr_expr(const char* first, const char* last, C& db) { - if (last - first >= 2) + if (last - first >= 3 && first[0] == 's' && first[1] == 'z') { - 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_expression(first+2, last, db); + if (t != first+2) { - 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; + if (db.names.empty()) + return first; + db.names.back() = "sizeof (" + db.names.back().move_full() + ")"; + first = t; } } return first; } -// <unresolved-type> ::= <template-param> -// ::= <decltype> -// ::= <substitution> +// sZ <template-param> # size of a parameter pack +template <class C> const char* -__demangle_tree::__parse_unresolved_type(const char* first, const char* last) +parse_sizeof_param_pack_expr(const char* first, const char* last, C& db) { - if (first != last) + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') { - const char* t; - switch (*first) + 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) { - case 'T': - t = __parse_template_param(first, last); - if (t != first) + typename C::String tmp("sizeof...("); + size_t k = k0; + if (k != k1) { - 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; - } + tmp += db.names[k].move_full(); + for (++k; k != k1; ++k) + tmp += ", " + db.names[k].move_full(); } - break; - case 'S': - t = __parse_substitution(first, last); - if (t != first) - first = t; - break; + tmp += ")"; + for (; k1 != k0; --k1) + db.names.pop_back(); + db.names.push_back(std::move(tmp)); + first = t; } } return first; } -// <unresolved-qualifier-level> ::= <source-name> [ <template-args> ] - -const char* -__demangle_tree::__parse_unresolved_qualifier_level(const char* first, const char* last) -{ - if (first != last) - { - const char* t = __parse_source_name(first, last); - if (t != first) - first = __parse_template_args(t, last); - } - return first; -} - -// <unresolved-name> -// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> -// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x -// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> -// # A::x, N::y, A<T>::z; "gs" means leading "::" -// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x -// # T::N::x /decltype(p)::N::x -// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> +// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter +// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter +// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L > 0, second and later parameters +template <class C> const char* -__demangle_tree::__parse_unresolved_name(const char* first, const char* last) +parse_function_param(const char* first, const char* last, C& db) { - if (last - first > 2) + if (last - first >= 3 && *first == 'f') { - 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 (first[1] == 'p') { - if (!global && t[2] == 'N') + unsigned cv; + const char* t = parse_cv_qualifiers(first+2, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') { - 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; - } + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+1; } - else + } + else if (first[1] == 'L') + { + unsigned cv; + const char* t0 = parse_number(first+2, last); + if (t0 != last && *t0 == 'p') { - 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) + ++t0; + const char* t = parse_cv_qualifiers(t0, last, cv); + const char* t1 = parse_number(t, last); + if (t1 != last && *t1 == '_') { - __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; + db.names.push_back("fp" + typename C::String(t, t1)); + first = t1+1; } } } @@ -7407,256 +816,438 @@ __demangle_tree::__parse_unresolved_name(const char* first, const char* last) return first; } -// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, first parameter -// ::= fp <top-level CV-qualifiers> <parameter-2 non-negative number> _ # L == 0, second and later parameters -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> _ # L > 0, first parameter -// ::= fL <L-1 non-negative number> p <top-level CV-qualifiers> +// sZ <function-param> # size of a function parameter pack +template <class C> const char* -__demangle_tree::__parse_function_param(const char* first, const char* last) +parse_sizeof_function_param_pack_expr(const char* first, const char* last, C& db) { - if (last - first >= 3 && *first == 'f') + if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') { - if (first[1] == 'p') + const char* t = parse_function_param(first+2, last, db); + if (t != first+2) { -// assert(!"__parse_function_param not implemented"); - __status_ = not_yet_implemented; + if (db.names.empty()) + return first; + db.names.back() = "sizeof...(" + db.names.back().move_full() + ")"; + first = t; } - else if (first[1] == 'L') + } + return first; +} + +// te <expression> # typeid (expression) +// ti <type> # typeid (type) + +template <class C> +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')) + { + 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) { -// assert(!"__parse_function_param not implemented"); - __status_ = not_yet_implemented; + if (db.names.empty()) + return first; + db.names.back() = "typeid(" + db.names.back().move_full() + ")"; + first = t; } } return first; } -// at <type> # alignof (a type) +// tw <expression> # throw expression +template <class C> const char* -__demangle_tree::__parse_alignof_expr(const char* first, const char* last) +parse_throw_expr(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 'a' && first[1] == 't') + if (last - first >= 3 && first[0] == 't' && first[1] == 'w') { - const char* t = __parse_type(first+2, last); + const char* t = parse_expression(first+2, last, db); if (t != first+2) { - if (__make<__operator_alignof_expression>(__root_)) - first = t; + if (db.names.empty()) + return first; + db.names.back() = "throw " + db.names.back().move_full(); + first = t; } } return first; } -// cc <type> <expression> # const_cast<type> (expression) +// ds <expression> <expression> # expr.*expr +template <class C> const char* -__demangle_tree::__parse_const_cast_expr(const char* first, const char* last) +parse_dot_star_expr(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 'c' && first[1] == 'c') + if (last - first >= 3 && first[0] == 'd' && first[1] == 's') { - const char* t = __parse_type(first+2, last); + const char* t = parse_expression(first+2, last, db); if (t != first+2) { - __node* type = __root_; - const char* t1 = __parse_expression(t, last); + const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (__make<__const_cast>(type, __root_)) - first = t1; + 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; } } } return first; } -// cl <expression>+ E # call +// <simple-id> ::= <source-name> [ <template-args> ] +template <class C> const char* -__demangle_tree::__parse_call_expr(const char* first, const char* last) +parse_simple_id(const char* first, const char* last, C& db) { - if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') + if (first != last) { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + const char* t = parse_source_name(first, last, db); + if (t != first) { - if (t == last) - return first; - __node* name = __root_; - __node* args = 0; - __node* prev = 0; - while (*t != 'E') + const char* t1 = parse_template_args(t, last, db); + if (t1 != t) { - const char* t1 = __parse_expression(t, last); - if (t1 == t || t1 == last) - return first; - if (!__make<__list>(__root_)) + if (db.names.size() < 2) return first; - if (args == 0) - args = __root_; - if (prev) - { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; - } - prev = __root_; - t = t1; + auto args = db.names.back().move_full(); + db.names.pop_back(); + db.names.back().first += std::move(args); } - ++t; - if (__make<__call_expr>(name, args)) - first = t; + first = t1; } + else + first = t; } return first; } -// cv <type> <expression> # conversion with one argument -// cv <type> _ <expression>* E # conversion with a different number of arguments +// <unresolved-type> ::= <template-param> +// ::= <decltype> +// ::= <substitution> +template <class C> const char* -__demangle_tree::__parse_conversion_expr(const char* first, const char* last) +parse_unresolved_type(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') + if (first != last) { - const char* t = __parse_type(first+2, last); - if (t != first+2 && t != last) + const char* t = first; + switch (*first) { - __node* type = __root_; - __node* args = 0; - if (*t != '_') + 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) { - const char* t1 = __parse_expression(t, last); - if (t1 == t) - return first; - args = __root_; - t = t1; + db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator())); + first = t; } else { - ++t; - if (t == last) + 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; - __node* prev = 0; - while (*t != 'E') + 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') { - 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) + t = parse_unqualified_name(first+2, last, db); + if (t != first+2) { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; + 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; } - prev = __root_; - t = t1; } - ++t; } - if (__make<__operator_cast>(type, args)) - first = t; - } + break; + } } return first; } -// [gs] da <expression> # delete[] expression +// <destructor-name> ::= <unresolved-type> # e.g., ~T or ~decltype(f()) +// ::= <simple-id> # e.g., ~A<2*N> +template <class C> const char* -__demangle_tree::__parse_delete_array_expr(const char* first, const char* last) +parse_destructor_name(const char* first, const char* last, C& db) { - if (last - first >= 4) + if (first != last) { - 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') + const char* t = parse_unresolved_type(first, last, db); + if (t == first) + t = parse_simple_id(first, last, db); + if (t != first) { - t += 2; - const char* t1 = __parse_expression(t, last); - if (t1 != t) - { - if (__make<__delete_array_expr>(parsed_gs, __root_)) - first = t1; - } + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "~"); + first = t; } } return first; } -// dc <type> <expression> # dynamic_cast<type> (expression) +// <base-unresolved-name> ::= <simple-id> # unresolved name +// extension ::= <operator-name> # unresolved operator-function-id +// extension ::= <operator-name> <template-args> # unresolved operator template-id +// ::= on <operator-name> # unresolved operator-function-id +// ::= on <operator-name> <template-args> # unresolved operator template-id +// ::= dn <destructor-name> # destructor or pseudo-destructor; +// # e.g. ~X or ~X<N-1> +template <class C> const char* -__demangle_tree::__parse_dynamic_cast_expr(const char* first, const char* last) +parse_base_unresolved_name(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 'd' && first[1] == 'c') + if (last - first >= 2) { - const char* t = __parse_type(first+2, last); - if (t != first+2) + if ((first[0] == 'o' || first[0] == 'd') && first[1] == 'n') { - __node* type = __root_; - const char* t1 = __parse_expression(t, last); - if (t1 != t) + if (first[0] == 'o') { - if (__make<__dynamic_cast>(type, __root_)) - first = t1; + 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 char* t = parse_destructor_name(first+2, last, db); + if (t != first+2) + first = t; + } + } + else + { + 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 first; } -// [gs] dl <expression> # delete expression +// <unresolved-qualifier-level> ::= <simple-id> +template <class C> const char* -__demangle_tree::__parse_delete_expr(const char* first, const char* last) +parse_unresolved_qualifier_level(const char* first, const char* last, C& db) { - if (last - first >= 4) + return parse_simple_id(first, last, db); +} + +// <unresolved-name> +// extension ::= srN <unresolved-type> [<template-args>] <unresolved-qualifier-level>* E <base-unresolved-name> +// ::= [gs] <base-unresolved-name> # x or (with "gs") ::x +// ::= [gs] sr <unresolved-qualifier-level>+ E <base-unresolved-name> +// # A::x, N::y, A<T>::z; "gs" means leading "::" +// ::= sr <unresolved-type> <base-unresolved-name> # T::x / decltype(p)::x +// extension ::= sr <unresolved-type> <template-args> <base-unresolved-name> +// # T::N::x /decltype(p)::N::x +// (ignored) ::= srN <unresolved-type> <unresolved-qualifier-level>+ E <base-unresolved-name> + +template <class C> +const char* +parse_unresolved_name(const char* first, const char* last, C& db) +{ + if (last - first > 2) { const char* t = first; - bool parsed_gs = false; + bool global = false; if (t[0] == 'g' && t[1] == 's') { + global = true; t += 2; - parsed_gs = true; } - if (t[0] == 'd' && t[1] == 'l') + const char* t2 = parse_base_unresolved_name(t, last, db); + if (t2 != t) { - t += 2; - const char* t1 = __parse_expression(t, last); - if (t1 != t) + if (global) { - if (__make<__delete_expr>(parsed_gs, __root_)) - first = t1; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "::"); } + first = t2; } - } - return first; -} - -// ds <expression> <expression> # expr.*expr - -const char* -__demangle_tree::__parse_dot_star_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 'd' && first[1] == 's') - { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + else if (last - t > 2 && t[0] == 's' && t[1] == 'r') { - __node* expr = __root_; - const char* t1 = __parse_expression(t, last); - if (t1 != t) + 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 { - if (__make<__dot_star_expr>(expr, __root_)) + 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; + } } } } @@ -7665,55 +1256,76 @@ __demangle_tree::__parse_dot_star_expr(const char* first, const char* last) // dt <expression> <unresolved-name> # expr.name +template <class C> const char* -__demangle_tree::__parse_dot_expr(const char* first, const char* last) +parse_dot_expr(const char* first, const char* last, C& db) { if (last - first >= 3 && first[0] == 'd' && first[1] == 't') { - const char* t = __parse_expression(first+2, last); + const char* t = parse_expression(first+2, last, db); if (t != first+2) { - __node* expr = __root_; - const char* t1 = __parse_unresolved_name(t, last); + const char* t1 = parse_unresolved_name(t, last, db); if (t1 != t) { - if (__make<__dot_expr>(expr, __root_)) - first = t1; + 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 first; } -// mm_ <expression> # prefix -- - -const char* -__demangle_tree::__parse_decrement_expr(const char* first, const char* last) -{ - if (last - first > 3 && first[0] == 'm' && first[1] == 'm' && first[2] == '_') - { - const char* t = __parse_expression(first+3, last); - if (t != first+3) - { - if (__make<__operator_decrement>(true, __root_)) - first = t; - } - } - return first; -} - -// pp_ <expression> # prefix ++ +// cl <expression>+ E # call +template <class C> const char* -__demangle_tree::__parse_increment_expr(const char* first, const char* last) +parse_call_expr(const char* first, const char* last, C& db) { - if (last - first > 3 && first[0] == 'p' && first[1] == 'p' && first[2] == '_') + if (last - first >= 4 && first[0] == 'c' && first[1] == 'l') { - const char* t = __parse_expression(first+3, last); - if (t != first+3) + const char* t = parse_expression(first+2, last, db); + if (t != first+2) { - if (__make<__operator_increment>(true, __root_)) - first = t; + 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; @@ -7725,8 +1337,9 @@ __demangle_tree::__parse_increment_expr(const char* first, const char* last) // [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) // <initializer> ::= pi <expression>* E # parenthesized initialization +template <class C> const char* -__demangle_tree::__parse_new_expr(const char* first, const char* last) +parse_new_expr(const char* first, const char* last, C& db) { if (last - first >= 4) { @@ -7743,419 +1356,325 @@ __demangle_tree::__parse_new_expr(const char* first, const char* last) t += 2; if (t == last) return first; - __node* expr = 0; - __node* prev = 0; + bool has_expr_list = false; + bool first_expr = true; while (*t != '_') { - const char* t1 = __parse_expression(t, last); + const char* t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!__make<__list>(__root_)) - return first; - if (expr == 0) - expr = __root_; - if (prev) + has_expr_list = true; + if (!first_expr) { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; + 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; + } } - prev = __root_; t = t1; } ++t; - const char* t1 = __parse_type(t, last); + const char* t1 = parse_type(t, last, db); 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; + first_expr = true; while (*t != 'E') { - t1 = __parse_expression(t, last); + t1 = parse_expression(t, last, db); if (t1 == t || t1 == last) return first; - if (!__make<__list>(__root_)) - return first; - if (init == 0) - init = __root_; - if (prev) + if (!first_expr) { - prev->__right_ = __root_; - __root_->__size_ = prev->__size_ + 1; + 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; + } } - prev = __root_; t = t1; } } if (*t != 'E') return first; - if (__make<__new_expr>(parsed_gs, is_array, has_init, - expr, type, init)) - first = t; - } - } - return first; -} - -// pt <expression> <unresolved-name> # expr->name - -const char* -__demangle_tree::__parse_arrow_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 'p' && first[1] == 't') - { - const char* t = __parse_expression(first+2, last); - if (t != first+2) - { - __node* expr = __root_; - const char* t1 = __parse_unresolved_name(t, last); - if (t1 != t) + typename C::String init_list; + if (has_init) { - if (__make<__arrow_expr>(expr, __root_)) - first = t1; + 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 first; } -// rc <type> <expression> # reinterpret_cast<type> (expression) +// cv <type> <expression> # conversion with one argument +// cv <type> _ <expression>* E # conversion with a different number of arguments +template <class C> const char* -__demangle_tree::__parse_reinterpret_cast_expr(const char* first, const char* last) +parse_conversion_expr(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 'r' && first[1] == 'c') + if (last - first >= 3 && first[0] == 'c' && first[1] == 'v') { - const char* t = __parse_type(first+2, last); - if (t != first+2) + 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) { - __node* type = __root_; - const char* t1 = __parse_expression(t, last); - if (t1 != t) + if (*t != '_') { - if (__make<__reinterpret_cast>(type, __root_)) - first = t1; + const char* t1 = parse_expression(t, last, db); + if (t1 == t) + return first; + t = t1; + } + else + { + ++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 first; } -// sc <type> <expression> # static_cast<type> (expression) +// pt <expression> <expression> # expr->name +template <class C> const char* -__demangle_tree::__parse_static_cast_expr(const char* first, const char* last) +parse_arrow_expr(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 's' && first[1] == 'c') + if (last - first >= 3 && first[0] == 'p' && first[1] == 't') { - const char* t = __parse_type(first+2, last); + const char* t = parse_expression(first+2, last, db); if (t != first+2) { - __node* type = __root_; - const char* t1 = __parse_expression(t, last); + const char* t1 = parse_expression(t, last, db); if (t1 != t) { - if (__make<__static_cast>(type, __root_)) - first = t1; + 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 first; } -// st <type> # sizeof (a type) - -const char* -__demangle_tree::__parse_sizeof_type_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 't') - { - const char* t = __parse_type(first+2, last); - if (t != first+2) - { - if (__make<__operator_sizeof_expression>(__root_)) - first = t; - } - } - return first; -} - -// sZ <template-param> # size of a parameter pack - -const char* -__demangle_tree::__parse_sizeof_param_pack_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'T') - { - const char* t = __parse_template_param(first+2, last); - if (t != first+2) - { - if (__make<__operator_sizeof_param_pack>(__root_)) - first = t; - } - } - return first; -} - -// sZ <function-param> # size of a function parameter pack - -const char* -__demangle_tree::__parse_sizeof_function_param_pack_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'Z' && first[2] == 'f') - { - const char* t = __parse_function_param(first+2, last); - if (t != first+2) - { - if (__make<__operator_sizeof_param_pack>(__root_)) - first = t; - } - } - return first; -} - -// sp <expression> # pack expansion - -const char* -__demangle_tree::__parse_pack_expansion(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 's' && first[1] == 'p') - { - const char* t = __parse_expression(first+2, last); - if (t != first+2) - { - if (__make<__pack_expansion>(__root_)) - first = t; - } - } - return first; -} - -// te <expression> # typeid (expression) -// ti <type> # typeid (type) - -const char* -__demangle_tree::__parse_typeid_expr(const char* first, const char* last) -{ - if (last - first >= 3 && first[0] == 't' && (first[1] == 'e' || first[1] == 'i')) - { - const char* t; - if (first[1] == 'e') - t = __parse_expression(first+2, last); - else - t = __parse_type(first+2, last); - if (t != first+2) - { - if (__make<__typeid>(__root_)) - first = t; - } - } - return first; -} +// <ref-qualifier> ::= R # & ref-qualifier +// <ref-qualifier> ::= O # && ref-qualifier -// tw <expression> # throw expression +// <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E +template <class C> const char* -__demangle_tree::__parse_throw_expr(const char* first, const char* last) +parse_function_type(const char* first, const char* last, C& db) { - if (last - first >= 3 && first[0] == 't' && first[1] == 'w') + if (first != last && *first == 'F') { - const char* t = __parse_expression(first+2, last); - if (t != first+2) + const char* t = first+1; + if (t != last) { - if (__make<__throw>(__root_)) + 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 first; } -// <expression> ::= <unary operator-name> <expression> -// ::= <binary operator-name> <expression> <expression> -// ::= <ternary operator-name> <expression> <expression> <expression> -// ::= cl <expression>+ E # call -// ::= cv <type> <expression> # conversion with one argument -// ::= cv <type> _ <expression>* E # conversion with a different number of arguments -// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type -// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) -// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type -// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) -// ::= [gs] dl <expression> # delete expression -// ::= [gs] da <expression> # delete[] expression -// ::= pp_ <expression> # prefix ++ -// ::= mm_ <expression> # prefix -- -// ::= ti <type> # typeid (type) -// ::= te <expression> # typeid (expression) -// ::= dc <type> <expression> # dynamic_cast<type> (expression) -// ::= sc <type> <expression> # static_cast<type> (expression) -// ::= cc <type> <expression> # const_cast<type> (expression) -// ::= rc <type> <expression> # reinterpret_cast<type> (expression) -// ::= st <type> # sizeof (a type) -// ::= at <type> # alignof (a type) -// ::= <template-param> -// ::= <function-param> -// ::= dt <expression> <unresolved-name> # expr.name -// ::= pt <expression> <unresolved-name> # expr->name -// ::= ds <expression> <expression> # expr.*expr -// ::= sZ <template-param> # size of a parameter pack -// ::= sZ <function-param> # size of a function parameter pack -// ::= sp <expression> # pack expansion -// ::= tw <expression> # throw expression -// ::= tr # throw with no operand (rethrow) -// ::= <unresolved-name> # f(p), N::f(p), ::f(p), -// # freestanding dependent name (e.g., T::x), -// # objectless nonstatic member reference -// ::= <expr-primary> +// <pointer-to-member-type> ::= M <class type> <member type> +template <class C> const char* -__demangle_tree::__parse_expression(const char* first, const char* last) +parse_pointer_to_member_type(const char* first, const char* last, C& db) { - if (last - first >= 2) + if (first != last && *first == 'M') { - 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) + const char* t = parse_type(first+1, last, db); + if (t != first+1) { - case 'L': - t = __parse_expr_primary(first, last); - break; - case 'T': - t = __parse_template_param(first, last); - break; - case 'f': - t = __parse_function_param(first, last); - break; - case 'a': - if (t[1] == 't') - t = __parse_alignof_expr(first, last); - break; - case 'c': - switch (t[1]) - { - case 'c': - t = __parse_const_cast_expr(first, last); - break; - case 'l': - t = __parse_call_expr(first, last); - break; - case 'v': - t = __parse_conversion_expr(first, last); - break; - } - break; - case 'd': - switch (t[1]) - { - case 'a': - t = __parse_delete_array_expr(first, last); - break; - case 'c': - t = __parse_dynamic_cast_expr(first, last); - break; - case 'l': - t = __parse_delete_expr(first, last); - break; - case 's': - t = __parse_dot_star_expr(first, last); - break; - case 't': - t = __parse_dot_expr(first, last); - break; - } - break; - case 'm': - t = __parse_decrement_expr(first, last); - break; - case 'n': - switch (t[1]) - { - case 'a': - case 'w': - t = __parse_new_expr(first, last); - break; - } - break; - case 'p': - switch (t[1]) - { - case 'p': - t = __parse_increment_expr(first, last); - break; - case 't': - t = __parse_arrow_expr(first, last); - break; - } - break; - case 'r': - t = __parse_reinterpret_cast_expr(first, last); - break; - case 's': - switch (t[1]) + const char* t2 = parse_type(t, last, db); + if (t2 != t) { - case 'c': - t = __parse_static_cast_expr(first, last); - break; - case 'p': - t = __parse_pack_expansion(first, last); - break; - case 't': - t = __parse_sizeof_type_expr(first, last); - break; - case 'Z': - if (last - t >= 3) + 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() == '(') { - 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; - } + db.names.back().first = std::move(func.first) + "(" + class_type.move_full() + "::*"; + db.names.back().second = ")" + std::move(func.second); } - break; - } - break; - case 't': - switch (t[1]) - { - case 'e': - case 'i': - t = __parse_typeid_expr(first, last); - break; - case 'r': - if (__make<__rethrow>()) - t = first +2; - break; - case 'w': - t = __parse_throw_expr(first, last); - break; + else + { + db.names.back().first = std::move(func.first) + " " + class_type.move_full() + "::*"; + db.names.back().second = std::move(func.second); + } + first = t2; } - 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; } @@ -8163,78 +1682,61 @@ __demangle_tree::__parse_expression(const char* first, const char* last) // <array-type> ::= A <positive dimension number> _ <element type> // ::= A [<dimension expression>] _ <element type> +template <class C> const char* -__demangle_tree::__parse_array_type(const char* first, const char* last) +parse_array_type(const char* first, const char* last, C& db) { if (first != last && *first == 'A' && first+1 != last) { if (first[1] == '_') { - const char* t = __parse_type(first+2, last); + const char* t = parse_type(first+2, last, db); if (t != first+2) { - if (__make<__array>(__root_)) - first = t; + 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; } } else if ('1' <= first[1] && first[1] <= '9') { - size_t dim = static_cast<size_t>(first[1] - '0'); - const char* t = first+2; - for (; t != last && isdigit(*t); ++t) - dim = dim * 10 + static_cast<size_t>(*t - '0'); + const char* t = parse_number(first+1, last); if (t != last && *t == '_') { - const char* t2 = __parse_type(t+1, last); + const char* t2 = parse_type(t+1, last, db); if (t2 != t+1) { - if (__make<__array>(__root_, dim)) - first = t2; + 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 { - const char* t = __parse_expression(first+1, last); + const char* t = parse_expression(first+1, last, db); if (t != first+1 && t != last && *t == '_') { - __node* dim = __root_; - const char* t2 = __parse_type(++t, last); + const char* t2 = parse_type(++t, last, db); if (t2 != t) { - if (__make<__array>(__root_, dim)) - first = t2; - } - } - } - } - return first; -} - -// <class-enum-type> ::= <name> - -const char* -__demangle_tree::__parse_class_enum_type(const char* first, const char* last) -{ - return __parse_name(first, last); -} - -// <pointer-to-member-type> ::= M <class type> <member type> - -const char* -__demangle_tree::__parse_pointer_to_member_type(const char* first, const char* last) -{ - if (first != last && *first == 'M') - { - const char* t = __parse_type(first+1, last); - if (t != first+1) - { - __node* class_type = __root_; - const char* t2 = __parse_type(t, last, true, true); - if (t2 != t) - { - if (__make<__pointer_to_member_type>(class_type, __root_)) + 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; + } } } } @@ -8244,8 +1746,9 @@ __demangle_tree::__parse_pointer_to_member_type(const char* first, const char* l // <decltype> ::= Dt <expression> E # decltype of an id-expression or class member access (C++0x) // ::= DT <expression> E # decltype of an expression (C++0x) +template <class C> const char* -__demangle_tree::__parse_decltype(const char* first, const char* last) +parse_decltype(const char* first, const char* last, C& db) { if (last - first >= 4 && first[0] == 'D') { @@ -8254,11 +1757,13 @@ __demangle_tree::__parse_decltype(const char* first, const char* last) case 't': case 'T': { - const char* t = __parse_expression(first+2, last); + const char* t = parse_expression(first+2, last, db); if (t != first+2 && t != last && *t == 'E') { - if (__make<__decltype_node>(__root_)) - first = t+1; + if (db.names.empty()) + return first; + db.names.back() = "decltype(" + db.names.back().move_full() + ")"; + first = t+1; } } break; @@ -8267,63 +1772,6 @@ __demangle_tree::__parse_decltype(const char* first, const char* last) return first; } -// <template-param> ::= T_ # first template parameter -// ::= T <parameter-2 non-negative number> _ - -const char* -__demangle_tree::__parse_template_param(const char* first, const char* last) -{ - if (last - first >= 2) - { - if (*first == 'T') - { - if (first[1] == '_') - { - if (__t_begin_ != __t_end_) - { - if (__make<__sub>(*__t_begin_)) - first += 2; - } - else - { - if (__make<__sub>(size_t(0))) - { - first += 2; - __fix_forward_references_ = true; - } - } - } - else if (isdigit(first[1])) - { - const char* t = first+1; - size_t sub = static_cast<size_t>(*t - '0'); - for (++t; t != last && isdigit(*t); ++t) - { - sub *= 10; - sub += static_cast<size_t>(*t - '0'); - } - if (t == last || *t != '_') - return first; - ++sub; - if (sub < static_cast<size_t>(__t_end_ - __t_begin_)) - { - if (__make<__sub>(__t_begin_[sub])) - first = t+1; - } - else - { - if (__make<__sub>(sub)) - { - first = t+1; - __fix_forward_references_ = true; - } - } - } - } - } - return first; -} - // extension: // <vector-type> ::= Dv <positive dimension number> _ // <extended element type> @@ -8331,58 +1779,65 @@ __demangle_tree::__parse_template_param(const char* first, const char* last) // <extended element type> ::= <element type> // ::= p # AltiVec vector pixel +template <class C> const char* -__demangle_tree::__parse_vector_type(const char* first, const char* last) +parse_vector_type(const char* first, const char* last, C& db) { 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* t = parse_number(first+2, last); + if (t == last || *t != '_') + return first; const char* num = first + 2; size_t sz = static_cast<size_t>(t - num); if (++t != last) { if (*t != 'p') { - const char* t1 = __parse_type(t, last); + const char* t1 = parse_type(t, last, db); if (t1 != t) { - if (__make<__vector_type>(__root_, num, sz)) - first = t1; + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + typename C::String(num, sz) + "]"; + first = t1; } } else { ++t; - if (__make<__vector_type>((__node*)0, num, sz)) - first = t; + db.names.push_back("pixel vector[" + typename C::String(num, sz) + "]"); + first = t; } } } else { - __node* num = 0; + typename C::String num; const char* t1 = first+2; if (*t1 != '_') { - const char* t = __parse_expression(t1, last); + const char* t = parse_expression(t1, last, db); if (t != t1) - num = __root_; - t1 = t; + { + 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); + const char* t = parse_type(t1, last, db); if (t != t1) { - if (__make<__vector_type>(__root_, num)) - first = t; + if (db.names.empty()) + return first; + db.names.back().first += " vector[" + num + "]"; + first = t; } } } @@ -8407,1905 +1862,2016 @@ __demangle_tree::__parse_vector_type(const char* first, const char* last) // ::= G <type> # imaginary (C 2000) // ::= Dp <type> # pack expansion (C++0x) // ::= U <source-name> <type> # vendor extended type qualifier +// extension := U <objc-name> <objc-type> # objc-type<identifier> // extension := <vector-type> # <vector-type> starts with Dv +// <objc-name> ::= <k0 number> objcproto <k1 number> <identifier> # k0 = 9 + <number of digits in k1> + k1 +// <objc-type> := <source-name> # PU<11+>objcproto 11objc_object<source-name> 11objc_object -> id<source-name> + +template <class C> const char* -__demangle_tree::__parse_type(const char* first, const char* last, - bool try_to_parse_template_args, - bool look_for_ref_quals) +parse_type(const char* first, const char* last, C& db) { - unsigned cv = 0; - const char* t = __parse_cv_qualifiers(first, last, cv, look_for_ref_quals); - if (t != first) + if (first != last) { - const char* t2 = __parse_type(t, last, try_to_parse_template_args); - if (t2 != t) + switch (*first) { - if (__make<__cv_qualifiers>(cv, __root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else + case 'r': + case 'V': + case 'K': + { + unsigned cv = 0; + const char* t = parse_cv_qualifiers(first, last, cv); + if (t != first) { - *__sub_end_++ = __root_; - first = t2; + 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) + { + 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; + } } + } + 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 + // <template-param> it might be followed by <template-args>. + 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 <template-template-param> <template-args> + 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; } - if (first != last) + return first; +} + +// <operator-name> +// ::= aa # && +// ::= ad # & (unary) +// ::= an # & +// ::= aN # &= +// ::= aS # = +// ::= cl # () +// ::= cm # , +// ::= co # ~ +// ::= cv <type> # (cast) +// ::= da # delete[] +// ::= de # * (unary) +// ::= dl # delete +// ::= dv # / +// ::= dV # /= +// ::= eo # ^ +// ::= eO # ^= +// ::= eq # == +// ::= ge # >= +// ::= gt # > +// ::= ix # [] +// ::= le # <= +// ::= li <source-name> # operator "" +// ::= ls # << +// ::= lS # <<= +// ::= lt # < +// ::= mi # - +// ::= mI # -= +// ::= ml # * +// ::= mL # *= +// ::= mm # -- (postfix in <expression> context) +// ::= na # new[] +// ::= ne # != +// ::= ng # - (unary) +// ::= nt # ! +// ::= nw # new +// ::= oo # || +// ::= or # | +// ::= oR # |= +// ::= pm # ->* +// ::= pl # + +// ::= pL # += +// ::= pp # ++ (postfix in <expression> context) +// ::= ps # + (unary) +// ::= pt # -> +// ::= qu # ? +// ::= rm # % +// ::= rM # %= +// ::= rs # >> +// ::= rS # >>= +// ::= v <digit> <source-name> # vendor extended operator + +template <class C> +const char* +parse_operator_name(const char* first, const char* last, C& db) +{ + if (last - first >= 2) { - switch (*first) + switch (first[0]) { - case 'A': - t = __parse_array_type(first, last); - if (t != first) + case 'a': + switch (first[1]) { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + 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': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'c': + switch (first[1]) { - if (__make<__d_complex>(__root_)) + case 'l': + 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': { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else + 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) { - *__sub_end_++ = __root_; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator "); + db.parsed_ctor_dtor_cv = true; first = t; } } - return first; + break; } break; - case 'F': - t = __parse_function_type(first, last); - if (t != first) + case 'd': + switch (first[1]) { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + case 'a': + db.names.push_back("operator delete[]"); + first += 2; + break; + case 'e': + db.names.push_back("operator*"); + first += 2; + break; + case 'l': + db.names.push_back("operator delete"); + first += 2; + break; + case 'v': + db.names.push_back("operator/"); + first += 2; + break; + case 'V': + db.names.push_back("operator/="); + first += 2; + break; } break; - case 'G': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'e': + switch (first[1]) { - if (__make<__imaginary>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + 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 'M': - t = __parse_pointer_to_member_type(first, last); - if (t != first) + case 'g': + switch (first[1]) { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } + case 'e': + db.names.push_back("operator>="); + first += 2; + break; + case 't': + db.names.push_back("operator>"); + first += 2; + break; } break; - case 'O': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'i': + if (first[1] == 'x') { - if (__make<__rvalue_reference_to>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + db.names.push_back("operator[]"); + first += 2; } break; - case 'P': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'l': + switch (first[1]) { - if (__make<__pointer_to>(__root_)) + case 'e': + db.names.push_back("operator<="); + first += 2; + break; + case 'i': { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else + const char* t = parse_source_name(first+2, last, db); + if (t != first+2) { - *__sub_end_++ = __root_; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "operator\"\" "); first = t; } } - return first; + break; + case 's': + 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; - case 'R': - t = __parse_type(first+1, last, try_to_parse_template_args); - if (t != first+1) + case 'm': + switch (first[1]) { - if (__make<__lvalue_reference_to>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; + 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 'T': - t = __parse_template_param(first, last); - if (t != first) + case 'n': + switch (first[1]) { - 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; - } - } + case 'a': + db.names.push_back("operator new[]"); + first += 2; + break; + case 'e': + db.names.push_back("operator!="); + first += 2; + break; + case 'g': + db.names.push_back("operator-"); + first += 2; + break; + case 't': + db.names.push_back("operator!"); + first += 2; + break; + case 'w': + db.names.push_back("operator new"); + first += 2; + break; } break; - case 'U': - if (first+1 != last) + case 'o': + switch (first[1]) { - 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; - } - } + case 'o': + db.names.push_back("operator||"); + first += 2; + break; + case 'r': + db.names.push_back("operator|"); + first += 2; + break; + case 'R': + db.names.push_back("operator|="); + first += 2; + break; } break; - case 'S': - if (first+1 != last && first[1] == 't') + case 'p': + switch (first[1]) { - 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; - } - } + 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; } - else + break; + case 'q': + if (first[1] == 'u') { - t = __parse_substitution(first, last); - if (t != first) + db.names.push_back("operator?"); + first += 2; + } + break; + case 'r': + switch (first[1]) + { + 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; + } + break; + case 'v': + if (std::isdigit(first[1])) + { + 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; - // Parsed a substitution. If the substitution is a - // <template-param> it might be followed by <template-args>. - t = __parse_template_args(first, last); - if (t != first) - { - // Need to create substitution for <template-template-param> <template-args> - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } } } break; - case 'D': - if (first+1 != last) + } + } + return first; +} + +template <class C> +const char* +parse_integer_literal(const char* first, const char* last, const typename C::String& lit, C& db) +{ + const char* t = parse_number(first, last); + if (t != first && t != last && *t == 'E') + { + if (lit.size() > 3) + db.names.push_back("(" + lit + ")"); + else + db.names.emplace_back(); + if (*first == 'n') + { + db.names.back().first += '-'; + ++first; + } + db.names.back().first.append(first, t); + if (lit.size() <= 3) + db.names.back().first += lit; + first = t+1; + } + return first; +} + +// <expr-primary> ::= L <type> <value number> E # integer literal +// ::= L <type> <value float> E # floating literal +// ::= L <string type> E # string literal +// ::= L <nullptr type> E # nullptr literal (i.e., "LDnE") +// ::= L <type> <real-part float> _ <imag-part float> E # complex floating point literal (C 2000) +// ::= L <mangled-name> E # external name + +template <class C> +const char* +parse_expr_primary(const char* first, const char* last, C& db) +{ + if (last - first >= 4 && *first == 'L') + { + switch (first[1]) + { + case 'w': { - switch (first[1]) + const char* t = parse_integer_literal(first+2, last, "wchar_t", db); + if (t != first+2) + first = t; + } + break; + case 'b': + if (first[3] == 'E') + { + switch (first[2]) { - case 'p': - t = __parse_type(first+2, last, try_to_parse_template_args); - if (t != first+1) - { - if (__make<__pack_expansion>(__root_)) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - } - return first; - } - break; - case 't': - case 'T': - t = __parse_decltype(first, last); - if (t != first) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - return first; - } + case '0': + db.names.push_back("false"); + first += 4; break; - case 'v': - t = __parse_vector_type(first, last); - if (t != first) - { - if (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; - else - { - *__sub_end_++ = __root_; - first = t; - } - return first; - } + case '1': + db.names.push_back("true"); + first += 4; 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) + break; + case 'c': { + const char* t = parse_integer_literal(first+2, last, "char", db); + if (t != first+2) first = t; } - else + break; + case 'a': { - t = __parse_class_enum_type(first, last); - if (t != first) + const char* t = parse_integer_literal(first+2, last, "signed char", db); + if (t != first+2) + first = t; + } + break; + case 'h': + { + const char* t = parse_integer_literal(first+2, last, "unsigned char", db); + if (t != first+2) + first = t; + } + break; + case 's': + { + const char* t = parse_integer_literal(first+2, last, "short", db); + if (t != first+2) + first = t; + } + break; + case 't': + { + const char* t = parse_integer_literal(first+2, last, "unsigned short", db); + if (t != first+2) + first = t; + } + break; + case 'i': + { + const char* t = parse_integer_literal(first+2, last, "", db); + if (t != first+2) + first = t; + } + break; + case 'j': + { + const char* t = parse_integer_literal(first+2, last, "u", db); + if (t != first+2) + first = t; + } + break; + case 'l': + { + const char* t = parse_integer_literal(first+2, last, "l", db); + if (t != first+2) + first = t; + } + break; + case 'm': + { + const char* t = parse_integer_literal(first+2, last, "ul", db); + if (t != first+2) + first = t; + } + break; + case 'x': + { + const char* t = parse_integer_literal(first+2, last, "ll", db); + if (t != first+2) + first = t; + } + break; + case 'y': + { + 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<float>(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'd': + { + const char* t = parse_floating_number<double>(first+2, last, db); + if (t != first+2) + first = t; + } + break; + case 'e': + { + const char* t = parse_floating_number<long double>(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 (__sub_end_ == __sub_cap_) - __status_ = memory_alloc_failure; + if (*t != 'E') + { + const char* n = t; + for (; n != last && isdigit(*n); ++n) + ; + if (n != t && n != last && *n == 'E') + { + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n); + first = n+1; + break; + } + } else { - *__sub_end_++ = __root_; - first = t; + first = t+1; + break; } } } - break; } } return first; } -// <number> ::= [n] <non-negative decimal integer> +template <class String> +String +base_name(String& s) +{ + if (s.empty()) + return s; + if (s == "std::string") + { + s = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"; + return "basic_string"; + } + if (s == "std::istream") + { + s = "std::basic_istream<char, std::char_traits<char> >"; + return "basic_istream"; + } + if (s == "std::ostream") + { + s = "std::basic_ostream<char, std::char_traits<char> >"; + return "basic_ostream"; + } + if (s == "std::iostream") + { + s = "std::basic_iostream<char, std::char_traits<char> >"; + 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] == '<') + { + if (--c == 0) + { + --pe; + break; + } + } + else if (pe[-1] == '>') + ++c; + } + } + const char* p0 = pe - 1; + for (; p0 != pf; --p0) + { + if (*p0 == ':') + { + ++p0; + break; + } + } + return String(p0, pe); +} + +// <ctor-dtor-name> ::= 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 <class C> 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; } -// <call-offset> ::= h <nv-offset> _ -// ::= v <v-offset> _ +// <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ +// ::= <closure-type-name> // -// <nv-offset> ::= <offset number> -// # non-virtual base override +// <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ // -// <v-offset> ::= <offset number> _ <virtual offset number> -// # virtual base override, with vcall offset +// <lambda-sig> ::= <parameter type>+ # Parameter types or "v" if the lambda has no parameters +template <class C> 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; } -// <special-name> ::= TV <type> # virtual table -// ::= TT <type> # VTT structure (construction vtable index) -// ::= TI <type> # typeinfo structure -// ::= TS <type> # typeinfo name (null-terminated byte string) -// ::= Tc <call-offset> <call-offset> <base encoding> -// # base is the nominal target function of thunk -// # first call-offset is 'this' adjustment -// # second call-offset is result adjustment -// ::= T <call-offset> <base encoding> -// # base is the nominal target function of thunk -// ::= GV <object name> # Guard variable for one-time initialization -// # No <type> -// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first -// extension ::= GR <object name> # reference temporary for object +// <unqualified-name> ::= <operator-name> +// ::= <ctor-dtor-name> +// ::= <source-name> +// ::= <unnamed-type-name> +template <class C> 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 <type> # virtual table - t = __parse_type(first+2, last); - if (t != first+2 && __make<__vtable>(__root_)) - first = t; - break; - case 'T': - // TT <type> # VTT structure (construction vtable index) - t = __parse_type(first+2, last); - if (t != first+2 && __make<__VTT>(__root_)) - first = t; - break; - case 'I': - // TI <type> # typeinfo structure - t = __parse_type(first+2, last); - if (t != first+2 && __make<__typeinfo>(__root_)) - first = t; - break; - case 'S': - // TS <type> # typeinfo name (null-terminated byte string) - t = __parse_type(first+2, last); - if (t != first+2 && __make<__typeinfo_name>(__root_)) - first = t; - break; - case 'c': - // Tc <call-offset> <call-offset> <base encoding> - { - const char* t0 = __parse_call_offset(first+2, last); - if (t0 == first+2) - break; - const char* t1 = __parse_call_offset(t0, last); - if (t1 == t0) - break; - t = __parse_encoding(t1, last); - if (t != t1 && __make<__covariant_return_thunk>(__root_)) - first = t; - } - break; - case 'C': - // extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first - t = __parse_type(first+2, last); - if (t != first+2) - { - __node* op1 = __root_; - const char* t0 = __parse_number(t, last); - if (t0 != t && t0 != last && *t0 == '_') - { - const char* t1 = __parse_type(++t0, last); - if (t1 != t0) - { - if (__make<__construction_vtable>(__root_, op1)) - first = t1; - } - } - } - break; - default: - // T <call-offset> <base encoding> - { - const char* t0 = __parse_call_offset(first+1, last); - if (t0 == first+1) - break; - t = __parse_encoding(t0, last); - if (t != t0) - { - if (first[2] == 'v') - { - if (__make<__virtual_thunk>(__root_)) - first = t; - } - else - { - if (__make<__non_virtual_thunk>(__root_)) - first = t; - } - } - } - break; - } + 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; +} + +// <unscoped-name> ::= <unqualified-name> +// ::= St <unqualified-name> # ::std:: +// extension ::= StL<unqualified-name> + +template <class C> +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 <object name> # Guard variable for one-time initialization - t = __parse_name(first+2, last); - if (t != first+2 && __make<__guard_variable>(__root_)) - first = t; - break; - case 'R': - // extension ::= GR <object name> # reference temporary for object - t = __parse_name(first+2, last); - if (t != first+2 && __make<__reference_temporary>(__root_)) - first = t; - break; + if (db.names.empty()) + return first; + db.names.back().first.insert(0, "std::"); } - break; + first = t1; + } + } + return first; +} + +// at <type> # alignof (a type) + +template <class C> +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; } -// <operator-name> -// ::= aa # && -// ::= ad # & (unary) -// ::= an # & -// ::= aN # &= -// ::= aS # = -// ::= at # alignof (a type) -// ::= az # alignof (an expression) -// ::= cl # () -// ::= cm # , -// ::= co # ~ -// ::= cv <type> # (cast) -// ::= da # delete[] -// ::= de # * (unary) -// ::= dl # delete -// ::= dv # / -// ::= dV # /= -// ::= eo # ^ -// ::= eO # ^= -// ::= eq # == -// ::= ge # >= -// ::= gt # > -// ::= ix # [] -// ::= le # <= -// ::= ls # << -// ::= lS # <<= -// ::= lt # < -// ::= mi # - -// ::= mI # -= -// ::= ml # * -// ::= mL # *= -// ::= mm # -- (postfix in <expression> context) -// ::= na # new[] -// ::= ne # != -// ::= ng # - (unary) -// ::= nt # ! -// ::= nw # new -// ::= oo # || -// ::= or # | -// ::= oR # |= -// ::= pm # ->* -// ::= pl # + -// ::= pL # += -// ::= pp # ++ (postfix in <expression> context) -// ::= ps # + (unary) -// ::= pt # -> -// ::= qu # ? -// ::= rm # % -// ::= rM # %= -// ::= rs # >> -// ::= rS # >>= -// ::= st # sizeof (a type) -// ::= sz # sizeof (an expression) -// ::= v <digit> <source-name> # vendor extended operator +// az <expression> # alignof (a expression) + +template <class C> +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 <class C> +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 <class C> +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 <class C> const char* -__demangle_tree::__parse_operator_name(const char* first, const char* last, int* type) +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; +} + +// <expression> ::= <unary operator-name> <expression> +// ::= <binary operator-name> <expression> <expression> +// ::= <ternary operator-name> <expression> <expression> <expression> +// ::= cl <expression>+ E # call +// ::= cv <type> <expression> # conversion with one argument +// ::= cv <type> _ <expression>* E # conversion with a different number of arguments +// ::= [gs] nw <expression>* _ <type> E # new (expr-list) type +// ::= [gs] nw <expression>* _ <type> <initializer> # new (expr-list) type (init) +// ::= [gs] na <expression>* _ <type> E # new[] (expr-list) type +// ::= [gs] na <expression>* _ <type> <initializer> # new[] (expr-list) type (init) +// ::= [gs] dl <expression> # delete expression +// ::= [gs] da <expression> # delete[] expression +// ::= pp_ <expression> # prefix ++ +// ::= mm_ <expression> # prefix -- +// ::= ti <type> # typeid (type) +// ::= te <expression> # typeid (expression) +// ::= dc <type> <expression> # dynamic_cast<type> (expression) +// ::= sc <type> <expression> # static_cast<type> (expression) +// ::= cc <type> <expression> # const_cast<type> (expression) +// ::= rc <type> <expression> # reinterpret_cast<type> (expression) +// ::= st <type> # sizeof (a type) +// ::= sz <expression> # sizeof (an expression) +// ::= at <type> # alignof (a type) +// ::= az <expression> # alignof (an expression) +// ::= nx <expression> # noexcept (expression) +// ::= <template-param> +// ::= <function-param> +// ::= dt <expression> <unresolved-name> # expr.name +// ::= pt <expression> <unresolved-name> # expr->name +// ::= ds <expression> <expression> # expr.*expr +// ::= sZ <template-param> # size of a parameter pack +// ::= sZ <function-param> # size of a function parameter pack +// ::= sp <expression> # pack expansion +// ::= tw <expression> # throw expression +// ::= tr # throw with no operand (rethrow) +// ::= <unresolved-name> # f(p), N::f(p), ::f(p), +// # freestanding dependent name (e.g., T::x), +// # objectless nonstatic member reference +// ::= <expr-primary> + +template <class C> +const char* +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 <type> - { - 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]) + switch (t[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; - } + t = parse_binary_expression(first+2, last, "-", db); + if (t != first+2) + first = t; 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; - } + 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>(op1, __root_)) - { - *type = 2; - first = t2; - } - } - } - } - else - { - if (__make<__operator_times>()) - 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_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 <expression> 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; - } + 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_equal>(op1, __root_)) - { - *type = 2; - first = t2; - } - } - } - } - else - { - if (__make<__operator_plus_equal>()) - first += 2; - } + t = parse_binary_expression(first+2, last, "+=", db); + if (t != first+2) + first = t; break; case 'p': - // ++ (postfix in <expression> context) - if (type) + if (first+2 != last && first[2] == '_') { - const char* t = __parse_expression(first+2, last); - if (t != first+2) - { - if (__make<__operator_increment>(false, __root_)) - { - *type = 1; - first = t; - } - } + t = parse_prefix_expression(first+3, last, "++", db); + if (t != first+3) + 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) + const char* t1 = parse_expression(first+2, last, db); + if (t1 != first+2) { - if (__make<__operator_unary_plus>(__root_)) - { - *type = 1; - first = t; - } + if (db.names.empty()) + return first; + db.names.back() = "(" + db.names.back().move_full() + ")++"; + first = t1; } } - else - { - if (__make<__operator_unary_plus>()) - first += 2; - } + break; + case 's': + 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) - { - __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; - } + first = parse_arrow_expr(first, last, db); break; } break; case 'q': - // ? - if (first[1] == 'u') + if (t[1] == 'u') { - if (type) + 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) { - __node* op2 = __root_; - const char* t3 = __parse_expression(t2, last); - if (t3 != t2) - { - if (__make<__operator_conditional>(op1, op2, __root_)) - { - *type = 3; - first = t3; - } - } + 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 + { + db.names.pop_back(); + db.names.pop_back(); } } - } - else - { - if (__make<__operator_conditional>()) - first += 2; + else + db.names.pop_back(); } } break; case 'r': - switch (first[1]) + switch (t[1]) { + case 'c': + first = parse_reinterpret_cast_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_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) - { - const char* t = __parse_expression(first+2, last); - if (t != first+2) - { - __node* op1 = __root_; - const char* t2 = __parse_expression(t, last); - if (t != t2) - { - if (__make<__operator_mod_equal>(op1, __root_)) - { - *type = 2; - first = t2; - } - } - } - } - else - { - if (__make<__operator_mod_equal>()) - first += 2; - } + 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_right_shift>(op1, __root_)) - { - *type = 2; - first = t2; - } - } - } - } - else - { - if (__make<__operator_right_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_right_shift_equal>(op1, __root_)) - { - *type = 2; - first = t2; - } - } - } - } - else - { - if (__make<__operator_right_shift_equal>()) - first += 2; - } + 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; } -// <source-name> ::= <positive length number> <identifier> +// <template-arg> ::= <type> # type or template +// ::= X <expression> E # expression +// ::= <expr-primary> # simple expressions +// ::= J <template-arg>* E # argument pack +// ::= LZ <encoding> E # extension +template <class C> 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<size_t>(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<size_t>(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': + // <expr-primary> or LZ <encoding> 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<size_t>(last - t) >= n && __make<__source_name>(t, n)) - first = t + n; - } - } - return first; -} - -// <unqualified-name> ::= <operator-name> -// ::= <ctor-dtor-name> -// ::= <source-name> -// ::= <unnamed-type-name> - -const char* -__demangle_tree::__parse_unqualified_name(const char* first, const char* last) -{ - const char* t = __parse_source_name(first, last); - if (t == first) - { - t = __parse_ctor_dtor_name(first, last); - if (t == first) - { - t = __parse_operator_name(first, last); - if (t == first) - first = __parse_unnamed_type_name(first, last); else - first = t; + first = parse_expr_primary(first, last, db); + break; + default: + // <type> + first = parse_type(first, last, db); + break; } - else - first = t; } - else - first = t; return first; } -// <unscoped-name> ::= <unqualified-name> -// ::= St <unqualified-name> # ::std:: -// extension ::= StL<unqualified-name> +// <template-args> ::= I <template-arg>* E +// extension, the abi says <template-arg>+ +template <class C> 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; } -// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E -// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E +// <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E +// ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E // // <prefix> ::= <prefix> <unqualified-name> // ::= <template-prefix> <template-args> @@ -10320,717 +3886,1052 @@ __demangle_tree::__parse_unscoped_name(const char* first, const char* last) // ::= <template-param> // ::= <substitution> +template <class C> 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"; + } + if (t0 == last) + { + db.names.pop_back(); + return first; } - while (t0 != last) + bool pop_subs = false; + while (*t0 != 'E') { - bool can_sub = true; - bool make_nested = true; - const char* t1 = NULL; + const char* t1; switch (*t0) { - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - t1 = __parse_source_name(t0, last); - if (t1 == t0 || t1 == last) - return first; - if (*t1 == 'M') - { - // This is a data-member-prefix - ++t1; - } - else if (*t1 == 'I') - { - // has following <template-args> - if (prev) + 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()) { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __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 <template-args> - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __status_ = memory_alloc_failure; - return first; - } - else - *__sub_end_++ = __root_; - const char* t2 = __parse_template_args(t1, last); - if (t2 == t1) - return first; - t1 = t2; - } - break; - case 'U': - 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') + t1 = parse_template_param(t0, last, db); + if (t1 != t0 && t1 != last) { - // has following <template-args> - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __status_ = memory_alloc_failure; - return first; - } + 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 <template-args> - if (prev) - { - if (!__make<__nested_delimeter>(prev, __root_)) - return first; - make_nested = false; - } - if (__sub_end_ == __sub_cap_) - { - __status_ = memory_alloc_failure; - return first; - } + 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; +} + +// <discriminator> := _ <non-negative number> # when number < 10 +// := __ <non-negative number> _ # 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; +} + +// <local-name> := Z <function encoding> E <entity name> [<discriminator>] +// := Z <function encoding> E s [<discriminator>] +// := Z <function encoding> Ed [ <parameter number> ] _ <entity name> + +template <class C> +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; } -// <template-arg> ::= <type> # type or template -// ::= X <expression> E # expression -// ::= <expr-primary> # simple expressions -// ::= J <template-arg>* E # argument pack -// ::= LZ <encoding> E # extension +// <name> ::= <nested-name> // N +// ::= <local-name> # See Scope Encoding below // Z +// ::= <unscoped-template-name> <template-args> +// ::= <unscoped-name> + +// <unscoped-template-name> ::= <unscoped-name> +// ::= <substitution> +template <class C> 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') // <unscoped-template-name> <template-args> { - 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': - // <expr-primary> or LZ <encoding> E - if (first+1 != last && first[1] == 'Z') - { - t = __parse_encoding(first+2, last); - if (t != first+2 && t != last && *t == 'E') - first = t+1; + } + else // <unscoped-name> + first = t1; } else - first = __parse_expr_primary(first, last); - break; - default: - // <type> - first = __parse_type(first, last); + { // try <substitution> <template-args> + 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; } -// <template-args> ::= I <template-arg>* E -// extension, the abi says <template-arg>+ +// <call-offset> ::= h <nv-offset> _ +// ::= v <v-offset> _ +// +// <nv-offset> ::= <offset number> +// # non-virtual base override +// +// <v-offset> ::= <offset number> _ <virtual offset number> +// # virtual base override, with vcall offset const char* -__demangle_tree::__parse_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; } -// <substitution> ::= S <seq-id> _ -// ::= S_ -// <substitution> ::= Sa # ::std::allocator -// <substitution> ::= Sb # ::std::basic_string -// <substitution> ::= Ss # ::std::basic_string < char, -// ::std::char_traits<char>, -// ::std::allocator<char> > -// <substitution> ::= Si # ::std::basic_istream<char, std::char_traits<char> > -// <substitution> ::= So # ::std::basic_ostream<char, std::char_traits<char> > -// <substitution> ::= Sd # ::std::basic_iostream<char, std::char_traits<char> > +// <special-name> ::= TV <type> # virtual table +// ::= TT <type> # VTT structure (construction vtable index) +// ::= TI <type> # typeinfo structure +// ::= TS <type> # typeinfo name (null-terminated byte string) +// ::= Tc <call-offset> <call-offset> <base encoding> +// # base is the nominal target function of thunk +// # first call-offset is 'this' adjustment +// # second call-offset is result adjustment +// ::= T <call-offset> <base encoding> +// # base is the nominal target function of thunk +// ::= GV <object name> # Guard variable for one-time initialization +// # No <type> +// extension ::= TC <first type> <number> _ <second type> # construction vtable for second-in-first +// extension ::= GR <object name> # reference temporary for object +template <class C> 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 <type> # 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 <type> # 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 <type> # 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 <type> # 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 <call-offset> <call-offset> <base encoding> + { + const char* t0 = parse_call_offset(first+2, last); + if (t0 == first+2) + break; + const char* t1 = parse_call_offset(t0, last); + if (t1 == t0) + break; + t = parse_encoding(t1, last, 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 <first type> <number> _ <second type> # 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 <call-offset> <base encoding> { - size_t sub = 0; - const char* t = first+1; - if (isdigit(*t)) - sub = static_cast<size_t>(*t - '0'); - else - sub = static_cast<size_t>(*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<size_t>(*t - '0'); - else - sub += static_cast<size_t>(*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<size_t>(__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 <object name> # 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 <object name> # 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; } -// <name> ::= <nested-name> -// ::= <local-name> # See Scope Encoding below -// ::= <unscoped-template-name> <template-args> -// ::= <unscoped-name> +template <class T> +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; +}; + +// <encoding> ::= <function name> <bare-function-type> +// ::= <data name> +// ::= <special-name> +template <class C> 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<decltype(db.encoding_depth)> su(db.encoding_depth); + ++db.encoding_depth; + save_value<decltype(db.tag_templates)> 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 <nested-name> nor <local-name> - // Try to parse <unscoped-template-name> <template-args> or - // <unscoped-name> which are nearly ambiguous. - // This logic occurs nowhere else. - if (last - t0 >= 2) + 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<bool> 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 = __parse_unscoped_name(t0, last); - if (t != t0) + ++t; + } + else + { + bool first_arg = true; + while (true) { - // unscoped-name might be <unscoped-template-name> - 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 - { - // <unscoped-name> - 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 -// <dot-suffix> := .<anything and everything> +// _block_invoke +// _block_invoke<decimal-digit>+ +// _block_invoke_<decimal-digit>+ +template <class C> 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<size_t>(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; } -// <encoding> ::= <function name> <bare-function-type> -// ::= <data name> -// ::= <special-name> +// extension +// <dot-suffix> := .<anything and everything> +template <class C> 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; } +// <block-involcaton-function> ___Z<encoding>_block_invoke +// <block-involcaton-function> ___Z<encoding>_block_invoke<decimal-digit>+ +// <block-involcaton-function> ___Z<encoding>_block_invoke_<decimal-digit>+ // <mangled-name> ::= _Z<encoding> // ::= <type> +template <class C> 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 <std::size_t N> +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);} -__demangle_tree -__demangle(const char* mangled_name) + bool + pointer_in_buffer(char* p) noexcept + {return buf_ <= p && p <= buf_ + N;} + +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<std::size_t>(ptr_ - buf_);} + void reset() {ptr_ = buf_;} +}; + +template <std::size_t N> +char* +arena<N>::allocate(std::size_t n) { - return __demangle(mangled_name, 0, 0); + n = align_up(n); + if (static_cast<std::size_t>(buf_ + N - ptr_) >= n) + { + char* r = ptr_; + ptr_ += n; + return r; + } + return static_cast<char*>(std::malloc(n)); } -char* -__demangle(__demangle_tree dmg_tree, char* buf, size_t* n, int* status) +template <std::size_t N> +void +arena<N>::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<size_t>(est) <= bs) + else + std::free(p); +} + +template <class T, std::size_t N> +class short_alloc +{ + arena<N>& a_; +public: + typedef T value_type; + +public: + template <class _Up> struct rebind {typedef short_alloc<_Up, N> other;}; + + short_alloc(arena<N>& a) noexcept : a_(a) {} + template <class U> + short_alloc(const short_alloc<U, N>& 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<T*>(a_.allocate(n*sizeof(T))); } - else if (static_cast<size_t>(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<char*>(p), n*sizeof(T)); } - else - s = static_cast<ptrdiff_t>(dmg_tree.size() + 1); - if (static_cast<size_t>(s) > bs) + + template <class T1, std::size_t N1, class U, std::size_t M> + friend + bool + operator==(const short_alloc<T1, N1>& x, const short_alloc<U, M>& y) noexcept; + + template <class U, std::size_t M> friend class short_alloc; +}; + +template <class T, std::size_t N, class U, std::size_t M> +inline +bool +operator==(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept +{ + return N == M && &x.a_ == &y.a_; +} + +template <class T, std::size_t N, class U, std::size_t M> +inline +bool +operator!=(const short_alloc<T, N>& x, const short_alloc<U, M>& y) noexcept +{ + return !(x == y); +} + +template <class T> +class malloc_alloc +{ +public: + typedef T value_type; + + malloc_alloc() = default; + template <class U> malloc_alloc(const malloc_alloc<U>&) noexcept {} + + T* allocate(std::size_t n) { - buf = static_cast<char*>(realloc(buf, static_cast<size_t>(s))); - if (buf == NULL) - { - if (status) - *status = memory_alloc_failure; - return NULL; - } - if (n) - *n = static_cast<size_t>(s); + return static_cast<T*>(std::malloc(n*sizeof(T))); } - if (static_cast<size_t>(est) > bs) + void deallocate(T* p, std::size_t) noexcept { - if (static_cast<size_t>(est) <= N) - strncpy(buf, tmp, static_cast<size_t>(s)); - else - *dmg_tree.__get_demangled_name(buf) = '\0'; + std::free(p); } - if (status) - *status = success; - return buf; +}; + +template <class T, class U> +inline +bool +operator==(const malloc_alloc<T>&, const malloc_alloc<U>&) noexcept +{ + return true; } -} // __libcxxabi +template <class T, class U> +inline +bool +operator!=(const malloc_alloc<T>& x, const malloc_alloc<U>& y) noexcept +{ + return !(x == y); +} -#pragma GCC visibility pop -#pragma GCC visibility push(default) +const size_t bs = 4 * 1024; +template <class T> using Alloc = short_alloc<T, bs>; +template <class T> using Vector = std::vector<T, Alloc<T>>; +using String = std::basic_string<char, std::char_traits<char>, malloc_alloc<char>>; -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 <size_t N> + 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<string_pair> sub_type; + typedef Vector<sub_type> template_param_type; + Vector<string_pair> names; + Vector<sub_type> subs; + Vector<template_param_type> 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 <size_t N> + Db(arena<N>& 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<bs> 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<char*>(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 <exception> // for std::terminate #include <cstdlib> // for malloc, free -#include <string> // for memset +#include <cstring> // for memset #include <pthread.h> #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 <new> #include <cstdlib> @@ -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 <sys/syslog.h> #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 <string.h> +#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<char*>(c_str()), msg); + std::memcpy(const_cast<char*>(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 diff --git a/tests/core/test_literal_negative_zero.in b/tests/core/test_literal_negative_zero.in new file mode 100644 index 00000000..1554fbf5 --- /dev/null +++ b/tests/core/test_literal_negative_zero.in @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <math.h> + +static float XXXf = -0.0f; +static double XXXd = -0.0; + +struct x { + float f; + double d; +}; + +static struct x xx[] = { + -0x0p+0, + -0x0p+0, +}; + +int main(int argc, char ** argv) { + float YYYf = -0.0f; + float YYYd = -0.0; + + printf("%.2f\n", XXXf); + printf("%.2f\n", XXXd); + printf("%.2f\n", YYYf); + printf("%.2f\n", YYYd); + printf("%.2f\n", xx->f); + printf("%.2f\n", xx->d); +} diff --git a/tests/core/test_literal_negative_zero.out b/tests/core/test_literal_negative_zero.out new file mode 100644 index 00000000..d1b863b8 --- /dev/null +++ b/tests/core/test_literal_negative_zero.out @@ -0,0 +1,6 @@ +-0.00 +-0.00 +-0.00 +-0.00 +-0.00 +-0.00 diff --git a/tests/math/lgamma.in b/tests/math/lgamma.in new file mode 100644 index 00000000..e96f5610 --- /dev/null +++ b/tests/math/lgamma.in @@ -0,0 +1,105 @@ +#define _BSD_SOURCE 1 +#define _XOPEN_SOURCE 700 +#include <stdint.h> +#include <stdio.h> +#include <fenv.h> +#include <float.h> +#include <math.h> + +#define RN 0 +#define T(...) {__FILE__, __LINE__, __VA_ARGS__}, +#define POS const char *file; int line; +struct f_fi {POS int r; float x; float y; float dy; long long i; int e; }; + +#define DIVBYZERO 0 +#define INEXACT 0 +#define INVALID 0 +#define OVERFLOW 0 +#define UNDERFLOW 0 + +#define inf INFINITY +#define nan NAN + +static struct f_fi t[] = { +T(RN, -0x1.02239f3c6a8f1p+3, -0x1.0120f61b63d5ep+3, 0x1.89ccc4p-6, -1, INEXACT) +T(RN, 0x1.161868e18bc67p+2, 0x1.1ef3b263fd60bp+1, -0x1.6d0264p-3, 1, INEXACT) +T(RN, -0x1.0c34b3e01e6e7p+3, -0x1.46d73255263d9p+3, 0x1.e0ec76p-3, -1, INEXACT) +T(RN, -0x1.a206f0a19dcc4p+2, -0x1.9c91f19ac48c5p+2, 0x1.c2a38cp-2, -1, INEXACT) +T(RN, 0x1.288bbb0d6a1e6p+3, 0x1.65c60768fcc11p+3, 0x1.2f22c2p-2, 1, INEXACT) +T(RN, 0x1.52efd0cd80497p-1, 0x1.3cc760be720b3p-2, 0x1.0527e2p-2, 1, INEXACT) +T(RN, -0x1.a05cc754481d1p-2, 0x1.4ef387fea1014p+0, -0x1.c3b036p-2, -1, INEXACT) +T(RN, 0x1.1f9ef934745cbp-1, 0x1.d6f0efacc5699p-2, 0x1.c0b0a8p-2, 1, INEXACT) +T(RN, 0x1.8c5db097f7442p-1, 0x1.6c1a14cf91533p-3, 0x1.16f4cap-5, 1, INEXACT) +T(RN, -0x1.5b86ea8118a0ep-1, 0x1.695b1e0a0a59ep+0, 0x1.ada69ep-2, -1, INEXACT) +T(RN, 0x0p+0, inf, 0x0p+0, 1, DIVBYZERO) +/* T(RN, -0x0p+0, inf, 0x0p+0, -1, DIVBYZERO) This one fails in native as well */ +T(RN, 0x1p+0, 0x0p+0, 0x0p+0, 1, 0) +T(RN, -0x1p+0, inf, 0x0p+0, 1, DIVBYZERO) +T(RN, 0x1p+1, 0x0p+0, 0x0p+0, 1, 0) +T(RN, -0x1p+1, inf, 0x0p+0, 1, DIVBYZERO) +T(RN, inf, inf, 0x0p+0, 1, 0) +T(RN, -inf, inf, 0x0p+0, -1, 0) +T(RN, nan, nan, 0x0p+0, 1, 0) +}; + +static int eulpf(float x) +{ + union { float f; uint32_t i; } u = { x }; + int e = u.i>>23 & 0xff; + + if (!e) + e++; + return e - 0x7f - 23; +} + +static int checkulp(float d, int r) +{ + // TODO: we only care about >=1.5 ulp errors for now, should be 1.0 + if (r == RN) + return fabsf(d) < 1.5; + return 1; +} + +static float ulperrf(float got, float want, float dwant) +{ + if (isnan(got) && isnan(want)) + return 0; + if (got == want) { + if (signbit(got) == signbit(want)) + return dwant; + return INFINITY; + } + if (isinf(got)) { + got = copysignf(0x1p127, got); + want *= 0.5; + } + return scalbn(got - want, -eulpf(want)) + dwant; +} + +int main(void) +{ + int yi; + double y; + float d; + int e, i, err = 0; + struct f_fi *p; + + for (i = 0; i < sizeof t/sizeof *t; i++) { + p = t + i; + + if (p->r < 0) + continue; + y = lgammaf(p->x); + yi = signgam; + + printf("%g,%d\n", y, yi); + + d = ulperrf(y, p->y, p->dy); + if (!checkulp(d, p->r) || (!isnan(p->x) && p->x!=-inf && !(p->e&DIVBYZERO) && yi != p->i)) { + /* printf("%s:%d: %d lgammaf(%g) want %g,%lld got %g,%d ulperr %.3f = %g + %g\n", + p->file, p->line, p->r, p->x, p->y, p->i, y, yi, d, d-p->dy, p->dy); */ + err++; + } + } + return !!err; +} diff --git a/tests/math/lgamma.out b/tests/math/lgamma.out new file mode 100644 index 00000000..7412ffb6 --- /dev/null +++ b/tests/math/lgamma.out @@ -0,0 +1,18 @@ +-8.03528,-1 +2.24181,1 +-10.2138,-1 +-6.44641,-1 +11.1804,1 +0.309354,1 +1.3084,-1 +0.459903,1 +0.177784,1 +1.41155,-1 +inf,1 +0,1 +inf,1 +0,1 +inf,1 +inf,1 +inf,1 +nan,1 diff --git a/tests/test_core.py b/tests/test_core.py index 799e47f0..c89e785e 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -477,6 +477,14 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co self.do_run_from_file(src, output) + def test_literal_negative_zero(self): + if self.emcc_args == None: return self.skip('needs emcc') + + test_path = path_from_root('tests', 'core', 'test_literal_negative_zero') + src, output = (test_path + s for s in ('.in', '.out')) + + self.do_run_from_file(src, output) + def test_llvm_intrinsics(self): if self.emcc_args == None: return self.skip('needs ta2') @@ -502,6 +510,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co def test_cube2md5(self): if self.emcc_args == None: return self.skip('needs emcc') + if not self.is_le32(): return self.skip('le32 needed for accurate math') self.emcc_args += ['--embed-file', 'cube2md5.txt'] shutil.copyfile(path_from_root('tests', 'cube2md5.txt'), os.path.join(self.get_dir(), 'cube2md5.txt')) self.do_run(open(path_from_root('tests', 'cube2md5.cpp')).read(), open(path_from_root('tests', 'cube2md5.ok')).read()) @@ -829,6 +838,15 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co expected = open(path_from_root('tests', 'hyperbolic', 'output.txt'), 'r').read() self.do_run(src, expected) + def test_math_lgamma(self): + if self.emcc_args is None: return self.skip('requires emcc') + if not self.is_le32(): return self.skip('le32 needed for accurate math') + + test_path = path_from_root('tests', 'math', 'lgamma') + src, output = (test_path + s for s in ('.in', '.out')) + + self.do_run_from_file(src, output) + def test_frexp(self): test_path = path_from_root('tests', 'core', 'test_frexp') src, output = (test_path + s for s in ('.in', '.out')) @@ -1281,6 +1299,7 @@ class T(RunnerCore): # Short name, to make it more fun to use manually on the co self.do_run_from_file(src, output) + def test_white_list_exception(self): if os.environ.get('EMCC_FAST_COMPILER') == '1': return self.skip('todo in fastcomp') @@ -3536,6 +3555,7 @@ ok def test_strtod(self): if self.emcc_args is None: return self.skip('needs emcc for libc') + if not self.is_le32(): return self.skip('le32 needed for accurate math') src = r''' #include <stdio.h> @@ -3565,6 +3585,8 @@ ok printf("%g\n", strtod("123e-50", &endptr)); printf("%g\n", strtod("123e-250", &endptr)); printf("%g\n", strtod("123e-450", &endptr)); + printf("%g\n", strtod("0x6", &endptr)); + printf("%g\n", strtod("-0x0p+0", &endptr)); char str[] = " 12.34e56end"; printf("%g\n", strtod(str, &endptr)); @@ -3597,6 +3619,8 @@ ok 1.23e-48 1.23e-248 0 + 6 + -0 1.234e+57 10 inf @@ -3681,6 +3705,7 @@ ok def test_sscanf(self): if self.emcc_args is None: return self.skip('needs emcc for libc') + if not self.is_le32(): return self.skip('le32 needed for accurate math') test_path = path_from_root('tests', 'core', 'test_sscanf') src, output = (test_path + s for s in ('.in', '.out')) diff --git a/tools/shared.py b/tools/shared.py index efca1a85..32f8f797 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -345,7 +345,7 @@ def find_temp_directory(): # we re-check sanity when the settings are changed) # We also re-check sanity and clear the cache when the version changes -EMSCRIPTEN_VERSION = '1.8.7' +EMSCRIPTEN_VERSION = '1.8.8' def generate_sanity(): return EMSCRIPTEN_VERSION + '|' + get_llvm_target() + '|' + LLVM_ROOT + '|' + get_clang_version() |