llvm.org GIT mirror llvm / fed38e2
[codeview] Add type stream merging prototype Summary: This code is intended to be used as part of LLD's PDB writing. Until that exists, this is exposed via llvm-readobj for testing purposes. Type stream merging uses the following algorithm: - Begin with a new empty stream, and a new empty hash table that maps from type record contents to new type index. - For each new type stream, maintain a map from source type index to destination type index. - For each record, copy it and rewrite its type indices to be valid in the destination type stream. - If the new type record is not already present in the destination stream hash table, append it to the destination type stream, assign it the next type index, and update the two hash tables. - If the type record already exists in the destination stream, discard it and update the type index map to forward the source type index to the existing destination type index. Reviewers: zturner, ruiu Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D20122 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@269521 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 4 years ago
22 changed file(s) with 821 addition(s) and 136 deletion(s). Raw diff Collapse all Expand all
1313 #include "llvm/DebugInfo/CodeView/RecordIterator.h"
1414 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
1515 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeStream.h"
1617 #include "llvm/Support/ErrorOr.h"
1718
1819 namespace llvm {
109110 /// Visits individual member records of a field list record. Member records do
110111 /// not describe their own length, and need special handling.
111112 void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData) {
113 auto *DerivedThis = static_cast(this);
112114 while (!FieldData.empty()) {
113115 const ulittle16_t *LeafPtr;
114116 if (!CVTypeVisitor::consumeObject(FieldData, LeafPtr))
118120 default:
119121 // Field list records do not describe their own length, so we cannot
120122 // continue parsing past an unknown member type.
121 visitUnknownMember(Leaf);
123 DerivedThis->visitUnknownMember(Leaf);
122124 return parseError();
123125 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
124126 case EnumName: { \
126128 auto Result = Name##Record::deserialize(RK, FieldData); \
127129 if (Result.getError()) \
128130 return parseError(); \
129 static_cast(this)->visit##Name(Leaf, *Result); \
131 DerivedThis->visit##Name(Leaf, *Result); \
130132 break; \
131133 }
132134 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
1010 #define LLVM_DEBUGINFO_CODEVIEW_FIELDLISTRECORDBUILDER_H
1111
1212 #include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
13 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1314
1415 namespace llvm {
1516 namespace codeview {
4546 public:
4647 FieldListRecordBuilder();
4748
48 void writeBaseClass(MemberAccess Access, TypeIndex Type, uint64_t Offset);
49 void writeEnumerate(MemberAccess Access, uint64_t Value, StringRef Name);
50 void writeIndirectVirtualBaseClass(MemberAccess Access, TypeIndex Type,
51 TypeIndex VirtualBasePointerType,
52 int64_t VirtualBasePointerOffset,
53 uint64_t SlotIndex);
54 void writeMember(MemberAccess Access, TypeIndex Type, uint64_t Offset,
55 StringRef Name);
56 void writeOneMethod(MemberAccess Access, MethodKind Kind,
57 MethodOptions Options, TypeIndex Type,
58 int32_t VTableSlotOffset, StringRef Name);
59 void writeOneMethod(const MethodInfo &Method, StringRef Name);
60 void writeMethod(uint16_t OverloadCount, TypeIndex MethodList,
61 StringRef Name);
62 void writeNestedType(TypeIndex Type, StringRef Name);
63 void writeStaticMember(MemberAccess Access, TypeIndex Type, StringRef Name);
64 void writeVirtualBaseClass(MemberAccess Access, TypeIndex Type,
65 TypeIndex VirtualBasePointerType,
66 int64_t VirtualBasePointerOffset,
67 uint64_t SlotIndex);
68 void writeVirtualBaseClass(TypeRecordKind Kind, MemberAccess Access,
69 TypeIndex Type, TypeIndex VirtualBasePointerType,
70 int64_t VirtualBasePointerOffset,
71 uint64_t SlotIndex);
72 void writeVirtualFunctionTablePointer(TypeIndex Type);
49 void writeBaseClass(const BaseClassRecord &Record);
50 void writeEnumerator(const EnumeratorRecord &Record);
51 void writeDataMember(const DataMemberRecord &Record);
52 void writeOneMethod(const OneMethodRecord &Record);
53 void writeOverloadedMethod(const OverloadedMethodRecord &Record);
54 void writeNestedType(const NestedTypeRecord &Record);
55 void writeStaticDataMember(const StaticDataMemberRecord &Record);
56 void writeVirtualBaseClass(const VirtualBaseClassRecord &Record);
57 void writeVFPtr(const VFPtrRecord &Type);
7358 };
7459 }
7560 }
2727 public:
2828 llvm::StringRef str() { return Builder.str(); }
2929
30 void reset() { Builder.reset(); }
31
3032 protected:
3133 void finishSubRecord();
3234
5454 }
5555 }
5656
57 private:
57 protected:
5858 TypeIndex writeRecord(llvm::StringRef Data) override;
5959
6060 private:
2929 /// Equvalent to CV_fldattr_t in cvinfo.h.
3030 struct MemberAttributes {
3131 ulittle16_t Attrs;
32 enum {
33 MethodKindShift = 2,
34 };
3235
3336 /// Get the access specifier. Valid for any kind of member.
3437 MemberAccess getAccess() const {
3841 /// Indicates if a method is defined with friend, virtual, static, etc.
3942 MethodKind getMethodKind() const {
4043 return MethodKind(
41 (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >> 2);
44 (unsigned(Attrs) & unsigned(MethodOptions::MethodKindMask)) >>
45 MethodKindShift);
4246 }
4347
4448 /// Get the flags that are not included in access control or method
7478 PointerToMemberRepresentation Representation)
7579 : ContainingType(ContainingType), Representation(Representation) {}
7680
81 /// Rewrite member type indices with IndexMap. Returns false if a type index
82 /// is not in the map.
83 bool remapTypeIndices(ArrayRef IndexMap);
84
7785 static ErrorOr deserialize(ArrayRef &Data) {
7886 const Layout *L = nullptr;
7987 if (auto EC = consumeObject(Data, L))
118126 ModifierRecord(TypeIndex ModifiedType, ModifierOptions Modifiers)
119127 : TypeRecord(TypeRecordKind::Modifier), ModifiedType(ModifiedType),
120128 Modifiers(Modifiers) {}
129
130 /// Rewrite member type indices with IndexMap. Returns false if a type index
131 /// is not in the map.
132 bool remapTypeIndices(ArrayRef IndexMap);
121133
122134 static ErrorOr deserialize(TypeRecordKind Kind,
123135 ArrayRef &Data) {
153165 : TypeRecord(TypeRecordKind::Procedure), ReturnType(ReturnType),
154166 CallConv(CallConv), Options(Options), ParameterCount(ParameterCount),
155167 ArgumentList(ArgumentList) {}
168
169 /// Rewrite member type indices with IndexMap. Returns false if a type index
170 /// is not in the map.
171 bool remapTypeIndices(ArrayRef IndexMap);
156172
157173 static ErrorOr deserialize(TypeRecordKind Kind,
158174 ArrayRef &Data) {
201217 ArgumentList(ArgumentList),
202218 ThisPointerAdjustment(ThisPointerAdjustment) {}
203219
220 /// Rewrite member type indices with IndexMap. Returns false if a type index
221 /// is not in the map.
222 bool remapTypeIndices(ArrayRef IndexMap);
223
204224 static ErrorOr deserialize(TypeRecordKind Kind,
205225 ArrayRef &Data) {
206226 const Layout *L = nullptr;
250270 : TypeRecord(TypeRecordKind::MemberFuncId), ClassType(ClassType),
251271 FunctionType(FunctionType), Name(Name) {}
252272
273 /// Rewrite member type indices with IndexMap. Returns false if a type index
274 /// is not in the map.
275 bool remapTypeIndices(ArrayRef IndexMap);
276
253277 static ErrorOr deserialize(TypeRecordKind Kind,
254 ArrayRef &Data) {
278 ArrayRef &Data) {
255279 const Layout *L = nullptr;
256280 StringRef Name;
257281 CV_DESERIALIZE(Data, L, Name);
279303 public:
280304 ArgListRecord(TypeRecordKind Kind, ArrayRef Indices)
281305 : TypeRecord(Kind), StringIndices(Indices) {}
306
307 /// Rewrite member type indices with IndexMap. Returns false if a type index
308 /// is not in the map.
309 bool remapTypeIndices(ArrayRef IndexMap);
282310
283311 static ErrorOr deserialize(TypeRecordKind Kind,
284312 ArrayRef &Data) {
302330 // ArgTypes[]: Type indicies of arguments
303331 };
304332
305 ArrayRef StringIndices;
333 std::vector StringIndices;
306334 };
307335
308336 // LF_POINTER
328356 : TypeRecord(TypeRecordKind::Pointer), ReferentType(ReferentType),
329357 PtrKind(Kind), Mode(Mode), Options(Options), Size(Size),
330358 MemberInfo(Member) {}
359
360 /// Rewrite member type indices with IndexMap. Returns false if a type index
361 /// is not in the map.
362 bool remapTypeIndices(ArrayRef IndexMap);
331363
332364 static ErrorOr deserialize(TypeRecordKind Kind,
333365 ArrayRef &Data) {
420452 NestedTypeRecord(TypeIndex Type, StringRef Name)
421453 : TypeRecord(TypeRecordKind::NestedType), Type(Type), Name(Name) {}
422454
455 /// Rewrite member type indices with IndexMap. Returns false if a type index
456 /// is not in the map.
457 bool remapTypeIndices(ArrayRef IndexMap);
458
423459 static ErrorOr deserialize(TypeRecordKind Kind,
424460 ArrayRef &Data) {
425461 const Layout *L = nullptr;
450486 StringRef Name)
451487 : TypeRecord(TypeRecordKind::Array), ElementType(ElementType),
452488 IndexType(IndexType), Size(Size), Name(Name) {}
489
490 /// Rewrite member type indices with IndexMap. Returns false if a type index
491 /// is not in the map.
492 bool remapTypeIndices(ArrayRef IndexMap);
453493
454494 static ErrorOr deserialize(TypeRecordKind Kind,
455495 ArrayRef &Data) {
488528 FieldList(FieldList), Name(Name), UniqueName(UniqueName) {}
489529
490530 public:
531 /// Rewrite member type indices with IndexMap. Returns false if a type index
532 /// is not in the map.
533 bool remapTypeIndices(ArrayRef IndexMap);
534
491535 static const int HfaKindShift = 11;
492536 static const int HfaKindMask = 0x1800;
493537 static const int WinRTKindShift = 14;
517561 : TagRecord(Kind, MemberCount, Options, FieldList, Name, UniqueName),
518562 Hfa(Hfa), WinRTKind(WinRTKind), DerivationList(DerivationList),
519563 VTableShape(VTableShape), Size(Size) {}
564
565 /// Rewrite member type indices with IndexMap. Returns false if a type index
566 /// is not in the map.
567 bool remapTypeIndices(ArrayRef IndexMap);
520568
521569 static ErrorOr deserialize(TypeRecordKind Kind,
522570 ArrayRef &Data) {
628676 UniqueName),
629677 UnderlyingType(UnderlyingType) {}
630678
679 /// Rewrite member type indices with IndexMap. Returns false if a type index is not in the map.
680 bool remapTypeIndices(ArrayRef IndexMap);
681
631682 static ErrorOr deserialize(TypeRecordKind Kind,
632683 ArrayRef &Data) {
633684 const Layout *L = nullptr;
678729 explicit VFTableShapeRecord(std::vector Slots)
679730 : TypeRecord(TypeRecordKind::VFTableShape), Slots(Slots) {}
680731
732 /// Rewrite member type indices with IndexMap. Returns false if a type index
733 /// is not in the map.
734 bool remapTypeIndices(ArrayRef IndexMap);
735
681736 static ErrorOr deserialize(TypeRecordKind Kind,
682 ArrayRef &Data) {
737 ArrayRef &Data) {
683738 const Layout *L = nullptr;
684739 if (auto EC = consumeObject(Data, L))
685740 return EC;
732787 : TypeRecord(TypeRecordKind::TypeServer2), Guid(Guid), Age(Age),
733788 Name(Name) {}
734789
790 /// Rewrite member type indices with IndexMap. Returns false if a type index
791 /// is not in the map.
792 bool remapTypeIndices(ArrayRef IndexMap);
793
735794 static ErrorOr deserialize(TypeRecordKind Kind,
736795 ArrayRef &Data) {
737796 const Layout *L = nullptr;
765824 StringIdRecord(TypeIndex Id, StringRef String)
766825 : TypeRecord(TypeRecordKind::StringId), Id(Id), String(String) {}
767826
827 /// Rewrite member type indices with IndexMap. Returns false if a type index
828 /// is not in the map.
829 bool remapTypeIndices(ArrayRef IndexMap);
830
768831 static ErrorOr deserialize(TypeRecordKind Kind,
769832 ArrayRef &Data) {
770833 const Layout *L = nullptr;
795858 : TypeRecord(TypeRecordKind::FuncId), ParentScope(ParentScope),
796859 FunctionType(FunctionType), Name(Name) {}
797860
861 /// Rewrite member type indices with IndexMap. Returns false if a type index
862 /// is not in the map.
863 bool remapTypeIndices(ArrayRef IndexMap);
864
798865 static ErrorOr deserialize(TypeRecordKind Kind,
799866 ArrayRef &Data) {
800867 const Layout *L = nullptr;
829896 : TypeRecord(TypeRecordKind::UdtSourceLine), UDT(UDT),
830897 SourceFile(SourceFile), LineNumber(LineNumber) {}
831898
899 /// Rewrite member type indices with IndexMap. Returns false if a type index
900 /// is not in the map.
901 bool remapTypeIndices(ArrayRef IndexMap);
902
832903 static ErrorOr deserialize(TypeRecordKind Kind,
833904 ArrayRef &Data) {
834905 const Layout *L = nullptr;
857928 class BuildInfoRecord : public TypeRecord {
858929 public:
859930 BuildInfoRecord(ArrayRef ArgIndices)
860 : TypeRecord(TypeRecordKind::Modifier), ArgIndices(ArgIndices) {}
931 : TypeRecord(TypeRecordKind::BuildInfo),
932 ArgIndices(ArgIndices.begin(), ArgIndices.end()) {}
933
934 /// Rewrite member type indices with IndexMap. Returns false if a type index
935 /// is not in the map.
936 bool remapTypeIndices(ArrayRef IndexMap);
861937
862938 static ErrorOr deserialize(TypeRecordKind Kind,
863939 ArrayRef &Data) {
875951 ulittle16_t NumArgs; // Number of arguments
876952 // ArgTypes[]: Type indicies of arguments
877953 };
878 ArrayRef> ArgIndices;
954 SmallVector> ArgIndices;
879955 };
880956
881957 // LF_VFTABLE
894970 CompleteClass(CompleteClass), OverriddenVFTable(OverriddenVFTable),
895971 VFPtrOffset(VFPtrOffset), Name(Name), MethodNames(Methods) {}
896972
973 /// Rewrite member type indices with IndexMap. Returns false if a type index
974 /// is not in the map.
975 bool remapTypeIndices(ArrayRef IndexMap);
976
897977 static ErrorOr deserialize(TypeRecordKind Kind,
898978 ArrayRef &Data) {
899979 const Layout *L = nullptr;
9421022 Options(Options), Access(Access), VFTableOffset(VFTableOffset),
9431023 Name(Name) {}
9441024
1025 /// Rewrite member type indices with IndexMap. Returns false if a type index
1026 /// is not in the map.
1027 bool remapTypeIndices(ArrayRef IndexMap);
1028
9451029 static ErrorOr deserialize(TypeRecordKind Kind,
9461030 ArrayRef &Data) {
9471031 const Layout *L = nullptr;
9481032 StringRef Name;
949 int32_t VFTableOffset = 0;
1033 int32_t VFTableOffset = -1;
9501034
9511035 CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(
9521036 VFTableOffset, L->Attrs.isIntroducedVirtual()),
9931077 // LF_METHODLIST
9941078 class MethodOverloadListRecord : public TypeRecord {
9951079 public:
996 MethodOverloadListRecord(ArrayRef Methods)
997 : TypeRecord(TypeRecordKind::MethodOverloadList), MethodsRef(Methods) {}
9981080 MethodOverloadListRecord(std::vector &Methods)
9991081 : TypeRecord(TypeRecordKind::MethodOverloadList), Methods(Methods) {}
1082
1083 /// Rewrite member type indices with IndexMap. Returns false if a type index
1084 /// is not in the map.
1085 bool remapTypeIndices(ArrayRef IndexMap);
10001086
10011087 static ErrorOr deserialize(TypeRecordKind Kind,
10021088 ArrayRef &Data) {
10031089 std::vector Methods;
10041090 while (!Data.empty()) {
10051091 const Layout *L = nullptr;
1006 int32_t VFTableOffset = 0;
1092 int32_t VFTableOffset = -1;
10071093 CV_DESERIALIZE(
10081094 Data, L,
10091095 CV_CONDITIONAL_FIELD(VFTableOffset, L->Attrs.isIntroducedVirtual()));
10181104 return MethodOverloadListRecord(Methods);
10191105 }
10201106
1021 ArrayRef getMethods() const {
1022 if (!MethodsRef.empty())
1023 return MethodsRef;
1024 return Methods;
1025 }
1107 ArrayRef getMethods() const { return Methods; }
10261108
10271109 private:
10281110 struct Layout {
10341116 // VFTableOffset: int32_t offset in vftable
10351117 };
10361118
1037 ArrayRef MethodsRef;
10381119 std::vector Methods;
10391120 };
10401121
10461127 : TypeRecord(TypeRecordKind::OverloadedMethod),
10471128 NumOverloads(NumOverloads), MethodList(MethodList), Name(Name) {}
10481129
1130 /// Rewrite member type indices with IndexMap. Returns false if a type index
1131 /// is not in the map.
1132 bool remapTypeIndices(ArrayRef IndexMap);
1133
10491134 static ErrorOr deserialize(TypeRecordKind Kind,
10501135 ArrayRef &Data) {
10511136 const Layout *L = nullptr;
10791164 : TypeRecord(TypeRecordKind::DataMember), Access(Access), Type(Type),
10801165 FieldOffset(Offset), Name(Name) {}
10811166
1167 /// Rewrite member type indices with IndexMap. Returns false if a type index
1168 /// is not in the map.
1169 bool remapTypeIndices(ArrayRef IndexMap);
1170
10821171 static ErrorOr deserialize(TypeRecordKind Kind,
10831172 ArrayRef &Data) {
10841173 const Layout *L = nullptr;
11151204 : TypeRecord(TypeRecordKind::StaticDataMember), Access(Access),
11161205 Type(Type), Name(Name) {}
11171206
1207 /// Rewrite member type indices with IndexMap. Returns false if a type index
1208 /// is not in the map.
1209 bool remapTypeIndices(ArrayRef IndexMap);
1210
11181211 static ErrorOr deserialize(TypeRecordKind Kind,
11191212 ArrayRef &Data) {
11201213 const Layout *L = nullptr;
11471240 : TypeRecord(TypeRecordKind::Enumerator), Access(Access), Value(Value),
11481241 Name(Name) {}
11491242
1243 /// Rewrite member type indices with IndexMap. Returns false if a type index
1244 /// is not in the map.
1245 bool remapTypeIndices(ArrayRef IndexMap);
1246
11501247 static ErrorOr deserialize(TypeRecordKind Kind,
11511248 ArrayRef &Data) {
11521249 const Layout *L = nullptr;
11781275 public:
11791276 VFPtrRecord(TypeIndex Type)
11801277 : TypeRecord(TypeRecordKind::VFPtr), Type(Type) {}
1278
1279 /// Rewrite member type indices with IndexMap. Returns false if a type index
1280 /// is not in the map.
1281 bool remapTypeIndices(ArrayRef IndexMap);
1282
11811283 static ErrorOr
11821284 deserialize(TypeRecordKind Kind, ArrayRef &Data) {
11831285 const Layout *L = nullptr;
12031305 BaseClassRecord(MemberAccess Access, TypeIndex Type, uint64_t Offset)
12041306 : TypeRecord(TypeRecordKind::BaseClass), Access(Access), Type(Type),
12051307 Offset(Offset) {}
1308
1309 /// Rewrite member type indices with IndexMap. Returns false if a type index
1310 /// is not in the map.
1311 bool remapTypeIndices(ArrayRef IndexMap);
12061312
12071313 static ErrorOr deserialize(TypeRecordKind Kind,
12081314 ArrayRef &Data) {
12371343 BaseType(BaseType), VBPtrType(VBPtrType), VBPtrOffset(Offset),
12381344 VTableIndex(Index) {}
12391345
1346 /// Rewrite member type indices with IndexMap. Returns false if a type index
1347 /// is not in the map.
1348 bool remapTypeIndices(ArrayRef IndexMap);
1349
12401350 static ErrorOr deserialize(TypeRecordKind Kind,
12411351 ArrayRef &Data) {
12421352 const Layout *L = nullptr;
4040 void writeEncodedUnsignedInteger(uint64_t Value);
4141 void writeNullTerminatedString(const char *Value);
4242 void writeNullTerminatedString(StringRef Value);
43 void writeGuid(StringRef Guid);
4344
4445 llvm::StringRef str();
4546
4647 uint64_t size() const { return Stream.tell(); }
48
49 void reset() { Buffer.clear(); }
4750
4851 private:
4952 llvm::SmallVector Buffer;
0 //===- TypeStreamMerger.h ---------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
10 #define LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
11
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
15
16 namespace llvm {
17 namespace codeview {
18
19 /// Merges one type stream into another. Returns true on success.
20 bool mergeTypeStreams(TypeTableBuilder &DestStream,
21 ArrayRef SrcStream);
22
23 } // end namespace codeview
24 } // end namespace llvm
25
26 #endif // LLVM_DEBUGINFO_CODEVIEW_TYPESTREAMMERGER_H
4040 TypeIndex writeProcedure(const ProcedureRecord &Record);
4141 TypeIndex writeMemberFunction(const MemberFunctionRecord &Record);
4242 TypeIndex writeArgList(const ArgListRecord &Record);
43 TypeIndex writeRecord(TypeRecordBuilder &builder);
4443 TypeIndex writePointer(const PointerRecord &Record);
4544 TypeIndex writeArray(const ArrayRecord &Record);
4645 TypeIndex writeClass(const ClassRecord &Record);
46 TypeIndex writeUnion(const UnionRecord &Record);
4747 TypeIndex writeEnum(const EnumRecord &Record);
4848 TypeIndex writeBitField(const BitFieldRecord &Record);
4949 TypeIndex writeVFTableShape(const VFTableShapeRecord &Record);
50 TypeIndex writeStringId(const StringIdRecord &Record);
51 TypeIndex writeVFTable(const VFTableRecord &Record);
52 TypeIndex writeUdtSourceLine(const UdtSourceLineRecord &Record);
53 TypeIndex writeFuncId(const FuncIdRecord &Record);
54 TypeIndex writeMemberFuncId(const MemberFuncIdRecord &Record);
55 TypeIndex writeBuildInfo(const BuildInfoRecord &Record);
56 TypeIndex writeMethodOverloadList(const MethodOverloadListRecord &Record);
57 TypeIndex writeTypeServer2(const TypeServer2Record &Record);
5058
5159 TypeIndex writeFieldList(FieldListRecordBuilder &FieldList);
52 TypeIndex writeMethodList(MethodListRecordBuilder &MethodList);
5360
54 private:
61 TypeIndex writeRecord(TypeRecordBuilder &builder);
62
5563 virtual TypeIndex writeRecord(llvm::StringRef record) = 0;
5664 };
5765 }
55 MethodListRecordBuilder.cpp
66 RecordSerialization.cpp
77 TypeDumper.cpp
8 TypeRecord.cpp
89 TypeRecordBuilder.cpp
10 TypeStreamMerger.cpp
911 TypeTableBuilder.cpp
1012
1113 ADDITIONAL_HEADER_DIRS
1414 FieldListRecordBuilder::FieldListRecordBuilder()
1515 : ListRecordBuilder(TypeRecordKind::FieldList) {}
1616
17 void FieldListRecordBuilder::writeBaseClass(MemberAccess Access, TypeIndex Type,
18 uint64_t Offset) {
17 void FieldListRecordBuilder::writeBaseClass(const BaseClassRecord &Record) {
1918 TypeRecordBuilder &Builder = getBuilder();
2019
2120 Builder.writeTypeRecordKind(TypeRecordKind::BaseClass);
22 Builder.writeUInt16(static_cast(Access));
23 Builder.writeTypeIndex(Type);
24 Builder.writeEncodedUnsignedInteger(Offset);
21 Builder.writeUInt16(static_cast(Record.getAccess()));
22 Builder.writeTypeIndex(Record.getBaseType());
23 Builder.writeEncodedUnsignedInteger(Record.getBaseOffset());
2524
2625 finishSubRecord();
2726 }
2827
29 void FieldListRecordBuilder::writeEnumerate(MemberAccess Access, uint64_t Value,
30 StringRef Name) {
28 void FieldListRecordBuilder::writeEnumerator(const EnumeratorRecord &Record) {
3129 TypeRecordBuilder &Builder = getBuilder();
3230
3331 Builder.writeTypeRecordKind(TypeRecordKind::Enumerator);
34 Builder.writeUInt16(static_cast(Access));
35 Builder.writeEncodedUnsignedInteger(Value);
36 Builder.writeNullTerminatedString(Name);
32 Builder.writeUInt16(static_cast(Record.getAccess()));
33 // FIXME: Handle full APInt such as __int128.
34 Builder.writeEncodedUnsignedInteger(Record.getValue().getZExtValue());
35 Builder.writeNullTerminatedString(Record.getName());
3736
3837 finishSubRecord();
3938 }
4039
41 void FieldListRecordBuilder::writeMember(MemberAccess Access, TypeIndex Type,
42 uint64_t Offset, StringRef Name) {
40 void FieldListRecordBuilder::writeDataMember(const DataMemberRecord &Record) {
4341 TypeRecordBuilder &Builder = getBuilder();
4442
45 Builder.writeTypeRecordKind(TypeRecordKind::DataMember);
46 Builder.writeUInt16(static_cast(Access));
47 Builder.writeTypeIndex(Type);
48 Builder.writeEncodedUnsignedInteger(Offset);
49 Builder.writeNullTerminatedString(Name);
43 Builder.writeTypeRecordKind(Record.getKind());
44 Builder.writeUInt16(static_cast(Record.getAccess()));
45 Builder.writeTypeIndex(Record.getType());
46 Builder.writeEncodedUnsignedInteger(Record.getFieldOffset());
47 Builder.writeNullTerminatedString(Record.getName());
5048
5149 finishSubRecord();
5250 }
5351
54 void FieldListRecordBuilder::writeMethod(uint16_t OverloadCount,
55 TypeIndex MethodList, StringRef Name) {
52 void FieldListRecordBuilder::writeOverloadedMethod(
53 const OverloadedMethodRecord &Record) {
5654 TypeRecordBuilder &Builder = getBuilder();
5755
5856 Builder.writeTypeRecordKind(TypeRecordKind::OverloadedMethod);
59 Builder.writeUInt16(OverloadCount);
60 Builder.writeTypeIndex(MethodList);
61 Builder.writeNullTerminatedString(Name);
57 Builder.writeUInt16(Record.getNumOverloads());
58 Builder.writeTypeIndex(Record.getMethodList());
59 Builder.writeNullTerminatedString(Record.getName());
6260
6361 finishSubRecord();
6462 }
6563
66 void FieldListRecordBuilder::writeOneMethod(
67 MemberAccess Access, MethodKind Kind, MethodOptions Options, TypeIndex Type,
68 int32_t VTableSlotOffset, StringRef Name) {
64 void FieldListRecordBuilder::writeOneMethod(const OneMethodRecord &Record) {
6965 TypeRecordBuilder &Builder = getBuilder();
7066
71 uint16_t Flags = static_cast(Access);
72 Flags |= static_cast(Kind) << MethodKindShift;
73 Flags |= static_cast(Options);
67 uint16_t Flags = static_cast(Record.getAccess());
68 Flags |= static_cast(Record.getKind()) << MethodKindShift;
69 Flags |= static_cast(Record.getOptions());
7470
7571 Builder.writeTypeRecordKind(TypeRecordKind::OneMethod);
7672 Builder.writeUInt16(Flags);
77 Builder.writeTypeIndex(Type);
78 switch (Kind) {
79 case MethodKind::IntroducingVirtual:
80 case MethodKind::PureIntroducingVirtual:
81 assert(VTableSlotOffset >= 0);
82 Builder.writeInt32(VTableSlotOffset);
83 break;
84
85 default:
86 assert(VTableSlotOffset == -1);
87 break;
73 Builder.writeTypeIndex(Record.getType());
74 if (Record.isIntroducingVirtual()) {
75 assert(Record.getVFTableOffset() >= 0);
76 Builder.writeInt32(Record.getVFTableOffset());
77 } else {
78 assert(Record.getVFTableOffset() == -1);
8879 }
8980
90 Builder.writeNullTerminatedString(Name);
81 Builder.writeNullTerminatedString(Record.getName());
9182
9283 finishSubRecord();
9384 }
9485
95 void FieldListRecordBuilder::writeOneMethod(const MethodInfo &Method,
96 StringRef Name) {
97 writeOneMethod(Method.getAccess(), Method.getKind(), Method.getOptions(),
98 Method.getType(), Method.getVTableSlotOffset(), Name);
99 }
100
101 void FieldListRecordBuilder::writeNestedType(TypeIndex Type, StringRef Name) {
86 void FieldListRecordBuilder::writeNestedType(const NestedTypeRecord &Record) {
10287 TypeRecordBuilder &Builder = getBuilder();
10388
104 Builder.writeTypeRecordKind(TypeRecordKind::NestedType);
89 Builder.writeTypeRecordKind(Record.getKind());
10590 Builder.writeUInt16(0);
106 Builder.writeTypeIndex(Type);
107 Builder.writeNullTerminatedString(Name);
91 Builder.writeTypeIndex(Record.getNestedType());
92 Builder.writeNullTerminatedString(Record.getName());
10893
10994 finishSubRecord();
11095 }
11196
112 void FieldListRecordBuilder::writeStaticMember(MemberAccess Access,
113 TypeIndex Type, StringRef Name) {
97 void FieldListRecordBuilder::writeStaticDataMember(
98 const StaticDataMemberRecord &Record) {
11499 TypeRecordBuilder &Builder = getBuilder();
115100
116 Builder.writeTypeRecordKind(TypeRecordKind::StaticDataMember);
117 Builder.writeUInt16(static_cast(Access));
118 Builder.writeTypeIndex(Type);
119 Builder.writeNullTerminatedString(Name);
101 Builder.writeTypeRecordKind(Record.getKind());
102 Builder.writeUInt16(static_cast(Record.getAccess()));
103 Builder.writeTypeIndex(Record.getType());
104 Builder.writeNullTerminatedString(Record.getName());
120105
121106 finishSubRecord();
122107 }
123108
124 void FieldListRecordBuilder::writeIndirectVirtualBaseClass(
125 MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
126 int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
127 writeVirtualBaseClass(TypeRecordKind::IndirectVirtualBaseClass, Access, Type,
128 VirtualBasePointerType, VirtualBasePointerOffset,
129 SlotIndex);
130 }
131
132109 void FieldListRecordBuilder::writeVirtualBaseClass(
133 MemberAccess Access, TypeIndex Type, TypeIndex VirtualBasePointerType,
134 int64_t VirtualBasePointerOffset, uint64_t SlotIndex) {
135 writeVirtualBaseClass(TypeRecordKind::VirtualBaseClass, Access, Type,
136 VirtualBasePointerType, VirtualBasePointerOffset,
137 SlotIndex);
138 }
139
140 void FieldListRecordBuilder::writeVirtualBaseClass(
141 TypeRecordKind Kind, MemberAccess Access, TypeIndex Type,
142 TypeIndex VirtualBasePointerType, int64_t VirtualBasePointerOffset,
143 uint64_t SlotIndex) {
110 const VirtualBaseClassRecord &Record) {
144111 TypeRecordBuilder &Builder = getBuilder();
145112
146 Builder.writeTypeRecordKind(Kind);
147 Builder.writeUInt16(static_cast(Access));
148 Builder.writeTypeIndex(Type);
149 Builder.writeTypeIndex(VirtualBasePointerType);
150 Builder.writeEncodedInteger(VirtualBasePointerOffset);
151 Builder.writeEncodedUnsignedInteger(SlotIndex);
113 Builder.writeTypeRecordKind(Record.getKind());
114 Builder.writeUInt16(static_cast(Record.getAccess()));
115 Builder.writeTypeIndex(Record.getBaseType());
116 Builder.writeTypeIndex(Record.getVBPtrType());
117 Builder.writeEncodedInteger(Record.getVBPtrOffset());
118 Builder.writeEncodedUnsignedInteger(Record.getVTableIndex());
152119
153120 finishSubRecord();
154121 }
155122
156 void FieldListRecordBuilder::writeVirtualFunctionTablePointer(TypeIndex Type) {
123 void FieldListRecordBuilder::writeVFPtr(const VFPtrRecord &Record) {
157124 TypeRecordBuilder &Builder = getBuilder();
158125
159126 Builder.writeTypeRecordKind(TypeRecordKind::VFPtr);
160127 Builder.writeUInt16(0);
161 Builder.writeTypeIndex(Type);
128 Builder.writeTypeIndex(Record.getType());
162129
163130 finishSubRecord();
164131 }
279279 // Put this in CVUDTNames so it gets printed with LF_UDT_SRC_LINE.
280280 Name = String.getString();
281281 }
282
282283 void CVTypeDumperImpl::visitArgList(TypeLeafKind Leaf, ArgListRecord &Args) {
283284 auto Indices = Args.getIndices();
284285 uint32_t Size = Indices.size();
0 //===-- TypeRecord.cpp ------------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
10 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
11
12 using namespace llvm;
13 using namespace llvm::codeview;
14
15 static bool remapIndex(ArrayRef IndexMap, TypeIndex &Idx) {
16 // Simple types are unchanged.
17 if (Idx.isSimple())
18 return true;
19 unsigned MapPos = Idx.getIndex() - TypeIndex::FirstNonSimpleIndex;
20 if (MapPos < IndexMap.size()) {
21 Idx = IndexMap[MapPos];
22 return true;
23 }
24
25 // This type index is invalid. Remap this to "not translated by cvpack",
26 // and return failure.
27 Idx = TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct);
28 return false;
29 }
30
31 bool ModifierRecord::remapTypeIndices(ArrayRef IndexMap) {
32 return remapIndex(IndexMap, ModifiedType);
33 }
34
35 bool ProcedureRecord::remapTypeIndices(ArrayRef IndexMap) {
36 bool Success = true;
37 Success &= remapIndex(IndexMap, ReturnType);
38 Success &= remapIndex(IndexMap, ArgumentList);
39 return Success;
40 }
41
42 bool MemberFunctionRecord::remapTypeIndices(ArrayRef IndexMap) {
43 bool Success = true;
44 Success &= remapIndex(IndexMap, ReturnType);
45 Success &= remapIndex(IndexMap, ClassType);
46 Success &= remapIndex(IndexMap, ThisType);
47 Success &= remapIndex(IndexMap, ArgumentList);
48 return Success;
49 }
50
51 bool MemberFuncIdRecord::remapTypeIndices(ArrayRef IndexMap) {
52 bool Success = true;
53 Success &= remapIndex(IndexMap, ClassType);
54 Success &= remapIndex(IndexMap, FunctionType);
55 return Success;
56 }
57
58 bool ArgListRecord::remapTypeIndices(ArrayRef IndexMap) {
59 bool Success = true;
60 for (TypeIndex &Str : StringIndices)
61 Success &= remapIndex(IndexMap, Str);
62 return Success;
63 }
64
65 bool MemberPointerInfo::remapTypeIndices(ArrayRef IndexMap) {
66 return remapIndex(IndexMap, ContainingType);
67 }
68
69 bool PointerRecord::remapTypeIndices(ArrayRef IndexMap) {
70 bool Success = true;
71 Success &= remapIndex(IndexMap, ReferentType);
72 if (isPointerToMember())
73 Success &= MemberInfo.remapTypeIndices(IndexMap);
74 return Success;
75 }
76
77 bool NestedTypeRecord::remapTypeIndices(ArrayRef IndexMap) {
78 return remapIndex(IndexMap, Type);
79 }
80
81 bool ArrayRecord::remapTypeIndices(ArrayRef IndexMap) {
82 bool Success = true;
83 Success &= remapIndex(IndexMap, ElementType);
84 Success &= remapIndex(IndexMap, IndexType);
85 return Success;
86 }
87
88 bool TagRecord::remapTypeIndices(ArrayRef IndexMap) {
89 return remapIndex(IndexMap, FieldList);
90 }
91
92 bool ClassRecord::remapTypeIndices(ArrayRef IndexMap) {
93 bool Success = true;
94 Success &= TagRecord::remapTypeIndices(IndexMap);
95 Success &= remapIndex(IndexMap, DerivationList);
96 Success &= remapIndex(IndexMap, VTableShape);
97 return Success;
98 }
99
100 bool EnumRecord::remapTypeIndices(ArrayRef IndexMap) {
101 bool Success = true;
102 Success &= TagRecord::remapTypeIndices(IndexMap);
103 Success &= remapIndex(IndexMap, UnderlyingType);
104 return Success;
105 }
106
107 bool VFTableShapeRecord::remapTypeIndices(ArrayRef IndexMap) {
108 return true;
109 }
110
111 bool TypeServer2Record::remapTypeIndices(ArrayRef IndexMap) {
112 return true;
113 }
114
115 bool StringIdRecord::remapTypeIndices(ArrayRef IndexMap) {
116 return remapIndex(IndexMap, Id);
117 }
118
119 bool FuncIdRecord::remapTypeIndices(ArrayRef IndexMap) {
120 bool Success = true;
121 Success &= remapIndex(IndexMap, ParentScope);
122 Success &= remapIndex(IndexMap, FunctionType);
123 return Success;
124 }
125
126 bool UdtSourceLineRecord::remapTypeIndices(ArrayRef IndexMap) {
127 bool Success = true;
128 Success &= remapIndex(IndexMap, UDT);
129 Success &= remapIndex(IndexMap, SourceFile);
130 return Success;
131 }
132
133 bool BuildInfoRecord::remapTypeIndices(ArrayRef IndexMap) {
134 bool Success = true;
135 for (TypeIndex &Arg : ArgIndices)
136 Success &= remapIndex(IndexMap, Arg);
137 return Success;
138 }
139
140 bool VFTableRecord::remapTypeIndices(ArrayRef IndexMap) {
141 bool Success = true;
142 Success &= remapIndex(IndexMap, CompleteClass);
143 Success &= remapIndex(IndexMap, OverriddenVFTable);
144 return Success;
145 }
146
147 bool OneMethodRecord::remapTypeIndices(ArrayRef IndexMap) {
148 bool Success = true;
149 Success &= remapIndex(IndexMap, Type);
150 return Success;
151 }
152
153 bool MethodOverloadListRecord::remapTypeIndices(ArrayRef IndexMap) {
154 bool Success = true;
155 for (OneMethodRecord &Meth : Methods)
156 if ((Success = Meth.remapTypeIndices(IndexMap)))
157 return Success;
158 return Success;
159 }
160
161 bool OverloadedMethodRecord::remapTypeIndices(ArrayRef IndexMap) {
162 return remapIndex(IndexMap, MethodList);
163 }
164
165 bool DataMemberRecord::remapTypeIndices(ArrayRef IndexMap) {
166 return remapIndex(IndexMap, Type);
167 }
168
169 bool StaticDataMemberRecord::remapTypeIndices(ArrayRef IndexMap) {
170 return remapIndex(IndexMap, Type);
171 }
172
173 bool EnumeratorRecord::remapTypeIndices(ArrayRef IndexMap) {
174 return true;
175 }
176
177 bool VFPtrRecord::remapTypeIndices(ArrayRef IndexMap) {
178 return remapIndex(IndexMap, Type);
179 }
180
181 bool BaseClassRecord::remapTypeIndices(ArrayRef IndexMap) {
182 return remapIndex(IndexMap, Type);
183 }
184
185 bool VirtualBaseClassRecord::remapTypeIndices(ArrayRef IndexMap) {
186 bool Success = true;
187 Success &= remapIndex(IndexMap, BaseType);
188 Success &= remapIndex(IndexMap, VBPtrType);
189 return Success;
190 }
1111 using namespace llvm;
1212 using namespace codeview;
1313
14 TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind) : Stream(Buffer),
15 Writer(Stream) {
14 TypeRecordBuilder::TypeRecordBuilder(TypeRecordKind Kind)
15 : Stream(Buffer), Writer(Stream) {
1616 writeTypeRecordKind(Kind);
1717 }
1818
103103 writeUInt8(0);
104104 }
105105
106 void TypeRecordBuilder::writeGuid(StringRef Guid) {
107 assert(Guid.size() == 16);
108 Stream.write(Guid.data(), 16);
109 }
110
106111 void TypeRecordBuilder::writeTypeIndex(TypeIndex TypeInd) {
107112 writeUInt32(TypeInd.getIndex());
108113 }
0 //===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
10 #include "llvm/ADT/SmallString.h"
11 #include "llvm/ADT/StringExtras.h"
12 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
13 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h"
14 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
15 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
16 #include "llvm/DebugInfo/CodeView/TypeStream.h"
17 #include "llvm/Support/ScopedPrinter.h"
18
19 using namespace llvm;
20 using namespace llvm::codeview;
21
22 namespace {
23
24 /// Implementation of CodeView type stream merging.
25 ///
26 /// A CodeView type stream is a series of records that reference each other
27 /// through type indices. A type index is either "simple", meaning it is less
28 /// than 0x1000 and refers to a builtin type, or it is complex, meaning it
29 /// refers to a prior type record in the current stream. The type index of a
30 /// record is equal to the number of records before it in the stream plus
31 /// 0x1000.
32 ///
33 /// Type records are only allowed to use type indices smaller than their own, so
34 /// a type stream is effectively a topologically sorted DAG. Cycles occuring in
35 /// the type graph of the source program are resolved with forward declarations
36 /// of composite types. This class implements the following type stream merging
37 /// algorithm, which relies on this DAG structure:
38 ///
39 /// - Begin with a new empty stream, and a new empty hash table that maps from
40 /// type record contents to new type index.
41 /// - For each new type stream, maintain a map from source type index to
42 /// destination type index.
43 /// - For each record, copy it and rewrite its type indices to be valid in the
44 /// destination type stream.
45 /// - If the new type record is not already present in the destination stream
46 /// hash table, append it to the destination type stream, assign it the next
47 /// type index, and update the two hash tables.
48 /// - If the type record already exists in the destination stream, discard it
49 /// and update the type index map to forward the source type index to the
50 /// existing destination type index.
51 class TypeStreamMerger : public CVTypeVisitor {
52 public:
53 TypeStreamMerger(TypeTableBuilder &DestStream) : DestStream(DestStream) {
54 assert(!hadError());
55 }
56
57 /// CVTypeVisitor overrides.
58 #define TYPE_RECORD(EnumName, EnumVal, Name) \
59 void visit##Name(TypeLeafKind LeafType, Name##Record &Record);
60 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
61 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
62 void visit##Name(TypeLeafKind LeafType, Name##Record &Record);
63 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
64 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
65
66 void visitUnknownMember(TypeLeafKind Leaf);
67
68 void visitTypeBegin(TypeLeafKind Leaf, ArrayRef RecordData);
69 void visitTypeEnd(TypeLeafKind Leaf, ArrayRef RecordData);
70
71 void visitFieldList(TypeLeafKind Leaf, ArrayRef FieldData);
72
73 bool mergeStream(ArrayRef SrcStream);
74
75 private:
76 bool hadError() { return FoundBadTypeIndex || CVTypeVisitor::hadError(); }
77
78 bool FoundBadTypeIndex = false;
79
80 FieldListRecordBuilder FieldBuilder;
81
82 TypeTableBuilder &DestStream;
83
84 size_t BeginIndexMapSize = 0;
85
86 /// Map from source type index to destination type index. Indexed by source
87 /// type index minus 0x1000.
88 SmallVector IndexMap;
89 };
90
91 } // end anonymous namespace
92
93 void TypeStreamMerger::visitTypeBegin(TypeLeafKind Leaf,
94 ArrayRef RecordData) {
95 BeginIndexMapSize = IndexMap.size();
96 }
97
98 void TypeStreamMerger::visitTypeEnd(TypeLeafKind Leaf,
99 ArrayRef RecordData) {
100 assert(IndexMap.size() == BeginIndexMapSize + 1);
101 }
102
103 void TypeStreamMerger::visitFieldList(TypeLeafKind Leaf,
104 ArrayRef FieldData) {
105 CVTypeVisitor::visitFieldList(Leaf, FieldData);
106 IndexMap.push_back(DestStream.writeFieldList(FieldBuilder));
107 FieldBuilder.reset();
108 }
109
110 #define TYPE_RECORD(EnumName, EnumVal, Name) \
111 void TypeStreamMerger::visit##Name(TypeLeafKind LeafType, \
112 Name##Record &Record) { \
113 FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
114 IndexMap.push_back(DestStream.write##Name(Record)); \
115 }
116 #define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
117 #define MEMBER_RECORD(EnumName, EnumVal, Name) \
118 void TypeStreamMerger::visit##Name(TypeLeafKind LeafType, \
119 Name##Record &Record) { \
120 FoundBadTypeIndex |= !Record.remapTypeIndices(IndexMap); \
121 FieldBuilder.write##Name(Record); \
122 }
123 #define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
124 #include "llvm/DebugInfo/CodeView/TypeRecords.def"
125
126 void TypeStreamMerger::visitUnknownMember(TypeLeafKind LF) {
127 // We failed to translate a type. Translate this index as "not translated".
128 IndexMap.push_back(
129 TypeIndex(SimpleTypeKind::NotTranslated, SimpleTypeMode::Direct));
130 parseError();
131 }
132
133 bool TypeStreamMerger::mergeStream(ArrayRef SrcStream) {
134 assert(IndexMap.empty());
135 visitTypeStream(SrcStream);
136 IndexMap.clear();
137 return !hadError();
138 }
139
140 bool llvm::codeview::mergeTypeStreams(TypeTableBuilder &DestStream,
141 ArrayRef SrcStream) {
142 return TypeStreamMerger(DestStream).mergeStream(SrcStream);
143 }
127127 return writeRecord(Builder);
128128 }
129129
130 TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) {
131 TypeRecordBuilder Builder(TypeRecordKind::Union);
132 Builder.writeUInt16(Record.getMemberCount());
133 uint16_t Flags =
134 static_cast(Record.getOptions()) |
135 (static_cast(Record.getHfa()) << ClassRecord::HfaKindShift);
136 Builder.writeUInt16(Flags);
137 Builder.writeTypeIndex(Record.getFieldList());
138 Builder.writeEncodedUnsignedInteger(Record.getSize());
139 Builder.writeNullTerminatedString(Record.getName());
140 if ((Record.getOptions() & ClassOptions::HasUniqueName) !=
141 ClassOptions::None) {
142 Builder.writeNullTerminatedString(Record.getUniqueName());
143 }
144 return writeRecord(Builder);
145 }
146
130147 TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) {
131148 TypeRecordBuilder Builder(Record.getKind());
132149
171188 return writeRecord(Builder);
172189 }
173190
191 TypeIndex
192 TypeTableBuilder::writeVFTable(const VFTableRecord &Record) {
193 TypeRecordBuilder Builder(Record.getKind());
194 Builder.writeTypeIndex(Record.getCompleteClass());
195 Builder.writeTypeIndex(Record.getOverriddenVTable());
196 Builder.writeUInt32(Record.getVFPtrOffset());
197
198 // Sum up the lengths of the null-terminated names.
199 size_t NamesLen = Record.getName().size() + 1;
200 for (StringRef MethodName : Record.getMethodNames())
201 NamesLen += MethodName.size() + 1;
202
203 Builder.writeUInt32(NamesLen);
204 Builder.writeNullTerminatedString(Record.getName());
205 for (StringRef MethodName : Record.getMethodNames())
206 Builder.writeNullTerminatedString(MethodName);
207
208 return writeRecord(Builder);
209 }
210
211 TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) {
212 TypeRecordBuilder Builder(TypeRecordKind::StringId);
213 Builder.writeTypeIndex(Record.getId());
214 Builder.writeNullTerminatedString(Record.getString());
215 return writeRecord(Builder);
216 }
217
218 TypeIndex
219 TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) {
220 TypeRecordBuilder Builder(Record.getKind());
221 Builder.writeTypeIndex(Record.getUDT());
222 Builder.writeTypeIndex(Record.getSourceFile());
223 Builder.writeUInt32(Record.getLineNumber());
224 return writeRecord(Builder);
225 }
226
227 TypeIndex
228 TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) {
229 TypeRecordBuilder Builder(Record.getKind());
230 Builder.writeTypeIndex(Record.getParentScope());
231 Builder.writeTypeIndex(Record.getFunctionType());
232 Builder.writeNullTerminatedString(Record.getName());
233 return writeRecord(Builder);
234 }
235
236 TypeIndex
237 TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) {
238 TypeRecordBuilder Builder(Record.getKind());
239 Builder.writeTypeIndex(Record.getClassType());
240 Builder.writeTypeIndex(Record.getFunctionType());
241 Builder.writeNullTerminatedString(Record.getName());
242 return writeRecord(Builder);
243 }
244
245 TypeIndex
246 TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) {
247 TypeRecordBuilder Builder(Record.getKind());
248 assert(Record.getArgs().size() <= UINT16_MAX);
249 Builder.writeUInt16(Record.getArgs().size());
250 for (TypeIndex Arg : Record.getArgs())
251 Builder.writeTypeIndex(Arg);
252 return writeRecord(Builder);
253 }
254
174255 TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) {
175256 return writeRecord(Builder.str());
176257 }
181262 return writeRecord(FieldList.str());
182263 }
183264
184 TypeIndex
185 TypeTableBuilder::writeMethodList(MethodListRecordBuilder &MethodList) {
265 TypeIndex TypeTableBuilder::writeMethodOverloadList(
266 const MethodOverloadListRecord &Record) {
267 TypeRecordBuilder Builder(Record.getKind());
268 for (const OneMethodRecord &Method : Record.getMethods()) {
269 uint16_t Flags = static_cast(Method.getAccess());
270 Flags |= static_cast(Method.getKind())
271 << MemberAttributes::MethodKindShift;
272 Flags |= static_cast(Method.getOptions());
273 Builder.writeUInt16(Flags);
274 Builder.writeUInt16(0); // padding
275 Builder.writeTypeIndex(Method.getType());
276 if (Method.isIntroducingVirtual()) {
277 assert(Method.getVFTableOffset() >= 0);
278 Builder.writeInt32(Method.getVFTableOffset());
279 } else {
280 assert(Method.getVFTableOffset() == -1);
281 }
282 }
283
186284 // TODO: Split the list into multiple records if it's longer than 64KB, using
187285 // a subrecord of TypeRecordKind::Index to chain the records together.
188 return writeRecord(MethodList.str());
189 }
286 return writeRecord(Builder);
287 }
288
289 TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) {
290 TypeRecordBuilder Builder(Record.getKind());
291 Builder.writeGuid(Record.getGuid());
292 Builder.writeUInt32(Record.getAge());
293 Builder.writeNullTerminatedString(Record.getName());
294 return writeRecord(Builder);
295 }
0 # To regenerate t1.obj and t2.obj, run the following:
1 # $ cat t.cpp
2 # #ifdef CONFIG1
3 # struct A;
4 # struct B {
5 # A *a;
6 # };
7 # int f(A *a);
8 # int g(B *b) { return f(b->a); }
9 # #else
10 # struct B;
11 # struct A {
12 # B *b;
13 # };
14 # int g(B *b);
15 # int f(A *a) { return g(a->b); }
16 # #endif
17 # $ cl -c -DCONFIG1 -Z7 t.cpp -Fot1.obj && cl -c -Z7 t.cpp -Fot2.obj
18
19 RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-1.obj | FileCheck %s --check-prefix=OBJ1
20 RUN: llvm-readobj -codeview %S/Inputs/codeview-merging-2.obj | FileCheck %s --check-prefix=OBJ2
21 RUN: llvm-readobj -codeview-merged-types %S/Inputs/codeview-merging-1.obj %S/Inputs/codeview-merging-2.obj | FileCheck %s
22
23 OBJ1: FuncId (0x100D) {
24 OBJ1-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
25 OBJ1-NEXT: ParentScope: 0x0
26 OBJ1-NEXT: FunctionType: int (B*) (0x100C)
27 OBJ1-NEXT: Name: g
28 OBJ1-NEXT: }
29 OBJ1-NEXT: FuncId (0x100E) {
30 OBJ1-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
31 OBJ1-NEXT: ParentScope: 0x0
32 OBJ1-NEXT: FunctionType: int (A*) (0x1003)
33 OBJ1-NEXT: Name: f
34 OBJ1-NEXT: }
35 OBJ1-NOT: FuncId
36
37 OBJ2: FuncId (0x100D) {
38 OBJ2-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
39 OBJ2-NEXT: ParentScope: 0x0
40 OBJ2-NEXT: FunctionType: int (A*) (0x100C)
41 OBJ2-NEXT: Name: f
42 OBJ2-NEXT: }
43
44 OBJ2: FuncId (0x1069) {
45 OBJ2-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
46 OBJ2-NEXT: ParentScope: 0x0
47 OBJ2-NEXT: FunctionType: int (B*) (0x1003)
48 OBJ2-NEXT: Name: g
49 OBJ2-NEXT: }
50 OBJ2-NOT: FuncId
51
52 CHECK: FuncId (0x100D) {
53 CHECK-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
54 CHECK-NEXT: ParentScope: 0x0
55 CHECK-NEXT: FunctionType: int (B*) (0x100C)
56 CHECK-NEXT: Name: g
57 CHECK-NEXT: }
58 CHECK-NEXT: FuncId (0x100E) {
59 CHECK-NEXT: TypeLeafKind: LF_FUNC_ID (0x1601)
60 CHECK-NEXT: ParentScope: 0x0
61 CHECK-NEXT: FunctionType: int (A*) (0x1003)
62 CHECK-NEXT: Name: f
63 CHECK-NEXT: }
64 CHECK-NOT: FuncId
11 DebugInfoCodeView
22 Object
33 Support
4 DebugInfoCodeView
45 )
56
67 add_llvm_tool(llvm-readobj
2424 #include "llvm/DebugInfo/CodeView/CodeView.h"
2525 #include "llvm/DebugInfo/CodeView/Line.h"
2626 #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
27 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
2728 #include "llvm/DebugInfo/CodeView/SymbolRecord.h"
2829 #include "llvm/DebugInfo/CodeView/TypeDumper.h"
2930 #include "llvm/DebugInfo/CodeView/TypeIndex.h"
3031 #include "llvm/DebugInfo/CodeView/TypeRecord.h"
3132 #include "llvm/DebugInfo/CodeView/TypeStream.h"
33 #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
3234 #include "llvm/Object/COFF.h"
3335 #include "llvm/Object/ObjectFile.h"
3436 #include "llvm/Support/COFF.h"
7072 void printCOFFDirectives() override;
7173 void printCOFFBaseReloc() override;
7274 void printCodeViewDebugInfo() override;
75 void
76 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) override;
7377 void printStackMap() const override;
7478 private:
7579 void printSymbol(const SymbolRef &Sym);
16201624 W.printHex(Label, getFileNameForFileOffset(FileOffset), FileOffset);
16211625 }
16221626
1627 void COFFDumper::mergeCodeViewTypes(MemoryTypeTableBuilder &CVTypes) {
1628 for (const SectionRef &S : Obj->sections()) {
1629 StringRef SectionName;
1630 error(S.getName(SectionName));
1631 if (SectionName == ".debug$T") {
1632 StringRef Data;
1633 error(S.getContents(Data));
1634 unsigned Magic = *reinterpret_cast(Data.data());
1635 if (Magic != 4)
1636 error(object_error::parse_failed);
1637 Data = Data.drop_front(4);
1638 ArrayRef Bytes(reinterpret_cast(Data.data()),
1639 Data.size());
1640 if (!mergeTypeStreams(CVTypes, Bytes))
1641 return error(object_error::parse_failed);
1642 }
1643 }
1644 }
1645
16231646 void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
16241647 const SectionRef &Section) {
16251648 ListScope D(W, "CodeViewTypes");
20752098 prettyPrintStackMap(llvm::outs(),
20762099 StackMapV1Parser(StackMapContentsArray));
20772100 }
2101
2102 void llvm::dumpCodeViewMergedTypes(
2103 ScopedPrinter &Writer, llvm::codeview::MemoryTypeTableBuilder &CVTypes) {
2104 // Flatten it first, then run our dumper on it.
2105 ListScope S(Writer, "MergedTypeStream");
2106 SmallString<0> Buf;
2107 CVTypes.ForEachRecord([&](TypeIndex TI, MemoryTypeTableBuilder::Record *R) {
2108 // The record data doesn't include the 16 bit size.
2109 Buf.push_back(R->size() & 0xff);
2110 Buf.push_back((R->size() >> 8) & 0xff);
2111 Buf.append(R->data(), R->data() + R->size());
2112 });
2113 CVTypeDumper CVTD(Writer, opts::CodeViewSubsectionBytes);
2114 ArrayRef BinaryData(reinterpret_cast(Buf.data()),
2115 Buf.size());
2116 if (!CVTD.dump(BinaryData)) {
2117 Writer.flush();
2118 error(object_error::parse_failed);
2119 }
2120 }
1717 class COFFImportFile;
1818 class ObjectFile;
1919 }
20 namespace codeview {
21 class MemoryTypeTableBuilder;
22 };
2023
2124 class ScopedPrinter;
2225
5962 virtual void printCOFFDirectives() { }
6063 virtual void printCOFFBaseReloc() { }
6164 virtual void printCodeViewDebugInfo() { }
65 virtual void
66 mergeCodeViewTypes(llvm::codeview::MemoryTypeTableBuilder &CVTypes) {}
6267
6368 // Only implemented for MachO.
6469 virtual void printMachODataInCode() { }
8893
8994 void dumpCOFFImportFile(const object::COFFImportFile *File);
9095
96 void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
97 llvm::codeview::MemoryTypeTableBuilder &CVTypes);
98
9199 } // namespace llvm
92100
93101 #endif
2121 #include "llvm-readobj.h"
2222 #include "Error.h"
2323 #include "ObjDumper.h"
24 #include "llvm/DebugInfo/CodeView/MemoryTypeTableBuilder.h"
2425 #include "llvm/Object/Archive.h"
2526 #include "llvm/Object/COFFImportFile.h"
2627 #include "llvm/Object/ELFObjectFile.h"
143144 cl::opt CodeView("codeview",
144145 cl::desc("Display CodeView debug information"));
145146
147 // -codeview-merged-types
148 cl::opt
149 CodeViewMergedTypes("codeview-merged-types",
150 cl::desc("Display the merged CodeView type stream"));
151
146152 // -codeview-subsection-bytes
147153 cl::opt CodeViewSubsectionBytes(
148154 "codeview-subsection-bytes",
294300 return false;
295301 }
296302 }
303
304 static llvm::codeview::MemoryTypeTableBuilder CVTypes;
297305
298306 /// @brief Creates an format-specific object file dumper.
299307 static std::error_code createDumper(const ObjectFile *Obj,
385393 Dumper->printCOFFBaseReloc();
386394 if (opts::CodeView)
387395 Dumper->printCodeViewDebugInfo();
396 if (opts::CodeViewMergedTypes)
397 Dumper->mergeCodeViewTypes(CVTypes);
388398 }
389399 if (Obj->isMachO()) {
390400 if (opts::MachODataInCode)
477487 std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
478488 dumpInput);
479489
490 if (opts::CodeViewMergedTypes) {
491 ScopedPrinter W(outs());
492 dumpCodeViewMergedTypes(W, CVTypes);
493 }
494
480495 return 0;
481496 }