public:
FieldListRecordBuilder();
- void reset() { ListRecordBuilder::reset(TypeRecordKind::FieldList); }
+ void reset() { ListRecordBuilder::reset(); }
void writeBaseClass(const BaseClassRecord &Record);
void writeEnumerator(const EnumeratorRecord &Record);
namespace llvm {
namespace codeview {
+class TypeTableBuilder;
class ListRecordBuilder {
private:
public:
llvm::StringRef str() { return Builder.str(); }
- void reset(TypeRecordKind K) {
- Builder.reset(K);
+ void reset() {
+ Builder.reset(Kind);
ContinuationOffsets.clear();
- SubrecordCount = 0;
+ SubrecordStart = 0;
}
- unsigned getSubrecordCount() { return SubrecordCount; }
+ void writeListContinuation(const ListContinuationRecord &R);
+
+ /// Writes this list record as a possible sequence of records.
+ TypeIndex writeListRecord(TypeTableBuilder &Table);
protected:
void finishSubRecord();
TypeRecordBuilder &getBuilder() { return Builder; }
private:
+ size_t getLastContinuationStart() const {
+ return ContinuationOffsets.empty() ? 0 : ContinuationOffsets.back();
+ }
+ size_t getLastContinuationEnd() const { return Builder.size(); }
+ unsigned getLastContinuationSize() const {
+ return getLastContinuationEnd() - getLastContinuationStart();
+ }
+
+ TypeRecordKind Kind;
TypeRecordBuilder Builder;
SmallVector<size_t, 4> ContinuationOffsets;
- unsigned SubrecordCount = 0;
+ size_t SubrecordStart = 0;
};
}
}
uint64_t VTableIndex;
};
+/// LF_INDEX - Used to chain two large LF_FIELDLIST or LF_METHODLIST records
+/// together. The first will end in an LF_INDEX record that points to the next.
+class ListContinuationRecord : public TypeRecord {
+public:
+ ListContinuationRecord(TypeIndex ContinuationIndex)
+ : TypeRecord(TypeRecordKind::ListContinuation),
+ ContinuationIndex(ContinuationIndex) {}
+
+ TypeIndex getContinuationIndex() const { return ContinuationIndex; }
+
+ bool remapTypeIndices(ArrayRef<TypeIndex> IndexMap);
+
+ static ErrorOr<ListContinuationRecord> deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data);
+
+private:
+ struct Layout {
+ ulittle16_t Pad0;
+ TypeIndex ContinuationIndex;
+ };
+ TypeIndex ContinuationIndex;
+};
+
typedef CVRecord<TypeLeafKind> CVType;
typedef VarStreamArray<CVType> CVTypeArray;
}
void writeNullTerminatedString(const char *Value);
void writeNullTerminatedString(StringRef Value);
void writeGuid(StringRef Guid);
+ void writeBytes(StringRef Value) { Stream << Value; }
llvm::StringRef str();
uint64_t size() const { return Stream.tell(); }
+ void truncate(uint64_t Size) {
+ // This works because raw_svector_ostream is not buffered.
+ assert(Size < Buffer.size());
+ Buffer.resize(Size);
+ }
+
void reset(TypeRecordKind K) {
Buffer.clear();
writeTypeRecordKind(K);
MEMBER_RECORD(LF_NESTTYPE, 0x1510, NestedType)
MEMBER_RECORD(LF_ONEMETHOD, 0x1511, OneMethod)
MEMBER_RECORD(LF_ENUMERATE, 0x1502, Enumerator)
+MEMBER_RECORD(LF_INDEX, 0x1404, ListContinuation)
// ID leaf records. Subsequent leaf types may be referenced from .debug$S.
TYPE_RECORD(LF_FUNC_ID, 0x1601, FuncId)
// Member type records. These are generally not length prefixed, and appear
// inside of a field list record.
CV_TYPE(LF_FRIENDFCN_ST, 0x1403)
-CV_TYPE(LF_INDEX, 0x1404)
CV_TYPE(LF_MEMBER_ST, 0x1405)
CV_TYPE(LF_STMEMBER_ST, 0x1406)
CV_TYPE(LF_METHOD_ST, 0x1407)
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/ListRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
using namespace llvm;
using namespace codeview;
-ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind) : Builder(Kind) {}
+ListRecordBuilder::ListRecordBuilder(TypeRecordKind Kind)
+ : Kind(Kind), Builder(Kind) {}
-void ListRecordBuilder::finishSubRecord() {
- SubrecordCount++;
+void ListRecordBuilder::writeListContinuation(const ListContinuationRecord &R) {
+ TypeRecordBuilder &Builder = getBuilder();
+
+ assert(getLastContinuationSize() < 65535 - 8 && "continuation won't fit");
+
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeTypeIndex(R.getContinuationIndex());
+
+ // End the current segment manually so that nothing comes after the
+ // continuation.
+ ContinuationOffsets.push_back(Builder.size());
+ SubrecordStart = Builder.size();
+}
+void ListRecordBuilder::finishSubRecord() {
// The builder starts at offset 2 in the actual CodeView buffer, so add an
// additional offset of 2 before computing the alignment.
uint32_t Remainder = (Builder.size() + 2) % 4;
if (Remainder != 0) {
for (int32_t PaddingBytesLeft = 4 - Remainder; PaddingBytesLeft > 0;
--PaddingBytesLeft) {
- Builder.writeUInt8(0xf0 + PaddingBytesLeft);
+ Builder.writeUInt8(LF_PAD0 + PaddingBytesLeft);
}
}
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- assert(Builder.size() < 65536);
+ // Check if this subrecord makes the current segment not fit in 64K minus the
+ // space for a continuation record (8 bytes). If the segment does not fit,
+ // back up and insert a continuation record, sliding the current subrecord
+ // down.
+ if (getLastContinuationSize() > 65535 - 8) {
+ SmallString<128> SubrecordCopy(Builder.str().slice(SubrecordStart, Builder.size()));
+ Builder.truncate(SubrecordStart);
+
+ // Write a placeholder continuation record.
+ Builder.writeTypeRecordKind(TypeRecordKind::ListContinuation);
+ Builder.writeUInt16(0);
+ Builder.writeUInt32(0);
+ ContinuationOffsets.push_back(Builder.size());
+ assert(Builder.size() == SubrecordStart + 8 && "wrong continuation size");
+ assert(getLastContinuationSize() < 65535 && "segment too big");
+
+ // Start a new list record of the appropriate kind, and copy the previous
+ // subrecord into place.
+ Builder.writeTypeRecordKind(Kind);
+ Builder.writeBytes(SubrecordCopy);
+ }
+
+ SubrecordStart = Builder.size();
+}
+
+TypeIndex ListRecordBuilder::writeListRecord(TypeTableBuilder &Table) {
+ // Get the continuation segments as a reversed vector of StringRefs for
+ // convenience.
+ SmallVector<StringRef, 1> Segments;
+ StringRef Data = str();
+ size_t LastEnd = 0;
+ for (size_t SegEnd : ContinuationOffsets) {
+ Segments.push_back(Data.slice(LastEnd, SegEnd));
+ LastEnd = SegEnd;
+ }
+ Segments.push_back(Data.slice(LastEnd, Builder.size()));
+
+ // Pop the last record off and emit it directly.
+ StringRef LastRec = Segments.pop_back_val();
+ TypeIndex ContinuationIndex = Table.writeRecord(LastRec);
+
+ // Emit each record with a continuation in reverse order, so that each one
+ // references the previous record.
+ for (StringRef Rec : reverse(Segments)) {
+ assert(*reinterpret_cast<const ulittle16_t *>(Rec.data()) ==
+ unsigned(Kind));
+ ulittle32_t *ContinuationPtr =
+ reinterpret_cast<ulittle32_t *>(const_cast<char *>(Rec.end())) - 1;
+ *ContinuationPtr = ContinuationIndex.getIndex();
+ ContinuationIndex = Table.writeRecord(Rec);
+ }
+ return ContinuationIndex;
}
case ename: \
return #name;
#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ case LF_FIELDLIST:
+ return "FieldList";
default:
break;
}
}
Error CVTypeDumper::visitTypeEnd(const CVRecord<TypeLeafKind> &Record) {
+ if (Record.Type == LF_FIELDLIST)
+ Name = "<field list>";
+
// Always record some name for every type, even if Name is empty. CVUDTNames
// is indexed by type index, and must have one entry for every type.
recordType(Name);
return Error::success();
}
+Error CVTypeDumper::visitListContinuation(ListContinuationRecord &Cont) {
+ DictScope S(*W, "ListContinuation");
+ printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+ return Error::success();
+}
+
StringRef CVTypeDumper::getTypeName(TypeIndex TI) {
if (TI.isNoneType())
return "<no type>";
Offset, Index);
}
+ErrorOr<ListContinuationRecord>
+ListContinuationRecord::deserialize(TypeRecordKind Kind,
+ ArrayRef<uint8_t> &Data) {
+ const Layout *L = nullptr;
+ CV_DESERIALIZE(Data, L);
+ return ListContinuationRecord(L->ContinuationIndex);
+}
+
//===----------------------------------------------------------------------===//
// Type index remapping
//===----------------------------------------------------------------------===//
Success &= remapIndex(IndexMap, VBPtrType);
return Success;
}
+
+bool ListContinuationRecord::remapTypeIndices(ArrayRef<TypeIndex> IndexMap) {
+ return remapIndex(IndexMap, ContinuationIndex);
+}
}
TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) {
- // TODO: Split the list into multiple records if it's longer than 64KB, using
- // a subrecord of TypeRecordKind::Index to chain the records together.
- return writeRecord(FieldList.str());
+ return FieldList.writeListRecord(*this);
}
TypeIndex TypeTableBuilder::writeMethodOverloadList(
; E e;
; CHECK: CodeViewTypes [
-; CHECK: UnknownLeaf (0x1000) {
+; CHECK: FieldList (0x1000) {
; CHECK-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK-NEXT: Enumerator {
; CHECK-NEXT: AccessSpecifier: Public (0x3)
; CHECK-NEXT: Properties [ (0x0)
; CHECK-NEXT: ]
; CHECK-NEXT: UnderlyingType: int (0x74)
-; CHECK-NEXT: FieldListType: BLAH (0x1000)
+; CHECK-NEXT: FieldListType: <field list> (0x1000)
; CHECK-NEXT: Name: E
; CHECK-NEXT: }
; CHECK: Const (0x1)
; CHECK: ]
; CHECK: }
-; CHECK: UnknownLeaf (0x1005) {
+; CHECK: FieldList (0x1005) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: Properties [ (0x200)
; CHECK: HasUniqueName (0x200)
; CHECK: ]
-; CHECK: FieldList: sdm (0x1005)
+; CHECK: FieldList: <field list> (0x1005)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 12
; CHECK: Name: Union
; CHECK: LinkageName: .?ATUnion@@
; CHECK: }
-; CHECK: UnknownLeaf (0x1008) {
+; CHECK: FieldList (0x1008) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: Properties [ (0x200)
; CHECK: HasUniqueName (0x200)
; CHECK: ]
-; CHECK: FieldList: b (0x1008)
+; CHECK: FieldList: <field list> (0x1008)
; CHECK: SizeOf: 4
; CHECK: Name: Union
; CHECK: LinkageName: .?ATUnion@@
; CHECK: SizeOf: 0
; CHECK: Name: Class
; CHECK: }
-; CHECK: UnknownLeaf (0x100B) {
+; CHECK: FieldList (0x100B) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: Properties [ (0x200)
; CHECK: HasUniqueName (0x200)
; CHECK: ]
-; CHECK: FieldList: prot (0x100B)
+; CHECK: FieldList: <field list> (0x100B)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 12
; CHECK: IsVolatile: 0
; CHECK: IsUnaligned: 0
; CHECK: }
-; CHECK: UnknownLeaf (0x1011) {
+; CHECK: FieldList (0x1011) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: Properties [ (0x200)
; CHECK: HasUniqueName (0x200)
; CHECK: ]
-; CHECK: FieldList: d (0x1011)
+; CHECK: FieldList: <field list> (0x1011)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 48
; CHECK: Name: Nested
; CHECK: LinkageName: .?AUNested@Class@@
; CHECK: }
-; CHECK: UnknownLeaf (0x1014) {
+; CHECK: FieldList (0x1014) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: Properties [ (0x200)
; CHECK: HasUniqueName (0x200)
; CHECK: ]
-; CHECK: FieldList: n (0x1014)
+; CHECK: FieldList: <field list> (0x1014)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 4
; CHECK: ArgListType: () (0x1000)
; CHECK: ThisAdjustment: 0
; CHECK: }
-; CHECK: UnknownLeaf (0x1006) {
+; CHECK: FieldList (0x1006) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: OneMethod {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: MemberCount: 4
; CHECK: Properties [ (0x0)
; CHECK: ]
-; CHECK: FieldList: A::f_public (0x1006)
+; CHECK: FieldList: <field list> (0x1006)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 1
; CHECK: Type: void B::(int) (0x100E)
; CHECK: ]
; CHECK: }
-; CHECK: UnknownLeaf (0x1010) {
+; CHECK: FieldList (0x1010) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: OneMethod {
; CHECK: AccessSpecifier: Private (0x1)
; CHECK: MemberCount: 3
; CHECK: Properties [ (0x0)
; CHECK: ]
-; CHECK: FieldList: B::f (0x1010)
+; CHECK: FieldList: <field list> (0x1010)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 1
; CHECK: IsVolatile: 0
; CHECK: IsUnaligned: 0
; CHECK: }
-; CHECK: UnknownLeaf (0x1006) {
+; CHECK: FieldList (0x1006) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: MemberCount: 1
; CHECK: Properties [ (0x0)
; CHECK: ]
-; CHECK: FieldList: b (0x1006)
+; CHECK: FieldList: <field list> (0x1006)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 8
; CHECK: Name: A
; CHECK: }
-; CHECK: UnknownLeaf (0x1008) {
+; CHECK: FieldList (0x1008) {
; CHECK: TypeLeafKind: LF_FIELDLIST (0x1203)
; CHECK: DataMember {
; CHECK: AccessSpecifier: Public (0x3)
; CHECK: MemberCount: 1
; CHECK: Properties [ (0x0)
; CHECK: ]
-; CHECK: FieldList: a (0x1008)
+; CHECK: FieldList: <field list> (0x1008)
; CHECK: DerivedFrom: 0x0
; CHECK: VShape: 0x0
; CHECK: SizeOf: 8
; EMPTY-NEXT: )
; EMPTY-NEXT: }
; EMPTY-NEXT: {
-; EMPTY-NEXT: UnknownLeaf (0x1002) {
+; EMPTY-NEXT: FieldList (0x1002) {
; EMPTY-NEXT: TypeLeafKind: LF_FIELDLIST (0x1203)
; EMPTY-NEXT: Enumerator {
; EMPTY-NEXT: AccessSpecifier: Public (0x3)
; ALL: {
; ALL: StringId (0x1058) {
; ALL: TypeLeafKind: LF_STRING_ID (0x1605)
-; ALL: Id: managed (0x100C)
+; ALL: Id: <field list> (0x100C)
; ALL: StringData: Kits\8.1\include\um" -I"C:\Program Files (x86)\Windows Kits\8.1\include\winrt" -TP -X
; ALL: }
; ALL: }
; ALL: ArgType: void __vc_attributes::threadingAttribute::(__vc_attributes::threadingAttribute::threading_e) (0x1007)
; ALL: ArgType: void __vc_attributes::threadingAttribute::() (0x1008)
; ALL: ArgType: 0x1009
-; ALL: ArgType: value (0x100A)
+; ALL: ArgType: <field list> (0x100A)
; ALL: ArgType: __vc_attributes::event_receiverAttribute::type_e (0x100D)
; ALL: ]
; ALL: }