diff --git a/src/demangle.cc b/src/demangle.cc index cc7cebb..2fbb790 100644 --- a/src/demangle.cc +++ b/src/demangle.cc @@ -143,14 +143,12 @@ static const AbbrevPair kSubstitutionList[] = { // State needed for demangling. typedef struct { const char *mangled_cur; // Cursor of mangled name. - const char *mangled_end; // End of mangled name. char *out_cur; // Cursor of output string. const char *out_begin; // Beginning of output string. const char *out_end; // End of output string. const char *prev_name; // For constructors/destructors. int prev_name_length; // For constructors/destructors. - int nest_level; // For nested names. - int number; // Remember the previous number. + short nest_level; // For nested names. bool append; // Append flag. bool overflowed; // True if output gets overflowed. } State; @@ -166,6 +164,16 @@ static size_t StrLen(const char *str) { return len; } +// Returns true if "str" has at least "n" characters remaining. +static bool AtLeastNumCharsRemaining(const char *str, int n) { + for (int i = 0; i < n; ++i) { + if (str == '\0') { + return false; + } + } + return true; +} + // Returns true if "str" has "prefix" as a prefix. static bool StrPrefix(const char *str, const char *prefix) { size_t i = 0; @@ -179,39 +187,33 @@ static bool StrPrefix(const char *str, const char *prefix) { static void InitState(State *state, const char *mangled, char *out, int out_size) { state->mangled_cur = mangled; - state->mangled_end = mangled + StrLen(mangled); state->out_cur = out; state->out_begin = out; state->out_end = out + out_size; state->prev_name = NULL; state->prev_name_length = -1; state->nest_level = -1; - state->number = -1; state->append = true; state->overflowed = false; } -// Calculates the remaining length of the mangled name. -static int RemainingLength(State *state) { - return state->mangled_end - state->mangled_cur; -} - -// Returns true and advances "mangled_cur" if we find "c" at -// "mangled_cur" position. -static bool ParseChar(State *state, const char c) { - if (RemainingLength(state) >= 1 && *state->mangled_cur == c) { +// Returns true and advances "mangled_cur" if we find "one_char_token" +// at "mangled_cur" position. It is assumed that "one_char_token" does +// not contain '\0'. +static bool ParseOneCharToken(State *state, const char one_char_token) { + if (state->mangled_cur[0] == one_char_token) { ++state->mangled_cur; return true; } return false; } -// Returns true and advances "mangled_cur" if we find "two_chars" at -// "mangled_cur" position. -static bool ParseTwoChar(State *state, const char *two_chars) { - if (RemainingLength(state) >= 2 && - state->mangled_cur[0] == two_chars[0] && - state->mangled_cur[1] == two_chars[1]) { +// Returns true and advances "mangled_cur" if we find "two_char_token" +// at "mangled_cur" position. It is assumed that "two_char_token" does +// not contain '\0'. +static bool ParseTwoCharToken(State *state, const char *two_char_token) { + if (state->mangled_cur[0] == two_char_token[0] && + state->mangled_cur[1] == two_char_token[1]) { state->mangled_cur += 2; return true; } @@ -221,13 +223,13 @@ static bool ParseTwoChar(State *state, const char *two_chars) { // Returns true and advances "mangled_cur" if we find any character in // "char_class" at "mangled_cur" position. static bool ParseCharClass(State *state, const char *char_class) { - if (state->mangled_cur == state->mangled_end) { + if (state->mangled_cur == '\0') { return false; } const char *p = char_class; for (; *p != '\0'; ++p) { - if (*state->mangled_cur == *p) { - state->mangled_cur += 1; + if (state->mangled_cur[0] == *p) { + ++state->mangled_cur; return true; } } @@ -251,8 +253,9 @@ static bool OneOrMore(ParseFunc parse_func, State *state) { } // This function is used for handling * syntax. The function -// always returns true and must be followed by a termination symbol or a -// terminating sequence not handled by parse_func (e.g. ParseChar(state, 'E')). +// always returns true and must be followed by a termination token or a +// terminating sequence not handled by parse_func (e.g. +// ParseOneCharToken(state, 'E')). static bool ZeroOrMore(ParseFunc parse_func, State *state) { while (parse_func(state)) { } @@ -284,7 +287,7 @@ static bool IsLower(char c) { } static bool IsAlpha(char c) { - return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } static bool IsDigit(char c) { @@ -353,7 +356,7 @@ static bool EnterNestedName(State *state) { } // This function is used for handling nested names. -static bool LeaveNestedName(State *state, int prev_value) { +static bool LeaveNestedName(State *state, short prev_value) { state->nest_level = prev_value; return true; } @@ -393,11 +396,11 @@ static void MaybeCancelLastSeparator(State *state) { } } -// Returns true if identifier pointed by "mangled_cur" is anonymous -// namespace. -static bool IdentifierIsAnonymousNamespace(State *state) { - const char anon_prefix[] = "_GLOBAL__N_"; - return (state->number > sizeof(anon_prefix) - 1 && // Should be longer. +// Returns true if the identifier of the given length pointed to by +// "mangled_cur" is anonymous namespace. +static bool IdentifierIsAnonymousNamespace(State *state, int length) { + static const char anon_prefix[] = "_GLOBAL__N_"; + return (length > sizeof(anon_prefix) - 1 && // Should be longer. StrPrefix(state->mangled_cur, anon_prefix)); } @@ -412,10 +415,10 @@ static bool ParsePrefix(State *state); static bool ParseUnqualifiedName(State *state); static bool ParseSourceName(State *state); static bool ParseLocalSourceName(State *state); -static bool ParseNumber(State *state); +static bool ParseNumber(State *state, int *number_out); static bool ParseFloatNumber(State *state); static bool ParseSeqId(State *state); -static bool ParseIdentifier(State *state); +static bool ParseIdentifier(State *state, int length); static bool ParseOperatorName(State *state); static bool ParseSpecialName(State *state); static bool ParseCallOffset(State *state); @@ -472,21 +475,7 @@ static bool ParseSubstitution(State *state); // ::= _Z static bool ParseMangledName(State *state) { - if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) { - // Drop trailing function clone suffix, if any. - if (IsFunctionCloneSuffix(state->mangled_cur)) { - state->mangled_cur = state->mangled_end; - } - // Append trailing version suffix if any. - // ex. _Z3foo@@GLIBCXX_3.4 - if (state->mangled_cur < state->mangled_end && - state->mangled_cur[0] == '@') { - MaybeAppend(state, state->mangled_cur); - state->mangled_cur = state->mangled_end; - } - return true; - } - return false; + return ParseTwoCharToken(state, "_Z") && ParseEncoding(state); } // ::= <(function) name> @@ -536,7 +525,7 @@ static bool ParseUnscopedName(State *state) { } State copy = *state; - if (ParseTwoChar(state, "St") && + if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") && ParseUnqualifiedName(state)) { return true; @@ -555,12 +544,12 @@ static bool ParseUnscopedTemplateName(State *state) { // ::= N [] E static bool ParseNestedName(State *state) { State copy = *state; - if (ParseChar(state, 'N') && + if (ParseOneCharToken(state, 'N') && EnterNestedName(state) && Optional(ParseCVQualifiers(state)) && ParsePrefix(state) && LeaveNestedName(state, copy.nest_level) && - ParseChar(state, 'E')) { + ParseOneCharToken(state, 'E')) { return true; } *state = copy; @@ -613,7 +602,8 @@ static bool ParseUnqualifiedName(State *state) { // ::= static bool ParseSourceName(State *state) { State copy = *state; - if (ParseNumber(state) && ParseIdentifier(state)) { + int length = -1; + if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { return true; } *state = copy; @@ -627,7 +617,7 @@ static bool ParseSourceName(State *state) { // http://gcc.gnu.org/viewcvs?view=rev&revision=124467 static bool ParseLocalSourceName(State *state) { State copy = *state; - if (ParseChar(state, 'L') && ParseSourceName(state) && + if (ParseOneCharToken(state, 'L') && ParseSourceName(state) && Optional(ParseDiscriminator(state))) { return true; } @@ -636,14 +626,16 @@ static bool ParseLocalSourceName(State *state) { } // ::= [n] -static bool ParseNumber(State *state) { +// If "number_out" is non-null, then *number_out is set to the value of the +// parsed number on success. +static bool ParseNumber(State *state, int *number_out) { int sign = 1; - if (ParseChar(state, 'n')) { + if (ParseOneCharToken(state, 'n')) { sign = -1; } const char *p = state->mangled_cur; int number = 0; - for (;p < state->mangled_end; ++p) { + for (;*p != '\0'; ++p) { if (IsDigit(*p)) { number = number * 10 + (*p - '0'); } else { @@ -652,7 +644,9 @@ static bool ParseNumber(State *state) { } if (p != state->mangled_cur) { // Conversion succeeded. state->mangled_cur = p; - state->number = number * sign; + if (number_out != NULL) { + *number_out = number * sign; + } return true; } return false; @@ -662,19 +656,13 @@ static bool ParseNumber(State *state) { // hexadecimal string. static bool ParseFloatNumber(State *state) { const char *p = state->mangled_cur; - int number = 0; - for (;p < state->mangled_end; ++p) { - if (IsDigit(*p)) { - number = number * 16 + (*p - '0'); - } else if (*p >= 'a' && *p <= 'f') { - number = number * 16 + (*p - 'a' + 10); - } else { + for (;*p != '\0'; ++p) { + if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) { break; } } if (p != state->mangled_cur) { // Conversion succeeded. state->mangled_cur = p; - state->number = number; return true; } return false; @@ -684,37 +672,30 @@ static bool ParseFloatNumber(State *state) { // using digits and upper case letters static bool ParseSeqId(State *state) { const char *p = state->mangled_cur; - int number = 0; - for (;p < state->mangled_end; ++p) { - if (IsDigit(*p)) { - number = number * 36 + (*p - '0'); - } else if (*p >= 'A' && *p <= 'Z') { - number = number * 36 + (*p - 'A' + 10); - } else { + for (;*p != '\0'; ++p) { + if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) { break; } } if (p != state->mangled_cur) { // Conversion succeeded. state->mangled_cur = p; - state->number = number; return true; } return false; } -// ::= -static bool ParseIdentifier(State *state) { - if (state->number == -1 || - RemainingLength(state) < state->number) { +// ::= (of given length) +static bool ParseIdentifier(State *state, int length) { + if (length == -1 || + !AtLeastNumCharsRemaining(state->mangled_cur, length)) { return false; } - if (IdentifierIsAnonymousNamespace(state)) { + if (IdentifierIsAnonymousNamespace(state, length)) { MaybeAppend(state, "(anonymous namespace)"); } else { - MaybeAppendWithLength(state, state->mangled_cur, state->number); + MaybeAppendWithLength(state, state->mangled_cur, length); } - state->mangled_cur += state->number; - state->number = -1; // Reset the number. + state->mangled_cur += length; return true; } @@ -722,12 +703,12 @@ static bool ParseIdentifier(State *state) { // ::= cv # (cast) // ::= v # vendor extended operator static bool ParseOperatorName(State *state) { - if (RemainingLength(state) < 2) { + if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) { return false; } // First check with "cv" (cast) case. State copy = *state; - if (ParseTwoChar(state, "cv") && + if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") && EnterNestedName(state) && ParseType(state) && @@ -737,7 +718,7 @@ static bool ParseOperatorName(State *state) { *state = copy; // Then vendor extended operators. - if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") && + if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") && ParseSourceName(state)) { return true; } @@ -786,34 +767,34 @@ static bool ParseOperatorName(State *state) { // stack traces. The are special data. static bool ParseSpecialName(State *state) { State copy = *state; - if (ParseChar(state, 'T') && + if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && ParseType(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) && + if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) && ParseCallOffset(state) && ParseEncoding(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "GV") && + if (ParseTwoCharToken(state, "GV") && ParseName(state)) { return true; } *state = copy; - if (ParseChar(state, 'T') && ParseCallOffset(state) && + if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) && ParseEncoding(state)) { return true; } *state = copy; // G++ extensions - if (ParseTwoChar(state, "TC") && ParseType(state) && - ParseNumber(state) && ParseChar(state, '_') && + if (ParseTwoCharToken(state, "TC") && ParseType(state) && + ParseNumber(state, NULL) && ParseOneCharToken(state, '_') && DisableAppend(state) && ParseType(state)) { RestoreAppend(state, copy.append); @@ -821,23 +802,23 @@ static bool ParseSpecialName(State *state) { } *state = copy; - if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") && + if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") && ParseType(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "GR") && ParseName(state)) { + if (ParseTwoCharToken(state, "GR") && ParseName(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "GA") && ParseEncoding(state)) { + if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) { return true; } *state = copy; - if (ParseChar(state, 'T') && ParseCharClass(state, "hv") && + if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") && ParseCallOffset(state) && ParseEncoding(state)) { return true; } @@ -849,14 +830,14 @@ static bool ParseSpecialName(State *state) { // ::= v _ static bool ParseCallOffset(State *state) { State copy = *state; - if (ParseChar(state, 'h') && - ParseNVOffset(state) && ParseChar(state, '_')) { + if (ParseOneCharToken(state, 'h') && + ParseNVOffset(state) && ParseOneCharToken(state, '_')) { return true; } *state = copy; - if (ParseChar(state, 'v') && - ParseVOffset(state) && ParseChar(state, '_')) { + if (ParseOneCharToken(state, 'v') && + ParseVOffset(state) && ParseOneCharToken(state, '_')) { return true; } *state = copy; @@ -866,14 +847,14 @@ static bool ParseCallOffset(State *state) { // ::= <(offset) number> static bool ParseNVOffset(State *state) { - return ParseNumber(state); + return ParseNumber(state, NULL); } // ::= <(offset) number> _ <(virtual offset) number> static bool ParseVOffset(State *state) { State copy = *state; - if (ParseNumber(state) && ParseChar(state, '_') && - ParseNumber(state)) { + if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') && + ParseNumber(state, NULL)) { return true; } *state = copy; @@ -884,7 +865,7 @@ static bool ParseVOffset(State *state) { // ::= D0 | D1 | D2 static bool ParseCtorDtorName(State *state) { State copy = *state; - if (ParseChar(state, 'C') && + if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "123")) { const char * const prev_name = state->prev_name; const int prev_name_length = state->prev_name_length; @@ -893,7 +874,7 @@ static bool ParseCtorDtorName(State *state) { } *state = copy; - if (ParseChar(state, 'D') && + if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "012")) { const char * const prev_name = state->prev_name; const int prev_name_length = state->prev_name_length; @@ -938,18 +919,18 @@ static bool ParseType(State *state) { } *state = copy; - if (ParseTwoChar(state, "Dp") && ParseType(state)) { + if (ParseTwoCharToken(state, "Dp") && ParseType(state)) { return true; } *state = copy; - if (ParseChar(state, 'D') && ParseCharClass(state, "tT") && - ParseExpression(state) && ParseChar(state, 'E')) { + if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") && + ParseExpression(state) && ParseOneCharToken(state, 'E')) { return true; } *state = copy; - if (ParseChar(state, 'U') && ParseSourceName(state) && + if (ParseOneCharToken(state, 'U') && ParseSourceName(state) && ParseType(state)) { return true; } @@ -983,9 +964,9 @@ static bool ParseType(State *state) { // ParseType(). static bool ParseCVQualifiers(State *state) { int num_cv_qualifiers = 0; - num_cv_qualifiers += ParseChar(state, 'r'); - num_cv_qualifiers += ParseChar(state, 'V'); - num_cv_qualifiers += ParseChar(state, 'K'); + num_cv_qualifiers += ParseOneCharToken(state, 'r'); + num_cv_qualifiers += ParseOneCharToken(state, 'V'); + num_cv_qualifiers += ParseOneCharToken(state, 'K'); return num_cv_qualifiers > 0; } @@ -1002,7 +983,7 @@ static bool ParseBuiltinType(State *state) { } State copy = *state; - if (ParseChar(state, 'u') && ParseSourceName(state)) { + if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) { return true; } *state = copy; @@ -1012,8 +993,9 @@ static bool ParseBuiltinType(State *state) { // ::= F [Y] E static bool ParseFunctionType(State *state) { State copy = *state; - if (ParseChar(state, 'F') && Optional(ParseChar(state, 'Y')) && - ParseBareFunctionType(state) && ParseChar(state, 'E')) { + if (ParseOneCharToken(state, 'F') && + Optional(ParseOneCharToken(state, 'Y')) && + ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) { return true; } *state = copy; @@ -1042,14 +1024,14 @@ static bool ParseClassEnumType(State *state) { // ::= A [<(dimension) expression>] _ <(element) type> static bool ParseArrayType(State *state) { State copy = *state; - if (ParseChar(state, 'A') && ParseNumber(state) && - ParseChar(state, '_') && ParseType(state)) { + if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) && + ParseOneCharToken(state, '_') && ParseType(state)) { return true; } *state = copy; - if (ParseChar(state, 'A') && Optional(ParseExpression(state)) && - ParseChar(state, '_') && ParseType(state)) { + if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) && + ParseOneCharToken(state, '_') && ParseType(state)) { return true; } *state = copy; @@ -1059,7 +1041,7 @@ static bool ParseArrayType(State *state) { // ::= M <(class) type> <(member) type> static bool ParsePointerToMemberType(State *state) { State copy = *state; - if (ParseChar(state, 'M') && ParseType(state) && + if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) { return true; } @@ -1070,14 +1052,14 @@ static bool ParsePointerToMemberType(State *state) { // ::= T_ // ::= T _ static bool ParseTemplateParam(State *state) { - if (ParseTwoChar(state, "T_")) { + if (ParseTwoCharToken(state, "T_")) { MaybeAppend(state, "?"); // We don't support template substitutions. return true; } State copy = *state; - if (ParseChar(state, 'T') && ParseNumber(state) && - ParseChar(state, '_')) { + if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) && + ParseOneCharToken(state, '_')) { MaybeAppend(state, "?"); // We don't support template substitutions. return true; } @@ -1097,9 +1079,9 @@ static bool ParseTemplateTemplateParam(State *state) { static bool ParseTemplateArgs(State *state) { State copy = *state; DisableAppend(state); - if (ParseChar(state, 'I') && + if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) && - ParseChar(state, 'E')) { + ParseOneCharToken(state, 'E')) { RestoreAppend(state, copy.append); MaybeAppend(state, "<>"); return true; @@ -1114,9 +1096,9 @@ static bool ParseTemplateArgs(State *state) { // ::= X E static bool ParseTemplateArg(State *state) { State copy = *state; - if (ParseChar(state, 'I') && + if (ParseOneCharToken(state, 'I') && ZeroOrMore(ParseTemplateArg, state) && - ParseChar(state, 'E')) { + ParseOneCharToken(state, 'E')) { return true; } *state = copy; @@ -1127,8 +1109,8 @@ static bool ParseTemplateArg(State *state) { } *state = copy; - if (ParseChar(state, 'X') && ParseExpression(state) && - ParseChar(state, 'E')) { + if (ParseOneCharToken(state, 'X') && ParseExpression(state) && + ParseOneCharToken(state, 'E')) { return true; } *state = copy; @@ -1171,19 +1153,19 @@ static bool ParseExpression(State *state) { } *state = copy; - if (ParseTwoChar(state, "st") && ParseType(state)) { + if (ParseTwoCharToken(state, "st") && ParseType(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "sr") && ParseType(state) && + if (ParseTwoCharToken(state, "sr") && ParseType(state) && ParseUnqualifiedName(state) && ParseTemplateArgs(state)) { return true; } *state = copy; - if (ParseTwoChar(state, "sr") && ParseType(state) && + if (ParseTwoCharToken(state, "sr") && ParseType(state) && ParseUnqualifiedName(state)) { return true; } @@ -1198,28 +1180,28 @@ static bool ParseExpression(State *state) { // ::= LZ E static bool ParseExprPrimary(State *state) { State copy = *state; - if (ParseChar(state, 'L') && ParseType(state) && - ParseNumber(state) && - ParseChar(state, 'E')) { + if (ParseOneCharToken(state, 'L') && ParseType(state) && + ParseNumber(state, NULL) && + ParseOneCharToken(state, 'E')) { return true; } *state = copy; - if (ParseChar(state, 'L') && ParseType(state) && + if (ParseOneCharToken(state, 'L') && ParseType(state) && ParseFloatNumber(state) && - ParseChar(state, 'E')) { + ParseOneCharToken(state, 'E')) { return true; } *state = copy; - if (ParseChar(state, 'L') && ParseMangledName(state) && - ParseChar(state, 'E')) { + if (ParseOneCharToken(state, 'L') && ParseMangledName(state) && + ParseOneCharToken(state, 'E')) { return true; } *state = copy; - if (ParseTwoChar(state, "LZ") && ParseEncoding(state) && - ParseChar(state, 'E')) { + if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) && + ParseOneCharToken(state, 'E')) { return true; } *state = copy; @@ -1232,15 +1214,15 @@ static bool ParseExprPrimary(State *state) { // := Z <(function) encoding> E s [] static bool ParseLocalName(State *state) { State copy = *state; - if (ParseChar(state, 'Z') && ParseEncoding(state) && - ParseChar(state, 'E') && MaybeAppend(state, "::") && + if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && + ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") && ParseName(state) && Optional(ParseDiscriminator(state))) { return true; } *state = copy; - if (ParseChar(state, 'Z') && ParseEncoding(state) && - ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) { + if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) && + ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) { return true; } *state = copy; @@ -1250,7 +1232,7 @@ static bool ParseLocalName(State *state) { // := _ <(non-negative) number> static bool ParseDiscriminator(State *state) { State copy = *state; - if (ParseChar(state, '_') && ParseNumber(state)) { + if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) { return true; } *state = copy; @@ -1261,21 +1243,21 @@ static bool ParseDiscriminator(State *state) { // ::= S _ // ::= St, etc. static bool ParseSubstitution(State *state) { - if (ParseTwoChar(state, "S_")) { + if (ParseTwoCharToken(state, "S_")) { MaybeAppend(state, "?"); // We don't support substitutions. return true; } State copy = *state; - if (ParseChar(state, 'S') && ParseSeqId(state) && - ParseChar(state, '_')) { + if (ParseOneCharToken(state, 'S') && ParseSeqId(state) && + ParseOneCharToken(state, '_')) { MaybeAppend(state, "?"); // We don't support substitutions. return true; } *state = copy; // Expand abbreviations like "St" => "std". - if (ParseChar(state, 'S')) { + if (ParseOneCharToken(state, 'S')) { const AbbrevPair *p; for (p = kSubstitutionList; p->abbrev != NULL; ++p) { if (state->mangled_cur[0] == p->abbrev[1]) { @@ -1284,7 +1266,7 @@ static bool ParseSubstitution(State *state) { MaybeAppend(state, "::"); MaybeAppend(state, p->real_name); } - state->mangled_cur += 1; + ++state->mangled_cur; return true; } } @@ -1293,13 +1275,33 @@ static bool ParseSubstitution(State *state) { return false; } +// Parse , optionally followed by either a function-clone suffix +// or version suffix. Returns true only if all of "mangled_cur" was consumed. +static bool ParseTopLevelMangledName(State *state) { + if (ParseMangledName(state)) { + if (state->mangled_cur[0] != '\0') { + // Drop trailing function clone suffix, if any. + if (IsFunctionCloneSuffix(state->mangled_cur)) { + return true; + } + // Append trailing version suffix if any. + // ex. _Z3foo@@GLIBCXX_3.4 + if (state->mangled_cur[0] == '@') { + MaybeAppend(state, state->mangled_cur); + return true; + } + return false; // Unconsumed suffix. + } + return true; + } + return false; +} + // The demangler entry point. bool Demangle(const char *mangled, char *out, int out_size) { State state; InitState(&state, mangled, out, out_size); - return (ParseMangledName(&state) && - state.overflowed == false && - RemainingLength(&state) == 0); + return ParseTopLevelMangledName(&state) && !state.overflowed; } _END_GOOGLE_NAMESPACE_