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 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> 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> 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> 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 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 { 121 explicit MapOneMethodRecord(bool IsFromOverloadList) 122 : IsFromOverloadList(IsFromOverloadList) {} 123 124 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 731 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, 732 EndPrecompRecord &EndPrecomp) { 733 error(IO.mapInteger(EndPrecomp.Signature, "Signature")); 734 return Error::success(); 735 } 736