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