|  | //===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/DebugInfo/CodeView/SymbolDumper.h" | 
|  | #include "llvm/ADT/DenseMap.h" | 
|  | #include "llvm/ADT/SmallString.h" | 
|  | #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" | 
|  | #include "llvm/DebugInfo/CodeView/EnumTables.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h" | 
|  | #include "llvm/DebugInfo/CodeView/SymbolRecord.h" | 
|  | #include "llvm/DebugInfo/CodeView/TypeDumper.h" | 
|  | #include "llvm/DebugInfo/CodeView/TypeIndex.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 CVSymbolVisitor<CVSymbolDumperImpl> { | 
|  | public: | 
|  | CVSymbolDumperImpl(CVTypeDumper &CVTD, SymbolDumpDelegate *ObjDelegate, | 
|  | ScopedPrinter &W, bool PrintRecordBytes) | 
|  | : CVSymbolVisitor(ObjDelegate), CVTD(CVTD), ObjDelegate(ObjDelegate), | 
|  | W(W), PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {} | 
|  |  | 
|  | /// CVSymbolVisitor overrides. | 
|  | #define SYMBOL_RECORD(EnumName, EnumVal, Name)                                 \ | 
|  | void visit##Name(SymbolKind Kind, Name &Record); | 
|  | #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) | 
|  | #include "llvm/DebugInfo/CodeView/CVSymbolTypes.def" | 
|  |  | 
|  | void visitSymbolBegin(SymbolKind Kind, ArrayRef<uint8_t> Data); | 
|  | void visitSymbolEnd(SymbolKind Kind, ArrayRef<uint8_t> OriginalSymData); | 
|  | void visitUnknownSymbol(SymbolKind Kind, ArrayRef<uint8_t> Data); | 
|  |  | 
|  | private: | 
|  | void printLocalVariableAddrRange(const LocalVariableAddrRange &Range, | 
|  | uint32_t RelocationOffset); | 
|  | void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps); | 
|  |  | 
|  | CVTypeDumper &CVTD; | 
|  | SymbolDumpDelegate *ObjDelegate; | 
|  | ScopedPrinter &W; | 
|  |  | 
|  | bool PrintRecordBytes; | 
|  | bool InFunctionScope; | 
|  | }; | 
|  | } | 
|  |  | 
|  | 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::visitSymbolBegin(SymbolKind Kind, | 
|  | ArrayRef<uint8_t> Data) {} | 
|  |  | 
|  | void CVSymbolDumperImpl::visitSymbolEnd(SymbolKind Kind, | 
|  | ArrayRef<uint8_t> OriginalSymData) { | 
|  | if (PrintRecordBytes && ObjDelegate) | 
|  | ObjDelegate->printBinaryBlockWithRelocs("SymData", OriginalSymData); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitBlockSym(SymbolKind Kind, BlockSym &Block) { | 
|  | DictScope S(W, "BlockStart"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | W.printHex("PtrParent", Block.Header.PtrParent); | 
|  | W.printHex("PtrEnd", Block.Header.PtrEnd); | 
|  | W.printHex("CodeSize", Block.Header.CodeSize); | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(), | 
|  | Block.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Block.Header.Segment); | 
|  | W.printString("BlockName", Block.Name); | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitThunk32Sym(SymbolKind Kind, Thunk32Sym &Thunk) { | 
|  | DictScope S(W, "Thunk32"); | 
|  | W.printNumber("Parent", Thunk.Header.Parent); | 
|  | W.printNumber("End", Thunk.Header.End); | 
|  | W.printNumber("Next", Thunk.Header.Next); | 
|  | W.printNumber("Off", Thunk.Header.Off); | 
|  | W.printNumber("Seg", Thunk.Header.Seg); | 
|  | W.printNumber("Len", Thunk.Header.Len); | 
|  | W.printEnum("Ordinal", Thunk.Header.Ord, getThunkOrdinalNames()); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitTrampolineSym(SymbolKind Kind, | 
|  | TrampolineSym &Tramp) { | 
|  | DictScope S(W, "Trampoline"); | 
|  | W.printEnum("Type", Tramp.Header.Type, getTrampolineNames()); | 
|  | W.printNumber("Size", Tramp.Header.Size); | 
|  | W.printNumber("ThunkOff", Tramp.Header.ThunkOff); | 
|  | W.printNumber("TargetOff", Tramp.Header.TargetOff); | 
|  | W.printNumber("ThunkSection", Tramp.Header.ThunkSection); | 
|  | W.printNumber("TargetSection", Tramp.Header.TargetSection); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitSectionSym(SymbolKind Kind, SectionSym &Section) { | 
|  | DictScope S(W, "Section"); | 
|  | W.printNumber("SectionNumber", Section.Header.SectionNumber); | 
|  | W.printNumber("Alignment", Section.Header.Alignment); | 
|  | W.printNumber("Reserved", Section.Header.Reserved); | 
|  | W.printNumber("Rva", Section.Header.Rva); | 
|  | W.printNumber("Length", Section.Header.Length); | 
|  | W.printFlags("Characteristics", Section.Header.Characteristics, | 
|  | getImageSectionCharacteristicNames(), | 
|  | COFF::SectionCharacteristics(0x00F00000)); | 
|  |  | 
|  | W.printString("Name", Section.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitCoffGroupSym(SymbolKind Kind, | 
|  | CoffGroupSym &CoffGroup) { | 
|  | DictScope S(W, "COFF Group"); | 
|  | W.printNumber("Size", CoffGroup.Header.Size); | 
|  | W.printFlags("Characteristics", CoffGroup.Header.Characteristics, | 
|  | getImageSectionCharacteristicNames(), | 
|  | COFF::SectionCharacteristics(0x00F00000)); | 
|  | W.printNumber("Offset", CoffGroup.Header.Offset); | 
|  | W.printNumber("Segment", CoffGroup.Header.Segment); | 
|  | W.printString("Name", CoffGroup.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitBPRelativeSym(SymbolKind Kind, | 
|  | BPRelativeSym &BPRel) { | 
|  | DictScope S(W, "BPRelativeSym"); | 
|  |  | 
|  | W.printNumber("Offset", BPRel.Header.Offset); | 
|  | CVTD.printTypeIndex("Type", BPRel.Header.Type); | 
|  | W.printString("VarName", BPRel.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitBuildInfoSym(SymbolKind Kind, | 
|  | BuildInfoSym &BuildInfo) { | 
|  | DictScope S(W, "BuildInfo"); | 
|  |  | 
|  | W.printNumber("BuildId", BuildInfo.Header.BuildId); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitCallSiteInfoSym(SymbolKind Kind, | 
|  | CallSiteInfoSym &CallSiteInfo) { | 
|  | DictScope S(W, "CallSiteInfo"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField( | 
|  | "CodeOffset", CallSiteInfo.getRelocationOffset(), | 
|  | CallSiteInfo.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", CallSiteInfo.Header.Segment); | 
|  | W.printHex("Reserved", CallSiteInfo.Header.Reserved); | 
|  | CVTD.printTypeIndex("Type", CallSiteInfo.Header.Type); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitEnvBlockSym(SymbolKind Kind, | 
|  | EnvBlockSym &EnvBlock) { | 
|  | DictScope S(W, "EnvBlock"); | 
|  |  | 
|  | W.printNumber("Reserved", EnvBlock.Header.Reserved); | 
|  | ListScope L(W, "Entries"); | 
|  | for (auto Entry : EnvBlock.Fields) { | 
|  | W.printString(Entry); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitFileStaticSym(SymbolKind Kind, | 
|  | FileStaticSym &FileStatic) { | 
|  | DictScope S(W, "FileStatic"); | 
|  | W.printNumber("Index", FileStatic.Header.Index); | 
|  | W.printNumber("ModFilenameOffset", FileStatic.Header.ModFilenameOffset); | 
|  | W.printFlags("Flags", uint16_t(FileStatic.Header.Flags), getLocalFlagNames()); | 
|  | W.printString("Name", FileStatic.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitExportSym(SymbolKind Kind, ExportSym &Export) { | 
|  | DictScope S(W, "Export"); | 
|  | W.printNumber("Ordinal", Export.Header.Ordinal); | 
|  | W.printFlags("Flags", Export.Header.Flags, getExportSymFlagNames()); | 
|  | W.printString("Name", Export.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitCompile2Sym(SymbolKind Kind, | 
|  | Compile2Sym &Compile2) { | 
|  | DictScope S(W, "CompilerFlags2"); | 
|  |  | 
|  | W.printEnum("Language", Compile2.Header.getLanguage(), | 
|  | getSourceLanguageNames()); | 
|  | W.printFlags("Flags", Compile2.Header.flags & ~0xff, | 
|  | getCompileSym2FlagNames()); | 
|  | W.printEnum("Machine", unsigned(Compile2.Header.Machine), getCPUTypeNames()); | 
|  | std::string FrontendVersion; | 
|  | { | 
|  | raw_string_ostream Out(FrontendVersion); | 
|  | Out << Compile2.Header.VersionFrontendMajor << '.' | 
|  | << Compile2.Header.VersionFrontendMinor << '.' | 
|  | << Compile2.Header.VersionFrontendBuild; | 
|  | } | 
|  | std::string BackendVersion; | 
|  | { | 
|  | raw_string_ostream Out(BackendVersion); | 
|  | Out << Compile2.Header.VersionBackendMajor << '.' | 
|  | << Compile2.Header.VersionBackendMinor << '.' | 
|  | << Compile2.Header.VersionBackendBuild; | 
|  | } | 
|  | W.printString("FrontendVersion", FrontendVersion); | 
|  | W.printString("BackendVersion", BackendVersion); | 
|  | W.printString("VersionName", Compile2.Version); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitCompile3Sym(SymbolKind Kind, | 
|  | Compile3Sym &Compile3) { | 
|  | DictScope S(W, "CompilerFlags3"); | 
|  |  | 
|  | W.printEnum("Language", Compile3.Header.getLanguage(), | 
|  | getSourceLanguageNames()); | 
|  | W.printFlags("Flags", Compile3.Header.flags & ~0xff, | 
|  | getCompileSym3FlagNames()); | 
|  | W.printEnum("Machine", unsigned(Compile3.Header.Machine), getCPUTypeNames()); | 
|  | std::string FrontendVersion; | 
|  | { | 
|  | raw_string_ostream Out(FrontendVersion); | 
|  | Out << Compile3.Header.VersionFrontendMajor << '.' | 
|  | << Compile3.Header.VersionFrontendMinor << '.' | 
|  | << Compile3.Header.VersionFrontendBuild << '.' | 
|  | << Compile3.Header.VersionFrontendQFE; | 
|  | } | 
|  | std::string BackendVersion; | 
|  | { | 
|  | raw_string_ostream Out(BackendVersion); | 
|  | Out << Compile3.Header.VersionBackendMajor << '.' | 
|  | << Compile3.Header.VersionBackendMinor << '.' | 
|  | << Compile3.Header.VersionBackendBuild << '.' | 
|  | << Compile3.Header.VersionBackendQFE; | 
|  | } | 
|  | W.printString("FrontendVersion", FrontendVersion); | 
|  | W.printString("BackendVersion", BackendVersion); | 
|  | W.printString("VersionName", Compile3.Version); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitConstantSym(SymbolKind Kind, | 
|  | ConstantSym &Constant) { | 
|  | DictScope S(W, "Constant"); | 
|  |  | 
|  | CVTD.printTypeIndex("Type", Constant.Header.Type); | 
|  | W.printNumber("Value", Constant.Value); | 
|  | W.printString("Name", Constant.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDataSym(SymbolKind Kind, DataSym &Data) { | 
|  | DictScope S(W, "DataSym"); | 
|  |  | 
|  | W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), | 
|  | Data.Header.DataOffset, &LinkageName); | 
|  | } | 
|  | CVTD.printTypeIndex("Type", Data.Header.Type); | 
|  | W.printString("DisplayName", Data.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeFramePointerRelFullScopeSym( | 
|  | SymbolKind Kind, | 
|  | DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) { | 
|  | DictScope S(W, "DefRangeFramePointerRelFullScope"); | 
|  | W.printNumber("Offset", DefRangeFramePointerRelFullScope.Header.Offset); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeFramePointerRelSym( | 
|  | SymbolKind Kind, DefRangeFramePointerRelSym &DefRangeFramePointerRel) { | 
|  | DictScope S(W, "DefRangeFramePointerRel"); | 
|  |  | 
|  | W.printNumber("Offset", DefRangeFramePointerRel.Header.Offset); | 
|  | printLocalVariableAddrRange(DefRangeFramePointerRel.Header.Range, | 
|  | DefRangeFramePointerRel.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeRegisterRelSym( | 
|  | SymbolKind Kind, DefRangeRegisterRelSym &DefRangeRegisterRel) { | 
|  | DictScope S(W, "DefRangeRegisterRel"); | 
|  |  | 
|  | W.printNumber("BaseRegister", DefRangeRegisterRel.Header.BaseRegister); | 
|  | W.printBoolean("HasSpilledUDTMember", | 
|  | DefRangeRegisterRel.hasSpilledUDTMember()); | 
|  | W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent()); | 
|  | W.printNumber("BasePointerOffset", | 
|  | DefRangeRegisterRel.Header.BasePointerOffset); | 
|  | printLocalVariableAddrRange(DefRangeRegisterRel.Header.Range, | 
|  | DefRangeRegisterRel.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeRegisterRel.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeRegisterSym( | 
|  | SymbolKind Kind, DefRangeRegisterSym &DefRangeRegister) { | 
|  | DictScope S(W, "DefRangeRegister"); | 
|  |  | 
|  | W.printNumber("Register", DefRangeRegister.Header.Register); | 
|  | W.printNumber("MayHaveNoName", DefRangeRegister.Header.MayHaveNoName); | 
|  | printLocalVariableAddrRange(DefRangeRegister.Header.Range, | 
|  | DefRangeRegister.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeRegister.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeSubfieldRegisterSym( | 
|  | SymbolKind Kind, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) { | 
|  | DictScope S(W, "DefRangeSubfieldRegister"); | 
|  |  | 
|  | W.printNumber("Register", DefRangeSubfieldRegister.Header.Register); | 
|  | W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Header.MayHaveNoName); | 
|  | W.printNumber("OffsetInParent", | 
|  | DefRangeSubfieldRegister.Header.OffsetInParent); | 
|  | printLocalVariableAddrRange(DefRangeSubfieldRegister.Header.Range, | 
|  | DefRangeSubfieldRegister.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeSubfieldSym( | 
|  | SymbolKind Kind, DefRangeSubfieldSym &DefRangeSubfield) { | 
|  | DictScope S(W, "DefRangeSubfield"); | 
|  |  | 
|  | if (ObjDelegate) { | 
|  | StringRef StringTable = ObjDelegate->getStringTable(); | 
|  | auto ProgramStringTableOffset = DefRangeSubfield.Header.Program; | 
|  | if (ProgramStringTableOffset >= StringTable.size()) | 
|  | return parseError(); | 
|  | StringRef Program = | 
|  | StringTable.drop_front(ProgramStringTableOffset).split('\0').first; | 
|  | W.printString("Program", Program); | 
|  | } | 
|  | W.printNumber("OffsetInParent", DefRangeSubfield.Header.OffsetInParent); | 
|  | printLocalVariableAddrRange(DefRangeSubfield.Header.Range, | 
|  | DefRangeSubfield.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRangeSubfield.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitDefRangeSym(SymbolKind Kind, | 
|  | DefRangeSym &DefRange) { | 
|  | DictScope S(W, "DefRange"); | 
|  |  | 
|  | if (ObjDelegate) { | 
|  | StringRef StringTable = ObjDelegate->getStringTable(); | 
|  | auto ProgramStringTableOffset = DefRange.Header.Program; | 
|  | if (ProgramStringTableOffset >= StringTable.size()) | 
|  | return parseError(); | 
|  | StringRef Program = | 
|  | StringTable.drop_front(ProgramStringTableOffset).split('\0').first; | 
|  | W.printString("Program", Program); | 
|  | } | 
|  | printLocalVariableAddrRange(DefRange.Header.Range, | 
|  | DefRange.getRelocationOffset()); | 
|  | printLocalVariableAddrGap(DefRange.Gaps); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitFrameCookieSym(SymbolKind Kind, | 
|  | FrameCookieSym &FrameCookie) { | 
|  | DictScope S(W, "FrameCookie"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField( | 
|  | "CodeOffset", FrameCookie.getRelocationOffset(), | 
|  | FrameCookie.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Register", FrameCookie.Header.Register); | 
|  | W.printEnum("CookieKind", uint16_t(FrameCookie.Header.CookieKind), | 
|  | getFrameCookieKindNames()); | 
|  | W.printHex("Flags", FrameCookie.Header.Flags); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitFrameProcSym(SymbolKind Kind, | 
|  | FrameProcSym &FrameProc) { | 
|  | DictScope S(W, "FrameProc"); | 
|  |  | 
|  | W.printHex("TotalFrameBytes", FrameProc.Header.TotalFrameBytes); | 
|  | W.printHex("PaddingFrameBytes", FrameProc.Header.PaddingFrameBytes); | 
|  | W.printHex("OffsetToPadding", FrameProc.Header.OffsetToPadding); | 
|  | W.printHex("BytesOfCalleeSavedRegisters", | 
|  | FrameProc.Header.BytesOfCalleeSavedRegisters); | 
|  | W.printHex("OffsetOfExceptionHandler", | 
|  | FrameProc.Header.OffsetOfExceptionHandler); | 
|  | W.printHex("SectionIdOfExceptionHandler", | 
|  | FrameProc.Header.SectionIdOfExceptionHandler); | 
|  | W.printFlags("Flags", FrameProc.Header.Flags, getFrameProcSymFlagNames()); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitHeapAllocationSiteSym( | 
|  | SymbolKind Kind, HeapAllocationSiteSym &HeapAllocSite) { | 
|  | DictScope S(W, "HeapAllocationSite"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField( | 
|  | "CodeOffset", HeapAllocSite.getRelocationOffset(), | 
|  | HeapAllocSite.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", HeapAllocSite.Header.Segment); | 
|  | W.printHex("CallInstructionSize", HeapAllocSite.Header.CallInstructionSize); | 
|  | CVTD.printTypeIndex("Type", HeapAllocSite.Header.Type); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitInlineSiteSym(SymbolKind Kind, | 
|  | InlineSiteSym &InlineSite) { | 
|  | DictScope S(W, "InlineSite"); | 
|  |  | 
|  | W.printHex("PtrParent", InlineSite.Header.PtrParent); | 
|  | W.printHex("PtrEnd", InlineSite.Header.PtrEnd); | 
|  | CVTD.printTypeIndex("Inlinee", InlineSite.Header.Inlinee); | 
|  |  | 
|  | ListScope BinaryAnnotations(W, "BinaryAnnotations"); | 
|  | for (auto &Annotation : InlineSite.annotations()) { | 
|  | switch (Annotation.OpCode) { | 
|  | case BinaryAnnotationsOpCode::Invalid: | 
|  | return parseError(); | 
|  | 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; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitRegisterSym(SymbolKind Kind, | 
|  | RegisterSym &Register) { | 
|  | DictScope S(W, "RegisterSym"); | 
|  | W.printNumber("Type", Register.Header.Index); | 
|  | W.printEnum("Seg", uint16_t(Register.Header.Register), getRegisterNames()); | 
|  | W.printString("Name", Register.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitPublicSym32(SymbolKind Kind, | 
|  | PublicSym32 &Public) { | 
|  | DictScope S(W, "PublicSym"); | 
|  | W.printNumber("Type", Public.Header.Index); | 
|  | W.printNumber("Seg", Public.Header.Seg); | 
|  | W.printNumber("Off", Public.Header.Off); | 
|  | W.printString("Name", Public.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitProcRefSym(SymbolKind Kind, ProcRefSym &ProcRef) { | 
|  | DictScope S(W, "ProcRef"); | 
|  | W.printNumber("SumName", ProcRef.Header.SumName); | 
|  | W.printNumber("SymOffset", ProcRef.Header.SymOffset); | 
|  | W.printNumber("Mod", ProcRef.Header.Mod); | 
|  | W.printString("Name", ProcRef.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitLabelSym(SymbolKind Kind, LabelSym &Label) { | 
|  | DictScope S(W, "Label"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(), | 
|  | Label.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Label.Header.Segment); | 
|  | W.printHex("Flags", Label.Header.Flags); | 
|  | W.printFlags("Flags", Label.Header.Flags, getProcSymFlagNames()); | 
|  | W.printString("DisplayName", Label.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitLocalSym(SymbolKind Kind, LocalSym &Local) { | 
|  | DictScope S(W, "Local"); | 
|  |  | 
|  | CVTD.printTypeIndex("Type", Local.Header.Type); | 
|  | W.printFlags("Flags", uint16_t(Local.Header.Flags), getLocalFlagNames()); | 
|  | W.printString("VarName", Local.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitObjNameSym(SymbolKind Kind, ObjNameSym &ObjName) { | 
|  | DictScope S(W, "ObjectName"); | 
|  |  | 
|  | W.printHex("Signature", ObjName.Header.Signature); | 
|  | W.printString("ObjectName", ObjName.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitProcSym(SymbolKind Kind, ProcSym &Proc) { | 
|  | DictScope S(W, "ProcStart"); | 
|  |  | 
|  | if (InFunctionScope) | 
|  | return parseError(); | 
|  |  | 
|  | InFunctionScope = true; | 
|  |  | 
|  | StringRef LinkageName; | 
|  | W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); | 
|  | W.printHex("PtrParent", Proc.Header.PtrParent); | 
|  | W.printHex("PtrEnd", Proc.Header.PtrEnd); | 
|  | W.printHex("PtrNext", Proc.Header.PtrNext); | 
|  | W.printHex("CodeSize", Proc.Header.CodeSize); | 
|  | W.printHex("DbgStart", Proc.Header.DbgStart); | 
|  | W.printHex("DbgEnd", Proc.Header.DbgEnd); | 
|  | CVTD.printTypeIndex("FunctionType", Proc.Header.FunctionType); | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(), | 
|  | Proc.Header.CodeOffset, &LinkageName); | 
|  | } | 
|  | W.printHex("Segment", Proc.Header.Segment); | 
|  | W.printFlags("Flags", static_cast<uint8_t>(Proc.Header.Flags), | 
|  | getProcSymFlagNames()); | 
|  | W.printString("DisplayName", Proc.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitScopeEndSym(SymbolKind Kind, | 
|  | ScopeEndSym &ScopeEnd) { | 
|  | if (Kind == SymbolKind::S_END) | 
|  | DictScope S(W, "BlockEnd"); | 
|  | else if (Kind == SymbolKind::S_PROC_ID_END) | 
|  | DictScope S(W, "ProcEnd"); | 
|  | else if (Kind == SymbolKind::S_INLINESITE_END) | 
|  | DictScope S(W, "InlineSiteEnd"); | 
|  |  | 
|  | InFunctionScope = false; | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitCallerSym(SymbolKind Kind, CallerSym &Caller) { | 
|  | ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers"); | 
|  | for (auto FuncID : Caller.Indices) | 
|  | CVTD.printTypeIndex("FuncID", FuncID); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitRegRelativeSym(SymbolKind Kind, | 
|  | RegRelativeSym &RegRel) { | 
|  | DictScope S(W, "RegRelativeSym"); | 
|  |  | 
|  | W.printHex("Offset", RegRel.Header.Offset); | 
|  | CVTD.printTypeIndex("Type", RegRel.Header.Type); | 
|  | W.printHex("Register", RegRel.Header.Register); | 
|  | W.printString("VarName", RegRel.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitThreadLocalDataSym(SymbolKind Kind, | 
|  | ThreadLocalDataSym &Data) { | 
|  | DictScope S(W, "ThreadLocalDataSym"); | 
|  |  | 
|  | StringRef LinkageName; | 
|  | if (ObjDelegate) { | 
|  | ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(), | 
|  | Data.Header.DataOffset, &LinkageName); | 
|  | } | 
|  | CVTD.printTypeIndex("Type", Data.Header.Type); | 
|  | W.printString("DisplayName", Data.Name); | 
|  | if (!LinkageName.empty()) | 
|  | W.printString("LinkageName", LinkageName); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitUDTSym(SymbolKind Kind, UDTSym &UDT) { | 
|  | DictScope S(W, "UDT"); | 
|  | CVTD.printTypeIndex("Type", UDT.Header.Type); | 
|  | W.printString("UDTName", UDT.Name); | 
|  | } | 
|  |  | 
|  | void CVSymbolDumperImpl::visitUnknownSymbol(SymbolKind Kind, | 
|  | ArrayRef<uint8_t> Data) { | 
|  | DictScope S(W, "UnknownSym"); | 
|  | W.printEnum("Kind", uint16_t(Kind), getSymbolTypeNames()); | 
|  | W.printNumber("Length", uint32_t(Data.size())); | 
|  | } | 
|  |  | 
|  | bool CVSymbolDumper::dump(const CVRecord<SymbolKind> &Record) { | 
|  | CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); | 
|  | Dumper.visitSymbolRecord(Record); | 
|  | return !Dumper.hadError(); | 
|  | } | 
|  |  | 
|  | bool CVSymbolDumper::dump(const CVSymbolArray &Symbols) { | 
|  | CVSymbolDumperImpl Dumper(CVTD, ObjDelegate.get(), W, PrintRecordBytes); | 
|  | Dumper.visitSymbolStream(Symbols); | 
|  | return !Dumper.hadError(); | 
|  | } |