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