// <special-name> ::= TV <type> // ::= TT <type> // ::= TI <type> // ::= TS <type> // ::= Tc <call-offset> <call-offset> <(base) encoding> // ::= GV <(object) name> // ::= T <call-offset> <(base) encoding> // G++ extensions: // ::= TC <type> <(offset) number> _ <(base) type> // ::= TF <type> // ::= TJ <type> // ::= GR <name> // ::= GA <encoding> // ::= Th <call-offset> <(base) encoding> // ::= Tv <call-offset> <(base) encoding> // // Note: we don't care much about them since they don't appear in // stack traces. The are special data. static bool ParseSpecialName(State *state) { State copy = *state; if (ParseChar(state, 'T') && ParseCharClass(state, "VTIS") && ParseType(state)) { return true; } *state = copy; if (ParseTwoChar(state, "Tc") && ParseCallOffset(state) && ParseCallOffset(state) && ParseEncoding(state)) { return true; } *state = copy; if (ParseTwoChar(state, "GV") && ParseName(state)) { return true; } *state = copy; if (ParseChar(state, 'T') && ParseCallOffset(state) && ParseEncoding(state)) { return true; } *state = copy; // G++ extensions if (ParseTwoChar(state, "TC") && ParseType(state) && ParseNumber(state) && ParseChar(state, '_') && DisableAppend(state) && ParseType(state)) { RestoreAppend(state, copy.append); return true; } *state = copy; if (ParseChar(state, 'T') && ParseCharClass(state, "FJ") && ParseType(state)) { return true; } *state = copy; if (ParseTwoChar(state, "GR") && ParseName(state)) { return true; } *state = copy; if (ParseTwoChar(state, "GA") && ParseEncoding(state)) { return true; } *state = copy; if (ParseChar(state, 'T') && ParseCharClass(state, "hv") && ParseCallOffset(state) && ParseEncoding(state)) { return true; } *state = copy; return false; }
// <substitution> ::= S_ // ::= S <seq-id> _ // ::= St, etc. static bool ParseSubstitution(State *state) { if (ParseTwoChar(state, "S_")) { MaybeAppend(state, "?"); // We don't support substitutions. return true; } State copy = *state; if (ParseChar(state, 'S') && ParseSeqId(state) && ParseChar(state, '_')) { MaybeAppend(state, "?"); // We don't support substitutions. return true; } *state = copy; // Expand abbreviations like "St" => "std". if (ParseChar(state, 'S')) { const AbbrevPair *p; for (p = kSubstitutionList; p->abbrev != nullptr; ++p) { if (state->mangled_cur[0] == p->abbrev[1]) { MaybeAppend(state, "std"); if (p->real_name[0] != '\0') { MaybeAppend(state, "::"); MaybeAppend(state, p->real_name); } state->mangled_cur += 1; return true; } } } *state = copy; return false; }
// <expr-primary> ::= L <type> <(value) number> E // ::= L <type> <(value) float> E // ::= L <mangled-name> E // // A bug in g++'s C++ ABI version 2 (-fabi-version=2). // ::= LZ <encoding> E static bool ParseExprPrimary(State *state) { State copy = *state; if (ParseChar(state, 'L') && ParseType(state) && ParseNumber(state) && ParseChar(state, 'E')) { return true; } *state = copy; if (ParseChar(state, 'L') && ParseType(state) && ParseFloatNumber(state) && ParseChar(state, 'E')) { return true; } *state = copy; if (ParseChar(state, 'L') && ParseMangledName(state) && ParseChar(state, 'E')) { return true; } *state = copy; if (ParseTwoChar(state, "LZ") && ParseEncoding(state) && ParseChar(state, 'E')) { return true; } *state = copy; return false; }
// <expression> ::= <template-param> // ::= <expr-primary> // ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> // ::= <trinary operator-name> <expression> <expression> // <expression> // ::= st <type> // ::= sr <type> <unqualified-name> <template-args> // ::= sr <type> <unqualified-name> static bool ParseExpression(State *state) { if (ParseTemplateParam(state) || ParseExprPrimary(state)) { return true; } State copy = *state; if (ParseOperatorName(state) && ParseExpression(state) && ParseExpression(state) && ParseExpression(state)) { return true; } *state = copy; if (ParseOperatorName(state) && ParseExpression(state) && ParseExpression(state)) { return true; } *state = copy; if (ParseOperatorName(state) && ParseExpression(state)) { return true; } *state = copy; if (ParseTwoChar(state, "st") && ParseType(state)) { return true; } *state = copy; if (ParseTwoChar(state, "sr") && ParseType(state) && ParseUnqualifiedName(state) && ParseTemplateArgs(state)) { return true; } *state = copy; if (ParseTwoChar(state, "sr") && ParseType(state) && ParseUnqualifiedName(state)) { return true; } *state = copy; return false; }
// <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; }
// <unscoped-name> ::= <unqualified-name> // ::= St <unqualified-name> static bool ParseUnscopedName(State *state) { if (ParseUnqualifiedName(state)) { return true; } State copy = *state; if (ParseTwoChar(state, "St") && MaybeAppend(state, "std::") && ParseUnqualifiedName(state)) { return true; } *state = copy; return false; }
// <template-param> ::= T_ // ::= T <parameter-2 non-negative number> _ static bool ParseTemplateParam(State *state) { if (ParseTwoChar(state, "T_")) { MaybeAppend(state, "?"); // We don't support template substitutions. return true; } State copy = *state; if (ParseChar(state, 'T') && ParseNumber(state) && ParseChar(state, '_')) { MaybeAppend(state, "?"); // We don't support template substitutions. return true; } *state = copy; return false; }
// <local-name> := Z <(function) encoding> E <(entity) name> // [<discriminator>] // := 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, "::") && ParseName(state) && Optional(ParseDiscriminator(state))) { return true; } *state = copy; if (ParseChar(state, 'Z') && ParseEncoding(state) && ParseTwoChar(state, "Es") && Optional(ParseDiscriminator(state))) { return true; } *state = copy; return false; }
// <operator-name> ::= nw, and other two letters cases // ::= cv <type> # (cast) // ::= v <digit> <source-name> # vendor extended operator static bool ParseOperatorName(State *state) { if (RemainingLength(state) < 2) { return false; } // First check with "cv" (cast) case. State copy = *state; if (ParseTwoChar(state, "cv") && MaybeAppend(state, "operator ") && EnterNestedName(state) && ParseType(state) && LeaveNestedName(state, copy.nest_level)) { return true; } *state = copy; // Then vendor extended operators. if (ParseChar(state, 'v') && ParseCharClass(state, "0123456789") && ParseSourceName(state)) { return true; } *state = copy; // Other operator names should start with a lower alphabet followed // by a lower/upper alphabet. if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) { return false; } // We may want to perform a binary search if we really need speed. const AbbrevPair *p; for (p = kOperatorList; p->abbrev != nullptr; ++p) { if (state->mangled_cur[0] == p->abbrev[0] && state->mangled_cur[1] == p->abbrev[1]) { MaybeAppend(state, "operator"); if (IsLower(*p->real_name)) { // new, delete, etc. MaybeAppend(state, " "); } MaybeAppend(state, p->real_name); state->mangled_cur += 2; return true; } } return false; }