10b57cec5SDimitry Andric //==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
100b57cec5SDimitry Andric
11*06c3fb27SDimitry Andric #include "llvm/ADT/StringExtras.h"
1281ad6265SDimitry Andric #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
1381ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/HashTable.h"
140b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
150b57cec5SDimitry Andric #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
1681ad6265SDimitry Andric #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric namespace llvm {
190b57cec5SDimitry Andric namespace pdb {
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric namespace {
220b57cec5SDimitry Andric
readStreamData(BinaryStream & Stream,uint64_t Limit)23349cc55cSDimitry Andric Expected<std::string> readStreamData(BinaryStream &Stream, uint64_t Limit) {
24349cc55cSDimitry Andric uint64_t Offset = 0, DataLength = std::min(Limit, Stream.getLength());
250b57cec5SDimitry Andric std::string Result;
260b57cec5SDimitry Andric Result.reserve(DataLength);
270b57cec5SDimitry Andric while (Offset < DataLength) {
280b57cec5SDimitry Andric ArrayRef<uint8_t> Data;
290b57cec5SDimitry Andric if (auto E = Stream.readLongestContiguousChunk(Offset, Data))
300b57cec5SDimitry Andric return std::move(E);
310b57cec5SDimitry Andric Data = Data.take_front(DataLength - Offset);
320b57cec5SDimitry Andric Offset += Data.size();
330b57cec5SDimitry Andric Result += toStringRef(Data);
340b57cec5SDimitry Andric }
350b57cec5SDimitry Andric return Result;
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric class NativeInjectedSource final : public IPDBInjectedSource {
390b57cec5SDimitry Andric const SrcHeaderBlockEntry &Entry;
400b57cec5SDimitry Andric const PDBStringTable &Strings;
410b57cec5SDimitry Andric PDBFile &File;
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric public:
NativeInjectedSource(const SrcHeaderBlockEntry & Entry,PDBFile & File,const PDBStringTable & Strings)440b57cec5SDimitry Andric NativeInjectedSource(const SrcHeaderBlockEntry &Entry,
450b57cec5SDimitry Andric PDBFile &File, const PDBStringTable &Strings)
460b57cec5SDimitry Andric : Entry(Entry), Strings(Strings), File(File) {}
470b57cec5SDimitry Andric
getCrc32() const480b57cec5SDimitry Andric uint32_t getCrc32() const override { return Entry.CRC; }
getCodeByteSize() const490b57cec5SDimitry Andric uint64_t getCodeByteSize() const override { return Entry.FileSize; }
500b57cec5SDimitry Andric
getFileName() const510b57cec5SDimitry Andric std::string getFileName() const override {
528bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI),
538bcb0991SDimitry Andric "InjectedSourceStream should have rejected this");
545ffd83dbSDimitry Andric return std::string(Ret);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
getObjectFileName() const570b57cec5SDimitry Andric std::string getObjectFileName() const override {
588bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI),
598bcb0991SDimitry Andric "InjectedSourceStream should have rejected this");
605ffd83dbSDimitry Andric return std::string(Ret);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
getVirtualFileName() const630b57cec5SDimitry Andric std::string getVirtualFileName() const override {
648bcb0991SDimitry Andric StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI),
658bcb0991SDimitry Andric "InjectedSourceStream should have rejected this");
665ffd83dbSDimitry Andric return std::string(Ret);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric
getCompression() const690b57cec5SDimitry Andric uint32_t getCompression() const override { return Entry.Compression; }
700b57cec5SDimitry Andric
getCode() const710b57cec5SDimitry Andric std::string getCode() const override {
720b57cec5SDimitry Andric // Get name of stream storing the data.
738bcb0991SDimitry Andric StringRef VName =
748bcb0991SDimitry Andric cantFail(Strings.getStringForID(Entry.VFileNI),
758bcb0991SDimitry Andric "InjectedSourceStream should have rejected this");
768bcb0991SDimitry Andric std::string StreamName = ("/src/files/" + VName).str();
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric // Find stream with that name and read its data.
790b57cec5SDimitry Andric // FIXME: Consider validating (or even loading) all this in
800b57cec5SDimitry Andric // InjectedSourceStream so that no error can happen here.
810b57cec5SDimitry Andric auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName);
820b57cec5SDimitry Andric if (!ExpectedFileStream) {
830b57cec5SDimitry Andric consumeError(ExpectedFileStream.takeError());
840b57cec5SDimitry Andric return "(failed to open data stream)";
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric
870b57cec5SDimitry Andric auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize);
880b57cec5SDimitry Andric if (!Data) {
890b57cec5SDimitry Andric consumeError(Data.takeError());
900b57cec5SDimitry Andric return "(failed to read data)";
910b57cec5SDimitry Andric }
920b57cec5SDimitry Andric return *Data;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric };
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric } // namespace
970b57cec5SDimitry Andric
NativeEnumInjectedSources(PDBFile & File,const InjectedSourceStream & IJS,const PDBStringTable & Strings)980b57cec5SDimitry Andric NativeEnumInjectedSources::NativeEnumInjectedSources(
990b57cec5SDimitry Andric PDBFile &File, const InjectedSourceStream &IJS,
1000b57cec5SDimitry Andric const PDBStringTable &Strings)
1010b57cec5SDimitry Andric : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {}
1020b57cec5SDimitry Andric
getChildCount() const1030b57cec5SDimitry Andric uint32_t NativeEnumInjectedSources::getChildCount() const {
1040b57cec5SDimitry Andric return static_cast<uint32_t>(Stream.size());
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource>
getChildAtIndex(uint32_t N) const1080b57cec5SDimitry Andric NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const {
1090b57cec5SDimitry Andric if (N >= getChildCount())
1100b57cec5SDimitry Andric return nullptr;
1118bcb0991SDimitry Andric return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second,
1120b57cec5SDimitry Andric File, Strings);
1130b57cec5SDimitry Andric }
1140b57cec5SDimitry Andric
getNext()1150b57cec5SDimitry Andric std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() {
1160b57cec5SDimitry Andric if (Cur == Stream.end())
1170b57cec5SDimitry Andric return nullptr;
1188bcb0991SDimitry Andric return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric
reset()1210b57cec5SDimitry Andric void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); }
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric }
125