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