| 1 | //===-- PdbYaml.cpp ------------------------------------------- *- C++ --*-===// |
| 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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "PdbYaml.h" |
| 10 | |
| 11 | #include "llvm/ADT/StringExtras.h" |
| 12 | #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" |
| 13 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
| 14 | #include "llvm/DebugInfo/PDB/Native/RawTypes.h" |
| 15 | #include "llvm/DebugInfo/PDB/Native/TpiHashing.h" |
| 16 | #include "llvm/DebugInfo/PDB/PDBTypes.h" |
| 17 | #include "llvm/ObjectYAML/CodeViewYAMLDebugSections.h" |
| 18 | #include "llvm/ObjectYAML/CodeViewYAMLTypes.h" |
| 19 | |
| 20 | using namespace llvm; |
| 21 | using namespace llvm::pdb; |
| 22 | using namespace llvm::pdb::yaml; |
| 23 | using namespace llvm::yaml; |
| 24 | |
| 25 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::CoffSectionHeader) |
| 26 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::NamedStreamMapping) |
| 27 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::PdbDbiModuleInfo) |
| 28 | LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList) |
| 29 | LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::pdb::PdbRaw_FeatureSig) |
| 30 | |
| 31 | namespace llvm { |
| 32 | namespace yaml { |
| 33 | |
| 34 | template <> struct ScalarEnumerationTraits<llvm::pdb::PDB_Machine> { |
| 35 | static void enumeration(IO &io, llvm::pdb::PDB_Machine &Value) { |
| 36 | io.enumCase(Val&: Value, Str: "Invalid" , ConstVal: PDB_Machine::Invalid); |
| 37 | io.enumCase(Val&: Value, Str: "Am33" , ConstVal: PDB_Machine::Am33); |
| 38 | io.enumCase(Val&: Value, Str: "Amd64" , ConstVal: PDB_Machine::Amd64); |
| 39 | io.enumCase(Val&: Value, Str: "Arm" , ConstVal: PDB_Machine::Arm); |
| 40 | io.enumCase(Val&: Value, Str: "ArmNT" , ConstVal: PDB_Machine::ArmNT); |
| 41 | io.enumCase(Val&: Value, Str: "Ebc" , ConstVal: PDB_Machine::Ebc); |
| 42 | io.enumCase(Val&: Value, Str: "x86" , ConstVal: PDB_Machine::x86); |
| 43 | io.enumCase(Val&: Value, Str: "Ia64" , ConstVal: PDB_Machine::Ia64); |
| 44 | io.enumCase(Val&: Value, Str: "M32R" , ConstVal: PDB_Machine::M32R); |
| 45 | io.enumCase(Val&: Value, Str: "Mips16" , ConstVal: PDB_Machine::Mips16); |
| 46 | io.enumCase(Val&: Value, Str: "MipsFpu" , ConstVal: PDB_Machine::MipsFpu); |
| 47 | io.enumCase(Val&: Value, Str: "MipsFpu16" , ConstVal: PDB_Machine::MipsFpu16); |
| 48 | io.enumCase(Val&: Value, Str: "PowerPCFP" , ConstVal: PDB_Machine::PowerPCFP); |
| 49 | io.enumCase(Val&: Value, Str: "R4000" , ConstVal: PDB_Machine::R4000); |
| 50 | io.enumCase(Val&: Value, Str: "SH3" , ConstVal: PDB_Machine::SH3); |
| 51 | io.enumCase(Val&: Value, Str: "SH3DSP" , ConstVal: PDB_Machine::SH3DSP); |
| 52 | io.enumCase(Val&: Value, Str: "Thumb" , ConstVal: PDB_Machine::Thumb); |
| 53 | io.enumCase(Val&: Value, Str: "WceMipsV2" , ConstVal: PDB_Machine::WceMipsV2); |
| 54 | io.enumCase(Val&: Value, Str: "Arm64" , ConstVal: PDB_Machine::Arm64); |
| 55 | } |
| 56 | }; |
| 57 | |
| 58 | template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_DbiVer> { |
| 59 | static void enumeration(IO &io, llvm::pdb::PdbRaw_DbiVer &Value) { |
| 60 | io.enumCase(Val&: Value, Str: "V41" , ConstVal: llvm::pdb::PdbRaw_DbiVer::PdbDbiVC41); |
| 61 | io.enumCase(Val&: Value, Str: "V50" , ConstVal: llvm::pdb::PdbRaw_DbiVer::PdbDbiV50); |
| 62 | io.enumCase(Val&: Value, Str: "V60" , ConstVal: llvm::pdb::PdbRaw_DbiVer::PdbDbiV60); |
| 63 | io.enumCase(Val&: Value, Str: "V70" , ConstVal: llvm::pdb::PdbRaw_DbiVer::PdbDbiV70); |
| 64 | io.enumCase(Val&: Value, Str: "V110" , ConstVal: llvm::pdb::PdbRaw_DbiVer::PdbDbiV110); |
| 65 | } |
| 66 | }; |
| 67 | |
| 68 | template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_ImplVer> { |
| 69 | static void enumeration(IO &io, llvm::pdb::PdbRaw_ImplVer &Value) { |
| 70 | io.enumCase(Val&: Value, Str: "VC2" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC2); |
| 71 | io.enumCase(Val&: Value, Str: "VC4" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC4); |
| 72 | io.enumCase(Val&: Value, Str: "VC41" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC41); |
| 73 | io.enumCase(Val&: Value, Str: "VC50" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC50); |
| 74 | io.enumCase(Val&: Value, Str: "VC98" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC98); |
| 75 | io.enumCase(Val&: Value, Str: "VC70Dep" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC70Dep); |
| 76 | io.enumCase(Val&: Value, Str: "VC70" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC70); |
| 77 | io.enumCase(Val&: Value, Str: "VC80" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC80); |
| 78 | io.enumCase(Val&: Value, Str: "VC110" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC110); |
| 79 | io.enumCase(Val&: Value, Str: "VC140" , ConstVal: llvm::pdb::PdbRaw_ImplVer::PdbImplVC140); |
| 80 | } |
| 81 | }; |
| 82 | |
| 83 | template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_TpiVer> { |
| 84 | static void enumeration(IO &io, llvm::pdb::PdbRaw_TpiVer &Value) { |
| 85 | io.enumCase(Val&: Value, Str: "VC40" , ConstVal: llvm::pdb::PdbRaw_TpiVer::PdbTpiV40); |
| 86 | io.enumCase(Val&: Value, Str: "VC41" , ConstVal: llvm::pdb::PdbRaw_TpiVer::PdbTpiV41); |
| 87 | io.enumCase(Val&: Value, Str: "VC50" , ConstVal: llvm::pdb::PdbRaw_TpiVer::PdbTpiV50); |
| 88 | io.enumCase(Val&: Value, Str: "VC70" , ConstVal: llvm::pdb::PdbRaw_TpiVer::PdbTpiV70); |
| 89 | io.enumCase(Val&: Value, Str: "VC80" , ConstVal: llvm::pdb::PdbRaw_TpiVer::PdbTpiV80); |
| 90 | } |
| 91 | }; |
| 92 | |
| 93 | template <> struct ScalarEnumerationTraits<llvm::pdb::PdbRaw_FeatureSig> { |
| 94 | static void enumeration(IO &io, PdbRaw_FeatureSig &Features) { |
| 95 | io.enumCase(Val&: Features, Str: "MinimalDebugInfo" , |
| 96 | ConstVal: PdbRaw_FeatureSig::MinimalDebugInfo); |
| 97 | io.enumCase(Val&: Features, Str: "NoTypeMerge" , ConstVal: PdbRaw_FeatureSig::NoTypeMerge); |
| 98 | io.enumCase(Val&: Features, Str: "VC110" , ConstVal: PdbRaw_FeatureSig::VC110); |
| 99 | io.enumCase(Val&: Features, Str: "VC140" , ConstVal: PdbRaw_FeatureSig::VC140); |
| 100 | } |
| 101 | }; |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | void MappingTraits<PdbObject>::mapping(IO &IO, PdbObject &Obj) { |
| 106 | IO.mapOptional(Key: "MSF" , Val&: Obj.Headers); |
| 107 | IO.mapOptional(Key: "StreamSizes" , Val&: Obj.StreamSizes); |
| 108 | IO.mapOptional(Key: "StreamMap" , Val&: Obj.StreamMap); |
| 109 | IO.mapOptional(Key: "StringTable" , Val&: Obj.StringTable); |
| 110 | IO.mapOptional(Key: "PdbStream" , Val&: Obj.PdbStream); |
| 111 | IO.mapOptional(Key: "DbiStream" , Val&: Obj.DbiStream); |
| 112 | IO.mapOptional(Key: "TpiStream" , Val&: Obj.TpiStream); |
| 113 | IO.mapOptional(Key: "IpiStream" , Val&: Obj.IpiStream); |
| 114 | IO.mapOptional(Key: "PublicsStream" , Val&: Obj.PublicsStream); |
| 115 | } |
| 116 | |
| 117 | void MappingTraits<MSFHeaders>::(IO &IO, MSFHeaders &Obj) { |
| 118 | IO.mapOptional(Key: "SuperBlock" , Val&: Obj.SuperBlock); |
| 119 | IO.mapOptional(Key: "NumDirectoryBlocks" , Val&: Obj.NumDirectoryBlocks); |
| 120 | IO.mapOptional(Key: "DirectoryBlocks" , Val&: Obj.DirectoryBlocks); |
| 121 | IO.mapOptional(Key: "NumStreams" , Val&: Obj.NumStreams); |
| 122 | IO.mapOptional(Key: "FileSize" , Val&: Obj.FileSize); |
| 123 | } |
| 124 | |
| 125 | void MappingTraits<msf::SuperBlock>::mapping(IO &IO, msf::SuperBlock &SB) { |
| 126 | if (!IO.outputting()) { |
| 127 | ::memcpy(dest: SB.MagicBytes, src: msf::Magic, n: sizeof(msf::Magic)); |
| 128 | } |
| 129 | |
| 130 | using u32 = support::ulittle32_t; |
| 131 | IO.mapOptional(Key: "BlockSize" , Val&: SB.BlockSize, Default: u32(4096U)); |
| 132 | IO.mapOptional(Key: "FreeBlockMap" , Val&: SB.FreeBlockMapBlock, Default: u32(0U)); |
| 133 | IO.mapOptional(Key: "NumBlocks" , Val&: SB.NumBlocks, Default: u32(0U)); |
| 134 | IO.mapOptional(Key: "NumDirectoryBytes" , Val&: SB.NumDirectoryBytes, Default: u32(0U)); |
| 135 | IO.mapOptional(Key: "Unknown1" , Val&: SB.Unknown1, Default: u32(0U)); |
| 136 | IO.mapOptional(Key: "BlockMapAddr" , Val&: SB.BlockMapAddr, Default: u32(0U)); |
| 137 | } |
| 138 | |
| 139 | CoffSectionHeader::() = default; |
| 140 | |
| 141 | CoffSectionHeader::(const object::coff_section &Section) |
| 142 | : Name(Section.Name), VirtualSize(Section.VirtualSize), |
| 143 | VirtualAddress(Section.VirtualAddress), |
| 144 | SizeOfRawData(Section.SizeOfRawData), |
| 145 | PointerToRawData(Section.PointerToRawData), |
| 146 | PointerToRelocations(Section.PointerToRelocations), |
| 147 | PointerToLinenumbers(Section.PointerToLinenumbers), |
| 148 | NumberOfRelocations(Section.NumberOfRelocations), |
| 149 | NumberOfLinenumbers(Section.NumberOfLinenumbers), |
| 150 | Characteristics(Section.Characteristics) {} |
| 151 | |
| 152 | object::coff_section CoffSectionHeader::() const { |
| 153 | object::coff_section Sec; |
| 154 | std::memset(s: Sec.Name, c: 0, n: COFF::NameSize); |
| 155 | std::memcpy(dest: Sec.Name, src: Name.data(), |
| 156 | n: std::min(a: static_cast<size_t>(COFF::NameSize), b: Name.size())); |
| 157 | Sec.VirtualSize = VirtualSize; |
| 158 | Sec.VirtualAddress = VirtualAddress; |
| 159 | Sec.SizeOfRawData = SizeOfRawData; |
| 160 | Sec.PointerToRawData = PointerToRawData; |
| 161 | Sec.PointerToRelocations = PointerToRelocations; |
| 162 | Sec.PointerToLinenumbers = PointerToLinenumbers; |
| 163 | Sec.NumberOfRelocations = NumberOfRelocations; |
| 164 | Sec.NumberOfLinenumbers = NumberOfLinenumbers; |
| 165 | Sec.Characteristics = Characteristics; |
| 166 | return Sec; |
| 167 | } |
| 168 | |
| 169 | void MappingTraits<CoffSectionHeader>::(IO &IO, CoffSectionHeader &Obj) { |
| 170 | IO.mapRequired(Key: "Name" , Val&: Obj.Name); |
| 171 | IO.mapOptional(Key: "VirtualSize" , Val&: Obj.VirtualSize); |
| 172 | IO.mapOptional(Key: "VirtualAddress" , Val&: Obj.VirtualAddress); |
| 173 | IO.mapOptional(Key: "SizeOfRawData" , Val&: Obj.SizeOfRawData); |
| 174 | IO.mapOptional(Key: "PointerToRawData" , Val&: Obj.PointerToRawData); |
| 175 | IO.mapOptional(Key: "PointerToRelocations" , Val&: Obj.PointerToRelocations); |
| 176 | IO.mapOptional(Key: "PointerToLinenumbers" , Val&: Obj.PointerToLinenumbers); |
| 177 | IO.mapOptional(Key: "NumberOfRelocations" , Val&: Obj.NumberOfRelocations); |
| 178 | IO.mapOptional(Key: "NumberOfLinenumbers" , Val&: Obj.NumberOfLinenumbers); |
| 179 | IO.mapOptional(Key: "Characteristics" , Val&: Obj.Characteristics); |
| 180 | } |
| 181 | |
| 182 | void MappingTraits<StreamBlockList>::mapping(IO &IO, StreamBlockList &SB) { |
| 183 | IO.mapRequired(Key: "Stream" , Val&: SB.Blocks); |
| 184 | } |
| 185 | |
| 186 | void MappingTraits<PdbInfoStream>::mapping(IO &IO, PdbInfoStream &Obj) { |
| 187 | IO.mapOptional(Key: "Age" , Val&: Obj.Age, Default: 1U); |
| 188 | IO.mapOptional(Key: "Guid" , Val&: Obj.Guid); |
| 189 | IO.mapOptional(Key: "Signature" , Val&: Obj.Signature, Default: 0U); |
| 190 | IO.mapOptional(Key: "Features" , Val&: Obj.Features); |
| 191 | IO.mapOptional(Key: "Version" , Val&: Obj.Version, Default: PdbImplVC70); |
| 192 | } |
| 193 | |
| 194 | void MappingTraits<PdbDbiStream>::mapping(IO &IO, PdbDbiStream &Obj) { |
| 195 | IO.mapOptional(Key: "VerHeader" , Val&: Obj.VerHeader, Default: PdbDbiV70); |
| 196 | IO.mapOptional(Key: "Age" , Val&: Obj.Age, Default: 1U); |
| 197 | IO.mapOptional(Key: "BuildNumber" , Val&: Obj.BuildNumber, Default: uint16_t(0U)); |
| 198 | IO.mapOptional(Key: "PdbDllVersion" , Val&: Obj.PdbDllVersion, Default: 0U); |
| 199 | IO.mapOptional(Key: "PdbDllRbld" , Val&: Obj.PdbDllRbld, Default: uint16_t(0U)); |
| 200 | IO.mapOptional(Key: "Flags" , Val&: Obj.Flags, Default: uint16_t(1U)); |
| 201 | IO.mapOptional(Key: "MachineType" , Val&: Obj.MachineType, Default: PDB_Machine::x86); |
| 202 | // This is a workaround for IO not having document context with the |
| 203 | // machine type. The machine type is needed to properly parse Register enums |
| 204 | // in the PDB. |
| 205 | if (!IO.getContext()) { |
| 206 | Obj.FakeHeader.Machine = static_cast<uint16_t>(Obj.MachineType); |
| 207 | IO.setContext(&Obj.FakeHeader); |
| 208 | } |
| 209 | IO.mapOptional(Key: "Modules" , Val&: Obj.ModInfos); |
| 210 | IO.mapOptional(Key: "SectionHeaders" , Val&: Obj.SectionHeaders); |
| 211 | } |
| 212 | |
| 213 | void MappingTraits<PdbTpiStream>::mapping(IO &IO, |
| 214 | pdb::yaml::PdbTpiStream &Obj) { |
| 215 | IO.mapOptional(Key: "Version" , Val&: Obj.Version, Default: PdbTpiV80); |
| 216 | IO.mapRequired(Key: "Records" , Val&: Obj.Records); |
| 217 | } |
| 218 | |
| 219 | void MappingTraits<PdbPublicsStream>::mapping( |
| 220 | IO &IO, pdb::yaml::PdbPublicsStream &Obj) { |
| 221 | IO.mapRequired(Key: "Records" , Val&: Obj.PubSyms); |
| 222 | } |
| 223 | |
| 224 | void MappingTraits<NamedStreamMapping>::mapping(IO &IO, |
| 225 | NamedStreamMapping &Obj) { |
| 226 | IO.mapRequired(Key: "Name" , Val&: Obj.StreamName); |
| 227 | IO.mapRequired(Key: "StreamNum" , Val&: Obj.StreamNumber); |
| 228 | } |
| 229 | |
| 230 | void MappingTraits<PdbModiStream>::mapping(IO &IO, PdbModiStream &Obj) { |
| 231 | IO.mapOptional(Key: "Signature" , Val&: Obj.Signature, Default: 4U); |
| 232 | IO.mapRequired(Key: "Records" , Val&: Obj.Symbols); |
| 233 | } |
| 234 | |
| 235 | void MappingTraits<PdbDbiModuleInfo>::mapping(IO &IO, PdbDbiModuleInfo &Obj) { |
| 236 | IO.mapRequired(Key: "Module" , Val&: Obj.Mod); |
| 237 | IO.mapOptional(Key: "ObjFile" , Val&: Obj.Obj, Default: Obj.Mod); |
| 238 | IO.mapOptional(Key: "SourceFiles" , Val&: Obj.SourceFiles); |
| 239 | IO.mapOptional(Key: "Subsections" , Val&: Obj.Subsections); |
| 240 | IO.mapOptional(Key: "Modi" , Val&: Obj.Modi); |
| 241 | } |
| 242 | |