From bac69d33d013a86277cf2acb9809819e1623c732 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Fri, 22 Jul 2016 19:56:05 +0000 Subject: [msf] Create LLVMDebugInfoMsf This provides a better layering of responsibilities among different aspects of PDB writing code. Some of the MSF related code was contained in CodeView, and some was in PDB prior to this. Further, we were often saying PDB when we meant MSF, and the two are actually independent of each other since in theory you can have other types of data besides PDB data in an MSF. So, this patch separates the MSF specific code into its own library, with no dependencies on anything else, and DebugInfoCodeView and DebugInfoPDB take dependencies on DebugInfoMsf. llvm-svn: 276458 --- llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 4 +- llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt | 2 +- llvm/lib/DebugInfo/CMakeLists.txt | 3 +- llvm/lib/DebugInfo/CodeView/ByteStream.cpp | 79 ------ llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 3 - llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp | 1 + llvm/lib/DebugInfo/CodeView/LLVMBuild.txt | 2 +- llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp | 3 +- .../DebugInfo/CodeView/ModuleSubstreamVisitor.cpp | 1 + llvm/lib/DebugInfo/CodeView/StreamReader.cpp | 93 ------ llvm/lib/DebugInfo/CodeView/StreamWriter.cpp | 78 ------ llvm/lib/DebugInfo/CodeView/TypeDumper.cpp | 6 +- llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 1 - llvm/lib/DebugInfo/LLVMBuild.txt | 2 +- llvm/lib/DebugInfo/Msf/ByteStream.cpp | 79 ++++++ llvm/lib/DebugInfo/Msf/CMakeLists.txt | 12 + llvm/lib/DebugInfo/Msf/IndexedStreamData.cpp | 25 ++ llvm/lib/DebugInfo/Msf/LLVMBuild.txt | 22 ++ llvm/lib/DebugInfo/Msf/MappedBlockStream.cpp | 311 +++++++++++++++++++++ llvm/lib/DebugInfo/Msf/MsfBuilder.cpp | 279 ++++++++++++++++++ llvm/lib/DebugInfo/Msf/MsfCommon.cpp | 48 ++++ llvm/lib/DebugInfo/Msf/MsfError.cpp | 70 +++++ llvm/lib/DebugInfo/Msf/StreamReader.cpp | 93 ++++++ llvm/lib/DebugInfo/Msf/StreamWriter.cpp | 78 ++++++ llvm/lib/DebugInfo/PDB/CMakeLists.txt | 4 - llvm/lib/DebugInfo/PDB/LLVMBuild.txt | 2 +- llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp | 20 +- llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp | 5 +- llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp | 25 -- llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp | 9 +- llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp | 5 +- llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp | 310 -------------------- llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp | 7 +- llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp | 11 +- llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp | 279 ------------------ llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp | 48 ---- llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp | 10 +- llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp | 10 +- llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp | 19 +- llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp | 9 +- llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp | 9 +- llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp | 7 +- llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp | 9 +- llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp | 7 +- 44 files changed, 1108 insertions(+), 992 deletions(-) delete mode 100644 llvm/lib/DebugInfo/CodeView/ByteStream.cpp delete mode 100644 llvm/lib/DebugInfo/CodeView/StreamReader.cpp delete mode 100644 llvm/lib/DebugInfo/CodeView/StreamWriter.cpp create mode 100644 llvm/lib/DebugInfo/Msf/ByteStream.cpp create mode 100644 llvm/lib/DebugInfo/Msf/CMakeLists.txt create mode 100644 llvm/lib/DebugInfo/Msf/IndexedStreamData.cpp create mode 100644 llvm/lib/DebugInfo/Msf/LLVMBuild.txt create mode 100644 llvm/lib/DebugInfo/Msf/MappedBlockStream.cpp create mode 100644 llvm/lib/DebugInfo/Msf/MsfBuilder.cpp create mode 100644 llvm/lib/DebugInfo/Msf/MsfCommon.cpp create mode 100644 llvm/lib/DebugInfo/Msf/MsfError.cpp create mode 100644 llvm/lib/DebugInfo/Msf/StreamReader.cpp create mode 100644 llvm/lib/DebugInfo/Msf/StreamWriter.cpp delete mode 100644 llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp delete mode 100644 llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp delete mode 100644 llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp delete mode 100644 llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp (limited to 'llvm/lib') diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index b0ba5712220..10c76e793bd 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -13,7 +13,6 @@ #include "CodeViewDebug.h" #include "llvm/ADT/TinyPtrVector.h" -#include "llvm/DebugInfo/CodeView/ByteStream.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" @@ -23,6 +22,8 @@ #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" +#include "llvm/DebugInfo/Msf/ByteStream.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/IR/Constants.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCSectionCOFF.h" @@ -35,6 +36,7 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; CodeViewDebug::CodeViewDebug(AsmPrinter *AP) : DebugHandlerBase(AP), OS(*Asm->OutStreamer), CurFn(nullptr) { diff --git a/llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt b/llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt index e741a1a4c4e..3b240f21fc0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt +++ b/llvm/lib/CodeGen/AsmPrinter/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = AsmPrinter parent = Libraries -required_libraries = Analysis CodeGen Core DebugInfoCodeView MC MCParser Support Target TransformUtils +required_libraries = Analysis CodeGen Core DebugInfoCodeView DebugInfoMsf MC MCParser Support Target TransformUtils diff --git a/llvm/lib/DebugInfo/CMakeLists.txt b/llvm/lib/DebugInfo/CMakeLists.txt index 2c2848d1e5c..944dfb67cbe 100644 --- a/llvm/lib/DebugInfo/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CMakeLists.txt @@ -1,4 +1,5 @@ -add_subdirectory(CodeView) add_subdirectory(DWARF) +add_subdirectory(Msf) +add_subdirectory(CodeView) add_subdirectory(PDB) add_subdirectory(Symbolize) diff --git a/llvm/lib/DebugInfo/CodeView/ByteStream.cpp b/llvm/lib/DebugInfo/CodeView/ByteStream.cpp deleted file mode 100644 index 2c43bc6958d..00000000000 --- a/llvm/lib/DebugInfo/CodeView/ByteStream.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===- ByteStream.cpp - Reads stream data from a byte sequence ------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/ByteStream.h" -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include - -using namespace llvm; -using namespace llvm::codeview; - -static Error writeBytes(uint32_t Offset, ArrayRef Src, - ArrayRef Dest) { - return make_error(cv_error_code::operation_unsupported, - "ByteStream is immutable."); -} - -static Error writeBytes(uint32_t Offset, ArrayRef Src, - MutableArrayRef Dest) { - if (Dest.size() < Src.size()) - return make_error(cv_error_code::insufficient_buffer); - if (Offset > Src.size() - Dest.size()) - return make_error(cv_error_code::insufficient_buffer); - - ::memcpy(Dest.data() + Offset, Src.data(), Src.size()); - return Error::success(); -} - -template -Error ByteStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - if (Offset > Data.size()) - return make_error(cv_error_code::insufficient_buffer); - if (Data.size() < Size + Offset) - return make_error(cv_error_code::insufficient_buffer); - Buffer = Data.slice(Offset, Size); - return Error::success(); -} - -template -Error ByteStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef &Buffer) const { - if (Offset >= Data.size()) - return make_error(cv_error_code::insufficient_buffer); - Buffer = Data.slice(Offset); - return Error::success(); -} - -template -Error ByteStream::writeBytes(uint32_t Offset, - ArrayRef Buffer) const { - return ::writeBytes(Offset, Buffer, Data); -} - -template uint32_t ByteStream::getLength() const { - return Data.size(); -} - -template Error ByteStream::commit() const { - return Error::success(); -} - -template StringRef ByteStream::str() const { - const char *CharData = reinterpret_cast(Data.data()); - return StringRef(CharData, Data.size()); -} - -namespace llvm { -namespace codeview { -template class ByteStream; -template class ByteStream; -} -} diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 47297a9131e..d8c21953967 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -1,5 +1,4 @@ add_llvm_library(LLVMDebugInfoCodeView - ByteStream.cpp CodeViewError.cpp CVTypeVisitor.cpp EnumTables.cpp @@ -11,8 +10,6 @@ add_llvm_library(LLVMDebugInfoCodeView ModuleSubstream.cpp ModuleSubstreamVisitor.cpp RecordSerialization.cpp - StreamReader.cpp - StreamWriter.cpp SymbolDumper.cpp TypeDumper.cpp TypeRecord.cpp diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index 09f72214c52..f1f9acf570d 100644 --- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" +#include "llvm/DebugInfo/CodeView/CodeViewError.h" using namespace llvm; using namespace llvm::codeview; diff --git a/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt b/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt index 4db23376fce..c1e35abf150 100644 --- a/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt +++ b/llvm/lib/DebugInfo/CodeView/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Library name = DebugInfoCodeView parent = DebugInfo -required_libraries = Support +required_libraries = Support DebugInfoMsf diff --git a/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp b/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp index 2e31ed6b5b7..5ab8212d3bd 100644 --- a/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp +++ b/llvm/lib/DebugInfo/CodeView/ModuleSubstream.cpp @@ -9,10 +9,11 @@ #include "llvm/DebugInfo/CodeView/ModuleSubstream.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; ModuleSubstream::ModuleSubstream() : Kind(ModuleSubstreamKind::None) {} diff --git a/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp b/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp index 6f237ee67fe..e4fe8d8053a 100644 --- a/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/ModuleSubstreamVisitor.cpp @@ -11,6 +11,7 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; Error IModuleSubstreamVisitor::visitSymbols(StreamRef Data) { return visitUnknown(ModuleSubstreamKind::Symbols, Data); diff --git a/llvm/lib/DebugInfo/CodeView/StreamReader.cpp b/llvm/lib/DebugInfo/CodeView/StreamReader.cpp deleted file mode 100644 index 64e45487322..00000000000 --- a/llvm/lib/DebugInfo/CodeView/StreamReader.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/StreamReader.h" - -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" - -using namespace llvm; -using namespace llvm::codeview; - -StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {} - -Error StreamReader::readLongestContiguousChunk(ArrayRef &Buffer) { - if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamReader::readBytes(ArrayRef &Buffer, uint32_t Size) { - if (auto EC = Stream.readBytes(Offset, Size, Buffer)) - return EC; - Offset += Size; - return Error::success(); -} - -Error StreamReader::readInteger(uint16_t &Dest) { - const support::ulittle16_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readInteger(uint32_t &Dest) { - const support::ulittle32_t *P; - if (auto EC = readObject(P)) - return EC; - Dest = *P; - return Error::success(); -} - -Error StreamReader::readZeroString(StringRef &Dest) { - uint32_t Length = 0; - // First compute the length of the string by reading 1 byte at a time. - uint32_t OriginalOffset = getOffset(); - const char *C; - do { - if (auto EC = readObject(C)) - return EC; - if (*C != '\0') - ++Length; - } while (*C != '\0'); - // Now go back and request a reference for that many bytes. - uint32_t NewOffset = getOffset(); - setOffset(OriginalOffset); - - ArrayRef Data; - if (auto EC = readBytes(Data, Length)) - return EC; - Dest = StringRef(reinterpret_cast(Data.begin()), Data.size()); - - // Now set the offset back to where it was after we calculated the length. - setOffset(NewOffset); - return Error::success(); -} - -Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) { - ArrayRef Bytes; - if (auto EC = readBytes(Bytes, Length)) - return EC; - Dest = StringRef(reinterpret_cast(Bytes.begin()), Bytes.size()); - return Error::success(); -} - -Error StreamReader::readStreamRef(StreamRef &Ref) { - return readStreamRef(Ref, bytesRemaining()); -} - -Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) { - if (bytesRemaining() < Length) - return make_error(cv_error_code::insufficient_buffer); - Ref = Stream.slice(Offset, Length); - Offset += Length; - return Error::success(); -} diff --git a/llvm/lib/DebugInfo/CodeView/StreamWriter.cpp b/llvm/lib/DebugInfo/CodeView/StreamWriter.cpp deleted file mode 100644 index 90eafbb9c83..00000000000 --- a/llvm/lib/DebugInfo/CodeView/StreamWriter.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/DebugInfo/CodeView/StreamWriter.h" - -#include "llvm/DebugInfo/CodeView/CodeViewError.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" - -using namespace llvm; -using namespace llvm::codeview; - -StreamWriter::StreamWriter(StreamRef S) : Stream(S), Offset(0) {} - -Error StreamWriter::writeBytes(ArrayRef Buffer) { - if (auto EC = Stream.writeBytes(Offset, Buffer)) - return EC; - Offset += Buffer.size(); - return Error::success(); -} - -Error StreamWriter::writeInteger(uint16_t Int) { - return writeObject(support::ulittle16_t(Int)); -} - -Error StreamWriter::writeInteger(uint32_t Int) { - return writeObject(support::ulittle32_t(Int)); -} - -Error StreamWriter::writeZeroString(StringRef Str) { - if (auto EC = writeFixedString(Str)) - return EC; - if (auto EC = writeObject('\0')) - return EC; - - return Error::success(); -} - -Error StreamWriter::writeFixedString(StringRef Str) { - ArrayRef Bytes(Str.bytes_begin(), Str.bytes_end()); - if (auto EC = Stream.writeBytes(Offset, Bytes)) - return EC; - - Offset += Str.size(); - return Error::success(); -} - -Error StreamWriter::writeStreamRef(StreamRef Ref) { - if (auto EC = writeStreamRef(Ref, Ref.getLength())) - return EC; - // Don't increment Offset here, it is done by the overloaded call to - // writeStreamRef. - return Error::success(); -} - -Error StreamWriter::writeStreamRef(StreamRef Ref, uint32_t Length) { - Ref = Ref.slice(0, Length); - - StreamReader SrcReader(Ref); - // This is a bit tricky. If we just call readBytes, we are requiring that it - // return us the entire stream as a contiguous buffer. For large streams this - // will allocate a huge amount of space from the pool. Instead, iterate over - // each contiguous chunk until we've consumed the entire stream. - while (SrcReader.bytesRemaining() > 0) { - ArrayRef Chunk; - if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) - return EC; - if (auto EC = writeBytes(Chunk)) - return EC; - } - return Error::success(); -} diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index 345e2a49888..cf5adb6b75e 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -12,7 +12,7 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/CodeView/ByteStream.h" +#include "llvm/DebugInfo/Msf/ByteStream.h" #include "llvm/Support/ScopedPrinter.h" using namespace llvm; @@ -681,9 +681,9 @@ Error CVTypeDumper::dump(const CVTypeArray &Types) { } Error CVTypeDumper::dump(ArrayRef Data) { - ByteStream<> Stream(Data); + msf::ByteStream<> Stream(Data); CVTypeArray Types; - StreamReader Reader(Stream); + msf::StreamReader Reader(Stream); if (auto EC = Reader.readArray(Types, Reader.getLength())) return EC; diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index ebfda2462be..8c2bc072cd9 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -12,7 +12,6 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamRef.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" diff --git a/llvm/lib/DebugInfo/LLVMBuild.txt b/llvm/lib/DebugInfo/LLVMBuild.txt index 23a5a3db562..876c43a5749 100644 --- a/llvm/lib/DebugInfo/LLVMBuild.txt +++ b/llvm/lib/DebugInfo/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = CodeView DWARF PDB Symbolize +subdirectories = DWARF Msf CodeView PDB Symbolize [component_0] type = Group diff --git a/llvm/lib/DebugInfo/Msf/ByteStream.cpp b/llvm/lib/DebugInfo/Msf/ByteStream.cpp new file mode 100644 index 00000000000..32fcbccaacc --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/ByteStream.cpp @@ -0,0 +1,79 @@ +//===- ByteStream.cpp - Reads stream data from a byte sequence ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Msf/ByteStream.h" +#include "llvm/DebugInfo/Msf/MsfError.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include + +using namespace llvm; +using namespace llvm::msf; + +static Error writeBytes(uint32_t Offset, ArrayRef Src, + ArrayRef Dest) { + return make_error(msf_error_code::not_writable, + "ByteStream is immutable."); +} + +static Error writeBytes(uint32_t Offset, ArrayRef Src, + MutableArrayRef Dest) { + if (Dest.size() < Src.size()) + return make_error(msf_error_code::insufficient_buffer); + if (Offset > Src.size() - Dest.size()) + return make_error(msf_error_code::insufficient_buffer); + + ::memcpy(Dest.data() + Offset, Src.data(), Src.size()); + return Error::success(); +} + +template +Error ByteStream::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + if (Offset > Data.size()) + return make_error(msf_error_code::insufficient_buffer); + if (Data.size() < Size + Offset) + return make_error(msf_error_code::insufficient_buffer); + Buffer = Data.slice(Offset, Size); + return Error::success(); +} + +template +Error ByteStream::readLongestContiguousChunk( + uint32_t Offset, ArrayRef &Buffer) const { + if (Offset >= Data.size()) + return make_error(msf_error_code::insufficient_buffer); + Buffer = Data.slice(Offset); + return Error::success(); +} + +template +Error ByteStream::writeBytes(uint32_t Offset, + ArrayRef Buffer) const { + return ::writeBytes(Offset, Buffer, Data); +} + +template uint32_t ByteStream::getLength() const { + return Data.size(); +} + +template Error ByteStream::commit() const { + return Error::success(); +} + +template StringRef ByteStream::str() const { + const char *CharData = reinterpret_cast(Data.data()); + return StringRef(CharData, Data.size()); +} + +namespace llvm { +namespace msf { +template class ByteStream; +template class ByteStream; +} +} diff --git a/llvm/lib/DebugInfo/Msf/CMakeLists.txt b/llvm/lib/DebugInfo/Msf/CMakeLists.txt new file mode 100644 index 00000000000..49a71a8409c --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/CMakeLists.txt @@ -0,0 +1,12 @@ +add_llvm_library(LLVMDebugInfoMsf + ByteStream.cpp + IndexedStreamData.cpp + MappedBlockStream.cpp + MsfBuilder.cpp + MsfCommon.cpp + MsfError.cpp + StreamReader.cpp + StreamWriter.cpp + ADDITIONAL_HEADER_DIRS + "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/MSF" + ) diff --git a/llvm/lib/DebugInfo/Msf/IndexedStreamData.cpp b/llvm/lib/DebugInfo/Msf/IndexedStreamData.cpp new file mode 100644 index 00000000000..81303aeb8f4 --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/IndexedStreamData.cpp @@ -0,0 +1,25 @@ +//===- IndexedStreamData.cpp - Standard PDB Stream Data ---------*- 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/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/IMsfFile.h" + +using namespace llvm; +using namespace llvm::msf; + +IndexedStreamData::IndexedStreamData(uint32_t StreamIdx, const IMsfFile &File) + : StreamIdx(StreamIdx), File(File) {} + +uint32_t IndexedStreamData::getLength() { + return File.getStreamByteSize(StreamIdx); +} + +ArrayRef IndexedStreamData::getStreamBlocks() { + return File.getStreamBlockList(StreamIdx); +} diff --git a/llvm/lib/DebugInfo/Msf/LLVMBuild.txt b/llvm/lib/DebugInfo/Msf/LLVMBuild.txt new file mode 100644 index 00000000000..4598c437a93 --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/DebugInfo/Msf/LLVMBuild.txt -------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Library +name = DebugInfoMsf +parent = DebugInfo +required_libraries = Support diff --git a/llvm/lib/DebugInfo/Msf/MappedBlockStream.cpp b/llvm/lib/DebugInfo/Msf/MappedBlockStream.cpp new file mode 100644 index 00000000000..f2c80122169 --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/MappedBlockStream.cpp @@ -0,0 +1,311 @@ +//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/DirectoryStreamData.h" +#include "llvm/DebugInfo/Msf/IMsfStreamData.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/MsfError.h" + +using namespace llvm; +using namespace llvm::msf; + +namespace { +// This exists so that we can use make_unique (which requires a public default +// constructor, while still keeping the constructor of MappedBlockStream +// protected, forcing users to go through the `create` interface. +class MappedBlockStreamImpl : public MappedBlockStream { +public: + MappedBlockStreamImpl(std::unique_ptr Data, + const IMsfFile &File) + : MappedBlockStream(std::move(Data), File) {} +}; +} + +typedef std::pair Interval; +static Interval intersect(const Interval &I1, const Interval &I2) { + return std::make_pair(std::max(I1.first, I2.first), + std::min(I1.second, I2.second)); +} + +MappedBlockStream::MappedBlockStream(std::unique_ptr Data, + const IMsfFile &File) + : Msf(File), Data(std::move(Data)) {} + +Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + // Make sure we aren't trying to read beyond the end of the stream. + if (Size > Data->getLength()) + return make_error(msf_error_code::insufficient_buffer); + if (Offset > Data->getLength() - Size) + return make_error(msf_error_code::insufficient_buffer); + + if (tryReadContiguously(Offset, Size, Buffer)) + return Error::success(); + + auto CacheIter = CacheMap.find(Offset); + if (CacheIter != CacheMap.end()) { + // Try to find an alloc that was large enough for this request. + for (auto &Entry : CacheIter->second) { + if (Entry.size() >= Size) { + Buffer = Entry.slice(0, Size); + return Error::success(); + } + } + } + + // We couldn't find a buffer that started at the correct offset (the most + // common scenario). Try to see if there is a buffer that starts at some + // other offset but overlaps the desired range. + for (auto &CacheItem : CacheMap) { + Interval RequestExtent = std::make_pair(Offset, Offset + Size); + + // We already checked this one on the fast path above. + if (CacheItem.first == Offset) + continue; + // If the initial extent of the cached item is beyond the ending extent + // of the request, there is no overlap. + if (CacheItem.first >= Offset + Size) + continue; + + // We really only have to check the last item in the list, since we append + // in order of increasing length. + if (CacheItem.second.empty()) + continue; + + auto CachedAlloc = CacheItem.second.back(); + // If the initial extent of the request is beyond the ending extent of + // the cached item, there is no overlap. + Interval CachedExtent = + std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); + if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) + continue; + + Interval Intersection = intersect(CachedExtent, RequestExtent); + // Only use this if the entire request extent is contained in the cached + // extent. + if (Intersection != RequestExtent) + continue; + + uint32_t CacheRangeOffset = + AbsoluteDifference(CachedExtent.first, Intersection.first); + Buffer = CachedAlloc.slice(CacheRangeOffset, Size); + return Error::success(); + } + + // Otherwise allocate a large enough buffer in the pool, memcpy the data + // into it, and return an ArrayRef to that. Do not touch existing pool + // allocations, as existing clients may be holding a pointer which must + // not be invalidated. + uint8_t *WriteBuffer = static_cast(Pool.Allocate(Size, 8)); + if (auto EC = readBytes(Offset, MutableArrayRef(WriteBuffer, Size))) + return EC; + + if (CacheIter != CacheMap.end()) { + CacheIter->second.emplace_back(WriteBuffer, Size); + } else { + std::vector List; + List.emplace_back(WriteBuffer, Size); + CacheMap.insert(std::make_pair(Offset, List)); + } + Buffer = ArrayRef(WriteBuffer, Size); + return Error::success(); +} + +Error MappedBlockStream::readLongestContiguousChunk( + uint32_t Offset, ArrayRef &Buffer) const { + // Make sure we aren't trying to read beyond the end of the stream. + if (Offset >= Data->getLength()) + return make_error(msf_error_code::insufficient_buffer); + uint32_t First = Offset / Msf.getBlockSize(); + uint32_t Last = First; + + auto BlockList = Data->getStreamBlocks(); + while (Last < Msf.getBlockCount() - 1) { + if (BlockList[Last] != BlockList[Last + 1] - 1) + break; + ++Last; + } + + uint32_t OffsetInFirstBlock = Offset % Msf.getBlockSize(); + uint32_t BytesFromFirstBlock = Msf.getBlockSize() - OffsetInFirstBlock; + uint32_t BlockSpan = Last - First + 1; + uint32_t ByteSpan = + BytesFromFirstBlock + (BlockSpan - 1) * Msf.getBlockSize(); + auto Result = Msf.getBlockData(BlockList[First], Msf.getBlockSize()); + if (!Result) + return Result.takeError(); + Buffer = Result->drop_front(OffsetInFirstBlock); + Buffer = ArrayRef(Buffer.data(), ByteSpan); + return Error::success(); +} + +uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } + +Error MappedBlockStream::commit() const { return Error::success(); } + +bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, + ArrayRef &Buffer) const { + // Attempt to fulfill the request with a reference directly into the stream. + // This can work even if the request crosses a block boundary, provided that + // all subsequent blocks are contiguous. For example, a 10k read with a 4k + // block size can be filled with a reference if, from the starting offset, + // 3 blocks in a row are contiguous. + uint32_t BlockNum = Offset / Msf.getBlockSize(); + uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); + uint32_t BytesFromFirstBlock = + std::min(Size, Msf.getBlockSize() - OffsetInBlock); + uint32_t NumAdditionalBlocks = + llvm::alignTo(Size - BytesFromFirstBlock, Msf.getBlockSize()) / + Msf.getBlockSize(); + + auto BlockList = Data->getStreamBlocks(); + uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; + uint32_t E = BlockList[BlockNum]; + for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { + if (BlockList[I + BlockNum] != E) + return false; + } + + uint32_t FirstBlockAddr = BlockList[BlockNum]; + auto Result = Msf.getBlockData(FirstBlockAddr, Msf.getBlockSize()); + if (!Result) { + consumeError(Result.takeError()); + return false; + } + auto Data = Result->drop_front(OffsetInBlock); + Buffer = ArrayRef(Data.data(), Size); + return true; +} + +Error MappedBlockStream::readBytes(uint32_t Offset, + MutableArrayRef Buffer) const { + uint32_t BlockNum = Offset / Msf.getBlockSize(); + uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); + + // Make sure we aren't trying to read beyond the end of the stream. + if (Buffer.size() > Data->getLength()) + return make_error(msf_error_code::insufficient_buffer); + if (Offset > Data->getLength() - Buffer.size()) + return make_error(msf_error_code::insufficient_buffer); + + uint32_t BytesLeft = Buffer.size(); + uint32_t BytesWritten = 0; + uint8_t *WriteBuffer = Buffer.data(); + auto BlockList = Data->getStreamBlocks(); + while (BytesLeft > 0) { + uint32_t StreamBlockAddr = BlockList[BlockNum]; + + auto Result = Msf.getBlockData(StreamBlockAddr, Msf.getBlockSize()); + if (!Result) + return Result.takeError(); + + auto Data = *Result; + const uint8_t *ChunkStart = Data.data() + OffsetInBlock; + uint32_t BytesInChunk = + std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); + ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); + + BytesWritten += BytesInChunk; + BytesLeft -= BytesInChunk; + ++BlockNum; + OffsetInBlock = 0; + } + + return Error::success(); +} + +Error MappedBlockStream::writeBytes(uint32_t Offset, + ArrayRef Buffer) const { + // Make sure we aren't trying to write beyond the end of the stream. + if (Buffer.size() > Data->getLength()) + return make_error(msf_error_code::insufficient_buffer); + + if (Offset > Data->getLength() - Buffer.size()) + return make_error(msf_error_code::insufficient_buffer); + + uint32_t BlockNum = Offset / Msf.getBlockSize(); + uint32_t OffsetInBlock = Offset % Msf.getBlockSize(); + + uint32_t BytesLeft = Buffer.size(); + auto BlockList = Data->getStreamBlocks(); + uint32_t BytesWritten = 0; + while (BytesLeft > 0) { + uint32_t StreamBlockAddr = BlockList[BlockNum]; + uint32_t BytesToWriteInChunk = + std::min(BytesLeft, Msf.getBlockSize() - OffsetInBlock); + + const uint8_t *Chunk = Buffer.data() + BytesWritten; + ArrayRef ChunkData(Chunk, BytesToWriteInChunk); + if (auto EC = Msf.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData)) + return EC; + + BytesLeft -= BytesToWriteInChunk; + BytesWritten += BytesToWriteInChunk; + ++BlockNum; + OffsetInBlock = 0; + } + + // If this write overlapped a read which previously came from the pool, + // someone may still be holding a pointer to that alloc which is now invalid. + // Compute the overlapping range and update the cache entry, so any + // outstanding buffers are automatically updated. + for (const auto &MapEntry : CacheMap) { + // If the end of the written extent precedes the beginning of the cached + // extent, ignore this map entry. + if (Offset + BytesWritten < MapEntry.first) + continue; + for (const auto &Alloc : MapEntry.second) { + // If the end of the cached extent precedes the beginning of the written + // extent, ignore this alloc. + if (MapEntry.first + Alloc.size() < Offset) + continue; + + // If we get here, they are guaranteed to overlap. + Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten); + Interval CachedInterval = + std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); + // If they overlap, we need to write the new data into the overlapping + // range. + auto Intersection = intersect(WriteInterval, CachedInterval); + assert(Intersection.first <= Intersection.second); + + uint32_t Length = Intersection.second - Intersection.first; + uint32_t SrcOffset = + AbsoluteDifference(WriteInterval.first, Intersection.first); + uint32_t DestOffset = + AbsoluteDifference(CachedInterval.first, Intersection.first); + ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length); + } + } + + return Error::success(); +} + +uint32_t MappedBlockStream::getNumBytesCopied() const { + return static_cast(Pool.getBytesAllocated()); +} + +Expected> +MappedBlockStream::createIndexedStream(uint32_t StreamIdx, + const IMsfFile &File) { + if (StreamIdx >= File.getNumStreams()) + return make_error(msf_error_code::no_stream); + + auto Data = llvm::make_unique(StreamIdx, File); + return llvm::make_unique(std::move(Data), File); +} + +Expected> +MappedBlockStream::createDirectoryStream(uint32_t Length, + ArrayRef Blocks, + const IMsfFile &File) { + auto Data = llvm::make_unique(Length, Blocks); + return llvm::make_unique(std::move(Data), File); +} diff --git a/llvm/lib/DebugInfo/Msf/MsfBuilder.cpp b/llvm/lib/DebugInfo/Msf/MsfBuilder.cpp new file mode 100644 index 00000000000..e6f15d8877e --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/MsfBuilder.cpp @@ -0,0 +1,279 @@ +//===- MSFBuilder.cpp - MSF Directory & Metadata Builder --------*- 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/Msf/MsfBuilder.h" +#include "llvm/DebugInfo/Msf/MsfError.h" + +using namespace llvm; +using namespace llvm::msf; +using namespace llvm::support; + +namespace { +const uint32_t kSuperBlockBlock = 0; +const uint32_t kFreePageMap0Block = 1; +const uint32_t kFreePageMap1Block = 2; +const uint32_t kNumReservedPages = 3; + +const uint32_t kDefaultBlockMapAddr = kNumReservedPages; +} + +MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, + BumpPtrAllocator &Allocator) + : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize), + MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr), + FreeBlocks(MinBlockCount, true) { + FreeBlocks[kSuperBlockBlock] = false; + FreeBlocks[kFreePageMap0Block] = false; + FreeBlocks[kFreePageMap1Block] = false; + FreeBlocks[BlockMapAddr] = false; +} + +Expected MsfBuilder::create(BumpPtrAllocator &Allocator, + uint32_t BlockSize, + uint32_t MinBlockCount, bool CanGrow) { + if (!isValidBlockSize(BlockSize)) + return make_error(msf_error_code::invalid_format, + "The requested block size is unsupported"); + + return MsfBuilder(BlockSize, + std::max(MinBlockCount, msf::getMinimumBlockCount()), + CanGrow, Allocator); +} + +Error MsfBuilder::setBlockMapAddr(uint32_t Addr) { + if (Addr == BlockMapAddr) + return Error::success(); + + if (Addr >= FreeBlocks.size()) { + if (!IsGrowable) + return make_error(msf_error_code::insufficient_buffer, + "Cannot grow the number of blocks"); + FreeBlocks.resize(Addr + 1); + } + + if (!isBlockFree(Addr)) + return make_error( + msf_error_code::block_in_use, + "Requested block map address is already in use"); + FreeBlocks[BlockMapAddr] = true; + FreeBlocks[Addr] = false; + BlockMapAddr = Addr; + return Error::success(); +} + +void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; } + +void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } + +Error MsfBuilder::setDirectoryBlocksHint(ArrayRef DirBlocks) { + for (auto B : DirectoryBlocks) + FreeBlocks[B] = true; + for (auto B : DirBlocks) { + if (!isBlockFree(B)) { + return make_error(msf_error_code::unspecified, + "Attempt to reuse an allocated block"); + } + FreeBlocks[B] = false; + } + + DirectoryBlocks = DirBlocks; + return Error::success(); +} + +Error MsfBuilder::allocateBlocks(uint32_t NumBlocks, + MutableArrayRef Blocks) { + if (NumBlocks == 0) + return Error::success(); + + uint32_t NumFreeBlocks = FreeBlocks.count(); + if (NumFreeBlocks < NumBlocks) { + if (!IsGrowable) + return make_error(msf_error_code::insufficient_buffer, + "There are no free Blocks in the file"); + uint32_t AllocBlocks = NumBlocks - NumFreeBlocks; + FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true); + } + + int I = 0; + int Block = FreeBlocks.find_first(); + do { + assert(Block != -1 && "We ran out of Blocks!"); + + uint32_t NextBlock = static_cast(Block); + Blocks[I++] = NextBlock; + FreeBlocks.reset(NextBlock); + Block = FreeBlocks.find_next(Block); + } while (--NumBlocks > 0); + return Error::success(); +} + +uint32_t MsfBuilder::getNumUsedBlocks() const { + return getTotalBlockCount() - getNumFreeBlocks(); +} + +uint32_t MsfBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } + +uint32_t MsfBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } + +bool MsfBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } + +Error MsfBuilder::addStream(uint32_t Size, ArrayRef Blocks) { + // Add a new stream mapped to the specified blocks. Verify that the specified + // blocks are both necessary and sufficient for holding the requested number + // of bytes, and verify that all requested blocks are free. + uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); + if (ReqBlocks != Blocks.size()) + return make_error( + msf_error_code::invalid_format, + "Incorrect number of blocks for requested stream size"); + for (auto Block : Blocks) { + if (Block >= FreeBlocks.size()) + FreeBlocks.resize(Block + 1, true); + + if (!FreeBlocks.test(Block)) + return make_error( + msf_error_code::unspecified, + "Attempt to re-use an already allocated block"); + } + // Mark all the blocks occupied by the new stream as not free. + for (auto Block : Blocks) { + FreeBlocks.reset(Block); + } + StreamData.push_back(std::make_pair(Size, Blocks)); + return Error::success(); +} + +Error MsfBuilder::addStream(uint32_t Size) { + uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); + std::vector NewBlocks; + NewBlocks.resize(ReqBlocks); + if (auto EC = allocateBlocks(ReqBlocks, NewBlocks)) + return EC; + StreamData.push_back(std::make_pair(Size, NewBlocks)); + return Error::success(); +} + +Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { + uint32_t OldSize = getStreamSize(Idx); + if (OldSize == Size) + return Error::success(); + + uint32_t NewBlocks = bytesToBlocks(Size, BlockSize); + uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize); + + if (NewBlocks > OldBlocks) { + uint32_t AddedBlocks = NewBlocks - OldBlocks; + // If we're growing, we have to allocate new Blocks. + std::vector AddedBlockList; + AddedBlockList.resize(AddedBlocks); + if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList)) + return EC; + auto &CurrentBlocks = StreamData[Idx].second; + CurrentBlocks.insert(CurrentBlocks.end(), AddedBlockList.begin(), + AddedBlockList.end()); + } else if (OldBlocks > NewBlocks) { + // For shrinking, free all the Blocks in the Block map, update the stream + // data, then shrink the directory. + uint32_t RemovedBlocks = OldBlocks - NewBlocks; + auto CurrentBlocks = ArrayRef(StreamData[Idx].second); + auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks); + for (auto P : RemovedBlockList) + FreeBlocks[P] = true; + StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks); + } + + StreamData[Idx].first = Size; + return Error::success(); +} + +uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); } + +uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const { + return StreamData[StreamIdx].first; +} + +ArrayRef MsfBuilder::getStreamBlocks(uint32_t StreamIdx) const { + return StreamData[StreamIdx].second; +} + +uint32_t MsfBuilder::computeDirectoryByteSize() const { + // The directory has the following layout, where each item is a ulittle32_t: + // NumStreams + // StreamSizes[NumStreams] + // StreamBlocks[NumStreams][] + uint32_t Size = sizeof(ulittle32_t); // NumStreams + Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes + for (const auto &D : StreamData) { + uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize); + assert(ExpectedNumBlocks == D.second.size() && + "Unexpected number of blocks"); + Size += ExpectedNumBlocks * sizeof(ulittle32_t); + } + return Size; +} + +Expected MsfBuilder::build() { + Layout L; + L.SB = Allocator.Allocate(); + std::memcpy(L.SB->MagicBytes, Magic, sizeof(Magic)); + L.SB->BlockMapAddr = BlockMapAddr; + L.SB->BlockSize = BlockSize; + L.SB->NumDirectoryBytes = computeDirectoryByteSize(); + L.SB->FreeBlockMapBlock = FreePageMap; + L.SB->Unknown1 = Unknown1; + + uint32_t NumDirectoryBlocks = + bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize); + if (NumDirectoryBlocks > DirectoryBlocks.size()) { + // Our hint wasn't enough to satisfy the entire directory. Allocate + // remaining pages. + std::vector ExtraBlocks; + uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size(); + ExtraBlocks.resize(NumExtraBlocks); + if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks)) + return std::move(EC); + DirectoryBlocks.insert(DirectoryBlocks.end(), ExtraBlocks.begin(), + ExtraBlocks.end()); + } else if (NumDirectoryBlocks < DirectoryBlocks.size()) { + uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks; + for (auto B : + ArrayRef(DirectoryBlocks).drop_back(NumUnnecessaryBlocks)) + FreeBlocks[B] = true; + DirectoryBlocks.resize(NumDirectoryBlocks); + } + + // Don't set the number of blocks in the file until after allocating Blocks + // for the directory, since the allocation might cause the file to need to + // grow. + L.SB->NumBlocks = FreeBlocks.size(); + + ulittle32_t *DirBlocks = Allocator.Allocate(NumDirectoryBlocks); + std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, + DirBlocks); + L.DirectoryBlocks = ArrayRef(DirBlocks, NumDirectoryBlocks); + + // The stream sizes should be re-allocated as a stable pointer and the stream + // map should have each of its entries allocated as a separate stable pointer. + if (StreamData.size() > 0) { + ulittle32_t *Sizes = Allocator.Allocate(StreamData.size()); + L.StreamSizes = ArrayRef(Sizes, StreamData.size()); + L.StreamMap.resize(StreamData.size()); + for (uint32_t I = 0; I < StreamData.size(); ++I) { + Sizes[I] = StreamData[I].first; + ulittle32_t *BlockList = + Allocator.Allocate(StreamData[I].second.size()); + std::uninitialized_copy_n(StreamData[I].second.begin(), + StreamData[I].second.size(), BlockList); + L.StreamMap[I] = + ArrayRef(BlockList, StreamData[I].second.size()); + } + } + + return L; +} diff --git a/llvm/lib/DebugInfo/Msf/MsfCommon.cpp b/llvm/lib/DebugInfo/Msf/MsfCommon.cpp new file mode 100644 index 00000000000..e22087f705f --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/MsfCommon.cpp @@ -0,0 +1,48 @@ +//===- MsfCommon.cpp - Common types and functions for MSF files -*- 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/Msf/MsfCommon.h" +#include "llvm/DebugInfo/Msf/MsfError.h" + +using namespace llvm; +using namespace llvm::msf; + +Error llvm::msf::validateSuperBlock(const SuperBlock &SB) { + // Check the magic bytes. + if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0) + return make_error(msf_error_code::invalid_format, + "MSF magic header doesn't match"); + + if (!isValidBlockSize(SB.BlockSize)) + return make_error(msf_error_code::invalid_format, + "Unsupported block size."); + + // We don't support directories whose sizes aren't a multiple of four bytes. + if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) + return make_error(msf_error_code::invalid_format, + "Directory size is not multiple of 4."); + + // The number of blocks which comprise the directory is a simple function of + // the number of bytes it contains. + uint64_t NumDirectoryBlocks = + bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize); + + // The directory, as we understand it, is a block which consists of a list of + // block numbers. It is unclear what would happen if the number of blocks + // couldn't fit on a single block. + if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t)) + return make_error(msf_error_code::invalid_format, + "Too many directory blocks."); + + if (SB.BlockMapAddr == 0) + return make_error(msf_error_code::invalid_format, + "Block 0 is reserved"); + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/Msf/MsfError.cpp b/llvm/lib/DebugInfo/Msf/MsfError.cpp new file mode 100644 index 00000000000..246beb9b0de --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/MsfError.cpp @@ -0,0 +1,70 @@ +//===- MsfError.cpp - Error extensions for Msf files ------------*- 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/Msf/MsfError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::msf; + +namespace { +// FIXME: This class is only here to support the transition to llvm::Error. It +// will be removed once this transition is complete. Clients should prefer to +// deal with the Error value directly, rather than converting to error_code. +class MsfErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { return "llvm.msf"; } + + std::string message(int Condition) const override { + switch (static_cast(Condition)) { + case msf_error_code::unspecified: + return "An unknown error has occurred."; + case msf_error_code::insufficient_buffer: + return "The buffer is not large enough to read the requested number of " + "bytes."; + case msf_error_code::not_writable: + return "The specified stream is not writable."; + case msf_error_code::no_stream: + return "The specified stream does not exist."; + case msf_error_code::invalid_format: + return "The data is in an unexpected format."; + case msf_error_code::block_in_use: + return "The block is already in use."; + } + llvm_unreachable("Unrecognized msf_error_code"); + } +}; +} // end anonymous namespace + +static ManagedStatic Category; + +char MsfError::ID = 0; + +MsfError::MsfError(msf_error_code C) : MsfError(C, "") {} + +MsfError::MsfError(const std::string &Context) + : MsfError(msf_error_code::unspecified, Context) {} + +MsfError::MsfError(msf_error_code C, const std::string &Context) : Code(C) { + ErrMsg = "Msf Error: "; + std::error_code EC = convertToErrorCode(); + if (Code != msf_error_code::unspecified) + ErrMsg += EC.message() + " "; + if (!Context.empty()) + ErrMsg += Context; +} + +void MsfError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +const std::string &MsfError::getErrorMessage() const { return ErrMsg; } + +std::error_code MsfError::convertToErrorCode() const { + return std::error_code(static_cast(Code), *Category); +} diff --git a/llvm/lib/DebugInfo/Msf/StreamReader.cpp b/llvm/lib/DebugInfo/Msf/StreamReader.cpp new file mode 100644 index 00000000000..a2f0f49c3d9 --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/StreamReader.cpp @@ -0,0 +1,93 @@ +//===- StreamReader.cpp - Reads bytes and objects from a stream -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Msf/StreamReader.h" + +#include "llvm/DebugInfo/Msf/MsfError.h" +#include "llvm/DebugInfo/Msf/StreamRef.h" + +using namespace llvm; +using namespace llvm::msf; + +StreamReader::StreamReader(StreamRef S) : Stream(S), Offset(0) {} + +Error StreamReader::readLongestContiguousChunk(ArrayRef &Buffer) { + if (auto EC = Stream.readLongestContiguousChunk(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error StreamReader::readBytes(ArrayRef &Buffer, uint32_t Size) { + if (auto EC = Stream.readBytes(Offset, Size, Buffer)) + return EC; + Offset += Size; + return Error::success(); +} + +Error StreamReader::readInteger(uint16_t &Dest) { + const support::ulittle16_t *P; + if (auto EC = readObject(P)) + return EC; + Dest = *P; + return Error::success(); +} + +Error StreamReader::readInteger(uint32_t &Dest) { + const support::ulittle32_t *P; + if (auto EC = readObject(P)) + return EC; + Dest = *P; + return Error::success(); +} + +Error StreamReader::readZeroString(StringRef &Dest) { + uint32_t Length = 0; + // First compute the length of the string by reading 1 byte at a time. + uint32_t OriginalOffset = getOffset(); + const char *C; + do { + if (auto EC = readObject(C)) + return EC; + if (*C != '\0') + ++Length; + } while (*C != '\0'); + // Now go back and request a reference for that many bytes. + uint32_t NewOffset = getOffset(); + setOffset(OriginalOffset); + + ArrayRef Data; + if (auto EC = readBytes(Data, Length)) + return EC; + Dest = StringRef(reinterpret_cast(Data.begin()), Data.size()); + + // Now set the offset back to where it was after we calculated the length. + setOffset(NewOffset); + return Error::success(); +} + +Error StreamReader::readFixedString(StringRef &Dest, uint32_t Length) { + ArrayRef Bytes; + if (auto EC = readBytes(Bytes, Length)) + return EC; + Dest = StringRef(reinterpret_cast(Bytes.begin()), Bytes.size()); + return Error::success(); +} + +Error StreamReader::readStreamRef(StreamRef &Ref) { + return readStreamRef(Ref, bytesRemaining()); +} + +Error StreamReader::readStreamRef(StreamRef &Ref, uint32_t Length) { + if (bytesRemaining() < Length) + return make_error(msf_error_code::insufficient_buffer); + Ref = Stream.slice(Offset, Length); + Offset += Length; + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/Msf/StreamWriter.cpp b/llvm/lib/DebugInfo/Msf/StreamWriter.cpp new file mode 100644 index 00000000000..eb11012c475 --- /dev/null +++ b/llvm/lib/DebugInfo/Msf/StreamWriter.cpp @@ -0,0 +1,78 @@ +//===- StreamWrite.cpp - Writes bytes and objects to a stream -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/Msf/StreamWriter.h" + +#include "llvm/DebugInfo/Msf/MsfError.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamRef.h" + +using namespace llvm; +using namespace llvm::msf; + +StreamWriter::StreamWriter(StreamRef S) : Stream(S), Offset(0) {} + +Error StreamWriter::writeBytes(ArrayRef Buffer) { + if (auto EC = Stream.writeBytes(Offset, Buffer)) + return EC; + Offset += Buffer.size(); + return Error::success(); +} + +Error StreamWriter::writeInteger(uint16_t Int) { + return writeObject(support::ulittle16_t(Int)); +} + +Error StreamWriter::writeInteger(uint32_t Int) { + return writeObject(support::ulittle32_t(Int)); +} + +Error StreamWriter::writeZeroString(StringRef Str) { + if (auto EC = writeFixedString(Str)) + return EC; + if (auto EC = writeObject('\0')) + return EC; + + return Error::success(); +} + +Error StreamWriter::writeFixedString(StringRef Str) { + ArrayRef Bytes(Str.bytes_begin(), Str.bytes_end()); + if (auto EC = Stream.writeBytes(Offset, Bytes)) + return EC; + + Offset += Str.size(); + return Error::success(); +} + +Error StreamWriter::writeStreamRef(StreamRef Ref) { + if (auto EC = writeStreamRef(Ref, Ref.getLength())) + return EC; + // Don't increment Offset here, it is done by the overloaded call to + // writeStreamRef. + return Error::success(); +} + +Error StreamWriter::writeStreamRef(StreamRef Ref, uint32_t Length) { + Ref = Ref.slice(0, Length); + + StreamReader SrcReader(Ref); + // This is a bit tricky. If we just call readBytes, we are requiring that it + // return us the entire stream as a contiguous buffer. For large streams this + // will allocate a huge amount of space from the pool. Instead, iterate over + // each contiguous chunk until we've consumed the entire stream. + while (SrcReader.bytesRemaining() > 0) { + ArrayRef Chunk; + if (auto EC = SrcReader.readLongestContiguousChunk(Chunk)) + return EC; + if (auto EC = writeBytes(Chunk)) + return EC; + } + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/PDB/CMakeLists.txt b/llvm/lib/DebugInfo/PDB/CMakeLists.txt index b5a2bc1600f..126be38167b 100644 --- a/llvm/lib/DebugInfo/PDB/CMakeLists.txt +++ b/llvm/lib/DebugInfo/PDB/CMakeLists.txt @@ -32,14 +32,10 @@ add_pdb_impl_folder(Raw Raw/DbiStreamBuilder.cpp Raw/EnumTables.cpp Raw/Hash.cpp - Raw/IndexedStreamData.cpp Raw/InfoStream.cpp Raw/InfoStreamBuilder.cpp - Raw/MappedBlockStream.cpp Raw/ModInfo.cpp Raw/ModStream.cpp - Raw/MsfBuilder.cpp - Raw/MsfCommon.cpp Raw/NameHashTable.cpp Raw/NameMap.cpp Raw/NameMapBuilder.cpp diff --git a/llvm/lib/DebugInfo/PDB/LLVMBuild.txt b/llvm/lib/DebugInfo/PDB/LLVMBuild.txt index 76e537a57fc..a2196837723 100644 --- a/llvm/lib/DebugInfo/PDB/LLVMBuild.txt +++ b/llvm/lib/DebugInfo/PDB/LLVMBuild.txt @@ -19,5 +19,5 @@ type = Library name = DebugInfoPDB parent = DebugInfo -required_libraries = Object Support DebugInfoCodeView +required_libraries = Object Support DebugInfoCodeView DebugInfoMsf diff --git a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp index 430a84f93a2..1bad0009c37 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -9,11 +9,11 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/CodeView/StreamArray.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/StreamArray.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/ISectionContribVisitor.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" @@ -25,6 +25,7 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; @@ -204,17 +205,16 @@ PDB_Machine DbiStream::getMachineType() const { return static_cast(Machine); } -codeview::FixedStreamArray -DbiStream::getSectionHeaders() { +msf::FixedStreamArray DbiStream::getSectionHeaders() { return SectionHeaders; } -codeview::FixedStreamArray DbiStream::getFpoRecords() { +msf::FixedStreamArray DbiStream::getFpoRecords() { return FpoRecords; } ArrayRef DbiStream::modules() const { return ModuleInfos; } -codeview::FixedStreamArray DbiStream::getSectionMap() const { +msf::FixedStreamArray DbiStream::getSectionMap() const { return SectionMap; } @@ -283,7 +283,7 @@ Error DbiStream::initializeSectionHeadersData() { "Corrupted section header stream."); size_t NumSections = StreamLen / sizeof(object::coff_section); - codeview::StreamReader Reader(**SHS); + msf::StreamReader Reader(**SHS); if (auto EC = Reader.readArray(SectionHeaders, NumSections)) return make_error(raw_error_code::corrupt_file, "Could not read a bitmap."); @@ -316,7 +316,7 @@ Error DbiStream::initializeFpoRecords() { "Corrupted New FPO stream."); size_t NumRecords = StreamLen / sizeof(object::FpoData); - codeview::StreamReader Reader(**FS); + msf::StreamReader Reader(**FS); if (auto EC = Reader.readArray(FpoRecords, NumRecords)) return make_error(raw_error_code::corrupt_file, "Corrupted New FPO stream."); diff --git a/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp index 751f869c52a..7a688cb8968 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/DbiStreamBuilder.cpp @@ -9,13 +9,14 @@ #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; namespace { diff --git a/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp b/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp deleted file mode 100644 index 9bd16ea76ef..00000000000 --- a/llvm/lib/DebugInfo/PDB/Raw/IndexedStreamData.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===- IndexedStreamData.cpp - Standard PDB Stream Data ---------*- 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/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IPDBFile.h" - -using namespace llvm; -using namespace llvm::pdb; - -IndexedStreamData::IndexedStreamData(uint32_t StreamIdx, const IPDBFile &File) - : StreamIdx(StreamIdx), File(File) {} - -uint32_t IndexedStreamData::getLength() { - return File.getStreamByteSize(StreamIdx); -} - -ArrayRef IndexedStreamData::getStreamBlocks() { - return File.getStreamBlockList(StreamIdx); -} diff --git a/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp index c33a764587c..3d1bcdfd849 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -10,22 +10,23 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; InfoStream::InfoStream(std::unique_ptr Stream) : Stream(std::move(Stream)) {} Error InfoStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); const HeaderInfo *H; if (auto EC = Reader.readObject(H)) diff --git a/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp b/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp index 7be9cc32db9..444aba6be0b 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/InfoStreamBuilder.cpp @@ -9,13 +9,14 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStreamBuilder.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; InfoStreamBuilder::InfoStreamBuilder() {} diff --git a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp deleted file mode 100644 index 92b2048c3c2..00000000000 --- a/llvm/lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ /dev/null @@ -1,310 +0,0 @@ -//===- MappedBlockStream.cpp - Reads stream data from a PDBFile -----------===// -// -// 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/MappedBlockStream.h" -#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IPDBStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/PDBFile.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" - -using namespace llvm; -using namespace llvm::pdb; - -namespace { -// This exists so that we can use make_unique while still keeping the -// constructor of MappedBlockStream private, forcing users to go through -// the `create` interface. -class MappedBlockStreamImpl : public MappedBlockStream { -public: - MappedBlockStreamImpl(std::unique_ptr Data, - const IPDBFile &File) - : MappedBlockStream(std::move(Data), File) {} -}; -} - -typedef std::pair Interval; -static Interval intersect(const Interval &I1, const Interval &I2) { - return std::make_pair(std::max(I1.first, I2.first), - std::min(I1.second, I2.second)); -} - -MappedBlockStream::MappedBlockStream(std::unique_ptr Data, - const IPDBFile &Pdb) - : Pdb(Pdb), Data(std::move(Data)) {} - -Error MappedBlockStream::readBytes(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - // Make sure we aren't trying to read beyond the end of the stream. - if (Size > Data->getLength()) - return make_error(raw_error_code::insufficient_buffer); - if (Offset > Data->getLength() - Size) - return make_error(raw_error_code::insufficient_buffer); - - if (tryReadContiguously(Offset, Size, Buffer)) - return Error::success(); - - auto CacheIter = CacheMap.find(Offset); - if (CacheIter != CacheMap.end()) { - // Try to find an alloc that was large enough for this request. - for (auto &Entry : CacheIter->second) { - if (Entry.size() >= Size) { - Buffer = Entry.slice(0, Size); - return Error::success(); - } - } - } - - // We couldn't find a buffer that started at the correct offset (the most - // common scenario). Try to see if there is a buffer that starts at some - // other offset but overlaps the desired range. - for (auto &CacheItem : CacheMap) { - Interval RequestExtent = std::make_pair(Offset, Offset + Size); - - // We already checked this one on the fast path above. - if (CacheItem.first == Offset) - continue; - // If the initial extent of the cached item is beyond the ending extent - // of the request, there is no overlap. - if (CacheItem.first >= Offset + Size) - continue; - - // We really only have to check the last item in the list, since we append - // in order of increasing length. - if (CacheItem.second.empty()) - continue; - - auto CachedAlloc = CacheItem.second.back(); - // If the initial extent of the request is beyond the ending extent of - // the cached item, there is no overlap. - Interval CachedExtent = - std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size()); - if (RequestExtent.first >= CachedExtent.first + CachedExtent.second) - continue; - - Interval Intersection = intersect(CachedExtent, RequestExtent); - // Only use this if the entire request extent is contained in the cached - // extent. - if (Intersection != RequestExtent) - continue; - - uint32_t CacheRangeOffset = - AbsoluteDifference(CachedExtent.first, Intersection.first); - Buffer = CachedAlloc.slice(CacheRangeOffset, Size); - return Error::success(); - } - - // Otherwise allocate a large enough buffer in the pool, memcpy the data - // into it, and return an ArrayRef to that. Do not touch existing pool - // allocations, as existing clients may be holding a pointer which must - // not be invalidated. - uint8_t *WriteBuffer = static_cast(Pool.Allocate(Size, 8)); - if (auto EC = readBytes(Offset, MutableArrayRef(WriteBuffer, Size))) - return EC; - - if (CacheIter != CacheMap.end()) { - CacheIter->second.emplace_back(WriteBuffer, Size); - } else { - std::vector List; - List.emplace_back(WriteBuffer, Size); - CacheMap.insert(std::make_pair(Offset, List)); - } - Buffer = ArrayRef(WriteBuffer, Size); - return Error::success(); -} - -Error MappedBlockStream::readLongestContiguousChunk( - uint32_t Offset, ArrayRef &Buffer) const { - // Make sure we aren't trying to read beyond the end of the stream. - if (Offset >= Data->getLength()) - return make_error(raw_error_code::insufficient_buffer); - uint32_t First = Offset / Pdb.getBlockSize(); - uint32_t Last = First; - - auto BlockList = Data->getStreamBlocks(); - while (Last < Pdb.getBlockCount() - 1) { - if (BlockList[Last] != BlockList[Last + 1] - 1) - break; - ++Last; - } - - uint32_t OffsetInFirstBlock = Offset % Pdb.getBlockSize(); - uint32_t BytesFromFirstBlock = Pdb.getBlockSize() - OffsetInFirstBlock; - uint32_t BlockSpan = Last - First + 1; - uint32_t ByteSpan = - BytesFromFirstBlock + (BlockSpan - 1) * Pdb.getBlockSize(); - auto Result = Pdb.getBlockData(BlockList[First], Pdb.getBlockSize()); - if (!Result) - return Result.takeError(); - Buffer = Result->drop_front(OffsetInFirstBlock); - Buffer = ArrayRef(Buffer.data(), ByteSpan); - return Error::success(); -} - -uint32_t MappedBlockStream::getLength() const { return Data->getLength(); } - -Error MappedBlockStream::commit() const { return Error::success(); } - -bool MappedBlockStream::tryReadContiguously(uint32_t Offset, uint32_t Size, - ArrayRef &Buffer) const { - // Attempt to fulfill the request with a reference directly into the stream. - // This can work even if the request crosses a block boundary, provided that - // all subsequent blocks are contiguous. For example, a 10k read with a 4k - // block size can be filled with a reference if, from the starting offset, - // 3 blocks in a row are contiguous. - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - uint32_t BytesFromFirstBlock = - std::min(Size, Pdb.getBlockSize() - OffsetInBlock); - uint32_t NumAdditionalBlocks = - llvm::alignTo(Size - BytesFromFirstBlock, Pdb.getBlockSize()) / - Pdb.getBlockSize(); - - auto BlockList = Data->getStreamBlocks(); - uint32_t RequiredContiguousBlocks = NumAdditionalBlocks + 1; - uint32_t E = BlockList[BlockNum]; - for (uint32_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) { - if (BlockList[I + BlockNum] != E) - return false; - } - - uint32_t FirstBlockAddr = BlockList[BlockNum]; - auto Result = Pdb.getBlockData(FirstBlockAddr, Pdb.getBlockSize()); - if (!Result) { - consumeError(Result.takeError()); - return false; - } - auto Data = Result->drop_front(OffsetInBlock); - Buffer = ArrayRef(Data.data(), Size); - return true; -} - -Error MappedBlockStream::readBytes(uint32_t Offset, - MutableArrayRef Buffer) const { - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - - // Make sure we aren't trying to read beyond the end of the stream. - if (Buffer.size() > Data->getLength()) - return make_error(raw_error_code::insufficient_buffer); - if (Offset > Data->getLength() - Buffer.size()) - return make_error(raw_error_code::insufficient_buffer); - - uint32_t BytesLeft = Buffer.size(); - uint32_t BytesWritten = 0; - uint8_t *WriteBuffer = Buffer.data(); - auto BlockList = Data->getStreamBlocks(); - while (BytesLeft > 0) { - uint32_t StreamBlockAddr = BlockList[BlockNum]; - - auto Result = Pdb.getBlockData(StreamBlockAddr, Pdb.getBlockSize()); - if (!Result) - return Result.takeError(); - - auto Data = *Result; - const uint8_t *ChunkStart = Data.data() + OffsetInBlock; - uint32_t BytesInChunk = - std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock); - ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk); - - BytesWritten += BytesInChunk; - BytesLeft -= BytesInChunk; - ++BlockNum; - OffsetInBlock = 0; - } - - return Error::success(); -} - -Error MappedBlockStream::writeBytes(uint32_t Offset, - ArrayRef Buffer) const { - // Make sure we aren't trying to write beyond the end of the stream. - if (Buffer.size() > Data->getLength()) - return make_error(raw_error_code::insufficient_buffer); - - if (Offset > Data->getLength() - Buffer.size()) - return make_error(raw_error_code::insufficient_buffer); - - uint32_t BlockNum = Offset / Pdb.getBlockSize(); - uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); - - uint32_t BytesLeft = Buffer.size(); - auto BlockList = Data->getStreamBlocks(); - uint32_t BytesWritten = 0; - while (BytesLeft > 0) { - uint32_t StreamBlockAddr = BlockList[BlockNum]; - uint32_t BytesToWriteInChunk = - std::min(BytesLeft, Pdb.getBlockSize() - OffsetInBlock); - - const uint8_t *Chunk = Buffer.data() + BytesWritten; - ArrayRef ChunkData(Chunk, BytesToWriteInChunk); - if (auto EC = Pdb.setBlockData(StreamBlockAddr, OffsetInBlock, ChunkData)) - return EC; - - BytesLeft -= BytesToWriteInChunk; - BytesWritten += BytesToWriteInChunk; - ++BlockNum; - OffsetInBlock = 0; - } - - // If this write overlapped a read which previously came from the pool, - // someone may still be holding a pointer to that alloc which is now invalid. - // Compute the overlapping range and update the cache entry, so any - // outstanding buffers are automatically updated. - for (const auto &MapEntry : CacheMap) { - // If the end of the written extent precedes the beginning of the cached - // extent, ignore this map entry. - if (Offset + BytesWritten < MapEntry.first) - continue; - for (const auto &Alloc : MapEntry.second) { - // If the end of the cached extent precedes the beginning of the written - // extent, ignore this alloc. - if (MapEntry.first + Alloc.size() < Offset) - continue; - - // If we get here, they are guaranteed to overlap. - Interval WriteInterval = std::make_pair(Offset, Offset + BytesWritten); - Interval CachedInterval = - std::make_pair(MapEntry.first, MapEntry.first + Alloc.size()); - // If they overlap, we need to write the new data into the overlapping - // range. - auto Intersection = intersect(WriteInterval, CachedInterval); - assert(Intersection.first <= Intersection.second); - - uint32_t Length = Intersection.second - Intersection.first; - uint32_t SrcOffset = - AbsoluteDifference(WriteInterval.first, Intersection.first); - uint32_t DestOffset = - AbsoluteDifference(CachedInterval.first, Intersection.first); - ::memcpy(Alloc.data() + DestOffset, Buffer.data() + SrcOffset, Length); - } - } - - return Error::success(); -} - -uint32_t MappedBlockStream::getNumBytesCopied() const { - return static_cast(Pool.getBytesAllocated()); -} - -Expected> -MappedBlockStream::createIndexedStream(uint32_t StreamIdx, - const IPDBFile &File) { - if (StreamIdx >= File.getNumStreams()) - return make_error(raw_error_code::no_stream); - - auto Data = llvm::make_unique(StreamIdx, File); - return llvm::make_unique(std::move(Data), File); -} - -Expected> -MappedBlockStream::createDirectoryStream(const PDBFile &File) { - auto Data = llvm::make_unique(File); - return llvm::make_unique(std::move(Data), File); -} diff --git a/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp b/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp index 9d0a0ae6e36..89a03ec3a4d 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/ModInfo.cpp @@ -9,11 +9,12 @@ #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; @@ -26,8 +27,8 @@ ModInfo::ModInfo(const ModInfo &Info) ModInfo::~ModInfo() {} -Error ModInfo::initialize(codeview::StreamRef Stream, ModInfo &Info) { - codeview::StreamReader Reader(Stream); +Error ModInfo::initialize(StreamRef Stream, ModInfo &Info) { + StreamReader Reader(Stream); if (auto EC = Reader.readObject(Info.Layout)) return EC; diff --git a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp index 3415fcd4779..39e9dfaf3e2 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/ModStream.cpp @@ -9,14 +9,15 @@ #include "llvm/DebugInfo/PDB/Raw/ModStream.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/RawTypes.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::pdb; ModStream::ModStream(const ModInfo &Module, @@ -26,7 +27,7 @@ ModStream::ModStream(const ModInfo &Module, ModStream::~ModStream() {} Error ModStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize(); uint32_t C11Size = Mod.getLineInfoByteSize(); @@ -36,7 +37,7 @@ Error ModStream::reload() { return llvm::make_error(raw_error_code::corrupt_file, "Module has both C11 and C13 line info"); - codeview::StreamRef S; + StreamRef S; uint32_t SymbolSubstreamSig = 0; if (auto EC = Reader.readInteger(SymbolSubstreamSig)) @@ -49,7 +50,7 @@ Error ModStream::reload() { if (auto EC = Reader.readStreamRef(C13LinesSubstream, C13Size)) return EC; - codeview::StreamReader LineReader(C13LinesSubstream); + StreamReader LineReader(C13LinesSubstream); if (auto EC = LineReader.readArray(LineInfo, LineReader.bytesRemaining())) return EC; diff --git a/llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp b/llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp deleted file mode 100644 index 16b086bdaa9..00000000000 --- a/llvm/lib/DebugInfo/PDB/Raw/MsfBuilder.cpp +++ /dev/null @@ -1,279 +0,0 @@ -//===- MSFBuilder.cpp - MSF Directory & Metadata Builder --------*- 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/Raw/MsfBuilder.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" - -using namespace llvm; -using namespace llvm::pdb; -using namespace llvm::pdb::msf; -using namespace llvm::support; - -namespace { -const uint32_t kSuperBlockBlock = 0; -const uint32_t kFreePageMap0Block = 1; -const uint32_t kFreePageMap1Block = 2; -const uint32_t kNumReservedPages = 3; - -const uint32_t kDefaultBlockMapAddr = kNumReservedPages; -} - -MsfBuilder::MsfBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow, - BumpPtrAllocator &Allocator) - : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize), - MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr), - FreeBlocks(MinBlockCount, true) { - FreeBlocks[kSuperBlockBlock] = false; - FreeBlocks[kFreePageMap0Block] = false; - FreeBlocks[kFreePageMap1Block] = false; - FreeBlocks[BlockMapAddr] = false; -} - -Expected MsfBuilder::create(BumpPtrAllocator &Allocator, - uint32_t BlockSize, - uint32_t MinBlockCount, bool CanGrow) { - if (!msf::isValidBlockSize(BlockSize)) - return make_error(raw_error_code::unspecified, - "The requested block size is unsupported"); - - return MsfBuilder(BlockSize, - std::max(MinBlockCount, msf::getMinimumBlockCount()), - CanGrow, Allocator); -} - -Error MsfBuilder::setBlockMapAddr(uint32_t Addr) { - if (Addr == BlockMapAddr) - return Error::success(); - - if (Addr >= FreeBlocks.size()) { - if (!IsGrowable) - return make_error(raw_error_code::unspecified, - "Cannot grow the number of blocks"); - FreeBlocks.resize(Addr + 1); - } - - if (!isBlockFree(Addr)) - return make_error(raw_error_code::unspecified, - "Attempt to reuse an allocated block"); - FreeBlocks[BlockMapAddr] = true; - FreeBlocks[Addr] = false; - BlockMapAddr = Addr; - return Error::success(); -} - -void MsfBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; } - -void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; } - -Error MsfBuilder::setDirectoryBlocksHint(ArrayRef DirBlocks) { - for (auto B : DirectoryBlocks) - FreeBlocks[B] = true; - for (auto B : DirBlocks) { - if (!isBlockFree(B)) { - return make_error(raw_error_code::unspecified, - "Attempt to reuse an allocated block"); - } - FreeBlocks[B] = false; - } - - DirectoryBlocks = DirBlocks; - return Error::success(); -} - -Error MsfBuilder::allocateBlocks(uint32_t NumBlocks, - MutableArrayRef Blocks) { - if (NumBlocks == 0) - return Error::success(); - - uint32_t NumFreeBlocks = FreeBlocks.count(); - if (NumFreeBlocks < NumBlocks) { - if (!IsGrowable) - return make_error(raw_error_code::unspecified, - "There are no free Blocks in the file"); - uint32_t AllocBlocks = NumBlocks - NumFreeBlocks; - FreeBlocks.resize(AllocBlocks + FreeBlocks.size(), true); - } - - int I = 0; - int Block = FreeBlocks.find_first(); - do { - assert(Block != -1 && "We ran out of Blocks!"); - - uint32_t NextBlock = static_cast(Block); - Blocks[I++] = NextBlock; - FreeBlocks.reset(NextBlock); - Block = FreeBlocks.find_next(Block); - } while (--NumBlocks > 0); - return Error::success(); -} - -uint32_t MsfBuilder::getNumUsedBlocks() const { - return getTotalBlockCount() - getNumFreeBlocks(); -} - -uint32_t MsfBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); } - -uint32_t MsfBuilder::getTotalBlockCount() const { return FreeBlocks.size(); } - -bool MsfBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; } - -Error MsfBuilder::addStream(uint32_t Size, ArrayRef Blocks) { - // Add a new stream mapped to the specified blocks. Verify that the specified - // blocks are both necessary and sufficient for holding the requested number - // of bytes, and verify that all requested blocks are free. - uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); - if (ReqBlocks != Blocks.size()) - return make_error( - raw_error_code::unspecified, - "Incorrect number of blocks for requested stream size"); - for (auto Block : Blocks) { - if (Block >= FreeBlocks.size()) - FreeBlocks.resize(Block + 1, true); - - if (!FreeBlocks.test(Block)) - return make_error( - raw_error_code::unspecified, - "Attempt to re-use an already allocated block"); - } - // Mark all the blocks occupied by the new stream as not free. - for (auto Block : Blocks) { - FreeBlocks.reset(Block); - } - StreamData.push_back(std::make_pair(Size, Blocks)); - return Error::success(); -} - -Error MsfBuilder::addStream(uint32_t Size) { - uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize); - std::vector NewBlocks; - NewBlocks.resize(ReqBlocks); - if (auto EC = allocateBlocks(ReqBlocks, NewBlocks)) - return EC; - StreamData.push_back(std::make_pair(Size, NewBlocks)); - return Error::success(); -} - -Error MsfBuilder::setStreamSize(uint32_t Idx, uint32_t Size) { - uint32_t OldSize = getStreamSize(Idx); - if (OldSize == Size) - return Error::success(); - - uint32_t NewBlocks = bytesToBlocks(Size, BlockSize); - uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize); - - if (NewBlocks > OldBlocks) { - uint32_t AddedBlocks = NewBlocks - OldBlocks; - // If we're growing, we have to allocate new Blocks. - std::vector AddedBlockList; - AddedBlockList.resize(AddedBlocks); - if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList)) - return EC; - auto &CurrentBlocks = StreamData[Idx].second; - CurrentBlocks.insert(CurrentBlocks.end(), AddedBlockList.begin(), - AddedBlockList.end()); - } else if (OldBlocks > NewBlocks) { - // For shrinking, free all the Blocks in the Block map, update the stream - // data, then shrink the directory. - uint32_t RemovedBlocks = OldBlocks - NewBlocks; - auto CurrentBlocks = ArrayRef(StreamData[Idx].second); - auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks); - for (auto P : RemovedBlockList) - FreeBlocks[P] = true; - StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks); - } - - StreamData[Idx].first = Size; - return Error::success(); -} - -uint32_t MsfBuilder::getNumStreams() const { return StreamData.size(); } - -uint32_t MsfBuilder::getStreamSize(uint32_t StreamIdx) const { - return StreamData[StreamIdx].first; -} - -ArrayRef MsfBuilder::getStreamBlocks(uint32_t StreamIdx) const { - return StreamData[StreamIdx].second; -} - -uint32_t MsfBuilder::computeDirectoryByteSize() const { - // The directory has the following layout, where each item is a ulittle32_t: - // NumStreams - // StreamSizes[NumStreams] - // StreamBlocks[NumStreams][] - uint32_t Size = sizeof(ulittle32_t); // NumStreams - Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes - for (const auto &D : StreamData) { - uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize); - assert(ExpectedNumBlocks == D.second.size() && - "Unexpected number of blocks"); - Size += ExpectedNumBlocks * sizeof(ulittle32_t); - } - return Size; -} - -Expected MsfBuilder::build() { - Layout L; - L.SB = Allocator.Allocate(); - std::memcpy(L.SB->MagicBytes, Magic, sizeof(Magic)); - L.SB->BlockMapAddr = BlockMapAddr; - L.SB->BlockSize = BlockSize; - L.SB->NumDirectoryBytes = computeDirectoryByteSize(); - L.SB->FreeBlockMapBlock = FreePageMap; - L.SB->Unknown1 = Unknown1; - - uint32_t NumDirectoryBlocks = - bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize); - if (NumDirectoryBlocks > DirectoryBlocks.size()) { - // Our hint wasn't enough to satisfy the entire directory. Allocate - // remaining pages. - std::vector ExtraBlocks; - uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size(); - ExtraBlocks.resize(NumExtraBlocks); - if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks)) - return std::move(EC); - DirectoryBlocks.insert(DirectoryBlocks.end(), ExtraBlocks.begin(), - ExtraBlocks.end()); - } else if (NumDirectoryBlocks < DirectoryBlocks.size()) { - uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks; - for (auto B : - ArrayRef(DirectoryBlocks).drop_back(NumUnnecessaryBlocks)) - FreeBlocks[B] = true; - DirectoryBlocks.resize(NumDirectoryBlocks); - } - - // Don't set the number of blocks in the file until after allocating Blocks - // for - // the directory, since the allocation might cause the file to need to grow. - L.SB->NumBlocks = FreeBlocks.size(); - - ulittle32_t *DirBlocks = Allocator.Allocate(NumDirectoryBlocks); - std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks, - DirBlocks); - L.DirectoryBlocks = ArrayRef(DirBlocks, NumDirectoryBlocks); - - // The stream sizes should be re-allocated as a stable pointer and the stream - // map should have each of its entries allocated as a separate stable pointer. - if (StreamData.size() > 0) { - ulittle32_t *Sizes = Allocator.Allocate(StreamData.size()); - L.StreamSizes = ArrayRef(Sizes, StreamData.size()); - L.StreamMap.resize(StreamData.size()); - for (uint32_t I = 0; I < StreamData.size(); ++I) { - Sizes[I] = StreamData[I].first; - ulittle32_t *BlockList = - Allocator.Allocate(StreamData[I].second.size()); - std::uninitialized_copy_n(StreamData[I].second.begin(), - StreamData[I].second.size(), BlockList); - L.StreamMap[I] = - ArrayRef(BlockList, StreamData[I].second.size()); - } - } - - return L; -} diff --git a/llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp b/llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp deleted file mode 100644 index 5d97f33e110..00000000000 --- a/llvm/lib/DebugInfo/PDB/Raw/MsfCommon.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===- MsfCommon.cpp - Common types and functions for MSF files -*- 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/Raw/MsfCommon.h" -#include "llvm/DebugInfo/PDB/Raw/RawError.h" - -using namespace llvm; -using namespace llvm::pdb::msf; - -Error llvm::pdb::msf::validateSuperBlock(const SuperBlock &SB) { - // Check the magic bytes. - if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0) - return make_error(raw_error_code::corrupt_file, - "MSF magic header doesn't match"); - - if (!isValidBlockSize(SB.BlockSize)) - return make_error(raw_error_code::corrupt_file, - "Unsupported block size."); - - // We don't support directories whose sizes aren't a multiple of four bytes. - if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) - return make_error(raw_error_code::corrupt_file, - "Directory size is not multiple of 4."); - - // The number of blocks which comprise the directory is a simple function of - // the number of bytes it contains. - uint64_t NumDirectoryBlocks = - bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize); - - // The directory, as we understand it, is a block which consists of a list of - // block numbers. It is unclear what would happen if the number of blocks - // couldn't fit on a single block. - if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t)) - return make_error(raw_error_code::corrupt_file, - "Too many directory blocks."); - - if (SB.BlockMapAddr == 0) - return make_error(raw_error_code::corrupt_file, - "Block 0 is reserved"); - - return Error::success(); -} diff --git a/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp b/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp index ae4ebf27721..3e22e7686bd 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -10,18 +10,19 @@ #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/Hash.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {} -Error NameHashTable::load(codeview::StreamReader &Stream) { +Error NameHashTable::load(StreamReader &Stream) { struct Header { support::ulittle32_t Signature; support::ulittle32_t HashVersion; @@ -72,7 +73,7 @@ StringRef NameHashTable::getStringForID(uint32_t ID) const { // the starting offset of the string we're looking for. So just seek into // the desired offset and a read a null terminated stream from that offset. StringRef Result; - codeview::StreamReader NameReader(NamesBuffer); + StreamReader NameReader(NamesBuffer); NameReader.setOffset(ID); if (auto EC = NameReader.readZeroString(Result)) consumeError(std::move(EC)); @@ -98,7 +99,6 @@ uint32_t NameHashTable::getIDForString(StringRef Str) const { return IDs[0]; } -codeview::FixedStreamArray -NameHashTable::name_ids() const { +FixedStreamArray NameHashTable::name_ids() const { return IDs; } diff --git a/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp b/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp index b8a4eb79a48..e17600986c9 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/NameMap.cpp @@ -9,17 +9,17 @@ #include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/ADT/SparseBitVector.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; -using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; NameMap::NameMap() {} -Error NameMap::load(codeview::StreamReader &Stream) { +Error NameMap::load(StreamReader &Stream) { // This is some sort of weird string-set/hash table encoded in the stream. // It starts with the number of bytes in the table. @@ -145,7 +145,7 @@ Error NameMap::load(codeview::StreamReader &Stream) { return Error::success(); } -Error NameMap::commit(codeview::StreamWriter &Writer) { +Error NameMap::commit(StreamWriter &Writer) { // The first field is the number of bytes of string data. So add // up the length of all strings plus a null terminator for each // one. diff --git a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp index 95016753dc1..b44a474b63d 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -10,13 +10,13 @@ #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/DebugInfo/CodeView/StreamArray.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/DirectoryStreamData.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/StreamArray.h" +#include "llvm/DebugInfo/Msf/StreamInterface.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" -#include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" @@ -29,6 +29,7 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; namespace { @@ -130,7 +131,8 @@ Error PDBFile::parseStreamData() { // 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(*this); + auto DS = MappedBlockStream::createDirectoryStream( + SB->NumDirectoryBytes, getDirectoryBlockArray(), *this); if (!DS) return DS.takeError(); StreamReader Reader(**DS); @@ -315,7 +317,8 @@ Error PDBFile::commit() { if (auto EC = Writer.writeArray(DirectoryBlocks)) return EC; - auto DS = MappedBlockStream::createDirectoryStream(*this); + auto DS = MappedBlockStream::createDirectoryStream( + SB->NumDirectoryBytes, getDirectoryBlockArray(), *this); if (!DS) return DS.takeError(); auto DirStream = std::move(*DS); diff --git a/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp b/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp index 7ed7abefd53..c6bcd5106ca 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/PDBFileBuilder.cpp @@ -11,8 +11,9 @@ #include "llvm/ADT/BitVector.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" -#include "llvm/DebugInfo/CodeView/StreamWriter.h" +#include "llvm/DebugInfo/Msf/MsfBuilder.h" +#include "llvm/DebugInfo/Msf/StreamInterface.h" +#include "llvm/DebugInfo/Msf/StreamWriter.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" @@ -21,11 +22,11 @@ using namespace llvm; using namespace llvm::codeview; +using namespace llvm::msf; using namespace llvm::pdb; using namespace llvm::support; -PDBFileBuilder::PDBFileBuilder( - std::unique_ptr FileBuffer) +PDBFileBuilder::PDBFileBuilder(std::unique_ptr FileBuffer) : File(llvm::make_unique(std::move(FileBuffer))) {} Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) { diff --git a/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp index af3d2d026b4..426efb8fd88 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/PublicsStream.cpp @@ -25,10 +25,10 @@ #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -40,6 +40,7 @@ #include "llvm/Support/MathExtras.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; @@ -86,7 +87,7 @@ uint32_t PublicsStream::getAddrMap() const { return Header->AddrMap; } // we skip over the hash table which we believe contains information about // public symbols. Error PublicsStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); // Check stream size. if (Reader.bytesRemaining() < sizeof(HeaderInfo) + sizeof(GSIHashHeader)) diff --git a/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp b/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp index 455d33140dd..e734aebf47f 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/RawSession.cpp @@ -9,8 +9,8 @@ #include "llvm/DebugInfo/PDB/Raw/RawSession.h" -#include "llvm/DebugInfo/CodeView/ByteStream.h" -#include "llvm/DebugInfo/CodeView/StreamInterface.h" +#include "llvm/DebugInfo/Msf/ByteStream.h" +#include "llvm/DebugInfo/Msf/StreamInterface.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" @@ -23,13 +23,14 @@ #include "llvm/Support/MemoryBuffer.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::pdb; namespace { // We need a class which behaves like an immutable ByteStream, but whose data // is backed by an llvm::MemoryBuffer. It also needs to own the underlying // MemoryBuffer, so this simple adapter is a good way to achieve that. -class InputByteStream : public codeview::ByteStream { +class InputByteStream : public ByteStream { public: explicit InputByteStream(std::unique_ptr Buffer) : ByteStream(ArrayRef(Buffer->getBuffer().bytes_begin(), diff --git a/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp index 41b2a64bfb1..f98b5d4688b 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/SymbolStream.cpp @@ -10,10 +10,10 @@ #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -21,6 +21,7 @@ #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::msf; using namespace llvm::support; using namespace llvm::pdb; @@ -30,7 +31,7 @@ SymbolStream::SymbolStream(std::unique_ptr Stream) SymbolStream::~SymbolStream() {} Error SymbolStream::reload() { - codeview::StreamReader Reader(*Stream); + StreamReader Reader(*Stream); if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength())) return EC; diff --git a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp index 5617e57ccf6..f642940bbc9 100644 --- a/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ b/llvm/lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -11,12 +11,12 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeView.h" -#include "llvm/DebugInfo/CodeView/StreamReader.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/Msf/IndexedStreamData.h" +#include "llvm/DebugInfo/Msf/MappedBlockStream.h" +#include "llvm/DebugInfo/Msf/StreamReader.h" #include "llvm/DebugInfo/PDB/Raw/Hash.h" -#include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" -#include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/RawError.h" @@ -27,6 +27,7 @@ using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; +using namespace llvm::msf; using namespace llvm::pdb; namespace { -- cgit v1.2.3