1*d100b5ddSNico Weber //==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==//
2*d100b5ddSNico Weber //
3*d100b5ddSNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*d100b5ddSNico Weber // See https://llvm.org/LICENSE.txt for license information.
5*d100b5ddSNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*d100b5ddSNico Weber //
7*d100b5ddSNico Weber //===----------------------------------------------------------------------===//
8*d100b5ddSNico Weber 
9*d100b5ddSNico Weber #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
10*d100b5ddSNico Weber 
11*d100b5ddSNico Weber #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
12*d100b5ddSNico Weber #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
13*d100b5ddSNico Weber #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
14*d100b5ddSNico Weber 
15*d100b5ddSNico Weber namespace llvm {
16*d100b5ddSNico Weber namespace pdb {
17*d100b5ddSNico Weber 
18*d100b5ddSNico Weber namespace {
19*d100b5ddSNico Weber 
20*d100b5ddSNico Weber Expected<std::string> readStreamData(BinaryStream &Stream) {
21*d100b5ddSNico Weber   uint32_t Offset = 0, DataLength = Stream.getLength();
22*d100b5ddSNico Weber   std::string Result;
23*d100b5ddSNico Weber   Result.reserve(DataLength);
24*d100b5ddSNico Weber   while (Offset < DataLength) {
25*d100b5ddSNico Weber     ArrayRef<uint8_t> Data;
26*d100b5ddSNico Weber     if (auto E = Stream.readLongestContiguousChunk(Offset, Data))
27*d100b5ddSNico Weber       return std::move(E);
28*d100b5ddSNico Weber     Offset += Data.size();
29*d100b5ddSNico Weber     Result += toStringRef(Data);
30*d100b5ddSNico Weber   }
31*d100b5ddSNico Weber   return Result;
32*d100b5ddSNico Weber }
33*d100b5ddSNico Weber 
34*d100b5ddSNico Weber class NativeInjectedSource final : public IPDBInjectedSource {
35*d100b5ddSNico Weber   const SrcHeaderBlockEntry &Entry;
36*d100b5ddSNico Weber   const PDBStringTable &Strings;
37*d100b5ddSNico Weber   PDBFile &File;
38*d100b5ddSNico Weber 
39*d100b5ddSNico Weber public:
40*d100b5ddSNico Weber   NativeInjectedSource(const SrcHeaderBlockEntry &Entry,
41*d100b5ddSNico Weber                        PDBFile &File, const PDBStringTable &Strings)
42*d100b5ddSNico Weber       : Entry(Entry), Strings(Strings), File(File) {}
43*d100b5ddSNico Weber 
44*d100b5ddSNico Weber   uint32_t getCrc32() const override { return Entry.CRC; }
45*d100b5ddSNico Weber   uint64_t getCodeByteSize() const override { return Entry.FileSize; }
46*d100b5ddSNico Weber 
47*d100b5ddSNico Weber   std::string getFileName() const override {
48*d100b5ddSNico Weber     auto Name = Strings.getStringForID(Entry.FileNI);
49*d100b5ddSNico Weber     assert(Name && "InjectedSourceStream should have rejected this");
50*d100b5ddSNico Weber     return *Name;
51*d100b5ddSNico Weber   }
52*d100b5ddSNico Weber 
53*d100b5ddSNico Weber   std::string getObjectFileName() const override {
54*d100b5ddSNico Weber     auto ObjName = Strings.getStringForID(Entry.ObjNI);
55*d100b5ddSNico Weber     assert(ObjName && "InjectedSourceStream should have rejected this");
56*d100b5ddSNico Weber     return *ObjName;
57*d100b5ddSNico Weber   }
58*d100b5ddSNico Weber 
59*d100b5ddSNico Weber   std::string getVirtualFileName() const override {
60*d100b5ddSNico Weber     auto VName = Strings.getStringForID(Entry.VFileNI);
61*d100b5ddSNico Weber     assert(VName && "InjectedSourceStream should have rejected this");
62*d100b5ddSNico Weber     return *VName;
63*d100b5ddSNico Weber   }
64*d100b5ddSNico Weber 
65*d100b5ddSNico Weber   PDB_SourceCompression getCompression() const override {
66*d100b5ddSNico Weber     return static_cast<PDB_SourceCompression>(Entry.Compression);
67*d100b5ddSNico Weber   }
68*d100b5ddSNico Weber 
69*d100b5ddSNico Weber   std::string getCode() const override {
70*d100b5ddSNico Weber     // Get name of stream storing the data.
71*d100b5ddSNico Weber     auto VName = Strings.getStringForID(Entry.VFileNI);
72*d100b5ddSNico Weber     assert(VName && "InjectedSourceStream should have rejected this");
73*d100b5ddSNico Weber     std::string StreamName = ("/src/files/" + *VName).str();
74*d100b5ddSNico Weber 
75*d100b5ddSNico Weber     // Find stream with that name and read its data.
76*d100b5ddSNico Weber     // FIXME: Consider validating (or even loading) all this in
77*d100b5ddSNico Weber     // InjectedSourceStream so that no error can happen here.
78*d100b5ddSNico Weber     auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName);
79*d100b5ddSNico Weber     if (!ExpectedFileStream) {
80*d100b5ddSNico Weber       consumeError(ExpectedFileStream.takeError());
81*d100b5ddSNico Weber       return "(failed to open data stream)";
82*d100b5ddSNico Weber     }
83*d100b5ddSNico Weber 
84*d100b5ddSNico Weber     auto Data = readStreamData(**ExpectedFileStream);
85*d100b5ddSNico Weber     if (!Data) {
86*d100b5ddSNico Weber       consumeError(Data.takeError());
87*d100b5ddSNico Weber       return "(failed to read data)";
88*d100b5ddSNico Weber     }
89*d100b5ddSNico Weber     return *Data;
90*d100b5ddSNico Weber   }
91*d100b5ddSNico Weber };
92*d100b5ddSNico Weber 
93*d100b5ddSNico Weber } // namespace
94*d100b5ddSNico Weber 
95*d100b5ddSNico Weber NativeEnumInjectedSources::NativeEnumInjectedSources(
96*d100b5ddSNico Weber     PDBFile &File, const InjectedSourceStream &IJS,
97*d100b5ddSNico Weber     const PDBStringTable &Strings)
98*d100b5ddSNico Weber     : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {}
99*d100b5ddSNico Weber 
100*d100b5ddSNico Weber uint32_t NativeEnumInjectedSources::getChildCount() const {
101*d100b5ddSNico Weber   return static_cast<uint32_t>(Stream.size());
102*d100b5ddSNico Weber }
103*d100b5ddSNico Weber 
104*d100b5ddSNico Weber std::unique_ptr<IPDBInjectedSource>
105*d100b5ddSNico Weber NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const {
106*d100b5ddSNico Weber   if (N >= getChildCount())
107*d100b5ddSNico Weber     return nullptr;
108*d100b5ddSNico Weber   return make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second,
109*d100b5ddSNico Weber                                            File, Strings);
110*d100b5ddSNico Weber }
111*d100b5ddSNico Weber 
112*d100b5ddSNico Weber std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() {
113*d100b5ddSNico Weber   if (Cur == Stream.end())
114*d100b5ddSNico Weber     return nullptr;
115*d100b5ddSNico Weber   return make_unique<NativeInjectedSource>((Cur++)->second, File, Strings);
116*d100b5ddSNico Weber }
117*d100b5ddSNico Weber 
118*d100b5ddSNico Weber void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); }
119*d100b5ddSNico Weber 
120*d100b5ddSNico Weber }
121*d100b5ddSNico Weber }
122