|  | //===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===// | 
|  | // | 
|  | // 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/DebugInfo/CodeView/SymbolDumper.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" | 
|  | #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" | 
|  | #include "llvm/DebugInfo/CodeView/EnumTables.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h" | 
|  | #include "llvm/DebugInfo/CodeView/TypeIndex.h" | 
|  | #include "llvm/Support/Error.h" | 
|  | #include "llvm/Support/ScopedPrinter.h" | 
|  |  | 
|  | #include <system_error> | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace llvm::codeview; | 
|  |  | 
|  | namespace { | 
|  | /// Use this private dumper implementation to keep implementation details about | 
|  | /// the visitor out of SymbolDumper.h. | 
|  | class CVSymbolDumperImpl : public SymbolVisitorCallbacks { | 
|  | public: | 
|  | CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate, | 
|  | ScopedPrinter &W, CPUType CPU, bool PrintRecordBytes) | 
|  | : Types(Types), ObjDelegate(ObjDelegate), W(W), CompilationCPUType(CPU), | 
|  | PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} | 
|  |  | 
|  | /// CVSymbolVisitor overrides. | 
|  | #define SYMBOL_RECORD(EnumName, EnumVal, Name)                                 \ | 
|  | Error visitKnownRecord(CVSymbol &CVR, Name &Record) override; | 
|  | #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) | 
|  | #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" | 
|  |  | 
|  | Error visitSymbolBegin(CVSymbol &Record) override; | 
|  | Error visitSymbolEnd(CVSymbol &Record) override; | 
|  | Error visitUnknownSymbol(CVSymbol &Record) override; | 
|  |  | 
|  | CPUType getCompilationCPUType() const { return CompilationCPUType; } | 
|  |  | 
|  | private: | 
|  | void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, | 
|  | uint32_t RelocationOffset); | 
|  | void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); | 
|  | void printTypeIndex(StringRef FieldName, TypeIndex TI); | 
|  |  | 
|  | TypeCollection &Types; | 
|  | SymbolDumpDelegate *ObjDelegate; | 
|  | ScopedPrinter &W; | 
|  |  | 
|  | /// Save the machine or CPU type when dumping a compile symbols. | 
|  | CPUType CompilationCPUType = CPUType::X64; | 
|  |  | 
|  | bool PrintRecordBytes; | 
|  | bool InFunctionScope; | 
|  | }; | 
|  | } | 
|  |  | 
|  | static StringRef getSymbolKindName(SymbolKind Kind) { | 
|  | switch (Kind) { | 
|  | #define SYMBOL_RECORD(EnumName, EnumVal, Name)                                 \ | 
|  | case EnumName:                                                               \ | 
|  | return #Name; | 
|  | #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" | 
|  | default: | 
|  | break; | 
|  | } | 
|  | return "UnknownSym"; | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::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 CVSymbolDumperImpl::printLocalVariableAddrGap( | 
|  | ArrayRef<LocalVariableAddrGap> Gaps) { | 
|  | for (auto &Gap : Gaps) { | 
|  | ListScope S(W, "LocalVariableAddrGap"); | 
|  | W.printHex("GapStartOffset", Gap.GapStartOffset); | 
|  | W.printHex("Range", Gap.Range); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) { | 
|  | codeview::printTypeIndex(W, FieldName, TI, Types); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) { | 
|  | W.startLine() << getSymbolKindName(CVR.kind()); | 
|  | W.getOStream() << " {\n"; | 
|  | W.indent(); | 
|  | W.printEnum("Kind", unsigned(CVR.kind()), getSymbolTypeNames()); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) { | 
|  | if (PrintRecordBytes && ObjDelegate) | 
|  | ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content()); | 
|  |  | 
|  | W.unindent(); | 
|  | W.startLine() << "}\n"; | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) { | 
|  | StringRef LinkageName; | 
|  | W.printHex("PtrParent", Block.Parent); | 
|  | W.printHex("PtrEnd", Block.End); | 
|  | W.printHex("CodeSize", Block.CodeSize); | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(), | 
|  | Block.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Block.Segment); | 
|  | W.printString("BlockName", Block.Name); | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) { | 
|  | W.printString("Name", Thunk.Name); | 
|  | W.printNumber("Parent", Thunk.Parent); | 
|  | W.printNumber("End", Thunk.End); | 
|  | W.printNumber("Next", Thunk.Next); | 
|  | W.printNumber("Off", Thunk.Offset); | 
|  | W.printNumber("Seg", Thunk.Segment); | 
|  | W.printNumber("Len", Thunk.Length); | 
|  | W.printEnum("Ordinal", uint8_t(Thunk.Thunk), getThunkOrdinalNames()); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | TrampolineSym &Tramp) { | 
|  | W.printEnum("Type", uint16_t(Tramp.Type), getTrampolineNames()); | 
|  | W.printNumber("Size", Tramp.Size); | 
|  | W.printNumber("ThunkOff", Tramp.ThunkOffset); | 
|  | W.printNumber("TargetOff", Tramp.TargetOffset); | 
|  | W.printNumber("ThunkSection", Tramp.ThunkSection); | 
|  | W.printNumber("TargetSection", Tramp.TargetSection); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) { | 
|  | W.printNumber("SectionNumber", Section.SectionNumber); | 
|  | W.printNumber("Alignment", Section.Alignment); | 
|  | W.printNumber("Rva", Section.Rva); | 
|  | W.printNumber("Length", Section.Length); | 
|  | W.printFlags("Characteristics", Section.Characteristics, | 
|  | getImageSectionCharacteristicNames(), | 
|  | COFF::SectionCharacteristics(0x00F00000)); | 
|  |  | 
|  | W.printString("Name", Section.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | CoffGroupSym &CoffGroup) { | 
|  | W.printNumber("Size", CoffGroup.Size); | 
|  | W.printFlags("Characteristics", CoffGroup.Characteristics, | 
|  | getImageSectionCharacteristicNames(), | 
|  | COFF::SectionCharacteristics(0x00F00000)); | 
|  | W.printNumber("Offset", CoffGroup.Offset); | 
|  | W.printNumber("Segment", CoffGroup.Segment); | 
|  | W.printString("Name", CoffGroup.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | BPRelativeSym &BPRel) { | 
|  | W.printNumber("Offset", BPRel.Offset); | 
|  | printTypeIndex("Type", BPRel.Type); | 
|  | W.printString("VarName", BPRel.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | BuildInfoSym &BuildInfo) { | 
|  | printTypeIndex("BuildId", BuildInfo.BuildId); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | CallSiteInfoSym &CallSiteInfo) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", | 
|  | CallSiteInfo.getRelocationOffset(), | 
|  | CallSiteInfo.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", CallSiteInfo.Segment); | 
|  | printTypeIndex("Type", CallSiteInfo.Type); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | EnvBlockSym &EnvBlock) { | 
|  | ListScope L(W, "Entries"); | 
|  | for (auto Entry : EnvBlock.Fields) { | 
|  | W.printString(Entry); | 
|  | } | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | FileStaticSym &FileStatic) { | 
|  | printTypeIndex("Index", FileStatic.Index); | 
|  | W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset); | 
|  | W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames()); | 
|  | W.printString("Name", FileStatic.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) { | 
|  | W.printNumber("Ordinal", Export.Ordinal); | 
|  | W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames()); | 
|  | W.printString("Name", Export.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | Compile2Sym &Compile2) { | 
|  | W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames()); | 
|  | W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames()); | 
|  | W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames()); | 
|  | CompilationCPUType = Compile2.Machine; | 
|  | std::string FrontendVersion; | 
|  | { | 
|  | raw_string_ostream Out(FrontendVersion); | 
|  | Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor | 
|  | << '.' << Compile2.VersionFrontendBuild; | 
|  | } | 
|  | std::string BackendVersion; | 
|  | { | 
|  | raw_string_ostream Out(BackendVersion); | 
|  | Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor | 
|  | << '.' << Compile2.VersionBackendBuild; | 
|  | } | 
|  | W.printString("FrontendVersion", FrontendVersion); | 
|  | W.printString("BackendVersion", BackendVersion); | 
|  | W.printString("VersionName", Compile2.Version); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | Compile3Sym &Compile3) { | 
|  | W.printEnum("Language", uint8_t(Compile3.getLanguage()), getSourceLanguageNames()); | 
|  | W.printFlags("Flags", uint32_t(Compile3.getFlags()), | 
|  | getCompileSym3FlagNames()); | 
|  | W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames()); | 
|  | CompilationCPUType = Compile3.Machine; | 
|  | std::string FrontendVersion; | 
|  | { | 
|  | raw_string_ostream Out(FrontendVersion); | 
|  | Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor | 
|  | << '.' << Compile3.VersionFrontendBuild << '.' | 
|  | << Compile3.VersionFrontendQFE; | 
|  | } | 
|  | std::string BackendVersion; | 
|  | { | 
|  | raw_string_ostream Out(BackendVersion); | 
|  | Out << Compile3.VersionBackendMajor << '.' << Compile3.VersionBackendMinor | 
|  | << '.' << Compile3.VersionBackendBuild << '.' | 
|  | << Compile3.VersionBackendQFE; | 
|  | } | 
|  | W.printString("FrontendVersion", FrontendVersion); | 
|  | W.printString("BackendVersion", BackendVersion); | 
|  | W.printString("VersionName", Compile3.Version); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | ConstantSym &Constant) { | 
|  | printTypeIndex("Type", Constant.Type); | 
|  | W.printNumber("Value", Constant.Value); | 
|  | W.printString("Name", Constant.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), | 
|  | Data.DataOffset, &LinkageName); | 
|  | } | 
|  | printTypeIndex("Type", Data.Type); | 
|  | W.printString("DisplayName", Data.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, | 
|  | DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { | 
|  | W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { | 
|  | W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset); | 
|  | printLocalVariableAddrRange(DefRangeFramePointerRel.Range, | 
|  | DefRangeFramePointerRel.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) { | 
|  | W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printBoolean("HasSpilledUDTMember", | 
|  | DefRangeRegisterRel.hasSpilledUDTMember()); | 
|  | W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); | 
|  | W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset); | 
|  | printLocalVariableAddrRange(DefRangeRegisterRel.Range, | 
|  | DefRangeRegisterRel.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) { | 
|  | W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName); | 
|  | printLocalVariableAddrRange(DefRangeRegister.Range, | 
|  | DefRangeRegister.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeRegister.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { | 
|  | W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName); | 
|  | W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent); | 
|  | printLocalVariableAddrRange(DefRangeSubfieldRegister.Range, | 
|  | DefRangeSubfieldRegister.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) { | 
|  | if (ObjDelegate) { | 
|  | DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); | 
|  | auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program); | 
|  | if (!ExpectedProgram) { | 
|  | consumeError(ExpectedProgram.takeError()); | 
|  | return llvm::make_error<CodeViewError>( | 
|  | "String table offset outside of bounds of String Table!"); | 
|  | } | 
|  | W.printString("Program", *ExpectedProgram); | 
|  | } | 
|  | W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent); | 
|  | printLocalVariableAddrRange(DefRangeSubfield.Range, | 
|  | DefRangeSubfield.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeSubfield.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | DefRangeSym &DefRange) { | 
|  | if (ObjDelegate) { | 
|  | DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable(); | 
|  | auto ExpectedProgram = Strings.getString(DefRange.Program); | 
|  | if (!ExpectedProgram) { | 
|  | consumeError(ExpectedProgram.takeError()); | 
|  | return llvm::make_error<CodeViewError>( | 
|  | "String table offset outside of bounds of String Table!"); | 
|  | } | 
|  | W.printString("Program", *ExpectedProgram); | 
|  | } | 
|  | printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRange.Gaps); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | FrameCookieSym &FrameCookie) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", | 
|  | FrameCookie.getRelocationOffset(), | 
|  | FrameCookie.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printEnum("Register", uint16_t(FrameCookie.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind), | 
|  | getFrameCookieKindNames()); | 
|  | W.printHex("Flags", FrameCookie.Flags); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | FrameProcSym &FrameProc) { | 
|  | W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes); | 
|  | W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes); | 
|  | W.printHex("OffsetToPadding", FrameProc.OffsetToPadding); | 
|  | W.printHex("BytesOfCalleeSavedRegisters", | 
|  | FrameProc.BytesOfCalleeSavedRegisters); | 
|  | W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler); | 
|  | W.printHex("SectionIdOfExceptionHandler", | 
|  | FrameProc.SectionIdOfExceptionHandler); | 
|  | W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags), | 
|  | getFrameProcSymFlagNames()); | 
|  | W.printEnum("LocalFramePtrReg", | 
|  | uint16_t(FrameProc.getLocalFramePtrReg(CompilationCPUType)), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printEnum("ParamFramePtrReg", | 
|  | uint16_t(FrameProc.getParamFramePtrReg(CompilationCPUType)), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord( | 
|  | CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", | 
|  | HeapAllocSite.getRelocationOffset(), | 
|  | HeapAllocSite.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", HeapAllocSite.Segment); | 
|  | W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize); | 
|  | printTypeIndex("Type", HeapAllocSite.Type); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | InlineSiteSym &InlineSite) { | 
|  | W.printHex("PtrParent", InlineSite.Parent); | 
|  | W.printHex("PtrEnd", InlineSite.End); | 
|  | printTypeIndex("Inlinee", InlineSite.Inlinee); | 
|  |  | 
|  | ListScope BinaryAnnotations(W, "BinaryAnnotations"); | 
|  | for (auto &Annotation : InlineSite.annotations()) { | 
|  | switch (Annotation.OpCode) { | 
|  | case BinaryAnnotationsOpCode::Invalid: | 
|  | W.printString("(Annotation Padding)"); | 
|  | break; | 
|  | case BinaryAnnotationsOpCode::CodeOffset: | 
|  | case BinaryAnnotationsOpCode::ChangeCodeOffset: | 
|  | case BinaryAnnotationsOpCode::ChangeCodeLength: | 
|  | W.printHex(Annotation.Name, Annotation.U1); | 
|  | break; | 
|  | case BinaryAnnotationsOpCode::ChangeCodeOffsetBase: | 
|  | case BinaryAnnotationsOpCode::ChangeLineEndDelta: | 
|  | case BinaryAnnotationsOpCode::ChangeRangeKind: | 
|  | case BinaryAnnotationsOpCode::ChangeColumnStart: | 
|  | case BinaryAnnotationsOpCode::ChangeColumnEnd: | 
|  | W.printNumber(Annotation.Name, Annotation.U1); | 
|  | break; | 
|  | case BinaryAnnotationsOpCode::ChangeLineOffset: | 
|  | case BinaryAnnotationsOpCode::ChangeColumnEndDelta: | 
|  | W.printNumber(Annotation.Name, Annotation.S1); | 
|  | break; | 
|  | case BinaryAnnotationsOpCode::ChangeFile: | 
|  | if (ObjDelegate) { | 
|  | W.printHex("ChangeFile", | 
|  | ObjDelegate->getFileNameForFileOffset(Annotation.U1), | 
|  | Annotation.U1); | 
|  | } else { | 
|  | W.printHex("ChangeFile", Annotation.U1); | 
|  | } | 
|  |  | 
|  | break; | 
|  | case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: { | 
|  | W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: " | 
|  | << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1 | 
|  | << "}\n"; | 
|  | break; | 
|  | } | 
|  | case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: { | 
|  | W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: " | 
|  | << W.hex(Annotation.U2) | 
|  | << ", Length: " << W.hex(Annotation.U1) << "}\n"; | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | RegisterSym &Register) { | 
|  | printTypeIndex("Type", Register.Index); | 
|  | W.printEnum("Seg", uint16_t(Register.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printString("Name", Register.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) { | 
|  | W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames()); | 
|  | W.printNumber("Seg", Public.Segment); | 
|  | W.printNumber("Off", Public.Offset); | 
|  | W.printString("Name", Public.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) { | 
|  | W.printNumber("SumName", ProcRef.SumName); | 
|  | W.printNumber("SymOffset", ProcRef.SymOffset); | 
|  | W.printNumber("Mod", ProcRef.Module); | 
|  | W.printString("Name", ProcRef.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(), | 
|  | Label.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Label.Segment); | 
|  | W.printHex("Flags", uint8_t(Label.Flags)); | 
|  | W.printFlags("Flags", uint8_t(Label.Flags), getProcSymFlagNames()); | 
|  | W.printString("DisplayName", Label.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) { | 
|  | printTypeIndex("Type", Local.Type); | 
|  | W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames()); | 
|  | W.printString("VarName", Local.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) { | 
|  | W.printHex("Signature", ObjName.Signature); | 
|  | W.printString("ObjectName", ObjName.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) { | 
|  | if (InFunctionScope) | 
|  | return llvm::make_error<CodeViewError>( | 
|  | "Visiting a ProcSym while inside function scope!"); | 
|  |  | 
|  | InFunctionScope = true; | 
|  |  | 
|  | StringRef LinkageName; | 
|  | W.printHex("PtrParent", Proc.Parent); | 
|  | W.printHex("PtrEnd", Proc.End); | 
|  | W.printHex("PtrNext", Proc.Next); | 
|  | W.printHex("CodeSize", Proc.CodeSize); | 
|  | W.printHex("DbgStart", Proc.DbgStart); | 
|  | W.printHex("DbgEnd", Proc.DbgEnd); | 
|  | printTypeIndex("FunctionType", Proc.FunctionType); | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(), | 
|  | Proc.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Proc.Segment); | 
|  | W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags), | 
|  | getProcSymFlagNames()); | 
|  | W.printString("DisplayName", Proc.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | ScopeEndSym &ScopeEnd) { | 
|  | InFunctionScope = false; | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) { | 
|  | ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers"); | 
|  | for (auto FuncID : Caller.Indices) | 
|  | printTypeIndex("FuncID", FuncID); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | RegRelativeSym &RegRel) { | 
|  | W.printHex("Offset", RegRel.Offset); | 
|  | printTypeIndex("Type", RegRel.Type); | 
|  | W.printEnum("Register", uint16_t(RegRel.Register), | 
|  | getRegisterNames(CompilationCPUType)); | 
|  | W.printString("VarName", RegRel.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | ThreadLocalDataSym &Data) { | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), | 
|  | Data.DataOffset, &LinkageName); | 
|  | } | 
|  | printTypeIndex("Type", Data.Type); | 
|  | W.printString("DisplayName", Data.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) { | 
|  | printTypeIndex("Type", UDT.Type); | 
|  | W.printString("UDTName", UDT.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | UsingNamespaceSym &UN) { | 
|  | W.printString("Namespace", UN.Name); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, | 
|  | AnnotationSym &Annot) { | 
|  | W.printHex("Offset", Annot.CodeOffset); | 
|  | W.printHex("Segment", Annot.Segment); | 
|  |  | 
|  | ListScope S(W, "Strings"); | 
|  | for (StringRef Str : Annot.Strings) | 
|  | W.printString(Str); | 
|  |  | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) { | 
|  | W.printNumber("Length", CVR.length()); | 
|  | return Error::success(); | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) { | 
|  | SymbolVisitorCallbackPipeline Pipeline; | 
|  | SymbolDeserializer Deserializer(ObjDelegate.get(), Container); | 
|  | CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, | 
|  | PrintRecordBytes); | 
|  |  | 
|  | Pipeline.addCallbackToPipeline(Deserializer); | 
|  | Pipeline.addCallbackToPipeline(Dumper); | 
|  | CVSymbolVisitor Visitor(Pipeline); | 
|  | auto Err = Visitor.visitSymbolRecord(Record); | 
|  | CompilationCPUType = Dumper.getCompilationCPUType(); | 
|  | return Err; | 
|  | } | 
|  |  | 
|  | Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) { | 
|  | SymbolVisitorCallbackPipeline Pipeline; | 
|  | SymbolDeserializer Deserializer(ObjDelegate.get(), Container); | 
|  | CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType, | 
|  | PrintRecordBytes); | 
|  |  | 
|  | Pipeline.addCallbackToPipeline(Deserializer); | 
|  | Pipeline.addCallbackToPipeline(Dumper); | 
|  | CVSymbolVisitor Visitor(Pipeline); | 
|  | auto Err = Visitor.visitSymbolStream(Symbols); | 
|  | CompilationCPUType = Dumper.getCompilationCPUType(); | 
|  | return Err; | 
|  | } |