summaryrefslogtreecommitdiffstats
path: root/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
diff options
context:
space:
mode:
authorAdrian McCarthy <amccarth@google.com>2017-01-25 22:38:55 +0000
committerAdrian McCarthy <amccarth@google.com>2017-01-25 22:38:55 +0000
commit6b6b8c4fb9de06aecef40b8aadcc92dfbfec2e33 (patch)
treecdef766dc0d3728f643359f40671078727d9487e /llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
parent896b4513e1bb1a96192b71db9da3ed7955778346 (diff)
downloadbcm5719-llvm-6b6b8c4fb9de06aecef40b8aadcc92dfbfec2e33.tar.gz
bcm5719-llvm-6b6b8c4fb9de06aecef40b8aadcc92dfbfec2e33.zip
NFC: Rename (PDB) RawSession to NativeSession
This eliminates one overload on the term Raw. Differential Revision: https://reviews.llvm.org/D29098 llvm-svn: 293104
Diffstat (limited to 'llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp')
-rw-r--r--llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp404
1 files changed, 404 insertions, 0 deletions
diff --git a/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
new file mode 100644
index 00000000000..02e883b8418
--- /dev/null
+++ b/llvm/lib/DebugInfo/PDB/Native/PDBFile.cpp
@@ -0,0 +1,404 @@
+//===- PDBFile.cpp - Low level interface to a PDB file ----------*- C++ -*-===//
+//
+// 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/Native/PDBFile.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/MSF/StreamArray.h"
+#include "llvm/DebugInfo/MSF/StreamInterface.h"
+#include "llvm/DebugInfo/MSF/StreamReader.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/StringTable.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
+} // end anonymous namespace
+
+PDBFile::PDBFile(std::unique_ptr<ReadableStream> PdbFileBuffer,
+ BumpPtrAllocator &Allocator)
+ : Allocator(Allocator), Buffer(std::move(PdbFileBuffer)) {}
+
+PDBFile::~PDBFile() = default;
+
+uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
+
+uint32_t PDBFile::getFreeBlockMapBlock() const {
+ return ContainerLayout.SB->FreeBlockMapBlock;
+}
+
+uint32_t PDBFile::getBlockCount() const {
+ return ContainerLayout.SB->NumBlocks;
+}
+
+uint32_t PDBFile::getNumDirectoryBytes() const {
+ return ContainerLayout.SB->NumDirectoryBytes;
+}
+
+uint32_t PDBFile::getBlockMapIndex() const {
+ return ContainerLayout.SB->BlockMapAddr;
+}
+
+uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
+
+uint32_t PDBFile::getNumDirectoryBlocks() const {
+ return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
+ ContainerLayout.SB->BlockSize);
+}
+
+uint64_t PDBFile::getBlockMapOffset() const {
+ return (uint64_t)ContainerLayout.SB->BlockMapAddr *
+ ContainerLayout.SB->BlockSize;
+}
+
+uint32_t PDBFile::getNumStreams() const {
+ return ContainerLayout.StreamSizes.size();
+}
+
+uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
+ return ContainerLayout.StreamSizes[StreamIndex];
+}
+
+ArrayRef<support::ulittle32_t>
+PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
+ return ContainerLayout.StreamMap[StreamIndex];
+}
+
+uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); }
+
+Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
+ uint32_t NumBytes) const {
+ uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
+
+ ArrayRef<uint8_t> Result;
+ if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
+ return std::move(EC);
+ return Result;
+}
+
+Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
+ ArrayRef<uint8_t> Data) const {
+ return make_error<RawError>(raw_error_code::not_writable,
+ "PDBFile is immutable");
+}
+
+Error PDBFile::parseFileHeaders() {
+ StreamReader Reader(*Buffer);
+
+ // Initialize SB.
+ const msf::SuperBlock *SB = nullptr;
+ if (auto EC = Reader.readObject(SB)) {
+ consumeError(std::move(EC));
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Does not contain superblock");
+ }
+
+ if (auto EC = msf::validateSuperBlock(*SB))
+ return EC;
+
+ if (Buffer->getLength() % SB->BlockSize != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "File size is not a multiple of block size");
+ ContainerLayout.SB = SB;
+
+ // Initialize Free Page Map.
+ ContainerLayout.FreePageMap.resize(SB->NumBlocks);
+ // The Fpm exists either at block 1 or block 2 of the MSF. However, this
+ // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
+ // thusly an equal number of total blocks in the file. For a block size
+ // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
+ // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
+ // the Fpm is split across the file at `getBlockSize()` intervals. As a
+ // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
+ // for any non-negative integer k is an Fpm block. In theory, we only really
+ // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
+ // current versions of the MSF format already expect the Fpm to be arranged
+ // at getBlockSize() intervals, so we have to be compatible.
+ // See the function fpmPn() for more information:
+ // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
+ auto FpmStream = MappedBlockStream::createFpmStream(ContainerLayout, *Buffer);
+ StreamReader FpmReader(*FpmStream);
+ ArrayRef<uint8_t> FpmBytes;
+ if (auto EC = FpmReader.readBytes(FpmBytes,
+ msf::getFullFpmByteSize(ContainerLayout)))
+ return EC;
+ uint32_t BlocksRemaining = getBlockCount();
+ uint32_t BI = 0;
+ for (auto Byte : FpmBytes) {
+ uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
+ for (uint32_t I = 0; I < BlocksThisByte; ++I) {
+ if (Byte & (1 << I))
+ ContainerLayout.FreePageMap[BI] = true;
+ --BlocksRemaining;
+ ++BI;
+ }
+ }
+
+ Reader.setOffset(getBlockMapOffset());
+ if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
+ getNumDirectoryBlocks()))
+ return EC;
+
+ return Error::success();
+}
+
+Error PDBFile::parseStreamData() {
+ assert(ContainerLayout.SB);
+ if (DirectoryStream)
+ return Error::success();
+
+ uint32_t NumStreams = 0;
+
+ // Normally you can't use a MappedBlockStream without having fully parsed the
+ // PDB file, because it accesses the directory and various other things, which
+ // is exactly what we are attempting to parse. By specifying a custom
+ // subclass of IPDBStreamData which only accesses the fields that have already
+ // been parsed, we can avoid this and reuse MappedBlockStream.
+ auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer);
+ StreamReader Reader(*DS);
+ if (auto EC = Reader.readInteger(NumStreams))
+ return EC;
+
+ if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
+ return EC;
+ for (uint32_t I = 0; I < NumStreams; ++I) {
+ uint32_t StreamSize = getStreamByteSize(I);
+ // FIXME: What does StreamSize ~0U mean?
+ uint64_t NumExpectedStreamBlocks =
+ StreamSize == UINT32_MAX
+ ? 0
+ : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
+
+ // For convenience, we store the block array contiguously. This is because
+ // if someone calls setStreamMap(), it is more convenient to be able to call
+ // it with an ArrayRef instead of setting up a StreamRef. Since the
+ // DirectoryStream is cached in the class and thus lives for the life of the
+ // class, we can be guaranteed that readArray() will return a stable
+ // reference, even if it has to allocate from its internal pool.
+ ArrayRef<support::ulittle32_t> Blocks;
+ if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
+ return EC;
+ for (uint32_t Block : Blocks) {
+ uint64_t BlockEndOffset =
+ (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
+ if (BlockEndOffset > getFileSize())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Stream block map is corrupt.");
+ }
+ ContainerLayout.StreamMap.push_back(Blocks);
+ }
+
+ // We should have read exactly SB->NumDirectoryBytes bytes.
+ assert(Reader.bytesRemaining() == 0);
+ DirectoryStream = std::move(DS);
+ return Error::success();
+}
+
+ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
+ return ContainerLayout.DirectoryBlocks;
+}
+
+Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
+ if (!Globals) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto GlobalS = safelyCreateIndexedStream(
+ ContainerLayout, *Buffer, DbiS->getGlobalSymbolStreamIndex());
+ if (!GlobalS)
+ return GlobalS.takeError();
+ auto TempGlobals = llvm::make_unique<GlobalsStream>(std::move(*GlobalS));
+ if (auto EC = TempGlobals->reload())
+ return std::move(EC);
+ Globals = std::move(TempGlobals);
+ }
+ return *Globals;
+}
+
+Expected<InfoStream &> PDBFile::getPDBInfoStream() {
+ if (!Info) {
+ auto InfoS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamPDB);
+ if (!InfoS)
+ return InfoS.takeError();
+ auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS));
+ if (auto EC = TempInfo->reload())
+ return std::move(EC);
+ Info = std::move(TempInfo);
+ }
+ return *Info;
+}
+
+Expected<DbiStream &> PDBFile::getPDBDbiStream() {
+ if (!Dbi) {
+ auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
+ if (!DbiS)
+ return DbiS.takeError();
+ auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
+ if (auto EC = TempDbi->reload())
+ return std::move(EC);
+ Dbi = std::move(TempDbi);
+ }
+ return *Dbi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBTpiStream() {
+ if (!Tpi) {
+ auto TpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamTPI);
+ if (!TpiS)
+ return TpiS.takeError();
+ auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS));
+ if (auto EC = TempTpi->reload())
+ return std::move(EC);
+ Tpi = std::move(TempTpi);
+ }
+ return *Tpi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBIpiStream() {
+ if (!Ipi) {
+ auto IpiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamIPI);
+ if (!IpiS)
+ return IpiS.takeError();
+ auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS));
+ if (auto EC = TempIpi->reload())
+ return std::move(EC);
+ Ipi = std::move(TempIpi);
+ }
+ return *Ipi;
+}
+
+Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
+ if (!Publics) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto PublicS = safelyCreateIndexedStream(
+ ContainerLayout, *Buffer, DbiS->getPublicSymbolStreamIndex());
+ if (!PublicS)
+ return PublicS.takeError();
+ auto TempPublics =
+ llvm::make_unique<PublicsStream>(*this, std::move(*PublicS));
+ if (auto EC = TempPublics->reload())
+ return std::move(EC);
+ Publics = std::move(TempPublics);
+ }
+ return *Publics;
+}
+
+Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
+ if (!Symbols) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
+ auto SymbolS =
+ safelyCreateIndexedStream(ContainerLayout, *Buffer, SymbolStreamNum);
+ if (!SymbolS)
+ return SymbolS.takeError();
+
+ auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS));
+ if (auto EC = TempSymbols->reload())
+ return std::move(EC);
+ Symbols = std::move(TempSymbols);
+ }
+ return *Symbols;
+}
+
+Expected<StringTable &> PDBFile::getStringTable() {
+ if (!Strings || !StringTableStream) {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names");
+
+ auto NS =
+ safelyCreateIndexedStream(ContainerLayout, *Buffer, NameStreamIndex);
+ if (!NS)
+ return NS.takeError();
+
+ StreamReader Reader(**NS);
+ auto N = llvm::make_unique<StringTable>();
+ if (auto EC = N->load(Reader))
+ return std::move(EC);
+ Strings = std::move(N);
+ StringTableStream = std::move(*NS);
+ }
+ return *Strings;
+}
+
+bool PDBFile::hasPDBDbiStream() const { return StreamDBI < getNumStreams(); }
+
+bool PDBFile::hasPDBGlobalsStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return false;
+ return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBInfoStream() { return StreamPDB < getNumStreams(); }
+
+bool PDBFile::hasPDBIpiStream() const { return StreamIPI < getNumStreams(); }
+
+bool PDBFile::hasPDBPublicsStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return false;
+ return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBSymbolStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return false;
+ return DbiS->getSymRecordStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
+
+bool PDBFile::hasStringTable() {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return false;
+ return IS->getNamedStreamIndex("/names") < getNumStreams();
+}
+
+/// Wrapper around MappedBlockStream::createIndexedStream()
+/// that checks if a stream with that index actually exists.
+/// If it does not, the return value will have an MSFError with
+/// code msf_error_code::no_stream. Else, the return value will
+/// contain the stream returned by createIndexedStream().
+Expected<std::unique_ptr<MappedBlockStream>>
+PDBFile::safelyCreateIndexedStream(const MSFLayout &Layout,
+ const ReadableStream &MsfData,
+ uint32_t StreamIndex) const {
+ if (StreamIndex >= getNumStreams())
+ return make_error<RawError>(raw_error_code::no_stream);
+ return MappedBlockStream::createIndexedStream(Layout, MsfData, StreamIndex);
+}
OpenPOWER on IntegriCloud