//===-- 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 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(CVReference), Record)) consumeError(std::move(Err)); else RecordName = Record.getName(); }; TypeRecordKind RK = static_cast(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; namespace { class LVTypeRecords { LVShared *Shared = nullptr; // Logical elements associated to their CodeView Type Index. using RecordEntry = std::pair; using RecordTable = std::map; RecordTable RecordFromTypes; RecordTable RecordFromIds; using NameTable = std::map; 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; using ForwardTypeNames = std::map; ForwardTypeNames ForwardTypesNames; // Forward reference and its definition (TypeIndex as key). using ForwardType = std::map; 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; Names NamespaceNames; using LookupSet = std::set; 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; using StringIds = std::map; 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; using LVSymbolKinds = std::set; // 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) llvm::erase_if(Components, [&](StringRef Component) { LookupSet::iterator Iter = IdentifiedNamespaces.find(Component); return Iter == IdentifiedNamespaces.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(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 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 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 == "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 == "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( "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( "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 == "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("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(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 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("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("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 == 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(); } // S_ARMSWITCHTABLE Error LVSymbolVisitor::visitKnownRecord(CVSymbol &CVR, JumpTableSym &JumpTable) { LLVM_DEBUG({ W.printHex("BaseOffset", JumpTable.BaseOffset); W.printNumber("BaseSegment", JumpTable.BaseSegment); W.printFlags("SwitchType", static_cast(JumpTable.SwitchType), getJumpTableEntrySizeNames()); W.printHex("BranchOffset", JumpTable.BranchOffset); W.printHex("TableOffset", JumpTable.TableOffset); W.printNumber("BranchSegment", JumpTable.BranchSegment); W.printNumber("TableSegment", JumpTable.TableSegment); W.printNumber("EntriesCount", JumpTable.EntriesCount); }); return Error::success(); } // S_CALLERS, S_CALLEES, S_INLINEES Error LVSymbolVisitor::visitKnownRecord(CVSymbol &Record, CallerSym &Caller) { LLVM_DEBUG({ llvm::StringRef FieldName; switch (Caller.getKind()) { case SymbolRecordKind::CallerSym: FieldName = "Callee"; break; case SymbolRecordKind::CalleeSym: FieldName = "Caller"; break; case SymbolRecordKind::InlineesSym: FieldName = "Inlinee"; break; default: return llvm::make_error( "Unknown CV Record type for a CallerSym object!"); } for (auto FuncID : Caller.Indices) { printTypeIndex(FieldName, FuncID); } }); 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(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 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(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(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(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(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(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(CVReference.kind()); ClassRecord ReferenceRecord(RK); if (Error Err = TypeDeserializer::deserializeAs( const_cast(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(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(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(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( 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(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(Element); if (!LastLink->getParentScope()) CompileUnit->addElement(LastLink); bool SeenModifier = false; uint16_t Mods = static_cast(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(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: // // 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(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(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 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(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(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(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(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 == 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(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(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(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(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(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 FieldList) { BinaryByteStream Stream(FieldList, llvm::endianness::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(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(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(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(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(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(); }