diff options
author | Zachary Turner <zturner@google.com> | 2016-11-02 17:05:19 +0000 |
---|---|---|
committer | Zachary Turner <zturner@google.com> | 2016-11-02 17:05:19 +0000 |
commit | 7251ede7c5ee82d25e309b6a30952a6b5e7c1f89 (patch) | |
tree | 3b4fb352c4fb41db708e3778d3e1aef75a47eed0 /llvm/lib/DebugInfo | |
parent | 368972c3b3b8ad62fa064b495223809074c39115 (diff) | |
download | bcm5719-llvm-7251ede7c5ee82d25e309b6a30952a6b5e7c1f89.tar.gz bcm5719-llvm-7251ede7c5ee82d25e309b6a30952a6b5e7c1f89.zip |
Add CodeViewRecordIO for reading and writing.
Using a pattern similar to that of YamlIO, this allows
us to have a single codepath for translating codeview
records to and from serialized byte streams. The
current patch only hooks this up to the reading of
CodeView type records. A subsequent patch will hook
it up for writing of CodeView type records, and then a
third patch will hook up the reading and writing of
CodeView symbols.
Differential Revision: https://reviews.llvm.org/D26040
llvm-svn: 285836
Diffstat (limited to 'llvm/lib/DebugInfo')
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CMakeLists.txt | 2 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp | 66 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp | 186 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeDumper.cpp | 7 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecord.cpp | 378 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp | 417 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp | 9 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/DebugInfo/MSF/StreamWriter.cpp | 20 |
9 files changed, 657 insertions, 436 deletions
diff --git a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt index a0700804301..4bbc48d111f 100644 --- a/llvm/lib/DebugInfo/CodeView/CMakeLists.txt +++ b/llvm/lib/DebugInfo/CodeView/CMakeLists.txt @@ -1,5 +1,6 @@ add_llvm_library(LLVMDebugInfoCodeView CodeViewError.cpp + CodeViewRecordIO.cpp CVSymbolVisitor.cpp CVTypeVisitor.cpp EnumTables.cpp @@ -15,6 +16,7 @@ add_llvm_library(LLVMDebugInfoCodeView TypeDumper.cpp TypeRecord.cpp TypeRecordBuilder.cpp + TypeRecordMapping.cpp TypeStreamMerger.cpp TypeTableBuilder.cpp diff --git a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp index 2dee8988df9..5f5d5fe35ef 100644 --- a/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp +++ b/llvm/lib/DebugInfo/CodeView/CVTypeVisitor.cpp @@ -10,44 +10,29 @@ #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" +#include "llvm/DebugInfo/CodeView/TypeDeserializer.h" +#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h" #include "llvm/DebugInfo/MSF/ByteStream.h" using namespace llvm; using namespace llvm::codeview; -static Error skipPadding(msf::StreamReader &Reader) { - if (Reader.empty()) - return Error::success(); - - uint8_t Leaf = Reader.peek(); - if (Leaf < LF_PAD0) - return Error::success(); - // Leaf is greater than 0xf0. We should advance by the number of bytes in - // the low 4 bits. - unsigned BytesToAdvance = Leaf & 0x0F; - return Reader.skip(BytesToAdvance); -} - template <typename T> static Expected<CVMemberRecord> -deserializeMemberRecord(msf::StreamReader &Reader, TypeLeafKind Kind) { - msf::StreamReader OldReader = Reader; - TypeRecordKind RK = static_cast<TypeRecordKind>(Kind); - auto ExpectedRecord = T::deserialize(RK, Reader); - if (!ExpectedRecord) - return ExpectedRecord.takeError(); - assert(Reader.bytesRemaining() < OldReader.bytesRemaining()); - if (auto EC = skipPadding(Reader)) - return std::move(EC); +deserializeMemberRecord(FieldListDeserializer &Deserializer, + msf::StreamReader &Reader, TypeLeafKind Kind) { + T MR(static_cast<TypeRecordKind>(Kind)); + CVMemberRecord CVR; + CVR.Kind = Kind; - CVMemberRecord CVMR; - CVMR.Kind = Kind; - - uint32_t RecordLength = OldReader.bytesRemaining() - Reader.bytesRemaining(); - if (auto EC = OldReader.readBytes(CVMR.Data, RecordLength)) + 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 CVMR; + return CVR; } CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks) @@ -138,22 +123,28 @@ Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) { } template <typename MR> -static Error visitKnownMember(msf::StreamReader &Reader, TypeLeafKind Leaf, +static Error visitKnownMember(FieldListDeserializer &Deserializer, + msf::StreamReader &Reader, TypeLeafKind Leaf, TypeVisitorCallbacks &Callbacks) { - auto ExpectedRecord = deserializeMemberRecord<MR>(Reader, Leaf); - if (!ExpectedRecord) - return ExpectedRecord.takeError(); - CVMemberRecord &Record = *ExpectedRecord; - if (auto EC = Callbacks.visitMemberBegin(Record)) + MR Record(static_cast<TypeRecordKind>(Leaf)); + CVMemberRecord CVR; + CVR.Kind = Leaf; + + if (auto EC = Callbacks.visitMemberBegin(CVR)) return EC; - if (auto EC = visitKnownMember<MR>(Record, Callbacks)) + if (auto EC = Callbacks.visitKnownMember(CVR, Record)) return EC; - if (auto EC = Callbacks.visitMemberEnd(Record)) + if (auto EC = Callbacks.visitMemberEnd(CVR)) return EC; return Error::success(); } Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { + FieldListDeserializer Deserializer(Reader); + TypeVisitorCallbackPipeline Pipeline; + Pipeline.addCallbackToPipeline(Deserializer); + Pipeline.addCallbackToPipeline(Callbacks); + TypeLeafKind Leaf; while (!Reader.empty()) { if (auto EC = Reader.readEnum(Leaf)) @@ -168,7 +159,8 @@ Error CVTypeVisitor::visitFieldListMemberStream(msf::StreamReader Reader) { cv_error_code::unknown_member_record); #define MEMBER_RECORD(EnumName, EnumVal, Name) \ case EnumName: { \ - if (auto EC = visitKnownMember<Name##Record>(Reader, Leaf, Callbacks)) \ + if (auto EC = visitKnownMember<Name##Record>(Deserializer, Reader, Leaf, \ + Pipeline)) \ return EC; \ break; \ } diff --git a/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp new file mode 100644 index 00000000000..7841e4f2f6a --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp @@ -0,0 +1,186 @@ +//===- CodeViewRecordIO.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/CodeViewRecordIO.h" +#include "llvm/DebugInfo/CodeView/CodeView.h" +#include "llvm/DebugInfo/CodeView/RecordSerialization.h" +#include "llvm/DebugInfo/MSF/StreamReader.h" +#include "llvm/DebugInfo/MSF/StreamWriter.h" + +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; + return Error::success(); +} + +Error CodeViewRecordIO::endRecord() { + assert(CurrentRecord.hasValue() && "Not in a record!"); + CurrentRecord.reset(); + return Error::success(); +} + +Error CodeViewRecordIO::skipPadding() { + assert(!isWriting() && "Cannot skip padding while writing!"); + + if (Reader->bytesRemaining() == 0) + return Error::success(); + + uint8_t Leaf = Reader->peek(); + if (Leaf < LF_PAD0) + return Error::success(); + // Leaf is greater than 0xf0. We should advance by the number of bytes in + // the low 4 bits. + unsigned BytesToAdvance = Leaf & 0x0F; + return Reader->skip(BytesToAdvance); +} + +Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes) { + if (isWriting()) { + if (auto EC = Writer->writeBytes(Bytes)) + return EC; + } else { + if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining())) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd) { + if (isWriting()) { + if (auto EC = Writer->writeInteger(TypeInd.getIndex())) + return EC; + return Error::success(); + } + + uint32_t I; + if (auto EC = Reader->readInteger(I)) + return EC; + TypeInd.setIndex(I); + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value) { + if (isWriting()) { + if (Value >= 0) { + if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value))) + return EC; + } else { + if (auto EC = writeEncodedSignedInteger(Value)) + return EC; + } + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getExtValue(); + } + + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value) { + if (isWriting()) { + if (auto EC = writeEncodedUnsignedInteger(Value)) + return EC; + } else { + APSInt N; + if (auto EC = consume(*Reader, N)) + return EC; + Value = N.getZExtValue(); + } + return Error::success(); +} + +Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value) { + if (isWriting()) { + if (Value.isSigned()) + return writeEncodedSignedInteger(Value.getSExtValue()); + return writeEncodedUnsignedInteger(Value.getZExtValue()); + } + + return consume(*Reader, Value); +} + +Error CodeViewRecordIO::mapStringZ(StringRef &Value) { + if (isWriting()) { + if (auto EC = Writer->writeZeroString(Value)) + return EC; + } else { + if (auto EC = Reader->readZeroString(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::mapGuid(StringRef &Guid) { + if (isWriting()) { + assert(Guid.size() == 16 && "Invalid Guid Size!"); + if (auto EC = Writer->writeFixedString(Guid)) + return EC; + } else { + if (auto EC = Reader->readFixedString(Guid, 16)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) { + assert(Value < 0 && "Encoded integer is not signed!"); + if (Value >= std::numeric_limits<int8_t>::min()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_CHAR))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<int8_t>(Value))) + return EC; + } else if (Value >= std::numeric_limits<int16_t>::min()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_SHORT))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<int16_t>(Value))) + return EC; + } else if (Value >= std::numeric_limits<int32_t>::min()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_LONG))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<int32_t>(Value))) + return EC; + } else { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_QUADWORD))) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + return Error::success(); +} + +Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) { + if (Value < LF_NUMERIC) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value))) + return EC; + } else if (Value <= std::numeric_limits<uint16_t>::max()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_USHORT))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(Value))) + return EC; + } else if (Value <= std::numeric_limits<uint32_t>::max()) { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_ULONG))) + return EC; + if (auto EC = Writer->writeInteger(static_cast<uint32_t>(Value))) + return EC; + } else { + if (auto EC = Writer->writeInteger(static_cast<uint16_t>(LF_UQUADWORD))) + return EC; + if (auto EC = Writer->writeInteger(Value)) + return EC; + } + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp index 1e7af16e841..84abad91c53 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeDumper.cpp @@ -268,12 +268,7 @@ Error CVTypeDumper::visitMemberEnd(CVMemberRecord &Record) { Error CVTypeDumper::visitKnownRecord(CVRecord<TypeLeafKind> &CVR, FieldListRecord &FieldList) { - TypeDeserializer Deserializer; - TypeVisitorCallbackPipeline Pipeline; - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(*this); - - CVTypeVisitor Visitor(Pipeline); + CVTypeVisitor Visitor(*this); if (auto EC = Visitor.visitFieldListMemberStream(FieldList.Data)) return EC; diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp index 7a2dc8fa803..b951c068ca8 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeRecord.cpp @@ -17,384 +17,6 @@ using namespace llvm; using namespace llvm::codeview; //===----------------------------------------------------------------------===// -// Type record deserialization -//===----------------------------------------------------------------------===// - -Expected<MemberPointerInfo> -MemberPointerInfo::deserialize(msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - - TypeIndex T = L->ClassType; - uint16_t R = L->Representation; - PointerToMemberRepresentation PMR = - static_cast<PointerToMemberRepresentation>(R); - return MemberPointerInfo(T, PMR); -} - -Expected<ModifierRecord> -ModifierRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - - TypeIndex M = L->ModifiedType; - uint16_t O = L->Modifiers; - ModifierOptions MO = static_cast<ModifierOptions>(O); - return ModifierRecord(M, MO); -} - -Expected<ProcedureRecord> -ProcedureRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - return ProcedureRecord(L->ReturnType, L->CallConv, L->Options, - L->NumParameters, L->ArgListType); -} - -Expected<MemberFunctionRecord> -MemberFunctionRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - CV_DESERIALIZE(Reader, L); - return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType, - L->CallConv, L->Options, L->NumParameters, - L->ArgListType, L->ThisAdjustment); -} - -Expected<MemberFuncIdRecord> -MemberFuncIdRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name); -} - -Expected<ArgListRecord> ArgListRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList) - return make_error<CodeViewError>( - cv_error_code::corrupt_record, - "ArgListRecord contains unexpected TypeRecordKind"); - - const Layout *L = nullptr; - ArrayRef<TypeIndex> Indices; - CV_DESERIALIZE(Reader, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); - return ArgListRecord(Kind, Indices); -} - -Expected<PointerRecord> PointerRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - - PointerKind PtrKind = L->getPtrKind(); - PointerMode Mode = L->getPtrMode(); - uint32_t Opts = L->Attrs; - PointerOptions Options = static_cast<PointerOptions>(Opts); - uint8_t Size = L->getPtrSize(); - - if (L->isPointerToMember()) { - if (auto ExpectedMPI = MemberPointerInfo::deserialize(Reader)) - return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, - *ExpectedMPI); - else - return ExpectedMPI.takeError(); - } - - return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size); -} - -Expected<NestedTypeRecord> -NestedTypeRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return NestedTypeRecord(L->Type, Name); -} - -Expected<FieldListRecord> -FieldListRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - ArrayRef<uint8_t> Data; - if (auto EC = Reader.readBytes(Data, Reader.bytesRemaining())) - return std::move(EC); - return FieldListRecord(Data); -} - -Expected<ArrayRecord> ArrayRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - uint64_t Size; - StringRef Name; - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name); - return ArrayRecord(L->ElementType, L->IndexType, Size, Name); -} - -Expected<ClassRecord> ClassRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - uint64_t Size = 0; - StringRef Name; - StringRef UniqueName; - uint16_t Props; - const Layout *L = nullptr; - - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - Props = L->Properties; - uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift; - WindowsRTClassKind WRT = static_cast<WindowsRTClassKind>(WrtValue); - uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; - HfaKind Hfa = static_cast<HfaKind>(HfaMask); - - ClassOptions Options = static_cast<ClassOptions>(Props); - return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList, - L->DerivedFrom, L->VShape, Size, Name, UniqueName); -} - -Expected<UnionRecord> UnionRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - uint64_t Size = 0; - StringRef Name; - StringRef UniqueName; - uint16_t Props; - - const Layout *L = nullptr; - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Size), Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - Props = L->Properties; - - uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; - HfaKind Hfa = static_cast<HfaKind>(HfaMask); - ClassOptions Options = static_cast<ClassOptions>(Props); - return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name, - UniqueName); -} - -Expected<EnumRecord> EnumRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - StringRef UniqueName; - CV_DESERIALIZE(Reader, L, Name, - CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); - - uint16_t P = L->Properties; - ClassOptions Options = static_cast<ClassOptions>(P); - return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, - UniqueName, L->UnderlyingType); -} - -Expected<BitFieldRecord> -BitFieldRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - CV_DESERIALIZE(Reader, L); - return BitFieldRecord(L->Type, L->BitSize, L->BitOffset); -} - -Expected<VFTableShapeRecord> -VFTableShapeRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - - std::vector<VFTableSlotKind> Slots; - uint16_t Count = L->VFEntryCount; - while (Count > 0) { - // Process up to 2 nibbles at a time (if there are at least 2 remaining) - uint8_t Data; - if (auto EC = Reader.readInteger(Data)) - return std::move(EC); - - uint8_t Value = Data & 0x0F; - Slots.push_back(static_cast<VFTableSlotKind>(Value)); - if (--Count > 0) { - Value = (Data & 0xF0) >> 4; - Slots.push_back(static_cast<VFTableSlotKind>(Value)); - --Count; - } - } - - return VFTableShapeRecord(Slots); -} - -Expected<TypeServer2Record> -TypeServer2Record::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name); -} - -Expected<StringIdRecord> -StringIdRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return StringIdRecord(L->id, Name); -} - -Expected<FuncIdRecord> FuncIdRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return FuncIdRecord(L->ParentScope, L->FunctionType, Name); -} - -Expected<UdtSourceLineRecord> -UdtSourceLineRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - CV_DESERIALIZE(Reader, L); - return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber); -} - -Expected<BuildInfoRecord> -BuildInfoRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - ArrayRef<TypeIndex> Indices; - CV_DESERIALIZE(Reader, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); - return BuildInfoRecord(Indices); -} - -Expected<VFTableRecord> VFTableRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - std::vector<StringRef> Names; - CV_DESERIALIZE(Reader, L, Name, CV_ARRAY_FIELD_TAIL(Names)); - return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset, - Name, Names); -} - -Expected<OneMethodRecord> -OneMethodRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - int32_t VFTableOffset = -1; - - CV_DESERIALIZE(Reader, L, CV_CONDITIONAL_FIELD( - VFTableOffset, L->Attrs.isIntroducedVirtual()), - Name); - - MethodOptions Options = L->Attrs.getFlags(); - MethodKind MethKind = L->Attrs.getMethodKind(); - MemberAccess Access = L->Attrs.getAccess(); - OneMethodRecord Method(L->Type, MethKind, Options, Access, VFTableOffset, - Name); - // Validate the vftable offset. - if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid VFTableOffset"); - return Method; -} - -Expected<MethodOverloadListRecord> -MethodOverloadListRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - std::vector<OneMethodRecord> Methods; - while (!Reader.empty()) { - const Layout *L = nullptr; - int32_t VFTableOffset = -1; - CV_DESERIALIZE( - Reader, L, - CV_CONDITIONAL_FIELD(VFTableOffset, L->Attrs.isIntroducedVirtual())); - - MethodOptions Options = L->Attrs.getFlags(); - MethodKind MethKind = L->Attrs.getMethodKind(); - MemberAccess Access = L->Attrs.getAccess(); - - Methods.emplace_back(L->Type, MethKind, Options, Access, VFTableOffset, - StringRef()); - - // Validate the vftable offset. - auto &Method = Methods.back(); - if (Method.isIntroducingVirtual() && Method.getVFTableOffset() < 0) - return make_error<CodeViewError>(cv_error_code::corrupt_record, - "Invalid VFTableOffset"); - } - return MethodOverloadListRecord(Methods); -} - -Expected<OverloadedMethodRecord> -OverloadedMethodRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return OverloadedMethodRecord(L->MethodCount, L->MethList, Name); -} - -Expected<DataMemberRecord> -DataMemberRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - uint64_t Offset; - StringRef Name; - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset), Name); - return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name); -} - -Expected<StaticDataMemberRecord> -StaticDataMemberRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - StringRef Name; - CV_DESERIALIZE(Reader, L, Name); - return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name); -} - -Expected<EnumeratorRecord> -EnumeratorRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - APSInt Value; - StringRef Name; - CV_DESERIALIZE(Reader, L, Value, Name); - return EnumeratorRecord(L->Attrs.getAccess(), Value, Name); -} - -Expected<VFPtrRecord> VFPtrRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - if (auto EC = Reader.readObject(L)) - return std::move(EC); - return VFPtrRecord(L->Type); -} - -Expected<BaseClassRecord> -BaseClassRecord::deserialize(TypeRecordKind Kind, msf::StreamReader &Reader) { - const Layout *L = nullptr; - uint64_t Offset; - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset)); - return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset); -} - -Expected<VirtualBaseClassRecord> -VirtualBaseClassRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - uint64_t Offset; - uint64_t Index; - CV_DESERIALIZE(Reader, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index)); - return VirtualBaseClassRecord(Kind, L->Attrs.getAccess(), L->BaseType, - L->VBPtrType, Offset, Index); -} - -Expected<ListContinuationRecord> -ListContinuationRecord::deserialize(TypeRecordKind Kind, - msf::StreamReader &Reader) { - const Layout *L = nullptr; - CV_DESERIALIZE(Reader, L); - return ListContinuationRecord(L->ContinuationIndex); -} - -//===----------------------------------------------------------------------===// // Type index remapping //===----------------------------------------------------------------------===// diff --git a/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp new file mode 100644 index 00000000000..d85a643c6d2 --- /dev/null +++ b/llvm/lib/DebugInfo/CodeView/TypeRecordMapping.cpp @@ -0,0 +1,417 @@ +//===- TypeRecordMapping.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/TypeRecordMapping.h" + +using namespace llvm; +using namespace llvm::codeview; + +#define error(X) \ + if (auto EC = X) \ + 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) {} + + Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const { + error(IO.mapInteger(Method.Attrs.Attrs)); + if (IsFromOverloadList) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + } + error(IO.mapInteger(Method.Type)); + if (Method.isIntroducingVirtual()) { + error(IO.mapInteger(Method.VFTableOffset)); + } else if (!IO.isWriting()) + Method.VFTableOffset = -1; + + if (!IsFromOverloadList) + error(IO.mapStringZ(Method.Name)); + + return Error::success(); + } + +private: + bool IsFromOverloadList; +}; +} + +static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name, + StringRef &UniqueName, bool HasUniqueName) { + error(IO.mapStringZ(Name)); + if (HasUniqueName) + error(IO.mapStringZ(UniqueName)); + + return Error::success(); +} + +Error TypeRecordMapping::visitTypeBegin(CVType &CVR) { + error(IO.beginRecord(CVR.Type)); + TypeKind = CVR.Type; + return Error::success(); +} + +Error TypeRecordMapping::visitTypeEnd(CVType &Record) { + error(IO.endRecord()); + TypeKind.reset(); + return Error::success(); +} + +Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) { + return Error::success(); +} + +Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) { + if (!IO.isWriting()) { + if (auto EC = IO.skipPadding()) + return EC; + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) { + error(IO.mapInteger(Record.ModifiedType)); + error(IO.mapEnum(Record.Modifiers)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + ProcedureRecord &Record) { + error(IO.mapInteger(Record.ReturnType)); + error(IO.mapEnum(Record.CallConv)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.ParameterCount)); + error(IO.mapInteger(Record.ArgumentList)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFunctionRecord &Record) { + error(IO.mapInteger(Record.ReturnType)); + error(IO.mapInteger(Record.ClassType)); + error(IO.mapInteger(Record.ThisType)); + error(IO.mapEnum(Record.CallConv)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.ParameterCount)); + error(IO.mapInteger(Record.ArgumentList)); + error(IO.mapInteger(Record.ThisPointerAdjustment)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) { + error(IO.mapVectorN<uint32_t>(Record.StringIndices, MapInteger())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) { + error(IO.mapInteger(Record.ReferentType)); + error(IO.mapInteger(Record.Attrs)); + + if (Record.isPointerToMember()) { + if (!IO.isWriting()) + Record.MemberInfo.emplace(); + + MemberPointerInfo &M = *Record.MemberInfo; + error(IO.mapInteger(M.ContainingType)); + error(IO.mapEnum(M.Representation)); + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) { + error(IO.mapInteger(Record.ElementType)); + error(IO.mapInteger(Record.IndexType)); + error(IO.mapEncodedInteger(Record.Size)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) { + assert((CVR.Type == TypeLeafKind::LF_STRUCTURE) || + (CVR.Type == TypeLeafKind::LF_CLASS) || + (CVR.Type == TypeLeafKind::LF_INTERFACE)); + + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.FieldList)); + error(IO.mapInteger(Record.DerivationList)); + error(IO.mapInteger(Record.VTableShape)); + error(IO.mapEncodedInteger(Record.Size)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) { + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.FieldList)); + error(IO.mapEncodedInteger(Record.Size)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) { + error(IO.mapInteger(Record.MemberCount)); + error(IO.mapEnum(Record.Options)); + error(IO.mapInteger(Record.UnderlyingType)); + error(IO.mapInteger(Record.FieldList)); + error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName, + Record.hasUniqueName())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) { + error(IO.mapInteger(Record.Type)); + error(IO.mapInteger(Record.BitSize)); + error(IO.mapInteger(Record.BitOffset)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + VFTableShapeRecord &Record) { + uint16_t Size; + if (IO.isWriting()) { + ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); + Size = Slots.size(); + error(IO.mapInteger(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]); + } + error(IO.mapInteger(Byte)); + } + } else { + error(IO.mapInteger(Size)); + for (uint16_t I = 0; I < Size; I += 2) { + uint8_t Byte; + error(IO.mapInteger(Byte)); + Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF)); + if ((I + 1) < Size) + Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4)); + } + } + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) { + error(IO.mapInteger(Record.CompleteClass)); + error(IO.mapInteger(Record.OverriddenVFTable)); + error(IO.mapInteger(Record.VFPtrOffset)); + uint32_t NamesLen = 0; + if (IO.isWriting()) { + for (auto Name : Record.MethodNames) + NamesLen += Name.size() + 1; + } + error(IO.mapInteger(NamesLen)); + error(IO.mapVectorTail(Record.MethodNames, MapStringZ())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) { + error(IO.mapInteger(Record.Id)); + error(IO.mapStringZ(Record.String)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT)); + error(IO.mapInteger(Record.SourceFile)); + error(IO.mapInteger(Record.LineNumber)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + UdtModSourceLineRecord &Record) { + error(IO.mapInteger(Record.UDT)); + error(IO.mapInteger(Record.SourceFile)); + error(IO.mapInteger(Record.LineNumber)); + error(IO.mapInteger(Record.Module)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) { + error(IO.mapInteger(Record.ParentScope)); + error(IO.mapInteger(Record.FunctionType)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MemberFuncIdRecord &Record) { + error(IO.mapInteger(Record.ClassType)); + error(IO.mapInteger(Record.FunctionType)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + BuildInfoRecord &Record) { + error(IO.mapVectorN<uint16_t>(Record.ArgIndices, MapInteger())); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + MethodOverloadListRecord &Record) { + // TODO: Split the list into multiple records if it's longer than 64KB, using + // a subrecord of TypeRecordKind::Index to chain the records together. + error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true))); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + FieldListRecord &Record) { + error(IO.mapByteVectorTail(Record.Data)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownRecord(CVType &CVR, + TypeServer2Record &Record) { + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + BaseClassRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapEncodedInteger(Record.Offset)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + EnumeratorRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + + // FIXME: Handle full APInt such as __int128. + error(IO.mapEncodedInteger(Record.Value)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + DataMemberRecord &Record) { + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapEncodedInteger(Record.FieldOffset)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OverloadedMethodRecord &Record) { + error(IO.mapInteger(Record.NumOverloads)); + error(IO.mapInteger(Record.MethodList)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + OneMethodRecord &Record) { + MapOneMethodRecord Mapper(false); + return Mapper(IO, Record); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + NestedTypeRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.Type)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + StaticDataMemberRecord &Record) { + + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.Type)); + error(IO.mapStringZ(Record.Name)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VirtualBaseClassRecord &Record) { + + error(IO.mapInteger(Record.Attrs.Attrs)); + error(IO.mapInteger(Record.BaseType)); + error(IO.mapInteger(Record.VBPtrType)); + error(IO.mapEncodedInteger(Record.VBPtrOffset)); + error(IO.mapEncodedInteger(Record.VTableIndex)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + VFPtrRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.Type)); + + return Error::success(); +} + +Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR, + ListContinuationRecord &Record) { + uint16_t Padding = 0; + error(IO.mapInteger(Padding)); + error(IO.mapInteger(Record.ContinuationIndex)); + + return Error::success(); +} diff --git a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp index acd7f74a3cc..551a98a67c8 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeStreamMerger.cpp @@ -84,14 +84,7 @@ private: } Error visitKnownRecordImpl(FieldListRecord &Record) { - // Don't do anything, this will get written in the call to visitTypeEnd(). - TypeVisitorCallbackPipeline Pipeline; - TypeDeserializer Deserializer; - - Pipeline.addCallbackToPipeline(Deserializer); - Pipeline.addCallbackToPipeline(*this); - - CVTypeVisitor Visitor(Pipeline); + CVTypeVisitor Visitor(*this); if (auto EC = Visitor.visitFieldListMemberStream(Record.Data)) return EC; diff --git a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp index fcf27962102..1bd0b3f4382 100644 --- a/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp +++ b/llvm/lib/DebugInfo/CodeView/TypeTableBuilder.cpp @@ -72,13 +72,7 @@ TypeIndex TypeTableBuilder::writeKnownType(const PointerRecord &Record) { TypeRecordBuilder Builder(Record.getKind()); Builder.writeTypeIndex(Record.getReferentType()); - uint32_t flags = static_cast<uint32_t>(Record.getOptions()) | - (Record.getSize() << PointerRecord::PointerSizeShift) | - (static_cast<uint32_t>(Record.getMode()) - << PointerRecord::PointerModeShift) | - (static_cast<uint32_t>(Record.getPointerKind()) - << PointerRecord::PointerKindShift); - Builder.writeUInt32(flags); + Builder.writeUInt32(Record.Attrs); if (Record.isPointerToMember()) { const MemberPointerInfo &M = Record.getMemberInfo(); diff --git a/llvm/lib/DebugInfo/MSF/StreamWriter.cpp b/llvm/lib/DebugInfo/MSF/StreamWriter.cpp index a91cffe840f..cdae7c5acc0 100644 --- a/llvm/lib/DebugInfo/MSF/StreamWriter.cpp +++ b/llvm/lib/DebugInfo/MSF/StreamWriter.cpp @@ -25,6 +25,8 @@ Error StreamWriter::writeBytes(ArrayRef<uint8_t> Buffer) { return Error::success(); } +Error StreamWriter::writeInteger(uint8_t Int) { return writeObject(Int); } + Error StreamWriter::writeInteger(uint16_t Int) { return writeObject(support::ulittle16_t(Int)); } @@ -33,6 +35,24 @@ Error StreamWriter::writeInteger(uint32_t Int) { return writeObject(support::ulittle32_t(Int)); } +Error StreamWriter::writeInteger(uint64_t Int) { + return writeObject(support::ulittle64_t(Int)); +} + +Error StreamWriter::writeInteger(int8_t Int) { return writeObject(Int); } + +Error StreamWriter::writeInteger(int16_t Int) { + return writeObject(support::little16_t(Int)); +} + +Error StreamWriter::writeInteger(int32_t Int) { + return writeObject(support::little32_t(Int)); +} + +Error StreamWriter::writeInteger(int64_t Int) { + return writeObject(support::little64_t(Int)); +} + Error StreamWriter::writeZeroString(StringRef Str) { if (auto EC = writeFixedString(Str)) return EC; |