}
}
+static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Count;
+ // FIXME: In the future it would be nice if we could avoid hardcoding these
+ // values. One idea is to define some structures representing these types
+ // that would allow the use of offsetof().
+ switch (Kind) {
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID:
+ Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
+ break;
+ case SymbolKind::S_UDT:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
+ break;
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_BUILDINFO:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
+ break;
+ case SymbolKind::S_LOCAL:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_CONSTANT:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_REGREL32:
+ Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
+ break;
+ case SymbolKind::S_CALLSITEINFO:
+ Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
+ break;
+ case SymbolKind::S_CALLERS:
+ case SymbolKind::S_CALLEES:
+ // The record is a count followed by an array of type indices.
+ Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
+ Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
+ break;
+ case SymbolKind::S_INLINESITE:
+ Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
+ break;
+
+ // Defranges don't have types, just registers and code offsets.
+ case SymbolKind::S_DEFRANGE_REGISTER:
+ case SymbolKind::S_DEFRANGE_REGISTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ break;
+
+ // No type refernces.
+ case SymbolKind::S_LABEL32:
+ case SymbolKind::S_OBJNAME:
+ case SymbolKind::S_COMPILE:
+ case SymbolKind::S_COMPILE2:
+ case SymbolKind::S_COMPILE3:
+ case SymbolKind::S_BLOCK32:
+ case SymbolKind::S_FRAMEPROC:
+ break;
+ // Scope ending symbols.
+ case SymbolKind::S_END:
+ case SymbolKind::S_INLINESITE_END:
+ case SymbolKind::S_PROC_ID_END:
+ break;
+ default:
+ return false; // Unknown symbol.
+ }
+ return true;
+}
+
void llvm::codeview::discoverTypeIndices(const CVType &Type,
SmallVectorImpl<TiReference> &Refs) {
::discoverTypeIndices(Type.content(), Type.kind(), Refs);
TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
}
+
+bool llvm::codeview::discoverTypeIndices(const CVSymbol &Sym,
+ SmallVectorImpl<TiReference> &Refs) {
+ SymbolKind K = Sym.kind();
+ return ::discoverTypeIndices(Sym.content(), K, Refs);
+}
#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/Support/Allocator.h"
#include "gmock/gmock.h"
Refs.clear();
TTB = make_unique<TypeTableBuilder>(Storage);
FLRB = make_unique<FieldListRecordBuilder>(*TTB);
+ Symbols.clear();
}
void TearDown() override {
template <typename... Indices>
bool checkTypeReferences(uint32_t RecordIndex, Indices &&... TIs) const {
EXPECT_EQ(sizeof...(Indices), countRefs(RecordIndex));
- return checkTypeReferencesImpl(RecordIndex, std::forward<Indices>(TIs)...);
+
+ // Choose between type or symbol records. The checking code doesn't care
+ // which we have.
+ std::vector<ArrayRef<uint8_t>> CVRecords;
+ if (Symbols.empty()) {
+ CVRecords = TTB->records();
+ } else {
+ for (const CVSymbol &S : Symbols)
+ CVRecords.push_back(S.data());
+ }
+
+ return checkTypeReferencesImpl(RecordIndex, CVRecords,
+ std::forward<Indices>(TIs)...);
}
template <typename... T> void writeFieldList(T &&... MemberRecords) {
discoverAllTypeIndices();
}
+ template <typename... T> void writeSymbolRecords(T &&... Records) {
+ writeSymbolRecordsImpl(std::forward<T>(Records)...);
+ ASSERT_EQ(sizeof...(T), Symbols.size());
+ discoverTypeIndicesInSymbols();
+ }
+
+
std::unique_ptr<TypeTableBuilder> TTB;
private:
}
template <typename... Indices>
- bool checkTypeReferencesImpl(uint32_t RecordIndex) const {
+ bool checkTypeReferencesImpl(uint32_t RecordIndex,
+ ArrayRef<ArrayRef<uint8_t>> CVRecords) const {
return true;
}
template <typename... Indices>
- bool checkTypeReferencesImpl(uint32_t RecordIndex, TypeIndex TI,
- Indices &&... Rest) const {
- ArrayRef<uint8_t> Record = TTB->records()[RecordIndex];
+ bool checkTypeReferencesImpl(uint32_t RecordIndex,
+ ArrayRef<ArrayRef<uint8_t>> CVRecords,
+ TypeIndex TI, Indices &&... Rest) const {
+ ArrayRef<uint8_t> Record = CVRecords[RecordIndex];
bool Success = checkOneTypeReference(RecordIndex, Record, TI);
EXPECT_TRUE(Success);
- return Success &
- checkTypeReferencesImpl(RecordIndex, std::forward<Indices>(Rest)...);
+ return Success & checkTypeReferencesImpl(RecordIndex, CVRecords,
+ std::forward<Indices>(Rest)...);
}
void discoverAllTypeIndices() {
}
}
+ void discoverTypeIndicesInSymbols() {
+ Refs.resize(Symbols.size());
+ for (uint32_t I = 0; I < Symbols.size(); ++I)
+ discoverTypeIndices(Symbols[I], Refs[I]);
+ }
+
// Helper function to write out a field list record with the given list
// of member records.
void writeFieldListImpl() {}
writeTypeRecordsImpl(std::forward<Rest>(Records)...);
}
+ // Helper function to write out a list of symbol records.
+ void writeSymbolRecordsImpl() {}
+
+ template <typename RecType, typename... Rest>
+ void writeSymbolRecordsImpl(RecType &&Record, Rest &&... Records) {
+ Symbols.push_back(SymbolSerializer::writeOneSymbol(Record, Storage,
+ CodeViewContainer::Pdb));
+ writeSymbolRecordsImpl(std::forward<Rest>(Records)...);
+ }
+
std::vector<SmallVector<TiReference, 4>> Refs;
std::unique_ptr<FieldListRecordBuilder> FLRB;
+ std::vector<CVSymbol> Symbols;
BumpPtrAllocator Storage;
};
OneMethod.T1, OneMethod.T2, OneMethod.T3, OneMethod.T4, NestedType.Type,
StaticDataMember.Type, VirtualBaseClass.BaseType,
VirtualBaseClass.VBPtrType, VFPtr.Type, Continuation.ContinuationIndex);
-}
\ No newline at end of file
+}
+
+TEST_F(TypeIndexIteratorTest, ProcSym) {
+ ProcSym GS(SymbolRecordKind::GlobalProcSym);
+ GS.FunctionType = TypeIndex(0x40);
+ ProcSym LS(SymbolRecordKind::ProcSym);
+ LS.FunctionType = TypeIndex(0x41);
+ writeSymbolRecords(GS, LS);
+ checkTypeReferences(0, GS.FunctionType);
+ checkTypeReferences(1, LS.FunctionType);
+}
+
+TEST_F(TypeIndexIteratorTest, DataSym) {
+ DataSym DS(SymbolRecordKind::GlobalData);
+ DS.Type = TypeIndex(0x40);
+ writeSymbolRecords(DS);
+ checkTypeReferences(0, DS.Type);
+}
+
+TEST_F(TypeIndexIteratorTest, CallerSym) {
+ CallerSym Callees(SymbolRecordKind::CalleeSym);
+ Callees.Indices.push_back(TypeIndex(1));
+ Callees.Indices.push_back(TypeIndex(2));
+ Callees.Indices.push_back(TypeIndex(3));
+ CallerSym Callers(SymbolRecordKind::CallerSym);
+ Callers.Indices.push_back(TypeIndex(4));
+ Callers.Indices.push_back(TypeIndex(5));
+ Callers.Indices.push_back(TypeIndex(6));
+ writeSymbolRecords(Callees, Callers);
+ checkTypeReferences(0, TypeIndex(1), TypeIndex(2), TypeIndex(3));
+ checkTypeReferences(1, TypeIndex(4), TypeIndex(5), TypeIndex(6));
+}