diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp index c93e2ab93..5825e6ce2 100644 --- a/demangle/DemangleTest.cpp +++ b/demangle/DemangleTest.cpp @@ -334,6 +334,29 @@ TEST(DemangleTest, TemplateFunction) { // Template within templates. ASSERT_EQ("one::two>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE")); ASSERT_EQ("one::two>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE")); + + ASSERT_EQ("one", demangler.Parse("_Z3oneIcE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneIvE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneIPvE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneIKvE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneIcibE")); + ASSERT_EQ("one(two)", demangler.Parse("_Z3one3twoIN5threeEE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneIciN3two5threeEE")); + // Template within templates. + ASSERT_EQ("one(two>)", demangler.Parse("_Z3one3twoIN5threeIciEEE")); + ASSERT_EQ("one(two>>)", + demangler.Parse("_Z3one3twoIN5threeIcN4fourIiEEEEE")); +} + +TEST(DemangleTest, TemplateFunctionWithReturnType) { + Demangler demangler; + + ASSERT_EQ("char one(char)", demangler.Parse("_Z3oneIiEcc")); + ASSERT_EQ("void one()", demangler.Parse("_Z3oneIiEvv")); + ASSERT_EQ("char one()", demangler.Parse("_Z3oneIiEcv")); + ASSERT_EQ("char one(void, void)", demangler.Parse("_Z3oneIiEcvv")); + ASSERT_EQ("char one()", demangler.Parse("_ZN3oneIiEEcv")); + ASSERT_EQ("char one(void, void)", demangler.Parse("_ZN3oneIiEEcvv")); } TEST(DemangleTest, TemplateArguments) { @@ -410,6 +433,28 @@ TEST(DemangleTest, ComplexSubstitution) { demangler.Parse("_ZN3one3two5three4fourINS_4fiveEED2EPS3_")); } +TEST(DemangleTest, TemplateSubstitution) { + Demangler demangler; + + ASSERT_EQ("void one(int)", demangler.Parse("_ZN3oneIidEEvT_")); + ASSERT_EQ("void one(double)", demangler.Parse("_ZN3oneIidEEvT0_")); + ASSERT_EQ("void one(char)", demangler.Parse("_ZN3oneIidcvEEvT1_")); + + ASSERT_EQ("void one(int)", demangler.Parse("_Z3oneIidEvT_")); + ASSERT_EQ("void one(double)", demangler.Parse("_Z3oneIidEvT0_")); + ASSERT_EQ("void one(char)", demangler.Parse("_Z3oneIidcvEvT1_")); + + ASSERT_EQ("void one(l)", + demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT10_")); + ASSERT_EQ("void one(m)", + demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT11_")); + + ASSERT_EQ("void one(l)", + demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT10_")); + ASSERT_EQ("void one(m)", + demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT11_")); +} + TEST(DemangleTest, StringTooLong) { Demangler demangler; @@ -434,6 +479,13 @@ TEST(DemangleTest, BooleanLiterals) { ASSERT_EQ("one", demangler.Parse("_ZN3oneILb1EEE")); ASSERT_EQ("one", demangler.Parse("_ZN3oneILb0EEE")); ASSERT_EQ("one", demangler.Parse("_ZN3oneILb0ELb1EEE")); + + ASSERT_EQ("one", demangler.Parse("_Z3oneILb1EE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneILb0EE")); + ASSERT_EQ("one", demangler.Parse("_Z3oneILb0ELb1EE")); + + ASSERT_EQ("one(two, false, true>)", + demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE")); } TEST(DemangleTest, demangle) { diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp index f148b21a5..18a90b4a9 100644 --- a/demangle/Demangler.cpp +++ b/demangle/Demangler.cpp @@ -347,6 +347,33 @@ const char* Demangler::ParseS(const char* name) { return name + 1; } +const char* Demangler::ParseT(const char* name) { + if (template_saves_.empty()) { + return nullptr; + } + + if (*name == '_') { + last_save_name_ = false; + AppendCurrent(template_saves_[0]); + return name + 1; + } + + // Need to get the total number. + char* end; + unsigned long int index = strtoul(name, &end, 10) + 1; + if (name == end || *end != '_') { + return nullptr; + } + + if (index >= template_saves_.size()) { + return nullptr; + } + + last_save_name_ = false; + AppendCurrent(template_saves_[index]); + return end + 1; +} + const char* Demangler::ParseFunctionName(const char* name) { if (*name == 'E') { if (parse_funcs_.empty()) { @@ -371,9 +398,28 @@ const char* Demangler::ParseFunctionName(const char* name) { return name + 1; } + if (*name == 'I') { + state_stack_.push(cur_state_); + cur_state_.Clear(); + + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseFunctionNameTemplate; + return name + 1; + } + return ParseComplexString(name); } +const char* Demangler::ParseFunctionNameTemplate(const char* name) { + if (*name == 'E' && name[1] == 'E') { + // Only consider this a template with saves if it is right before + // the end of the name. + template_found_ = true; + template_saves_ = cur_state_.args; + } + return ParseTemplateArgumentsComplex(name); +} + const char* Demangler::ParseComplexArgument(const char* name) { if (*name == 'E') { if (parse_funcs_.empty()) { @@ -690,6 +736,7 @@ const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { } parse_func_ = parse_funcs_.back(); parse_funcs_.pop_back(); + FinalizeTemplate(); Save(cur_state_.str, false); return name + 1; @@ -699,6 +746,7 @@ const char* Demangler::ParseTemplateArgumentsComplex(const char* name) { parse_func_ = &Demangler::ParseTemplateLiteral; return name + 1; } + return ParseArguments(name); } @@ -713,13 +761,33 @@ const char* Demangler::ParseTemplateArguments(const char* name) { AppendArgument(cur_state_.str); cur_state_.str.clear(); return name + 1; + } else if (*name == 'L') { + // Literal value for a template. + parse_funcs_.push_back(parse_func_); + parse_func_ = &Demangler::ParseTemplateLiteral; + return name + 1; } + return ParseArguments(name); } +const char* Demangler::ParseFunctionTemplateArguments(const char* name) { + if (*name == 'E') { + parse_func_ = parse_funcs_.back(); + parse_funcs_.pop_back(); + + function_name_ += '<' + GetArgumentsString() + '>'; + template_found_ = true; + template_saves_ = cur_state_.args; + cur_state_.Clear(); + return name + 1; + } + return ParseTemplateArgumentsComplex(name); +} + const char* Demangler::FindFunctionName(const char* name) { if (*name == 'N') { - parse_funcs_.push_back(&Demangler::ParseArguments); + parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel); parse_func_ = &Demangler::ParseFunctionName; return name + 1; } @@ -732,11 +800,35 @@ const char* Demangler::FindFunctionName(const char* name) { name = AppendOperatorString(name); function_name_ = cur_state_.str; } - parse_func_ = &Demangler::ParseArguments; cur_state_.Clear(); + + // Check for a template argument, which will still be part of the function + // name. + if (name != nullptr && *name == 'I') { + parse_funcs_.push_back(&Demangler::ParseArgumentsAtTopLevel); + parse_func_ = &Demangler::ParseFunctionTemplateArguments; + return name + 1; + } + parse_func_ = &Demangler::ParseArgumentsAtTopLevel; return name; } +const char* Demangler::ParseArgumentsAtTopLevel(const char* name) { + // At the top level is the only place where T is allowed. + if (*name == 'T') { + name++; + name = ParseT(name); + if (name == nullptr) { + return nullptr; + } + AppendArgument(cur_state_.str); + cur_state_.str.clear(); + return name; + } + + return Demangler::ParseArguments(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. @@ -757,6 +849,21 @@ std::string Demangler::Parse(const char* name, size_t max_length) { return name; } + std::string return_type; + if (template_found_) { + // Only a single argument with a template is not allowed. + if (cur_state_.args.size() == 1) { + return name; + } + + // If there are at least two arguments, this template has a return type. + if (cur_state_.args.size() > 1) { + // The first argument will be the return value. + return_type = cur_state_.args[0] + ' '; + cur_state_.args.erase(cur_state_.args.begin()); + } + } + 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. @@ -767,7 +874,7 @@ std::string Demangler::Parse(const char* name, size_t max_length) { arg_str = '(' + arg_str + ')'; } } - return function_name_ + arg_str + function_suffix_; + return return_type + function_name_ + arg_str + function_suffix_; } std::string demangle(const char* name) { diff --git a/demangle/Demangler.h b/demangle/Demangler.h index f76def64a..3b7d44ef3 100644 --- a/demangle/Demangler.h +++ b/demangle/Demangler.h @@ -39,6 +39,7 @@ class Demangler { std::string GetArgumentsString(); void FinalizeTemplate(); const char* ParseS(const char* name); + const char* ParseT(const char* name); const char* AppendOperatorString(const char* name); void Save(const std::string& str, bool is_name); @@ -50,17 +51,21 @@ class Demangler { first_save_.clear(); cur_state_.Clear(); saves_.clear(); + template_saves_.clear(); while (!state_stack_.empty()) { state_stack_.pop(); } last_save_name_ = false; + template_found_ = false; } using parse_func_type = const char* (Demangler::*)(const char*); parse_func_type parse_func_; std::vector parse_funcs_; std::vector saves_; + std::vector template_saves_; bool last_save_name_; + bool template_found_; std::string function_name_; std::string function_suffix_; @@ -89,12 +94,15 @@ class Demangler { // Parsing functions. const char* ParseComplexString(const char* name); const char* ParseComplexArgument(const char* name); + const char* ParseArgumentsAtTopLevel(const char* name); const char* ParseArguments(const char* name); const char* ParseTemplateArguments(const char* name); const char* ParseTemplateArgumentsComplex(const char* name); const char* ParseTemplateLiteral(const char* name); const char* ParseFunctionArgument(const char* name); const char* ParseFunctionName(const char* name); + const char* ParseFunctionNameTemplate(const char* name); + const char* ParseFunctionTemplateArguments(const char* name); const char* FindFunctionName(const char* name); const char* Fail(const char*) { return nullptr; }