diff --git a/demangle/Android.bp b/demangle/Android.bp new file mode 100644 index 000000000..e80cdc549 --- /dev/null +++ b/demangle/Android.bp @@ -0,0 +1,65 @@ +// +// Copyright (C) 2017 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_defaults { + name: "libdemangle_defaults", + + host_supported: true, + + cflags: [ + "-Wall", + "-Werror", + "-Wextra", + ], +} + +cc_library { + name: "libdemangle", + defaults: ["libdemangle_defaults"], + + srcs: [ + "Demangler.cpp", + ], + + local_include_dirs: [ + "include", + ], + + export_include_dirs: [ + "include", + ], +} + +//------------------------------------------------------------------------- +// Unit Tests +//------------------------------------------------------------------------- +cc_test { + name: "libdemangle_test", + defaults: ["libdemangle_defaults"], + + srcs: [ + "DemangleTest.cpp", + ], + + cflags: [ + "-O0", + "-g", + ], + + shared_libs: [ + "libdemangle", + ], +} diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp new file mode 100644 index 000000000..fb6811947 --- /dev/null +++ b/demangle/DemangleTest.cpp @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +#include "Demangler.h" + +TEST(DemangleTest, VoidArgumentTest) { + Demangler demangler; + + ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv")); + ASSERT_EQ("func(void&)", demangler.Parse("_ZN4funcERv")); + ASSERT_EQ("func(void, void)", demangler.Parse("_ZN4funcEvv")); + ASSERT_EQ("func(void*)", demangler.Parse("_ZN4funcEPv")); + ASSERT_EQ("func(void const)", demangler.Parse("_ZN4funcEKv")); + ASSERT_EQ("func(void volatile)", demangler.Parse("_ZN4funcEVv")); +} + +TEST(DemangleTest, ArgumentModifiers) { + Demangler demangler; + + ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc")); + ASSERT_EQ("func(char*)", demangler.Parse("_ZN4funcEPc")); + ASSERT_EQ("func(char**)", demangler.Parse("_ZN4funcEPPc")); + ASSERT_EQ("func(char***)", demangler.Parse("_ZN4funcEPPPc")); + ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERc")); + ASSERT_EQ("func(char*&)", demangler.Parse("_ZN4funcERPc")); + ASSERT_EQ("func(char&)", demangler.Parse("_ZN4funcERRc")); + ASSERT_EQ("func(char*&*)", demangler.Parse("_ZN4funcEPRPc")); + ASSERT_EQ("func(char**&)", demangler.Parse("_ZN4funcERRPPc")); + ASSERT_EQ("func(char const)", demangler.Parse("_ZN4funcEKc")); + ASSERT_EQ("func(char volatile)", demangler.Parse("_ZN4funcEVc")); + ASSERT_EQ("func(char volatile const)", demangler.Parse("_ZN4funcEKVc")); + ASSERT_EQ("func(char const volatile)", demangler.Parse("_ZN4funcEVKc")); + ASSERT_EQ("func(char const* volatile&)", demangler.Parse("_ZN4funcERVPKc")); + ASSERT_EQ("func(void, char, short)", demangler.Parse("_ZN4funcEvcs")); + ASSERT_EQ("func(void*, char&, short&*)", demangler.Parse("_ZN4funcEPvRcPRs")); +} + +TEST(DemangleTest, FunctionModifiers) { + Demangler demangler; + + ASSERT_EQ("func() const", demangler.Parse("_ZNK4funcEv")); + ASSERT_EQ("func() volatile", demangler.Parse("_ZNV4funcEv")); + ASSERT_EQ("func() volatile const", demangler.Parse("_ZNKV4funcEv")); + ASSERT_EQ("func() const volatile", demangler.Parse("_ZNVK4funcEv")); +} + +TEST(DemangleTest, MultiplePartsInName) { + Demangler demangler; + + ASSERT_EQ("one::two()", demangler.Parse("_ZN3one3twoEv")); + ASSERT_EQ("one::two::three()", demangler.Parse("_ZN3one3two5threeEv")); + ASSERT_EQ("one::two::three::four()", demangler.Parse("_ZN3one3two5three4fourEv")); + ASSERT_EQ("one::two::three::four::five()", demangler.Parse("_ZN3one3two5three4four4fiveEv")); + ASSERT_EQ("one(two::three::four::five)", demangler.Parse("_ZN3oneEN3two5three4four4fiveE")); +} + +TEST(DemangleTest, AnonymousNamespace) { + Demangler demangler; + + ASSERT_EQ("(anonymous namespace)::two()", demangler.Parse("_ZN12_GLOBAL__N_13twoEv")); + ASSERT_EQ("one::two((anonymous namespace))", demangler.Parse("_ZN3one3twoE12_GLOBAL__N_1")); +} + +TEST(DemangleTest, DestructorValues) { + Demangler demangler; + + ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD0Ev")); + ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD1Ev")); + ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD2Ev")); + ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoD5Ev")); + ASSERT_EQ("one::two::three::~three()", demangler.Parse("_ZN3one3two5threeD0Ev")); + + ASSERT_EQ("_ZN3one3twoD3Ev", demangler.Parse("_ZN3one3twoD3Ev")); + ASSERT_EQ("_ZN3one3twoD4Ev", demangler.Parse("_ZN3one3twoD4Ev")); + ASSERT_EQ("_ZN3one3twoD6Ev", demangler.Parse("_ZN3one3twoD6Ev")); + ASSERT_EQ("_ZN3one3twoD7Ev", demangler.Parse("_ZN3one3twoD7Ev")); + ASSERT_EQ("_ZN3one3twoD8Ev", demangler.Parse("_ZN3one3twoD8Ev")); + ASSERT_EQ("_ZN3one3twoD9Ev", demangler.Parse("_ZN3one3twoD9Ev")); + + ASSERT_EQ("one::two::~two()", demangler.Parse("_ZN3one3twoIN5three4fourEED2Ev")); +} + +TEST(DemangleTest, ConstructorValues) { + Demangler demangler; + + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC1Ev")); + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC2Ev")); + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC3Ev")); + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoC5Ev")); + ASSERT_EQ("one::two::three::three()", demangler.Parse("_ZN3one3two5threeC1Ev")); + + ASSERT_EQ("_ZN3one3twoC0Ev", demangler.Parse("_ZN3one3twoC0Ev")); + ASSERT_EQ("_ZN3one3twoC4Ev", demangler.Parse("_ZN3one3twoC4Ev")); + ASSERT_EQ("_ZN3one3twoC6Ev", demangler.Parse("_ZN3one3twoC6Ev")); + ASSERT_EQ("_ZN3one3twoC7Ev", demangler.Parse("_ZN3one3twoC7Ev")); + ASSERT_EQ("_ZN3one3twoC8Ev", demangler.Parse("_ZN3one3twoC8Ev")); + ASSERT_EQ("_ZN3one3twoC9Ev", demangler.Parse("_ZN3one3twoC9Ev")); + + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoIN5three4fourEEC1Ev")); +} + +TEST(DemangleTest, OperatorValues) { + Demangler demangler; + + ASSERT_EQ("operator&&()", demangler.Parse("_Zaav")); + ASSERT_EQ("operator&()", demangler.Parse("_Zadv")); + ASSERT_EQ("operator&()", demangler.Parse("_Zanv")); + ASSERT_EQ("operator&=()", demangler.Parse("_ZaNv")); + ASSERT_EQ("operator=()", demangler.Parse("_ZaSv")); + ASSERT_EQ("operator()()", demangler.Parse("_Zclv")); + ASSERT_EQ("operator,()", demangler.Parse("_Zcmv")); + ASSERT_EQ("operator~()", demangler.Parse("_Zcov")); + ASSERT_EQ("operator delete[]()", demangler.Parse("_Zdav")); + ASSERT_EQ("operator*()", demangler.Parse("_Zdev")); + ASSERT_EQ("operator delete()", demangler.Parse("_Zdlv")); + ASSERT_EQ("operator/()", demangler.Parse("_Zdvv")); + ASSERT_EQ("operator/=()", demangler.Parse("_ZdVv")); + ASSERT_EQ("operator^()", demangler.Parse("_Zeov")); + ASSERT_EQ("operator^=()", demangler.Parse("_ZeOv")); + ASSERT_EQ("operator==()", demangler.Parse("_Zeqv")); + ASSERT_EQ("operator>=()", demangler.Parse("_Zgev")); + ASSERT_EQ("operator>()", demangler.Parse("_Zgtv")); + ASSERT_EQ("operator[]()", demangler.Parse("_Zixv")); + ASSERT_EQ("operator<=()", demangler.Parse("_Zlev")); + ASSERT_EQ("operator<<()", demangler.Parse("_Zlsv")); + ASSERT_EQ("operator<<=()", demangler.Parse("_ZlSv")); + ASSERT_EQ("operator<()", demangler.Parse("_Zltv")); + ASSERT_EQ("operator-()", demangler.Parse("_Zmiv")); + ASSERT_EQ("operator-=()", demangler.Parse("_ZmIv")); + ASSERT_EQ("operator*()", demangler.Parse("_Zmlv")); + ASSERT_EQ("operator*=()", demangler.Parse("_ZmLv")); + ASSERT_EQ("operator--()", demangler.Parse("_Zmmv")); + ASSERT_EQ("operator new[]()", demangler.Parse("_Znav")); + ASSERT_EQ("operator!=()", demangler.Parse("_Znev")); + ASSERT_EQ("operator-()", demangler.Parse("_Zngv")); + ASSERT_EQ("operator!()", demangler.Parse("_Zntv")); + ASSERT_EQ("operator new()", demangler.Parse("_Znwv")); + ASSERT_EQ("operator||()", demangler.Parse("_Zoov")); + ASSERT_EQ("operator|()", demangler.Parse("_Zorv")); + ASSERT_EQ("operator|=()", demangler.Parse("_ZoRv")); + ASSERT_EQ("operator->*()", demangler.Parse("_Zpmv")); + ASSERT_EQ("operator+()", demangler.Parse("_Zplv")); + ASSERT_EQ("operator+=()", demangler.Parse("_ZpLv")); + ASSERT_EQ("operator++()", demangler.Parse("_Zppv")); + ASSERT_EQ("operator+()", demangler.Parse("_Zpsv")); + ASSERT_EQ("operator->()", demangler.Parse("_Zptv")); + ASSERT_EQ("operator?()", demangler.Parse("_Zquv")); + ASSERT_EQ("operator%()", demangler.Parse("_Zrmv")); + ASSERT_EQ("operator%=()", demangler.Parse("_ZrMv")); + ASSERT_EQ("operator>>()", demangler.Parse("_Zrsv")); + ASSERT_EQ("operator>>=()", demangler.Parse("_ZrSv")); + + // Spot check using an operator as part of function name. + ASSERT_EQ("operator&&()", demangler.Parse("_ZNaaEv")); + ASSERT_EQ("operator++()", demangler.Parse("_ZNppEv")); + ASSERT_EQ("one::operator++()", demangler.Parse("_ZN3oneppEv")); + + // Spot check using an operator in an argument name. + ASSERT_EQ("operator+(operator|=)", demangler.Parse("_ZNpsENoRE")); + ASSERT_EQ("operator==()", demangler.Parse("_Zeqv")); + ASSERT_EQ("one(arg1::operator|=, arg2::operator==)", + demangler.Parse("_ZN3oneEN4arg1oREN4arg2eqE")); +} + +TEST(DemangleTest, FunctionStartsWithNumber) { + Demangler demangler; + + ASSERT_EQ("value(char, int)", demangler.Parse("_Z5valueci")); + ASSERT_EQ("abcdefjklmn(signed char)", demangler.Parse("_Z11abcdefjklmna")); + ASSERT_EQ("value(one, signed char)", demangler.Parse("_Z5value3onea")); +} + +TEST(DemangleTest, StdTypes) { + Demangler demangler; + + ASSERT_EQ("std::one", demangler.Parse("_ZNSt3oneE")); + ASSERT_EQ("std::one(std::two)", demangler.Parse("_ZNSt3oneESt3two")); + ASSERT_EQ("std::std::one(std::two)", demangler.Parse("_ZNStSt3oneESt3two")); + ASSERT_EQ("std()", demangler.Parse("_ZNStEv")); + ASSERT_EQ("one::std::std::two::~two(one::std::std::two)", + demangler.Parse("_ZN3oneStSt3twoD0ES0_")); + + ASSERT_EQ("std::allocator", demangler.Parse("_ZNSaE")); + ASSERT_EQ("std::basic_string", demangler.Parse("_ZNSbE")); + ASSERT_EQ("_ZNScE", demangler.Parse("_ZNScE")); + ASSERT_EQ("std::iostream", demangler.Parse("_ZNSdE")); + ASSERT_EQ("_ZNSeE", demangler.Parse("_ZNSeE")); + ASSERT_EQ("_ZNSfE", demangler.Parse("_ZNSfE")); + ASSERT_EQ("_ZNSgE", demangler.Parse("_ZNSgE")); + ASSERT_EQ("_ZNShE", demangler.Parse("_ZNShE")); + ASSERT_EQ("std::istream", demangler.Parse("_ZNSiE")); + ASSERT_EQ("_ZNSjE", demangler.Parse("_ZNSjE")); + ASSERT_EQ("_ZNSkE", demangler.Parse("_ZNSkE")); + ASSERT_EQ("_ZNSlE", demangler.Parse("_ZNSlE")); + ASSERT_EQ("_ZNSmE", demangler.Parse("_ZNSmE")); + ASSERT_EQ("_ZNSnE", demangler.Parse("_ZNSnE")); + ASSERT_EQ("std::ostream", demangler.Parse("_ZNSoE")); + ASSERT_EQ("_ZNSpE", demangler.Parse("_ZNSpE")); + ASSERT_EQ("_ZNSqE", demangler.Parse("_ZNSqE")); + ASSERT_EQ("_ZNSrE", demangler.Parse("_ZNSrE")); + ASSERT_EQ("std::string", demangler.Parse("_ZNSsE")); + ASSERT_EQ("_ZNSuE", demangler.Parse("_ZNSuE")); + ASSERT_EQ("_ZNSvE", demangler.Parse("_ZNSvE")); + ASSERT_EQ("_ZNSwE", demangler.Parse("_ZNSwE")); + ASSERT_EQ("_ZNSxE", demangler.Parse("_ZNSxE")); + ASSERT_EQ("_ZNSyE", demangler.Parse("_ZNSyE")); + ASSERT_EQ("_ZNSzE", demangler.Parse("_ZNSzE")); +} + +TEST(DemangleTest, SingleLetterArguments) { + Demangler demangler; + + ASSERT_EQ("func(signed char)", demangler.Parse("_ZN4funcEa")); + ASSERT_EQ("func(bool)", demangler.Parse("_ZN4funcEb")); + ASSERT_EQ("func(char)", demangler.Parse("_ZN4funcEc")); + ASSERT_EQ("func(double)", demangler.Parse("_ZN4funcEd")); + ASSERT_EQ("func(long double)", demangler.Parse("_ZN4funcEe")); + ASSERT_EQ("func(float)", demangler.Parse("_ZN4funcEf")); + ASSERT_EQ("func(__float128)", demangler.Parse("_ZN4funcEg")); + ASSERT_EQ("func(unsigned char)", demangler.Parse("_ZN4funcEh")); + ASSERT_EQ("func(int)", demangler.Parse("_ZN4funcEi")); + ASSERT_EQ("func(unsigned int)", demangler.Parse("_ZN4funcEj")); + ASSERT_EQ("_ZN4funcEk", demangler.Parse("_ZN4funcEk")); + ASSERT_EQ("func(long)", demangler.Parse("_ZN4funcEl")); + ASSERT_EQ("func(unsigned long)", demangler.Parse("_ZN4funcEm")); + ASSERT_EQ("func(__int128)", demangler.Parse("_ZN4funcEn")); + ASSERT_EQ("func(unsigned __int128)", demangler.Parse("_ZN4funcEo")); + ASSERT_EQ("_ZN4funcEp", demangler.Parse("_ZN4funcEp")); + ASSERT_EQ("_ZN4funcEq", demangler.Parse("_ZN4funcEq")); + ASSERT_EQ("_ZN4funcEr", demangler.Parse("_ZN4funcEr")); + ASSERT_EQ("func(short)", demangler.Parse("_ZN4funcEs")); + ASSERT_EQ("func(unsigned short)", demangler.Parse("_ZN4funcEt")); + ASSERT_EQ("_ZN4funcEu", demangler.Parse("_ZN4funcEu")); + ASSERT_EQ("func()", demangler.Parse("_ZN4funcEv")); + ASSERT_EQ("func(wchar_t)", demangler.Parse("_ZN4funcEw")); + ASSERT_EQ("func(long long)", demangler.Parse("_ZN4funcEx")); + ASSERT_EQ("func(unsigned long long)", demangler.Parse("_ZN4funcEy")); + ASSERT_EQ("func(...)", demangler.Parse("_ZN4funcEz")); +} + +TEST(DemangleTest, DArguments) { + Demangler demangler; + + ASSERT_EQ("func(auto)", demangler.Parse("_ZN4funcEDa")); + ASSERT_EQ("_ZN4funcEDb", demangler.Parse("_ZN4funcEDb")); + ASSERT_EQ("_ZN4funcEDc", demangler.Parse("_ZN4funcEDc")); + ASSERT_EQ("func(decimal64)", demangler.Parse("_ZN4funcEDd")); + ASSERT_EQ("func(decimal128)", demangler.Parse("_ZN4funcEDe")); + ASSERT_EQ("func(decimal32)", demangler.Parse("_ZN4funcEDf")); + ASSERT_EQ("_ZN4funcEDg", demangler.Parse("_ZN4funcEDg")); + ASSERT_EQ("func(half)", demangler.Parse("_ZN4funcEDh")); + ASSERT_EQ("func(char32_t)", demangler.Parse("_ZN4funcEDi")); + ASSERT_EQ("_ZN4funcEDj", demangler.Parse("_ZN4funcEDj")); + ASSERT_EQ("_ZN4funcEDk", demangler.Parse("_ZN4funcEDk")); + ASSERT_EQ("_ZN4funcEDl", demangler.Parse("_ZN4funcEDl")); + ASSERT_EQ("_ZN4funcEDm", demangler.Parse("_ZN4funcEDm")); + ASSERT_EQ("func(decltype(nullptr))", demangler.Parse("_ZN4funcEDn")); + ASSERT_EQ("_ZN4funcEDo", demangler.Parse("_ZN4funcEDo")); + ASSERT_EQ("_ZN4funcEDp", demangler.Parse("_ZN4funcEDp")); + ASSERT_EQ("_ZN4funcEDq", demangler.Parse("_ZN4funcEDq")); + ASSERT_EQ("_ZN4funcEDr", demangler.Parse("_ZN4funcEDr")); + ASSERT_EQ("func(char16_t)", demangler.Parse("_ZN4funcEDs")); + ASSERT_EQ("_ZN4funcEDt", demangler.Parse("_ZN4funcEDt")); + ASSERT_EQ("_ZN4funcEDu", demangler.Parse("_ZN4funcEDu")); + ASSERT_EQ("_ZN4funcEDv", demangler.Parse("_ZN4funcEDv")); + ASSERT_EQ("_ZN4funcEDw", demangler.Parse("_ZN4funcEDw")); + ASSERT_EQ("_ZN4funcEDx", demangler.Parse("_ZN4funcEDx")); + ASSERT_EQ("_ZN4funcEDy", demangler.Parse("_ZN4funcEDy")); + ASSERT_EQ("_ZN4funcEDz", demangler.Parse("_ZN4funcEDz")); +} + +TEST(DemangleTest, FunctionArguments) { + Demangler demangler; + + ASSERT_EQ("func(char ())", demangler.Parse("_ZN4funcEFcvE")); + ASSERT_EQ("func(char (*)())", demangler.Parse("_ZN4funcEPFcvE")); + ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE")); + ASSERT_EQ("func(char (&)())", demangler.Parse("_ZN4funcERFcvE")); + ASSERT_EQ("func(char (*&)())", demangler.Parse("_ZN4funcERPFcvE")); + ASSERT_EQ("func(char (*)(int) const)", demangler.Parse("_ZN4funcEPKFciE")); + ASSERT_EQ("func(char (&)() const)", demangler.Parse("_ZN4funcERKFcvE")); + ASSERT_EQ("func(char (&)() volatile)", demangler.Parse("_ZN4funcERVFcvE")); + ASSERT_EQ("func(char (&)() volatile const)", demangler.Parse("_ZN4funcERKVFcvE")); + ASSERT_EQ("func(char (&)() const volatile)", demangler.Parse("_ZN4funcERVKFcvE")); + ASSERT_EQ("func(char (&)(int, signed char) const)", demangler.Parse("_ZN4funcERKFciaE")); + ASSERT_EQ("fake(char (&* volatile const)(void, void, signed char), signed char)", + demangler.Parse("_ZN4fakeEKVPRFcvvaEa")); +} + +TEST(DemangleTest, TemplateFunction) { + Demangler demangler; + + ASSERT_EQ("one", demangler.Parse("_ZN3oneIcEE")); + ASSERT_EQ("one", demangler.Parse("_ZN3oneIvEE")); + ASSERT_EQ("one", demangler.Parse("_ZN3oneIPvEE")); + ASSERT_EQ("one", demangler.Parse("_ZN3oneIKvEE")); + ASSERT_EQ("one", demangler.Parse("_ZN3oneIcibEE")); + ASSERT_EQ("one::two", demangler.Parse("_ZN3one3twoIN5threeEEE")); + ASSERT_EQ("one", demangler.Parse("_ZN3oneIciN3two5threeEEE")); + // Template within templates. + ASSERT_EQ("one::two>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE")); + ASSERT_EQ("one::two>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE")); +} + +TEST(DemangleTest, TemplateArguments) { + Demangler demangler; + + ASSERT_EQ("one(two)", demangler.Parse("_ZN3oneE3twoIcE")); + ASSERT_EQ("one(two)", demangler.Parse("_ZN3oneE3twoIcvE")); + ASSERT_EQ("one(two>)", + demangler.Parse("_ZN3oneE3twoIcv5threeI4fouriEE")); +} + +TEST(DemangleTest, SubstitutionUnderscore) { + Demangler demangler; + + ASSERT_EQ("a::a", demangler.Parse("_ZN1aS_E")); + ASSERT_EQ("one::one", demangler.Parse("_ZN3oneS_E")); + ASSERT_EQ("one::two::one", demangler.Parse("_ZN3one3twoS_E")); + ASSERT_EQ("one::two::three::one", demangler.Parse("_ZN3one3two5threeS_E")); + ASSERT_EQ("one::two(one)", demangler.Parse("_ZN3one3twoES_")); + ASSERT_EQ("one::two(three::one)", demangler.Parse("_ZN3one3twoEN5threeS_E")); + + // Special case that St is part of the saved value used in the substitution. + ASSERT_EQ("std::one::std::one", demangler.Parse("_ZNSt3oneS_E")); + + // Multiple substitutions in the string. + ASSERT_EQ("one::one(one, one)", demangler.Parse("_ZN3oneS_ES_S_")); + ASSERT_EQ("std::one::two::std::one(std::one)", demangler.Parse("_ZNSt3one3twoS_ES_")); +} + +TEST(DemangleTest, SubstitutionByNumber) { + Demangler demangler; + + // Basic substitution. + ASSERT_EQ("a::b::c(a::b)", demangler.Parse("_ZN1a1b1cES0_")); + ASSERT_EQ("_ZN1a1b1cES1_", demangler.Parse("_ZN1a1b1cES1_")); + ASSERT_EQ("a::b::c::d(a::b::c)", demangler.Parse("_ZN1a1b1c1dES1_")); + ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l)", + demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESA_")); + ASSERT_EQ("a::b::c::d::e::f::g::h::i::j::k::l::m::n::o::p::q(a::b::c::d::e::f::g::h::i::j::k::l::m)", + demangler.Parse("_ZN1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1qESB_")); + + // Verify argument modifiers are included in substitution list. + ASSERT_EQ("one::two(char&* volatile const, char&)", demangler.Parse("_ZN3one3twoEKVPRcS0_")); + ASSERT_EQ("one::two(char&* volatile const, char&*)", demangler.Parse("_ZN3one3twoEKVPRcS1_")); + ASSERT_EQ("one::two(char&* volatile const, char&* volatile const)", + demangler.Parse("_ZN3one3twoEKVPRcS2_")); + ASSERT_EQ("one::two(int&* volatile* const, int&)", demangler.Parse("_ZN3one3twoEKPVPRiS0_")); + ASSERT_EQ("one::two(int&* volatile const, int&*)", demangler.Parse("_ZN3one3twoEKVPRiS1_")); + ASSERT_EQ("one::two(int&* volatile const, int&* volatile const)", + demangler.Parse("_ZN3one3twoEKVPRiS2_")); + + // Verify Constructor/Destructor does properly save from function name. + ASSERT_EQ("_ZN1a1bES0_", demangler.Parse("_ZN1a1bES0_")); + ASSERT_EQ("a::b::b(a::b)", demangler.Parse("_ZN1a1bC1ES0_")); + ASSERT_EQ("a::b::~b(a::b)", demangler.Parse("_ZN1a1bD0ES0_")); + + // Make sure substitution values are not saved. + ASSERT_EQ("a::b::b(a::b, char*, char*)", demangler.Parse("_ZN1a1bC1ES0_PcS1_")); +} + +TEST(DemangleTest, ComplexSubstitution) { + Demangler demangler; + + ASSERT_EQ("one::two::two()", demangler.Parse("_ZN3one3twoINS_5threeEEC1Ev")); + ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)", + demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE")); + ASSERT_EQ("one::two::three::four::~four(one::two*)", + demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS0_")); + ASSERT_EQ("one::two::three::four::~four(one::two::three*)", + demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS1_")); + ASSERT_EQ("one::two::three::four::~four(one::two::three::four*)", + demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS2_")); + ASSERT_EQ("one::two::three::four::~four(one::five*)", + demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_")); +} + +TEST(DemangleTest, StringTooLong) { + Demangler demangler; + + ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE", + demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 10)); + ASSERT_EQ("_ZN3one3twoC2ERKS0_bPNS_5threeE", + demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 30)); + ASSERT_EQ("one::two::two(one::two const&, bool, one::three*)", + demangler.Parse("_ZN3one3twoC2ERKS0_bPNS_5threeE", 31)); + + // Check the length check only occurs after the two letter value + // has been processed. + ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 15)); + ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 14)); + ASSERT_EQ("one::two(auto)", demangler.Parse("_ZN3one3twoEDa", 13)); + ASSERT_EQ("_ZN3one3twoEDa", demangler.Parse("_ZN3one3twoEDa", 12)); +} + +TEST(DemangleTest, demangle) { + std::string str; + + str = demangle("_ZN1a1b1cES0_"); + ASSERT_EQ("a::b::c(a::b)", str); + + str = demangle("_"); + ASSERT_EQ("_", str); + + str = demangle("_Z"); + ASSERT_EQ("_Z", str); + + str = demangle("_Za"); + ASSERT_EQ("_Za", str); + + str = demangle("_Zaa"); + ASSERT_EQ("operator&&", str); + + str = demangle("Xa"); + ASSERT_EQ("Xa", str); +} diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp new file mode 100644 index 000000000..77cfd3be6 --- /dev/null +++ b/demangle/Demangler.cpp @@ -0,0 +1,746 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +#include "Demangler.h" + +constexpr const char* Demangler::kTypes[]; +constexpr const char* Demangler::kDTypes[]; +constexpr const char* Demangler::kSTypes[]; + +void Demangler::Save(const std::string& str, bool is_name) { + saves_.push_back(str); + last_save_name_ = is_name; +} + +std::string Demangler::GetArgumentsString() { + size_t num_args = cur_state_.args.size(); + std::string arg_str; + if (num_args > 0) { + arg_str = cur_state_.args[0]; + for (size_t i = 1; i < num_args; i++) { + arg_str += ", " + cur_state_.args[i]; + } + } + return arg_str; +} + +const char* Demangler::AppendOperatorString(const char* name) { + const char* oper = nullptr; + switch (*name) { + case 'a': + name++; + switch (*name) { + case 'a': + oper = "operator&&"; + break; + case 'd': + case 'n': + oper = "operator&"; + break; + case 'N': + oper = "operator&="; + break; + case 'S': + oper = "operator="; + break; + } + break; + case 'c': + name++; + switch (*name) { + case 'l': + oper = "operator()"; + break; + case 'm': + oper = "operator,"; + break; + case 'o': + oper = "operator~"; + break; + } + break; + case 'd': + name++; + switch (*name) { + case 'a': + oper = "operator delete[]"; + break; + case 'e': + oper = "operator*"; + break; + case 'l': + oper = "operator delete"; + break; + case 'v': + oper = "operator/"; + break; + case 'V': + oper = "operator/="; + break; + } + break; + case 'e': + name++; + switch (*name) { + case 'o': + oper = "operator^"; + break; + case 'O': + oper = "operator^="; + break; + case 'q': + oper = "operator=="; + break; + } + break; + case 'g': + name++; + switch (*name) { + case 'e': + oper = "operator>="; + break; + case 't': + oper = "operator>"; + break; + } + break; + case 'i': + name++; + switch (*name) { + case 'x': + oper = "operator[]"; + break; + } + break; + case 'l': + name++; + switch (*name) { + case 'e': + oper = "operator<="; + break; + case 's': + oper = "operator<<"; + break; + case 'S': + oper = "operator<<="; + break; + case 't': + oper = "operator<"; + break; + } + break; + case 'm': + name++; + switch (*name) { + case 'i': + oper = "operator-"; + break; + case 'I': + oper = "operator-="; + break; + case 'l': + oper = "operator*"; + break; + case 'L': + oper = "operator*="; + break; + case 'm': + oper = "operator--"; + break; + } + break; + case 'n': + name++; + switch (*name) { + case 'a': + oper = "operator new[]"; + break; + case 'e': + oper = "operator!="; + break; + case 'g': + oper = "operator-"; + break; + case 't': + oper = "operator!"; + break; + case 'w': + oper = "operator new"; + break; + } + break; + case 'o': + name++; + switch (*name) { + case 'o': + oper = "operator||"; + break; + case 'r': + oper = "operator|"; + break; + case 'R': + oper = "operator|="; + break; + } + break; + case 'p': + name++; + switch (*name) { + case 'm': + oper = "operator->*"; + break; + case 'l': + oper = "operator+"; + break; + case 'L': + oper = "operator+="; + break; + case 'p': + oper = "operator++"; + break; + case 's': + oper = "operator+"; + break; + case 't': + oper = "operator->"; + break; + } + break; + case 'q': + name++; + switch (*name) { + case 'u': + oper = "operator?"; + break; + } + break; + case 'r': + name++; + switch (*name) { + case 'm': + oper = "operator%"; + break; + case 'M': + oper = "operator%="; + break; + case 's': + oper = "operator>>"; + break; + case 'S': + oper = "operator>>="; + break; + } + break; + } + if (oper == nullptr) { + return nullptr; + } + AppendCurrent(oper); + cur_state_.last_save = oper; + return name + 1; +} + +const char* Demangler::GetStringFromLength(const char* name, std::string* str) { + assert(std::isdigit(*name)); + + size_t length = *name - '0'; + name++; + while (*name != '\0' && std::isdigit(*name)) { + length = length * 10 + *name - '0'; + name++; + } + + std::string read_str; + while (*name != '\0' && length != 0) { + read_str += *name; + name++; + length--; + } + if (length != 0) { + return nullptr; + } + // Special replacement of _GLOBAL__N_1 to (anonymous namespace). + if (read_str == "_GLOBAL__N_1") { + *str += "(anonymous namespace)"; + } else { + *str += read_str; + } + return name; +} + +void Demangler::AppendCurrent(const std::string& str) { + if (!cur_state_.str.empty()) { + cur_state_.str += "::"; + } + cur_state_.str += str; +} + +void Demangler::AppendCurrent(const char* str) { + if (!cur_state_.str.empty()) { + cur_state_.str += "::"; + } + cur_state_.str += str; +} + +const char* Demangler::ParseS(const char* name) { + if (std::islower(*name)) { + const char* type = kSTypes[*name - 'a']; + if (type == nullptr) { + return nullptr; + } + AppendCurrent(type); + return name + 1; + } + + if (saves_.empty()) { + return nullptr; + } + + if (*name == '_') { + last_save_name_ = false; + AppendCurrent(saves_[0]); + return name + 1; + } + + bool isdigit = std::isdigit(*name); + if (!isdigit && !std::isupper(*name)) { + return nullptr; + } + + size_t index; + if (isdigit) { + index = *name - '0' + 1; + } else { + index = *name - 'A' + 11; + } + name++; + if (*name != '_') { + return nullptr; + } + + if (index >= saves_.size()) { + return nullptr; + } + + last_save_name_ = false; + AppendCurrent(saves_[index]); + return name + 1; +} + +const char* Demangler::ParseFunctionName(const char* name) { + if (*name == 'E') { + if (parse_funcs_.empty()) { + return nullptr; + } + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + + // Remove the last saved part so that the full function name is not saved. + // But only if the last save was not something like a substitution. + if (!saves_.empty() && last_save_name_) { + saves_.pop_back(); + } + + function_name_ = cur_state_.str; + while (!cur_state_.suffixes.empty()) { + function_suffix_ += cur_state_.suffixes.back(); + cur_state_.suffixes.pop_back(); + } + cur_state_.Clear(); + + return name + 1; + } + + return ParseComplexString(name); +} + +const char* Demangler::ParseComplexArgument(const char* name) { + if (*name == 'E') { + if (parse_funcs_.empty()) { + return nullptr; + } + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + + AppendArgument(cur_state_.str); + cur_state_.str.clear(); + + return name + 1; + } + + return ParseComplexString(name); +} + +void Demangler::FinalizeTemplate() { + std::string arg_str(GetArgumentsString()); + cur_state_ = state_stack_.top(); + state_stack_.pop(); + cur_state_.str += '<' + arg_str + '>'; +} + +const char* Demangler::ParseComplexString(const char* name) { + if (*name == 'S') { + name++; + if (*name == 't') { + AppendCurrent("std"); + return name + 1; + } + return ParseS(name); + } + if (*name == 'L') { + name++; + if (!std::isdigit(*name)) { + return nullptr; + } + } + if (std::isdigit(*name)) { + std::string str; + name = GetStringFromLength(name, &str); + if (name == nullptr) { + return name; + } + AppendCurrent(str); + Save(cur_state_.str, true); + cur_state_.last_save = std::move(str); + return name; + } + if (*name == 'D') { + name++; + if (saves_.empty() || (*name != '0' && *name != '1' && *name != '2' + && *name != '5')) { + return nullptr; + } + last_save_name_ = false; + AppendCurrent("~" + cur_state_.last_save); + return name + 1; + } + if (*name == 'C') { + name++; + if (saves_.empty() || (*name != '1' && *name != '2' && *name != '3' + && *name != '5')) { + return nullptr; + } + last_save_name_ = false; + AppendCurrent(cur_state_.last_save); + return name + 1; + } + if (*name == 'K') { + cur_state_.suffixes.push_back(" const"); + return name + 1; + } + if (*name == 'V') { + cur_state_.suffixes.push_back(" volatile"); + return name + 1; + } + if (*name == 'I') { + // Save the current argument state. + state_stack_.push(cur_state_); + cur_state_.Clear(); + + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseTemplateArgumentsComplex; + return name + 1; + } + name = AppendOperatorString(name); + if (name != nullptr) { + Save(cur_state_.str, true); + } + return name; +} + +void Demangler::AppendArgument(const std::string& str) { + std::string arg(str); + while (!cur_state_.suffixes.empty()) { + arg += cur_state_.suffixes.back(); + cur_state_.suffixes.pop_back(); + Save(arg, false); + } + cur_state_.args.push_back(arg); +} + +const char* Demangler::ParseFunctionArgument(const char* name) { + if (*name == 'E') { + // The first argument is the function modifier. + // The second argument is the function type. + // The third argument is the return type of the function. + // The rest of the arguments are the function arguments. + size_t num_args = cur_state_.args.size(); + if (num_args < 4) { + return nullptr; + } + std::string function_modifier = cur_state_.args[0]; + std::string function_type = cur_state_.args[1]; + + std::string str = cur_state_.args[2] + ' '; + if (!cur_state_.args[1].empty()) { + str += '(' + cur_state_.args[1] + ')'; + } + + if (num_args == 4 && cur_state_.args[3] == "void") { + str += "()"; + } else { + str += '(' + cur_state_.args[3]; + for (size_t i = 4; i < num_args; i++) { + str += ", " + cur_state_.args[i]; + } + str += ')'; + } + str += cur_state_.args[0]; + + cur_state_ = state_stack_.top(); + state_stack_.pop(); + cur_state_.args.emplace_back(std::move(str)); + + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + return name + 1; + } + return ParseArguments(name); +} + +const char* Demangler::ParseArguments(const char* name) { + switch (*name) { + case 'P': + cur_state_.suffixes.push_back("*"); + return name + 1; + + case 'R': + // This should always be okay because the string is guaranteed to have + // at least two characters before this. A mangled string always starts + // with _Z. + if (name[-1] != 'R') { + // Multiple 'R's in a row only add a single &. + cur_state_.suffixes.push_back("&"); + } + return name + 1; + + case 'K': + case 'V': { + const char* suffix; + if (*name == 'K') { + suffix = " const"; + } else { + suffix = " volatile"; + } + if (name[-1] == 'K' || name[-1] == 'V') { + // Special case, const/volatile apply as a single entity. + assert(!cur_state_.suffixes.empty()); + size_t index = cur_state_.suffixes.size(); + cur_state_.suffixes[index-1].insert(0, suffix); + } else { + cur_state_.suffixes.push_back(suffix); + } + return name + 1; + } + + case 'F': { + std::string function_modifier; + std::string function_type; + if (!cur_state_.suffixes.empty()) { + // If the first element starts with a ' ', then this modifies the + // function itself. + if (cur_state_.suffixes.back()[0] == ' ') { + function_modifier = cur_state_.suffixes.back(); + cur_state_.suffixes.pop_back(); + } + while (!cur_state_.suffixes.empty()) { + function_type += cur_state_.suffixes.back(); + cur_state_.suffixes.pop_back(); + } + } + + state_stack_.push(cur_state_); + + cur_state_.Clear(); + + // The function parameter has this format: + // First argument is the function modifier. + // Second argument is the function type. + // Third argument will be the return function type but has not + // been parsed yet. + // Any other parameters are the arguments to the function. There + // must be at least one or this isn't valid. + cur_state_.args.push_back(function_modifier); + cur_state_.args.push_back(function_type); + + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseFunctionArgument; + return name + 1; + } + + case 'N': + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseComplexArgument; + return name + 1; + + case 'S': + name++; + if (*name == 't') { + cur_state_.str = "std::"; + return name + 1; + } + name = ParseS(name); + if (name == nullptr) { + return nullptr; + } + AppendArgument(cur_state_.str); + cur_state_.str.clear(); + return name; + + case 'D': + name++; + if (*name >= 'a' && *name <= 'z') { + const char* arg = Demangler::kDTypes[*name - 'a']; + if (arg == nullptr) { + return nullptr; + } + AppendArgument(arg); + return name + 1; + } + return nullptr; + + case 'I': + // Save the current argument state. + state_stack_.push(cur_state_); + cur_state_.Clear(); + + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseTemplateArguments; + return name + 1; + + case 'v': + AppendArgument("void"); + return name + 1; + + default: + if (*name >= 'a' && *name <= 'z') { + const char* arg = Demangler::kTypes[*name - 'a']; + if (arg == nullptr) { + return nullptr; + } + AppendArgument(arg); + return name + 1; + } else if (std::isdigit(*name)) { + std::string arg = cur_state_.str; + name = GetStringFromLength(name, &arg); + if (name == nullptr) { + return nullptr; + } + Save(arg, true); + if (*name == 'I') { + // There is one case where this argument is not complete, and that's + // where this is a template argument. + cur_state_.str = arg; + } else { + AppendArgument(arg); + cur_state_.str.clear(); + } + return name; + } + } + return nullptr; +} + +const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { + if (*name == 'E') { + if (parse_funcs_.empty()) { + return nullptr; + } + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + FinalizeTemplate(); + Save(cur_state_.str, false); + return name + 1; + } + return ParseArguments(name); +} + +const char* Demangler::ParseTemplateArguments(const char* name) { + if (*name == 'E') { + if (parse_funcs_.empty()) { + return nullptr; + } + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + FinalizeTemplate(); + AppendArgument(cur_state_.str); + cur_state_.str.clear(); + return name + 1; + } + return ParseArguments(name); +} + +const char* Demangler::FindFunctionName(const char* name) { + if (*name == 'N') { + parse_funcs_.push_back(&Demangler::ParseArguments); + parse_func_ = &Demangler::ParseFunctionName; + return name + 1; + } + + if (std::isdigit(*name)) { + name = GetStringFromLength(name, &function_name_); + } else { + name = AppendOperatorString(name); + function_name_ = cur_state_.str; + } + parse_func_ = &Demangler::ParseArguments; + cur_state_.Clear(); + return name; +} + +std::string Demangler::Parse(const char* name, size_t max_length) { + if (name[0] == '\0' || name[0] != '_' || name[1] == '\0' || name[1] != 'Z') { + // Name is not mangled. + return name; + } + + Clear(); + + parse_func_ = &Demangler::FindFunctionName; + parse_funcs_.push_back(&Demangler::Fail); + const char* cur_name = name + 2; + while (cur_name != nullptr && *cur_name != '\0' + && static_cast(cur_name - name) < max_length) { + cur_name = (this->*parse_func_)(cur_name); + } + if (cur_name == nullptr || *cur_name != '\0' || function_name_.empty()) { + return name; + } + + std::string arg_str; + if (cur_state_.args.size() == 1 && cur_state_.args[0] == "void") { + // If the only argument is void, then don't print any args. + arg_str = "()"; + } else { + arg_str = GetArgumentsString(); + if (!arg_str.empty()) { + arg_str = '(' + arg_str + ')'; + } + } + return function_name_ + arg_str + function_suffix_; +} + +std::string demangle(const char* name) { + Demangler demangler; + return demangler.Parse(name); +} diff --git a/demangle/Demangler.h b/demangle/Demangler.h new file mode 100644 index 000000000..3bd4f3c00 --- /dev/null +++ b/demangle/Demangler.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LIB_DEMANGLE_DEMANGLER_H +#define __LIB_DEMANGLE_DEMANGLER_H + +#include + +#include +#include +#include + +class Demangler { + public: + Demangler() = default; + + // NOTE: The max_length is not guaranteed to be the absolute max length + // of a string that will be rejected. Under certain circumstances the + // length check will not occur until after the second letter of a pair + // is checked. + std::string Parse(const char* name, size_t max_length = kMaxDefaultLength); + + void AppendCurrent(const std::string& str); + void AppendCurrent(const char* str); + void AppendArgument(const std::string& str); + std::string GetArgumentsString(); + void FinalizeTemplate(); + const char* ParseS(const char* name); + const char* AppendOperatorString(const char* name); + void Save(const std::string& str, bool is_name); + + private: + void Clear() { + parse_funcs_.clear(); + function_name_.clear(); + function_suffix_.clear(); + first_save_.clear(); + cur_state_.Clear(); + saves_.clear(); + while (!state_stack_.empty()) { + state_stack_.pop(); + } + last_save_name_ = false; + } + + using parse_func_type = const char* (Demangler::*)(const char*); + parse_func_type parse_func_; + std::vector parse_funcs_; + std::vector saves_; + bool last_save_name_; + + std::string function_name_; + std::string function_suffix_; + + struct StateData { + void Clear() { + str.clear(); + args.clear(); + prefix.clear(); + suffixes.clear(); + last_save.clear(); + } + + std::string str; + std::vector args; + std::string prefix; + std::vector suffixes; + std::string last_save; + }; + std::stack state_stack_; + std::string first_save_; + StateData cur_state_; + + static const char* GetStringFromLength(const char* name, std::string* str); + + // Parsing functions. + const char* ParseComplexString(const char* name); + const char* ParseComplexArgument(const char* name); + const char* ParseArguments(const char* name); + const char* ParseTemplateArguments(const char* name); + const char* ParseTemplateArgumentsComplex(const char* name); + const char* ParseFunctionArgument(const char* name); + const char* ParseFunctionName(const char* name); + const char* FindFunctionName(const char* name); + const char* Fail(const char*) { return nullptr; } + + // The default maximum string length string to process. + static constexpr size_t kMaxDefaultLength = 2048; + + static constexpr const char* kTypes[] = { + "signed char", // a + "bool", // b + "char", // c + "double", // d + "long double", // e + "float", // f + "__float128", // g + "unsigned char", // h + "int", // i + "unsigned int", // j + nullptr, // k + "long", // l + "unsigned long", // m + "__int128", // n + "unsigned __int128", // o + nullptr, // p + nullptr, // q + nullptr, // r + "short", // s + "unsigned short", // t + nullptr, // u + "void", // v + "wchar_t", // w + "long long", // x + "unsigned long long", // y + "...", // z + }; + + static constexpr const char* kDTypes[] = { + "auto", // a + nullptr, // b + nullptr, // c + "decimal64", // d + "decimal128", // e + "decimal32", // f + nullptr, // g + "half", // h + "char32_t", // i + nullptr, // j + nullptr, // k + nullptr, // l + nullptr, // m + "decltype(nullptr)", // n + nullptr, // o + nullptr, // p + nullptr, // q + nullptr, // r + "char16_t", // s + nullptr, // t + nullptr, // u + nullptr, // v + nullptr, // w + nullptr, // x + nullptr, // y + nullptr, // z + }; + + static constexpr const char* kSTypes[] = { + "std::allocator", // a + "std::basic_string", // b + nullptr, // c + "std::iostream", // d + nullptr, // e + nullptr, // f + nullptr, // g + nullptr, // h + "std::istream", // i + nullptr, // j + nullptr, // k + nullptr, // l + nullptr, // m + nullptr, // n + "std::ostream", // o + nullptr, // p + nullptr, // q + nullptr, // r + "std::string", // s + nullptr, // t + nullptr, // u + nullptr, // v + nullptr, // w + nullptr, // x + nullptr, // y + nullptr, // z + }; +}; + +#endif // __LIB_DEMANGLE_DEMANGLER_H diff --git a/demangle/include/demangle.h b/demangle/include/demangle.h new file mode 100644 index 000000000..01f1b809a --- /dev/null +++ b/demangle/include/demangle.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LIB_DEMANGLE_H_ +#define __LIB_DEMANGLE_H_ + +#include + +// If the name cannot be demangled, the original name will be returned as +// a std::string. If the name can be demangled, then the demangled name +// will be returned as a std::string. +std::string demangle(const char* name); + +#endif // __LIB_DEMANGLE_H_