827 lines · cpp
1//===- CodeViewYAMLTypes.cpp - CodeView YAMLIO types implementation -------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines classes for handling the YAML representation of CodeView10// Debug Info.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ObjectYAML/CodeViewYAMLTypes.h"15#include "llvm/ADT/APSInt.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/BinaryFormat/COFF.h"19#include "llvm/DebugInfo/CodeView/AppendingTypeTableBuilder.h"20#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"21#include "llvm/DebugInfo/CodeView/CodeView.h"22#include "llvm/DebugInfo/CodeView/CodeViewError.h"23#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"24#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"25#include "llvm/DebugInfo/CodeView/TypeIndex.h"26#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"27#include "llvm/Support/Allocator.h"28#include "llvm/Support/BinaryStreamReader.h"29#include "llvm/Support/BinaryStreamWriter.h"30#include "llvm/Support/Endian.h"31#include "llvm/Support/Error.h"32#include "llvm/Support/ErrorHandling.h"33#include "llvm/Support/YAMLTraits.h"34#include "llvm/Support/raw_ostream.h"35#include <algorithm>36#include <cassert>37#include <cstdint>38#include <vector>39 40using namespace llvm;41using namespace llvm::codeview;42using namespace llvm::CodeViewYAML;43using namespace llvm::CodeViewYAML::detail;44using namespace llvm::yaml;45 46LLVM_YAML_IS_SEQUENCE_VECTOR(OneMethodRecord)47LLVM_YAML_IS_SEQUENCE_VECTOR(VFTableSlotKind)48LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex)49 50LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None)51LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None)52 53LLVM_YAML_DECLARE_ENUM_TRAITS(TypeLeafKind)54LLVM_YAML_DECLARE_ENUM_TRAITS(PointerToMemberRepresentation)55LLVM_YAML_DECLARE_ENUM_TRAITS(VFTableSlotKind)56LLVM_YAML_DECLARE_ENUM_TRAITS(CallingConvention)57LLVM_YAML_DECLARE_ENUM_TRAITS(PointerKind)58LLVM_YAML_DECLARE_ENUM_TRAITS(PointerMode)59LLVM_YAML_DECLARE_ENUM_TRAITS(HfaKind)60LLVM_YAML_DECLARE_ENUM_TRAITS(MemberAccess)61LLVM_YAML_DECLARE_ENUM_TRAITS(MethodKind)62LLVM_YAML_DECLARE_ENUM_TRAITS(WindowsRTClassKind)63LLVM_YAML_DECLARE_ENUM_TRAITS(LabelType)64 65LLVM_YAML_DECLARE_BITSET_TRAITS(PointerOptions)66LLVM_YAML_DECLARE_BITSET_TRAITS(ModifierOptions)67LLVM_YAML_DECLARE_BITSET_TRAITS(FunctionOptions)68LLVM_YAML_DECLARE_BITSET_TRAITS(ClassOptions)69LLVM_YAML_DECLARE_BITSET_TRAITS(MethodOptions)70 71LLVM_YAML_DECLARE_MAPPING_TRAITS(OneMethodRecord)72LLVM_YAML_DECLARE_MAPPING_TRAITS(MemberPointerInfo)73 74namespace llvm {75namespace CodeViewYAML {76namespace detail {77 78struct LeafRecordBase {79 TypeLeafKind Kind;80 81 explicit LeafRecordBase(TypeLeafKind K) : Kind(K) {}82 virtual ~LeafRecordBase() = default;83 84 virtual void map(yaml::IO &io) = 0;85 virtual CVType toCodeViewRecord(AppendingTypeTableBuilder &TS) const = 0;86 virtual Error fromCodeViewRecord(CVType Type) = 0;87};88 89template <typename T> struct LeafRecordImpl : public LeafRecordBase {90 explicit LeafRecordImpl(TypeLeafKind K)91 : LeafRecordBase(K), Record(static_cast<TypeRecordKind>(K)) {}92 93 void map(yaml::IO &io) override;94 95 Error fromCodeViewRecord(CVType Type) override {96 return TypeDeserializer::deserializeAs<T>(Type, Record);97 }98 99 CVType toCodeViewRecord(AppendingTypeTableBuilder &TS) const override {100 TS.writeLeafType(Record);101 return CVType(TS.records().back());102 }103 104 mutable T Record;105};106 107template <> struct LeafRecordImpl<FieldListRecord> : public LeafRecordBase {108 explicit LeafRecordImpl(TypeLeafKind K) : LeafRecordBase(K) {}109 110 void map(yaml::IO &io) override;111 CVType toCodeViewRecord(AppendingTypeTableBuilder &TS) const override;112 Error fromCodeViewRecord(CVType Type) override;113 114 std::vector<MemberRecord> Members;115};116 117struct MemberRecordBase {118 TypeLeafKind Kind;119 120 explicit MemberRecordBase(TypeLeafKind K) : Kind(K) {}121 virtual ~MemberRecordBase() = default;122 123 virtual void map(yaml::IO &io) = 0;124 virtual void writeTo(ContinuationRecordBuilder &CRB) = 0;125};126 127template <typename T> struct MemberRecordImpl : public MemberRecordBase {128 explicit MemberRecordImpl(TypeLeafKind K)129 : MemberRecordBase(K), Record(static_cast<TypeRecordKind>(K)) {}130 131 void map(yaml::IO &io) override;132 133 void writeTo(ContinuationRecordBuilder &CRB) override {134 CRB.writeMemberType(Record);135 }136 137 mutable T Record;138};139 140} // end namespace detail141} // end namespace CodeViewYAML142} // end namespace llvm143 144void ScalarTraits<GUID>::output(const GUID &G, void *, llvm::raw_ostream &OS) {145 OS << G;146}147 148StringRef ScalarTraits<GUID>::input(StringRef Scalar, void *Ctx, GUID &S) {149 if (Scalar.size() != 38)150 return "GUID strings are 38 characters long";151 if (Scalar.front() != '{' || Scalar.back() != '}')152 return "GUID is not enclosed in {}";153 Scalar = Scalar.substr(1, Scalar.size() - 2);154 SmallVector<StringRef, 6> A;155 Scalar.split(A, '-', 5);156 if (A.size() != 5 || Scalar[8] != '-' || Scalar[13] != '-' ||157 Scalar[18] != '-' || Scalar[23] != '-')158 return "GUID sections are not properly delineated with dashes";159 struct MSGuid {160 support::ulittle32_t Data1;161 support::ulittle16_t Data2;162 support::ulittle16_t Data3;163 support::ubig64_t Data4;164 };165 MSGuid G = {};166 uint64_t D41{}, D42{};167 if (!to_integer(A[0], G.Data1, 16) || !to_integer(A[1], G.Data2, 16) ||168 !to_integer(A[2], G.Data3, 16) || !to_integer(A[3], D41, 16) ||169 !to_integer(A[4], D42, 16))170 return "GUID contains non hex digits";171 G.Data4 = (D41 << 48) | D42;172 ::memcpy(&S, &G, sizeof(GUID));173 return "";174}175 176void ScalarTraits<TypeIndex>::output(const TypeIndex &S, void *,177 raw_ostream &OS) {178 OS << S.getIndex();179}180 181StringRef ScalarTraits<TypeIndex>::input(StringRef Scalar, void *Ctx,182 TypeIndex &S) {183 uint32_t I;184 StringRef Result = ScalarTraits<uint32_t>::input(Scalar, Ctx, I);185 S.setIndex(I);186 return Result;187}188 189void ScalarTraits<APSInt>::output(const APSInt &S, void *, raw_ostream &OS) {190 S.print(OS, S.isSigned());191}192 193StringRef ScalarTraits<APSInt>::input(StringRef Scalar, void *Ctx, APSInt &S) {194 S = APSInt(Scalar);195 return "";196}197 198void ScalarEnumerationTraits<TypeLeafKind>::enumeration(IO &io,199 TypeLeafKind &Value) {200#define CV_TYPE(name, val) io.enumCase(Value, #name, name);201#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"202#undef CV_TYPE203}204 205void ScalarEnumerationTraits<PointerToMemberRepresentation>::enumeration(206 IO &IO, PointerToMemberRepresentation &Value) {207 IO.enumCase(Value, "Unknown", PointerToMemberRepresentation::Unknown);208 IO.enumCase(Value, "SingleInheritanceData",209 PointerToMemberRepresentation::SingleInheritanceData);210 IO.enumCase(Value, "MultipleInheritanceData",211 PointerToMemberRepresentation::MultipleInheritanceData);212 IO.enumCase(Value, "VirtualInheritanceData",213 PointerToMemberRepresentation::VirtualInheritanceData);214 IO.enumCase(Value, "GeneralData", PointerToMemberRepresentation::GeneralData);215 IO.enumCase(Value, "SingleInheritanceFunction",216 PointerToMemberRepresentation::SingleInheritanceFunction);217 IO.enumCase(Value, "MultipleInheritanceFunction",218 PointerToMemberRepresentation::MultipleInheritanceFunction);219 IO.enumCase(Value, "VirtualInheritanceFunction",220 PointerToMemberRepresentation::VirtualInheritanceFunction);221 IO.enumCase(Value, "GeneralFunction",222 PointerToMemberRepresentation::GeneralFunction);223}224 225void ScalarEnumerationTraits<VFTableSlotKind>::enumeration(226 IO &IO, VFTableSlotKind &Kind) {227 IO.enumCase(Kind, "Near16", VFTableSlotKind::Near16);228 IO.enumCase(Kind, "Far16", VFTableSlotKind::Far16);229 IO.enumCase(Kind, "This", VFTableSlotKind::This);230 IO.enumCase(Kind, "Outer", VFTableSlotKind::Outer);231 IO.enumCase(Kind, "Meta", VFTableSlotKind::Meta);232 IO.enumCase(Kind, "Near", VFTableSlotKind::Near);233 IO.enumCase(Kind, "Far", VFTableSlotKind::Far);234}235 236void ScalarEnumerationTraits<CallingConvention>::enumeration(237 IO &IO, CallingConvention &Value) {238 IO.enumCase(Value, "NearC", CallingConvention::NearC);239 IO.enumCase(Value, "FarC", CallingConvention::FarC);240 IO.enumCase(Value, "NearPascal", CallingConvention::NearPascal);241 IO.enumCase(Value, "FarPascal", CallingConvention::FarPascal);242 IO.enumCase(Value, "NearFast", CallingConvention::NearFast);243 IO.enumCase(Value, "FarFast", CallingConvention::FarFast);244 IO.enumCase(Value, "NearStdCall", CallingConvention::NearStdCall);245 IO.enumCase(Value, "FarStdCall", CallingConvention::FarStdCall);246 IO.enumCase(Value, "NearSysCall", CallingConvention::NearSysCall);247 IO.enumCase(Value, "FarSysCall", CallingConvention::FarSysCall);248 IO.enumCase(Value, "ThisCall", CallingConvention::ThisCall);249 IO.enumCase(Value, "MipsCall", CallingConvention::MipsCall);250 IO.enumCase(Value, "Generic", CallingConvention::Generic);251 IO.enumCase(Value, "AlphaCall", CallingConvention::AlphaCall);252 IO.enumCase(Value, "PpcCall", CallingConvention::PpcCall);253 IO.enumCase(Value, "SHCall", CallingConvention::SHCall);254 IO.enumCase(Value, "ArmCall", CallingConvention::ArmCall);255 IO.enumCase(Value, "AM33Call", CallingConvention::AM33Call);256 IO.enumCase(Value, "TriCall", CallingConvention::TriCall);257 IO.enumCase(Value, "SH5Call", CallingConvention::SH5Call);258 IO.enumCase(Value, "M32RCall", CallingConvention::M32RCall);259 IO.enumCase(Value, "ClrCall", CallingConvention::ClrCall);260 IO.enumCase(Value, "Inline", CallingConvention::Inline);261 IO.enumCase(Value, "NearVector", CallingConvention::NearVector);262 IO.enumCase(Value, "Swift", CallingConvention::Swift);263}264 265void ScalarEnumerationTraits<PointerKind>::enumeration(IO &IO,266 PointerKind &Kind) {267 IO.enumCase(Kind, "Near16", PointerKind::Near16);268 IO.enumCase(Kind, "Far16", PointerKind::Far16);269 IO.enumCase(Kind, "Huge16", PointerKind::Huge16);270 IO.enumCase(Kind, "BasedOnSegment", PointerKind::BasedOnSegment);271 IO.enumCase(Kind, "BasedOnValue", PointerKind::BasedOnValue);272 IO.enumCase(Kind, "BasedOnSegmentValue", PointerKind::BasedOnSegmentValue);273 IO.enumCase(Kind, "BasedOnAddress", PointerKind::BasedOnAddress);274 IO.enumCase(Kind, "BasedOnSegmentAddress",275 PointerKind::BasedOnSegmentAddress);276 IO.enumCase(Kind, "BasedOnType", PointerKind::BasedOnType);277 IO.enumCase(Kind, "BasedOnSelf", PointerKind::BasedOnSelf);278 IO.enumCase(Kind, "Near32", PointerKind::Near32);279 IO.enumCase(Kind, "Far32", PointerKind::Far32);280 IO.enumCase(Kind, "Near64", PointerKind::Near64);281}282 283void ScalarEnumerationTraits<PointerMode>::enumeration(IO &IO,284 PointerMode &Mode) {285 IO.enumCase(Mode, "Pointer", PointerMode::Pointer);286 IO.enumCase(Mode, "LValueReference", PointerMode::LValueReference);287 IO.enumCase(Mode, "PointerToDataMember", PointerMode::PointerToDataMember);288 IO.enumCase(Mode, "PointerToMemberFunction",289 PointerMode::PointerToMemberFunction);290 IO.enumCase(Mode, "RValueReference", PointerMode::RValueReference);291}292 293void ScalarEnumerationTraits<HfaKind>::enumeration(IO &IO, HfaKind &Value) {294 IO.enumCase(Value, "None", HfaKind::None);295 IO.enumCase(Value, "Float", HfaKind::Float);296 IO.enumCase(Value, "Double", HfaKind::Double);297 IO.enumCase(Value, "Other", HfaKind::Other);298}299 300void ScalarEnumerationTraits<MemberAccess>::enumeration(IO &IO,301 MemberAccess &Access) {302 IO.enumCase(Access, "None", MemberAccess::None);303 IO.enumCase(Access, "Private", MemberAccess::Private);304 IO.enumCase(Access, "Protected", MemberAccess::Protected);305 IO.enumCase(Access, "Public", MemberAccess::Public);306}307 308void ScalarEnumerationTraits<MethodKind>::enumeration(IO &IO,309 MethodKind &Kind) {310 IO.enumCase(Kind, "Vanilla", MethodKind::Vanilla);311 IO.enumCase(Kind, "Virtual", MethodKind::Virtual);312 IO.enumCase(Kind, "Static", MethodKind::Static);313 IO.enumCase(Kind, "Friend", MethodKind::Friend);314 IO.enumCase(Kind, "IntroducingVirtual", MethodKind::IntroducingVirtual);315 IO.enumCase(Kind, "PureVirtual", MethodKind::PureVirtual);316 IO.enumCase(Kind, "PureIntroducingVirtual",317 MethodKind::PureIntroducingVirtual);318}319 320void ScalarEnumerationTraits<WindowsRTClassKind>::enumeration(321 IO &IO, WindowsRTClassKind &Value) {322 IO.enumCase(Value, "None", WindowsRTClassKind::None);323 IO.enumCase(Value, "Ref", WindowsRTClassKind::RefClass);324 IO.enumCase(Value, "Value", WindowsRTClassKind::ValueClass);325 IO.enumCase(Value, "Interface", WindowsRTClassKind::Interface);326}327 328void ScalarEnumerationTraits<LabelType>::enumeration(IO &IO, LabelType &Value) {329 IO.enumCase(Value, "Near", LabelType::Near);330 IO.enumCase(Value, "Far", LabelType::Far);331}332 333void ScalarBitSetTraits<PointerOptions>::bitset(IO &IO,334 PointerOptions &Options) {335 IO.bitSetCase(Options, "None", PointerOptions::None);336 IO.bitSetCase(Options, "Flat32", PointerOptions::Flat32);337 IO.bitSetCase(Options, "Volatile", PointerOptions::Volatile);338 IO.bitSetCase(Options, "Const", PointerOptions::Const);339 IO.bitSetCase(Options, "Unaligned", PointerOptions::Unaligned);340 IO.bitSetCase(Options, "Restrict", PointerOptions::Restrict);341 IO.bitSetCase(Options, "WinRTSmartPointer",342 PointerOptions::WinRTSmartPointer);343}344 345void ScalarBitSetTraits<ModifierOptions>::bitset(IO &IO,346 ModifierOptions &Options) {347 IO.bitSetCase(Options, "None", ModifierOptions::None);348 IO.bitSetCase(Options, "Const", ModifierOptions::Const);349 IO.bitSetCase(Options, "Volatile", ModifierOptions::Volatile);350 IO.bitSetCase(Options, "Unaligned", ModifierOptions::Unaligned);351}352 353void ScalarBitSetTraits<FunctionOptions>::bitset(IO &IO,354 FunctionOptions &Options) {355 IO.bitSetCase(Options, "None", FunctionOptions::None);356 IO.bitSetCase(Options, "CxxReturnUdt", FunctionOptions::CxxReturnUdt);357 IO.bitSetCase(Options, "Constructor", FunctionOptions::Constructor);358 IO.bitSetCase(Options, "ConstructorWithVirtualBases",359 FunctionOptions::ConstructorWithVirtualBases);360}361 362void ScalarBitSetTraits<ClassOptions>::bitset(IO &IO, ClassOptions &Options) {363 IO.bitSetCase(Options, "None", ClassOptions::None);364 IO.bitSetCase(Options, "HasConstructorOrDestructor",365 ClassOptions::HasConstructorOrDestructor);366 IO.bitSetCase(Options, "HasOverloadedOperator",367 ClassOptions::HasOverloadedOperator);368 IO.bitSetCase(Options, "Nested", ClassOptions::Nested);369 IO.bitSetCase(Options, "ContainsNestedClass",370 ClassOptions::ContainsNestedClass);371 IO.bitSetCase(Options, "HasOverloadedAssignmentOperator",372 ClassOptions::HasOverloadedAssignmentOperator);373 IO.bitSetCase(Options, "HasConversionOperator",374 ClassOptions::HasConversionOperator);375 IO.bitSetCase(Options, "ForwardReference", ClassOptions::ForwardReference);376 IO.bitSetCase(Options, "Scoped", ClassOptions::Scoped);377 IO.bitSetCase(Options, "HasUniqueName", ClassOptions::HasUniqueName);378 IO.bitSetCase(Options, "Sealed", ClassOptions::Sealed);379 IO.bitSetCase(Options, "Intrinsic", ClassOptions::Intrinsic);380}381 382void ScalarBitSetTraits<MethodOptions>::bitset(IO &IO, MethodOptions &Options) {383 IO.bitSetCase(Options, "None", MethodOptions::None);384 IO.bitSetCase(Options, "Pseudo", MethodOptions::Pseudo);385 IO.bitSetCase(Options, "NoInherit", MethodOptions::NoInherit);386 IO.bitSetCase(Options, "NoConstruct", MethodOptions::NoConstruct);387 IO.bitSetCase(Options, "CompilerGenerated", MethodOptions::CompilerGenerated);388 IO.bitSetCase(Options, "Sealed", MethodOptions::Sealed);389}390 391void MappingTraits<MemberPointerInfo>::mapping(IO &IO, MemberPointerInfo &MPI) {392 IO.mapRequired("ContainingType", MPI.ContainingType);393 IO.mapRequired("Representation", MPI.Representation);394}395 396namespace llvm {397namespace CodeViewYAML {398namespace detail {399 400template <> void LeafRecordImpl<ModifierRecord>::map(IO &IO) {401 IO.mapRequired("ModifiedType", Record.ModifiedType);402 IO.mapRequired("Modifiers", Record.Modifiers);403}404 405template <> void LeafRecordImpl<ProcedureRecord>::map(IO &IO) {406 IO.mapRequired("ReturnType", Record.ReturnType);407 IO.mapRequired("CallConv", Record.CallConv);408 IO.mapRequired("Options", Record.Options);409 IO.mapRequired("ParameterCount", Record.ParameterCount);410 IO.mapRequired("ArgumentList", Record.ArgumentList);411}412 413template <> void LeafRecordImpl<MemberFunctionRecord>::map(IO &IO) {414 IO.mapRequired("ReturnType", Record.ReturnType);415 IO.mapRequired("ClassType", Record.ClassType);416 IO.mapRequired("ThisType", Record.ThisType);417 IO.mapRequired("CallConv", Record.CallConv);418 IO.mapRequired("Options", Record.Options);419 IO.mapRequired("ParameterCount", Record.ParameterCount);420 IO.mapRequired("ArgumentList", Record.ArgumentList);421 IO.mapRequired("ThisPointerAdjustment", Record.ThisPointerAdjustment);422}423 424template <> void LeafRecordImpl<LabelRecord>::map(IO &IO) {425 IO.mapRequired("Mode", Record.Mode);426}427 428template <> void LeafRecordImpl<MemberFuncIdRecord>::map(IO &IO) {429 IO.mapRequired("ClassType", Record.ClassType);430 IO.mapRequired("FunctionType", Record.FunctionType);431 IO.mapRequired("Name", Record.Name);432}433 434template <> void LeafRecordImpl<ArgListRecord>::map(IO &IO) {435 IO.mapRequired("ArgIndices", Record.ArgIndices);436}437 438template <> void LeafRecordImpl<StringListRecord>::map(IO &IO) {439 IO.mapRequired("StringIndices", Record.StringIndices);440}441 442template <> void LeafRecordImpl<PointerRecord>::map(IO &IO) {443 IO.mapRequired("ReferentType", Record.ReferentType);444 IO.mapRequired("Attrs", Record.Attrs);445 IO.mapOptional("MemberInfo", Record.MemberInfo);446}447 448template <> void LeafRecordImpl<ArrayRecord>::map(IO &IO) {449 IO.mapRequired("ElementType", Record.ElementType);450 IO.mapRequired("IndexType", Record.IndexType);451 IO.mapRequired("Size", Record.Size);452 IO.mapRequired("Name", Record.Name);453}454 455void LeafRecordImpl<FieldListRecord>::map(IO &IO) {456 IO.mapRequired("FieldList", Members);457}458 459} // end namespace detail460} // end namespace CodeViewYAML461} // end namespace llvm462 463namespace {464 465class MemberRecordConversionVisitor : public TypeVisitorCallbacks {466public:467 explicit MemberRecordConversionVisitor(std::vector<MemberRecord> &Records)468 : Records(Records) {}469 470#define TYPE_RECORD(EnumName, EnumVal, Name)471#define MEMBER_RECORD(EnumName, EnumVal, Name) \472 Error visitKnownMember(CVMemberRecord &CVR, Name##Record &Record) override { \473 return visitKnownMemberImpl(Record); \474 }475#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)476#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)477#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"478private:479 template <typename T> Error visitKnownMemberImpl(T &Record) {480 TypeLeafKind K = static_cast<TypeLeafKind>(Record.getKind());481 auto Impl = std::make_shared<MemberRecordImpl<T>>(K);482 Impl->Record = Record;483 Records.push_back(MemberRecord{Impl});484 return Error::success();485 }486 487 std::vector<MemberRecord> &Records;488};489 490} // end anonymous namespace491 492Error LeafRecordImpl<FieldListRecord>::fromCodeViewRecord(CVType Type) {493 MemberRecordConversionVisitor V(Members);494 FieldListRecord FieldList;495 cantFail(TypeDeserializer::deserializeAs<FieldListRecord>(Type,496 FieldList));497 return visitMemberRecordStream(FieldList.Data, V);498}499 500CVType LeafRecordImpl<FieldListRecord>::toCodeViewRecord(501 AppendingTypeTableBuilder &TS) const {502 ContinuationRecordBuilder CRB;503 CRB.begin(ContinuationRecordKind::FieldList);504 for (const auto &Member : Members) {505 Member.Member->writeTo(CRB);506 }507 TS.insertRecord(CRB);508 return CVType(TS.records().back());509}510 511void MappingTraits<OneMethodRecord>::mapping(IO &io, OneMethodRecord &Record) {512 io.mapRequired("Type", Record.Type);513 io.mapRequired("Attrs", Record.Attrs.Attrs);514 io.mapRequired("VFTableOffset", Record.VFTableOffset);515 io.mapRequired("Name", Record.Name);516}517 518namespace llvm {519namespace CodeViewYAML {520namespace detail {521 522template <> void LeafRecordImpl<ClassRecord>::map(IO &IO) {523 IO.mapRequired("MemberCount", Record.MemberCount);524 IO.mapRequired("Options", Record.Options);525 IO.mapRequired("FieldList", Record.FieldList);526 IO.mapRequired("Name", Record.Name);527 IO.mapRequired("UniqueName", Record.UniqueName);528 IO.mapRequired("DerivationList", Record.DerivationList);529 IO.mapRequired("VTableShape", Record.VTableShape);530 IO.mapRequired("Size", Record.Size);531}532 533template <> void LeafRecordImpl<UnionRecord>::map(IO &IO) {534 IO.mapRequired("MemberCount", Record.MemberCount);535 IO.mapRequired("Options", Record.Options);536 IO.mapRequired("FieldList", Record.FieldList);537 IO.mapRequired("Name", Record.Name);538 IO.mapRequired("UniqueName", Record.UniqueName);539 IO.mapRequired("Size", Record.Size);540}541 542template <> void LeafRecordImpl<EnumRecord>::map(IO &IO) {543 IO.mapRequired("NumEnumerators", Record.MemberCount);544 IO.mapRequired("Options", Record.Options);545 IO.mapRequired("FieldList", Record.FieldList);546 IO.mapRequired("Name", Record.Name);547 IO.mapRequired("UniqueName", Record.UniqueName);548 IO.mapRequired("UnderlyingType", Record.UnderlyingType);549}550 551template <> void LeafRecordImpl<BitFieldRecord>::map(IO &IO) {552 IO.mapRequired("Type", Record.Type);553 IO.mapRequired("BitSize", Record.BitSize);554 IO.mapRequired("BitOffset", Record.BitOffset);555}556 557template <> void LeafRecordImpl<VFTableShapeRecord>::map(IO &IO) {558 IO.mapRequired("Slots", Record.Slots);559}560 561template <> void LeafRecordImpl<TypeServer2Record>::map(IO &IO) {562 IO.mapRequired("Guid", Record.Guid);563 IO.mapRequired("Age", Record.Age);564 IO.mapRequired("Name", Record.Name);565}566 567template <> void LeafRecordImpl<StringIdRecord>::map(IO &IO) {568 IO.mapRequired("Id", Record.Id);569 IO.mapRequired("String", Record.String);570}571 572template <> void LeafRecordImpl<FuncIdRecord>::map(IO &IO) {573 IO.mapRequired("ParentScope", Record.ParentScope);574 IO.mapRequired("FunctionType", Record.FunctionType);575 IO.mapRequired("Name", Record.Name);576}577 578template <> void LeafRecordImpl<UdtSourceLineRecord>::map(IO &IO) {579 IO.mapRequired("UDT", Record.UDT);580 IO.mapRequired("SourceFile", Record.SourceFile);581 IO.mapRequired("LineNumber", Record.LineNumber);582}583 584template <> void LeafRecordImpl<UdtModSourceLineRecord>::map(IO &IO) {585 IO.mapRequired("UDT", Record.UDT);586 IO.mapRequired("SourceFile", Record.SourceFile);587 IO.mapRequired("LineNumber", Record.LineNumber);588 IO.mapRequired("Module", Record.Module);589}590 591template <> void LeafRecordImpl<BuildInfoRecord>::map(IO &IO) {592 IO.mapRequired("ArgIndices", Record.ArgIndices);593}594 595template <> void LeafRecordImpl<VFTableRecord>::map(IO &IO) {596 IO.mapRequired("CompleteClass", Record.CompleteClass);597 IO.mapRequired("OverriddenVFTable", Record.OverriddenVFTable);598 IO.mapRequired("VFPtrOffset", Record.VFPtrOffset);599 IO.mapRequired("MethodNames", Record.MethodNames);600}601 602template <> void LeafRecordImpl<MethodOverloadListRecord>::map(IO &IO) {603 IO.mapRequired("Methods", Record.Methods);604}605 606template <> void LeafRecordImpl<PrecompRecord>::map(IO &IO) {607 IO.mapRequired("StartTypeIndex", Record.StartTypeIndex);608 IO.mapRequired("TypesCount", Record.TypesCount);609 IO.mapRequired("Signature", Record.Signature);610 IO.mapRequired("PrecompFilePath", Record.PrecompFilePath);611}612 613template <> void LeafRecordImpl<EndPrecompRecord>::map(IO &IO) {614 IO.mapRequired("Signature", Record.Signature);615}616 617template <> void MemberRecordImpl<OneMethodRecord>::map(IO &IO) {618 MappingTraits<OneMethodRecord>::mapping(IO, Record);619}620 621template <> void MemberRecordImpl<OverloadedMethodRecord>::map(IO &IO) {622 IO.mapRequired("NumOverloads", Record.NumOverloads);623 IO.mapRequired("MethodList", Record.MethodList);624 IO.mapRequired("Name", Record.Name);625}626 627template <> void MemberRecordImpl<NestedTypeRecord>::map(IO &IO) {628 IO.mapRequired("Type", Record.Type);629 IO.mapRequired("Name", Record.Name);630}631 632template <> void MemberRecordImpl<DataMemberRecord>::map(IO &IO) {633 IO.mapRequired("Attrs", Record.Attrs.Attrs);634 IO.mapRequired("Type", Record.Type);635 IO.mapRequired("FieldOffset", Record.FieldOffset);636 IO.mapRequired("Name", Record.Name);637}638 639template <> void MemberRecordImpl<StaticDataMemberRecord>::map(IO &IO) {640 IO.mapRequired("Attrs", Record.Attrs.Attrs);641 IO.mapRequired("Type", Record.Type);642 IO.mapRequired("Name", Record.Name);643}644 645template <> void MemberRecordImpl<EnumeratorRecord>::map(IO &IO) {646 IO.mapRequired("Attrs", Record.Attrs.Attrs);647 IO.mapRequired("Value", Record.Value);648 IO.mapRequired("Name", Record.Name);649}650 651template <> void MemberRecordImpl<VFPtrRecord>::map(IO &IO) {652 IO.mapRequired("Type", Record.Type);653}654 655template <> void MemberRecordImpl<BaseClassRecord>::map(IO &IO) {656 IO.mapRequired("Attrs", Record.Attrs.Attrs);657 IO.mapRequired("Type", Record.Type);658 IO.mapRequired("Offset", Record.Offset);659}660 661template <> void MemberRecordImpl<VirtualBaseClassRecord>::map(IO &IO) {662 IO.mapRequired("Attrs", Record.Attrs.Attrs);663 IO.mapRequired("BaseType", Record.BaseType);664 IO.mapRequired("VBPtrType", Record.VBPtrType);665 IO.mapRequired("VBPtrOffset", Record.VBPtrOffset);666 IO.mapRequired("VTableIndex", Record.VTableIndex);667}668 669template <> void MemberRecordImpl<ListContinuationRecord>::map(IO &IO) {670 IO.mapRequired("ContinuationIndex", Record.ContinuationIndex);671}672 673} // end namespace detail674} // end namespace CodeViewYAML675} // end namespace llvm676 677template <typename T>678static inline Expected<LeafRecord> fromCodeViewRecordImpl(CVType Type) {679 LeafRecord Result;680 681 auto Impl = std::make_shared<LeafRecordImpl<T>>(Type.kind());682 if (auto EC = Impl->fromCodeViewRecord(Type))683 return std::move(EC);684 Result.Leaf = Impl;685 return Result;686}687 688Expected<LeafRecord> LeafRecord::fromCodeViewRecord(CVType Type) {689#define TYPE_RECORD(EnumName, EnumVal, ClassName) \690 case EnumName: \691 return fromCodeViewRecordImpl<ClassName##Record>(Type);692#define TYPE_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \693 TYPE_RECORD(EnumName, EnumVal, ClassName)694#define MEMBER_RECORD(EnumName, EnumVal, ClassName)695#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName)696 switch (Type.kind()) {697#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"698 default:699 llvm_unreachable("Unknown leaf kind!");700 }701 return make_error<CodeViewError>(cv_error_code::corrupt_record);702}703 704CVType705LeafRecord::toCodeViewRecord(AppendingTypeTableBuilder &Serializer) const {706 return Leaf->toCodeViewRecord(Serializer);707}708 709namespace llvm {710namespace yaml {711 712template <> struct MappingTraits<LeafRecordBase> {713 static void mapping(IO &io, LeafRecordBase &Record) { Record.map(io); }714};715 716template <> struct MappingTraits<MemberRecordBase> {717 static void mapping(IO &io, MemberRecordBase &Record) { Record.map(io); }718};719 720} // end namespace yaml721} // end namespace llvm722 723template <typename ConcreteType>724static void mapLeafRecordImpl(IO &IO, const char *Class, TypeLeafKind Kind,725 LeafRecord &Obj) {726 if (!IO.outputting())727 Obj.Leaf = std::make_shared<LeafRecordImpl<ConcreteType>>(Kind);728 729 if (Kind == LF_FIELDLIST)730 Obj.Leaf->map(IO);731 else732 IO.mapRequired(Class, *Obj.Leaf);733}734 735void MappingTraits<LeafRecord>::mapping(IO &IO, LeafRecord &Obj) {736 TypeLeafKind Kind;737 if (IO.outputting())738 Kind = Obj.Leaf->Kind;739 IO.mapRequired("Kind", Kind);740 741#define TYPE_RECORD(EnumName, EnumVal, ClassName) \742 case EnumName: \743 mapLeafRecordImpl<ClassName##Record>(IO, #ClassName, Kind, Obj); \744 break;745#define TYPE_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \746 TYPE_RECORD(EnumName, EnumVal, ClassName)747#define MEMBER_RECORD(EnumName, EnumVal, ClassName)748#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName)749 switch (Kind) {750#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"751 default: { llvm_unreachable("Unknown leaf kind!"); }752 }753}754 755template <typename ConcreteType>756static void mapMemberRecordImpl(IO &IO, const char *Class, TypeLeafKind Kind,757 MemberRecord &Obj) {758 if (!IO.outputting())759 Obj.Member = std::make_shared<MemberRecordImpl<ConcreteType>>(Kind);760 761 IO.mapRequired(Class, *Obj.Member);762}763 764void MappingTraits<MemberRecord>::mapping(IO &IO, MemberRecord &Obj) {765 TypeLeafKind Kind;766 if (IO.outputting())767 Kind = Obj.Member->Kind;768 IO.mapRequired("Kind", Kind);769 770#define MEMBER_RECORD(EnumName, EnumVal, ClassName) \771 case EnumName: \772 mapMemberRecordImpl<ClassName##Record>(IO, #ClassName, Kind, Obj); \773 break;774#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \775 MEMBER_RECORD(EnumName, EnumVal, ClassName)776#define TYPE_RECORD(EnumName, EnumVal, ClassName)777#define TYPE_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName)778 switch (Kind) {779#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"780 default: { llvm_unreachable("Unknown member kind!"); }781 }782}783 784std::vector<LeafRecord>785llvm::CodeViewYAML::fromDebugT(ArrayRef<uint8_t> DebugTorP,786 StringRef SectionName) {787 ExitOnError Err("Invalid " + std::string(SectionName) + " section!");788 BinaryStreamReader Reader(DebugTorP, llvm::endianness::little);789 CVTypeArray Types;790 uint32_t Magic;791 792 Err(Reader.readInteger(Magic));793 assert(Magic == COFF::DEBUG_SECTION_MAGIC &&794 "Invalid .debug$T or .debug$P section!");795 796 std::vector<LeafRecord> Result;797 Err(Reader.readArray(Types, Reader.bytesRemaining()));798 for (const auto &T : Types) {799 auto CVT = Err(LeafRecord::fromCodeViewRecord(T));800 Result.push_back(CVT);801 }802 return Result;803}804 805ArrayRef<uint8_t> llvm::CodeViewYAML::toDebugT(ArrayRef<LeafRecord> Leafs,806 BumpPtrAllocator &Alloc,807 StringRef SectionName) {808 AppendingTypeTableBuilder TS(Alloc);809 uint32_t Size = sizeof(uint32_t);810 for (const auto &Leaf : Leafs) {811 CVType T = Leaf.Leaf->toCodeViewRecord(TS);812 Size += T.length();813 assert(T.length() % 4 == 0 && "Improper type record alignment!");814 }815 uint8_t *ResultBuffer = Alloc.Allocate<uint8_t>(Size);816 MutableArrayRef<uint8_t> Output(ResultBuffer, Size);817 BinaryStreamWriter Writer(Output, llvm::endianness::little);818 ExitOnError Err("Error writing type record to " + std::string(SectionName) +819 " section");820 Err(Writer.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC));821 for (const auto &R : TS.records()) {822 Err(Writer.writeBytes(R));823 }824 assert(Writer.bytesRemaining() == 0 && "Didn't write all type record bytes!");825 return Output;826}827