uint32_t length() const { return RecordData.size(); }
Kind kind() const { return Type; }
ArrayRef<uint8_t> data() const { return RecordData; }
+ StringRef str_data() const {
+ return StringRef(reinterpret_cast<const char *>(RecordData.data()),
+ RecordData.size());
+ }
ArrayRef<uint8_t> content() const {
return RecordData.drop_front(sizeof(RecordPrefix));
+++ /dev/null
-//===-- CVTypeDumper.h - CodeView type info dumper --------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEDUMPER_H
-#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEDUMPER_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
-#include "llvm/DebugInfo/CodeView/TypeIndex.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-namespace llvm {
-
-namespace codeview {
-
-class TypeServerHandler;
-
-/// Dumper for CodeView type streams found in COFF object files and PDB files.
-class CVTypeDumper {
-public:
- explicit CVTypeDumper(TypeDatabase &TypeDB,
- TypeServerHandler *Handler = nullptr)
- : TypeDB(TypeDB), Handler(Handler) {}
-
- /// Dumps one type record. Returns false if there was a type parsing error,
- /// and true otherwise. This should be called in order, since the dumper
- /// maintains state about previous records which are necessary for cross
- /// type references.
- Error dump(const CVType &Record, TypeVisitorCallbacks &Dumper);
-
- /// Dumps the type records in Types. Returns false if there was a type stream
- /// parse error, and true otherwise.
- Error dump(const CVTypeArray &Types, TypeVisitorCallbacks &Dumper);
-
- /// Dumps the type records in Data. Returns false if there was a type stream
- /// parse error, and true otherwise. Use this method instead of the
- /// CVTypeArray overload when type records are laid out contiguously in
- /// memory.
- Error dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper);
-
- static void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
- TypeIndex TI, TypeDatabase &DB);
-
-private:
- TypeDatabase &TypeDB;
- TypeServerHandler *Handler;
-};
-
-} // end namespace codeview
-} // end namespace llvm
-
-#endif // LLVM_DEBUGINFO_CODEVIEW_TYPEDUMPER_H
#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
#define LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
-#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/Error.h"
namespace llvm {
namespace codeview {
-
-class CVTypeVisitor {
-public:
- explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
-
- void addTypeServerHandler(TypeServerHandler &Handler);
-
- Error visitTypeRecord(CVType &Record, TypeIndex Index);
- Error visitTypeRecord(CVType &Record);
- Error visitMemberRecord(CVMemberRecord Record);
-
- /// Visits the type records in Data. Sets the error flag on parse failures.
- Error visitTypeStream(const CVTypeArray &Types);
- Error visitTypeStream(CVTypeRange Types);
-
- Error visitFieldListMemberStream(ArrayRef<uint8_t> FieldList);
- Error visitFieldListMemberStream(BinaryStreamReader Reader);
-
-private:
- Expected<bool> handleTypeServer(CVType &Record);
- Error finishVisitation(CVType &Record);
-
- /// The interface to the class that gets notified of each visitation.
- TypeVisitorCallbacks &Callbacks;
-
- TinyPtrVector<TypeServerHandler *> Handlers;
-};
+class TypeCollection;
+class TypeServerHandler;
+class TypeVisitorCallbacks;
enum VisitorDataSource {
VDS_BytesPresent, // The record bytes are passed into the the visitation
TypeServerHandler *TS = nullptr);
Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
TypeServerHandler *TS = nullptr);
+Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS = nullptr);
} // end namespace codeview
} // end namespace llvm
-//===- RandomAccessTypeVisitor.h ------------------------------ *- C++ --*-===//
+//===- LazyRandomTypeCollection.h ---------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
-#define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
+#ifndef LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
+#define LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
-#include "llvm/ADT/TinyPtrVector.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
namespace codeview {
class TypeDatabase;
-class TypeServerHandler;
class TypeVisitorCallbacks;
/// \brief Provides amortized O(1) random access to a CodeView type stream.
/// consumer much better access time, because the consumer can find the nearest
/// index in this array, and do a linear scan forward only from there.
///
-/// RandomAccessTypeVisitor implements this algorithm, but additionally goes one
-/// step further by caching offsets of every record that has been visited at
+/// LazyRandomTypeCollection implements this algorithm, but additionally goes
+/// one step further by caching offsets of every record that has been visited at
/// least once. This way, even repeated visits of the same record will never
/// require more than one linear scan. For a type stream of N elements divided
/// into M chunks of roughly equal size, this yields a worst case lookup time
/// of O(N/M) and an amortized time of O(1).
-class RandomAccessTypeVisitor {
+class LazyRandomTypeCollection : public TypeCollection {
typedef FixedStreamArray<TypeIndexOffset> PartialOffsetArray;
public:
- RandomAccessTypeVisitor(const CVTypeArray &Types, uint32_t NumRecords,
- PartialOffsetArray PartialOffsets);
-
- Error visitTypeIndex(TypeIndex Index, TypeVisitorCallbacks &Callbacks);
+ explicit LazyRandomTypeCollection(uint32_t RecordCountHint);
+ LazyRandomTypeCollection(StringRef Data, uint32_t RecordCountHint);
+ LazyRandomTypeCollection(ArrayRef<uint8_t> Data, uint32_t RecordCountHint);
+ LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint,
+ PartialOffsetArray PartialOffsets);
+ LazyRandomTypeCollection(const CVTypeArray &Types, uint32_t RecordCountHint);
+
+ void reset(ArrayRef<uint8_t> Data);
+ void reset(StringRef Data);
+
+ CVType getType(TypeIndex Index) override;
+ StringRef getTypeName(TypeIndex Index) override;
+ bool contains(TypeIndex Index) override;
+ uint32_t size() override;
+ uint32_t capacity() override;
+ TypeIndex getFirst() override;
+ Optional<TypeIndex> getNext(TypeIndex Prev) override;
+private:
const TypeDatabase &database() const { return Database; }
+ Error ensureTypeExists(TypeIndex Index);
-private:
Error visitRangeForType(TypeIndex TI);
+ Error fullScanForType(TypeIndex TI);
Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End);
+ Error visitOneRecord(TypeIndex TI, uint32_t Offset, CVType &Record);
/// Visited records get automatically added to the type database.
TypeDatabase Database;
/// The type array to allow random access visitation of.
- const CVTypeArray &Types;
+ CVTypeArray Types;
/// The database visitor which adds new records to the database.
TypeDatabaseVisitor DatabaseVisitor;
} // end namespace codeview
} // end namespace llvm
-#endif // LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
+#endif // LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
class ScopedPrinter;
namespace codeview {
-class TypeDatabase;
+class TypeCollection;
/// Dumper for CodeView symbol streams found in COFF object files and PDB files.
class CVSymbolDumper {
public:
- CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB,
+ CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
bool PrintRecordBytes)
- : W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)),
+ : W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
PrintRecordBytes(PrintRecordBytes) {}
/// Dumps one type record. Returns false if there was a type parsing error,
private:
ScopedPrinter &W;
- TypeDatabase &TypeDB;
+ TypeCollection &Types;
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
bool PrintRecordBytes;
--- /dev/null
+//===- TypeCollection.h - A collection of CodeView type records -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPECOLLECTION_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPECOLLECTION_H
+
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+
+namespace llvm {
+namespace codeview {
+class TypeCollection {
+public:
+ virtual ~TypeCollection() = default;
+
+ bool empty() { return size() == 0; }
+
+ virtual TypeIndex getFirst() = 0;
+ virtual Optional<TypeIndex> getNext(TypeIndex Prev) = 0;
+
+ virtual CVType getType(TypeIndex Index) = 0;
+ virtual StringRef getTypeName(TypeIndex Index) = 0;
+ virtual bool contains(TypeIndex Index) = 0;
+ virtual uint32_t size() = 0;
+ virtual uint32_t capacity() = 0;
+};
+}
+}
+
+#endif
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/Support/Allocator.h"
namespace llvm {
namespace codeview {
-class TypeDatabase {
+class TypeDatabase : public TypeCollection {
friend class RandomAccessTypeVisitor;
public:
CVType &getTypeRecord(TypeIndex Index);
bool contains(TypeIndex Index) const;
-
uint32_t size() const;
uint32_t capacity() const;
bool empty() const;
- TypeIndex getAppendIndex() const;
+ CVType getType(TypeIndex Index) override;
+ StringRef getTypeName(TypeIndex Index) override;
+ bool contains(TypeIndex Index) override;
+ uint32_t size() override;
+ uint32_t capacity() override;
+
+ TypeIndex getFirst() override;
+ Optional<TypeIndex> getNext(TypeIndex Prev) override;
+
+ Optional<TypeIndex> largestTypeIndexLessThan(TypeIndex TI) const;
private:
+ TypeIndex getAppendIndex() const;
+
void grow();
+ void grow(TypeIndex Index);
BumpPtrAllocator Allocator;
uint32_t Count = 0;
+ TypeIndex LargestTypeIndex;
/// All user defined type records in .debug$T live in here. Type indices
/// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringSet.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
namespace codeview {
+class TypeCollection;
+
/// Dumper for CodeView type streams found in COFF object files and PDB files.
class TypeDumpVisitor : public TypeVisitorCallbacks {
public:
- TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes)
- : W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {}
+ TypeDumpVisitor(TypeCollection &TpiTypes, ScopedPrinter *W,
+ bool PrintRecordBytes)
+ : W(W), PrintRecordBytes(PrintRecordBytes), TpiTypes(TpiTypes) {}
/// When dumping types from an IPI stream in a PDB, a type index may refer to
/// a type or an item ID. The dumper will lookup the "name" of the index in
/// the item database if appropriate. If ItemDB is null, it will use TypeDB,
/// which is correct when dumping types from an object file (/Z7).
- void setItemDB(TypeDatabase &DB) { ItemDB = &DB; }
+ void setIpiTypes(TypeCollection &Types) { IpiTypes = &Types; }
void printTypeIndex(StringRef FieldName, TypeIndex TI) const;
/// Get the database of indices for the stream that we are dumping. If ItemDB
/// is set, then we must be dumping an item (IPI) stream. This will also
/// always get the appropriate DB for printing item names.
- TypeDatabase &getSourceDB() const { return ItemDB ? *ItemDB : TypeDB; }
+ TypeCollection &getSourceTypes() const {
+ return IpiTypes ? *IpiTypes : TpiTypes;
+ }
ScopedPrinter *W;
bool PrintRecordBytes = false;
- TypeDatabase &TypeDB;
- TypeDatabase *ItemDB = nullptr;
+ TypeCollection &TpiTypes;
+ TypeCollection *IpiTypes = nullptr;
};
} // end namespace codeview
#include <cinttypes>
namespace llvm {
+
+class ScopedPrinter;
+
namespace codeview {
+class TypeCollection;
+
enum class SimpleTypeKind : uint32_t {
None = 0x0000, // uncharacterized type (no type)
Void = 0x0003, // void
return Result;
}
+ friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) {
+ assert(A >= B);
+ return A.toArrayIndex() - B.toArrayIndex();
+ }
+
private:
support::ulittle32_t Index;
};
TypeIndex Type;
support::ulittle32_t Offset;
};
+
+void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI,
+ TypeCollection &Types);
}
}
--- /dev/null
+//===- TypeTableCollection.h ---------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H
+#define LLVM_DEBUGINFO_CODEVIEW_TYPETABLECOLLECTION_H
+
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+
+namespace llvm {
+namespace codeview {
+
+class TypeTableCollection : public TypeCollection {
+public:
+ explicit TypeTableCollection(ArrayRef<MutableArrayRef<uint8_t>> Records);
+
+ TypeIndex getFirst() override;
+ Optional<TypeIndex> getNext(TypeIndex Prev) override;
+
+ CVType getType(TypeIndex Index) override;
+ StringRef getTypeName(TypeIndex Index) override;
+ bool contains(TypeIndex Index) override;
+ uint32_t size() override;
+ uint32_t capacity() override;
+
+private:
+ bool hasCapacityFor(TypeIndex Index) const;
+ void ensureTypeExists(TypeIndex Index);
+
+ ArrayRef<MutableArrayRef<uint8_t>> Records;
+ TypeDatabase Database;
+};
+}
+}
+
+#endif
namespace codeview {
class TypeVisitorCallbacks {
- friend class CVTypeVisitor;
-
public:
virtual ~TypeVisitorCallbacks() = default;
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
#include "CodeViewDebug.h"
#include "llvm/ADT/TinyPtrVector.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/IR/Constants.h"
#include "llvm/MC/MCAsmInfo.h"
CommentPrefix += ' ';
}
- TypeDatabase TypeDB(TypeTable.records().size());
- CVTypeDumper CVTD(TypeDB);
- TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
+ TypeTableCollection Table(TypeTable.records());
+ Optional<TypeIndex> B = Table.getFirst();
+ do {
+ // This will fail if the record data is invalid.
+ CVType Record = Table.getType(*B);
+
if (OS.isVerboseAsm()) {
// Emit a block comment describing the type record for readability.
SmallString<512> CommentBlock;
raw_svector_ostream CommentOS(CommentBlock);
ScopedPrinter SP(CommentOS);
SP.setPrefix(CommentPrefix);
- TypeDumpVisitor TDV(TypeDB, &SP, false);
- Error E = CVTD.dump(Record, TDV);
+ TypeDumpVisitor TDV(Table, &SP, false);
+
+ Error E = codeview::visitTypeRecord(Record, *B, TDV);
if (E) {
logAllUnhandledErrors(std::move(E), errs(), "error: ");
llvm_unreachable("produced malformed type record");
// newline.
OS.emitRawComment(
CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
- } else {
-#ifndef NDEBUG
- // Assert that the type data is valid even if we aren't dumping
- // comments. The MSVC linker doesn't do much type record validation,
- // so the first link of an invalid type record can succeed while
- // subsequent links will fail with LNK1285.
- BinaryByteStream Stream(Record, llvm::support::little);
- CVTypeArray Types;
- BinaryStreamReader Reader(Stream);
- Error E = Reader.readArray(Types, Reader.getLength());
- if (!E) {
- TypeVisitorCallbacks C;
- E = codeview::visitTypeStream(Types, C);
- }
- if (E) {
- logAllUnhandledErrors(std::move(E), errs(), "error: ");
- llvm_unreachable("produced malformed type record");
- }
-#endif
}
- StringRef S(reinterpret_cast<const char *>(Record.data()), Record.size());
- OS.EmitBinaryData(S);
- });
+ OS.EmitBinaryData(Record.str_data());
+ } while (B = Table.getNext(*B));
}
namespace {
CodeViewError.cpp
CodeViewRecordIO.cpp
CVSymbolVisitor.cpp
- CVTypeDumper.cpp
CVTypeVisitor.cpp
EnumTables.cpp
Formatters.cpp
+ LazyRandomTypeCollection.cpp
Line.cpp
ModuleDebugFileChecksumFragment.cpp
ModuleDebugFragment.cpp
ModuleDebugFragmentVisitor.cpp
ModuleDebugInlineeLinesFragment.cpp
ModuleDebugLineFragment.cpp
- RandomAccessTypeVisitor.cpp
RecordSerialization.cpp
StringTable.cpp
SymbolRecordMapping.cpp
TypeDatabase.cpp
TypeDatabaseVisitor.cpp
TypeDumpVisitor.cpp
+ TypeIndex.cpp
TypeRecordMapping.cpp
TypeSerializer.cpp
TypeStreamMerger.cpp
-
+ TypeTableCollection.cpp
+
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
)
+++ /dev/null
-//===-- CVTypeDumper.cpp - CodeView type info dumper ------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
-#include "llvm/Support/BinaryByteStream.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-
-Error CVTypeDumper::dump(const CVType &Record, TypeVisitorCallbacks &Dumper) {
- TypeDatabaseVisitor DBV(TypeDB);
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(DBV);
- Pipeline.addCallbackToPipeline(Dumper);
-
- CVType RecordCopy = Record;
- return codeview::visitTypeRecord(RecordCopy, Pipeline, VDS_BytesPresent,
- Handler);
-}
-
-Error CVTypeDumper::dump(const CVTypeArray &Types,
- TypeVisitorCallbacks &Dumper) {
- TypeDatabaseVisitor DBV(TypeDB);
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(DBV);
- Pipeline.addCallbackToPipeline(Dumper);
-
- return codeview::visitTypeStream(Types, Pipeline, Handler);
-}
-
-Error CVTypeDumper::dump(ArrayRef<uint8_t> Data, TypeVisitorCallbacks &Dumper) {
- BinaryByteStream Stream(Data, llvm::support::little);
- CVTypeArray Types;
- BinaryStreamReader Reader(Stream);
- if (auto EC = Reader.readArray(Types, Reader.getLength()))
- return EC;
-
- return dump(Types, Dumper);
-}
-
-void CVTypeDumper::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
- TypeIndex TI, TypeDatabase &DB) {
- StringRef TypeName;
- if (!TI.isNoneType())
- TypeName = DB.getTypeName(TI);
- if (!TypeName.empty())
- Printer.printHex(FieldName, TypeName, TI.getIndex());
- else
- Printer.printHex(FieldName, TI.getIndex());
-}
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
using namespace llvm;
using namespace llvm::codeview;
-CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
- : Callbacks(Callbacks) {}
template <typename T>
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
return R;
}
+static Error visitMemberRecord(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
+ if (auto EC = Callbacks.visitMemberBegin(Record))
+ return EC;
+
+ switch (Record.Kind) {
+ default:
+ if (auto EC = Callbacks.visitUnknownMember(Record))
+ return EC;
+ break;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#define TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/TypeRecords.def"
+ }
+
+ if (auto EC = Callbacks.visitMemberEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+namespace {
+
+class CVTypeVisitor {
+public:
+ explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
+
+ void addTypeServerHandler(TypeServerHandler &Handler);
+
+ Error visitTypeRecord(CVType &Record, TypeIndex Index);
+ Error visitTypeRecord(CVType &Record);
+
+ /// Visits the type records in Data. Sets the error flag on parse failures.
+ Error visitTypeStream(const CVTypeArray &Types);
+ Error visitTypeStream(CVTypeRange Types);
+ Error visitTypeStream(TypeCollection &Types);
+
+ Error visitMemberRecord(CVMemberRecord Record);
+ Error visitFieldListMemberStream(BinaryStreamReader &Stream);
+
+private:
+ Expected<bool> handleTypeServer(CVType &Record);
+ Error finishVisitation(CVType &Record);
+
+ /// The interface to the class that gets notified of each visitation.
+ TypeVisitorCallbacks &Callbacks;
+
+ TinyPtrVector<TypeServerHandler *> Handlers;
+};
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
Handlers.push_back(&Handler);
}
return finishVisitation(Record);
}
-static Error visitMemberRecord(CVMemberRecord &Record,
- TypeVisitorCallbacks &Callbacks) {
- if (auto EC = Callbacks.visitMemberBegin(Record))
- return EC;
-
- switch (Record.Kind) {
- default:
- if (auto EC = Callbacks.visitUnknownMember(Record))
- return EC;
- break;
-#define MEMBER_RECORD(EnumName, EnumVal, Name) \
- case EnumName: { \
- if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
- return EC; \
- break; \
- }
-#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
- MEMBER_RECORD(EnumVal, EnumVal, AliasName)
-#define TYPE_RECORD(EnumName, EnumVal, Name)
-#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
-#include "llvm/DebugInfo/CodeView/TypeRecords.def"
- }
-
- if (auto EC = Callbacks.visitMemberEnd(Record))
- return EC;
-
- return Error::success();
-}
-
Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
return ::visitMemberRecord(Record, Callbacks);
}
return Error::success();
}
-Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
- FieldListDeserializer Deserializer(Reader);
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(Deserializer);
- Pipeline.addCallbackToPipeline(Callbacks);
+Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
+ Optional<TypeIndex> I = Types.getFirst();
+ do {
+ CVType Type = Types.getType(*I);
+ if (auto EC = visitTypeRecord(Type, *I))
+ return EC;
+ } while (I = Types.getNext(*I));
+ return Error::success();
+}
+Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
TypeLeafKind Leaf;
while (!Reader.empty()) {
if (auto EC = Reader.readEnum(Leaf))
CVMemberRecord Record;
Record.Kind = Leaf;
- if (auto EC = ::visitMemberRecord(Record, Pipeline))
+ if (auto EC = ::visitMemberRecord(Record, Callbacks))
return EC;
}
return Error::success();
}
-Error CVTypeVisitor::visitFieldListMemberStream(ArrayRef<uint8_t> Data) {
- BinaryByteStream S(Data, llvm::support::little);
- BinaryStreamReader SR(S);
- return visitFieldListMemberStream(SR);
-}
-
-namespace {
struct FieldListVisitHelper {
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
VisitorDataSource Source)
};
struct VisitHelper {
- VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
- TypeServerHandler *TS)
+ VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
: Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
- if (TS)
- Visitor.addTypeServerHandler(*TS);
if (Source == VDS_BytesPresent) {
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Callbacks);
TypeVisitorCallbacks &Callbacks,
VisitorDataSource Source,
TypeServerHandler *TS) {
- VisitHelper Helper(Callbacks, Source, TS);
- return Helper.Visitor.visitTypeRecord(Record, Index);
+ VisitHelper V(Callbacks, Source);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeRecord(Record, Index);
}
Error llvm::codeview::visitTypeRecord(CVType &Record,
TypeVisitorCallbacks &Callbacks,
VisitorDataSource Source,
TypeServerHandler *TS) {
- VisitHelper Helper(Callbacks, Source, TS);
- return Helper.Visitor.visitTypeRecord(Record);
+ VisitHelper V(Callbacks, Source);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeRecord(Record);
}
-Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
- TypeVisitorCallbacks &Callbacks) {
- CVTypeVisitor Visitor(Callbacks);
- return Visitor.visitFieldListMemberStream(FieldList);
+Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
+ TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(CVTypeRange Types,
+ TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS) {
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(TypeCollection &Types,
+ TypeVisitorCallbacks &Callbacks,
+ TypeServerHandler *TS) {
+ // When the internal visitor calls Types.getType(Index) the interface is
+ // required to return a CVType with the bytes filled out. So we can assume
+ // that the bytes will be present when individual records are visited.
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ if (TS)
+ V.Visitor.addTypeServerHandler(*TS);
+ return V.Visitor.visitTypeStream(Types);
}
Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
TypeVisitorCallbacks &Callbacks,
VisitorDataSource Source) {
- FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
- return Helper.Visitor.visitMemberRecord(Record);
+ FieldListVisitHelper V(Callbacks, Record.Data, Source);
+ return V.Visitor.visitMemberRecord(Record);
}
Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
}
-Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
- TypeVisitorCallbacks &Callbacks,
- TypeServerHandler *TS) {
- VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
- return Helper.Visitor.visitTypeStream(Types);
-}
-
-Error llvm::codeview::visitTypeStream(CVTypeRange Types,
- TypeVisitorCallbacks &Callbacks,
- TypeServerHandler *TS) {
- VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
- return Helper.Visitor.visitTypeStream(Types);
+Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
+ TypeVisitorCallbacks &Callbacks) {
+ FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
+ return V.Visitor.visitFieldListMemberStream(V.Reader);
}
--- /dev/null
+//===- LazyRandomTypeCollection.cpp ---------------------------- *- C++--*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
+#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void error(Error &&EC) {
+ assert(!static_cast<bool>(EC));
+ if (EC)
+ consumeError(std::move(EC));
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
+ PartialOffsetArray()) {}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(
+ const CVTypeArray &Types, uint32_t RecordCountHint,
+ PartialOffsetArray PartialOffsets)
+ : Database(RecordCountHint), Types(Types), DatabaseVisitor(Database),
+ PartialOffsets(PartialOffsets) {
+ KnownOffsets.resize(Database.capacity());
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(RecordCountHint) {
+ reset(Data);
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(
+ makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) {
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
+ uint32_t NumRecords)
+ : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
+
+void LazyRandomTypeCollection::reset(StringRef Data) {
+ reset(makeArrayRef(Data.bytes_begin(), Data.bytes_end()));
+}
+
+void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data) {
+ PartialOffsets = PartialOffsetArray();
+
+ BinaryStreamReader Reader(Data, support::little);
+ error(Reader.readArray(Types, Reader.getLength()));
+
+ KnownOffsets.resize(Database.capacity());
+}
+
+CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
+ error(ensureTypeExists(Index));
+ return Database.getTypeRecord(Index);
+}
+
+StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
+ if (!Index.isSimple()) {
+ // Try to make sure the type exists. Even if it doesn't though, it may be
+ // because we're dumping a symbol stream with no corresponding type stream
+ // present, in which case we still want to be able to print <unknown UDT>
+ // for the type names.
+ consumeError(ensureTypeExists(Index));
+ }
+
+ return Database.getTypeName(Index);
+}
+
+bool LazyRandomTypeCollection::contains(TypeIndex Index) {
+ return Database.contains(Index);
+}
+
+uint32_t LazyRandomTypeCollection::size() { return Database.size(); }
+
+uint32_t LazyRandomTypeCollection::capacity() { return Database.capacity(); }
+
+Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
+ if (!Database.contains(TI)) {
+ if (auto EC = visitRangeForType(TI))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
+ if (PartialOffsets.empty())
+ return fullScanForType(TI);
+
+ auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
+ [](TypeIndex Value, const TypeIndexOffset &IO) {
+ return Value < IO.Type;
+ });
+
+ assert(Next != PartialOffsets.begin());
+ auto Prev = std::prev(Next);
+
+ TypeIndex TIB = Prev->Type;
+ if (Database.contains(TIB)) {
+ // They've asked us to fetch a type index, but the entry we found in the
+ // partial offsets array has already been visited. Since we visit an entire
+ // block every time, that means this record should have been previously
+ // discovered. Ultimately, this means this is a request for a non-existant
+ // type index.
+ return make_error<CodeViewError>("Invalid type index");
+ }
+
+ TypeIndex TIE;
+ if (Next == PartialOffsets.end()) {
+ TIE = TypeIndex::fromArrayIndex(Database.capacity());
+ } else {
+ TIE = Next->Type;
+ }
+
+ if (auto EC = visitRange(TIB, Prev->Offset, TIE))
+ return EC;
+ return Error::success();
+}
+
+TypeIndex LazyRandomTypeCollection::getFirst() {
+ TypeIndex TI = TypeIndex::fromArrayIndex(0);
+ error(ensureTypeExists(TI));
+ return TI;
+}
+
+Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) {
+ // We can't be sure how long this type stream is, given that the initial count
+ // given to the constructor is just a hint. So just try to make sure the next
+ // record exists, and if anything goes wrong, we must be at the end.
+ if (auto EC = ensureTypeExists(Prev + 1)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+
+ return Prev + 1;
+}
+
+Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
+ assert(PartialOffsets.empty());
+
+ TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
+ uint32_t Offset = 0;
+ auto Begin = Types.begin();
+
+ if (!Database.empty()) {
+ // In the case of type streams which we don't know the number of records of,
+ // it's possible to search for a type index triggering a full scan, but then
+ // later additional records are added since we didn't know how many there
+ // would be until we did a full visitation, then you try to access the new
+ // type triggering another full scan. To avoid this, we assume that if the
+ // database has some records, this must be what's going on. So we ask the
+ // database for the largest type index less than the one we're searching for
+ // and only do the forward scan from there.
+ auto Prev = Database.largestTypeIndexLessThan(TI);
+ assert(Prev.hasValue() && "Empty database with valid types?");
+ Offset = KnownOffsets[Prev->toArrayIndex()];
+ CurrentTI = *Prev;
+ ++CurrentTI;
+ Begin = Types.at(Offset);
+ ++Begin;
+ Offset = Begin.offset();
+ }
+
+ auto End = Types.end();
+ while (Begin != End) {
+ if (auto EC = visitOneRecord(CurrentTI, Offset, *Begin))
+ return EC;
+
+ Offset += Begin.getRecordLength();
+ ++Begin;
+ ++CurrentTI;
+ }
+ if (CurrentTI <= TI) {
+ return make_error<CodeViewError>("Type Index does not exist!");
+ }
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitRange(TypeIndex Begin,
+ uint32_t BeginOffset,
+ TypeIndex End) {
+
+ auto RI = Types.at(BeginOffset);
+ assert(RI != Types.end());
+
+ while (Begin != End) {
+ if (auto EC = visitOneRecord(Begin, BeginOffset, *RI))
+ return EC;
+
+ BeginOffset += RI.getRecordLength();
+ ++Begin;
+ ++RI;
+ }
+
+ return Error::success();
+}
+
+Error LazyRandomTypeCollection::visitOneRecord(TypeIndex TI, uint32_t Offset,
+ CVType &Record) {
+ assert(!Database.contains(TI));
+ if (auto EC = codeview::visitTypeRecord(Record, TI, DatabaseVisitor))
+ return EC;
+ // Keep the KnownOffsets array the same size as the Database's capacity. Since
+ // we don't always know how many records are in the type stream, we need to be
+ // prepared for the database growing and receicing a type index that can't fit
+ // in our current buffer.
+ if (KnownOffsets.size() < Database.capacity())
+ KnownOffsets.resize(Database.capacity());
+ KnownOffsets[TI.toArrayIndex()] = Offset;
+ return Error::success();
+}
+++ /dev/null
-//===- RandomAccessTypeVisitor.cpp ---------------------------- *- C++ --*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
-
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
-#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-
-RandomAccessTypeVisitor::RandomAccessTypeVisitor(
- const CVTypeArray &Types, uint32_t NumRecords,
- PartialOffsetArray PartialOffsets)
- : Database(NumRecords), Types(Types), DatabaseVisitor(Database),
- PartialOffsets(PartialOffsets) {
-
- KnownOffsets.resize(Database.capacity());
-}
-
-Error RandomAccessTypeVisitor::visitTypeIndex(TypeIndex TI,
- TypeVisitorCallbacks &Callbacks) {
- assert(TI.toArrayIndex() < Database.capacity());
-
- if (!Database.contains(TI)) {
- if (auto EC = visitRangeForType(TI))
- return EC;
- }
-
- assert(Database.contains(TI));
- auto &Record = Database.getTypeRecord(TI);
- return codeview::visitTypeRecord(Record, TI, Callbacks);
-}
-
-Error RandomAccessTypeVisitor::visitRangeForType(TypeIndex TI) {
- if (PartialOffsets.empty()) {
- TypeIndex TIB(TypeIndex::FirstNonSimpleIndex);
- TypeIndex TIE = TIB + Database.capacity();
- return visitRange(TIB, 0, TIE);
- }
-
- auto Next = std::upper_bound(PartialOffsets.begin(), PartialOffsets.end(), TI,
- [](TypeIndex Value, const TypeIndexOffset &IO) {
- return Value < IO.Type;
- });
-
- assert(Next != PartialOffsets.begin());
- auto Prev = std::prev(Next);
-
- TypeIndex TIB = Prev->Type;
- TypeIndex TIE;
- if (Next == PartialOffsets.end()) {
- TIE = TypeIndex::fromArrayIndex(Database.capacity());
- } else {
- TIE = Next->Type;
- }
-
- if (auto EC = visitRange(TIB, Prev->Offset, TIE))
- return EC;
- return Error::success();
-}
-
-Error RandomAccessTypeVisitor::visitRange(TypeIndex Begin, uint32_t BeginOffset,
- TypeIndex End) {
-
- auto RI = Types.at(BeginOffset);
- assert(RI != Types.end());
-
- while (Begin != End) {
- assert(!Database.contains(Begin));
- if (auto EC = codeview::visitTypeRecord(*RI, Begin, DatabaseVisitor))
- return EC;
- KnownOffsets[Begin.toArrayIndex()] = BeginOffset;
-
- BeginOffset += RI.getRecordLength();
- ++Begin;
- ++RI;
- }
-
- return Error::success();
-}
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
#include "llvm/DebugInfo/CodeView/StringTable.h"
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
/// the visitor out of SymbolDumper.h.
class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
public:
- CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate,
+ CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate,
ScopedPrinter &W, bool PrintRecordBytes)
- : TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W),
+ : Types(Types), ObjDelegate(ObjDelegate), W(W),
PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
/// CVSymbolVisitor overrides.
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
void printTypeIndex(StringRef FieldName, TypeIndex TI);
- TypeDatabase &TypeDB;
+ TypeCollection &Types;
SymbolDumpDelegate *ObjDelegate;
ScopedPrinter &W;
}
void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
- CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB);
+ codeview::printTypeIndex(W, FieldName, TI, Types);
}
Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(ObjDelegate.get());
- CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Dumper);
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
SymbolVisitorCallbackPipeline Pipeline;
SymbolDeserializer Deserializer(ObjDelegate.get());
- CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
Pipeline.addCallbackToPipeline(Deserializer);
Pipeline.addCallbackToPipeline(Dumper);
}
TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) {
- TypeIndex TI;
- TI = getAppendIndex();
- if (TI.toArrayIndex() >= capacity())
+ LargestTypeIndex = getAppendIndex();
+ if (LargestTypeIndex.toArrayIndex() >= capacity())
grow();
- recordType(Name, TI, Data);
- return TI;
+ recordType(Name, LargestTypeIndex, Data);
+ return LargestTypeIndex;
}
void TypeDatabase::recordType(StringRef Name, TypeIndex Index,
const CVType &Data) {
+ LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex);
+
+ if (LargestTypeIndex.toArrayIndex() >= capacity())
+ grow(Index);
+
uint32_t AI = Index.toArrayIndex();
assert(!contains(Index));
uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); }
-void TypeDatabase::grow() {
- TypeRecords.emplace_back();
- CVUDTNames.emplace_back();
- ValidRecords.resize(ValidRecords.size() + 1);
+CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); }
+
+StringRef TypeDatabase::getTypeName(TypeIndex Index) {
+ return static_cast<const TypeDatabase *>(this)->getTypeName(Index);
+}
+
+bool TypeDatabase::contains(TypeIndex Index) {
+ return static_cast<const TypeDatabase *>(this)->contains(Index);
+}
+
+uint32_t TypeDatabase::size() {
+ return static_cast<const TypeDatabase *>(this)->size();
+}
+
+uint32_t TypeDatabase::capacity() {
+ return static_cast<const TypeDatabase *>(this)->capacity();
+}
+
+void TypeDatabase::grow() { grow(LargestTypeIndex + 1); }
+
+void TypeDatabase::grow(TypeIndex NewIndex) {
+ uint32_t NewSize = NewIndex.toArrayIndex() + 1;
+
+ if (NewSize <= capacity())
+ return;
+
+ uint32_t NewCapacity = NewSize * 3 / 2;
+
+ TypeRecords.resize(NewCapacity);
+ CVUDTNames.resize(NewCapacity);
+ ValidRecords.resize(NewCapacity);
}
bool TypeDatabase::empty() const { return size() == 0; }
+Optional<TypeIndex> TypeDatabase::largestTypeIndexLessThan(TypeIndex TI) const {
+ uint32_t AI = TI.toArrayIndex();
+ int N = ValidRecords.find_prev(AI);
+ if (N == -1)
+ return None;
+ return TypeIndex::fromArrayIndex(N);
+}
+
TypeIndex TypeDatabase::getAppendIndex() const {
if (empty())
return TypeIndex::fromArrayIndex(0);
- int Index = ValidRecords.find_last();
- assert(Index != -1);
- return TypeIndex::fromArrayIndex(Index) + 1;
+ return LargestTypeIndex + 1;
+}
+
+TypeIndex TypeDatabase::getFirst() {
+ int N = ValidRecords.find_first();
+ assert(N != -1);
+ return TypeIndex::fromArrayIndex(N);
+}
+
+Optional<TypeIndex> TypeDatabase::getNext(TypeIndex Prev) {
+ int N = ValidRecords.find_next(Prev.toArrayIndex());
+ if (N == -1)
+ return None;
+ return TypeIndex::fromArrayIndex(N);
}
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
}
void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
- CVTypeDumper::printTypeIndex(*W, FieldName, TI, TypeDB);
+ codeview::printTypeIndex(*W, FieldName, TI, TpiTypes);
}
void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
- CVTypeDumper::printTypeIndex(*W, FieldName, TI, getSourceDB());
+ codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes());
}
Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
- TypeIndex TI = getSourceDB().getAppendIndex();
- return visitTypeBegin(Record, TI);
+ return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
}
Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
--- /dev/null
+//===-- TypeIndex.cpp - CodeView type index ---------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+ TypeIndex TI, TypeCollection &Types) {
+ StringRef TypeName;
+ if (!TI.isNoneType())
+ TypeName = Types.getTypeName(TI);
+ if (!TypeName.empty())
+ Printer.printHex(FieldName, TypeName, TI.getIndex());
+ else
+ Printer.printHex(FieldName, TI.getIndex());
+}
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ScopedPrinter.h"
--- /dev/null
+//===- TypeTableCollection.cpp -------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void error(Error &&EC) {
+ assert(!static_cast<bool>(EC));
+ if (EC)
+ consumeError(std::move(EC));
+}
+
+TypeTableCollection::TypeTableCollection(
+ ArrayRef<MutableArrayRef<uint8_t>> Records)
+ : Records(Records), Database(Records.size()) {}
+
+TypeIndex TypeTableCollection::getFirst() {
+ assert(!empty());
+ return TypeIndex::fromArrayIndex(0);
+}
+
+Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) {
+ ++Prev;
+ assert(Prev.toArrayIndex() <= size());
+ if (Prev.toArrayIndex() == size())
+ return None;
+ return Prev;
+}
+
+void TypeTableCollection::ensureTypeExists(TypeIndex Index) {
+ assert(hasCapacityFor(Index));
+
+ if (Database.contains(Index))
+ return;
+
+ BinaryByteStream Bytes(Records[Index.toArrayIndex()], support::little);
+
+ CVType Type;
+ uint32_t Len;
+ error(VarStreamArrayExtractor<CVType>::extract(Bytes, Len, Type));
+
+ TypeDatabaseVisitor DBV(Database);
+ error(codeview::visitTypeRecord(Type, Index, DBV));
+ assert(Database.contains(Index));
+}
+
+CVType TypeTableCollection::getType(TypeIndex Index) {
+ ensureTypeExists(Index);
+ return Database.getTypeRecord(Index);
+}
+
+StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
+ if (!Index.isSimple())
+ ensureTypeExists(Index);
+ return Database.getTypeName(Index);
+}
+
+bool TypeTableCollection::contains(TypeIndex Index) {
+ return Database.contains(Index);
+}
+
+uint32_t TypeTableCollection::size() { return Records.size(); }
+
+uint32_t TypeTableCollection::capacity() { return Records.size(); }
+
+bool TypeTableCollection::hasCapacityFor(TypeIndex Index) const {
+ return Index.toArrayIndex() < Records.size();
+}
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/PDB/GenericError.h"
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
#include "llvm/ADT/iterator_range.h"
-#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
return StringRef();
}
-CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
+CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
ScopedPrinter *W)
- : CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex),
+ : CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex),
W) {}
-CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
+CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
TypeIndex FirstTI,
ScopedPrinter *W)
- : W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {}
+ : W(W), TI(FirstTI), Offset(0), Types(Types) {}
Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
return Error::success();
Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
uint32_t I = TI.getIndex();
StringRef Leaf = getLeafName(Record.Type);
- StringRef Name = TypeDB.getTypeName(TI);
+ StringRef Name = Types.getTypeName(TI);
W->printString(
llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I,
Record.length(), Offset, Leaf, Name)
namespace llvm {
class ScopedPrinter;
namespace codeview {
-class TypeDatabase;
+class TypeCollection;
}
namespace pdb {
/// Dumps records on a single line, and ignores member records.
class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
public:
- CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W);
- CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB,
+ CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W);
+ CompactTypeDumpVisitor(codeview::TypeCollection &Types,
codeview::TypeIndex FirstTI, ScopedPrinter *W);
/// Paired begin/end actions for all types. Receives all record data,
codeview::TypeIndex TI;
uint32_t Offset;
- codeview::TypeDatabase &TypeDB;
+ codeview::TypeCollection &Types;
};
} // end namespace pdb
#include "StreamUtil.h"
#include "llvm-pdbdump.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
class C13RawVisitor : public C13DebugFragmentVisitor {
public:
- C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI)
+ C13RawVisitor(ScopedPrinter &P, PDBFile &F, LazyRandomTypeCollection &IPI)
: C13DebugFragmentVisitor(F), P(P), IPI(IPI) {}
Error handleLines() override {
if (auto EC = printFileName("FileName", L.Header->FileID))
return EC;
- if (auto EC = dumpTypeRecord("Function", IPI, L.Header->Inlinee))
+ if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee))
return EC;
P.printNumber("SourceLine", L.Header->SourceLineNum);
if (IL.hasExtraFiles()) {
}
private:
- Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) {
- CompactTypeDumpVisitor CTDV(DB, Index, &P);
+ Error dumpTypeRecord(StringRef Label, TypeIndex Index) {
+ CompactTypeDumpVisitor CTDV(IPI, Index, &P);
DictScope D(P, Label);
- if (DB.contains(Index)) {
- CVType &Type = DB.getTypeRecord(Index);
+ if (IPI.contains(Index)) {
+ CVType Type = IPI.getType(Index);
if (auto EC = codeview::visitTypeRecord(Type, CTDV))
return EC;
} else {
}
ScopedPrinter &P;
- TypeDatabase &IPI;
+ LazyRandomTypeCollection &IPI;
};
}
VerLabel = "IPI Version";
}
- if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
- return Error::success();
-
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
: File.getPDBIpiStream();
if (!Tpi)
return Tpi.takeError();
+ auto ExpectedTypes = initializeTypeDatabase(StreamIdx);
+ if (!ExpectedTypes)
+ return ExpectedTypes.takeError();
+ auto &Types = *ExpectedTypes;
+
+ if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
+ return Error::success();
+
std::unique_ptr<DictScope> StreamScope;
std::unique_ptr<ListScope> RecordScope;
P.printNumber(VerLabel, Tpi->getTpiVersion());
P.printNumber("Record count", Tpi->getNumTypeRecords());
- Optional<TypeDatabase> &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB;
-
std::vector<std::unique_ptr<TypeVisitorCallbacks>> Visitors;
- if (!StreamDB.hasValue()) {
- StreamDB.emplace(Tpi->getNumTypeRecords());
- Visitors.push_back(make_unique<TypeDatabaseVisitor>(*StreamDB));
- }
// If we're in dump mode, add a dumper with the appropriate detail level.
if (DumpRecords) {
std::unique_ptr<TypeVisitorCallbacks> Dumper;
if (opts::raw::CompactRecords)
- Dumper = make_unique<CompactTypeDumpVisitor>(*StreamDB, &P);
+ Dumper = make_unique<CompactTypeDumpVisitor>(Types, &P);
else {
- assert(TypeDB.hasValue());
+ assert(TpiTypes);
- auto X = make_unique<TypeDumpVisitor>(*TypeDB, &P, false);
+ auto X = make_unique<TypeDumpVisitor>(*TpiTypes, &P, false);
if (StreamIdx == StreamIPI)
- X->setItemDB(*ItemDB);
+ X->setIpiTypes(*IpiTypes);
Dumper = std::move(X);
}
Visitors.push_back(std::move(Dumper));
if (DumpRecords || DumpRecordBytes)
RecordScope = llvm::make_unique<ListScope>(P, "Records");
- bool HadError = false;
-
- TypeIndex T(TypeIndex::FirstNonSimpleIndex);
- for (auto Type : Tpi->types(&HadError)) {
+ Optional<TypeIndex> I = Types.getFirst();
+ do {
std::unique_ptr<DictScope> OneRecordScope;
if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
OneRecordScope = llvm::make_unique<DictScope>(P, "");
- if (auto EC = codeview::visitTypeRecord(Type, Pipeline))
+ auto T = Types.getType(*I);
+ if (auto EC = codeview::visitTypeRecord(T, *I, Pipeline))
return EC;
-
- ++T;
- }
- if (HadError)
- return make_error<RawError>(raw_error_code::corrupt_file,
- "TPI stream contained corrupt record");
+ } while (I = Types.getNext(*I));
if (DumpTpiHash) {
DictScope DD(P, "Hash");
return Error::success();
}
-Error LLVMOutputStyle::buildTypeDatabase(uint32_t SN) {
- assert(SN == StreamIPI || SN == StreamTPI);
-
- auto &DB = (SN == StreamIPI) ? ItemDB : TypeDB;
-
- if (DB.hasValue())
- return Error::success();
-
+Expected<codeview::LazyRandomTypeCollection &>
+LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) {
+ auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
auto Tpi =
(SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
-
if (!Tpi)
return Tpi.takeError();
- DB.emplace(Tpi->getNumTypeRecords());
-
- TypeDatabaseVisitor DBV(*DB);
-
- auto HashValues = Tpi->getHashValues();
- if (HashValues.empty())
- return codeview::visitTypeStream(Tpi->typeArray(), DBV);
-
- TypeVisitorCallbackPipeline Pipeline;
- Pipeline.addCallbackToPipeline(DBV);
-
- TpiHashVerifier HashVerifier(HashValues, Tpi->getNumHashBuckets());
- Pipeline.addCallbackToPipeline(HashVerifier);
+ if (!TypeCollection) {
+ // Initialize the type collection, even if we're not going to dump it. This
+ // way if some other part of the dumper decides it wants to use some or all
+ // of the records for whatever purposes, it can still access them lazily.
+ auto &Types = Tpi->typeArray();
+ uint32_t Count = Tpi->getNumTypeRecords();
+ auto Offsets = Tpi->getTypeIndexOffsets();
+ TypeCollection =
+ llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
+ }
- return codeview::visitTypeStream(Tpi->typeArray(), Pipeline);
+ return *TypeCollection;
}
Error LLVMOutputStyle::dumpDbiStream() {
return EC;
if (ShouldDumpSymbols) {
- if (auto EC = buildTypeDatabase(StreamTPI))
- return EC;
+ auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
+ if (!ExpectedTypes)
+ return ExpectedTypes.takeError();
+ auto &Types = *ExpectedTypes;
ListScope SS(P, "Symbols");
- codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
+ codeview::CVSymbolDumper SD(P, Types, nullptr, false);
bool HadError = false;
for (auto S : ModS.symbols(&HadError)) {
DictScope LL(P, "");
}
if (opts::raw::DumpLineInfo) {
ListScope SS(P, "LineInfo");
- if (auto EC = buildTypeDatabase(StreamIPI))
- return EC;
-
- C13RawVisitor V(P, File, *ItemDB);
+ auto ExpectedTypes = initializeTypeDatabase(StreamIPI);
+ if (!ExpectedTypes)
+ return ExpectedTypes.takeError();
+ auto &IpiItems = *ExpectedTypes;
+ C13RawVisitor V(P, File, IpiItems);
if (auto EC = codeview::visitModuleDebugFragments(
ModS.linesAndChecksums(), V))
return EC;
P.printList("Section Offsets", Publics->getSectionOffsets(),
printSectionOffset);
ListScope L(P, "Symbols");
- if (auto EC = buildTypeDatabase(StreamTPI))
- return EC;
+ auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
+ if (!ExpectedTypes)
+ return ExpectedTypes.takeError();
+ auto &Tpi = *ExpectedTypes;
- codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
+ codeview::CVSymbolDumper SD(P, Tpi, nullptr, false);
bool HadError = false;
for (auto S : Publics->getSymbols(&HadError)) {
DictScope DD(P, "");
namespace llvm {
class BitVector;
+
+namespace codeview {
+class LazyRandomTypeCollection;
+}
+
namespace pdb {
class LLVMOutputStyle : public OutputStyle {
public:
Error dump() override;
private:
- Error buildTypeDatabase(uint32_t SN);
+ Expected<codeview::LazyRandomTypeCollection &>
+ initializeTypeDatabase(uint32_t SN);
Error dumpFileHeaders();
Error dumpStreamSummary();
PDBFile &File;
ScopedPrinter P;
- Optional<codeview::TypeDatabase> TypeDB;
- Optional<codeview::TypeDatabase> ItemDB;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
+ std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
SmallVector<std::string, 32> StreamPurposes;
};
}
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
pdb::yaml::SerializationContext &Context) {
-
if (IO.outputting()) {
// For PDB to Yaml, deserialize into a high level record type, then dump it.
consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper));
#include "OutputStyle.h"
#include "PdbYaml.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/EnumTables.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
+#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/COFF.h"
-#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
public:
friend class COFFObjectDumpDelegate;
COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
- : ObjDumper(Writer), Obj(Obj), Writer(Writer), TypeDB(100) {}
+ : ObjDumper(Writer), Obj(Obj), Writer(Writer), Types(100) {}
void printFileHeaders() override;
void printSections() override;
void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
void printTypeIndex(StringRef FieldName, TypeIndex TI) {
// Forward to CVTypeDumper for simplicity.
- CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
+ codeview::printTypeIndex(Writer, FieldName, TI, Types);
}
void printCodeViewSymbolsSubsection(StringRef Subsection,
StringTableRef CVStringTable;
ScopedPrinter &Writer;
- TypeDatabase TypeDB;
+ BinaryByteStream TypeContents;
+ LazyRandomTypeCollection Types;
};
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
Subsection.bytes_end());
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
SectionContents);
-
- CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
- opts::CodeViewSubsectionBytes);
+ CVSymbolDumper CVSD(W, Types, std::move(CODD), opts::CodeViewSubsectionBytes);
CVSymbolArray Symbols;
BinaryStreamReader Reader(BinaryData, llvm::support::little);
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
- CVTypeDumper CVTD(TypeDB);
- TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
- if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
- W.flush();
- error(llvm::errorToErrorCode(std::move(EC)));
- }
+ Types.reset(Data);
+
+ TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
+ error(codeview::visitTypeStream(Types, TDV));
+ W.flush();
}
void COFFDumper::printSections() {
TypeBuf.append(Record.begin(), Record.end());
});
- TypeDatabase TypeDB(CVTypes.records().size());
+ TypeTableCollection TpiTypes(CVTypes.records());
{
ListScope S(Writer, "MergedTypeStream");
- CVTypeDumper CVTD(TypeDB);
- TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
- if (auto EC = CVTD.dump(
- {TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
- Writer.flush();
- error(std::move(EC));
- }
+ TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
+ error(codeview::visitTypeStream(TpiTypes, TDV));
+ Writer.flush();
}
// Flatten the id stream and print it next. The ID stream refers to names from
// the type stream.
- SmallString<0> IDBuf;
- IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
- IDBuf.append(Record.begin(), Record.end());
- });
-
+ TypeTableCollection IpiTypes(IDTable.records());
{
ListScope S(Writer, "MergedIDStream");
- TypeDatabase IDDB(IDTable.records().size());
- CVTypeDumper CVTD(IDDB);
- TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
- TDV.setItemDB(IDDB);
- if (auto EC = CVTD.dump(
- {IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
- Writer.flush();
- error(std::move(EC));
- }
+ TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
+ TDV.setIpiTypes(IpiTypes);
+ error(codeview::visitTypeStream(IpiTypes, TDV));
+ Writer.flush();
}
}
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
-#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
-#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/Allocator.h"
void SetUp() override {
TestState = llvm::make_unique<PerTestState>();
-
- TestState->Pipeline.addCallbackToPipeline(TestState->Deserializer);
- TestState->Pipeline.addCallbackToPipeline(TestState->Callbacks);
}
void TearDown() override { TestState.reset(); }
protected:
- bool ValidateDatabaseRecord(const RandomAccessTypeVisitor &Visitor,
- uint32_t Index) {
+ bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) {
TypeIndex TI = TypeIndex::fromArrayIndex(Index);
- if (!Visitor.database().contains(TI))
+ if (!Types.contains(TI))
return false;
- if (GlobalState->TypeVector[Index] != Visitor.database().getTypeRecord(TI))
+ if (GlobalState->TypeVector[Index] != Types.getType(TI))
return false;
return true;
}
struct PerTestState {
FixedStreamArray<TypeIndexOffset> Offsets;
- TypeVisitorCallbackPipeline Pipeline;
- TypeDeserializer Deserializer;
MockCallbacks Callbacks;
};
TEST_F(RandomAccessVisitorTest, MultipleVisits) {
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
- RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
- GlobalState->TypeVector.size(),
- TestState->Offsets);
+ LazyRandomTypeCollection Types(GlobalState->TypeArray,
+ GlobalState->TypeVector.size(),
+ TestState->Offsets);
std::vector<uint32_t> IndicesToVisit = {5, 5, 5};
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
- EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
+ CVType T = Types.getType(TI);
+ EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
}
// [0,8) should be present
- EXPECT_EQ(8u, Visitor.database().size());
+ EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
- EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
+ EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 5, 5, 5
EXPECT_EQ(3u, TestState->Callbacks.count());
std::vector<uint32_t> IndicesToVisit = {7, 4, 2};
- RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
- GlobalState->TypeVector.size(),
- TestState->Offsets);
-
+ LazyRandomTypeCollection Types(GlobalState->TypeArray,
+ GlobalState->TypeVector.size(),
+ TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
- EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
+ CVType T = Types.getType(TI);
+ EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
}
// [0, 7]
- EXPECT_EQ(8u, Visitor.database().size());
+ EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
- EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
+ EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 2, 4, 7
EXPECT_EQ(3u, TestState->Callbacks.count());
std::vector<uint32_t> IndicesToVisit = {2, 4, 7};
- RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
- GlobalState->TypeVector.size(),
- TestState->Offsets);
-
+ LazyRandomTypeCollection Types(GlobalState->TypeArray,
+ GlobalState->TypeVector.size(),
+ TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
- EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
+ CVType T = Types.getType(TI);
+ EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
}
// [0, 7]
- EXPECT_EQ(8u, Visitor.database().size());
+ EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
- EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
+ EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 2, 4, 7
EXPECT_EQ(3u, TestState->Callbacks.count());
std::vector<uint32_t> IndicesToVisit = {0, 1, 2};
- RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
- GlobalState->TypeVector.size(),
- TestState->Offsets);
+ LazyRandomTypeCollection Types(GlobalState->TypeArray,
+ GlobalState->TypeVector.size(),
+ TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
- EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
+ CVType T = Types.getType(TI);
+ EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
}
// [0, 8) should be visited.
- EXPECT_EQ(8u, Visitor.database().size());
+ EXPECT_EQ(8u, Types.size());
for (uint32_t I = 0; I < 8; ++I)
- EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
+ EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// [0, 2]
EXPECT_EQ(3u, TestState->Callbacks.count());
std::vector<uint32_t> IndicesToVisit = {5, 7};
- RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
- GlobalState->TypeVector.size(),
- TestState->Offsets);
+ LazyRandomTypeCollection Types(GlobalState->TypeArray,
+ GlobalState->TypeVector.size(),
+ TestState->Offsets);
for (uint32_t I : IndicesToVisit) {
TypeIndex TI = TypeIndex::fromArrayIndex(I);
- EXPECT_NO_ERROR(Visitor.visitTypeIndex(TI, TestState->Pipeline));
+ CVType T = Types.getType(TI);
+ EXPECT_NO_ERROR(codeview::visitTypeRecord(T, TI, TestState->Callbacks));
}
// [4, 9)
- EXPECT_EQ(5u, Visitor.database().size());
+ EXPECT_EQ(5u, Types.size());
for (uint32_t I = 4; I < 9; ++I)
- EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
+ EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
// 5, 7
EXPECT_EQ(2u, TestState->Callbacks.count());