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