mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-07 13:09:52 +00:00
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:
parent
9484675111
commit
d32a382ebb
@ -32,6 +32,10 @@ public:
|
|||||||
uint32_t length() const { return RecordData.size(); }
|
uint32_t length() const { return RecordData.size(); }
|
||||||
Kind kind() const { return Type; }
|
Kind kind() const { return Type; }
|
||||||
ArrayRef<uint8_t> data() const { return RecordData; }
|
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 {
|
ArrayRef<uint8_t> content() const {
|
||||||
return RecordData.drop_front(sizeof(RecordPrefix));
|
return RecordData.drop_front(sizeof(RecordPrefix));
|
||||||
|
@ -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
|
|
@ -10,42 +10,15 @@
|
|||||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
|
#ifndef LLVM_DEBUGINFO_CODEVIEW_CVTYPEVISITOR_H
|
||||||
#define 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/CVRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
|
||||||
#include "llvm/Support/Error.h"
|
#include "llvm/Support/Error.h"
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
class TypeCollection;
|
||||||
class CVTypeVisitor {
|
class TypeServerHandler;
|
||||||
public:
|
class TypeVisitorCallbacks;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum VisitorDataSource {
|
enum VisitorDataSource {
|
||||||
VDS_BytesPresent, // The record bytes are passed into the the visitation
|
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);
|
TypeServerHandler *TS = nullptr);
|
||||||
Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
|
Error visitTypeStream(CVTypeRange Types, TypeVisitorCallbacks &Callbacks,
|
||||||
TypeServerHandler *TS = nullptr);
|
TypeServerHandler *TS = nullptr);
|
||||||
|
Error visitTypeStream(TypeCollection &Types, TypeVisitorCallbacks &Callbacks,
|
||||||
|
TypeServerHandler *TS = nullptr);
|
||||||
|
|
||||||
} // end namespace codeview
|
} // end namespace codeview
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
//===- RandomAccessTypeVisitor.h ------------------------------ *- C++ --*-===//
|
//===- LazyRandomTypeCollection.h ---------------------------- *- C++ --*-===//
|
||||||
//
|
//
|
||||||
// The LLVM Compiler Infrastructure
|
// The LLVM Compiler Infrastructure
|
||||||
//
|
//
|
||||||
@ -7,10 +7,10 @@
|
|||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
|
#ifndef LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
|
||||||
#define LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_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/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
@ -21,7 +21,6 @@ namespace llvm {
|
|||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
|
||||||
class TypeDatabase;
|
class TypeDatabase;
|
||||||
class TypeServerHandler;
|
|
||||||
class TypeVisitorCallbacks;
|
class TypeVisitorCallbacks;
|
||||||
|
|
||||||
/// \brief Provides amortized O(1) random access to a CodeView type stream.
|
/// \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
|
/// 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.
|
/// index in this array, and do a linear scan forward only from there.
|
||||||
///
|
///
|
||||||
/// RandomAccessTypeVisitor implements this algorithm, but additionally goes one
|
/// LazyRandomTypeCollection implements this algorithm, but additionally goes
|
||||||
/// step further by caching offsets of every record that has been visited at
|
/// 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
|
/// 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
|
/// 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
|
/// 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).
|
/// of O(N/M) and an amortized time of O(1).
|
||||||
class RandomAccessTypeVisitor {
|
class LazyRandomTypeCollection : public TypeCollection {
|
||||||
typedef FixedStreamArray<TypeIndexOffset> PartialOffsetArray;
|
typedef FixedStreamArray<TypeIndexOffset> PartialOffsetArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RandomAccessTypeVisitor(const CVTypeArray &Types, uint32_t NumRecords,
|
explicit LazyRandomTypeCollection(uint32_t RecordCountHint);
|
||||||
PartialOffsetArray PartialOffsets);
|
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:
|
private:
|
||||||
|
const TypeDatabase &database() const { return Database; }
|
||||||
|
Error ensureTypeExists(TypeIndex Index);
|
||||||
|
|
||||||
Error visitRangeForType(TypeIndex TI);
|
Error visitRangeForType(TypeIndex TI);
|
||||||
|
Error fullScanForType(TypeIndex TI);
|
||||||
Error visitRange(TypeIndex Begin, uint32_t BeginOffset, TypeIndex End);
|
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.
|
/// Visited records get automatically added to the type database.
|
||||||
TypeDatabase Database;
|
TypeDatabase Database;
|
||||||
|
|
||||||
/// The type array to allow random access visitation of.
|
/// The type array to allow random access visitation of.
|
||||||
const CVTypeArray &Types;
|
CVTypeArray Types;
|
||||||
|
|
||||||
/// The database visitor which adds new records to the database.
|
/// The database visitor which adds new records to the database.
|
||||||
TypeDatabaseVisitor DatabaseVisitor;
|
TypeDatabaseVisitor DatabaseVisitor;
|
||||||
@ -85,4 +100,4 @@ private:
|
|||||||
} // end namespace codeview
|
} // end namespace codeview
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
|
||||||
#endif // LLVM_DEBUGINFO_CODEVIEW_RANDOMACCESSTYPEVISITOR_H
|
#endif // LLVM_DEBUGINFO_CODEVIEW_LAZYRANDOMTYPECOLLECTION_H
|
@ -20,15 +20,15 @@ namespace llvm {
|
|||||||
class ScopedPrinter;
|
class ScopedPrinter;
|
||||||
|
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
class TypeDatabase;
|
class TypeCollection;
|
||||||
|
|
||||||
/// Dumper for CodeView symbol streams found in COFF object files and PDB files.
|
/// Dumper for CodeView symbol streams found in COFF object files and PDB files.
|
||||||
class CVSymbolDumper {
|
class CVSymbolDumper {
|
||||||
public:
|
public:
|
||||||
CVSymbolDumper(ScopedPrinter &W, TypeDatabase &TypeDB,
|
CVSymbolDumper(ScopedPrinter &W, TypeCollection &Types,
|
||||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
|
std::unique_ptr<SymbolDumpDelegate> ObjDelegate,
|
||||||
bool PrintRecordBytes)
|
bool PrintRecordBytes)
|
||||||
: W(W), TypeDB(TypeDB), ObjDelegate(std::move(ObjDelegate)),
|
: W(W), Types(Types), ObjDelegate(std::move(ObjDelegate)),
|
||||||
PrintRecordBytes(PrintRecordBytes) {}
|
PrintRecordBytes(PrintRecordBytes) {}
|
||||||
|
|
||||||
/// Dumps one type record. Returns false if there was a type parsing error,
|
/// Dumps one type record. Returns false if there was a type parsing error,
|
||||||
@ -43,7 +43,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ScopedPrinter &W;
|
ScopedPrinter &W;
|
||||||
TypeDatabase &TypeDB;
|
TypeCollection &Types;
|
||||||
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
|
std::unique_ptr<SymbolDumpDelegate> ObjDelegate;
|
||||||
|
|
||||||
bool PrintRecordBytes;
|
bool PrintRecordBytes;
|
||||||
|
38
include/llvm/DebugInfo/CodeView/TypeCollection.h
Normal file
38
include/llvm/DebugInfo/CodeView/TypeCollection.h
Normal 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
|
@ -13,6 +13,7 @@
|
|||||||
#include "llvm/ADT/BitVector.h"
|
#include "llvm/ADT/BitVector.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
@ -20,7 +21,7 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
class TypeDatabase {
|
class TypeDatabase : public TypeCollection {
|
||||||
friend class RandomAccessTypeVisitor;
|
friend class RandomAccessTypeVisitor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -41,19 +42,31 @@ public:
|
|||||||
CVType &getTypeRecord(TypeIndex Index);
|
CVType &getTypeRecord(TypeIndex Index);
|
||||||
|
|
||||||
bool contains(TypeIndex Index) const;
|
bool contains(TypeIndex Index) const;
|
||||||
|
|
||||||
uint32_t size() const;
|
uint32_t size() const;
|
||||||
uint32_t capacity() const;
|
uint32_t capacity() const;
|
||||||
bool empty() 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:
|
private:
|
||||||
|
TypeIndex getAppendIndex() const;
|
||||||
|
|
||||||
void grow();
|
void grow();
|
||||||
|
void grow(TypeIndex Index);
|
||||||
|
|
||||||
BumpPtrAllocator Allocator;
|
BumpPtrAllocator Allocator;
|
||||||
|
|
||||||
uint32_t Count = 0;
|
uint32_t Count = 0;
|
||||||
|
TypeIndex LargestTypeIndex;
|
||||||
|
|
||||||
/// All user defined type records in .debug$T live in here. Type indices
|
/// 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
|
/// greater than 0x1000 are user defined. Subtract 0x1000 from the index to
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/StringSet.h"
|
#include "llvm/ADT/StringSet.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
@ -22,17 +21,20 @@ class ScopedPrinter;
|
|||||||
|
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
|
||||||
|
class TypeCollection;
|
||||||
|
|
||||||
/// Dumper for CodeView type streams found in COFF object files and PDB files.
|
/// Dumper for CodeView type streams found in COFF object files and PDB files.
|
||||||
class TypeDumpVisitor : public TypeVisitorCallbacks {
|
class TypeDumpVisitor : public TypeVisitorCallbacks {
|
||||||
public:
|
public:
|
||||||
TypeDumpVisitor(TypeDatabase &TypeDB, ScopedPrinter *W, bool PrintRecordBytes)
|
TypeDumpVisitor(TypeCollection &TpiTypes, ScopedPrinter *W,
|
||||||
: W(W), PrintRecordBytes(PrintRecordBytes), TypeDB(TypeDB) {}
|
bool PrintRecordBytes)
|
||||||
|
: W(W), PrintRecordBytes(PrintRecordBytes), TpiTypes(TpiTypes) {}
|
||||||
|
|
||||||
/// When dumping types from an IPI stream in a PDB, a type index may refer to
|
/// 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
|
/// 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,
|
/// the item database if appropriate. If ItemDB is null, it will use TypeDB,
|
||||||
/// which is correct when dumping types from an object file (/Z7).
|
/// 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;
|
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
|
/// 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
|
/// is set, then we must be dumping an item (IPI) stream. This will also
|
||||||
/// always get the appropriate DB for printing item names.
|
/// 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;
|
ScopedPrinter *W;
|
||||||
|
|
||||||
bool PrintRecordBytes = false;
|
bool PrintRecordBytes = false;
|
||||||
|
|
||||||
TypeDatabase &TypeDB;
|
TypeCollection &TpiTypes;
|
||||||
TypeDatabase *ItemDB = nullptr;
|
TypeCollection *IpiTypes = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace codeview
|
} // end namespace codeview
|
||||||
|
@ -15,8 +15,13 @@
|
|||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
|
class ScopedPrinter;
|
||||||
|
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
|
||||||
|
class TypeCollection;
|
||||||
|
|
||||||
enum class SimpleTypeKind : uint32_t {
|
enum class SimpleTypeKind : uint32_t {
|
||||||
None = 0x0000, // uncharacterized type (no type)
|
None = 0x0000, // uncharacterized type (no type)
|
||||||
Void = 0x0003, // void
|
Void = 0x0003, // void
|
||||||
@ -238,6 +243,11 @@ public:
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend inline uint32_t operator-(const TypeIndex &A, const TypeIndex &B) {
|
||||||
|
assert(A >= B);
|
||||||
|
return A.toArrayIndex() - B.toArrayIndex();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
support::ulittle32_t Index;
|
support::ulittle32_t Index;
|
||||||
};
|
};
|
||||||
@ -249,6 +259,9 @@ struct TypeIndexOffset {
|
|||||||
TypeIndex Type;
|
TypeIndex Type;
|
||||||
support::ulittle32_t Offset;
|
support::ulittle32_t Offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void printTypeIndex(ScopedPrinter &Printer, StringRef FieldName, TypeIndex TI,
|
||||||
|
TypeCollection &Types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
include/llvm/DebugInfo/CodeView/TypeTableCollection.h
Normal file
42
include/llvm/DebugInfo/CodeView/TypeTableCollection.h
Normal 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
|
@ -17,8 +17,6 @@ namespace llvm {
|
|||||||
namespace codeview {
|
namespace codeview {
|
||||||
|
|
||||||
class TypeVisitorCallbacks {
|
class TypeVisitorCallbacks {
|
||||||
friend class CVTypeVisitor;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~TypeVisitorCallbacks() = default;
|
virtual ~TypeVisitorCallbacks() = default;
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
#include "llvm/ADT/StringMap.h"
|
#include "llvm/ADT/StringMap.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "CodeViewDebug.h"
|
#include "CodeViewDebug.h"
|
||||||
#include "llvm/ADT/TinyPtrVector.h"
|
#include "llvm/ADT/TinyPtrVector.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||||
@ -23,6 +22,7 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
#include "llvm/IR/Constants.h"
|
#include "llvm/IR/Constants.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
@ -469,17 +469,21 @@ void CodeViewDebug::emitTypeInformation() {
|
|||||||
CommentPrefix += ' ';
|
CommentPrefix += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDatabase TypeDB(TypeTable.records().size());
|
TypeTableCollection Table(TypeTable.records());
|
||||||
CVTypeDumper CVTD(TypeDB);
|
Optional<TypeIndex> B = Table.getFirst();
|
||||||
TypeTable.ForEachRecord([&](TypeIndex Index, ArrayRef<uint8_t> Record) {
|
while (B) {
|
||||||
|
// This will fail if the record data is invalid.
|
||||||
|
CVType Record = Table.getType(*B);
|
||||||
|
|
||||||
if (OS.isVerboseAsm()) {
|
if (OS.isVerboseAsm()) {
|
||||||
// Emit a block comment describing the type record for readability.
|
// Emit a block comment describing the type record for readability.
|
||||||
SmallString<512> CommentBlock;
|
SmallString<512> CommentBlock;
|
||||||
raw_svector_ostream CommentOS(CommentBlock);
|
raw_svector_ostream CommentOS(CommentBlock);
|
||||||
ScopedPrinter SP(CommentOS);
|
ScopedPrinter SP(CommentOS);
|
||||||
SP.setPrefix(CommentPrefix);
|
SP.setPrefix(CommentPrefix);
|
||||||
TypeDumpVisitor TDV(TypeDB, &SP, false);
|
TypeDumpVisitor TDV(Table, &SP, false);
|
||||||
Error E = CVTD.dump(Record, TDV);
|
|
||||||
|
Error E = codeview::visitTypeRecord(Record, *B, TDV);
|
||||||
if (E) {
|
if (E) {
|
||||||
logAllUnhandledErrors(std::move(E), errs(), "error: ");
|
logAllUnhandledErrors(std::move(E), errs(), "error: ");
|
||||||
llvm_unreachable("produced malformed type record");
|
llvm_unreachable("produced malformed type record");
|
||||||
@ -489,29 +493,10 @@ void CodeViewDebug::emitTypeInformation() {
|
|||||||
// newline.
|
// newline.
|
||||||
OS.emitRawComment(
|
OS.emitRawComment(
|
||||||
CommentOS.str().drop_front(CommentPrefix.size() - 1).rtrim());
|
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(Record.str_data());
|
||||||
OS.EmitBinaryData(S);
|
B = Table.getNext(*B);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -2,10 +2,10 @@ add_llvm_library(LLVMDebugInfoCodeView
|
|||||||
CodeViewError.cpp
|
CodeViewError.cpp
|
||||||
CodeViewRecordIO.cpp
|
CodeViewRecordIO.cpp
|
||||||
CVSymbolVisitor.cpp
|
CVSymbolVisitor.cpp
|
||||||
CVTypeDumper.cpp
|
|
||||||
CVTypeVisitor.cpp
|
CVTypeVisitor.cpp
|
||||||
EnumTables.cpp
|
EnumTables.cpp
|
||||||
Formatters.cpp
|
Formatters.cpp
|
||||||
|
LazyRandomTypeCollection.cpp
|
||||||
Line.cpp
|
Line.cpp
|
||||||
ModuleDebugFileChecksumFragment.cpp
|
ModuleDebugFileChecksumFragment.cpp
|
||||||
ModuleDebugFragment.cpp
|
ModuleDebugFragment.cpp
|
||||||
@ -13,7 +13,6 @@ add_llvm_library(LLVMDebugInfoCodeView
|
|||||||
ModuleDebugFragmentVisitor.cpp
|
ModuleDebugFragmentVisitor.cpp
|
||||||
ModuleDebugInlineeLinesFragment.cpp
|
ModuleDebugInlineeLinesFragment.cpp
|
||||||
ModuleDebugLineFragment.cpp
|
ModuleDebugLineFragment.cpp
|
||||||
RandomAccessTypeVisitor.cpp
|
|
||||||
RecordSerialization.cpp
|
RecordSerialization.cpp
|
||||||
StringTable.cpp
|
StringTable.cpp
|
||||||
SymbolRecordMapping.cpp
|
SymbolRecordMapping.cpp
|
||||||
@ -22,10 +21,12 @@ add_llvm_library(LLVMDebugInfoCodeView
|
|||||||
TypeDatabase.cpp
|
TypeDatabase.cpp
|
||||||
TypeDatabaseVisitor.cpp
|
TypeDatabaseVisitor.cpp
|
||||||
TypeDumpVisitor.cpp
|
TypeDumpVisitor.cpp
|
||||||
|
TypeIndex.cpp
|
||||||
TypeRecordMapping.cpp
|
TypeRecordMapping.cpp
|
||||||
TypeSerializer.cpp
|
TypeSerializer.cpp
|
||||||
TypeStreamMerger.cpp
|
TypeStreamMerger.cpp
|
||||||
|
TypeTableCollection.cpp
|
||||||
|
|
||||||
ADDITIONAL_HEADER_DIRS
|
ADDITIONAL_HEADER_DIRS
|
||||||
${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
|
${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
|
||||||
)
|
)
|
||||||
|
@ -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());
|
|
||||||
}
|
|
@ -9,7 +9,9 @@
|
|||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
|
|
||||||
|
#include "llvm/ADT/TinyPtrVector.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
||||||
@ -22,8 +24,6 @@
|
|||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace llvm::codeview;
|
using namespace llvm::codeview;
|
||||||
|
|
||||||
CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
|
|
||||||
: Callbacks(Callbacks) {}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
|
static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
|
||||||
@ -66,6 +66,67 @@ static Expected<TypeServer2Record> deserializeTypeServerRecord(CVType &Record) {
|
|||||||
return R;
|
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) {
|
void CVTypeVisitor::addTypeServerHandler(TypeServerHandler &Handler) {
|
||||||
Handlers.push_back(&Handler);
|
Handlers.push_back(&Handler);
|
||||||
}
|
}
|
||||||
@ -144,35 +205,6 @@ Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
|
|||||||
return finishVisitation(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) {
|
Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
|
||||||
return ::visitMemberRecord(Record, Callbacks);
|
return ::visitMemberRecord(Record, Callbacks);
|
||||||
}
|
}
|
||||||
@ -194,12 +226,18 @@ Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
|
Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
|
||||||
FieldListDeserializer Deserializer(Reader);
|
Optional<TypeIndex> I = Types.getFirst();
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
while (I) {
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
CVType Type = Types.getType(*I);
|
||||||
Pipeline.addCallbackToPipeline(Callbacks);
|
if (auto EC = visitTypeRecord(Type, *I))
|
||||||
|
return EC;
|
||||||
|
I = Types.getNext(*I);
|
||||||
|
}
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
|
||||||
TypeLeafKind Leaf;
|
TypeLeafKind Leaf;
|
||||||
while (!Reader.empty()) {
|
while (!Reader.empty()) {
|
||||||
if (auto EC = Reader.readEnum(Leaf))
|
if (auto EC = Reader.readEnum(Leaf))
|
||||||
@ -207,20 +245,13 @@ Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader Reader) {
|
|||||||
|
|
||||||
CVMemberRecord Record;
|
CVMemberRecord Record;
|
||||||
Record.Kind = Leaf;
|
Record.Kind = Leaf;
|
||||||
if (auto EC = ::visitMemberRecord(Record, Pipeline))
|
if (auto EC = ::visitMemberRecord(Record, Callbacks))
|
||||||
return EC;
|
return EC;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Error::success();
|
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 {
|
struct FieldListVisitHelper {
|
||||||
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
|
FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
|
||||||
VisitorDataSource Source)
|
VisitorDataSource Source)
|
||||||
@ -241,11 +272,8 @@ struct FieldListVisitHelper {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct VisitHelper {
|
struct VisitHelper {
|
||||||
VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source,
|
VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
|
||||||
TypeServerHandler *TS)
|
|
||||||
: Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
|
: Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
|
||||||
if (TS)
|
|
||||||
Visitor.addTypeServerHandler(*TS);
|
|
||||||
if (Source == VDS_BytesPresent) {
|
if (Source == VDS_BytesPresent) {
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
Pipeline.addCallbackToPipeline(Callbacks);
|
Pipeline.addCallbackToPipeline(Callbacks);
|
||||||
@ -262,29 +290,57 @@ Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
|
|||||||
TypeVisitorCallbacks &Callbacks,
|
TypeVisitorCallbacks &Callbacks,
|
||||||
VisitorDataSource Source,
|
VisitorDataSource Source,
|
||||||
TypeServerHandler *TS) {
|
TypeServerHandler *TS) {
|
||||||
VisitHelper Helper(Callbacks, Source, TS);
|
VisitHelper V(Callbacks, Source);
|
||||||
return Helper.Visitor.visitTypeRecord(Record, Index);
|
if (TS)
|
||||||
|
V.Visitor.addTypeServerHandler(*TS);
|
||||||
|
return V.Visitor.visitTypeRecord(Record, Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error llvm::codeview::visitTypeRecord(CVType &Record,
|
Error llvm::codeview::visitTypeRecord(CVType &Record,
|
||||||
TypeVisitorCallbacks &Callbacks,
|
TypeVisitorCallbacks &Callbacks,
|
||||||
VisitorDataSource Source,
|
VisitorDataSource Source,
|
||||||
TypeServerHandler *TS) {
|
TypeServerHandler *TS) {
|
||||||
VisitHelper Helper(Callbacks, Source, TS);
|
VisitHelper V(Callbacks, Source);
|
||||||
return Helper.Visitor.visitTypeRecord(Record);
|
if (TS)
|
||||||
|
V.Visitor.addTypeServerHandler(*TS);
|
||||||
|
return V.Visitor.visitTypeRecord(Record);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
|
||||||
TypeVisitorCallbacks &Callbacks) {
|
TypeVisitorCallbacks &Callbacks,
|
||||||
CVTypeVisitor Visitor(Callbacks);
|
TypeServerHandler *TS) {
|
||||||
return Visitor.visitFieldListMemberStream(FieldList);
|
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,
|
Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
|
||||||
TypeVisitorCallbacks &Callbacks,
|
TypeVisitorCallbacks &Callbacks,
|
||||||
VisitorDataSource Source) {
|
VisitorDataSource Source) {
|
||||||
FieldListVisitHelper Helper(Callbacks, Record.Data, Source);
|
FieldListVisitHelper V(Callbacks, Record.Data, Source);
|
||||||
return Helper.Visitor.visitMemberRecord(Record);
|
return V.Visitor.visitMemberRecord(Record);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
||||||
@ -296,16 +352,8 @@ Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
|
|||||||
return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
|
return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
|
Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
|
||||||
TypeVisitorCallbacks &Callbacks,
|
TypeVisitorCallbacks &Callbacks) {
|
||||||
TypeServerHandler *TS) {
|
FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
|
||||||
VisitHelper Helper(Callbacks, VDS_BytesPresent, TS);
|
return V.Visitor.visitFieldListMemberStream(V.Reader);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
229
lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
Normal file
229
lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
Normal 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();
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
@ -11,7 +11,6 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||||
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
#include "llvm/DebugInfo/CodeView/StringTable.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||||
@ -33,9 +32,9 @@ namespace {
|
|||||||
/// the visitor out of SymbolDumper.h.
|
/// the visitor out of SymbolDumper.h.
|
||||||
class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
|
class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
|
||||||
public:
|
public:
|
||||||
CVSymbolDumperImpl(TypeDatabase &TypeDB, SymbolDumpDelegate *ObjDelegate,
|
CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate,
|
||||||
ScopedPrinter &W, bool PrintRecordBytes)
|
ScopedPrinter &W, bool PrintRecordBytes)
|
||||||
: TypeDB(TypeDB), ObjDelegate(ObjDelegate), W(W),
|
: Types(Types), ObjDelegate(ObjDelegate), W(W),
|
||||||
PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
|
PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
|
||||||
|
|
||||||
/// CVSymbolVisitor overrides.
|
/// CVSymbolVisitor overrides.
|
||||||
@ -54,7 +53,7 @@ private:
|
|||||||
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
|
void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
|
||||||
void printTypeIndex(StringRef FieldName, TypeIndex TI);
|
void printTypeIndex(StringRef FieldName, TypeIndex TI);
|
||||||
|
|
||||||
TypeDatabase &TypeDB;
|
TypeCollection &Types;
|
||||||
SymbolDumpDelegate *ObjDelegate;
|
SymbolDumpDelegate *ObjDelegate;
|
||||||
ScopedPrinter &W;
|
ScopedPrinter &W;
|
||||||
|
|
||||||
@ -83,7 +82,7 @@ void CVSymbolDumperImpl::printLocalVariableAddrGap(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
|
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 CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
|
||||||
@ -670,7 +669,7 @@ Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
|
|||||||
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
||||||
SymbolVisitorCallbackPipeline Pipeline;
|
SymbolVisitorCallbackPipeline Pipeline;
|
||||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
SymbolDeserializer Deserializer(ObjDelegate.get());
|
||||||
CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
|
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||||
|
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
Pipeline.addCallbackToPipeline(Dumper);
|
Pipeline.addCallbackToPipeline(Dumper);
|
||||||
@ -681,7 +680,7 @@ Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
|
|||||||
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
|
Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
|
||||||
SymbolVisitorCallbackPipeline Pipeline;
|
SymbolVisitorCallbackPipeline Pipeline;
|
||||||
SymbolDeserializer Deserializer(ObjDelegate.get());
|
SymbolDeserializer Deserializer(ObjDelegate.get());
|
||||||
CVSymbolDumperImpl Dumper(TypeDB, ObjDelegate.get(), W, PrintRecordBytes);
|
CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, PrintRecordBytes);
|
||||||
|
|
||||||
Pipeline.addCallbackToPipeline(Deserializer);
|
Pipeline.addCallbackToPipeline(Deserializer);
|
||||||
Pipeline.addCallbackToPipeline(Dumper);
|
Pipeline.addCallbackToPipeline(Dumper);
|
||||||
|
@ -72,16 +72,20 @@ TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) {
|
TypeIndex TypeDatabase::appendType(StringRef Name, const CVType &Data) {
|
||||||
TypeIndex TI;
|
LargestTypeIndex = getAppendIndex();
|
||||||
TI = getAppendIndex();
|
if (LargestTypeIndex.toArrayIndex() >= capacity())
|
||||||
if (TI.toArrayIndex() >= capacity())
|
|
||||||
grow();
|
grow();
|
||||||
recordType(Name, TI, Data);
|
recordType(Name, LargestTypeIndex, Data);
|
||||||
return TI;
|
return LargestTypeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeDatabase::recordType(StringRef Name, TypeIndex Index,
|
void TypeDatabase::recordType(StringRef Name, TypeIndex Index,
|
||||||
const CVType &Data) {
|
const CVType &Data) {
|
||||||
|
LargestTypeIndex = empty() ? Index : std::max(Index, LargestTypeIndex);
|
||||||
|
|
||||||
|
if (LargestTypeIndex.toArrayIndex() >= capacity())
|
||||||
|
grow(Index);
|
||||||
|
|
||||||
uint32_t AI = Index.toArrayIndex();
|
uint32_t AI = Index.toArrayIndex();
|
||||||
|
|
||||||
assert(!contains(Index));
|
assert(!contains(Index));
|
||||||
@ -144,19 +148,66 @@ uint32_t TypeDatabase::size() const { return Count; }
|
|||||||
|
|
||||||
uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); }
|
uint32_t TypeDatabase::capacity() const { return TypeRecords.size(); }
|
||||||
|
|
||||||
void TypeDatabase::grow() {
|
CVType TypeDatabase::getType(TypeIndex Index) { return getTypeRecord(Index); }
|
||||||
TypeRecords.emplace_back();
|
|
||||||
CVUDTNames.emplace_back();
|
StringRef TypeDatabase::getTypeName(TypeIndex Index) {
|
||||||
ValidRecords.resize(ValidRecords.size() + 1);
|
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; }
|
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 {
|
TypeIndex TypeDatabase::getAppendIndex() const {
|
||||||
if (empty())
|
if (empty())
|
||||||
return TypeIndex::fromArrayIndex(0);
|
return TypeIndex::fromArrayIndex(0);
|
||||||
|
|
||||||
int Index = ValidRecords.find_last();
|
return LargestTypeIndex + 1;
|
||||||
assert(Index != -1);
|
}
|
||||||
return TypeIndex::fromArrayIndex(Index) + 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);
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,13 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||||
|
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/Formatters.h"
|
#include "llvm/DebugInfo/CodeView/Formatters.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
|
||||||
#include "llvm/Support/BinaryByteStream.h"
|
#include "llvm/Support/BinaryByteStream.h"
|
||||||
#include "llvm/Support/FormatVariadic.h"
|
#include "llvm/Support/FormatVariadic.h"
|
||||||
#include "llvm/Support/ScopedPrinter.h"
|
#include "llvm/Support/ScopedPrinter.h"
|
||||||
@ -165,16 +163,15 @@ static StringRef getLeafTypeName(TypeLeafKind LT) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
|
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 {
|
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) {
|
Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
|
||||||
TypeIndex TI = getSourceDB().getAppendIndex();
|
return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
|
||||||
return visitTypeBegin(Record, TI);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
|
Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
|
||||||
@ -245,7 +242,7 @@ Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
|
|||||||
W->printNumber("NumStrings", Size);
|
W->printNumber("NumStrings", Size);
|
||||||
ListScope Arguments(*W, "Strings");
|
ListScope Arguments(*W, "Strings");
|
||||||
for (uint32_t I = 0; I < Size; ++I) {
|
for (uint32_t I = 0; I < Size; ++I) {
|
||||||
printTypeIndex("String", Indices[I]);
|
printItemIndex("String", Indices[I]);
|
||||||
}
|
}
|
||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
27
lib/DebugInfo/CodeView/TypeIndex.cpp
Normal file
27
lib/DebugInfo/CodeView/TypeIndex.cpp
Normal 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());
|
||||||
|
}
|
@ -11,11 +11,9 @@
|
|||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
#include "llvm/Support/Error.h"
|
#include "llvm/Support/Error.h"
|
||||||
#include "llvm/Support/ScopedPrinter.h"
|
#include "llvm/Support/ScopedPrinter.h"
|
||||||
|
83
lib/DebugInfo/CodeView/TypeTableCollection.cpp
Normal file
83
lib/DebugInfo/CodeView/TypeTableCollection.cpp
Normal 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();
|
||||||
|
}
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
|
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
|
||||||
|
|
||||||
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
|
||||||
#include "llvm/DebugInfo/PDB/GenericError.h"
|
#include "llvm/DebugInfo/PDB/GenericError.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
|
|
||||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||||
#include "llvm/ADT/iterator_range.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/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
|
||||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
|
#include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h"
|
||||||
|
@ -326,7 +326,7 @@
|
|||||||
; EMPTY-NEXT: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
|
; EMPTY-NEXT: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
|
||||||
; EMPTY-NEXT: NumStrings: 1
|
; EMPTY-NEXT: NumStrings: 1
|
||||||
; EMPTY-NEXT: Strings [
|
; 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: }
|
; EMPTY-NEXT: }
|
||||||
; EMPTY-NEXT: Bytes (
|
; EMPTY-NEXT: Bytes (
|
||||||
@ -1253,7 +1253,7 @@
|
|||||||
; ALL: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
|
; ALL: TypeLeafKind: LF_SUBSTR_LIST (0x1604)
|
||||||
; ALL: NumStrings: 1
|
; ALL: NumStrings: 1
|
||||||
; ALL: Strings [
|
; 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: }
|
; ALL: }
|
||||||
; ALL: }
|
; ALL: }
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
|
@ -29,15 +29,15 @@ static StringRef getLeafName(TypeLeafKind K) {
|
|||||||
return StringRef();
|
return StringRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
|
CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
|
||||||
ScopedPrinter *W)
|
ScopedPrinter *W)
|
||||||
: CompactTypeDumpVisitor(TypeDB, TypeIndex(TypeIndex::FirstNonSimpleIndex),
|
: CompactTypeDumpVisitor(Types, TypeIndex(TypeIndex::FirstNonSimpleIndex),
|
||||||
W) {}
|
W) {}
|
||||||
|
|
||||||
CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeDatabase &TypeDB,
|
CompactTypeDumpVisitor::CompactTypeDumpVisitor(TypeCollection &Types,
|
||||||
TypeIndex FirstTI,
|
TypeIndex FirstTI,
|
||||||
ScopedPrinter *W)
|
ScopedPrinter *W)
|
||||||
: W(W), TI(FirstTI), Offset(0), TypeDB(TypeDB) {}
|
: W(W), TI(FirstTI), Offset(0), Types(Types) {}
|
||||||
|
|
||||||
Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
|
Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
|
||||||
return Error::success();
|
return Error::success();
|
||||||
@ -46,7 +46,7 @@ Error CompactTypeDumpVisitor::visitTypeBegin(CVType &Record) {
|
|||||||
Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
|
Error CompactTypeDumpVisitor::visitTypeEnd(CVType &Record) {
|
||||||
uint32_t I = TI.getIndex();
|
uint32_t I = TI.getIndex();
|
||||||
StringRef Leaf = getLeafName(Record.Type);
|
StringRef Leaf = getLeafName(Record.Type);
|
||||||
StringRef Name = TypeDB.getTypeName(TI);
|
StringRef Name = Types.getTypeName(TI);
|
||||||
W->printString(
|
W->printString(
|
||||||
llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I,
|
llvm::formatv("Index: {0:x} ({1:N} bytes, offset {2:N}) {3} \"{4}\"", I,
|
||||||
Record.length(), Offset, Leaf, Name)
|
Record.length(), Offset, Leaf, Name)
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
namespace llvm {
|
namespace llvm {
|
||||||
class ScopedPrinter;
|
class ScopedPrinter;
|
||||||
namespace codeview {
|
namespace codeview {
|
||||||
class TypeDatabase;
|
class TypeCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
@ -26,8 +26,8 @@ namespace pdb {
|
|||||||
/// Dumps records on a single line, and ignores member records.
|
/// Dumps records on a single line, and ignores member records.
|
||||||
class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
|
class CompactTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
|
||||||
public:
|
public:
|
||||||
CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB, ScopedPrinter *W);
|
CompactTypeDumpVisitor(codeview::TypeCollection &Types, ScopedPrinter *W);
|
||||||
CompactTypeDumpVisitor(codeview::TypeDatabase &TypeDB,
|
CompactTypeDumpVisitor(codeview::TypeCollection &Types,
|
||||||
codeview::TypeIndex FirstTI, ScopedPrinter *W);
|
codeview::TypeIndex FirstTI, ScopedPrinter *W);
|
||||||
|
|
||||||
/// Paired begin/end actions for all types. Receives all record data,
|
/// Paired begin/end actions for all types. Receives all record data,
|
||||||
@ -40,7 +40,7 @@ private:
|
|||||||
|
|
||||||
codeview::TypeIndex TI;
|
codeview::TypeIndex TI;
|
||||||
uint32_t Offset;
|
uint32_t Offset;
|
||||||
codeview::TypeDatabase &TypeDB;
|
codeview::TypeCollection &Types;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace pdb
|
} // end namespace pdb
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
#include "StreamUtil.h"
|
#include "StreamUtil.h"
|
||||||
#include "llvm-pdbdump.h"
|
#include "llvm-pdbdump.h"
|
||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h"
|
||||||
@ -25,7 +25,6 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugUnknownFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDatabaseVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||||
@ -84,7 +83,7 @@ struct PageStats {
|
|||||||
|
|
||||||
class C13RawVisitor : public C13DebugFragmentVisitor {
|
class C13RawVisitor : public C13DebugFragmentVisitor {
|
||||||
public:
|
public:
|
||||||
C13RawVisitor(ScopedPrinter &P, PDBFile &F, TypeDatabase &IPI)
|
C13RawVisitor(ScopedPrinter &P, PDBFile &F, LazyRandomTypeCollection &IPI)
|
||||||
: C13DebugFragmentVisitor(F), P(P), IPI(IPI) {}
|
: C13DebugFragmentVisitor(F), P(P), IPI(IPI) {}
|
||||||
|
|
||||||
Error handleLines() override {
|
Error handleLines() override {
|
||||||
@ -160,7 +159,7 @@ public:
|
|||||||
if (auto EC = printFileName("FileName", L.Header->FileID))
|
if (auto EC = printFileName("FileName", L.Header->FileID))
|
||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
if (auto EC = dumpTypeRecord("Function", IPI, L.Header->Inlinee))
|
if (auto EC = dumpTypeRecord("Function", L.Header->Inlinee))
|
||||||
return EC;
|
return EC;
|
||||||
P.printNumber("SourceLine", L.Header->SourceLineNum);
|
P.printNumber("SourceLine", L.Header->SourceLineNum);
|
||||||
if (IL.hasExtraFiles()) {
|
if (IL.hasExtraFiles()) {
|
||||||
@ -176,11 +175,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error dumpTypeRecord(StringRef Label, TypeDatabase &DB, TypeIndex Index) {
|
Error dumpTypeRecord(StringRef Label, TypeIndex Index) {
|
||||||
CompactTypeDumpVisitor CTDV(DB, Index, &P);
|
CompactTypeDumpVisitor CTDV(IPI, Index, &P);
|
||||||
DictScope D(P, Label);
|
DictScope D(P, Label);
|
||||||
if (DB.contains(Index)) {
|
if (IPI.contains(Index)) {
|
||||||
CVType &Type = DB.getTypeRecord(Index);
|
CVType Type = IPI.getType(Index);
|
||||||
if (auto EC = codeview::visitTypeRecord(Type, CTDV))
|
if (auto EC = codeview::visitTypeRecord(Type, CTDV))
|
||||||
return EC;
|
return EC;
|
||||||
} else {
|
} else {
|
||||||
@ -199,7 +198,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScopedPrinter &P;
|
ScopedPrinter &P;
|
||||||
TypeDatabase &IPI;
|
LazyRandomTypeCollection &IPI;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,14 +608,19 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
|||||||
VerLabel = "IPI Version";
|
VerLabel = "IPI Version";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DumpRecordBytes && !DumpRecords && !DumpTpiHash)
|
|
||||||
return Error::success();
|
|
||||||
|
|
||||||
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
|
auto Tpi = (StreamIdx == StreamTPI) ? File.getPDBTpiStream()
|
||||||
: File.getPDBIpiStream();
|
: File.getPDBIpiStream();
|
||||||
if (!Tpi)
|
if (!Tpi)
|
||||||
return Tpi.takeError();
|
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<DictScope> StreamScope;
|
||||||
std::unique_ptr<ListScope> RecordScope;
|
std::unique_ptr<ListScope> RecordScope;
|
||||||
|
|
||||||
@ -624,25 +628,19 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
|||||||
P.printNumber(VerLabel, Tpi->getTpiVersion());
|
P.printNumber(VerLabel, Tpi->getTpiVersion());
|
||||||
P.printNumber("Record count", Tpi->getNumTypeRecords());
|
P.printNumber("Record count", Tpi->getNumTypeRecords());
|
||||||
|
|
||||||
Optional<TypeDatabase> &StreamDB = (StreamIdx == StreamTPI) ? TypeDB : ItemDB;
|
|
||||||
|
|
||||||
std::vector<std::unique_ptr<TypeVisitorCallbacks>> Visitors;
|
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 we're in dump mode, add a dumper with the appropriate detail level.
|
||||||
if (DumpRecords) {
|
if (DumpRecords) {
|
||||||
std::unique_ptr<TypeVisitorCallbacks> Dumper;
|
std::unique_ptr<TypeVisitorCallbacks> Dumper;
|
||||||
if (opts::raw::CompactRecords)
|
if (opts::raw::CompactRecords)
|
||||||
Dumper = make_unique<CompactTypeDumpVisitor>(*StreamDB, &P);
|
Dumper = make_unique<CompactTypeDumpVisitor>(Types, &P);
|
||||||
else {
|
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)
|
if (StreamIdx == StreamIPI)
|
||||||
X->setItemDB(*ItemDB);
|
X->setIpiTypes(*IpiTypes);
|
||||||
Dumper = std::move(X);
|
Dumper = std::move(X);
|
||||||
}
|
}
|
||||||
Visitors.push_back(std::move(Dumper));
|
Visitors.push_back(std::move(Dumper));
|
||||||
@ -660,23 +658,18 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
|||||||
if (DumpRecords || DumpRecordBytes)
|
if (DumpRecords || DumpRecordBytes)
|
||||||
RecordScope = llvm::make_unique<ListScope>(P, "Records");
|
RecordScope = llvm::make_unique<ListScope>(P, "Records");
|
||||||
|
|
||||||
bool HadError = false;
|
Optional<TypeIndex> I = Types.getFirst();
|
||||||
|
while (I) {
|
||||||
TypeIndex T(TypeIndex::FirstNonSimpleIndex);
|
|
||||||
for (auto Type : Tpi->types(&HadError)) {
|
|
||||||
std::unique_ptr<DictScope> OneRecordScope;
|
std::unique_ptr<DictScope> OneRecordScope;
|
||||||
|
|
||||||
if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
|
if ((DumpRecords || DumpRecordBytes) && !opts::raw::CompactRecords)
|
||||||
OneRecordScope = llvm::make_unique<DictScope>(P, "");
|
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;
|
return EC;
|
||||||
|
I = Types.getNext(*I);
|
||||||
++T;
|
|
||||||
}
|
}
|
||||||
if (HadError)
|
|
||||||
return make_error<RawError>(raw_error_code::corrupt_file,
|
|
||||||
"TPI stream contained corrupt record");
|
|
||||||
|
|
||||||
if (DumpTpiHash) {
|
if (DumpTpiHash) {
|
||||||
DictScope DD(P, "Hash");
|
DictScope DD(P, "Hash");
|
||||||
@ -711,35 +704,26 @@ Error LLVMOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
|||||||
return Error::success();
|
return Error::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LLVMOutputStyle::buildTypeDatabase(uint32_t SN) {
|
Expected<codeview::LazyRandomTypeCollection &>
|
||||||
assert(SN == StreamIPI || SN == StreamTPI);
|
LLVMOutputStyle::initializeTypeDatabase(uint32_t SN) {
|
||||||
|
auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
|
||||||
auto &DB = (SN == StreamIPI) ? ItemDB : TypeDB;
|
|
||||||
|
|
||||||
if (DB.hasValue())
|
|
||||||
return Error::success();
|
|
||||||
|
|
||||||
auto Tpi =
|
auto Tpi =
|
||||||
(SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
|
(SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
|
||||||
|
|
||||||
if (!Tpi)
|
if (!Tpi)
|
||||||
return Tpi.takeError();
|
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);
|
return *TypeCollection;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error LLVMOutputStyle::dumpDbiStream() {
|
Error LLVMOutputStyle::dumpDbiStream() {
|
||||||
@ -814,11 +798,13 @@ Error LLVMOutputStyle::dumpDbiStream() {
|
|||||||
return EC;
|
return EC;
|
||||||
|
|
||||||
if (ShouldDumpSymbols) {
|
if (ShouldDumpSymbols) {
|
||||||
if (auto EC = buildTypeDatabase(StreamTPI))
|
auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
|
||||||
return EC;
|
if (!ExpectedTypes)
|
||||||
|
return ExpectedTypes.takeError();
|
||||||
|
auto &Types = *ExpectedTypes;
|
||||||
|
|
||||||
ListScope SS(P, "Symbols");
|
ListScope SS(P, "Symbols");
|
||||||
codeview::CVSymbolDumper SD(P, *TypeDB, nullptr, false);
|
codeview::CVSymbolDumper SD(P, Types, nullptr, false);
|
||||||
bool HadError = false;
|
bool HadError = false;
|
||||||
for (auto S : ModS.symbols(&HadError)) {
|
for (auto S : ModS.symbols(&HadError)) {
|
||||||
DictScope LL(P, "");
|
DictScope LL(P, "");
|
||||||
@ -839,10 +825,11 @@ Error LLVMOutputStyle::dumpDbiStream() {
|
|||||||
}
|
}
|
||||||
if (opts::raw::DumpLineInfo) {
|
if (opts::raw::DumpLineInfo) {
|
||||||
ListScope SS(P, "LineInfo");
|
ListScope SS(P, "LineInfo");
|
||||||
if (auto EC = buildTypeDatabase(StreamIPI))
|
auto ExpectedTypes = initializeTypeDatabase(StreamIPI);
|
||||||
return EC;
|
if (!ExpectedTypes)
|
||||||
|
return ExpectedTypes.takeError();
|
||||||
C13RawVisitor V(P, File, *ItemDB);
|
auto &IpiItems = *ExpectedTypes;
|
||||||
|
C13RawVisitor V(P, File, IpiItems);
|
||||||
if (auto EC = codeview::visitModuleDebugFragments(
|
if (auto EC = codeview::visitModuleDebugFragments(
|
||||||
ModS.linesAndChecksums(), V))
|
ModS.linesAndChecksums(), V))
|
||||||
return EC;
|
return EC;
|
||||||
@ -960,10 +947,12 @@ Error LLVMOutputStyle::dumpPublicsStream() {
|
|||||||
P.printList("Section Offsets", Publics->getSectionOffsets(),
|
P.printList("Section Offsets", Publics->getSectionOffsets(),
|
||||||
printSectionOffset);
|
printSectionOffset);
|
||||||
ListScope L(P, "Symbols");
|
ListScope L(P, "Symbols");
|
||||||
if (auto EC = buildTypeDatabase(StreamTPI))
|
auto ExpectedTypes = initializeTypeDatabase(StreamTPI);
|
||||||
return EC;
|
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;
|
bool HadError = false;
|
||||||
for (auto S : Publics->getSymbols(&HadError)) {
|
for (auto S : Publics->getSymbols(&HadError)) {
|
||||||
DictScope DD(P, "");
|
DictScope DD(P, "");
|
||||||
|
@ -21,6 +21,11 @@
|
|||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class BitVector;
|
class BitVector;
|
||||||
|
|
||||||
|
namespace codeview {
|
||||||
|
class LazyRandomTypeCollection;
|
||||||
|
}
|
||||||
|
|
||||||
namespace pdb {
|
namespace pdb {
|
||||||
class LLVMOutputStyle : public OutputStyle {
|
class LLVMOutputStyle : public OutputStyle {
|
||||||
public:
|
public:
|
||||||
@ -29,7 +34,8 @@ public:
|
|||||||
Error dump() override;
|
Error dump() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error buildTypeDatabase(uint32_t SN);
|
Expected<codeview::LazyRandomTypeCollection &>
|
||||||
|
initializeTypeDatabase(uint32_t SN);
|
||||||
|
|
||||||
Error dumpFileHeaders();
|
Error dumpFileHeaders();
|
||||||
Error dumpStreamSummary();
|
Error dumpStreamSummary();
|
||||||
@ -54,8 +60,8 @@ private:
|
|||||||
|
|
||||||
PDBFile &File;
|
PDBFile &File;
|
||||||
ScopedPrinter P;
|
ScopedPrinter P;
|
||||||
Optional<codeview::TypeDatabase> TypeDB;
|
std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
|
||||||
Optional<codeview::TypeDatabase> ItemDB;
|
std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
|
||||||
SmallVector<std::string, 32> StreamPurposes;
|
SmallVector<std::string, 32> StreamPurposes;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
|
#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||||
@ -371,7 +370,6 @@ void MappingContextTraits<PdbInlineeInfo, SerializationContext>::mapping(
|
|||||||
void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
|
void MappingContextTraits<PdbTpiRecord, pdb::yaml::SerializationContext>::
|
||||||
mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
|
mapping(IO &IO, pdb::yaml::PdbTpiRecord &Obj,
|
||||||
pdb::yaml::SerializationContext &Context) {
|
pdb::yaml::SerializationContext &Context) {
|
||||||
|
|
||||||
if (IO.outputting()) {
|
if (IO.outputting()) {
|
||||||
// For PDB to Yaml, deserialize into a high level record type, then dump it.
|
// For PDB to Yaml, deserialize into a high level record type, then dump it.
|
||||||
consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper));
|
consumeError(codeview::visitTypeRecord(Obj.Record, Context.Dumper));
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
#include "OutputStyle.h"
|
#include "OutputStyle.h"
|
||||||
#include "PdbYaml.h"
|
#include "PdbYaml.h"
|
||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeDumper.h"
|
|
||||||
#include "llvm/Support/ScopedPrinter.h"
|
#include "llvm/Support/ScopedPrinter.h"
|
||||||
#include "llvm/Support/YAMLTraits.h"
|
#include "llvm/Support/YAMLTraits.h"
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/StringExtras.h"
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/Config/config.h"
|
#include "llvm/Config/config.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugLineFragment.h"
|
||||||
|
@ -22,8 +22,9 @@
|
|||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/StringExtras.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/CodeView.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugFileChecksumFragment.h"
|
||||||
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
#include "llvm/DebugInfo/CodeView/ModuleDebugInlineeLinesFragment.h"
|
||||||
@ -34,11 +35,13 @@
|
|||||||
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
||||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
||||||
|
#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
|
||||||
#include "llvm/Object/COFF.h"
|
#include "llvm/Object/COFF.h"
|
||||||
#include "llvm/Object/ObjectFile.h"
|
#include "llvm/Object/ObjectFile.h"
|
||||||
#include "llvm/Support/BinaryStreamReader.h"
|
#include "llvm/Support/BinaryStreamReader.h"
|
||||||
@ -70,7 +73,7 @@ class COFFDumper : public ObjDumper {
|
|||||||
public:
|
public:
|
||||||
friend class COFFObjectDumpDelegate;
|
friend class COFFObjectDumpDelegate;
|
||||||
COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer)
|
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 printFileHeaders() override;
|
||||||
void printSections() override;
|
void printSections() override;
|
||||||
@ -106,7 +109,7 @@ private:
|
|||||||
void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
|
void printFileNameForOffset(StringRef Label, uint32_t FileOffset);
|
||||||
void printTypeIndex(StringRef FieldName, TypeIndex TI) {
|
void printTypeIndex(StringRef FieldName, TypeIndex TI) {
|
||||||
// Forward to CVTypeDumper for simplicity.
|
// Forward to CVTypeDumper for simplicity.
|
||||||
CVTypeDumper::printTypeIndex(Writer, FieldName, TI, TypeDB);
|
codeview::printTypeIndex(Writer, FieldName, TI, Types);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printCodeViewSymbolsSubsection(StringRef Subsection,
|
void printCodeViewSymbolsSubsection(StringRef Subsection,
|
||||||
@ -159,7 +162,8 @@ private:
|
|||||||
StringTableRef CVStringTable;
|
StringTableRef CVStringTable;
|
||||||
|
|
||||||
ScopedPrinter &Writer;
|
ScopedPrinter &Writer;
|
||||||
TypeDatabase TypeDB;
|
BinaryByteStream TypeContents;
|
||||||
|
LazyRandomTypeCollection Types;
|
||||||
};
|
};
|
||||||
|
|
||||||
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
|
class COFFObjectDumpDelegate : public SymbolDumpDelegate {
|
||||||
@ -975,9 +979,7 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
|
|||||||
Subsection.bytes_end());
|
Subsection.bytes_end());
|
||||||
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
auto CODD = llvm::make_unique<COFFObjectDumpDelegate>(*this, Section, Obj,
|
||||||
SectionContents);
|
SectionContents);
|
||||||
|
CVSymbolDumper CVSD(W, Types, std::move(CODD), opts::CodeViewSubsectionBytes);
|
||||||
CVSymbolDumper CVSD(W, TypeDB, std::move(CODD),
|
|
||||||
opts::CodeViewSubsectionBytes);
|
|
||||||
CVSymbolArray Symbols;
|
CVSymbolArray Symbols;
|
||||||
BinaryStreamReader Reader(BinaryData, llvm::support::little);
|
BinaryStreamReader Reader(BinaryData, llvm::support::little);
|
||||||
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
|
if (auto EC = Reader.readArray(Symbols, Reader.getLength())) {
|
||||||
@ -1094,12 +1096,11 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
|
|||||||
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
if (Magic != COFF::DEBUG_SECTION_MAGIC)
|
||||||
return error(object_error::parse_failed);
|
return error(object_error::parse_failed);
|
||||||
|
|
||||||
CVTypeDumper CVTD(TypeDB);
|
Types.reset(Data);
|
||||||
TypeDumpVisitor TDV(TypeDB, &W, opts::CodeViewSubsectionBytes);
|
|
||||||
if (auto EC = CVTD.dump({Data.bytes_begin(), Data.bytes_end()}, TDV)) {
|
TypeDumpVisitor TDV(Types, &W, opts::CodeViewSubsectionBytes);
|
||||||
W.flush();
|
error(codeview::visitTypeStream(Types, TDV));
|
||||||
error(llvm::errorToErrorCode(std::move(EC)));
|
W.flush();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void COFFDumper::printSections() {
|
void COFFDumper::printSections() {
|
||||||
@ -1639,35 +1640,22 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
|
|||||||
TypeBuf.append(Record.begin(), Record.end());
|
TypeBuf.append(Record.begin(), Record.end());
|
||||||
});
|
});
|
||||||
|
|
||||||
TypeDatabase TypeDB(CVTypes.records().size());
|
TypeTableCollection TpiTypes(CVTypes.records());
|
||||||
{
|
{
|
||||||
ListScope S(Writer, "MergedTypeStream");
|
ListScope S(Writer, "MergedTypeStream");
|
||||||
CVTypeDumper CVTD(TypeDB);
|
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
|
||||||
TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
|
error(codeview::visitTypeStream(TpiTypes, TDV));
|
||||||
if (auto EC = CVTD.dump(
|
Writer.flush();
|
||||||
{TypeBuf.str().bytes_begin(), TypeBuf.str().bytes_end()}, TDV)) {
|
|
||||||
Writer.flush();
|
|
||||||
error(std::move(EC));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten the id stream and print it next. The ID stream refers to names from
|
// Flatten the id stream and print it next. The ID stream refers to names from
|
||||||
// the type stream.
|
// the type stream.
|
||||||
SmallString<0> IDBuf;
|
TypeTableCollection IpiTypes(IDTable.records());
|
||||||
IDTable.ForEachRecord([&](TypeIndex TI, ArrayRef<uint8_t> Record) {
|
|
||||||
IDBuf.append(Record.begin(), Record.end());
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
{
|
||||||
ListScope S(Writer, "MergedIDStream");
|
ListScope S(Writer, "MergedIDStream");
|
||||||
TypeDatabase IDDB(IDTable.records().size());
|
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
|
||||||
CVTypeDumper CVTD(IDDB);
|
TDV.setIpiTypes(IpiTypes);
|
||||||
TypeDumpVisitor TDV(TypeDB, &Writer, opts::CodeViewSubsectionBytes);
|
error(codeview::visitTypeStream(IpiTypes, TDV));
|
||||||
TDV.setItemDB(IDDB);
|
Writer.flush();
|
||||||
if (auto EC = CVTD.dump(
|
|
||||||
{IDBuf.str().bytes_begin(), IDBuf.str().bytes_end()}, TDV)) {
|
|
||||||
Writer.flush();
|
|
||||||
error(std::move(EC));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,14 +11,12 @@
|
|||||||
|
|
||||||
#include "llvm/ADT/SmallBitVector.h"
|
#include "llvm/ADT/SmallBitVector.h"
|
||||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||||
#include "llvm/DebugInfo/CodeView/RandomAccessTypeVisitor.h"
|
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
|
#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
#include "llvm/DebugInfo/CodeView/TypeSerializer.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
#include "llvm/DebugInfo/CodeView/TypeServerHandler.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
#include "llvm/DebugInfo/CodeView/TypeTableBuilder.h"
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
|
||||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||||
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
|
||||||
#include "llvm/Support/Allocator.h"
|
#include "llvm/Support/Allocator.h"
|
||||||
@ -130,20 +128,16 @@ public:
|
|||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
TestState = llvm::make_unique<PerTestState>();
|
TestState = llvm::make_unique<PerTestState>();
|
||||||
|
|
||||||
TestState->Pipeline.addCallbackToPipeline(TestState->Deserializer);
|
|
||||||
TestState->Pipeline.addCallbackToPipeline(TestState->Callbacks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override { TestState.reset(); }
|
void TearDown() override { TestState.reset(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool ValidateDatabaseRecord(const RandomAccessTypeVisitor &Visitor,
|
bool ValidateDatabaseRecord(LazyRandomTypeCollection &Types, uint32_t Index) {
|
||||||
uint32_t Index) {
|
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(Index);
|
TypeIndex TI = TypeIndex::fromArrayIndex(Index);
|
||||||
if (!Visitor.database().contains(TI))
|
if (!Types.contains(TI))
|
||||||
return false;
|
return false;
|
||||||
if (GlobalState->TypeVector[Index] != Visitor.database().getTypeRecord(TI))
|
if (GlobalState->TypeVector[Index] != Types.getType(TI))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -184,8 +178,6 @@ protected:
|
|||||||
struct PerTestState {
|
struct PerTestState {
|
||||||
FixedStreamArray<TypeIndexOffset> Offsets;
|
FixedStreamArray<TypeIndexOffset> Offsets;
|
||||||
|
|
||||||
TypeVisitorCallbackPipeline Pipeline;
|
|
||||||
TypeDeserializer Deserializer;
|
|
||||||
MockCallbacks Callbacks;
|
MockCallbacks Callbacks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -218,21 +210,22 @@ std::unique_ptr<RandomAccessVisitorTest::GlobalTestState>
|
|||||||
|
|
||||||
TEST_F(RandomAccessVisitorTest, MultipleVisits) {
|
TEST_F(RandomAccessVisitorTest, MultipleVisits) {
|
||||||
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
TestState->Offsets = createPartialOffsets(GlobalState->Stream, {0, 8});
|
||||||
RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
|
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||||
GlobalState->TypeVector.size(),
|
GlobalState->TypeVector.size(),
|
||||||
TestState->Offsets);
|
TestState->Offsets);
|
||||||
|
|
||||||
std::vector<uint32_t> IndicesToVisit = {5, 5, 5};
|
std::vector<uint32_t> IndicesToVisit = {5, 5, 5};
|
||||||
|
|
||||||
for (uint32_t I : IndicesToVisit) {
|
for (uint32_t I : IndicesToVisit) {
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
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
|
// [0,8) should be present
|
||||||
EXPECT_EQ(8u, Visitor.database().size());
|
EXPECT_EQ(8u, Types.size());
|
||||||
for (uint32_t I = 0; I < 8; ++I)
|
for (uint32_t I = 0; I < 8; ++I)
|
||||||
EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
|
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||||
|
|
||||||
// 5, 5, 5
|
// 5, 5, 5
|
||||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||||
@ -248,19 +241,19 @@ TEST_F(RandomAccessVisitorTest, DescendingWithinChunk) {
|
|||||||
|
|
||||||
std::vector<uint32_t> IndicesToVisit = {7, 4, 2};
|
std::vector<uint32_t> IndicesToVisit = {7, 4, 2};
|
||||||
|
|
||||||
RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
|
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||||
GlobalState->TypeVector.size(),
|
GlobalState->TypeVector.size(),
|
||||||
TestState->Offsets);
|
TestState->Offsets);
|
||||||
|
|
||||||
for (uint32_t I : IndicesToVisit) {
|
for (uint32_t I : IndicesToVisit) {
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
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]
|
// [0, 7]
|
||||||
EXPECT_EQ(8u, Visitor.database().size());
|
EXPECT_EQ(8u, Types.size());
|
||||||
for (uint32_t I = 0; I < 8; ++I)
|
for (uint32_t I = 0; I < 8; ++I)
|
||||||
EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
|
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||||
|
|
||||||
// 2, 4, 7
|
// 2, 4, 7
|
||||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||||
@ -276,19 +269,19 @@ TEST_F(RandomAccessVisitorTest, AscendingWithinChunk) {
|
|||||||
|
|
||||||
std::vector<uint32_t> IndicesToVisit = {2, 4, 7};
|
std::vector<uint32_t> IndicesToVisit = {2, 4, 7};
|
||||||
|
|
||||||
RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
|
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||||
GlobalState->TypeVector.size(),
|
GlobalState->TypeVector.size(),
|
||||||
TestState->Offsets);
|
TestState->Offsets);
|
||||||
|
|
||||||
for (uint32_t I : IndicesToVisit) {
|
for (uint32_t I : IndicesToVisit) {
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
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]
|
// [0, 7]
|
||||||
EXPECT_EQ(8u, Visitor.database().size());
|
EXPECT_EQ(8u, Types.size());
|
||||||
for (uint32_t I = 0; I < 8; ++I)
|
for (uint32_t I = 0; I < 8; ++I)
|
||||||
EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
|
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||||
|
|
||||||
// 2, 4, 7
|
// 2, 4, 7
|
||||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||||
@ -305,19 +298,20 @@ TEST_F(RandomAccessVisitorTest, StopPrematurelyInChunk) {
|
|||||||
|
|
||||||
std::vector<uint32_t> IndicesToVisit = {0, 1, 2};
|
std::vector<uint32_t> IndicesToVisit = {0, 1, 2};
|
||||||
|
|
||||||
RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
|
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||||
GlobalState->TypeVector.size(),
|
GlobalState->TypeVector.size(),
|
||||||
TestState->Offsets);
|
TestState->Offsets);
|
||||||
|
|
||||||
for (uint32_t I : IndicesToVisit) {
|
for (uint32_t I : IndicesToVisit) {
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
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.
|
// [0, 8) should be visited.
|
||||||
EXPECT_EQ(8u, Visitor.database().size());
|
EXPECT_EQ(8u, Types.size());
|
||||||
for (uint32_t I = 0; I < 8; ++I)
|
for (uint32_t I = 0; I < 8; ++I)
|
||||||
EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
|
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||||
|
|
||||||
// [0, 2]
|
// [0, 2]
|
||||||
EXPECT_EQ(3u, TestState->Callbacks.count());
|
EXPECT_EQ(3u, TestState->Callbacks.count());
|
||||||
@ -333,19 +327,20 @@ TEST_F(RandomAccessVisitorTest, InnerChunk) {
|
|||||||
|
|
||||||
std::vector<uint32_t> IndicesToVisit = {5, 7};
|
std::vector<uint32_t> IndicesToVisit = {5, 7};
|
||||||
|
|
||||||
RandomAccessTypeVisitor Visitor(GlobalState->TypeArray,
|
LazyRandomTypeCollection Types(GlobalState->TypeArray,
|
||||||
GlobalState->TypeVector.size(),
|
GlobalState->TypeVector.size(),
|
||||||
TestState->Offsets);
|
TestState->Offsets);
|
||||||
|
|
||||||
for (uint32_t I : IndicesToVisit) {
|
for (uint32_t I : IndicesToVisit) {
|
||||||
TypeIndex TI = TypeIndex::fromArrayIndex(I);
|
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)
|
// [4, 9)
|
||||||
EXPECT_EQ(5u, Visitor.database().size());
|
EXPECT_EQ(5u, Types.size());
|
||||||
for (uint32_t I = 4; I < 9; ++I)
|
for (uint32_t I = 4; I < 9; ++I)
|
||||||
EXPECT_TRUE(ValidateDatabaseRecord(Visitor, I));
|
EXPECT_TRUE(ValidateDatabaseRecord(Types, I));
|
||||||
|
|
||||||
// 5, 7
|
// 5, 7
|
||||||
EXPECT_EQ(2u, TestState->Callbacks.count());
|
EXPECT_EQ(2u, TestState->Callbacks.count());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user