| //===- 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/ScopedPrinter.h" |
| #include "llvm/Support/YAMLTraits.h" |
| #include <algorithm> |
| #include <cstdint> |
| #include <cstring> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| 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<TypeName>::input(StringRef S, void *V, TypeName &T) { |
| return ScalarTraits<StringRef>::input(S, V, T.value); |
| } |
| |
| void ScalarTraits<TypeName>::output(const TypeName &T, void *V, |
| raw_ostream &R) { |
| ScalarTraits<StringRef>::output(T.value, V, R); |
| } |
| |
| void ScalarEnumerationTraits<SymbolKind>::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<CompileSym2Flags>::bitset(IO &io, |
| CompileSym2Flags &Flags) { |
| auto FlagNames = getCompileSym2FlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<CompileSym2Flags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<CompileSym3Flags>::bitset(IO &io, |
| CompileSym3Flags &Flags) { |
| auto FlagNames = getCompileSym3FlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<CompileSym3Flags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<ExportFlags>::bitset(IO &io, ExportFlags &Flags) { |
| auto FlagNames = getExportSymFlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<ExportFlags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<PublicSymFlags>::bitset(IO &io, PublicSymFlags &Flags) { |
| auto FlagNames = getPublicSymFlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<PublicSymFlags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<LocalSymFlags>::bitset(IO &io, LocalSymFlags &Flags) { |
| auto FlagNames = getLocalFlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<LocalSymFlags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<ProcSymFlags>::bitset(IO &io, ProcSymFlags &Flags) { |
| auto FlagNames = getProcSymFlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<ProcSymFlags>(E.Value)); |
| } |
| } |
| |
| void ScalarBitSetTraits<FrameProcedureOptions>::bitset( |
| IO &io, FrameProcedureOptions &Flags) { |
| auto FlagNames = getFrameProcSymFlagNames(); |
| for (const auto &E : FlagNames) { |
| io.bitSetCase(Flags, E.Name.str().c_str(), |
| static_cast<FrameProcedureOptions>(E.Value)); |
| } |
| } |
| |
| void ScalarEnumerationTraits<CPUType>::enumeration(IO &io, CPUType &Cpu) { |
| auto CpuNames = getCPUTypeNames(); |
| for (const auto &E : CpuNames) { |
| io.enumCase(Cpu, E.Name.str().c_str(), static_cast<CPUType>(E.Value)); |
| } |
| } |
| |
| void ScalarEnumerationTraits<RegisterId>::enumeration(IO &io, RegisterId &Reg) { |
| const auto *Header = static_cast<COFF::header *>(io.getContext()); |
| assert(Header && "The IO context is not initialized"); |
| |
| std::optional<CPUType> CpuType; |
| ArrayRef<EnumEntry<uint16_t>> 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: |
| case COFF::IMAGE_FILE_MACHINE_ARM64EC: |
| CpuType = CPUType::ARM64; |
| break; |
| } |
| |
| if (CpuType) |
| RegNames = getRegisterNames(*CpuType); |
| |
| for (const auto &E : RegNames) { |
| io.enumCase(Reg, E.Name.str().c_str(), static_cast<RegisterId>(E.Value)); |
| } |
| io.enumFallback<Hex16>(Reg); |
| } |
| |
| void ScalarEnumerationTraits<TrampolineType>::enumeration( |
| IO &io, TrampolineType &Tramp) { |
| auto TrampNames = getTrampolineNames(); |
| for (const auto &E : TrampNames) { |
| io.enumCase(Tramp, E.Name.str().c_str(), |
| static_cast<TrampolineType>(E.Value)); |
| } |
| } |
| |
| void ScalarEnumerationTraits<ThunkOrdinal>::enumeration(IO &io, |
| ThunkOrdinal &Ord) { |
| auto ThunkNames = getThunkOrdinalNames(); |
| for (const auto &E : ThunkNames) { |
| io.enumCase(Ord, E.Name.str().c_str(), static_cast<ThunkOrdinal>(E.Value)); |
| } |
| } |
| |
| void ScalarEnumerationTraits<FrameCookieKind>::enumeration( |
| IO &io, FrameCookieKind &FC) { |
| auto ThunkNames = getFrameCookieKindNames(); |
| for (const auto &E : ThunkNames) { |
| io.enumCase(FC, E.Name.str().c_str(), |
| static_cast<FrameCookieKind>(E.Value)); |
| } |
| } |
| |
| namespace llvm { |
| namespace yaml { |
| template <> struct MappingTraits<LocalVariableAddrRange> { |
| 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<LocalVariableAddrGap> { |
| 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 <typename T> struct SymbolRecordImpl : public SymbolRecordBase { |
| explicit SymbolRecordImpl(codeview::SymbolKind K) |
| : SymbolRecordBase(K), Symbol(static_cast<SymbolRecordKind>(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<T>(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<uint8_t>(TotalLen); |
| ::memcpy(Buffer, &Prefix, sizeof(RecordPrefix)); |
| ::memcpy(Buffer + sizeof(RecordPrefix), Data.data(), Data.size()); |
| return CVSymbol(ArrayRef<uint8_t>(Buffer, TotalLen)); |
| } |
| |
| Error fromCodeViewSymbol(CVSymbol CVS) override { |
| this->Kind = CVS.kind(); |
| Data = CVS.RecordData.drop_front(sizeof(RecordPrefix)); |
| return Error::success(); |
| } |
| |
| std::vector<uint8_t> Data; |
| }; |
| |
| template <> void SymbolRecordImpl<ScopeEndSym>::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<Thunk32Sym>::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<TrampolineSym>::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<SectionSym>::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<CoffGroupSym>::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<ExportSym>::map(IO &IO) { |
| IO.mapRequired("Ordinal", Symbol.Ordinal); |
| IO.mapRequired("Flags", Symbol.Flags); |
| IO.mapRequired("Name", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<ProcSym>::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<RegisterSym>::map(IO &IO) { |
| IO.mapRequired("Type", Symbol.Index); |
| IO.mapRequired("Seg", Symbol.Register); |
| IO.mapRequired("Name", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<PublicSym32>::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<ProcRefSym>::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<EnvBlockSym>::map(IO &IO) { |
| IO.mapRequired("Entries", Symbol.Fields); |
| } |
| |
| template <> void SymbolRecordImpl<InlineSiteSym>::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<LocalSym>::map(IO &IO) { |
| IO.mapRequired("Type", Symbol.Type); |
| IO.mapRequired("Flags", Symbol.Flags); |
| |
| IO.mapRequired("VarName", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<DefRangeSym>::map(IO &IO) { |
| IO.mapRequired("Program", Symbol.Program); |
| IO.mapRequired("Range", Symbol.Range); |
| IO.mapRequired("Gaps", Symbol.Gaps); |
| } |
| |
| template <> void SymbolRecordImpl<DefRangeSubfieldSym>::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<DefRangeRegisterSym>::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<DefRangeFramePointerRelSym>::map(IO &IO) { |
| IO.mapRequired("Offset", Symbol.Hdr.Offset); |
| IO.mapRequired("Range", Symbol.Range); |
| IO.mapRequired("Gaps", Symbol.Gaps); |
| } |
| |
| template <> void SymbolRecordImpl<DefRangeSubfieldRegisterSym>::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<DefRangeFramePointerRelFullScopeSym>::map(IO &IO) { |
| IO.mapRequired("Register", Symbol.Offset); |
| } |
| |
| template <> void SymbolRecordImpl<DefRangeRegisterRelSym>::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<BlockSym>::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<LabelSym>::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<ObjNameSym>::map(IO &IO) { |
| IO.mapRequired("Signature", Symbol.Signature); |
| IO.mapRequired("ObjectName", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<Compile2Sym>::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<Compile3Sym>::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<FrameProcSym>::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<CallSiteInfoSym>::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<FileStaticSym>::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<HeapAllocationSiteSym>::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<FrameCookieSym>::map(IO &IO) { |
| IO.mapRequired("Register", Symbol.Register); |
| IO.mapRequired("CookieKind", Symbol.CookieKind); |
| IO.mapRequired("Flags", Symbol.Flags); |
| } |
| |
| template <> void SymbolRecordImpl<CallerSym>::map(IO &IO) { |
| IO.mapRequired("FuncID", Symbol.Indices); |
| } |
| |
| template <> void SymbolRecordImpl<UDTSym>::map(IO &IO) { |
| IO.mapRequired("Type", Symbol.Type); |
| IO.mapRequired("UDTName", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<BuildInfoSym>::map(IO &IO) { |
| IO.mapRequired("BuildId", Symbol.BuildId); |
| } |
| |
| template <> void SymbolRecordImpl<BPRelativeSym>::map(IO &IO) { |
| IO.mapRequired("Offset", Symbol.Offset); |
| IO.mapRequired("Type", Symbol.Type); |
| IO.mapRequired("VarName", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<RegRelativeSym>::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<ConstantSym>::map(IO &IO) { |
| IO.mapRequired("Type", Symbol.Type); |
| IO.mapRequired("Value", Symbol.Value); |
| IO.mapRequired("Name", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<DataSym>::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<ThreadLocalDataSym>::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<UsingNamespaceSym>::map(IO &IO) { |
| IO.mapRequired("Namespace", Symbol.Name); |
| } |
| |
| template <> void SymbolRecordImpl<AnnotationSym>::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<SymbolRecordBase> { |
| static void mapping(IO &io, SymbolRecordBase &Record) { Record.map(io); } |
| }; |
| |
| } // end namespace yaml |
| } // end namespace llvm |
| |
| template <typename SymbolType> |
| static inline Expected<CodeViewYAML::SymbolRecord> |
| fromCodeViewSymbolImpl(CVSymbol Symbol) { |
| CodeViewYAML::SymbolRecord Result; |
| |
| auto Impl = std::make_shared<SymbolType>(Symbol.kind()); |
| if (auto EC = Impl->fromCodeViewSymbol(Symbol)) |
| return std::move(EC); |
| Result.Symbol = Impl; |
| return Result; |
| } |
| |
| Expected<CodeViewYAML::SymbolRecord> |
| CodeViewYAML::SymbolRecord::fromCodeViewSymbol(CVSymbol Symbol) { |
| #define SYMBOL_RECORD(EnumName, EnumVal, ClassName) \ |
| case EnumName: \ |
| return fromCodeViewSymbolImpl<SymbolRecordImpl<ClassName>>(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<UnknownSymbolRecord>(Symbol); |
| } |
| return make_error<CodeViewError>(cv_error_code::corrupt_record); |
| } |
| |
| template <typename ConcreteType> |
| static void mapSymbolRecordImpl(IO &IO, const char *Class, SymbolKind Kind, |
| CodeViewYAML::SymbolRecord &Obj) { |
| if (!IO.outputting()) |
| Obj.Symbol = std::make_shared<ConcreteType>(Kind); |
| |
| IO.mapRequired(Class, *Obj.Symbol); |
| } |
| |
| void MappingTraits<CodeViewYAML::SymbolRecord>::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<SymbolRecordImpl<ClassName>>(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<UnknownSymbolRecord>(IO, "UnknownSym", Kind, Obj); |
| } |
| } |