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 @@ -31,21 +31,23 @@ Error readSparseBitVector(BinaryStreamReader &Stream, SparseBitVector<> &V); Error writeSparseBitVector(BinaryStreamWriter &Writer, SparseBitVector<> &Vec); -template class HashTable; +template class StaticHashTable; -template +template class HashTableIterator - : public iterator_facade_base, + : public iterator_facade_base, std::forward_iterator_tag, - std::pair> { - friend HashTable; + const std::pair> { + friend StaticHashTable; +public: - HashTableIterator(const HashTable &Map, uint32_t Index, + // XXX drat: don't want to make this public, but can't name subclass to + // friend just it either + HashTableIterator(const StaticHashTable &Map, uint32_t Index, bool IsEnd) : Map(&Map), Index(Index), IsEnd(IsEnd) {} -public: - HashTableIterator(const HashTable &Map) : Map(&Map) { + HashTableIterator(const StaticHashTable &Map) : Map(&Map) { int I = Map.Present.find_first(); if (I == -1) { Index = 0; @@ -60,6 +62,7 @@ Map = R.Map; return *this; } + bool operator==(const HashTableIterator &R) const { if (IsEnd && R.IsEnd) return true; @@ -68,10 +71,17 @@ return (Map == R.Map) && (Index == R.Index); } + const std::pair &operator*() const { assert(Map->Present.test(Index)); return Map->Buckets[Index]; } + + // Implement postfix op++ in terms of prefix op++ by using superclass + // implementation. + using iterator_facade_base, + std::forward_iterator_tag, + const std::pair>::operator++; HashTableIterator &operator++() { while (Index < Map->Buckets.size()) { ++Index; @@ -83,28 +93,17 @@ return *this; } -private: +// private: // XXX more drat bool isEnd() const { return IsEnd; } uint32_t index() const { return Index; } - const HashTable *Map; + const StaticHashTable *Map; uint32_t Index; bool IsEnd; }; -template struct PdbHashTraits {}; - -template <> struct PdbHashTraits { - uint32_t hashLookupKey(uint32_t N) const { return N; } - uint32_t storageKeyToLookupKey(uint32_t N) const { return N; } - uint32_t lookupKeyToStorageKey(uint32_t N) { return N; } -}; - -template > -class HashTable { - using iterator = HashTableIterator; - friend iterator; - +template +class StaticHashTable { struct Header { support::ulittle32_t Size; support::ulittle32_t Capacity; @@ -113,10 +112,11 @@ using BucketList = std::vector>; public: - HashTable() { Buckets.resize(8); } + using const_iterator = HashTableIterator; + friend const_iterator; - explicit HashTable(TraitsT Traits) : HashTable(8, std::move(Traits)) {} - HashTable(uint32_t Capacity, TraitsT Traits) : Traits(Traits) { + StaticHashTable() : StaticHashTable(8) {} + explicit StaticHashTable(uint32_t Capacity) { Buckets.resize(Capacity); } @@ -216,19 +216,47 @@ uint32_t capacity() const { return Buckets.size(); } uint32_t size() const { return Present.count(); } - iterator begin() const { return iterator(*this); } - iterator end() const { return iterator(*this, 0, true); } + const_iterator begin() const { return const_iterator(*this); } + const_iterator end() const { return const_iterator(*this, 0, true); } + +protected: + bool isPresent(uint32_t K) const { return Present.test(K); } + bool isDeleted(uint32_t K) const { return Deleted.test(K); } + + BucketList Buckets; + mutable SparseBitVector<> Present; + mutable SparseBitVector<> Deleted; + + static uint32_t maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; } +}; + +template struct PdbHashTraits {}; + +template <> struct PdbHashTraits { + uint32_t hashLookupKey(uint32_t N) const { return N; } + uint32_t storageKeyToLookupKey(uint32_t N) const { return N; } + uint32_t lookupKeyToStorageKey(uint32_t N) { return N; } +}; + +template > +class HashTable : public StaticHashTable { + using const_iterator = typename StaticHashTable::const_iterator; +public: + HashTable() : StaticHashTable(8) {} + explicit HashTable(TraitsT Traits) : HashTable(8, std::move(Traits)) {} + HashTable(uint32_t Capacity, TraitsT Traits) + : StaticHashTable(Capacity), Traits(Traits) {} /// Find the entry whose key has the specified hash value, using the specified /// traits defining hash function and equality. - template iterator find_as(const Key &K) const { - uint32_t H = Traits.hashLookupKey(K) % capacity(); + template const_iterator find_as(const Key &K) const { + uint32_t H = Traits.hashLookupKey(K) % this->capacity(); uint32_t I = H; Optional FirstUnused; do { - if (isPresent(I)) { - if (Traits.storageKeyToLookupKey(Buckets[I].first) == K) - return iterator(*this, I, false); + if (this->isPresent(I)) { + if (Traits.storageKeyToLookupKey(this->Buckets[I].first) == K) + return const_iterator(*this, I, false); } else { if (!FirstUnused) FirstUnused = I; @@ -237,17 +265,17 @@ // probing and find a location that is neither present nor deleted, then // nothing must have EVER been inserted at this location, and thus it is // not possible for a matching value to occur later. - if (!isDeleted(I)) + if (!this->isDeleted(I)) break; } - I = (I + 1) % capacity(); + I = (I + 1) % this->capacity(); } while (I != H); // The only way FirstUnused would not be set is if every single entry in the // table were Present. But this would violate the load factor constraints // that we impose, so it should never happen. assert(FirstUnused); - return iterator(*this, *FirstUnused, true); + return const_iterator(*this, *FirstUnused, true); } /// Set the entry using a key type that the specified Traits can convert @@ -256,20 +284,8 @@ return set_as_internal(K, std::move(V), None); } - template ValueT get(const Key &K) const { - auto Iter = find_as(K); - assert(Iter != end()); - return (*Iter).second; - } - protected: - bool isPresent(uint32_t K) const { return Present.test(K); } - bool isDeleted(uint32_t K) const { return Deleted.test(K); } - TraitsT Traits; - BucketList Buckets; - mutable SparseBitVector<> Present; - mutable SparseBitVector<> Deleted; private: /// Set the entry using a key type that the specified Traits can convert @@ -277,53 +293,54 @@ template bool set_as_internal(const Key &K, ValueT V, Optional InternalKey) { auto Entry = find_as(K); - if (Entry != end()) { - assert(isPresent(Entry.index())); - assert(Traits.storageKeyToLookupKey(Buckets[Entry.index()].first) == K); + if (Entry != this->end()) { + assert(this->isPresent(Entry.index())); + assert(Traits.storageKeyToLookupKey(this->Buckets[Entry.index()].first) == + K); // We're updating, no need to do anything special. - Buckets[Entry.index()].second = V; + this->Buckets[Entry.index()].second = V; return false; } - auto &B = Buckets[Entry.index()]; - assert(!isPresent(Entry.index())); + auto &B = this->Buckets[Entry.index()]; + assert(!this->isPresent(Entry.index())); assert(Entry.isEnd()); B.first = InternalKey ? *InternalKey : Traits.lookupKeyToStorageKey(K); B.second = V; - Present.set(Entry.index()); - Deleted.reset(Entry.index()); + this->Present.set(Entry.index()); + this->Deleted.reset(Entry.index()); grow(); - assert((find_as(K)) != end()); + assert((find_as(K)) != this->end()); return true; } - static uint32_t maxLoad(uint32_t capacity) { return capacity * 2 / 3 + 1; } - void grow() { - uint32_t S = size(); - uint32_t MaxLoad = maxLoad(capacity()); - if (S < maxLoad(capacity())) + uint32_t S = this->size(); + uint32_t MaxLoad = this->maxLoad(this->capacity()); + if (S < MaxLoad) return; - assert(capacity() != UINT32_MAX && "Can't grow Hash table!"); + assert(this->capacity() != UINT32_MAX && "Can't grow Hash table!"); - uint32_t NewCapacity = (capacity() <= INT32_MAX) ? MaxLoad * 2 : UINT32_MAX; + uint32_t NewCapacity = + (this->capacity() <= INT32_MAX) ? MaxLoad * 2 : UINT32_MAX; // Growing requires rebuilding the table and re-hashing every item. Make a // copy with a larger capacity, insert everything into the copy, then swap // it in. HashTable NewMap(NewCapacity, Traits); - for (auto I : Present) { - auto LookupKey = Traits.storageKeyToLookupKey(Buckets[I].first); - NewMap.set_as_internal(LookupKey, Buckets[I].second, Buckets[I].first); + for (auto I : this->Present) { + auto LookupKey = Traits.storageKeyToLookupKey(this->Buckets[I].first); + NewMap.set_as_internal(LookupKey, this->Buckets[I].second, + this->Buckets[I].first); } - Buckets.swap(NewMap.Buckets); - std::swap(Present, NewMap.Present); - std::swap(Deleted, NewMap.Deleted); - assert(capacity() == NewCapacity); - assert(size() == S); + this->Buckets.swap(NewMap.Buckets); + std::swap(this->Present, NewMap.Present); + std::swap(this->Deleted, NewMap.Deleted); + assert(this->capacity() == NewCapacity); + assert(this->size() == S); } }; 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 InjectedSourceStream { +public: + InjectedSourceStream(std::unique_ptr Stream); + ~InjectedSourceStream(); + Error reload(); + + using const_iterator = StaticHashTable::const_iterator; + const_iterator begin() { return InjectedSourceTable.begin(); } + const_iterator end() { return InjectedSourceTable.end(); } + + uint32_t size() const { return InjectedSourceTable.size(); } + +private: + Error readHeader(BinaryStreamReader &Reader); + + std::unique_ptr Stream; + + const SrcHeaderBlockHeader* Header; + StaticHashTable InjectedSourceTable; +}; +} +} + +#endif Index: llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h =================================================================== --- /dev/null +++ llvm/include/llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h @@ -0,0 +1,41 @@ +//==- 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(InjectedSourceStream &IJS, 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: + InjectedSourceStream &Stream; + 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,6 +112,7 @@ bool hasPDBSymbolStream(); bool hasPDBTpiStream() const; bool hasPDBStringTable(); + bool hasPDBInjectedSourceStream(); uint32_t getPointerSize(); @@ -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/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)) {} + +InjectedSourceStream::~InjectedSourceStream() {} + +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,96 @@ +//==- 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/PDBStringTable.h" + +namespace llvm { +namespace pdb { + +namespace { + +class NativeInjectedSource : public IPDBInjectedSource { + InjectedSourceStream::const_iterator I; + PDBStringTable &Strings; + +public: + NativeInjectedSource(InjectedSourceStream::const_iterator I, + PDBStringTable &Strings) + : I(I), Strings(Strings) {} + + 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 Name = Strings.getStringForID(I->second.ObjNI); + if (!Name) { + consumeError(Name.takeError()); + return "(invalid object file name ref)"; + } + return *Name; + } + + std::string getVirtualFileName() const override { + auto Name = Strings.getStringForID(I->second.VFileNI); + if (!Name) { + consumeError(Name.takeError()); + return "(invalid virtual file name ref)"; + } + return *Name; + } + + PDB_SourceCompression getCompression() const override { + return static_cast(I->second.Compression); + } + + std::string getCode() const override { + // This will have to call a future method in InjectedSourceStream that + // appends getVirtualFileName() to "/src/files" and return the data of that + // named stream. + assert(false && "not yet implemented"); + return ""; + } +}; + +} // namespace + +NativeEnumInjectedSources::NativeEnumInjectedSources(InjectedSourceStream &IJS, + PDBStringTable &Strings) + : 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()), Strings); +} + +std::unique_ptr NativeEnumInjectedSources::getNext() { + if (Cur == Stream.end()) + return nullptr; + return make_unique(Cur++, 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(*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" @@ -390,6 +391,31 @@ return *Strings; } +Expected PDBFile::getInjectedSourceStream() { + if (!InjectedSources) { + auto IS = getPDBInfoStream(); + if (!IS) + return IS.takeError(); + + Expected ExpectedNSI = + IS->getNamedStreamIndex("/src/headerblock"); + if (!ExpectedNSI) + return ExpectedNSI.takeError(); + uint32_t InjectedSourceStreamIndex = *ExpectedNSI; + + auto IJS = safelyCreateIndexedStream(ContainerLayout, *Buffer, + InjectedSourceStreamIndex); + 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,6 +484,19 @@ 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 Index: llvm/test/tools/llvm-pdbutil/injected-sources-native.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-pdbutil/injected-sources-native.test @@ -0,0 +1,17 @@ +; 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). +; FIXME: Add -injected-source-content like in injected-sources.test once +; that's implemented in the native code. + +; RUN: llvm-pdbutil pretty -native -injected-sources \ +; RUN: %p/Inputs/InjectedSource.pdb | FileCheck %s +; RUN: llvm-pdbutil pretty -native -injected-sources \ +; 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: a.natvis (140 bytes): obj=, vname=a.natvis, crc=334478030, compression=None +; CHECK: b.natvis (294 bytes): obj=, vname=b.natvis, crc=2059731902, compression=None + +; 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; } @@ -1280,9 +1280,9 @@ << "---INJECTED SOURCES---"; AutoIndent Indent1(Printer); - if (ReaderType == PDB_ReaderType::Native) + if (opts::pretty::ShowInjectedSourceContent) Printer.printLine( - "Injected sources are not supported with the native reader."); + "Printing injected source content not supported with native reader."); else dumpInjectedSources(Printer, *Session); } 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",