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 20*0b57cec5SDimitry Andric Expected<std::string> readStreamData(BinaryStream &Stream, uint32_t Limit) { 21*0b57cec5SDimitry Andric uint32_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 { 49*0b57cec5SDimitry Andric auto Name = Strings.getStringForID(Entry.FileNI); 50*0b57cec5SDimitry Andric assert(Name && "InjectedSourceStream should have rejected this"); 51*0b57cec5SDimitry Andric return *Name; 52*0b57cec5SDimitry Andric } 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric std::string getObjectFileName() const override { 55*0b57cec5SDimitry Andric auto ObjName = Strings.getStringForID(Entry.ObjNI); 56*0b57cec5SDimitry Andric assert(ObjName && "InjectedSourceStream should have rejected this"); 57*0b57cec5SDimitry Andric return *ObjName; 58*0b57cec5SDimitry Andric } 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric std::string getVirtualFileName() const override { 61*0b57cec5SDimitry Andric auto VName = Strings.getStringForID(Entry.VFileNI); 62*0b57cec5SDimitry Andric assert(VName && "InjectedSourceStream should have rejected this"); 63*0b57cec5SDimitry Andric return *VName; 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. 70*0b57cec5SDimitry Andric auto VName = Strings.getStringForID(Entry.VFileNI); 71*0b57cec5SDimitry Andric assert(VName && "InjectedSourceStream should have rejected this"); 72*0b57cec5SDimitry Andric std::string StreamName = ("/src/files/" + *VName).str(); 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric // Find stream with that name and read its data. 75*0b57cec5SDimitry Andric // FIXME: Consider validating (or even loading) all this in 76*0b57cec5SDimitry Andric // InjectedSourceStream so that no error can happen here. 77*0b57cec5SDimitry Andric auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName); 78*0b57cec5SDimitry Andric if (!ExpectedFileStream) { 79*0b57cec5SDimitry Andric consumeError(ExpectedFileStream.takeError()); 80*0b57cec5SDimitry Andric return "(failed to open data stream)"; 81*0b57cec5SDimitry Andric } 82*0b57cec5SDimitry Andric 83*0b57cec5SDimitry Andric auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize); 84*0b57cec5SDimitry Andric if (!Data) { 85*0b57cec5SDimitry Andric consumeError(Data.takeError()); 86*0b57cec5SDimitry Andric return "(failed to read data)"; 87*0b57cec5SDimitry Andric } 88*0b57cec5SDimitry Andric return *Data; 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric }; 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric } // namespace 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric NativeEnumInjectedSources::NativeEnumInjectedSources( 95*0b57cec5SDimitry Andric PDBFile &File, const InjectedSourceStream &IJS, 96*0b57cec5SDimitry Andric const PDBStringTable &Strings) 97*0b57cec5SDimitry Andric : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {} 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric uint32_t NativeEnumInjectedSources::getChildCount() const { 100*0b57cec5SDimitry Andric return static_cast<uint32_t>(Stream.size()); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource> 104*0b57cec5SDimitry Andric NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const { 105*0b57cec5SDimitry Andric if (N >= getChildCount()) 106*0b57cec5SDimitry Andric return nullptr; 107*0b57cec5SDimitry Andric return make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second, 108*0b57cec5SDimitry Andric File, Strings); 109*0b57cec5SDimitry Andric } 110*0b57cec5SDimitry Andric 111*0b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() { 112*0b57cec5SDimitry Andric if (Cur == Stream.end()) 113*0b57cec5SDimitry Andric return nullptr; 114*0b57cec5SDimitry Andric return make_unique<NativeInjectedSource>((Cur++)->second, File, Strings); 115*0b57cec5SDimitry Andric } 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); } 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric } 120*0b57cec5SDimitry Andric } 121