Index: lld/test/CMakeLists.txt =================================================================== --- lld/test/CMakeLists.txt +++ lld/test/CMakeLists.txt @@ -29,7 +29,7 @@ list(APPEND LLD_TEST_DEPS FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm llc llvm-config llvm-objdump llvm-readobj yaml2obj obj2yaml - llvm-mc llvm-lib llvm-pdbdump opt + llvm-mc llvm-lib llvm-pdbutil opt ) endif() Index: lld/test/COFF/pdb-none.test =================================================================== --- lld/test/COFF/pdb-none.test +++ lld/test/COFF/pdb-none.test @@ -3,7 +3,7 @@ # RUN: lld-link /debug /debugtype:pdata /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.pdb | FileCheck %s +# RUN: llvm-pdbutil pdb2yaml -pdb-stream %t.pdb | FileCheck %s # CHECK: PdbStream: # CHECK-NEXT: Age: 0 Index: lld/test/COFF/pdb.test =================================================================== --- lld/test/COFF/pdb.test +++ lld/test/COFF/pdb.test @@ -3,10 +3,10 @@ # RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ # RUN: %t1.obj %t2.obj -# RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream \ +# RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s -# RUN: llvm-pdbdump raw -modules -section-map -section-headers -section-contribs \ +# RUN: llvm-pdbutil raw -modules -section-map -section-headers -section-contribs \ # RUN: -tpi-records %t.pdb | FileCheck -check-prefix RAW %s # CHECK: MSF: Index: llvm/include/llvm/DebugInfo/CodeView/CVRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/CVRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -62,10 +62,8 @@ template struct VarStreamArrayExtractor> { - typedef void ContextType; - - static Error extract(BinaryStreamRef Stream, uint32_t &Len, - codeview::CVRecord &Item) { + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::CVRecord &Item) { using namespace codeview; const RecordPrefix *Prefix = nullptr; BinaryStreamReader Reader(Stream); Index: llvm/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h @@ -34,10 +34,8 @@ namespace llvm { template <> struct VarStreamArrayExtractor { public: - typedef void ContextType; - - static Error extract(BinaryStreamRef Stream, uint32_t &Len, - codeview::FileChecksumEntry &Item); + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::FileChecksumEntry &Item); }; } Index: llvm/include/llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h @@ -29,10 +29,8 @@ namespace llvm { template <> struct VarStreamArrayExtractor { public: - typedef void ContextType; - - static Error extract(BinaryStreamRef Stream, uint32_t &Len, - codeview::CrossModuleImportItem &Item); + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::CrossModuleImportItem &Item); }; } Index: llvm/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h @@ -43,10 +43,12 @@ } template <> struct VarStreamArrayExtractor { - typedef bool ContextType; + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::InlineeSourceLine &Item); + void setHasExtraFiles(bool Has) { ExtraFiles = Has; } - static Error extract(BinaryStreamRef Stream, uint32_t &Len, - codeview::InlineeSourceLine &Item, bool HasExtraFiles); +private: + bool ExtraFiles = false; }; namespace codeview { Index: llvm/include/llvm/DebugInfo/CodeView/DebugLinesSubsection.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugLinesSubsection.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugLinesSubsection.h @@ -66,8 +66,13 @@ public: typedef const LineFragmentHeader *ContextType; - static Error extract(BinaryStreamRef Stream, uint32_t &Len, - LineColumnEntry &Item, const LineFragmentHeader *Ctx); + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + LineColumnEntry &Item); + + void setHeader(const LineFragmentHeader *H) { Header = H; } + +private: + const LineFragmentHeader *Header = nullptr; }; class DebugLinesSubsectionRef final : public DebugSubsectionRef { Index: llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h =================================================================== --- llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h +++ llvm/include/llvm/DebugInfo/CodeView/DebugSubsectionRecord.h @@ -62,10 +62,8 @@ } // namespace codeview template <> struct VarStreamArrayExtractor { - typedef void ContextType; - - static Error extract(BinaryStreamRef Stream, uint32_t &Length, - codeview::DebugSubsectionRecord &Info) { + Error operator()(BinaryStreamRef Stream, uint32_t &Length, + codeview::DebugSubsectionRecord &Info) { if (auto EC = codeview::DebugSubsectionRecord::initialize( Stream, Info, codeview::CodeViewContainer::Pdb)) return EC; Index: llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h +++ llvm/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h @@ -56,9 +56,8 @@ } // end namespace pdb template <> struct VarStreamArrayExtractor { - typedef void ContextType; - static Error extract(BinaryStreamRef Stream, uint32_t &Length, - pdb::DbiModuleDescriptor &Info) { + Error operator()(BinaryStreamRef Stream, uint32_t &Length, + pdb::DbiModuleDescriptor &Info) { if (auto EC = pdb::DbiModuleDescriptor::initialize(Stream, Info)) return EC; Length = Info.getRecordLength(); Index: llvm/include/llvm/Support/BinaryStreamArray.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamArray.h +++ llvm/include/llvm/Support/BinaryStreamArray.h @@ -42,36 +42,114 @@ /// having to specify a second template argument to VarStreamArray (documented /// below). template struct VarStreamArrayExtractor { - struct ContextType {}; - // Method intentionally deleted. You must provide an explicit specialization - // with one of the following two methods implemented. - static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item) = delete; + // with the following method implemented. + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + T &Item) const = delete; +}; + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. Elements are parsed +/// lazily on iteration, so there is no upfront cost associated with building +/// or copying a VarStreamArray, no matter how large it may be. +/// +/// You create a VarStreamArray by specifying a ValueType and an Extractor type. +/// If you do not specify an Extractor type, you are expected to specialize +/// VarStreamArrayExtractor for your ValueType. +/// +/// By default an Extractor is default constructed in the class, but in some +/// cases you might find it useful for an Extractor to maintain state across +/// extractions. In this case you can provide your own Extractor through a +/// secondary constructor. The following examples show various ways of +/// creating a VarStreamArray. +/// +/// // Will use VarStreamArrayExtractor as the extractor. +/// VarStreamArray MyTypeArray; +/// +/// // Will use a default-constructed MyExtractor as the extractor. +/// VarStreamArray MyTypeArray2; +/// +/// // Will use the specific instance of MyExtractor provided. +/// // MyExtractor need not be default-constructible in this case. +/// MyExtractor E(SomeContext); +/// VarStreamArray MyTypeArray3(E); +/// + +template class VarStreamArrayIterator; + +template > +class VarStreamArray { + friend class VarStreamArrayIterator; + +public: + typedef VarStreamArrayIterator Iterator; + + VarStreamArray() = default; + + explicit VarStreamArray(const Extractor &E) : E(E) {} + + explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} - static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item, - const ContextType &Ctx) = delete; + VarStreamArray(BinaryStreamRef Stream, const Extractor &E) + : Stream(Stream), E(E) {} + + Iterator begin(bool *HadError = nullptr) const { + return Iterator(*this, E, HadError); + } + + bool valid() const { return Stream.valid(); } + + Iterator end() const { return Iterator(E); } + + bool empty() const { return Stream.getLength() == 0; } + + /// \brief given an offset into the array's underlying stream, return an + /// iterator to the record at that offset. This is considered unsafe + /// since the behavior is undefined if \p Offset does not refer to the + /// beginning of a valid record. + Iterator at(uint32_t Offset) const { + return Iterator(*this, E, Offset, nullptr); + } + + const Extractor &getExtractor() const { return E; } + Extractor &getExtractor() { return E; } + + BinaryStreamRef getUnderlyingStream() const { return Stream; } + void setUnderlyingStream(BinaryStreamRef S) { Stream = S; } + +private: + BinaryStreamRef Stream; + Extractor E; }; -template +template class VarStreamArrayIterator - : public iterator_facade_base< - VarStreamArrayIterator, - std::forward_iterator_tag, Value> { - typedef VarStreamArrayIterator - IterType; + : public iterator_facade_base, + std::forward_iterator_tag, ValueType> { + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; public: - VarStreamArrayIterator() = default; - VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, - BinaryStreamRef Stream, bool *HadError = nullptr, - uint32_t Offset = 0) - : IterRef(Stream), Ctx(&Ctx), Array(&Array), AbsOffset(Offset), - HadError(HadError) { + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError) + : VarStreamArrayIterator(Array, E, 0, HadError) {} + + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + uint32_t Offset, bool *HadError) + : IterRef(Array.Stream.drop_front(Offset)), Array(&Array), + AbsOffset(Offset), HadError(HadError), Extract(E) { if (IterRef.getLength() == 0) moveToEnd(); else { - auto EC = Ctx.template invoke(IterRef, ThisLen, ThisValue); + auto EC = Extract(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -79,13 +157,8 @@ } } - VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, - bool *HadError = nullptr) - : VarStreamArrayIterator(Array, Ctx, Array.Stream, HadError) {} - - VarStreamArrayIterator(const WrappedCtx &Ctx) : Ctx(&Ctx) {} - VarStreamArrayIterator(const VarStreamArrayIterator &Other) = default; - + VarStreamArrayIterator() = default; + explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} ~VarStreamArrayIterator() = default; bool operator==(const IterType &R) const { @@ -103,12 +176,12 @@ return false; } - const Value &operator*() const { + const ValueType &operator*() const { assert(Array && !HasError); return ThisValue; } - Value &operator*() { + ValueType &operator*() { assert(Array && !HasError); return ThisValue; } @@ -125,7 +198,7 @@ moveToEnd(); } else { // There is some data after the current record. - auto EC = Ctx->template invoke(IterRef, ThisLen, ThisValue); + auto EC = Extract(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -153,9 +226,9 @@ *HadError = true; } - Value ThisValue; + ValueType ThisValue; BinaryStreamRef IterRef; - const WrappedCtx *Ctx{nullptr}; + Extractor Extract; const ArrayType *Array{nullptr}; uint32_t ThisLen{0}; uint32_t AbsOffset{0}; @@ -163,127 +236,6 @@ bool *HadError{nullptr}; }; -template struct ContextWrapper { - ContextWrapper() = default; - - explicit ContextWrapper(Context &&Ctx) : Ctx(Ctx) {} - - template - Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { - return Extractor::extract(Stream, Len, Item, Ctx); - } - - Context Ctx; -}; - -template struct ContextWrapper { - ContextWrapper() = default; - - template - Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { - return Extractor::extract(Stream, Len, Item); - } -}; - -/// VarStreamArray represents an array of variable length records backed by a -/// stream. This could be a contiguous sequence of bytes in memory, it could -/// be a file on disk, or it could be a PDB stream where bytes are stored as -/// discontiguous blocks in a file. Usually it is desirable to treat arrays -/// as contiguous blocks of memory, but doing so with large PDB files, for -/// example, could mean allocating huge amounts of memory just to allow -/// re-ordering of stream data to be contiguous before iterating over it. By -/// abstracting this out, we need not duplicate this memory, and we can -/// iterate over arrays in arbitrarily formatted streams. Elements are parsed -/// lazily on iteration, so there is no upfront cost associated with building -/// or copying a VarStreamArray, no matter how large it may be. -/// -/// You create a VarStreamArray by specifying a ValueType and an Extractor type. -/// If you do not specify an Extractor type, you are expected to specialize -/// VarStreamArrayExtractor for your ValueType. -/// -/// The default extractor type is stateless, but by specializing -/// VarStreamArrayExtractor or defining your own custom extractor type and -/// adding the appropriate ContextType typedef to the class, you can pass a -/// context field during construction of the VarStreamArray that will be -/// passed to each call to extract. -/// -template -class VarStreamArrayBase { - typedef VarStreamArrayBase MyType; - -public: - typedef VarStreamArrayIterator Iterator; - friend Iterator; - - VarStreamArrayBase() = default; - - VarStreamArrayBase(BinaryStreamRef Stream, const WrappedCtx &Ctx) - : Stream(Stream), Ctx(Ctx) {} - - VarStreamArrayBase(const MyType &Other) - : Stream(Other.Stream), Ctx(Other.Ctx) {} - - Iterator begin(bool *HadError = nullptr) const { - if (empty()) - return end(); - - return Iterator(*this, Ctx, Stream, HadError); - } - - bool valid() const { return Stream.valid(); } - - Iterator end() const { return Iterator(Ctx); } - - bool empty() const { return Stream.getLength() == 0; } - - /// \brief given an offset into the array's underlying stream, return an - /// iterator to the record at that offset. This is considered unsafe - /// since the behavior is undefined if \p Offset does not refer to the - /// beginning of a valid record. - Iterator at(uint32_t Offset) const { - return Iterator(*this, Ctx, Stream.drop_front(Offset), nullptr, Offset); - } - - BinaryStreamRef getUnderlyingStream() const { return Stream; } - -private: - BinaryStreamRef Stream; - WrappedCtx Ctx; -}; - -template -class VarStreamArrayImpl - : public VarStreamArrayBase> { - typedef ContextWrapper WrappedContext; - typedef VarStreamArrayImpl MyType; - typedef VarStreamArrayBase BaseType; - -public: - typedef Context ContextType; - - VarStreamArrayImpl() = default; - VarStreamArrayImpl(BinaryStreamRef Stream, Context &&Ctx) - : BaseType(Stream, WrappedContext(std::forward(Ctx))) {} -}; - -template -class VarStreamArrayImpl - : public VarStreamArrayBase> { - typedef ContextWrapper WrappedContext; - typedef VarStreamArrayImpl MyType; - typedef VarStreamArrayBase BaseType; - -public: - VarStreamArrayImpl() = default; - VarStreamArrayImpl(BinaryStreamRef Stream) - : BaseType(Stream, WrappedContext()) {} -}; - -template > -using VarStreamArray = - VarStreamArrayImpl; - template class FixedStreamArrayIterator; /// FixedStreamArray is similar to VarStreamArray, except with each record Index: llvm/include/llvm/Support/BinaryStreamReader.h =================================================================== --- llvm/include/llvm/Support/BinaryStreamReader.h +++ llvm/include/llvm/Support/BinaryStreamReader.h @@ -198,25 +198,7 @@ BinaryStreamRef S; if (auto EC = readStreamRef(S, Size)) return EC; - Array = VarStreamArray(S); - return Error::success(); - } - - /// Read a VarStreamArray of size \p Size bytes and store the result into - /// \p Array. Updates the stream's offset to point after the newly read - /// array. Never causes a copy (although iterating the elements of the - /// VarStreamArray may, depending upon the implementation of the underlying - /// stream). - /// - /// \returns a success error code if the data was successfully read, otherwise - /// returns an appropriate error code. - template - Error readArray(VarStreamArray &Array, uint32_t Size, - ContextType &&Context) { - BinaryStreamRef S; - if (auto EC = readStreamRef(S, Size)) - return EC; - Array = VarStreamArray(S, std::move(Context)); + Array.setUnderlyingStream(S); return Error::success(); } Index: llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp @@ -25,8 +25,8 @@ // Checksum bytes follow. }; -Error llvm::VarStreamArrayExtractor::extract( - BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { +Error llvm::VarStreamArrayExtractor:: +operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) { BinaryStreamReader Reader(Stream); const FileChecksumEntryHeader *Header; Index: llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp @@ -16,9 +16,9 @@ using namespace llvm::codeview; namespace llvm { -Error VarStreamArrayExtractor::extract( - BinaryStreamRef Stream, uint32_t &Len, - codeview::CrossModuleImportItem &Item) { +Error VarStreamArrayExtractor:: +operator()(BinaryStreamRef Stream, uint32_t &Len, + codeview::CrossModuleImportItem &Item) { BinaryStreamReader Reader(Stream); if (Reader.bytesRemaining() < sizeof(CrossModuleImport)) return make_error( Index: llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp @@ -17,15 +17,14 @@ using namespace llvm; using namespace llvm::codeview; -Error VarStreamArrayExtractor::extract( - BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item, - bool HasExtraFiles) { +Error VarStreamArrayExtractor:: +operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) { BinaryStreamReader Reader(Stream); if (auto EC = Reader.readObject(Item.Header)) return EC; - if (HasExtraFiles) { + if (ExtraFiles) { uint32_t ExtraFileCount; if (auto EC = Reader.readInteger(ExtraFileCount)) return EC; @@ -44,8 +43,8 @@ if (auto EC = Reader.readEnum(Signature)) return EC; - if (auto EC = - Reader.readArray(Lines, Reader.bytesRemaining(), hasExtraFiles())) + Lines.getExtractor().setHasExtraFiles(hasExtraFiles()); + if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining())) return EC; assert(Reader.bytesRemaining() == 0); Index: llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp +++ llvm/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp @@ -17,9 +17,8 @@ using namespace llvm; using namespace llvm::codeview; -Error LineColumnExtractor::extract(BinaryStreamRef Stream, uint32_t &Len, - LineColumnEntry &Item, - const LineFragmentHeader *Header) { +Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len, + LineColumnEntry &Item) { using namespace codeview; const LineBlockFragmentHeader *BlockHeader; BinaryStreamReader Reader(Stream); @@ -56,8 +55,8 @@ if (auto EC = Reader.readObject(Header)) return EC; - if (auto EC = - Reader.readArray(LinesAndColumns, Reader.bytesRemaining(), Header)) + LinesAndColumns.getExtractor().setHeader(Header); + if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining())) return EC; return Error::success(); Index: llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp =================================================================== --- llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp +++ llvm/lib/DebugInfo/CodeView/TypeTableCollection.cpp @@ -49,9 +49,10 @@ BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little); + VarStreamArrayExtractor Extractor; CVType Type; uint32_t Len; - error(VarStreamArrayExtractor::extract(Bytes, Len, Type)); + error(Extractor(Bytes, Len, Type)); TypeDatabaseVisitor DBV(Database); error(codeview::visitTypeRecord(Type, Index, DBV)); Index: llvm/test/CMakeLists.txt =================================================================== --- llvm/test/CMakeLists.txt +++ llvm/test/CMakeLists.txt @@ -61,7 +61,7 @@ llvm-nm llvm-objdump llvm-opt-report - llvm-pdbdump + llvm-pdbutil llvm-profdata llvm-ranlib llvm-readobj Index: llvm/test/DebugInfo/PDB/DIA/pdbdump-flags.test =================================================================== --- llvm/test/DebugInfo/PDB/DIA/pdbdump-flags.test +++ llvm/test/DebugInfo/PDB/DIA/pdbdump-flags.test @@ -1,7 +1,7 @@ -; RUN: llvm-pdbdump pretty %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=NO_ARGS -; RUN: llvm-pdbdump pretty -types %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=TYPES -; RUN: llvm-pdbdump pretty -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=COMPILANDS -; RUN: llvm-pdbdump pretty -types -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=MULTIPLE +; RUN: llvm-pdbutil pretty %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=NO_ARGS +; RUN: llvm-pdbutil pretty -types %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=TYPES +; RUN: llvm-pdbutil pretty -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=COMPILANDS +; RUN: llvm-pdbutil pretty -types -compilands %p/../Inputs/empty.pdb | FileCheck %s -check-prefix=MULTIPLE ; Check that neither symbols nor compilands are dumped when neither argument specified. ; NO_ARGS: empty.pdb Index: llvm/test/DebugInfo/PDB/DIA/pdbdump-linenumbers.test =================================================================== --- llvm/test/DebugInfo/PDB/DIA/pdbdump-linenumbers.test +++ llvm/test/DebugInfo/PDB/DIA/pdbdump-linenumbers.test @@ -1,5 +1,5 @@ -; RUN: llvm-pdbdump pretty -lines %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=LINE_NUMS_FPO %s -; RUN: llvm-pdbdump pretty -lines %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=LINE_NUMS %s +; RUN: llvm-pdbutil pretty -lines %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=LINE_NUMS_FPO %s +; RUN: llvm-pdbutil pretty -lines %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=LINE_NUMS %s ; LINE_NUMS_FPO: llvm\test\debuginfo\pdb\inputs\symbolformat-fpo.cpp ; LINE_NUMS_FPO: Line 5, Address: [0x000011a0 - 0x000011a5] (6 bytes) Index: llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test =================================================================== --- llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test +++ llvm/test/DebugInfo/PDB/DIA/pdbdump-symbol-format.test @@ -1,11 +1,11 @@ -; RUN: llvm-pdbdump pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT_FPO %s -; RUN: llvm-pdbdump pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s -; RUN: llvm-pdbdump pretty -types %p/../Inputs/symbolformat.pdb > %t.types +; RUN: llvm-pdbutil pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT_FPO %s +; RUN: llvm-pdbutil pretty -module-syms %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=SYM_FORMAT %s +; RUN: llvm-pdbutil pretty -types %p/../Inputs/symbolformat.pdb > %t.types ; RUN: FileCheck --check-prefix=TYPES_FORMAT %s < %t.types ; RUN: FileCheck --check-prefix=TYPES_1 %s < %t.types ; RUN: FileCheck --check-prefix=TYPES_2 %s < %t.types -; RUN: llvm-pdbdump pretty -types %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=TYPES_FORMAT %s -; RUN: llvm-pdbdump pretty -globals %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=GLOBALS %s +; RUN: llvm-pdbutil pretty -types %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=TYPES_FORMAT %s +; RUN: llvm-pdbutil pretty -globals %p/../Inputs/symbolformat.pdb | FileCheck --check-prefix=GLOBALS %s ; The format is func [0x+ - 0x-] ; SYM_FORMAT_FPO: ---SYMBOLS--- Index: llvm/test/DebugInfo/PDB/Native/pdb-native-compilands.test =================================================================== --- llvm/test/DebugInfo/PDB/Native/pdb-native-compilands.test +++ llvm/test/DebugInfo/PDB/Native/pdb-native-compilands.test @@ -1,7 +1,7 @@ ; Test that the native PDB reader can enumerate the compilands. -; RUN: llvm-pdbdump pretty -native -compilands %p/../Inputs/empty.pdb \ +; RUN: llvm-pdbutil pretty -native -compilands %p/../Inputs/empty.pdb \ ; RUN: | FileCheck -check-prefix=EMPTY %s -; RUN: llvm-pdbdump pretty -native -compilands %p/../Inputs/big-read.pdb \ +; RUN: llvm-pdbutil pretty -native -compilands %p/../Inputs/big-read.pdb \ ; RUN: | FileCheck -check-prefix=BIGREAD %s ; Reference output was generated with the DIA reader to ensure that the Index: llvm/test/DebugInfo/PDB/Native/pdb-native-summary.test =================================================================== --- llvm/test/DebugInfo/PDB/Native/pdb-native-summary.test +++ llvm/test/DebugInfo/PDB/Native/pdb-native-summary.test @@ -1,5 +1,5 @@ ; Test that the native PDB reader gets the PDB summary correct. -; RUN: llvm-pdbdump pretty -native -color-output=false %p/../Inputs/empty.pdb \ +; RUN: llvm-pdbutil pretty -native -color-output=false %p/../Inputs/empty.pdb \ ; RUN: | FileCheck -check-prefix=EMPTY %s ; Reference output was generated with the DIA reader to ensure that the Index: llvm/test/DebugInfo/PDB/pdb-longname-truncation.test =================================================================== --- llvm/test/DebugInfo/PDB/pdb-longname-truncation.test +++ llvm/test/DebugInfo/PDB/pdb-longname-truncation.test @@ -1,3 +1,3 @@ -; For now just verify that this doesn't cause an error. Later we pdbdump can -; do type lookup, we can verify that the name matches what we expect. -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/longname-truncation.yaml +; For now just verify that this doesn't cause an error. Later we pdbdump can +; do type lookup, we can verify that the name matches what we expect. +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/longname-truncation.yaml Index: llvm/test/DebugInfo/PDB/pdb-minimal-construct.test =================================================================== --- llvm/test/DebugInfo/PDB/pdb-minimal-construct.test +++ llvm/test/DebugInfo/PDB/pdb-minimal-construct.test @@ -6,6 +6,6 @@ ; resulting PDB to go back to yaml, and verify that the resulting yaml ; is identical. -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml -; RUN: llvm-pdbdump pdb2yaml -minimal -module-syms -no-file-headers %t.pdb > %t.pdb.yaml +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/one-symbol.yaml +; RUN: llvm-pdbutil pdb2yaml -minimal -module-syms -no-file-headers %t.pdb > %t.pdb.yaml ; RUN: diff -b %p/Inputs/one-symbol.yaml %t.pdb.yaml Index: llvm/test/DebugInfo/PDB/pdb-yaml-symbols.test =================================================================== --- llvm/test/DebugInfo/PDB/pdb-yaml-symbols.test +++ llvm/test/DebugInfo/PDB/pdb-yaml-symbols.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pdb2yaml -module-syms %p/Inputs/empty.pdb \ +; RUN: llvm-pdbutil pdb2yaml -module-syms %p/Inputs/empty.pdb \ ; RUN: | FileCheck -check-prefix=YAML %s Index: llvm/test/DebugInfo/PDB/pdb-yaml-types.test =================================================================== --- llvm/test/DebugInfo/PDB/pdb-yaml-types.test +++ llvm/test/DebugInfo/PDB/pdb-yaml-types.test @@ -1,7 +1,7 @@ -RUN: llvm-pdbdump pdb2yaml -tpi-stream %p/Inputs/big-read.pdb > %t.yaml +RUN: llvm-pdbutil pdb2yaml -tpi-stream %p/Inputs/big-read.pdb > %t.yaml RUN: FileCheck -check-prefix=YAML %s < %t.yaml -RUN: llvm-pdbdump yaml2pdb %t.yaml -pdb %t.pdb -RUN: llvm-pdbdump raw -tpi-records %t.pdb | FileCheck %s --check-prefix=PDB +RUN: llvm-pdbutil yaml2pdb %t.yaml -pdb %t.pdb +RUN: llvm-pdbutil raw -tpi-records %t.pdb | FileCheck %s --check-prefix=PDB Only verify the beginning of the type stream. Index: llvm/test/DebugInfo/PDB/pdbdump-debug-subsections.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-debug-subsections.test +++ llvm/test/DebugInfo/PDB/pdbdump-debug-subsections.test @@ -1,6 +1,6 @@ -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.pdb %p/Inputs/debug-subsections.yaml -; RUN: llvm-pdbdump pdb2yaml -all -no-file-headers %t.pdb | FileCheck --check-prefix=YAML %s -; RUN: llvm-pdbdump raw -subsections=all %t.pdb | FileCheck --check-prefix=RAW %s +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/debug-subsections.yaml +; RUN: llvm-pdbutil pdb2yaml -all -no-file-headers %t.pdb | FileCheck --check-prefix=YAML %s +; RUN: llvm-pdbutil raw -subsections=all %t.pdb | FileCheck --check-prefix=RAW %s YAML: Modules: YAML-NEXT: - Module: Foo.obj Index: llvm/test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-headers.test +++ llvm/test/DebugInfo/PDB/pdbdump-headers.test @@ -1,12 +1,12 @@ -; RUN: llvm-pdbdump raw -headers -string-table -tpi-records -tpi-record-bytes -module-syms \ +; RUN: llvm-pdbutil raw -headers -string-table -tpi-records -tpi-record-bytes -module-syms \ ; RUN: -sym-record-bytes -globals -publics -module-files \ ; RUN: -stream-summary -stream-blocks -ipi-records -ipi-record-bytes \ ; RUN: -section-contribs -section-map -section-headers -subsections=all \ ; RUN: -tpi-hash -fpo -page-stats %p/Inputs/empty.pdb | FileCheck -check-prefix=EMPTY %s -; RUN: llvm-pdbdump raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s -; RUN: llvm-pdbdump raw -headers -modules -module-files \ +; RUN: llvm-pdbutil raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s +; RUN: llvm-pdbutil raw -headers -modules -module-files \ ; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s -; RUN: not llvm-pdbdump raw -headers %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s +; RUN: not llvm-pdbutil raw -headers %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s ; EMPTY: FileHeaders { ; EMPTY-NEXT: BlockSize: 4096 Index: llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test +++ llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test @@ -1,12 +1,12 @@ -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml -; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s -; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s -; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s -; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml +; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s +; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s +; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s +; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s TPI-TYPES: Type Info Stream (TPI) TPI-TYPES: Record count: 9 Index: llvm/test/DebugInfo/PDB/pdbdump-mergeids.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-mergeids.test +++ llvm/test/DebugInfo/PDB/pdbdump-mergeids.test @@ -1,9 +1,9 @@ -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml -; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s -; RUN: llvm-pdbdump raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml +; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s +; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s MERGED: Type Info Stream (IPI) Index: llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test +++ llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test @@ -1,24 +1,24 @@ -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml -; RUN: llvm-pdbdump merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s -; RUN: llvm-pdbdump raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s - - -MERGED: Type Info Stream (TPI) -MERGED: Record count: 9 -MERGED-DAG: PointeeType: unsigned -MERGED-DAG: PointeeType: unsigned* -MERGED-DAG: PointeeType: unsigned** -MERGED-DAG: PointeeType: __int64 -MERGED-DAG: PointeeType: __int64* -MERGED-DAG: Name: OnlyInMerge1 -MERGED-DAG: Name: OnlyInMerge2 -MERGED-DAG: TypeLeafKind: LF_ARGLIST - -ARGLIST: TypeLeafKind: LF_ARGLIST -ARGLIST-NEXT: NumArgs: 3 -ARGLIST-NEXT: Arguments [ -ARGLIST-NEXT: ArgType: unsigned -ARGLIST-NEXT: ArgType: unsigned* -ARGLIST-NEXT: ArgType: unsigned** +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml +; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s +; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s + + +MERGED: Type Info Stream (TPI) +MERGED: Record count: 9 +MERGED-DAG: PointeeType: unsigned +MERGED-DAG: PointeeType: unsigned* +MERGED-DAG: PointeeType: unsigned** +MERGED-DAG: PointeeType: __int64 +MERGED-DAG: PointeeType: __int64* +MERGED-DAG: Name: OnlyInMerge1 +MERGED-DAG: Name: OnlyInMerge2 +MERGED-DAG: TypeLeafKind: LF_ARGLIST + +ARGLIST: TypeLeafKind: LF_ARGLIST +ARGLIST-NEXT: NumArgs: 3 +ARGLIST-NEXT: Arguments [ +ARGLIST-NEXT: ArgType: unsigned +ARGLIST-NEXT: ArgType: unsigned* +ARGLIST-NEXT: ArgType: unsigned** Index: llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test +++ llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test @@ -1,35 +1,35 @@ -; RUN: llvm-pdbdump raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s -; RUN: llvm-pdbdump raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s -; RUN: not llvm-pdbdump raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s -; RUN: not llvm-pdbdump raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s -; RUN: not llvm-pdbdump raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s - -BLOCK0: Block Data { -BLOCK0-NEXT: Block 0 ( -BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | -BLOCK0-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| -BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| -BLOCK0-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| -BLOCK0: 0FE0: 00000000 00000000 00000000 00000000 |................| -BLOCK0-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| -BLOCK0-NEXT: ) -BLOCK0-NEXT: } - -BLOCK01: Block Data { -BLOCK01-NEXT: Block 0 ( -BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | -BLOCK01-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| -BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| -BLOCK01-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| -BLOCK01: 0FE0: 00000000 00000000 00000000 00000000 |................| -BLOCK01-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| -BLOCK01-NEXT: ) -BLOCK01-NEXT: Block 1 ( -BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: 0010: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01: 0FE0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: 0FF0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -BLOCK01-NEXT: ) -BLOCK01-NEXT: } - -BADSYNTAX: Argument '{{.*}}' invalid format. +; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s +; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s +; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s +; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s +; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s + +BLOCK0: Block Data { +BLOCK0-NEXT: Block 0 ( +BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | +BLOCK0-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| +BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| +BLOCK0-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| +BLOCK0: 0FE0: 00000000 00000000 00000000 00000000 |................| +BLOCK0-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| +BLOCK0-NEXT: ) +BLOCK0-NEXT: } + +BLOCK01: Block Data { +BLOCK01-NEXT: Block 0 ( +BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ | +BLOCK01-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...| +BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 |................| +BLOCK01-NEXT: 0030: 00000000 18000000 00000000 00000000 |................| +BLOCK01: 0FE0: 00000000 00000000 00000000 00000000 |................| +BLOCK01-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................| +BLOCK01-NEXT: ) +BLOCK01-NEXT: Block 1 ( +BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +BLOCK01-NEXT: 0010: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +BLOCK01: 0FE0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +BLOCK01-NEXT: 0FF0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +BLOCK01-NEXT: ) +BLOCK01-NEXT: } + +BADSYNTAX: Argument '{{.*}}' invalid format. Index: llvm/test/DebugInfo/PDB/pdbdump-raw-stream.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-raw-stream.test +++ llvm/test/DebugInfo/PDB/pdbdump-raw-stream.test @@ -1,23 +1,23 @@ -; RUN: llvm-pdbdump raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM1 %s -; RUN: not llvm-pdbdump raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s - -STREAM1: Stream Data { -STREAM1-NEXT: Stream { -STREAM1-NEXT: Index: 1 -STREAM1-NEXT: Type: PDB Stream -STREAM1-NEXT: Size: 118 -STREAM1-NEXT: Blocks: [19] -STREAM1-NEXT: Data ( -STREAM1-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 |..1....T.....5VA| -STREAM1-NEXT: 0010: 86A0A249 896F9988 FAE52FF0 22000000 |...I.o..../."...| -STREAM1-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 |/LinkInfo./names| -STREAM1-NEXT: 0030: 002F7372 632F6865 61646572 626C6F63 |./src/headerbloc| -STREAM1-NEXT: 0040: 6B000300 00000600 00000100 00001A00 |k...............| -STREAM1-NEXT: 0050: 00000000 00001100 00000900 00000A00 |................| -STREAM1-NEXT: 0060: 00000D00 00000000 00000500 00000000 |................| -STREAM1-NEXT: 0070: 00004191 3201 |..A.2.| -STREAM1-NEXT: ) -STREAM1-NEXT: } -STREAM1-NEXT: } - -INVALIDSTREAM: Native PDB Error: The specified stream could not be loaded. +; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM1 %s +; RUN: not llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s + +STREAM1: Stream Data { +STREAM1-NEXT: Stream { +STREAM1-NEXT: Index: 1 +STREAM1-NEXT: Type: PDB Stream +STREAM1-NEXT: Size: 118 +STREAM1-NEXT: Blocks: [19] +STREAM1-NEXT: Data ( +STREAM1-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 |..1....T.....5VA| +STREAM1-NEXT: 0010: 86A0A249 896F9988 FAE52FF0 22000000 |...I.o..../."...| +STREAM1-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 |/LinkInfo./names| +STREAM1-NEXT: 0030: 002F7372 632F6865 61646572 626C6F63 |./src/headerbloc| +STREAM1-NEXT: 0040: 6B000300 00000600 00000100 00001A00 |k...............| +STREAM1-NEXT: 0050: 00000000 00001100 00000900 00000A00 |................| +STREAM1-NEXT: 0060: 00000D00 00000000 00000500 00000000 |................| +STREAM1-NEXT: 0070: 00004191 3201 |..A.2.| +STREAM1-NEXT: ) +STREAM1-NEXT: } +STREAM1-NEXT: } + +INVALIDSTREAM: Native PDB Error: The specified stream could not be loaded. Index: llvm/test/DebugInfo/PDB/pdbdump-readwrite.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-readwrite.test +++ llvm/test/DebugInfo/PDB/pdbdump-readwrite.test @@ -1,10 +1,10 @@ -RUN: llvm-pdbdump pdb2yaml -modules -module-files -dbi-stream \ +RUN: llvm-pdbutil pdb2yaml -modules -module-files -dbi-stream \ RUN: -pdb-stream -string-table -tpi-stream -stream-directory \ RUN: -stream-metadata %p/Inputs/empty.pdb > %t.1 -RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1 +RUN: llvm-pdbutil yaml2pdb -pdb=%t.2 %t.1 -RUN: llvm-pdbdump raw -headers -string-table -tpi-records %p/Inputs/empty.pdb | FileCheck %s -RUN: llvm-pdbdump raw -headers -string-table -tpi-records %t.2 | FileCheck %s +RUN: llvm-pdbutil raw -headers -string-table -tpi-records %p/Inputs/empty.pdb | FileCheck %s +RUN: llvm-pdbutil raw -headers -string-table -tpi-records %t.2 | FileCheck %s CHECK: FileHeaders { CHECK-NEXT: BlockSize: 4096 Index: llvm/test/DebugInfo/PDB/pdbdump-source-names.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-source-names.test +++ llvm/test/DebugInfo/PDB/pdbdump-source-names.test @@ -6,11 +6,11 @@ # that differ by one byte, so that at least one of those will only # pass if alignment is implemented correctly. -RUN: llvm-pdbdump yaml2pdb -pdb=%T/source-names-1.pdb %p/Inputs/source-names-1.yaml -RUN: llvm-pdbdump pdb2yaml -module-files %T/source-names-1.pdb \ +RUN: llvm-pdbutil yaml2pdb -pdb=%T/source-names-1.pdb %p/Inputs/source-names-1.yaml +RUN: llvm-pdbutil pdb2yaml -module-files %T/source-names-1.pdb \ RUN: | FileCheck -check-prefix=CHECK1 %s -RUN: llvm-pdbdump yaml2pdb -pdb=%T/source-names-2.pdb %p/Inputs/source-names-2.yaml -RUN: llvm-pdbdump pdb2yaml -module-files %T/source-names-2.pdb \ +RUN: llvm-pdbutil yaml2pdb -pdb=%T/source-names-2.pdb %p/Inputs/source-names-2.yaml +RUN: llvm-pdbutil pdb2yaml -module-files %T/source-names-2.pdb \ RUN: | FileCheck -check-prefix=CHECK2 %s CHECK1: SourceFiles: Index: llvm/test/DebugInfo/PDB/pdbdump-write.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-write.test +++ llvm/test/DebugInfo/PDB/pdbdump-write.test @@ -10,11 +10,11 @@ ; stream metadata, since the layout of the MSF file might be different ; (for example if we don't write the entire stream) ; -; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory \ +; RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory \ ; RUN: -pdb-stream -tpi-stream -module-syms %p/Inputs/empty.pdb > %t.1 -; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1 -; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \ +; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2 %t.1 +; RUN: llvm-pdbutil pdb2yaml -pdb-stream -tpi-stream \ ; RUN: -module-syms -no-file-headers %p/Inputs/empty.pdb > %t.3 -; RUN: llvm-pdbdump pdb2yaml -pdb-stream -tpi-stream \ +; RUN: llvm-pdbutil pdb2yaml -pdb-stream -tpi-stream \ ; RUN: -module-syms -no-file-headers %t.2 > %t.4 ; RUN: diff %t.3 %t.4 Index: llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test +++ llvm/test/DebugInfo/PDB/pdbdump-yaml-types.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pdb2yaml -tpi-stream %p/Inputs/empty.pdb \ +; RUN: llvm-pdbutil pdb2yaml -tpi-stream %p/Inputs/empty.pdb \ ; RUN: | FileCheck -check-prefix=YAML %s YAML: --- Index: llvm/test/DebugInfo/PDB/pdbdump-yaml.test =================================================================== --- llvm/test/DebugInfo/PDB/pdbdump-yaml.test +++ llvm/test/DebugInfo/PDB/pdbdump-yaml.test @@ -1,6 +1,6 @@ -; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -string-table -pdb-stream \ +; RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -string-table -pdb-stream \ ; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=YAML %s -; RUN: llvm-pdbdump pdb2yaml -no-file-headers -stream-metadata -stream-directory -pdb-stream \ +; RUN: llvm-pdbutil pdb2yaml -no-file-headers -stream-metadata -stream-directory -pdb-stream \ ; RUN: %p/Inputs/empty.pdb | FileCheck -check-prefix=NO-HEADERS %s ; YAML: --- Index: llvm/test/tools/llvm-pdbdump/class-layout.test =================================================================== --- llvm/test/tools/llvm-pdbdump/class-layout.test +++ llvm/test/tools/llvm-pdbdump/class-layout.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pretty -all -class-recurse-depth=1 \ +; RUN: llvm-pdbutil pretty -all -class-recurse-depth=1 \ ; RUN: %p/Inputs/ClassLayoutTest.pdb > %t ; RUN: FileCheck -input-file=%t %s -check-prefix=GLOBALS_TEST ; RUN: FileCheck -input-file=%t %s -check-prefix=MEMBERS_TEST Index: llvm/test/tools/llvm-pdbdump/complex-padding-graphical.test =================================================================== --- llvm/test/tools/llvm-pdbdump/complex-padding-graphical.test +++ llvm/test/tools/llvm-pdbdump/complex-padding-graphical.test @@ -1,53 +1,53 @@ -; RUN: llvm-pdbdump pretty -classes -class-definitions=layout \ -; RUN: -include-types=Test %p/Inputs/ComplexPaddingTest.pdb > %t - -; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_ONLY -; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_AND_NON_VB -; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_VB -; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_AND_DIRECT_VB - - -; DIRECT_VB_ONLY: struct TestIVBBase [sizeof = 16] -; DIRECT_VB_ONLY-NEXT: : public virtual TestVB { -; DIRECT_VB_ONLY-NEXT: vbptr +0x00 [sizeof=4] -; DIRECT_VB_ONLY-NEXT: data +0x04 [sizeof=4] int A -; DIRECT_VB_ONLY-NEXT: vbase +0x08 [sizeof=8] TestVB -; DIRECT_VB_ONLY-NEXT: vfptr +0x08 [sizeof=4] -; DIRECT_VB_ONLY-NEXT: data +0x0c [sizeof=4] int X -; DIRECT_VB_ONLY-NEXT: } - -DIRECT_VB_AND_NON_VB: struct TestVBLayout [sizeof = 24] -DIRECT_VB_AND_NON_VB-NEXT: : public TestNVB -DIRECT_VB_AND_NON_VB-NEXT: , public virtual TestVB { -DIRECT_VB_AND_NON_VB-NEXT: base +0x00 [sizeof=8] TestNVB -DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x00 [sizeof=4] -DIRECT_VB_AND_NON_VB-NEXT: data +0x04 [sizeof=4] int Y -DIRECT_VB_AND_NON_VB-NEXT: vbptr +0x08 [sizeof=4] -DIRECT_VB_AND_NON_VB-NEXT: data +0x0c [sizeof=4] int Z -DIRECT_VB_AND_NON_VB-NEXT: vbase +0x10 [sizeof=8] TestVB -DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x10 [sizeof=4] -DIRECT_VB_AND_NON_VB-NEXT: data +0x14 [sizeof=4] int X -DIRECT_VB_AND_NON_VB-NEXT: } - -INDIRECT_VB: struct TestIVBDerived [sizeof = 20] -INDIRECT_VB-NEXT: : public TestIVBBase { -INDIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase -INDIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] -INDIRECT_VB-NEXT: data +0x04 [sizeof=4] int A -INDIRECT_VB-NEXT: data +0x08 [sizeof=4] int B -INDIRECT_VB-NEXT: ivbase +0x0c [sizeof=8] TestVB -INDIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] -INDIRECT_VB-NEXT: data +0x10 [sizeof=4] int X -INDIRECT_VB-NEXT: } - -INDIRECT_AND_DIRECT_VB: struct TestIVBMergedDerived [sizeof = 20] -INDIRECT_AND_DIRECT_VB-NEXT: : public TestIVBBase -INDIRECT_AND_DIRECT_VB-NEXT: , public virtual TestVB { -INDIRECT_AND_DIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase -INDIRECT_AND_DIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] -INDIRECT_AND_DIRECT_VB-NEXT: data +0x04 [sizeof=4] int A -INDIRECT_AND_DIRECT_VB-NEXT: data +0x08 [sizeof=4] int B -INDIRECT_AND_DIRECT_VB-NEXT: vbase +0x0c [sizeof=8] TestVB -INDIRECT_AND_DIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] -INDIRECT_AND_DIRECT_VB-NEXT: data +0x10 [sizeof=4] int X -INDIRECT_AND_DIRECT_VB-NEXT: } +; RUN: llvm-pdbutil pretty -classes -class-definitions=layout \ +; RUN: -include-types=Test %p/Inputs/ComplexPaddingTest.pdb > %t + +; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_ONLY +; RUN: FileCheck -input-file=%t %s -check-prefix=DIRECT_VB_AND_NON_VB +; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_VB +; RUN: FileCheck -input-file=%t %s -check-prefix=INDIRECT_AND_DIRECT_VB + + +; DIRECT_VB_ONLY: struct TestIVBBase [sizeof = 16] +; DIRECT_VB_ONLY-NEXT: : public virtual TestVB { +; DIRECT_VB_ONLY-NEXT: vbptr +0x00 [sizeof=4] +; DIRECT_VB_ONLY-NEXT: data +0x04 [sizeof=4] int A +; DIRECT_VB_ONLY-NEXT: vbase +0x08 [sizeof=8] TestVB +; DIRECT_VB_ONLY-NEXT: vfptr +0x08 [sizeof=4] +; DIRECT_VB_ONLY-NEXT: data +0x0c [sizeof=4] int X +; DIRECT_VB_ONLY-NEXT: } + +DIRECT_VB_AND_NON_VB: struct TestVBLayout [sizeof = 24] +DIRECT_VB_AND_NON_VB-NEXT: : public TestNVB +DIRECT_VB_AND_NON_VB-NEXT: , public virtual TestVB { +DIRECT_VB_AND_NON_VB-NEXT: base +0x00 [sizeof=8] TestNVB +DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x00 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x04 [sizeof=4] int Y +DIRECT_VB_AND_NON_VB-NEXT: vbptr +0x08 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x0c [sizeof=4] int Z +DIRECT_VB_AND_NON_VB-NEXT: vbase +0x10 [sizeof=8] TestVB +DIRECT_VB_AND_NON_VB-NEXT: vfptr +0x10 [sizeof=4] +DIRECT_VB_AND_NON_VB-NEXT: data +0x14 [sizeof=4] int X +DIRECT_VB_AND_NON_VB-NEXT: } + +INDIRECT_VB: struct TestIVBDerived [sizeof = 20] +INDIRECT_VB-NEXT: : public TestIVBBase { +INDIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase +INDIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] +INDIRECT_VB-NEXT: data +0x04 [sizeof=4] int A +INDIRECT_VB-NEXT: data +0x08 [sizeof=4] int B +INDIRECT_VB-NEXT: ivbase +0x0c [sizeof=8] TestVB +INDIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] +INDIRECT_VB-NEXT: data +0x10 [sizeof=4] int X +INDIRECT_VB-NEXT: } + +INDIRECT_AND_DIRECT_VB: struct TestIVBMergedDerived [sizeof = 20] +INDIRECT_AND_DIRECT_VB-NEXT: : public TestIVBBase +INDIRECT_AND_DIRECT_VB-NEXT: , public virtual TestVB { +INDIRECT_AND_DIRECT_VB-NEXT: base +0x00 [sizeof=8] TestIVBBase +INDIRECT_AND_DIRECT_VB-NEXT: vbptr +0x00 [sizeof=4] +INDIRECT_AND_DIRECT_VB-NEXT: data +0x04 [sizeof=4] int A +INDIRECT_AND_DIRECT_VB-NEXT: data +0x08 [sizeof=4] int B +INDIRECT_AND_DIRECT_VB-NEXT: vbase +0x0c [sizeof=8] TestVB +INDIRECT_AND_DIRECT_VB-NEXT: vfptr +0x0c [sizeof=4] +INDIRECT_AND_DIRECT_VB-NEXT: data +0x10 [sizeof=4] int X +INDIRECT_AND_DIRECT_VB-NEXT: } Index: llvm/test/tools/llvm-pdbdump/enum-layout.test =================================================================== --- llvm/test/tools/llvm-pdbdump/enum-layout.test +++ llvm/test/tools/llvm-pdbdump/enum-layout.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pretty -types %p/Inputs/ClassLayoutTest.pdb > %t +; RUN: llvm-pdbutil pretty -types %p/Inputs/ClassLayoutTest.pdb > %t ; RUN: FileCheck -input-file=%t %s -check-prefix=GLOBAL_ENUM ; RUN: FileCheck -input-file=%t %s -check-prefix=MEMBER_ENUM Index: llvm/test/tools/llvm-pdbdump/load-address.test =================================================================== --- llvm/test/tools/llvm-pdbdump/load-address.test +++ llvm/test/tools/llvm-pdbdump/load-address.test @@ -1,6 +1,6 @@ -; RUN: llvm-pdbdump pretty -externals %p/Inputs/LoadAddressTest.pdb \ +; RUN: llvm-pdbutil pretty -externals %p/Inputs/LoadAddressTest.pdb \ ; RUN: | FileCheck --check-prefix=RVA %s -; RUN: llvm-pdbdump pretty -externals -load-address=0x40000000 \ +; RUN: llvm-pdbutil pretty -externals -load-address=0x40000000 \ ; RUN: %p/Inputs/LoadAddressTest.pdb | FileCheck --check-prefix=VA %s ; RVA: ---EXTERNALS--- Index: llvm/test/tools/llvm-pdbdump/raw-stream-data.test =================================================================== --- llvm/test/tools/llvm-pdbdump/raw-stream-data.test +++ llvm/test/tools/llvm-pdbdump/raw-stream-data.test @@ -1,47 +1,47 @@ -; RUN: llvm-pdbdump raw -stream-data=8 %p/Inputs/LoadAddressTest.pdb \ -; RUN: | FileCheck %s -check-prefix=FULL_STREAM -; RUN: llvm-pdbdump raw -stream-data=8:4 %p/Inputs/LoadAddressTest.pdb \ -; RUN: | FileCheck %s -check-prefix=OFFSET_STREAM -; RUN: llvm-pdbdump raw -stream-data=8:4@24 %p/Inputs/LoadAddressTest.pdb \ -; RUN: | FileCheck %s -check-prefix=OFFSET_AND_LENGTH - -FULL_STREAM: Stream Data { -FULL_STREAM-NEXT: Stream { -FULL_STREAM-NEXT: Index: 8 -FULL_STREAM-NEXT: Type: Public Symbol Records -FULL_STREAM-NEXT: Size: 40 -FULL_STREAM-NEXT: Blocks: -FULL_STREAM-NEXT: Data ( -FULL_STREAM-NEXT: 0000: 12000E11 02000000 10000000 01005F6D |.............._m| -FULL_STREAM-NEXT: 0010: 61696E00 12002511 00000000 88000000 |ain...%.........| -FULL_STREAM-NEXT: 0020: 01006D61 696E0000 |..main..| -FULL_STREAM-NEXT: ) -FULL_STREAM-NEXT: } -FULL_STREAM-NEXT: } - -OFFSET_STREAM: Stream Data { -OFFSET_STREAM-NEXT: Stream { -OFFSET_STREAM-NEXT: Index: 8 -OFFSET_STREAM-NEXT: Type: Public Symbol Records -OFFSET_STREAM-NEXT: Size: 40 -OFFSET_STREAM-NEXT: Blocks: -OFFSET_STREAM-NEXT: Data ( -OFFSET_STREAM-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| -OFFSET_STREAM-NEXT: 0014: 12002511 00000000 88000000 01006D61 |..%...........ma| -OFFSET_STREAM-NEXT: 0024: 696E0000 |in..| -OFFSET_STREAM-NEXT: ) -OFFSET_STREAM-NEXT: } -OFFSET_STREAM-NEXT:} - -OFFSET_AND_LENGTH: Stream Data { -OFFSET_AND_LENGTH-NEXT: Stream { -OFFSET_AND_LENGTH-NEXT: Index: 8 -OFFSET_AND_LENGTH-NEXT: Type: Public Symbol Records -OFFSET_AND_LENGTH-NEXT: Size: 40 -OFFSET_AND_LENGTH-NEXT: Blocks: -OFFSET_AND_LENGTH-NEXT: Data ( -OFFSET_AND_LENGTH-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| -OFFSET_AND_LENGTH-NEXT: 0014: 12002511 00000000 |..%.....| -OFFSET_AND_LENGTH-NEXT: ) -OFFSET_AND_LENGTH-NEXT: } +; RUN: llvm-pdbutil raw -stream-data=8 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=FULL_STREAM +; RUN: llvm-pdbutil raw -stream-data=8:4 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=OFFSET_STREAM +; RUN: llvm-pdbutil raw -stream-data=8:4@24 %p/Inputs/LoadAddressTest.pdb \ +; RUN: | FileCheck %s -check-prefix=OFFSET_AND_LENGTH + +FULL_STREAM: Stream Data { +FULL_STREAM-NEXT: Stream { +FULL_STREAM-NEXT: Index: 8 +FULL_STREAM-NEXT: Type: Public Symbol Records +FULL_STREAM-NEXT: Size: 40 +FULL_STREAM-NEXT: Blocks: +FULL_STREAM-NEXT: Data ( +FULL_STREAM-NEXT: 0000: 12000E11 02000000 10000000 01005F6D |.............._m| +FULL_STREAM-NEXT: 0010: 61696E00 12002511 00000000 88000000 |ain...%.........| +FULL_STREAM-NEXT: 0020: 01006D61 696E0000 |..main..| +FULL_STREAM-NEXT: ) +FULL_STREAM-NEXT: } +FULL_STREAM-NEXT: } + +OFFSET_STREAM: Stream Data { +OFFSET_STREAM-NEXT: Stream { +OFFSET_STREAM-NEXT: Index: 8 +OFFSET_STREAM-NEXT: Type: Public Symbol Records +OFFSET_STREAM-NEXT: Size: 40 +OFFSET_STREAM-NEXT: Blocks: +OFFSET_STREAM-NEXT: Data ( +OFFSET_STREAM-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| +OFFSET_STREAM-NEXT: 0014: 12002511 00000000 88000000 01006D61 |..%...........ma| +OFFSET_STREAM-NEXT: 0024: 696E0000 |in..| +OFFSET_STREAM-NEXT: ) +OFFSET_STREAM-NEXT: } +OFFSET_STREAM-NEXT:} + +OFFSET_AND_LENGTH: Stream Data { +OFFSET_AND_LENGTH-NEXT: Stream { +OFFSET_AND_LENGTH-NEXT: Index: 8 +OFFSET_AND_LENGTH-NEXT: Type: Public Symbol Records +OFFSET_AND_LENGTH-NEXT: Size: 40 +OFFSET_AND_LENGTH-NEXT: Blocks: +OFFSET_AND_LENGTH-NEXT: Data ( +OFFSET_AND_LENGTH-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.| +OFFSET_AND_LENGTH-NEXT: 0014: 12002511 00000000 |..%.....| +OFFSET_AND_LENGTH-NEXT: ) +OFFSET_AND_LENGTH-NEXT: } OFFSET_AND_LENGTH-NEXT:} \ No newline at end of file Index: llvm/test/tools/llvm-pdbdump/regex-filter.test =================================================================== --- llvm/test/tools/llvm-pdbdump/regex-filter.test +++ llvm/test/tools/llvm-pdbdump/regex-filter.test @@ -1,25 +1,25 @@ -; RUN: llvm-pdbdump pretty -module-syms -globals -types %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -module-syms -globals -types %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=NO_FILTER %s -; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \ +; RUN: llvm-pdbutil pretty -types -exclude-types="GlobalTypedef|NestedTypedef" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s -; RUN: llvm-pdbdump pretty -classes -enums %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -classes -enums %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=EXCLUDE_TYPEDEFS %s -; RUN: llvm-pdbdump pretty -types -exclude-types="GlobalEnum|NestedEnum" \ +; RUN: llvm-pdbutil pretty -types -exclude-types="GlobalEnum|NestedEnum" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_ENUMS %s -; RUN: llvm-pdbdump pretty -classes -typedefs %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -classes -typedefs %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=EXCLUDE_ENUMS %s -; RUN: llvm-pdbdump pretty -types -module-syms -globals -exclude-symbols="MemberVar|GlobalVar" \ +; RUN: llvm-pdbutil pretty -types -module-syms -globals -exclude-symbols="MemberVar|GlobalVar" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_VARS %s -; RUN: llvm-pdbdump pretty -types -exclude-types="FilterTestClass" \ +; RUN: llvm-pdbutil pretty -types -exclude-types="FilterTestClass" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_WHOLE_CLASS %s -; RUN: llvm-pdbdump pretty -module-syms -globals -exclude-compilands="FilterTest.obj" \ +; RUN: llvm-pdbutil pretty -module-syms -globals -exclude-compilands="FilterTest.obj" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=EXCLUDE_COMPILAND %s -; RUN: llvm-pdbdump pretty -types -include-types="FilterTestClass" \ +; RUN: llvm-pdbutil pretty -types -include-types="FilterTestClass" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_TYPES %s -; RUN: llvm-pdbdump pretty -types -module-syms -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \ +; RUN: llvm-pdbutil pretty -types -module-syms -globals -include-symbols="[[:<:]](IntGlobalVar|DoubleGlobalVar)[[:>:]]" \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=INCLUDE_ONLY_VARS %s ; NO_FILTER: ---TYPES--- Index: llvm/test/tools/llvm-pdbdump/simple-padding-graphical.test =================================================================== --- llvm/test/tools/llvm-pdbdump/simple-padding-graphical.test +++ llvm/test/tools/llvm-pdbdump/simple-padding-graphical.test @@ -1,4 +1,4 @@ -; RUN: llvm-pdbdump pretty -classes -class-definitions=layout \ +; RUN: llvm-pdbutil pretty -classes -class-definitions=layout \ ; RUN: -include-types=SimplePad %p/Inputs/SimplePaddingTest.pdb > %t ; RUN: FileCheck -input-file=%t %s -check-prefix=NO_PADDING Index: llvm/test/tools/llvm-pdbdump/symbol-filters.test =================================================================== --- llvm/test/tools/llvm-pdbdump/symbol-filters.test +++ llvm/test/tools/llvm-pdbdump/symbol-filters.test @@ -1,25 +1,25 @@ -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=data %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=ONLY_DATA %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=thunks %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=thunks %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=ONLY_THUNKS %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs %p/Inputs/FilterTest.pdb \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=funcs %p/Inputs/FilterTest.pdb \ ; RUN: | FileCheck --check-prefix=ONLY_FUNCS %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs -sym-types=data \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=funcs -sym-types=data \ ; RUN: %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=TWO_TYPES %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=data \ ; RUN: -symbol-order=name %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=NAME_SORT_DATA %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=data \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=data \ ; RUN: -symbol-order=size %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=SIZE_SORT_DATA %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=funcs \ ; RUN: -symbol-order=name %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=NAME_SORT_FUNCS %s -; RUN: llvm-pdbdump pretty -globals -module-syms -sym-types=funcs \ +; RUN: llvm-pdbutil pretty -globals -module-syms -sym-types=funcs \ ; RUN: -symbol-order=size %p/Inputs/FilterTest.pdb | FileCheck --check-prefix=SIZE_SORT_FUNCS %s ; ONLY_DATA-NOT: func Index: llvm/tools/LLVMBuild.txt =================================================================== --- llvm/tools/LLVMBuild.txt +++ llvm/tools/LLVMBuild.txt @@ -40,7 +40,7 @@ llvm-modextract llvm-nm llvm-objdump - llvm-pdbdump + llvm-pdbutil llvm-profdata llvm-rtdyld llvm-size Index: llvm/tools/llvm-pdbdump/Analyze.h =================================================================== --- llvm/tools/llvm-pdbdump/Analyze.h +++ /dev/null @@ -1,30 +0,0 @@ -//===- Analyze.h - PDB analysis functions -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H -#define LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H - -#include "OutputStyle.h" - -namespace llvm { -namespace pdb { -class PDBFile; -class AnalysisStyle : public OutputStyle { -public: - explicit AnalysisStyle(PDBFile &File); - - Error dump() override; - -private: - PDBFile &File; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/Analyze.cpp =================================================================== --- llvm/tools/llvm-pdbdump/Analyze.cpp +++ /dev/null @@ -1,152 +0,0 @@ -//===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Analyze.h" - -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" - -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" - -#include - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -static StringRef getLeafTypeName(TypeLeafKind LT) { - switch (LT) { -#define TYPE_RECORD(ename, value, name) \ - case ename: \ - return #name; -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" - default: - break; - } - return "UnknownLeaf"; -} - -namespace { -struct HashLookupVisitor : public TypeVisitorCallbacks { - struct Entry { - TypeIndex TI; - CVType Record; - }; - - explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {} - - Error visitTypeBegin(CVType &Record) override { - uint32_t H = Tpi.getHashValues()[I]; - Record.Hash = H; - TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex); - Lookup[H].push_back(Entry{TI, Record}); - ++I; - return Error::success(); - } - - uint32_t I = 0; - DenseMap> Lookup; - TpiStream &Tpi; -}; -} - -AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {} - -Error AnalysisStyle::dump() { - auto Tpi = File.getPDBTpiStream(); - if (!Tpi) - return Tpi.takeError(); - - TypeDatabase TypeDB(Tpi->getNumTypeRecords()); - TypeDatabaseVisitor DBV(TypeDB); - TypeVisitorCallbackPipeline Pipeline; - HashLookupVisitor Hasher(*Tpi); - // Add them to the database - Pipeline.addCallbackToPipeline(DBV); - // Store their hash values - Pipeline.addCallbackToPipeline(Hasher); - - if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline)) - return EC; - - auto &Adjusters = Tpi->getHashAdjusters(); - DenseSet AdjusterSet; - for (const auto &Adj : Adjusters) { - assert(AdjusterSet.find(Adj.second) == AdjusterSet.end()); - AdjusterSet.insert(Adj.second); - } - - uint32_t Count = 0; - outs() << "Searching for hash collisions\n"; - for (const auto &H : Hasher.Lookup) { - if (H.second.size() <= 1) - continue; - ++Count; - outs() << formatv("Hash: {0}, Count: {1} records\n", H.first, - H.second.size()); - for (const auto &R : H.second) { - auto Iter = AdjusterSet.find(R.TI.getIndex()); - StringRef Prefix; - if (Iter != AdjusterSet.end()) { - Prefix = "[HEAD]"; - AdjusterSet.erase(Iter); - } - StringRef LeafName = getLeafTypeName(R.Record.Type); - uint32_t TI = R.TI.getIndex(); - StringRef TypeName = TypeDB.getTypeName(R.TI); - outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, - TypeName); - } - } - - outs() << "\n"; - outs() << "Dumping hash adjustment chains\n"; - for (const auto &A : Tpi->getHashAdjusters()) { - TypeIndex TI(A.second); - StringRef TypeName = TypeDB.getTypeName(TI); - const CVType &HeadRecord = TypeDB.getTypeRecord(TI); - assert(HeadRecord.Hash.hasValue()); - - auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); - if (CollisionsIter == Hasher.Lookup.end()) - continue; - - const auto &Collisions = CollisionsIter->second; - outs() << TypeName << "\n"; - outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second, - getLeafTypeName(HeadRecord.Type), TypeName); - for (const auto &Chain : Collisions) { - if (Chain.TI == TI) - continue; - const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI); - outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), - getLeafTypeName(TailRecord.Type), - TypeDB.getTypeName(Chain.TI)); - } - } - outs() << formatv("There are {0} orphaned hash adjusters\n", - AdjusterSet.size()); - for (const auto &Adj : AdjusterSet) { - outs() << formatv(" {0}\n", Adj); - } - - uint32_t DistinctHashValues = Hasher.Lookup.size(); - outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues); - return Error::success(); -} Index: llvm/tools/llvm-pdbdump/CMakeLists.txt =================================================================== --- llvm/tools/llvm-pdbdump/CMakeLists.txt +++ /dev/null @@ -1,34 +0,0 @@ -set(LLVM_LINK_COMPONENTS - DebugInfoCodeView - DebugInfoMSF - DebugInfoPDB - Object - ObjectYAML - Support - ) - -add_llvm_tool(llvm-pdbdump - Analyze.cpp - CompactTypeDumpVisitor.cpp - Diff.cpp - llvm-pdbdump.cpp - LinePrinter.cpp - LLVMOutputStyle.cpp - PdbYaml.cpp - PrettyBuiltinDumper.cpp - PrettyClassDefinitionDumper.cpp - PrettyClassLayoutGraphicalDumper.cpp - PrettyCompilandDumper.cpp - PrettyEnumDumper.cpp - PrettyExternalSymbolDumper.cpp - PrettyFunctionDumper.cpp - PrettyTypeDumper.cpp - PrettyTypedefDumper.cpp - PrettyVariableDumper.cpp - StreamUtil.cpp - YAMLOutputStyle.cpp - ) - -if(LLVM_USE_SANITIZE_COVERAGE) - add_subdirectory(fuzzer) -endif() Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h =================================================================== --- llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.h +++ /dev/null @@ -1,49 +0,0 @@ -//===-- CompactTypeDumpVisitor.h - CodeView type info dumper ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H -#define LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H - -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" - -namespace llvm { -class ScopedPrinter; -namespace codeview { -class TypeCollection; -} - -namespace pdb { - -/// Dumper for CodeView type streams found in COFF object files and PDB files. -/// Dumps records on a single line, and ignores member records. -class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { -public: - CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W); - CompactTypeDumpVisitor(codeview::TypeCollection &Types, - codeview::TypeIndex FirstTI, ScopedPrinter *W); - - /// Paired begin/end actions for all types. Receives all record data, - /// including the fixed-length record prefix. - Error visitTypeBegin(codeview::CVType &Record) override; - Error visitTypeEnd(codeview::CVType &Record) override; - -private: - ScopedPrinter *W; - - codeview::TypeIndex TI; - uint32_t Offset; - codeview::TypeCollection &Types; -}; - -} // end namespace pdb -} // end namespace llvm - -#endif Index: llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp =================================================================== --- llvm/tools/llvm-pdbdump/CompactTypeDumpVisitor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -//===-- CompactTypeDumpVisitor.cpp - CodeView type 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 "CompactTypeDumpVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -static const EnumEntry LeafTypeNames[] = { -#define CV_TYPE(enum, val) {#enum, enum}, -#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" -}; - -static StringRef getLeafName(TypeLeafKind K) { - for (const auto &E : LeafTypeNames) { - if (E.Value == K) - return E.Name; - } - return StringRef(); -} - -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, - ScopedPrinter *W) - : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex), - W) {} - -CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, - TypeIndex FirstTI, - ScopedPrinter *W) - : W(W), TI(FirstTI), Offset(0), Types(Types) {} - -Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { - return Error::success(); -} - -Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { - uint32_t I = TI.getIndex(); - StringRef Leaf = getLeafName(Record.Type); - StringRef Name = Types.getTypeName(TI); - W->printString( - llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I, - Record.length(), Offset, Leaf, Name) - .str()); - - Offset += Record.length(); - TI.setIndex(TI.getIndex() + 1); - - return Error::success(); -} Index: llvm/tools/llvm-pdbdump/Diff.h =================================================================== --- llvm/tools/llvm-pdbdump/Diff.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- Diff.h - PDB diff utility --------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_DIFF_H -#define LLVM_TOOLS_LLVMPDBDUMP_DIFF_H - -#include "OutputStyle.h" - -namespace llvm { -namespace pdb { -class PDBFile; -class DiffStyle : public OutputStyle { -public: - explicit DiffStyle(PDBFile &File1, PDBFile &File2); - - Error dump() override; - -private: - Error diffSuperBlock(); - Error diffStreamDirectory(); - Error diffStringTable(); - Error diffFreePageMap(); - Error diffInfoStream(); - Error diffDbiStream(); - Error diffSectionContribs(); - Error diffSectionMap(); - Error diffFpoStream(); - Error diffTpiStream(int Index); - Error diffModuleInfoStream(int Index); - Error diffPublics(); - Error diffGlobals(); - - PDBFile &File1; - PDBFile &File2; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/Diff.cpp =================================================================== --- llvm/tools/llvm-pdbdump/Diff.cpp +++ /dev/null @@ -1,537 +0,0 @@ -//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Diff.h" - -#include "StreamUtil.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/Native/Formatters.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" - -#include "llvm/Support/FormatAdapters.h" -#include "llvm/Support/FormatProviders.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::pdb; - -namespace llvm { -template <> struct format_provider { - static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream, - StringRef Style) { - switch (Sig) { - case PdbRaw_FeatureSig::MinimalDebugInfo: - Stream << "MinimalDebugInfo"; - break; - case PdbRaw_FeatureSig::NoTypeMerge: - Stream << "NoTypeMerge"; - break; - case PdbRaw_FeatureSig::VC110: - Stream << "VC110"; - break; - case PdbRaw_FeatureSig::VC140: - Stream << "VC140"; - break; - } - } -}; -} - -template using ValueOfRange = llvm::detail::ValueOfRange; - -template -static void set_differences(Range &&R1, Range &&R2, - SmallVectorImpl> *OnlyLeft, - SmallVectorImpl> *OnlyRight, - SmallVectorImpl> *Intersection, - Comp Comparator) { - - std::sort(R1.begin(), R1.end(), Comparator); - std::sort(R2.begin(), R2.end(), Comparator); - - if (OnlyLeft) { - OnlyLeft->reserve(R1.size()); - auto End = std::set_difference(R1.begin(), R1.end(), R2.begin(), R2.end(), - OnlyLeft->begin(), Comparator); - OnlyLeft->set_size(std::distance(OnlyLeft->begin(), End)); - } - if (OnlyRight) { - OnlyLeft->reserve(R2.size()); - auto End = std::set_difference(R2.begin(), R2.end(), R1.begin(), R1.end(), - OnlyRight->begin(), Comparator); - OnlyRight->set_size(std::distance(OnlyRight->begin(), End)); - } - if (Intersection) { - Intersection->reserve(std::min(R1.size(), R2.size())); - auto End = std::set_intersection(R1.begin(), R1.end(), R2.begin(), R2.end(), - Intersection->begin(), Comparator); - Intersection->set_size(std::distance(Intersection->begin(), End)); - } -} - -template -static void -set_differences(Range &&R1, Range &&R2, - SmallVectorImpl> *OnlyLeft, - SmallVectorImpl> *OnlyRight, - SmallVectorImpl> *Intersection = nullptr) { - std::less> Comp; - set_differences(std::forward(R1), std::forward(R2), OnlyLeft, - OnlyRight, Intersection, Comp); -} - -DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2) - : File1(File1), File2(File2) {} - -Error DiffStyle::dump() { - if (auto EC = diffSuperBlock()) - return EC; - - if (auto EC = diffFreePageMap()) - return EC; - - if (auto EC = diffStreamDirectory()) - return EC; - - if (auto EC = diffStringTable()) - return EC; - - if (auto EC = diffInfoStream()) - return EC; - - if (auto EC = diffDbiStream()) - return EC; - - if (auto EC = diffSectionContribs()) - return EC; - - if (auto EC = diffSectionMap()) - return EC; - - if (auto EC = diffFpoStream()) - return EC; - - if (auto EC = diffTpiStream(StreamTPI)) - return EC; - - if (auto EC = diffTpiStream(StreamIPI)) - return EC; - - if (auto EC = diffPublics()) - return EC; - - if (auto EC = diffGlobals()) - return EC; - - return Error::success(); -} - -template -static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1, - T V2) { - if (V1 == V2) { - outs() << formatv(" {0}: No differences detected!\n", Label); - return false; - } - - outs().indent(2) << Label << "\n"; - outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1); - outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2); - return true; -} - -template -static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, - ArrayRef V1, ArrayRef V2) { - if (V1 == V2) { - outs() << formatv(" {0}: No differences detected!\n", Label); - return false; - } - - outs().indent(2) << Label << "\n"; - outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), - make_range(V1.begin(), V1.end())); - outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), - make_range(V2.begin(), V2.end())); - return true; -} - -template -static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2, - T &&OnlyRange1, T &&OnlyRange2, - StringRef Label) { - bool HasDiff = false; - if (!OnlyRange1.empty()) { - HasDiff = true; - outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange1.size(), Label, - File1.getFilePath()); - for (const auto &Item : OnlyRange1) - outs() << formatv(" {0}\n", Label, Item); - } - if (!OnlyRange2.empty()) { - HasDiff = true; - outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange2.size(), - File2.getFilePath()); - for (const auto &Item : OnlyRange2) - outs() << formatv(" {0}\n", Item); - } - return HasDiff; -} - -Error DiffStyle::diffSuperBlock() { - outs() << "MSF Super Block: Searching for differences...\n"; - bool Diffs = false; - - Diffs |= diffAndPrint("Block Size", File1, File2, File1.getBlockSize(), - File2.getBlockSize()); - Diffs |= diffAndPrint("Block Count", File1, File2, File1.getBlockCount(), - File2.getBlockCount()); - Diffs |= diffAndPrint("Unknown 1", File1, File2, File1.getUnknown1(), - File2.getUnknown1()); - - if (opts::diff::Pedantic) { - Diffs |= diffAndPrint("Free Block Map", File1, File2, - File1.getFreeBlockMapBlock(), - File2.getFreeBlockMapBlock()); - Diffs |= diffAndPrint("Directory Size", File1, File2, - File1.getNumDirectoryBytes(), - File2.getNumDirectoryBytes()); - Diffs |= diffAndPrint("Block Map Addr", File1, File2, - File1.getBlockMapOffset(), File2.getBlockMapOffset()); - } - if (!Diffs) - outs() << "MSF Super Block: No differences detected...\n"; - return Error::success(); -} - -Error DiffStyle::diffStreamDirectory() { - SmallVector P; - SmallVector Q; - discoverStreamPurposes(File1, P); - discoverStreamPurposes(File2, Q); - outs() << "Stream Directory: Searching for differences...\n"; - - bool HasDifferences = false; - if (opts::diff::Pedantic) { - size_t Min = std::min(P.size(), Q.size()); - for (size_t I = 0; I < Min; ++I) { - StringRef Names[] = {P[I], Q[I]}; - uint32_t Sizes[] = {File1.getStreamByteSize(I), - File2.getStreamByteSize(I)}; - bool NamesDiffer = Names[0] != Names[1]; - bool SizesDiffer = Sizes[0] != Sizes[1]; - if (NamesDiffer) { - HasDifferences = true; - outs().indent(2) << formatv("Stream {0} - {1}: {2}, {3}: {4}\n", I, - File1.getFilePath(), Names[0], - File2.getFilePath(), Names[1]); - continue; - } - if (SizesDiffer) { - HasDifferences = true; - outs().indent(2) << formatv( - "Stream {0} ({1}): {2}: {3} bytes, {4}: {5} bytes\n", I, Names[0], - File1.getFilePath(), Sizes[0], File2.getFilePath(), Sizes[1]); - continue; - } - } - - ArrayRef MaxNames = (P.size() > Q.size() ? P : Q); - size_t Max = std::max(P.size(), Q.size()); - PDBFile &MaxFile = (P.size() > Q.size() ? File1 : File2); - StringRef MinFileName = - (P.size() < Q.size() ? File1.getFilePath() : File2.getFilePath()); - for (size_t I = Min; I < Max; ++I) { - HasDifferences = true; - StringRef StreamName = MaxNames[I]; - - outs().indent(2) << formatv( - "Stream {0} - {1}: , {2}: Index {3}, {4} bytes\n", - StreamName, MinFileName, MaxFile.getFilePath(), I, - MaxFile.getStreamByteSize(I)); - } - if (!HasDifferences) - outs() << "Stream Directory: No differences detected...\n"; - } else { - auto PI = to_vector<32>(enumerate(P)); - auto QI = to_vector<32>(enumerate(Q)); - - typedef decltype(PI) ContainerType; - typedef typename ContainerType::value_type value_type; - - auto Comparator = [](const value_type &I1, const value_type &I2) { - return I1.value() < I2.value(); - }; - - decltype(PI) OnlyP; - decltype(QI) OnlyQ; - decltype(PI) Common; - - set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator); - - if (!OnlyP.empty()) { - HasDifferences = true; - outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(), - File1.getFilePath()); - for (auto &Item : OnlyP) { - outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), - Item.value()); - } - } - - if (!OnlyQ.empty()) { - HasDifferences = true; - outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n", - OnlyQ.size(), File2.getFilePath()); - for (auto &Item : OnlyQ) { - outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), - Item.value()); - } - } - if (!Common.empty()) { - outs().indent(2) << formatv("Found {0} common streams. Searching for " - "intra-stream differences.\n", - Common.size()); - bool HasCommonDifferences = false; - for (const auto &Left : Common) { - // Left was copied from the first range so its index refers to a stream - // index in the first file. Find the corresponding stream index in the - // second file. - auto Range = - std::equal_range(QI.begin(), QI.end(), Left, - [](const value_type &L, const value_type &R) { - return L.value() < R.value(); - }); - const auto &Right = *Range.first; - assert(Left.value() == Right.value()); - uint32_t LeftSize = File1.getStreamByteSize(Left.index()); - uint32_t RightSize = File2.getStreamByteSize(Right.index()); - if (LeftSize != RightSize) { - HasDifferences = true; - HasCommonDifferences = true; - outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n", - Left.value(), File1.getFilePath(), - LeftSize, File2.getFilePath(), RightSize); - } - } - if (!HasCommonDifferences) - outs().indent(2) << "Common Streams: No differences detected!\n"; - } - if (!HasDifferences) - outs() << "Stream Directory: No differences detected!\n"; - } - - return Error::success(); -} - -Error DiffStyle::diffStringTable() { - auto ExpectedST1 = File1.getStringTable(); - auto ExpectedST2 = File2.getStringTable(); - outs() << "String Table: Searching for differences...\n"; - bool Has1 = !!ExpectedST1; - bool Has2 = !!ExpectedST2; - if (!(Has1 && Has2)) { - // If one has a string table and the other doesn't, we can print less - // output. - if (Has1 != Has2) { - if (Has1) { - outs() << formatv(" {0}: ({1} strings)\n", File1.getFilePath(), - ExpectedST1->getNameCount()); - outs() << formatv(" {0}: (string table not present)\n", - File2.getFilePath()); - } else { - outs() << formatv(" {0}: (string table not present)\n", - File1.getFilePath()); - outs() << formatv(" {0}: ({1})\n", File2.getFilePath(), - ExpectedST2->getNameCount()); - } - } - consumeError(ExpectedST1.takeError()); - consumeError(ExpectedST2.takeError()); - return Error::success(); - } - - bool HasDiff = false; - auto &ST1 = *ExpectedST1; - auto &ST2 = *ExpectedST2; - - if (ST1.getByteSize() != ST2.getByteSize()) { - outs() << " Stream Size\n"; - outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(), - ST1.getByteSize()); - outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(), - ST2.getByteSize()); - outs() << formatv(" Difference: {0} bytes\n", - AbsoluteDifference(ST1.getByteSize(), ST2.getByteSize())); - HasDiff = true; - } - HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(), - ST1.getHashVersion()); - HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(), - ST1.getSignature()); - - // Both have a valid string table, dive in and compare individual strings. - - auto IdList1 = ST1.name_ids(); - auto IdList2 = ST2.name_ids(); - if (opts::diff::Pedantic) { - // In pedantic mode, we compare index by index (i.e. the strings are in the - // same order - // in both tables. - uint32_t Max = std::max(IdList1.size(), IdList2.size()); - for (uint32_t I = 0; I < Max; ++I) { - Optional Id1, Id2; - StringRef S1, S2; - if (I < IdList1.size()) { - Id1 = IdList1[I]; - if (auto Result = ST1.getStringForID(*Id1)) - S1 = *Result; - else - return Result.takeError(); - } - if (I < IdList2.size()) { - Id2 = IdList2[I]; - if (auto Result = ST2.getStringForID(*Id2)) - S2 = *Result; - else - return Result.takeError(); - } - if (Id1 == Id2 && S1 == S2) - continue; - - std::string OutId1 = - Id1 ? formatv("{0}", *Id1).str() : "(index not present)"; - std::string OutId2 = - Id2 ? formatv("{0}", *Id2).str() : "(index not present)"; - outs() << formatv(" String {0}\n", I); - outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", - File1.getFilePath(), OutId1, S1); - outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", - File2.getFilePath(), OutId2, S2); - HasDiff = true; - } - } else { - std::vector Strings1, Strings2; - Strings1.reserve(IdList1.size()); - Strings2.reserve(IdList2.size()); - for (auto ID : IdList1) { - auto S = ST1.getStringForID(ID); - if (!S) - return S.takeError(); - Strings1.push_back(*S); - } - for (auto ID : IdList2) { - auto S = ST2.getStringForID(ID); - if (!S) - return S.takeError(); - Strings2.push_back(*S); - } - - SmallVector OnlyP; - SmallVector OnlyQ; - auto End1 = std::remove(Strings1.begin(), Strings1.end(), ""); - auto End2 = std::remove(Strings2.begin(), Strings2.end(), ""); - uint32_t Empty1 = std::distance(End1, Strings1.end()); - uint32_t Empty2 = std::distance(End2, Strings2.end()); - Strings1.erase(End1, Strings1.end()); - Strings2.erase(End2, Strings2.end()); - set_differences(Strings1, Strings2, &OnlyP, &OnlyQ); - printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String"); - - if (Empty1 != Empty2) { - PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2; - PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2; - uint32_t Difference = AbsoluteDifference(Empty1, Empty2); - outs() << formatv(" {0} had {1} more empty strings than {2}\n", - MoreF.getFilePath(), Difference, LessF.getFilePath()); - } - } - if (!HasDiff) - outs() << "String Table: No differences detected!\n"; - return Error::success(); -} - -Error DiffStyle::diffFreePageMap() { return Error::success(); } - -Error DiffStyle::diffInfoStream() { - auto ExpectedInfo1 = File1.getPDBInfoStream(); - auto ExpectedInfo2 = File2.getPDBInfoStream(); - - outs() << "PDB Stream: Searching for differences...\n"; - bool Has1 = !!ExpectedInfo1; - bool Has2 = !!ExpectedInfo2; - if (!(Has1 && Has2)) { - if (Has1 != Has2) - outs() << formatv("{0} does not have a PDB Stream!\n", - Has1 ? File1.getFilePath() : File2.getFilePath()); - consumeError(ExpectedInfo2.takeError()); - consumeError(ExpectedInfo2.takeError()); - return Error::success(); - } - - bool HasDiff = false; - auto &IS1 = *ExpectedInfo1; - auto &IS2 = *ExpectedInfo2; - if (IS1.getStreamSize() != IS2.getStreamSize()) { - outs() << " Stream Size\n"; - outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(), - IS1.getStreamSize()); - outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(), - IS2.getStreamSize()); - outs() << formatv( - " Difference: {0} bytes\n", - AbsoluteDifference(IS1.getStreamSize(), IS2.getStreamSize())); - HasDiff = true; - } - HasDiff |= diffAndPrint("Age", File1, File2, IS1.getAge(), IS2.getAge()); - HasDiff |= diffAndPrint("Guid", File1, File2, IS1.getGuid(), IS2.getGuid()); - HasDiff |= diffAndPrint("Signature", File1, File2, IS1.getSignature(), - IS2.getSignature()); - HasDiff |= - diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion()); - HasDiff |= diffAndPrint("Features", File1, File2, IS1.getFeatureSignatures(), - IS2.getFeatureSignatures()); - HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2, - IS1.getNamedStreamMapByteSize(), - IS2.getNamedStreamMapByteSize()); - SmallVector NS1; - SmallVector NS2; - for (const auto &X : IS1.getNamedStreams().entries()) - NS1.push_back(X.getKey()); - for (const auto &X : IS2.getNamedStreams().entries()) - NS2.push_back(X.getKey()); - SmallVector OnlyP; - SmallVector OnlyQ; - set_differences(NS1, NS2, &OnlyP, &OnlyQ); - printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "Named Streams"); - if (!HasDiff) - outs() << "PDB Stream: No differences detected!\n"; - - return Error::success(); -} - -Error DiffStyle::diffDbiStream() { return Error::success(); } - -Error DiffStyle::diffSectionContribs() { return Error::success(); } - -Error DiffStyle::diffSectionMap() { return Error::success(); } - -Error DiffStyle::diffFpoStream() { return Error::success(); } - -Error DiffStyle::diffTpiStream(int Index) { return Error::success(); } - -Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); } - -Error DiffStyle::diffPublics() { return Error::success(); } - -Error DiffStyle::diffGlobals() { return Error::success(); } Index: llvm/tools/llvm-pdbdump/LLVMBuild.txt =================================================================== --- llvm/tools/llvm-pdbdump/LLVMBuild.txt +++ /dev/null @@ -1,23 +0,0 @@ -;===- ./tools/llvm-pdbdump/LLVMBuild.txt -----------------------*- Conf -*--===; -; -; The LLVM Compiler Infrastructure -; -; This file is distributed under the University of Illinois Open Source -; License. See LICENSE.TXT for details. -; -;===------------------------------------------------------------------------===; -; -; This is an LLVMBuild description file for the components in this subdirectory. -; -; For more information on the LLVMBuild system, please see: -; -; http://llvm.org/docs/LLVMBuild.html -; -;===------------------------------------------------------------------------===; - -[component_0] -type = Tool -name = llvm-pdbdump -parent = Tools -required_libraries = DebugInfoMSF DebugInfoPDB - Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.h +++ /dev/null @@ -1,70 +0,0 @@ -//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H -#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H - -#include "OutputStyle.h" - -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/TypeDatabase.h" -#include "llvm/Support/ScopedPrinter.h" - -#include - -namespace llvm { -class BitVector; - -namespace codeview { -class LazyRandomTypeCollection; -} - -namespace pdb { -class LLVMOutputStyle : public OutputStyle { -public: - LLVMOutputStyle(PDBFile &File); - - Error dump() override; - -private: - Expected - initializeTypeDatabase(uint32_t SN); - - Error dumpFileHeaders(); - Error dumpStreamSummary(); - Error dumpFreePageMap(); - Error dumpBlockRanges(); - Error dumpGlobalsStream(); - Error dumpStreamBytes(); - Error dumpStreamBlocks(); - Error dumpStringTable(); - Error dumpInfoStream(); - Error dumpTpiStream(uint32_t StreamIdx); - Error dumpDbiStream(); - Error dumpSectionContribs(); - Error dumpSectionMap(); - Error dumpPublicsStream(); - Error dumpSectionHeaders(); - Error dumpFpoStream(); - - void dumpBitVector(StringRef Name, const BitVector &V); - - void flush(); - - PDBFile &File; - ScopedPrinter P; - std::unique_ptr TpiTypes; - std::unique_ptr IpiTypes; - SmallVector StreamPurposes; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LLVMOutputStyle.cpp +++ /dev/null @@ -1,1177 +0,0 @@ -//===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LLVMOutputStyle.h" - -#include "CompactTypeDumpVisitor.h" -#include "StreamUtil.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" -#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" -#include "llvm/DebugInfo/CodeView/EnumTables.h" -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/Line.h" -#include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/EnumTables.h" -#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" -#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/Object/COFF.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/FormatVariadic.h" - -#include - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -namespace { -struct PageStats { - explicit PageStats(const BitVector &FreePages) - : Upm(FreePages), ActualUsedPages(FreePages.size()), - MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) { - const_cast(Upm).flip(); - // To calculate orphaned pages, we start with the set of pages that the - // MSF thinks are used. Each time we find one that actually *is* used, - // we unset it. Whichever bits remain set at the end are orphaned. - OrphanedPages = Upm; - } - - // The inverse of the MSF File's copy of the Fpm. The basis for which we - // determine the allocation status of each page. - const BitVector Upm; - - // Pages which are marked as used in the FPM and are used at least once. - BitVector ActualUsedPages; - - // Pages which are marked as used in the FPM but are used more than once. - BitVector MultiUsePages; - - // Pages which are marked as used in the FPM but are not used at all. - BitVector OrphanedPages; - - // Pages which are marked free in the FPM but are used. - BitVector UseAfterFreePages; -}; - -class C13RawVisitor : public DebugSubsectionVisitor { -public: - C13RawVisitor(ScopedPrinter &P, LazyRandomTypeCollection &TPI, - LazyRandomTypeCollection &IPI) - : P(P), TPI(TPI), IPI(IPI) {} - - Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::Unknown)) - return Error::success(); - DictScope DD(P, "Unknown"); - P.printHex("Kind", static_cast(Unknown.kind())); - ArrayRef Data; - BinaryStreamReader Reader(Unknown.getData()); - consumeError(Reader.readBytes(Data, Reader.bytesRemaining())); - P.printBinaryBlock("Data", Data); - return Error::success(); - } - - Error visitLines(DebugLinesSubsectionRef &Lines, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::Lines)) - return Error::success(); - - DictScope DD(P, "Lines"); - - P.printNumber("RelocSegment", Lines.header()->RelocSegment); - P.printNumber("RelocOffset", Lines.header()->RelocOffset); - P.printNumber("CodeSize", Lines.header()->CodeSize); - P.printBoolean("HasColumns", Lines.hasColumnInfo()); - - for (const auto &L : Lines) { - DictScope DDDD(P, "FileEntry"); - - if (auto EC = printFileName("FileName", L.NameIndex, State)) - return EC; - - for (const auto &N : L.LineNumbers) { - DictScope DDD(P, "Line"); - LineInfo LI(N.Flags); - P.printNumber("Offset", N.Offset); - if (LI.isAlwaysStepInto()) - P.printString("StepInto", StringRef("Always")); - else if (LI.isNeverStepInto()) - P.printString("StepInto", StringRef("Never")); - else - P.printNumber("LineNumberStart", LI.getStartLine()); - P.printNumber("EndDelta", LI.getLineDelta()); - P.printBoolean("IsStatement", LI.isStatement()); - } - for (const auto &C : L.Columns) { - DictScope DDD(P, "Column"); - P.printNumber("Start", C.StartColumn); - P.printNumber("End", C.EndColumn); - } - } - - return Error::success(); - } - - Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums)) - return Error::success(); - - DictScope DD(P, "FileChecksums"); - for (const auto &CS : Checksums) { - DictScope DDD(P, "Checksum"); - if (auto Result = getNameFromStringTable(CS.FileNameOffset, State)) - P.printString("FileName", *Result); - else - return Result.takeError(); - P.printEnum("Kind", uint8_t(CS.Kind), getFileChecksumNames()); - P.printBinaryBlock("Checksum", CS.Checksum); - } - return Error::success(); - } - - Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines)) - return Error::success(); - - DictScope D(P, "InlineeLines"); - P.printBoolean("HasExtraFiles", Inlinees.hasExtraFiles()); - ListScope LS(P, "Lines"); - for (const auto &L : Inlinees) { - DictScope DDD(P, "Inlinee"); - if (auto EC = printFileName("FileName", L.Header->FileID, State)) - return EC; - - if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee)) - return EC; - P.printNumber("SourceLine", L.Header->SourceLineNum); - if (Inlinees.hasExtraFiles()) { - ListScope DDDD(P, "ExtraFiles"); - for (const auto &EF : L.ExtraFiles) { - if (auto EC = printFileName("File", EF, State)) - return EC; - } - } - } - return Error::success(); - } - - Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports)) - return Error::success(); - - ListScope D(P, "CrossModuleExports"); - for (const auto &M : CSE) { - DictScope D(P, "Export"); - P.printHex("Local", M.Local); - P.printHex("Global", M.Global); - } - return Error::success(); - } - - Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSI, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports)) - return Error::success(); - - ListScope L(P, "CrossModuleImports"); - for (const auto &M : CSI) { - DictScope D(P, "ModuleImport"); - auto Name = getNameFromStringTable(M.Header->ModuleNameOffset, State); - if (!Name) - return Name.takeError(); - P.printString("Module", *Name); - P.printHexList("Imports", M.Imports); - } - return Error::success(); - } - - Error visitFrameData(DebugFrameDataSubsectionRef &FD, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::FrameData)) - return Error::success(); - - ListScope L(P, "FrameData"); - for (const auto &Frame : FD) { - DictScope D(P, "Frame"); - auto Name = getNameFromStringTable(Frame.FrameFunc, State); - if (!Name) - return joinErrors(make_error(raw_error_code::invalid_format, - "Invalid Frame.FrameFunc index"), - Name.takeError()); - P.printNumber("Rva", Frame.RvaStart); - P.printNumber("CodeSize", Frame.CodeSize); - P.printNumber("LocalSize", Frame.LocalSize); - P.printNumber("ParamsSize", Frame.ParamsSize); - P.printNumber("MaxStackSize", Frame.MaxStackSize); - P.printString("FrameFunc", *Name); - P.printNumber("PrologSize", Frame.PrologSize); - P.printNumber("SavedRegsSize", Frame.SavedRegsSize); - P.printNumber("Flags", Frame.Flags); - } - return Error::success(); - } - - Error visitSymbols(DebugSymbolsSubsectionRef &Symbols, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::Symbols)) - return Error::success(); - ListScope L(P, "Symbols"); - - // This section should not actually appear in a PDB file, it really only - // appears in object files. But we support it here for testing. So we - // specify the Object File container type. - codeview::CVSymbolDumper SD(P, TPI, CodeViewContainer::ObjectFile, nullptr, - false); - for (auto S : Symbols) { - DictScope LL(P, ""); - if (auto EC = SD.dump(S)) { - return make_error( - raw_error_code::corrupt_file, - "DEBUG_S_SYMBOLS subsection contained corrupt symbol record"); - } - } - return Error::success(); - } - - Error visitStringTable(DebugStringTableSubsectionRef &Strings, - const DebugSubsectionState &State) override { - if (!opts::checkModuleSubsection(opts::ModuleSubsection::StringTable)) - return Error::success(); - - ListScope D(P, "String Table"); - BinaryStreamReader Reader(Strings.getBuffer()); - StringRef S; - consumeError(Reader.readCString(S)); - while (Reader.bytesRemaining() > 0) { - consumeError(Reader.readCString(S)); - if (S.empty() && Reader.bytesRemaining() < 4) - break; - P.printString(S); - } - return Error::success(); - } - -private: - Error dumpTypeRecord(StringRef Label, TypeIndex Index) { - CompactTypeDumpVisitor CTDV(IPI, Index, &P); - DictScope D(P, Label); - if (IPI.contains(Index)) { - CVType Type = IPI.getType(Index); - if (auto EC = codeview::visitTypeRecord(Type, CTDV)) - return EC; - } else { - P.printString( - llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex()) - .str()); - } - return Error::success(); - } - Error printFileName(StringRef Label, uint32_t Offset, - const DebugSubsectionState &State) { - if (auto Result = getNameFromChecksumsBuffer(Offset, State)) { - P.printString(Label, *Result); - return Error::success(); - } else - return Result.takeError(); - } - - Expected - getNameFromStringTable(uint32_t Offset, const DebugSubsectionState &State) { - return State.strings().getString(Offset); - } - - Expected - getNameFromChecksumsBuffer(uint32_t Offset, - const DebugSubsectionState &State) { - auto Array = State.checksums().getArray(); - auto ChecksumIter = Array.at(Offset); - if (ChecksumIter == Array.end()) - return make_error(raw_error_code::invalid_format); - const auto &Entry = *ChecksumIter; - return getNameFromStringTable(Entry.FileNameOffset, State); - } - - ScopedPrinter &P; - LazyRandomTypeCollection &TPI; - LazyRandomTypeCollection &IPI; -}; -} - -static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) { - if (Stats.Upm.test(UsedIndex)) { - if (Stats.ActualUsedPages.test(UsedIndex)) - Stats.MultiUsePages.set(UsedIndex); - Stats.ActualUsedPages.set(UsedIndex); - Stats.OrphanedPages.reset(UsedIndex); - } else { - // The MSF doesn't think this page is used, but it is. - Stats.UseAfterFreePages.set(UsedIndex); - } -} - -static void printSectionOffset(llvm::raw_ostream &OS, - const SectionOffset &Off) { - OS << Off.Off << ", " << Off.Isect; -} - -LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {} - -Error LLVMOutputStyle::dump() { - if (auto EC = dumpFileHeaders()) - return EC; - - if (auto EC = dumpStreamSummary()) - return EC; - - if (auto EC = dumpFreePageMap()) - return EC; - - if (auto EC = dumpStreamBlocks()) - return EC; - - if (auto EC = dumpBlockRanges()) - return EC; - - if (auto EC = dumpStreamBytes()) - return EC; - - if (auto EC = dumpStringTable()) - return EC; - - if (auto EC = dumpInfoStream()) - return EC; - - if (auto EC = dumpTpiStream(StreamTPI)) - return EC; - - if (auto EC = dumpTpiStream(StreamIPI)) - return EC; - - if (auto EC = dumpDbiStream()) - return EC; - - if (auto EC = dumpSectionContribs()) - return EC; - - if (auto EC = dumpSectionMap()) - return EC; - - if (auto EC = dumpGlobalsStream()) - return EC; - - if (auto EC = dumpPublicsStream()) - return EC; - - if (auto EC = dumpSectionHeaders()) - return EC; - - if (auto EC = dumpFpoStream()) - return EC; - - flush(); - - return Error::success(); -} - -Error LLVMOutputStyle::dumpFileHeaders() { - if (!opts::raw::DumpHeaders) - return Error::success(); - - DictScope D(P, "FileHeaders"); - P.printNumber("BlockSize", File.getBlockSize()); - P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock()); - P.printNumber("NumBlocks", File.getBlockCount()); - P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes()); - P.printNumber("Unknown1", File.getUnknown1()); - P.printNumber("BlockMapAddr", File.getBlockMapIndex()); - P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks()); - - // The directory is not contiguous. Instead, the block map contains a - // contiguous list of block numbers whose contents, when concatenated in - // order, make up the directory. - P.printList("DirectoryBlocks", File.getDirectoryBlockArray()); - P.printNumber("NumStreams", File.getNumStreams()); - return Error::success(); -} - -Error LLVMOutputStyle::dumpStreamSummary() { - if (!opts::raw::DumpStreamSummary) - return Error::success(); - - if (StreamPurposes.empty()) - discoverStreamPurposes(File, StreamPurposes); - - uint32_t StreamCount = File.getNumStreams(); - - ListScope L(P, "Streams"); - for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { - std::string Label("Stream "); - Label += to_string(StreamIdx); - - std::string Value = "[" + StreamPurposes[StreamIdx] + "] ("; - Value += to_string(File.getStreamByteSize(StreamIdx)); - Value += " bytes)"; - - P.printString(Label, Value); - } - - P.flush(); - return Error::success(); -} - -Error LLVMOutputStyle::dumpFreePageMap() { - if (!opts::raw::DumpPageStats) - return Error::success(); - - // Start with used pages instead of free pages because - // the number of free pages is far larger than used pages. - BitVector FPM = File.getMsfLayout().FreePageMap; - - PageStats PS(FPM); - - recordKnownUsedPage(PS, 0); // MSF Super Block - - uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout()); - uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout()); - for (uint32_t I = 0; I < NumSections; ++I) { - uint32_t Fpm0 = 1 + BlocksPerSection * I; - // 2 Fpm blocks spaced at `getBlockSize()` block intervals - recordKnownUsedPage(PS, Fpm0); - recordKnownUsedPage(PS, Fpm0 + 1); - } - - recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table - - for (auto DB : File.getDirectoryBlockArray()) - recordKnownUsedPage(PS, DB); - - // Record pages used by streams. Note that pages for stream 0 - // are considered being unused because that's what MSVC tools do. - // Stream 0 doesn't contain actual data, so it makes some sense, - // though it's a bit confusing to us. - for (auto &SE : File.getStreamMap().drop_front(1)) - for (auto &S : SE) - recordKnownUsedPage(PS, S); - - dumpBitVector("Msf Free Pages", FPM); - dumpBitVector("Orphaned Pages", PS.OrphanedPages); - dumpBitVector("Multiply Used Pages", PS.MultiUsePages); - dumpBitVector("Use After Free Pages", PS.UseAfterFreePages); - return Error::success(); -} - -void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) { - std::vector Vec; - for (uint32_t I = 0, E = V.size(); I != E; ++I) - if (V[I]) - Vec.push_back(I); - P.printList(Name, Vec); -} - -Error LLVMOutputStyle::dumpGlobalsStream() { - if (!opts::raw::DumpGlobals) - return Error::success(); - if (!File.hasPDBGlobalsStream()) { - P.printString("Globals Stream not present"); - return Error::success(); - } - - auto Globals = File.getPDBGlobalsStream(); - if (!Globals) - return Globals.takeError(); - DictScope D(P, "Globals Stream"); - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex()); - P.printNumber("Number of buckets", Globals->getNumBuckets()); - P.printList("Hash Buckets", Globals->getHashBuckets()); - - return Error::success(); -} - -Error LLVMOutputStyle::dumpStreamBlocks() { - if (!opts::raw::DumpStreamBlocks) - return Error::success(); - - ListScope L(P, "StreamBlocks"); - uint32_t StreamCount = File.getNumStreams(); - for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { - std::string Name("Stream "); - Name += to_string(StreamIdx); - auto StreamBlocks = File.getStreamBlockList(StreamIdx); - P.printList(Name, StreamBlocks); - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpBlockRanges() { - if (!opts::raw::DumpBlockRange.hasValue()) - return Error::success(); - auto &R = *opts::raw::DumpBlockRange; - uint32_t Max = R.Max.getValueOr(R.Min); - - if (Max < R.Min) - return make_error( - "Invalid block range specified. Max < Min", - std::make_error_code(std::errc::bad_address)); - if (Max >= File.getBlockCount()) - return make_error( - "Invalid block range specified. Requested block out of bounds", - std::make_error_code(std::errc::bad_address)); - - DictScope D(P, "Block Data"); - for (uint32_t I = R.Min; I <= Max; ++I) { - auto ExpectedData = File.getBlockData(I, File.getBlockSize()); - if (!ExpectedData) - return ExpectedData.takeError(); - std::string Label; - llvm::raw_string_ostream S(Label); - S << "Block " << I; - S.flush(); - P.printBinaryBlock(Label, *ExpectedData); - } - - return Error::success(); -} - -static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset, - uint32_t &Size) { - if (Str.consumeInteger(0, SI)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - if (Str.consume_front(":")) { - if (Str.consumeInteger(0, Offset)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (Str.consume_front("@")) { - if (Str.consumeInteger(0, Size)) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - } - if (!Str.empty()) - return make_error(raw_error_code::invalid_format, - "Invalid Stream Specification"); - return Error::success(); -} - -Error LLVMOutputStyle::dumpStreamBytes() { - if (opts::raw::DumpStreamData.empty()) - return Error::success(); - - if (StreamPurposes.empty()) - discoverStreamPurposes(File, StreamPurposes); - - DictScope D(P, "Stream Data"); - for (auto &Str : opts::raw::DumpStreamData) { - uint32_t SI = 0; - uint32_t Begin = 0; - uint32_t Size = 0; - uint32_t End = 0; - - if (auto EC = parseStreamSpec(Str, SI, Begin, Size)) - return EC; - - if (SI >= File.getNumStreams()) - return make_error(raw_error_code::no_stream); - - auto S = MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator()); - if (!S) - continue; - DictScope DD(P, "Stream"); - if (Size == 0) - End = S->getLength(); - else { - End = Begin + Size; - if (End >= S->getLength()) - return make_error(raw_error_code::index_out_of_bounds, - "Stream is not long enough!"); - } - - P.printNumber("Index", SI); - P.printString("Type", StreamPurposes[SI]); - P.printNumber("Size", S->getLength()); - auto Blocks = File.getMsfLayout().StreamMap[SI]; - P.printList("Blocks", Blocks); - - BinaryStreamReader R(*S); - ArrayRef StreamData; - if (auto EC = R.readBytes(StreamData, S->getLength())) - return EC; - Size = End - Begin; - StreamData = StreamData.slice(Begin, Size); - P.printBinaryBlock("Data", StreamData, Begin); - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpStringTable() { - if (!opts::raw::DumpStringTable) - return Error::success(); - - auto IS = File.getStringTable(); - if (!IS) - return IS.takeError(); - - DictScope D(P, "String Table"); - for (uint32_t I : IS->name_ids()) { - auto ES = IS->getStringForID(I); - if (!ES) - return ES.takeError(); - - if (ES->empty()) - continue; - llvm::SmallString<32> Str; - Str.append("'"); - Str.append(*ES); - Str.append("'"); - P.printString(Str); - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpInfoStream() { - if (!opts::raw::DumpHeaders) - return Error::success(); - if (!File.hasPDBInfoStream()) { - P.printString("PDB Stream not present"); - return Error::success(); - } - auto IS = File.getPDBInfoStream(); - if (!IS) - return IS.takeError(); - - DictScope D(P, "PDB Stream"); - P.printNumber("Version", IS->getVersion()); - P.printHex("Signature", IS->getSignature()); - P.printNumber("Age", IS->getAge()); - P.printObject("Guid", IS->getGuid()); - P.printHex("Features", IS->getFeatures()); - { - DictScope DD(P, "Named Streams"); - for (const auto &S : IS->getNamedStreams().entries()) - P.printObject(S.getKey(), S.getValue()); - } - return Error::success(); -} - -namespace { -class RecordBytesVisitor : public TypeVisitorCallbacks { -public: - explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {} - - Error visitTypeEnd(CVType &Record) override { - P.printBinaryBlock("Bytes", Record.content()); - return Error::success(); - } - -private: - ScopedPrinter &P; -}; -} - -Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { - assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); - - bool DumpRecordBytes = false; - bool DumpRecords = false; - bool DumpTpiHash = false; - StringRef Label; - StringRef VerLabel; - if (StreamIdx == StreamTPI) { - if (!File.hasPDBTpiStream()) { - P.printString("Type Info Stream (TPI) not present"); - return Error::success(); - } - DumpRecordBytes = opts::raw::DumpTpiRecordBytes; - DumpRecords = opts::raw::DumpTpiRecords; - DumpTpiHash = opts::raw::DumpTpiHash; - Label = "Type Info Stream (TPI)"; - VerLabel = "TPI Version"; - } else if (StreamIdx == StreamIPI) { - if (!File.hasPDBIpiStream()) { - P.printString("Type Info Stream (IPI) not present"); - return Error::success(); - } - DumpRecordBytes = opts::raw::DumpIpiRecordBytes; - DumpRecords = opts::raw::DumpIpiRecords; - Label = "Type Info Stream (IPI)"; - VerLabel = "IPI Version"; - } - - auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() - : File.getPDBIpiStream(); - if (!Tpi) - return Tpi.takeError(); - - auto ExpectedTypes = initializeTypeDatabase(StreamIdx); - if (!ExpectedTypes) - return ExpectedTypes.takeError(); - auto &Types = *ExpectedTypes; - - if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash) - return Error::success(); - - std::unique_ptr StreamScope; - std::unique_ptr RecordScope; - - StreamScope = llvm::make_unique(P, Label); - P.printNumber(VerLabel, Tpi->getTpiVersion()); - P.printNumber("Record count", Tpi->getNumTypeRecords()); - - std::vector> Visitors; - - // If we're in dump mode, add a dumper with the appropriate detail level. - if (DumpRecords) { - std::unique_ptr Dumper; - if (opts::raw::CompactRecords) - Dumper = make_unique(Types, &P); - else { - assert(TpiTypes); - - auto X = make_unique(*TpiTypes, &P, false); - if (StreamIdx == StreamIPI) - X->setIpiTypes(*IpiTypes); - Dumper = std::move(X); - } - Visitors.push_back(std::move(Dumper)); - } - if (DumpRecordBytes) - Visitors.push_back(make_unique(P)); - - // We always need to deserialize and add it to the type database. This is - // true if even if we're not dumping anything, because we could need the - // type database for the purposes of dumping symbols. - TypeVisitorCallbackPipeline Pipeline; - for (const auto &V : Visitors) - Pipeline.addCallbackToPipeline(*V); - - if (DumpRecords || DumpRecordBytes) - RecordScope = llvm::make_unique(P, "Records"); - - Optional I = Types.getFirst(); - while (I) { - std::unique_ptr OneRecordScope; - - if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords) - OneRecordScope = llvm::make_unique(P, ""); - - auto T = Types.getType(*I); - if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline)) - return EC; - I = Types.getNext(*I); - } - - if (DumpTpiHash) { - DictScope DD(P, "Hash"); - P.printNumber("Number of Hash Buckets", Tpi->getNumHashBuckets()); - P.printNumber("Hash Key Size", Tpi->getHashKeySize()); - P.printList("Values", Tpi->getHashValues()); - - ListScope LHA(P, "Adjusters"); - auto ExpectedST = File.getStringTable(); - if (!ExpectedST) - return ExpectedST.takeError(); - const auto &ST = *ExpectedST; - for (const auto &E : Tpi->getHashAdjusters()) { - DictScope DHA(P); - auto Name = ST.getStringForID(E.first); - if (!Name) - return Name.takeError(); - - P.printString("Type", *Name); - P.printHex("TI", E.second); - } - } - - ListScope L(P, "TypeIndexOffsets"); - for (const auto &IO : Tpi->getTypeIndexOffsets()) { - P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(), - (uint32_t)IO.Offset) - .str()); - } - - P.flush(); - return Error::success(); -} - -Expected -LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) { - auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes; - auto Tpi = - (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); - if (!Tpi) - return Tpi.takeError(); - - if (!TypeCollection) { - // Initialize the type collection, even if we're not going to dump it. This - // way if some other part of the dumper decides it wants to use some or all - // of the records for whatever purposes, it can still access them lazily. - auto &Types = Tpi->typeArray(); - uint32_t Count = Tpi->getNumTypeRecords(); - auto Offsets = Tpi->getTypeIndexOffsets(); - TypeCollection = - llvm::make_unique(Types, Count, Offsets); - } - - return *TypeCollection; -} - -Error LLVMOutputStyle::dumpDbiStream() { - bool DumpModules = opts::shared::DumpModules || - opts::shared::DumpModuleSyms || - opts::shared::DumpModuleFiles || - !opts::shared::DumpModuleSubsections.empty(); - if (!opts::raw::DumpHeaders && !DumpModules) - return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } - - auto DS = File.getPDBDbiStream(); - if (!DS) - return DS.takeError(); - - DictScope D(P, "DBI Stream"); - P.printNumber("Dbi Version", DS->getDbiVersion()); - P.printNumber("Age", DS->getAge()); - P.printBoolean("Incremental Linking", DS->isIncrementallyLinked()); - P.printBoolean("Has CTypes", DS->hasCTypes()); - P.printBoolean("Is Stripped", DS->isStripped()); - P.printObject("Machine Type", DS->getMachineType()); - P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex()); - P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex()); - P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex()); - - uint16_t Major = DS->getBuildMajorVersion(); - uint16_t Minor = DS->getBuildMinorVersion(); - P.printVersion("Toolchain Version", Major, Minor); - - std::string DllName; - raw_string_ostream DllStream(DllName); - DllStream << "mspdb" << Major << Minor << ".dll version"; - DllStream.flush(); - P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion()); - - if (DumpModules) { - ListScope L(P, "Modules"); - const DbiModuleList &Modules = DS->modules(); - for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { - const DbiModuleDescriptor &Modi = Modules.getModuleDescriptor(I); - DictScope DD(P); - P.printString("Name", Modi.getModuleName().str()); - P.printNumber("Debug Stream Index", Modi.getModuleStreamIndex()); - P.printString("Object File Name", Modi.getObjFileName().str()); - P.printNumber("Num Files", Modi.getNumberOfFiles()); - P.printNumber("Source File Name Idx", Modi.getSourceFileNameIndex()); - P.printNumber("Pdb File Name Idx", Modi.getPdbFilePathNameIndex()); - P.printNumber("Line Info Byte Size", Modi.getC11LineInfoByteSize()); - P.printNumber("C13 Line Info Byte Size", Modi.getC13LineInfoByteSize()); - P.printNumber("Symbol Byte Size", Modi.getSymbolDebugInfoByteSize()); - P.printNumber("Type Server Index", Modi.getTypeServerIndex()); - P.printBoolean("Has EC Info", Modi.hasECInfo()); - if (opts::shared::DumpModuleFiles) { - std::string FileListName = to_string(Modules.getSourceFileCount(I)) + - " Contributing Source Files"; - ListScope LL(P, FileListName); - for (auto File : Modules.source_files(I)) - P.printString(File); - } - bool HasModuleDI = (Modi.getModuleStreamIndex() < File.getNumStreams()); - bool ShouldDumpSymbols = - (opts::shared::DumpModuleSyms || opts::raw::DumpSymRecordBytes); - if (HasModuleDI && - (ShouldDumpSymbols || !opts::shared::DumpModuleSubsections.empty())) { - auto ModStreamData = MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), - Modi.getModuleStreamIndex(), File.getAllocator()); - - ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); - if (auto EC = ModS.reload()) - return EC; - - auto ExpectedTpi = initializeTypeDatabase(StreamTPI); - if (!ExpectedTpi) - return ExpectedTpi.takeError(); - auto &Tpi = *ExpectedTpi; - if (ShouldDumpSymbols) { - - ListScope SS(P, "Symbols"); - codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, - false); - bool HadError = false; - for (auto S : ModS.symbols(&HadError)) { - DictScope LL(P, ""); - if (opts::shared::DumpModuleSyms) { - if (auto EC = SD.dump(S)) { - llvm::consumeError(std::move(EC)); - HadError = true; - break; - } - } - if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.content()); - } - if (HadError) - return make_error( - raw_error_code::corrupt_file, - "DBI stream contained corrupt symbol record"); - } - if (!opts::shared::DumpModuleSubsections.empty()) { - ListScope SS(P, "Subsections"); - auto ExpectedIpi = initializeTypeDatabase(StreamIPI); - if (!ExpectedIpi) - return ExpectedIpi.takeError(); - auto &Ipi = *ExpectedIpi; - auto ExpectedStrings = File.getStringTable(); - if (!ExpectedStrings) - return joinErrors( - make_error(raw_error_code::no_stream, - "Could not get string table!"), - ExpectedStrings.takeError()); - - C13RawVisitor V(P, Tpi, Ipi); - if (auto EC = codeview::visitDebugSubsections( - ModS.subsections(), V, ExpectedStrings->getStringTable())) - return EC; - } - } - } - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpSectionContribs() { - if (!opts::raw::DumpSectionContribs) - return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - ListScope L(P, "Section Contributions"); - class Visitor : public ISectionContribVisitor { - public: - Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {} - void visit(const SectionContrib &SC) override { - DictScope D(P, "Contribution"); - P.printNumber("ISect", SC.ISect); - P.printNumber("Off", SC.Off); - P.printNumber("Size", SC.Size); - P.printFlags("Characteristics", SC.Characteristics, - codeview::getImageSectionCharacteristicNames(), - COFF::SectionCharacteristics(0x00F00000)); - { - DictScope DD(P, "Module"); - P.printNumber("Index", SC.Imod); - const DbiModuleList &Modules = DS.modules(); - if (Modules.getModuleCount() > SC.Imod) { - P.printString("Name", - Modules.getModuleDescriptor(SC.Imod).getModuleName()); - } - } - P.printNumber("Data CRC", SC.DataCrc); - P.printNumber("Reloc CRC", SC.RelocCrc); - P.flush(); - } - void visit(const SectionContrib2 &SC) override { - visit(SC.Base); - P.printNumber("ISect Coff", SC.ISectCoff); - P.flush(); - } - - private: - ScopedPrinter &P; - DbiStream &DS; - }; - Visitor V(P, *Dbi); - Dbi->visitSectionContributions(V); - return Error::success(); -} - -Error LLVMOutputStyle::dumpSectionMap() { - if (!opts::raw::DumpSectionMap) - return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - ListScope L(P, "Section Map"); - for (auto &M : Dbi->getSectionMap()) { - DictScope D(P, "Entry"); - P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames()); - P.printNumber("Ovl", M.Ovl); - P.printNumber("Group", M.Group); - P.printNumber("Frame", M.Frame); - P.printNumber("SecName", M.SecName); - P.printNumber("ClassName", M.ClassName); - P.printNumber("Offset", M.Offset); - P.printNumber("SecByteLength", M.SecByteLength); - P.flush(); - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpPublicsStream() { - if (!opts::raw::DumpPublics) - return Error::success(); - if (!File.hasPDBPublicsStream()) { - P.printString("Publics Stream not present"); - return Error::success(); - } - - auto Publics = File.getPDBPublicsStream(); - if (!Publics) - return Publics.takeError(); - DictScope D(P, "Publics Stream"); - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex()); - P.printNumber("SymHash", Publics->getSymHash()); - P.printNumber("AddrMap", Publics->getAddrMap()); - P.printNumber("Number of buckets", Publics->getNumBuckets()); - P.printList("Hash Buckets", Publics->getHashBuckets()); - P.printList("Address Map", Publics->getAddressMap()); - P.printList("Thunk Map", Publics->getThunkMap()); - P.printList("Section Offsets", Publics->getSectionOffsets(), - printSectionOffset); - ListScope L(P, "Symbols"); - auto ExpectedTypes = initializeTypeDatabase(StreamTPI); - if (!ExpectedTypes) - return ExpectedTypes.takeError(); - auto &Tpi = *ExpectedTypes; - - codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, false); - bool HadError = false; - for (auto S : Publics->getSymbols(&HadError)) { - DictScope DD(P, ""); - - if (auto EC = SD.dump(S)) { - HadError = true; - break; - } - if (opts::raw::DumpSymRecordBytes) - P.printBinaryBlock("Bytes", S.content()); - } - if (HadError) - return make_error( - raw_error_code::corrupt_file, - "Public symbol stream contained corrupt record"); - - return Error::success(); -} - -Error LLVMOutputStyle::dumpSectionHeaders() { - if (!opts::raw::DumpSectionHeaders) - return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - ListScope D(P, "Section Headers"); - for (const object::coff_section &Section : Dbi->getSectionHeaders()) { - DictScope DD(P, ""); - - // If a name is 8 characters long, there is no NUL character at end. - StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name))); - P.printString("Name", Name); - P.printNumber("Virtual Size", Section.VirtualSize); - P.printNumber("Virtual Address", Section.VirtualAddress); - P.printNumber("Size of Raw Data", Section.SizeOfRawData); - P.printNumber("File Pointer to Raw Data", Section.PointerToRawData); - P.printNumber("File Pointer to Relocations", Section.PointerToRelocations); - P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers); - P.printNumber("Number of Relocations", Section.NumberOfRelocations); - P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers); - P.printFlags("Characteristics", Section.Characteristics, - getImageSectionCharacteristicNames()); - } - return Error::success(); -} - -Error LLVMOutputStyle::dumpFpoStream() { - if (!opts::raw::DumpFpo) - return Error::success(); - if (!File.hasPDBDbiStream()) { - P.printString("DBI Stream not present"); - return Error::success(); - } - - auto Dbi = File.getPDBDbiStream(); - if (!Dbi) - return Dbi.takeError(); - - ListScope D(P, "New FPO"); - for (const object::FpoData &Fpo : Dbi->getFpoRecords()) { - DictScope DD(P, ""); - P.printNumber("Offset", Fpo.Offset); - P.printNumber("Size", Fpo.Size); - P.printNumber("Number of locals", Fpo.NumLocals); - P.printNumber("Number of params", Fpo.NumParams); - P.printNumber("Size of Prolog", Fpo.getPrologSize()); - P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs()); - P.printBoolean("Has SEH", Fpo.hasSEH()); - P.printBoolean("Use BP", Fpo.useBP()); - P.printNumber("Frame Pointer", Fpo.getFP()); - } - return Error::success(); -} - -void LLVMOutputStyle::flush() { P.flush(); } Index: llvm/tools/llvm-pdbdump/LinePrinter.h =================================================================== --- llvm/tools/llvm-pdbdump/LinePrinter.h +++ /dev/null @@ -1,102 +0,0 @@ -//===- LinePrinter.h ------------------------------------------ *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H -#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Regex.h" - -#include - -namespace llvm { -namespace pdb { - -class ClassLayout; - -class LinePrinter { - friend class WithColor; - -public: - LinePrinter(int Indent, bool UseColor, raw_ostream &Stream); - - void Indent(); - void Unindent(); - void NewLine(); - - bool hasColor() const { return UseColor; } - raw_ostream &getStream() { return OS; } - int getIndentLevel() const { return CurrentIndent; } - - bool IsClassExcluded(const ClassLayout &Class); - bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size); - bool IsSymbolExcluded(llvm::StringRef SymbolName); - bool IsCompilandExcluded(llvm::StringRef CompilandName); - -private: - template - void SetFilters(std::list &List, Iter Begin, Iter End) { - List.clear(); - for (; Begin != End; ++Begin) - List.emplace_back(StringRef(*Begin)); - } - - raw_ostream &OS; - int IndentSpaces; - int CurrentIndent; - bool UseColor; - - std::list ExcludeCompilandFilters; - std::list ExcludeTypeFilters; - std::list ExcludeSymbolFilters; - - std::list IncludeCompilandFilters; - std::list IncludeTypeFilters; - std::list IncludeSymbolFilters; -}; - -template -inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) { - Printer.getStream() << Item; - return Printer.getStream(); -} - -enum class PDB_ColorItem { - None, - Address, - Type, - Comment, - Padding, - Keyword, - Offset, - Identifier, - Path, - SectionHeader, - LiteralValue, - Register, -}; - -class WithColor { -public: - WithColor(LinePrinter &P, PDB_ColorItem C); - ~WithColor(); - - raw_ostream &get() { return OS; } - -private: - void applyColor(PDB_ColorItem C); - raw_ostream &OS; - bool UseColor; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/LinePrinter.cpp =================================================================== --- llvm/tools/llvm-pdbdump/LinePrinter.cpp +++ /dev/null @@ -1,145 +0,0 @@ -//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "LinePrinter.h" - -#include "llvm-pdbdump.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/PDB/UDTLayout.h" -#include "llvm/Support/Regex.h" - -#include - -using namespace llvm; -using namespace llvm::pdb; - -namespace { -bool IsItemExcluded(llvm::StringRef Item, - std::list &IncludeFilters, - std::list &ExcludeFilters) { - if (Item.empty()) - return false; - - auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); }; - - // Include takes priority over exclude. If the user specified include - // filters, and none of them include this item, them item is gone. - if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred)) - return true; - - if (any_of(ExcludeFilters, match_pred)) - return true; - - return false; -} -} - -using namespace llvm; - -LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream) - : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) { - SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(), - opts::pretty::ExcludeTypes.end()); - SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(), - opts::pretty::ExcludeSymbols.end()); - SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(), - opts::pretty::ExcludeCompilands.end()); - - SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(), - opts::pretty::IncludeTypes.end()); - SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(), - opts::pretty::IncludeSymbols.end()); - SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(), - opts::pretty::IncludeCompilands.end()); -} - -void LinePrinter::Indent() { CurrentIndent += IndentSpaces; } - -void LinePrinter::Unindent() { - CurrentIndent = std::max(0, CurrentIndent - IndentSpaces); -} - -void LinePrinter::NewLine() { - OS << "\n"; - OS.indent(CurrentIndent); -} - -bool LinePrinter::IsClassExcluded(const ClassLayout &Class) { - if (IsTypeExcluded(Class.getName(), Class.getSize())) - return true; - if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold) - return true; - return false; -} - -bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) { - if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters)) - return true; - if (Size < opts::pretty::SizeThreshold) - return true; - return false; -} - -bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { - return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters); -} - -bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { - return IsItemExcluded(CompilandName, IncludeCompilandFilters, - ExcludeCompilandFilters); -} - -WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) - : OS(P.OS), UseColor(P.hasColor()) { - if (UseColor) - applyColor(C); -} - -WithColor::~WithColor() { - if (UseColor) - OS.resetColor(); -} - -void WithColor::applyColor(PDB_ColorItem C) { - switch (C) { - case PDB_ColorItem::None: - OS.resetColor(); - return; - case PDB_ColorItem::Comment: - OS.changeColor(raw_ostream::GREEN, false); - return; - case PDB_ColorItem::Address: - OS.changeColor(raw_ostream::YELLOW, /*bold=*/true); - return; - case PDB_ColorItem::Keyword: - OS.changeColor(raw_ostream::MAGENTA, true); - return; - case PDB_ColorItem::Register: - case PDB_ColorItem::Offset: - OS.changeColor(raw_ostream::YELLOW, false); - return; - case PDB_ColorItem::Type: - OS.changeColor(raw_ostream::CYAN, true); - return; - case PDB_ColorItem::Identifier: - OS.changeColor(raw_ostream::CYAN, false); - return; - case PDB_ColorItem::Path: - OS.changeColor(raw_ostream::CYAN, false); - return; - case PDB_ColorItem::Padding: - case PDB_ColorItem::SectionHeader: - OS.changeColor(raw_ostream::RED, true); - return; - case PDB_ColorItem::LiteralValue: - OS.changeColor(raw_ostream::GREEN, true); - return; - } -} Index: llvm/tools/llvm-pdbdump/OutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/OutputStyle.h +++ /dev/null @@ -1,28 +0,0 @@ -//===- OutputStyle.h ------------------------------------------ *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H -#define LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H - -#include "llvm/Support/Error.h" - -namespace llvm { -namespace pdb { -class PDBFile; - -class OutputStyle { -public: - virtual ~OutputStyle() {} - - virtual Error dump() = 0; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PdbYaml.h =================================================================== --- llvm/tools/llvm-pdbdump/PdbYaml.h +++ /dev/null @@ -1,125 +0,0 @@ -//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H -#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H - -#include "OutputStyle.h" - -#include "llvm/ADT/Optional.h" -#include "llvm/DebugInfo/CodeView/SymbolRecord.h" -#include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/MSF/MSFCommon.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" -#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" -#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/YAMLTraits.h" - -#include - -namespace llvm { -namespace codeview { -class DebugStringTableSubsection; -} -namespace pdb { - -namespace yaml { -struct SerializationContext; - -struct MSFHeaders { - msf::SuperBlock SuperBlock; - uint32_t NumDirectoryBlocks = 0; - std::vector DirectoryBlocks; - uint32_t NumStreams = 0; - uint32_t FileSize = 0; -}; - -struct StreamBlockList { - std::vector Blocks; -}; - -struct NamedStreamMapping { - StringRef StreamName; - uint32_t StreamNumber; -}; - -struct PdbInfoStream { - PdbRaw_ImplVer Version = PdbImplVC70; - uint32_t Signature = 0; - uint32_t Age = 1; - PDB_UniqueId Guid; - std::vector Features; - std::vector NamedStreams; -}; - -struct PdbModiStream { - uint32_t Signature; - std::vector Symbols; -}; - -struct PdbDbiModuleInfo { - StringRef Obj; - StringRef Mod; - std::vector SourceFiles; - std::vector Subsections; - Optional Modi; -}; - -struct PdbDbiStream { - PdbRaw_DbiVer VerHeader = PdbDbiV70; - uint32_t Age = 1; - uint16_t BuildNumber = 0; - uint32_t PdbDllVersion = 0; - uint16_t PdbDllRbld = 0; - uint16_t Flags = 1; - PDB_Machine MachineType = PDB_Machine::x86; - - std::vector ModInfos; -}; - -struct PdbTpiStream { - PdbRaw_TpiVer Version = PdbTpiV80; - std::vector Records; -}; - -struct PdbObject { - explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {} - - Optional Headers; - Optional> StreamSizes; - Optional> StreamMap; - Optional PdbStream; - Optional DbiStream; - Optional TpiStream; - Optional IpiStream; - - Optional> StringTable; - - BumpPtrAllocator &Allocator; -}; -} -} -} - -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbObject) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::MSFHeaders) -LLVM_YAML_DECLARE_MAPPING_TRAITS(msf::SuperBlock) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::StreamBlockList) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbInfoStream) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiStream) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbTpiStream) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::NamedStreamMapping) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbModiStream) -LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiModuleInfo) - -#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H Index: llvm/tools/llvm-pdbdump/PdbYaml.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PdbYaml.cpp +++ /dev/null @@ -1,227 +0,0 @@ -//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PdbYaml.h" - -#include "llvm/ADT/StringExtras.h" -#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" -#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" -#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" -#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/CodeView/TypeSerializer.h" -#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawTypes.h" -#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" -#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" -#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" - -using namespace llvm; -using namespace llvm::pdb; -using namespace llvm::pdb::yaml; -using namespace llvm::yaml; - -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) -LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) -LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig) - -namespace llvm { -namespace yaml { - -template <> struct ScalarTraits { - static void output(const llvm::pdb::PDB_UniqueId &S, void *, - llvm::raw_ostream &OS) { - OS << S; - } - - static StringRef input(StringRef Scalar, void *Ctx, - llvm::pdb::PDB_UniqueId &S) { - if (Scalar.size() != 38) - return "GUID strings are 38 characters long"; - if (Scalar[0] != '{' || Scalar[37] != '}') - return "GUID is not enclosed in {}"; - if (Scalar[9] != '-' || Scalar[14] != '-' || Scalar[19] != '-' || - Scalar[24] != '-') - return "GUID sections are not properly delineated with dashes"; - - uint8_t *OutBuffer = S.Guid; - for (auto Iter = Scalar.begin(); Iter != Scalar.end();) { - if (*Iter == '-' || *Iter == '{' || *Iter == '}') { - ++Iter; - continue; - } - uint8_t Value = (llvm::hexDigitValue(*Iter) << 4); - ++Iter; - Value |= llvm::hexDigitValue(*Iter); - ++Iter; - *OutBuffer++ = Value; - } - - return ""; - } - - static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) { - io.enumCase(Value, "Invalid", PDB_Machine::Invalid); - io.enumCase(Value, "Am33", PDB_Machine::Am33); - io.enumCase(Value, "Amd64", PDB_Machine::Amd64); - io.enumCase(Value, "Arm", PDB_Machine::Arm); - io.enumCase(Value, "ArmNT", PDB_Machine::ArmNT); - io.enumCase(Value, "Ebc", PDB_Machine::Ebc); - io.enumCase(Value, "x86", PDB_Machine::x86); - io.enumCase(Value, "Ia64", PDB_Machine::Ia64); - io.enumCase(Value, "M32R", PDB_Machine::M32R); - io.enumCase(Value, "Mips16", PDB_Machine::Mips16); - io.enumCase(Value, "MipsFpu", PDB_Machine::MipsFpu); - io.enumCase(Value, "MipsFpu16", PDB_Machine::MipsFpu16); - io.enumCase(Value, "PowerPCFP", PDB_Machine::PowerPCFP); - io.enumCase(Value, "R4000", PDB_Machine::R4000); - io.enumCase(Value, "SH3", PDB_Machine::SH3); - io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP); - io.enumCase(Value, "Thumb", PDB_Machine::Thumb); - io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) { - io.enumCase(Value, "V41", llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41); - io.enumCase(Value, "V50", llvm::pdb::PdbRaw_DbiVer::PdbDbiV50); - io.enumCase(Value, "V60", llvm::pdb::PdbRaw_DbiVer::PdbDbiV60); - io.enumCase(Value, "V70", llvm::pdb::PdbRaw_DbiVer::PdbDbiV70); - io.enumCase(Value, "V110", llvm::pdb::PdbRaw_DbiVer::PdbDbiV110); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) { - io.enumCase(Value, "VC2", llvm::pdb::PdbRaw_ImplVer::PdbImplVC2); - io.enumCase(Value, "VC4", llvm::pdb::PdbRaw_ImplVer::PdbImplVC4); - io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_ImplVer::PdbImplVC41); - io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_ImplVer::PdbImplVC50); - io.enumCase(Value, "VC98", llvm::pdb::PdbRaw_ImplVer::PdbImplVC98); - io.enumCase(Value, "VC70Dep", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep); - io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70); - io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_ImplVer::PdbImplVC80); - io.enumCase(Value, "VC110", llvm::pdb::PdbRaw_ImplVer::PdbImplVC110); - io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { - io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); - io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); - io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); - io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); - io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); - } -}; - -template <> struct ScalarEnumerationTraits { - static void enumeration(IO &io, PdbRaw_FeatureSig &Features) { - io.enumCase(Features, "MinimalDebugInfo", - PdbRaw_FeatureSig::MinimalDebugInfo); - io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge); - io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110); - io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140); - } -}; -} -} - -void MappingTraits::mapping(IO &IO, PdbObject &Obj) { - IO.mapOptional("MSF", Obj.Headers); - IO.mapOptional("StreamSizes", Obj.StreamSizes); - IO.mapOptional("StreamMap", Obj.StreamMap); - IO.mapOptional("StringTable", Obj.StringTable); - IO.mapOptional("PdbStream", Obj.PdbStream); - IO.mapOptional("DbiStream", Obj.DbiStream); - IO.mapOptional("TpiStream", Obj.TpiStream); - IO.mapOptional("IpiStream", Obj.IpiStream); -} - -void MappingTraits::mapping(IO &IO, MSFHeaders &Obj) { - IO.mapOptional("SuperBlock", Obj.SuperBlock); - IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks); - IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks); - IO.mapOptional("NumStreams", Obj.NumStreams); - IO.mapOptional("FileSize", Obj.FileSize); -} - -void MappingTraits::mapping(IO &IO, msf::SuperBlock &SB) { - if (!IO.outputting()) { - ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic)); - } - - using u32 = support::ulittle32_t; - IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U)); - IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U)); - IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U)); - IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U)); - IO.mapOptional("Unknown1", SB.Unknown1, u32(0U)); - IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U)); -} - -void MappingTraits::mapping(IO &IO, StreamBlockList &SB) { - IO.mapRequired("Stream", SB.Blocks); -} - -void MappingTraits::mapping(IO &IO, PdbInfoStream &Obj) { - IO.mapOptional("Age", Obj.Age, 1U); - IO.mapOptional("Guid", Obj.Guid); - IO.mapOptional("Signature", Obj.Signature, 0U); - IO.mapOptional("Features", Obj.Features); - IO.mapOptional("Version", Obj.Version, PdbImplVC70); -} - -void MappingTraits::mapping(IO &IO, PdbDbiStream &Obj) { - IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70); - IO.mapOptional("Age", Obj.Age, 1U); - IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U)); - IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U); - IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U)); - IO.mapOptional("Flags", Obj.Flags, uint16_t(1U)); - IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86); - IO.mapOptional("Modules", Obj.ModInfos); -} - -void MappingTraits::mapping(IO &IO, - pdb::yaml::PdbTpiStream &Obj) { - IO.mapOptional("Version", Obj.Version, PdbTpiV80); - IO.mapRequired("Records", Obj.Records); -} - -void MappingTraits::mapping(IO &IO, - NamedStreamMapping &Obj) { - IO.mapRequired("Name", Obj.StreamName); - IO.mapRequired("StreamNum", Obj.StreamNumber); -} - -void MappingTraits::mapping(IO &IO, PdbModiStream &Obj) { - IO.mapOptional("Signature", Obj.Signature, 4U); - IO.mapRequired("Records", Obj.Symbols); -} - -void MappingTraits::mapping(IO &IO, PdbDbiModuleInfo &Obj) { - IO.mapRequired("Module", Obj.Mod); - IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod); - IO.mapOptional("SourceFiles", Obj.SourceFiles); - IO.mapOptional("Subsections", Obj.Subsections); - IO.mapOptional("Modi", Obj.Modi); -} Index: llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.h +++ /dev/null @@ -1,35 +0,0 @@ -//===- PrettyBuiltinDumper.h ---------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { - -class LinePrinter; - -class BuiltinDumper : public PDBSymDumper { -public: - BuiltinDumper(LinePrinter &P); - - void start(const PDBSymbolTypeBuiltin &Symbol); - -private: - StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol); - - LinePrinter &Printer; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyBuiltinDumper.cpp +++ /dev/null @@ -1,94 +0,0 @@ -//===- PrettyBuiltinDumper.cpp ---------------------------------- *- C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyBuiltinDumper.h" -#include "LinePrinter.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" - -using namespace llvm; -using namespace llvm::pdb; - -BuiltinDumper::BuiltinDumper(LinePrinter &P) - : PDBSymDumper(false), Printer(P) {} - -void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) { - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; - WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol); -} - -StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) { - PDB_BuiltinType Type = Symbol.getBuiltinType(); - switch (Type) { - case PDB_BuiltinType::Float: - if (Symbol.getLength() == 4) - return "float"; - return "double"; - case PDB_BuiltinType::UInt: - switch (Symbol.getLength()) { - case 8: - return "unsigned __int64"; - case 4: - return "unsigned int"; - case 2: - return "unsigned short"; - case 1: - return "unsigned char"; - default: - return "unsigned"; - } - case PDB_BuiltinType::Int: - switch (Symbol.getLength()) { - case 8: - return "__int64"; - case 4: - return "int"; - case 2: - return "short"; - case 1: - return "char"; - default: - return "int"; - } - case PDB_BuiltinType::Char: - return "char"; - case PDB_BuiltinType::WCharT: - return "wchar_t"; - case PDB_BuiltinType::Void: - return "void"; - case PDB_BuiltinType::Long: - return "long"; - case PDB_BuiltinType::ULong: - return "unsigned long"; - case PDB_BuiltinType::Bool: - return "bool"; - case PDB_BuiltinType::Currency: - return "CURRENCY"; - case PDB_BuiltinType::Date: - return "DATE"; - case PDB_BuiltinType::Variant: - return "VARIANT"; - case PDB_BuiltinType::Complex: - return "complex"; - case PDB_BuiltinType::Bitfield: - return "bitfield"; - case PDB_BuiltinType::BSTR: - return "BSTR"; - case PDB_BuiltinType::HResult: - return "HRESULT"; - case PDB_BuiltinType::BCD: - return "HRESULT"; - default: - return "void"; - } -} Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.h +++ /dev/null @@ -1,47 +0,0 @@ -//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H - -#include "llvm/ADT/BitVector.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" - -#include -#include -#include - -namespace llvm { -class BitVector; - -namespace pdb { - -class ClassLayout; -class LinePrinter; - -class ClassDefinitionDumper : public PDBSymDumper { -public: - ClassDefinitionDumper(LinePrinter &P); - - void start(const PDBSymbolTypeUDT &Class); - void start(const ClassLayout &Class); - -private: - void prettyPrintClassIntro(const ClassLayout &Class); - void prettyPrintClassOutro(const ClassLayout &Class); - - LinePrinter &Printer; - bool DumpedAnything = false; -}; -} -} -#endif Index: llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassDefinitionDumper.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyClassDefinitionDumper.h" - -#include "LinePrinter.h" -#include "PrettyClassLayoutGraphicalDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/ADT/APFloat.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/UDTLayout.h" - -#include "llvm/Support/Format.h" - -using namespace llvm; -using namespace llvm::pdb; - -ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) - : PDBSymDumper(true), Printer(P) {} - -void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { - assert(opts::pretty::ClassFormat != - opts::pretty::ClassDefinitionFormat::None); - - ClassLayout Layout(Class); - start(Layout); -} - -void ClassDefinitionDumper::start(const ClassLayout &Layout) { - prettyPrintClassIntro(Layout); - - PrettyClassLayoutGraphicalDumper Dumper(Printer, 1, 0); - DumpedAnything |= Dumper.start(Layout); - - prettyPrintClassOutro(Layout); -} - -void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { - DumpedAnything = false; - Printer.NewLine(); - - uint32_t Size = Layout.getSize(); - const PDBSymbolTypeUDT &Class = Layout.getClass(); - - WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; - WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); - WithColor(Printer, PDB_ColorItem::Comment).get() << " [sizeof = " << Size - << "]"; - uint32_t BaseCount = Layout.bases().size(); - if (BaseCount > 0) { - Printer.Indent(); - char NextSeparator = ':'; - for (auto BC : Layout.bases()) { - const auto &Base = BC->getBase(); - if (Base.isIndirectVirtualBaseClass()) - continue; - - Printer.NewLine(); - Printer << NextSeparator << " "; - WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); - if (BC->isVirtualBase()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; - - WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); - NextSeparator = ','; - } - - Printer.Unindent(); - } - - Printer << " {"; - Printer.Indent(); -} - -void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) { - Printer.Unindent(); - if (DumpedAnything) - Printer.NewLine(); - Printer << "}"; - Printer.NewLine(); - if (Layout.deepPaddingSize() > 0) { - APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / - (double)Layout.getSize()); - SmallString<8> PctStr; - Pct.toString(PctStr, 4); - WithColor(Printer, PDB_ColorItem::Padding).get() - << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr - << "% of class size)"; - Printer.NewLine(); - APFloat Pct2(100.0 * (double)Layout.immediatePadding() / - (double)Layout.getSize()); - PctStr.clear(); - Pct2.toString(PctStr, 4); - WithColor(Printer, PDB_ColorItem::Padding).get() - << "Immediate padding " << Layout.immediatePadding() << " bytes (" - << PctStr << "% of class size)"; - Printer.NewLine(); - } -} Index: llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.h +++ /dev/null @@ -1,58 +0,0 @@ -//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H - -#include "llvm/ADT/BitVector.h" - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { - -namespace pdb { - -class UDTLayoutBase; -class LayoutItemBase; -class LinePrinter; - -class PrettyClassLayoutGraphicalDumper : public PDBSymDumper { -public: - PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t RecurseLevel, - uint32_t InitialOffset); - - bool start(const UDTLayoutBase &Layout); - - // Layout based symbol types. - void dump(const PDBSymbolTypeBaseClass &Symbol) override; - void dump(const PDBSymbolData &Symbol) override; - void dump(const PDBSymbolTypeVTable &Symbol) override; - - // Non layout-based symbol types. - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolFunc &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; - void dump(const PDBSymbolTypeBuiltin &Symbol) override; - -private: - bool shouldRecurse() const; - void printPaddingRow(uint32_t Amount); - - LinePrinter &Printer; - - LayoutItemBase *CurrentItem = nullptr; - uint32_t RecursionLevel = 0; - uint32_t ClassOffsetZero = 0; - uint32_t CurrentAbsoluteOffset = 0; - bool DumpedAnything = false; -}; -} -} -#endif Index: llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyClassLayoutGraphicalDumper.cpp +++ /dev/null @@ -1,216 +0,0 @@ -//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyClassLayoutGraphicalDumper.h" - -#include "LinePrinter.h" -#include "PrettyClassDefinitionDumper.h" -#include "PrettyEnumDumper.h" -#include "PrettyFunctionDumper.h" -#include "PrettyTypedefDumper.h" -#include "PrettyVariableDumper.h" -#include "PrettyVariableDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/UDTLayout.h" -#include "llvm/Support/Format.h" - -using namespace llvm; -using namespace llvm::pdb; - -PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( - LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset) - : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel), - ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {} - -bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { - - if (RecursionLevel == 1 && - opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) { - for (auto &Other : Layout.other_items()) - Other->dump(*this); - for (auto &Func : Layout.funcs()) - Func->dump(*this); - } - - const BitVector &UseMap = Layout.usedBytes(); - int NextPaddingByte = UseMap.find_first_unset(); - - for (auto &Item : Layout.layout_items()) { - // Calculate the absolute offset of the first byte of the next field. - uint32_t RelativeOffset = Item->getOffsetInParent(); - CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; - - // Since there is storage there, it should be set! However, this might - // be an empty base, in which case it could extend outside the bounds of - // the parent class. - if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { - assert(UseMap.test(RelativeOffset)); - - // If there is any remaining padding in this class, and the offset of the - // new item is after the padding, then we must have just jumped over some - // padding. Print a padding row and then look for where the next block - // of padding begins. - if ((NextPaddingByte >= 0) && - (RelativeOffset > uint32_t(NextPaddingByte))) { - printPaddingRow(RelativeOffset - NextPaddingByte); - NextPaddingByte = UseMap.find_next_unset(RelativeOffset); - } - } - - CurrentItem = Item; - if (Item->isVBPtr()) { - VTableLayoutItem &Layout = static_cast(*CurrentItem); - - VariableDumper VarDumper(Printer); - VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); - } else { - if (auto Sym = Item->getSymbol()) - Sym->dump(*this); - } - - if (Item->getLayoutSize() > 0) { - uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; - if (Prev < UseMap.size()) - NextPaddingByte = UseMap.find_next_unset(Prev); - } - } - - auto TailPadding = Layout.tailPadding(); - if (TailPadding > 0) { - if (TailPadding != 1 || Layout.getSize() != 1) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Padding).get() - << " (" << TailPadding << " bytes)"; - DumpedAnything = true; - } - } - - return DumpedAnything; -} - -void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { - if (Amount == 0) - return; - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Padding).get() << " (" << Amount - << " bytes)"; - DumpedAnything = true; -} - -void PrettyClassLayoutGraphicalDumper::dump( - const PDBSymbolTypeBaseClass &Symbol) { - assert(CurrentItem != nullptr); - - Printer.NewLine(); - BaseClassLayout &Layout = static_cast(*CurrentItem); - - std::string Label = "base"; - if (Layout.isVirtualBase()) { - Label.insert(Label.begin(), 'v'); - if (Layout.getBase().isIndirectVirtualBaseClass()) - Label.insert(Label.begin(), 'i'); - } - Printer << Label << " "; - - uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); - - WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size - << "] "; - - WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); - - if (shouldRecurse()) { - Printer.Indent(); - uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); - PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1, - ChildOffsetZero); - DumpedAnything |= BaseDumper.start(Layout); - Printer.Unindent(); - } - - DumpedAnything = true; -} - -bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const { - uint32_t Limit = opts::pretty::ClassRecursionDepth; - if (Limit == 0) - return true; - return RecursionLevel < Limit; -} - -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { - assert(CurrentItem != nullptr); - - DataMemberLayoutItem &Layout = - static_cast(*CurrentItem); - - VariableDumper VarDumper(Printer); - VarDumper.start(Symbol, ClassOffsetZero); - - if (Layout.hasUDTLayout() && shouldRecurse()) { - uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); - Printer.Indent(); - PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1, - ChildOffsetZero); - TypeDumper.start(Layout.getUDTLayout()); - Printer.Unindent(); - } - - DumpedAnything = true; -} - -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { - assert(CurrentItem != nullptr); - - VariableDumper VarDumper(Printer); - VarDumper.start(Symbol, ClassOffsetZero); - - DumpedAnything = true; -} - -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) { - DumpedAnything = true; - Printer.NewLine(); - EnumDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void PrettyClassLayoutGraphicalDumper::dump( - const PDBSymbolTypeTypedef &Symbol) { - DumpedAnything = true; - Printer.NewLine(); - TypedefDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void PrettyClassLayoutGraphicalDumper::dump( - const PDBSymbolTypeBuiltin &Symbol) {} - -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} - -void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) { - if (Printer.IsSymbolExcluded(Symbol.getName())) - return; - if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) - return; - if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && - !Symbol.isIntroVirtualFunction()) - return; - - DumpedAnything = true; - Printer.NewLine(); - FunctionDumper Dumper(Printer); - Dumper.start(Symbol, FunctionDumper::PointerType::None); -} Index: llvm/tools/llvm-pdbdump/PrettyCompilandDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyCompilandDumper.h +++ /dev/null @@ -1,44 +0,0 @@ -//===- PrettyCompilandDumper.h - llvm-pdbdump compiland dumper -*- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { - -class LinePrinter; - -typedef int CompilandDumpFlags; -class CompilandDumper : public PDBSymDumper { -public: - enum Flags { None = 0x0, Children = 0x1, Symbols = 0x2, Lines = 0x4 }; - - CompilandDumper(LinePrinter &P); - - void start(const PDBSymbolCompiland &Symbol, CompilandDumpFlags flags); - - void dump(const PDBSymbolCompilandDetails &Symbol) override; - void dump(const PDBSymbolCompilandEnv &Symbol) override; - void dump(const PDBSymbolData &Symbol) override; - void dump(const PDBSymbolFunc &Symbol) override; - void dump(const PDBSymbolLabel &Symbol) override; - void dump(const PDBSymbolThunk &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolUnknown &Symbol) override; - -private: - LinePrinter &Printer; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PrettyCompilandDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyCompilandDumper.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//===- PrettyCompilandDumper.cpp - llvm-pdbdump compiland dumper -*- C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyCompilandDumper.h" - -#include "LinePrinter.h" -#include "PrettyFunctionDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBSymbol.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" -#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" -#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" - -#include - -using namespace llvm; -using namespace llvm::pdb; - -CompilandDumper::CompilandDumper(LinePrinter &P) - : PDBSymDumper(true), Printer(P) {} - -void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {} - -void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {} - -void CompilandDumper::start(const PDBSymbolCompiland &Symbol, - CompilandDumpFlags opts) { - std::string FullName = Symbol.getName(); - if (Printer.IsCompilandExcluded(FullName)) - return; - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Path).get() << FullName; - - if (opts & Flags::Lines) { - const IPDBSession &Session = Symbol.getSession(); - auto Files = Session.getSourceFilesForCompiland(Symbol); - Printer.Indent(); - while (auto File = Files->getNext()) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Path).get() << File->getFileName(); - - auto Lines = Session.findLineNumbers(Symbol, *File); - Printer.Indent(); - while (auto Line = Lines->getNext()) { - Printer.NewLine(); - uint32_t LineStart = Line->getLineNumber(); - uint32_t LineEnd = Line->getLineNumberEnd(); - - Printer << "Line "; - PDB_ColorItem StatementColor = Line->isStatement() - ? PDB_ColorItem::Keyword - : PDB_ColorItem::LiteralValue; - WithColor(Printer, StatementColor).get() << LineStart; - if (LineStart != LineEnd) - WithColor(Printer, StatementColor).get() << " - " << LineEnd; - - uint32_t ColumnStart = Line->getColumnNumber(); - uint32_t ColumnEnd = Line->getColumnNumberEnd(); - if (ColumnStart != 0 || ColumnEnd != 0) { - Printer << ", Column: "; - WithColor(Printer, StatementColor).get() << ColumnStart; - if (ColumnEnd != ColumnStart) - WithColor(Printer, StatementColor).get() << " - " << ColumnEnd; - } - - Printer << ", Address: "; - if (Line->getLength() > 0) { - uint64_t AddrStart = Line->getVirtualAddress(); - uint64_t AddrEnd = AddrStart + Line->getLength() - 1; - WithColor(Printer, PDB_ColorItem::Address).get() - << "[" << format_hex(AddrStart, 10) << " - " - << format_hex(AddrEnd, 10) << "]"; - Printer << " (" << Line->getLength() << " bytes)"; - } else { - uint64_t AddrStart = Line->getVirtualAddress(); - WithColor(Printer, PDB_ColorItem::Address).get() - << "[" << format_hex(AddrStart, 10) << "] "; - Printer << "(0 bytes)"; - } - } - Printer.Unindent(); - } - Printer.Unindent(); - } - - if (opts & Flags::Children) { - auto ChildrenEnum = Symbol.findAllChildren(); - Printer.Indent(); - while (auto Child = ChildrenEnum->getNext()) - Child->dump(*this); - Printer.Unindent(); - } -} - -void CompilandDumper::dump(const PDBSymbolData &Symbol) { - if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data)) - return; - if (Printer.IsSymbolExcluded(Symbol.getName())) - return; - - Printer.NewLine(); - - switch (auto LocType = Symbol.getLocationType()) { - case PDB_LocType::Static: - Printer << "data: "; - WithColor(Printer, PDB_ColorItem::Address).get() - << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]"; - - WithColor(Printer, PDB_ColorItem::Comment).get() - << " [sizeof = " << getTypeLength(Symbol) << "]"; - - break; - case PDB_LocType::Constant: - Printer << "constant: "; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() - << "[" << Symbol.getValue() << "]"; - WithColor(Printer, PDB_ColorItem::Comment).get() - << " [sizeof = " << getTypeLength(Symbol) << "]"; - break; - default: - Printer << "data(unexpected type=" << LocType << ")"; - } - - Printer << " "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); -} - -void CompilandDumper::dump(const PDBSymbolFunc &Symbol) { - if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) - return; - if (Symbol.getLength() == 0) - return; - if (Printer.IsSymbolExcluded(Symbol.getName())) - return; - - Printer.NewLine(); - FunctionDumper Dumper(Printer); - Dumper.start(Symbol, FunctionDumper::PointerType::None); -} - -void CompilandDumper::dump(const PDBSymbolLabel &Symbol) { - if (Printer.IsSymbolExcluded(Symbol.getName())) - return; - - Printer.NewLine(); - Printer << "label "; - WithColor(Printer, PDB_ColorItem::Address).get() - << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); -} - -void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { - if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) - return; - if (Printer.IsSymbolExcluded(Symbol.getName())) - return; - - Printer.NewLine(); - Printer << "thunk "; - codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); - uint64_t VA = Symbol.getVirtualAddress(); - if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) { - uint64_t Target = Symbol.getTargetVirtualAddress(); - WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10); - Printer << " -> "; - WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10); - } else { - WithColor(Printer, PDB_ColorItem::Address).get() - << "[" << format_hex(VA, 10) << " - " - << format_hex(VA + Symbol.getLength(), 10) << "]"; - } - Printer << " ("; - WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal; - Printer << ") "; - std::string Name = Symbol.getName(); - if (!Name.empty()) - WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; -} - -void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {} - -void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) { - Printer.NewLine(); - Printer << "unknown (" << Symbol.getSymTag() << ")"; -} Index: llvm/tools/llvm-pdbdump/PrettyEnumDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyEnumDumper.h +++ /dev/null @@ -1,31 +0,0 @@ -//===- PrettyEnumDumper.h ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { - -class LinePrinter; - -class EnumDumper : public PDBSymDumper { -public: - EnumDumper(LinePrinter &P); - - void start(const PDBSymbolTypeEnum &Symbol); - -private: - LinePrinter &Printer; -}; -} -} -#endif Index: llvm/tools/llvm-pdbdump/PrettyEnumDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyEnumDumper.cpp +++ /dev/null @@ -1,53 +0,0 @@ -//===- PrettyEnumDumper.cpp -------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyEnumDumper.h" - -#include "LinePrinter.h" -#include "PrettyBuiltinDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" - -using namespace llvm; -using namespace llvm::pdb; - -EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} - -void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { - WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); - if (!opts::pretty::NoEnumDefs) { - auto BuiltinType = Symbol.getUnderlyingType(); - if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int || - BuiltinType->getLength() != 4) { - Printer << " : "; - BuiltinDumper Dumper(Printer); - Dumper.start(*BuiltinType); - } - Printer << " {"; - Printer.Indent(); - auto EnumValues = Symbol.findAllChildren(); - while (auto EnumValue = EnumValues->getNext()) { - if (EnumValue->getDataKind() != PDB_DataKind::Constant) - continue; - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() - << EnumValue->getName(); - Printer << " = "; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() - << EnumValue->getValue(); - } - Printer.Unindent(); - Printer.NewLine(); - Printer << "}"; - } -} Index: llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.h +++ /dev/null @@ -1,34 +0,0 @@ -//===- PrettyExternalSymbolDumper.h --------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { - -class LinePrinter; - -class ExternalSymbolDumper : public PDBSymDumper { -public: - ExternalSymbolDumper(LinePrinter &P); - - void start(const PDBSymbolExe &Symbol); - - void dump(const PDBSymbolPublicSymbol &Symbol) override; - -private: - LinePrinter &Printer; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyExternalSymbolDumper.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//===- PrettyExternalSymbolDumper.cpp -------------------------- *- C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyExternalSymbolDumper.h" -#include "LinePrinter.h" - -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" -#include "llvm/Support/Format.h" - -using namespace llvm; -using namespace llvm::pdb; - -ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P) - : PDBSymDumper(true), Printer(P) {} - -void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) { - auto Vars = Symbol.findAllChildren(); - while (auto Var = Vars->getNext()) - Var->dump(*this); -} - -void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) { - std::string LinkageName = Symbol.getName(); - if (Printer.IsSymbolExcluded(LinkageName)) - return; - - Printer.NewLine(); - uint64_t Addr = Symbol.getVirtualAddress(); - - Printer << "["; - WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10); - Printer << "] "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName; -} Index: llvm/tools/llvm-pdbdump/PrettyFunctionDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyFunctionDumper.h +++ /dev/null @@ -1,43 +0,0 @@ -//===- PrettyFunctionDumper.h --------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { -class LinePrinter; - -class FunctionDumper : public PDBSymDumper { -public: - FunctionDumper(LinePrinter &P); - - enum class PointerType { None, Pointer, Reference }; - - void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name, - PointerType Pointer); - void start(const PDBSymbolFunc &Symbol, PointerType Pointer); - - void dump(const PDBSymbolTypeArray &Symbol) override; - void dump(const PDBSymbolTypeBuiltin &Symbol) override; - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolTypeFunctionArg &Symbol) override; - void dump(const PDBSymbolTypePointer &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; - -private: - LinePrinter &Printer; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyFunctionDumper.cpp +++ /dev/null @@ -1,259 +0,0 @@ -//===- PrettyFunctionDumper.cpp --------------------------------- *- C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyFunctionDumper.h" -#include "LinePrinter.h" -#include "PrettyBuiltinDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -namespace { -template -void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer, - FunctionDumper &Dumper) { - uint32_t ClassParentId = Symbol.getClassParentId(); - auto ClassParent = - Symbol.getSession().template getConcreteSymbolById( - ClassParentId); - if (!ClassParent) - return; - - WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName(); - Printer << "::"; -} -} - -FunctionDumper::FunctionDumper(LinePrinter &P) - : PDBSymDumper(true), Printer(P) {} - -void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, - const char *Name, PointerType Pointer) { - auto ReturnType = Symbol.getReturnType(); - ReturnType->dump(*this); - Printer << " "; - uint32_t ClassParentId = Symbol.getClassParentId(); - auto ClassParent = - Symbol.getSession().getConcreteSymbolById( - ClassParentId); - - PDB_CallingConv CC = Symbol.getCallingConvention(); - bool ShouldDumpCallingConvention = true; - if ((ClassParent && CC == CallingConvention::ThisCall) || - (!ClassParent && CC == CallingConvention::NearStdCall)) { - ShouldDumpCallingConvention = false; - } - - if (Pointer == PointerType::None) { - if (ShouldDumpCallingConvention) - WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; - if (ClassParent) { - Printer << "("; - WithColor(Printer, PDB_ColorItem::Identifier).get() - << ClassParent->getName(); - Printer << "::)"; - } - } else { - Printer << "("; - if (ShouldDumpCallingConvention) - WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; - if (ClassParent) { - WithColor(Printer, PDB_ColorItem::Identifier).get() - << ClassParent->getName(); - Printer << "::"; - } - if (Pointer == PointerType::Reference) - Printer << "&"; - else - Printer << "*"; - if (Name) - WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; - Printer << ")"; - } - - Printer << "("; - if (auto ChildEnum = Symbol.getArguments()) { - uint32_t Index = 0; - while (auto Arg = ChildEnum->getNext()) { - Arg->dump(*this); - if (++Index < ChildEnum->getChildCount()) - Printer << ", "; - } - } - Printer << ")"; - - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; -} - -void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) { - uint64_t FuncStart = Symbol.getVirtualAddress(); - uint64_t FuncEnd = FuncStart + Symbol.getLength(); - - Printer << "func ["; - WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10); - if (auto DebugStart = Symbol.findOneChild()) { - uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart; - WithColor(Printer, PDB_ColorItem::Offset).get() - << formatv("+{0,2}", Prologue); - } - Printer << " - "; - WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10); - if (auto DebugEnd = Symbol.findOneChild()) { - uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress(); - WithColor(Printer, PDB_ColorItem::Offset).get() - << formatv("-{0,2}", Epilogue); - } - - WithColor(Printer, PDB_ColorItem::Comment).get() - << formatv(" | sizeof={0,3}", Symbol.getLength()); - Printer << "] ("; - - if (Symbol.hasFramePointer()) { - WithColor(Printer, PDB_ColorItem::Register).get() - << Symbol.getLocalBasePointerRegisterId(); - } else { - WithColor(Printer, PDB_ColorItem::Register).get() << "FPO"; - } - Printer << ") "; - - if (Symbol.isVirtual() || Symbol.isPureVirtual()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual "; - - auto Signature = Symbol.getSignature(); - if (!Signature) { - WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); - if (Pointer == PointerType::Pointer) - Printer << "*"; - else if (Pointer == FunctionDumper::PointerType::Reference) - Printer << "&"; - return; - } - - auto ReturnType = Signature->getReturnType(); - ReturnType->dump(*this); - Printer << " "; - - auto ClassParent = Symbol.getClassParent(); - CallingConvention CC = Signature->getCallingConvention(); - if (Pointer != FunctionDumper::PointerType::None) - Printer << "("; - - if ((ClassParent && CC != CallingConvention::ThisCall) || - (!ClassParent && CC != CallingConvention::NearStdCall)) { - WithColor(Printer, PDB_ColorItem::Keyword).get() - << Signature->getCallingConvention() << " "; - } - WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); - if (Pointer != FunctionDumper::PointerType::None) { - if (Pointer == PointerType::Pointer) - Printer << "*"; - else if (Pointer == FunctionDumper::PointerType::Reference) - Printer << "&"; - Printer << ")"; - } - - Printer << "("; - if (auto Arguments = Symbol.getArguments()) { - uint32_t Index = 0; - while (auto Arg = Arguments->getNext()) { - auto ArgType = Arg->getType(); - ArgType->dump(*this); - WithColor(Printer, PDB_ColorItem::Identifier).get() << " " - << Arg->getName(); - if (++Index < Arguments->getChildCount()) - Printer << ", "; - } - } - Printer << ")"; - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; - if (Symbol.isPureVirtual()) - Printer << " = 0"; -} - -void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) { - auto ElementType = Symbol.getElementType(); - - ElementType->dump(*this); - Printer << "["; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength(); - Printer << "]"; -} - -void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { - BuiltinDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) { - dumpClassParentWithScopeOperator(Symbol, Printer, *this); - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} - -void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { - // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill - // through to the real thing and dump it. - uint32_t TypeId = Symbol.getTypeId(); - auto Type = Symbol.getSession().getSymbolById(TypeId); - if (!Type) - return; - Type->dump(*this); -} - -void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { - dumpClassParentWithScopeOperator(Symbol, Printer, *this); - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} - -void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) { - auto PointeeType = Symbol.getPointeeType(); - if (!PointeeType) - return; - - if (auto FuncSig = unique_dyn_cast(PointeeType)) { - FunctionDumper NestedDumper(Printer); - PointerType Pointer = - Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; - NestedDumper.start(*FuncSig, nullptr, Pointer); - } else { - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; - PointeeType->dump(*this); - Printer << (Symbol.isReference() ? "&" : "*"); - } -} - -void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) { - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} Index: llvm/tools/llvm-pdbdump/PrettyTypeDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypeDumper.h +++ /dev/null @@ -1,36 +0,0 @@ -//===- PrettyTypeDumper.h - PDBSymDumper implementation for types *- C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { -class LinePrinter; -class ClassLayout; - -class TypeDumper : public PDBSymDumper { -public: - TypeDumper(LinePrinter &P); - - void start(const PDBSymbolExe &Exe); - - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - - void dumpClassLayout(const ClassLayout &Class); - -private: - LinePrinter &Printer; -}; -} -} -#endif Index: llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypeDumper.cpp +++ /dev/null @@ -1,255 +0,0 @@ -//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyTypeDumper.h" - -#include "LinePrinter.h" -#include "PrettyBuiltinDumper.h" -#include "PrettyClassDefinitionDumper.h" -#include "PrettyEnumDumper.h" -#include "PrettyTypedefDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/UDTLayout.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/FormatVariadic.h" - -using namespace llvm; -using namespace llvm::pdb; - -using LayoutPtr = std::unique_ptr; - -typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); - -static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { - return S1->getName() < S2->getName(); -} - -static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { - return S1->getSize() < S2->getSize(); -} - -static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { - return S1->deepPaddingSize() < S2->deepPaddingSize(); -} - -static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { - double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); - double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); - return Pct1 < Pct2; -} - -static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) { - return S1->immediatePadding() < S2->immediatePadding(); -} - -static bool ComparePaddingPctImmediate(const LayoutPtr &S1, - const LayoutPtr &S2) { - double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize(); - double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize(); - return Pct1 < Pct2; -} - -static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { - switch (Mode) { - case opts::pretty::ClassSortMode::Name: - return CompareNames; - case opts::pretty::ClassSortMode::Size: - return CompareSizes; - case opts::pretty::ClassSortMode::Padding: - return ComparePadding; - case opts::pretty::ClassSortMode::PaddingPct: - return ComparePaddingPct; - case opts::pretty::ClassSortMode::PaddingImmediate: - return ComparePaddingImmediate; - case opts::pretty::ClassSortMode::PaddingPctImmediate: - return ComparePaddingPctImmediate; - default: - return nullptr; - } -} - -template -static std::vector> -filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, - uint32_t UnfilteredCount) { - std::vector> Filtered; - - Filtered.reserve(UnfilteredCount); - CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); - - if (UnfilteredCount > 10000) { - errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); - errs().flush(); - } - uint32_t Examined = 0; - uint32_t Discarded = 0; - while (auto Class = E.getNext()) { - ++Examined; - if (Examined % 10000 == 0) { - errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", - Examined, UnfilteredCount, Discarded); - errs().flush(); - } - - if (Class->getUnmodifiedTypeId() != 0) { - ++Discarded; - continue; - } - - if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { - ++Discarded; - continue; - } - - auto Layout = llvm::make_unique(std::move(Class)); - if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { - ++Discarded; - continue; - } - if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) { - ++Discarded; - continue; - } - - Filtered.push_back(std::move(Layout)); - } - - if (Comp) - std::sort(Filtered.begin(), Filtered.end(), Comp); - return Filtered; -} - -TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} - -void TypeDumper::start(const PDBSymbolExe &Exe) { - auto Children = Exe.findAllChildren(); - if (opts::pretty::Enums) { - if (auto Enums = Exe.findAllChildren()) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums"; - Printer << ": (" << Enums->getChildCount() << " items)"; - Printer.Indent(); - while (auto Enum = Enums->getNext()) - Enum->dump(*this); - Printer.Unindent(); - } - } - - if (opts::pretty::Typedefs) { - if (auto Typedefs = Exe.findAllChildren()) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs"; - Printer << ": (" << Typedefs->getChildCount() << " items)"; - Printer.Indent(); - while (auto Typedef = Typedefs->getNext()) - Typedef->dump(*this); - Printer.Unindent(); - } - } - - if (opts::pretty::Classes) { - if (auto Classes = Exe.findAllChildren()) { - uint32_t All = Classes->getChildCount(); - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; - - bool Precompute = false; - Precompute = - (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); - - // If we're using no sort mode, then we can start getting immediate output - // from the tool by just filtering as we go, rather than processing - // everything up front so that we can sort it. This makes the tool more - // responsive. So only precompute the filtered/sorted set of classes if - // necessary due to the specified options. - std::vector Filtered; - uint32_t Shown = All; - if (Precompute) { - Filtered = filterAndSortClassDefs(Printer, *Classes, All); - - Shown = Filtered.size(); - } - - Printer << ": (Showing " << Shown << " items"; - if (Shown < All) - Printer << ", " << (All - Shown) << " filtered"; - Printer << ")"; - Printer.Indent(); - - // If we pre-computed, iterate the filtered/sorted list, otherwise iterate - // the DIA enumerator and filter on the fly. - if (Precompute) { - for (auto &Class : Filtered) - dumpClassLayout(*Class); - } else { - while (auto Class = Classes->getNext()) { - if (Class->getUnmodifiedTypeId() != 0) - continue; - - if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) - continue; - - auto Layout = llvm::make_unique(std::move(Class)); - if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) - continue; - - dumpClassLayout(*Layout); - } - } - - Printer.Unindent(); - } - } -} - -void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { - assert(opts::pretty::Enums); - - if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) - return; - // Dump member enums when dumping their class definition. - if (nullptr != Symbol.getClassParent()) - return; - - Printer.NewLine(); - EnumDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { - assert(opts::pretty::Typedefs); - - if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) - return; - - Printer.NewLine(); - TypedefDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void TypeDumper::dumpClassLayout(const ClassLayout &Class) { - assert(opts::pretty::Classes); - - if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName(); - } else { - ClassDefinitionDumper Dumper(Printer); - Dumper.start(Class); - } -} Index: llvm/tools/llvm-pdbdump/PrettyTypedefDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypedefDumper.h +++ /dev/null @@ -1,39 +0,0 @@ -//===- PrettyTypedefDumper.h - llvm-pdbdump typedef dumper ---*- C++ ----*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { -namespace pdb { - -class LinePrinter; - -class TypedefDumper : public PDBSymDumper { -public: - TypedefDumper(LinePrinter &P); - - void start(const PDBSymbolTypeTypedef &Symbol); - - void dump(const PDBSymbolTypeArray &Symbol) override; - void dump(const PDBSymbolTypeBuiltin &Symbol) override; - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolTypeFunctionSig &Symbol) override; - void dump(const PDBSymbolTypePointer &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; - -private: - LinePrinter &Printer; -}; -} -} - -#endif Index: llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyTypedefDumper.cpp +++ /dev/null @@ -1,77 +0,0 @@ -//===- PrettyTypedefDumper.cpp - PDBSymDumper impl for typedefs -- * C++ *-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyTypedefDumper.h" - -#include "LinePrinter.h" -#include "PrettyBuiltinDumper.h" -#include "PrettyFunctionDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" - -using namespace llvm; -using namespace llvm::pdb; - -TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} - -void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) { - WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; - uint32_t TargetId = Symbol.getTypeId(); - if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId)) - TypeSymbol->dump(*this); - WithColor(Printer, PDB_ColorItem::Identifier).get() << " " - << Symbol.getName(); -} - -void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {} - -void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { - BuiltinDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) { - WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; - WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName(); -} - -void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) { - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; - auto PointeeType = Symbol.getPointeeType(); - if (auto FuncSig = unique_dyn_cast(PointeeType)) { - FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; - if (Symbol.isReference()) - Pointer = FunctionDumper::PointerType::Reference; - FunctionDumper NestedDumper(Printer); - NestedDumper.start(*FuncSig, nullptr, Pointer); - } else { - PointeeType->dump(*this); - Printer << ((Symbol.isReference()) ? "&" : "*"); - } -} - -void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { - FunctionDumper Dumper(Printer); - Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); -} - -void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) { - WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} Index: llvm/tools/llvm-pdbdump/PrettyVariableDumper.h =================================================================== --- llvm/tools/llvm-pdbdump/PrettyVariableDumper.h +++ /dev/null @@ -1,50 +0,0 @@ -//===- PrettyVariableDumper.h - PDBSymDumper variable dumper ----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H -#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H - -#include "llvm/DebugInfo/PDB/PDBSymDumper.h" - -namespace llvm { - -class StringRef; - -namespace pdb { - -class LinePrinter; - -class VariableDumper : public PDBSymDumper { -public: - VariableDumper(LinePrinter &P); - - void start(const PDBSymbolData &Var, uint32_t Offset = 0); - void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0); - void startVbptr(uint32_t Offset, uint32_t Size); - - void dump(const PDBSymbolTypeArray &Symbol) override; - void dump(const PDBSymbolTypeBuiltin &Symbol) override; - void dump(const PDBSymbolTypeEnum &Symbol) override; - void dump(const PDBSymbolTypeFunctionSig &Symbol) override; - void dump(const PDBSymbolTypePointer &Symbol) override; - void dump(const PDBSymbolTypeTypedef &Symbol) override; - void dump(const PDBSymbolTypeUDT &Symbol) override; - - void dumpRight(const PDBSymbolTypeArray &Symbol) override; - void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override; - void dumpRight(const PDBSymbolTypePointer &Symbol) override; - -private: - void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name); - - LinePrinter &Printer; -}; -} -} -#endif Index: llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp =================================================================== --- llvm/tools/llvm-pdbdump/PrettyVariableDumper.cpp +++ /dev/null @@ -1,220 +0,0 @@ -//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "PrettyVariableDumper.h" - -#include "LinePrinter.h" -#include "PrettyBuiltinDumper.h" -#include "PrettyFunctionDumper.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" -#include "llvm/DebugInfo/PDB/PDBTypes.h" - -#include "llvm/Support/Format.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -VariableDumper::VariableDumper(LinePrinter &P) - : PDBSymDumper(true), Printer(P) {} - -void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) { - if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) - return; - if (Printer.IsSymbolExcluded(Var.getName())) - return; - - auto VarType = Var.getType(); - - uint64_t Length = VarType->getRawSymbol().getLength(); - - switch (auto LocType = Var.getLocationType()) { - case PDB_LocType::Static: - Printer.NewLine(); - Printer << "data ["; - WithColor(Printer, PDB_ColorItem::Address).get() - << format_hex(Var.getVirtualAddress(), 10); - Printer << ", sizeof=" << Length << "] "; - WithColor(Printer, PDB_ColorItem::Keyword).get() << "static "; - dumpSymbolTypeAndName(*VarType, Var.getName()); - break; - case PDB_LocType::Constant: - if (isa(*VarType)) - break; - Printer.NewLine(); - Printer << "data [sizeof=" << Length << "] "; - dumpSymbolTypeAndName(*VarType, Var.getName()); - Printer << " = "; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue(); - break; - case PDB_LocType::ThisRel: - Printer.NewLine(); - Printer << "data "; - WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Offset + Var.getOffset(), 4) - << " [sizeof=" << Length << "] "; - dumpSymbolTypeAndName(*VarType, Var.getName()); - break; - case PDB_LocType::BitField: - Printer.NewLine(); - Printer << "data "; - WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Offset + Var.getOffset(), 4) - << " [sizeof=" << Length << "] "; - dumpSymbolTypeAndName(*VarType, Var.getName()); - Printer << " : "; - WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); - break; - default: - Printer.NewLine(); - Printer << "data [sizeof=" << Length << "] "; - Printer << "unknown(" << LocType << ") "; - WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName(); - break; - } -} - -void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) { - Printer.NewLine(); - Printer << "vbptr "; - - WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] "; -} - -void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) { - Printer.NewLine(); - Printer << "vfptr "; - auto VTableType = cast(Var.getType()); - uint32_t PointerSize = VTableType->getLength(); - - WithColor(Printer, PDB_ColorItem::Offset).get() - << "+" << format_hex(Offset + Var.getOffset(), 4) - << " [sizeof=" << PointerSize << "] "; -} - -void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) { - auto ElementType = Symbol.getElementType(); - assert(ElementType); - if (!ElementType) - return; - ElementType->dump(*this); -} - -void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) { - auto ElementType = Symbol.getElementType(); - assert(ElementType); - if (!ElementType) - return; - Printer << '[' << Symbol.getCount() << ']'; - ElementType->dumpRight(*this); -} - -void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { - BuiltinDumper Dumper(Printer); - Dumper.start(Symbol); -} - -void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) { - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} - -void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { - auto ReturnType = Symbol.getReturnType(); - ReturnType->dump(*this); - Printer << " "; - - uint32_t ClassParentId = Symbol.getClassParentId(); - auto ClassParent = - Symbol.getSession().getConcreteSymbolById( - ClassParentId); - - if (ClassParent) { - WithColor(Printer, PDB_ColorItem::Identifier).get() - << ClassParent->getName(); - Printer << "::"; - } -} - -void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) { - Printer << "("; - if (auto Arguments = Symbol.getArguments()) { - uint32_t Index = 0; - while (auto Arg = Arguments->getNext()) { - Arg->dump(*this); - if (++Index < Arguments->getChildCount()) - Printer << ", "; - } - } - Printer << ")"; - - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; -} - -void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) { - auto PointeeType = Symbol.getPointeeType(); - if (!PointeeType) - return; - PointeeType->dump(*this); - if (auto FuncSig = unique_dyn_cast(PointeeType)) { - // A hack to get the calling convention in the right spot. - Printer << " ("; - PDB_CallingConv CC = FuncSig->getCallingConvention(); - WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; - } else if (isa(PointeeType)) { - Printer << " ("; - } - Printer << (Symbol.isReference() ? "&" : "*"); - if (Symbol.isConstType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " const "; - if (Symbol.isVolatileType()) - WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile "; -} - -void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) { - auto PointeeType = Symbol.getPointeeType(); - assert(PointeeType); - if (!PointeeType) - return; - if (isa(PointeeType) || - isa(PointeeType)) { - Printer << ")"; - } - PointeeType->dumpRight(*this); -} - -void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) { - WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} - -void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) { - WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); -} - -void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type, - StringRef Name) { - Type.dump(*this); - WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name; - Type.dumpRight(*this); -} Index: llvm/tools/llvm-pdbdump/StreamUtil.h =================================================================== --- llvm/tools/llvm-pdbdump/StreamUtil.h +++ /dev/null @@ -1,25 +0,0 @@ -//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H -#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H - -#include "llvm/ADT/SmallVector.h" - -#include - -namespace llvm { -namespace pdb { -class PDBFile; -void discoverStreamPurposes(PDBFile &File, - SmallVectorImpl &Purposes); -} -} - -#endif Index: llvm/tools/llvm-pdbdump/StreamUtil.cpp =================================================================== --- llvm/tools/llvm-pdbdump/StreamUtil.cpp +++ /dev/null @@ -1,139 +0,0 @@ -//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "StreamUtil.h" - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseMapInfo.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" - -namespace llvm { -namespace pdb { -void discoverStreamPurposes(PDBFile &File, - SmallVectorImpl &Purposes) { - - // It's OK if we fail to load some of these streams, we still attempt to print - // what we can. - auto Dbi = File.getPDBDbiStream(); - auto Tpi = File.getPDBTpiStream(); - auto Ipi = File.getPDBIpiStream(); - auto Info = File.getPDBInfoStream(); - - uint32_t StreamCount = File.getNumStreams(); - DenseMap ModStreams; - DenseMap NamedStreams; - - if (Dbi) { - const DbiModuleList &Modules = Dbi->modules(); - for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { - DbiModuleDescriptor Descriptor = Modules.getModuleDescriptor(I); - uint16_t SN = Descriptor.getModuleStreamIndex(); - if (SN != kInvalidStreamIndex) - ModStreams[SN] = Descriptor; - } - } - if (Info) { - for (auto &NSE : Info->named_streams()) { - if (NSE.second != kInvalidStreamIndex) - NamedStreams[NSE.second] = NSE.first(); - } - } - - Purposes.resize(StreamCount); - for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { - std::string Value; - if (StreamIdx == OldMSFDirectory) - Value = "Old MSF Directory"; - else if (StreamIdx == StreamPDB) - Value = "PDB Stream"; - else if (StreamIdx == StreamDBI) - Value = "DBI Stream"; - else if (StreamIdx == StreamTPI) - Value = "TPI Stream"; - else if (StreamIdx == StreamIPI) - Value = "IPI Stream"; - else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) - Value = "Global Symbol Hash"; - else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) - Value = "Public Symbol Hash"; - else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) - Value = "Public Symbol Records"; - else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) - Value = "TPI Hash"; - else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) - Value = "TPI Aux Hash"; - else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) - Value = "IPI Hash"; - else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) - Value = "IPI Aux Hash"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) - Value = "Exception Data"; - else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) - Value = "Fixup Data"; - else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) - Value = "FPO Data"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) - Value = "New FPO Data"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) - Value = "Omap From Source Data"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) - Value = "Omap To Source Data"; - else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) - Value = "Pdata"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) - Value = "Section Header Data"; - else if (Dbi && - StreamIdx == - Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) - Value = "Section Header Original Data"; - else if (Dbi && - StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) - Value = "Token Rid Data"; - else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) - Value = "Xdata"; - else { - auto ModIter = ModStreams.find(StreamIdx); - auto NSIter = NamedStreams.find(StreamIdx); - if (ModIter != ModStreams.end()) { - Value = "Module \""; - Value += ModIter->second.getModuleName(); - Value += "\""; - } else if (NSIter != NamedStreams.end()) { - Value = "Named Stream \""; - Value += NSIter->second; - Value += "\""; - } else { - Value = "???"; - } - } - Purposes[StreamIdx] = Value; - } - - // Consume errors from missing streams. - if (!Dbi) - consumeError(Dbi.takeError()); - if (!Tpi) - consumeError(Tpi.takeError()); - if (!Ipi) - consumeError(Ipi.takeError()); - if (!Info) - consumeError(Info.takeError()); -} -} -} Index: llvm/tools/llvm-pdbdump/YAMLOutputStyle.h =================================================================== --- llvm/tools/llvm-pdbdump/YAMLOutputStyle.h +++ /dev/null @@ -1,49 +0,0 @@ -//===- YAMLOutputStyle.h -------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H -#define LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H - -#include "OutputStyle.h" -#include "PdbYaml.h" - -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/YAMLTraits.h" - -namespace llvm { -namespace pdb { -class ModuleDebugStreamRef; - -class YAMLOutputStyle : public OutputStyle { -public: - YAMLOutputStyle(PDBFile &File); - - Error dump() override; - -private: - Error dumpStringTable(); - Error dumpFileHeaders(); - Error dumpStreamMetadata(); - Error dumpStreamDirectory(); - Error dumpPDBStream(); - Error dumpDbiStream(); - Error dumpTpiStream(); - Error dumpIpiStream(); - - void flush(); - - PDBFile &File; - llvm::yaml::Output Out; - - yaml::PdbObject Obj; -}; -} // namespace pdb -} // namespace llvm - -#endif // LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H Index: llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp =================================================================== --- llvm/tools/llvm-pdbdump/YAMLOutputStyle.cpp +++ /dev/null @@ -1,317 +0,0 @@ -//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "YAMLOutputStyle.h" - -#include "PdbYaml.h" -#include "llvm-pdbdump.h" - -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" -#include "llvm/DebugInfo/CodeView/Line.h" -#include "llvm/DebugInfo/MSF/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::pdb; - -YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) - : File(File), Out(outs()), Obj(File.getAllocator()) { - Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal); -} - -Error YAMLOutputStyle::dump() { - if (opts::pdb2yaml::StreamDirectory) - opts::pdb2yaml::StreamMetadata = true; - - if (auto EC = dumpFileHeaders()) - return EC; - - if (auto EC = dumpStreamMetadata()) - return EC; - - if (auto EC = dumpStreamDirectory()) - return EC; - - if (auto EC = dumpStringTable()) - return EC; - - if (auto EC = dumpPDBStream()) - return EC; - - if (auto EC = dumpDbiStream()) - return EC; - - if (auto EC = dumpTpiStream()) - return EC; - - if (auto EC = dumpIpiStream()) - return EC; - - flush(); - return Error::success(); -} - - -Error YAMLOutputStyle::dumpFileHeaders() { - if (opts::pdb2yaml::NoFileHeaders) - return Error::success(); - - yaml::MSFHeaders Headers; - Obj.Headers.emplace(); - Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); - Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); - Obj.Headers->SuperBlock.BlockSize = File.getBlockSize(); - auto Blocks = File.getDirectoryBlockArray(); - Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); - Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks(); - Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); - Obj.Headers->NumStreams = - opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; - Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock(); - Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1(); - Obj.Headers->FileSize = File.getFileSize(); - - return Error::success(); -} - -Error YAMLOutputStyle::dumpStringTable() { - bool RequiresStringTable = opts::shared::DumpModuleFiles || - !opts::shared::DumpModuleSubsections.empty(); - bool RequestedStringTable = opts::pdb2yaml::StringTable; - if (!RequiresStringTable && !RequestedStringTable) - return Error::success(); - - auto ExpectedST = File.getStringTable(); - if (!ExpectedST) - return ExpectedST.takeError(); - - Obj.StringTable.emplace(); - const auto &ST = ExpectedST.get(); - for (auto ID : ST.name_ids()) { - auto S = ST.getStringForID(ID); - if (!S) - return S.takeError(); - if (S->empty()) - continue; - Obj.StringTable->push_back(*S); - } - return Error::success(); -} - -Error YAMLOutputStyle::dumpStreamMetadata() { - if (!opts::pdb2yaml::StreamMetadata) - return Error::success(); - - Obj.StreamSizes.emplace(); - Obj.StreamSizes->assign(File.getStreamSizes().begin(), - File.getStreamSizes().end()); - return Error::success(); -} - -Error YAMLOutputStyle::dumpStreamDirectory() { - if (!opts::pdb2yaml::StreamDirectory) - return Error::success(); - - auto StreamMap = File.getStreamMap(); - Obj.StreamMap.emplace(); - for (auto &Stream : StreamMap) { - pdb::yaml::StreamBlockList BlockList; - BlockList.Blocks.assign(Stream.begin(), Stream.end()); - Obj.StreamMap->push_back(BlockList); - } - - return Error::success(); -} - -Error YAMLOutputStyle::dumpPDBStream() { - if (!opts::pdb2yaml::PdbStream) - return Error::success(); - - auto IS = File.getPDBInfoStream(); - if (!IS) - return IS.takeError(); - - auto &InfoS = IS.get(); - Obj.PdbStream.emplace(); - Obj.PdbStream->Age = InfoS.getAge(); - Obj.PdbStream->Guid = InfoS.getGuid(); - Obj.PdbStream->Signature = InfoS.getSignature(); - Obj.PdbStream->Version = InfoS.getVersion(); - Obj.PdbStream->Features = InfoS.getFeatureSignatures(); - - return Error::success(); -} - -static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) { - switch (K) { - case DebugSubsectionKind::CrossScopeExports: - return opts::ModuleSubsection::CrossScopeExports; - case DebugSubsectionKind::CrossScopeImports: - return opts::ModuleSubsection::CrossScopeImports; - case DebugSubsectionKind::FileChecksums: - return opts::ModuleSubsection::FileChecksums; - case DebugSubsectionKind::InlineeLines: - return opts::ModuleSubsection::InlineeLines; - case DebugSubsectionKind::Lines: - return opts::ModuleSubsection::Lines; - case DebugSubsectionKind::Symbols: - return opts::ModuleSubsection::Symbols; - case DebugSubsectionKind::StringTable: - return opts::ModuleSubsection::StringTable; - case DebugSubsectionKind::FrameData: - return opts::ModuleSubsection::FrameData; - default: - return opts::ModuleSubsection::Unknown; - } - llvm_unreachable("Unreachable!"); -} - -Error YAMLOutputStyle::dumpDbiStream() { - if (!opts::pdb2yaml::DbiStream) - return Error::success(); - - auto DbiS = File.getPDBDbiStream(); - if (!DbiS) - return DbiS.takeError(); - - auto &DS = DbiS.get(); - Obj.DbiStream.emplace(); - Obj.DbiStream->Age = DS.getAge(); - Obj.DbiStream->BuildNumber = DS.getBuildNumber(); - Obj.DbiStream->Flags = DS.getFlags(); - Obj.DbiStream->MachineType = DS.getMachineType(); - Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); - Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); - Obj.DbiStream->VerHeader = DS.getDbiVersion(); - if (opts::shared::DumpModules) { - const auto &Modules = DS.modules(); - for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { - DbiModuleDescriptor MI = Modules.getModuleDescriptor(I); - - Obj.DbiStream->ModInfos.emplace_back(); - yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back(); - - DMI.Mod = MI.getModuleName(); - DMI.Obj = MI.getObjFileName(); - if (opts::shared::DumpModuleFiles) { - auto Files = Modules.source_files(I); - DMI.SourceFiles.assign(Files.begin(), Files.end()); - } - - uint16_t ModiStream = MI.getModuleStreamIndex(); - if (ModiStream == kInvalidStreamIndex) - continue; - - auto ModStreamData = msf::MappedBlockStream::createIndexedStream( - File.getMsfLayout(), File.getMsfBuffer(), ModiStream, - File.getAllocator()); - - pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData)); - if (auto EC = ModS.reload()) - return EC; - - auto ExpectedST = File.getStringTable(); - if (!ExpectedST) - return ExpectedST.takeError(); - if (!opts::shared::DumpModuleSubsections.empty() && - ModS.hasDebugSubsections()) { - auto ExpectedChecksums = ModS.findChecksumsSubsection(); - if (!ExpectedChecksums) - return ExpectedChecksums.takeError(); - - for (const auto &SS : ModS.subsections()) { - opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind()); - if (!opts::checkModuleSubsection(OptionKind)) - continue; - - auto Converted = - CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection( - ExpectedST->getStringTable(), *ExpectedChecksums, SS); - if (!Converted) - return Converted.takeError(); - DMI.Subsections.push_back(*Converted); - } - } - - if (opts::shared::DumpModuleSyms) { - DMI.Modi.emplace(); - - DMI.Modi->Signature = ModS.signature(); - bool HadError = false; - for (auto &Sym : ModS.symbols(&HadError)) { - auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym); - if (!ES) - return ES.takeError(); - - DMI.Modi->Symbols.push_back(*ES); - } - } - } - } - return Error::success(); -} - -Error YAMLOutputStyle::dumpTpiStream() { - if (!opts::pdb2yaml::TpiStream) - return Error::success(); - - auto TpiS = File.getPDBTpiStream(); - if (!TpiS) - return TpiS.takeError(); - - auto &TS = TpiS.get(); - Obj.TpiStream.emplace(); - Obj.TpiStream->Version = TS.getTpiVersion(); - for (auto &Record : TS.types(nullptr)) { - auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); - if (!ExpectedRecord) - return ExpectedRecord.takeError(); - Obj.TpiStream->Records.push_back(*ExpectedRecord); - } - - return Error::success(); -} - -Error YAMLOutputStyle::dumpIpiStream() { - if (!opts::pdb2yaml::IpiStream) - return Error::success(); - - auto IpiS = File.getPDBIpiStream(); - if (!IpiS) - return IpiS.takeError(); - - auto &IS = IpiS.get(); - Obj.IpiStream.emplace(); - Obj.IpiStream->Version = IS.getTpiVersion(); - for (auto &Record : IS.types(nullptr)) { - auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); - if (!ExpectedRecord) - return ExpectedRecord.takeError(); - - Obj.IpiStream->Records.push_back(*ExpectedRecord); - } - - return Error::success(); -} - -void YAMLOutputStyle::flush() { - Out << Obj; - outs().flush(); -} Index: llvm/tools/llvm-pdbdump/fuzzer/CMakeLists.txt =================================================================== --- llvm/tools/llvm-pdbdump/fuzzer/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(LLVM_LINK_COMPONENTS - DebugInfoCodeView - DebugInfoPDB - Object - Support - ) - -add_llvm_executable(llvm-pdbdump-fuzzer - EXCLUDE_FROM_ALL - llvm-pdbdump-fuzzer.cpp - ) - -target_link_libraries(llvm-pdbdump-fuzzer - LLVMFuzzer - ) Index: llvm/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp =================================================================== --- llvm/tools/llvm-pdbdump/fuzzer/llvm-pdbdump-fuzzer.cpp +++ /dev/null @@ -1,105 +0,0 @@ -//===-- llvm-pdbdump-fuzzer.cpp - Fuzz the llvm-pdbdump tool --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief This file implements a function that runs llvm-pdbdump -/// on a single input. This function is then linked into the Fuzzer library. -/// -//===----------------------------------------------------------------------===// -#include "llvm/ADT/STLExtras.h" -#include "llvm/DebugInfo/CodeView/BinaryByteStream.h" -#include "llvm/DebugInfo/CodeView/SymbolDumper.h" -#include "llvm/DebugInfo/CodeView/TypeDumper.h" -#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Raw/ModuleDebugStream.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawSession.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ScopedPrinter.h" - -using namespace llvm; - -namespace { -// We need a class which behaves like an immutable BinaryByteStream, but whose -// data -// is backed by an llvm::MemoryBuffer. It also needs to own the underlying -// MemoryBuffer, so this simple adapter is a good way to achieve that. -class InputByteStream : public codeview::BinaryByteStream { -public: - explicit InputByteStream(std::unique_ptr Buffer) - : BinaryByteStream(ArrayRef(Buffer->getBuffer().bytes_begin(), - Buffer->getBuffer().bytes_end())), - MemBuffer(std::move(Buffer)) {} - - std::unique_ptr MemBuffer; -}; -} - -extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { - std::unique_ptr Buff = MemoryBuffer::getMemBuffer( - StringRef((const char *)data, size), "", false); - - ScopedPrinter P(nulls()); - codeview::CVTypeDumper TD(&P, false); - - auto InputStream = llvm::make_unique(std::move(Buff)); - std::unique_ptr File(new pdb::PDBFile(std::move(InputStream))); - if (auto E = File->parseFileHeaders()) { - consumeError(std::move(E)); - return 0; - } - if (auto E = File->parseStreamData()) { - consumeError(std::move(E)); - return 0; - } - - auto DbiS = File->getPDBDbiStream(); - if (auto E = DbiS.takeError()) { - consumeError(std::move(E)); - return 0; - } - auto TpiS = File->getPDBTpiStream(); - if (auto E = TpiS.takeError()) { - consumeError(std::move(E)); - return 0; - } - auto IpiS = File->getPDBIpiStream(); - if (auto E = IpiS.takeError()) { - consumeError(std::move(E)); - return 0; - } - auto InfoS = File->getPDBInfoStream(); - if (auto E = InfoS.takeError()) { - consumeError(std::move(E)); - return 0; - } - pdb::DbiStream &DS = DbiS.get(); - - for (auto &Modi : DS.modules()) { - auto ModStreamData = pdb::MappedBlockStream::createIndexedStream( - Modi.Info.getModuleStreamIndex(), *File, File->getAllocator()); - if (!ModStreamData) { - consumeError(ModStreamData.takeError()); - return 0; - } - pdb::ModuleDebugStreamRef ModS(Modi.Info, std::move(*ModStreamData)); - if (auto E = ModS.reload()) { - consumeError(std::move(E)); - return 0; - } - codeview::CVSymbolDumper SD(P, TD, nullptr, false); - bool HadError = false; - for (auto &S : ModS.symbols(&HadError)) { - SD.dump(S); - } - } - return 0; -} Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.h =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.h +++ /dev/null @@ -1,156 +0,0 @@ -//===- llvm-pdbdump.h ----------------------------------------- *- C++ --*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H -#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H - -#include "llvm/ADT/Optional.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include - -namespace llvm { -namespace pdb { -class PDBSymbolData; -class PDBSymbolFunc; -uint32_t getTypeLength(const PDBSymbolData &Symbol); -} -} - -namespace opts { - -enum class ModuleSubsection { - Unknown, - Lines, - FileChecksums, - InlineeLines, - CrossScopeImports, - CrossScopeExports, - StringTable, - Symbols, - FrameData, - All -}; - -bool checkModuleSubsection(ModuleSubsection Kind); - -template -bool checkModuleSubsection(ModuleSubsection K1, ModuleSubsection K2, - Ts &&... Rest) { - return checkModuleSubsection(K1) || - checkModuleSubsection(K2, std::forward(Rest)...); -} - -namespace pretty { - -enum class ClassDefinitionFormat { None, Layout, All }; -enum class ClassSortMode { - None, - Name, - Size, - Padding, - PaddingPct, - PaddingImmediate, - PaddingPctImmediate -}; - -enum class SymbolSortMode { None, Name, Size }; - -enum class SymLevel { Functions, Data, Thunks, All }; - -bool shouldDumpSymLevel(SymLevel Level); -bool compareFunctionSymbols( - const std::unique_ptr &F1, - const std::unique_ptr &F2); -bool compareDataSymbols(const std::unique_ptr &F1, - const std::unique_ptr &F2); - -extern llvm::cl::opt Compilands; -extern llvm::cl::opt Symbols; -extern llvm::cl::opt Globals; -extern llvm::cl::opt Classes; -extern llvm::cl::opt Enums; -extern llvm::cl::opt Typedefs; -extern llvm::cl::opt All; -extern llvm::cl::opt ExcludeCompilerGenerated; - -extern llvm::cl::opt NoEnumDefs; -extern llvm::cl::list ExcludeTypes; -extern llvm::cl::list ExcludeSymbols; -extern llvm::cl::list ExcludeCompilands; -extern llvm::cl::list IncludeTypes; -extern llvm::cl::list IncludeSymbols; -extern llvm::cl::list IncludeCompilands; -extern llvm::cl::opt SymbolOrder; -extern llvm::cl::opt ClassOrder; -extern llvm::cl::opt SizeThreshold; -extern llvm::cl::opt PaddingThreshold; -extern llvm::cl::opt ImmediatePaddingThreshold; -extern llvm::cl::opt ClassFormat; -extern llvm::cl::opt ClassRecursionDepth; -} - -namespace raw { -struct BlockRange { - uint32_t Min; - llvm::Optional Max; -}; - -extern llvm::Optional DumpBlockRange; -extern llvm::cl::list DumpStreamData; - -extern llvm::cl::opt CompactRecords; -extern llvm::cl::opt DumpGlobals; -extern llvm::cl::opt DumpHeaders; -extern llvm::cl::opt DumpStreamBlocks; -extern llvm::cl::opt DumpStreamSummary; -extern llvm::cl::opt DumpPageStats; -extern llvm::cl::opt DumpTpiHash; -extern llvm::cl::opt DumpTpiRecordBytes; -extern llvm::cl::opt DumpTpiRecords; -extern llvm::cl::opt DumpIpiRecords; -extern llvm::cl::opt DumpIpiRecordBytes; -extern llvm::cl::opt DumpPublics; -extern llvm::cl::opt DumpSectionContribs; -extern llvm::cl::opt DumpSectionMap; -extern llvm::cl::opt DumpSymRecordBytes; -extern llvm::cl::opt DumpSectionHeaders; -extern llvm::cl::opt DumpFpo; -extern llvm::cl::opt DumpStringTable; -} - -namespace diff { -extern llvm::cl::opt Pedantic; -} - -namespace pdb2yaml { -extern llvm::cl::opt All; -extern llvm::cl::opt NoFileHeaders; -extern llvm::cl::opt Minimal; -extern llvm::cl::opt StreamMetadata; -extern llvm::cl::opt StreamDirectory; -extern llvm::cl::opt StringTable; -extern llvm::cl::opt PdbStream; -extern llvm::cl::opt DbiStream; -extern llvm::cl::opt TpiStream; -extern llvm::cl::opt IpiStream; -extern llvm::cl::list InputFilename; -} - -namespace shared { -extern llvm::cl::opt DumpModules; -extern llvm::cl::opt DumpModuleFiles; -extern llvm::cl::list DumpModuleSubsections; -extern llvm::cl::opt DumpModuleSyms; -} // namespace shared -} - -#endif Index: llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- llvm/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ /dev/null @@ -1,1023 +0,0 @@ -//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Dumps debug information present in PDB files. -// -//===----------------------------------------------------------------------===// - -#include "llvm-pdbdump.h" - -#include "Analyze.h" -#include "Diff.h" -#include "LLVMOutputStyle.h" -#include "LinePrinter.h" -#include "OutputStyle.h" -#include "PrettyCompilandDumper.h" -#include "PrettyExternalSymbolDumper.h" -#include "PrettyFunctionDumper.h" -#include "PrettyTypeDumper.h" -#include "PrettyVariableDumper.h" -#include "YAMLOutputStyle.h" - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Config/config.h" -#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" -#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" -#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" -#include "llvm/DebugInfo/MSF/MSFBuilder.h" -#include "llvm/DebugInfo/PDB/GenericError.h" -#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" -#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" -#include "llvm/DebugInfo/PDB/IPDBSession.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiStream.h" -#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/InfoStream.h" -#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" -#include "llvm/DebugInfo/PDB/Native/NativeSession.h" -#include "llvm/DebugInfo/PDB/Native/PDBFile.h" -#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" -#include "llvm/DebugInfo/PDB/Native/RawConstants.h" -#include "llvm/DebugInfo/PDB/Native/RawError.h" -#include "llvm/DebugInfo/PDB/Native/TpiStream.h" -#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" -#include "llvm/DebugInfo/PDB/PDB.h" -#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" -#include "llvm/DebugInfo/PDB/PDBSymbolData.h" -#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" -#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" -#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" -#include "llvm/Support/BinaryByteStream.h" -#include "llvm/Support/COM.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/FileOutputBuffer.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Regex.h" -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace llvm::codeview; -using namespace llvm::msf; -using namespace llvm::pdb; - -namespace opts { - -cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); -cl::SubCommand - PrettySubcommand("pretty", - "Dump semantic information about types and symbols"); - -cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files"); - -cl::SubCommand - YamlToPdbSubcommand("yaml2pdb", - "Generate a PDB file from a YAML description"); -cl::SubCommand - PdbToYamlSubcommand("pdb2yaml", - "Generate a detailed YAML description of a PDB File"); - -cl::SubCommand - AnalyzeSubcommand("analyze", - "Analyze various aspects of a PDB's structure"); - -cl::SubCommand MergeSubcommand("merge", - "Merge multiple PDBs into a single PDB"); - -cl::OptionCategory TypeCategory("Symbol Type Options"); -cl::OptionCategory FilterCategory("Filtering and Sorting Options"); -cl::OptionCategory OtherOptions("Other Options"); - -namespace pretty { -cl::list InputFilenames(cl::Positional, - cl::desc(""), - cl::OneOrMore, cl::sub(PrettySubcommand)); - -cl::opt Compilands("compilands", cl::desc("Display compilands"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Symbols("module-syms", - cl::desc("Display symbols for each compiland"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Globals("globals", cl::desc("Dump global symbols"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Externals("externals", cl::desc("Dump external symbols"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::list SymTypes( - "sym-types", cl::desc("Type of symbols to dump (default all)"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore, - cl::values( - clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"), - clEnumValN(SymLevel::Data, "data", "Display data symbols"), - clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"), - clEnumValN(SymLevel::All, "all", "Display all symbols (default)"))); - -cl::opt - Types("types", - cl::desc("Display all types (implies -classes, -enums, -typedefs)"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Classes("classes", cl::desc("Display class types"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Enums("enums", cl::desc("Display enum types"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt SymbolOrder( - "symbol-order", cl::desc("symbol sort order"), - cl::init(SymbolSortMode::None), - cl::values(clEnumValN(SymbolSortMode::None, "none", - "Undefined / no particular sort order"), - clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"), - clEnumValN(SymbolSortMode::Size, "size", - "Sort symbols by size")), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); - -cl::opt ClassOrder( - "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), - cl::values( - clEnumValN(ClassSortMode::None, "none", - "Undefined / no particular sort order"), - clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"), - clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"), - clEnumValN(ClassSortMode::Padding, "padding", - "Sort classes by amount of padding"), - clEnumValN(ClassSortMode::PaddingPct, "padding-pct", - "Sort classes by percentage of space consumed by padding"), - clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm", - "Sort classes by amount of immediate padding"), - clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm", - "Sort classes by percentage of space consumed by immediate " - "padding")), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); - -cl::opt ClassFormat( - "class-definitions", cl::desc("Class definition format"), - cl::init(ClassDefinitionFormat::All), - cl::values( - clEnumValN(ClassDefinitionFormat::All, "all", - "Display all class members including data, constants, " - "typedefs, functions, etc"), - clEnumValN(ClassDefinitionFormat::Layout, "layout", - "Only display members that contribute to class size."), - clEnumValN(ClassDefinitionFormat::None, "none", - "Don't display class definitions")), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); -cl::opt ClassRecursionDepth( - "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"), - cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); - -cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), - cl::sub(PrettySubcommand)); -cl::opt - All("all", cl::desc("Implies all other options in 'Symbol Types' category"), - cl::cat(TypeCategory), cl::sub(PrettySubcommand)); - -cl::opt LoadAddress( - "load-address", - cl::desc("Assume the module is loaded at the specified address"), - cl::cat(OtherOptions), cl::sub(PrettySubcommand)); -cl::opt Native("native", cl::desc("Use native PDB reader instead of DIA"), - cl::cat(OtherOptions), cl::sub(PrettySubcommand)); -cl::opt - ColorOutput("color-output", - cl::desc("Override use of color (default = isatty)"), - cl::cat(OtherOptions), cl::sub(PrettySubcommand)); -cl::list ExcludeTypes( - "exclude-types", cl::desc("Exclude types by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::list ExcludeSymbols( - "exclude-symbols", cl::desc("Exclude symbols by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::list ExcludeCompilands( - "exclude-compilands", cl::desc("Exclude compilands by regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); - -cl::list IncludeTypes( - "include-types", - cl::desc("Include only types which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::list IncludeSymbols( - "include-symbols", - cl::desc("Include only symbols which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::list IncludeCompilands( - "include-compilands", - cl::desc("Include only compilands those which match a regular expression"), - cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt SizeThreshold( - "min-type-size", cl::desc("Displays only those types which are greater " - "than or equal to the specified size."), - cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt PaddingThreshold( - "min-class-padding", cl::desc("Displays only those classes which have at " - "least the specified amount of padding."), - cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt ImmediatePaddingThreshold( - "min-class-padding-imm", - cl::desc("Displays only those classes which have at least the specified " - "amount of immediate padding, ignoring padding internal to bases " - "and aggregates."), - cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); - -cl::opt ExcludeCompilerGenerated( - "no-compiler-generated", - cl::desc("Don't show compiler generated types and symbols"), - cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -cl::opt - ExcludeSystemLibraries("no-system-libs", - cl::desc("Don't show symbols from system libraries"), - cl::cat(FilterCategory), cl::sub(PrettySubcommand)); - -cl::opt NoEnumDefs("no-enum-definitions", - cl::desc("Don't display full enum definitions"), - cl::cat(FilterCategory), cl::sub(PrettySubcommand)); -} - -namespace diff { -cl::opt Pedantic("pedantic", - cl::desc("Finds all differences (even structural ones " - "that produce otherwise identical PDBs)"), - cl::sub(DiffSubcommand)); - -cl::list InputFilenames(cl::Positional, - cl::desc(" "), - cl::OneOrMore, cl::sub(DiffSubcommand)); -} - -namespace raw { - -cl::OptionCategory MsfOptions("MSF Container Options"); -cl::OptionCategory TypeOptions("Type Record Options"); -cl::OptionCategory SymbolOptions("Symbol Options"); -cl::OptionCategory MiscOptions("Miscellaneous Options"); - -// MSF OPTIONS -cl::opt DumpHeaders("headers", cl::desc("dump PDB headers"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -cl::opt DumpStreamBlocks("stream-blocks", - cl::desc("dump PDB stream blocks"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -cl::opt DumpStreamSummary("stream-summary", - cl::desc("dump summary of the PDB streams"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -cl::opt DumpPageStats( - "page-stats", - cl::desc("dump allocation stats of the pages in the MSF file"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -cl::opt - DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), - cl::desc("Dump binary data from specified range."), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); -llvm::Optional DumpBlockRange; - -cl::list - DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, - cl::desc("Dump binary data from specified streams. Format " - "is SN[:Start][@Size]"), - cl::cat(MsfOptions), cl::sub(RawSubcommand)); - -// TYPE OPTIONS -cl::opt - CompactRecords("compact-records", - cl::desc("Dump type and symbol records with less detail"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); - -cl::opt - DumpTpiRecords("tpi-records", - cl::desc("dump CodeView type records from TPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); -cl::opt DumpTpiRecordBytes( - "tpi-record-bytes", - cl::desc("dump CodeView type record raw bytes from TPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); -cl::opt DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); -cl::opt - DumpIpiRecords("ipi-records", - cl::desc("dump CodeView type records from IPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); -cl::opt DumpIpiRecordBytes( - "ipi-record-bytes", - cl::desc("dump CodeView type record raw bytes from IPI stream"), - cl::cat(TypeOptions), cl::sub(RawSubcommand)); - -// SYMBOL OPTIONS -cl::opt DumpGlobals("globals", cl::desc("dump globals stream data"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); -cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); -cl::opt - DumpSymRecordBytes("sym-record-bytes", - cl::desc("dump CodeView symbol record raw bytes"), - cl::cat(SymbolOptions), cl::sub(RawSubcommand)); - -// MISCELLANEOUS OPTIONS -cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); - -cl::opt DumpSectionContribs("section-contribs", - cl::desc("dump section contributions"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); -cl::opt DumpSectionMap("section-map", cl::desc("dump section map"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); -cl::opt DumpSectionHeaders("section-headers", - cl::desc("dump section headers"), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); -cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions), - cl::sub(RawSubcommand)); - -cl::opt RawAll("all", cl::desc("Implies most other options."), - cl::cat(MiscOptions), cl::sub(RawSubcommand)); - -cl::list InputFilenames(cl::Positional, - cl::desc(""), - cl::OneOrMore, cl::sub(RawSubcommand)); -} - -namespace yaml2pdb { -cl::opt - YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), - cl::sub(YamlToPdbSubcommand)); - -cl::opt InputFilename(cl::Positional, - cl::desc(""), cl::Required, - cl::sub(YamlToPdbSubcommand)); -} - -namespace pdb2yaml { -cl::opt All("all", - cl::desc("Dump everything we know how to dump."), - cl::sub(PdbToYamlSubcommand), cl::init(false)); -cl::opt NoFileHeaders("no-file-headers", - cl::desc("Do not dump MSF file headers"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); -cl::opt Minimal("minimal", - cl::desc("Don't write fields with default values"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::opt StreamMetadata( - "stream-metadata", - cl::desc("Dump the number of streams and each stream's size"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); -cl::opt StreamDirectory( - "stream-directory", - cl::desc("Dump each stream's block map (implies -stream-metadata)"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); -cl::opt PdbStream("pdb-stream", - cl::desc("Dump the PDB Stream (Stream 1)"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::opt StringTable("string-table", cl::desc("Dump the PDB String Table"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::opt DbiStream("dbi-stream", - cl::desc("Dump the DBI Stream Headers (Stream 2)"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::opt TpiStream("tpi-stream", - cl::desc("Dump the TPI Stream (Stream 3)"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::opt IpiStream("ipi-stream", - cl::desc("Dump the IPI Stream (Stream 5)"), - cl::sub(PdbToYamlSubcommand), cl::init(false)); - -cl::list InputFilename(cl::Positional, - cl::desc(""), cl::Required, - cl::sub(PdbToYamlSubcommand)); -} - -namespace shared { -cl::OptionCategory FileOptions("Module & File Options"); - -// MODULE & FILE OPTIONS -cl::opt DumpModules("modules", cl::desc("dump compiland information"), - cl::cat(FileOptions), cl::sub(RawSubcommand), - cl::sub(PdbToYamlSubcommand)); -cl::opt DumpModuleFiles("module-files", cl::desc("dump file information"), - cl::cat(FileOptions), cl::sub(RawSubcommand), - cl::sub(PdbToYamlSubcommand)); -cl::list DumpModuleSubsections( - "subsections", cl::ZeroOrMore, cl::CommaSeparated, - cl::desc("dump subsections from each module's debug stream"), - cl::values( - clEnumValN( - ModuleSubsection::CrossScopeExports, "cme", - "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), - clEnumValN( - ModuleSubsection::CrossScopeImports, "cmi", - "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), - clEnumValN(ModuleSubsection::FileChecksums, "fc", - "File checksums (DEBUG_S_CHECKSUMS subsection)"), - clEnumValN(ModuleSubsection::InlineeLines, "ilines", - "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), - clEnumValN(ModuleSubsection::Lines, "lines", - "Lines (DEBUG_S_LINES subsection)"), - clEnumValN(ModuleSubsection::StringTable, "strings", - "String Table (DEBUG_S_STRINGTABLE subsection) (not " - "typically present in PDB file)"), - clEnumValN(ModuleSubsection::FrameData, "frames", - "Frame Data (DEBUG_S_FRAMEDATA subsection)"), - clEnumValN(ModuleSubsection::Symbols, "symbols", - "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " - "present in PDB file)"), - clEnumValN(ModuleSubsection::Unknown, "unknown", - "Any subsection not covered by another option"), - clEnumValN(ModuleSubsection::All, "all", "All known subsections")), - cl::cat(FileOptions), cl::sub(RawSubcommand), cl::sub(PdbToYamlSubcommand)); -cl::opt DumpModuleSyms("module-syms", cl::desc("dump module symbols"), - cl::cat(FileOptions), cl::sub(RawSubcommand), - cl::sub(PdbToYamlSubcommand)); -} // namespace shared - -namespace analyze { -cl::opt StringTable("hash-collisions", cl::desc("Find hash collisions"), - cl::sub(AnalyzeSubcommand), cl::init(false)); -cl::list InputFilename(cl::Positional, - cl::desc(""), cl::Required, - cl::sub(AnalyzeSubcommand)); -} - -namespace merge { -cl::list InputFilenames(cl::Positional, - cl::desc(""), - cl::OneOrMore, cl::sub(MergeSubcommand)); -cl::opt - PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), - cl::sub(MergeSubcommand)); -} -} - -static ExitOnError ExitOnErr; - -bool opts::checkModuleSubsection(opts::ModuleSubsection MS) { - return any_of(opts::shared::DumpModuleSubsections, - [=](opts::ModuleSubsection M) { - return M == MS || M == opts::ModuleSubsection::All; - }); -} - -static void yamlToPdb(StringRef Path) { - BumpPtrAllocator Allocator; - ErrorOr> ErrorOrBuffer = - MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - - if (ErrorOrBuffer.getError()) { - ExitOnErr(make_error(generic_error_code::invalid_path, Path)); - } - - std::unique_ptr &Buffer = ErrorOrBuffer.get(); - - llvm::yaml::Input In(Buffer->getBuffer()); - pdb::yaml::PdbObject YamlObj(Allocator); - In >> YamlObj; - - PDBFileBuilder Builder(Allocator); - - uint32_t BlockSize = 4096; - if (YamlObj.Headers.hasValue()) - BlockSize = YamlObj.Headers->SuperBlock.BlockSize; - ExitOnErr(Builder.initialize(BlockSize)); - // Add each of the reserved streams. We ignore stream metadata in the - // yaml, because we will reconstruct our own view of the streams. For - // example, the YAML may say that there were 20 streams in the original - // PDB, but maybe we only dump a subset of those 20 streams, so we will - // have fewer, and the ones we do have may end up with different indices - // than the ones in the original PDB. So we just start with a clean slate. - for (uint32_t I = 0; I < kSpecialStreamCount; ++I) - ExitOnErr(Builder.getMsfBuilder().addStream(0)); - - if (YamlObj.StringTable.hasValue()) { - auto &Strings = Builder.getStringTableBuilder(); - for (auto S : *YamlObj.StringTable) - Strings.insert(S); - } - - pdb::yaml::PdbInfoStream DefaultInfoStream; - pdb::yaml::PdbDbiStream DefaultDbiStream; - pdb::yaml::PdbTpiStream DefaultTpiStream; - pdb::yaml::PdbTpiStream DefaultIpiStream; - - const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); - - auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(Info.Age); - InfoBuilder.setGuid(Info.Guid); - InfoBuilder.setSignature(Info.Signature); - InfoBuilder.setVersion(Info.Version); - for (auto F : Info.Features) - InfoBuilder.addFeature(F); - - auto &Strings = Builder.getStringTableBuilder().getStrings(); - - const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); - auto &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setAge(Dbi.Age); - DbiBuilder.setBuildNumber(Dbi.BuildNumber); - DbiBuilder.setFlags(Dbi.Flags); - DbiBuilder.setMachineType(Dbi.MachineType); - DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); - DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); - DbiBuilder.setVersionHeader(Dbi.VerHeader); - for (const auto &MI : Dbi.ModInfos) { - auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); - ModiBuilder.setObjFileName(MI.Obj); - - for (auto S : MI.SourceFiles) - ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); - if (MI.Modi.hasValue()) { - const auto &ModiStream = *MI.Modi; - for (auto Symbol : ModiStream.Symbols) { - ModiBuilder.addSymbol( - Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); - } - } - - auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList( - Allocator, MI.Subsections, Strings)); - for (auto &SS : CodeViewSubsections) { - ModiBuilder.addDebugSubsection(std::move(SS)); - } - } - - auto &TpiBuilder = Builder.getTpiBuilder(); - const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); - TpiBuilder.setVersionHeader(Tpi.Version); - for (const auto &R : Tpi.Records) { - CVType Type = R.toCodeViewRecord(Allocator); - TpiBuilder.addTypeRecord(Type.RecordData, None); - } - - const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); - auto &IpiBuilder = Builder.getIpiBuilder(); - IpiBuilder.setVersionHeader(Ipi.Version); - for (const auto &R : Ipi.Records) { - CVType Type = R.toCodeViewRecord(Allocator); - IpiBuilder.addTypeRecord(Type.RecordData, None); - } - - ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); -} - -static PDBFile &loadPDB(StringRef Path, std::unique_ptr &Session) { - ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session)); - - NativeSession *NS = static_cast(Session.get()); - return NS->getPDBFile(); -} - -static void pdb2Yaml(StringRef Path) { - std::unique_ptr Session; - auto &File = loadPDB(Path, Session); - - auto O = llvm::make_unique(File); - O = llvm::make_unique(File); - - ExitOnErr(O->dump()); -} - -static void dumpRaw(StringRef Path) { - std::unique_ptr Session; - auto &File = loadPDB(Path, Session); - - auto O = llvm::make_unique(File); - - ExitOnErr(O->dump()); -} - -static void dumpAnalysis(StringRef Path) { - std::unique_ptr Session; - auto &File = loadPDB(Path, Session); - auto O = llvm::make_unique(File); - - ExitOnErr(O->dump()); -} - -static void diff(StringRef Path1, StringRef Path2) { - std::unique_ptr Session1; - std::unique_ptr Session2; - - auto &File1 = loadPDB(Path1, Session1); - auto &File2 = loadPDB(Path2, Session2); - - auto O = llvm::make_unique(File1, File2); - - ExitOnErr(O->dump()); -} - -bool opts::pretty::shouldDumpSymLevel(SymLevel Search) { - if (SymTypes.empty()) - return true; - if (llvm::find(SymTypes, Search) != SymTypes.end()) - return true; - if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end()) - return true; - return false; -} - -uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) { - auto SymbolType = Symbol.getType(); - const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); - - return RawType.getLength(); -} - -bool opts::pretty::compareFunctionSymbols( - const std::unique_ptr &F1, - const std::unique_ptr &F2) { - assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); - - if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) - return F1->getName() < F2->getName(); - - // Note that we intentionally sort in descending order on length, since - // long functions are more interesting than short functions. - return F1->getLength() > F2->getLength(); -} - -bool opts::pretty::compareDataSymbols( - const std::unique_ptr &F1, - const std::unique_ptr &F2) { - assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); - - if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) - return F1->getName() < F2->getName(); - - // Note that we intentionally sort in descending order on length, since - // large types are more interesting than short ones. - return getTypeLength(*F1) > getTypeLength(*F2); -} - -static void dumpPretty(StringRef Path) { - std::unique_ptr Session; - - const auto ReaderType = - opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; - ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); - - if (opts::pretty::LoadAddress) - Session->setLoadAddress(opts::pretty::LoadAddress); - - auto &Stream = outs(); - const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET - ? Stream.has_colors() - : opts::pretty::ColorOutput == cl::BOU_TRUE; - LinePrinter Printer(2, UseColor, Stream); - - auto GlobalScope(Session->getGlobalScope()); - std::string FileName(GlobalScope->getSymbolsFileName()); - - WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; - WithColor(Printer, PDB_ColorItem::Path).get() << FileName; - Printer.Indent(); - uint64_t FileSize = 0; - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; - if (!sys::fs::file_size(FileName, FileSize)) { - Printer << ": " << FileSize << " bytes"; - } else { - Printer << ": (Unable to obtain file size)"; - } - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; - Printer << ": " << GlobalScope->getGuid(); - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; - Printer << ": " << GlobalScope->getAge(); - - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; - Printer << ": "; - if (GlobalScope->hasCTypes()) - outs() << "HasCTypes "; - if (GlobalScope->hasPrivateSymbols()) - outs() << "HasPrivateSymbols "; - Printer.Unindent(); - - if (opts::pretty::Compilands) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::SectionHeader).get() - << "---COMPILANDS---"; - Printer.Indent(); - auto Compilands = GlobalScope->findAllChildren(); - CompilandDumper Dumper(Printer); - CompilandDumpFlags options = CompilandDumper::Flags::None; - if (opts::pretty::Lines) - options = options | CompilandDumper::Flags::Lines; - while (auto Compiland = Compilands->getNext()) - Dumper.start(*Compiland, options); - Printer.Unindent(); - } - - if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; - Printer.Indent(); - TypeDumper Dumper(Printer); - Dumper.start(*GlobalScope); - Printer.Unindent(); - } - - if (opts::pretty::Symbols) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; - Printer.Indent(); - auto Compilands = GlobalScope->findAllChildren(); - CompilandDumper Dumper(Printer); - while (auto Compiland = Compilands->getNext()) - Dumper.start(*Compiland, true); - Printer.Unindent(); - } - - if (opts::pretty::Globals) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; - Printer.Indent(); - if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { - FunctionDumper Dumper(Printer); - auto Functions = GlobalScope->findAllChildren(); - if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { - while (auto Function = Functions->getNext()) { - Printer.NewLine(); - Dumper.start(*Function, FunctionDumper::PointerType::None); - } - } else { - std::vector> Funcs; - while (auto Func = Functions->getNext()) - Funcs.push_back(std::move(Func)); - std::sort(Funcs.begin(), Funcs.end(), - opts::pretty::compareFunctionSymbols); - for (const auto &Func : Funcs) { - Printer.NewLine(); - Dumper.start(*Func, FunctionDumper::PointerType::None); - } - } - } - if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { - auto Vars = GlobalScope->findAllChildren(); - VariableDumper Dumper(Printer); - if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { - while (auto Var = Vars->getNext()) - Dumper.start(*Var); - } else { - std::vector> Datas; - while (auto Var = Vars->getNext()) - Datas.push_back(std::move(Var)); - std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols); - for (const auto &Var : Datas) - Dumper.start(*Var); - } - } - if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { - auto Thunks = GlobalScope->findAllChildren(); - CompilandDumper Dumper(Printer); - while (auto Thunk = Thunks->getNext()) - Dumper.dump(*Thunk); - } - Printer.Unindent(); - } - if (opts::pretty::Externals) { - Printer.NewLine(); - WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; - Printer.Indent(); - ExternalSymbolDumper Dumper(Printer); - Dumper.start(*GlobalScope); - } - if (opts::pretty::Lines) { - Printer.NewLine(); - } - outs().flush(); -} - -static void mergePdbs() { - BumpPtrAllocator Allocator; - TypeTableBuilder MergedTpi(Allocator); - TypeTableBuilder MergedIpi(Allocator); - - // Create a Tpi and Ipi type table with all types from all input files. - for (const auto &Path : opts::merge::InputFilenames) { - std::unique_ptr Session; - auto &File = loadPDB(Path, Session); - SmallVector TypeMap; - SmallVector IdMap; - if (File.hasPDBTpiStream()) { - auto &Tpi = ExitOnErr(File.getPDBTpiStream()); - ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr, - Tpi.typeArray())); - } - if (File.hasPDBIpiStream()) { - auto &Ipi = ExitOnErr(File.getPDBIpiStream()); - ExitOnErr(codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, - Ipi.typeArray())); - } - } - - // Then write the PDB. - PDBFileBuilder Builder(Allocator); - ExitOnErr(Builder.initialize(4096)); - // Add each of the reserved streams. We might not put any data in them, - // but at least they have to be present. - for (uint32_t I = 0; I < kSpecialStreamCount; ++I) - ExitOnErr(Builder.getMsfBuilder().addStream(0)); - - auto &DestTpi = Builder.getTpiBuilder(); - auto &DestIpi = Builder.getIpiBuilder(); - MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef Data) { - DestTpi.addTypeRecord(Data, None); - }); - MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef Data) { - DestIpi.addTypeRecord(Data, None); - }); - - SmallString<64> OutFile(opts::merge::PdbOutputFile); - if (OutFile.empty()) { - OutFile = opts::merge::InputFilenames[0]; - llvm::sys::path::replace_extension(OutFile, "merged.pdb"); - } - ExitOnErr(Builder.commit(OutFile)); -} - -int main(int argc_, const char *argv_[]) { - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(argv_[0]); - PrettyStackTraceProgram X(argc_, argv_); - - ExitOnErr.setBanner("llvm-pdbdump: "); - - SmallVector argv; - SpecificBumpPtrAllocator ArgAllocator; - ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( - argv, makeArrayRef(argv_, argc_), ArgAllocator))); - - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); - if (!opts::raw::DumpBlockRangeOpt.empty()) { - llvm::Regex R("^([0-9]+)(-([0-9]+))?$"); - llvm::SmallVector Matches; - if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) { - errs() << "Argument '" << opts::raw::DumpBlockRangeOpt - << "' invalid format.\n"; - errs().flush(); - exit(1); - } - opts::raw::DumpBlockRange.emplace(); - Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min); - if (!Matches[3].empty()) { - opts::raw::DumpBlockRange->Max.emplace(); - Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max); - } - } - - if ((opts::RawSubcommand && opts::raw::RawAll) || - (opts::PdbToYamlSubcommand && opts::pdb2yaml::All)) { - opts::shared::DumpModules = true; - opts::shared::DumpModuleFiles = true; - opts::shared::DumpModuleSyms = true; - opts::shared::DumpModuleSubsections.push_back(opts::ModuleSubsection::All); - if (llvm::is_contained(opts::shared::DumpModuleSubsections, - opts::ModuleSubsection::All)) { - opts::shared::DumpModuleSubsections.reset(); - opts::shared::DumpModuleSubsections.push_back( - opts::ModuleSubsection::All); - } - } - - if (opts::shared::DumpModuleSyms || opts::shared::DumpModuleFiles) - opts::shared::DumpModules = true; - - if (opts::shared::DumpModules) - opts::pdb2yaml::DbiStream = true; - - if (opts::RawSubcommand) { - if (opts::raw::RawAll) { - opts::raw::DumpHeaders = true; - opts::raw::DumpGlobals = true; - opts::raw::DumpPublics = true; - opts::raw::DumpSectionHeaders = true; - opts::raw::DumpStreamSummary = true; - opts::raw::DumpPageStats = true; - opts::raw::DumpStreamBlocks = true; - opts::raw::DumpTpiRecords = true; - opts::raw::DumpTpiHash = true; - opts::raw::DumpIpiRecords = true; - opts::raw::DumpSectionMap = true; - opts::raw::DumpSectionContribs = true; - opts::raw::DumpFpo = true; - opts::raw::DumpStringTable = true; - } - - if (opts::raw::CompactRecords && - (opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) { - errs() << "-compact-records is incompatible with -tpi-record-bytes and " - "-ipi-record-bytes.\n"; - exit(1); - } - } - if (opts::PdbToYamlSubcommand) { - if (opts::pdb2yaml::All) { - opts::pdb2yaml::StreamMetadata = true; - opts::pdb2yaml::StreamDirectory = true; - opts::pdb2yaml::PdbStream = true; - opts::pdb2yaml::StringTable = true; - opts::pdb2yaml::DbiStream = true; - opts::pdb2yaml::TpiStream = true; - opts::pdb2yaml::IpiStream = true; - } - } - - llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); - - if (opts::PdbToYamlSubcommand) { - pdb2Yaml(opts::pdb2yaml::InputFilename.front()); - } else if (opts::YamlToPdbSubcommand) { - if (opts::yaml2pdb::YamlPdbOutputFile.empty()) { - SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue()); - sys::path::replace_extension(OutputFilename, ".pdb"); - opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str(); - } - yamlToPdb(opts::yaml2pdb::InputFilename); - } else if (opts::AnalyzeSubcommand) { - dumpAnalysis(opts::analyze::InputFilename.front()); - } else if (opts::PrettySubcommand) { - if (opts::pretty::Lines) - opts::pretty::Compilands = true; - - if (opts::pretty::All) { - opts::pretty::Compilands = true; - opts::pretty::Symbols = true; - opts::pretty::Globals = true; - opts::pretty::Types = true; - opts::pretty::Externals = true; - opts::pretty::Lines = true; - } - - if (opts::pretty::Types) { - opts::pretty::Classes = true; - opts::pretty::Typedefs = true; - opts::pretty::Enums = true; - } - - // When adding filters for excluded compilands and types, we need to - // remember that these are regexes. So special characters such as * and \ - // need to be escaped in the regex. In the case of a literal \, this means - // it needs to be escaped again in the C++. So matching a single \ in the - // input requires 4 \es in the C++. - if (opts::pretty::ExcludeCompilerGenerated) { - opts::pretty::ExcludeTypes.push_back("__vc_attributes"); - opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); - } - if (opts::pretty::ExcludeSystemLibraries) { - opts::pretty::ExcludeCompilands.push_back( - "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); - opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); - opts::pretty::ExcludeCompilands.push_back( - "d:\\\\th.obj.x86fre\\\\minkernel"); - } - std::for_each(opts::pretty::InputFilenames.begin(), - opts::pretty::InputFilenames.end(), dumpPretty); - } else if (opts::RawSubcommand) { - std::for_each(opts::raw::InputFilenames.begin(), - opts::raw::InputFilenames.end(), dumpRaw); - } else if (opts::DiffSubcommand) { - if (opts::diff::InputFilenames.size() != 2) { - errs() << "diff subcommand expects exactly 2 arguments.\n"; - exit(1); - } - diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]); - } else if (opts::MergeSubcommand) { - if (opts::merge::InputFilenames.size() < 2) { - errs() << "merge subcommand requires at least 2 input files.\n"; - exit(1); - } - mergePdbs(); - } - - outs().flush(); - return 0; -} Index: llvm/tools/llvm-pdbutil/Analyze.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/Analyze.h @@ -0,0 +1,30 @@ +//===- Analyze.h - PDB analysis functions -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H +#define LLVM_TOOLS_LLVMPDBDUMP_ANALYSIS_H + +#include "OutputStyle.h" + +namespace llvm { +namespace pdb { +class PDBFile; +class AnalysisStyle : public OutputStyle { +public: + explicit AnalysisStyle(PDBFile &File); + + Error dump() override; + +private: + PDBFile &File; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/Analyze.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/Analyze.cpp @@ -0,0 +1,152 @@ +//===- Analyze.cpp - PDB analysis functions ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Analyze.h" + +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static StringRef getLeafTypeName(TypeLeafKind LT) { + switch (LT) { +#define TYPE_RECORD(ename, value, name) \ + case ename: \ + return #name; +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" + default: + break; + } + return "UnknownLeaf"; +} + +namespace { +struct HashLookupVisitor : public TypeVisitorCallbacks { + struct Entry { + TypeIndex TI; + CVType Record; + }; + + explicit HashLookupVisitor(TpiStream &Tpi) : Tpi(Tpi) {} + + Error visitTypeBegin(CVType &Record) override { + uint32_t H = Tpi.getHashValues()[I]; + Record.Hash = H; + TypeIndex TI(I + TypeIndex::FirstNonSimpleIndex); + Lookup[H].push_back(Entry{TI, Record}); + ++I; + return Error::success(); + } + + uint32_t I = 0; + DenseMap> Lookup; + TpiStream &Tpi; +}; +} // namespace + +AnalysisStyle::AnalysisStyle(PDBFile &File) : File(File) {} + +Error AnalysisStyle::dump() { + auto Tpi = File.getPDBTpiStream(); + if (!Tpi) + return Tpi.takeError(); + + TypeDatabase TypeDB(Tpi->getNumTypeRecords()); + TypeDatabaseVisitor DBV(TypeDB); + TypeVisitorCallbackPipeline Pipeline; + HashLookupVisitor Hasher(*Tpi); + // Add them to the database + Pipeline.addCallbackToPipeline(DBV); + // Store their hash values + Pipeline.addCallbackToPipeline(Hasher); + + if (auto EC = codeview::visitTypeStream(Tpi->typeArray(), Pipeline)) + return EC; + + auto &Adjusters = Tpi->getHashAdjusters(); + DenseSet AdjusterSet; + for (const auto &Adj : Adjusters) { + assert(AdjusterSet.find(Adj.second) == AdjusterSet.end()); + AdjusterSet.insert(Adj.second); + } + + uint32_t Count = 0; + outs() << "Searching for hash collisions\n"; + for (const auto &H : Hasher.Lookup) { + if (H.second.size() <= 1) + continue; + ++Count; + outs() << formatv("Hash: {0}, Count: {1} records\n", H.first, + H.second.size()); + for (const auto &R : H.second) { + auto Iter = AdjusterSet.find(R.TI.getIndex()); + StringRef Prefix; + if (Iter != AdjusterSet.end()) { + Prefix = "[HEAD]"; + AdjusterSet.erase(Iter); + } + StringRef LeafName = getLeafTypeName(R.Record.Type); + uint32_t TI = R.TI.getIndex(); + StringRef TypeName = TypeDB.getTypeName(R.TI); + outs() << formatv("{0,-6} {1} ({2:x}) {3}\n", Prefix, LeafName, TI, + TypeName); + } + } + + outs() << "\n"; + outs() << "Dumping hash adjustment chains\n"; + for (const auto &A : Tpi->getHashAdjusters()) { + TypeIndex TI(A.second); + StringRef TypeName = TypeDB.getTypeName(TI); + const CVType &HeadRecord = TypeDB.getTypeRecord(TI); + assert(HeadRecord.Hash.hasValue()); + + auto CollisionsIter = Hasher.Lookup.find(*HeadRecord.Hash); + if (CollisionsIter == Hasher.Lookup.end()) + continue; + + const auto &Collisions = CollisionsIter->second; + outs() << TypeName << "\n"; + outs() << formatv(" [HEAD] {0:x} {1} {2}\n", A.second, + getLeafTypeName(HeadRecord.Type), TypeName); + for (const auto &Chain : Collisions) { + if (Chain.TI == TI) + continue; + const CVType &TailRecord = TypeDB.getTypeRecord(Chain.TI); + outs() << formatv(" {0:x} {1} {2}\n", Chain.TI.getIndex(), + getLeafTypeName(TailRecord.Type), + TypeDB.getTypeName(Chain.TI)); + } + } + outs() << formatv("There are {0} orphaned hash adjusters\n", + AdjusterSet.size()); + for (const auto &Adj : AdjusterSet) { + outs() << formatv(" {0}\n", Adj); + } + + uint32_t DistinctHashValues = Hasher.Lookup.size(); + outs() << formatv("{0}/{1} hash collisions", Count, DistinctHashValues); + return Error::success(); +} Index: llvm/tools/llvm-pdbutil/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/CMakeLists.txt @@ -0,0 +1,34 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoCodeView + DebugInfoMSF + DebugInfoPDB + Object + ObjectYAML + Support + ) + +add_llvm_tool(llvm-pdbutil + Analyze.cpp + CompactTypeDumpVisitor.cpp + Diff.cpp + llvm-pdbutil.cpp + LinePrinter.cpp + LLVMOutputStyle.cpp + PdbYaml.cpp + PrettyBuiltinDumper.cpp + PrettyClassDefinitionDumper.cpp + PrettyClassLayoutGraphicalDumper.cpp + PrettyCompilandDumper.cpp + PrettyEnumDumper.cpp + PrettyExternalSymbolDumper.cpp + PrettyFunctionDumper.cpp + PrettyTypeDumper.cpp + PrettyTypedefDumper.cpp + PrettyVariableDumper.cpp + StreamUtil.cpp + YAMLOutputStyle.cpp + ) + +if(LLVM_USE_SANITIZE_COVERAGE) + add_subdirectory(fuzzer) +endif() Index: llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.h @@ -0,0 +1,49 @@ +//===-- CompactTypeDumpVisitor.h - CodeView type info dumper ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H +#define LLVM_DEBUGINFO_CODEVIEW_COMPACTTYPEDUMPVISITOR_H + +#include "llvm/DebugInfo/CodeView/TypeIndex.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" + +namespace llvm { +class ScopedPrinter; +namespace codeview { +class TypeCollection; +} + +namespace pdb { + +/// Dumper for CodeView type streams found in COFF object files and PDB files. +/// Dumps records on a single line, and ignores member records. +class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks { +public: + CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W); + CompactTypeDumpVisitor(codeview::TypeCollection &Types, + codeview::TypeIndex FirstTI, ScopedPrinter *W); + + /// Paired begin/end actions for all types. Receives all record data, + /// including the fixed-length record prefix. + Error visitTypeBegin(codeview::CVType &Record) override; + Error visitTypeEnd(codeview::CVType &Record) override; + +private: + ScopedPrinter *W; + + codeview::TypeIndex TI; + uint32_t Offset; + codeview::TypeCollection &Types; +}; + +} // end namespace pdb +} // end namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/CompactTypeDumpVisitor.cpp @@ -0,0 +1,59 @@ +//===-- CompactTypeDumpVisitor.cpp - CodeView type 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 "CompactTypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +static const EnumEntry LeafTypeNames[] = { +#define CV_TYPE(enum, val) {#enum, enum}, +#include "llvm/DebugInfo/CodeView/CodeViewTypes.def" +}; + +static StringRef getLeafName(TypeLeafKind K) { + for (const auto &E : LeafTypeNames) { + if (E.Value == K) + return E.Name; + } + return StringRef(); +} + +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, + ScopedPrinter *W) + : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex), + W) {} + +CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types, + TypeIndex FirstTI, + ScopedPrinter *W) + : W(W), TI(FirstTI), Offset(0), Types(Types) {} + +Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) { + return Error::success(); +} + +Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) { + uint32_t I = TI.getIndex(); + StringRef Leaf = getLeafName(Record.Type); + StringRef Name = Types.getTypeName(TI); + W->printString( + llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I, + Record.length(), Offset, Leaf, Name) + .str()); + + Offset += Record.length(); + TI.setIndex(TI.getIndex() + 1); + + return Error::success(); +} Index: llvm/tools/llvm-pdbutil/Diff.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/Diff.h @@ -0,0 +1,45 @@ +//===- Diff.h - PDB diff utility --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_DIFF_H +#define LLVM_TOOLS_LLVMPDBDUMP_DIFF_H + +#include "OutputStyle.h" + +namespace llvm { +namespace pdb { +class PDBFile; +class DiffStyle : public OutputStyle { +public: + explicit DiffStyle(PDBFile &File1, PDBFile &File2); + + Error dump() override; + +private: + Error diffSuperBlock(); + Error diffStreamDirectory(); + Error diffStringTable(); + Error diffFreePageMap(); + Error diffInfoStream(); + Error diffDbiStream(); + Error diffSectionContribs(); + Error diffSectionMap(); + Error diffFpoStream(); + Error diffTpiStream(int Index); + Error diffModuleInfoStream(int Index); + Error diffPublics(); + Error diffGlobals(); + + PDBFile &File1; + PDBFile &File2; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/Diff.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/Diff.cpp @@ -0,0 +1,537 @@ +//===- Diff.cpp - PDB diff utility ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Diff.h" + +#include "StreamUtil.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/Native/Formatters.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" + +#include "llvm/Support/FormatAdapters.h" +#include "llvm/Support/FormatProviders.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::pdb; + +namespace llvm { +template <> struct format_provider { + static void format(const PdbRaw_FeatureSig &Sig, raw_ostream &Stream, + StringRef Style) { + switch (Sig) { + case PdbRaw_FeatureSig::MinimalDebugInfo: + Stream << "MinimalDebugInfo"; + break; + case PdbRaw_FeatureSig::NoTypeMerge: + Stream << "NoTypeMerge"; + break; + case PdbRaw_FeatureSig::VC110: + Stream << "VC110"; + break; + case PdbRaw_FeatureSig::VC140: + Stream << "VC140"; + break; + } + } +}; +} // namespace llvm + +template using ValueOfRange = llvm::detail::ValueOfRange; + +template +static void set_differences(Range &&R1, Range &&R2, + SmallVectorImpl> *OnlyLeft, + SmallVectorImpl> *OnlyRight, + SmallVectorImpl> *Intersection, + Comp Comparator) { + + std::sort(R1.begin(), R1.end(), Comparator); + std::sort(R2.begin(), R2.end(), Comparator); + + if (OnlyLeft) { + OnlyLeft->reserve(R1.size()); + auto End = std::set_difference(R1.begin(), R1.end(), R2.begin(), R2.end(), + OnlyLeft->begin(), Comparator); + OnlyLeft->set_size(std::distance(OnlyLeft->begin(), End)); + } + if (OnlyRight) { + OnlyLeft->reserve(R2.size()); + auto End = std::set_difference(R2.begin(), R2.end(), R1.begin(), R1.end(), + OnlyRight->begin(), Comparator); + OnlyRight->set_size(std::distance(OnlyRight->begin(), End)); + } + if (Intersection) { + Intersection->reserve(std::min(R1.size(), R2.size())); + auto End = std::set_intersection(R1.begin(), R1.end(), R2.begin(), R2.end(), + Intersection->begin(), Comparator); + Intersection->set_size(std::distance(Intersection->begin(), End)); + } +} + +template +static void +set_differences(Range &&R1, Range &&R2, + SmallVectorImpl> *OnlyLeft, + SmallVectorImpl> *OnlyRight, + SmallVectorImpl> *Intersection = nullptr) { + std::less> Comp; + set_differences(std::forward(R1), std::forward(R2), OnlyLeft, + OnlyRight, Intersection, Comp); +} + +DiffStyle::DiffStyle(PDBFile &File1, PDBFile &File2) + : File1(File1), File2(File2) {} + +Error DiffStyle::dump() { + if (auto EC = diffSuperBlock()) + return EC; + + if (auto EC = diffFreePageMap()) + return EC; + + if (auto EC = diffStreamDirectory()) + return EC; + + if (auto EC = diffStringTable()) + return EC; + + if (auto EC = diffInfoStream()) + return EC; + + if (auto EC = diffDbiStream()) + return EC; + + if (auto EC = diffSectionContribs()) + return EC; + + if (auto EC = diffSectionMap()) + return EC; + + if (auto EC = diffFpoStream()) + return EC; + + if (auto EC = diffTpiStream(StreamTPI)) + return EC; + + if (auto EC = diffTpiStream(StreamIPI)) + return EC; + + if (auto EC = diffPublics()) + return EC; + + if (auto EC = diffGlobals()) + return EC; + + return Error::success(); +} + +template +static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, T V1, + T V2) { + if (V1 == V2) { + outs() << formatv(" {0}: No differences detected!\n", Label); + return false; + } + + outs().indent(2) << Label << "\n"; + outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), V1); + outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), V2); + return true; +} + +template +static bool diffAndPrint(StringRef Label, PDBFile &File1, PDBFile &File2, + ArrayRef V1, ArrayRef V2) { + if (V1 == V2) { + outs() << formatv(" {0}: No differences detected!\n", Label); + return false; + } + + outs().indent(2) << Label << "\n"; + outs().indent(4) << formatv("{0}: {1}\n", File1.getFilePath(), + make_range(V1.begin(), V1.end())); + outs().indent(4) << formatv("{0}: {1}\n", File2.getFilePath(), + make_range(V2.begin(), V2.end())); + return true; +} + +template +static bool printSymmetricDifferences(PDBFile &File1, PDBFile &File2, + T &&OnlyRange1, T &&OnlyRange2, + StringRef Label) { + bool HasDiff = false; + if (!OnlyRange1.empty()) { + HasDiff = true; + outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange1.size(), Label, + File1.getFilePath()); + for (const auto &Item : OnlyRange1) + outs() << formatv(" {0}\n", Label, Item); + } + if (!OnlyRange2.empty()) { + HasDiff = true; + outs() << formatv(" {0} {1}(s) only in ({2})\n", OnlyRange2.size(), + File2.getFilePath()); + for (const auto &Item : OnlyRange2) + outs() << formatv(" {0}\n", Item); + } + return HasDiff; +} + +Error DiffStyle::diffSuperBlock() { + outs() << "MSF Super Block: Searching for differences...\n"; + bool Diffs = false; + + Diffs |= diffAndPrint("Block Size", File1, File2, File1.getBlockSize(), + File2.getBlockSize()); + Diffs |= diffAndPrint("Block Count", File1, File2, File1.getBlockCount(), + File2.getBlockCount()); + Diffs |= diffAndPrint("Unknown 1", File1, File2, File1.getUnknown1(), + File2.getUnknown1()); + + if (opts::diff::Pedantic) { + Diffs |= diffAndPrint("Free Block Map", File1, File2, + File1.getFreeBlockMapBlock(), + File2.getFreeBlockMapBlock()); + Diffs |= diffAndPrint("Directory Size", File1, File2, + File1.getNumDirectoryBytes(), + File2.getNumDirectoryBytes()); + Diffs |= diffAndPrint("Block Map Addr", File1, File2, + File1.getBlockMapOffset(), File2.getBlockMapOffset()); + } + if (!Diffs) + outs() << "MSF Super Block: No differences detected...\n"; + return Error::success(); +} + +Error DiffStyle::diffStreamDirectory() { + SmallVector P; + SmallVector Q; + discoverStreamPurposes(File1, P); + discoverStreamPurposes(File2, Q); + outs() << "Stream Directory: Searching for differences...\n"; + + bool HasDifferences = false; + if (opts::diff::Pedantic) { + size_t Min = std::min(P.size(), Q.size()); + for (size_t I = 0; I < Min; ++I) { + StringRef Names[] = {P[I], Q[I]}; + uint32_t Sizes[] = {File1.getStreamByteSize(I), + File2.getStreamByteSize(I)}; + bool NamesDiffer = Names[0] != Names[1]; + bool SizesDiffer = Sizes[0] != Sizes[1]; + if (NamesDiffer) { + HasDifferences = true; + outs().indent(2) << formatv("Stream {0} - {1}: {2}, {3}: {4}\n", I, + File1.getFilePath(), Names[0], + File2.getFilePath(), Names[1]); + continue; + } + if (SizesDiffer) { + HasDifferences = true; + outs().indent(2) << formatv( + "Stream {0} ({1}): {2}: {3} bytes, {4}: {5} bytes\n", I, Names[0], + File1.getFilePath(), Sizes[0], File2.getFilePath(), Sizes[1]); + continue; + } + } + + ArrayRef MaxNames = (P.size() > Q.size() ? P : Q); + size_t Max = std::max(P.size(), Q.size()); + PDBFile &MaxFile = (P.size() > Q.size() ? File1 : File2); + StringRef MinFileName = + (P.size() < Q.size() ? File1.getFilePath() : File2.getFilePath()); + for (size_t I = Min; I < Max; ++I) { + HasDifferences = true; + StringRef StreamName = MaxNames[I]; + + outs().indent(2) << formatv( + "Stream {0} - {1}: , {2}: Index {3}, {4} bytes\n", + StreamName, MinFileName, MaxFile.getFilePath(), I, + MaxFile.getStreamByteSize(I)); + } + if (!HasDifferences) + outs() << "Stream Directory: No differences detected...\n"; + } else { + auto PI = to_vector<32>(enumerate(P)); + auto QI = to_vector<32>(enumerate(Q)); + + typedef decltype(PI) ContainerType; + typedef typename ContainerType::value_type value_type; + + auto Comparator = [](const value_type &I1, const value_type &I2) { + return I1.value() < I2.value(); + }; + + decltype(PI) OnlyP; + decltype(QI) OnlyQ; + decltype(PI) Common; + + set_differences(PI, QI, &OnlyP, &OnlyQ, &Common, Comparator); + + if (!OnlyP.empty()) { + HasDifferences = true; + outs().indent(2) << formatv("{0} Stream(s) only in ({1})\n", OnlyP.size(), + File1.getFilePath()); + for (auto &Item : OnlyP) { + outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), + Item.value()); + } + } + + if (!OnlyQ.empty()) { + HasDifferences = true; + outs().indent(2) << formatv("{0} Streams(s) only in ({1})\n", + OnlyQ.size(), File2.getFilePath()); + for (auto &Item : OnlyQ) { + outs().indent(4) << formatv("Stream {0} - {1}\n", Item.index(), + Item.value()); + } + } + if (!Common.empty()) { + outs().indent(2) << formatv("Found {0} common streams. Searching for " + "intra-stream differences.\n", + Common.size()); + bool HasCommonDifferences = false; + for (const auto &Left : Common) { + // Left was copied from the first range so its index refers to a stream + // index in the first file. Find the corresponding stream index in the + // second file. + auto Range = + std::equal_range(QI.begin(), QI.end(), Left, + [](const value_type &L, const value_type &R) { + return L.value() < R.value(); + }); + const auto &Right = *Range.first; + assert(Left.value() == Right.value()); + uint32_t LeftSize = File1.getStreamByteSize(Left.index()); + uint32_t RightSize = File2.getStreamByteSize(Right.index()); + if (LeftSize != RightSize) { + HasDifferences = true; + HasCommonDifferences = true; + outs().indent(4) << formatv("{0} ({1}: {2} bytes, {3}: {4} bytes)\n", + Left.value(), File1.getFilePath(), + LeftSize, File2.getFilePath(), RightSize); + } + } + if (!HasCommonDifferences) + outs().indent(2) << "Common Streams: No differences detected!\n"; + } + if (!HasDifferences) + outs() << "Stream Directory: No differences detected!\n"; + } + + return Error::success(); +} + +Error DiffStyle::diffStringTable() { + auto ExpectedST1 = File1.getStringTable(); + auto ExpectedST2 = File2.getStringTable(); + outs() << "String Table: Searching for differences...\n"; + bool Has1 = !!ExpectedST1; + bool Has2 = !!ExpectedST2; + if (!(Has1 && Has2)) { + // If one has a string table and the other doesn't, we can print less + // output. + if (Has1 != Has2) { + if (Has1) { + outs() << formatv(" {0}: ({1} strings)\n", File1.getFilePath(), + ExpectedST1->getNameCount()); + outs() << formatv(" {0}: (string table not present)\n", + File2.getFilePath()); + } else { + outs() << formatv(" {0}: (string table not present)\n", + File1.getFilePath()); + outs() << formatv(" {0}: ({1})\n", File2.getFilePath(), + ExpectedST2->getNameCount()); + } + } + consumeError(ExpectedST1.takeError()); + consumeError(ExpectedST2.takeError()); + return Error::success(); + } + + bool HasDiff = false; + auto &ST1 = *ExpectedST1; + auto &ST2 = *ExpectedST2; + + if (ST1.getByteSize() != ST2.getByteSize()) { + outs() << " Stream Size\n"; + outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(), + ST1.getByteSize()); + outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(), + ST2.getByteSize()); + outs() << formatv(" Difference: {0} bytes\n", + AbsoluteDifference(ST1.getByteSize(), ST2.getByteSize())); + HasDiff = true; + } + HasDiff |= diffAndPrint("Hash Version", File1, File2, ST1.getHashVersion(), + ST1.getHashVersion()); + HasDiff |= diffAndPrint("Signature", File1, File2, ST1.getSignature(), + ST1.getSignature()); + + // Both have a valid string table, dive in and compare individual strings. + + auto IdList1 = ST1.name_ids(); + auto IdList2 = ST2.name_ids(); + if (opts::diff::Pedantic) { + // In pedantic mode, we compare index by index (i.e. the strings are in the + // same order + // in both tables. + uint32_t Max = std::max(IdList1.size(), IdList2.size()); + for (uint32_t I = 0; I < Max; ++I) { + Optional Id1, Id2; + StringRef S1, S2; + if (I < IdList1.size()) { + Id1 = IdList1[I]; + if (auto Result = ST1.getStringForID(*Id1)) + S1 = *Result; + else + return Result.takeError(); + } + if (I < IdList2.size()) { + Id2 = IdList2[I]; + if (auto Result = ST2.getStringForID(*Id2)) + S2 = *Result; + else + return Result.takeError(); + } + if (Id1 == Id2 && S1 == S2) + continue; + + std::string OutId1 = + Id1 ? formatv("{0}", *Id1).str() : "(index not present)"; + std::string OutId2 = + Id2 ? formatv("{0}", *Id2).str() : "(index not present)"; + outs() << formatv(" String {0}\n", I); + outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", + File1.getFilePath(), OutId1, S1); + outs() << formatv(" {0}: Hash - {1}, Value - {2}\n", + File2.getFilePath(), OutId2, S2); + HasDiff = true; + } + } else { + std::vector Strings1, Strings2; + Strings1.reserve(IdList1.size()); + Strings2.reserve(IdList2.size()); + for (auto ID : IdList1) { + auto S = ST1.getStringForID(ID); + if (!S) + return S.takeError(); + Strings1.push_back(*S); + } + for (auto ID : IdList2) { + auto S = ST2.getStringForID(ID); + if (!S) + return S.takeError(); + Strings2.push_back(*S); + } + + SmallVector OnlyP; + SmallVector OnlyQ; + auto End1 = std::remove(Strings1.begin(), Strings1.end(), ""); + auto End2 = std::remove(Strings2.begin(), Strings2.end(), ""); + uint32_t Empty1 = std::distance(End1, Strings1.end()); + uint32_t Empty2 = std::distance(End2, Strings2.end()); + Strings1.erase(End1, Strings1.end()); + Strings2.erase(End2, Strings2.end()); + set_differences(Strings1, Strings2, &OnlyP, &OnlyQ); + printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "String"); + + if (Empty1 != Empty2) { + PDBFile &MoreF = (Empty1 > Empty2) ? File1 : File2; + PDBFile &LessF = (Empty1 < Empty2) ? File1 : File2; + uint32_t Difference = AbsoluteDifference(Empty1, Empty2); + outs() << formatv(" {0} had {1} more empty strings than {2}\n", + MoreF.getFilePath(), Difference, LessF.getFilePath()); + } + } + if (!HasDiff) + outs() << "String Table: No differences detected!\n"; + return Error::success(); +} + +Error DiffStyle::diffFreePageMap() { return Error::success(); } + +Error DiffStyle::diffInfoStream() { + auto ExpectedInfo1 = File1.getPDBInfoStream(); + auto ExpectedInfo2 = File2.getPDBInfoStream(); + + outs() << "PDB Stream: Searching for differences...\n"; + bool Has1 = !!ExpectedInfo1; + bool Has2 = !!ExpectedInfo2; + if (!(Has1 && Has2)) { + if (Has1 != Has2) + outs() << formatv("{0} does not have a PDB Stream!\n", + Has1 ? File1.getFilePath() : File2.getFilePath()); + consumeError(ExpectedInfo2.takeError()); + consumeError(ExpectedInfo2.takeError()); + return Error::success(); + } + + bool HasDiff = false; + auto &IS1 = *ExpectedInfo1; + auto &IS2 = *ExpectedInfo2; + if (IS1.getStreamSize() != IS2.getStreamSize()) { + outs() << " Stream Size\n"; + outs() << formatv(" {0} - {1} byte(s)\n", File1.getFilePath(), + IS1.getStreamSize()); + outs() << formatv(" {0} - {1} byte(s)\n", File2.getFilePath(), + IS2.getStreamSize()); + outs() << formatv( + " Difference: {0} bytes\n", + AbsoluteDifference(IS1.getStreamSize(), IS2.getStreamSize())); + HasDiff = true; + } + HasDiff |= diffAndPrint("Age", File1, File2, IS1.getAge(), IS2.getAge()); + HasDiff |= diffAndPrint("Guid", File1, File2, IS1.getGuid(), IS2.getGuid()); + HasDiff |= diffAndPrint("Signature", File1, File2, IS1.getSignature(), + IS2.getSignature()); + HasDiff |= + diffAndPrint("Version", File1, File2, IS1.getVersion(), IS2.getVersion()); + HasDiff |= diffAndPrint("Features", File1, File2, IS1.getFeatureSignatures(), + IS2.getFeatureSignatures()); + HasDiff |= diffAndPrint("Named Stream Byte Size", File1, File2, + IS1.getNamedStreamMapByteSize(), + IS2.getNamedStreamMapByteSize()); + SmallVector NS1; + SmallVector NS2; + for (const auto &X : IS1.getNamedStreams().entries()) + NS1.push_back(X.getKey()); + for (const auto &X : IS2.getNamedStreams().entries()) + NS2.push_back(X.getKey()); + SmallVector OnlyP; + SmallVector OnlyQ; + set_differences(NS1, NS2, &OnlyP, &OnlyQ); + printSymmetricDifferences(File1, File2, OnlyP, OnlyQ, "Named Streams"); + if (!HasDiff) + outs() << "PDB Stream: No differences detected!\n"; + + return Error::success(); +} + +Error DiffStyle::diffDbiStream() { return Error::success(); } + +Error DiffStyle::diffSectionContribs() { return Error::success(); } + +Error DiffStyle::diffSectionMap() { return Error::success(); } + +Error DiffStyle::diffFpoStream() { return Error::success(); } + +Error DiffStyle::diffTpiStream(int Index) { return Error::success(); } + +Error DiffStyle::diffModuleInfoStream(int Index) { return Error::success(); } + +Error DiffStyle::diffPublics() { return Error::success(); } + +Error DiffStyle::diffGlobals() { return Error::success(); } Index: llvm/tools/llvm-pdbutil/LLVMBuild.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./tools/llvm-pdbutil/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-pdbutil +parent = Tools +required_libraries = DebugInfoMSF DebugInfoPDB + Index: llvm/tools/llvm-pdbutil/LLVMOutputStyle.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/LLVMOutputStyle.h @@ -0,0 +1,70 @@ +//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H + +#include "OutputStyle.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/CodeView/TypeDatabase.h" +#include "llvm/Support/ScopedPrinter.h" + +#include + +namespace llvm { +class BitVector; + +namespace codeview { +class LazyRandomTypeCollection; +} + +namespace pdb { +class LLVMOutputStyle : public OutputStyle { +public: + LLVMOutputStyle(PDBFile &File); + + Error dump() override; + +private: + Expected + initializeTypeDatabase(uint32_t SN); + + Error dumpFileHeaders(); + Error dumpStreamSummary(); + Error dumpFreePageMap(); + Error dumpBlockRanges(); + Error dumpGlobalsStream(); + Error dumpStreamBytes(); + Error dumpStreamBlocks(); + Error dumpStringTable(); + Error dumpInfoStream(); + Error dumpTpiStream(uint32_t StreamIdx); + Error dumpDbiStream(); + Error dumpSectionContribs(); + Error dumpSectionMap(); + Error dumpPublicsStream(); + Error dumpSectionHeaders(); + Error dumpFpoStream(); + + void dumpBitVector(StringRef Name, const BitVector &V); + + void flush(); + + PDBFile &File; + ScopedPrinter P; + std::unique_ptr TpiTypes; + std::unique_ptr IpiTypes; + SmallVector StreamPurposes; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp @@ -0,0 +1,1177 @@ +//===- LLVMOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LLVMOutputStyle.h" + +#include "CompactTypeDumpVisitor.h" +#include "StreamUtil.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" +#include "llvm/DebugInfo/CodeView/EnumTables.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/EnumTables.h" +#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" +#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PublicsStream.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/FormatVariadic.h" + +#include + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace { +struct PageStats { + explicit PageStats(const BitVector &FreePages) + : Upm(FreePages), ActualUsedPages(FreePages.size()), + MultiUsePages(FreePages.size()), UseAfterFreePages(FreePages.size()) { + const_cast(Upm).flip(); + // To calculate orphaned pages, we start with the set of pages that the + // MSF thinks are used. Each time we find one that actually *is* used, + // we unset it. Whichever bits remain set at the end are orphaned. + OrphanedPages = Upm; + } + + // The inverse of the MSF File's copy of the Fpm. The basis for which we + // determine the allocation status of each page. + const BitVector Upm; + + // Pages which are marked as used in the FPM and are used at least once. + BitVector ActualUsedPages; + + // Pages which are marked as used in the FPM but are used more than once. + BitVector MultiUsePages; + + // Pages which are marked as used in the FPM but are not used at all. + BitVector OrphanedPages; + + // Pages which are marked free in the FPM but are used. + BitVector UseAfterFreePages; +}; + +class C13RawVisitor : public DebugSubsectionVisitor { +public: + C13RawVisitor(ScopedPrinter &P, LazyRandomTypeCollection &TPI, + LazyRandomTypeCollection &IPI) + : P(P), TPI(TPI), IPI(IPI) {} + + Error visitUnknown(DebugUnknownSubsectionRef &Unknown) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::Unknown)) + return Error::success(); + DictScope DD(P, "Unknown"); + P.printHex("Kind", static_cast(Unknown.kind())); + ArrayRef Data; + BinaryStreamReader Reader(Unknown.getData()); + consumeError(Reader.readBytes(Data, Reader.bytesRemaining())); + P.printBinaryBlock("Data", Data); + return Error::success(); + } + + Error visitLines(DebugLinesSubsectionRef &Lines, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::Lines)) + return Error::success(); + + DictScope DD(P, "Lines"); + + P.printNumber("RelocSegment", Lines.header()->RelocSegment); + P.printNumber("RelocOffset", Lines.header()->RelocOffset); + P.printNumber("CodeSize", Lines.header()->CodeSize); + P.printBoolean("HasColumns", Lines.hasColumnInfo()); + + for (const auto &L : Lines) { + DictScope DDDD(P, "FileEntry"); + + if (auto EC = printFileName("FileName", L.NameIndex, State)) + return EC; + + for (const auto &N : L.LineNumbers) { + DictScope DDD(P, "Line"); + LineInfo LI(N.Flags); + P.printNumber("Offset", N.Offset); + if (LI.isAlwaysStepInto()) + P.printString("StepInto", StringRef("Always")); + else if (LI.isNeverStepInto()) + P.printString("StepInto", StringRef("Never")); + else + P.printNumber("LineNumberStart", LI.getStartLine()); + P.printNumber("EndDelta", LI.getLineDelta()); + P.printBoolean("IsStatement", LI.isStatement()); + } + for (const auto &C : L.Columns) { + DictScope DDD(P, "Column"); + P.printNumber("Start", C.StartColumn); + P.printNumber("End", C.EndColumn); + } + } + + return Error::success(); + } + + Error visitFileChecksums(DebugChecksumsSubsectionRef &Checksums, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::FileChecksums)) + return Error::success(); + + DictScope DD(P, "FileChecksums"); + for (const auto &CS : Checksums) { + DictScope DDD(P, "Checksum"); + if (auto Result = getNameFromStringTable(CS.FileNameOffset, State)) + P.printString("FileName", *Result); + else + return Result.takeError(); + P.printEnum("Kind", uint8_t(CS.Kind), getFileChecksumNames()); + P.printBinaryBlock("Checksum", CS.Checksum); + } + return Error::success(); + } + + Error visitInlineeLines(DebugInlineeLinesSubsectionRef &Inlinees, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::InlineeLines)) + return Error::success(); + + DictScope D(P, "InlineeLines"); + P.printBoolean("HasExtraFiles", Inlinees.hasExtraFiles()); + ListScope LS(P, "Lines"); + for (const auto &L : Inlinees) { + DictScope DDD(P, "Inlinee"); + if (auto EC = printFileName("FileName", L.Header->FileID, State)) + return EC; + + if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee)) + return EC; + P.printNumber("SourceLine", L.Header->SourceLineNum); + if (Inlinees.hasExtraFiles()) { + ListScope DDDD(P, "ExtraFiles"); + for (const auto &EF : L.ExtraFiles) { + if (auto EC = printFileName("File", EF, State)) + return EC; + } + } + } + return Error::success(); + } + + Error visitCrossModuleExports(DebugCrossModuleExportsSubsectionRef &CSE, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeExports)) + return Error::success(); + + ListScope D(P, "CrossModuleExports"); + for (const auto &M : CSE) { + DictScope D(P, "Export"); + P.printHex("Local", M.Local); + P.printHex("Global", M.Global); + } + return Error::success(); + } + + Error visitCrossModuleImports(DebugCrossModuleImportsSubsectionRef &CSI, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::CrossScopeImports)) + return Error::success(); + + ListScope L(P, "CrossModuleImports"); + for (const auto &M : CSI) { + DictScope D(P, "ModuleImport"); + auto Name = getNameFromStringTable(M.Header->ModuleNameOffset, State); + if (!Name) + return Name.takeError(); + P.printString("Module", *Name); + P.printHexList("Imports", M.Imports); + } + return Error::success(); + } + + Error visitFrameData(DebugFrameDataSubsectionRef &FD, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::FrameData)) + return Error::success(); + + ListScope L(P, "FrameData"); + for (const auto &Frame : FD) { + DictScope D(P, "Frame"); + auto Name = getNameFromStringTable(Frame.FrameFunc, State); + if (!Name) + return joinErrors(make_error(raw_error_code::invalid_format, + "Invalid Frame.FrameFunc index"), + Name.takeError()); + P.printNumber("Rva", Frame.RvaStart); + P.printNumber("CodeSize", Frame.CodeSize); + P.printNumber("LocalSize", Frame.LocalSize); + P.printNumber("ParamsSize", Frame.ParamsSize); + P.printNumber("MaxStackSize", Frame.MaxStackSize); + P.printString("FrameFunc", *Name); + P.printNumber("PrologSize", Frame.PrologSize); + P.printNumber("SavedRegsSize", Frame.SavedRegsSize); + P.printNumber("Flags", Frame.Flags); + } + return Error::success(); + } + + Error visitSymbols(DebugSymbolsSubsectionRef &Symbols, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::Symbols)) + return Error::success(); + ListScope L(P, "Symbols"); + + // This section should not actually appear in a PDB file, it really only + // appears in object files. But we support it here for testing. So we + // specify the Object File container type. + codeview::CVSymbolDumper SD(P, TPI, CodeViewContainer::ObjectFile, nullptr, + false); + for (auto S : Symbols) { + DictScope LL(P, ""); + if (auto EC = SD.dump(S)) { + return make_error( + raw_error_code::corrupt_file, + "DEBUG_S_SYMBOLS subsection contained corrupt symbol record"); + } + } + return Error::success(); + } + + Error visitStringTable(DebugStringTableSubsectionRef &Strings, + const DebugSubsectionState &State) override { + if (!opts::checkModuleSubsection(opts::ModuleSubsection::StringTable)) + return Error::success(); + + ListScope D(P, "String Table"); + BinaryStreamReader Reader(Strings.getBuffer()); + StringRef S; + consumeError(Reader.readCString(S)); + while (Reader.bytesRemaining() > 0) { + consumeError(Reader.readCString(S)); + if (S.empty() && Reader.bytesRemaining() < 4) + break; + P.printString(S); + } + return Error::success(); + } + +private: + Error dumpTypeRecord(StringRef Label, TypeIndex Index) { + CompactTypeDumpVisitor CTDV(IPI, Index, &P); + DictScope D(P, Label); + if (IPI.contains(Index)) { + CVType Type = IPI.getType(Index); + if (auto EC = codeview::visitTypeRecord(Type, CTDV)) + return EC; + } else { + P.printString( + llvm::formatv("Index: {0:x} (unknown function)", Index.getIndex()) + .str()); + } + return Error::success(); + } + Error printFileName(StringRef Label, uint32_t Offset, + const DebugSubsectionState &State) { + if (auto Result = getNameFromChecksumsBuffer(Offset, State)) { + P.printString(Label, *Result); + return Error::success(); + } else + return Result.takeError(); + } + + Expected + getNameFromStringTable(uint32_t Offset, const DebugSubsectionState &State) { + return State.strings().getString(Offset); + } + + Expected + getNameFromChecksumsBuffer(uint32_t Offset, + const DebugSubsectionState &State) { + auto Array = State.checksums().getArray(); + auto ChecksumIter = Array.at(Offset); + if (ChecksumIter == Array.end()) + return make_error(raw_error_code::invalid_format); + const auto &Entry = *ChecksumIter; + return getNameFromStringTable(Entry.FileNameOffset, State); + } + + ScopedPrinter &P; + LazyRandomTypeCollection &TPI; + LazyRandomTypeCollection &IPI; +}; +} // namespace + +static void recordKnownUsedPage(PageStats &Stats, uint32_t UsedIndex) { + if (Stats.Upm.test(UsedIndex)) { + if (Stats.ActualUsedPages.test(UsedIndex)) + Stats.MultiUsePages.set(UsedIndex); + Stats.ActualUsedPages.set(UsedIndex); + Stats.OrphanedPages.reset(UsedIndex); + } else { + // The MSF doesn't think this page is used, but it is. + Stats.UseAfterFreePages.set(UsedIndex); + } +} + +static void printSectionOffset(llvm::raw_ostream &OS, + const SectionOffset &Off) { + OS << Off.Off << ", " << Off.Isect; +} + +LLVMOutputStyle::LLVMOutputStyle(PDBFile &File) : File(File), P(outs()) {} + +Error LLVMOutputStyle::dump() { + if (auto EC = dumpFileHeaders()) + return EC; + + if (auto EC = dumpStreamSummary()) + return EC; + + if (auto EC = dumpFreePageMap()) + return EC; + + if (auto EC = dumpStreamBlocks()) + return EC; + + if (auto EC = dumpBlockRanges()) + return EC; + + if (auto EC = dumpStreamBytes()) + return EC; + + if (auto EC = dumpStringTable()) + return EC; + + if (auto EC = dumpInfoStream()) + return EC; + + if (auto EC = dumpTpiStream(StreamTPI)) + return EC; + + if (auto EC = dumpTpiStream(StreamIPI)) + return EC; + + if (auto EC = dumpDbiStream()) + return EC; + + if (auto EC = dumpSectionContribs()) + return EC; + + if (auto EC = dumpSectionMap()) + return EC; + + if (auto EC = dumpGlobalsStream()) + return EC; + + if (auto EC = dumpPublicsStream()) + return EC; + + if (auto EC = dumpSectionHeaders()) + return EC; + + if (auto EC = dumpFpoStream()) + return EC; + + flush(); + + return Error::success(); +} + +Error LLVMOutputStyle::dumpFileHeaders() { + if (!opts::raw::DumpHeaders) + return Error::success(); + + DictScope D(P, "FileHeaders"); + P.printNumber("BlockSize", File.getBlockSize()); + P.printNumber("FreeBlockMap", File.getFreeBlockMapBlock()); + P.printNumber("NumBlocks", File.getBlockCount()); + P.printNumber("NumDirectoryBytes", File.getNumDirectoryBytes()); + P.printNumber("Unknown1", File.getUnknown1()); + P.printNumber("BlockMapAddr", File.getBlockMapIndex()); + P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks()); + + // The directory is not contiguous. Instead, the block map contains a + // contiguous list of block numbers whose contents, when concatenated in + // order, make up the directory. + P.printList("DirectoryBlocks", File.getDirectoryBlockArray()); + P.printNumber("NumStreams", File.getNumStreams()); + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamSummary() { + if (!opts::raw::DumpStreamSummary) + return Error::success(); + + if (StreamPurposes.empty()) + discoverStreamPurposes(File, StreamPurposes); + + uint32_t StreamCount = File.getNumStreams(); + + ListScope L(P, "Streams"); + for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Label("Stream "); + Label += to_string(StreamIdx); + + std::string Value = "[" + StreamPurposes[StreamIdx] + "] ("; + Value += to_string(File.getStreamByteSize(StreamIdx)); + Value += " bytes)"; + + P.printString(Label, Value); + } + + P.flush(); + return Error::success(); +} + +Error LLVMOutputStyle::dumpFreePageMap() { + if (!opts::raw::DumpPageStats) + return Error::success(); + + // Start with used pages instead of free pages because + // the number of free pages is far larger than used pages. + BitVector FPM = File.getMsfLayout().FreePageMap; + + PageStats PS(FPM); + + recordKnownUsedPage(PS, 0); // MSF Super Block + + uint32_t BlocksPerSection = msf::getFpmIntervalLength(File.getMsfLayout()); + uint32_t NumSections = msf::getNumFpmIntervals(File.getMsfLayout()); + for (uint32_t I = 0; I < NumSections; ++I) { + uint32_t Fpm0 = 1 + BlocksPerSection * I; + // 2 Fpm blocks spaced at `getBlockSize()` block intervals + recordKnownUsedPage(PS, Fpm0); + recordKnownUsedPage(PS, Fpm0 + 1); + } + + recordKnownUsedPage(PS, File.getBlockMapIndex()); // Stream Table + + for (auto DB : File.getDirectoryBlockArray()) + recordKnownUsedPage(PS, DB); + + // Record pages used by streams. Note that pages for stream 0 + // are considered being unused because that's what MSVC tools do. + // Stream 0 doesn't contain actual data, so it makes some sense, + // though it's a bit confusing to us. + for (auto &SE : File.getStreamMap().drop_front(1)) + for (auto &S : SE) + recordKnownUsedPage(PS, S); + + dumpBitVector("Msf Free Pages", FPM); + dumpBitVector("Orphaned Pages", PS.OrphanedPages); + dumpBitVector("Multiply Used Pages", PS.MultiUsePages); + dumpBitVector("Use After Free Pages", PS.UseAfterFreePages); + return Error::success(); +} + +void LLVMOutputStyle::dumpBitVector(StringRef Name, const BitVector &V) { + std::vector Vec; + for (uint32_t I = 0, E = V.size(); I != E; ++I) + if (V[I]) + Vec.push_back(I); + P.printList(Name, Vec); +} + +Error LLVMOutputStyle::dumpGlobalsStream() { + if (!opts::raw::DumpGlobals) + return Error::success(); + if (!File.hasPDBGlobalsStream()) { + P.printString("Globals Stream not present"); + return Error::success(); + } + + auto Globals = File.getPDBGlobalsStream(); + if (!Globals) + return Globals.takeError(); + DictScope D(P, "Globals Stream"); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + P.printNumber("Stream number", Dbi->getGlobalSymbolStreamIndex()); + P.printNumber("Number of buckets", Globals->getNumBuckets()); + P.printList("Hash Buckets", Globals->getHashBuckets()); + + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamBlocks() { + if (!opts::raw::DumpStreamBlocks) + return Error::success(); + + ListScope L(P, "StreamBlocks"); + uint32_t StreamCount = File.getNumStreams(); + for (uint32_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Name("Stream "); + Name += to_string(StreamIdx); + auto StreamBlocks = File.getStreamBlockList(StreamIdx); + P.printList(Name, StreamBlocks); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpBlockRanges() { + if (!opts::raw::DumpBlockRange.hasValue()) + return Error::success(); + auto &R = *opts::raw::DumpBlockRange; + uint32_t Max = R.Max.getValueOr(R.Min); + + if (Max < R.Min) + return make_error( + "Invalid block range specified. Max < Min", + std::make_error_code(std::errc::bad_address)); + if (Max >= File.getBlockCount()) + return make_error( + "Invalid block range specified. Requested block out of bounds", + std::make_error_code(std::errc::bad_address)); + + DictScope D(P, "Block Data"); + for (uint32_t I = R.Min; I <= Max; ++I) { + auto ExpectedData = File.getBlockData(I, File.getBlockSize()); + if (!ExpectedData) + return ExpectedData.takeError(); + std::string Label; + llvm::raw_string_ostream S(Label); + S << "Block " << I; + S.flush(); + P.printBinaryBlock(Label, *ExpectedData); + } + + return Error::success(); +} + +static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset, + uint32_t &Size) { + if (Str.consumeInteger(0, SI)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + if (Str.consume_front(":")) { + if (Str.consumeInteger(0, Offset)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (Str.consume_front("@")) { + if (Str.consumeInteger(0, Size)) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + } + if (!Str.empty()) + return make_error(raw_error_code::invalid_format, + "Invalid Stream Specification"); + return Error::success(); +} + +Error LLVMOutputStyle::dumpStreamBytes() { + if (opts::raw::DumpStreamData.empty()) + return Error::success(); + + if (StreamPurposes.empty()) + discoverStreamPurposes(File, StreamPurposes); + + DictScope D(P, "Stream Data"); + for (auto &Str : opts::raw::DumpStreamData) { + uint32_t SI = 0; + uint32_t Begin = 0; + uint32_t Size = 0; + uint32_t End = 0; + + if (auto EC = parseStreamSpec(Str, SI, Begin, Size)) + return EC; + + if (SI >= File.getNumStreams()) + return make_error(raw_error_code::no_stream); + + auto S = MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator()); + if (!S) + continue; + DictScope DD(P, "Stream"); + if (Size == 0) + End = S->getLength(); + else { + End = Begin + Size; + if (End >= S->getLength()) + return make_error(raw_error_code::index_out_of_bounds, + "Stream is not long enough!"); + } + + P.printNumber("Index", SI); + P.printString("Type", StreamPurposes[SI]); + P.printNumber("Size", S->getLength()); + auto Blocks = File.getMsfLayout().StreamMap[SI]; + P.printList("Blocks", Blocks); + + BinaryStreamReader R(*S); + ArrayRef StreamData; + if (auto EC = R.readBytes(StreamData, S->getLength())) + return EC; + Size = End - Begin; + StreamData = StreamData.slice(Begin, Size); + P.printBinaryBlock("Data", StreamData, Begin); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpStringTable() { + if (!opts::raw::DumpStringTable) + return Error::success(); + + auto IS = File.getStringTable(); + if (!IS) + return IS.takeError(); + + DictScope D(P, "String Table"); + for (uint32_t I : IS->name_ids()) { + auto ES = IS->getStringForID(I); + if (!ES) + return ES.takeError(); + + if (ES->empty()) + continue; + llvm::SmallString<32> Str; + Str.append("'"); + Str.append(*ES); + Str.append("'"); + P.printString(Str); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpInfoStream() { + if (!opts::raw::DumpHeaders) + return Error::success(); + if (!File.hasPDBInfoStream()) { + P.printString("PDB Stream not present"); + return Error::success(); + } + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + DictScope D(P, "PDB Stream"); + P.printNumber("Version", IS->getVersion()); + P.printHex("Signature", IS->getSignature()); + P.printNumber("Age", IS->getAge()); + P.printObject("Guid", IS->getGuid()); + P.printHex("Features", IS->getFeatures()); + { + DictScope DD(P, "Named Streams"); + for (const auto &S : IS->getNamedStreams().entries()) + P.printObject(S.getKey(), S.getValue()); + } + return Error::success(); +} + +namespace { +class RecordBytesVisitor : public TypeVisitorCallbacks { +public: + explicit RecordBytesVisitor(ScopedPrinter &P) : P(P) {} + + Error visitTypeEnd(CVType &Record) override { + P.printBinaryBlock("Bytes", Record.content()); + return Error::success(); + } + +private: + ScopedPrinter &P; +}; +} // namespace + +Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) { + assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI); + + bool DumpRecordBytes = false; + bool DumpRecords = false; + bool DumpTpiHash = false; + StringRef Label; + StringRef VerLabel; + if (StreamIdx == StreamTPI) { + if (!File.hasPDBTpiStream()) { + P.printString("Type Info Stream (TPI) not present"); + return Error::success(); + } + DumpRecordBytes = opts::raw::DumpTpiRecordBytes; + DumpRecords = opts::raw::DumpTpiRecords; + DumpTpiHash = opts::raw::DumpTpiHash; + Label = "Type Info Stream (TPI)"; + VerLabel = "TPI Version"; + } else if (StreamIdx == StreamIPI) { + if (!File.hasPDBIpiStream()) { + P.printString("Type Info Stream (IPI) not present"); + return Error::success(); + } + DumpRecordBytes = opts::raw::DumpIpiRecordBytes; + DumpRecords = opts::raw::DumpIpiRecords; + Label = "Type Info Stream (IPI)"; + VerLabel = "IPI Version"; + } + + auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream() + : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + auto ExpectedTypes = initializeTypeDatabase(StreamIdx); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &Types = *ExpectedTypes; + + if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash) + return Error::success(); + + std::unique_ptr StreamScope; + std::unique_ptr RecordScope; + + StreamScope = llvm::make_unique(P, Label); + P.printNumber(VerLabel, Tpi->getTpiVersion()); + P.printNumber("Record count", Tpi->getNumTypeRecords()); + + std::vector> Visitors; + + // If we're in dump mode, add a dumper with the appropriate detail level. + if (DumpRecords) { + std::unique_ptr Dumper; + if (opts::raw::CompactRecords) + Dumper = make_unique(Types, &P); + else { + assert(TpiTypes); + + auto X = make_unique(*TpiTypes, &P, false); + if (StreamIdx == StreamIPI) + X->setIpiTypes(*IpiTypes); + Dumper = std::move(X); + } + Visitors.push_back(std::move(Dumper)); + } + if (DumpRecordBytes) + Visitors.push_back(make_unique(P)); + + // We always need to deserialize and add it to the type database. This is + // true if even if we're not dumping anything, because we could need the + // type database for the purposes of dumping symbols. + TypeVisitorCallbackPipeline Pipeline; + for (const auto &V : Visitors) + Pipeline.addCallbackToPipeline(*V); + + if (DumpRecords || DumpRecordBytes) + RecordScope = llvm::make_unique(P, "Records"); + + Optional I = Types.getFirst(); + while (I) { + std::unique_ptr OneRecordScope; + + if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords) + OneRecordScope = llvm::make_unique(P, ""); + + auto T = Types.getType(*I); + if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline)) + return EC; + I = Types.getNext(*I); + } + + if (DumpTpiHash) { + DictScope DD(P, "Hash"); + P.printNumber("Number of Hash Buckets", Tpi->getNumHashBuckets()); + P.printNumber("Hash Key Size", Tpi->getHashKeySize()); + P.printList("Values", Tpi->getHashValues()); + + ListScope LHA(P, "Adjusters"); + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + const auto &ST = *ExpectedST; + for (const auto &E : Tpi->getHashAdjusters()) { + DictScope DHA(P); + auto Name = ST.getStringForID(E.first); + if (!Name) + return Name.takeError(); + + P.printString("Type", *Name); + P.printHex("TI", E.second); + } + } + + ListScope L(P, "TypeIndexOffsets"); + for (const auto &IO : Tpi->getTypeIndexOffsets()) { + P.printString(formatv("Index: {0:x}, Offset: {1:N}", IO.Type.getIndex(), + (uint32_t)IO.Offset) + .str()); + } + + P.flush(); + return Error::success(); +} + +Expected +LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) { + auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes; + auto Tpi = + (SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream(); + if (!Tpi) + return Tpi.takeError(); + + if (!TypeCollection) { + // Initialize the type collection, even if we're not going to dump it. This + // way if some other part of the dumper decides it wants to use some or all + // of the records for whatever purposes, it can still access them lazily. + auto &Types = Tpi->typeArray(); + uint32_t Count = Tpi->getNumTypeRecords(); + auto Offsets = Tpi->getTypeIndexOffsets(); + TypeCollection = + llvm::make_unique(Types, Count, Offsets); + } + + return *TypeCollection; +} + +Error LLVMOutputStyle::dumpDbiStream() { + bool DumpModules = opts::shared::DumpModules || + opts::shared::DumpModuleSyms || + opts::shared::DumpModuleFiles || + !opts::shared::DumpModuleSubsections.empty(); + if (!opts::raw::DumpHeaders && !DumpModules) + return Error::success(); + if (!File.hasPDBDbiStream()) { + P.printString("DBI Stream not present"); + return Error::success(); + } + + auto DS = File.getPDBDbiStream(); + if (!DS) + return DS.takeError(); + + DictScope D(P, "DBI Stream"); + P.printNumber("Dbi Version", DS->getDbiVersion()); + P.printNumber("Age", DS->getAge()); + P.printBoolean("Incremental Linking", DS->isIncrementallyLinked()); + P.printBoolean("Has CTypes", DS->hasCTypes()); + P.printBoolean("Is Stripped", DS->isStripped()); + P.printObject("Machine Type", DS->getMachineType()); + P.printNumber("Symbol Record Stream Index", DS->getSymRecordStreamIndex()); + P.printNumber("Public Symbol Stream Index", DS->getPublicSymbolStreamIndex()); + P.printNumber("Global Symbol Stream Index", DS->getGlobalSymbolStreamIndex()); + + uint16_t Major = DS->getBuildMajorVersion(); + uint16_t Minor = DS->getBuildMinorVersion(); + P.printVersion("Toolchain Version", Major, Minor); + + std::string DllName; + raw_string_ostream DllStream(DllName); + DllStream << "mspdb" << Major << Minor << ".dll version"; + DllStream.flush(); + P.printVersion(DllName, Major, Minor, DS->getPdbDllVersion()); + + if (DumpModules) { + ListScope L(P, "Modules"); + const DbiModuleList &Modules = DS->modules(); + for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { + const DbiModuleDescriptor &Modi = Modules.getModuleDescriptor(I); + DictScope DD(P); + P.printString("Name", Modi.getModuleName().str()); + P.printNumber("Debug Stream Index", Modi.getModuleStreamIndex()); + P.printString("Object File Name", Modi.getObjFileName().str()); + P.printNumber("Num Files", Modi.getNumberOfFiles()); + P.printNumber("Source File Name Idx", Modi.getSourceFileNameIndex()); + P.printNumber("Pdb File Name Idx", Modi.getPdbFilePathNameIndex()); + P.printNumber("Line Info Byte Size", Modi.getC11LineInfoByteSize()); + P.printNumber("C13 Line Info Byte Size", Modi.getC13LineInfoByteSize()); + P.printNumber("Symbol Byte Size", Modi.getSymbolDebugInfoByteSize()); + P.printNumber("Type Server Index", Modi.getTypeServerIndex()); + P.printBoolean("Has EC Info", Modi.hasECInfo()); + if (opts::shared::DumpModuleFiles) { + std::string FileListName = to_string(Modules.getSourceFileCount(I)) + + " Contributing Source Files"; + ListScope LL(P, FileListName); + for (auto File : Modules.source_files(I)) + P.printString(File); + } + bool HasModuleDI = (Modi.getModuleStreamIndex() < File.getNumStreams()); + bool ShouldDumpSymbols = + (opts::shared::DumpModuleSyms || opts::raw::DumpSymRecordBytes); + if (HasModuleDI && + (ShouldDumpSymbols || !opts::shared::DumpModuleSubsections.empty())) { + auto ModStreamData = MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), + Modi.getModuleStreamIndex(), File.getAllocator()); + + ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData)); + if (auto EC = ModS.reload()) + return EC; + + auto ExpectedTpi = initializeTypeDatabase(StreamTPI); + if (!ExpectedTpi) + return ExpectedTpi.takeError(); + auto &Tpi = *ExpectedTpi; + if (ShouldDumpSymbols) { + + ListScope SS(P, "Symbols"); + codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, + false); + bool HadError = false; + for (auto S : ModS.symbols(&HadError)) { + DictScope LL(P, ""); + if (opts::shared::DumpModuleSyms) { + if (auto EC = SD.dump(S)) { + llvm::consumeError(std::move(EC)); + HadError = true; + break; + } + } + if (opts::raw::DumpSymRecordBytes) + P.printBinaryBlock("Bytes", S.content()); + } + if (HadError) + return make_error( + raw_error_code::corrupt_file, + "DBI stream contained corrupt symbol record"); + } + if (!opts::shared::DumpModuleSubsections.empty()) { + ListScope SS(P, "Subsections"); + auto ExpectedIpi = initializeTypeDatabase(StreamIPI); + if (!ExpectedIpi) + return ExpectedIpi.takeError(); + auto &Ipi = *ExpectedIpi; + auto ExpectedStrings = File.getStringTable(); + if (!ExpectedStrings) + return joinErrors( + make_error(raw_error_code::no_stream, + "Could not get string table!"), + ExpectedStrings.takeError()); + + C13RawVisitor V(P, Tpi, Ipi); + if (auto EC = codeview::visitDebugSubsections( + ModS.subsections(), V, ExpectedStrings->getStringTable())) + return EC; + } + } + } + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionContribs() { + if (!opts::raw::DumpSectionContribs) + return Error::success(); + if (!File.hasPDBDbiStream()) { + P.printString("DBI Stream not present"); + return Error::success(); + } + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope L(P, "Section Contributions"); + class Visitor : public ISectionContribVisitor { + public: + Visitor(ScopedPrinter &P, DbiStream &DS) : P(P), DS(DS) {} + void visit(const SectionContrib &SC) override { + DictScope D(P, "Contribution"); + P.printNumber("ISect", SC.ISect); + P.printNumber("Off", SC.Off); + P.printNumber("Size", SC.Size); + P.printFlags("Characteristics", SC.Characteristics, + codeview::getImageSectionCharacteristicNames(), + COFF::SectionCharacteristics(0x00F00000)); + { + DictScope DD(P, "Module"); + P.printNumber("Index", SC.Imod); + const DbiModuleList &Modules = DS.modules(); + if (Modules.getModuleCount() > SC.Imod) { + P.printString("Name", + Modules.getModuleDescriptor(SC.Imod).getModuleName()); + } + } + P.printNumber("Data CRC", SC.DataCrc); + P.printNumber("Reloc CRC", SC.RelocCrc); + P.flush(); + } + void visit(const SectionContrib2 &SC) override { + visit(SC.Base); + P.printNumber("ISect Coff", SC.ISectCoff); + P.flush(); + } + + private: + ScopedPrinter &P; + DbiStream &DS; + }; + Visitor V(P, *Dbi); + Dbi->visitSectionContributions(V); + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionMap() { + if (!opts::raw::DumpSectionMap) + return Error::success(); + if (!File.hasPDBDbiStream()) { + P.printString("DBI Stream not present"); + return Error::success(); + } + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope L(P, "Section Map"); + for (auto &M : Dbi->getSectionMap()) { + DictScope D(P, "Entry"); + P.printFlags("Flags", M.Flags, getOMFSegMapDescFlagNames()); + P.printNumber("Ovl", M.Ovl); + P.printNumber("Group", M.Group); + P.printNumber("Frame", M.Frame); + P.printNumber("SecName", M.SecName); + P.printNumber("ClassName", M.ClassName); + P.printNumber("Offset", M.Offset); + P.printNumber("SecByteLength", M.SecByteLength); + P.flush(); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpPublicsStream() { + if (!opts::raw::DumpPublics) + return Error::success(); + if (!File.hasPDBPublicsStream()) { + P.printString("Publics Stream not present"); + return Error::success(); + } + + auto Publics = File.getPDBPublicsStream(); + if (!Publics) + return Publics.takeError(); + DictScope D(P, "Publics Stream"); + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + P.printNumber("Stream number", Dbi->getPublicSymbolStreamIndex()); + P.printNumber("SymHash", Publics->getSymHash()); + P.printNumber("AddrMap", Publics->getAddrMap()); + P.printNumber("Number of buckets", Publics->getNumBuckets()); + P.printList("Hash Buckets", Publics->getHashBuckets()); + P.printList("Address Map", Publics->getAddressMap()); + P.printList("Thunk Map", Publics->getThunkMap()); + P.printList("Section Offsets", Publics->getSectionOffsets(), + printSectionOffset); + ListScope L(P, "Symbols"); + auto ExpectedTypes = initializeTypeDatabase(StreamTPI); + if (!ExpectedTypes) + return ExpectedTypes.takeError(); + auto &Tpi = *ExpectedTypes; + + codeview::CVSymbolDumper SD(P, Tpi, CodeViewContainer::Pdb, nullptr, false); + bool HadError = false; + for (auto S : Publics->getSymbols(&HadError)) { + DictScope DD(P, ""); + + if (auto EC = SD.dump(S)) { + HadError = true; + break; + } + if (opts::raw::DumpSymRecordBytes) + P.printBinaryBlock("Bytes", S.content()); + } + if (HadError) + return make_error( + raw_error_code::corrupt_file, + "Public symbol stream contained corrupt record"); + + return Error::success(); +} + +Error LLVMOutputStyle::dumpSectionHeaders() { + if (!opts::raw::DumpSectionHeaders) + return Error::success(); + if (!File.hasPDBDbiStream()) { + P.printString("DBI Stream not present"); + return Error::success(); + } + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope D(P, "Section Headers"); + for (const object::coff_section &Section : Dbi->getSectionHeaders()) { + DictScope DD(P, ""); + + // If a name is 8 characters long, there is no NUL character at end. + StringRef Name(Section.Name, strnlen(Section.Name, sizeof(Section.Name))); + P.printString("Name", Name); + P.printNumber("Virtual Size", Section.VirtualSize); + P.printNumber("Virtual Address", Section.VirtualAddress); + P.printNumber("Size of Raw Data", Section.SizeOfRawData); + P.printNumber("File Pointer to Raw Data", Section.PointerToRawData); + P.printNumber("File Pointer to Relocations", Section.PointerToRelocations); + P.printNumber("File Pointer to Linenumbers", Section.PointerToLinenumbers); + P.printNumber("Number of Relocations", Section.NumberOfRelocations); + P.printNumber("Number of Linenumbers", Section.NumberOfLinenumbers); + P.printFlags("Characteristics", Section.Characteristics, + getImageSectionCharacteristicNames()); + } + return Error::success(); +} + +Error LLVMOutputStyle::dumpFpoStream() { + if (!opts::raw::DumpFpo) + return Error::success(); + if (!File.hasPDBDbiStream()) { + P.printString("DBI Stream not present"); + return Error::success(); + } + + auto Dbi = File.getPDBDbiStream(); + if (!Dbi) + return Dbi.takeError(); + + ListScope D(P, "New FPO"); + for (const object::FpoData &Fpo : Dbi->getFpoRecords()) { + DictScope DD(P, ""); + P.printNumber("Offset", Fpo.Offset); + P.printNumber("Size", Fpo.Size); + P.printNumber("Number of locals", Fpo.NumLocals); + P.printNumber("Number of params", Fpo.NumParams); + P.printNumber("Size of Prolog", Fpo.getPrologSize()); + P.printNumber("Number of Saved Registers", Fpo.getNumSavedRegs()); + P.printBoolean("Has SEH", Fpo.hasSEH()); + P.printBoolean("Use BP", Fpo.useBP()); + P.printNumber("Frame Pointer", Fpo.getFP()); + } + return Error::success(); +} + +void LLVMOutputStyle::flush() { P.flush(); } Index: llvm/tools/llvm-pdbutil/LinePrinter.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/LinePrinter.h @@ -0,0 +1,102 @@ +//===- LinePrinter.h ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H +#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" + +#include + +namespace llvm { +namespace pdb { + +class ClassLayout; + +class LinePrinter { + friend class WithColor; + +public: + LinePrinter(int Indent, bool UseColor, raw_ostream &Stream); + + void Indent(); + void Unindent(); + void NewLine(); + + bool hasColor() const { return UseColor; } + raw_ostream &getStream() { return OS; } + int getIndentLevel() const { return CurrentIndent; } + + bool IsClassExcluded(const ClassLayout &Class); + bool IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size); + bool IsSymbolExcluded(llvm::StringRef SymbolName); + bool IsCompilandExcluded(llvm::StringRef CompilandName); + +private: + template + void SetFilters(std::list &List, Iter Begin, Iter End) { + List.clear(); + for (; Begin != End; ++Begin) + List.emplace_back(StringRef(*Begin)); + } + + raw_ostream &OS; + int IndentSpaces; + int CurrentIndent; + bool UseColor; + + std::list ExcludeCompilandFilters; + std::list ExcludeTypeFilters; + std::list ExcludeSymbolFilters; + + std::list IncludeCompilandFilters; + std::list IncludeTypeFilters; + std::list IncludeSymbolFilters; +}; + +template +inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) { + Printer.getStream() << Item; + return Printer.getStream(); +} + +enum class PDB_ColorItem { + None, + Address, + Type, + Comment, + Padding, + Keyword, + Offset, + Identifier, + Path, + SectionHeader, + LiteralValue, + Register, +}; + +class WithColor { +public: + WithColor(LinePrinter &P, PDB_ColorItem C); + ~WithColor(); + + raw_ostream &get() { return OS; } + +private: + void applyColor(PDB_ColorItem C); + raw_ostream &OS; + bool UseColor; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/LinePrinter.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/LinePrinter.cpp @@ -0,0 +1,145 @@ +//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LinePrinter.h" + +#include "llvm-pdbutil.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Regex.h" + +#include + +using namespace llvm; +using namespace llvm::pdb; + +namespace { +bool IsItemExcluded(llvm::StringRef Item, + std::list &IncludeFilters, + std::list &ExcludeFilters) { + if (Item.empty()) + return false; + + auto match_pred = [Item](llvm::Regex &R) { return R.match(Item); }; + + // Include takes priority over exclude. If the user specified include + // filters, and none of them include this item, them item is gone. + if (!IncludeFilters.empty() && !any_of(IncludeFilters, match_pred)) + return true; + + if (any_of(ExcludeFilters, match_pred)) + return true; + + return false; +} +} // namespace + +using namespace llvm; + +LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream) + : OS(Stream), IndentSpaces(Indent), CurrentIndent(0), UseColor(UseColor) { + SetFilters(ExcludeTypeFilters, opts::pretty::ExcludeTypes.begin(), + opts::pretty::ExcludeTypes.end()); + SetFilters(ExcludeSymbolFilters, opts::pretty::ExcludeSymbols.begin(), + opts::pretty::ExcludeSymbols.end()); + SetFilters(ExcludeCompilandFilters, opts::pretty::ExcludeCompilands.begin(), + opts::pretty::ExcludeCompilands.end()); + + SetFilters(IncludeTypeFilters, opts::pretty::IncludeTypes.begin(), + opts::pretty::IncludeTypes.end()); + SetFilters(IncludeSymbolFilters, opts::pretty::IncludeSymbols.begin(), + opts::pretty::IncludeSymbols.end()); + SetFilters(IncludeCompilandFilters, opts::pretty::IncludeCompilands.begin(), + opts::pretty::IncludeCompilands.end()); +} + +void LinePrinter::Indent() { CurrentIndent += IndentSpaces; } + +void LinePrinter::Unindent() { + CurrentIndent = std::max(0, CurrentIndent - IndentSpaces); +} + +void LinePrinter::NewLine() { + OS << "\n"; + OS.indent(CurrentIndent); +} + +bool LinePrinter::IsClassExcluded(const ClassLayout &Class) { + if (IsTypeExcluded(Class.getName(), Class.getSize())) + return true; + if (Class.deepPaddingSize() < opts::pretty::PaddingThreshold) + return true; + return false; +} + +bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) { + if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters)) + return true; + if (Size < opts::pretty::SizeThreshold) + return true; + return false; +} + +bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { + return IsItemExcluded(SymbolName, IncludeSymbolFilters, ExcludeSymbolFilters); +} + +bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { + return IsItemExcluded(CompilandName, IncludeCompilandFilters, + ExcludeCompilandFilters); +} + +WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) + : OS(P.OS), UseColor(P.hasColor()) { + if (UseColor) + applyColor(C); +} + +WithColor::~WithColor() { + if (UseColor) + OS.resetColor(); +} + +void WithColor::applyColor(PDB_ColorItem C) { + switch (C) { + case PDB_ColorItem::None: + OS.resetColor(); + return; + case PDB_ColorItem::Comment: + OS.changeColor(raw_ostream::GREEN, false); + return; + case PDB_ColorItem::Address: + OS.changeColor(raw_ostream::YELLOW, /*bold=*/true); + return; + case PDB_ColorItem::Keyword: + OS.changeColor(raw_ostream::MAGENTA, true); + return; + case PDB_ColorItem::Register: + case PDB_ColorItem::Offset: + OS.changeColor(raw_ostream::YELLOW, false); + return; + case PDB_ColorItem::Type: + OS.changeColor(raw_ostream::CYAN, true); + return; + case PDB_ColorItem::Identifier: + OS.changeColor(raw_ostream::CYAN, false); + return; + case PDB_ColorItem::Path: + OS.changeColor(raw_ostream::CYAN, false); + return; + case PDB_ColorItem::Padding: + case PDB_ColorItem::SectionHeader: + OS.changeColor(raw_ostream::RED, true); + return; + case PDB_ColorItem::LiteralValue: + OS.changeColor(raw_ostream::GREEN, true); + return; + } +} Index: llvm/tools/llvm-pdbutil/OutputStyle.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/OutputStyle.h @@ -0,0 +1,28 @@ +//===- OutputStyle.h ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_OUTPUTSTYLE_H + +#include "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { +class PDBFile; + +class OutputStyle { +public: + virtual ~OutputStyle() {} + + virtual Error dump() = 0; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PdbYaml.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PdbYaml.h @@ -0,0 +1,125 @@ +//===- PdbYAML.h ---------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H +#define LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H + +#include "OutputStyle.h" + +#include "llvm/ADT/Optional.h" +#include "llvm/DebugInfo/CodeView/SymbolRecord.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" +#include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" +#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/YAMLTraits.h" + +#include + +namespace llvm { +namespace codeview { +class DebugStringTableSubsection; +} +namespace pdb { + +namespace yaml { +struct SerializationContext; + +struct MSFHeaders { + msf::SuperBlock SuperBlock; + uint32_t NumDirectoryBlocks = 0; + std::vector DirectoryBlocks; + uint32_t NumStreams = 0; + uint32_t FileSize = 0; +}; + +struct StreamBlockList { + std::vector Blocks; +}; + +struct NamedStreamMapping { + StringRef StreamName; + uint32_t StreamNumber; +}; + +struct PdbInfoStream { + PdbRaw_ImplVer Version = PdbImplVC70; + uint32_t Signature = 0; + uint32_t Age = 1; + PDB_UniqueId Guid; + std::vector Features; + std::vector NamedStreams; +}; + +struct PdbModiStream { + uint32_t Signature; + std::vector Symbols; +}; + +struct PdbDbiModuleInfo { + StringRef Obj; + StringRef Mod; + std::vector SourceFiles; + std::vector Subsections; + Optional Modi; +}; + +struct PdbDbiStream { + PdbRaw_DbiVer VerHeader = PdbDbiV70; + uint32_t Age = 1; + uint16_t BuildNumber = 0; + uint32_t PdbDllVersion = 0; + uint16_t PdbDllRbld = 0; + uint16_t Flags = 1; + PDB_Machine MachineType = PDB_Machine::x86; + + std::vector ModInfos; +}; + +struct PdbTpiStream { + PdbRaw_TpiVer Version = PdbTpiV80; + std::vector Records; +}; + +struct PdbObject { + explicit PdbObject(BumpPtrAllocator &Allocator) : Allocator(Allocator) {} + + Optional Headers; + Optional> StreamSizes; + Optional> StreamMap; + Optional PdbStream; + Optional DbiStream; + Optional TpiStream; + Optional IpiStream; + + Optional> StringTable; + + BumpPtrAllocator &Allocator; +}; +} // namespace yaml +} // namespace pdb +} // namespace llvm + +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbObject) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::MSFHeaders) +LLVM_YAML_DECLARE_MAPPING_TRAITS(msf::SuperBlock) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::StreamBlockList) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbInfoStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbTpiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::NamedStreamMapping) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbModiStream) +LLVM_YAML_DECLARE_MAPPING_TRAITS(pdb::yaml::PdbDbiModuleInfo) + +#endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H Index: llvm/tools/llvm-pdbutil/PdbYaml.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PdbYaml.cpp @@ -0,0 +1,227 @@ +//===- PdbYAML.cpp -------------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PdbYaml.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" +#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h" +#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" +#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/CodeView/TypeSerializer.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/DebugInfo/PDB/Native/TpiHashing.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" +#include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" +#include "llvm/ObjectYAML/CodeViewYAMLTypes.h" + +using namespace llvm; +using namespace llvm::pdb; +using namespace llvm::pdb::yaml; +using namespace llvm::yaml; + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::StringRef) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig) + +namespace llvm { +namespace yaml { + +template <> struct ScalarTraits { + static void output(const llvm::pdb::PDB_UniqueId &S, void *, + llvm::raw_ostream &OS) { + OS << S; + } + + static StringRef input(StringRef Scalar, void *Ctx, + llvm::pdb::PDB_UniqueId &S) { + if (Scalar.size() != 38) + return "GUID strings are 38 characters long"; + if (Scalar[0] != '{' || Scalar[37] != '}') + return "GUID is not enclosed in {}"; + if (Scalar[9] != '-' || Scalar[14] != '-' || Scalar[19] != '-' || + Scalar[24] != '-') + return "GUID sections are not properly delineated with dashes"; + + uint8_t *OutBuffer = S.Guid; + for (auto Iter = Scalar.begin(); Iter != Scalar.end();) { + if (*Iter == '-' || *Iter == '{' || *Iter == '}') { + ++Iter; + continue; + } + uint8_t Value = (llvm::hexDigitValue(*Iter) << 4); + ++Iter; + Value |= llvm::hexDigitValue(*Iter); + ++Iter; + *OutBuffer++ = Value; + } + + return ""; + } + + static bool mustQuote(StringRef Scalar) { return needsQuotes(Scalar); } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) { + io.enumCase(Value, "Invalid", PDB_Machine::Invalid); + io.enumCase(Value, "Am33", PDB_Machine::Am33); + io.enumCase(Value, "Amd64", PDB_Machine::Amd64); + io.enumCase(Value, "Arm", PDB_Machine::Arm); + io.enumCase(Value, "ArmNT", PDB_Machine::ArmNT); + io.enumCase(Value, "Ebc", PDB_Machine::Ebc); + io.enumCase(Value, "x86", PDB_Machine::x86); + io.enumCase(Value, "Ia64", PDB_Machine::Ia64); + io.enumCase(Value, "M32R", PDB_Machine::M32R); + io.enumCase(Value, "Mips16", PDB_Machine::Mips16); + io.enumCase(Value, "MipsFpu", PDB_Machine::MipsFpu); + io.enumCase(Value, "MipsFpu16", PDB_Machine::MipsFpu16); + io.enumCase(Value, "PowerPCFP", PDB_Machine::PowerPCFP); + io.enumCase(Value, "R4000", PDB_Machine::R4000); + io.enumCase(Value, "SH3", PDB_Machine::SH3); + io.enumCase(Value, "SH3DSP", PDB_Machine::SH3DSP); + io.enumCase(Value, "Thumb", PDB_Machine::Thumb); + io.enumCase(Value, "WceMipsV2", PDB_Machine::WceMipsV2); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) { + io.enumCase(Value, "V41", llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41); + io.enumCase(Value, "V50", llvm::pdb::PdbRaw_DbiVer::PdbDbiV50); + io.enumCase(Value, "V60", llvm::pdb::PdbRaw_DbiVer::PdbDbiV60); + io.enumCase(Value, "V70", llvm::pdb::PdbRaw_DbiVer::PdbDbiV70); + io.enumCase(Value, "V110", llvm::pdb::PdbRaw_DbiVer::PdbDbiV110); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) { + io.enumCase(Value, "VC2", llvm::pdb::PdbRaw_ImplVer::PdbImplVC2); + io.enumCase(Value, "VC4", llvm::pdb::PdbRaw_ImplVer::PdbImplVC4); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_ImplVer::PdbImplVC41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_ImplVer::PdbImplVC50); + io.enumCase(Value, "VC98", llvm::pdb::PdbRaw_ImplVer::PdbImplVC98); + io.enumCase(Value, "VC70Dep", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_ImplVer::PdbImplVC70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_ImplVer::PdbImplVC80); + io.enumCase(Value, "VC110", llvm::pdb::PdbRaw_ImplVer::PdbImplVC110); + io.enumCase(Value, "VC140", llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { + io.enumCase(Value, "VC40", llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); + io.enumCase(Value, "VC41", llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); + io.enumCase(Value, "VC50", llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); + io.enumCase(Value, "VC70", llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); + io.enumCase(Value, "VC80", llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); + } +}; + +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, PdbRaw_FeatureSig &Features) { + io.enumCase(Features, "MinimalDebugInfo", + PdbRaw_FeatureSig::MinimalDebugInfo); + io.enumCase(Features, "NoTypeMerge", PdbRaw_FeatureSig::NoTypeMerge); + io.enumCase(Features, "VC110", PdbRaw_FeatureSig::VC110); + io.enumCase(Features, "VC140", PdbRaw_FeatureSig::VC140); + } +}; +} // namespace yaml +} // namespace llvm + +void MappingTraits::mapping(IO &IO, PdbObject &Obj) { + IO.mapOptional("MSF", Obj.Headers); + IO.mapOptional("StreamSizes", Obj.StreamSizes); + IO.mapOptional("StreamMap", Obj.StreamMap); + IO.mapOptional("StringTable", Obj.StringTable); + IO.mapOptional("PdbStream", Obj.PdbStream); + IO.mapOptional("DbiStream", Obj.DbiStream); + IO.mapOptional("TpiStream", Obj.TpiStream); + IO.mapOptional("IpiStream", Obj.IpiStream); +} + +void MappingTraits::mapping(IO &IO, MSFHeaders &Obj) { + IO.mapOptional("SuperBlock", Obj.SuperBlock); + IO.mapOptional("NumDirectoryBlocks", Obj.NumDirectoryBlocks); + IO.mapOptional("DirectoryBlocks", Obj.DirectoryBlocks); + IO.mapOptional("NumStreams", Obj.NumStreams); + IO.mapOptional("FileSize", Obj.FileSize); +} + +void MappingTraits::mapping(IO &IO, msf::SuperBlock &SB) { + if (!IO.outputting()) { + ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic)); + } + + using u32 = support::ulittle32_t; + IO.mapOptional("BlockSize", SB.BlockSize, u32(4096U)); + IO.mapOptional("FreeBlockMap", SB.FreeBlockMapBlock, u32(0U)); + IO.mapOptional("NumBlocks", SB.NumBlocks, u32(0U)); + IO.mapOptional("NumDirectoryBytes", SB.NumDirectoryBytes, u32(0U)); + IO.mapOptional("Unknown1", SB.Unknown1, u32(0U)); + IO.mapOptional("BlockMapAddr", SB.BlockMapAddr, u32(0U)); +} + +void MappingTraits::mapping(IO &IO, StreamBlockList &SB) { + IO.mapRequired("Stream", SB.Blocks); +} + +void MappingTraits::mapping(IO &IO, PdbInfoStream &Obj) { + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("Guid", Obj.Guid); + IO.mapOptional("Signature", Obj.Signature, 0U); + IO.mapOptional("Features", Obj.Features); + IO.mapOptional("Version", Obj.Version, PdbImplVC70); +} + +void MappingTraits::mapping(IO &IO, PdbDbiStream &Obj) { + IO.mapOptional("VerHeader", Obj.VerHeader, PdbDbiV70); + IO.mapOptional("Age", Obj.Age, 1U); + IO.mapOptional("BuildNumber", Obj.BuildNumber, uint16_t(0U)); + IO.mapOptional("PdbDllVersion", Obj.PdbDllVersion, 0U); + IO.mapOptional("PdbDllRbld", Obj.PdbDllRbld, uint16_t(0U)); + IO.mapOptional("Flags", Obj.Flags, uint16_t(1U)); + IO.mapOptional("MachineType", Obj.MachineType, PDB_Machine::x86); + IO.mapOptional("Modules", Obj.ModInfos); +} + +void MappingTraits::mapping(IO &IO, + pdb::yaml::PdbTpiStream &Obj) { + IO.mapOptional("Version", Obj.Version, PdbTpiV80); + IO.mapRequired("Records", Obj.Records); +} + +void MappingTraits::mapping(IO &IO, + NamedStreamMapping &Obj) { + IO.mapRequired("Name", Obj.StreamName); + IO.mapRequired("StreamNum", Obj.StreamNumber); +} + +void MappingTraits::mapping(IO &IO, PdbModiStream &Obj) { + IO.mapOptional("Signature", Obj.Signature, 4U); + IO.mapRequired("Records", Obj.Symbols); +} + +void MappingTraits::mapping(IO &IO, PdbDbiModuleInfo &Obj) { + IO.mapRequired("Module", Obj.Mod); + IO.mapOptional("ObjFile", Obj.Obj, Obj.Mod); + IO.mapOptional("SourceFiles", Obj.SourceFiles); + IO.mapOptional("Subsections", Obj.Subsections); + IO.mapOptional("Modi", Obj.Modi); +} Index: llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.h @@ -0,0 +1,35 @@ +//===- PrettyBuiltinDumper.h ---------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYBUILTINDUMPER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class BuiltinDumper : public PDBSymDumper { +public: + BuiltinDumper(LinePrinter &P); + + void start(const PDBSymbolTypeBuiltin &Symbol); + +private: + StringRef getTypeName(const PDBSymbolTypeBuiltin &Symbol); + + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyBuiltinDumper.cpp @@ -0,0 +1,94 @@ +//===- PrettyBuiltinDumper.cpp ---------------------------------- *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyBuiltinDumper.h" +#include "LinePrinter.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +using namespace llvm; +using namespace llvm::pdb; + +BuiltinDumper::BuiltinDumper(LinePrinter &P) + : PDBSymDumper(false), Printer(P) {} + +void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + WithColor(Printer, PDB_ColorItem::Type).get() << getTypeName(Symbol); +} + +StringRef BuiltinDumper::getTypeName(const PDBSymbolTypeBuiltin &Symbol) { + PDB_BuiltinType Type = Symbol.getBuiltinType(); + switch (Type) { + case PDB_BuiltinType::Float: + if (Symbol.getLength() == 4) + return "float"; + return "double"; + case PDB_BuiltinType::UInt: + switch (Symbol.getLength()) { + case 8: + return "unsigned __int64"; + case 4: + return "unsigned int"; + case 2: + return "unsigned short"; + case 1: + return "unsigned char"; + default: + return "unsigned"; + } + case PDB_BuiltinType::Int: + switch (Symbol.getLength()) { + case 8: + return "__int64"; + case 4: + return "int"; + case 2: + return "short"; + case 1: + return "char"; + default: + return "int"; + } + case PDB_BuiltinType::Char: + return "char"; + case PDB_BuiltinType::WCharT: + return "wchar_t"; + case PDB_BuiltinType::Void: + return "void"; + case PDB_BuiltinType::Long: + return "long"; + case PDB_BuiltinType::ULong: + return "unsigned long"; + case PDB_BuiltinType::Bool: + return "bool"; + case PDB_BuiltinType::Currency: + return "CURRENCY"; + case PDB_BuiltinType::Date: + return "DATE"; + case PDB_BuiltinType::Variant: + return "VARIANT"; + case PDB_BuiltinType::Complex: + return "complex"; + case PDB_BuiltinType::Bitfield: + return "bitfield"; + case PDB_BuiltinType::BSTR: + return "BSTR"; + case PDB_BuiltinType::HResult: + return "HRESULT"; + case PDB_BuiltinType::BCD: + return "HRESULT"; + default: + return "void"; + } +} Index: llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.h @@ -0,0 +1,47 @@ +//===- PrettyClassDefinitionDumper.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSDEFINITIONDUMPER_H + +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" + +#include +#include +#include + +namespace llvm { +class BitVector; + +namespace pdb { + +class ClassLayout; +class LinePrinter; + +class ClassDefinitionDumper : public PDBSymDumper { +public: + ClassDefinitionDumper(LinePrinter &P); + + void start(const PDBSymbolTypeUDT &Class); + void start(const ClassLayout &Class); + +private: + void prettyPrintClassIntro(const ClassLayout &Class); + void prettyPrintClassOutro(const ClassLayout &Class); + + LinePrinter &Printer; + bool DumpedAnything = false; +}; +} // namespace pdb +} // namespace llvm +#endif Index: llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyClassDefinitionDumper.cpp @@ -0,0 +1,108 @@ +//===- PrettyClassDefinitionDumper.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyClassDefinitionDumper.h" + +#include "LinePrinter.h" +#include "PrettyClassLayoutGraphicalDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { + assert(opts::pretty::ClassFormat != + opts::pretty::ClassDefinitionFormat::None); + + ClassLayout Layout(Class); + start(Layout); +} + +void ClassDefinitionDumper::start(const ClassLayout &Layout) { + prettyPrintClassIntro(Layout); + + PrettyClassLayoutGraphicalDumper Dumper(Printer, 1, 0); + DumpedAnything |= Dumper.start(Layout); + + prettyPrintClassOutro(Layout); +} + +void ClassDefinitionDumper::prettyPrintClassIntro(const ClassLayout &Layout) { + DumpedAnything = false; + Printer.NewLine(); + + uint32_t Size = Layout.getSize(); + const PDBSymbolTypeUDT &Class = Layout.getClass(); + + WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; + WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << Size << "]"; + uint32_t BaseCount = Layout.bases().size(); + if (BaseCount > 0) { + Printer.Indent(); + char NextSeparator = ':'; + for (auto BC : Layout.bases()) { + const auto &Base = BC->getBase(); + if (Base.isIndirectVirtualBaseClass()) + continue; + + Printer.NewLine(); + Printer << NextSeparator << " "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << Base.getAccess(); + if (BC->isVirtualBase()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; + + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base.getName(); + NextSeparator = ','; + } + + Printer.Unindent(); + } + + Printer << " {"; + Printer.Indent(); +} + +void ClassDefinitionDumper::prettyPrintClassOutro(const ClassLayout &Layout) { + Printer.Unindent(); + if (DumpedAnything) + Printer.NewLine(); + Printer << "}"; + Printer.NewLine(); + if (Layout.deepPaddingSize() > 0) { + APFloat Pct(100.0 * (double)Layout.deepPaddingSize() / + (double)Layout.getSize()); + SmallString<8> PctStr; + Pct.toString(PctStr, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Total padding " << Layout.deepPaddingSize() << " bytes (" << PctStr + << "% of class size)"; + Printer.NewLine(); + APFloat Pct2(100.0 * (double)Layout.immediatePadding() / + (double)Layout.getSize()); + PctStr.clear(); + Pct2.toString(PctStr, 4); + WithColor(Printer, PDB_ColorItem::Padding).get() + << "Immediate padding " << Layout.immediatePadding() << " bytes (" + << PctStr << "% of class size)"; + Printer.NewLine(); + } +} Index: llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.h @@ -0,0 +1,58 @@ +//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCLASSLAYOUTGRAPHICALDUMPER_H + +#include "llvm/ADT/BitVector.h" + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +namespace pdb { + +class UDTLayoutBase; +class LayoutItemBase; +class LinePrinter; + +class PrettyClassLayoutGraphicalDumper : public PDBSymDumper { +public: + PrettyClassLayoutGraphicalDumper(LinePrinter &P, uint32_t RecurseLevel, + uint32_t InitialOffset); + + bool start(const UDTLayoutBase &Layout); + + // Layout based symbol types. + void dump(const PDBSymbolTypeBaseClass &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolTypeVTable &Symbol) override; + + // Non layout-based symbol types. + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + +private: + bool shouldRecurse() const; + void printPaddingRow(uint32_t Amount); + + LinePrinter &Printer; + + LayoutItemBase *CurrentItem = nullptr; + uint32_t RecursionLevel = 0; + uint32_t ClassOffsetZero = 0; + uint32_t CurrentAbsoluteOffset = 0; + bool DumpedAnything = false; +}; +} // namespace pdb +} // namespace llvm +#endif Index: llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyClassLayoutGraphicalDumper.cpp @@ -0,0 +1,215 @@ +//===- PrettyClassLayoutGraphicalDumper.h -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyClassLayoutGraphicalDumper.h" + +#include "LinePrinter.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyEnumDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypedefDumper.h" +#include "PrettyVariableDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +PrettyClassLayoutGraphicalDumper::PrettyClassLayoutGraphicalDumper( + LinePrinter &P, uint32_t RecurseLevel, uint32_t InitialOffset) + : PDBSymDumper(true), Printer(P), RecursionLevel(RecurseLevel), + ClassOffsetZero(InitialOffset), CurrentAbsoluteOffset(InitialOffset) {} + +bool PrettyClassLayoutGraphicalDumper::start(const UDTLayoutBase &Layout) { + + if (RecursionLevel == 1 && + opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::All) { + for (auto &Other : Layout.other_items()) + Other->dump(*this); + for (auto &Func : Layout.funcs()) + Func->dump(*this); + } + + const BitVector &UseMap = Layout.usedBytes(); + int NextPaddingByte = UseMap.find_first_unset(); + + for (auto &Item : Layout.layout_items()) { + // Calculate the absolute offset of the first byte of the next field. + uint32_t RelativeOffset = Item->getOffsetInParent(); + CurrentAbsoluteOffset = ClassOffsetZero + RelativeOffset; + + // Since there is storage there, it should be set! However, this might + // be an empty base, in which case it could extend outside the bounds of + // the parent class. + if (RelativeOffset < UseMap.size() && (Item->getSize() > 0)) { + assert(UseMap.test(RelativeOffset)); + + // If there is any remaining padding in this class, and the offset of the + // new item is after the padding, then we must have just jumped over some + // padding. Print a padding row and then look for where the next block + // of padding begins. + if ((NextPaddingByte >= 0) && + (RelativeOffset > uint32_t(NextPaddingByte))) { + printPaddingRow(RelativeOffset - NextPaddingByte); + NextPaddingByte = UseMap.find_next_unset(RelativeOffset); + } + } + + CurrentItem = Item; + if (Item->isVBPtr()) { + VTableLayoutItem &Layout = static_cast(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.startVbptr(CurrentAbsoluteOffset, Layout.getSize()); + } else { + if (auto Sym = Item->getSymbol()) + Sym->dump(*this); + } + + if (Item->getLayoutSize() > 0) { + uint32_t Prev = RelativeOffset + Item->getLayoutSize() - 1; + if (Prev < UseMap.size()) + NextPaddingByte = UseMap.find_next_unset(Prev); + } + } + + auto TailPadding = Layout.tailPadding(); + if (TailPadding > 0) { + if (TailPadding != 1 || Layout.getSize() != 1) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() + << " (" << TailPadding << " bytes)"; + DumpedAnything = true; + } + } + + return DumpedAnything; +} + +void PrettyClassLayoutGraphicalDumper::printPaddingRow(uint32_t Amount) { + if (Amount == 0) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Padding).get() + << " (" << Amount << " bytes)"; + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeBaseClass &Symbol) { + assert(CurrentItem != nullptr); + + Printer.NewLine(); + BaseClassLayout &Layout = static_cast(*CurrentItem); + + std::string Label = "base"; + if (Layout.isVirtualBase()) { + Label.insert(Label.begin(), 'v'); + if (Layout.getBase().isIndirectVirtualBaseClass()) + Label.insert(Label.begin(), 'i'); + } + Printer << Label << " "; + + uint32_t Size = Layout.isEmptyBase() ? 1 : Layout.getLayoutSize(); + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(CurrentAbsoluteOffset, 4) << " [sizeof=" << Size + << "] "; + + WithColor(Printer, PDB_ColorItem::Identifier).get() << Layout.getName(); + + if (shouldRecurse()) { + Printer.Indent(); + uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); + PrettyClassLayoutGraphicalDumper BaseDumper(Printer, RecursionLevel + 1, + ChildOffsetZero); + DumpedAnything |= BaseDumper.start(Layout); + Printer.Unindent(); + } + + DumpedAnything = true; +} + +bool PrettyClassLayoutGraphicalDumper::shouldRecurse() const { + uint32_t Limit = opts::pretty::ClassRecursionDepth; + if (Limit == 0) + return true; + return RecursionLevel < Limit; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolData &Symbol) { + assert(CurrentItem != nullptr); + + DataMemberLayoutItem &Layout = + static_cast(*CurrentItem); + + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + if (Layout.hasUDTLayout() && shouldRecurse()) { + uint32_t ChildOffsetZero = ClassOffsetZero + Layout.getOffsetInParent(); + Printer.Indent(); + PrettyClassLayoutGraphicalDumper TypeDumper(Printer, RecursionLevel + 1, + ChildOffsetZero); + TypeDumper.start(Layout.getUDTLayout()); + Printer.Unindent(); + } + + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeVTable &Symbol) { + assert(CurrentItem != nullptr); + + VariableDumper VarDumper(Printer); + VarDumper.start(Symbol, ClassOffsetZero); + + DumpedAnything = true; +} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeEnum &Symbol) { + DumpedAnything = true; + Printer.NewLine(); + EnumDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeTypedef &Symbol) { + DumpedAnything = true; + Printer.NewLine(); + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void PrettyClassLayoutGraphicalDumper::dump( + const PDBSymbolTypeBuiltin &Symbol) {} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolTypeUDT &Symbol) {} + +void PrettyClassLayoutGraphicalDumper::dump(const PDBSymbolFunc &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + if (Symbol.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) + return; + if (Symbol.getLength() == 0 && !Symbol.isPureVirtual() && + !Symbol.isIntroVirtualFunction()) + return; + + DumpedAnything = true; + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); +} Index: llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyCompilandDumper.h @@ -0,0 +1,44 @@ +//===- PrettyCompilandDumper.h - llvm-pdbutil compiland dumper -*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYCOMPILANDDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +typedef int CompilandDumpFlags; +class CompilandDumper : public PDBSymDumper { +public: + enum Flags { None = 0x0, Children = 0x1, Symbols = 0x2, Lines = 0x4 }; + + CompilandDumper(LinePrinter &P); + + void start(const PDBSymbolCompiland &Symbol, CompilandDumpFlags flags); + + void dump(const PDBSymbolCompilandDetails &Symbol) override; + void dump(const PDBSymbolCompilandEnv &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolLabel &Symbol) override; + void dump(const PDBSymbolThunk &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolUnknown &Symbol) override; + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyCompilandDumper.cpp @@ -0,0 +1,207 @@ +//===- PrettyCompilandDumper.cpp - llvm-pdbutil compiland dumper -*- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyCompilandDumper.h" + +#include "LinePrinter.h" +#include "PrettyFunctionDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBLineNumber.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/IPDBSourceFile.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; +using namespace llvm::pdb; + +CompilandDumper::CompilandDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {} + +void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {} + +void CompilandDumper::start(const PDBSymbolCompiland &Symbol, + CompilandDumpFlags opts) { + std::string FullName = Symbol.getName(); + if (Printer.IsCompilandExcluded(FullName)) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Path).get() << FullName; + + if (opts & Flags::Lines) { + const IPDBSession &Session = Symbol.getSession(); + auto Files = Session.getSourceFilesForCompiland(Symbol); + Printer.Indent(); + while (auto File = Files->getNext()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Path).get() << File->getFileName(); + + auto Lines = Session.findLineNumbers(Symbol, *File); + Printer.Indent(); + while (auto Line = Lines->getNext()) { + Printer.NewLine(); + uint32_t LineStart = Line->getLineNumber(); + uint32_t LineEnd = Line->getLineNumberEnd(); + + Printer << "Line "; + PDB_ColorItem StatementColor = Line->isStatement() + ? PDB_ColorItem::Keyword + : PDB_ColorItem::LiteralValue; + WithColor(Printer, StatementColor).get() << LineStart; + if (LineStart != LineEnd) + WithColor(Printer, StatementColor).get() << " - " << LineEnd; + + uint32_t ColumnStart = Line->getColumnNumber(); + uint32_t ColumnEnd = Line->getColumnNumberEnd(); + if (ColumnStart != 0 || ColumnEnd != 0) { + Printer << ", Column: "; + WithColor(Printer, StatementColor).get() << ColumnStart; + if (ColumnEnd != ColumnStart) + WithColor(Printer, StatementColor).get() << " - " << ColumnEnd; + } + + Printer << ", Address: "; + if (Line->getLength() > 0) { + uint64_t AddrStart = Line->getVirtualAddress(); + uint64_t AddrEnd = AddrStart + Line->getLength() - 1; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(AddrStart, 10) << " - " + << format_hex(AddrEnd, 10) << "]"; + Printer << " (" << Line->getLength() << " bytes)"; + } else { + uint64_t AddrStart = Line->getVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(AddrStart, 10) << "] "; + Printer << "(0 bytes)"; + } + } + Printer.Unindent(); + } + Printer.Unindent(); + } + + if (opts & Flags::Children) { + auto ChildrenEnum = Symbol.findAllChildren(); + Printer.Indent(); + while (auto Child = ChildrenEnum->getNext()) + Child->dump(*this); + Printer.Unindent(); + } +} + +void CompilandDumper::dump(const PDBSymbolData &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Data)) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + + switch (auto LocType = Symbol.getLocationType()) { + case PDB_LocType::Static: + Printer << "data: "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]"; + + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; + + break; + case PDB_LocType::Constant: + Printer << "constant: "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << "[" << Symbol.getValue() << "]"; + WithColor(Printer, PDB_ColorItem::Comment).get() + << " [sizeof = " << getTypeLength(Symbol) << "]"; + break; + default: + Printer << "data(unexpected type=" << LocType << ")"; + } + + Printer << " "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); +} + +void CompilandDumper::dump(const PDBSymbolFunc &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) + return; + if (Symbol.getLength() == 0) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); +} + +void CompilandDumper::dump(const PDBSymbolLabel &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "label "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); +} + +void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { + if (!shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) + return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "thunk "; + codeview::ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); + uint64_t VA = Symbol.getVirtualAddress(); + if (Ordinal == codeview::ThunkOrdinal::TrampIncremental) { + uint64_t Target = Symbol.getTargetVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10); + Printer << " -> "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10); + } else { + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(VA, 10) << " - " + << format_hex(VA + Symbol.getLength(), 10) << "]"; + } + Printer << " ("; + WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal; + Printer << ") "; + std::string Name = Symbol.getName(); + if (!Name.empty()) + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; +} + +void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {} + +void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) { + Printer.NewLine(); + Printer << "unknown (" << Symbol.getSymTag() << ")"; +} Index: llvm/tools/llvm-pdbutil/PrettyEnumDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyEnumDumper.h @@ -0,0 +1,31 @@ +//===- PrettyEnumDumper.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYENUMDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class EnumDumper : public PDBSymDumper { +public: + EnumDumper(LinePrinter &P); + + void start(const PDBSymbolTypeEnum &Symbol); + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm +#endif Index: llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyEnumDumper.cpp @@ -0,0 +1,53 @@ +//===- PrettyEnumDumper.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyEnumDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; +using namespace llvm::pdb; + +EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); + if (!opts::pretty::NoEnumDefs) { + auto BuiltinType = Symbol.getUnderlyingType(); + if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int || + BuiltinType->getLength() != 4) { + Printer << " : "; + BuiltinDumper Dumper(Printer); + Dumper.start(*BuiltinType); + } + Printer << " {"; + Printer.Indent(); + auto EnumValues = Symbol.findAllChildren(); + while (auto EnumValue = EnumValues->getNext()) { + if (EnumValue->getDataKind() != PDB_DataKind::Constant) + continue; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << EnumValue->getName(); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << EnumValue->getValue(); + } + Printer.Unindent(); + Printer.NewLine(); + Printer << "}"; + } +} Index: llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.h @@ -0,0 +1,34 @@ +//===- PrettyExternalSymbolDumper.h --------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYEXTERNALSYMBOLDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class ExternalSymbolDumper : public PDBSymDumper { +public: + ExternalSymbolDumper(LinePrinter &P); + + void start(const PDBSymbolExe &Symbol); + + void dump(const PDBSymbolPublicSymbol &Symbol) override; + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyExternalSymbolDumper.cpp @@ -0,0 +1,41 @@ +//===- PrettyExternalSymbolDumper.cpp -------------------------- *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyExternalSymbolDumper.h" +#include "LinePrinter.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::pdb; + +ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) { + auto Vars = Symbol.findAllChildren(); + while (auto Var = Vars->getNext()) + Var->dump(*this); +} + +void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) { + std::string LinkageName = Symbol.getName(); + if (Printer.IsSymbolExcluded(LinkageName)) + return; + + Printer.NewLine(); + uint64_t Addr = Symbol.getVirtualAddress(); + + Printer << "["; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10); + Printer << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName; +} Index: llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyFunctionDumper.h @@ -0,0 +1,43 @@ +//===- PrettyFunctionDumper.h --------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYFUNCTIONDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { +class LinePrinter; + +class FunctionDumper : public PDBSymDumper { +public: + FunctionDumper(LinePrinter &P); + + enum class PointerType { None, Pointer, Reference }; + + void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name, + PointerType Pointer); + void start(const PDBSymbolFunc &Symbol, PointerType Pointer); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionArg &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyFunctionDumper.cpp @@ -0,0 +1,259 @@ +//===- PrettyFunctionDumper.cpp --------------------------------- *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyFunctionDumper.h" +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +namespace { +template +void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer, + FunctionDumper &Dumper) { + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().template getConcreteSymbolById( + ClassParentId); + if (!ClassParent) + return; + + WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName(); + Printer << "::"; +} +} // namespace + +FunctionDumper::FunctionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, + const char *Name, PointerType Pointer) { + auto ReturnType = Symbol.getReturnType(); + ReturnType->dump(*this); + Printer << " "; + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().getConcreteSymbolById( + ClassParentId); + + PDB_CallingConv CC = Symbol.getCallingConvention(); + bool ShouldDumpCallingConvention = true; + if ((ClassParent && CC == CallingConvention::ThisCall) || + (!ClassParent && CC == CallingConvention::NearStdCall)) { + ShouldDumpCallingConvention = false; + } + + if (Pointer == PointerType::None) { + if (ShouldDumpCallingConvention) + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + Printer << "("; + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::)"; + } + } else { + Printer << "("; + if (ShouldDumpCallingConvention) + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::"; + } + if (Pointer == PointerType::Reference) + Printer << "&"; + else + Printer << "*"; + if (Name) + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; + Printer << ")"; + } + + Printer << "("; + if (auto ChildEnum = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = ChildEnum->getNext()) { + Arg->dump(*this); + if (++Index < ChildEnum->getChildCount()) + Printer << ", "; + } + } + Printer << ")"; + + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; +} + +void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) { + uint64_t FuncStart = Symbol.getVirtualAddress(); + uint64_t FuncEnd = FuncStart + Symbol.getLength(); + + Printer << "func ["; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10); + if (auto DebugStart = Symbol.findOneChild()) { + uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart; + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("+{0,2}", Prologue); + } + Printer << " - "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10); + if (auto DebugEnd = Symbol.findOneChild()) { + uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Offset).get() + << formatv("-{0,2}", Epilogue); + } + + WithColor(Printer, PDB_ColorItem::Comment).get() + << formatv(" | sizeof={0,3}", Symbol.getLength()); + Printer << "] ("; + + if (Symbol.hasFramePointer()) { + WithColor(Printer, PDB_ColorItem::Register).get() + << Symbol.getLocalBasePointerRegisterId(); + } else { + WithColor(Printer, PDB_ColorItem::Register).get() << "FPO"; + } + Printer << ") "; + + if (Symbol.isVirtual() || Symbol.isPureVirtual()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual "; + + auto Signature = Symbol.getSignature(); + if (!Signature) { + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); + if (Pointer == PointerType::Pointer) + Printer << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + Printer << "&"; + return; + } + + auto ReturnType = Signature->getReturnType(); + ReturnType->dump(*this); + Printer << " "; + + auto ClassParent = Symbol.getClassParent(); + CallingConvention CC = Signature->getCallingConvention(); + if (Pointer != FunctionDumper::PointerType::None) + Printer << "("; + + if ((ClassParent && CC != CallingConvention::ThisCall) || + (!ClassParent && CC != CallingConvention::NearStdCall)) { + WithColor(Printer, PDB_ColorItem::Keyword).get() + << Signature->getCallingConvention() << " "; + } + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); + if (Pointer != FunctionDumper::PointerType::None) { + if (Pointer == PointerType::Pointer) + Printer << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + Printer << "&"; + Printer << ")"; + } + + Printer << "("; + if (auto Arguments = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = Arguments->getNext()) { + auto ArgType = Arg->getType(); + ArgType->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << " " << Arg->getName(); + if (++Index < Arguments->getChildCount()) + Printer << ", "; + } + } + Printer << ")"; + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; + if (Symbol.isPureVirtual()) + Printer << " = 0"; +} + +void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + + ElementType->dump(*this); + Printer << "["; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength(); + Printer << "]"; +} + +void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { + // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill + // through to the real thing and dump it. + uint32_t TypeId = Symbol.getTypeId(); + auto Type = Symbol.getSession().getSymbolById(TypeId); + if (!Type) + return; + Type->dump(*this); +} + +void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + if (!PointeeType) + return; + + if (auto FuncSig = unique_dyn_cast(PointeeType)) { + FunctionDumper NestedDumper(Printer); + PointerType Pointer = + Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; + NestedDumper.start(*FuncSig, nullptr, Pointer); + } else { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + PointeeType->dump(*this); + Printer << (Symbol.isReference() ? "&" : "*"); + } +} + +void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} Index: llvm/tools/llvm-pdbutil/PrettyTypeDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyTypeDumper.h @@ -0,0 +1,36 @@ +//===- PrettyTypeDumper.h - PDBSymDumper implementation for types *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { +class LinePrinter; +class ClassLayout; + +class TypeDumper : public PDBSymDumper { +public: + TypeDumper(LinePrinter &P); + + void start(const PDBSymbolExe &Exe); + + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + + void dumpClassLayout(const ClassLayout &Class); + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm +#endif Index: llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyTypeDumper.cpp @@ -0,0 +1,255 @@ +//===- PrettyTypeDumper.cpp - PDBSymDumper type dumper *------------ C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyTypeDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyClassDefinitionDumper.h" +#include "PrettyEnumDumper.h" +#include "PrettyTypedefDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/UDTLayout.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace llvm; +using namespace llvm::pdb; + +using LayoutPtr = std::unique_ptr; + +typedef bool (*CompareFunc)(const LayoutPtr &S1, const LayoutPtr &S2); + +static bool CompareNames(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getName() < S2->getName(); +} + +static bool CompareSizes(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->getSize() < S2->getSize(); +} + +static bool ComparePadding(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->deepPaddingSize() < S2->deepPaddingSize(); +} + +static bool ComparePaddingPct(const LayoutPtr &S1, const LayoutPtr &S2) { + double Pct1 = (double)S1->deepPaddingSize() / (double)S1->getSize(); + double Pct2 = (double)S2->deepPaddingSize() / (double)S2->getSize(); + return Pct1 < Pct2; +} + +static bool ComparePaddingImmediate(const LayoutPtr &S1, const LayoutPtr &S2) { + return S1->immediatePadding() < S2->immediatePadding(); +} + +static bool ComparePaddingPctImmediate(const LayoutPtr &S1, + const LayoutPtr &S2) { + double Pct1 = (double)S1->immediatePadding() / (double)S1->getSize(); + double Pct2 = (double)S2->immediatePadding() / (double)S2->getSize(); + return Pct1 < Pct2; +} + +static CompareFunc getComparisonFunc(opts::pretty::ClassSortMode Mode) { + switch (Mode) { + case opts::pretty::ClassSortMode::Name: + return CompareNames; + case opts::pretty::ClassSortMode::Size: + return CompareSizes; + case opts::pretty::ClassSortMode::Padding: + return ComparePadding; + case opts::pretty::ClassSortMode::PaddingPct: + return ComparePaddingPct; + case opts::pretty::ClassSortMode::PaddingImmediate: + return ComparePaddingImmediate; + case opts::pretty::ClassSortMode::PaddingPctImmediate: + return ComparePaddingPctImmediate; + default: + return nullptr; + } +} + +template +static std::vector> +filterAndSortClassDefs(LinePrinter &Printer, Enumerator &E, + uint32_t UnfilteredCount) { + std::vector> Filtered; + + Filtered.reserve(UnfilteredCount); + CompareFunc Comp = getComparisonFunc(opts::pretty::ClassOrder); + + if (UnfilteredCount > 10000) { + errs() << formatv("Filtering and sorting {0} types", UnfilteredCount); + errs().flush(); + } + uint32_t Examined = 0; + uint32_t Discarded = 0; + while (auto Class = E.getNext()) { + ++Examined; + if (Examined % 10000 == 0) { + errs() << formatv("Examined {0}/{1} items. {2} items discarded\n", + Examined, UnfilteredCount, Discarded); + errs().flush(); + } + + if (Class->getUnmodifiedTypeId() != 0) { + ++Discarded; + continue; + } + + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) { + ++Discarded; + continue; + } + + auto Layout = llvm::make_unique(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) { + ++Discarded; + continue; + } + if (Layout->immediatePadding() < opts::pretty::ImmediatePaddingThreshold) { + ++Discarded; + continue; + } + + Filtered.push_back(std::move(Layout)); + } + + if (Comp) + std::sort(Filtered.begin(), Filtered.end(), Comp); + return Filtered; +} + +TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void TypeDumper::start(const PDBSymbolExe &Exe) { + auto Children = Exe.findAllChildren(); + if (opts::pretty::Enums) { + if (auto Enums = Exe.findAllChildren()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums"; + Printer << ": (" << Enums->getChildCount() << " items)"; + Printer.Indent(); + while (auto Enum = Enums->getNext()) + Enum->dump(*this); + Printer.Unindent(); + } + } + + if (opts::pretty::Typedefs) { + if (auto Typedefs = Exe.findAllChildren()) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs"; + Printer << ": (" << Typedefs->getChildCount() << " items)"; + Printer.Indent(); + while (auto Typedef = Typedefs->getNext()) + Typedef->dump(*this); + Printer.Unindent(); + } + } + + if (opts::pretty::Classes) { + if (auto Classes = Exe.findAllChildren()) { + uint32_t All = Classes->getChildCount(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; + + bool Precompute = false; + Precompute = + (opts::pretty::ClassOrder != opts::pretty::ClassSortMode::None); + + // If we're using no sort mode, then we can start getting immediate output + // from the tool by just filtering as we go, rather than processing + // everything up front so that we can sort it. This makes the tool more + // responsive. So only precompute the filtered/sorted set of classes if + // necessary due to the specified options. + std::vector Filtered; + uint32_t Shown = All; + if (Precompute) { + Filtered = filterAndSortClassDefs(Printer, *Classes, All); + + Shown = Filtered.size(); + } + + Printer << ": (Showing " << Shown << " items"; + if (Shown < All) + Printer << ", " << (All - Shown) << " filtered"; + Printer << ")"; + Printer.Indent(); + + // If we pre-computed, iterate the filtered/sorted list, otherwise iterate + // the DIA enumerator and filter on the fly. + if (Precompute) { + for (auto &Class : Filtered) + dumpClassLayout(*Class); + } else { + while (auto Class = Classes->getNext()) { + if (Class->getUnmodifiedTypeId() != 0) + continue; + + if (Printer.IsTypeExcluded(Class->getName(), Class->getLength())) + continue; + + auto Layout = llvm::make_unique(std::move(Class)); + if (Layout->deepPaddingSize() < opts::pretty::PaddingThreshold) + continue; + + dumpClassLayout(*Layout); + } + } + + Printer.Unindent(); + } + } +} + +void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { + assert(opts::pretty::Enums); + + if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) + return; + // Dump member enums when dumping their class definition. + if (nullptr != Symbol.getClassParent()) + return; + + Printer.NewLine(); + EnumDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + assert(opts::pretty::Typedefs); + + if (Printer.IsTypeExcluded(Symbol.getName(), Symbol.getLength())) + return; + + Printer.NewLine(); + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypeDumper::dumpClassLayout(const ClassLayout &Class) { + assert(opts::pretty::Classes); + + if (opts::pretty::ClassFormat == opts::pretty::ClassDefinitionFormat::None) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Class.getName(); + } else { + ClassDefinitionDumper Dumper(Printer); + Dumper.start(Class); + } +} Index: llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyTypedefDumper.h @@ -0,0 +1,39 @@ +//===- PrettyTypedefDumper.h - llvm-pdbutil typedef dumper ---*- C++ ----*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYTYPEDEFDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { +namespace pdb { + +class LinePrinter; + +class TypedefDumper : public PDBSymDumper { +public: + TypedefDumper(LinePrinter &P); + + void start(const PDBSymbolTypeTypedef &Symbol); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyTypedefDumper.cpp @@ -0,0 +1,77 @@ +//===- PrettyTypedefDumper.cpp - PDBSymDumper impl for typedefs -- * C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyTypedefDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyFunctionDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +using namespace llvm; +using namespace llvm::pdb; + +TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; + uint32_t TargetId = Symbol.getTypeId(); + if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId)) + TypeSymbol->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << " " << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {} + +void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) { + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + auto PointeeType = Symbol.getPointeeType(); + if (auto FuncSig = unique_dyn_cast(PointeeType)) { + FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; + if (Symbol.isReference()) + Pointer = FunctionDumper::PointerType::Reference; + FunctionDumper NestedDumper(Printer); + NestedDumper.start(*FuncSig, nullptr, Pointer); + } else { + PointeeType->dump(*this); + Printer << ((Symbol.isReference()) ? "&" : "*"); + } +} + +void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); +} + +void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} Index: llvm/tools/llvm-pdbutil/PrettyVariableDumper.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyVariableDumper.h @@ -0,0 +1,50 @@ +//===- PrettyVariableDumper.h - PDBSymDumper variable dumper ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_PRETTYVARIABLEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class StringRef; + +namespace pdb { + +class LinePrinter; + +class VariableDumper : public PDBSymDumper { +public: + VariableDumper(LinePrinter &P); + + void start(const PDBSymbolData &Var, uint32_t Offset = 0); + void start(const PDBSymbolTypeVTable &Var, uint32_t Offset = 0); + void startVbptr(uint32_t Offset, uint32_t Size); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + + void dumpRight(const PDBSymbolTypeArray &Symbol) override; + void dumpRight(const PDBSymbolTypeFunctionSig &Symbol) override; + void dumpRight(const PDBSymbolTypePointer &Symbol) override; + +private: + void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name); + + LinePrinter &Printer; +}; +} // namespace pdb +} // namespace llvm +#endif Index: llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/PrettyVariableDumper.cpp @@ -0,0 +1,219 @@ +//===- PrettyVariableDumper.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PrettyVariableDumper.h" + +#include "LinePrinter.h" +#include "PrettyBuiltinDumper.h" +#include "PrettyFunctionDumper.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +VariableDumper::VariableDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void VariableDumper::start(const PDBSymbolData &Var, uint32_t Offset) { + if (Var.isCompilerGenerated() && opts::pretty::ExcludeCompilerGenerated) + return; + if (Printer.IsSymbolExcluded(Var.getName())) + return; + + auto VarType = Var.getType(); + + uint64_t Length = VarType->getRawSymbol().getLength(); + + switch (auto LocType = Var.getLocationType()) { + case PDB_LocType::Static: + Printer.NewLine(); + Printer << "data ["; + WithColor(Printer, PDB_ColorItem::Address).get() + << format_hex(Var.getVirtualAddress(), 10); + Printer << ", sizeof=" << Length << "] "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "static "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + break; + case PDB_LocType::Constant: + if (isa(*VarType)) + break; + Printer.NewLine(); + Printer << "data [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue(); + break; + case PDB_LocType::ThisRel: + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + break; + case PDB_LocType::BitField: + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << Length << "] "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " : "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); + break; + default: + Printer.NewLine(); + Printer << "data [sizeof=" << Length << "] "; + Printer << "unknown(" << LocType << ") "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName(); + break; + } +} + +void VariableDumper::startVbptr(uint32_t Offset, uint32_t Size) { + Printer.NewLine(); + Printer << "vbptr "; + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset, 4) << " [sizeof=" << Size << "] "; +} + +void VariableDumper::start(const PDBSymbolTypeVTable &Var, uint32_t Offset) { + Printer.NewLine(); + Printer << "vfptr "; + auto VTableType = cast(Var.getType()); + uint32_t PointerSize = VTableType->getLength(); + + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Offset + Var.getOffset(), 4) + << " [sizeof=" << PointerSize << "] "; +} + +void VariableDumper::dump(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + assert(ElementType); + if (!ElementType) + return; + ElementType->dump(*this); +} + +void VariableDumper::dumpRight(const PDBSymbolTypeArray &Symbol) { + auto ElementType = Symbol.getElementType(); + assert(ElementType); + if (!ElementType) + return; + Printer << '[' << Symbol.getCount() << ']'; + ElementType->dumpRight(*this); +} + +void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); +} + +void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + auto ReturnType = Symbol.getReturnType(); + ReturnType->dump(*this); + Printer << " "; + + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().getConcreteSymbolById( + ClassParentId); + + if (ClassParent) { + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::"; + } +} + +void VariableDumper::dumpRight(const PDBSymbolTypeFunctionSig &Symbol) { + Printer << "("; + if (auto Arguments = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = Arguments->getNext()) { + Arg->dump(*this); + if (++Index < Arguments->getChildCount()) + Printer << ", "; + } + } + Printer << ")"; + + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; +} + +void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + if (!PointeeType) + return; + PointeeType->dump(*this); + if (auto FuncSig = unique_dyn_cast(PointeeType)) { + // A hack to get the calling convention in the right spot. + Printer << " ("; + PDB_CallingConv CC = FuncSig->getCallingConvention(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + } else if (isa(PointeeType)) { + Printer << " ("; + } + Printer << (Symbol.isReference() ? "&" : "*"); + if (Symbol.isConstType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const "; + if (Symbol.isVolatileType()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile "; +} + +void VariableDumper::dumpRight(const PDBSymbolTypePointer &Symbol) { + auto PointeeType = Symbol.getPointeeType(); + assert(PointeeType); + if (!PointeeType) + return; + if (isa(PointeeType) || + isa(PointeeType)) { + Printer << ")"; + } + PointeeType->dumpRight(*this); +} + +void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); +} + +void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type, + StringRef Name) { + Type.dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name; + Type.dumpRight(*this); +} Index: llvm/tools/llvm-pdbutil/StreamUtil.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/StreamUtil.h @@ -0,0 +1,25 @@ +//===- Streamutil.h - PDB stream utilities ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H +#define LLVM_TOOLS_LLVMPDBDUMP_STREAMUTIL_H + +#include "llvm/ADT/SmallVector.h" + +#include + +namespace llvm { +namespace pdb { +class PDBFile; +void discoverStreamPurposes(PDBFile &File, + SmallVectorImpl &Purposes); +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/tools/llvm-pdbutil/StreamUtil.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/StreamUtil.cpp @@ -0,0 +1,138 @@ +//===- StreamUtil.cpp - PDB stream utilities --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "StreamUtil.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleList.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +namespace llvm { +namespace pdb { +void discoverStreamPurposes(PDBFile &File, + SmallVectorImpl &Purposes) { + + // It's OK if we fail to load some of these streams, we still attempt to print + // what we can. + auto Dbi = File.getPDBDbiStream(); + auto Tpi = File.getPDBTpiStream(); + auto Ipi = File.getPDBIpiStream(); + auto Info = File.getPDBInfoStream(); + + uint32_t StreamCount = File.getNumStreams(); + DenseMap ModStreams; + DenseMap NamedStreams; + + if (Dbi) { + const DbiModuleList &Modules = Dbi->modules(); + for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { + DbiModuleDescriptor Descriptor = Modules.getModuleDescriptor(I); + uint16_t SN = Descriptor.getModuleStreamIndex(); + if (SN != kInvalidStreamIndex) + ModStreams[SN] = Descriptor; + } + } + if (Info) { + for (auto &NSE : Info->named_streams()) { + if (NSE.second != kInvalidStreamIndex) + NamedStreams[NSE.second] = NSE.first(); + } + } + + Purposes.resize(StreamCount); + for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) { + std::string Value; + if (StreamIdx == OldMSFDirectory) + Value = "Old MSF Directory"; + else if (StreamIdx == StreamPDB) + Value = "PDB Stream"; + else if (StreamIdx == StreamDBI) + Value = "DBI Stream"; + else if (StreamIdx == StreamTPI) + Value = "TPI Stream"; + else if (StreamIdx == StreamIPI) + Value = "IPI Stream"; + else if (Dbi && StreamIdx == Dbi->getGlobalSymbolStreamIndex()) + Value = "Global Symbol Hash"; + else if (Dbi && StreamIdx == Dbi->getPublicSymbolStreamIndex()) + Value = "Public Symbol Hash"; + else if (Dbi && StreamIdx == Dbi->getSymRecordStreamIndex()) + Value = "Public Symbol Records"; + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamIndex()) + Value = "TPI Hash"; + else if (Tpi && StreamIdx == Tpi->getTypeHashStreamAuxIndex()) + Value = "TPI Aux Hash"; + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamIndex()) + Value = "IPI Hash"; + else if (Ipi && StreamIdx == Ipi->getTypeHashStreamAuxIndex()) + Value = "IPI Aux Hash"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Exception)) + Value = "Exception Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Fixup)) + Value = "Fixup Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::FPO)) + Value = "FPO Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::NewFPO)) + Value = "New FPO Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapFromSrc)) + Value = "Omap From Source Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::OmapToSrc)) + Value = "Omap To Source Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Pdata)) + Value = "Pdata"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdr)) + Value = "Section Header Data"; + else if (Dbi && StreamIdx == + Dbi->getDebugStreamIndex(DbgHeaderType::SectionHdrOrig)) + Value = "Section Header Original Data"; + else if (Dbi && + StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::TokenRidMap)) + Value = "Token Rid Data"; + else if (Dbi && StreamIdx == Dbi->getDebugStreamIndex(DbgHeaderType::Xdata)) + Value = "Xdata"; + else { + auto ModIter = ModStreams.find(StreamIdx); + auto NSIter = NamedStreams.find(StreamIdx); + if (ModIter != ModStreams.end()) { + Value = "Module \""; + Value += ModIter->second.getModuleName(); + Value += "\""; + } else if (NSIter != NamedStreams.end()) { + Value = "Named Stream \""; + Value += NSIter->second; + Value += "\""; + } else { + Value = "???"; + } + } + Purposes[StreamIdx] = Value; + } + + // Consume errors from missing streams. + if (!Dbi) + consumeError(Dbi.takeError()); + if (!Tpi) + consumeError(Tpi.takeError()); + if (!Ipi) + consumeError(Ipi.takeError()); + if (!Info) + consumeError(Info.takeError()); +} +} // namespace pdb +} // namespace llvm Index: llvm/tools/llvm-pdbutil/YAMLOutputStyle.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/YAMLOutputStyle.h @@ -0,0 +1,49 @@ +//===- YAMLOutputStyle.h -------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H +#define LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H + +#include "OutputStyle.h" +#include "PdbYaml.h" + +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/YAMLTraits.h" + +namespace llvm { +namespace pdb { +class ModuleDebugStreamRef; + +class YAMLOutputStyle : public OutputStyle { +public: + YAMLOutputStyle(PDBFile &File); + + Error dump() override; + +private: + Error dumpStringTable(); + Error dumpFileHeaders(); + Error dumpStreamMetadata(); + Error dumpStreamDirectory(); + Error dumpPDBStream(); + Error dumpDbiStream(); + Error dumpTpiStream(); + Error dumpIpiStream(); + + void flush(); + + PDBFile &File; + llvm::yaml::Output Out; + + yaml::PdbObject Obj; +}; +} // namespace pdb +} // namespace llvm + +#endif // LLVM_TOOLS_LLVMPDBDUMP_YAMLOUTPUTSTYLE_H Index: llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp @@ -0,0 +1,316 @@ +//===- YAMLOutputStyle.cpp ------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "YAMLOutputStyle.h" + +#include "PdbYaml.h" +#include "llvm-pdbutil.h" + +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h" +#include "llvm/DebugInfo/CodeView/Line.h" +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::pdb; + +YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) + : File(File), Out(outs()), Obj(File.getAllocator()) { + Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal); +} + +Error YAMLOutputStyle::dump() { + if (opts::pdb2yaml::StreamDirectory) + opts::pdb2yaml::StreamMetadata = true; + + if (auto EC = dumpFileHeaders()) + return EC; + + if (auto EC = dumpStreamMetadata()) + return EC; + + if (auto EC = dumpStreamDirectory()) + return EC; + + if (auto EC = dumpStringTable()) + return EC; + + if (auto EC = dumpPDBStream()) + return EC; + + if (auto EC = dumpDbiStream()) + return EC; + + if (auto EC = dumpTpiStream()) + return EC; + + if (auto EC = dumpIpiStream()) + return EC; + + flush(); + return Error::success(); +} + +Error YAMLOutputStyle::dumpFileHeaders() { + if (opts::pdb2yaml::NoFileHeaders) + return Error::success(); + + yaml::MSFHeaders Headers; + Obj.Headers.emplace(); + Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount(); + Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex(); + Obj.Headers->SuperBlock.BlockSize = File.getBlockSize(); + auto Blocks = File.getDirectoryBlockArray(); + Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end()); + Obj.Headers->NumDirectoryBlocks = File.getNumDirectoryBlocks(); + Obj.Headers->SuperBlock.NumDirectoryBytes = File.getNumDirectoryBytes(); + Obj.Headers->NumStreams = + opts::pdb2yaml::StreamMetadata ? File.getNumStreams() : 0; + Obj.Headers->SuperBlock.FreeBlockMapBlock = File.getFreeBlockMapBlock(); + Obj.Headers->SuperBlock.Unknown1 = File.getUnknown1(); + Obj.Headers->FileSize = File.getFileSize(); + + return Error::success(); +} + +Error YAMLOutputStyle::dumpStringTable() { + bool RequiresStringTable = opts::shared::DumpModuleFiles || + !opts::shared::DumpModuleSubsections.empty(); + bool RequestedStringTable = opts::pdb2yaml::StringTable; + if (!RequiresStringTable && !RequestedStringTable) + return Error::success(); + + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + + Obj.StringTable.emplace(); + const auto &ST = ExpectedST.get(); + for (auto ID : ST.name_ids()) { + auto S = ST.getStringForID(ID); + if (!S) + return S.takeError(); + if (S->empty()) + continue; + Obj.StringTable->push_back(*S); + } + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamMetadata() { + if (!opts::pdb2yaml::StreamMetadata) + return Error::success(); + + Obj.StreamSizes.emplace(); + Obj.StreamSizes->assign(File.getStreamSizes().begin(), + File.getStreamSizes().end()); + return Error::success(); +} + +Error YAMLOutputStyle::dumpStreamDirectory() { + if (!opts::pdb2yaml::StreamDirectory) + return Error::success(); + + auto StreamMap = File.getStreamMap(); + Obj.StreamMap.emplace(); + for (auto &Stream : StreamMap) { + pdb::yaml::StreamBlockList BlockList; + BlockList.Blocks.assign(Stream.begin(), Stream.end()); + Obj.StreamMap->push_back(BlockList); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpPDBStream() { + if (!opts::pdb2yaml::PdbStream) + return Error::success(); + + auto IS = File.getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + auto &InfoS = IS.get(); + Obj.PdbStream.emplace(); + Obj.PdbStream->Age = InfoS.getAge(); + Obj.PdbStream->Guid = InfoS.getGuid(); + Obj.PdbStream->Signature = InfoS.getSignature(); + Obj.PdbStream->Version = InfoS.getVersion(); + Obj.PdbStream->Features = InfoS.getFeatureSignatures(); + + return Error::success(); +} + +static opts::ModuleSubsection convertSubsectionKind(DebugSubsectionKind K) { + switch (K) { + case DebugSubsectionKind::CrossScopeExports: + return opts::ModuleSubsection::CrossScopeExports; + case DebugSubsectionKind::CrossScopeImports: + return opts::ModuleSubsection::CrossScopeImports; + case DebugSubsectionKind::FileChecksums: + return opts::ModuleSubsection::FileChecksums; + case DebugSubsectionKind::InlineeLines: + return opts::ModuleSubsection::InlineeLines; + case DebugSubsectionKind::Lines: + return opts::ModuleSubsection::Lines; + case DebugSubsectionKind::Symbols: + return opts::ModuleSubsection::Symbols; + case DebugSubsectionKind::StringTable: + return opts::ModuleSubsection::StringTable; + case DebugSubsectionKind::FrameData: + return opts::ModuleSubsection::FrameData; + default: + return opts::ModuleSubsection::Unknown; + } + llvm_unreachable("Unreachable!"); +} + +Error YAMLOutputStyle::dumpDbiStream() { + if (!opts::pdb2yaml::DbiStream) + return Error::success(); + + auto DbiS = File.getPDBDbiStream(); + if (!DbiS) + return DbiS.takeError(); + + auto &DS = DbiS.get(); + Obj.DbiStream.emplace(); + Obj.DbiStream->Age = DS.getAge(); + Obj.DbiStream->BuildNumber = DS.getBuildNumber(); + Obj.DbiStream->Flags = DS.getFlags(); + Obj.DbiStream->MachineType = DS.getMachineType(); + Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld(); + Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion(); + Obj.DbiStream->VerHeader = DS.getDbiVersion(); + if (opts::shared::DumpModules) { + const auto &Modules = DS.modules(); + for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) { + DbiModuleDescriptor MI = Modules.getModuleDescriptor(I); + + Obj.DbiStream->ModInfos.emplace_back(); + yaml::PdbDbiModuleInfo &DMI = Obj.DbiStream->ModInfos.back(); + + DMI.Mod = MI.getModuleName(); + DMI.Obj = MI.getObjFileName(); + if (opts::shared::DumpModuleFiles) { + auto Files = Modules.source_files(I); + DMI.SourceFiles.assign(Files.begin(), Files.end()); + } + + uint16_t ModiStream = MI.getModuleStreamIndex(); + if (ModiStream == kInvalidStreamIndex) + continue; + + auto ModStreamData = msf::MappedBlockStream::createIndexedStream( + File.getMsfLayout(), File.getMsfBuffer(), ModiStream, + File.getAllocator()); + + pdb::ModuleDebugStreamRef ModS(MI, std::move(ModStreamData)); + if (auto EC = ModS.reload()) + return EC; + + auto ExpectedST = File.getStringTable(); + if (!ExpectedST) + return ExpectedST.takeError(); + if (!opts::shared::DumpModuleSubsections.empty() && + ModS.hasDebugSubsections()) { + auto ExpectedChecksums = ModS.findChecksumsSubsection(); + if (!ExpectedChecksums) + return ExpectedChecksums.takeError(); + + for (const auto &SS : ModS.subsections()) { + opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind()); + if (!opts::checkModuleSubsection(OptionKind)) + continue; + + auto Converted = + CodeViewYAML::YAMLDebugSubsection::fromCodeViewSubection( + ExpectedST->getStringTable(), *ExpectedChecksums, SS); + if (!Converted) + return Converted.takeError(); + DMI.Subsections.push_back(*Converted); + } + } + + if (opts::shared::DumpModuleSyms) { + DMI.Modi.emplace(); + + DMI.Modi->Signature = ModS.signature(); + bool HadError = false; + for (auto &Sym : ModS.symbols(&HadError)) { + auto ES = CodeViewYAML::SymbolRecord::fromCodeViewSymbol(Sym); + if (!ES) + return ES.takeError(); + + DMI.Modi->Symbols.push_back(*ES); + } + } + } + } + return Error::success(); +} + +Error YAMLOutputStyle::dumpTpiStream() { + if (!opts::pdb2yaml::TpiStream) + return Error::success(); + + auto TpiS = File.getPDBTpiStream(); + if (!TpiS) + return TpiS.takeError(); + + auto &TS = TpiS.get(); + Obj.TpiStream.emplace(); + Obj.TpiStream->Version = TS.getTpiVersion(); + for (auto &Record : TS.types(nullptr)) { + auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + Obj.TpiStream->Records.push_back(*ExpectedRecord); + } + + return Error::success(); +} + +Error YAMLOutputStyle::dumpIpiStream() { + if (!opts::pdb2yaml::IpiStream) + return Error::success(); + + auto IpiS = File.getPDBIpiStream(); + if (!IpiS) + return IpiS.takeError(); + + auto &IS = IpiS.get(); + Obj.IpiStream.emplace(); + Obj.IpiStream->Version = IS.getTpiVersion(); + for (auto &Record : IS.types(nullptr)) { + auto ExpectedRecord = CodeViewYAML::LeafRecord::fromCodeViewRecord(Record); + if (!ExpectedRecord) + return ExpectedRecord.takeError(); + + Obj.IpiStream->Records.push_back(*ExpectedRecord); + } + + return Error::success(); +} + +void YAMLOutputStyle::flush() { + Out << Obj; + outs().flush(); +} Index: llvm/tools/llvm-pdbutil/fuzzer/CMakeLists.txt =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/fuzzer/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoCodeView + DebugInfoPDB + Object + Support + ) + +add_llvm_executable(llvm-pdbtoolpdbdump-fuzzer + EXCLUDE_FROM_ALL + llvm-pdbutil-fuzzer.cpp + ) + +target_link_libraries(llvm-pdbutil-fuzzer + LLVMFuzzer + ) Index: llvm/tools/llvm-pdbutil/fuzzer/llvm-pdbtool-fuzzer.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/fuzzer/llvm-pdbtool-fuzzer.cpp @@ -0,0 +1,105 @@ +//===-- llvm-pdbutil-fuzzer.cpp - Fuzz the llvm-pdbutil tool --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements a function that runs llvm-pdbutil +/// on a single input. This function is then linked into the Fuzzer library. +/// +//===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/CodeView/BinaryByteStream.h" +#include "llvm/DebugInfo/CodeView/SymbolDumper.h" +#include "llvm/DebugInfo/CodeView/TypeDumper.h" +#include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawSession.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ScopedPrinter.h" + +using namespace llvm; + +namespace { +// We need a class which behaves like an immutable BinaryByteStream, but whose +// data +// is backed by an llvm::MemoryBuffer. It also needs to own the underlying +// MemoryBuffer, so this simple adapter is a good way to achieve that. +class InputByteStream : public codeview::BinaryByteStream { +public: + explicit InputByteStream(std::unique_ptr Buffer) + : BinaryByteStream(ArrayRef(Buffer->getBuffer().bytes_begin(), + Buffer->getBuffer().bytes_end())), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr MemBuffer; +}; +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) { + std::unique_ptr Buff = MemoryBuffer::getMemBuffer( + StringRef((const char *)data, size), "", false); + + ScopedPrinter P(nulls()); + codeview::CVTypeDumper TD(&P, false); + + auto InputStream = llvm::make_unique(std::move(Buff)); + std::unique_ptr File(new pdb::PDBFile(std::move(InputStream))); + if (auto E = File->parseFileHeaders()) { + consumeError(std::move(E)); + return 0; + } + if (auto E = File->parseStreamData()) { + consumeError(std::move(E)); + return 0; + } + + auto DbiS = File->getPDBDbiStream(); + if (auto E = DbiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto TpiS = File->getPDBTpiStream(); + if (auto E = TpiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto IpiS = File->getPDBIpiStream(); + if (auto E = IpiS.takeError()) { + consumeError(std::move(E)); + return 0; + } + auto InfoS = File->getPDBInfoStream(); + if (auto E = InfoS.takeError()) { + consumeError(std::move(E)); + return 0; + } + pdb::DbiStream &DS = DbiS.get(); + + for (auto &Modi : DS.modules()) { + auto ModStreamData = pdb::MappedBlockStream::createIndexedStream( + Modi.Info.getModuleStreamIndex(), *File, File->getAllocator()); + if (!ModStreamData) { + consumeError(ModStreamData.takeError()); + return 0; + } + pdb::ModuleDebugStreamRef ModS(Modi.Info, std::move(*ModStreamData)); + if (auto E = ModS.reload()) { + consumeError(std::move(E)); + return 0; + } + codeview::CVSymbolDumper SD(P, TD, nullptr, false); + bool HadError = false; + for (auto &S : ModS.symbols(&HadError)) { + SD.dump(S); + } + } + return 0; +} Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.h =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.h @@ -0,0 +1,156 @@ +//===- llvm-pdbutil.h ----------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H +#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H + +#include "llvm/ADT/Optional.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include + +namespace llvm { +namespace pdb { +class PDBSymbolData; +class PDBSymbolFunc; +uint32_t getTypeLength(const PDBSymbolData &Symbol); +} // namespace pdb +} // namespace llvm + +namespace opts { + +enum class ModuleSubsection { + Unknown, + Lines, + FileChecksums, + InlineeLines, + CrossScopeImports, + CrossScopeExports, + StringTable, + Symbols, + FrameData, + All +}; + +bool checkModuleSubsection(ModuleSubsection Kind); + +template +bool checkModuleSubsection(ModuleSubsection K1, ModuleSubsection K2, + Ts &&... Rest) { + return checkModuleSubsection(K1) || + checkModuleSubsection(K2, std::forward(Rest)...); +} + +namespace pretty { + +enum class ClassDefinitionFormat { None, Layout, All }; +enum class ClassSortMode { + None, + Name, + Size, + Padding, + PaddingPct, + PaddingImmediate, + PaddingPctImmediate +}; + +enum class SymbolSortMode { None, Name, Size }; + +enum class SymLevel { Functions, Data, Thunks, All }; + +bool shouldDumpSymLevel(SymLevel Level); +bool compareFunctionSymbols( + const std::unique_ptr &F1, + const std::unique_ptr &F2); +bool compareDataSymbols(const std::unique_ptr &F1, + const std::unique_ptr &F2); + +extern llvm::cl::opt Compilands; +extern llvm::cl::opt Symbols; +extern llvm::cl::opt Globals; +extern llvm::cl::opt Classes; +extern llvm::cl::opt Enums; +extern llvm::cl::opt Typedefs; +extern llvm::cl::opt All; +extern llvm::cl::opt ExcludeCompilerGenerated; + +extern llvm::cl::opt NoEnumDefs; +extern llvm::cl::list ExcludeTypes; +extern llvm::cl::list ExcludeSymbols; +extern llvm::cl::list ExcludeCompilands; +extern llvm::cl::list IncludeTypes; +extern llvm::cl::list IncludeSymbols; +extern llvm::cl::list IncludeCompilands; +extern llvm::cl::opt SymbolOrder; +extern llvm::cl::opt ClassOrder; +extern llvm::cl::opt SizeThreshold; +extern llvm::cl::opt PaddingThreshold; +extern llvm::cl::opt ImmediatePaddingThreshold; +extern llvm::cl::opt ClassFormat; +extern llvm::cl::opt ClassRecursionDepth; +} // namespace pretty + +namespace raw { +struct BlockRange { + uint32_t Min; + llvm::Optional Max; +}; + +extern llvm::Optional DumpBlockRange; +extern llvm::cl::list DumpStreamData; + +extern llvm::cl::opt CompactRecords; +extern llvm::cl::opt DumpGlobals; +extern llvm::cl::opt DumpHeaders; +extern llvm::cl::opt DumpStreamBlocks; +extern llvm::cl::opt DumpStreamSummary; +extern llvm::cl::opt DumpPageStats; +extern llvm::cl::opt DumpTpiHash; +extern llvm::cl::opt DumpTpiRecordBytes; +extern llvm::cl::opt DumpTpiRecords; +extern llvm::cl::opt DumpIpiRecords; +extern llvm::cl::opt DumpIpiRecordBytes; +extern llvm::cl::opt DumpPublics; +extern llvm::cl::opt DumpSectionContribs; +extern llvm::cl::opt DumpSectionMap; +extern llvm::cl::opt DumpSymRecordBytes; +extern llvm::cl::opt DumpSectionHeaders; +extern llvm::cl::opt DumpFpo; +extern llvm::cl::opt DumpStringTable; +} // namespace raw + +namespace diff { +extern llvm::cl::opt Pedantic; +} + +namespace pdb2yaml { +extern llvm::cl::opt All; +extern llvm::cl::opt NoFileHeaders; +extern llvm::cl::opt Minimal; +extern llvm::cl::opt StreamMetadata; +extern llvm::cl::opt StreamDirectory; +extern llvm::cl::opt StringTable; +extern llvm::cl::opt PdbStream; +extern llvm::cl::opt DbiStream; +extern llvm::cl::opt TpiStream; +extern llvm::cl::opt IpiStream; +extern llvm::cl::list InputFilename; +} // namespace pdb2yaml + +namespace shared { +extern llvm::cl::opt DumpModules; +extern llvm::cl::opt DumpModuleFiles; +extern llvm::cl::list DumpModuleSubsections; +extern llvm::cl::opt DumpModuleSyms; +} // namespace shared +} // namespace opts + +#endif Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- /dev/null +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -0,0 +1,1026 @@ +//===- llvm-pdbutil.cpp - Dump debug info from a PDB file -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Dumps debug information present in PDB files. +// +//===----------------------------------------------------------------------===// + +#include "llvm-pdbutil.h" + +#include "Analyze.h" +#include "Diff.h" +#include "LLVMOutputStyle.h" +#include "LinePrinter.h" +#include "OutputStyle.h" +#include "PrettyCompilandDumper.h" +#include "PrettyExternalSymbolDumper.h" +#include "PrettyFunctionDumper.h" +#include "PrettyTypeDumper.h" +#include "PrettyVariableDumper.h" +#include "YAMLOutputStyle.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h" +#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" +#include "llvm/DebugInfo/MSF/MSFBuilder.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawError.h" +#include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/COM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::codeview; +using namespace llvm::msf; +using namespace llvm::pdb; + +namespace opts { + +cl::SubCommand RawSubcommand("raw", "Dump raw structure of the PDB file"); +cl::SubCommand + PrettySubcommand("pretty", + "Dump semantic information about types and symbols"); + +cl::SubCommand DiffSubcommand("diff", "Diff the contents of 2 PDB files"); + +cl::SubCommand + YamlToPdbSubcommand("yaml2pdb", + "Generate a PDB file from a YAML description"); +cl::SubCommand + PdbToYamlSubcommand("pdb2yaml", + "Generate a detailed YAML description of a PDB File"); + +cl::SubCommand + AnalyzeSubcommand("analyze", + "Analyze various aspects of a PDB's structure"); + +cl::SubCommand MergeSubcommand("merge", + "Merge multiple PDBs into a single PDB"); + +cl::OptionCategory TypeCategory("Symbol Type Options"); +cl::OptionCategory FilterCategory("Filtering and Sorting Options"); +cl::OptionCategory OtherOptions("Other Options"); + +namespace pretty { +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(PrettySubcommand)); + +cl::opt Compilands("compilands", cl::desc("Display compilands"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Symbols("module-syms", + cl::desc("Display symbols for each compiland"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Globals("globals", cl::desc("Dump global symbols"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Externals("externals", cl::desc("Dump external symbols"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::list SymTypes( + "sym-types", cl::desc("Type of symbols to dump (default all)"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand), cl::ZeroOrMore, + cl::values( + clEnumValN(SymLevel::Thunks, "thunks", "Display thunk symbols"), + clEnumValN(SymLevel::Data, "data", "Display data symbols"), + clEnumValN(SymLevel::Functions, "funcs", "Display function symbols"), + clEnumValN(SymLevel::All, "all", "Display all symbols (default)"))); + +cl::opt + Types("types", + cl::desc("Display all types (implies -classes, -enums, -typedefs)"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Classes("classes", cl::desc("Display class types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Enums("enums", cl::desc("Display enum types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt Typedefs("typedefs", cl::desc("Display typedef types"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt SymbolOrder( + "symbol-order", cl::desc("symbol sort order"), + cl::init(SymbolSortMode::None), + cl::values(clEnumValN(SymbolSortMode::None, "none", + "Undefined / no particular sort order"), + clEnumValN(SymbolSortMode::Name, "name", "Sort symbols by name"), + clEnumValN(SymbolSortMode::Size, "size", + "Sort symbols by size")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt ClassOrder( + "class-order", cl::desc("Class sort order"), cl::init(ClassSortMode::None), + cl::values( + clEnumValN(ClassSortMode::None, "none", + "Undefined / no particular sort order"), + clEnumValN(ClassSortMode::Name, "name", "Sort classes by name"), + clEnumValN(ClassSortMode::Size, "size", "Sort classes by size"), + clEnumValN(ClassSortMode::Padding, "padding", + "Sort classes by amount of padding"), + clEnumValN(ClassSortMode::PaddingPct, "padding-pct", + "Sort classes by percentage of space consumed by padding"), + clEnumValN(ClassSortMode::PaddingImmediate, "padding-imm", + "Sort classes by amount of immediate padding"), + clEnumValN(ClassSortMode::PaddingPctImmediate, "padding-pct-imm", + "Sort classes by percentage of space consumed by immediate " + "padding")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt ClassFormat( + "class-definitions", cl::desc("Class definition format"), + cl::init(ClassDefinitionFormat::All), + cl::values( + clEnumValN(ClassDefinitionFormat::All, "all", + "Display all class members including data, constants, " + "typedefs, functions, etc"), + clEnumValN(ClassDefinitionFormat::Layout, "layout", + "Only display members that contribute to class size."), + clEnumValN(ClassDefinitionFormat::None, "none", + "Don't display class definitions")), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); +cl::opt ClassRecursionDepth( + "class-recurse-depth", cl::desc("Class recursion depth (0=no limit)"), + cl::init(0), cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt Lines("lines", cl::desc("Line tables"), cl::cat(TypeCategory), + cl::sub(PrettySubcommand)); +cl::opt + All("all", cl::desc("Implies all other options in 'Symbol Types' category"), + cl::cat(TypeCategory), cl::sub(PrettySubcommand)); + +cl::opt LoadAddress( + "load-address", + cl::desc("Assume the module is loaded at the specified address"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt Native("native", cl::desc("Use native PDB reader instead of DIA"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::opt + ColorOutput("color-output", + cl::desc("Override use of color (default = isatty)"), + cl::cat(OtherOptions), cl::sub(PrettySubcommand)); +cl::list ExcludeTypes( + "exclude-types", cl::desc("Exclude types by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list ExcludeSymbols( + "exclude-symbols", cl::desc("Exclude symbols by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list ExcludeCompilands( + "exclude-compilands", cl::desc("Exclude compilands by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::list IncludeTypes( + "include-types", + cl::desc("Include only types which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list IncludeSymbols( + "include-symbols", + cl::desc("Include only symbols which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::list IncludeCompilands( + "include-compilands", + cl::desc("Include only compilands those which match a regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt + SizeThreshold("min-type-size", + cl::desc("Displays only those types which are greater " + "than or equal to the specified size."), + cl::init(0), cl::cat(FilterCategory), + cl::sub(PrettySubcommand)); +cl::opt + PaddingThreshold("min-class-padding", + cl::desc("Displays only those classes which have at " + "least the specified amount of padding."), + cl::init(0), cl::cat(FilterCategory), + cl::sub(PrettySubcommand)); +cl::opt ImmediatePaddingThreshold( + "min-class-padding-imm", + cl::desc("Displays only those classes which have at least the specified " + "amount of immediate padding, ignoring padding internal to bases " + "and aggregates."), + cl::init(0), cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::opt ExcludeCompilerGenerated( + "no-compiler-generated", + cl::desc("Don't show compiler generated types and symbols"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +cl::opt + ExcludeSystemLibraries("no-system-libs", + cl::desc("Don't show symbols from system libraries"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); + +cl::opt NoEnumDefs("no-enum-definitions", + cl::desc("Don't display full enum definitions"), + cl::cat(FilterCategory), cl::sub(PrettySubcommand)); +} // namespace pretty + +namespace diff { +cl::opt Pedantic("pedantic", + cl::desc("Finds all differences (even structural ones " + "that produce otherwise identical PDBs)"), + cl::sub(DiffSubcommand)); + +cl::list InputFilenames(cl::Positional, + cl::desc(" "), + cl::OneOrMore, cl::sub(DiffSubcommand)); +} // namespace diff + +namespace raw { + +cl::OptionCategory MsfOptions("MSF Container Options"); +cl::OptionCategory TypeOptions("Type Record Options"); +cl::OptionCategory SymbolOptions("Symbol Options"); +cl::OptionCategory MiscOptions("Miscellaneous Options"); + +// MSF OPTIONS +cl::opt DumpHeaders("headers", cl::desc("dump PDB headers"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpStreamBlocks("stream-blocks", + cl::desc("dump PDB stream blocks"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpStreamSummary("stream-summary", + cl::desc("dump summary of the PDB streams"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt DumpPageStats( + "page-stats", + cl::desc("dump allocation stats of the pages in the MSF file"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +cl::opt + DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"), + cl::desc("Dump binary data from specified range."), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); +llvm::Optional DumpBlockRange; + +cl::list + DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore, + cl::desc("Dump binary data from specified streams. Format " + "is SN[:Start][@Size]"), + cl::cat(MsfOptions), cl::sub(RawSubcommand)); + +// TYPE OPTIONS +cl::opt + CompactRecords("compact-records", + cl::desc("Dump type and symbol records with less detail"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); + +cl::opt + DumpTpiRecords("tpi-records", + cl::desc("dump CodeView type records from TPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpTpiRecordBytes( + "tpi-record-bytes", + cl::desc("dump CodeView type record raw bytes from TPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt + DumpIpiRecords("ipi-records", + cl::desc("dump CodeView type records from IPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); +cl::opt DumpIpiRecordBytes( + "ipi-record-bytes", + cl::desc("dump CodeView type record raw bytes from IPI stream"), + cl::cat(TypeOptions), cl::sub(RawSubcommand)); + +// SYMBOL OPTIONS +cl::opt DumpGlobals("globals", cl::desc("dump globals stream data"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); +cl::opt DumpPublics("publics", cl::desc("dump Publics stream data"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); +cl::opt + DumpSymRecordBytes("sym-record-bytes", + cl::desc("dump CodeView symbol record raw bytes"), + cl::cat(SymbolOptions), cl::sub(RawSubcommand)); + +// MISCELLANEOUS OPTIONS +cl::opt DumpStringTable("string-table", cl::desc("dump PDB String Table"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); + +cl::opt DumpSectionContribs("section-contribs", + cl::desc("dump section contributions"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpSectionMap("section-map", cl::desc("dump section map"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpSectionHeaders("section-headers", + cl::desc("dump section headers"), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); +cl::opt DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions), + cl::sub(RawSubcommand)); + +cl::opt RawAll("all", cl::desc("Implies most other options."), + cl::cat(MiscOptions), cl::sub(RawSubcommand)); + +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(RawSubcommand)); +} // namespace raw + +namespace yaml2pdb { +cl::opt + YamlPdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), + cl::sub(YamlToPdbSubcommand)); + +cl::opt InputFilename(cl::Positional, + cl::desc(""), cl::Required, + cl::sub(YamlToPdbSubcommand)); +} // namespace yaml2pdb + +namespace pdb2yaml { +cl::opt All("all", cl::desc("Dump everything we know how to dump."), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt NoFileHeaders("no-file-headers", + cl::desc("Do not dump MSF file headers"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt Minimal("minimal", + cl::desc("Don't write fields with default values"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt StreamMetadata( + "stream-metadata", + cl::desc("Dump the number of streams and each stream's size"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt StreamDirectory( + "stream-directory", + cl::desc("Dump each stream's block map (implies -stream-metadata)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); +cl::opt PdbStream("pdb-stream", + cl::desc("Dump the PDB Stream (Stream 1)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt StringTable("string-table", cl::desc("Dump the PDB String Table"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt DbiStream("dbi-stream", + cl::desc("Dump the DBI Stream Headers (Stream 2)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt TpiStream("tpi-stream", + cl::desc("Dump the TPI Stream (Stream 3)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::opt IpiStream("ipi-stream", + cl::desc("Dump the IPI Stream (Stream 5)"), + cl::sub(PdbToYamlSubcommand), cl::init(false)); + +cl::list InputFilename(cl::Positional, + cl::desc(""), cl::Required, + cl::sub(PdbToYamlSubcommand)); +} // namespace pdb2yaml + +namespace shared { +cl::OptionCategory FileOptions("Module & File Options"); + +// MODULE & FILE OPTIONS +cl::opt DumpModules("modules", cl::desc("dump compiland information"), + cl::cat(FileOptions), cl::sub(RawSubcommand), + cl::sub(PdbToYamlSubcommand)); +cl::opt DumpModuleFiles("module-files", cl::desc("dump file information"), + cl::cat(FileOptions), cl::sub(RawSubcommand), + cl::sub(PdbToYamlSubcommand)); +cl::list DumpModuleSubsections( + "subsections", cl::ZeroOrMore, cl::CommaSeparated, + cl::desc("dump subsections from each module's debug stream"), + cl::values( + clEnumValN( + ModuleSubsection::CrossScopeExports, "cme", + "Cross module exports (DEBUG_S_CROSSSCOPEEXPORTS subsection)"), + clEnumValN( + ModuleSubsection::CrossScopeImports, "cmi", + "Cross module imports (DEBUG_S_CROSSSCOPEIMPORTS subsection)"), + clEnumValN(ModuleSubsection::FileChecksums, "fc", + "File checksums (DEBUG_S_CHECKSUMS subsection)"), + clEnumValN(ModuleSubsection::InlineeLines, "ilines", + "Inlinee lines (DEBUG_S_INLINEELINES subsection)"), + clEnumValN(ModuleSubsection::Lines, "lines", + "Lines (DEBUG_S_LINES subsection)"), + clEnumValN(ModuleSubsection::StringTable, "strings", + "String Table (DEBUG_S_STRINGTABLE subsection) (not " + "typically present in PDB file)"), + clEnumValN(ModuleSubsection::FrameData, "frames", + "Frame Data (DEBUG_S_FRAMEDATA subsection)"), + clEnumValN(ModuleSubsection::Symbols, "symbols", + "Symbols (DEBUG_S_SYMBOLS subsection) (not typically " + "present in PDB file)"), + clEnumValN(ModuleSubsection::Unknown, "unknown", + "Any subsection not covered by another option"), + clEnumValN(ModuleSubsection::All, "all", "All known subsections")), + cl::cat(FileOptions), cl::sub(RawSubcommand), cl::sub(PdbToYamlSubcommand)); +cl::opt DumpModuleSyms("module-syms", cl::desc("dump module symbols"), + cl::cat(FileOptions), cl::sub(RawSubcommand), + cl::sub(PdbToYamlSubcommand)); +} // namespace shared + +namespace analyze { +cl::opt StringTable("hash-collisions", cl::desc("Find hash collisions"), + cl::sub(AnalyzeSubcommand), cl::init(false)); +cl::list InputFilename(cl::Positional, + cl::desc(""), cl::Required, + cl::sub(AnalyzeSubcommand)); +} // namespace analyze + +namespace merge { +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore, cl::sub(MergeSubcommand)); +cl::opt + PdbOutputFile("pdb", cl::desc("the name of the PDB file to write"), + cl::sub(MergeSubcommand)); +} // namespace merge +} // namespace opts + +static ExitOnError ExitOnErr; + +bool opts::checkModuleSubsection(opts::ModuleSubsection MS) { + return any_of(opts::shared::DumpModuleSubsections, + [=](opts::ModuleSubsection M) { + return M == MS || M == opts::ModuleSubsection::All; + }); +} + +static void yamlToPdb(StringRef Path) { + BumpPtrAllocator Allocator; + ErrorOr> ErrorOrBuffer = + MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + + if (ErrorOrBuffer.getError()) { + ExitOnErr(make_error(generic_error_code::invalid_path, Path)); + } + + std::unique_ptr &Buffer = ErrorOrBuffer.get(); + + llvm::yaml::Input In(Buffer->getBuffer()); + pdb::yaml::PdbObject YamlObj(Allocator); + In >> YamlObj; + + PDBFileBuilder Builder(Allocator); + + uint32_t BlockSize = 4096; + if (YamlObj.Headers.hasValue()) + BlockSize = YamlObj.Headers->SuperBlock.BlockSize; + ExitOnErr(Builder.initialize(BlockSize)); + // Add each of the reserved streams. We ignore stream metadata in the + // yaml, because we will reconstruct our own view of the streams. For + // example, the YAML may say that there were 20 streams in the original + // PDB, but maybe we only dump a subset of those 20 streams, so we will + // have fewer, and the ones we do have may end up with different indices + // than the ones in the original PDB. So we just start with a clean slate. + for (uint32_t I = 0; I < kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); + + if (YamlObj.StringTable.hasValue()) { + auto &Strings = Builder.getStringTableBuilder(); + for (auto S : *YamlObj.StringTable) + Strings.insert(S); + } + + pdb::yaml::PdbInfoStream DefaultInfoStream; + pdb::yaml::PdbDbiStream DefaultDbiStream; + pdb::yaml::PdbTpiStream DefaultTpiStream; + pdb::yaml::PdbTpiStream DefaultIpiStream; + + const auto &Info = YamlObj.PdbStream.getValueOr(DefaultInfoStream); + + auto &InfoBuilder = Builder.getInfoBuilder(); + InfoBuilder.setAge(Info.Age); + InfoBuilder.setGuid(Info.Guid); + InfoBuilder.setSignature(Info.Signature); + InfoBuilder.setVersion(Info.Version); + for (auto F : Info.Features) + InfoBuilder.addFeature(F); + + auto &Strings = Builder.getStringTableBuilder().getStrings(); + + const auto &Dbi = YamlObj.DbiStream.getValueOr(DefaultDbiStream); + auto &DbiBuilder = Builder.getDbiBuilder(); + DbiBuilder.setAge(Dbi.Age); + DbiBuilder.setBuildNumber(Dbi.BuildNumber); + DbiBuilder.setFlags(Dbi.Flags); + DbiBuilder.setMachineType(Dbi.MachineType); + DbiBuilder.setPdbDllRbld(Dbi.PdbDllRbld); + DbiBuilder.setPdbDllVersion(Dbi.PdbDllVersion); + DbiBuilder.setVersionHeader(Dbi.VerHeader); + for (const auto &MI : Dbi.ModInfos) { + auto &ModiBuilder = ExitOnErr(DbiBuilder.addModuleInfo(MI.Mod)); + ModiBuilder.setObjFileName(MI.Obj); + + for (auto S : MI.SourceFiles) + ExitOnErr(DbiBuilder.addModuleSourceFile(MI.Mod, S)); + if (MI.Modi.hasValue()) { + const auto &ModiStream = *MI.Modi; + for (auto Symbol : ModiStream.Symbols) { + ModiBuilder.addSymbol( + Symbol.toCodeViewSymbol(Allocator, CodeViewContainer::Pdb)); + } + } + + auto CodeViewSubsections = ExitOnErr(CodeViewYAML::toCodeViewSubsectionList( + Allocator, MI.Subsections, Strings)); + for (auto &SS : CodeViewSubsections) { + ModiBuilder.addDebugSubsection(std::move(SS)); + } + } + + auto &TpiBuilder = Builder.getTpiBuilder(); + const auto &Tpi = YamlObj.TpiStream.getValueOr(DefaultTpiStream); + TpiBuilder.setVersionHeader(Tpi.Version); + for (const auto &R : Tpi.Records) { + CVType Type = R.toCodeViewRecord(Allocator); + TpiBuilder.addTypeRecord(Type.RecordData, None); + } + + const auto &Ipi = YamlObj.IpiStream.getValueOr(DefaultIpiStream); + auto &IpiBuilder = Builder.getIpiBuilder(); + IpiBuilder.setVersionHeader(Ipi.Version); + for (const auto &R : Ipi.Records) { + CVType Type = R.toCodeViewRecord(Allocator); + IpiBuilder.addTypeRecord(Type.RecordData, None); + } + + ExitOnErr(Builder.commit(opts::yaml2pdb::YamlPdbOutputFile)); +} + +static PDBFile &loadPDB(StringRef Path, std::unique_ptr &Session) { + ExitOnErr(loadDataForPDB(PDB_ReaderType::Native, Path, Session)); + + NativeSession *NS = static_cast(Session.get()); + return NS->getPDBFile(); +} + +static void pdb2Yaml(StringRef Path) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + + auto O = llvm::make_unique(File); + O = llvm::make_unique(File); + + ExitOnErr(O->dump()); +} + +static void dumpRaw(StringRef Path) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + + auto O = llvm::make_unique(File); + + ExitOnErr(O->dump()); +} + +static void dumpAnalysis(StringRef Path) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + auto O = llvm::make_unique(File); + + ExitOnErr(O->dump()); +} + +static void diff(StringRef Path1, StringRef Path2) { + std::unique_ptr Session1; + std::unique_ptr Session2; + + auto &File1 = loadPDB(Path1, Session1); + auto &File2 = loadPDB(Path2, Session2); + + auto O = llvm::make_unique(File1, File2); + + ExitOnErr(O->dump()); +} + +bool opts::pretty::shouldDumpSymLevel(SymLevel Search) { + if (SymTypes.empty()) + return true; + if (llvm::find(SymTypes, Search) != SymTypes.end()) + return true; + if (llvm::find(SymTypes, SymLevel::All) != SymTypes.end()) + return true; + return false; +} + +uint32_t llvm::pdb::getTypeLength(const PDBSymbolData &Symbol) { + auto SymbolType = Symbol.getType(); + const IPDBRawSymbol &RawType = SymbolType->getRawSymbol(); + + return RawType.getLength(); +} + +bool opts::pretty::compareFunctionSymbols( + const std::unique_ptr &F1, + const std::unique_ptr &F2) { + assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); + + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) + return F1->getName() < F2->getName(); + + // Note that we intentionally sort in descending order on length, since + // long functions are more interesting than short functions. + return F1->getLength() > F2->getLength(); +} + +bool opts::pretty::compareDataSymbols( + const std::unique_ptr &F1, + const std::unique_ptr &F2) { + assert(opts::pretty::SymbolOrder != opts::pretty::SymbolSortMode::None); + + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::Name) + return F1->getName() < F2->getName(); + + // Note that we intentionally sort in descending order on length, since + // large types are more interesting than short ones. + return getTypeLength(*F1) > getTypeLength(*F2); +} + +static void dumpPretty(StringRef Path) { + std::unique_ptr Session; + + const auto ReaderType = + opts::pretty::Native ? PDB_ReaderType::Native : PDB_ReaderType::DIA; + ExitOnErr(loadDataForPDB(ReaderType, Path, Session)); + + if (opts::pretty::LoadAddress) + Session->setLoadAddress(opts::pretty::LoadAddress); + + auto &Stream = outs(); + const bool UseColor = opts::pretty::ColorOutput == cl::BOU_UNSET + ? Stream.has_colors() + : opts::pretty::ColorOutput == cl::BOU_TRUE; + LinePrinter Printer(2, UseColor, Stream); + + auto GlobalScope(Session->getGlobalScope()); + std::string FileName(GlobalScope->getSymbolsFileName()); + + WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; + WithColor(Printer, PDB_ColorItem::Path).get() << FileName; + Printer.Indent(); + uint64_t FileSize = 0; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; + if (!sys::fs::file_size(FileName, FileSize)) { + Printer << ": " << FileSize << " bytes"; + } else { + Printer << ": (Unable to obtain file size)"; + } + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; + Printer << ": " << GlobalScope->getGuid(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; + Printer << ": " << GlobalScope->getAge(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; + Printer << ": "; + if (GlobalScope->hasCTypes()) + outs() << "HasCTypes "; + if (GlobalScope->hasPrivateSymbols()) + outs() << "HasPrivateSymbols "; + Printer.Unindent(); + + if (opts::pretty::Compilands) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() + << "---COMPILANDS---"; + Printer.Indent(); + auto Compilands = GlobalScope->findAllChildren(); + CompilandDumper Dumper(Printer); + CompilandDumpFlags options = CompilandDumper::Flags::None; + if (opts::pretty::Lines) + options = options | CompilandDumper::Flags::Lines; + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, options); + Printer.Unindent(); + } + + if (opts::pretty::Classes || opts::pretty::Enums || opts::pretty::Typedefs) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; + Printer.Indent(); + TypeDumper Dumper(Printer); + Dumper.start(*GlobalScope); + Printer.Unindent(); + } + + if (opts::pretty::Symbols) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; + Printer.Indent(); + auto Compilands = GlobalScope->findAllChildren(); + CompilandDumper Dumper(Printer); + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, true); + Printer.Unindent(); + } + + if (opts::pretty::Globals) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; + Printer.Indent(); + if (shouldDumpSymLevel(opts::pretty::SymLevel::Functions)) { + FunctionDumper Dumper(Printer); + auto Functions = GlobalScope->findAllChildren(); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Function = Functions->getNext()) { + Printer.NewLine(); + Dumper.start(*Function, FunctionDumper::PointerType::None); + } + } else { + std::vector> Funcs; + while (auto Func = Functions->getNext()) + Funcs.push_back(std::move(Func)); + std::sort(Funcs.begin(), Funcs.end(), + opts::pretty::compareFunctionSymbols); + for (const auto &Func : Funcs) { + Printer.NewLine(); + Dumper.start(*Func, FunctionDumper::PointerType::None); + } + } + } + if (shouldDumpSymLevel(opts::pretty::SymLevel::Data)) { + auto Vars = GlobalScope->findAllChildren(); + VariableDumper Dumper(Printer); + if (opts::pretty::SymbolOrder == opts::pretty::SymbolSortMode::None) { + while (auto Var = Vars->getNext()) + Dumper.start(*Var); + } else { + std::vector> Datas; + while (auto Var = Vars->getNext()) + Datas.push_back(std::move(Var)); + std::sort(Datas.begin(), Datas.end(), opts::pretty::compareDataSymbols); + for (const auto &Var : Datas) + Dumper.start(*Var); + } + } + if (shouldDumpSymLevel(opts::pretty::SymLevel::Thunks)) { + auto Thunks = GlobalScope->findAllChildren(); + CompilandDumper Dumper(Printer); + while (auto Thunk = Thunks->getNext()) + Dumper.dump(*Thunk); + } + Printer.Unindent(); + } + if (opts::pretty::Externals) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---"; + Printer.Indent(); + ExternalSymbolDumper Dumper(Printer); + Dumper.start(*GlobalScope); + } + if (opts::pretty::Lines) { + Printer.NewLine(); + } + outs().flush(); +} + +static void mergePdbs() { + BumpPtrAllocator Allocator; + TypeTableBuilder MergedTpi(Allocator); + TypeTableBuilder MergedIpi(Allocator); + + // Create a Tpi and Ipi type table with all types from all input files. + for (const auto &Path : opts::merge::InputFilenames) { + std::unique_ptr Session; + auto &File = loadPDB(Path, Session); + SmallVector TypeMap; + SmallVector IdMap; + if (File.hasPDBTpiStream()) { + auto &Tpi = ExitOnErr(File.getPDBTpiStream()); + ExitOnErr(codeview::mergeTypeRecords(MergedTpi, TypeMap, nullptr, + Tpi.typeArray())); + } + if (File.hasPDBIpiStream()) { + auto &Ipi = ExitOnErr(File.getPDBIpiStream()); + ExitOnErr( + codeview::mergeIdRecords(MergedIpi, TypeMap, IdMap, Ipi.typeArray())); + } + } + + // Then write the PDB. + PDBFileBuilder Builder(Allocator); + ExitOnErr(Builder.initialize(4096)); + // Add each of the reserved streams. We might not put any data in them, + // but at least they have to be present. + for (uint32_t I = 0; I < kSpecialStreamCount; ++I) + ExitOnErr(Builder.getMsfBuilder().addStream(0)); + + auto &DestTpi = Builder.getTpiBuilder(); + auto &DestIpi = Builder.getIpiBuilder(); + MergedTpi.ForEachRecord([&DestTpi](TypeIndex TI, ArrayRef Data) { + DestTpi.addTypeRecord(Data, None); + }); + MergedIpi.ForEachRecord([&DestIpi](TypeIndex TI, ArrayRef Data) { + DestIpi.addTypeRecord(Data, None); + }); + + SmallString<64> OutFile(opts::merge::PdbOutputFile); + if (OutFile.empty()) { + OutFile = opts::merge::InputFilenames[0]; + llvm::sys::path::replace_extension(OutFile, "merged.pdb"); + } + ExitOnErr(Builder.commit(OutFile)); +} + +int main(int argc_, const char *argv_[]) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(argv_[0]); + PrettyStackTraceProgram X(argc_, argv_); + + ExitOnErr.setBanner("llvm-pdbutil: "); + + SmallVector argv; + SpecificBumpPtrAllocator ArgAllocator; + ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector( + argv, makeArrayRef(argv_, argc_), ArgAllocator))); + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); + if (!opts::raw::DumpBlockRangeOpt.empty()) { + llvm::Regex R("^([0-9]+)(-([0-9]+))?$"); + llvm::SmallVector Matches; + if (!R.match(opts::raw::DumpBlockRangeOpt, &Matches)) { + errs() << "Argument '" << opts::raw::DumpBlockRangeOpt + << "' invalid format.\n"; + errs().flush(); + exit(1); + } + opts::raw::DumpBlockRange.emplace(); + Matches[1].getAsInteger(10, opts::raw::DumpBlockRange->Min); + if (!Matches[3].empty()) { + opts::raw::DumpBlockRange->Max.emplace(); + Matches[3].getAsInteger(10, *opts::raw::DumpBlockRange->Max); + } + } + + if ((opts::RawSubcommand && opts::raw::RawAll) || + (opts::PdbToYamlSubcommand && opts::pdb2yaml::All)) { + opts::shared::DumpModules = true; + opts::shared::DumpModuleFiles = true; + opts::shared::DumpModuleSyms = true; + opts::shared::DumpModuleSubsections.push_back(opts::ModuleSubsection::All); + if (llvm::is_contained(opts::shared::DumpModuleSubsections, + opts::ModuleSubsection::All)) { + opts::shared::DumpModuleSubsections.reset(); + opts::shared::DumpModuleSubsections.push_back( + opts::ModuleSubsection::All); + } + } + + if (opts::shared::DumpModuleSyms || opts::shared::DumpModuleFiles) + opts::shared::DumpModules = true; + + if (opts::shared::DumpModules) + opts::pdb2yaml::DbiStream = true; + + if (opts::RawSubcommand) { + if (opts::raw::RawAll) { + opts::raw::DumpHeaders = true; + opts::raw::DumpGlobals = true; + opts::raw::DumpPublics = true; + opts::raw::DumpSectionHeaders = true; + opts::raw::DumpStreamSummary = true; + opts::raw::DumpPageStats = true; + opts::raw::DumpStreamBlocks = true; + opts::raw::DumpTpiRecords = true; + opts::raw::DumpTpiHash = true; + opts::raw::DumpIpiRecords = true; + opts::raw::DumpSectionMap = true; + opts::raw::DumpSectionContribs = true; + opts::raw::DumpFpo = true; + opts::raw::DumpStringTable = true; + } + + if (opts::raw::CompactRecords && + (opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) { + errs() << "-compact-records is incompatible with -tpi-record-bytes and " + "-ipi-record-bytes.\n"; + exit(1); + } + } + if (opts::PdbToYamlSubcommand) { + if (opts::pdb2yaml::All) { + opts::pdb2yaml::StreamMetadata = true; + opts::pdb2yaml::StreamDirectory = true; + opts::pdb2yaml::PdbStream = true; + opts::pdb2yaml::StringTable = true; + opts::pdb2yaml::DbiStream = true; + opts::pdb2yaml::TpiStream = true; + opts::pdb2yaml::IpiStream = true; + } + } + + llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded); + + if (opts::PdbToYamlSubcommand) { + pdb2Yaml(opts::pdb2yaml::InputFilename.front()); + } else if (opts::YamlToPdbSubcommand) { + if (opts::yaml2pdb::YamlPdbOutputFile.empty()) { + SmallString<16> OutputFilename(opts::yaml2pdb::InputFilename.getValue()); + sys::path::replace_extension(OutputFilename, ".pdb"); + opts::yaml2pdb::YamlPdbOutputFile = OutputFilename.str(); + } + yamlToPdb(opts::yaml2pdb::InputFilename); + } else if (opts::AnalyzeSubcommand) { + dumpAnalysis(opts::analyze::InputFilename.front()); + } else if (opts::PrettySubcommand) { + if (opts::pretty::Lines) + opts::pretty::Compilands = true; + + if (opts::pretty::All) { + opts::pretty::Compilands = true; + opts::pretty::Symbols = true; + opts::pretty::Globals = true; + opts::pretty::Types = true; + opts::pretty::Externals = true; + opts::pretty::Lines = true; + } + + if (opts::pretty::Types) { + opts::pretty::Classes = true; + opts::pretty::Typedefs = true; + opts::pretty::Enums = true; + } + + // When adding filters for excluded compilands and types, we need to + // remember that these are regexes. So special characters such as * and \ + // need to be escaped in the regex. In the case of a literal \, this + // means it needs to be escaped again in the C++. So matching a single \ in + // the input requires 4 \es in the C++. + if (opts::pretty::ExcludeCompilerGenerated) { + opts::pretty::ExcludeTypes.push_back("__vc_attributes"); + opts::pretty::ExcludeCompilands.push_back("\\* Linker \\*"); + } + if (opts::pretty::ExcludeSystemLibraries) { + opts::pretty::ExcludeCompilands.push_back( + "f:\\\\binaries\\\\Intermediate\\\\vctools\\\\crt_bld"); + opts::pretty::ExcludeCompilands.push_back("f:\\\\dd\\\\vctools\\\\crt"); + opts::pretty::ExcludeCompilands.push_back( + "d:\\\\th.obj.x86fre\\\\minkernel"); + } + std::for_each(opts::pretty::InputFilenames.begin(), + opts::pretty::InputFilenames.end(), dumpPretty); + } else if (opts::RawSubcommand) { + std::for_each(opts::raw::InputFilenames.begin(), + opts::raw::InputFilenames.end(), dumpRaw); + } else if (opts::DiffSubcommand) { + if (opts::diff::InputFilenames.size() != 2) { + errs() << "diff subcommand expects exactly 2 arguments.\n"; + exit(1); + } + diff(opts::diff::InputFilenames[0], opts::diff::InputFilenames[1]); + } else if (opts::MergeSubcommand) { + if (opts::merge::InputFilenames.size() < 2) { + errs() << "merge subcommand requires at least 2 input files.\n"; + exit(1); + } + mergePdbs(); + } + + outs().flush(); + return 0; +} Index: llvm/unittests/Support/BinaryStreamTest.cpp =================================================================== --- llvm/unittests/Support/BinaryStreamTest.cpp +++ llvm/unittests/Support/BinaryStreamTest.cpp @@ -416,9 +416,7 @@ struct StringExtractor { public: - typedef uint32_t &ContextType; - static Error extract(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item, - uint32_t &Index) { + Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { if (Index == 0) Len = strlen("1. Test"); else if (Index == 1) @@ -435,11 +433,12 @@ ++Index; return Error::success(); } + + uint32_t Index = 0; }; for (auto &Stream : Streams) { - uint32_t Context = 0; - VarStreamArray Array(*Stream.Input, Context); + VarStreamArray Array(*Stream.Input); auto Iter = Array.begin(); ASSERT_EQ("1. Test", *Iter++); ASSERT_EQ("2. Longer Test", *Iter++);