1 //==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h" 10 11 #include "llvm/ADT/StringExtras.h" 12 #include "llvm/DebugInfo/MSF/MappedBlockStream.h" 13 #include "llvm/DebugInfo/PDB/Native/HashTable.h" 14 #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 15 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 16 #include "llvm/DebugInfo/PDB/Native/RawTypes.h" 17 18 namespace llvm { 19 namespace pdb { 20 21 namespace { 22 23 Expected<std::string> readStreamData(BinaryStream &Stream, uint64_t Limit) { 24 uint64_t Offset = 0, DataLength = std::min(Limit, Stream.getLength()); 25 std::string Result; 26 Result.reserve(DataLength); 27 while (Offset < DataLength) { 28 ArrayRef<uint8_t> Data; 29 if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) 30 return std::move(E); 31 Data = Data.take_front(DataLength - Offset); 32 Offset += Data.size(); 33 Result += toStringRef(Data); 34 } 35 return Result; 36 } 37 38 class NativeInjectedSource final : public IPDBInjectedSource { 39 const SrcHeaderBlockEntry &Entry; 40 const PDBStringTable &Strings; 41 PDBFile &File; 42 43 public: 44 NativeInjectedSource(const SrcHeaderBlockEntry &Entry, 45 PDBFile &File, const PDBStringTable &Strings) 46 : Entry(Entry), Strings(Strings), File(File) {} 47 48 uint32_t getCrc32() const override { return Entry.CRC; } 49 uint64_t getCodeByteSize() const override { return Entry.FileSize; } 50 51 std::string getFileName() const override { 52 StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI), 53 "InjectedSourceStream should have rejected this"); 54 return std::string(Ret); 55 } 56 57 std::string getObjectFileName() const override { 58 StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI), 59 "InjectedSourceStream should have rejected this"); 60 return std::string(Ret); 61 } 62 63 std::string getVirtualFileName() const override { 64 StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI), 65 "InjectedSourceStream should have rejected this"); 66 return std::string(Ret); 67 } 68 69 uint32_t getCompression() const override { return Entry.Compression; } 70 71 std::string getCode() const override { 72 // Get name of stream storing the data. 73 StringRef VName = 74 cantFail(Strings.getStringForID(Entry.VFileNI), 75 "InjectedSourceStream should have rejected this"); 76 std::string StreamName = ("/src/files/" + VName).str(); 77 78 // Find stream with that name and read its data. 79 // FIXME: Consider validating (or even loading) all this in 80 // InjectedSourceStream so that no error can happen here. 81 auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); 82 if (!ExpectedFileStream) { 83 consumeError(ExpectedFileStream.takeError()); 84 return "(failed to open data stream)"; 85 } 86 87 auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); 88 if (!Data) { 89 consumeError(Data.takeError()); 90 return "(failed to read data)"; 91 } 92 return *Data; 93 } 94 }; 95 96 } // namespace 97 98 NativeEnumInjectedSources::NativeEnumInjectedSources( 99 PDBFile &File, const InjectedSourceStream &IJS, 100 const PDBStringTable &Strings) 101 : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} 102 103 uint32_t NativeEnumInjectedSources::getChildCount() const { 104 return static_cast<uint32_t>(Stream.size()); 105 } 106 107 std::unique_ptr<IPDBInjectedSource> 108 NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { 109 if (N >= getChildCount()) 110 return nullptr; 111 return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, 112 File, Strings); 113 } 114 115 std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { 116 if (Cur == Stream.end()) 117 return nullptr; 118 return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); 119 } 120 121 void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } 122 123 } 124 } 125