1 //===- TypeRecordMapping.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 "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
10 #include "llvm/ADT/StringExtras.h"
11 #include "llvm/ADT/Twine.h"
12 #include "llvm/DebugInfo/CodeView/EnumTables.h"
13 #include "llvm/Support/MD5.h"
14
15 using namespace llvm;
16 using namespace llvm::codeview;
17
18 namespace {
19
20 #define error(X) \
21 if (auto EC = X) \
22 return EC;
23
24 static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
25 #define CV_TYPE(enum, val) {#enum, enum},
26 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
27 };
28
getLeafTypeName(TypeLeafKind LT)29 static StringRef getLeafTypeName(TypeLeafKind LT) {
30 switch (LT) {
31 #define TYPE_RECORD(ename, value, name) \
32 case ename: \
33 return #name;
34 #include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
35 default:
36 break;
37 }
38 return "UnknownLeaf";
39 }
40
41 template <typename T>
compEnumNames(const EnumEntry<T> & lhs,const EnumEntry<T> & rhs)42 static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
43 return lhs.Name < rhs.Name;
44 }
45
46 template <typename T, typename TFlag>
getFlagNames(CodeViewRecordIO & IO,T Value,ArrayRef<EnumEntry<TFlag>> Flags)47 static std::string getFlagNames(CodeViewRecordIO &IO, T Value,
48 ArrayRef<EnumEntry<TFlag>> Flags) {
49 if (!IO.isStreaming())
50 return std::string("");
51 typedef EnumEntry<TFlag> FlagEntry;
52 typedef SmallVector<FlagEntry, 10> FlagVector;
53 FlagVector SetFlags;
54 for (const auto &Flag : Flags) {
55 if (Flag.Value == 0)
56 continue;
57 if ((Value & Flag.Value) == Flag.Value) {
58 SetFlags.push_back(Flag);
59 }
60 }
61
62 llvm::sort(SetFlags, &compEnumNames<TFlag>);
63
64 std::string FlagLabel;
65 bool FirstOcc = true;
66 for (const auto &Flag : SetFlags) {
67 if (FirstOcc)
68 FirstOcc = false;
69 else
70 FlagLabel += (" | ");
71
72 FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")");
73 }
74
75 if (!FlagLabel.empty()) {
76 std::string LabelWithBraces(" ( ");
77 LabelWithBraces += FlagLabel + " )";
78 return LabelWithBraces;
79 } else
80 return FlagLabel;
81 }
82
83 template <typename T, typename TEnum>
getEnumName(CodeViewRecordIO & IO,T Value,ArrayRef<EnumEntry<TEnum>> EnumValues)84 static StringRef getEnumName(CodeViewRecordIO &IO, T Value,
85 ArrayRef<EnumEntry<TEnum>> EnumValues) {
86 if (!IO.isStreaming())
87 return "";
88 StringRef Name;
89 for (const auto &EnumItem : EnumValues) {
90 if (EnumItem.Value == Value) {
91 Name = EnumItem.Name;
92 break;
93 }
94 }
95
96 return Name;
97 }
98
getMemberAttributes(CodeViewRecordIO & IO,MemberAccess Access,MethodKind Kind,MethodOptions Options)99 static std::string getMemberAttributes(CodeViewRecordIO &IO,
100 MemberAccess Access, MethodKind Kind,
101 MethodOptions Options) {
102 if (!IO.isStreaming())
103 return "";
104 std::string AccessSpecifier = std::string(
105 getEnumName(IO, uint8_t(Access), makeArrayRef(getMemberAccessNames())));
106 std::string MemberAttrs(AccessSpecifier);
107 if (Kind != MethodKind::Vanilla) {
108 std::string MethodKind = std::string(
109 getEnumName(IO, unsigned(Kind), makeArrayRef(getMemberKindNames())));
110 MemberAttrs += ", " + MethodKind;
111 }
112 if (Options != MethodOptions::None) {
113 std::string MethodOptions = getFlagNames(
114 IO, unsigned(Options), makeArrayRef(getMethodOptionNames()));
115 MemberAttrs += ", " + MethodOptions;
116 }
117 return MemberAttrs;
118 }
119
120 struct MapOneMethodRecord {
MapOneMethodRecord__anon431bd71f0111::MapOneMethodRecord121 explicit MapOneMethodRecord(bool IsFromOverloadList)
122 : IsFromOverloadList(IsFromOverloadList) {}
123
operator ()__anon431bd71f0111::MapOneMethodRecord124 Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
125 std::string Attrs = getMemberAttributes(
126 IO, Method.getAccess(), Method.getMethodKind(), Method.getOptions());
127 error(IO.mapInteger(Method.Attrs.Attrs, "Attrs: " + Attrs));
128 if (IsFromOverloadList) {
129 uint16_t Padding = 0;
130 error(IO.mapInteger(Padding));
131 }
132 error(IO.mapInteger(Method.Type, "Type"));
133 if (Method.isIntroducingVirtual()) {
134 error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset"));
135 } else if (IO.isReading())
136 Method.VFTableOffset = -1;
137
138 if (!IsFromOverloadList)
139 error(IO.mapStringZ(Method.Name, "Name"));
140
141 return Error::success();
142 }
143
144 private:
145 bool IsFromOverloadList;
146 };
147 } // namespace
148
149 // Computes a string representation of a hash of the specified name, suitable
150 // for use when emitting CodeView type names.
computeHashString(StringRef Name,SmallString<32> & StringifiedHash)151 static void computeHashString(StringRef Name,
152 SmallString<32> &StringifiedHash) {
153 llvm::MD5 Hash;
154 llvm::MD5::MD5Result Result;
155 Hash.update(Name);
156 Hash.final(Result);
157 Hash.stringifyResult(Result, StringifiedHash);
158 }
159
mapNameAndUniqueName(CodeViewRecordIO & IO,StringRef & Name,StringRef & UniqueName,bool HasUniqueName)160 static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
161 StringRef &UniqueName, bool HasUniqueName) {
162 if (IO.isWriting()) {
163 // Try to be smart about what we write here. We can't write anything too
164 // large, so if we're going to go over the limit, replace lengthy names with
165 // a stringified hash value.
166 size_t BytesLeft = IO.maxFieldLength();
167 if (HasUniqueName) {
168 size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
169 if (BytesNeeded > BytesLeft) {
170 // The minimum space required for emitting hashes of both names.
171 assert(BytesLeft >= 70);
172
173 // Replace the entire unique name with a hash of the unique name.
174 SmallString<32> Hash;
175 computeHashString(UniqueName, Hash);
176 std::string UniqueB = Twine("??@" + Hash + "@").str();
177 assert(UniqueB.size() == 36);
178
179 // Truncate the name if necessary and append a hash of the name.
180 // The name length, hash included, is limited to 4096 bytes.
181 const size_t MaxTakeN = 4096;
182 size_t TakeN = std::min(MaxTakeN, BytesLeft - UniqueB.size() - 2) - 32;
183 computeHashString(Name, Hash);
184 std::string NameB = (Name.take_front(TakeN) + Hash).str();
185
186 StringRef N = NameB;
187 StringRef U = UniqueB;
188 error(IO.mapStringZ(N));
189 error(IO.mapStringZ(U));
190 } else {
191 error(IO.mapStringZ(Name));
192 error(IO.mapStringZ(UniqueName));
193 }
194 } else {
195 // Cap the length of the string at however many bytes we have available,
196 // plus one for the required null terminator.
197 auto N = StringRef(Name).take_front(BytesLeft - 1);
198 error(IO.mapStringZ(N));
199 }
200 } else {
201 // Reading & Streaming mode come after writing mode is executed for each
202 // record. Truncating large names are done during writing, so its not
203 // necessary to do it while reading or streaming.
204 error(IO.mapStringZ(Name, "Name"));
205 if (HasUniqueName)
206 error(IO.mapStringZ(UniqueName, "LinkageName"));
207 }
208
209 return Error::success();
210 }
211
visitTypeBegin(CVType & CVR)212 Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
213 assert(!TypeKind.hasValue() && "Already in a type mapping!");
214 assert(!MemberKind.hasValue() && "Already in a member mapping!");
215
216 // FieldList and MethodList records can be any length because they can be
217 // split with continuation records. All other record types cannot be
218 // longer than the maximum record length.
219 Optional<uint32_t> MaxLen;
220 if (CVR.kind() != TypeLeafKind::LF_FIELDLIST &&
221 CVR.kind() != TypeLeafKind::LF_METHODLIST)
222 MaxLen = MaxRecordLength - sizeof(RecordPrefix);
223 error(IO.beginRecord(MaxLen));
224 TypeKind = CVR.kind();
225
226 if (IO.isStreaming()) {
227 auto RecordKind = CVR.kind();
228 uint16_t RecordLen = CVR.length() - 2;
229 std::string RecordKindName = std::string(
230 getEnumName(IO, unsigned(RecordKind), makeArrayRef(LeafTypeNames)));
231 error(IO.mapInteger(RecordLen, "Record length"));
232 error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName));
233 }
234 return Error::success();
235 }
236
visitTypeBegin(CVType & CVR,TypeIndex Index)237 Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) {
238 if (IO.isStreaming())
239 IO.emitRawComment(" " + getLeafTypeName(CVR.kind()) + " (0x" +
240 utohexstr(Index.getIndex()) + ")");
241 return visitTypeBegin(CVR);
242 }
243
visitTypeEnd(CVType & Record)244 Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
245 assert(TypeKind.hasValue() && "Not in a type mapping!");
246 assert(!MemberKind.hasValue() && "Still in a member mapping!");
247
248 error(IO.endRecord());
249
250 TypeKind.reset();
251 return Error::success();
252 }
253
visitMemberBegin(CVMemberRecord & Record)254 Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
255 assert(TypeKind.hasValue() && "Not in a type mapping!");
256 assert(!MemberKind.hasValue() && "Already in a member mapping!");
257
258 // The largest possible subrecord is one in which there is a record prefix,
259 // followed by the subrecord, followed by a continuation, and that entire
260 // sequence spawns `MaxRecordLength` bytes. So the record's length is
261 // calculated as follows.
262
263 constexpr uint32_t ContinuationLength = 8;
264 error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
265 ContinuationLength));
266
267 MemberKind = Record.Kind;
268 if (IO.isStreaming()) {
269 std::string MemberKindName = std::string(getLeafTypeName(Record.Kind));
270 MemberKindName +=
271 " ( " +
272 (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames)))
273 .str() +
274 " )";
275 error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName));
276 }
277 return Error::success();
278 }
279
visitMemberEnd(CVMemberRecord & Record)280 Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
281 assert(TypeKind.hasValue() && "Not in a type mapping!");
282 assert(MemberKind.hasValue() && "Not in a member mapping!");
283
284 if (IO.isReading()) {
285 if (auto EC = IO.skipPadding())
286 return EC;
287 }
288
289 MemberKind.reset();
290 error(IO.endRecord());
291 return Error::success();
292 }
293
visitKnownRecord(CVType & CVR,ModifierRecord & Record)294 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
295 std::string ModifierNames =
296 getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers),
297 makeArrayRef(getTypeModifierNames()));
298 error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
299 error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames));
300 return Error::success();
301 }
302
visitKnownRecord(CVType & CVR,ProcedureRecord & Record)303 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
304 ProcedureRecord &Record) {
305 std::string CallingConvName = std::string(getEnumName(
306 IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions())));
307 std::string FuncOptionNames =
308 getFlagNames(IO, static_cast<uint16_t>(Record.Options),
309 makeArrayRef(getFunctionOptionEnum()));
310 error(IO.mapInteger(Record.ReturnType, "ReturnType"));
311 error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
312 error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
313 error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
314 error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
315
316 return Error::success();
317 }
318
visitKnownRecord(CVType & CVR,MemberFunctionRecord & Record)319 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
320 MemberFunctionRecord &Record) {
321 std::string CallingConvName = std::string(getEnumName(
322 IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions())));
323 std::string FuncOptionNames =
324 getFlagNames(IO, static_cast<uint16_t>(Record.Options),
325 makeArrayRef(getFunctionOptionEnum()));
326 error(IO.mapInteger(Record.ReturnType, "ReturnType"));
327 error(IO.mapInteger(Record.ClassType, "ClassType"));
328 error(IO.mapInteger(Record.ThisType, "ThisType"));
329 error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
330 error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
331 error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
332 error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
333 error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment"));
334
335 return Error::success();
336 }
337
visitKnownRecord(CVType & CVR,ArgListRecord & Record)338 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
339 error(IO.mapVectorN<uint32_t>(
340 Record.ArgIndices,
341 [](CodeViewRecordIO &IO, TypeIndex &N) {
342 return IO.mapInteger(N, "Argument");
343 },
344 "NumArgs"));
345 return Error::success();
346 }
347
visitKnownRecord(CVType & CVR,StringListRecord & Record)348 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
349 StringListRecord &Record) {
350 error(IO.mapVectorN<uint32_t>(
351 Record.StringIndices,
352 [](CodeViewRecordIO &IO, TypeIndex &N) {
353 return IO.mapInteger(N, "Strings");
354 },
355 "NumStrings"));
356
357 return Error::success();
358 }
359
visitKnownRecord(CVType & CVR,PointerRecord & Record)360 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
361
362 SmallString<128> Attr("Attrs: ");
363
364 if (IO.isStreaming()) {
365 std::string PtrType =
366 std::string(getEnumName(IO, unsigned(Record.getPointerKind()),
367 makeArrayRef(getPtrKindNames())));
368 Attr += "[ Type: " + PtrType;
369
370 std::string PtrMode = std::string(getEnumName(
371 IO, unsigned(Record.getMode()), makeArrayRef(getPtrModeNames())));
372 Attr += ", Mode: " + PtrMode;
373
374 auto PtrSizeOf = Record.getSize();
375 Attr += ", SizeOf: " + itostr(PtrSizeOf);
376
377 if (Record.isFlat())
378 Attr += ", isFlat";
379 if (Record.isConst())
380 Attr += ", isConst";
381 if (Record.isVolatile())
382 Attr += ", isVolatile";
383 if (Record.isUnaligned())
384 Attr += ", isUnaligned";
385 if (Record.isRestrict())
386 Attr += ", isRestricted";
387 if (Record.isLValueReferenceThisPtr())
388 Attr += ", isThisPtr&";
389 if (Record.isRValueReferenceThisPtr())
390 Attr += ", isThisPtr&&";
391 Attr += " ]";
392 }
393
394 error(IO.mapInteger(Record.ReferentType, "PointeeType"));
395 error(IO.mapInteger(Record.Attrs, Attr));
396
397 if (Record.isPointerToMember()) {
398 if (IO.isReading())
399 Record.MemberInfo.emplace();
400
401 MemberPointerInfo &M = *Record.MemberInfo;
402 error(IO.mapInteger(M.ContainingType, "ClassType"));
403 std::string PtrMemberGetRepresentation = std::string(getEnumName(
404 IO, uint16_t(M.Representation), makeArrayRef(getPtrMemberRepNames())));
405 error(IO.mapEnum(M.Representation,
406 "Representation: " + PtrMemberGetRepresentation));
407 }
408
409 return Error::success();
410 }
411
visitKnownRecord(CVType & CVR,ArrayRecord & Record)412 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
413 error(IO.mapInteger(Record.ElementType, "ElementType"));
414 error(IO.mapInteger(Record.IndexType, "IndexType"));
415 error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
416 error(IO.mapStringZ(Record.Name, "Name"));
417
418 return Error::success();
419 }
420
visitKnownRecord(CVType & CVR,ClassRecord & Record)421 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
422 assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
423 (CVR.kind() == TypeLeafKind::LF_CLASS) ||
424 (CVR.kind() == TypeLeafKind::LF_INTERFACE));
425
426 std::string PropertiesNames =
427 getFlagNames(IO, static_cast<uint16_t>(Record.Options),
428 makeArrayRef(getClassOptionNames()));
429 error(IO.mapInteger(Record.MemberCount, "MemberCount"));
430 error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
431 error(IO.mapInteger(Record.FieldList, "FieldList"));
432 error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
433 error(IO.mapInteger(Record.VTableShape, "VShape"));
434 error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
435 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
436 Record.hasUniqueName()));
437
438 return Error::success();
439 }
440
visitKnownRecord(CVType & CVR,UnionRecord & Record)441 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
442 std::string PropertiesNames =
443 getFlagNames(IO, static_cast<uint16_t>(Record.Options),
444 makeArrayRef(getClassOptionNames()));
445 error(IO.mapInteger(Record.MemberCount, "MemberCount"));
446 error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
447 error(IO.mapInteger(Record.FieldList, "FieldList"));
448 error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
449 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
450 Record.hasUniqueName()));
451
452 return Error::success();
453 }
454
visitKnownRecord(CVType & CVR,EnumRecord & Record)455 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
456 std::string PropertiesNames =
457 getFlagNames(IO, static_cast<uint16_t>(Record.Options),
458 makeArrayRef(getClassOptionNames()));
459 error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
460 error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
461 error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
462 error(IO.mapInteger(Record.FieldList, "FieldListType"));
463 error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
464 Record.hasUniqueName()));
465
466 return Error::success();
467 }
468
visitKnownRecord(CVType & CVR,BitFieldRecord & Record)469 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
470 error(IO.mapInteger(Record.Type, "Type"));
471 error(IO.mapInteger(Record.BitSize, "BitSize"));
472 error(IO.mapInteger(Record.BitOffset, "BitOffset"));
473
474 return Error::success();
475 }
476
visitKnownRecord(CVType & CVR,VFTableShapeRecord & Record)477 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
478 VFTableShapeRecord &Record) {
479 uint16_t Size;
480 if (!IO.isReading()) {
481 ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
482 Size = Slots.size();
483 error(IO.mapInteger(Size, "VFEntryCount"));
484
485 for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
486 uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
487 if ((SlotIndex + 1) < Slots.size()) {
488 Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
489 }
490 error(IO.mapInteger(Byte));
491 }
492 } else {
493 error(IO.mapInteger(Size));
494 for (uint16_t I = 0; I < Size; I += 2) {
495 uint8_t Byte;
496 error(IO.mapInteger(Byte));
497 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
498 if ((I + 1) < Size)
499 Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
500 }
501 }
502
503 return Error::success();
504 }
505
visitKnownRecord(CVType & CVR,VFTableRecord & Record)506 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
507 error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
508 error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
509 error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
510 uint32_t NamesLen = 0;
511 if (!IO.isReading()) {
512 for (auto Name : Record.MethodNames)
513 NamesLen += Name.size() + 1;
514 }
515 error(IO.mapInteger(NamesLen));
516 error(IO.mapVectorTail(
517 Record.MethodNames,
518 [](CodeViewRecordIO &IO, StringRef &S) {
519 return IO.mapStringZ(S, "MethodName");
520 },
521 "VFTableName"));
522
523 return Error::success();
524 }
525
visitKnownRecord(CVType & CVR,StringIdRecord & Record)526 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
527 error(IO.mapInteger(Record.Id, "Id"));
528 error(IO.mapStringZ(Record.String, "StringData"));
529
530 return Error::success();
531 }
532
visitKnownRecord(CVType & CVR,UdtSourceLineRecord & Record)533 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
534 UdtSourceLineRecord &Record) {
535 error(IO.mapInteger(Record.UDT, "UDT"));
536 error(IO.mapInteger(Record.SourceFile, "SourceFile"));
537 error(IO.mapInteger(Record.LineNumber, "LineNumber"));
538
539 return Error::success();
540 }
541
visitKnownRecord(CVType & CVR,UdtModSourceLineRecord & Record)542 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
543 UdtModSourceLineRecord &Record) {
544 error(IO.mapInteger(Record.UDT, "UDT"));
545 error(IO.mapInteger(Record.SourceFile, "SourceFile"));
546 error(IO.mapInteger(Record.LineNumber, "LineNumber"));
547 error(IO.mapInteger(Record.Module, "Module"));
548
549 return Error::success();
550 }
551
visitKnownRecord(CVType & CVR,FuncIdRecord & Record)552 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
553 error(IO.mapInteger(Record.ParentScope, "ParentScope"));
554 error(IO.mapInteger(Record.FunctionType, "FunctionType"));
555 error(IO.mapStringZ(Record.Name, "Name"));
556
557 return Error::success();
558 }
559
visitKnownRecord(CVType & CVR,MemberFuncIdRecord & Record)560 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
561 MemberFuncIdRecord &Record) {
562 error(IO.mapInteger(Record.ClassType, "ClassType"));
563 error(IO.mapInteger(Record.FunctionType, "FunctionType"));
564 error(IO.mapStringZ(Record.Name, "Name"));
565
566 return Error::success();
567 }
568
visitKnownRecord(CVType & CVR,BuildInfoRecord & Record)569 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
570 BuildInfoRecord &Record) {
571 error(IO.mapVectorN<uint16_t>(
572 Record.ArgIndices,
573 [](CodeViewRecordIO &IO, TypeIndex &N) {
574 return IO.mapInteger(N, "Argument");
575 },
576 "NumArgs"));
577
578 return Error::success();
579 }
580
visitKnownRecord(CVType & CVR,MethodOverloadListRecord & Record)581 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
582 MethodOverloadListRecord &Record) {
583 // TODO: Split the list into multiple records if it's longer than 64KB, using
584 // a subrecord of TypeRecordKind::Index to chain the records together.
585 error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
586
587 return Error::success();
588 }
589
visitKnownRecord(CVType & CVR,FieldListRecord & Record)590 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
591 FieldListRecord &Record) {
592 if (IO.isStreaming()) {
593 if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
594 return EC;
595 } else
596 error(IO.mapByteVectorTail(Record.Data));
597
598 return Error::success();
599 }
600
visitKnownRecord(CVType & CVR,TypeServer2Record & Record)601 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
602 TypeServer2Record &Record) {
603 error(IO.mapGuid(Record.Guid, "Guid"));
604 error(IO.mapInteger(Record.Age, "Age"));
605 error(IO.mapStringZ(Record.Name, "Name"));
606 return Error::success();
607 }
608
visitKnownRecord(CVType & CVR,LabelRecord & Record)609 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
610 std::string ModeName = std::string(
611 getEnumName(IO, uint16_t(Record.Mode), makeArrayRef(getLabelTypeEnum())));
612 error(IO.mapEnum(Record.Mode, "Mode: " + ModeName));
613 return Error::success();
614 }
615
visitKnownMember(CVMemberRecord & CVR,BaseClassRecord & Record)616 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
617 BaseClassRecord &Record) {
618 std::string Attrs = getMemberAttributes(
619 IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
620 error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
621 error(IO.mapInteger(Record.Type, "BaseType"));
622 error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
623
624 return Error::success();
625 }
626
visitKnownMember(CVMemberRecord & CVR,EnumeratorRecord & Record)627 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
628 EnumeratorRecord &Record) {
629 std::string Attrs = getMemberAttributes(
630 IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
631 error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
632
633 // FIXME: Handle full APInt such as __int128.
634 error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
635 error(IO.mapStringZ(Record.Name, "Name"));
636
637 return Error::success();
638 }
639
visitKnownMember(CVMemberRecord & CVR,DataMemberRecord & Record)640 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
641 DataMemberRecord &Record) {
642 std::string Attrs = getMemberAttributes(
643 IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
644 error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
645 error(IO.mapInteger(Record.Type, "Type"));
646 error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
647 error(IO.mapStringZ(Record.Name, "Name"));
648
649 return Error::success();
650 }
651
visitKnownMember(CVMemberRecord & CVR,OverloadedMethodRecord & Record)652 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
653 OverloadedMethodRecord &Record) {
654 error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
655 error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
656 error(IO.mapStringZ(Record.Name, "Name"));
657
658 return Error::success();
659 }
660
visitKnownMember(CVMemberRecord & CVR,OneMethodRecord & Record)661 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
662 OneMethodRecord &Record) {
663 const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
664 MapOneMethodRecord Mapper(IsFromOverloadList);
665 return Mapper(IO, Record);
666 }
667
visitKnownMember(CVMemberRecord & CVR,NestedTypeRecord & Record)668 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
669 NestedTypeRecord &Record) {
670 uint16_t Padding = 0;
671 error(IO.mapInteger(Padding, "Padding"));
672 error(IO.mapInteger(Record.Type, "Type"));
673 error(IO.mapStringZ(Record.Name, "Name"));
674
675 return Error::success();
676 }
677
visitKnownMember(CVMemberRecord & CVR,StaticDataMemberRecord & Record)678 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
679 StaticDataMemberRecord &Record) {
680
681 std::string Attrs = getMemberAttributes(
682 IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
683 error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
684 error(IO.mapInteger(Record.Type, "Type"));
685 error(IO.mapStringZ(Record.Name, "Name"));
686
687 return Error::success();
688 }
689
visitKnownMember(CVMemberRecord & CVR,VirtualBaseClassRecord & Record)690 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
691 VirtualBaseClassRecord &Record) {
692
693 std::string Attrs = getMemberAttributes(
694 IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
695 error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
696 error(IO.mapInteger(Record.BaseType, "BaseType"));
697 error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
698 error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
699 error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
700
701 return Error::success();
702 }
703
visitKnownMember(CVMemberRecord & CVR,VFPtrRecord & Record)704 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
705 VFPtrRecord &Record) {
706 uint16_t Padding = 0;
707 error(IO.mapInteger(Padding, "Padding"));
708 error(IO.mapInteger(Record.Type, "Type"));
709
710 return Error::success();
711 }
712
visitKnownMember(CVMemberRecord & CVR,ListContinuationRecord & Record)713 Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
714 ListContinuationRecord &Record) {
715 uint16_t Padding = 0;
716 error(IO.mapInteger(Padding, "Padding"));
717 error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
718
719 return Error::success();
720 }
721
visitKnownRecord(CVType & CVR,PrecompRecord & Precomp)722 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
723 PrecompRecord &Precomp) {
724 error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
725 error(IO.mapInteger(Precomp.TypesCount, "Count"));
726 error(IO.mapInteger(Precomp.Signature, "Signature"));
727 error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
728 return Error::success();
729 }
730
visitKnownRecord(CVType & CVR,EndPrecompRecord & EndPrecomp)731 Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
732 EndPrecompRecord &EndPrecomp) {
733 error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
734 return Error::success();
735 }
736