//===-- TypeRecord.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/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" using namespace llvm; using namespace llvm::codeview; //===----------------------------------------------------------------------===// // Type record deserialization //===----------------------------------------------------------------------===// ErrorOr MemberPointerInfo::deserialize(ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; TypeIndex T = L->ClassType; uint16_t R = L->Representation; PointerToMemberRepresentation PMR = static_cast(R); return MemberPointerInfo(T, PMR); } ErrorOr ModifierRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; TypeIndex M = L->ModifiedType; uint16_t O = L->Modifiers; ModifierOptions MO = static_cast(O); return ModifierRecord(M, MO); } ErrorOr ProcedureRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; return ProcedureRecord(L->ReturnType, L->CallConv, L->Options, L->NumParameters, L->ArgListType); } ErrorOr MemberFunctionRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; CV_DESERIALIZE(Data, L); return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType, L->CallConv, L->Options, L->NumParameters, L->ArgListType, L->ThisAdjustment); } ErrorOr MemberFuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return MemberFuncIdRecord(L->ClassType, L->FunctionType, Name); } ErrorOr ArgListRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { if (Kind != TypeRecordKind::StringList && Kind != TypeRecordKind::ArgList) return std::make_error_code(std::errc::illegal_byte_sequence); const Layout *L = nullptr; ArrayRef Indices; CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); return ArgListRecord(Kind, Indices); } ErrorOr PointerRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; PointerKind PtrKind = L->getPtrKind(); PointerMode Mode = L->getPtrMode(); uint32_t Opts = L->Attrs; PointerOptions Options = static_cast(Opts); uint8_t Size = L->getPtrSize(); if (L->isPointerToMember()) { auto E = MemberPointerInfo::deserialize(Data); if (E.getError()) return std::make_error_code(std::errc::illegal_byte_sequence); return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size, *E); } return PointerRecord(L->PointeeType, PtrKind, Mode, Options, Size); } ErrorOr NestedTypeRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return NestedTypeRecord(L->Type, Name); } ErrorOr ArrayRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; uint64_t Size; StringRef Name; CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name); return ArrayRecord(L->ElementType, L->IndexType, Size, Name); } ErrorOr ClassRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { uint64_t Size = 0; StringRef Name; StringRef UniqueName; uint16_t Props; const Layout *L = nullptr; CV_DESERIALIZE(Data, 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(WrtValue); uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift; HfaKind Hfa = static_cast(HfaMask); ClassOptions Options = static_cast(Props); return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList, L->DerivedFrom, L->VShape, Size, Name, UniqueName); } ErrorOr UnionRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { uint64_t Size = 0; StringRef Name; StringRef UniqueName; uint16_t Props; const Layout *L = nullptr; CV_DESERIALIZE(Data, 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(HfaMask); ClassOptions Options = static_cast(Props); return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name, UniqueName); } ErrorOr EnumRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; StringRef UniqueName; CV_DESERIALIZE(Data, L, Name, CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName())); uint16_t P = L->Properties; ClassOptions Options = static_cast(P); return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, UniqueName, L->UnderlyingType); } ErrorOr BitFieldRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; CV_DESERIALIZE(Data, L); return BitFieldRecord(L->Type, L->BitSize, L->BitOffset); } ErrorOr VFTableShapeRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; std::vector Slots; uint16_t Count = L->VFEntryCount; while (Count > 0) { if (Data.empty()) return std::make_error_code(std::errc::illegal_byte_sequence); // Process up to 2 nibbles at a time (if there are at least 2 remaining) uint8_t Value = Data[0] & 0x0F; Slots.push_back(static_cast(Value)); if (--Count > 0) { Value = (Data[0] & 0xF0) >> 4; Slots.push_back(static_cast(Value)); --Count; } Data = Data.slice(1); } return VFTableShapeRecord(Slots); } ErrorOr TypeServer2Record::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name); } ErrorOr StringIdRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return StringIdRecord(L->id, Name); } ErrorOr FuncIdRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return FuncIdRecord(L->ParentScope, L->FunctionType, Name); } ErrorOr UdtSourceLineRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; CV_DESERIALIZE(Data, L); return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber); } ErrorOr BuildInfoRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; ArrayRef Indices; CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs)); return BuildInfoRecord(Indices); } ErrorOr VFTableRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; std::vector Names; CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names)); return VFTableRecord(L->CompleteClass, L->OverriddenVFTable, L->VFPtrOffset, Name, Names); } ErrorOr OneMethodRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; int32_t VFTableOffset = -1; CV_DESERIALIZE(Data, 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 std::make_error_code(std::errc::illegal_byte_sequence); return Method; } ErrorOr MethodOverloadListRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { std::vector Methods; while (!Data.empty()) { const Layout *L = nullptr; int32_t VFTableOffset = -1; CV_DESERIALIZE(Data, 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 std::make_error_code(std::errc::illegal_byte_sequence); } return MethodOverloadListRecord(Methods); } ErrorOr OverloadedMethodRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return OverloadedMethodRecord(L->MethodCount, L->MethList, Name); } ErrorOr DataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; uint64_t Offset; StringRef Name; CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name); return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name); } ErrorOr StaticDataMemberRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; StringRef Name; CV_DESERIALIZE(Data, L, Name); return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name); } ErrorOr EnumeratorRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; APSInt Value; StringRef Name; CV_DESERIALIZE(Data, L, Value, Name); return EnumeratorRecord(L->Attrs.getAccess(), Value, Name); } ErrorOr VFPtrRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; if (auto EC = consumeObject(Data, L)) return EC; return VFPtrRecord(L->Type); } ErrorOr BaseClassRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; uint64_t Offset; CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset)); return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset); } ErrorOr VirtualBaseClassRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; uint64_t Offset; uint64_t Index; CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index)); return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType, L->VBPtrType, Offset, Index); } ErrorOr ListContinuationRecord::deserialize(TypeRecordKind Kind, ArrayRef &Data) { const Layout *L = nullptr; CV_DESERIALIZE(Data, L); return ListContinuationRecord(L->ContinuationIndex); } //===----------------------------------------------------------------------===// // Type index remapping //===----------------------------------------------------------------------===// static bool remapIndex(ArrayRef IndexMap, TypeIndex &Idx) { // Simple types are unchanged. if (Idx.isSimple()) return true; unsigned MapPos = Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; if (MapPos < IndexMap.size()) { Idx = IndexMap[MapPos]; return true; } // This type index is invalid. Remap this to "not translated by cvpack", // and return failure. Idx = TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct); return false; } bool ModifierRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, ModifiedType); } bool ProcedureRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ReturnType); Success &= remapIndex(IndexMap, ArgumentList); return Success; } bool MemberFunctionRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ReturnType); Success &= remapIndex(IndexMap, ClassType); Success &= remapIndex(IndexMap, ThisType); Success &= remapIndex(IndexMap, ArgumentList); return Success; } bool MemberFuncIdRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ClassType); Success &= remapIndex(IndexMap, FunctionType); return Success; } bool ArgListRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; for (TypeIndex &Str : StringIndices) Success &= remapIndex(IndexMap, Str); return Success; } bool MemberPointerInfo::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, ContainingType); } bool PointerRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ReferentType); if (isPointerToMember()) Success &= MemberInfo.remapTypeIndices(IndexMap); return Success; } bool NestedTypeRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool ArrayRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ElementType); Success &= remapIndex(IndexMap, IndexType); return Success; } bool TagRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, FieldList); } bool ClassRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= TagRecord::remapTypeIndices(IndexMap); Success &= remapIndex(IndexMap, DerivationList); Success &= remapIndex(IndexMap, VTableShape); return Success; } bool EnumRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= TagRecord::remapTypeIndices(IndexMap); Success &= remapIndex(IndexMap, UnderlyingType); return Success; } bool BitFieldRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool VFTableShapeRecord::remapTypeIndices(ArrayRef IndexMap) { return true; } bool TypeServer2Record::remapTypeIndices(ArrayRef IndexMap) { return true; } bool StringIdRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Id); } bool FuncIdRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, ParentScope); Success &= remapIndex(IndexMap, FunctionType); return Success; } bool UdtSourceLineRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, UDT); Success &= remapIndex(IndexMap, SourceFile); return Success; } bool UdtModSourceLineRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, UDT); Success &= remapIndex(IndexMap, SourceFile); return Success; } bool BuildInfoRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; for (TypeIndex &Arg : ArgIndices) Success &= remapIndex(IndexMap, Arg); return Success; } bool VFTableRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, CompleteClass); Success &= remapIndex(IndexMap, OverriddenVFTable); return Success; } bool OneMethodRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, Type); return Success; } bool MethodOverloadListRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; for (OneMethodRecord &Meth : Methods) if ((Success = Meth.remapTypeIndices(IndexMap))) return Success; return Success; } bool OverloadedMethodRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, MethodList); } bool DataMemberRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool StaticDataMemberRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool EnumeratorRecord::remapTypeIndices(ArrayRef IndexMap) { return true; } bool VFPtrRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool BaseClassRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, Type); } bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef IndexMap) { bool Success = true; Success &= remapIndex(IndexMap, BaseType); Success &= remapIndex(IndexMap, VBPtrType); return Success; } bool ListContinuationRecord::remapTypeIndices(ArrayRef IndexMap) { return remapIndex(IndexMap, ContinuationIndex); }