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