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