diff options
author | Zachary Turner <zturner@google.com> | 2016-11-08 22:24:53 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2016-11-08 22:24:53 +0000 |
commit | 4efa0a4201c5df01817895f476dfac71b3064acc (patch) | |
tree | cd4c78a2b08baa8a3285c30d5a061e4a6acdbee3 /llvm/lib/DebugInfo/CodeView | |
parent | cb3c9f6c749c6ec76b328c2a405b79430868ef23 (diff) | |
download | bcm5719-llvm-4efa0a4201c5df01817895f476dfac71b3064acc.tar.gz bcm5719-llvm-4efa0a4201c5df01817895f476dfac71b3064acc.zip |
[CodeView] Hook up CodeViewRecordIO to type serialization path.
Previously support had been added for using CodeViewRecordIO
to read (deserialize) CodeView type records. This patch adds
support for writing those same records. With this patch,
reading and writing of CodeView type records finally uses a single
codepath.
Differential Revision: https://reviews.llvm.org/D26253
llvm-svn: 286304
Diffstat (limited to 'llvm/lib/DebugInfo/CodeView')
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 7 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp | 65 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp | 41 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp | 132 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp | 103 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp | 46 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp | 49 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeDumper.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp | 119 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp | 100 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp | 243 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 15 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp | 300 |
13 files changed, 374 insertions, 850 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index 4bbc48d111f..12675c3c631 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -4,21 +4,16 @@ add_llvm_library(LLVMDebugInfoCodeView CVSymbolVisitor.cpp CVTypeVisitor.cpp EnumTables.cpp - FieldListRecordBuilder.cpp Line.cpp - ListRecordBuilder.cpp - MemoryTypeTableBuilder.cpp - MethodListRecordBuilder.cpp ModuleSubstream.cpp ModuleSubstreamVisitor.cpp RecordSerialization.cpp SymbolDumper.cpp TypeDumper.cpp TypeRecord.cpp - TypeRecordBuilder.cpp TypeRecordMapping.cpp + TypeSerializer.cpp TypeStreamMerger.cpp - TypeTableBuilder.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index 5f5d5fe35ef..5171e24f3aa 100644 --- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -17,24 +17,6 @@ using namespace llvm; using namespace llvm::codeview; -template <typename T> -static Expected<CVMemberRecord> -deserializeMemberRecord(FieldListDeserializer &Deserializer, - msf::StreamReader &Reader, TypeLeafKind Kind) { - T MR(static_cast<TypeRecordKind>(Kind)); - CVMemberRecord CVR; - CVR.Kind = Kind; - - if (auto EC = Deserializer.visitMemberBegin(CVR)) - return std::move(EC); - if (auto EC = Deserializer.visitKnownMember(CVR, MR)) - return std::move(EC); - if (auto EC = Deserializer.visitMemberEnd(CVR)) - return std::move(EC); - - return CVR; -} - CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) : Callbacks(Callbacks) {} @@ -85,7 +67,8 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) { return Error::success(); } -Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) { +static Error visitMemberRecord(CVMemberRecord &Record, + TypeVisitorCallbacks &Callbacks) { if (auto EC = Callbacks.visitMemberBegin(Record)) return EC; @@ -113,6 +96,10 @@ Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) { return Error::success(); } +Error CVTypeVisitor::visitMemberRecord(CVMemberRecord &Record) { + return ::visitMemberRecord(Record, Callbacks); +} + /// Visits the type records in Data. Sets the error flag on parse failures. Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { for (auto I : Types) { @@ -122,23 +109,6 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { return Error::success(); } -template <typename MR> -static Error visitKnownMember(FieldListDeserializer &Deserializer, - msf::StreamReader &Reader, TypeLeafKind Leaf, - TypeVisitorCallbacks &Callbacks) { - MR Record(static_cast<TypeRecordKind>(Leaf)); - CVMemberRecord CVR; - CVR.Kind = Leaf; - - if (auto EC = Callbacks.visitMemberBegin(CVR)) - return EC; - if (auto EC = Callbacks.visitKnownMember(CVR, Record)) - return EC; - if (auto EC = Callbacks.visitMemberEnd(CVR)) - return EC; - return Error::success(); -} - Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { FieldListDeserializer Deserializer(Reader); TypeVisitorCallbackPipeline Pipeline; @@ -150,25 +120,12 @@ Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { if (auto EC = Reader.readEnum(Leaf)) return EC; - CVType Record; - switch (Leaf) { - default: - // Field list records do not describe their own length, so we cannot - // continue parsing past a type that we don't know how to deserialize. - return llvm::make_error<CodeViewError>( - cv_error_code::unknown_member_record); -#define MEMBER_RECORD(EnumName, EnumVal, Name) \ - case EnumName: { \ - if (auto EC = visitKnownMember<Name##Record>(Deserializer, Reader, Leaf, \ - Pipeline)) \ - return EC; \ - break; \ - } -#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \ - MEMBER_RECORD(EnumVal, EnumVal, AliasName) -#include "llvm/DebugInfo/CodeView/TypeRecords.def" - } + CVMemberRecord Record; + Record.Kind = Leaf; + if (auto EC = ::visitMemberRecord(Record, Pipeline)) + return EC; } + return Error::success(); } diff --git a/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp index 7841e4f2f6a..19facaec9f0 100644 --- a/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp +++ b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -16,20 +16,39 @@ using namespace llvm; using namespace llvm::codeview; -Error CodeViewRecordIO::beginRecord(uint16_t Kind) { - assert(!CurrentRecord.hasValue() && "There is already a record active!"); - CurrentRecord.emplace(); - - CurrentRecord->Kind = Kind; +Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) { + RecordLimit Limit; + Limit.MaxLength = MaxLength; + Limit.BeginOffset = getCurrentOffset(); + Limits.push_back(Limit); return Error::success(); } Error CodeViewRecordIO::endRecord() { - assert(CurrentRecord.hasValue() && "Not in a record!"); - CurrentRecord.reset(); + assert(!Limits.empty() && "Not in a record!"); + Limits.pop_back(); return Error::success(); } +uint32_t CodeViewRecordIO::maxFieldLength() const { + assert(!Limits.empty() && "Not in a record!"); + + // The max length of the next field is the minimum of all lengths that would + // be allowed by any of the sub-records we're in. In practice, we can only + // ever be at most 1 sub-record deep (in a FieldList), but this works for + // the general case. + uint32_t Offset = getCurrentOffset(); + Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset); + for (auto X : makeArrayRef(Limits).drop_front()) { + Optional<uint32_t> ThisMin = X.bytesRemaining(Offset); + if (ThisMin.hasValue()) + Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin; + } + assert(Min.hasValue() && "Every field must have a maximum length!"); + + return *Min; +} + Error CodeViewRecordIO::skipPadding() { assert(!isWriting() && "Cannot skip padding while writing!"); @@ -114,7 +133,9 @@ Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value) { Error CodeViewRecordIO::mapStringZ(StringRef &Value) { if (isWriting()) { - if (auto EC = Writer->writeZeroString(Value)) + // Truncate if we attempt to write too much. + StringRef S = Value.take_front(maxFieldLength() - 1); + if (auto EC = Writer->writeZeroString(S)) return EC; } else { if (auto EC = Reader->readZeroString(Value)) @@ -124,6 +145,10 @@ Error CodeViewRecordIO::mapStringZ(StringRef &Value) { } Error CodeViewRecordIO::mapGuid(StringRef &Guid) { + constexpr uint32_t GuidSize = 16; + if (maxFieldLength() < GuidSize) + return make_error<CodeViewError>(cv_error_code::insufficient_buffer); + if (isWriting()) { assert(Guid.size() == 16 && "Invalid Guid Size!"); if (auto EC = Writer->writeFixedString(Guid)) diff --git a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp deleted file mode 100644 index ac2ef3972b6..00000000000 --- a/llvm/lib/DebugInfo/CodeView/FieldListRecordBuilder.cpp +++ /dev/null @@ -1,132 +0,0 @@ -//===-- FieldListRecordBuilder.cpp ----------------------------------------===// -// -// 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/FieldListRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -FieldListRecordBuilder::FieldListRecordBuilder() - : ListRecordBuilder(TypeRecordKind::FieldList) {} - -void FieldListRecordBuilder::writeMemberType(const BaseClassRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::BaseClass); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getBaseType()); - Builder.writeEncodedUnsignedInteger(Record.getBaseOffset()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType(const EnumeratorRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::Enumerator); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - // FIXME: Handle full APInt such as __int128. - Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType(const DataMemberRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getType()); - Builder.writeEncodedUnsignedInteger(Record.getFieldOffset()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType( - const OverloadedMethodRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod); - Builder.writeUInt16(Record.getNumOverloads()); - Builder.writeTypeIndex(Record.getMethodList()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType(const OneMethodRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - uint16_t Flags = static_cast<uint16_t>(Record.getAccess()); - Flags |= static_cast<uint16_t>(Record.getKind()) << MethodKindShift; - Flags |= static_cast<uint16_t>(Record.getOptions()); - - Builder.writeTypeRecordKind(TypeRecordKind::OneMethod); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getType()); - if (Record.isIntroducingVirtual()) { - assert(Record.getVFTableOffset() >= 0); - Builder.writeInt32(Record.getVFTableOffset()); - } else { - assert(Record.getVFTableOffset() == -1); - } - - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType(const NestedTypeRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Record.getNestedType()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType( - const StaticDataMemberRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getType()); - Builder.writeNullTerminatedString(Record.getName()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType( - const VirtualBaseClassRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(Record.getKind()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getAccess())); - Builder.writeTypeIndex(Record.getBaseType()); - Builder.writeTypeIndex(Record.getVBPtrType()); - Builder.writeEncodedInteger(Record.getVBPtrOffset()); - Builder.writeEncodedUnsignedInteger(Record.getVTableIndex()); - - finishSubRecord(); -} - -void FieldListRecordBuilder::writeMemberType(const VFPtrRecord &Record) { - TypeRecordBuilder &Builder = getBuilder(); - - Builder.writeTypeRecordKind(TypeRecordKind::VFPtr); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Record.getType()); - - finishSubRecord(); -} diff --git a/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp deleted file mode 100644 index efac32a0f86..00000000000 --- a/llvm/lib/DebugInfo/CodeView/ListRecordBuilder.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//===-- ListRecordBuilder.cpp ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallString.h" -#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" - -using namespace llvm; -using namespace codeview; - -ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) - : Kind(Kind), Builder(Kind) {} - -void ListRecordBuilder::writeMemberType(const ListContinuationRecord &R) { - TypeRecordBuilder &Builder = getBuilder(); - - assert(getLastContinuationSize() < MaxRecordLength - 8 && "continuation won't fit"); - - Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); - Builder.writeUInt16(0); - Builder.writeTypeIndex(R.getContinuationIndex()); - - // End the current segment manually so that nothing comes after the - // continuation. - ContinuationOffsets.push_back(Builder.size()); - SubrecordStart = Builder.size(); -} - -void ListRecordBuilder::finishSubRecord() { - // The type table inserts a 16 bit size field before each list, so factor that - // into our alignment padding. - uint32_t Remainder = - (Builder.size() + 2 * (ContinuationOffsets.size() + 1)) % 4; - if (Remainder != 0) { - for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0; - --PaddingBytesLeft) { - Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft); - } - } - - // Check if this subrecord makes the current segment not fit in 64K minus the - // space for a continuation record (8 bytes). If the segment does not fit, - // back up and insert a continuation record, sliding the current subrecord - // down. - if (getLastContinuationSize() > MaxRecordLength - 8) { - assert(SubrecordStart != 0 && "can't slide from the start!"); - SmallString<128> SubrecordCopy( - Builder.str().slice(SubrecordStart, Builder.size())); - assert(SubrecordCopy.size() < MaxRecordLength - 8 && - "subrecord is too large to slide!"); - Builder.truncate(SubrecordStart); - - // Write a placeholder continuation record. - Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation); - Builder.writeUInt16(0); - Builder.writeUInt32(0); - ContinuationOffsets.push_back(Builder.size()); - assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size"); - assert(getLastContinuationSize() < MaxRecordLength && "segment too big"); - - // Start a new list record of the appropriate kind, and copy the previous - // subrecord into place. - Builder.writeTypeRecordKind(Kind); - Builder.writeBytes(SubrecordCopy); - } - - SubrecordStart = Builder.size(); -} - -TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) { - // Get the continuation segments as a reversed vector of StringRefs for - // convenience. - SmallVector<StringRef, 1> Segments; - StringRef Data = str(); - size_t LastEnd = 0; - for (size_t SegEnd : ContinuationOffsets) { - Segments.push_back(Data.slice(LastEnd, SegEnd)); - LastEnd = SegEnd; - } - Segments.push_back(Data.slice(LastEnd, Builder.size())); - - // Pop the last record off and emit it directly. - StringRef LastRec = Segments.pop_back_val(); - TypeIndex ContinuationIndex = Table.writeRecord(LastRec); - - // Emit each record with a continuation in reverse order, so that each one - // references the previous record. - for (StringRef Rec : reverse(Segments)) { - assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) == - unsigned(Kind)); - ulittle32_t *ContinuationPtr = - reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1; - *ContinuationPtr = ContinuationIndex.getIndex(); - ContinuationIndex = Table.writeRecord(Rec); - } - return ContinuationIndex; -} diff --git a/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp deleted file mode 100644 index 8b9e73b94ff..00000000000 --- a/llvm/lib/DebugInfo/CodeView/MemoryTypeTableBuilder.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//===-- MemoryTypeTableBuilder.cpp ----------------------------------------===// -// -// 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/MemoryTypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" - -using namespace llvm; -using namespace codeview; - -TypeIndex MemoryTypeTableBuilder::writeRecord(StringRef Data) { - assert(Data.size() <= UINT16_MAX); - auto I = HashedRecords.find(Data); - if (I != HashedRecords.end()) { - return I->second; - } - - // The record provided by the user lacks the 2 byte size field prefix and is - // not padded to 4 bytes. Ultimately, that is what gets emitted in the object - // file, so pad it out now. - const int SizeOfRecLen = 2; - const int Align = 4; - int TotalSize = alignTo(Data.size() + SizeOfRecLen, Align); - assert(TotalSize - SizeOfRecLen <= UINT16_MAX); - char *Mem = - reinterpret_cast<char *>(RecordStorage.Allocate(TotalSize, Align)); - *reinterpret_cast<ulittle16_t *>(Mem) = uint16_t(TotalSize - SizeOfRecLen); - memcpy(Mem + SizeOfRecLen, Data.data(), Data.size()); - for (int I = Data.size() + SizeOfRecLen; I < TotalSize; ++I) - Mem[I] = LF_PAD0 + (TotalSize - I); - - TypeIndex TI(static_cast<uint32_t>(Records.size()) + - TypeIndex::FirstNonSimpleIndex); - - // Use only the data supplied by the user as a key to the hash table, so that - // future lookups will succeed. - HashedRecords.insert(std::make_pair(StringRef(Mem + SizeOfRecLen, Data.size()), TI)); - Records.push_back(StringRef(Mem, TotalSize)); - - return TI; -} diff --git a/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp deleted file mode 100644 index ae089a35208..00000000000 --- a/llvm/lib/DebugInfo/CodeView/MethodListRecordBuilder.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===-- MethodListRecordBuilder.cpp ---------------------------------------===// -// -// 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/MethodListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -MethodListRecordBuilder::MethodListRecordBuilder() - : ListRecordBuilder(TypeRecordKind::MethodOverloadList) {} - -void MethodListRecordBuilder::writeMethod(MemberAccess Access, MethodKind Kind, - MethodOptions Options, TypeIndex Type, - int32_t VTableSlotOffset) { - TypeRecordBuilder &Builder = getBuilder(); - - uint16_t Flags = static_cast<uint16_t>(Access); - Flags |= static_cast<uint16_t>(Kind) << MethodKindShift; - Flags |= static_cast<uint16_t>(Options); - - Builder.writeUInt16(Flags); - Builder.writeUInt16(0); - Builder.writeTypeIndex(Type); - switch (Kind) { - case MethodKind::IntroducingVirtual: - case MethodKind::PureIntroducingVirtual: - assert(VTableSlotOffset >= 0); - Builder.writeInt32(VTableSlotOffset); - break; - - default: - assert(VTableSlotOffset == -1); - break; - } - - // TODO: Fail if too big? -} - -void MethodListRecordBuilder::writeMethod(const MethodInfo &Method) { - writeMethod(Method.getAccess(), Method.getKind(), Method.getOptions(), - Method.getType(), Method.getVTableSlotOffset()); -} diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index 84abad91c53..4274d834076 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -428,7 +428,7 @@ Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, MethodOverloadListRecord &MethodList) { for (auto &M : MethodList.getMethods()) { ListScope S(*W, "Method"); - printMemberAttributes(M.getAccess(), M.getKind(), M.getOptions()); + printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions()); printTypeIndex("Type", M.getType()); if (M.isIntroducingVirtual()) W->printHex("VFTableOffset", M.getVFTableOffset()); @@ -607,7 +607,7 @@ Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, Error CVTypeDumper::visitKnownMember(CVMemberRecord &CVR, OneMethodRecord &Method) { - MethodKind K = Method.getKind(); + MethodKind K = Method.getMethodKind(); printMemberAttributes(Method.getAccess(), K, Method.getOptions()); printTypeIndex("Type", Method.getType()); // If virtual, then read the vftable offset. diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp deleted file mode 100644 index f775bdd8202..00000000000 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordBuilder.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===-- TypeRecordBuilder.cpp ---------------------------------------------===// -// -// 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/TypeRecordBuilder.h" - -using namespace llvm; -using namespace codeview; - -TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) - : Kind(Kind), Stream(Buffer), Writer(Stream) { - writeTypeRecordKind(Kind); -} - -StringRef TypeRecordBuilder::str() { - return StringRef(Buffer.data(), Buffer.size()); -} - -void TypeRecordBuilder::writeUInt8(uint8_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt16(int16_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt16(uint16_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt32(int32_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt32(uint32_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeInt64(int64_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeUInt64(uint64_t Value) { - Writer.write(Value); -} - -void TypeRecordBuilder::writeEncodedInteger(int64_t Value) { - if (Value >= 0) { - writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)); - } else { - writeEncodedSignedInteger(Value); - } -} - -void TypeRecordBuilder::writeEncodedSignedInteger(int64_t Value) { - if (Value >= std::numeric_limits<int8_t>::min() && - Value <= std::numeric_limits<int8_t>::max()) { - writeUInt16(LF_CHAR); - writeInt16(static_cast<int8_t>(Value)); - } else if (Value >= std::numeric_limits<int16_t>::min() && - Value <= std::numeric_limits<int16_t>::max()) { - writeUInt16(LF_SHORT); - writeInt16(static_cast<int16_t>(Value)); - } else if (Value >= std::numeric_limits<int32_t>::min() && - Value <= std::numeric_limits<int32_t>::max()) { - writeUInt16(LF_LONG); - writeInt32(static_cast<int32_t>(Value)); - } else { - writeUInt16(LF_QUADWORD); - writeInt64(Value); - } -} - -void TypeRecordBuilder::writeEncodedUnsignedInteger(uint64_t Value) { - if (Value < LF_CHAR) { - writeUInt16(static_cast<uint16_t>(Value)); - } else if (Value <= std::numeric_limits<uint16_t>::max()) { - writeUInt16(LF_USHORT); - writeUInt16(static_cast<uint16_t>(Value)); - } else if (Value <= std::numeric_limits<uint32_t>::max()) { - writeUInt16(LF_ULONG); - writeUInt32(static_cast<uint32_t>(Value)); - } else { - writeUInt16(LF_UQUADWORD); - writeUInt64(Value); - } -} - -void TypeRecordBuilder::writeNullTerminatedString(StringRef Value) { - // Usually the null terminated string comes last, so truncate it to avoid a - // record larger than MaxNameLength. Don't do this if this is a list record. - // Those have special handling to split the record. - unsigned MaxNameLength = MaxRecordLength; - if (Kind != TypeRecordKind::FieldList && - Kind != TypeRecordKind::MethodOverloadList) - MaxNameLength = maxBytesRemaining(); - assert(MaxNameLength > 0 && "need room for null terminator"); - Value = Value.take_front(MaxNameLength - 1); - Stream.write(Value.data(), Value.size()); - writeUInt8(0); -} - -void TypeRecordBuilder::writeGuid(StringRef Guid) { - assert(Guid.size() == 16); - Stream.write(Guid.data(), 16); -} - -void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) { - writeUInt32(TypeInd.getIndex()); -} - -void TypeRecordBuilder::writeTypeRecordKind(TypeRecordKind Kind) { - writeUInt16(static_cast<uint16_t>(Kind)); -} diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp index d85a643c6d2..f260ddad3fd 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -17,24 +17,6 @@ using namespace llvm::codeview; return EC; namespace { -struct MapStringZ { - Error operator()(CodeViewRecordIO &IO, StringRef &S) const { - return IO.mapStringZ(S); - } -}; - -struct MapInteger { - template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const { - return IO.mapInteger(N); - } -}; - -struct MapEnum { - template <typename T> Error operator()(CodeViewRecordIO &IO, T &N) const { - return IO.mapEnum(N); - } -}; - struct MapOneMethodRecord { explicit MapOneMethodRecord(bool IsFromOverloadList) : IsFromOverloadList(IsFromOverloadList) {} @@ -64,35 +46,97 @@ private: static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name, StringRef &UniqueName, bool HasUniqueName) { - error(IO.mapStringZ(Name)); - if (HasUniqueName) - error(IO.mapStringZ(UniqueName)); + if (IO.isWriting()) { + // Try to be smart about what we write here. We can't write anything too + // large, so if we're going to go over the limit, truncate both the name + // and unique name by the same amount. + uint32_t BytesLeft = IO.maxFieldLength(); + if (HasUniqueName) { + uint32_t BytesNeeded = Name.size() + UniqueName.size() + 2; + StringRef N = Name; + StringRef U = UniqueName; + if (BytesNeeded > BytesLeft) { + uint32_t BytesToDrop = (BytesNeeded - BytesLeft); + uint32_t DropN = std::min(N.size(), BytesToDrop / 2); + uint32_t DropU = std::min(U.size(), BytesToDrop - DropN); + + N = N.drop_back(DropN); + U = U.drop_back(DropU); + } + + error(IO.mapStringZ(N)); + error(IO.mapStringZ(U)); + } else { + uint32_t BytesNeeded = Name.size() + 1; + StringRef N = Name; + if (BytesNeeded > BytesLeft) { + uint32_t BytesToDrop = std::min(N.size(), BytesToDrop); + N = N.drop_back(BytesToDrop); + } + error(IO.mapStringZ(N)); + } + } else { + error(IO.mapStringZ(Name)); + if (HasUniqueName) + error(IO.mapStringZ(UniqueName)); + } return Error::success(); } Error TypeRecordMapping::visitTypeBegin(CVType &CVR) { - error(IO.beginRecord(CVR.Type)); + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(!MemberKind.hasValue() && "Already in a member mapping!"); + + // FieldList and MethodList records can be any length because they can be + // split with continuation records. All other record types cannot be + // longer than the maximum record length. + Optional<uint32_t> MaxLen; + if (CVR.Type != TypeLeafKind::LF_FIELDLIST && + CVR.Type != TypeLeafKind::LF_METHODLIST) + MaxLen = MaxRecordLength - sizeof(RecordPrefix); + error(IO.beginRecord(MaxLen)); TypeKind = CVR.Type; return Error::success(); } Error TypeRecordMapping::visitTypeEnd(CVType &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(!MemberKind.hasValue() && "Still in a member mapping!"); + error(IO.endRecord()); + TypeKind.reset(); return Error::success(); } Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(!MemberKind.hasValue() && "Already in a member mapping!"); + + // The largest possible subrecord is one in which there is a record prefix, + // followed by the subrecord, followed by a continuation, and that entire + // sequence spaws `MaxRecordLength` bytes. So the record's length is + // calculated as follows. + constexpr uint32_t ContinuationLength = 8; + error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) - + ContinuationLength)); + + MemberKind = Record.Kind; return Error::success(); } Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + assert(MemberKind.hasValue() && "Not in a member mapping!"); + if (!IO.isWriting()) { if (auto EC = IO.skipPadding()) return EC; } + MemberKind.reset(); + error(IO.endRecord()); return Error::success(); } @@ -129,7 +173,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, } Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { - error(IO.mapVectorN<uint32_t>(Record.StringIndices, MapInteger())); + error(IO.mapVectorN<uint32_t>( + Record.StringIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); return Error::success(); } @@ -245,7 +291,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) { NamesLen += Name.size() + 1; } error(IO.mapInteger(NamesLen)); - error(IO.mapVectorTail(Record.MethodNames, MapStringZ())); + error(IO.mapVectorTail( + Record.MethodNames, + [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); })); return Error::success(); } @@ -295,7 +343,9 @@ Error TypeRecordMapping::visitKnownRecord(CVType &CVR, Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BuildInfoRecord &Record) { - error(IO.mapVectorN<uint16_t>(Record.ArgIndices, MapInteger())); + error(IO.mapVectorN<uint16_t>( + Record.ArgIndices, + [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); })); return Error::success(); } diff --git a/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp b/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp new file mode 100644 index 00000000000..f24fcff8627 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeSerializer.cpp @@ -0,0 +1,243 @@ +//===- TypeSerialzier.cpp ---------------------------------------*- 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/CodeView/TypeSerializer.h" + +#include "llvm/DebugInfo/MSF/StreamWriter.h" + +#include <string.h> + +using namespace llvm; +using namespace llvm::codeview; + +bool TypeSerializer::isInFieldList() const { + return TypeKind.hasValue() && *TypeKind == TypeLeafKind::LF_FIELDLIST; +} + +TypeIndex TypeSerializer::calcNextTypeIndex() const { + if (LastTypeIndex.isNoneType()) + return TypeIndex(TypeIndex::FirstNonSimpleIndex); + else + return TypeIndex(LastTypeIndex.getIndex() + 1); +} + +TypeIndex TypeSerializer::incrementTypeIndex() { + TypeIndex Previous = LastTypeIndex; + LastTypeIndex = calcNextTypeIndex(); + return Previous; +} + +MutableArrayRef<uint8_t> TypeSerializer::getCurrentSubRecordData() { + assert(isInFieldList()); + return getCurrentRecordData().drop_front(CurrentSegment.length()); +} + +MutableArrayRef<uint8_t> TypeSerializer::getCurrentRecordData() { + return MutableArrayRef<uint8_t>(RecordBuffer).take_front(Writer.getOffset()); +} + +Error TypeSerializer::writeRecordPrefix(TypeLeafKind Kind) { + RecordPrefix Prefix; + Prefix.RecordKind = Kind; + Prefix.RecordLen = 0; + if (auto EC = Writer.writeObject(Prefix)) + return EC; + return Error::success(); +} + +TypeIndex +TypeSerializer::insertRecordBytesPrivate(MutableArrayRef<uint8_t> Record) { + assert(Record.size() % 4 == 0 && "Record is not aligned to 4 bytes!"); + + StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size()); + + TypeIndex NextTypeIndex = calcNextTypeIndex(); + auto Result = HashedRecords.try_emplace(S, NextTypeIndex); + if (Result.second) { + LastTypeIndex = NextTypeIndex; + SeenRecords.push_back(Record); + } + return Result.first->getValue(); +} + +Expected<MutableArrayRef<uint8_t>> +TypeSerializer::addPadding(MutableArrayRef<uint8_t> Record) { + uint32_t Align = Record.size() % 4; + if (Align == 0) + return Record; + + int PaddingBytes = 4 - Align; + int N = PaddingBytes; + while (PaddingBytes > 0) { + uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes); + if (auto EC = Writer.writeInteger(Pad)) + return std::move(EC); + --PaddingBytes; + } + return MutableArrayRef<uint8_t>(Record.data(), Record.size() + N); +} + +TypeSerializer::TypeSerializer(BumpPtrAllocator &Storage) + : RecordStorage(Storage), LastTypeIndex(), + RecordBuffer(MaxRecordLength * 2), Stream(RecordBuffer), Writer(Stream), + Mapping(Writer) { + // RecordBuffer needs to be able to hold enough data so that if we are 1 + // byte short of MaxRecordLen, and then we try to write MaxRecordLen bytes, + // we won't overflow. +} + +ArrayRef<MutableArrayRef<uint8_t>> TypeSerializer::records() const { + return SeenRecords; +} + +TypeIndex TypeSerializer::getLastTypeIndex() const { return LastTypeIndex; } + +TypeIndex TypeSerializer::insertRecordBytes(MutableArrayRef<uint8_t> Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + return insertRecordBytesPrivate(Record); +} + +Error TypeSerializer::visitTypeBegin(CVType &Record) { + assert(!TypeKind.hasValue() && "Already in a type mapping!"); + assert(Writer.getOffset() == 0 && "Stream has data already!"); + + if (auto EC = writeRecordPrefix(Record.kind())) + return EC; + + TypeKind = Record.kind(); + if (auto EC = Mapping.visitTypeBegin(Record)) + return EC; + + return Error::success(); +} + +Expected<TypeIndex> TypeSerializer::visitTypeEndGetIndex(CVType &Record) { + assert(TypeKind.hasValue() && "Not in a type mapping!"); + if (auto EC = Mapping.visitTypeEnd(Record)) + return std::move(EC); + + // Update the record's length and fill out the CVType members to point to + // the stable memory holding the record's data. + auto ThisRecordData = getCurrentRecordData(); + auto ExpectedData = addPadding(ThisRecordData); + if (!ExpectedData) + return ExpectedData.takeError(); + ThisRecordData = *ExpectedData; + + RecordPrefix *Prefix = + reinterpret_cast<RecordPrefix *>(ThisRecordData.data()); + Prefix->RecordLen = ThisRecordData.size() - sizeof(uint16_t); + + uint8_t *Copy = RecordStorage.Allocate<uint8_t>(ThisRecordData.size()); + ::memcpy(Copy, ThisRecordData.data(), ThisRecordData.size()); + ThisRecordData = MutableArrayRef<uint8_t>(Copy, ThisRecordData.size()); + Record = CVType(*TypeKind, ThisRecordData); + TypeIndex InsertedTypeIndex = insertRecordBytesPrivate(ThisRecordData); + + // Write out each additional segment in reverse order, and update each + // record's continuation index to point to the previous one. + for (auto X : reverse(FieldListSegments)) { + auto CIBytes = X.take_back(sizeof(uint32_t)); + support::ulittle32_t *CI = + reinterpret_cast<support::ulittle32_t *>(CIBytes.data()); + assert(*CI == 0xB0C0B0C0 && "Invalid TypeIndex placeholder"); + *CI = InsertedTypeIndex.getIndex(); + InsertedTypeIndex = insertRecordBytesPrivate(X); + } + + TypeKind.reset(); + Writer.setOffset(0); + FieldListSegments.clear(); + CurrentSegment.SubRecords.clear(); + + return InsertedTypeIndex; +} + +Error TypeSerializer::visitTypeEnd(CVType &Record) { + auto ExpectedIndex = visitTypeEndGetIndex(Record); + if (!ExpectedIndex) + return ExpectedIndex.takeError(); + return Error::success(); +} + +Error TypeSerializer::visitMemberBegin(CVMemberRecord &Record) { + assert(isInFieldList() && "Not in a field list!"); + assert(!MemberKind.hasValue() && "Already in a member record!"); + MemberKind = Record.Kind; + + if (auto EC = Mapping.visitMemberBegin(Record)) + return EC; + + return Error::success(); +} + +Error TypeSerializer::visitMemberEnd(CVMemberRecord &Record) { + if (auto EC = Mapping.visitMemberEnd(Record)) + return EC; + + // Check if this subrecord makes the current segment not fit in 64K minus + // the space for a continuation record (8 bytes). If the segment does not + // fit, insert a continuation record. + if (Writer.getOffset() > MaxRecordLength - ContinuationLength) { + MutableArrayRef<uint8_t> Data = getCurrentRecordData(); + SubRecord LastSubRecord = CurrentSegment.SubRecords.back(); + uint32_t CopySize = CurrentSegment.length() - LastSubRecord.Size; + auto CopyData = Data.take_front(CopySize); + auto LeftOverData = Data.drop_front(CopySize); + assert(LastSubRecord.Size == LeftOverData.size()); + + // Allocate stable storage for the record and copy the old record plus + // continuation over. + uint16_t LengthWithSize = CopySize + ContinuationLength; + assert(LengthWithSize <= MaxRecordLength); + RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(CopyData.data()); + Prefix->RecordLen = LengthWithSize - sizeof(uint16_t); + + uint8_t *SegmentBytes = RecordStorage.Allocate<uint8_t>(LengthWithSize); + auto SavedSegment = MutableArrayRef<uint8_t>(SegmentBytes, LengthWithSize); + msf::MutableByteStream CS(SavedSegment); + msf::StreamWriter CW(CS); + if (auto EC = CW.writeBytes(CopyData)) + return EC; + if (auto EC = CW.writeEnum(TypeLeafKind::LF_INDEX)) + return EC; + if (auto EC = CW.writeInteger(uint16_t(0))) + return EC; + if (auto EC = CW.writeInteger(uint32_t(0xB0C0B0C0))) + return EC; + FieldListSegments.push_back(SavedSegment); + + // Write a new placeholder record prefix to mark the start of this new + // top-level record. + Writer.setOffset(0); + if (auto EC = writeRecordPrefix(TypeLeafKind::LF_FIELDLIST)) + return EC; + + // Then move over the subrecord that overflowed the old segment to the + // beginning of this segment. Note that we have to use memmove here + // instead of Writer.writeBytes(), because the new and old locations + // could overlap. + ::memmove(Stream.data().data() + sizeof(RecordPrefix), LeftOverData.data(), + LeftOverData.size()); + // And point the segment writer at the end of that subrecord. + Writer.setOffset(LeftOverData.size() + sizeof(RecordPrefix)); + + CurrentSegment.SubRecords.clear(); + CurrentSegment.SubRecords.push_back(LastSubRecord); + } + + // Update the CVMemberRecord since we may have shifted around or gotten + // padded. + Record.Data = getCurrentSubRecordData(); + + MemberKind.reset(); + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index 551a98a67c8..ed6cf5743a1 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -11,10 +11,10 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" #include "llvm/Support/Error.h" @@ -54,7 +54,8 @@ namespace { /// existing destination type index. class TypeStreamMerger : public TypeVisitorCallbacks { public: - TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) { + TypeStreamMerger(TypeTableBuilder &DestStream) + : DestStream(DestStream), FieldListBuilder(DestStream) { assert(!hadError()); } @@ -94,7 +95,7 @@ private: template <typename RecordType> Error visitKnownMemberRecordImpl(RecordType &Record) { FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); - FieldBuilder.writeMemberType(Record); + FieldListBuilder.writeMemberType(Record); return Error::success(); } @@ -102,9 +103,10 @@ private: bool FoundBadTypeIndex = false; - FieldListRecordBuilder FieldBuilder; + BumpPtrAllocator Allocator; TypeTableBuilder &DestStream; + FieldListRecordBuilder FieldListBuilder; bool IsInFieldList{false}; size_t BeginIndexMapSize = 0; @@ -120,6 +122,7 @@ Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) { if (Rec.Type == TypeLeafKind::LF_FIELDLIST) { assert(!IsInFieldList); IsInFieldList = true; + FieldListBuilder.begin(); } else BeginIndexMapSize = IndexMap.size(); return Error::success(); @@ -127,8 +130,8 @@ Error TypeStreamMerger::visitTypeBegin(CVRecord<TypeLeafKind> &Rec) { Error TypeStreamMerger::visitTypeEnd(CVRecord<TypeLeafKind> &Rec) { if (Rec.Type == TypeLeafKind::LF_FIELDLIST) { - IndexMap.push_back(DestStream.writeFieldList(FieldBuilder)); - FieldBuilder.reset(); + TypeIndex Index = FieldListBuilder.end(); + IndexMap.push_back(Index); IsInFieldList = false; } return Error::success(); diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp deleted file mode 100644 index 1bd0b3f4382..00000000000 --- a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ /dev/null @@ -1,300 +0,0 @@ -//===-- TypeTableBuilder.cpp ----------------------------------------------===// -// -// 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/TypeTableBuilder.h" -#include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" -#include "llvm/DebugInfo/CodeView/TypeIndex.h" -#include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" -#include "llvm/Support/raw_ostream.h" - -using namespace llvm; -using namespace codeview; - -TypeTableBuilder::TypeTableBuilder() {} - -TypeTableBuilder::~TypeTableBuilder() {} - -TypeIndex TypeTableBuilder::writeKnownType(const ModifierRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getModifiedType()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers())); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const ProcedureRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReturnType()); - Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); - Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); - Builder.writeUInt16(Record.getParameterCount()); - Builder.writeTypeIndex(Record.getArgumentList()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const MemberFunctionRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReturnType()); - Builder.writeTypeIndex(Record.getClassType()); - Builder.writeTypeIndex(Record.getThisType()); - Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); - Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); - Builder.writeUInt16(Record.getParameterCount()); - Builder.writeTypeIndex(Record.getArgumentList()); - Builder.writeInt32(Record.getThisPointerAdjustment()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const ArgListRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt32(Record.getIndices().size()); - for (TypeIndex TI : Record.getIndices()) { - Builder.writeTypeIndex(TI); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getReferentType()); - Builder.writeUInt32(Record.Attrs); - - if (Record.isPointerToMember()) { - const MemberPointerInfo &M = Record.getMemberInfo(); - Builder.writeTypeIndex(M.getContainingType()); - Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation())); - } - - return writeRecord(Builder); -} - -static void writeNameAndUniqueName(TypeRecordBuilder &Builder, ClassOptions CO, - StringRef Name, StringRef UniqueName) { - // Truncate the names to half the remaining record length. - unsigned MaxNameLength = Builder.maxBytesRemaining() / 2; - Name = Name.take_front(MaxNameLength - 1); - UniqueName = UniqueName.take_front(MaxNameLength - 1); - - Builder.writeNullTerminatedString(Name); - if ((CO & ClassOptions::HasUniqueName) != ClassOptions::None) { - Builder.writeNullTerminatedString(UniqueName); - } -} - -TypeIndex TypeTableBuilder::writeKnownType(const ArrayRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getElementType()); - Builder.writeTypeIndex(Record.getIndexType()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - Builder.writeNullTerminatedString(Record.getName()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const ClassRecord &Record) { - assert((Record.getKind() == TypeRecordKind::Struct) || - (Record.getKind() == TypeRecordKind::Class) || - (Record.getKind() == TypeRecordKind::Interface)); - - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt16(Record.getMemberCount()); - uint16_t Flags = - static_cast<uint16_t>(Record.getOptions()) | - (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) | - (static_cast<uint16_t>(Record.getWinRTKind()) - << ClassRecord::WinRTKindShift); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getFieldList()); - Builder.writeTypeIndex(Record.getDerivationList()); - Builder.writeTypeIndex(Record.getVTableShape()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(), - Record.getUniqueName()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const UnionRecord &Record) { - TypeRecordBuilder Builder(TypeRecordKind::Union); - Builder.writeUInt16(Record.getMemberCount()); - uint16_t Flags = - static_cast<uint16_t>(Record.getOptions()) | - (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift); - Builder.writeUInt16(Flags); - Builder.writeTypeIndex(Record.getFieldList()); - Builder.writeEncodedUnsignedInteger(Record.getSize()); - writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(), - Record.getUniqueName()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const EnumRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeUInt16(Record.getMemberCount()); - Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions())); - Builder.writeTypeIndex(Record.getUnderlyingType()); - Builder.writeTypeIndex(Record.getFieldList()); - writeNameAndUniqueName(Builder, Record.getOptions(), Record.getName(), - Record.getUniqueName()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const BitFieldRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - Builder.writeTypeIndex(Record.getType()); - Builder.writeUInt8(Record.getBitSize()); - Builder.writeUInt8(Record.getBitOffset()); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const VFTableShapeRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - - ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); - - Builder.writeUInt16(Slots.size()); - for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { - uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; - if ((SlotIndex + 1) < Slots.size()) { - Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); - } - Builder.writeUInt8(Byte); - } - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const VFTableRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getCompleteClass()); - Builder.writeTypeIndex(Record.getOverriddenVTable()); - Builder.writeUInt32(Record.getVFPtrOffset()); - - // Sum up the lengths of the null-terminated names. - size_t NamesLen = Record.getName().size() + 1; - for (StringRef MethodName : Record.getMethodNames()) - NamesLen += MethodName.size() + 1; - - // FIXME: Avoid creating a record longer than MaxRecordLength. - Builder.writeUInt32(NamesLen); - Builder.writeNullTerminatedString(Record.getName()); - for (StringRef MethodName : Record.getMethodNames()) - Builder.writeNullTerminatedString(MethodName); - - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const StringIdRecord &Record) { - TypeRecordBuilder Builder(TypeRecordKind::StringId); - Builder.writeTypeIndex(Record.getId()); - Builder.writeNullTerminatedString(Record.getString()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const UdtSourceLineRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getUDT()); - Builder.writeTypeIndex(Record.getSourceFile()); - Builder.writeUInt32(Record.getLineNumber()); - return writeRecord(Builder); -} - -TypeIndex -TypeTableBuilder::writeKnownType(const UdtModSourceLineRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getUDT()); - Builder.writeTypeIndex(Record.getSourceFile()); - Builder.writeUInt32(Record.getLineNumber()); - Builder.writeUInt16(Record.getModule()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const FuncIdRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getParentScope()); - Builder.writeTypeIndex(Record.getFunctionType()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const MemberFuncIdRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeTypeIndex(Record.getClassType()); - Builder.writeTypeIndex(Record.getFunctionType()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const BuildInfoRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - assert(Record.getArgs().size() <= UINT16_MAX); - Builder.writeUInt16(Record.getArgs().size()); - for (TypeIndex Arg : Record.getArgs()) - Builder.writeTypeIndex(Arg); - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) { - TypeIndex I = writeRecord(Builder.str()); - RecordKinds.push_back(Builder.kind()); - return I; -} - -TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { - TypeIndex I = FieldList.writeListRecord(*this); - RecordKinds.push_back(TypeRecordKind::FieldList); - return I; -} - -TypeIndex -TypeTableBuilder::writeKnownType(const MethodOverloadListRecord &Record) { - TypeRecordBuilder Builder(Record.getKind()); - for (const OneMethodRecord &Method : Record.getMethods()) { - uint16_t Flags = static_cast<uint16_t>(Method.getAccess()); - Flags |= static_cast<uint16_t>(Method.getKind()) - << MemberAttributes::MethodKindShift; - Flags |= static_cast<uint16_t>(Method.getOptions()); - Builder.writeUInt16(Flags); - Builder.writeUInt16(0); // padding - Builder.writeTypeIndex(Method.getType()); - if (Method.isIntroducingVirtual()) { - assert(Method.getVFTableOffset() >= 0); - Builder.writeInt32(Method.getVFTableOffset()); - } else { - assert(Method.getVFTableOffset() == -1); - } - } - - // TODO: Split the list into multiple records if it's longer than 64KB, using - // a subrecord of TypeRecordKind::Index to chain the records together. - return writeRecord(Builder); -} - -TypeIndex TypeTableBuilder::writeKnownType(const TypeServer2Record &Record) { - TypeRecordBuilder Builder(Record.getKind()); - Builder.writeGuid(Record.getGuid()); - Builder.writeUInt32(Record.getAge()); - Builder.writeNullTerminatedString(Record.getName()); - return writeRecord(Builder); -} |