Resubmit "[CodeView] Provide a common interface for type collections."

This was originally reverted because it was a breaking a bunch
of bots and the breakage was not surfacing on Windows.  After much
head-scratching this was ultimately traced back to a bug in the
lit test runner related to its pipe handling.  Now that the bug
in lit is fixed, Windows correctly reports these test failures,
and as such I have finally (hopefully) fixed all of them in this
patch.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303446 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Zachary Turner 2017-05-19 19:26:58 +00:00
parent 9484675111
commit d32a382ebb
38 changed files with 848 additions and 568 deletions

View File

@ -32,6 +32,10 @@ public:
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));

View File

@ -1,61 +0,0 @@
//===-- 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

View File

@ -10,42 +10,15 @@
#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
@ -76,6 +49,8 @@ Error visitTypeStream(const CVTypeArray &Types, TypeVisitorCallbacks &Callbacks,
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

View File

@ -1,4 +1,4 @@
//===- RandomAccessTypeVisitor.h ------------------------------ *- C++ --*-===//
//===- LazyRandomTypeCollection.h ---------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,10 +7,10 @@
//
//===----------------------------------------------------------------------===//
#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"
@ -21,7 +21,6 @@ namespace llvm {
namespace codeview {
class TypeDatabase;
class TypeServerHandler;
class TypeVisitorCallbacks;
/// \brief Provides amortized O(1) random access to a CodeView type stream.
@ -40,32 +39,48 @@ class TypeVisitorCallbacks;
/// 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);
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);
Error visitTypeIndex(TypeIndex Index, TypeVisitorCallbacks &Callbacks);
void reset(ArrayRef<uint8_t> Data);
void reset(StringRef Data);
const TypeDatabase &database() const { return Database; }
CVType getType(TypeIndex Index) override;
StringRef getTypeName(TypeIndex Index) override;
bool contains(TypeIndex Index) override;
uint32_t size() override;
uint32_t capacity() override;
Optional<TypeIndex> getFirst() override;
Optional<TypeIndex> getNext(TypeIndex Prev) override;
private:
const TypeDatabase &database() const { return Database; }
Error ensureTypeExists(TypeIndex Index);
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;
@ -85,4 +100,4 @@ private:
} // end namespace codeview
} // end namespace llvm
#endif // LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
#endif // LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H

View File

@ -20,15 +20,15 @@ namespace llvm {
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,
@ -43,7 +43,7 @@ public:
private:
ScopedPrinter &W;
TypeDatabase &TypeDB;
TypeCollection &Types;
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
bool PrintRecordBytes;

View File

@ -0,0 +1,38 @@
//===- 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 Optional<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

View File

@ -13,6 +13,7 @@
#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"
@ -20,7 +21,7 @@
namespace llvm {
namespace codeview {
class TypeDatabase {
class TypeDatabase : public TypeCollection {
friend class RandomAccessTypeVisitor;
public:
@ -41,19 +42,31 @@ 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;
Optional<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

View File

@ -12,7 +12,6 @@
#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"
@ -22,17 +21,20 @@ class ScopedPrinter;
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;
@ -66,14 +68,16 @@ private:
/// 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

View File

@ -15,8 +15,13 @@
#include <cinttypes>
namespace llvm {
class ScopedPrinter;
namespace codeview {
class TypeCollection;
enum class SimpleTypeKind : uint32_t {
None = 0x0000, // uncharacterized type (no type)
Void = 0x0003, // void
@ -238,6 +243,11 @@ public:
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;
};
@ -249,6 +259,9 @@ struct TypeIndexOffset {
TypeIndex Type;
support::ulittle32_t Offset;
};
void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI,
TypeCollection &Types);
}
}

View File

@ -0,0 +1,42 @@
//===- 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);
Optional<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

View File

@ -17,8 +17,6 @@ namespace llvm {
namespace codeview {
class TypeVisitorCallbacks {
friend class CVTypeVisitor;
public:
virtual ~TypeVisitorCallbacks() = default;

View File

@ -13,7 +13,6 @@
#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"

View File

@ -13,7 +13,6 @@
#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"
@ -23,6 +22,7 @@
#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"
@ -469,17 +469,21 @@ void CodeViewDebug::emitTypeInformation() {
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();
while (B) {
// 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");
@ -489,29 +493,10 @@ void CodeViewDebug::emitTypeInformation() {
// 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());
B = Table.getNext(*B);
}
}
namespace {

View File

@ -2,10 +2,10 @@ add_llvm_library(LLVMDebugInfoCodeView
CodeViewError.cpp
CodeViewRecordIO.cpp
CVSymbolVisitor.cpp
CVTypeDumper.cpp
CVTypeVisitor.cpp
EnumTables.cpp
Formatters.cpp
LazyRandomTypeCollection.cpp
Line.cpp
ModuleDebugFileChecksumFragment.cpp
ModuleDebugFragment.cpp
@ -13,7 +13,6 @@ add_llvm_library(LLVMDebugInfoCodeView
ModuleDebugFragmentVisitor.cpp
ModuleDebugInlineeLinesFragment.cpp
ModuleDebugLineFragment.cpp
RandomAccessTypeVisitor.cpp
RecordSerialization.cpp
StringTable.cpp
SymbolRecordMapping.cpp
@ -22,10 +21,12 @@ add_llvm_library(LLVMDebugInfoCodeView
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
)

View File

@ -1,61 +0,0 @@
//===-- 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());
}

View File

@ -9,7 +9,9 @@
#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"
@ -22,8 +24,6 @@
using namespace llvm;
using namespace llvm::codeview;
CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
: Callbacks(Callbacks) {}
template <typename T>
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
@ -66,6 +66,67 @@ static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
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);
}
@ -144,35 +205,6 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
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);
}
@ -194,12 +226,18 @@ Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
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();
while (I) {
CVType Type = Types.getType(*I);
if (auto EC = visitTypeRecord(Type, *I))
return EC;
I = Types.getNext(*I);
}
return Error::success();
}
Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
TypeLeafKind Leaf;
while (!Reader.empty()) {
if (auto EC = Reader.readEnum(Leaf))
@ -207,20 +245,13 @@ Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
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)
@ -241,11 +272,8 @@ struct FieldListVisitHelper {
};
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);
@ -262,29 +290,57 @@ Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
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,
@ -296,16 +352,8 @@ 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);
}

View File

@ -0,0 +1,229 @@
//===- 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();
}
Optional<TypeIndex> LazyRandomTypeCollection::getFirst() {
TypeIndex TI = TypeIndex::fromArrayIndex(0);
if (auto EC = ensureTypeExists(TI)) {
consumeError(std::move(EC));
return None;
}
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();
}

View File

@ -1,89 +0,0 @@
//===- 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();
}

View File

@ -11,7 +11,6 @@
#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"
@ -33,9 +32,9 @@ namespace {
/// 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.
@ -54,7 +53,7 @@ private:
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
void printTypeIndex(StringRef FieldName, TypeIndex TI);
TypeDatabase &TypeDB;
TypeCollection &Types;
SymbolDumpDelegate *ObjDelegate;
ScopedPrinter &W;
@ -83,7 +82,7 @@ void CVSymbolDumperImpl::printLocalVariableAddrGap(
}
void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
CVTypeDumper::printTypeIndex(W, FieldName, TI, TypeDB);
codeview::printTypeIndex(W, FieldName, TI, Types);
}
Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
@ -670,7 +669,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(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);
@ -681,7 +680,7 @@ Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
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);

View File

@ -72,16 +72,20 @@ TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) {
}
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));
@ -144,19 +148,66 @@ uint32_t TypeDatabase::size() const { return Count; }
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;
}
Optional<TypeIndex> TypeDatabase::getFirst() {
int N = ValidRecords.find_first();
if (N == -1)
return None;
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);
}

View File

@ -10,15 +10,13 @@
#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"
@ -165,16 +163,15 @@ static StringRef getLeafTypeName(TypeLeafKind LT) {
}
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) {
@ -245,7 +242,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
W->printNumber("NumStrings", Size);
ListScope Arguments(*W, "Strings");
for (uint32_t I = 0; I < Size; ++I) {
printTypeIndex("String", Indices[I]);
printItemIndex("String", Indices[I]);
}
return Error::success();
}

View File

@ -0,0 +1,27 @@
//===-- 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());
}

View File

@ -11,11 +11,9 @@
#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"

View File

@ -0,0 +1,83 @@
//===- 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()) {}
Optional<TypeIndex> TypeTableCollection::getFirst() {
if (empty())
return None;
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();
}

View File

@ -21,6 +21,7 @@
#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"

View File

@ -9,10 +9,7 @@
#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"

View File

@ -326,7 +326,7 @@
; EMPTY-NEXT: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
; EMPTY-NEXT: NumStrings: 1
; EMPTY-NEXT: Strings [
; EMPTY-NEXT: String: __vc_attributes::threadingAttribute (0x100B)
; EMPTY-NEXT: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows
; EMPTY-NEXT: ]
; EMPTY-NEXT: }
; EMPTY-NEXT: Bytes (
@ -1253,7 +1253,7 @@
; ALL: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
; ALL: NumStrings: 1
; ALL: Strings [
; ALL: String: __vc_attributes::threadingAttribute (0x100B)
; ALL: String: -Zi -MT -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE" -I"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\ATLMFC\INCLUDE" -I"C:\Program Files (x86)\Windows Kits\8.1\include\shared" -I"C:\Program Files (x86)\Windows (0x100B)
; ALL: ]
; ALL: }
; ALL: }

View File

@ -14,7 +14,6 @@
#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"

View File

@ -29,15 +29,15 @@ static StringRef getLeafName(TypeLeafKind K) {
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();
@ -46,7 +46,7 @@ Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
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)

View File

@ -17,7 +17,7 @@
namespace llvm {
class ScopedPrinter;
namespace codeview {
class TypeDatabase;
class TypeCollection;
}
namespace pdb {
@ -26,8 +26,8 @@ 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,
@ -40,7 +40,7 @@ private:
codeview::TypeIndex TI;
uint32_t Offset;
codeview::TypeDatabase &TypeDB;
codeview::TypeCollection &Types;
};
} // end namespace pdb

View File

@ -14,9 +14,9 @@
#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"
@ -25,7 +25,6 @@
#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"
@ -84,7 +83,7 @@ struct PageStats {
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 {
@ -160,7 +159,7 @@ public:
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()) {
@ -176,11 +175,11 @@ public:
}
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 {
@ -199,7 +198,7 @@ private:
}
ScopedPrinter &P;
TypeDatabase &IPI;
LazyRandomTypeCollection &IPI;
};
}
@ -609,14 +608,19 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
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;
@ -624,25 +628,19 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
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));
@ -660,23 +658,18 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
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();
while (I) {
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;
I = Types.getNext(*I);
}
if (HadError)
return make_error<RawError>(raw_error_code::corrupt_file,
"TPI stream contained corrupt record");
if (DumpTpiHash) {
DictScope DD(P, "Hash");
@ -711,35 +704,26 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
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());
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);
}
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);
return codeview::visitTypeStream(Tpi->typeArray(), Pipeline);
return *TypeCollection;
}
Error LLVMOutputStyle::dumpDbiStream() {
@ -814,11 +798,13 @@ 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, "");
@ -839,10 +825,11 @@ Error LLVMOutputStyle::dumpDbiStream() {
}
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;
@ -960,10 +947,12 @@ Error LLVMOutputStyle::dumpPublicsStream() {
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, "");

View File

@ -21,6 +21,11 @@
namespace llvm {
class BitVector;
namespace codeview {
class LazyRandomTypeCollection;
}
namespace pdb {
class LLVMOutputStyle : public OutputStyle {
public:
@ -29,7 +34,8 @@ public:
Error dump() override;
private:
Error buildTypeDatabase(uint32_t SN);
Expected<codeview::LazyRandomTypeCollection &>
initializeTypeDatabase(uint32_t SN);
Error dumpFileHeaders();
Error dumpStreamSummary();
@ -54,8 +60,8 @@ private:
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;
};
}

View File

@ -19,7 +19,6 @@
#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"
@ -371,7 +370,6 @@ void MappingContextTraits<PdbInlineeInfo, SerializationContext>::mapping(
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));

View File

@ -13,7 +13,6 @@
#include "OutputStyle.h"
#include "PdbYaml.h"
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/YAMLTraits.h"

View File

@ -13,7 +13,6 @@
#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"

View File

@ -31,6 +31,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"

View File

@ -22,8 +22,9 @@
#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"
@ -34,11 +35,13 @@
#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"
@ -70,7 +73,7 @@ class COFFDumper : public ObjDumper {
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;
@ -106,7 +109,7 @@ private:
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,
@ -159,7 +162,8 @@ private:
StringTableRef CVStringTable;
ScopedPrinter &Writer;
TypeDatabase TypeDB;
BinaryByteStream TypeContents;
LazyRandomTypeCollection Types;
};
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
@ -975,9 +979,7 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
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())) {
@ -1094,12 +1096,11 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
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() {
@ -1639,35 +1640,22 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
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();
}
}

View File

@ -11,14 +11,12 @@
#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"
@ -130,20 +128,16 @@ public:
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;
}
@ -184,8 +178,6 @@ protected:
struct PerTestState {
FixedStreamArray<TypeIndexOffset> Offsets;
TypeVisitorCallbackPipeline Pipeline;
TypeDeserializer Deserializer;
MockCallbacks Callbacks;
};
@ -218,21 +210,22 @@ std::unique_ptr<RandomAccessVisitorTest::GlobalTestState>
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());
@ -248,19 +241,19 @@ TEST_F(RandomAccessVisitorTest, DescendingWithinChunk) {
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());
@ -276,19 +269,19 @@ TEST_F(RandomAccessVisitorTest, AscendingWithinChunk) {
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());
@ -305,19 +298,20 @@ TEST_F(RandomAccessVisitorTest, StopPrematurelyInChunk) {
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());
@ -333,19 +327,20 @@ TEST_F(RandomAccessVisitorTest, InnerChunk) {
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());