diff options
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/ByteStream.cpp | 9 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp | 6 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp | 15 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/StreamReader.cpp | 8 | ||||
| -rw-r--r-- | llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp | 143 |
6 files changed, 179 insertions, 5 deletions
diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt index 2fa74b96246..b11fb306ad4 100644 --- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -36,7 +36,8 @@ add_pdb_impl_folder(Raw Raw/NameHashTable.cpp Raw/NameMap.cpp Raw/RawSession.cpp - Raw/StreamReader.cpp) + Raw/StreamReader.cpp + Raw/TpiStream.cpp) list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") diff --git a/llvm/lib/DebugInfo/PDB/Raw/ByteStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/ByteStream.cpp index 89477ead223..0826b21a9b9 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/ByteStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/ByteStream.cpp @@ -58,6 +58,15 @@ std::error_code ByteStream::readBytes(uint32_t Offset, return std::error_code(); } +std::error_code ByteStream::getArrayRef(uint32_t Offset, + ArrayRef<uint8_t> &Buffer, + uint32_t Length) const { + if (Data.size() < Length + Offset) + return std::make_error_code(std::errc::bad_address); + Buffer = Data.slice(Offset, Length); + return std::error_code(); +} + uint32_t ByteStream::getLength() const { return Data.size(); } StringRef ByteStream::str() const { diff --git a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp index 860f7639a06..25c28e587a4 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp @@ -51,3 +51,9 @@ MappedBlockStream::readBytes(uint32_t Offset, return std::error_code(); } + +std::error_code MappedBlockStream::getArrayRef(uint32_t Offset, + ArrayRef<uint8_t> &Buffer, + uint32_t Length) const { + return std::make_error_code(std::errc::operation_not_supported); +} diff --git a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp index df47ced8cd6..05b3dc7fc31 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" @@ -119,6 +120,8 @@ StringRef PDBFile::getBlockData(uint32_t BlockIndex, uint32_t NumBytes) const { std::error_code PDBFile::parseFileHeaders() { std::error_code EC; MemoryBufferRef BufferRef = *Context->Buffer; + // Make sure the file is sufficiently large to hold a super block. + // Do this before attempting to read the super block. if (BufferRef.getBufferSize() < sizeof(SuperBlock)) return std::make_error_code(std::errc::illegal_byte_sequence); @@ -135,10 +138,6 @@ std::error_code PDBFile::parseFileHeaders() { if (BufferRef.getBufferSize() % SB->BlockSize != 0) return std::make_error_code(std::errc::illegal_byte_sequence); - // Make sure the file is sufficiently large to hold a super block. - if (BufferRef.getBufferSize() < sizeof(SuperBlock)) - return std::make_error_code(std::errc::illegal_byte_sequence); - // Check the magic bytes. if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) return std::make_error_code(std::errc::illegal_byte_sequence); @@ -271,3 +270,11 @@ DbiStream &PDBFile::getPDBDbiStream() { } return *Dbi; } + +TpiStream &PDBFile::getPDBTpiStream() { + if (!Tpi) { + Tpi.reset(new TpiStream(*this)); + Tpi->reload(); + } + return *Tpi; +} diff --git a/llvm/lib/DebugInfo/PDB/Raw/StreamReader.cpp b/llvm/lib/DebugInfo/PDB/Raw/StreamReader.cpp index 42fe4521acf..18d29953e25 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/StreamReader.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/StreamReader.cpp @@ -39,3 +39,11 @@ std::error_code StreamReader::readZeroString(std::string &Dest) { } while (C != '\0'); return std::error_code(); } + +std::error_code StreamReader::getArrayRef(ArrayRef<uint8_t> &Array, + uint32_t Length) { + if (auto EC = Stream.getArrayRef(Offset, Array, Length)) + return EC; + Offset += Length; + return std::error_code(); +} diff --git a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp new file mode 100644 index 00000000000..7ee4c60789b --- /dev/null +++ b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -0,0 +1,143 @@ +//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Raw/TpiStream.h" + +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/StreamReader.h" + +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support; +using namespace llvm::pdb; + +namespace { +const uint32_t MinTypeIndex = codeview::TypeIndex::FirstNonSimpleIndex; + +const uint32_t MinHashBuckets = 0x1000; +const uint32_t MaxHashBuckets = 0x40000; +} + +static uint32_t HashBufferV8(uint8_t *buffer, uint32_t NumBuckets) { + // Not yet implemented, this is probably some variation of CRC32 but we need + // to be sure of the precise implementation otherwise we won't be able to work + // with persisted hash values. + return 0; +} + +struct TpiStream::HeaderInfo { + struct EmbeddedBuf { + little32_t Off; + ulittle32_t Length; + }; + + ulittle32_t Version; + ulittle32_t HeaderSize; + ulittle32_t TypeIndexBegin; + ulittle32_t TypeIndexEnd; + ulittle32_t TypeRecordBytes; + + ulittle16_t HashStreamIndex; + ulittle16_t HashAuxStreamIndex; + ulittle32_t HashKeySize; + ulittle32_t NumHashBuckets; + + EmbeddedBuf HashValueBuffer; + EmbeddedBuf IndexOffsetBuffer; + EmbeddedBuf HashAdjBuffer; +}; + +TpiStream::TpiStream(PDBFile &File) + : Pdb(File), Stream(StreamTPI, File), HashFunction(nullptr) {} + +TpiStream::~TpiStream() {} + +std::error_code TpiStream::reload() { + StreamReader Reader(Stream); + + if (Reader.bytesRemaining() < sizeof(HeaderInfo)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + Header.reset(new HeaderInfo()); + Reader.readObject(Header.get()); + + if (Header->Version != PdbTpiV80) + return std::make_error_code(std::errc::not_supported); + + if (Header->HeaderSize != sizeof(HeaderInfo)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + if (Header->HashKeySize != sizeof(ulittle32_t)) + return std::make_error_code(std::errc::illegal_byte_sequence); + + if (Header->NumHashBuckets < MinHashBuckets || + Header->NumHashBuckets > MaxHashBuckets) + return std::make_error_code(std::errc::illegal_byte_sequence); + + HashFunction = HashBufferV8; + + // The actual type records themselves come from this stream + RecordsBuffer.initialize(Reader, Header->TypeRecordBytes); + TypeRecords.resize(TypeIndexEnd() - ::MinTypeIndex); + StreamReader RecordsReader(RecordsBuffer); + for (uint32_t I = TypeIndexBegin(); I < TypeIndexEnd(); ++I) { + HashedTypeRecord &Record = TypeRecords[I - ::MinTypeIndex]; + codeview::TypeRecordPrefix Prefix; + if (auto EC = RecordsReader.readObject(&Prefix)) + return EC; + + Record.Kind = + static_cast<codeview::TypeLeafKind>(static_cast<uint16_t>(Prefix.Leaf)); + + // Since we read this entire buffer into a ByteStream, we are guaranteed + // that the entire buffer is contiguous (i.e. there's no longer a chance + // that it splits across a page boundary. So we can request a reference + // directly into the stream buffer to avoid unnecessary memory copies. + uint32_t RecordSize = Prefix.Len - sizeof(Prefix.Leaf); + if (auto EC = RecordsReader.getArrayRef(Record.Record, RecordSize)) + return EC; + } + + // Hash indices, hash values, etc come from the hash stream. + MappedBlockStream HS(Header->HashStreamIndex, Pdb); + StreamReader HSR(HS); + HSR.setOffset(Header->HashValueBuffer.Off); + HashValuesBuffer.initialize(HSR, Header->HashValueBuffer.Length); + + HSR.setOffset(Header->HashAdjBuffer.Off); + HashAdjBuffer.initialize(HSR, Header->HashAdjBuffer.Length); + + HSR.setOffset(Header->IndexOffsetBuffer.Off); + TypeIndexOffsetBuffer.initialize(HSR, Header->IndexOffsetBuffer.Length); + + return std::error_code(); +} + +PdbRaw_TpiVer TpiStream::getTpiVersion() const { + uint32_t Value = Header->Version; + return static_cast<PdbRaw_TpiVer>(Value); +} + +uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; } + +uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; } + +uint32_t TpiStream::NumTypeRecords() const { + return TypeIndexEnd() - TypeIndexBegin(); +} + +ArrayRef<TpiStream::HashedTypeRecord> TpiStream::records() const { + const HashedTypeRecord *Begin = + &TypeRecords[TypeIndexBegin() - ::MinTypeIndex]; + return ArrayRef<HashedTypeRecord>(Begin, NumTypeRecords()); +} |

