| Index: base/third_party/symbolize/demangle.cc
|
| diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
|
| index 46556bf3c13059dd74a63f58453b9d040680b6dd..e858181a68f4ec83b4a3e30e71ba13c5bb082cd8 100644
|
| --- a/base/third_party/symbolize/demangle.cc
|
| +++ b/base/third_party/symbolize/demangle.cc
|
| @@ -28,6 +28,11 @@
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| //
|
| // Author: Satoru Takabayashi
|
| +//
|
| +// For reference check out:
|
| +// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
|
| +//
|
| +// Note that we only have partial C++0x support yet.
|
|
|
| #include <stdio.h> // for NULL
|
| #include "demangle.h"
|
| @@ -138,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;
|
| @@ -161,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[i] == '\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;
|
| @@ -174,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;
|
| }
|
| @@ -216,13 +223,10 @@ 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) {
|
| - 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;
|
| }
|
| }
|
| @@ -230,7 +234,7 @@ static bool ParseCharClass(State *state, const char *char_class) {
|
| }
|
|
|
| // This function is used for handling an optional non-terminal.
|
| -static bool Optional(bool status) {
|
| +static bool Optional(bool) {
|
| return true;
|
| }
|
|
|
| @@ -245,6 +249,16 @@ static bool OneOrMore(ParseFunc parse_func, State *state) {
|
| return false;
|
| }
|
|
|
| +// This function is used for handling <non-terminal>* syntax. The function
|
| +// 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)) {
|
| + }
|
| + return true;
|
| +}
|
| +
|
| // Append "str" at "out_cur". If there is an overflow, "overflowed"
|
| // is set to true for later use. The output string is ensured to
|
| // always terminate with '\0' as long as there is no overflow.
|
| @@ -270,7 +284,37 @@ 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) {
|
| + return c >= '0' && c <= '9';
|
| +}
|
| +
|
| +// Returns true if "str" is a function clone suffix. These suffixes are used
|
| +// by GCC 4.5.x and later versions to indicate functions which have been
|
| +// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
|
| +// a function clone suffix.
|
| +static bool IsFunctionCloneSuffix(const char *str) {
|
| + size_t i = 0;
|
| + while (str[i] != '\0') {
|
| + // Consume a single .<alpha>+.<digit>+ sequence.
|
| + if (str[i] != '.' || !IsAlpha(str[i + 1])) {
|
| + return false;
|
| + }
|
| + i += 2;
|
| + while (IsAlpha(str[i])) {
|
| + ++i;
|
| + }
|
| + if (str[i] != '.' || !IsDigit(str[i + 1])) {
|
| + return false;
|
| + }
|
| + i += 2;
|
| + while (IsDigit(str[i])) {
|
| + ++i;
|
| + }
|
| + }
|
| + return true; // Consumed everything in "str".
|
| }
|
|
|
| // Append "str" with some tweaks, iff "append" state is true.
|
| @@ -309,7 +353,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;
|
| }
|
| @@ -349,11 +393,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 > (int)sizeof(anon_prefix) - 1 && // Should be longer.
|
| StrPrefix(state->mangled_cur, anon_prefix));
|
| }
|
|
|
| @@ -368,10 +412,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);
|
| @@ -428,17 +472,7 @@ static bool ParseSubstitution(State *state);
|
|
|
| // <mangled-name> ::= _Z <encoding>
|
| static bool ParseMangledName(State *state) {
|
| - if (ParseTwoChar(state, "_Z") && ParseEncoding(state)) {
|
| - // 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);
|
| }
|
|
|
| // <encoding> ::= <(function) name> <bare-function-type>
|
| @@ -488,7 +522,7 @@ static bool ParseUnscopedName(State *state) {
|
| }
|
|
|
| State copy = *state;
|
| - if (ParseTwoChar(state, "St") &&
|
| + if (ParseTwoCharToken(state, "St") &&
|
| MaybeAppend(state, "std::") &&
|
| ParseUnqualifiedName(state)) {
|
| return true;
|
| @@ -507,12 +541,12 @@ static bool ParseUnscopedTemplateName(State *state) {
|
| // ::= N [<CV-qualifiers>] <template-prefix> <template-args> 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;
|
| @@ -565,7 +599,8 @@ static bool ParseUnqualifiedName(State *state) {
|
| // <source-name> ::= <positive length number> <identifier>
|
| 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;
|
| @@ -579,7 +614,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;
|
| }
|
| @@ -588,15 +623,17 @@ static bool ParseLocalSourceName(State *state) {
|
| }
|
|
|
| // <number> ::= [n] <non-negative decimal integer>
|
| -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) {
|
| - if ((*p >= '0' && *p <= '9')) {
|
| + for (;*p != '\0'; ++p) {
|
| + if (IsDigit(*p)) {
|
| number = number * 10 + (*p - '0');
|
| } else {
|
| break;
|
| @@ -604,7 +641,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;
|
| @@ -614,19 +653,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 ((*p >= '0' && *p <= '9')) {
|
| - 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;
|
| @@ -636,37 +669,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 ((*p >= '0' && *p <= '9')) {
|
| - 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;
|
| }
|
|
|
| -// <identifier> ::= <unqualified source code identifier>
|
| -static bool ParseIdentifier(State *state) {
|
| - if (state->number == -1 ||
|
| - RemainingLength(state) < state->number) {
|
| +// <identifier> ::= <unqualified source code identifier> (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;
|
| }
|
|
|
| @@ -674,12 +700,12 @@ static bool ParseIdentifier(State *state) {
|
| // ::= cv <type> # (cast)
|
| // ::= v <digit> <source-name> # 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) &&
|
| @@ -689,7 +715,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;
|
| }
|
| @@ -738,34 +764,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);
|
| @@ -773,23 +799,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;
|
| }
|
| @@ -801,14 +827,14 @@ static bool ParseSpecialName(State *state) {
|
| // ::= v <v-offset> _
|
| 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;
|
| @@ -818,14 +844,14 @@ static bool ParseCallOffset(State *state) {
|
|
|
| // <nv-offset> ::= <(offset) number>
|
| static bool ParseNVOffset(State *state) {
|
| - return ParseNumber(state);
|
| + return ParseNumber(state, NULL);
|
| }
|
|
|
| // <v-offset> ::= <(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;
|
| @@ -836,7 +862,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;
|
| @@ -845,7 +871,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;
|
| @@ -858,11 +884,12 @@ static bool ParseCtorDtorName(State *state) {
|
| }
|
|
|
| // <type> ::= <CV-qualifiers> <type>
|
| -// ::= P <type>
|
| -// ::= R <type>
|
| -// ::= C <type>
|
| -// ::= G <type>
|
| -// ::= U <source-name> <type>
|
| +// ::= P <type> # pointer-to
|
| +// ::= R <type> # reference-to
|
| +// ::= O <type> # rvalue reference-to (C++0x)
|
| +// ::= C <type> # complex pair (C 2000)
|
| +// ::= G <type> # imaginary (C 2000)
|
| +// ::= U <source-name> <type> # vendor extended type qualifier
|
| // ::= <builtin-type>
|
| // ::= <function-type>
|
| // ::= <class-enum-type>
|
| @@ -871,6 +898,11 @@ static bool ParseCtorDtorName(State *state) {
|
| // ::= <template-template-param> <template-args>
|
| // ::= <template-param>
|
| // ::= <substitution>
|
| +// ::= Dp <type> # pack expansion of (C++0x)
|
| +// ::= Dt <expression> E # decltype of an id-expression or class
|
| +// # member access (C++0x)
|
| +// ::= DT <expression> E # decltype of an expression (C++0x)
|
| +//
|
| static bool ParseType(State *state) {
|
| // We should check CV-qualifers, and PRGC things first.
|
| State copy = *state;
|
| @@ -879,12 +911,23 @@ static bool ParseType(State *state) {
|
| }
|
| *state = copy;
|
|
|
| - if (ParseCharClass(state, "PRCG") && ParseType(state)) {
|
| + if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
|
| return true;
|
| }
|
| *state = copy;
|
|
|
| - if (ParseChar(state, 'U') && ParseSourceName(state) &&
|
| + if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
|
| + return true;
|
| + }
|
| + *state = copy;
|
| +
|
| + if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
|
| + ParseExpression(state) && ParseOneCharToken(state, 'E')) {
|
| + return true;
|
| + }
|
| + *state = copy;
|
| +
|
| + if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
|
| ParseType(state)) {
|
| return true;
|
| }
|
| @@ -918,9 +961,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;
|
| }
|
|
|
| @@ -937,7 +980,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;
|
| @@ -947,8 +990,9 @@ static bool ParseBuiltinType(State *state) {
|
| // <function-type> ::= F [Y] <bare-function-type> 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;
|
| @@ -977,14 +1021,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;
|
| @@ -994,7 +1038,7 @@ static bool ParseArrayType(State *state) {
|
| // <pointer-to-member-type> ::= 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;
|
| }
|
| @@ -1005,14 +1049,14 @@ static bool ParsePointerToMemberType(State *state) {
|
| // <template-param> ::= T_
|
| // ::= T <parameter-2 non-negative number> _
|
| 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;
|
| }
|
| @@ -1032,9 +1076,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;
|
| @@ -1045,16 +1089,25 @@ static bool ParseTemplateArgs(State *state) {
|
|
|
| // <template-arg> ::= <type>
|
| // ::= <expr-primary>
|
| +// ::= I <template-arg>* E # argument pack
|
| // ::= X <expression> E
|
| static bool ParseTemplateArg(State *state) {
|
| + State copy = *state;
|
| + if (ParseOneCharToken(state, 'I') &&
|
| + ZeroOrMore(ParseTemplateArg, state) &&
|
| + ParseOneCharToken(state, 'E')) {
|
| + return true;
|
| + }
|
| + *state = copy;
|
| +
|
| if (ParseType(state) ||
|
| ParseExprPrimary(state)) {
|
| return true;
|
| }
|
| + *state = copy;
|
|
|
| - State copy = *state;
|
| - if (ParseChar(state, 'X') && ParseExpression(state) &&
|
| - ParseChar(state, 'E')) {
|
| + if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
|
| + ParseOneCharToken(state, 'E')) {
|
| return true;
|
| }
|
| *state = copy;
|
| @@ -1097,19 +1150,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;
|
| }
|
| @@ -1124,28 +1177,28 @@ static bool ParseExpression(State *state) {
|
| // ::= LZ <encoding> 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;
|
| @@ -1158,15 +1211,15 @@ static bool ParseExprPrimary(State *state) {
|
| // := Z <(function) encoding> E s [<discriminator>]
|
| 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;
|
| @@ -1176,7 +1229,7 @@ static bool ParseLocalName(State *state) {
|
| // <discriminator> := _ <(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;
|
| @@ -1187,21 +1240,21 @@ static bool ParseDiscriminator(State *state) {
|
| // ::= S <seq-id> _
|
| // ::= 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]) {
|
| @@ -1210,7 +1263,7 @@ static bool ParseSubstitution(State *state) {
|
| MaybeAppend(state, "::");
|
| MaybeAppend(state, p->real_name);
|
| }
|
| - state->mangled_cur += 1;
|
| + ++state->mangled_cur;
|
| return true;
|
| }
|
| }
|
| @@ -1219,13 +1272,33 @@ static bool ParseSubstitution(State *state) {
|
| return false;
|
| }
|
|
|
| +// Parse <mangled-name>, 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_
|
|
|