Index: llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h +++ llvm/include/llvm/DebugInfo/PDB/Native/HashTable.h @@ -72,6 +72,12 @@ assert(Map->Present.test(Index)); return Map->Buckets[Index]; } + + // Implement postfix op++ in terms of prefix op++ by using the superclass + // implementation. + using iterator_facade_base, + std::forward_iterator_tag, + const std::pair>::operator++; HashTableIterator &operator++() { while (Index < Map->Buckets.size()) { ++Index; @@ -94,9 +100,6 @@ template class HashTable { - using const_iterator = HashTableIterator; - friend const_iterator; - struct Header { support::ulittle32_t Size; support::ulittle32_t Capacity; @@ -105,6 +108,9 @@ using BucketList = std::vector>; public: + using const_iterator = HashTableIterator; + friend const_iterator; + HashTable() { Buckets.resize(8); } explicit HashTable(uint32_t Capacity) { Buckets.resize(Capacity); Index: llvm/include/llvm/DebugInfo/PDB/Native/InjectedSourceStream.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/PDB/Native/InjectedSourceStream.h @@ -0,0 +1,46 @@ +//===- InjectedSourceStream.h - PDB Headerblock Stream Access ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_RAW_PDBINJECTEDSOURCESTREAM_H +#define LLVM_DEBUGINFO_PDB_RAW_PDBINJECTEDSOURCESTREAM_H + +#include "llvm/DebugInfo/PDB/Native/HashTable.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace msf { +class MappedBlockStream; +} +namespace pdb { +class PDBFile; +class PDBStringTable; + +class InjectedSourceStream { +public: + InjectedSourceStream(std::unique_ptr Stream); + Error reload(); + + using const_iterator = HashTable::const_iterator; + const_iterator begin() const { return InjectedSourceTable.begin(); } + const_iterator end() const { return InjectedSourceTable.end(); } + + uint32_t size() const { return InjectedSourceTable.size(); } + +private: + Error readHeader(BinaryStreamReader &Reader); + + std::unique_ptr Stream; + + const SrcHeaderBlockHeader* Header; + HashTable InjectedSourceTable; +}; +} +} + +#endif Index: llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h @@ -0,0 +1,43 @@ +//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMINJECTEDSOURCES_H +#define LLVM_DEBUGINFO_PDB_NATIVE_NATIVEENUMINJECTEDSOURCES_H + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h" +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" + +namespace llvm { +namespace pdb { + +class InjectedSourceStream; +class PDBStringTable; + +class NativeEnumInjectedSources : public IPDBEnumChildren { +public: + NativeEnumInjectedSources(PDBFile &File, const InjectedSourceStream &IJS, + const PDBStringTable &Strings); + + uint32_t getChildCount() const override; + std::unique_ptr + getChildAtIndex(uint32_t Index) const override; + std::unique_ptr getNext() override; + void reset() override; + +private: + PDBFile &File; + const InjectedSourceStream &Stream; + const PDBStringTable &Strings; + InjectedSourceStream::const_iterator Cur; +}; + +} // namespace pdb +} // namespace llvm + +#endif Index: llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h =================================================================== --- llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h +++ llvm/include/llvm/DebugInfo/PDB/Native/PDBFile.h @@ -32,6 +32,7 @@ class DbiStream; class GlobalsStream; class InfoStream; +class InjectedSourceStream; class PDBStringTable; class PDBFileBuilder; class PublicsStream; @@ -99,6 +100,7 @@ Expected getPDBPublicsStream(); Expected getPDBSymbolStream(); Expected getStringTable(); + Expected getInjectedSourceStream(); BumpPtrAllocator &getAllocator() { return Allocator; } @@ -110,15 +112,16 @@ bool hasPDBSymbolStream(); bool hasPDBTpiStream() const; bool hasPDBStringTable(); + bool hasPDBInjectedSourceStream(); uint32_t getPointerSize(); -private: Expected> - safelyCreateIndexedStream(const msf::MSFLayout &Layout, - BinaryStreamRef MsfData, - uint32_t StreamIndex) const; + safelyCreateIndexedStream(uint32_t StreamIndex) const; + Expected> + safelyCreateNamedStream(StringRef Name); +private: std::string FilePath; BumpPtrAllocator &Allocator; @@ -135,6 +138,7 @@ std::unique_ptr Symbols; std::unique_ptr DirectoryStream; std::unique_ptr StringTableStream; + std::unique_ptr InjectedSources; std::unique_ptr Strings; }; } Index: llvm/lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -47,9 +47,11 @@ Native/HashTable.cpp Native/InfoStream.cpp Native/InfoStreamBuilder.cpp + Native/InjectedSourceStream.cpp Native/ModuleDebugStream.cpp Native/NativeCompilandSymbol.cpp Native/NativeEnumGlobals.cpp + Native/NativeEnumInjectedSources.cpp Native/NativeEnumModules.cpp Native/NativeEnumTypes.cpp Native/NativeExeSymbol.cpp Index: llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp @@ -0,0 +1,59 @@ +//===- InjectedSourceStream.cpp - PDB Headerblock Stream Access -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" + +#include "llvm/DebugInfo/MSF/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Native/Hash.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" +#include "llvm/DebugInfo/PDB/Native/RawConstants.h" +#include "llvm/DebugInfo/PDB/Native/RawTypes.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; +using namespace llvm::pdb; + +InjectedSourceStream::InjectedSourceStream( + std::unique_ptr Stream) + : Stream(std::move(Stream)) {} + +Error InjectedSourceStream::readHeader(BinaryStreamReader &Reader) { + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} + +Error InjectedSourceStream::reload() { + BinaryStreamReader Reader(*Stream); + + if (auto EC = Reader.readObject(Header)) + return EC; + + if (Header->Version != + static_cast(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error(raw_error_code::corrupt_file, + "Invalid headerblock header version"); + + if (auto EC = InjectedSourceTable.load(Reader)) + return EC; + + for (const auto& Entry : *this) { + if (Entry.second.Size != sizeof(SrcHeaderBlockEntry)) + return make_error(raw_error_code::corrupt_file, + "Invalid headerbock entry size"); + if (Entry.second.Version != + static_cast(PdbRaw_SrcHeaderBlockVer::SrcVerOne)) + return make_error(raw_error_code::corrupt_file, + "Invalid headerbock entry version"); + } + + assert(Reader.bytesRemaining() == 0); + return Error::success(); +} Index: llvm/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp =================================================================== --- /dev/null +++ llvm/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp @@ -0,0 +1,131 @@ +//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" + +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" + +namespace llvm { +namespace pdb { + +namespace { + +Expected readStreamData(BinaryStream &Stream) { + uint32_t Offset = 0, DataLength = Stream.getLength(); + std::string Result; + Result.reserve(DataLength); + while (Offset < DataLength) { + ArrayRef Data; + if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) + return std::move(E); + Offset += Data.size(); + Result += toStringRef(Data); + } + return Result; +} + +class NativeInjectedSource : public IPDBInjectedSource { + InjectedSourceStream::const_iterator I; + const PDBStringTable &Strings; + PDBFile &File; + +public: + NativeInjectedSource(InjectedSourceStream::const_iterator I, + PDBFile &File, const PDBStringTable &Strings) + : I(I), Strings(Strings), File(File) {} + + uint32_t getCrc32() const override { return I->second.CRC; } + uint64_t getCodeByteSize() const override { return I->second.FileSize; } + + std::string getFileName() const override { + auto Name = Strings.getStringForID(I->second.FileNI); + if (!Name) { + consumeError(Name.takeError()); + return "(invalid file name ref)"; + } + return *Name; + } + + std::string getObjectFileName() const override { + auto ObjName = Strings.getStringForID(I->second.ObjNI); + if (!ObjName) { + consumeError(ObjName.takeError()); + return "(invalid object file name ref)"; + } + return *ObjName; + } + + std::string getVirtualFileName() const override { + auto VName = Strings.getStringForID(I->second.VFileNI); + if (!VName) { + consumeError(VName.takeError()); + return "(invalid virtual file name ref)"; + } + return *VName; + } + + PDB_SourceCompression getCompression() const override { + return static_cast(I->second.Compression); + } + + std::string getCode() const override { + // Get name of stream storing the data. + auto VName = Strings.getStringForID(I->second.VFileNI); + if (!VName) { + consumeError(VName.takeError()); + return "(failed: invalid virtual file name ref)"; + } + std::string StreamName = ("/src/files/" + *VName).str(); + + // Find stream with that name and read its data. + auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); + if (!ExpectedFileStream) { + consumeError(ExpectedFileStream.takeError()); + return "(failed to open data stream)"; + } + + auto Data = readStreamData(**ExpectedFileStream); + if (!Data) { + consumeError(Data.takeError()); + return "(failed to read data)"; + } + return *Data; + } +}; + +} // namespace + +NativeEnumInjectedSources::NativeEnumInjectedSources( + PDBFile &File, const InjectedSourceStream &IJS, + const PDBStringTable &Strings) + : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} + +uint32_t NativeEnumInjectedSources::getChildCount() const { + return static_cast(Stream.size()); +} + +std::unique_ptr +NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { + if (N >= getChildCount()) + return nullptr; + return make_unique(std::next(Stream.begin(), N), File, + Strings); +} + +std::unique_ptr NativeEnumInjectedSources::getNext() { + if (Cur == Stream.end()) + return nullptr; + return make_unique(Cur++, File, Strings); +} + +void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } + +} +} Index: llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp +++ llvm/lib/DebugInfo/PDB/Native/NativeSession.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h" +#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" #include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h" #include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h" #include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h" @@ -191,7 +192,17 @@ std::unique_ptr NativeSession::getInjectedSources() const { - return nullptr; + auto ISS = Pdb->getInjectedSourceStream(); + if (!ISS) { + consumeError(ISS.takeError()); + return nullptr; + } + auto ST = Pdb->getStringTable(); + if (!ST) { + consumeError(ST.takeError()); + return nullptr; + } + return make_unique(*Pdb, *ISS, *ST); } std::unique_ptr Index: llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp =================================================================== --- llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp +++ llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp @@ -14,6 +14,7 @@ #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" #include "llvm/DebugInfo/PDB/Native/PublicsStream.h" #include "llvm/DebugInfo/PDB/Native/RawError.h" @@ -258,8 +259,8 @@ if (!DbiS) return DbiS.takeError(); - auto GlobalS = safelyCreateIndexedStream( - ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex()); + auto GlobalS = + safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex()); if (!GlobalS) return GlobalS.takeError(); auto TempGlobals = llvm::make_unique(std::move(*GlobalS)); @@ -272,7 +273,7 @@ Expected PDBFile::getPDBInfoStream() { if (!Info) { - auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB); + auto InfoS = safelyCreateIndexedStream(StreamPDB); if (!InfoS) return InfoS.takeError(); auto TempInfo = llvm::make_unique(std::move(*InfoS)); @@ -285,7 +286,7 @@ Expected PDBFile::getPDBDbiStream() { if (!Dbi) { - auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI); + auto DbiS = safelyCreateIndexedStream(StreamDBI); if (!DbiS) return DbiS.takeError(); auto TempDbi = llvm::make_unique(std::move(*DbiS)); @@ -298,7 +299,7 @@ Expected PDBFile::getPDBTpiStream() { if (!Tpi) { - auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI); + auto TpiS = safelyCreateIndexedStream(StreamTPI); if (!TpiS) return TpiS.takeError(); auto TempTpi = llvm::make_unique(*this, std::move(*TpiS)); @@ -314,7 +315,7 @@ if (!hasPDBIpiStream()) return make_error(raw_error_code::no_stream); - auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI); + auto IpiS = safelyCreateIndexedStream(StreamIPI); if (!IpiS) return IpiS.takeError(); auto TempIpi = llvm::make_unique(*this, std::move(*IpiS)); @@ -331,8 +332,8 @@ if (!DbiS) return DbiS.takeError(); - auto PublicS = safelyCreateIndexedStream( - ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex()); + auto PublicS = + safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex()); if (!PublicS) return PublicS.takeError(); auto TempPublics = llvm::make_unique(std::move(*PublicS)); @@ -350,8 +351,7 @@ return DbiS.takeError(); uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); - auto SymbolS = - safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum); + auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum); if (!SymbolS) return SymbolS.takeError(); @@ -365,17 +365,7 @@ Expected PDBFile::getStringTable() { if (!Strings) { - auto IS = getPDBInfoStream(); - if (!IS) - return IS.takeError(); - - Expected ExpectedNSI = IS->getNamedStreamIndex("/names"); - if (!ExpectedNSI) - return ExpectedNSI.takeError(); - uint32_t NameStreamIndex = *ExpectedNSI; - - auto NS = - safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex); + auto NS = safelyCreateNamedStream("/names"); if (!NS) return NS.takeError(); @@ -390,6 +380,20 @@ return *Strings; } +Expected PDBFile::getInjectedSourceStream() { + if (!InjectedSources) { + auto IJS = safelyCreateNamedStream("/src/headerblock"); + if (!IJS) + return IJS.takeError(); + + auto IJ = llvm::make_unique(std::move(*IJS)); + if (auto EC = IJ->reload()) + return std::move(EC); + InjectedSources = std::move(IJ); + } + return *InjectedSources; +} + uint32_t PDBFile::getPointerSize() { auto DbiS = getPDBDbiStream(); if (!DbiS) @@ -458,16 +462,41 @@ return true; } +bool PDBFile::hasPDBInjectedSourceStream() { + auto IS = getPDBInfoStream(); + if (!IS) + return false; + Expected ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock"); + if (!ExpectedNSI) { + consumeError(ExpectedNSI.takeError()); + return false; + } + assert(*ExpectedNSI < getNumStreams()); + return true; +} + /// Wrapper around MappedBlockStream::createIndexedStream() that checks if a /// stream with that index actually exists. If it does not, the return value /// will have an MSFError with code msf_error_code::no_stream. Else, the return /// value will contain the stream returned by createIndexedStream(). Expected> -PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout, - BinaryStreamRef MsfData, - uint32_t StreamIndex) const { +PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const { if (StreamIndex >= getNumStreams()) return make_error(raw_error_code::no_stream); - return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex, - Allocator); + return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, + StreamIndex, Allocator); +} + +Expected> +PDBFile::safelyCreateNamedStream(StringRef Name) { + auto IS = getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + Expected ExpectedNSI = IS->getNamedStreamIndex(Name); + if (!ExpectedNSI) + return ExpectedNSI.takeError(); + uint32_t NameStreamIndex = *ExpectedNSI; + + return safelyCreateIndexedStream(NameStreamIndex); } Index: llvm/test/tools/llvm-pdbutil/injected-sources-native.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-pdbutil/injected-sources-native.test @@ -0,0 +1,30 @@ +; This is identical to injected-sources.test, except that it uses the -native +; mode of pretty (and hence doesn't require diasdk and runs on all platforms). + +; RUN: llvm-pdbutil pretty -native -injected-sources -injected-source-content \ +; RUN: %p/Inputs/InjectedSource.pdb | FileCheck %s +; RUN: llvm-pdbutil pretty -native -injected-sources -injected-source-content \ +; RUN: %p/Inputs/ClassLayoutTest.pdb | FileCheck --check-prefix=NEGATIVE %s + +; CHECK: ---INJECTED SOURCES--- +; CHECK: c.natvis (140 bytes): obj=, vname=c.natvis, crc=334478030, compression=None +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK: a.natvis (140 bytes): obj=, vname=a.natvis, crc=334478030, compression=None +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK: b.natvis (294 bytes): obj=, vname=b.natvis, crc=2059731902, compression=None +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK-NEXT: Third test +; CHECK-NEXT: +; CHECK-NEXT: +; CHECK-NEXT: Fourth test +; CHECK-NEXT: +; CHECK-NEXT: + +; NEGATIVE: ---INJECTED SOURCES--- +; NEGATIVE-NEXT: There are no injected sources. Index: llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp =================================================================== --- llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp +++ llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp @@ -934,7 +934,7 @@ static void dumpInjectedSources(LinePrinter &Printer, IPDBSession &Session) { auto Sources = Session.getInjectedSources(); - if (0 == Sources->getChildCount()) { + if (!Sources || !Sources->getChildCount()) { Printer.printLine("There are no injected sources."); return; } @@ -1279,12 +1279,7 @@ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---INJECTED SOURCES---"; AutoIndent Indent1(Printer); - - if (ReaderType == PDB_ReaderType::Native) - Printer.printLine( - "Injected sources are not supported with the native reader."); - else - dumpInjectedSources(Printer, *Session); + dumpInjectedSources(Printer, *Session); } Printer.NewLine(); Index: llvm/utils/gn/secondary/llvm/lib/DebugInfo/PDB/BUILD.gn =================================================================== --- llvm/utils/gn/secondary/llvm/lib/DebugInfo/PDB/BUILD.gn +++ llvm/utils/gn/secondary/llvm/lib/DebugInfo/PDB/BUILD.gn @@ -24,10 +24,12 @@ "Native/HashTable.cpp", "Native/InfoStream.cpp", "Native/InfoStreamBuilder.cpp", + "Native/InjectedSourceStream.cpp", "Native/ModuleDebugStream.cpp", "Native/NamedStreamMap.cpp", "Native/NativeCompilandSymbol.cpp", "Native/NativeEnumGlobals.cpp", + "Native/NativeEnumInjectedSources.cpp", "Native/NativeEnumModules.cpp", "Native/NativeEnumTypes.cpp", "Native/NativeExeSymbol.cpp",