| //===-- LVCodeViewVisitor.cpp ---------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This implements the LVCodeViewVisitor class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewVisitor.h" |
| #include "llvm/BinaryFormat/Magic.h" |
| #include "llvm/DebugInfo/CodeView/EnumTables.h" |
| #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" |
| #include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h" |
| #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" |
| #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVType.h" |
| #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h" |
| #include "llvm/DebugInfo/PDB/Native/DbiStream.h" |
| #include "llvm/DebugInfo/PDB/Native/InputFile.h" |
| #include "llvm/DebugInfo/PDB/Native/NativeSession.h" |
| #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
| #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" |
| #include "llvm/DebugInfo/PDB/Native/RawError.h" |
| #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
| #include "llvm/DebugInfo/PDB/PDB.h" |
| #include "llvm/Demangle/Demangle.h" |
| #include "llvm/Object/COFF.h" |
| #include "llvm/Support/Error.h" |
| #include "llvm/Support/FileSystem.h" |
| #include "llvm/Support/FormatAdapters.h" |
| #include "llvm/Support/FormatVariadic.h" |
| |
| using namespace llvm; |
| using namespace llvm::codeview; |
| using namespace llvm::object; |
| using namespace llvm::pdb; |
| using namespace llvm::logicalview; |
| |
| #define DEBUG_TYPE "CodeViewUtilities" |
| |
| namespace llvm { |
| namespace logicalview { |
| |
| static TypeIndex getTrueType(TypeIndex &TI) { |
| // Dealing with a MSVC generated PDB, we encountered a type index with the |
| // value of: 0x0280xxxx where xxxx=0000. |
| // |
| // There is some documentation about type indices: |
| // https://llvm.org/docs/PDB/TpiStream.html |
| // |
| // A type index is a 32-bit integer that uniquely identifies a type inside |
| // of an object file’s .debug$T section or a PDB file’s TPI or IPI stream. |
| // The value of the type index for the first type record from the TPI stream |
| // is given by the TypeIndexBegin member of the TPI Stream Header although |
| // in practice this value is always equal to 0x1000 (4096). |
| // |
| // Any type index with a high bit set is considered to come from the IPI |
| // stream, although this appears to be more of a hack, and LLVM does not |
| // generate type indices of this nature. They can, however, be observed in |
| // Microsoft PDBs occasionally, so one should be prepared to handle them. |
| // Note that having the high bit set is not a necessary condition to |
| // determine whether a type index comes from the IPI stream, it is only |
| // sufficient. |
| LLVM_DEBUG( |
| { dbgs() << "Index before: " << HexNumber(TI.getIndex()) << "\n"; }); |
| TI.setIndex(TI.getIndex() & 0x0000ffff); |
| LLVM_DEBUG( |
| { dbgs() << "Index after: " << HexNumber(TI.getIndex()) << "\n"; }); |
| return TI; |
| } |
| |
| static const EnumEntry<TypeLeafKind> LeafTypeNames[] = { |
| #define CV_TYPE(enum, val) {#enum, enum}, |
| #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" |
| }; |
| |
| // Return the type name pointed by the type index. It uses the kind to query |
| // the associated name for the record type. |
| static StringRef getRecordName(LazyRandomTypeCollection &Types, TypeIndex TI) { |
| if (TI.isSimple()) |
| return {}; |
| |
| StringRef RecordName; |
| CVType CVReference = Types.getType(TI); |
| auto GetName = [&](auto Record) { |
| if (Error Err = TypeDeserializer::deserializeAs( |
| const_cast<CVType &>(CVReference), Record)) |
| consumeError(std::move(Err)); |
| else |
| RecordName = Record.getName(); |
| }; |
| |
| TypeRecordKind RK = static_cast<TypeRecordKind>(CVReference.kind()); |
| if (RK == TypeRecordKind::Class || RK == TypeRecordKind::Struct) |
| GetName(ClassRecord(RK)); |
| else if (RK == TypeRecordKind::Union) |
| GetName(UnionRecord(RK)); |
| else if (RK == TypeRecordKind::Enum) |
| GetName(EnumRecord(RK)); |
| |
| return RecordName; |
| } |
| |
| } // namespace logicalview |
| } // namespace llvm |
| |
| #undef DEBUG_TYPE |
| #define DEBUG_TYPE "CodeViewDataVisitor" |
| |
| namespace llvm { |
| namespace logicalview { |
| |
| // Keeps the type indexes with line information. |
| using LVLineRecords = std::vector<TypeIndex>; |
| |
| namespace { |
| |
| class LVTypeRecords { |
| LVShared *Shared = nullptr; |
| |
| // Logical elements associated to their CodeView Type Index. |
| using RecordEntry = std::pair<TypeLeafKind, LVElement *>; |
| using RecordTable = std::map<TypeIndex, RecordEntry>; |
| RecordTable RecordFromTypes; |
| RecordTable RecordFromIds; |
| |
| using NameTable = std::map<StringRef, TypeIndex>; |
| NameTable NameFromTypes; |
| NameTable NameFromIds; |
| |
| public: |
| LVTypeRecords(LVShared *Shared) : Shared(Shared) {} |
| |
| void add(uint32_t StreamIdx, TypeIndex TI, TypeLeafKind Kind, |
| LVElement *Element = nullptr); |
| void add(uint32_t StreamIdx, TypeIndex TI, StringRef Name); |
| LVElement *find(uint32_t StreamIdx, TypeIndex TI, bool Create = true); |
| TypeIndex find(uint32_t StreamIdx, StringRef Name); |
| }; |
| |
| class LVForwardReferences { |
| // Forward reference and its definitions (Name as key). |
| using ForwardEntry = std::pair<TypeIndex, TypeIndex>; |
| using ForwardTypeNames = std::map<StringRef, ForwardEntry>; |
| ForwardTypeNames ForwardTypesNames; |
| |
| // Forward reference and its definition (TypeIndex as key). |
| using ForwardType = std::map<TypeIndex, TypeIndex>; |
| ForwardType ForwardTypes; |
| |
| // Forward types and its references. |
| void add(TypeIndex TIForward, TypeIndex TIReference) { |
| ForwardTypes.emplace(TIForward, TIReference); |
| } |
| |
| void add(StringRef Name, TypeIndex TIForward) { |
| if (ForwardTypesNames.find(Name) == ForwardTypesNames.end()) { |
| ForwardTypesNames.emplace( |
| std::piecewise_construct, std::forward_as_tuple(Name), |
| std::forward_as_tuple(TIForward, TypeIndex::None())); |
| } else { |
| // Update a recorded definition with its reference. |
| ForwardTypesNames[Name].first = TIForward; |
| add(TIForward, ForwardTypesNames[Name].second); |
| } |
| } |
| |
| // Update a previously recorded forward reference with its definition. |
| void update(StringRef Name, TypeIndex TIReference) { |
| if (ForwardTypesNames.find(Name) != ForwardTypesNames.end()) { |
| // Update the recorded forward reference with its definition. |
| ForwardTypesNames[Name].second = TIReference; |
| add(ForwardTypesNames[Name].first, TIReference); |
| } else { |
| // We have not seen the forward reference. Insert the definition. |
| ForwardTypesNames.emplace( |
| std::piecewise_construct, std::forward_as_tuple(Name), |
| std::forward_as_tuple(TypeIndex::None(), TIReference)); |
| } |
| } |
| |
| public: |
| LVForwardReferences() = default; |
| |
| void record(bool IsForwardRef, StringRef Name, TypeIndex TI) { |
| // We are expecting for the forward references to be first. But that |
| // is not always the case. A name must be recorded regardless of the |
| // order in which the forward reference appears. |
| (IsForwardRef) ? add(Name, TI) : update(Name, TI); |
| } |
| |
| TypeIndex find(TypeIndex TIForward) { |
| return (ForwardTypes.find(TIForward) != ForwardTypes.end()) |
| ? ForwardTypes[TIForward] |
| : TypeIndex::None(); |
| } |
| |
| TypeIndex find(StringRef Name) { |
| return (ForwardTypesNames.find(Name) != ForwardTypesNames.end()) |
| ? ForwardTypesNames[Name].second |
| : TypeIndex::None(); |
| } |
| |
| // If the given TI corresponds to a reference, return the reference. |
| // Otherwise return the given TI. |
| TypeIndex remap(TypeIndex TI) { |
| TypeIndex Forward = find(TI); |
| return Forward.isNoneType() ? TI : Forward; |
| } |
| }; |
| |
| // Namespace deduction. |
| class LVNamespaceDeduction { |
| LVShared *Shared = nullptr; |
| |
| using Names = std::map<StringRef, LVScope *>; |
| Names NamespaceNames; |
| |
| using LookupSet = std::set<StringRef>; |
| LookupSet DeducedScopes; |
| LookupSet UnresolvedScopes; |
| LookupSet IdentifiedNamespaces; |
| |
| void add(StringRef Name, LVScope *Namespace) { |
| if (NamespaceNames.find(Name) == NamespaceNames.end()) |
| NamespaceNames.emplace(Name, Namespace); |
| } |
| |
| public: |
| LVNamespaceDeduction(LVShared *Shared) : Shared(Shared) {} |
| |
| void init(); |
| void add(StringRef String); |
| LVScope *get(LVStringRefs Components); |
| LVScope *get(StringRef Name, bool CheckScope = true); |
| |
| // Find the logical namespace for the 'Name' component. |
| LVScope *find(StringRef Name) { |
| LVScope *Namespace = (NamespaceNames.find(Name) != NamespaceNames.end()) |
| ? NamespaceNames[Name] |
| : nullptr; |
| return Namespace; |
| } |
| |
| // For the given lexical components, return a tuple with the first entry |
| // being the outermost namespace and the second entry being the first |
| // non-namespace. |
| LVLexicalIndex find(LVStringRefs Components) { |
| if (Components.empty()) |
| return {}; |
| |
| LVStringRefs::size_type FirstNamespace = 0; |
| LVStringRefs::size_type FirstNonNamespace; |
| for (LVStringRefs::size_type Index = 0; Index < Components.size(); |
| ++Index) { |
| FirstNonNamespace = Index; |
| LookupSet::iterator Iter = IdentifiedNamespaces.find(Components[Index]); |
| if (Iter == IdentifiedNamespaces.end()) |
| // The component is not a namespace name. |
| break; |
| } |
| return std::make_tuple(FirstNamespace, FirstNonNamespace); |
| } |
| }; |
| |
| // Strings. |
| class LVStringRecords { |
| using StringEntry = std::tuple<uint32_t, std::string, LVScopeCompileUnit *>; |
| using StringIds = std::map<TypeIndex, StringEntry>; |
| StringIds Strings; |
| |
| public: |
| LVStringRecords() = default; |
| |
| void add(TypeIndex TI, StringRef String) { |
| static uint32_t Index = 0; |
| if (Strings.find(TI) == Strings.end()) |
| Strings.emplace( |
| std::piecewise_construct, std::forward_as_tuple(TI), |
| std::forward_as_tuple(++Index, std::string(String), nullptr)); |
| } |
| |
| StringRef find(TypeIndex TI) { |
| StringIds::iterator Iter = Strings.find(TI); |
| return Iter != Strings.end() ? std::get<1>(Iter->second) : StringRef{}; |
| } |
| |
| uint32_t findIndex(TypeIndex TI) { |
| StringIds::iterator Iter = Strings.find(TI); |
| return Iter != Strings.end() ? std::get<0>(Iter->second) : 0; |
| } |
| |
| // Move strings representing the filenames to the compile unit. |
| void addFilenames(); |
| void addFilenames(LVScopeCompileUnit *Scope); |
| }; |
| } // namespace |
| |
| using LVTypeKinds = std::set<TypeLeafKind>; |
| using LVSymbolKinds = std::set<SymbolKind>; |
| |
| // The following data keeps forward information, type records, names for |
| // namespace deduction, strings records, line records. |
| // It is shared by the type visitor, symbol visitor and logical visitor and |
| // it is independent from the CodeViewReader. |
| struct LVShared { |
| LVCodeViewReader *Reader; |
| LVLogicalVisitor *Visitor; |
| LVForwardReferences ForwardReferences; |
| LVLineRecords LineRecords; |
| LVNamespaceDeduction NamespaceDeduction; |
| LVStringRecords StringRecords; |
| LVTypeRecords TypeRecords; |
| |
| // In order to determine which types and/or symbols records should be handled |
| // by the reader, we record record kinds seen by the type and symbol visitors. |
| // At the end of the scopes creation, the '--internal=tag' option will allow |
| // to print the unique record ids collected. |
| LVTypeKinds TypeKinds; |
| LVSymbolKinds SymbolKinds; |
| |
| LVShared(LVCodeViewReader *Reader, LVLogicalVisitor *Visitor) |
| : Reader(Reader), Visitor(Visitor), NamespaceDeduction(this), |
| TypeRecords(this) {} |
| ~LVShared() = default; |
| }; |
| } // namespace logicalview |
| } // namespace llvm |
| |
| void LVTypeRecords::add(uint32_t StreamIdx, TypeIndex TI, TypeLeafKind Kind, |
| LVElement *Element) { |
| RecordTable &Target = |
| (StreamIdx == StreamTPI) ? RecordFromTypes : RecordFromIds; |
| Target.emplace(std::piecewise_construct, std::forward_as_tuple(TI), |
| std::forward_as_tuple(Kind, Element)); |
| } |
| |
| void LVTypeRecords::add(uint32_t StreamIdx, TypeIndex TI, StringRef Name) { |
| NameTable &Target = (StreamIdx == StreamTPI) ? NameFromTypes : NameFromIds; |
| Target.emplace(Name, TI); |
| } |
| |
| LVElement *LVTypeRecords::find(uint32_t StreamIdx, TypeIndex TI, bool Create) { |
| RecordTable &Target = |
| (StreamIdx == StreamTPI) ? RecordFromTypes : RecordFromIds; |
| |
| LVElement *Element = nullptr; |
| RecordTable::iterator Iter = Target.find(TI); |
| if (Iter != Target.end()) { |
| Element = Iter->second.second; |
| if (Element || !Create) |
| return Element; |
| |
| // Create the logical element if not found. |
| Element = Shared->Visitor->createElement(Iter->second.first); |
| if (Element) { |
| Element->setOffset(TI.getIndex()); |
| Element->setOffsetFromTypeIndex(); |
| Target[TI].second = Element; |
| } |
| } |
| return Element; |
| } |
| |
| TypeIndex LVTypeRecords::find(uint32_t StreamIdx, StringRef Name) { |
| NameTable &Target = (StreamIdx == StreamTPI) ? NameFromTypes : NameFromIds; |
| NameTable::iterator Iter = Target.find(Name); |
| return Iter != Target.end() ? Iter->second : TypeIndex::None(); |
| } |
| |
| void LVStringRecords::addFilenames() { |
| for (StringIds::const_reference Entry : Strings) { |
| StringRef Name = std::get<1>(Entry.second); |
| LVScopeCompileUnit *Scope = std::get<2>(Entry.second); |
| Scope->addFilename(transformPath(Name)); |
| } |
| Strings.clear(); |
| } |
| |
| void LVStringRecords::addFilenames(LVScopeCompileUnit *Scope) { |
| for (StringIds::reference Entry : Strings) |
| if (!std::get<2>(Entry.second)) |
| std::get<2>(Entry.second) = Scope; |
| } |
| |
| void LVNamespaceDeduction::add(StringRef String) { |
| StringRef InnerComponent; |
| StringRef OuterComponent; |
| std::tie(OuterComponent, InnerComponent) = getInnerComponent(String); |
| DeducedScopes.insert(InnerComponent); |
| if (OuterComponent.size()) |
| UnresolvedScopes.insert(OuterComponent); |
| } |
| |
| void LVNamespaceDeduction::init() { |
| // We have 2 sets of names: |
| // - deduced scopes (class, structure, union and enum) and |
| // - unresolved scopes, that can represent namespaces or any deduced. |
| // Before creating the namespaces, we have to traverse the unresolved |
| // and remove any references to already deduced scopes. |
| LVStringRefs Components; |
| for (const StringRef &Unresolved : UnresolvedScopes) { |
| Components = getAllLexicalComponents(Unresolved); |
| for (const StringRef &Component : Components) { |
| LookupSet::iterator Iter = DeducedScopes.find(Component); |
| if (Iter == DeducedScopes.end()) |
| IdentifiedNamespaces.insert(Component); |
| } |
| } |
| |
| LLVM_DEBUG({ |
| auto Print = [&](LookupSet &Container, const char *Title) { |
| auto Header = [&]() { |
| dbgs() << formatv("\n{0}\n", fmt_repeat('=', 72)); |
| dbgs() << formatv("{0}\n", Title); |
| dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); |
| }; |
| Header(); |
| for (const StringRef &Item : Container) |
| dbgs() << formatv("'{0}'\n", Item.str().c_str()); |
| }; |
| |
| Print(DeducedScopes, "Deducted Scopes"); |
| Print(UnresolvedScopes, "Unresolved Scopes"); |
| Print(IdentifiedNamespaces, "Namespaces"); |
| }); |
| } |
| |
| LVScope *LVNamespaceDeduction::get(LVStringRefs Components) { |
| LLVM_DEBUG({ |
| for (const StringRef &Component : Components) |
| dbgs() << formatv("'{0}'\n", Component.str().c_str()); |
| }); |
| |
| if (Components.empty()) |
| return nullptr; |
| |
| // Update the namespaces relationship. |
| LVScope *Namespace = nullptr; |
| LVScope *Parent = Shared->Reader->getCompileUnit(); |
| for (const StringRef &Component : Components) { |
| // Check if we have seen the namespace. |
| Namespace = find(Component); |
| if (!Namespace) { |
| // We have identified namespaces that are generated by MSVC. Mark them |
| // as 'system' so they will be excluded from the logical view. |
| Namespace = Shared->Reader->createScopeNamespace(); |
| Namespace->setTag(dwarf::DW_TAG_namespace); |
| Namespace->setName(Component); |
| Parent->addElement(Namespace); |
| getReader().isSystemEntry(Namespace); |
| add(Component, Namespace); |
| } |
| Parent = Namespace; |
| } |
| return Parent; |
| } |
| |
| LVScope *LVNamespaceDeduction::get(StringRef ScopedName, bool CheckScope) { |
| LVStringRefs Components = getAllLexicalComponents(ScopedName); |
| if (CheckScope) |
| Components.erase(std::remove_if(Components.begin(), Components.end(), |
| [&](StringRef Component) { |
| LookupSet::iterator Iter = |
| IdentifiedNamespaces.find(Component); |
| return Iter == IdentifiedNamespaces.end(); |
| }), |
| Components.end()); |
| |
| LLVM_DEBUG( |
| { dbgs() << formatv("ScopedName: '{0}'\n", ScopedName.str().c_str()); }); |
| |
| return get(Components); |
| } |
| |
| #undef DEBUG_TYPE |
| #define DEBUG_TYPE "CodeViewTypeVisitor" |
| |
| //===----------------------------------------------------------------------===// |
| // TypeRecord traversal. |
| //===----------------------------------------------------------------------===// |
| void LVTypeVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI, |
| uint32_t StreamIdx) const { |
| codeview::printTypeIndex(W, FieldName, TI, |
| StreamIdx == StreamTPI ? Types : Ids); |
| } |
| |
| Error LVTypeVisitor::visitTypeBegin(CVType &Record) { |
| return visitTypeBegin(Record, TypeIndex::fromArrayIndex(Types.size())); |
| } |
| |
| Error LVTypeVisitor::visitTypeBegin(CVType &Record, TypeIndex TI) { |
| LLVM_DEBUG({ |
| W.getOStream() << formatTypeLeafKind(Record.kind()); |
| W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")\n"; |
| }); |
| |
| if (options().getInternalTag()) |
| Shared->TypeKinds.insert(Record.kind()); |
| |
| // The collected type records, will be use to create the logical elements |
| // during the symbols traversal when a type is referenced. |
| CurrentTypeIndex = TI; |
| Shared->TypeRecords.add(StreamIdx, TI, Record.kind()); |
| return Error::success(); |
| } |
| |
| Error LVTypeVisitor::visitUnknownType(CVType &Record) { |
| LLVM_DEBUG({ W.printNumber("Length", uint32_t(Record.content().size())); }); |
| return Error::success(); |
| } |
| |
| Error LVTypeVisitor::visitMemberBegin(CVMemberRecord &Record) { |
| LLVM_DEBUG({ |
| W.startLine() << formatTypeLeafKind(Record.Kind); |
| W.getOStream() << " {\n"; |
| W.indent(); |
| }); |
| return Error::success(); |
| } |
| |
| Error LVTypeVisitor::visitMemberEnd(CVMemberRecord &Record) { |
| LLVM_DEBUG({ |
| W.unindent(); |
| W.startLine() << "}\n"; |
| }); |
| return Error::success(); |
| } |
| |
| Error LVTypeVisitor::visitUnknownMember(CVMemberRecord &Record) { |
| LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); }); |
| return Error::success(); |
| } |
| |
| // LF_BUILDINFO (TPI)/(IPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, BuildInfoRecord &Args) { |
| // All the args are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| W.printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size())); |
| ListScope Arguments(W, "Arguments"); |
| for (TypeIndex Arg : Args.getArgs()) |
| printTypeIndex("ArgType", Arg, StreamIPI); |
| }); |
| |
| // Only add the strings that hold information about filenames. They will be |
| // used to complete the line/file information for the logical elements. |
| // There are other strings holding information about namespaces. |
| TypeIndex TI; |
| StringRef String; |
| |
| // Absolute CWD path |
| TI = Args.getArgs()[BuildInfoRecord::BuildInfoArg::CurrentDirectory]; |
| String = Ids.getTypeName(TI); |
| if (!String.empty()) |
| Shared->StringRecords.add(TI, String); |
| |
| // Get the compile unit name. |
| TI = Args.getArgs()[BuildInfoRecord::BuildInfoArg::SourceFile]; |
| String = Ids.getTypeName(TI); |
| if (!String.empty()) |
| Shared->StringRecords.add(TI, String); |
| LogicalVisitor->setCompileUnitName(std::string(String)); |
| |
| return Error::success(); |
| } |
| |
| // LF_CLASS, LF_STRUCTURE, LF_INTERFACE (TPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI); |
| printTypeIndex("FieldListType", Class.getFieldList(), StreamTPI); |
| W.printString("Name", Class.getName()); |
| }); |
| |
| // Collect class name for scope deduction. |
| Shared->NamespaceDeduction.add(Class.getName()); |
| Shared->ForwardReferences.record(Class.isForwardRef(), Class.getName(), |
| CurrentTypeIndex); |
| |
| // Collect class name for contained scopes deduction. |
| Shared->TypeRecords.add(StreamIdx, CurrentTypeIndex, Class.getName()); |
| return Error::success(); |
| } |
| |
| // LF_ENUM (TPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI); |
| printTypeIndex("FieldListType", Enum.getFieldList(), StreamTPI); |
| W.printString("Name", Enum.getName()); |
| }); |
| |
| // Collect enum name for scope deduction. |
| Shared->NamespaceDeduction.add(Enum.getName()); |
| return Error::success(); |
| } |
| |
| // LF_FUNC_ID (TPI)/(IPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, FuncIdRecord &Func) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI); |
| printTypeIndex("Type", Func.getFunctionType(), StreamTPI); |
| printTypeIndex("Parent", Func.getParentScope(), StreamTPI); |
| W.printString("Name", Func.getName()); |
| }); |
| |
| // Collect function name for scope deduction. |
| Shared->NamespaceDeduction.add(Func.getName()); |
| return Error::success(); |
| } |
| |
| // LF_PROCEDURE (TPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, ProcedureRecord &Proc) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", CurrentTypeIndex, StreamTPI); |
| printTypeIndex("ReturnType", Proc.getReturnType(), StreamTPI); |
| W.printNumber("NumParameters", Proc.getParameterCount()); |
| printTypeIndex("ArgListType", Proc.getArgumentList(), StreamTPI); |
| }); |
| |
| // Collect procedure information as they can be referenced by typedefs. |
| Shared->TypeRecords.add(StreamTPI, CurrentTypeIndex, {}); |
| return Error::success(); |
| } |
| |
| // LF_STRING_ID (TPI)/(IPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, StringIdRecord &String) { |
| // No additional references are needed. |
| LLVM_DEBUG({ |
| printTypeIndex("Id", String.getId(), StreamIPI); |
| W.printString("StringData", String.getString()); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_UDT_SRC_LINE (TPI)/(IPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, |
| UdtSourceLineRecord &Line) { |
| // UDT and SourceFile are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| printTypeIndex("UDT", Line.getUDT(), StreamIPI); |
| printTypeIndex("SourceFile", Line.getSourceFile(), StreamIPI); |
| W.printNumber("LineNumber", Line.getLineNumber()); |
| }); |
| |
| Shared->LineRecords.push_back(CurrentTypeIndex); |
| return Error::success(); |
| } |
| |
| // LF_UNION (TPI) |
| Error LVTypeVisitor::visitKnownRecord(CVType &Record, UnionRecord &Union) { |
| LLVM_DEBUG({ |
| W.printNumber("MemberCount", Union.getMemberCount()); |
| printTypeIndex("FieldList", Union.getFieldList(), StreamTPI); |
| W.printNumber("SizeOf", Union.getSize()); |
| W.printString("Name", Union.getName()); |
| if (Union.hasUniqueName()) |
| W.printString("UniqueName", Union.getUniqueName()); |
| }); |
| |
| // Collect union name for scope deduction. |
| Shared->NamespaceDeduction.add(Union.getName()); |
| Shared->ForwardReferences.record(Union.isForwardRef(), Union.getName(), |
| CurrentTypeIndex); |
| |
| // Collect class name for contained scopes deduction. |
| Shared->TypeRecords.add(StreamIdx, CurrentTypeIndex, Union.getName()); |
| return Error::success(); |
| } |
| |
| #undef DEBUG_TYPE |
| #define DEBUG_TYPE "CodeViewSymbolVisitor" |
| |
| //===----------------------------------------------------------------------===// |
| // SymbolRecord traversal. |
| //===----------------------------------------------------------------------===// |
| void LVSymbolVisitorDelegate::printRelocatedField(StringRef Label, |
| uint32_t RelocOffset, |
| uint32_t Offset, |
| StringRef *RelocSym) { |
| Reader->printRelocatedField(Label, CoffSection, RelocOffset, Offset, |
| RelocSym); |
| } |
| |
| void LVSymbolVisitorDelegate::getLinkageName(uint32_t RelocOffset, |
| uint32_t Offset, |
| StringRef *RelocSym) { |
| Reader->getLinkageName(CoffSection, RelocOffset, Offset, RelocSym); |
| } |
| |
| StringRef |
| LVSymbolVisitorDelegate::getFileNameForFileOffset(uint32_t FileOffset) { |
| Expected<StringRef> Name = Reader->getFileNameForFileOffset(FileOffset); |
| if (!Name) { |
| consumeError(Name.takeError()); |
| return {}; |
| } |
| return *Name; |
| } |
| |
| DebugStringTableSubsectionRef LVSymbolVisitorDelegate::getStringTable() { |
| return Reader->CVStringTable; |
| } |
| |
| void LVSymbolVisitor::printLocalVariableAddrRange( |
| const LocalVariableAddrRange &Range, uint32_t RelocationOffset) { |
| DictScope S(W, "LocalVariableAddrRange"); |
| if (ObjDelegate) |
| ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset, |
| Range.OffsetStart); |
| W.printHex("ISectStart", Range.ISectStart); |
| W.printHex("Range", Range.Range); |
| } |
| |
| void LVSymbolVisitor::printLocalVariableAddrGap( |
| ArrayRef<LocalVariableAddrGap> Gaps) { |
| for (const LocalVariableAddrGap &Gap : Gaps) { |
| ListScope S(W, "LocalVariableAddrGap"); |
| W.printHex("GapStartOffset", Gap.GapStartOffset); |
| W.printHex("Range", Gap.Range); |
| } |
| } |
| |
| void LVSymbolVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const { |
| codeview::printTypeIndex(W, FieldName, TI, Types); |
| } |
| |
| Error LVSymbolVisitor::visitSymbolBegin(CVSymbol &Record) { |
| return visitSymbolBegin(Record, 0); |
| } |
| |
| Error LVSymbolVisitor::visitSymbolBegin(CVSymbol &Record, uint32_t Offset) { |
| SymbolKind Kind = Record.kind(); |
| LLVM_DEBUG({ |
| W.printNumber("Offset", Offset); |
| W.printEnum("Begin Kind", unsigned(Kind), getSymbolTypeNames()); |
| }); |
| |
| if (options().getInternalTag()) |
| Shared->SymbolKinds.insert(Kind); |
| |
| LogicalVisitor->CurrentElement = LogicalVisitor->createElement(Kind); |
| if (!LogicalVisitor->CurrentElement) { |
| LLVM_DEBUG({ |
| // We have an unsupported Symbol or Type Record. |
| // W.printEnum("Kind ignored", unsigned(Kind), getSymbolTypeNames()); |
| }); |
| return Error::success(); |
| } |
| |
| // Offset carried by the traversal routines when dealing with streams. |
| CurrentOffset = Offset; |
| IsCompileUnit = false; |
| if (!LogicalVisitor->CurrentElement->getOffsetFromTypeIndex()) |
| LogicalVisitor->CurrentElement->setOffset(Offset); |
| if (symbolOpensScope(Kind) || (IsCompileUnit = symbolIsCompileUnit(Kind))) { |
| assert(LogicalVisitor->CurrentScope && "Invalid scope!"); |
| LogicalVisitor->addElement(LogicalVisitor->CurrentScope, IsCompileUnit); |
| } else { |
| if (LogicalVisitor->CurrentSymbol) |
| LogicalVisitor->addElement(LogicalVisitor->CurrentSymbol); |
| if (LogicalVisitor->CurrentType) |
| LogicalVisitor->addElement(LogicalVisitor->CurrentType); |
| } |
| |
| return Error::success(); |
| } |
| |
| Error LVSymbolVisitor::visitSymbolEnd(CVSymbol &Record) { |
| SymbolKind Kind = Record.kind(); |
| LLVM_DEBUG( |
| { W.printEnum("End Kind", unsigned(Kind), getSymbolTypeNames()); }); |
| |
| if (symbolEndsScope(Kind)) { |
| LogicalVisitor->popScope(); |
| } |
| |
| return Error::success(); |
| } |
| |
| Error LVSymbolVisitor::visitUnknownSymbol(CVSymbol &Record) { |
| LLVM_DEBUG({ W.printNumber("Length", Record.length()); }); |
| return Error::success(); |
| } |
| |
| // S_BLOCK32 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, BlockSym &Block) { |
| LLVM_DEBUG({ |
| W.printHex("CodeSize", Block.CodeSize); |
| W.printHex("Segment", Block.Segment); |
| W.printString("BlockName", Block.Name); |
| }); |
| |
| if (LVScope *Scope = LogicalVisitor->CurrentScope) { |
| StringRef LinkageName; |
| if (ObjDelegate) |
| ObjDelegate->getLinkageName(Block.getRelocationOffset(), Block.CodeOffset, |
| &LinkageName); |
| Scope->setLinkageName(LinkageName); |
| |
| if (options().getGeneralCollectRanges()) { |
| // Record converted segment::offset addressing for this scope. |
| LVAddress Addendum = Reader->getSymbolTableAddress(LinkageName); |
| LVAddress LowPC = |
| Reader->linearAddress(Block.Segment, Block.CodeOffset, Addendum); |
| LVAddress HighPC = LowPC + Block.CodeSize - 1; |
| Scope->addObject(LowPC, HighPC); |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_BPREL32 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| BPRelativeSym &Local) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", Local.Type); |
| W.printNumber("Offset", Local.Offset); |
| W.printString("VarName", Local.Name); |
| }); |
| |
| if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) { |
| Symbol->setName(Local.Name); |
| // From the MS_Symbol_Type.pdf documentation (S_BPREL32): |
| // This symbol specifies symbols that are allocated on the stack for a |
| // procedure. For C and C++, these include the actual function parameters |
| // and the local non-static variables of functions. |
| // However, the offset for 'this' comes as a negative value. |
| |
| // Symbol was created as 'variable'; determine its real kind. |
| Symbol->resetIsVariable(); |
| |
| if (Local.Name.equals("this")) { |
| Symbol->setIsParameter(); |
| Symbol->setIsArtificial(); |
| } else { |
| // Determine symbol kind. |
| bool(Local.Offset > 0) ? Symbol->setIsParameter() |
| : Symbol->setIsVariable(); |
| } |
| |
| // Update correct debug information tag. |
| if (Symbol->getIsParameter()) |
| Symbol->setTag(dwarf::DW_TAG_formal_parameter); |
| |
| LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type); |
| if (Element && Element->getIsScoped()) { |
| // We have a local type. Find its parent function. |
| LVScope *Parent = Symbol->getFunctionParent(); |
| // The element representing the type has been already finalized. If |
| // the type is an aggregate type, its members have been already added. |
| // As the type is local, its level will be changed. |
| |
| // FIXME: Currently the algorithm used to scope lambda functions is |
| // incorrect. Before we allocate the type at this scope, check if is |
| // already allocated in other scope. |
| if (!Element->getParentScope()) { |
| Parent->addElement(Element); |
| Element->updateLevel(Parent); |
| } |
| } |
| Symbol->setType(Element); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_REGREL32 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| RegRelativeSym &Local) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", Local.Type); |
| W.printNumber("Offset", Local.Offset); |
| W.printString("VarName", Local.Name); |
| }); |
| |
| if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) { |
| Symbol->setName(Local.Name); |
| |
| // Symbol was created as 'variable'; determine its real kind. |
| Symbol->resetIsVariable(); |
| |
| // Check for the 'this' symbol. |
| if (Local.Name.equals("this")) { |
| Symbol->setIsArtificial(); |
| Symbol->setIsParameter(); |
| } else { |
| // Determine symbol kind. |
| determineSymbolKind(Symbol, Local.Register); |
| } |
| |
| // Update correct debug information tag. |
| if (Symbol->getIsParameter()) |
| Symbol->setTag(dwarf::DW_TAG_formal_parameter); |
| |
| LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type); |
| if (Element && Element->getIsScoped()) { |
| // We have a local type. Find its parent function. |
| LVScope *Parent = Symbol->getFunctionParent(); |
| // The element representing the type has been already finalized. If |
| // the type is an aggregate type, its members have been already added. |
| // As the type is local, its level will be changed. |
| |
| // FIXME: Currently the algorithm used to scope lambda functions is |
| // incorrect. Before we allocate the type at this scope, check if is |
| // already allocated in other scope. |
| if (!Element->getParentScope()) { |
| Parent->addElement(Element); |
| Element->updateLevel(Parent); |
| } |
| } |
| Symbol->setType(Element); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_BUILDINFO |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR, |
| BuildInfoSym &BuildInfo) { |
| LLVM_DEBUG({ printTypeIndex("BuildId", BuildInfo.BuildId); }); |
| |
| CVType CVBuildType = Ids.getType(BuildInfo.BuildId); |
| if (Error Err = LogicalVisitor->finishVisitation( |
| CVBuildType, BuildInfo.BuildId, Reader->getCompileUnit())) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| // S_COMPILE2 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| Compile2Sym &Compile2) { |
| LLVM_DEBUG({ |
| W.printEnum("Language", uint8_t(Compile2.getLanguage()), |
| getSourceLanguageNames()); |
| W.printFlags("Flags", uint32_t(Compile2.getFlags()), |
| getCompileSym3FlagNames()); |
| W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); |
| W.printString("VersionName", Compile2.Version); |
| }); |
| |
| // MSVC generates the following sequence for a CodeView module: |
| // S_OBJNAME --> Set 'CurrentObjectName'. |
| // S_COMPILE2 --> Set the compile unit name using 'CurrentObjectName'. |
| // ... |
| // S_BUILDINFO --> Extract the source name. |
| // |
| // Clang generates the following sequence for a CodeView module: |
| // S_COMPILE2 --> Set the compile unit name to empty string. |
| // ... |
| // S_BUILDINFO --> Extract the source name. |
| // |
| // For both toolchains, update the compile unit name from S_BUILDINFO. |
| if (LVScope *Scope = LogicalVisitor->CurrentScope) { |
| // The name of the CU, was extracted from the 'BuildInfo' subsection. |
| Reader->setCompileUnitCPUType(Compile2.Machine); |
| Scope->setName(CurrentObjectName); |
| if (options().getAttributeProducer()) |
| Scope->setProducer(Compile2.Version); |
| getReader().isSystemEntry(Scope, CurrentObjectName); |
| |
| // The line records in CodeView are recorded per Module ID. Update |
| // the relationship between the current CU and the Module ID. |
| Reader->addModule(Scope); |
| |
| // Updated the collected strings with their associated compile unit. |
| Shared->StringRecords.addFilenames(Reader->getCompileUnit()); |
| } |
| |
| // Clear any previous ObjectName. |
| CurrentObjectName = ""; |
| return Error::success(); |
| } |
| |
| // S_COMPILE3 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| Compile3Sym &Compile3) { |
| LLVM_DEBUG({ |
| W.printEnum("Language", uint8_t(Compile3.getLanguage()), |
| getSourceLanguageNames()); |
| W.printFlags("Flags", uint32_t(Compile3.getFlags()), |
| getCompileSym3FlagNames()); |
| W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); |
| W.printString("VersionName", Compile3.Version); |
| }); |
| |
| // MSVC generates the following sequence for a CodeView module: |
| // S_OBJNAME --> Set 'CurrentObjectName'. |
| // S_COMPILE3 --> Set the compile unit name using 'CurrentObjectName'. |
| // ... |
| // S_BUILDINFO --> Extract the source name. |
| // |
| // Clang generates the following sequence for a CodeView module: |
| // S_COMPILE3 --> Set the compile unit name to empty string. |
| // ... |
| // S_BUILDINFO --> Extract the source name. |
| // |
| // For both toolchains, update the compile unit name from S_BUILDINFO. |
| if (LVScope *Scope = LogicalVisitor->CurrentScope) { |
| // The name of the CU, was extracted from the 'BuildInfo' subsection. |
| Reader->setCompileUnitCPUType(Compile3.Machine); |
| Scope->setName(CurrentObjectName); |
| if (options().getAttributeProducer()) |
| Scope->setProducer(Compile3.Version); |
| getReader().isSystemEntry(Scope, CurrentObjectName); |
| |
| // The line records in CodeView are recorded per Module ID. Update |
| // the relationship between the current CU and the Module ID. |
| Reader->addModule(Scope); |
| |
| // Updated the collected strings with their associated compile unit. |
| Shared->StringRecords.addFilenames(Reader->getCompileUnit()); |
| } |
| |
| // Clear any previous ObjectName. |
| CurrentObjectName = ""; |
| return Error::success(); |
| } |
| |
| // S_CONSTANT, S_MANCONSTANT |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| ConstantSym &Constant) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", Constant.Type); |
| W.printNumber("Value", Constant.Value); |
| W.printString("Name", Constant.Name); |
| }); |
| |
| if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) { |
| Symbol->setName(Constant.Name); |
| Symbol->setType(LogicalVisitor->getElement(StreamTPI, Constant.Type)); |
| Symbol->resetIncludeInPrint(); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE |
| Error LVSymbolVisitor::visitKnownRecord( |
| CVSymbol &Record, |
| DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Offset, 0]. |
| dwarf::Attribute Attr = |
| dwarf::Attribute(SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE); |
| |
| uint64_t Operand1 = DefRangeFramePointerRelFullScope.Offset; |
| Symbol->addLocation(Attr, 0, 0, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_FRAMEPOINTER_REL |
| Error LVSymbolVisitor::visitKnownRecord( |
| CVSymbol &Record, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset); |
| printLocalVariableAddrRange(DefRangeFramePointerRel.Range, |
| DefRangeFramePointerRel.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); |
| }); |
| |
| // We are expecting the following sequence: |
| // 128 | S_LOCAL [size = 20] `ParamBar` |
| // ... |
| // 148 | S_DEFRANGE_FRAMEPOINTER_REL [size = 16] |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Offset, 0]. |
| dwarf::Attribute Attr = |
| dwarf::Attribute(SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL); |
| uint64_t Operand1 = DefRangeFramePointerRel.Hdr.Offset; |
| |
| LocalVariableAddrRange Range = DefRangeFramePointerRel.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_REGISTER_REL |
| Error LVSymbolVisitor::visitKnownRecord( |
| CVSymbol &Record, DefRangeRegisterRelSym &DefRangeRegisterRel) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| W.printBoolean("HasSpilledUDTMember", |
| DefRangeRegisterRel.hasSpilledUDTMember()); |
| W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); |
| W.printNumber("BasePointerOffset", |
| DefRangeRegisterRel.Hdr.BasePointerOffset); |
| printLocalVariableAddrRange(DefRangeRegisterRel.Range, |
| DefRangeRegisterRel.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Register, Offset]. |
| dwarf::Attribute Attr = |
| dwarf::Attribute(SymbolKind::S_DEFRANGE_REGISTER_REL); |
| uint64_t Operand1 = DefRangeRegisterRel.Hdr.Register; |
| uint64_t Operand2 = DefRangeRegisterRel.Hdr.BasePointerOffset; |
| |
| LocalVariableAddrRange Range = DefRangeRegisterRel.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1, Operand2}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_REGISTER |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| DefRangeRegisterSym &DefRangeRegister) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register), |
| getRegisterNames(Reader->getCompileUnitCPUType())); |
| W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); |
| printLocalVariableAddrRange(DefRangeRegister.Range, |
| DefRangeRegister.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRangeRegister.Gaps); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Register, 0]. |
| dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE_REGISTER); |
| uint64_t Operand1 = DefRangeRegister.Hdr.Register; |
| |
| LocalVariableAddrRange Range = DefRangeRegister.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_SUBFIELD_REGISTER |
| Error LVSymbolVisitor::visitKnownRecord( |
| CVSymbol &Record, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register), |
| getRegisterNames(Reader->getCompileUnitCPUType())); |
| W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); |
| W.printNumber("OffsetInParent", |
| DefRangeSubfieldRegister.Hdr.OffsetInParent); |
| printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, |
| DefRangeSubfieldRegister.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Register, 0]. |
| dwarf::Attribute Attr = |
| dwarf::Attribute(SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER); |
| uint64_t Operand1 = DefRangeSubfieldRegister.Hdr.Register; |
| |
| LocalVariableAddrRange Range = DefRangeSubfieldRegister.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE_SUBFIELD |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| DefRangeSubfieldSym &DefRangeSubfield) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| if (ObjDelegate) { |
| DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); |
| auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program); |
| if (!ExpectedProgram) { |
| consumeError(ExpectedProgram.takeError()); |
| return llvm::make_error<CodeViewError>( |
| "String table offset outside of bounds of String Table!"); |
| } |
| W.printString("Program", *ExpectedProgram); |
| } |
| W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); |
| printLocalVariableAddrRange(DefRangeSubfield.Range, |
| DefRangeSubfield.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRangeSubfield.Gaps); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Program, 0]. |
| dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE_SUBFIELD); |
| uint64_t Operand1 = DefRangeSubfield.Program; |
| |
| LocalVariableAddrRange Range = DefRangeSubfield.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1, /*Operand2=*/0}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_DEFRANGE |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| DefRangeSym &DefRange) { |
| // DefRanges don't have types, just registers and code offsets. |
| LLVM_DEBUG({ |
| if (LocalSymbol) |
| W.getOStream() << formatv("Symbol: {0}, ", LocalSymbol->getName()); |
| |
| if (ObjDelegate) { |
| DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); |
| auto ExpectedProgram = Strings.getString(DefRange.Program); |
| if (!ExpectedProgram) { |
| consumeError(ExpectedProgram.takeError()); |
| return llvm::make_error<CodeViewError>( |
| "String table offset outside of bounds of String Table!"); |
| } |
| W.printString("Program", *ExpectedProgram); |
| } |
| printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); |
| printLocalVariableAddrGap(DefRange.Gaps); |
| }); |
| |
| if (LVSymbol *Symbol = LocalSymbol) { |
| Symbol->setHasCodeViewLocation(); |
| LocalSymbol = nullptr; |
| |
| // Add location debug location. Operands: [Program, 0]. |
| dwarf::Attribute Attr = dwarf::Attribute(SymbolKind::S_DEFRANGE); |
| uint64_t Operand1 = DefRange.Program; |
| |
| LocalVariableAddrRange Range = DefRange.Range; |
| LVAddress Address = |
| Reader->linearAddress(Range.ISectStart, Range.OffsetStart); |
| |
| Symbol->addLocation(Attr, Address, Address + Range.Range, 0, 0); |
| Symbol->addLocationOperands(LVSmall(Attr), {Operand1, /*Operand2=*/0}); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_FRAMEPROC |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| FrameProcSym &FrameProc) { |
| if (LVScope *Function = LogicalVisitor->getReaderScope()) { |
| // S_FRAMEPROC contains extra information for the function described |
| // by any of the previous generated records: |
| // S_GPROC32, S_LPROC32, S_LPROC32_ID, S_GPROC32_ID. |
| |
| // The generated sequence is: |
| // S_GPROC32_ID ... |
| // S_FRAMEPROC ... |
| |
| // Collect additional inline flags for the current scope function. |
| FrameProcedureOptions Flags = FrameProc.Flags; |
| if (FrameProcedureOptions::MarkedInline == |
| (Flags & FrameProcedureOptions::MarkedInline)) |
| Function->setInlineCode(dwarf::DW_INL_declared_inlined); |
| if (FrameProcedureOptions::Inlined == |
| (Flags & FrameProcedureOptions::Inlined)) |
| Function->setInlineCode(dwarf::DW_INL_inlined); |
| |
| // To determine the symbol kind for any symbol declared in that function, |
| // we can access the S_FRAMEPROC for the parent scope function. It contains |
| // information about the local fp and param fp registers and compare with |
| // the register in the S_REGREL32 to get a match. |
| codeview::CPUType CPU = Reader->getCompileUnitCPUType(); |
| LocalFrameRegister = FrameProc.getLocalFramePtrReg(CPU); |
| ParamFrameRegister = FrameProc.getParamFramePtrReg(CPU); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_GDATA32, S_LDATA32, S_LMANDATA, S_GMANDATA |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, DataSym &Data) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", Data.Type); |
| W.printString("DisplayName", Data.Name); |
| }); |
| |
| if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) { |
| StringRef LinkageName; |
| if (ObjDelegate) |
| ObjDelegate->getLinkageName(Data.getRelocationOffset(), Data.DataOffset, |
| &LinkageName); |
| |
| Symbol->setName(Data.Name); |
| Symbol->setLinkageName(LinkageName); |
| |
| // The MSVC generates local data as initialization for aggregates. It |
| // contains the address for an initialization function. |
| // The symbols contains the '$initializer$' pattern. Allow them only if |
| // the '--internal=system' option is given. |
| // 0 | S_LDATA32 `Struct$initializer$` |
| // type = 0x1040 (void ()*) |
| if (getReader().isSystemEntry(Symbol) && !options().getAttributeSystem()) { |
| Symbol->resetIncludeInPrint(); |
| return Error::success(); |
| } |
| |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get(Data.Name)) { |
| // The variable is already at different scope. In order to reflect |
| // the correct parent, move it to the namespace. |
| if (Symbol->getParentScope()->removeElement(Symbol)) |
| Namespace->addElement(Symbol); |
| } |
| |
| Symbol->setType(LogicalVisitor->getElement(StreamTPI, Data.Type)); |
| if (Record.kind() == SymbolKind::S_GDATA32) |
| Symbol->setIsExternal(); |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_INLINESITE |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| InlineSiteSym &InlineSite) { |
| LLVM_DEBUG({ printTypeIndex("Inlinee", InlineSite.Inlinee); }); |
| |
| if (LVScope *InlinedFunction = LogicalVisitor->CurrentScope) { |
| LVScope *AbstractFunction = Reader->createScopeFunction(); |
| AbstractFunction->setIsSubprogram(); |
| AbstractFunction->setTag(dwarf::DW_TAG_subprogram); |
| AbstractFunction->setInlineCode(dwarf::DW_INL_inlined); |
| AbstractFunction->setIsInlinedAbstract(); |
| InlinedFunction->setReference(AbstractFunction); |
| |
| LogicalVisitor->startProcessArgumentList(); |
| // 'Inlinee' is a Type ID. |
| CVType CVFunctionType = Ids.getType(InlineSite.Inlinee); |
| if (Error Err = LogicalVisitor->finishVisitation( |
| CVFunctionType, InlineSite.Inlinee, AbstractFunction)) |
| return Err; |
| LogicalVisitor->stopProcessArgumentList(); |
| |
| // For inlined functions set the linkage name to be the same as |
| // the name. It used to find their lines and ranges. |
| StringRef Name = AbstractFunction->getName(); |
| InlinedFunction->setName(Name); |
| InlinedFunction->setLinkageName(Name); |
| |
| // Process annotation bytes to calculate code and line offsets. |
| if (Error Err = LogicalVisitor->inlineSiteAnnotation( |
| AbstractFunction, InlinedFunction, InlineSite)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_LOCAL |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, LocalSym &Local) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", Local.Type); |
| W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); |
| W.printString("VarName", Local.Name); |
| }); |
| |
| if (LVSymbol *Symbol = LogicalVisitor->CurrentSymbol) { |
| Symbol->setName(Local.Name); |
| |
| // Symbol was created as 'variable'; determine its real kind. |
| Symbol->resetIsVariable(); |
| |
| // Be sure the 'this' symbol is marked as 'compiler generated'. |
| if (bool(Local.Flags & LocalSymFlags::IsCompilerGenerated) || |
| Local.Name.equals("this")) { |
| Symbol->setIsArtificial(); |
| Symbol->setIsParameter(); |
| } else { |
| bool(Local.Flags & LocalSymFlags::IsParameter) ? Symbol->setIsParameter() |
| : Symbol->setIsVariable(); |
| } |
| |
| // Update correct debug information tag. |
| if (Symbol->getIsParameter()) |
| Symbol->setTag(dwarf::DW_TAG_formal_parameter); |
| |
| LVElement *Element = LogicalVisitor->getElement(StreamTPI, Local.Type); |
| if (Element && Element->getIsScoped()) { |
| // We have a local type. Find its parent function. |
| LVScope *Parent = Symbol->getFunctionParent(); |
| // The element representing the type has been already finalized. If |
| // the type is an aggregate type, its members have been already added. |
| // As the type is local, its level will be changed. |
| Parent->addElement(Element); |
| Element->updateLevel(Parent); |
| } |
| Symbol->setType(Element); |
| |
| // The CodeView records (S_DEFFRAME_*) describing debug location for |
| // this symbol, do not have any direct reference to it. Those records |
| // are emitted after this symbol. Record the current symbol. |
| LocalSymbol = Symbol; |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_OBJNAME |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, ObjNameSym &ObjName) { |
| LLVM_DEBUG({ |
| W.printHex("Signature", ObjName.Signature); |
| W.printString("ObjectName", ObjName.Name); |
| }); |
| |
| CurrentObjectName = ObjName.Name; |
| return Error::success(); |
| } |
| |
| // S_GPROC32, S_LPROC32, S_LPROC32_ID, S_GPROC32_ID |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, ProcSym &Proc) { |
| if (InFunctionScope) |
| return llvm::make_error<CodeViewError>("Visiting a ProcSym while inside " |
| "function scope!"); |
| |
| InFunctionScope = true; |
| |
| LLVM_DEBUG({ |
| printTypeIndex("FunctionType", Proc.FunctionType); |
| W.printHex("Segment", Proc.Segment); |
| W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags), |
| getProcSymFlagNames()); |
| W.printString("DisplayName", Proc.Name); |
| }); |
| |
| // Clang and Microsoft generated different debug information records: |
| // For functions definitions: |
| // Clang: S_GPROC32 -> LF_FUNC_ID -> LF_PROCEDURE |
| // Microsoft: S_GPROC32 -> LF_PROCEDURE |
| |
| // For member function definition: |
| // Clang: S_GPROC32 -> LF_MFUNC_ID -> LF_MFUNCTION |
| // Microsoft: S_GPROC32 -> LF_MFUNCTION |
| // In order to support both sequences, if we found LF_FUNCTION_ID, just |
| // get the TypeIndex for LF_PROCEDURE. |
| |
| // For the given test case, we have the sequence: |
| // namespace NSP_local { |
| // void foo_local() { |
| // } |
| // } |
| // |
| // 0x1000 | LF_STRING_ID String: NSP_local |
| // 0x1002 | LF_PROCEDURE |
| // return type = 0x0003 (void), # args = 0, param list = 0x1001 |
| // calling conv = cdecl, options = None |
| // 0x1003 | LF_FUNC_ID |
| // name = foo_local, type = 0x1002, parent scope = 0x1000 |
| // 0 | S_GPROC32_ID `NSP_local::foo_local` |
| // type = `0x1003 (foo_local)` |
| // 0x1004 | LF_STRING_ID String: suite |
| // 0x1005 | LF_STRING_ID String: suite_local.cpp |
| // |
| // The LF_STRING_ID can hold different information: |
| // 0x1000 - The enclosing namespace. |
| // 0x1004 - The compile unit directory name. |
| // 0x1005 - The compile unit name. |
| // |
| // Before deducting its scope, we need to evaluate its type and create any |
| // associated namespaces. |
| if (LVScope *Function = LogicalVisitor->CurrentScope) { |
| StringRef LinkageName; |
| if (ObjDelegate) |
| ObjDelegate->getLinkageName(Proc.getRelocationOffset(), Proc.CodeOffset, |
| &LinkageName); |
| |
| // The line table can be accessed using the linkage name. |
| Reader->addToSymbolTable(LinkageName, Function); |
| Function->setName(Proc.Name); |
| Function->setLinkageName(LinkageName); |
| |
| if (options().getGeneralCollectRanges()) { |
| // Record converted segment::offset addressing for this scope. |
| LVAddress Addendum = Reader->getSymbolTableAddress(LinkageName); |
| LVAddress LowPC = |
| Reader->linearAddress(Proc.Segment, Proc.CodeOffset, Addendum); |
| LVAddress HighPC = LowPC + Proc.CodeSize - 1; |
| Function->addObject(LowPC, HighPC); |
| |
| // If the scope is a function, add it to the public names. |
| if ((options().getAttributePublics() || options().getPrintAnyLine()) && |
| !Function->getIsInlinedFunction()) |
| Reader->getCompileUnit()->addPublicName(Function, LowPC, HighPC); |
| } |
| |
| if (Function->getIsSystem() && !options().getAttributeSystem()) { |
| Function->resetIncludeInPrint(); |
| return Error::success(); |
| } |
| |
| TypeIndex TIFunctionType = Proc.FunctionType; |
| if (TIFunctionType.isSimple()) |
| Function->setType(LogicalVisitor->getElement(StreamTPI, TIFunctionType)); |
| else { |
| // We have to detect the correct stream, using the lexical parent |
| // name, as there is not other obvious way to get the stream. |
| // Normal function: LF_FUNC_ID (TPI)/(IPI) |
| // LF_PROCEDURE (TPI) |
| // Lambda function: LF_MFUNCTION (TPI) |
| // Member function: LF_MFUNC_ID (TPI)/(IPI) |
| |
| StringRef OuterComponent; |
| std::tie(OuterComponent, std::ignore) = getInnerComponent(Proc.Name); |
| TypeIndex TI = Shared->ForwardReferences.find(OuterComponent); |
| |
| std::optional<CVType> CVFunctionType; |
| auto GetRecordType = [&]() -> bool { |
| CVFunctionType = Ids.tryGetType(TIFunctionType); |
| if (!CVFunctionType) |
| return false; |
| |
| if (TI.isNoneType()) |
| // Normal function. |
| if (CVFunctionType->kind() == LF_FUNC_ID) |
| return true; |
| |
| // Member function. |
| return (CVFunctionType->kind() == LF_MFUNC_ID); |
| }; |
| |
| // We can have a LF_FUNC_ID, LF_PROCEDURE or LF_MFUNCTION. |
| if (!GetRecordType()) { |
| CVFunctionType = Types.tryGetType(TIFunctionType); |
| if (!CVFunctionType) |
| return llvm::make_error<CodeViewError>("Invalid type index"); |
| } |
| |
| if (Error Err = LogicalVisitor->finishVisitation( |
| *CVFunctionType, TIFunctionType, Function)) |
| return Err; |
| } |
| |
| if (Record.kind() == SymbolKind::S_GPROC32 || |
| Record.kind() == SymbolKind::S_GPROC32_ID) |
| Function->setIsExternal(); |
| |
| // We don't have a way to see if the symbol is compiler generated. Use |
| // the linkage name, to detect `scalar deleting destructor' functions. |
| std::string DemangledSymbol = demangle(LinkageName); |
| if (DemangledSymbol.find("scalar deleting dtor") != std::string::npos) { |
| Function->setIsArtificial(); |
| } else { |
| // Clang generates global ctor and dtor names containing the substrings: |
| // 'dynamic initializer for' and 'dynamic atexit destructor for'. |
| if (DemangledSymbol.find("dynamic atexit destructor for") != |
| std::string::npos) |
| Function->setIsArtificial(); |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_END |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| ScopeEndSym &ScopeEnd) { |
| InFunctionScope = false; |
| return Error::success(); |
| } |
| |
| // S_THUNK32 |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, Thunk32Sym &Thunk) { |
| if (InFunctionScope) |
| return llvm::make_error<CodeViewError>("Visiting a Thunk32Sym while inside " |
| "function scope!"); |
| |
| InFunctionScope = true; |
| |
| LLVM_DEBUG({ |
| W.printHex("Segment", Thunk.Segment); |
| W.printString("Name", Thunk.Name); |
| }); |
| |
| if (LVScope *Function = LogicalVisitor->CurrentScope) |
| Function->setName(Thunk.Name); |
| |
| return Error::success(); |
| } |
| |
| // S_UDT, S_COBOLUDT |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, UDTSym &UDT) { |
| LLVM_DEBUG({ |
| printTypeIndex("Type", UDT.Type); |
| W.printString("UDTName", UDT.Name); |
| }); |
| |
| if (LVType *Type = LogicalVisitor->CurrentType) { |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get(UDT.Name)) { |
| if (Type->getParentScope()->removeElement(Type)) |
| Namespace->addElement(Type); |
| } |
| |
| Type->setName(UDT.Name); |
| |
| // We have to determine if the typedef is a real C/C++ definition or is |
| // the S_UDT record that describe all the user defined types. |
| // 0 | S_UDT `Name` original type = 0x1009 |
| // 0x1009 | LF_STRUCTURE `Name` |
| // Ignore type definitions for RTTI types: |
| // _s__RTTIBaseClassArray, _s__RTTIBaseClassDescriptor, |
| // _s__RTTICompleteObjectLocator, _s__RTTIClassHierarchyDescriptor. |
| if (getReader().isSystemEntry(Type)) |
| Type->resetIncludeInPrint(); |
| else { |
| StringRef RecordName = getRecordName(Types, UDT.Type); |
| if (UDT.Name.equals(RecordName)) |
| Type->resetIncludeInPrint(); |
| Type->setType(LogicalVisitor->getElement(StreamTPI, UDT.Type)); |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // S_UNAMESPACE |
| Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, |
| UsingNamespaceSym &UN) { |
| LLVM_DEBUG({ W.printString("Namespace", UN.Name); }); |
| return Error::success(); |
| } |
| |
| #undef DEBUG_TYPE |
| #define DEBUG_TYPE "CodeViewLogicalVisitor" |
| |
| //===----------------------------------------------------------------------===// |
| // Logical visitor. |
| //===----------------------------------------------------------------------===// |
| LVLogicalVisitor::LVLogicalVisitor(LVCodeViewReader *Reader, ScopedPrinter &W, |
| InputFile &Input) |
| : Reader(Reader), W(W), Input(Input) { |
| // The LogicalVisitor connects the CodeViewReader with the visitors that |
| // traverse the types, symbols, etc. Do any initialization that is needed. |
| Shared = std::make_shared<LVShared>(Reader, this); |
| } |
| |
| void LVLogicalVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI, |
| uint32_t StreamIdx) { |
| codeview::printTypeIndex(W, FieldName, TI, |
| StreamIdx == StreamTPI ? types() : ids()); |
| } |
| |
| void LVLogicalVisitor::printTypeBegin(CVType &Record, TypeIndex TI, |
| LVElement *Element, uint32_t StreamIdx) { |
| W.getOStream() << "\n"; |
| W.startLine() << formatTypeLeafKind(Record.kind()); |
| W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")"; |
| W.getOStream() << " {\n"; |
| W.indent(); |
| W.printEnum("TypeLeafKind", unsigned(Record.kind()), ArrayRef(LeafTypeNames)); |
| printTypeIndex("TI", TI, StreamIdx); |
| W.startLine() << "Element: " << HexNumber(Element->getOffset()) << " " |
| << Element->getName() << "\n"; |
| } |
| |
| void LVLogicalVisitor::printTypeEnd(CVType &Record) { |
| W.unindent(); |
| W.startLine() << "}\n"; |
| } |
| |
| void LVLogicalVisitor::printMemberBegin(CVMemberRecord &Record, TypeIndex TI, |
| LVElement *Element, |
| uint32_t StreamIdx) { |
| W.getOStream() << "\n"; |
| W.startLine() << formatTypeLeafKind(Record.Kind); |
| W.getOStream() << " (" << HexNumber(TI.getIndex()) << ")"; |
| W.getOStream() << " {\n"; |
| W.indent(); |
| W.printEnum("TypeLeafKind", unsigned(Record.Kind), ArrayRef(LeafTypeNames)); |
| printTypeIndex("TI", TI, StreamIdx); |
| W.startLine() << "Element: " << HexNumber(Element->getOffset()) << " " |
| << Element->getName() << "\n"; |
| } |
| |
| void LVLogicalVisitor::printMemberEnd(CVMemberRecord &Record) { |
| W.unindent(); |
| W.startLine() << "}\n"; |
| } |
| |
| Error LVLogicalVisitor::visitUnknownType(CVType &Record, TypeIndex TI) { |
| LLVM_DEBUG({ |
| printTypeIndex("\nTI", TI, StreamTPI); |
| W.printNumber("Length", uint32_t(Record.content().size())); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_ARGLIST (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ArgListRecord &Args, |
| TypeIndex TI, LVElement *Element) { |
| ArrayRef<TypeIndex> Indices = Args.getIndices(); |
| uint32_t Size = Indices.size(); |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("NumArgs", Size); |
| ListScope Arguments(W, "Arguments"); |
| for (uint32_t I = 0; I < Size; ++I) |
| printTypeIndex("ArgType", Indices[I], StreamTPI); |
| printTypeEnd(Record); |
| }); |
| |
| LVScope *Function = static_cast<LVScope *>(Element); |
| for (uint32_t Index = 0; Index < Size; ++Index) { |
| TypeIndex ParameterType = Indices[Index]; |
| createParameter(ParameterType, StringRef(), Function); |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_ARRAY (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ArrayRecord &AT, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("ElementType", AT.getElementType(), StreamTPI); |
| printTypeIndex("IndexType", AT.getIndexType(), StreamTPI); |
| W.printNumber("SizeOf", AT.getSize()); |
| W.printString("Name", AT.getName()); |
| printTypeEnd(Record); |
| }); |
| |
| if (Element->getIsFinalized()) |
| return Error::success(); |
| Element->setIsFinalized(); |
| |
| LVScopeArray *Array = static_cast<LVScopeArray *>(Element); |
| if (!Array) |
| return Error::success(); |
| |
| Reader->getCompileUnit()->addElement(Array); |
| TypeIndex TIElementType = AT.getElementType(); |
| |
| LVType *PrevSubrange = nullptr; |
| LazyRandomTypeCollection &Types = types(); |
| |
| // As the logical view is modeled on DWARF, for each dimension we have to |
| // create a DW_TAG_subrange_type, with dimension size. |
| // The subrange type can be: unsigned __int32 or unsigned __int64. |
| auto AddSubrangeType = [&](ArrayRecord &AR) { |
| LVType *Subrange = Reader->createTypeSubrange(); |
| Subrange->setTag(dwarf::DW_TAG_subrange_type); |
| Subrange->setType(getElement(StreamTPI, AR.getIndexType())); |
| Subrange->setCount(AR.getSize()); |
| Subrange->setOffset( |
| TIElementType.isSimple() |
| ? (uint32_t)(TypeLeafKind)TIElementType.getSimpleKind() |
| : TIElementType.getIndex()); |
| Array->addElement(Subrange); |
| |
| if (PrevSubrange) |
| if (int64_t Count = Subrange->getCount()) |
| PrevSubrange->setCount(PrevSubrange->getCount() / Count); |
| PrevSubrange = Subrange; |
| }; |
| |
| // Preserve the original TypeIndex; it would be updated in the case of: |
| // - The array type contains qualifiers. |
| // - In multidimensional arrays, the last LF_ARRAY entry contains the type. |
| TypeIndex TIArrayType; |
| |
| // For each dimension in the array, there is a LF_ARRAY entry. The last |
| // entry contains the array type, which can be a LF_MODIFIER in the case |
| // of the type being modified by a qualifier (const, etc). |
| ArrayRecord AR(AT); |
| CVType CVEntry = Record; |
| while (CVEntry.kind() == LF_ARRAY) { |
| // Create the subrange information, required by the logical view. Once |
| // the array has been processed, the dimension sizes will updated, as |
| // the sizes are a progression. For instance: |
| // sizeof(int) = 4 |
| // int Array[2]; Sizes: 8 Dim: 8 / 4 -> [2] |
| // int Array[2][3]; Sizes: 24, 12 Dim: 24 / 12 -> [2] |
| // Dim: 12 / 4 -> [3] |
| // int Array[2][3][4]; sizes: 96, 48, 16 Dim: 96 / 48 -> [2] |
| // Dim: 48 / 16 -> [3] |
| // Dim: 16 / 4 -> [4] |
| AddSubrangeType(AR); |
| TIArrayType = TIElementType; |
| |
| // The current ElementType can be a modifier, in which case we need to |
| // get the type being modified. |
| // If TypeIndex is not a simple type, check if we have a qualified type. |
| if (!TIElementType.isSimple()) { |
| CVType CVElementType = Types.getType(TIElementType); |
| if (CVElementType.kind() == LF_MODIFIER) { |
| LVElement *QualifiedType = |
| Shared->TypeRecords.find(StreamTPI, TIElementType); |
| if (Error Err = |
| finishVisitation(CVElementType, TIElementType, QualifiedType)) |
| return Err; |
| // Get the TypeIndex of the type that the LF_MODIFIER modifies. |
| TIElementType = getModifiedType(CVElementType); |
| } |
| } |
| // Ends the traversal, as we have reached a simple type (int, char, etc). |
| if (TIElementType.isSimple()) |
| break; |
| |
| // Read next dimension linked entry, if any. |
| CVEntry = Types.getType(TIElementType); |
| if (Error Err = TypeDeserializer::deserializeAs( |
| const_cast<CVType &>(CVEntry), AR)) { |
| consumeError(std::move(Err)); |
| break; |
| } |
| TIElementType = AR.getElementType(); |
| // NOTE: The typeindex has a value of: 0x0280.0000 |
| getTrueType(TIElementType); |
| } |
| |
| Array->setName(AT.getName()); |
| TIArrayType = Shared->ForwardReferences.remap(TIArrayType); |
| Array->setType(getElement(StreamTPI, TIArrayType)); |
| |
| if (PrevSubrange) |
| // In the case of an aggregate type (class, struct, union, interface), |
| // get the aggregate size. As the original record is pointing to its |
| // reference, we have to update it. |
| if (uint64_t Size = |
| isAggregate(CVEntry) |
| ? getSizeInBytesForTypeRecord(Types.getType(TIArrayType)) |
| : getSizeInBytesForTypeIndex(TIElementType)) |
| PrevSubrange->setCount(PrevSubrange->getCount() / Size); |
| |
| return Error::success(); |
| } |
| |
| // LF_BITFIELD (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, BitFieldRecord &BF, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", TI, StreamTPI); |
| W.printNumber("BitSize", BF.getBitSize()); |
| W.printNumber("BitOffset", BF.getBitOffset()); |
| printTypeEnd(Record); |
| }); |
| |
| Element->setType(getElement(StreamTPI, BF.getType())); |
| Element->setBitSize(BF.getBitSize()); |
| return Error::success(); |
| } |
| |
| // LF_BUILDINFO (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, BuildInfoRecord &BI, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamIPI); |
| W.printNumber("NumArgs", static_cast<uint32_t>(BI.getArgs().size())); |
| ListScope Arguments(W, "Arguments"); |
| for (TypeIndex Arg : BI.getArgs()) |
| printTypeIndex("ArgType", Arg, StreamIPI); |
| printTypeEnd(Record); |
| }); |
| |
| // The given 'Element' refers to the current compilation unit. |
| // All the args are references into the TPI/IPI stream. |
| TypeIndex TIName = BI.getArgs()[BuildInfoRecord::BuildInfoArg::SourceFile]; |
| std::string Name = std::string(ids().getTypeName(TIName)); |
| |
| // There are cases where LF_BUILDINFO fields are empty. |
| if (!Name.empty()) |
| Element->setName(Name); |
| |
| return Error::success(); |
| } |
| |
| // LF_CLASS, LF_STRUCTURE, LF_INTERFACE (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ClassRecord &Class, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("MemberCount", Class.getMemberCount()); |
| printTypeIndex("FieldList", Class.getFieldList(), StreamTPI); |
| printTypeIndex("DerivedFrom", Class.getDerivationList(), StreamTPI); |
| printTypeIndex("VShape", Class.getVTableShape(), StreamTPI); |
| W.printNumber("SizeOf", Class.getSize()); |
| W.printString("Name", Class.getName()); |
| if (Class.hasUniqueName()) |
| W.printString("UniqueName", Class.getUniqueName()); |
| printTypeEnd(Record); |
| }); |
| |
| if (Element->getIsFinalized()) |
| return Error::success(); |
| Element->setIsFinalized(); |
| |
| LVScopeAggregate *Scope = static_cast<LVScopeAggregate *>(Element); |
| if (!Scope) |
| return Error::success(); |
| |
| Scope->setName(Class.getName()); |
| if (Class.hasUniqueName()) |
| Scope->setLinkageName(Class.getUniqueName()); |
| |
| if (Class.isNested()) { |
| Scope->setIsNested(); |
| createParents(Class.getName(), Scope); |
| } |
| |
| if (Class.isScoped()) |
| Scope->setIsScoped(); |
| |
| // Nested types will be added to their parents at creation. The forward |
| // references are only processed to finish the referenced element creation. |
| if (!(Class.isNested() || Class.isScoped())) { |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get(Class.getName())) |
| Namespace->addElement(Scope); |
| else |
| Reader->getCompileUnit()->addElement(Scope); |
| } |
| |
| LazyRandomTypeCollection &Types = types(); |
| TypeIndex TIFieldList = Class.getFieldList(); |
| if (TIFieldList.isNoneType()) { |
| TypeIndex ForwardType = Shared->ForwardReferences.find(Class.getName()); |
| if (!ForwardType.isNoneType()) { |
| CVType CVReference = Types.getType(ForwardType); |
| TypeRecordKind RK = static_cast<TypeRecordKind>(CVReference.kind()); |
| ClassRecord ReferenceRecord(RK); |
| if (Error Err = TypeDeserializer::deserializeAs( |
| const_cast<CVType &>(CVReference), ReferenceRecord)) |
| return Err; |
| TIFieldList = ReferenceRecord.getFieldList(); |
| } |
| } |
| |
| if (!TIFieldList.isNoneType()) { |
| // Pass down the TypeIndex 'TI' for the aggregate containing the field list. |
| CVType CVFieldList = Types.getType(TIFieldList); |
| if (Error Err = finishVisitation(CVFieldList, TI, Scope)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_ENUM (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, EnumRecord &Enum, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("NumEnumerators", Enum.getMemberCount()); |
| printTypeIndex("UnderlyingType", Enum.getUnderlyingType(), StreamTPI); |
| printTypeIndex("FieldListType", Enum.getFieldList(), StreamTPI); |
| W.printString("Name", Enum.getName()); |
| printTypeEnd(Record); |
| }); |
| |
| LVScopeEnumeration *Scope = static_cast<LVScopeEnumeration *>(Element); |
| if (!Scope) |
| return Error::success(); |
| |
| if (Scope->getIsFinalized()) |
| return Error::success(); |
| Scope->setIsFinalized(); |
| |
| // Set the name, as in the case of nested, it would determine the relation |
| // to any potential parent, via the LF_NESTTYPE record. |
| Scope->setName(Enum.getName()); |
| if (Enum.hasUniqueName()) |
| Scope->setLinkageName(Enum.getUniqueName()); |
| |
| Scope->setType(getElement(StreamTPI, Enum.getUnderlyingType())); |
| |
| if (Enum.isNested()) { |
| Scope->setIsNested(); |
| createParents(Enum.getName(), Scope); |
| } |
| |
| if (Enum.isScoped()) { |
| Scope->setIsScoped(); |
| Scope->setIsEnumClass(); |
| } |
| |
| // Nested types will be added to their parents at creation. |
| if (!(Enum.isNested() || Enum.isScoped())) { |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get(Enum.getName())) |
| Namespace->addElement(Scope); |
| else |
| Reader->getCompileUnit()->addElement(Scope); |
| } |
| |
| TypeIndex TIFieldList = Enum.getFieldList(); |
| if (!TIFieldList.isNoneType()) { |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVFieldList = Types.getType(TIFieldList); |
| if (Error Err = finishVisitation(CVFieldList, TIFieldList, Scope)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_FIELDLIST (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| FieldListRecord &FieldList, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeEnd(Record); |
| }); |
| |
| if (Error Err = visitFieldListMemberStream(TI, Element, FieldList.Data)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| // LF_FUNC_ID (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, FuncIdRecord &Func, |
| TypeIndex TI, LVElement *Element) { |
| // ParentScope and FunctionType are references into the TPI stream. |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamIPI); |
| printTypeIndex("ParentScope", Func.getParentScope(), StreamTPI); |
| printTypeIndex("FunctionType", Func.getFunctionType(), StreamTPI); |
| W.printString("Name", Func.getName()); |
| printTypeEnd(Record); |
| }); |
| |
| // The TypeIndex (LF_PROCEDURE) returned by 'getFunctionType' is the |
| // function propotype, we need to use the function definition. |
| if (LVScope *FunctionDcl = static_cast<LVScope *>(Element)) { |
| // For inlined functions, the inlined instance has been already processed |
| // (all its information is contained in the Symbols section). |
| // 'Element' points to the created 'abstract' (out-of-line) function. |
| // Use the parent scope information to allocate it to the correct scope. |
| LazyRandomTypeCollection &Types = types(); |
| TypeIndex TIParent = Func.getParentScope(); |
| if (FunctionDcl->getIsInlinedAbstract()) { |
| FunctionDcl->setName(Func.getName()); |
| if (TIParent.isNoneType()) |
| Reader->getCompileUnit()->addElement(FunctionDcl); |
| } |
| |
| if (!TIParent.isNoneType()) { |
| CVType CVParentScope = ids().getType(TIParent); |
| if (Error Err = finishVisitation(CVParentScope, TIParent, FunctionDcl)) |
| return Err; |
| } |
| |
| TypeIndex TIFunctionType = Func.getFunctionType(); |
| CVType CVFunctionType = Types.getType(TIFunctionType); |
| if (Error Err = |
| finishVisitation(CVFunctionType, TIFunctionType, FunctionDcl)) |
| return Err; |
| |
| FunctionDcl->setIsFinalized(); |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_LABEL (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, LabelRecord &LR, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_MFUNC_ID (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, MemberFuncIdRecord &Id, |
| TypeIndex TI, LVElement *Element) { |
| // ClassType and FunctionType are references into the TPI stream. |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamIPI); |
| printTypeIndex("ClassType", Id.getClassType(), StreamTPI); |
| printTypeIndex("FunctionType", Id.getFunctionType(), StreamTPI); |
| W.printString("Name", Id.getName()); |
| printTypeEnd(Record); |
| }); |
| |
| LVScope *FunctionDcl = static_cast<LVScope *>(Element); |
| if (FunctionDcl->getIsInlinedAbstract()) { |
| // For inlined functions, the inlined instance has been already processed |
| // (all its information is contained in the Symbols section). |
| // 'Element' points to the created 'abstract' (out-of-line) function. |
| // Use the parent scope information to allocate it to the correct scope. |
| if (LVScope *Class = static_cast<LVScope *>( |
| Shared->TypeRecords.find(StreamTPI, Id.getClassType()))) |
| Class->addElement(FunctionDcl); |
| } |
| |
| TypeIndex TIFunctionType = Id.getFunctionType(); |
| CVType CVFunction = types().getType(TIFunctionType); |
| if (Error Err = finishVisitation(CVFunction, TIFunctionType, Element)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| // LF_MFUNCTION (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| MemberFunctionRecord &MF, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("ReturnType", MF.getReturnType(), StreamTPI); |
| printTypeIndex("ClassType", MF.getClassType(), StreamTPI); |
| printTypeIndex("ThisType", MF.getThisType(), StreamTPI); |
| W.printNumber("NumParameters", MF.getParameterCount()); |
| printTypeIndex("ArgListType", MF.getArgumentList(), StreamTPI); |
| W.printNumber("ThisAdjustment", MF.getThisPointerAdjustment()); |
| printTypeEnd(Record); |
| }); |
| |
| if (LVScope *MemberFunction = static_cast<LVScope *>(Element)) { |
| LVElement *Class = getElement(StreamTPI, MF.getClassType()); |
| |
| MemberFunction->setIsFinalized(); |
| MemberFunction->setType(getElement(StreamTPI, MF.getReturnType())); |
| MemberFunction->setOffset(TI.getIndex()); |
| MemberFunction->setOffsetFromTypeIndex(); |
| |
| if (ProcessArgumentList) { |
| ProcessArgumentList = false; |
| |
| if (!MemberFunction->getIsStatic()) { |
| LVElement *ThisPointer = getElement(StreamTPI, MF.getThisType()); |
| // When creating the 'this' pointer, check if it points to a reference. |
| ThisPointer->setType(Class); |
| LVSymbol *This = |
| createParameter(ThisPointer, StringRef(), MemberFunction); |
| This->setIsArtificial(); |
| } |
| |
| // Create formal parameters. |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVArguments = Types.getType(MF.getArgumentList()); |
| if (Error Err = finishVisitation(CVArguments, MF.getArgumentList(), |
| MemberFunction)) |
| return Err; |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_METHODLIST (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| MethodOverloadListRecord &Overloads, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeEnd(Record); |
| }); |
| |
| for (OneMethodRecord &Method : Overloads.Methods) { |
| CVMemberRecord Record; |
| Record.Kind = LF_METHOD; |
| Method.Name = OverloadedMethodName; |
| if (Error Err = visitKnownMember(Record, Method, TI, Element)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_MODIFIER (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ModifierRecord &Mod, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("ModifiedType", Mod.getModifiedType(), StreamTPI); |
| printTypeEnd(Record); |
| }); |
| |
| // Create the modified type, which will be attached to the type(s) that |
| // contains the modifiers. |
| LVElement *ModifiedType = getElement(StreamTPI, Mod.getModifiedType()); |
| |
| // At this point the types recording the qualifiers do not have a |
| // scope parent. They must be assigned to the current compile unit. |
| LVScopeCompileUnit *CompileUnit = Reader->getCompileUnit(); |
| |
| // The incoming element does not have a defined kind. Use the given |
| // modifiers to complete its type. A type can have more than one modifier; |
| // in that case, we have to create an extra type to have the other modifier. |
| LVType *LastLink = static_cast<LVType *>(Element); |
| if (!LastLink->getParentScope()) |
| CompileUnit->addElement(LastLink); |
| |
| bool SeenModifier = false; |
| uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers()); |
| if (Mods & uint16_t(ModifierOptions::Const)) { |
| SeenModifier = true; |
| LastLink->setTag(dwarf::DW_TAG_const_type); |
| LastLink->setIsConst(); |
| LastLink->setName("const"); |
| } |
| if (Mods & uint16_t(ModifierOptions::Volatile)) { |
| if (SeenModifier) { |
| LVType *Volatile = Reader->createType(); |
| Volatile->setIsModifier(); |
| LastLink->setType(Volatile); |
| LastLink = Volatile; |
| CompileUnit->addElement(LastLink); |
| } |
| LastLink->setTag(dwarf::DW_TAG_volatile_type); |
| LastLink->setIsVolatile(); |
| LastLink->setName("volatile"); |
| } |
| if (Mods & uint16_t(ModifierOptions::Unaligned)) { |
| if (SeenModifier) { |
| LVType *Unaligned = Reader->createType(); |
| Unaligned->setIsModifier(); |
| LastLink->setType(Unaligned); |
| LastLink = Unaligned; |
| CompileUnit->addElement(LastLink); |
| } |
| LastLink->setTag(dwarf::DW_TAG_unaligned); |
| LastLink->setIsUnaligned(); |
| LastLink->setName("unaligned"); |
| } |
| |
| LastLink->setType(ModifiedType); |
| return Error::success(); |
| } |
| |
| // LF_POINTER (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, PointerRecord &Ptr, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("PointeeType", Ptr.getReferentType(), StreamTPI); |
| W.printNumber("IsFlat", Ptr.isFlat()); |
| W.printNumber("IsConst", Ptr.isConst()); |
| W.printNumber("IsVolatile", Ptr.isVolatile()); |
| W.printNumber("IsUnaligned", Ptr.isUnaligned()); |
| W.printNumber("IsRestrict", Ptr.isRestrict()); |
| W.printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr()); |
| W.printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr()); |
| W.printNumber("SizeOf", Ptr.getSize()); |
| |
| if (Ptr.isPointerToMember()) { |
| const MemberPointerInfo &MI = Ptr.getMemberInfo(); |
| printTypeIndex("ClassType", MI.getContainingType(), StreamTPI); |
| } |
| printTypeEnd(Record); |
| }); |
| |
| // Find the pointed-to type. |
| LVType *Pointer = static_cast<LVType *>(Element); |
| LVElement *Pointee = nullptr; |
| |
| PointerMode Mode = Ptr.getMode(); |
| Pointee = Ptr.isPointerToMember() |
| ? Shared->TypeRecords.find(StreamTPI, Ptr.getReferentType()) |
| : getElement(StreamTPI, Ptr.getReferentType()); |
| |
| // At this point the types recording the qualifiers do not have a |
| // scope parent. They must be assigned to the current compile unit. |
| LVScopeCompileUnit *CompileUnit = Reader->getCompileUnit(); |
| |
| // Order for the different modifiers: |
| // <restrict> <pointer, Reference, ValueReference> <const, volatile> |
| // Const and volatile already processed. |
| bool SeenModifier = false; |
| LVType *LastLink = Pointer; |
| if (!LastLink->getParentScope()) |
| CompileUnit->addElement(LastLink); |
| |
| if (Ptr.isRestrict()) { |
| SeenModifier = true; |
| LVType *Restrict = Reader->createType(); |
| Restrict->setTag(dwarf::DW_TAG_restrict_type); |
| Restrict->setIsRestrict(); |
| Restrict->setName("restrict"); |
| LastLink->setType(Restrict); |
| LastLink = Restrict; |
| CompileUnit->addElement(LastLink); |
| } |
| if (Mode == PointerMode::LValueReference) { |
| if (SeenModifier) { |
| LVType *LReference = Reader->createType(); |
| LReference->setIsModifier(); |
| LastLink->setType(LReference); |
| LastLink = LReference; |
| CompileUnit->addElement(LastLink); |
| } |
| LastLink->setTag(dwarf::DW_TAG_reference_type); |
| LastLink->setIsReference(); |
| LastLink->setName("&"); |
| } |
| if (Mode == PointerMode::RValueReference) { |
| if (SeenModifier) { |
| LVType *RReference = Reader->createType(); |
| RReference->setIsModifier(); |
| LastLink->setType(RReference); |
| LastLink = RReference; |
| CompileUnit->addElement(LastLink); |
| } |
| LastLink->setTag(dwarf::DW_TAG_rvalue_reference_type); |
| LastLink->setIsRvalueReference(); |
| LastLink->setName("&&"); |
| } |
| |
| // When creating the pointer, check if it points to a reference. |
| LastLink->setType(Pointee); |
| return Error::success(); |
| } |
| |
| // LF_PROCEDURE (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, ProcedureRecord &Proc, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("ReturnType", Proc.getReturnType(), StreamTPI); |
| W.printNumber("NumParameters", Proc.getParameterCount()); |
| printTypeIndex("ArgListType", Proc.getArgumentList(), StreamTPI); |
| printTypeEnd(Record); |
| }); |
| |
| // There is no need to traverse the argument list, as the CodeView format |
| // declares the parameters as a 'S_LOCAL' symbol tagged as parameter. |
| // Only process parameters when dealing with inline functions. |
| if (LVScope *FunctionDcl = static_cast<LVScope *>(Element)) { |
| FunctionDcl->setType(getElement(StreamTPI, Proc.getReturnType())); |
| |
| if (ProcessArgumentList) { |
| ProcessArgumentList = false; |
| // Create formal parameters. |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVArguments = Types.getType(Proc.getArgumentList()); |
| if (Error Err = finishVisitation(CVArguments, Proc.getArgumentList(), |
| FunctionDcl)) |
| return Err; |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_UNION (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, UnionRecord &Union, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("MemberCount", Union.getMemberCount()); |
| printTypeIndex("FieldList", Union.getFieldList(), StreamTPI); |
| W.printNumber("SizeOf", Union.getSize()); |
| W.printString("Name", Union.getName()); |
| if (Union.hasUniqueName()) |
| W.printString("UniqueName", Union.getUniqueName()); |
| printTypeEnd(Record); |
| }); |
| |
| LVScopeAggregate *Scope = static_cast<LVScopeAggregate *>(Element); |
| if (!Scope) |
| return Error::success(); |
| |
| if (Scope->getIsFinalized()) |
| return Error::success(); |
| Scope->setIsFinalized(); |
| |
| Scope->setName(Union.getName()); |
| if (Union.hasUniqueName()) |
| Scope->setLinkageName(Union.getUniqueName()); |
| |
| if (Union.isNested()) { |
| Scope->setIsNested(); |
| createParents(Union.getName(), Scope); |
| } else { |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get(Union.getName())) |
| Namespace->addElement(Scope); |
| else |
| Reader->getCompileUnit()->addElement(Scope); |
| } |
| |
| if (!Union.getFieldList().isNoneType()) { |
| LazyRandomTypeCollection &Types = types(); |
| // Pass down the TypeIndex 'TI' for the aggregate containing the field list. |
| CVType CVFieldList = Types.getType(Union.getFieldList()); |
| if (Error Err = finishVisitation(CVFieldList, TI, Scope)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_TYPESERVER2 (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, TypeServer2Record &TS, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printString("Guid", formatv("{0}", TS.getGuid()).str()); |
| W.printNumber("Age", TS.getAge()); |
| W.printString("Name", TS.getName()); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_VFTABLE (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, VFTableRecord &VFT, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("CompleteClass", VFT.getCompleteClass(), StreamTPI); |
| printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable(), StreamTPI); |
| W.printHex("VFPtrOffset", VFT.getVFPtrOffset()); |
| W.printString("VFTableName", VFT.getName()); |
| for (const StringRef &N : VFT.getMethodNames()) |
| W.printString("MethodName", N); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_VTSHAPE (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| VFTableShapeRecord &Shape, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("VFEntryCount", Shape.getEntryCount()); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_SUBSTR_LIST (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| StringListRecord &Strings, |
| TypeIndex TI, LVElement *Element) { |
| // All the indices are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamIPI); |
| ArrayRef<TypeIndex> Indices = Strings.getIndices(); |
| uint32_t Size = Indices.size(); |
| W.printNumber("NumStrings", Size); |
| ListScope Arguments(W, "Strings"); |
| for (uint32_t I = 0; I < Size; ++I) |
| printTypeIndex("String", Indices[I], StreamIPI); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_STRING_ID (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, StringIdRecord &String, |
| TypeIndex TI, LVElement *Element) { |
| // All args are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| printTypeIndex("\nTI", TI, StreamIPI); |
| printTypeIndex("Id", String.getId(), StreamIPI); |
| W.printString("StringData", String.getString()); |
| }); |
| |
| if (LVScope *Namespace = Shared->NamespaceDeduction.get( |
| String.getString(), /*CheckScope=*/false)) { |
| // The function is already at different scope. In order to reflect |
| // the correct parent, move it to the namespace. |
| if (LVScope *Scope = Element->getParentScope()) |
| Scope->removeElement(Element); |
| Namespace->addElement(Element); |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_UDT_SRC_LINE (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| UdtSourceLineRecord &SourceLine, |
| TypeIndex TI, LVElement *Element) { |
| // All args are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| printTypeIndex("\nTI", TI, StreamIPI); |
| printTypeIndex("UDT", SourceLine.getUDT(), StreamIPI); |
| printTypeIndex("SourceFile", SourceLine.getSourceFile(), StreamIPI); |
| W.printNumber("LineNumber", SourceLine.getLineNumber()); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_UDT_MOD_SRC_LINE (TPI)/(IPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| UdtModSourceLineRecord &ModSourceLine, |
| TypeIndex TI, LVElement *Element) { |
| // All args are references into the TPI/IPI stream. |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamIPI); |
| printTypeIndex("\nTI", TI, StreamIPI); |
| printTypeIndex("UDT", ModSourceLine.getUDT(), StreamIPI); |
| printTypeIndex("SourceFile", ModSourceLine.getSourceFile(), StreamIPI); |
| W.printNumber("LineNumber", ModSourceLine.getLineNumber()); |
| W.printNumber("Module", ModSourceLine.getModule()); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_PRECOMP (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, PrecompRecord &Precomp, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printHex("StartIndex", Precomp.getStartTypeIndex()); |
| W.printHex("Count", Precomp.getTypesCount()); |
| W.printHex("Signature", Precomp.getSignature()); |
| W.printString("PrecompFile", Precomp.getPrecompFilePath()); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_ENDPRECOMP (TPI) |
| Error LVLogicalVisitor::visitKnownRecord(CVType &Record, |
| EndPrecompRecord &EndPrecomp, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printTypeBegin(Record, TI, Element, StreamTPI); |
| W.printHex("Signature", EndPrecomp.getSignature()); |
| printTypeEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| Error LVLogicalVisitor::visitUnknownMember(CVMemberRecord &Record, |
| TypeIndex TI) { |
| LLVM_DEBUG({ W.printHex("UnknownMember", unsigned(Record.Kind)); }); |
| return Error::success(); |
| } |
| |
| // LF_BCLASS, LF_BINTERFACE |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| BaseClassRecord &Base, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("BaseType", Base.getBaseType(), StreamTPI); |
| W.printHex("BaseOffset", Base.getBaseOffset()); |
| printMemberEnd(Record); |
| }); |
| |
| createElement(Record.Kind); |
| if (LVSymbol *Symbol = CurrentSymbol) { |
| LVElement *BaseClass = getElement(StreamTPI, Base.getBaseType()); |
| Symbol->setName(BaseClass->getName()); |
| Symbol->setType(BaseClass); |
| Symbol->setAccessibilityCode(Base.getAccess()); |
| static_cast<LVScope *>(Element)->addElement(Symbol); |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_MEMBER |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| DataMemberRecord &Field, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", Field.getType(), StreamTPI); |
| W.printHex("FieldOffset", Field.getFieldOffset()); |
| W.printString("Name", Field.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| // Create the data member. |
| createDataMember(Record, static_cast<LVScope *>(Element), Field.getName(), |
| Field.getType(), Field.getAccess()); |
| return Error::success(); |
| } |
| |
| // LF_ENUMERATE |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| EnumeratorRecord &Enum, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| W.printNumber("EnumValue", Enum.getValue()); |
| W.printString("Name", Enum.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| createElement(Record.Kind); |
| if (LVType *Type = CurrentType) { |
| Type->setName(Enum.getName()); |
| SmallString<16> Value; |
| Enum.getValue().toString(Value, 16, true, true); |
| Type->setValue(Value); |
| static_cast<LVScope *>(Element)->addElement(CurrentType); |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_INDEX |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| ListContinuationRecord &Cont, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("ContinuationIndex", Cont.getContinuationIndex(), StreamTPI); |
| printMemberEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_NESTTYPE |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| NestedTypeRecord &Nested, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", Nested.getNestedType(), StreamTPI); |
| W.printString("Name", Nested.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| if (LVElement *Typedef = createElement(SymbolKind::S_UDT)) { |
| Typedef->setName(Nested.getName()); |
| LVElement *NestedType = getElement(StreamTPI, Nested.getNestedType()); |
| Typedef->setType(NestedType); |
| LVScope *Scope = static_cast<LVScope *>(Element); |
| Scope->addElement(Typedef); |
| |
| if (NestedType && NestedType->getIsNested()) { |
| // 'Element' is an aggregate type that may contains this nested type |
| // definition. Used their scoped names, to decide on their relationship. |
| StringRef RecordName = getRecordName(types(), TI); |
| |
| StringRef NestedTypeName = NestedType->getName(); |
| if (NestedTypeName.size() && RecordName.size()) { |
| StringRef OuterComponent; |
| std::tie(OuterComponent, std::ignore) = |
| getInnerComponent(NestedTypeName); |
| // We have an already created nested type. Add it to the current scope |
| // and update all its children if any. |
| if (OuterComponent.size() && OuterComponent.equals(RecordName)) { |
| if (!NestedType->getIsScopedAlready()) { |
| Scope->addElement(NestedType); |
| NestedType->setIsScopedAlready(); |
| NestedType->updateLevel(Scope); |
| } |
| Typedef->resetIncludeInPrint(); |
| } |
| } |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| // LF_ONEMETHOD |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| OneMethodRecord &Method, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", Method.getType(), StreamTPI); |
| // If virtual, then read the vftable offset. |
| if (Method.isIntroducingVirtual()) |
| W.printHex("VFTableOffset", Method.getVFTableOffset()); |
| W.printString("Name", Method.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| // All the LF_ONEMETHOD objects share the same type description. |
| // We have to create a scope object for each one and get the required |
| // information from the LF_MFUNCTION object. |
| ProcessArgumentList = true; |
| if (LVElement *MemberFunction = createElement(TypeLeafKind::LF_ONEMETHOD)) { |
| MemberFunction->setIsFinalized(); |
| static_cast<LVScope *>(Element)->addElement(MemberFunction); |
| |
| MemberFunction->setName(Method.getName()); |
| MemberFunction->setAccessibilityCode(Method.getAccess()); |
| |
| MethodKind Kind = Method.getMethodKind(); |
| if (Kind == MethodKind::Static) |
| MemberFunction->setIsStatic(); |
| MemberFunction->setVirtualityCode(Kind); |
| |
| MethodOptions Flags = Method.Attrs.getFlags(); |
| if (MethodOptions::CompilerGenerated == |
| (Flags & MethodOptions::CompilerGenerated)) |
| MemberFunction->setIsArtificial(); |
| |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVMethodType = Types.getType(Method.getType()); |
| if (Error Err = |
| finishVisitation(CVMethodType, Method.getType(), MemberFunction)) |
| return Err; |
| } |
| ProcessArgumentList = false; |
| |
| return Error::success(); |
| } |
| |
| // LF_METHOD |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| OverloadedMethodRecord &Method, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| W.printHex("MethodCount", Method.getNumOverloads()); |
| printTypeIndex("MethodListIndex", Method.getMethodList(), StreamTPI); |
| W.printString("Name", Method.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| // Record the overloaded method name, which will be used during the |
| // traversal of the method list. |
| LazyRandomTypeCollection &Types = types(); |
| OverloadedMethodName = Method.getName(); |
| CVType CVMethods = Types.getType(Method.getMethodList()); |
| if (Error Err = finishVisitation(CVMethods, Method.getMethodList(), Element)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| // LF_STMEMBER |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| StaticDataMemberRecord &Field, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", Field.getType(), StreamTPI); |
| W.printString("Name", Field.getName()); |
| printMemberEnd(Record); |
| }); |
| |
| // Create the data member. |
| createDataMember(Record, static_cast<LVScope *>(Element), Field.getName(), |
| Field.getType(), Field.getAccess()); |
| return Error::success(); |
| } |
| |
| // LF_VFUNCTAB |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| VFPtrRecord &VFTable, TypeIndex TI, |
| LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("Type", VFTable.getType(), StreamTPI); |
| printMemberEnd(Record); |
| }); |
| return Error::success(); |
| } |
| |
| // LF_VBCLASS, LF_IVBCLASS |
| Error LVLogicalVisitor::visitKnownMember(CVMemberRecord &Record, |
| VirtualBaseClassRecord &Base, |
| TypeIndex TI, LVElement *Element) { |
| LLVM_DEBUG({ |
| printMemberBegin(Record, TI, Element, StreamTPI); |
| printTypeIndex("BaseType", Base.getBaseType(), StreamTPI); |
| printTypeIndex("VBPtrType", Base.getVBPtrType(), StreamTPI); |
| W.printHex("VBPtrOffset", Base.getVBPtrOffset()); |
| W.printHex("VBTableIndex", Base.getVTableIndex()); |
| printMemberEnd(Record); |
| }); |
| |
| createElement(Record.Kind); |
| if (LVSymbol *Symbol = CurrentSymbol) { |
| LVElement *BaseClass = getElement(StreamTPI, Base.getBaseType()); |
| Symbol->setName(BaseClass->getName()); |
| Symbol->setType(BaseClass); |
| Symbol->setAccessibilityCode(Base.getAccess()); |
| Symbol->setVirtualityCode(MethodKind::Virtual); |
| static_cast<LVScope *>(Element)->addElement(Symbol); |
| } |
| |
| return Error::success(); |
| } |
| |
| Error LVLogicalVisitor::visitMemberRecord(CVMemberRecord &Record, |
| TypeVisitorCallbacks &Callbacks, |
| TypeIndex TI, LVElement *Element) { |
| if (Error Err = Callbacks.visitMemberBegin(Record)) |
| return Err; |
| |
| switch (Record.Kind) { |
| default: |
| if (Error Err = Callbacks.visitUnknownMember(Record)) |
| return Err; |
| break; |
| #define MEMBER_RECORD(EnumName, EnumVal, Name) \ |
| case EnumName: { \ |
| if (Error Err = \ |
| visitKnownMember<Name##Record>(Record, Callbacks, TI, Element)) \ |
| return Err; \ |
| break; \ |
| } |
| #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ |
| MEMBER_RECORD(EnumVal, EnumVal, AliasName) |
| #define TYPE_RECORD(EnumName, EnumVal, Name) |
| #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) |
| #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" |
| } |
| |
| if (Error Err = Callbacks.visitMemberEnd(Record)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| Error LVLogicalVisitor::finishVisitation(CVType &Record, TypeIndex TI, |
| LVElement *Element) { |
| switch (Record.kind()) { |
| default: |
| if (Error Err = visitUnknownType(Record, TI)) |
| return Err; |
| break; |
| #define TYPE_RECORD(EnumName, EnumVal, Name) \ |
| case EnumName: { \ |
| if (Error Err = visitKnownRecord<Name##Record>(Record, TI, Element)) \ |
| return Err; \ |
| break; \ |
| } |
| #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ |
| TYPE_RECORD(EnumVal, EnumVal, AliasName) |
| #define MEMBER_RECORD(EnumName, EnumVal, Name) |
| #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) |
| #include "llvm/DebugInfo/CodeView/CodeViewTypes.def" |
| } |
| |
| return Error::success(); |
| } |
| |
| // Customized version of 'FieldListVisitHelper'. |
| Error LVLogicalVisitor::visitFieldListMemberStream( |
| TypeIndex TI, LVElement *Element, ArrayRef<uint8_t> FieldList) { |
| BinaryByteStream Stream(FieldList, llvm::support::little); |
| BinaryStreamReader Reader(Stream); |
| FieldListDeserializer Deserializer(Reader); |
| TypeVisitorCallbackPipeline Pipeline; |
| Pipeline.addCallbackToPipeline(Deserializer); |
| |
| TypeLeafKind Leaf; |
| while (!Reader.empty()) { |
| if (Error Err = Reader.readEnum(Leaf)) |
| return Err; |
| |
| CVMemberRecord Record; |
| Record.Kind = Leaf; |
| if (Error Err = visitMemberRecord(Record, Pipeline, TI, Element)) |
| return Err; |
| } |
| |
| return Error::success(); |
| } |
| |
| void LVLogicalVisitor::addElement(LVScope *Scope, bool IsCompileUnit) { |
| // The CodeView specifications does not treat S_COMPILE2 and S_COMPILE3 |
| // as symbols that open a scope. The CodeView reader, treat them in a |
| // similar way as DWARF. As there is no a symbole S_END to close the |
| // compile unit, we need to check for the next compile unit. |
| if (IsCompileUnit) { |
| if (!ScopeStack.empty()) |
| popScope(); |
| InCompileUnitScope = true; |
| } |
| |
| pushScope(Scope); |
| ReaderParent->addElement(Scope); |
| } |
| |
| void LVLogicalVisitor::addElement(LVSymbol *Symbol) { |
| ReaderScope->addElement(Symbol); |
| } |
| |
| void LVLogicalVisitor::addElement(LVType *Type) { |
| ReaderScope->addElement(Type); |
| } |
| |
| LVElement *LVLogicalVisitor::createElement(TypeLeafKind Kind) { |
| CurrentScope = nullptr; |
| CurrentSymbol = nullptr; |
| CurrentType = nullptr; |
| |
| if (Kind < TypeIndex::FirstNonSimpleIndex) { |
| CurrentType = Reader->createType(); |
| CurrentType->setIsBase(); |
| CurrentType->setTag(dwarf::DW_TAG_base_type); |
| if (options().getAttributeBase()) |
| CurrentType->setIncludeInPrint(); |
| return CurrentType; |
| } |
| |
| switch (Kind) { |
| // Types. |
| case TypeLeafKind::LF_ENUMERATE: |
| CurrentType = Reader->createTypeEnumerator(); |
| CurrentType->setTag(dwarf::DW_TAG_enumerator); |
| return CurrentType; |
| case TypeLeafKind::LF_MODIFIER: |
| CurrentType = Reader->createType(); |
| CurrentType->setIsModifier(); |
| return CurrentType; |
| case TypeLeafKind::LF_POINTER: |
| CurrentType = Reader->createType(); |
| CurrentType->setIsPointer(); |
| CurrentType->setName("*"); |
| CurrentType->setTag(dwarf::DW_TAG_pointer_type); |
| return CurrentType; |
| |
| // Symbols. |
| case TypeLeafKind::LF_BCLASS: |
| case TypeLeafKind::LF_IVBCLASS: |
| case TypeLeafKind::LF_VBCLASS: |
| CurrentSymbol = Reader->createSymbol(); |
| CurrentSymbol->setTag(dwarf::DW_TAG_inheritance); |
| CurrentSymbol->setIsInheritance(); |
| return CurrentSymbol; |
| case TypeLeafKind::LF_MEMBER: |
| case TypeLeafKind::LF_STMEMBER: |
| CurrentSymbol = Reader->createSymbol(); |
| CurrentSymbol->setIsMember(); |
| CurrentSymbol->setTag(dwarf::DW_TAG_member); |
| return CurrentSymbol; |
| |
| // Scopes. |
| case TypeLeafKind::LF_ARRAY: |
| CurrentScope = Reader->createScopeArray(); |
| CurrentScope->setTag(dwarf::DW_TAG_array_type); |
| return CurrentScope; |
| case TypeLeafKind::LF_CLASS: |
| CurrentScope = Reader->createScopeAggregate(); |
| CurrentScope->setTag(dwarf::DW_TAG_class_type); |
| CurrentScope->setIsClass(); |
| return CurrentScope; |
| case TypeLeafKind::LF_ENUM: |
| CurrentScope = Reader->createScopeEnumeration(); |
| CurrentScope->setTag(dwarf::DW_TAG_enumeration_type); |
| return CurrentScope; |
| case TypeLeafKind::LF_METHOD: |
| case TypeLeafKind::LF_ONEMETHOD: |
| case TypeLeafKind::LF_PROCEDURE: |
| CurrentScope = Reader->createScopeFunction(); |
| CurrentScope->setIsSubprogram(); |
| CurrentScope->setTag(dwarf::DW_TAG_subprogram); |
| return CurrentScope; |
| case TypeLeafKind::LF_STRUCTURE: |
| CurrentScope = Reader->createScopeAggregate(); |
| CurrentScope->setIsStructure(); |
| CurrentScope->setTag(dwarf::DW_TAG_structure_type); |
| return CurrentScope; |
| case TypeLeafKind::LF_UNION: |
| CurrentScope = Reader->createScopeAggregate(); |
| CurrentScope->setIsUnion(); |
| CurrentScope->setTag(dwarf::DW_TAG_union_type); |
| return CurrentScope; |
| default: |
| // If '--internal=tag' and '--print=warning' are specified in the command |
| // line, we record and print each seen 'TypeLeafKind'. |
| break; |
| } |
| return nullptr; |
| } |
| |
| LVElement *LVLogicalVisitor::createElement(SymbolKind Kind) { |
| CurrentScope = nullptr; |
| CurrentSymbol = nullptr; |
| CurrentType = nullptr; |
| switch (Kind) { |
| // Types. |
| case SymbolKind::S_UDT: |
| CurrentType = Reader->createTypeDefinition(); |
| CurrentType->setTag(dwarf::DW_TAG_typedef); |
| return CurrentType; |
| |
| // Symbols. |
| case SymbolKind::S_CONSTANT: |
| CurrentSymbol = Reader->createSymbol(); |
| CurrentSymbol->setIsConstant(); |
| CurrentSymbol->setTag(dwarf::DW_TAG_constant); |
| return CurrentSymbol; |
| |
| case SymbolKind::S_BPREL32: |
| case SymbolKind::S_REGREL32: |
| case SymbolKind::S_GDATA32: |
| case SymbolKind::S_LDATA32: |
| case SymbolKind::S_LOCAL: |
| // During the symbol traversal more information is available to |
| // determine if the symbol is a parameter or a variable. At this |
| // stage mark it as variable. |
| CurrentSymbol = Reader->createSymbol(); |
| CurrentSymbol->setIsVariable(); |
| CurrentSymbol->setTag(dwarf::DW_TAG_variable); |
| return CurrentSymbol; |
| |
| // Scopes. |
| case SymbolKind::S_BLOCK32: |
| CurrentScope = Reader->createScope(); |
| CurrentScope->setIsLexicalBlock(); |
| CurrentScope->setTag(dwarf::DW_TAG_lexical_block); |
| return CurrentScope; |
| case SymbolKind::S_COMPILE2: |
| case SymbolKind::S_COMPILE3: |
| CurrentScope = Reader->createScopeCompileUnit(); |
| CurrentScope->setTag(dwarf::DW_TAG_compile_unit); |
| Reader->setCompileUnit(static_cast<LVScopeCompileUnit *>(CurrentScope)); |
| return CurrentScope; |
| case SymbolKind::S_INLINESITE: |
| case SymbolKind::S_INLINESITE2: |
| CurrentScope = Reader->createScopeFunctionInlined(); |
| CurrentScope->setIsInlinedFunction(); |
| CurrentScope->setTag(dwarf::DW_TAG_inlined_subroutine); |
| return CurrentScope; |
| case SymbolKind::S_LPROC32: |
| case SymbolKind::S_GPROC32: |
| case SymbolKind::S_LPROC32_ID: |
| case SymbolKind::S_GPROC32_ID: |
| case SymbolKind::S_SEPCODE: |
| case SymbolKind::S_THUNK32: |
| CurrentScope = Reader->createScopeFunction(); |
| CurrentScope->setIsSubprogram(); |
| CurrentScope->setTag(dwarf::DW_TAG_subprogram); |
| return CurrentScope; |
| default: |
| // If '--internal=tag' and '--print=warning' are specified in the command |
| // line, we record and print each seen 'SymbolKind'. |
| break; |
| } |
| return nullptr; |
| } |
| |
| LVElement *LVLogicalVisitor::createElement(TypeIndex TI, TypeLeafKind Kind) { |
| LVElement *Element = Shared->TypeRecords.find(StreamTPI, TI); |
| if (!Element) { |
| // We are dealing with a base type or pointer to a base type, which are |
| // not included explicitly in the CodeView format. |
| if (Kind < TypeIndex::FirstNonSimpleIndex) { |
| Element = createElement(Kind); |
| Element->setIsFinalized(); |
| Shared->TypeRecords.add(StreamTPI, (TypeIndex)Kind, Kind, Element); |
| Element->setOffset(Kind); |
| return Element; |
| } |
| // We are dealing with a pointer to a base type. |
| if (TI.getIndex() < TypeIndex::FirstNonSimpleIndex) { |
| Element = createElement(Kind); |
| Shared->TypeRecords.add(StreamTPI, TI, Kind, Element); |
| Element->setOffset(TI.getIndex()); |
| Element->setOffsetFromTypeIndex(); |
| return Element; |
| } |
| |
| W.printString("** Not implemented. **"); |
| printTypeIndex("TypeIndex", TI, StreamTPI); |
| W.printString("TypeLeafKind", formatTypeLeafKind(Kind)); |
| return nullptr; |
| } |
| |
| Element->setOffset(TI.getIndex()); |
| Element->setOffsetFromTypeIndex(); |
| return Element; |
| } |
| |
| void LVLogicalVisitor::createDataMember(CVMemberRecord &Record, LVScope *Parent, |
| StringRef Name, TypeIndex TI, |
| MemberAccess Access) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", TI, StreamTPI); |
| W.printString("TypeName", Name); |
| }); |
| |
| createElement(Record.Kind); |
| if (LVSymbol *Symbol = CurrentSymbol) { |
| Symbol->setName(Name); |
| if (TI.isNoneType() || TI.isSimple()) |
| Symbol->setType(getElement(StreamTPI, TI)); |
| else { |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVMemberType = Types.getType(TI); |
| if (CVMemberType.kind() == LF_BITFIELD) { |
| if (Error Err = finishVisitation(CVMemberType, TI, Symbol)) { |
| consumeError(std::move(Err)); |
| return; |
| } |
| } else |
| Symbol->setType(getElement(StreamTPI, TI)); |
| } |
| Symbol->setAccessibilityCode(Access); |
| Parent->addElement(Symbol); |
| } |
| } |
| |
| LVSymbol *LVLogicalVisitor::createParameter(LVElement *Element, StringRef Name, |
| LVScope *Parent) { |
| LVSymbol *Parameter = Reader->createSymbol(); |
| Parent->addElement(Parameter); |
| Parameter->setIsParameter(); |
| Parameter->setTag(dwarf::DW_TAG_formal_parameter); |
| Parameter->setName(Name); |
| Parameter->setType(Element); |
| return Parameter; |
| } |
| |
| LVSymbol *LVLogicalVisitor::createParameter(TypeIndex TI, StringRef Name, |
| LVScope *Parent) { |
| return createParameter(getElement(StreamTPI, TI), Name, Parent); |
| } |
| |
| LVType *LVLogicalVisitor::createBaseType(TypeIndex TI, StringRef TypeName) { |
| TypeLeafKind SimpleKind = (TypeLeafKind)TI.getSimpleKind(); |
| TypeIndex TIR = (TypeIndex)SimpleKind; |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", TIR, StreamTPI); |
| W.printString("TypeName", TypeName); |
| }); |
| |
| if (LVElement *Element = Shared->TypeRecords.find(StreamTPI, TIR)) |
| return static_cast<LVType *>(Element); |
| |
| if (createElement(TIR, SimpleKind)) { |
| CurrentType->setName(TypeName); |
| Reader->getCompileUnit()->addElement(CurrentType); |
| } |
| return CurrentType; |
| } |
| |
| LVType *LVLogicalVisitor::createPointerType(TypeIndex TI, StringRef TypeName) { |
| LLVM_DEBUG({ |
| printTypeIndex("TypeIndex", TI, StreamTPI); |
| W.printString("TypeName", TypeName); |
| }); |
| |
| if (LVElement *Element = Shared->TypeRecords.find(StreamTPI, TI)) |
| return static_cast<LVType *>(Element); |
| |
| LVType *Pointee = createBaseType(TI, TypeName.drop_back(1)); |
| if (createElement(TI, TypeLeafKind::LF_POINTER)) { |
| CurrentType->setIsFinalized(); |
| CurrentType->setType(Pointee); |
| Reader->getCompileUnit()->addElement(CurrentType); |
| } |
| return CurrentType; |
| } |
| |
| void LVLogicalVisitor::createParents(StringRef ScopedName, LVElement *Element) { |
| // For the given test case: |
| // |
| // struct S { enum E { ... }; }; |
| // S::E V; |
| // |
| // 0 | S_LOCAL `V` |
| // type=0x1004 (S::E), flags = none |
| // 0x1004 | LF_ENUM `S::E` |
| // options: has unique name | is nested |
| // 0x1009 | LF_STRUCTURE `S` |
| // options: contains nested class |
| // |
| // When the local 'V' is processed, its type 'E' is created. But There is |
| // no direct reference to its parent 'S'. We use the scoped name for 'E', |
| // to create its parents. |
| |
| // The input scoped name must have at least parent and nested names. |
| // Drop the last element name, as it corresponds to the nested type. |
| LVStringRefs Components = getAllLexicalComponents(ScopedName); |
| if (Components.size() < 2) |
| return; |
| Components.pop_back(); |
| |
| LVStringRefs::size_type FirstNamespace; |
| LVStringRefs::size_type FirstAggregate; |
| std::tie(FirstNamespace, FirstAggregate) = |
| Shared->NamespaceDeduction.find(Components); |
| |
| LLVM_DEBUG({ |
| W.printString("First Namespace", Components[FirstNamespace]); |
| W.printString("First NonNamespace", Components[FirstAggregate]); |
| }); |
| |
| // Create any referenced namespaces. |
| if (FirstNamespace < FirstAggregate) { |
| Shared->NamespaceDeduction.get( |
| LVStringRefs(Components.begin() + FirstNamespace, |
| Components.begin() + FirstAggregate)); |
| } |
| |
| // Traverse the enclosing scopes (aggregates) and create them. In the |
| // case of nested empty aggregates, MSVC does not emit a full record |
| // description. It emits only the reference record. |
| LVScope *Aggregate = nullptr; |
| TypeIndex TIAggregate; |
| std::string AggregateName = getScopedName( |
| LVStringRefs(Components.begin(), Components.begin() + FirstAggregate)); |
| |
| // This traversal is executed at least once. |
| for (LVStringRefs::size_type Index = FirstAggregate; |
| Index < Components.size(); ++Index) { |
| AggregateName = getScopedName(LVStringRefs(Components.begin() + Index, |
| Components.begin() + Index + 1), |
| AggregateName); |
| TIAggregate = Shared->ForwardReferences.remap( |
| Shared->TypeRecords.find(StreamTPI, AggregateName)); |
| Aggregate = |
| TIAggregate.isNoneType() |
| ? nullptr |
| : static_cast<LVScope *>(getElement(StreamTPI, TIAggregate)); |
| } |
| |
| // Workaround for cases where LF_NESTTYPE is missing for nested templates. |
| // If we manage to get parent information from the scoped name, we can add |
| // the nested type without relying on the LF_NESTTYPE. |
| if (Aggregate && !Element->getIsScopedAlready()) { |
| Aggregate->addElement(Element); |
| Element->setIsScopedAlready(); |
| } |
| } |
| |
| LVElement *LVLogicalVisitor::getElement(uint32_t StreamIdx, TypeIndex TI, |
| LVScope *Parent) { |
| LLVM_DEBUG({ printTypeIndex("TypeIndex", TI, StreamTPI); }); |
| TI = Shared->ForwardReferences.remap(TI); |
| LLVM_DEBUG({ printTypeIndex("TypeIndex Remap", TI, StreamTPI); }); |
| |
| LVElement *Element = Shared->TypeRecords.find(StreamIdx, TI); |
| if (!Element) { |
| if (TI.isNoneType() || TI.isSimple()) { |
| StringRef TypeName = TypeIndex::simpleTypeName(TI); |
| // If the name ends with "*", create 2 logical types: a pointer and a |
| // pointee type. TypeIndex is composed of a SympleTypeMode byte followed |
| // by a SimpleTypeKind byte. The logical pointer will be identified by |
| // the full TypeIndex value and the pointee by the SimpleTypeKind. |
| return (TypeName.back() == '*') ? createPointerType(TI, TypeName) |
| : createBaseType(TI, TypeName); |
| } |
| |
| LLVM_DEBUG({ W.printHex("TypeIndex not implemented: ", TI.getIndex()); }); |
| return nullptr; |
| } |
| |
| // The element has been finalized. |
| if (Element->getIsFinalized()) |
| return Element; |
| |
| // Add the element in case of a given parent. |
| if (Parent) |
| Parent->addElement(Element); |
| |
| // Check for a composite type. |
| LazyRandomTypeCollection &Types = types(); |
| CVType CVRecord = Types.getType(TI); |
| if (Error Err = finishVisitation(CVRecord, TI, Element)) { |
| consumeError(std::move(Err)); |
| return nullptr; |
| } |
| Element->setIsFinalized(); |
| return Element; |
| } |
| |
| void LVLogicalVisitor::processLines() { |
| // Traverse the collected LF_UDT_SRC_LINE records and add the source line |
| // information to the logical elements. |
| for (const TypeIndex &Entry : Shared->LineRecords) { |
| CVType CVRecord = ids().getType(Entry); |
| UdtSourceLineRecord Line; |
| if (Error Err = TypeDeserializer::deserializeAs( |
| const_cast<CVType &>(CVRecord), Line)) |
| consumeError(std::move(Err)); |
| else { |
| LLVM_DEBUG({ |
| printTypeIndex("UDT", Line.getUDT(), StreamIPI); |
| printTypeIndex("SourceFile", Line.getSourceFile(), StreamIPI); |
| W.printNumber("LineNumber", Line.getLineNumber()); |
| }); |
| |
| // The TypeIndex returned by 'getUDT()' must point to an already |
| // created logical element. If no logical element is found, it means |
| // the LF_UDT_SRC_LINE is associated with a system TypeIndex. |
| if (LVElement *Element = Shared->TypeRecords.find( |
| StreamTPI, Line.getUDT(), /*Create=*/false)) { |
| Element->setLineNumber(Line.getLineNumber()); |
| Element->setFilenameIndex( |
| Shared->StringRecords.findIndex(Line.getSourceFile())); |
| } |
| } |
| } |
| } |
| |
| void LVLogicalVisitor::processNamespaces() { |
| // Create namespaces. |
| Shared->NamespaceDeduction.init(); |
| } |
| |
| void LVLogicalVisitor::processFiles() { Shared->StringRecords.addFilenames(); } |
| |
| void LVLogicalVisitor::printRecords(raw_ostream &OS) const { |
| if (!options().getInternalTag()) |
| return; |
| |
| unsigned Count = 0; |
| auto PrintItem = [&](StringRef Name) { |
| auto NewLine = [&]() { |
| if (++Count == 4) { |
| Count = 0; |
| OS << "\n"; |
| } |
| }; |
| OS << format("%20s", Name.str().c_str()); |
| NewLine(); |
| }; |
| |
| OS << "\nTypes:\n"; |
| for (const TypeLeafKind &Kind : Shared->TypeKinds) |
| PrintItem(formatTypeLeafKind(Kind)); |
| Shared->TypeKinds.clear(); |
| |
| Count = 0; |
| OS << "\nSymbols:\n"; |
| for (const SymbolKind &Kind : Shared->SymbolKinds) |
| PrintItem(LVCodeViewReader::getSymbolKindName(Kind)); |
| Shared->SymbolKinds.clear(); |
| |
| OS << "\n"; |
| } |
| |
| Error LVLogicalVisitor::inlineSiteAnnotation(LVScope *AbstractFunction, |
| LVScope *InlinedFunction, |
| InlineSiteSym &InlineSite) { |
| // Get the parent scope to update the address ranges of the nested |
| // scope representing the inlined function. |
| LVAddress ParentLowPC = 0; |
| LVScope *Parent = InlinedFunction->getParentScope(); |
| if (const LVLocations *Locations = Parent->getRanges()) { |
| if (!Locations->empty()) |
| ParentLowPC = (*Locations->begin())->getLowerAddress(); |
| } |
| |
| // For the given inlinesite, get the initial line number and its |
| // source filename. Update the logical scope representing it. |
| uint32_t LineNumber = 0; |
| StringRef Filename; |
| LVInlineeInfo::iterator Iter = InlineeInfo.find(InlineSite.Inlinee); |
| if (Iter != InlineeInfo.end()) { |
| LineNumber = Iter->second.first; |
| Filename = Iter->second.second; |
| AbstractFunction->setLineNumber(LineNumber); |
| // TODO: This part needs additional work in order to set properly the |
| // correct filename in order to detect changes between filenames. |
| // AbstractFunction->setFilename(Filename); |
| } |
| |
| LLVM_DEBUG({ |
| dbgs() << "inlineSiteAnnotation\n" |
| << "Abstract: " << AbstractFunction->getName() << "\n" |
| << "Inlined: " << InlinedFunction->getName() << "\n" |
| << "Parent: " << Parent->getName() << "\n" |
| << "Low PC: " << hexValue(ParentLowPC) << "\n"; |
| }); |
| |
| // Get the source lines if requested by command line option. |
| if (!options().getPrintLines()) |
| return Error::success(); |
| |
| // Limitation: Currently we don't track changes in the FileOffset. The |
| // side effects are the caller that it is unable to differentiate the |
| // source filename for the inlined code. |
| uint64_t CodeOffset = ParentLowPC; |
| int32_t LineOffset = LineNumber; |
| uint32_t FileOffset = 0; |
| |
| auto UpdateClose = [&]() { LLVM_DEBUG({ dbgs() << ("\n"); }); }; |
| auto UpdateCodeOffset = [&](uint32_t Delta) { |
| CodeOffset += Delta; |
| LLVM_DEBUG({ |
| dbgs() << formatv(" code 0x{0} (+0x{1})", utohexstr(CodeOffset), |
| utohexstr(Delta)); |
| }); |
| }; |
| auto UpdateLineOffset = [&](int32_t Delta) { |
| LineOffset += Delta; |
| LLVM_DEBUG({ |
| char Sign = Delta > 0 ? '+' : '-'; |
| dbgs() << formatv(" line {0} ({1}{2})", LineOffset, Sign, |
| std::abs(Delta)); |
| }); |
| }; |
| auto UpdateFileOffset = [&](int32_t Offset) { |
| FileOffset = Offset; |
| LLVM_DEBUG({ dbgs() << formatv(" file {0}", FileOffset); }); |
| }; |
| |
| LVLines InlineeLines; |
| auto CreateLine = [&]() { |
| // Create the logical line record. |
| LVLineDebug *Line = Reader->createLineDebug(); |
| Line->setAddress(CodeOffset); |
| Line->setLineNumber(LineOffset); |
| // TODO: This part needs additional work in order to set properly the |
| // correct filename in order to detect changes between filenames. |
| // Line->setFilename(Filename); |
| InlineeLines.push_back(Line); |
| }; |
| |
| bool SeenLowAddress = false; |
| bool SeenHighAddress = false; |
| uint64_t LowPC = 0; |
| uint64_t HighPC = 0; |
| |
| for (auto &Annot : InlineSite.annotations()) { |
| LLVM_DEBUG({ |
| dbgs() << formatv(" {0}", |
| fmt_align(toHex(Annot.Bytes), AlignStyle::Left, 9)); |
| }); |
| |
| // Use the opcode to interpret the integer values. |
| switch (Annot.OpCode) { |
| case BinaryAnnotationsOpCode::ChangeCodeOffset: |
| case BinaryAnnotationsOpCode::CodeOffset: |
| case BinaryAnnotationsOpCode::ChangeCodeLength: |
| UpdateCodeOffset(Annot.U1); |
| UpdateClose(); |
| if (Annot.OpCode == BinaryAnnotationsOpCode::ChangeCodeOffset) { |
| CreateLine(); |
| LowPC = CodeOffset; |
| SeenLowAddress = true; |
| break; |
| } |
| if (Annot.OpCode == BinaryAnnotationsOpCode::ChangeCodeLength) { |
| HighPC = CodeOffset - 1; |
| SeenHighAddress = true; |
| } |
| break; |
| case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: |
| UpdateCodeOffset(Annot.U2); |
| UpdateClose(); |
| break; |
| case BinaryAnnotationsOpCode::ChangeLineOffset: |
| case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: |
| UpdateCodeOffset(Annot.U1); |
| UpdateLineOffset(Annot.S1); |
| UpdateClose(); |
| if (Annot.OpCode == |
| BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset) |
| CreateLine(); |
| break; |
| case BinaryAnnotationsOpCode::ChangeFile: |
| UpdateFileOffset(Annot.U1); |
| UpdateClose(); |
| break; |
| default: |
| break; |
| } |
| if (SeenLowAddress && SeenHighAddress) { |
| SeenLowAddress = false; |
| SeenHighAddress = false; |
| InlinedFunction->addObject(LowPC, HighPC); |
| } |
| } |
| |
| Reader->addInlineeLines(InlinedFunction, InlineeLines); |
| UpdateClose(); |
| |
| return Error::success(); |
| } |