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 11*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/InfoStream.h" 12*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h" 13*0b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h" 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric namespace llvm { 16*0b57cec5SDimitry Andric namespace pdb { 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric namespace { 19*0b57cec5SDimitry Andric 20349cc55cSDimitry Andric Expected<std::string> readStreamData(BinaryStream &Stream, uint64_t Limit) { 21349cc55cSDimitry Andric uint64_t Offset = 0, DataLength = std::min(Limit, Stream.getLength()); 22*0b57cec5SDimitry Andric std::string Result; 23*0b57cec5SDimitry Andric Result.reserve(DataLength); 24*0b57cec5SDimitry Andric while (Offset < DataLength) { 25*0b57cec5SDimitry Andric ArrayRef<uint8_t> Data; 26*0b57cec5SDimitry Andric if (auto E = Stream.readLongestContiguousChunk(Offset, Data)) 27*0b57cec5SDimitry Andric return std::move(E); 28*0b57cec5SDimitry Andric Data = Data.take_front(DataLength - Offset); 29*0b57cec5SDimitry Andric Offset += Data.size(); 30*0b57cec5SDimitry Andric Result += toStringRef(Data); 31*0b57cec5SDimitry Andric } 32*0b57cec5SDimitry Andric return Result; 33*0b57cec5SDimitry Andric } 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric class NativeInjectedSource final : public IPDBInjectedSource { 36*0b57cec5SDimitry Andric const SrcHeaderBlockEntry &Entry; 37*0b57cec5SDimitry Andric const PDBStringTable &Strings; 38*0b57cec5SDimitry Andric PDBFile &File; 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric public: 41*0b57cec5SDimitry Andric NativeInjectedSource(const SrcHeaderBlockEntry &Entry, 42*0b57cec5SDimitry Andric PDBFile &File, const PDBStringTable &Strings) 43*0b57cec5SDimitry Andric : Entry(Entry), Strings(Strings), File(File) {} 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric uint32_t getCrc32() const override { return Entry.CRC; } 46*0b57cec5SDimitry Andric uint64_t getCodeByteSize() const override { return Entry.FileSize; } 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric std::string getFileName() const override { 498bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI), 508bcb0991SDimitry Andric "InjectedSourceStream should have rejected this"); 515ffd83dbSDimitry Andric return std::string(Ret); 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric std::string getObjectFileName() const override { 558bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI), 568bcb0991SDimitry Andric "InjectedSourceStream should have rejected this"); 575ffd83dbSDimitry Andric return std::string(Ret); 58*0b57cec5SDimitry Andric } 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric std::string getVirtualFileName() const override { 618bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI), 628bcb0991SDimitry Andric "InjectedSourceStream should have rejected this"); 635ffd83dbSDimitry Andric return std::string(Ret); 64*0b57cec5SDimitry Andric } 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric uint32_t getCompression() const override { return Entry.Compression; } 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric std::string getCode() const override { 69*0b57cec5SDimitry Andric // Get name of stream storing the data. 708bcb0991SDimitry Andric StringRef VName = 718bcb0991SDimitry Andric cantFail(Strings.getStringForID(Entry.VFileNI), 728bcb0991SDimitry Andric "InjectedSourceStream should have rejected this"); 738bcb0991SDimitry Andric std::string StreamName = ("/src/files/" + VName).str(); 74*0b57cec5SDimitry Andric 75*0b57cec5SDimitry Andric // Find stream with that name and read its data. 76*0b57cec5SDimitry Andric // FIXME: Consider validating (or even loading) all this in 77*0b57cec5SDimitry Andric // InjectedSourceStream so that no error can happen here. 78*0b57cec5SDimitry Andric auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); 79*0b57cec5SDimitry Andric if (!ExpectedFileStream) { 80*0b57cec5SDimitry Andric consumeError(ExpectedFileStream.takeError()); 81*0b57cec5SDimitry Andric return "(failed to open data stream)"; 82*0b57cec5SDimitry Andric } 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); 85*0b57cec5SDimitry Andric if (!Data) { 86*0b57cec5SDimitry Andric consumeError(Data.takeError()); 87*0b57cec5SDimitry Andric return "(failed to read data)"; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric return *Data; 90*0b57cec5SDimitry Andric } 91*0b57cec5SDimitry Andric }; 92*0b57cec5SDimitry Andric 93*0b57cec5SDimitry Andric } // namespace 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric NativeEnumInjectedSources::NativeEnumInjectedSources( 96*0b57cec5SDimitry Andric PDBFile &File, const InjectedSourceStream &IJS, 97*0b57cec5SDimitry Andric const PDBStringTable &Strings) 98*0b57cec5SDimitry Andric : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric uint32_t NativeEnumInjectedSources::getChildCount() const { 101*0b57cec5SDimitry Andric return static_cast<uint32_t>(Stream.size()); 102*0b57cec5SDimitry Andric } 103*0b57cec5SDimitry Andric 104*0b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource> 105*0b57cec5SDimitry Andric NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { 106*0b57cec5SDimitry Andric if (N >= getChildCount()) 107*0b57cec5SDimitry Andric return nullptr; 1088bcb0991SDimitry Andric return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, 109*0b57cec5SDimitry Andric File, Strings); 110*0b57cec5SDimitry Andric } 111*0b57cec5SDimitry Andric 112*0b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { 113*0b57cec5SDimitry Andric if (Cur == Stream.end()) 114*0b57cec5SDimitry Andric return nullptr; 1158bcb0991SDimitry Andric return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); 116*0b57cec5SDimitry Andric } 117*0b57cec5SDimitry Andric 118*0b57cec5SDimitry Andric void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric } 121*0b57cec5SDimitry Andric } 122