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