Index: include/llvm/DebugInfo/CodeView/StreamArray.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/StreamArray.h @@ -0,0 +1,188 @@ +//===- StreamArray.h - Array backed by an arbitrary stream ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H + +#include "llvm/DebugInfo/CodeView/StreamView.h" + +#include + +namespace llvm { +namespace codeview { + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. +class VarStreamArrayIterator; + +class VarStreamArray { + friend class VarStreamArrayIterator; + typedef std::function LengthFuncType; + +public: + template + VarStreamArray(StreamView Stream, const LengthFunc &Len) + : Stream(Stream), Len(Len) {} + + VarStreamArrayIterator begin() const; + VarStreamArrayIterator end() const; + +private: + StreamView Stream; + LengthFuncType Len; // Function used to calculate legth of a record +}; + +class VarStreamArrayIterator { +public: + VarStreamArrayIterator(const VarStreamArray &Array) + : Array(&Array), IterView(Array.Stream) { + ThisLen = Array.Len(IterView); + } + VarStreamArrayIterator() : Array(nullptr), IterView() {} + bool operator==(const VarStreamArrayIterator &R) const { + if (Array && R.Array) { + // Both have a valid array, make sure they're same. + assert(Array == R.Array); + return IterView == R.IterView; + } + + // Both iterators are at the end. + if (!Array && !R.Array) + return true; + + // One is not at the end and one is. + return false; + } + + bool operator!=(const VarStreamArrayIterator &R) { return !(*this == R); } + + StreamView operator*() const { + ArrayRef Result; + return IterView.keep_front(ThisLen); + } + + VarStreamArrayIterator &operator++() { + if (!Array || IterView.getLength() == 0) + return *this; + IterView = IterView.drop_front(ThisLen); + if (IterView.getLength() == 0) { + Array = nullptr; + ThisLen = 0; + } else { + ThisLen = Array->Len(IterView); + } + return *this; + } + + VarStreamArrayIterator operator++(int) { + VarStreamArrayIterator Original = *this; + ++*this; + return Original; + } + +private: + const VarStreamArray *Array; + uint32_t ThisLen; + StreamView IterView; +}; + +inline VarStreamArrayIterator VarStreamArray::begin() const { + return VarStreamArrayIterator(*this); +} +inline VarStreamArrayIterator VarStreamArray::end() const { + return VarStreamArrayIterator(); +} + +template class FixedStreamArrayIterator; + +template class FixedStreamArray { + friend class FixedStreamArrayIterator; + +public: + FixedStreamArray() : Stream(), TempItem() {} + FixedStreamArray(StreamView Stream) : Stream(Stream), TempItem() {} + + const T &operator[](uint32_t Index) const { + assert(Index < size()); + uint32_t Off = Index * sizeof(T); + ArrayRef Data; + if (auto EC = Stream.getArrayRef(Off, Data, sizeof(T))) { + consumeError(std::move(EC)); + MutableArrayRef Buf(reinterpret_cast(&TempItem), + sizeof(T)); + if (EC = Stream.readBytes(Off, Buf)) { + consumeError(std::move(EC)); + return TempItem; + } + } + return *reinterpret_cast(Data.data()); + } + + uint32_t size() const { return Stream.getLength() / sizeof(T); } + + FixedStreamArrayIterator begin() const { + return FixedStreamArrayIterator(*this, 0); + } + FixedStreamArrayIterator end() const { + return FixedStreamArrayIterator(*this); + } + +private: + StreamView Stream; + mutable T TempItem; +}; + +template class FixedStreamArrayIterator { +public: + FixedStreamArrayIterator(const FixedStreamArray &Array) + : Array(Array), Index(uint32_t(-1)) {} + FixedStreamArrayIterator(const FixedStreamArray &Array, uint32_t Index) + : Array(Array), Index(Index) {} + + bool operator==(const FixedStreamArrayIterator &R) { + assert(&Array == &R.Array); + return Index == R.Index; + } + + bool operator!=(const FixedStreamArrayIterator &R) { + return !(*this == R); + } + + const T &operator*() const { return Array[Index]; } + + FixedStreamArrayIterator &operator++() { + if (Index == uint32_t(-1)) + return *this; + if (++Index >= Array.size()) + Index = uint32_t(-1); + return *this; + } + + FixedStreamArrayIterator operator++(int) { + FixedStreamArrayIterator Original = *this; + ++*this; + return Original; + } + +private: + const FixedStreamArray &Array; + uint32_t Index; +}; + +} // namespace codeview +} // namespace llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMARRAY_H Index: include/llvm/DebugInfo/CodeView/StreamObject.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/StreamObject.h @@ -0,0 +1,59 @@ +//===- StreamObject.h - An object backed by an arbitrary stream -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMOBJECT_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMOBJECT_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/StreamView.h" + +#include + +namespace llvm { +namespace codeview { + +template class StreamObject { +public: + StreamObject(StreamView Stream) { + if (auto EC = Stream.getArrayRef(0, Ref, sizeof(T))) { + consumeError(std::move(EC)); + TempValue.reset(new uint8_t[sizeof(T)]); + MutableArrayRef Buf(TempValue.get(), sizeof(T)); + if (auto EC = Stream.readBytes(0, Buf)) { + consumeError(std::move(EC)); + return; + } + Ref = Buf; + } + Ptr = reinterpret_cast(Ref.data()); + } + StreamObject(const StreamObject &Other) { + if (Other.TempValue) { + TempValue.reset(new uint8_t[sizeof(T)]); + Ref = ArrayRef(TempValue.get(), sizeof(T)); + ::memcpy(TempValue.get(), Other.TempValue.get(), sizeof(T)); + } else { + Ref = Other.Ref; + } + Ptr = reinterpret_cast(Ref.data()); + } + + const T *operator->() const { return Ptr; } + + const T &get() const { return *Ptr; } + +private: + std::unique_ptr TempValue; + ArrayRef Ref; + const T *Ptr; +}; +} +} + +#endif Index: include/llvm/DebugInfo/CodeView/StreamReader.h =================================================================== --- include/llvm/DebugInfo/CodeView/StreamReader.h +++ include/llvm/DebugInfo/CodeView/StreamReader.h @@ -11,6 +11,8 @@ #define LLVM_DEBUGINFO_CODEVIEW_STREAMREADER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamInterface.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" @@ -20,13 +22,20 @@ namespace llvm { namespace codeview { +class StreamString; +class StreamView; + class StreamReader { public: StreamReader(const StreamInterface &S); Error readBytes(MutableArrayRef Buffer); + Error readInteger(uint16_t &Dest); Error readInteger(uint32_t &Dest); Error readZeroString(std::string &Dest); + Error readZeroString(StreamString &Dest); + Error readStreamView(StreamView &View); + Error readStreamView(StreamView &View, uint32_t Length); template Error readObject(T *Dest) { MutableArrayRef Buffer(reinterpret_cast(Dest), @@ -34,6 +43,17 @@ return readBytes(Buffer); } + template + Error readArray(FixedStreamArray &Array, uint32_t NumItems) { + uint32_t Length = NumItems * sizeof(T); + if (Offset + Length >= Stream.getLength()) + return make_error(cv_error_code::insufficient_buffer); + StreamView View(Stream, Offset, Length); + Array = FixedStreamArray(View); + Offset += Length; + return Error::success(); + } + template Error readArray(MutableArrayRef Array) { MutableArrayRef Casted(reinterpret_cast(Array.data()), Array.size() * sizeof(T)); Index: include/llvm/DebugInfo/CodeView/StreamString.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/StreamString.h @@ -0,0 +1,41 @@ +//===- StreamString.h - A string backed by an arbitrary stream ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMSTRING_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMSTRING_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/CodeView/StreamReader.h" + +#include + +namespace llvm { +namespace codeview { +class StreamString { +public: + StreamString() {} + StreamString(const std::string &Value) : Storage(Value), Ref(Storage) {} + StreamString(StringRef Value) : Ref(Value) {} + StreamString(const StreamString &Other) + : Storage(Other.Storage), Ref(Other.Ref) { + if (!Storage.empty()) + Ref = Storage; + } + + StringRef str() const { return Ref; } + +private: + std::string Storage; + StringRef Ref; +}; +} // codeview +} // llvm + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMSTRING_H Index: include/llvm/DebugInfo/CodeView/StreamView.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/CodeView/StreamView.h @@ -0,0 +1,81 @@ +//===- StreamView.h - A stream providing a view over another ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_CODEVIEW_STREAMVIEW_H +#define LLVM_DEBUGINFO_CODEVIEW_STREAMVIEW_H + +#include "llvm/DebugInfo/CodeView/StreamInterface.h" + +namespace llvm { +namespace codeview { + +class StreamView : public StreamInterface { +public: + StreamView() : Stream(nullptr), ViewOffset(0), Length(0) {} + StreamView(const StreamInterface &Stream) + : Stream(&Stream), ViewOffset(0), Length(Stream.getLength()) {} + StreamView(const StreamInterface &Stream, uint32_t Offset, uint32_t Length) + : Stream(&Stream), ViewOffset(Offset), Length(Length) {} + StreamView(const StreamView &Other) + : Stream(Other.Stream), ViewOffset(Other.ViewOffset), + Length(Other.Length) {} + + Error readBytes(uint32_t Offset, + MutableArrayRef Buffer) const override { + return Stream->readBytes(ViewOffset + Offset, Buffer); + } + Error getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const override { + return Stream->getArrayRef(ViewOffset + Offset, Buffer, Length); + } + + uint32_t getLength() const override { return Length; } + StreamView drop_front(uint32_t N) const { + if (!Stream) + return StreamView(); + + N = std::min(N, Length); + return StreamView(*Stream, ViewOffset + N, Length - N); + } + + StreamView keep_front(uint32_t N) const { + if (!Stream) + return StreamView(); + N = std::min(N, Length); + return StreamView(*Stream, ViewOffset, N); + } + + bool operator==(const StreamView &Other) const { + if (Stream != Other.Stream) + return false; + if (ViewOffset != Other.ViewOffset) + return false; + if (Length != Other.Length) + return false; + return true; + } + + bool operator!=(const StreamView &Other) const { return !(*this == Other); } + + StreamView &operator=(const StreamView &Other) { + Stream = Other.Stream; + ViewOffset = Other.ViewOffset; + Length = Other.Length; + return *this; + } + +private: + const StreamInterface *Stream; + uint32_t ViewOffset; + uint32_t Length; +}; +} +} + +#endif // LLVM_DEBUGINFO_CODEVIEW_STREAMVIEW_H \ No newline at end of file Index: include/llvm/DebugInfo/PDB/Raw/DbiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -11,6 +11,7 @@ #define LLVM_DEBUGINFO_PDB_RAW_PDBDBISTREAM_H #include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/CodeView/StreamView.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" @@ -62,13 +63,13 @@ std::vector ModuleInfos; NameHashTable ECNames; - codeview::ByteStream ModInfoSubstream; - codeview::ByteStream SecContrSubstream; - codeview::ByteStream SecMapSubstream; - codeview::ByteStream FileInfoSubstream; - codeview::ByteStream TypeServerMapSubstream; - codeview::ByteStream ECSubstream; - codeview::ByteStream DbgHeader; + codeview::StreamView ModInfoSubstream; + codeview::StreamView SecContrSubstream; + codeview::StreamView SecMapSubstream; + codeview::StreamView FileInfoSubstream; + codeview::StreamView TypeServerMapSubstream; + codeview::StreamView ECSubstream; + codeview::StreamView DbgHeader; std::unique_ptr Header; }; Index: include/llvm/DebugInfo/PDB/Raw/ModInfo.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/ModInfo.h +++ include/llvm/DebugInfo/PDB/Raw/ModInfo.h @@ -11,6 +11,8 @@ #define LLVM_DEBUGINFO_PDB_RAW_MODINFO_H #include "llvm/ADT/StringRef.h" +#include "llvm/DebugInfo/CodeView/StreamObject.h" +#include "llvm/DebugInfo/CodeView/StreamString.h" #include #include @@ -19,10 +21,52 @@ class ModInfo { private: - struct FileLayout; + struct SCBytes { + using ulittle16_t = llvm::support::ulittle16_t; + using ulittle32_t = llvm::support::ulittle32_t; + using little32_t = llvm::support::little32_t; + + ulittle16_t Section; + char Padding1[2]; + little32_t Offset; + little32_t Size; + ulittle32_t Characteristics; + ulittle16_t ModuleIndex; + char Padding2[2]; + ulittle32_t DataCrc; + ulittle32_t RelocCrc; + }; + + struct FileLayout { + using ulittle16_t = llvm::support::ulittle16_t; + using ulittle32_t = llvm::support::ulittle32_t; + + ulittle32_t Mod; // Currently opened module. This field is a + // pointer in the reference implementation, but + // that won't work on 64-bit systems, and anyway + // it doesn't make sense to read a pointer from a + // file. For now it is unused, so just ignore it. + SCBytes SC; // First section contribution of this module. + ulittle16_t Flags; // See Flags definition. + ulittle16_t ModDiStream; // Stream Number of module debug info + ulittle32_t SymBytes; // Size of local symbol debug info in above stream + ulittle32_t LineBytes; // Size of line number debug info in above stream + ulittle32_t C13Bytes; // Size of C13 line number info in above stream + ulittle16_t NumFiles; // Number of files contributing to this module + char Padding1[2]; // Padding so the next field is 4-byte aligned. + ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets. + // This field is a pointer in the reference + // implementation, but as with `Mod`, we ignore it + // for now since it is unused. + ulittle32_t SrcFileNameNI; // Name Index for src file name + ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB + // Null terminated Module name + // Null terminated Obj File Name + }; public: - ModInfo(const uint8_t *Bytes); + ModInfo(codeview::StreamView Stream); + ModInfo(const ModInfo &Info); ~ModInfo(); bool hasECInfo() const; @@ -35,35 +79,29 @@ uint32_t getSourceFileNameIndex() const; uint32_t getPdbFilePathNameIndex() const; - StringRef getModuleName() const; - StringRef getObjFileName() const; + codeview::StreamString getModuleName() const; + codeview::StreamString getObjFileName() const; + + uint32_t getRecordLength() const; private: - const FileLayout *Layout; + codeview::StreamString ModuleName; + codeview::StreamString ObjFileName; + codeview::StreamObject Layout; }; struct ModuleInfoEx { - ModuleInfoEx(ModInfo Module) : Info(Module) {} + ModuleInfoEx(codeview::StreamView Stream) : Info(Stream) {} + ModuleInfoEx(const ModuleInfoEx &Ex) + : Info(Ex.Info), SourceFiles(Ex.SourceFiles) {} ModInfo Info; - std::vector SourceFiles; + std::vector SourceFiles; }; -class ModInfoIterator { -public: - ModInfoIterator(const uint8_t *Stream); - ModInfoIterator(const ModInfoIterator &Other); - - ModInfo operator*(); - ModInfoIterator &operator++(); - ModInfoIterator operator++(int); - bool operator==(const ModInfoIterator &Other); - bool operator!=(const ModInfoIterator &Other); - ModInfoIterator &operator=(const ModInfoIterator &Other); - -private: - const uint8_t *Bytes; -}; +inline uint32_t ModInfoRecordLength(const codeview::StreamInterface &Stream) { + return ModInfo(Stream).getRecordLength(); +} } // end namespace pdb } // end namespace llvm Index: lib/DebugInfo/CodeView/StreamReader.cpp =================================================================== --- lib/DebugInfo/CodeView/StreamReader.cpp +++ lib/DebugInfo/CodeView/StreamReader.cpp @@ -10,6 +10,8 @@ #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/StreamString.h" +#include "llvm/DebugInfo/CodeView/StreamView.h" using namespace llvm; using namespace llvm::codeview; @@ -23,6 +25,14 @@ return Error::success(); } +Error StreamReader::readInteger(uint16_t &Dest) { + support::ulittle16_t P; + if (auto EC = readObject(&P)) + return EC; + Dest = P; + return Error::success(); +} + Error StreamReader::readInteger(uint32_t &Dest) { support::ulittle32_t P; if (auto EC = readObject(&P)) @@ -43,6 +53,38 @@ return Error::success(); } +Error StreamReader::readZeroString(StreamString &Dest) { + std::string S; + uint32_t OldOff = getOffset(); + if (auto EC = readZeroString(S)) + return EC; + uint32_t NewOff = getOffset(); + setOffset(OldOff); + ArrayRef DataRef; + if (auto EC = getArrayRef(DataRef, S.size())) { + consumeError(std::move(EC)); + Dest = StreamString(S); + } else { + StringRef SR(reinterpret_cast(DataRef.data()), + DataRef.size()); + Dest = StreamString(SR); + } + setOffset(NewOff); + return Error::success(); +} + +Error StreamReader::readStreamView(StreamView &View) { + return readStreamView(View, bytesRemaining()); +} + +Error StreamReader::readStreamView(StreamView &View, uint32_t Length) { + if (bytesRemaining() < Length) + return make_error(cv_error_code::insufficient_buffer); + View = StreamView(Stream, Offset, Length); + Offset += Length; + return Error::success(); +} + Error StreamReader::getArrayRef(ArrayRef &Array, uint32_t Length) { if (auto EC = Stream.getArrayRef(Offset, Array, Length)) return EC; Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -42,6 +42,7 @@ Raw/SymbolStream.cpp Raw/TpiStream.cpp) +list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB/Raw") list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") add_llvm_library(LLVMDebugInfoPDB Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" +#include "llvm/DebugInfo/CodeView/StreamArray.h" #include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" @@ -137,30 +138,30 @@ return make_error(raw_error_code::corrupt_file, "DBI type server substream not aligned."); - if (auto EC = ModInfoSubstream.initialize(Reader, Header->ModiSubstreamSize)) + if (auto EC = + Reader.readStreamView(ModInfoSubstream, Header->ModiSubstreamSize)) return EC; // Since each ModInfo in the stream is a variable length, we have to iterate // them to know how many there actually are. - auto Range = - llvm::make_range(ModInfoIterator(&ModInfoSubstream.data().front()), - ModInfoIterator(&ModInfoSubstream.data().back() + 1)); - for (auto Info : Range) - ModuleInfos.push_back(ModuleInfoEx(Info)); + codeview::VarStreamArray ModInfoArray(ModInfoSubstream, ModInfoRecordLength); + for (auto Info : ModInfoArray) { + ModuleInfos.emplace_back(Info); + } - if (auto EC = - SecContrSubstream.initialize(Reader, Header->SecContrSubstreamSize)) + if (auto EC = Reader.readStreamView(SecContrSubstream, + Header->SecContrSubstreamSize)) return EC; - if (auto EC = SecMapSubstream.initialize(Reader, Header->SectionMapSize)) + if (auto EC = Reader.readStreamView(SecMapSubstream, Header->SectionMapSize)) return EC; - if (auto EC = FileInfoSubstream.initialize(Reader, Header->FileInfoSize)) + if (auto EC = Reader.readStreamView(FileInfoSubstream, Header->FileInfoSize)) return EC; if (auto EC = - TypeServerMapSubstream.initialize(Reader, Header->TypeServerSize)) + Reader.readStreamView(TypeServerMapSubstream, Header->TypeServerSize)) return EC; - if (auto EC = ECSubstream.initialize(Reader, Header->ECSubstreamSize)) + if (auto EC = Reader.readStreamView(ECSubstream, Header->ECSubstreamSize)) return EC; - if (auto EC = DbgHeader.initialize(Reader, Header->OptionalDbgHdrSize)) + if (auto EC = Reader.readStreamView(DbgHeader, Header->OptionalDbgHdrSize)) return EC; if (auto EC = initializeFileInfo()) @@ -247,25 +248,30 @@ // with the caveat that `NumSourceFiles` cannot be trusted, so // it is computed by summing `ModFileCounts`. // - const uint8_t *Buf = &FileInfoSubstream.data().front(); - auto FI = reinterpret_cast(Buf); - Buf += sizeof(FileInfoSubstreamHeader); + FileInfoSubstreamHeader Header; + codeview::StreamReader FISR(FileInfoSubstream); + if (auto EC = FISR.readObject(&Header)) + return EC; + // The number of modules in the stream should be the same as reported by // the FileInfoSubstreamHeader. - if (FI->NumModules != ModuleInfos.size()) + if (Header.NumModules != ModuleInfos.size()) return make_error(raw_error_code::corrupt_file, "FileInfo substream count doesn't match DBI."); + codeview::FixedStreamArray ModIndexArray; + codeview::FixedStreamArray ModFileCountArray; + codeview::FixedStreamArray FileNameOffsets; + // First is an array of `NumModules` module indices. This is not used for the // same reason that `NumSourceFiles` is not used. It's an array of uint16's, // but it's possible there are more than 64k source files, which would imply // more than 64k modules (e.g. object files) as well. So we ignore this // field. - llvm::ArrayRef ModIndexArray( - reinterpret_cast(Buf), ModuleInfos.size()); - - llvm::ArrayRef ModFileCountArray(ModIndexArray.end(), - ModuleInfos.size()); + if (auto EC = FISR.readArray(ModIndexArray, ModuleInfos.size())) + return EC; + if (auto EC = FISR.readArray(ModFileCountArray, ModuleInfos.size())) + return EC; // Compute the real number of source files. uint32_t NumSourceFiles = 0; @@ -280,11 +286,13 @@ // them in `ModuleInfoEx`. The value written to and read from the file is // not used anyway, it is only there as a way to store the offsets for the // purposes of later accessing the names at runtime. - llvm::ArrayRef FileNameOffsets( - reinterpret_cast(ModFileCountArray.end()), - NumSourceFiles); + if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles)) + return EC; - const char *Names = reinterpret_cast(FileNameOffsets.end()); + codeview::StreamView NamesBufferView; + if (auto EC = FISR.readStreamView(NamesBufferView)) + return EC; + codeview::StreamReader Names(NamesBufferView); // We go through each ModuleInfo, determine the number N of source files for // that module, and then get the next N offsets from the Offsets array, using @@ -295,8 +303,10 @@ uint32_t NumFiles = ModFileCountArray[I]; ModuleInfos[I].SourceFiles.resize(NumFiles); for (size_t J = 0; J < NumFiles; ++J, ++NextFileIndex) { - uint32_t FileIndex = FileNameOffsets[NextFileIndex]; - ModuleInfos[I].SourceFiles[J] = StringRef(Names + FileIndex); + uint32_t FileOffset = FileNameOffsets[NextFileIndex]; + Names.setOffset(FileOffset); + if (auto EC = Names.readZeroString(ModuleInfos[I].SourceFiles[J])) + return EC; } } Index: lib/DebugInfo/PDB/Raw/ModInfo.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ lib/DebugInfo/PDB/Raw/ModInfo.cpp @@ -16,17 +16,6 @@ using namespace llvm::support; namespace { -struct SCBytes { - ulittle16_t Section; - char Padding1[2]; - little32_t Offset; - little32_t Size; - ulittle32_t Characteristics; - ulittle16_t ModuleIndex; - char Padding2[2]; - ulittle32_t DataCrc; - ulittle32_t RelocCrc; -}; // struct Flags { // uint16_t fWritten : 1; // True if ModInfo is dirty @@ -40,37 +29,24 @@ const uint16_t TypeServerIndexShift = 8; } -struct ModInfo::FileLayout { - ulittle32_t Mod; // Currently opened module. This field is a - // pointer in the reference implementation, but - // that won't work on 64-bit systems, and anyway - // it doesn't make sense to read a pointer from a - // file. For now it is unused, so just ignore it. - SCBytes SC; // First section contribution of this module. - ulittle16_t Flags; // See Flags definition. - ulittle16_t ModDiStream; // Stream Number of module debug info - ulittle32_t SymBytes; // Size of local symbol debug info in above stream - ulittle32_t LineBytes; // Size of line number debug info in above stream - ulittle32_t C13Bytes; // Size of C13 line number info in above stream - ulittle16_t NumFiles; // Number of files contributing to this module - char Padding1[2]; // Padding so the next field is 4-byte aligned. - ulittle32_t FileNameOffs; // array of [0..NumFiles) DBI name buffer offsets. - // This field is a pointer in the reference - // implementation, but as with `Mod`, we ignore it - // for now since it is unused. - ulittle32_t SrcFileNameNI; // Name Index for src file name - ulittle32_t PdbFilePathNI; // Name Index for path to compiler PDB - char VarInfo[1]; // Module name followed by Obj File Name - - StringRef getModuleName() const { return StringRef(VarInfo); } - - StringRef getObjectFileName() const { - return StringRef(getModuleName().end() + 1); +ModInfo::ModInfo(codeview::StreamView Stream) : Layout(Stream) { + codeview::StreamReader Reader(Stream); + Reader.setOffset(sizeof(FileLayout)); + if (auto EC = Reader.readZeroString(ModuleName)) { + consumeError(std::move(EC)); + return; } -}; + if (auto EC = Reader.readZeroString(ObjFileName)) { + consumeError(std::move(EC)); + return; + } +} -ModInfo::ModInfo(const uint8_t *Bytes) - : Layout(reinterpret_cast(Bytes)) {} +ModInfo::ModInfo(const ModInfo &Info) + : Layout(Info.Layout), ModuleName(Info.ModuleName), + ObjFileName(Info.ObjFileName) { + uint32_t Index = Layout->ModDiStream; +} ModInfo::~ModInfo() {} @@ -100,44 +76,14 @@ return Layout->PdbFilePathNI; } -llvm::StringRef ModInfo::getModuleName() const { - return Layout->getModuleName(); -} - -llvm::StringRef ModInfo::getObjFileName() const { - return Layout->getObjectFileName(); -} - -ModInfoIterator::ModInfoIterator(const uint8_t *Stream) : Bytes(Stream) {} - -ModInfoIterator::ModInfoIterator(const ModInfoIterator &Other) - : Bytes(Other.Bytes) {} - -ModInfo ModInfoIterator::operator*() { return ModInfo(Bytes); } +codeview::StreamString ModInfo::getModuleName() const { return ModuleName; } -ModInfoIterator &ModInfoIterator::operator++() { - StringRef Obj = ModInfo(Bytes).getObjFileName(); - Bytes = Obj.bytes_end() + 1; - Bytes = reinterpret_cast(llvm::alignAddr(Bytes, 4)); - - return *this; -} - -ModInfoIterator ModInfoIterator::operator++(int) { - ModInfoIterator Copy(*this); - ++(*this); - return Copy; -} - -bool ModInfoIterator::operator==(const ModInfoIterator &Other) { - return Bytes == Other.Bytes; -} - -bool ModInfoIterator::operator!=(const ModInfoIterator &Other) { - return !(*this == Other); -} +codeview::StreamString ModInfo::getObjFileName() const { return ObjFileName; } -ModInfoIterator &ModInfoIterator::operator=(const ModInfoIterator &Other) { - Bytes = Other.Bytes; - return *this; +uint32_t ModInfo::getRecordLength() const { + uint32_t M = ModuleName.str().size() + 1; + uint32_t O = ObjFileName.str().size() + 1; + uint32_t Size = sizeof(FileLayout) + M + O; + Size = llvm::alignTo(Size, 4); + return Size; } Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -299,7 +299,7 @@ auto NSIter = NamedStreams.find(StreamIdx); if (ModIter != ModStreams.end()) { Value = "Module \""; - Value += ModIter->second->Info.getModuleName(); + Value += ModIter->second->Info.getModuleName().str(); Value += "\""; } else if (NSIter != NamedStreams.end()) { Value = "Named Stream \""; @@ -449,9 +449,9 @@ ListScope L(P, "Modules"); for (auto &Modi : DS.modules()) { DictScope DD(P); - P.printString("Name", Modi.Info.getModuleName()); + P.printString("Name", Modi.Info.getModuleName().str()); P.printNumber("Debug Stream Index", Modi.Info.getModuleStreamIndex()); - P.printString("Object File Name", Modi.Info.getObjFileName()); + P.printString("Object File Name", Modi.Info.getObjFileName().str()); P.printNumber("Num Files", Modi.Info.getNumberOfFiles()); P.printNumber("Source File Name Idx", Modi.Info.getSourceFileNameIndex()); P.printNumber("Pdb File Name Idx", Modi.Info.getPdbFilePathNameIndex()); @@ -466,7 +466,7 @@ to_string(Modi.SourceFiles.size()) + " Contributing Source Files"; ListScope LL(P, FileListName); for (auto File : Modi.SourceFiles) - P.printString(File); + P.printString(File.str()); } bool HasModuleDI = (Modi.Info.getModuleStreamIndex() < File.getNumStreams());