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 {
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