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