//===- CodeViewYAMLSymbols.cpp - CodeView YAMLIO Symbol implementation ----===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines classes for handling the YAML representation of CodeView // Debug Info. // //===----------------------------------------------------------------------===// #include "llvm/ObjectYAML/CodeViewYAMLSymbols.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/CodeViewError.h" #include "llvm/DebugInfo/CodeView/EnumTables.h" #include "llvm/DebugInfo/CodeView/RecordSerialization.h" #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/ObjectYAML/YAML.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" #include #include #include #include #include using namespace llvm; using namespace llvm::codeview; using namespace llvm::CodeViewYAML; using namespace llvm::CodeViewYAML::detail; using namespace llvm::yaml; LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(TypeIndex) LLVM_YAML_IS_SEQUENCE_VECTOR(LocalVariableAddrGap) // We only need to declare these, the definitions are in CodeViewYAMLTypes.cpp LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, QuotingType::None) LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, QuotingType::None) LLVM_YAML_DECLARE_ENUM_TRAITS(SymbolKind) LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym2Flags) LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym3Flags) LLVM_YAML_DECLARE_BITSET_TRAITS(ExportFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(PublicSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(LocalSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(ProcSymFlags) LLVM_YAML_DECLARE_BITSET_TRAITS(FrameProcedureOptions) LLVM_YAML_DECLARE_ENUM_TRAITS(CPUType) LLVM_YAML_DECLARE_ENUM_TRAITS(RegisterId) LLVM_YAML_DECLARE_ENUM_TRAITS(TrampolineType) LLVM_YAML_DECLARE_ENUM_TRAITS(ThunkOrdinal) LLVM_YAML_STRONG_TYPEDEF(StringRef, TypeName) LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeName, QuotingType::Single) StringRef ScalarTraits::input(StringRef S, void *V, TypeName &T) { return ScalarTraits::input(S, V, T.value); } void ScalarTraits::output(const TypeName &T, void *V, raw_ostream &R) { ScalarTraits::output(T.value, V, R); } void ScalarEnumerationTraits::enumeration(IO &io, SymbolKind &Value) { auto SymbolNames = getSymbolTypeNames(); for (const auto &E : SymbolNames) io.enumCase(Value, E.Name.str().c_str(), E.Value); } void ScalarBitSetTraits::bitset(IO &io, CompileSym2Flags &Flags) { auto FlagNames = getCompileSym2FlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset(IO &io, CompileSym3Flags &Flags) { auto FlagNames = getCompileSym3FlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset(IO &io, ExportFlags &Flags) { auto FlagNames = getExportSymFlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset(IO &io, PublicSymFlags &Flags) { auto FlagNames = getPublicSymFlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset(IO &io, LocalSymFlags &Flags) { auto FlagNames = getLocalFlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset(IO &io, ProcSymFlags &Flags) { auto FlagNames = getProcSymFlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarBitSetTraits::bitset( IO &io, FrameProcedureOptions &Flags) { auto FlagNames = getFrameProcSymFlagNames(); for (const auto &E : FlagNames) { io.bitSetCase(Flags, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarEnumerationTraits::enumeration(IO &io, CPUType &Cpu) { auto CpuNames = getCPUTypeNames(); for (const auto &E : CpuNames) { io.enumCase(Cpu, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarEnumerationTraits::enumeration(IO &io, RegisterId &Reg) { const auto *Header = static_cast(io.getContext()); assert(Header && "The IO context is not initialized"); Optional CpuType; ArrayRef> RegNames; switch (Header->Machine) { case COFF::IMAGE_FILE_MACHINE_I386: CpuType = CPUType::Pentium3; break; case COFF::IMAGE_FILE_MACHINE_AMD64: CpuType = CPUType::X64; break; case COFF::IMAGE_FILE_MACHINE_ARMNT: CpuType = CPUType::ARMNT; break; case COFF::IMAGE_FILE_MACHINE_ARM64: CpuType = CPUType::ARM64; break; } if (CpuType) RegNames = getRegisterNames(*CpuType); for (const auto &E : RegNames) { io.enumCase(Reg, E.Name.str().c_str(), static_cast(E.Value)); } io.enumFallback(Reg); } void ScalarEnumerationTraits::enumeration( IO &io, TrampolineType &Tramp) { auto TrampNames = getTrampolineNames(); for (const auto &E : TrampNames) { io.enumCase(Tramp, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarEnumerationTraits::enumeration(IO &io, ThunkOrdinal &Ord) { auto ThunkNames = getThunkOrdinalNames(); for (const auto &E : ThunkNames) { io.enumCase(Ord, E.Name.str().c_str(), static_cast(E.Value)); } } void ScalarEnumerationTraits::enumeration( IO &io, FrameCookieKind &FC) { auto ThunkNames = getFrameCookieKindNames(); for (const auto &E : ThunkNames) { io.enumCase(FC, E.Name.str().c_str(), static_cast(E.Value)); } } namespace llvm { namespace yaml { template <> struct MappingTraits { static void mapping(IO &io, LocalVariableAddrRange &Range) { io.mapRequired("OffsetStart", Range.OffsetStart); io.mapRequired("ISectStart", Range.ISectStart); io.mapRequired("Range", Range.Range); } }; template <> struct MappingTraits { static void mapping(IO &io, LocalVariableAddrGap &Gap) { io.mapRequired("GapStartOffset", Gap.GapStartOffset); io.mapRequired("Range", Gap.Range); } }; } // namespace yaml } // namespace llvm namespace llvm { namespace CodeViewYAML { namespace detail { struct SymbolRecordBase { codeview::SymbolKind Kind; explicit SymbolRecordBase(codeview::SymbolKind K) : Kind(K) {} virtual ~SymbolRecordBase() = default; virtual void map(yaml::IO &io) = 0; virtual codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator, CodeViewContainer Container) const = 0; virtual Error fromCodeViewSymbol(codeview::CVSymbol Type) = 0; }; template struct SymbolRecordImpl : public SymbolRecordBase { explicit SymbolRecordImpl(codeview::SymbolKind K) : SymbolRecordBase(K), Symbol(static_cast(K)) {} void map(yaml::IO &io) override; codeview::CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator, CodeViewContainer Container) const override { return SymbolSerializer::writeOneSymbol(Symbol, Allocator, Container); } Error fromCodeViewSymbol(codeview::CVSymbol CVS) override { return SymbolDeserializer::deserializeAs(CVS, Symbol); } mutable T Symbol; }; struct UnknownSymbolRecord : public SymbolRecordBase { explicit UnknownSymbolRecord(codeview::SymbolKind K) : SymbolRecordBase(K) {} void map(yaml::IO &io) override; CVSymbol toCodeViewSymbol(BumpPtrAllocator &Allocator, CodeViewContainer Container) const override { RecordPrefix Prefix; uint32_t TotalLen = sizeof(RecordPrefix) + Data.size(); Prefix.RecordKind = Kind; Prefix.RecordLen = TotalLen - 2; uint8_t *Buffer = Allocator.Allocate(TotalLen); ::memcpy(Buffer, &Prefix, sizeof(RecordPrefix)); ::memcpy(Buffer + sizeof(RecordPrefix), Data.data(), Data.size()); return CVSymbol(ArrayRef(Buffer, TotalLen)); } Error fromCodeViewSymbol(CVSymbol CVS) override { this->Kind = CVS.kind(); Data = CVS.RecordData.drop_front(sizeof(RecordPrefix)); return Error::success(); } std::vector Data; }; template <> void SymbolRecordImpl::map(IO &IO) {} void UnknownSymbolRecord::map(yaml::IO &io) { yaml::BinaryRef Binary; if (io.outputting()) Binary = yaml::BinaryRef(Data); io.mapRequired("Data", Binary); if (!io.outputting()) { std::string Str; raw_string_ostream OS(Str); Binary.writeAsBinary(OS); OS.flush(); Data.assign(Str.begin(), Str.end()); } } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Parent", Symbol.Parent); IO.mapRequired("End", Symbol.End); IO.mapRequired("Next", Symbol.Next); IO.mapRequired("Off", Symbol.Offset); IO.mapRequired("Seg", Symbol.Segment); IO.mapRequired("Len", Symbol.Length); IO.mapRequired("Ordinal", Symbol.Thunk); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapRequired("Size", Symbol.Size); IO.mapRequired("ThunkOff", Symbol.ThunkOffset); IO.mapRequired("TargetOff", Symbol.TargetOffset); IO.mapRequired("ThunkSection", Symbol.ThunkSection); IO.mapRequired("TargetSection", Symbol.TargetSection); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("SectionNumber", Symbol.SectionNumber); IO.mapRequired("Alignment", Symbol.Alignment); IO.mapRequired("Rva", Symbol.Rva); IO.mapRequired("Length", Symbol.Length); IO.mapRequired("Characteristics", Symbol.Characteristics); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Size", Symbol.Size); IO.mapRequired("Characteristics", Symbol.Characteristics); IO.mapRequired("Offset", Symbol.Offset); IO.mapRequired("Segment", Symbol.Segment); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Ordinal", Symbol.Ordinal); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("PtrParent", Symbol.Parent, 0U); IO.mapOptional("PtrEnd", Symbol.End, 0U); IO.mapOptional("PtrNext", Symbol.Next, 0U); IO.mapRequired("CodeSize", Symbol.CodeSize); IO.mapRequired("DbgStart", Symbol.DbgStart); IO.mapRequired("DbgEnd", Symbol.DbgEnd); IO.mapRequired("FunctionType", Symbol.FunctionType); IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("DisplayName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Index); IO.mapRequired("Seg", Symbol.Register); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Flags", Symbol.Flags); IO.mapOptional("Offset", Symbol.Offset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("SumName", Symbol.SumName); IO.mapRequired("SymOffset", Symbol.SymOffset); IO.mapRequired("Mod", Symbol.Module); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Entries", Symbol.Fields); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("PtrParent", Symbol.Parent, 0U); IO.mapOptional("PtrEnd", Symbol.End, 0U); IO.mapRequired("Inlinee", Symbol.Inlinee); // TODO: The binary annotations } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("VarName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Program", Symbol.Program); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Program", Symbol.Program); IO.mapRequired("OffsetInParent", Symbol.OffsetInParent); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Register", Symbol.Hdr.Register); IO.mapRequired("MayHaveNoName", Symbol.Hdr.MayHaveNoName); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Offset", Symbol.Hdr.Offset); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Register", Symbol.Hdr.Register); IO.mapRequired("MayHaveNoName", Symbol.Hdr.MayHaveNoName); IO.mapRequired("OffsetInParent", Symbol.Hdr.OffsetInParent); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Register", Symbol.Offset); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Register", Symbol.Hdr.Register); IO.mapRequired("Flags", Symbol.Hdr.Flags); IO.mapRequired("BasePointerOffset", Symbol.Hdr.BasePointerOffset); IO.mapRequired("Range", Symbol.Range); IO.mapRequired("Gaps", Symbol.Gaps); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("PtrParent", Symbol.Parent, 0U); IO.mapOptional("PtrEnd", Symbol.End, 0U); IO.mapRequired("CodeSize", Symbol.CodeSize); IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("BlockName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("DisplayName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Signature", Symbol.Signature); IO.mapRequired("ObjectName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Machine", Symbol.Machine); IO.mapRequired("FrontendMajor", Symbol.VersionFrontendMajor); IO.mapRequired("FrontendMinor", Symbol.VersionFrontendMinor); IO.mapRequired("FrontendBuild", Symbol.VersionFrontendBuild); IO.mapRequired("BackendMajor", Symbol.VersionBackendMajor); IO.mapRequired("BackendMinor", Symbol.VersionBackendMinor); IO.mapRequired("BackendBuild", Symbol.VersionBackendBuild); IO.mapRequired("Version", Symbol.Version); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Machine", Symbol.Machine); IO.mapRequired("FrontendMajor", Symbol.VersionFrontendMajor); IO.mapRequired("FrontendMinor", Symbol.VersionFrontendMinor); IO.mapRequired("FrontendBuild", Symbol.VersionFrontendBuild); IO.mapRequired("FrontendQFE", Symbol.VersionFrontendQFE); IO.mapRequired("BackendMajor", Symbol.VersionBackendMajor); IO.mapRequired("BackendMinor", Symbol.VersionBackendMinor); IO.mapRequired("BackendBuild", Symbol.VersionBackendBuild); IO.mapRequired("BackendQFE", Symbol.VersionBackendQFE); IO.mapRequired("Version", Symbol.Version); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("TotalFrameBytes", Symbol.TotalFrameBytes); IO.mapRequired("PaddingFrameBytes", Symbol.PaddingFrameBytes); IO.mapRequired("OffsetToPadding", Symbol.OffsetToPadding); IO.mapRequired("BytesOfCalleeSavedRegisters", Symbol.BytesOfCalleeSavedRegisters); IO.mapRequired("OffsetOfExceptionHandler", Symbol.OffsetOfExceptionHandler); IO.mapRequired("SectionIdOfExceptionHandler", Symbol.SectionIdOfExceptionHandler); IO.mapRequired("Flags", Symbol.Flags); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Type", Symbol.Type); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Index", Symbol.Index); IO.mapRequired("ModFilenameOffset", Symbol.ModFilenameOffset); IO.mapRequired("Flags", Symbol.Flags); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("CallInstructionSize", Symbol.CallInstructionSize); IO.mapRequired("Type", Symbol.Type); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Register", Symbol.Register); IO.mapRequired("CookieKind", Symbol.CookieKind); IO.mapRequired("Flags", Symbol.Flags); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("FuncID", Symbol.Indices); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapRequired("UDTName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("BuildId", Symbol.BuildId); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Offset", Symbol.Offset); IO.mapRequired("Type", Symbol.Type); IO.mapRequired("VarName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Offset", Symbol.Offset); IO.mapRequired("Type", Symbol.Type); IO.mapRequired("Register", Symbol.Register); IO.mapRequired("VarName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapRequired("Value", Symbol.Value); IO.mapRequired("Name", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapOptional("Offset", Symbol.DataOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("DisplayName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Type", Symbol.Type); IO.mapOptional("Offset", Symbol.DataOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("DisplayName", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapRequired("Namespace", Symbol.Name); } template <> void SymbolRecordImpl::map(IO &IO) { IO.mapOptional("Offset", Symbol.CodeOffset, 0U); IO.mapOptional("Segment", Symbol.Segment, uint16_t(0)); IO.mapRequired("Strings", Symbol.Strings); } } // end namespace detail } // end namespace CodeViewYAML } // end namespace llvm CVSymbol CodeViewYAML::SymbolRecord::toCodeViewSymbol( BumpPtrAllocator &Allocator, CodeViewContainer Container) const { return Symbol->toCodeViewSymbol(Allocator, Container); } namespace llvm { namespace yaml { template <> struct MappingTraits { static void mapping(IO &io, SymbolRecordBase &Record) { Record.map(io); } }; } // end namespace yaml } // end namespace llvm template static inline Expected fromCodeViewSymbolImpl(CVSymbol Symbol) { CodeViewYAML::SymbolRecord Result; auto Impl = std::make_shared(Symbol.kind()); if (auto EC = Impl->fromCodeViewSymbol(Symbol)) return std::move(EC); Result.Symbol = Impl; return Result; } Expected CodeViewYAML::SymbolRecord::fromCodeViewSymbol(CVSymbol Symbol) { #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ case EnumName: \ return fromCodeViewSymbolImpl>(Symbol); #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \ SYMBOL_RECORD(EnumName, EnumVal, ClassName) switch (Symbol.kind()) { #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" default: return fromCodeViewSymbolImpl(Symbol); } return make_error(cv_error_code::corrupt_record); } template static void mapSymbolRecordImpl(IO &IO, const char *Class, SymbolKind Kind, CodeViewYAML::SymbolRecord &Obj) { if (!IO.outputting()) Obj.Symbol = std::make_shared(Kind); IO.mapRequired(Class, *Obj.Symbol); } void MappingTraits::mapping( IO &IO, CodeViewYAML::SymbolRecord &Obj) { SymbolKind Kind; if (IO.outputting()) Kind = Obj.Symbol->Kind; IO.mapRequired("Kind", Kind); #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ case EnumName: \ mapSymbolRecordImpl>(IO, #ClassName, Kind, \ Obj); \ break; #define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, AliasName, ClassName) \ SYMBOL_RECORD(EnumName, EnumVal, ClassName) switch (Kind) { #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" default: mapSymbolRecordImpl(IO, "UnknownSym", Kind, Obj); } }