Fix template support.
- Fix template applying to function name without a starting N. - Fix return types for templates handling. - Add support for the T substitution parameter. - Fix a case where the literal L handler was not being set properly. Bug: 67678053 Test: New unit tests, fuzzer. Change-Id: I4f831038047eb2cd8519426f16aa2bdcb846d92d
This commit is contained in:
parent
bb3769349d
commit
584333e3b2
3 changed files with 170 additions and 3 deletions
|
@ -334,6 +334,29 @@ TEST(DemangleTest, TemplateFunction) {
|
|||
// Template within templates.
|
||||
ASSERT_EQ("one::two<three<char, int>>", demangler.Parse("_ZN3one3twoIN5threeIciEEEE"));
|
||||
ASSERT_EQ("one::two<three<char, four<int>>>", demangler.Parse("_ZN3one3twoIN5threeIcN4fourIiEEEEEE"));
|
||||
|
||||
ASSERT_EQ("one<char>", demangler.Parse("_Z3oneIcE"));
|
||||
ASSERT_EQ("one<void>", demangler.Parse("_Z3oneIvE"));
|
||||
ASSERT_EQ("one<void*>", demangler.Parse("_Z3oneIPvE"));
|
||||
ASSERT_EQ("one<void const>", demangler.Parse("_Z3oneIKvE"));
|
||||
ASSERT_EQ("one<char, int, bool>", demangler.Parse("_Z3oneIcibE"));
|
||||
ASSERT_EQ("one(two<three>)", demangler.Parse("_Z3one3twoIN5threeEE"));
|
||||
ASSERT_EQ("one<char, int, two::three>", demangler.Parse("_Z3oneIciN3two5threeEE"));
|
||||
// Template within templates.
|
||||
ASSERT_EQ("one(two<three<char, int>>)", demangler.Parse("_Z3one3twoIN5threeIciEEE"));
|
||||
ASSERT_EQ("one(two<three<char, four<int>>>)",
|
||||
demangler.Parse("_Z3one3twoIN5threeIcN4fourIiEEEEE"));
|
||||
}
|
||||
|
||||
TEST(DemangleTest, TemplateFunctionWithReturnType) {
|
||||
Demangler demangler;
|
||||
|
||||
ASSERT_EQ("char one<int>(char)", demangler.Parse("_Z3oneIiEcc"));
|
||||
ASSERT_EQ("void one<int>()", demangler.Parse("_Z3oneIiEvv"));
|
||||
ASSERT_EQ("char one<int>()", demangler.Parse("_Z3oneIiEcv"));
|
||||
ASSERT_EQ("char one<int>(void, void)", demangler.Parse("_Z3oneIiEcvv"));
|
||||
ASSERT_EQ("char one<int>()", demangler.Parse("_ZN3oneIiEEcv"));
|
||||
ASSERT_EQ("char one<int>(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, double>(int)", demangler.Parse("_ZN3oneIidEEvT_"));
|
||||
ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_ZN3oneIidEEvT0_"));
|
||||
ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_ZN3oneIidcvEEvT1_"));
|
||||
|
||||
ASSERT_EQ("void one<int, double>(int)", demangler.Parse("_Z3oneIidEvT_"));
|
||||
ASSERT_EQ("void one<int, double>(double)", demangler.Parse("_Z3oneIidEvT0_"));
|
||||
ASSERT_EQ("void one<int, double, char, void>(char)", demangler.Parse("_Z3oneIidcvEvT1_"));
|
||||
|
||||
ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
|
||||
demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT10_"));
|
||||
ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
|
||||
demangler.Parse("_ZN3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEEvT11_"));
|
||||
|
||||
ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(l)",
|
||||
demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT10_"));
|
||||
ASSERT_EQ("void one<a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r>(m)",
|
||||
demangler.Parse("_Z3oneI1a1b1c1d1e1f1g1h1i1j1k1l1m1n1o1p1q1rEvT11_"));
|
||||
}
|
||||
|
||||
TEST(DemangleTest, StringTooLong) {
|
||||
Demangler demangler;
|
||||
|
||||
|
@ -434,6 +479,13 @@ TEST(DemangleTest, BooleanLiterals) {
|
|||
ASSERT_EQ("one<true>", demangler.Parse("_ZN3oneILb1EEE"));
|
||||
ASSERT_EQ("one<false>", demangler.Parse("_ZN3oneILb0EEE"));
|
||||
ASSERT_EQ("one<false, true>", demangler.Parse("_ZN3oneILb0ELb1EEE"));
|
||||
|
||||
ASSERT_EQ("one<true>", demangler.Parse("_Z3oneILb1EE"));
|
||||
ASSERT_EQ("one<false>", demangler.Parse("_Z3oneILb0EE"));
|
||||
ASSERT_EQ("one<false, true>", demangler.Parse("_Z3oneILb0ELb1EE"));
|
||||
|
||||
ASSERT_EQ("one(two<three<four>, false, true>)",
|
||||
demangler.Parse("_ZN3oneE3twoI5threeI4fourELb0ELb1EE"));
|
||||
}
|
||||
|
||||
TEST(DemangleTest, demangle) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_func_type> parse_funcs_;
|
||||
std::vector<std::string> saves_;
|
||||
std::vector<std::string> 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; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue