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