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 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> 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> 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> 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 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 { 141 explicit MapOneMethodRecord(bool IsFromOverloadList) 142 : IsFromOverloadList(IsFromOverloadList) {} 143 144 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 751 Error TypeRecordMapping::visitKnownRecord(CVType &CVR, 752 EndPrecompRecord &EndPrecomp) { 753 error(IO.mapInteger(EndPrecomp.Signature, "Signature")); 754 return Error::success(); 755 } 756