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