diff options
-rw-r--r-- | llvm/lib/Demangle/MicrosoftDemangle.cpp | 193 |
1 files changed, 106 insertions, 87 deletions
diff --git a/llvm/lib/Demangle/MicrosoftDemangle.cpp b/llvm/lib/Demangle/MicrosoftDemangle.cpp index 8b19d77acbf..0aec01eb600 100644 --- a/llvm/lib/Demangle/MicrosoftDemangle.cpp +++ b/llvm/lib/Demangle/MicrosoftDemangle.cpp @@ -209,6 +209,10 @@ enum class SymbolCategory { Function, Variable }; namespace { +struct NameResolver { + virtual StringView resolve(StringView S) = 0; +}; + struct Type; struct Name; @@ -246,15 +250,15 @@ struct Type { // Write the "first half" of a given type. This is a static functions to // give the code a chance to do processing that is common to a subset of // subclasses - static void outputPre(OutputStream &OS, Type &Ty); + static void outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver); // Write the "second half" of a given type. This is a static functions to // give the code a chance to do processing that is common to a subset of // subclasses - static void outputPost(OutputStream &OS, Type &Ty); + static void outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver); - virtual void outputPre(OutputStream &OS); - virtual void outputPost(OutputStream &OS); + virtual void outputPre(OutputStream &OS, NameResolver &Resolver); + virtual void outputPost(OutputStream &OS, NameResolver &Resolver); // Primitive type such as Int. PrimTy Prim = PrimTy::Unknown; @@ -270,6 +274,7 @@ struct Name { bool IsTemplateInstantiation = false; bool IsOperator = false; + bool IsBackReference = false; // Template parameters. Only valid if Flags contains NF_TemplateInstantiation. TemplateParams *TParams = nullptr; @@ -280,8 +285,8 @@ struct Name { struct PointerType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS) override; - void outputPost(OutputStream &OS) override; + void outputPre(OutputStream &OS, NameResolver &Resolver) override; + void outputPost(OutputStream &OS, NameResolver &Resolver) override; PointerAffinity Affinity; @@ -292,8 +297,8 @@ struct PointerType : public Type { struct MemberPointerType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS) override; - void outputPost(OutputStream &OS) override; + void outputPre(OutputStream &OS, NameResolver &Resolver) override; + void outputPost(OutputStream &OS, NameResolver &Resolver) override; Name *MemberName = nullptr; @@ -304,8 +309,8 @@ struct MemberPointerType : public Type { struct FunctionType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS) override; - void outputPost(OutputStream &OS) override; + void outputPre(OutputStream &OS, NameResolver &Resolver) override; + void outputPost(OutputStream &OS, NameResolver &Resolver) override; // True if this FunctionType instance is the Pointee of a PointerType or // MemberPointerType. @@ -323,15 +328,15 @@ struct FunctionType : public Type { struct UdtType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS) override; + void outputPre(OutputStream &OS, NameResolver &Resolver) override; Name *UdtName = nullptr; }; struct ArrayType : public Type { Type *clone(ArenaAllocator &Arena) const override; - void outputPre(OutputStream &OS) override; - void outputPost(OutputStream &OS) override; + void outputPre(OutputStream &OS, NameResolver &Resolver) override; + void outputPost(OutputStream &OS, NameResolver &Resolver) override; // Either NextDimension or ElementType will be valid. ArrayType *NextDimension = nullptr; @@ -473,11 +478,9 @@ static bool startsWithLocalScopePattern(StringView S) { return true; } -static void outputName(OutputStream &OS, const Name *TheName); - // Write a function or template parameter list. -static void outputParameterList(OutputStream &OS, - const FunctionParams &Params) { +static void outputParameterList(OutputStream &OS, const FunctionParams &Params, + NameResolver &Resolver) { if (!Params.Current) { OS << "void"; return; @@ -485,8 +488,8 @@ static void outputParameterList(OutputStream &OS, const FunctionParams *Head = &Params; while (Head) { - Type::outputPre(OS, *Head->Current); - Type::outputPost(OS, *Head->Current); + Type::outputPre(OS, *Head->Current, Resolver); + Type::outputPost(OS, *Head->Current, Resolver); Head = Head->Next; @@ -495,8 +498,11 @@ static void outputParameterList(OutputStream &OS, } } -static void outputParameterList(OutputStream &OS, - const TemplateParams &Params) { +static void outputName(OutputStream &OS, const Name *TheName, + NameResolver &Resolver); + +static void outputParameterList(OutputStream &OS, const TemplateParams &Params, + NameResolver &Resolver) { if (!Params.ParamType && !Params.ParamName) { OS << "<>"; return; @@ -511,16 +517,16 @@ static void outputParameterList(OutputStream &OS, if (Head->ParamType && Head->ParamName) { // Function pointer. OS << "&"; - Type::outputPre(OS, *Head->ParamType); - outputName(OS, Head->ParamName); - Type::outputPost(OS, *Head->ParamType); + Type::outputPre(OS, *Head->ParamType, Resolver); + outputName(OS, Head->ParamName, Resolver); + Type::outputPost(OS, *Head->ParamType, Resolver); } else if (Head->ParamType) { // simple type. - Type::outputPre(OS, *Head->ParamType); - Type::outputPost(OS, *Head->ParamType); + Type::outputPre(OS, *Head->ParamType, Resolver); + Type::outputPost(OS, *Head->ParamType, Resolver); } else { // Template alias. - outputName(OS, Head->ParamName); + outputName(OS, Head->ParamName, Resolver); } Head = Head->Next; @@ -531,7 +537,20 @@ static void outputParameterList(OutputStream &OS, OS << ">"; } -static void outputName(OutputStream &OS, const Name *TheName) { +static void outputNameComponent(OutputStream &OS, const Name &N, + NameResolver &Resolver) { + StringView S = N.Str; + + if (N.IsBackReference) + S = Resolver.resolve(N.Str); + OS << S; + + if (N.IsTemplateInstantiation) + outputParameterList(OS, *N.TParams, Resolver); +} + +static void outputName(OutputStream &OS, const Name *TheName, + NameResolver &Resolver) { if (!TheName) return; @@ -541,17 +560,13 @@ static void outputName(OutputStream &OS, const Name *TheName) { // Print out namespaces or outer class BackReferences. for (; TheName->Next; TheName = TheName->Next) { Previous = TheName; - OS << TheName->Str; - if (TheName->IsTemplateInstantiation) - outputParameterList(OS, *TheName->TParams); + outputNameComponent(OS, *TheName, Resolver); OS << "::"; } // Print out a regular name. if (!TheName->IsOperator) { - OS << TheName->Str; - if (TheName->IsTemplateInstantiation) - outputParameterList(OS, *TheName->TParams); + outputNameComponent(OS, *TheName, Resolver); return; } @@ -560,16 +575,13 @@ static void outputName(OutputStream &OS, const Name *TheName) { OS << "~"; if (TheName->Str == "ctor" || TheName->Str == "dtor") { - OS << Previous->Str; - if (Previous->TParams) - outputParameterList(OS, *Previous->TParams); + outputNameComponent(OS, *Previous, Resolver); return; } // Print out an overloaded operator. - OS << "operator" << TheName->Str; - if (TheName->IsTemplateInstantiation) - outputParameterList(OS, *TheName->TParams); + OS << "operator"; + outputNameComponent(OS, *TheName, Resolver); } namespace { @@ -579,12 +591,12 @@ Type *Type::clone(ArenaAllocator &Arena) const { } // Write the "first half" of a given type. -void Type::outputPre(OutputStream &OS, Type &Ty) { +void Type::outputPre(OutputStream &OS, Type &Ty, NameResolver &Resolver) { // Function types require custom handling of const and static so we // handle them separately. All other types use the same decoration // for these modifiers, so handle them here in common code. if (Ty.Prim == PrimTy::Function) { - Ty.outputPre(OS); + Ty.outputPre(OS, Resolver); return; } @@ -596,7 +608,7 @@ void Type::outputPre(OutputStream &OS, Type &Ty) { default: break; } - Ty.outputPre(OS); + Ty.outputPre(OS, Resolver); if (Ty.Quals & Q_Const) { outputSpaceIfNecessary(OS); @@ -615,9 +627,11 @@ void Type::outputPre(OutputStream &OS, Type &Ty) { } // Write the "second half" of a given type. -void Type::outputPost(OutputStream &OS, Type &Ty) { Ty.outputPost(OS); } +void Type::outputPost(OutputStream &OS, Type &Ty, NameResolver &Resolver) { + Ty.outputPost(OS, Resolver); +} -void Type::outputPre(OutputStream &OS) { +void Type::outputPre(OutputStream &OS, NameResolver &Resolver) { switch (Prim) { case PrimTy::Void: OS << "void"; @@ -683,15 +697,15 @@ void Type::outputPre(OutputStream &OS) { assert(false && "Invalid primitive type!"); } } -void Type::outputPost(OutputStream &OS) {} +void Type::outputPost(OutputStream &OS, NameResolver &Resolver) {} Type *PointerType::clone(ArenaAllocator &Arena) const { return Arena.alloc<PointerType>(*this); } static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, - const Name *MemberName, - const Type *Pointee) { + const Name *MemberName, const Type *Pointee, + NameResolver &Resolver) { // "[]" and "()" (for function parameters) take precedence over "*", // so "int *x(int)" means "x is a function returning int *". We need // parentheses to supercede the default precedence. (e.g. we want to @@ -707,7 +721,7 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, } if (MemberName) { - outputName(OS, MemberName); + outputName(OS, MemberName, Resolver); OS << "::"; } @@ -719,38 +733,39 @@ static void outputPointerIndicator(OutputStream &OS, PointerAffinity Affinity, OS << "&&"; } -void PointerType::outputPre(OutputStream &OS) { - Type::outputPre(OS, *Pointee); +void PointerType::outputPre(OutputStream &OS, NameResolver &Resolver) { + Type::outputPre(OS, *Pointee, Resolver); outputSpaceIfNecessary(OS); if (Quals & Q_Unaligned) OS << "__unaligned "; - outputPointerIndicator(OS, Affinity, nullptr, Pointee); + outputPointerIndicator(OS, Affinity, nullptr, Pointee, Resolver); // FIXME: We should output this, but it requires updating lots of tests. // if (Ty.Quals & Q_Pointer64) // OS << " __ptr64"; } -void PointerType::outputPost(OutputStream &OS) { +void PointerType::outputPost(OutputStream &OS, NameResolver &Resolver) { if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) OS << ")"; - Type::outputPost(OS, *Pointee); + Type::outputPost(OS, *Pointee, Resolver); } Type *MemberPointerType::clone(ArenaAllocator &Arena) const { return Arena.alloc<MemberPointerType>(*this); } -void MemberPointerType::outputPre(OutputStream &OS) { - Type::outputPre(OS, *Pointee); +void MemberPointerType::outputPre(OutputStream &OS, NameResolver &Resolver) { + Type::outputPre(OS, *Pointee, Resolver); outputSpaceIfNecessary(OS); - outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee); + outputPointerIndicator(OS, PointerAffinity::Pointer, MemberName, Pointee, + Resolver); // FIXME: We should output this, but it requires updating lots of tests. // if (Ty.Quals & Q_Pointer64) @@ -759,25 +774,25 @@ void MemberPointerType::outputPre(OutputStream &OS) { OS << " __restrict"; } -void MemberPointerType::outputPost(OutputStream &OS) { +void MemberPointerType::outputPost(OutputStream &OS, NameResolver &Resolver) { if (Pointee->Prim == PrimTy::Function || Pointee->Prim == PrimTy::Array) OS << ")"; - Type::outputPost(OS, *Pointee); + Type::outputPost(OS, *Pointee, Resolver); } Type *FunctionType::clone(ArenaAllocator &Arena) const { return Arena.alloc<FunctionType>(*this); } -void FunctionType::outputPre(OutputStream &OS) { +void FunctionType::outputPre(OutputStream &OS, NameResolver &Resolver) { if (!(FunctionClass & Global)) { if (FunctionClass & Static) OS << "static "; } if (ReturnType) { - Type::outputPre(OS, *ReturnType); + Type::outputPre(OS, *ReturnType, Resolver); OS << " "; } @@ -788,9 +803,9 @@ void FunctionType::outputPre(OutputStream &OS) { outputCallingConvention(OS, CallConvention); } -void FunctionType::outputPost(OutputStream &OS) { +void FunctionType::outputPost(OutputStream &OS, NameResolver &Resolver) { OS << "("; - outputParameterList(OS, Params); + outputParameterList(OS, Params, Resolver); OS << ")"; if (Quals & Q_Const) OS << " const"; @@ -807,7 +822,7 @@ void FunctionType::outputPost(OutputStream &OS) { OS << " &&"; if (ReturnType) - Type::outputPost(OS, *ReturnType); + Type::outputPost(OS, *ReturnType, Resolver); return; } @@ -815,7 +830,7 @@ Type *UdtType::clone(ArenaAllocator &Arena) const { return Arena.alloc<UdtType>(*this); } -void UdtType::outputPre(OutputStream &OS) { +void UdtType::outputPre(OutputStream &OS, NameResolver &Resolver) { switch (Prim) { case PrimTy::Class: OS << "class "; @@ -833,24 +848,24 @@ void UdtType::outputPre(OutputStream &OS) { assert(false && "Not a udt type!"); } - outputName(OS, UdtName); + outputName(OS, UdtName, Resolver); } Type *ArrayType::clone(ArenaAllocator &Arena) const { return Arena.alloc<ArrayType>(*this); } -void ArrayType::outputPre(OutputStream &OS) { - Type::outputPre(OS, *ElementType); +void ArrayType::outputPre(OutputStream &OS, NameResolver &Resolver) { + Type::outputPre(OS, *ElementType, Resolver); } -void ArrayType::outputPost(OutputStream &OS) { +void ArrayType::outputPost(OutputStream &OS, NameResolver &Resolver) { if (ArrayDimension > 0) OS << "[" << ArrayDimension << "]"; if (NextDimension) - Type::outputPost(OS, *NextDimension); + Type::outputPost(OS, *NextDimension, Resolver); else if (ElementType) - Type::outputPost(OS, *ElementType); + Type::outputPost(OS, *ElementType, Resolver); } struct Symbol { @@ -867,7 +882,7 @@ namespace { // Demangler class takes the main role in demangling symbols. // It has a set of functions to parse mangled symbols into Type instances. // It also has a set of functions to cnovert Type instances to strings. -class Demangler { +class Demangler : public NameResolver { public: Demangler() = default; @@ -876,6 +891,8 @@ public: Symbol *parse(StringView &MangledName); void output(const Symbol *S, OutputStream &OS); + StringView resolve(StringView N) override; + // True if an error occurred. bool Error = false; @@ -1098,16 +1115,10 @@ void Demangler::memorizeString(StringView S) { Name *Demangler::demangleBackRefName(StringView &MangledName) { assert(startsWithDigit(MangledName)); - - size_t I = MangledName[0] - '0'; - if (I >= BackRefCount) { - Error = true; - return nullptr; - } - - MangledName = MangledName.dropFront(); Name *Node = Arena.alloc<Name>(); - Node->Str = BackReferences[I]; + Node->IsBackReference = true; + Node->Str = {MangledName.begin(), 1}; + MangledName = MangledName.dropFront(); return Node; } @@ -1128,7 +1139,7 @@ Name *Demangler::demangleTemplateInstantiationName(StringView &MangledName) { // Render this class template name into a string buffer so that we can // memorize it for the purpose of back-referencing. OutputStream OS = OutputStream::create(nullptr, nullptr, 1024); - outputName(OS, Node); + outputName(OS, Node, *this); OS << '\0'; char *Name = OS.getBuffer(); @@ -2026,6 +2037,14 @@ Demangler::demangleTemplateParameterList(StringView &MangledName) { return nullptr; } +StringView Demangler::resolve(StringView N) { + assert(N.size() == 1 && isdigit(N[0])); + int Digit = N[0] - '0'; + if (Digit >= BackRefCount) + return N; + return BackReferences[Digit]; +} + void Demangler::output(const Symbol *S, OutputStream &OS) { // Converts an AST to a string. // @@ -2044,9 +2063,9 @@ void Demangler::output(const Symbol *S, OutputStream &OS) { // the "first half" of type declaration, and outputPost() writes the // "second half". For example, outputPre() writes a return type for a // function and outputPost() writes an parameter list. - Type::outputPre(OS, *S->SymbolType); - outputName(OS, S->SymbolName); - Type::outputPost(OS, *S->SymbolType); + Type::outputPre(OS, *S->SymbolType, *this); + outputName(OS, S->SymbolName, *this); + Type::outputPost(OS, *S->SymbolType, *this); } void Demangler::dumpBackReferences() { @@ -2059,8 +2078,8 @@ void Demangler::dumpBackReferences() { OS.setCurrentPosition(0); Type *T = FunctionParamBackRefs[I]; - Type::outputPre(OS, *T); - Type::outputPost(OS, *T); + Type::outputPre(OS, *T, *this); + Type::outputPost(OS, *T, *this); std::printf(" [%d] - %*s\n", (int)I, (int)OS.getCurrentPosition(), OS.getBuffer()); |