aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-01-13 16:54:38 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-01-13 16:54:38 -0800
commit2914deb17f3857bb02eeec87a58a3ed6d4a8853a (patch)
tree5425d058e199bade4f43cf0dc526a52f4b556b71
parent7844db37f5b6dce1e7772f955ff606ef806ae032 (diff)
parentee4a2df911e834285aed9148eb4cab4546c8a063 (diff)
Merge pull request #2004 from waywardmonkeys/updates
Updates
-rwxr-xr-xemcc58
-rw-r--r--src/jsifier.js3
-rw-r--r--src/library.js11
-rw-r--r--src/parseTools.js7
-rw-r--r--system/include/libcxx/__config22
-rw-r--r--system/include/libcxx/__undef_min_max6
-rw-r--r--system/include/libcxx/experimental/dynarray (renamed from system/include/libcxx/dynarray)13
-rw-r--r--system/include/libcxx/experimental/optional (renamed from system/include/libcxx/optional)20
-rw-r--r--system/include/libcxx/ext/__hash2
-rw-r--r--system/include/libcxx/iomanip4
-rw-r--r--system/include/libcxx/memory39
-rw-r--r--system/include/libcxx/new6
-rw-r--r--system/include/libcxx/readme.txt2
-rw-r--r--system/include/libcxx/support/ibm/support.h2
-rw-r--r--system/include/libcxx/support/win32/locale_win32.h2
-rw-r--r--system/include/libcxx/support/win32/support.h1
-rw-r--r--system/include/libcxx/type_traits4
-rw-r--r--system/include/libcxx/utility4
-rw-r--r--system/lib/libc.symbols31
-rw-r--r--system/lib/libc/musl/src/internal/floatscan.c496
-rw-r--r--system/lib/libc/musl/src/internal/floatscan.h8
-rw-r--r--system/lib/libc/musl/src/internal/intscan.c99
-rw-r--r--system/lib/libc/musl/src/internal/intscan.h8
-rw-r--r--system/lib/libc/musl/src/internal/libm.h169
-rw-r--r--system/lib/libc/musl/src/internal/shgetc.c27
-rw-r--r--system/lib/libc/musl/src/internal/shgetc.h9
-rw-r--r--system/lib/libc/musl/src/locale/strcasecmp_l.c7
-rw-r--r--system/lib/libc/musl/src/locale/strncasecmp_l.c7
-rw-r--r--system/lib/libc/musl/src/math/__cosdf.c35
-rw-r--r--system/lib/libc/musl/src/math/__sindf.c36
-rw-r--r--system/lib/libc/musl/src/math/ilogb.c26
-rw-r--r--system/lib/libc/musl/src/math/ilogbf.c26
-rw-r--r--system/lib/libc/musl/src/math/ilogbl.c55
-rw-r--r--system/lib/libc/musl/src/math/ldexp.c6
-rw-r--r--system/lib/libc/musl/src/math/ldexpf.c6
-rw-r--r--system/lib/libc/musl/src/math/ldexpl.c6
-rw-r--r--system/lib/libc/musl/src/math/lgamma.c9
-rw-r--r--system/lib/libc/musl/src/math/lgamma_r.c314
-rw-r--r--system/lib/libc/musl/src/math/lgammaf.c9
-rw-r--r--system/lib/libc/musl/src/math/lgammaf_r.c249
-rw-r--r--system/lib/libc/musl/src/math/lgammal.c386
-rw-r--r--system/lib/libc/musl/src/math/logb.c17
-rw-r--r--system/lib/libc/musl/src/math/logbf.c10
-rw-r--r--system/lib/libc/musl/src/math/logbl.c16
-rw-r--r--system/lib/libc/musl/src/math/scalbn.c31
-rw-r--r--system/lib/libc/musl/src/math/scalbnf.c31
-rw-r--r--system/lib/libc/musl/src/math/scalbnl.c36
-rw-r--r--system/lib/libc/musl/src/math/signgam.c4
-rw-r--r--system/lib/libc/musl/src/math/tgamma.c222
-rw-r--r--system/lib/libc/musl/src/math/tgammaf.c6
-rw-r--r--system/lib/libc/musl/src/math/tgammal.c275
-rw-r--r--system/lib/libc/musl/src/stdio/__overflow.c10
-rw-r--r--system/lib/libc/musl/src/stdio/__toread.c24
-rw-r--r--system/lib/libc/musl/src/stdio/__uflow.c11
-rw-r--r--system/lib/libc/musl/src/stdlib/atof.c6
-rw-r--r--system/lib/libc/musl/src/stdlib/strtod.c40
-rw-r--r--system/lib/libc/musl/src/stdlib/wcstod.c64
-rw-r--r--system/lib/libc/musl/src/stdlib/wcstol.c82
-rw-r--r--system/lib/libc/musl/src/string/memccpy.c32
-rw-r--r--system/lib/libc/musl/src/string/memmem.c148
-rw-r--r--system/lib/libc/musl/src/string/mempcpy.c6
-rw-r--r--system/lib/libc/musl/src/string/memrchr.c12
-rw-r--r--system/lib/libc/musl/src/string/strcasestr.c9
-rw-r--r--system/lib/libc/musl/src/string/strchrnul.c27
-rw-r--r--system/lib/libc/musl/src/string/strlcat.c9
-rw-r--r--system/lib/libc/musl/src/string/strlcpy.c32
-rw-r--r--system/lib/libc/musl/src/string/strsep.c13
-rw-r--r--system/lib/libc/musl/src/string/strverscmp.c42
-rw-r--r--system/lib/libcextra.symbols49
-rw-r--r--system/lib/libcxx/exception.cpp2
-rw-r--r--system/lib/libcxx/locale.cpp2
-rw-r--r--system/lib/libcxx/new.cpp2
-rw-r--r--system/lib/libcxx/optional.cpp6
-rw-r--r--system/lib/libcxx/random.cpp2
-rw-r--r--system/lib/libcxx/readme.txt2
-rw-r--r--system/lib/libcxx/support/win32/locale_win32.cpp10
-rw-r--r--system/lib/libcxx/symbols2
-rw-r--r--system/lib/libcxxabi/CREDITS.TXT28
-rw-r--r--system/lib/libcxxabi/LICENSE.TXT4
-rw-r--r--system/lib/libcxxabi/include/cxa_demangle.h167
-rw-r--r--system/lib/libcxxabi/include/libunwind.h486
-rw-r--r--system/lib/libcxxabi/include/mach-o/compact_unwind_encoding.h487
-rw-r--r--system/lib/libcxxabi/include/unwind.h217
-rwxr-xr-xsystem/lib/libcxxabi/lib/buildit6
-rw-r--r--system/lib/libcxxabi/readme.txt2
-rw-r--r--system/lib/libcxxabi/src/Unwind/AddressSpace.hpp430
-rw-r--r--system/lib/libcxxabi/src/Unwind/CompactUnwinder.hpp693
-rw-r--r--system/lib/libcxxabi/src/Unwind/DwarfInstructions.hpp888
-rw-r--r--system/lib/libcxxabi/src/Unwind/DwarfParser.hpp713
-rw-r--r--system/lib/libcxxabi/src/Unwind/Registers.hpp1568
-rw-r--r--system/lib/libcxxabi/src/Unwind/Unwind-sjlj.c468
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindCursor.hpp1063
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindLevel1-gcc-ext.c268
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindLevel1.c495
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindRegistersRestore.S329
-rw-r--r--system/lib/libcxxabi/src/Unwind/UnwindRegistersSave.S301
-rw-r--r--system/lib/libcxxabi/src/Unwind/Unwind_AppleExtras.cpp205
-rw-r--r--system/lib/libcxxabi/src/Unwind/assembly.h44
-rw-r--r--system/lib/libcxxabi/src/Unwind/config.h108
-rw-r--r--system/lib/libcxxabi/src/Unwind/dwarf2.h237
-rw-r--r--system/lib/libcxxabi/src/Unwind/libunwind.cpp353
-rw-r--r--system/lib/libcxxabi/src/Unwind/libunwind_ext.h38
-rw-r--r--system/lib/libcxxabi/src/Unwind/unwind_ext.h37
-rw-r--r--system/lib/libcxxabi/src/cxa_default_handlers.cpp120
-rw-r--r--system/lib/libcxxabi/src/cxa_demangle.cpp13415
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.cpp2
-rw-r--r--system/lib/libcxxabi/src/cxa_exception.hpp18
-rw-r--r--system/lib/libcxxabi/src/cxa_new_delete.cpp36
-rw-r--r--system/lib/libcxxabi/src/private_typeinfo.cpp20
-rw-r--r--system/lib/libcxxabi/src/stdexcept.cpp16
-rw-r--r--system/lib/libcxxabi/symbols3
-rw-r--r--tests/core/test_literal_negative_zero.in27
-rw-r--r--tests/core/test_literal_negative_zero.out6
-rw-r--r--tests/math/lgamma.in105
-rw-r--r--tests/math/lgamma.out18
-rw-r--r--tests/test_core.py25
116 files changed, 16912 insertions, 10056 deletions
diff --git a/emcc b/emcc
index ba927da5..4d6b8a73 100755
--- a/emcc
+++ b/emcc
@@ -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 6cbe7854..af37130c 100644
--- a/src/library.js
+++ b/src/library.js
@@ -4827,15 +4827,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);
},
@@ -9190,7 +9181,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 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86 &registers);
+ static void framelessUnwind(A &addressSpace,
+ typename A::pint_t returnAddressLocation,
+ Registers_x86 &registers);
+ static int
+ stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint32_t functionStart, A &addressSpace,
+ Registers_x86 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers) {
+ 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 &registers) {
+ 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 &registers, 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 &registers) {
+ 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 &registers) {
+ // 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 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
+ static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
+ Registers_x86_64 &registers);
+ static int
+ stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers) {
+ 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 &registers) {
+ 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 &registers, 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 &registers) {
+ 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 &registers) {
+ // 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 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static int
+ stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_arm64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers);
+};
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers) {
+ 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 &registers) {
+ 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 &registers) {
+ 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 &registers);
+
+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 &registers,
+ pint_t initialStackValue);
+ static pint_t getSavedRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static double getSavedFloatRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
+ 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 &registers, 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 &registers, 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 &registers, 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 &registers) {
+ 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 &registers,
+ 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 &registers) {
+ 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 &registers) {
+ 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 &registers) {
+ 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 &registers) {
+ 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 &sects,
+ 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 &sects);
+ 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 &sects,
+ 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 &sects) {
+ 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..826437b1 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'))