mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-27 21:50:40 +00:00
Resubmit "[llvm-pdbutil] rewrite the "raw" output style."
This resubmits commit c0c249e9f2ef83e1d1e5f166b50673d92f3579d7. It was broken due to some weird template issues, which have since been fixed. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@305517 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
02688b00ef
commit
7e5d31edd7
@ -418,6 +418,8 @@ CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(ProcSymFlags)
|
||||
|
||||
/// Corresponds to COMPILESYM2::Flags bitfield.
|
||||
enum class CompileSym2Flags : uint32_t {
|
||||
None = 0,
|
||||
SourceLanguageMask = 0xFF,
|
||||
EC = 1 << 8,
|
||||
NoDbgInfo = 1 << 9,
|
||||
LTCG = 1 << 10,
|
||||
@ -432,6 +434,8 @@ CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym2Flags)
|
||||
|
||||
/// Corresponds to COMPILESYM3::Flags bitfield.
|
||||
enum class CompileSym3Flags : uint32_t {
|
||||
None = 0,
|
||||
SourceLanguageMask = 0xFF,
|
||||
EC = 1 << 8,
|
||||
NoDbgInfo = 1 << 9,
|
||||
LTCG = 1 << 10,
|
||||
@ -448,6 +452,7 @@ enum class CompileSym3Flags : uint32_t {
|
||||
CV_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(CompileSym3Flags)
|
||||
|
||||
enum class ExportFlags : uint16_t {
|
||||
None = 0,
|
||||
IsConstant = 1 << 0,
|
||||
IsData = 1 << 1,
|
||||
IsPrivate = 1 << 2,
|
||||
|
@ -12,7 +12,10 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatProviders.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
@ -35,6 +38,20 @@ inline detail::GuidAdapter fmt_guid(ArrayRef<uint8_t> Item) {
|
||||
return detail::GuidAdapter(Item);
|
||||
}
|
||||
}
|
||||
|
||||
template <> struct format_provider<codeview::TypeIndex> {
|
||||
public:
|
||||
static void format(const codeview::TypeIndex &V, llvm::raw_ostream &Stream,
|
||||
StringRef Style) {
|
||||
if (V.isNoneType())
|
||||
Stream << "<no type>";
|
||||
else {
|
||||
Stream << formatv("{0:X+4}", V.getIndex());
|
||||
if (V.isSimple())
|
||||
Stream << " (" << codeview::TypeIndex::simpleTypeName(V) << ")";
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -363,7 +363,7 @@ public:
|
||||
: SymbolRecord(SymbolRecordKind::PublicSym32),
|
||||
RecordOffset(RecordOffset) {}
|
||||
|
||||
uint32_t Index;
|
||||
TypeIndex Index;
|
||||
uint32_t Offset;
|
||||
uint16_t Segment;
|
||||
StringRef Name;
|
||||
@ -379,7 +379,7 @@ public:
|
||||
: SymbolRecord(SymbolRecordKind::RegisterSym),
|
||||
RecordOffset(RecordOffset) {}
|
||||
|
||||
uint32_t Index;
|
||||
TypeIndex Index;
|
||||
RegisterId Register;
|
||||
StringRef Name;
|
||||
|
||||
@ -679,7 +679,7 @@ public:
|
||||
: SymbolRecord(SymbolRecordKind::FileStaticSym),
|
||||
RecordOffset(RecordOffset) {}
|
||||
|
||||
uint32_t Index;
|
||||
TypeIndex Index;
|
||||
uint32_t ModFilenameOffset;
|
||||
LocalSymFlags Flags;
|
||||
StringRef Name;
|
||||
@ -814,7 +814,7 @@ public:
|
||||
|
||||
uint32_t CodeOffset;
|
||||
uint16_t Register;
|
||||
uint8_t CookieKind;
|
||||
FrameCookieKind CookieKind;
|
||||
uint8_t Flags;
|
||||
|
||||
uint32_t RecordOffset;
|
||||
@ -871,7 +871,7 @@ public:
|
||||
|
||||
uint32_t Offset;
|
||||
TypeIndex Type;
|
||||
uint16_t Register;
|
||||
RegisterId Register;
|
||||
StringRef Name;
|
||||
|
||||
uint32_t RecordOffset;
|
||||
|
@ -248,6 +248,8 @@ public:
|
||||
return A.toArrayIndex() - B.toArrayIndex();
|
||||
}
|
||||
|
||||
static StringRef simpleTypeName(TypeIndex TI);
|
||||
|
||||
private:
|
||||
support::ulittle32_t Index;
|
||||
};
|
||||
|
@ -40,6 +40,10 @@ public:
|
||||
iterator_range<codeview::CVSymbolArray::Iterator>
|
||||
symbols(bool *HadError) const;
|
||||
|
||||
const codeview::CVSymbolArray &getSymbolArray() const {
|
||||
return SymbolsSubstream;
|
||||
}
|
||||
|
||||
llvm::iterator_range<DebugSubsectionIterator> subsections() const;
|
||||
|
||||
bool hasDebugSubsections() const;
|
||||
|
@ -35,6 +35,7 @@ public:
|
||||
uint32_t getSymHash() const;
|
||||
uint32_t getAddrMap() const;
|
||||
uint32_t getNumBuckets() const { return NumBuckets; }
|
||||
Expected<const codeview::CVSymbolArray &> getSymbolArray() const;
|
||||
iterator_range<codeview::CVSymbolArray::Iterator>
|
||||
getSymbols(bool *HadError) const;
|
||||
FixedStreamArray<support::ulittle32_t> getHashBuckets() const {
|
||||
|
@ -98,15 +98,19 @@ enum class DbgHeaderType : uint16_t {
|
||||
};
|
||||
|
||||
enum class OMFSegDescFlags : uint16_t {
|
||||
None = 0,
|
||||
Read = 1 << 0, // Segment is readable.
|
||||
Write = 1 << 1, // Segment is writable.
|
||||
Execute = 1 << 2, // Segment is executable.
|
||||
AddressIs32Bit = 1 << 3, // Descriptor describes a 32-bit linear address.
|
||||
IsSelector = 1 << 8, // Frame represents a selector.
|
||||
IsAbsoluteAddress = 1 << 9, // Frame represents an absolute address.
|
||||
IsGroup = 1 << 10 // If set, descriptor represents a group.
|
||||
IsGroup = 1 << 10, // If set, descriptor represents a group.
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IsGroup)
|
||||
};
|
||||
|
||||
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
|
||||
|
||||
} // end namespace pdb
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -27,6 +27,10 @@ public:
|
||||
~SymbolStream();
|
||||
Error reload();
|
||||
|
||||
const codeview::CVSymbolArray &getSymbolArray() const {
|
||||
return SymbolRecords;
|
||||
}
|
||||
|
||||
iterator_range<codeview::CVSymbolArray::Iterator>
|
||||
getSymbols(bool *HadError) const;
|
||||
|
||||
|
@ -290,6 +290,12 @@ public:
|
||||
return FixedStreamArrayIterator<T>(*this, size());
|
||||
}
|
||||
|
||||
const T &front() const { return *begin(); }
|
||||
const T &back() const {
|
||||
FixedStreamArrayIterator<T> I = end();
|
||||
return *(--I);
|
||||
}
|
||||
|
||||
BinaryStreamRef getUnderlyingStream() const { return Stream; }
|
||||
|
||||
private:
|
||||
|
@ -212,7 +212,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
FileStaticSym &FileStatic) {
|
||||
DictScope S(W, "FileStatic");
|
||||
W.printNumber("Index", FileStatic.Index);
|
||||
printTypeIndex("Index", FileStatic.Index);
|
||||
W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset);
|
||||
W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames());
|
||||
W.printString("Name", FileStatic.Name);
|
||||
@ -516,7 +516,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
RegisterSym &Register) {
|
||||
DictScope S(W, "RegisterSym");
|
||||
W.printNumber("Type", Register.Index);
|
||||
printTypeIndex("Type", Register.Index);
|
||||
W.printEnum("Seg", uint16_t(Register.Register), getRegisterNames());
|
||||
W.printString("Name", Register.Name);
|
||||
return Error::success();
|
||||
@ -524,7 +524,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
|
||||
Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) {
|
||||
DictScope S(W, "PublicSym");
|
||||
W.printNumber("Type", Public.Index);
|
||||
printTypeIndex("Type", Public.Index);
|
||||
W.printNumber("Seg", Public.Segment);
|
||||
W.printNumber("Off", Public.Offset);
|
||||
W.printString("Name", Public.Name);
|
||||
@ -631,7 +631,7 @@ Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
|
||||
|
||||
W.printHex("Offset", RegRel.Offset);
|
||||
printTypeIndex("Type", RegRel.Type);
|
||||
W.printHex("Register", RegRel.Register);
|
||||
W.printEnum("Register", uint16_t(RegRel.Register), getRegisterNames());
|
||||
W.printString("VarName", RegRel.Name);
|
||||
return Error::success();
|
||||
}
|
||||
|
@ -307,7 +307,7 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
|
||||
|
||||
error(IO.mapInteger(FrameCookie.CodeOffset));
|
||||
error(IO.mapInteger(FrameCookie.Register));
|
||||
error(IO.mapInteger(FrameCookie.CookieKind));
|
||||
error(IO.mapEnum(FrameCookie.CookieKind));
|
||||
error(IO.mapInteger(FrameCookie.Flags));
|
||||
|
||||
return Error::success();
|
||||
@ -439,7 +439,7 @@ Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
|
||||
|
||||
error(IO.mapInteger(RegRel.Offset));
|
||||
error(IO.mapInteger(RegRel.Type));
|
||||
error(IO.mapInteger(RegRel.Register));
|
||||
error(IO.mapEnum(RegRel.Register));
|
||||
error(IO.mapStringZ(RegRel.Name));
|
||||
|
||||
return Error::success();
|
||||
|
@ -12,59 +12,6 @@
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
namespace {
|
||||
struct SimpleTypeEntry {
|
||||
StringRef Name;
|
||||
SimpleTypeKind Kind;
|
||||
};
|
||||
}
|
||||
|
||||
/// The names here all end in "*". If the simple type is a pointer type, we
|
||||
/// return the whole name. Otherwise we lop off the last character in our
|
||||
/// StringRef.
|
||||
static const SimpleTypeEntry SimpleTypeNames[] = {
|
||||
{"void*", SimpleTypeKind::Void},
|
||||
{"<not translated>*", SimpleTypeKind::NotTranslated},
|
||||
{"HRESULT*", SimpleTypeKind::HResult},
|
||||
{"signed char*", SimpleTypeKind::SignedCharacter},
|
||||
{"unsigned char*", SimpleTypeKind::UnsignedCharacter},
|
||||
{"char*", SimpleTypeKind::NarrowCharacter},
|
||||
{"wchar_t*", SimpleTypeKind::WideCharacter},
|
||||
{"char16_t*", SimpleTypeKind::Character16},
|
||||
{"char32_t*", SimpleTypeKind::Character32},
|
||||
{"__int8*", SimpleTypeKind::SByte},
|
||||
{"unsigned __int8*", SimpleTypeKind::Byte},
|
||||
{"short*", SimpleTypeKind::Int16Short},
|
||||
{"unsigned short*", SimpleTypeKind::UInt16Short},
|
||||
{"__int16*", SimpleTypeKind::Int16},
|
||||
{"unsigned __int16*", SimpleTypeKind::UInt16},
|
||||
{"long*", SimpleTypeKind::Int32Long},
|
||||
{"unsigned long*", SimpleTypeKind::UInt32Long},
|
||||
{"int*", SimpleTypeKind::Int32},
|
||||
{"unsigned*", SimpleTypeKind::UInt32},
|
||||
{"__int64*", SimpleTypeKind::Int64Quad},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64Quad},
|
||||
{"__int64*", SimpleTypeKind::Int64},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64},
|
||||
{"__int128*", SimpleTypeKind::Int128},
|
||||
{"unsigned __int128*", SimpleTypeKind::UInt128},
|
||||
{"__half*", SimpleTypeKind::Float16},
|
||||
{"float*", SimpleTypeKind::Float32},
|
||||
{"float*", SimpleTypeKind::Float32PartialPrecision},
|
||||
{"__float48*", SimpleTypeKind::Float48},
|
||||
{"double*", SimpleTypeKind::Float64},
|
||||
{"long double*", SimpleTypeKind::Float80},
|
||||
{"__float128*", SimpleTypeKind::Float128},
|
||||
{"_Complex float*", SimpleTypeKind::Complex32},
|
||||
{"_Complex double*", SimpleTypeKind::Complex64},
|
||||
{"_Complex long double*", SimpleTypeKind::Complex80},
|
||||
{"_Complex __float128*", SimpleTypeKind::Complex128},
|
||||
{"bool*", SimpleTypeKind::Boolean8},
|
||||
{"__bool16*", SimpleTypeKind::Boolean16},
|
||||
{"__bool32*", SimpleTypeKind::Boolean32},
|
||||
{"__bool64*", SimpleTypeKind::Boolean64},
|
||||
};
|
||||
|
||||
TypeDatabase::TypeDatabase(uint32_t Capacity) : TypeNameStorage(Allocator) {
|
||||
CVUDTNames.resize(Capacity);
|
||||
TypeRecords.resize(Capacity);
|
||||
@ -103,22 +50,8 @@ StringRef TypeDatabase::saveTypeName(StringRef TypeName) {
|
||||
}
|
||||
|
||||
StringRef TypeDatabase::getTypeName(TypeIndex Index) const {
|
||||
if (Index.isNoneType())
|
||||
return "<no type>";
|
||||
|
||||
if (Index.isSimple()) {
|
||||
// This is a simple type.
|
||||
for (const auto &SimpleTypeName : SimpleTypeNames) {
|
||||
if (SimpleTypeName.Kind == Index.getSimpleKind()) {
|
||||
if (Index.getSimpleMode() == SimpleTypeMode::Direct)
|
||||
return SimpleTypeName.Name.drop_back(1);
|
||||
// Otherwise, this is a pointer type. We gloss over the distinction
|
||||
// between near, far, 64, 32, etc, and just give a pointer type.
|
||||
return SimpleTypeName.Name;
|
||||
}
|
||||
}
|
||||
return "<unknown simple type>";
|
||||
}
|
||||
if (Index.isNoneType() || Index.isSimple())
|
||||
return TypeIndex::simpleTypeName(Index);
|
||||
|
||||
if (contains(Index))
|
||||
return CVUDTNames[Index.toArrayIndex()];
|
||||
|
@ -15,11 +15,88 @@
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
|
||||
namespace {
|
||||
struct SimpleTypeEntry {
|
||||
StringRef Name;
|
||||
SimpleTypeKind Kind;
|
||||
};
|
||||
|
||||
/// The names here all end in "*". If the simple type is a pointer type, we
|
||||
/// return the whole name. Otherwise we lop off the last character in our
|
||||
/// StringRef.
|
||||
static const SimpleTypeEntry SimpleTypeNames[] = {
|
||||
{"void*", SimpleTypeKind::Void},
|
||||
{"<not translated>*", SimpleTypeKind::NotTranslated},
|
||||
{"HRESULT*", SimpleTypeKind::HResult},
|
||||
{"signed char*", SimpleTypeKind::SignedCharacter},
|
||||
{"unsigned char*", SimpleTypeKind::UnsignedCharacter},
|
||||
{"char*", SimpleTypeKind::NarrowCharacter},
|
||||
{"wchar_t*", SimpleTypeKind::WideCharacter},
|
||||
{"char16_t*", SimpleTypeKind::Character16},
|
||||
{"char32_t*", SimpleTypeKind::Character32},
|
||||
{"__int8*", SimpleTypeKind::SByte},
|
||||
{"unsigned __int8*", SimpleTypeKind::Byte},
|
||||
{"short*", SimpleTypeKind::Int16Short},
|
||||
{"unsigned short*", SimpleTypeKind::UInt16Short},
|
||||
{"__int16*", SimpleTypeKind::Int16},
|
||||
{"unsigned __int16*", SimpleTypeKind::UInt16},
|
||||
{"long*", SimpleTypeKind::Int32Long},
|
||||
{"unsigned long*", SimpleTypeKind::UInt32Long},
|
||||
{"int*", SimpleTypeKind::Int32},
|
||||
{"unsigned*", SimpleTypeKind::UInt32},
|
||||
{"__int64*", SimpleTypeKind::Int64Quad},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64Quad},
|
||||
{"__int64*", SimpleTypeKind::Int64},
|
||||
{"unsigned __int64*", SimpleTypeKind::UInt64},
|
||||
{"__int128*", SimpleTypeKind::Int128},
|
||||
{"unsigned __int128*", SimpleTypeKind::UInt128},
|
||||
{"__half*", SimpleTypeKind::Float16},
|
||||
{"float*", SimpleTypeKind::Float32},
|
||||
{"float*", SimpleTypeKind::Float32PartialPrecision},
|
||||
{"__float48*", SimpleTypeKind::Float48},
|
||||
{"double*", SimpleTypeKind::Float64},
|
||||
{"long double*", SimpleTypeKind::Float80},
|
||||
{"__float128*", SimpleTypeKind::Float128},
|
||||
{"_Complex float*", SimpleTypeKind::Complex32},
|
||||
{"_Complex double*", SimpleTypeKind::Complex64},
|
||||
{"_Complex long double*", SimpleTypeKind::Complex80},
|
||||
{"_Complex __float128*", SimpleTypeKind::Complex128},
|
||||
{"bool*", SimpleTypeKind::Boolean8},
|
||||
{"__bool16*", SimpleTypeKind::Boolean16},
|
||||
{"__bool32*", SimpleTypeKind::Boolean32},
|
||||
{"__bool64*", SimpleTypeKind::Boolean64},
|
||||
};
|
||||
} // namespace
|
||||
|
||||
StringRef TypeIndex::simpleTypeName(TypeIndex TI) {
|
||||
assert(TI.isNoneType() || TI.isSimple());
|
||||
|
||||
if (TI.isNoneType())
|
||||
return "<no type>";
|
||||
|
||||
// This is a simple type.
|
||||
for (const auto &SimpleTypeName : SimpleTypeNames) {
|
||||
if (SimpleTypeName.Kind == TI.getSimpleKind()) {
|
||||
if (TI.getSimpleMode() == SimpleTypeMode::Direct)
|
||||
return SimpleTypeName.Name.drop_back(1);
|
||||
// Otherwise, this is a pointer type. We gloss over the distinction
|
||||
// between near, far, 64, 32, etc, and just give a pointer type.
|
||||
return SimpleTypeName.Name;
|
||||
}
|
||||
}
|
||||
return "<unknown simple type>";
|
||||
}
|
||||
|
||||
void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
|
||||
TypeIndex TI, TypeCollection &Types) {
|
||||
StringRef TypeName;
|
||||
if (!TI.isNoneType())
|
||||
TypeName = Types.getTypeName(TI);
|
||||
if (!TI.isNoneType()) {
|
||||
if (TI.isSimple())
|
||||
TypeName = TypeIndex::simpleTypeName(TI);
|
||||
else
|
||||
TypeName = Types.getTypeName(TI);
|
||||
}
|
||||
|
||||
if (!TypeName.empty())
|
||||
Printer.printHex(FieldName, TypeName, TI.getIndex());
|
||||
else
|
||||
|
@ -130,4 +130,13 @@ PublicsStream::getSymbols(bool *HadError) const {
|
||||
return SS.getSymbols(HadError);
|
||||
}
|
||||
|
||||
Expected<const codeview::CVSymbolArray &>
|
||||
PublicsStream::getSymbolArray() const {
|
||||
auto SymbolS = Pdb.getPDBSymbolStream();
|
||||
if (!SymbolS)
|
||||
return SymbolS.takeError();
|
||||
|
||||
return SymbolS->getSymbolArray();
|
||||
}
|
||||
|
||||
Error PublicsStream::commit() { return Error::success(); }
|
||||
|
@ -35,6 +35,7 @@ LLVM_YAML_DECLARE_SCALAR_TRAITS(APSInt, false)
|
||||
LLVM_YAML_DECLARE_SCALAR_TRAITS(TypeIndex, false)
|
||||
|
||||
LLVM_YAML_DECLARE_ENUM_TRAITS(SymbolKind)
|
||||
LLVM_YAML_DECLARE_ENUM_TRAITS(FrameCookieKind)
|
||||
|
||||
LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym2Flags)
|
||||
LLVM_YAML_DECLARE_BITSET_TRAITS(CompileSym3Flags)
|
||||
@ -149,6 +150,15 @@ void ScalarEnumerationTraits<ThunkOrdinal>::enumeration(IO &io,
|
||||
}
|
||||
}
|
||||
|
||||
void ScalarEnumerationTraits<FrameCookieKind>::enumeration(
|
||||
IO &io, FrameCookieKind &FC) {
|
||||
auto ThunkNames = getFrameCookieKindNames();
|
||||
for (const auto &E : ThunkNames) {
|
||||
io.enumCase(FC, E.Name.str().c_str(),
|
||||
static_cast<FrameCookieKind>(E.Value));
|
||||
}
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
namespace CodeViewYAML {
|
||||
namespace detail {
|
||||
|
@ -1,74 +0,0 @@
|
||||
RUN: llvm-pdbutil pdb2yaml -tpi-stream %p/Inputs/big-read.pdb > %t.yaml
|
||||
RUN: FileCheck -check-prefix=YAML %s < %t.yaml
|
||||
RUN: llvm-pdbutil yaml2pdb %t.yaml -pdb %t.pdb
|
||||
RUN: llvm-pdbutil raw -tpi-records %t.pdb | FileCheck %s --check-prefix=PDB
|
||||
|
||||
Only verify the beginning of the type stream.
|
||||
|
||||
YAML: TpiStream:
|
||||
YAML-NEXT: Version: VC80
|
||||
YAML-NEXT: Records:
|
||||
YAML-NEXT: - Kind: LF_ARGLIST
|
||||
YAML-NEXT: ArgList:
|
||||
YAML-NEXT: ArgIndices: [ ]
|
||||
YAML-NEXT: - Kind: LF_PROCEDURE
|
||||
YAML-NEXT: Procedure:
|
||||
YAML-NEXT: ReturnType: 3
|
||||
YAML-NEXT: CallConv: NearC
|
||||
YAML-NEXT: Options: [ None ]
|
||||
YAML-NEXT: ParameterCount: 0
|
||||
YAML-NEXT: ArgumentList: 4096
|
||||
YAML-NEXT: - Kind: LF_PROCEDURE
|
||||
YAML-NEXT: Procedure:
|
||||
YAML-NEXT: ReturnType: 116
|
||||
YAML-NEXT: CallConv: NearC
|
||||
YAML-NEXT: Options: [ None ]
|
||||
YAML-NEXT: ParameterCount: 0
|
||||
YAML-NEXT: ArgumentList: 4096
|
||||
|
||||
This test is mostly checking to make sure we include the type index offset
|
||||
table, and eventually hash codes. The type index offsets should be similar to
|
||||
what are already present in big-read.pdb.
|
||||
|
||||
PDB: Type Info Stream (TPI) {
|
||||
PDB-NEXT: TPI Version: 20040203
|
||||
PDB-NEXT: Record count: 728
|
||||
PDB-NEXT: Records [
|
||||
PDB-NEXT: {
|
||||
PDB-NEXT: ArgList (0x1000) {
|
||||
PDB-NEXT: TypeLeafKind: LF_ARGLIST (0x1201)
|
||||
PDB-NEXT: NumArgs: 0
|
||||
PDB-NEXT: Arguments [
|
||||
PDB-NEXT: ]
|
||||
PDB-NEXT: }
|
||||
PDB-NEXT: }
|
||||
PDB-NEXT: {
|
||||
PDB-NEXT: Procedure (0x1001) {
|
||||
PDB-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008)
|
||||
PDB-NEXT: ReturnType: void (0x3)
|
||||
PDB-NEXT: CallingConvention: NearC (0x0)
|
||||
PDB-NEXT: FunctionOptions [ (0x0)
|
||||
PDB-NEXT: ]
|
||||
PDB-NEXT: NumParameters: 0
|
||||
PDB-NEXT: ArgListType: () (0x1000)
|
||||
PDB-NEXT: }
|
||||
PDB-NEXT: }
|
||||
PDB-NEXT: {
|
||||
PDB-NEXT: Procedure (0x1002) {
|
||||
PDB-NEXT: TypeLeafKind: LF_PROCEDURE (0x1008)
|
||||
PDB-NEXT: ReturnType: int (0x74)
|
||||
PDB-NEXT: CallingConvention: NearC (0x0)
|
||||
PDB-NEXT: FunctionOptions [ (0x0)
|
||||
PDB-NEXT: ]
|
||||
PDB-NEXT: NumParameters: 0
|
||||
PDB-NEXT: ArgListType: () (0x1000)
|
||||
PDB-NEXT: }
|
||||
PDB-NEXT: }
|
||||
...
|
||||
PDB: TypeIndexOffsets [
|
||||
PDB-NEXT: Index: 0x1000, Offset: 0
|
||||
PDB-NEXT: Index: 0x106c, Offset: 8,116
|
||||
PDB-NEXT: Index: 0x1118, Offset: 16,372
|
||||
PDB-NEXT: Index: 0x11df, Offset: 24,564
|
||||
PDB-NEXT: Index: 0x128e, Offset: 32,752
|
||||
PDB-NEXT: ]
|
@ -1,6 +1,5 @@
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.pdb %p/Inputs/debug-subsections.yaml
|
||||
; RUN: llvm-pdbutil pdb2yaml -all -no-file-headers %t.pdb | FileCheck --check-prefix=YAML %s
|
||||
; RUN: llvm-pdbutil raw -subsections=all %t.pdb | FileCheck --check-prefix=RAW %s
|
||||
|
||||
YAML: Modules:
|
||||
YAML-NEXT: - Module: Foo.obj
|
||||
@ -61,150 +60,7 @@ YAML-NEXT: EndDelta: 0
|
||||
YAML-NEXT: Columns:
|
||||
YAML-NEXT: - !InlineeLines
|
||||
YAML-NEXT: HasExtraFiles: false
|
||||
YAML-NEXT: Sites:
|
||||
YAML-NEXT: Sites:
|
||||
YAML-NEXT: - FileName: 'f:\dd\externalapis\windows\10\sdk\inc\winerror.h'
|
||||
YAML-NEXT: LineNum: 26950
|
||||
YAML-NEXT: Inlinee: 22767
|
||||
|
||||
|
||||
RAW: DBI Stream {
|
||||
RAW: Modules [
|
||||
RAW-NEXT: {
|
||||
RAW-NEXT: Name: Foo.obj
|
||||
RAW: Subsections [
|
||||
RAW-NEXT: CrossModuleExports [
|
||||
RAW-NEXT: Export {
|
||||
RAW-NEXT: Local: 0x12F4
|
||||
RAW-NEXT: Global: 0x2443
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Export {
|
||||
RAW-NEXT: Local: 0x80001083
|
||||
RAW-NEXT: Global: 0x23A3
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: {
|
||||
RAW-NEXT: Name: Bar.obj
|
||||
RAW: Subsections [
|
||||
RAW-NEXT: CrossModuleExports [
|
||||
RAW-NEXT: Export {
|
||||
RAW-NEXT: Local: 0x10A9
|
||||
RAW-NEXT: Global: 0x17D1
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Export {
|
||||
RAW-NEXT: Local: 0x10C9
|
||||
RAW-NEXT: Global: 0x1245
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: CrossModuleImports [
|
||||
RAW-NEXT: ModuleImport {
|
||||
RAW-NEXT: Module: Foo.obj
|
||||
RAW-NEXT: Imports: [0x12F4, 0x80001083]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: {
|
||||
RAW-NEXT: Name: d:\src\llvm\test\DebugInfo\PDB\Inputs\empty.obj
|
||||
RAW: Subsections [
|
||||
RAW-NEXT: FileChecksums {
|
||||
RAW-NEXT: Checksum {
|
||||
RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp
|
||||
RAW-NEXT: Kind: MD5 (0x1)
|
||||
RAW-NEXT: Checksum (
|
||||
RAW-NEXT: 0000: A0A5BD0D 3ECD93FC 29D19DE8 26FBF4BC |....>...)...&...|
|
||||
RAW-NEXT: )
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Checksum {
|
||||
RAW-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h
|
||||
RAW-NEXT: Kind: MD5 (0x1)
|
||||
RAW-NEXT: Checksum (
|
||||
RAW-NEXT: 0000: 1154D69F 5B265019 6E1FC34F 4134E56B |.T..[&P.n..OA4.k|
|
||||
RAW-NEXT: )
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Lines {
|
||||
RAW-NEXT: RelocSegment: 1
|
||||
RAW-NEXT: RelocOffset: 100016
|
||||
RAW-NEXT: CodeSize: 10
|
||||
RAW-NEXT: HasColumns: No
|
||||
RAW-NEXT: FileEntry {
|
||||
RAW-NEXT: FileName: d:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp
|
||||
RAW-NEXT: Line {
|
||||
RAW-NEXT: Offset: 0
|
||||
RAW-NEXT: LineNumberStart: 5
|
||||
RAW-NEXT: EndDelta: 0
|
||||
RAW-NEXT: IsStatement: Yes
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Line {
|
||||
RAW-NEXT: Offset: 3
|
||||
RAW-NEXT: LineNumberStart: 6
|
||||
RAW-NEXT: EndDelta: 0
|
||||
RAW-NEXT: IsStatement: Yes
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: Line {
|
||||
RAW-NEXT: Offset: 8
|
||||
RAW-NEXT: LineNumberStart: 7
|
||||
RAW-NEXT: EndDelta: 0
|
||||
RAW-NEXT: IsStatement: Yes
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: InlineeLines {
|
||||
RAW-NEXT: HasExtraFiles: No
|
||||
RAW-NEXT: Lines [
|
||||
RAW-NEXT: Inlinee {
|
||||
RAW-NEXT: FileName: f:\dd\externalapis\windows\10\sdk\inc\winerror.h
|
||||
RAW-NEXT: Function {
|
||||
RAW-NEXT: Index: 0x58ef (unknown function)
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: SourceLine: 26950
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: {
|
||||
RAW-NEXT: Name: ObjFileSubsections
|
||||
RAW-NEXT: Debug Stream Index: 11
|
||||
RAW-NEXT: Object File Name: ObjFileSubsections
|
||||
RAW-NEXT: Num Files: 0
|
||||
RAW-NEXT: Source File Name Idx: 0
|
||||
RAW-NEXT: Pdb File Name Idx: 0
|
||||
RAW-NEXT: Line Info Byte Size: 0
|
||||
RAW-NEXT: C13 Line Info Byte Size: 116
|
||||
RAW-NEXT: Symbol Byte Size: 4
|
||||
RAW-NEXT: Type Server Index: 0
|
||||
RAW-NEXT: Has EC Info: No
|
||||
RAW-NEXT: Subsections [
|
||||
RAW-NEXT: String Table [
|
||||
RAW-NEXT: String1
|
||||
RAW-NEXT: String2
|
||||
RAW-NEXT: String3
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: Symbols [
|
||||
RAW-NEXT: {
|
||||
RAW-NEXT: ObjectName {
|
||||
RAW-NEXT: Signature: 0x0
|
||||
RAW-NEXT: ObjectName: ObjFileSubsections
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: FrameData [
|
||||
RAW-NEXT: Frame {
|
||||
RAW-NEXT: Rva: 6
|
||||
RAW-NEXT: CodeSize: 1
|
||||
RAW-NEXT: LocalSize: 2
|
||||
RAW-NEXT: ParamsSize: 4
|
||||
RAW-NEXT: MaxStackSize: 3
|
||||
RAW-NEXT: FrameFunc: MyFunc
|
||||
RAW-NEXT: PrologSize: 5
|
||||
RAW-NEXT: SavedRegsSize: 7
|
||||
RAW-NEXT: Flags: 0
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
RAW-NEXT: ]
|
||||
RAW-NEXT: }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,65 +1,51 @@
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-and-types-1.yaml
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-and-types-2.yaml
|
||||
; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=INTMAIN %s
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=VOIDMAIN %s
|
||||
; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s
|
||||
; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-NAMES %s
|
||||
; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=IPI-UDT %s
|
||||
; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-TYPES %s
|
||||
; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=IPI-TYPES %s
|
||||
|
||||
TPI-TYPES: Type Info Stream (TPI)
|
||||
TPI-TYPES: Record count: 9
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_POINTER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_FIELDLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_STRUCTURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_MEMBER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_POINTER
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_MFUNCTION
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_PROCEDURE
|
||||
TPI-TYPES-DAG: TypeLeafKind: LF_ARGLIST
|
||||
TPI-TYPES: Types (TPI Stream)
|
||||
TPI-TYPES-NEXT: ============================================================
|
||||
TPI-TYPES-NEXT: Showing 9 records
|
||||
TPI-TYPES-NEXT: 0x1000 | LF_POINTER [size = 12]
|
||||
TPI-TYPES-NEXT: referent = 0x0470 (char*), mode = pointer, opts = None, kind = ptr32
|
||||
TPI-TYPES-NEXT: 0x1001 | LF_FIELDLIST [size = 24]
|
||||
TPI-TYPES-NEXT: - LF_MEMBER [name = `FooMember`, Type = 0x0403 (void*), offset = 0, attrs = public]
|
||||
TPI-TYPES-NEXT: 0x1002 | LF_ARGLIST [size = 16]
|
||||
TPI-TYPES-NEXT: 0x0074 (int): `int`
|
||||
TPI-TYPES-NEXT: 0x1000: `char**`
|
||||
TPI-TYPES-NEXT: 0x1003 | LF_STRUCTURE [size = 36]
|
||||
TPI-TYPES-NEXT: class name: `FooBar`
|
||||
TPI-TYPES-NEXT: unique name: `FooBar`
|
||||
TPI-TYPES-NEXT: vtable: <no type>, base list: <no type>, field list: 0x1001
|
||||
TPI-TYPES-NEXT: options: has unique name
|
||||
TPI-TYPES-NEXT: 0x1004 | LF_POINTER [size = 12]
|
||||
TPI-TYPES-NEXT: referent = 0x1003, mode = pointer, opts = None, kind = ptr32
|
||||
TPI-TYPES-NEXT: 0x1005 | LF_ARGLIST [size = 12]
|
||||
TPI-TYPES-NEXT: 0x0074 (int): `int`
|
||||
TPI-TYPES-NEXT: 0x1006 | LF_MFUNCTION [size = 28]
|
||||
TPI-TYPES-NEXT: return type = 1, # args = 0x1005, param list = 0x0003 (void)
|
||||
TPI-TYPES-NEXT: class type = 0x1003, this type = 0x1004, this adjust = 0
|
||||
TPI-TYPES-NEXT: calling conv = thiscall, options = constructor
|
||||
TPI-TYPES-NEXT: 0x1007 | LF_PROCEDURE [size = 16]
|
||||
TPI-TYPES-NEXT: return type = 0x0074 (int), # args = 2, param list = 0x1002
|
||||
TPI-TYPES-NEXT: calling conv = cdecl, options = None
|
||||
TPI-TYPES-NEXT: 0x1008 | LF_PROCEDURE [size = 16]
|
||||
TPI-TYPES-NEXT: return type = 0x0003 (void), # args = 2, param list = 0x1002
|
||||
TPI-TYPES-NEXT: calling conv = cdecl, options = None
|
||||
|
||||
; Both procedures should use the same arglist even though they have a different
|
||||
; return type.
|
||||
INTMAIN: ArgList ([[ID:.*]])
|
||||
INTMAIN-NEXT: TypeLeafKind: LF_ARGLIST
|
||||
INTMAIN-NEXT: NumArgs: 2
|
||||
INTMAIN-NEXT: Arguments [
|
||||
INTMAIN-NEXT: ArgType: int
|
||||
INTMAIN-NEXT: ArgType: char**
|
||||
INTMAIN: TypeLeafKind: LF_PROCEDURE
|
||||
INTMAIN: ReturnType: int
|
||||
INTMAIN: NumParameters: 2
|
||||
INTMAIN-NEXT: ArgListType: (int, char**) ([[ID]])
|
||||
|
||||
VOIDMAIN: ArgList ([[ID:.*]])
|
||||
VOIDMAIN-NEXT: TypeLeafKind: LF_ARGLIST
|
||||
VOIDMAIN-NEXT: NumArgs: 2
|
||||
VOIDMAIN-NEXT: Arguments [
|
||||
VOIDMAIN-NEXT: ArgType: int
|
||||
VOIDMAIN-NEXT: ArgType: char**
|
||||
VOIDMAIN: TypeLeafKind: LF_PROCEDURE
|
||||
VOIDMAIN: ReturnType: void
|
||||
VOIDMAIN: NumParameters: 2
|
||||
VOIDMAIN-NEXT: ArgListType: (int, char**) ([[ID]])
|
||||
|
||||
IPI-TYPES: Type Info Stream (IPI)
|
||||
IPI-TYPES: Record count: 6
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_UDT_MOD_SRC_LINE
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_FUNC_ID
|
||||
IPI-TYPES-DAG: TypeLeafKind: LF_MFUNC_ID
|
||||
|
||||
IPI-NAMES-DAG: Name: main
|
||||
IPI-NAMES-DAG: Name: FooMethod
|
||||
IPI-NAMES-DAG: Name: main2
|
||||
IPI-NAMES-DAG: Name: foo
|
||||
IPI-NAMES-DAG: Name: FooMethod2
|
||||
|
||||
IPI-UDT: TypeLeafKind: LF_UDT_MOD_SRC_LINE
|
||||
IPI-UDT-NEXT: UDT: FooBar
|
||||
IPI-TYPES: Types (IPI Stream)
|
||||
IPI-TYPES-NEXT: ============================================================
|
||||
IPI-TYPES-NEXT: Showing 6 records
|
||||
IPI-TYPES-NEXT: 0x1000 | LF_FUNC_ID [size = 20]
|
||||
IPI-TYPES-NEXT: name = main, type = 0x1007, parent scope = <no type>
|
||||
IPI-TYPES-NEXT: 0x1001 | LF_MFUNC_ID [size = 24]
|
||||
IPI-TYPES-NEXT: name = FooMethod, type = 0x1006, class type = 0x1003
|
||||
IPI-TYPES-NEXT: 0x1002 | LF_UDT_MOD_SRC_LINE [size = 20]
|
||||
IPI-TYPES-NEXT: udt = 0x1003, mod = 0, file = 0, line = 0
|
||||
IPI-TYPES-NEXT: 0x1003 | LF_FUNC_ID [size = 20]
|
||||
IPI-TYPES-NEXT: name = main2, type = 0x1007, parent scope = <no type>
|
||||
IPI-TYPES-NEXT: 0x1004 | LF_FUNC_ID [size = 16]
|
||||
IPI-TYPES-NEXT: name = foo, type = 0x1008, parent scope = <no type>
|
||||
IPI-TYPES-NEXT: 0x1005 | LF_MFUNC_ID [size = 24]
|
||||
IPI-TYPES-NEXT: name = FooMethod2, type = 0x1006, class type = 0x1003
|
||||
|
@ -1,31 +1,24 @@
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-ids-1.yaml
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-ids-2.yaml
|
||||
; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbutil raw -ipi-records %t.3.pdb | FileCheck -check-prefix=SUBSTRS %s
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s
|
||||
; RUN: llvm-pdbutil raw -ids %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=TPI-EMPTY %s
|
||||
|
||||
|
||||
MERGED: Type Info Stream (IPI)
|
||||
MERGED: Record count: 8
|
||||
MERGED-DAG: StringData: One
|
||||
MERGED-DAG: StringData: Two
|
||||
MERGED-DAG: StringData: SubOne
|
||||
MERGED-DAG: StringData: SubTwo
|
||||
MERGED-DAG: StringData: Main
|
||||
MERGED-DAG: TypeLeafKind: LF_SUBSTR_LIST
|
||||
MERGED-DAG: StringData: OnlyInFirst
|
||||
MERGED-DAG: StringData: OnlyInSecond
|
||||
MERGED: Types (IPI Stream)
|
||||
MERGED-NEXT: ============================================================
|
||||
MERGED-NEXT: Showing 8 records
|
||||
MERGED-NEXT: 0x1000 | LF_STRING_ID [size = 12] ID: <no type>, String: One
|
||||
MERGED-NEXT: 0x1001 | LF_STRING_ID [size = 12] ID: <no type>, String: Two
|
||||
MERGED-NEXT: 0x1002 | LF_STRING_ID [size = 20] ID: <no type>, String: OnlyInFirst
|
||||
MERGED-NEXT: 0x1003 | LF_STRING_ID [size = 16] ID: <no type>, String: SubOne
|
||||
MERGED-NEXT: 0x1004 | LF_STRING_ID [size = 16] ID: <no type>, String: SubTwo
|
||||
MERGED-NEXT: 0x1005 | LF_SUBSTR_LIST [size = 16]
|
||||
MERGED-NEXT: 0x1003: `SubOne`
|
||||
MERGED-NEXT: 0x1004: `SubTwo`
|
||||
MERGED-NEXT: 0x1006 | LF_STRING_ID [size = 16] ID: 0x1005, String: Main
|
||||
MERGED-NEXT: 0x1007 | LF_STRING_ID [size = 24] ID: <no type>, String: OnlyInSecond
|
||||
|
||||
SUBSTRS: StringList
|
||||
SUBSTRS: TypeLeafKind: LF_SUBSTR_LIST
|
||||
SUBSTRS-NEXT: NumStrings: 2
|
||||
SUBSTRS-NEXT: Strings [
|
||||
SUBSTRS-NEXT: SubOne
|
||||
SUBSTRS-NEXT: SubTwo
|
||||
SUBSTRS: StringId
|
||||
SUBSTRS-NEXT: TypeLeafKind: LF_STRING_ID
|
||||
SUBSTRS-NEXT: Id: "SubOne" "SubTwo"
|
||||
SUBSTRS-NEXT: StringData: Main
|
||||
|
||||
TPI-EMPTY: Record count: 0
|
||||
TPI-EMPTY: Types (TPI Stream)
|
||||
TPI-EMPTY-NEXT: ============================================================
|
||||
TPI-EMPTY-NEXT: Showing 0 records
|
||||
|
@ -1,24 +1,36 @@
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml
|
||||
; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
; RUN: llvm-pdbutil raw -tpi-records %t.3.pdb | FileCheck -check-prefix=ARGLIST %s
|
||||
|
||||
|
||||
MERGED: Type Info Stream (TPI)
|
||||
MERGED: Record count: 9
|
||||
MERGED-DAG: PointeeType: unsigned
|
||||
MERGED-DAG: PointeeType: unsigned*
|
||||
MERGED-DAG: PointeeType: unsigned**
|
||||
MERGED-DAG: PointeeType: __int64
|
||||
MERGED-DAG: PointeeType: __int64*
|
||||
MERGED-DAG: Name: OnlyInMerge1
|
||||
MERGED-DAG: Name: OnlyInMerge2
|
||||
MERGED-DAG: TypeLeafKind: LF_ARGLIST
|
||||
|
||||
ARGLIST: TypeLeafKind: LF_ARGLIST
|
||||
ARGLIST-NEXT: NumArgs: 3
|
||||
ARGLIST-NEXT: Arguments [
|
||||
ARGLIST-NEXT: ArgType: unsigned
|
||||
ARGLIST-NEXT: ArgType: unsigned*
|
||||
ARGLIST-NEXT: ArgType: unsigned**
|
||||
+; RUN: llvm-pdbutil yaml2pdb -pdb=%t.1.pdb %p/Inputs/merge-types-1.yaml
|
||||
; RUN: llvm-pdbutil yaml2pdb -pdb=%t.2.pdb %p/Inputs/merge-types-2.yaml
|
||||
; RUN: llvm-pdbutil merge -pdb=%t.3.pdb %t.1.pdb %t.2.pdb
|
||||
; RUN: llvm-pdbutil raw -types %t.3.pdb | FileCheck -check-prefix=MERGED %s
|
||||
|
||||
|
||||
MERGED: Types (TPI Stream)
|
||||
MERGED-NEXT: ============================================================
|
||||
MERGED-NEXT: Showing 9 records
|
||||
MERGED-NEXT: 0x1000 | LF_POINTER [size = 12]
|
||||
MERGED-NEXT: referent = 0x0075 (unsigned), mode = pointer, opts = None, kind = ptr32
|
||||
MERGED-NEXT: 0x1001 | LF_POINTER [size = 12]
|
||||
MERGED-NEXT: referent = 0x0076 (__int64), mode = pointer, opts = None, kind = ptr32
|
||||
MERGED-NEXT: 0x1002 | LF_STRUCTURE [size = 48]
|
||||
MERGED-NEXT: class name: `OnlyInMerge1`
|
||||
MERGED-NEXT: unique name: `OnlyInMerge1`
|
||||
MERGED-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
|
||||
MERGED-NEXT: options: forward ref | has unique name
|
||||
MERGED-NEXT: 0x1003 | LF_POINTER [size = 12]
|
||||
MERGED-NEXT: referent = 0x1000, mode = pointer, opts = None, kind = ptr32
|
||||
MERGED-NEXT: 0x1004 | LF_POINTER [size = 12]
|
||||
MERGED-NEXT: referent = 0x1003, mode = pointer, opts = None, kind = ptr32
|
||||
MERGED-NEXT: 0x1005 | LF_POINTER [size = 12]
|
||||
MERGED-NEXT: referent = 0x1001, mode = pointer, opts = None, kind = ptr32
|
||||
MERGED-NEXT: 0x1006 | LF_ARGLIST [size = 20]
|
||||
MERGED-NEXT: 0x0075 (unsigned): `unsigned`
|
||||
MERGED-NEXT: 0x1000: `unsigned*`
|
||||
MERGED-NEXT: 0x1003: `unsigned**`
|
||||
MERGED-NEXT: 0x1007 | LF_PROCEDURE [size = 16]
|
||||
MERGED-NEXT: return type = 0x0075 (unsigned), # args = 0, param list = 0x1006
|
||||
MERGED-NEXT: calling conv = cdecl, options = None
|
||||
MERGED-NEXT: 0x1008 | LF_STRUCTURE [size = 48]
|
||||
MERGED-NEXT: class name: `OnlyInMerge2`
|
||||
MERGED-NEXT: unique name: `OnlyInMerge2`
|
||||
MERGED-NEXT: vtable: <no type>, base list: <no type>, field list: <no type>
|
||||
MERGED-NEXT: options: forward ref | has unique name
|
||||
|
@ -1,35 +1,29 @@
|
||||
; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
|
||||
; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
|
||||
BLOCK0: Block Data {
|
||||
BLOCK0-NEXT: Block 0 (
|
||||
BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ |
|
||||
BLOCK0-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...|
|
||||
BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 |................|
|
||||
BLOCK0-NEXT: 0030: 00000000 18000000 00000000 00000000 |................|
|
||||
BLOCK0: 0FE0: 00000000 00000000 00000000 00000000 |................|
|
||||
BLOCK0-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................|
|
||||
BLOCK0-NEXT: )
|
||||
BLOCK0-NEXT: }
|
||||
|
||||
BLOCK01: Block Data {
|
||||
BLOCK01-NEXT: Block 0 (
|
||||
BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 |Microsoft C/C++ |
|
||||
BLOCK01-NEXT: 0010: 4D534620 372E3030 0D0A1A44 53000000 |MSF 7.00...DS...|
|
||||
BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 |................|
|
||||
BLOCK01-NEXT: 0030: 00000000 18000000 00000000 00000000 |................|
|
||||
BLOCK01: 0FE0: 00000000 00000000 00000000 00000000 |................|
|
||||
BLOCK01-NEXT: 0FF0: 00000000 00000000 00000000 00000000 |................|
|
||||
BLOCK01-NEXT: )
|
||||
BLOCK01-NEXT: Block 1 (
|
||||
BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
BLOCK01-NEXT: 0010: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
BLOCK01: 0FE0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
BLOCK01-NEXT: 0FF0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................|
|
||||
BLOCK01-NEXT: )
|
||||
BLOCK01-NEXT: }
|
||||
|
||||
BADSYNTAX: Argument '{{.*}}' invalid format.
|
||||
; RUN: llvm-pdbutil raw -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
|
||||
; RUN: llvm-pdbutil raw -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil raw -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
|
||||
BLOCK0: MSF Blocks
|
||||
BLOCK0-NEXT: ============================================================
|
||||
BLOCK0-NEXT: Block 0 (
|
||||
BLOCK0-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 4D534620 372E3030 0D0A1A44 53000000 |Microsoft C/C++ MSF 7.00...DS...|
|
||||
BLOCK0-NEXT: 0020: 00100000 02000000 19000000 88000000 00000000 18000000 00000000 00000000 |................................|
|
||||
BLOCK0-NEXT: 0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
|
||||
BLOCK0-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
|
||||
BLOCK0-NOT: Block 1 (
|
||||
|
||||
BLOCK01: MSF Blocks
|
||||
BLOCK01-NEXT: ============================================================
|
||||
BLOCK01-NEXT: Block 0 (
|
||||
BLOCK01-NEXT: 0000: 4D696372 6F736F66 7420432F 432B2B20 4D534620 372E3030 0D0A1A44 53000000 |Microsoft C/C++ MSF 7.00...DS...|
|
||||
BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 00000000 18000000 00000000 00000000 |................................|
|
||||
BLOCK01-NEXT: 0040: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
|
||||
BLOCK01-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................|
|
||||
BLOCK01: Block 1 (
|
||||
BLOCK01-NEXT: 0000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NEXT: 0020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NEXT: 0040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NOT: Block 2 (
|
||||
|
||||
BADSYNTAX: Argument '{{.*}}' invalid format.
|
||||
|
@ -1,23 +1,28 @@
|
||||
; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM1 %s
|
||||
; RUN: not llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
|
||||
|
||||
STREAM1: Stream Data {
|
||||
STREAM1-NEXT: Stream {
|
||||
STREAM1-NEXT: Index: 1
|
||||
STREAM1-NEXT: Type: PDB Stream
|
||||
STREAM1-NEXT: Size: 118
|
||||
STREAM1-NEXT: Blocks: [19]
|
||||
STREAM1-NEXT: Data (
|
||||
STREAM1-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 |..1....T.....5VA|
|
||||
STREAM1-NEXT: 0010: 86A0A249 896F9988 FAE52FF0 22000000 |...I.o..../."...|
|
||||
STREAM1-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 |/LinkInfo./names|
|
||||
STREAM1-NEXT: 0030: 002F7372 632F6865 61646572 626C6F63 |./src/headerbloc|
|
||||
STREAM1-NEXT: 0040: 6B000300 00000600 00000100 00001A00 |k...............|
|
||||
STREAM1-NEXT: 0050: 00000000 00001100 00000900 00000A00 |................|
|
||||
STREAM1-NEXT: 0060: 00000D00 00000000 00000500 00000000 |................|
|
||||
STREAM1-NEXT: 0070: 00004191 3201 |..A.2.|
|
||||
STREAM1-NEXT: )
|
||||
STREAM1-NEXT: }
|
||||
STREAM1-NEXT: }
|
||||
|
||||
INVALIDSTREAM: Native PDB Error: The specified stream could not be loaded.
|
||||
; RUN: llvm-pdbutil raw -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
|
||||
; RUN: llvm-pdbutil raw -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
|
||||
; RUN: llvm-pdbutil raw -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
|
||||
|
||||
STREAM: Stream Data
|
||||
STREAM-NEXT: ============================================================
|
||||
STREAM-NEXT: Stream 1 (118 bytes): PDB Stream
|
||||
STREAM-NEXT: Data (
|
||||
STREAM-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
|
||||
STREAM-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
|
||||
STREAM-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
|
||||
STREAM-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
|
||||
STREAM-NEXT: )
|
||||
|
||||
INVALIDSTREAM: Stream Data
|
||||
INVALIDSTREAM-NEXT: ============================================================
|
||||
INVALIDSTREAM-NEXT: Stream 100: Not present
|
||||
|
||||
BOTH: Stream Data
|
||||
BOTH-NEXT: ============================================================
|
||||
BOTH-NEXT: Stream 1 (118 bytes): PDB Stream
|
||||
BOTH-NEXT: Data (
|
||||
BOTH-NEXT: 0000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
|
||||
BOTH-NEXT: 0020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
|
||||
BOTH-NEXT: 0040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
|
||||
BOTH-NEXT: 0060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
|
||||
BOTH-NEXT: )
|
||||
BOTH-NEXT: Stream 100: Not present
|
||||
|
@ -3,48 +3,33 @@ RUN: -pdb-stream -string-table -tpi-stream -stream-directory \
|
||||
RUN: -stream-metadata %p/Inputs/empty.pdb > %t.1
|
||||
RUN: llvm-pdbutil yaml2pdb -pdb=%t.2 %t.1
|
||||
|
||||
RUN: llvm-pdbutil raw -headers -string-table -tpi-records %p/Inputs/empty.pdb | FileCheck %s
|
||||
RUN: llvm-pdbutil raw -headers -string-table -tpi-records %t.2 | FileCheck %s
|
||||
RUN: llvm-pdbutil raw -summary -string-table -types %p/Inputs/empty.pdb | FileCheck %s
|
||||
RUN: llvm-pdbutil raw -summary -string-table -types %t.2 | FileCheck %s
|
||||
|
||||
CHECK: FileHeaders {
|
||||
CHECK-NEXT: BlockSize: 4096
|
||||
CHECK-NEXT: FreeBlockMap:
|
||||
CHECK-NEXT: NumBlocks:
|
||||
CHECK-NEXT: NumDirectoryBytes:
|
||||
CHECK-NEXT: Unknown1: 0
|
||||
CHECK-NEXT: BlockMapAddr:
|
||||
CHECK-NEXT: NumDirectoryBlocks: 1
|
||||
CHECK-NEXT: DirectoryBlocks:
|
||||
CHECK-NEXT: NumStreams:
|
||||
CHECK-NEXT: }
|
||||
CHECK: String Table {
|
||||
CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)'
|
||||
CHECK-DAG: 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp'
|
||||
CHECK-DAG: '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
|
||||
CHECK-NEXT: }
|
||||
CHECK: PDB Stream {
|
||||
CHECK-NEXT: Version: 20000404
|
||||
CHECK-NEXT: Signature: 0x54E507E2
|
||||
CHECK-NEXT: Age: 1
|
||||
CHECK-NEXT: Guid: {0B355641-86A0-A249-896F-9988FAE52FF0}
|
||||
CHECK-NEXT: Features: 0x1
|
||||
CHECK-NEXT: Named Streams {
|
||||
CHECK: /names:
|
||||
CHECK: }
|
||||
CHECK-NEXT: }
|
||||
CHECK: Type Info Stream (TPI) {
|
||||
CHECK-NEXT: TPI Version: 20040203
|
||||
CHECK-NEXT: Record count: 75
|
||||
CHECK: DBI Stream {
|
||||
CHECK-NEXT: Dbi Version: 19990903
|
||||
CHECK-NEXT: Age: 1
|
||||
CHECK-NEXT: Incremental Linking: Yes
|
||||
CHECK-NEXT: Has CTypes: No
|
||||
CHECK-NEXT: Is Stripped: No
|
||||
CHECK-NEXT: Machine Type: x86
|
||||
CHECK-NEXT: Symbol Record Stream Index:
|
||||
CHECK-NEXT: Public Symbol Stream Index:
|
||||
CHECK-NEXT: Global Symbol Stream Index:
|
||||
CHECK-NEXT: Toolchain Version: 12.0
|
||||
CHECK-NEXT: mspdb120.dll version: 12.0.31101
|
||||
CHECK-NEXT: }
|
||||
|
||||
CHECK: Summary
|
||||
CHECK-NEXT: ============================================================
|
||||
CHECK-NEXT: Block Size: 4096
|
||||
CHECK-NEXT: Number of blocks:
|
||||
CHECK-NEXT: Number of streams:
|
||||
CHECK-NEXT: Signature: 1424295906
|
||||
CHECK-NEXT: Age: 1
|
||||
CHECK-NEXT: GUID: {0B355641-86A0-A249-896F-9988FAE52FF0}
|
||||
CHECK-NEXT: Features: 0x1
|
||||
CHECK-NEXT: Has Debug Info: true
|
||||
CHECK-NEXT: Has Types: true
|
||||
CHECK-NEXT: Has IDs: true
|
||||
CHECK-NEXT: Has Globals:
|
||||
CHECK-NEXT: Has Publics:
|
||||
CHECK-NEXT: Is incrementally linked: true
|
||||
CHECK-NEXT: Has conflicting types: false
|
||||
CHECK-NEXT: Is stripped: false
|
||||
CHECK: String Table
|
||||
CHECK-NEXT: ============================================================
|
||||
CHECK-NEXT: ID | String
|
||||
CHECK-NEXT: {{.*}} | 'd:\src\llvm\test\debuginfo\pdb\inputs\predefined c++ attributes (compiler internal)'
|
||||
CHECK-NEXT: {{.*}} | 'd:\src\llvm\test\debuginfo\pdb\inputs\empty.cpp'
|
||||
CHECK-NEXT: {{.*}} | '$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = '
|
||||
CHECK: Types (TPI Stream)
|
||||
CHECK-NEXT: ============================================================
|
||||
CHECK-NEXT: Showing 75 records
|
||||
|
@ -1,47 +0,0 @@
|
||||
; RUN: llvm-pdbutil raw -stream-data=8 %p/Inputs/LoadAddressTest.pdb \
|
||||
; RUN: | FileCheck %s -check-prefix=FULL_STREAM
|
||||
; RUN: llvm-pdbutil raw -stream-data=8:4 %p/Inputs/LoadAddressTest.pdb \
|
||||
; RUN: | FileCheck %s -check-prefix=OFFSET_STREAM
|
||||
; RUN: llvm-pdbutil raw -stream-data=8:4@24 %p/Inputs/LoadAddressTest.pdb \
|
||||
; RUN: | FileCheck %s -check-prefix=OFFSET_AND_LENGTH
|
||||
|
||||
FULL_STREAM: Stream Data {
|
||||
FULL_STREAM-NEXT: Stream {
|
||||
FULL_STREAM-NEXT: Index: 8
|
||||
FULL_STREAM-NEXT: Type: Public Symbol Records
|
||||
FULL_STREAM-NEXT: Size: 40
|
||||
FULL_STREAM-NEXT: Blocks:
|
||||
FULL_STREAM-NEXT: Data (
|
||||
FULL_STREAM-NEXT: 0000: 12000E11 02000000 10000000 01005F6D |.............._m|
|
||||
FULL_STREAM-NEXT: 0010: 61696E00 12002511 00000000 88000000 |ain...%.........|
|
||||
FULL_STREAM-NEXT: 0020: 01006D61 696E0000 |..main..|
|
||||
FULL_STREAM-NEXT: )
|
||||
FULL_STREAM-NEXT: }
|
||||
FULL_STREAM-NEXT: }
|
||||
|
||||
OFFSET_STREAM: Stream Data {
|
||||
OFFSET_STREAM-NEXT: Stream {
|
||||
OFFSET_STREAM-NEXT: Index: 8
|
||||
OFFSET_STREAM-NEXT: Type: Public Symbol Records
|
||||
OFFSET_STREAM-NEXT: Size: 40
|
||||
OFFSET_STREAM-NEXT: Blocks:
|
||||
OFFSET_STREAM-NEXT: Data (
|
||||
OFFSET_STREAM-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.|
|
||||
OFFSET_STREAM-NEXT: 0014: 12002511 00000000 88000000 01006D61 |..%...........ma|
|
||||
OFFSET_STREAM-NEXT: 0024: 696E0000 |in..|
|
||||
OFFSET_STREAM-NEXT: )
|
||||
OFFSET_STREAM-NEXT: }
|
||||
OFFSET_STREAM-NEXT:}
|
||||
|
||||
OFFSET_AND_LENGTH: Stream Data {
|
||||
OFFSET_AND_LENGTH-NEXT: Stream {
|
||||
OFFSET_AND_LENGTH-NEXT: Index: 8
|
||||
OFFSET_AND_LENGTH-NEXT: Type: Public Symbol Records
|
||||
OFFSET_AND_LENGTH-NEXT: Size: 40
|
||||
OFFSET_AND_LENGTH-NEXT: Blocks:
|
||||
OFFSET_AND_LENGTH-NEXT: Data (
|
||||
OFFSET_AND_LENGTH-NEXT: 0004: 02000000 10000000 01005F6D 61696E00 |.........._main.|
|
||||
OFFSET_AND_LENGTH-NEXT: 0014: 12002511 00000000 |..%.....|
|
||||
OFFSET_AND_LENGTH-NEXT: )
|
||||
OFFSET_AND_LENGTH-NEXT: }
|
||||
OFFSET_AND_LENGTH-NEXT:}
|
@ -12,8 +12,10 @@ add_llvm_tool(llvm-pdbutil
|
||||
CompactTypeDumpVisitor.cpp
|
||||
Diff.cpp
|
||||
llvm-pdbutil.cpp
|
||||
FormatUtil.cpp
|
||||
LinePrinter.cpp
|
||||
LLVMOutputStyle.cpp
|
||||
MinimalSymbolDumper.cpp
|
||||
MinimalTypeDumper.cpp
|
||||
PdbYaml.cpp
|
||||
PrettyBuiltinDumper.cpp
|
||||
PrettyClassDefinitionDumper.cpp
|
||||
@ -25,6 +27,7 @@ add_llvm_tool(llvm-pdbutil
|
||||
PrettyTypeDumper.cpp
|
||||
PrettyTypedefDumper.cpp
|
||||
PrettyVariableDumper.cpp
|
||||
RawOutputStyle.cpp
|
||||
StreamUtil.cpp
|
||||
YAMLOutputStyle.cpp
|
||||
)
|
||||
|
49
tools/llvm-pdbutil/FormatUtil.cpp
Normal file
49
tools/llvm-pdbutil/FormatUtil.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
//===- FormatUtil.cpp ----------------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FormatUtil.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
std::string llvm::pdb::typesetItemList(ArrayRef<std::string> Opts,
|
||||
uint32_t GroupSize, uint32_t IndentLevel,
|
||||
StringRef Sep) {
|
||||
std::string Result;
|
||||
while (!Opts.empty()) {
|
||||
ArrayRef<std::string> ThisGroup;
|
||||
ThisGroup = Opts.take_front(GroupSize);
|
||||
Opts = Opts.drop_front(ThisGroup.size());
|
||||
Result += join(ThisGroup, Sep);
|
||||
if (!Opts.empty()) {
|
||||
Result += Sep;
|
||||
Result += "\n";
|
||||
Result += formatv("{0}", fmt_repeat(' ', IndentLevel));
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string llvm::pdb::typesetStringList(uint32_t IndentLevel,
|
||||
ArrayRef<StringRef> Strings) {
|
||||
std::string Result = "[";
|
||||
for (const auto &S : Strings) {
|
||||
Result += formatv("\n{0}{1}", fmt_repeat(' ', IndentLevel), S);
|
||||
}
|
||||
Result += "]";
|
||||
return Result;
|
||||
}
|
||||
|
||||
std::string llvm::pdb::formatSegmentOffset(uint16_t Segment, uint32_t Offset) {
|
||||
return formatv("{0:4}:{1:4}", Segment, Offset);
|
||||
}
|
120
tools/llvm-pdbutil/FormatUtil.h
Normal file
120
tools/llvm-pdbutil/FormatUtil.h
Normal file
@ -0,0 +1,120 @@
|
||||
//===- FormatUtil.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_TOOLS_LLVMPDBUTIL_FORMAT_UTIL_H
|
||||
#define LLVM_TOOLS_LLVMPDBUTIL_FORMAT_UTIL_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace llvm {
|
||||
namespace pdb {
|
||||
|
||||
#define PUSH_MASKED_FLAG(Enum, Mask, TheOpt, Value, Text) \
|
||||
if (Enum::TheOpt == (Value & Mask)) \
|
||||
Opts.push_back(Text);
|
||||
|
||||
#define PUSH_FLAG(Enum, TheOpt, Value, Text) \
|
||||
PUSH_MASKED_FLAG(Enum, Enum::TheOpt, TheOpt, Value, Text)
|
||||
|
||||
#define RETURN_CASE(Enum, X, Ret) \
|
||||
case Enum::X: \
|
||||
return Ret;
|
||||
|
||||
template <typename T> static std::string formatUnknownEnum(T Value) {
|
||||
return formatv("unknown ({0})",
|
||||
static_cast<typename std::underlying_type<T>::type>(Value))
|
||||
.str();
|
||||
}
|
||||
|
||||
std::string formatSegmentOffset(uint16_t Segment, uint32_t Offset);
|
||||
|
||||
std::string typesetItemList(ArrayRef<std::string> Opts, uint32_t IndentLevel,
|
||||
uint32_t GroupSize, StringRef Sep);
|
||||
|
||||
std::string typesetStringList(uint32_t IndentLevel,
|
||||
ArrayRef<StringRef> Strings);
|
||||
|
||||
/// Returns the number of digits in the given integer.
|
||||
inline int NumDigits(uint64_t N) {
|
||||
if (N < 10ULL)
|
||||
return 1;
|
||||
if (N < 100ULL)
|
||||
return 2;
|
||||
if (N < 1000ULL)
|
||||
return 3;
|
||||
if (N < 10000ULL)
|
||||
return 4;
|
||||
if (N < 100000ULL)
|
||||
return 5;
|
||||
if (N < 1000000ULL)
|
||||
return 6;
|
||||
if (N < 10000000ULL)
|
||||
return 7;
|
||||
if (N < 100000000ULL)
|
||||
return 8;
|
||||
if (N < 1000000000ULL)
|
||||
return 9;
|
||||
if (N < 10000000000ULL)
|
||||
return 10;
|
||||
if (N < 100000000000ULL)
|
||||
return 11;
|
||||
if (N < 1000000000000ULL)
|
||||
return 12;
|
||||
if (N < 10000000000000ULL)
|
||||
return 13;
|
||||
if (N < 100000000000000ULL)
|
||||
return 14;
|
||||
if (N < 1000000000000000ULL)
|
||||
return 15;
|
||||
if (N < 10000000000000000ULL)
|
||||
return 16;
|
||||
if (N < 100000000000000000ULL)
|
||||
return 17;
|
||||
if (N < 1000000000000000000ULL)
|
||||
return 18;
|
||||
if (N < 10000000000000000000ULL)
|
||||
return 19;
|
||||
return 20;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct EndianAdapter final
|
||||
: public FormatAdapter<support::detail::packed_endian_specific_integral<
|
||||
T, support::little, support::unaligned>> {
|
||||
using EndianType =
|
||||
support::detail::packed_endian_specific_integral<T, support::little,
|
||||
support::unaligned>;
|
||||
|
||||
explicit EndianAdapter(EndianType &&Item)
|
||||
: FormatAdapter<EndianType>(std::move(Item)) {}
|
||||
|
||||
void format(llvm::raw_ostream &Stream, StringRef Style) {
|
||||
format_provider<T>::format(static_cast<T>(this->Item), Stream, Style);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
detail::EndianAdapter<T>
|
||||
fmtle(support::detail::packed_endian_specific_integral<T, support::little,
|
||||
support::unaligned>
|
||||
Value) {
|
||||
return detail::EndianAdapter<T>(std::move(Value));
|
||||
}
|
||||
}
|
||||
} // namespace llvm
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,7 @@
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/DebugInfo/PDB/UDTLayout.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -60,10 +61,16 @@ LinePrinter::LinePrinter(int Indent, bool UseColor, llvm::raw_ostream &Stream)
|
||||
opts::pretty::IncludeCompilands.end());
|
||||
}
|
||||
|
||||
void LinePrinter::Indent() { CurrentIndent += IndentSpaces; }
|
||||
void LinePrinter::Indent(uint32_t Amount) {
|
||||
if (Amount == 0)
|
||||
Amount = IndentSpaces;
|
||||
CurrentIndent += Amount;
|
||||
}
|
||||
|
||||
void LinePrinter::Unindent() {
|
||||
CurrentIndent = std::max(0, CurrentIndent - IndentSpaces);
|
||||
void LinePrinter::Unindent(uint32_t Amount) {
|
||||
if (Amount == 0)
|
||||
Amount = IndentSpaces;
|
||||
CurrentIndent = std::max<int>(0, CurrentIndent - Amount);
|
||||
}
|
||||
|
||||
void LinePrinter::NewLine() {
|
||||
@ -71,6 +78,13 @@ void LinePrinter::NewLine() {
|
||||
OS.indent(CurrentIndent);
|
||||
}
|
||||
|
||||
void LinePrinter::print(const Twine &T) { OS << T; }
|
||||
|
||||
void LinePrinter::printLine(const Twine &T) {
|
||||
NewLine();
|
||||
OS << T;
|
||||
}
|
||||
|
||||
bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
|
||||
if (IsTypeExcluded(Class.getName(), Class.getSize()))
|
||||
return true;
|
||||
@ -79,6 +93,19 @@ bool LinePrinter::IsClassExcluded(const ClassLayout &Class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
|
||||
uint32_t StartOffset) {
|
||||
NewLine();
|
||||
OS << Label << " (";
|
||||
if (!Data.empty()) {
|
||||
OS << "\n";
|
||||
OS << format_bytes_with_ascii(Data, StartOffset, 32, 4,
|
||||
CurrentIndent + IndentSpaces, true);
|
||||
NewLine();
|
||||
}
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
|
||||
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
|
||||
return true;
|
||||
|
@ -10,10 +10,12 @@
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
@ -28,10 +30,22 @@ class LinePrinter {
|
||||
public:
|
||||
LinePrinter(int Indent, bool UseColor, raw_ostream &Stream);
|
||||
|
||||
void Indent();
|
||||
void Unindent();
|
||||
void Indent(uint32_t Amount = 0);
|
||||
void Unindent(uint32_t Amount = 0);
|
||||
void NewLine();
|
||||
|
||||
void printLine(const Twine &T);
|
||||
void print(const Twine &T);
|
||||
template <typename... Ts> void formatLine(const char *Fmt, Ts &&... Items) {
|
||||
printLine(formatv(Fmt, std::forward<Ts>(Items)...));
|
||||
}
|
||||
template <typename... Ts> void format(const char *Fmt, Ts &&... Items) {
|
||||
print(formatv(Fmt, std::forward<Ts>(Items)...));
|
||||
}
|
||||
|
||||
void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
|
||||
uint32_t StartOffset);
|
||||
|
||||
bool hasColor() const { return UseColor; }
|
||||
raw_ostream &getStream() { return OS; }
|
||||
int getIndentLevel() const { return CurrentIndent; }
|
||||
@ -63,6 +77,17 @@ private:
|
||||
std::list<Regex> IncludeSymbolFilters;
|
||||
};
|
||||
|
||||
struct AutoIndent {
|
||||
explicit AutoIndent(LinePrinter &L, uint32_t Amount = 0)
|
||||
: L(L), Amount(Amount) {
|
||||
L.Indent(Amount);
|
||||
}
|
||||
~AutoIndent() { L.Unindent(Amount); }
|
||||
|
||||
LinePrinter &L;
|
||||
uint32_t Amount = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
|
||||
Printer.getStream() << Item;
|
||||
|
749
tools/llvm-pdbutil/MinimalSymbolDumper.cpp
Normal file
749
tools/llvm-pdbutil/MinimalSymbolDumper.cpp
Normal file
@ -0,0 +1,749 @@
|
||||
//===- MinimalSymbolDumper.cpp -------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MinimalSymbolDumper.h"
|
||||
|
||||
#include "FormatUtil.h"
|
||||
#include "LinePrinter.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/Formatters.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
static StringRef getSymbolKindName(SymbolKind K) {
|
||||
switch (K) {
|
||||
#define SYMBOL_RECORD(EnumName, value, name) \
|
||||
case EnumName: \
|
||||
return #EnumName;
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
default:
|
||||
llvm_unreachable("Unknown symbol kind!");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string formatLocalSymFlags(uint32_t IndentLevel,
|
||||
LocalSymFlags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
if (Flags == LocalSymFlags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(LocalSymFlags, IsParameter, Flags, "param");
|
||||
PUSH_FLAG(LocalSymFlags, IsAddressTaken, Flags, "address is taken");
|
||||
PUSH_FLAG(LocalSymFlags, IsCompilerGenerated, Flags, "compiler generated");
|
||||
PUSH_FLAG(LocalSymFlags, IsAggregate, Flags, "aggregate");
|
||||
PUSH_FLAG(LocalSymFlags, IsAggregated, Flags, "aggregated");
|
||||
PUSH_FLAG(LocalSymFlags, IsAliased, Flags, "aliased");
|
||||
PUSH_FLAG(LocalSymFlags, IsAlias, Flags, "alias");
|
||||
PUSH_FLAG(LocalSymFlags, IsReturnValue, Flags, "return val");
|
||||
PUSH_FLAG(LocalSymFlags, IsOptimizedOut, Flags, "optimized away");
|
||||
PUSH_FLAG(LocalSymFlags, IsEnregisteredGlobal, Flags, "enreg global");
|
||||
PUSH_FLAG(LocalSymFlags, IsEnregisteredStatic, Flags, "enreg static");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatExportFlags(uint32_t IndentLevel, ExportFlags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
if (Flags == ExportFlags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(ExportFlags, IsConstant, Flags, "constant");
|
||||
PUSH_FLAG(ExportFlags, IsData, Flags, "data");
|
||||
PUSH_FLAG(ExportFlags, IsPrivate, Flags, "private");
|
||||
PUSH_FLAG(ExportFlags, HasNoName, Flags, "no name");
|
||||
PUSH_FLAG(ExportFlags, HasExplicitOrdinal, Flags, "explicit ord");
|
||||
PUSH_FLAG(ExportFlags, IsForwarder, Flags, "forwarder");
|
||||
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatCompileSym2Flags(uint32_t IndentLevel,
|
||||
CompileSym2Flags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
Flags &= ~CompileSym2Flags::SourceLanguageMask;
|
||||
if (Flags == CompileSym2Flags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(CompileSym2Flags, EC, Flags, "edit and continue");
|
||||
PUSH_FLAG(CompileSym2Flags, NoDbgInfo, Flags, "no dbg info");
|
||||
PUSH_FLAG(CompileSym2Flags, LTCG, Flags, "ltcg");
|
||||
PUSH_FLAG(CompileSym2Flags, NoDataAlign, Flags, "no data align");
|
||||
PUSH_FLAG(CompileSym2Flags, ManagedPresent, Flags, "has managed code");
|
||||
PUSH_FLAG(CompileSym2Flags, SecurityChecks, Flags, "security checks");
|
||||
PUSH_FLAG(CompileSym2Flags, HotPatch, Flags, "hot patchable");
|
||||
PUSH_FLAG(CompileSym2Flags, CVTCIL, Flags, "cvtcil");
|
||||
PUSH_FLAG(CompileSym2Flags, MSILModule, Flags, "msil module");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatCompileSym3Flags(uint32_t IndentLevel,
|
||||
CompileSym3Flags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
Flags &= ~CompileSym3Flags::SourceLanguageMask;
|
||||
|
||||
if (Flags == CompileSym3Flags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(CompileSym3Flags, EC, Flags, "edit and continue");
|
||||
PUSH_FLAG(CompileSym3Flags, NoDbgInfo, Flags, "no dbg info");
|
||||
PUSH_FLAG(CompileSym3Flags, LTCG, Flags, "ltcg");
|
||||
PUSH_FLAG(CompileSym3Flags, NoDataAlign, Flags, "no data align");
|
||||
PUSH_FLAG(CompileSym3Flags, ManagedPresent, Flags, "has managed code");
|
||||
PUSH_FLAG(CompileSym3Flags, SecurityChecks, Flags, "security checks");
|
||||
PUSH_FLAG(CompileSym3Flags, HotPatch, Flags, "hot patchable");
|
||||
PUSH_FLAG(CompileSym3Flags, CVTCIL, Flags, "cvtcil");
|
||||
PUSH_FLAG(CompileSym3Flags, MSILModule, Flags, "msil module");
|
||||
PUSH_FLAG(CompileSym3Flags, Sdl, Flags, "sdl");
|
||||
PUSH_FLAG(CompileSym3Flags, PGO, Flags, "pgo");
|
||||
PUSH_FLAG(CompileSym3Flags, Exp, Flags, "exp");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatFrameProcedureOptions(uint32_t IndentLevel,
|
||||
FrameProcedureOptions FPO) {
|
||||
std::vector<std::string> Opts;
|
||||
if (FPO == FrameProcedureOptions::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(FrameProcedureOptions, HasAlloca, FPO, "has alloca");
|
||||
PUSH_FLAG(FrameProcedureOptions, HasSetJmp, FPO, "has setjmp");
|
||||
PUSH_FLAG(FrameProcedureOptions, HasLongJmp, FPO, "has longjmp");
|
||||
PUSH_FLAG(FrameProcedureOptions, HasInlineAssembly, FPO, "has inline asm");
|
||||
PUSH_FLAG(FrameProcedureOptions, HasExceptionHandling, FPO, "has eh");
|
||||
PUSH_FLAG(FrameProcedureOptions, MarkedInline, FPO, "marked inline");
|
||||
PUSH_FLAG(FrameProcedureOptions, HasStructuredExceptionHandling, FPO,
|
||||
"has seh");
|
||||
PUSH_FLAG(FrameProcedureOptions, Naked, FPO, "naked");
|
||||
PUSH_FLAG(FrameProcedureOptions, SecurityChecks, FPO, "secure checks");
|
||||
PUSH_FLAG(FrameProcedureOptions, AsynchronousExceptionHandling, FPO,
|
||||
"has async eh");
|
||||
PUSH_FLAG(FrameProcedureOptions, NoStackOrderingForSecurityChecks, FPO,
|
||||
"no stack order");
|
||||
PUSH_FLAG(FrameProcedureOptions, Inlined, FPO, "inlined");
|
||||
PUSH_FLAG(FrameProcedureOptions, StrictSecurityChecks, FPO,
|
||||
"strict secure checks");
|
||||
PUSH_FLAG(FrameProcedureOptions, SafeBuffers, FPO, "safe buffers");
|
||||
PUSH_FLAG(FrameProcedureOptions, ProfileGuidedOptimization, FPO, "pgo");
|
||||
PUSH_FLAG(FrameProcedureOptions, ValidProfileCounts, FPO,
|
||||
"has profile counts");
|
||||
PUSH_FLAG(FrameProcedureOptions, OptimizedForSpeed, FPO, "opt speed");
|
||||
PUSH_FLAG(FrameProcedureOptions, GuardCfg, FPO, "guard cfg");
|
||||
PUSH_FLAG(FrameProcedureOptions, GuardCfw, FPO, "guard cfw");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatProcSymFlags(uint32_t IndentLevel,
|
||||
ProcSymFlags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
if (Flags == ProcSymFlags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(ProcSymFlags, HasFP, Flags, "has fp");
|
||||
PUSH_FLAG(ProcSymFlags, HasIRET, Flags, "has iret");
|
||||
PUSH_FLAG(ProcSymFlags, HasFRET, Flags, "has fret");
|
||||
PUSH_FLAG(ProcSymFlags, IsNoReturn, Flags, "noreturn");
|
||||
PUSH_FLAG(ProcSymFlags, IsUnreachable, Flags, "unreachable");
|
||||
PUSH_FLAG(ProcSymFlags, HasCustomCallingConv, Flags, "custom calling conv");
|
||||
PUSH_FLAG(ProcSymFlags, IsNoInline, Flags, "noinline");
|
||||
PUSH_FLAG(ProcSymFlags, HasOptimizedDebugInfo, Flags, "opt debuginfo");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatThunkOrdinal(ThunkOrdinal Ordinal) {
|
||||
switch (Ordinal) {
|
||||
RETURN_CASE(ThunkOrdinal, Standard, "thunk");
|
||||
RETURN_CASE(ThunkOrdinal, ThisAdjustor, "this adjustor");
|
||||
RETURN_CASE(ThunkOrdinal, Vcall, "vcall");
|
||||
RETURN_CASE(ThunkOrdinal, Pcode, "pcode");
|
||||
RETURN_CASE(ThunkOrdinal, UnknownLoad, "unknown load");
|
||||
RETURN_CASE(ThunkOrdinal, TrampIncremental, "tramp incremental");
|
||||
RETURN_CASE(ThunkOrdinal, BranchIsland, "branch island");
|
||||
}
|
||||
return formatUnknownEnum(Ordinal);
|
||||
}
|
||||
|
||||
static std::string formatTrampolineType(TrampolineType Tramp) {
|
||||
switch (Tramp) {
|
||||
RETURN_CASE(TrampolineType, TrampIncremental, "tramp incremental");
|
||||
RETURN_CASE(TrampolineType, BranchIsland, "branch island");
|
||||
}
|
||||
return formatUnknownEnum(Tramp);
|
||||
}
|
||||
|
||||
static std::string formatSourceLanguage(SourceLanguage Lang) {
|
||||
switch (Lang) {
|
||||
RETURN_CASE(SourceLanguage, C, "c");
|
||||
RETURN_CASE(SourceLanguage, Cpp, "c++");
|
||||
RETURN_CASE(SourceLanguage, Fortran, "fortran");
|
||||
RETURN_CASE(SourceLanguage, Masm, "masm");
|
||||
RETURN_CASE(SourceLanguage, Pascal, "pascal");
|
||||
RETURN_CASE(SourceLanguage, Basic, "basic");
|
||||
RETURN_CASE(SourceLanguage, Cobol, "cobol");
|
||||
RETURN_CASE(SourceLanguage, Link, "link");
|
||||
RETURN_CASE(SourceLanguage, VB, "vb");
|
||||
RETURN_CASE(SourceLanguage, Cvtres, "cvtres");
|
||||
RETURN_CASE(SourceLanguage, Cvtpgd, "cvtpgd");
|
||||
RETURN_CASE(SourceLanguage, CSharp, "c#");
|
||||
RETURN_CASE(SourceLanguage, ILAsm, "il asm");
|
||||
RETURN_CASE(SourceLanguage, Java, "java");
|
||||
RETURN_CASE(SourceLanguage, JScript, "javascript");
|
||||
RETURN_CASE(SourceLanguage, MSIL, "msil");
|
||||
RETURN_CASE(SourceLanguage, HLSL, "hlsl");
|
||||
}
|
||||
return formatUnknownEnum(Lang);
|
||||
}
|
||||
|
||||
static std::string formatMachineType(CPUType Cpu) {
|
||||
switch (Cpu) {
|
||||
RETURN_CASE(CPUType, Intel8080, "intel 8080");
|
||||
RETURN_CASE(CPUType, Intel8086, "intel 8086");
|
||||
RETURN_CASE(CPUType, Intel80286, "intel 80286");
|
||||
RETURN_CASE(CPUType, Intel80386, "intel 80386");
|
||||
RETURN_CASE(CPUType, Intel80486, "intel 80486");
|
||||
RETURN_CASE(CPUType, Pentium, "intel pentium");
|
||||
RETURN_CASE(CPUType, PentiumPro, "intel pentium pro");
|
||||
RETURN_CASE(CPUType, Pentium3, "intel pentium 3");
|
||||
RETURN_CASE(CPUType, MIPS, "mips");
|
||||
RETURN_CASE(CPUType, MIPS16, "mips-16");
|
||||
RETURN_CASE(CPUType, MIPS32, "mips-32");
|
||||
RETURN_CASE(CPUType, MIPS64, "mips-64");
|
||||
RETURN_CASE(CPUType, MIPSI, "mips i");
|
||||
RETURN_CASE(CPUType, MIPSII, "mips ii");
|
||||
RETURN_CASE(CPUType, MIPSIII, "mips iii");
|
||||
RETURN_CASE(CPUType, MIPSIV, "mips iv");
|
||||
RETURN_CASE(CPUType, MIPSV, "mips v");
|
||||
RETURN_CASE(CPUType, M68000, "motorola 68000");
|
||||
RETURN_CASE(CPUType, M68010, "motorola 68010");
|
||||
RETURN_CASE(CPUType, M68020, "motorola 68020");
|
||||
RETURN_CASE(CPUType, M68030, "motorola 68030");
|
||||
RETURN_CASE(CPUType, M68040, "motorola 68040");
|
||||
RETURN_CASE(CPUType, Alpha, "alpha");
|
||||
RETURN_CASE(CPUType, Alpha21164, "alpha 21164");
|
||||
RETURN_CASE(CPUType, Alpha21164A, "alpha 21164a");
|
||||
RETURN_CASE(CPUType, Alpha21264, "alpha 21264");
|
||||
RETURN_CASE(CPUType, Alpha21364, "alpha 21364");
|
||||
RETURN_CASE(CPUType, PPC601, "powerpc 601");
|
||||
RETURN_CASE(CPUType, PPC603, "powerpc 603");
|
||||
RETURN_CASE(CPUType, PPC604, "powerpc 604");
|
||||
RETURN_CASE(CPUType, PPC620, "powerpc 620");
|
||||
RETURN_CASE(CPUType, PPCFP, "powerpc fp");
|
||||
RETURN_CASE(CPUType, PPCBE, "powerpc be");
|
||||
RETURN_CASE(CPUType, SH3, "sh3");
|
||||
RETURN_CASE(CPUType, SH3E, "sh3e");
|
||||
RETURN_CASE(CPUType, SH3DSP, "sh3 dsp");
|
||||
RETURN_CASE(CPUType, SH4, "sh4");
|
||||
RETURN_CASE(CPUType, SHMedia, "shmedia");
|
||||
RETURN_CASE(CPUType, ARM3, "arm 3");
|
||||
RETURN_CASE(CPUType, ARM4, "arm 4");
|
||||
RETURN_CASE(CPUType, ARM4T, "arm 4t");
|
||||
RETURN_CASE(CPUType, ARM5, "arm 5");
|
||||
RETURN_CASE(CPUType, ARM5T, "arm 5t");
|
||||
RETURN_CASE(CPUType, ARM6, "arm 6");
|
||||
RETURN_CASE(CPUType, ARM_XMAC, "arm xmac");
|
||||
RETURN_CASE(CPUType, ARM_WMMX, "arm wmmx");
|
||||
RETURN_CASE(CPUType, ARM7, "arm 7");
|
||||
RETURN_CASE(CPUType, Omni, "omni");
|
||||
RETURN_CASE(CPUType, Ia64, "intel itanium ia64");
|
||||
RETURN_CASE(CPUType, Ia64_2, "intel itanium ia64 2");
|
||||
RETURN_CASE(CPUType, CEE, "cee");
|
||||
RETURN_CASE(CPUType, AM33, "am33");
|
||||
RETURN_CASE(CPUType, M32R, "m32r");
|
||||
RETURN_CASE(CPUType, TriCore, "tri-core");
|
||||
RETURN_CASE(CPUType, X64, "intel x86-x64");
|
||||
RETURN_CASE(CPUType, EBC, "ebc");
|
||||
RETURN_CASE(CPUType, Thumb, "thumb");
|
||||
RETURN_CASE(CPUType, ARMNT, "arm nt");
|
||||
RETURN_CASE(CPUType, D3D11_Shader, "d3d11 shader");
|
||||
}
|
||||
return formatUnknownEnum(Cpu);
|
||||
}
|
||||
|
||||
static std::string formatCookieKind(FrameCookieKind Kind) {
|
||||
switch (Kind) {
|
||||
RETURN_CASE(FrameCookieKind, Copy, "copy");
|
||||
RETURN_CASE(FrameCookieKind, XorStackPointer, "xor stack ptr");
|
||||
RETURN_CASE(FrameCookieKind, XorFramePointer, "xor frame ptr");
|
||||
RETURN_CASE(FrameCookieKind, XorR13, "xor rot13");
|
||||
}
|
||||
return formatUnknownEnum(Kind);
|
||||
}
|
||||
|
||||
static std::string formatRegisterId(RegisterId Id) {
|
||||
switch (Id) {
|
||||
RETURN_CASE(RegisterId, VFrame, "vframe");
|
||||
RETURN_CASE(RegisterId, AL, "al");
|
||||
RETURN_CASE(RegisterId, CL, "cl");
|
||||
RETURN_CASE(RegisterId, DL, "dl");
|
||||
RETURN_CASE(RegisterId, BL, "bl");
|
||||
RETURN_CASE(RegisterId, AH, "ah");
|
||||
RETURN_CASE(RegisterId, CH, "ch");
|
||||
RETURN_CASE(RegisterId, DH, "dh");
|
||||
RETURN_CASE(RegisterId, BH, "bh");
|
||||
RETURN_CASE(RegisterId, AX, "ax");
|
||||
RETURN_CASE(RegisterId, CX, "cx");
|
||||
RETURN_CASE(RegisterId, DX, "dx");
|
||||
RETURN_CASE(RegisterId, BX, "bx");
|
||||
RETURN_CASE(RegisterId, SP, "sp");
|
||||
RETURN_CASE(RegisterId, BP, "bp");
|
||||
RETURN_CASE(RegisterId, SI, "si");
|
||||
RETURN_CASE(RegisterId, DI, "di");
|
||||
RETURN_CASE(RegisterId, EAX, "eax");
|
||||
RETURN_CASE(RegisterId, ECX, "ecx");
|
||||
RETURN_CASE(RegisterId, EDX, "edx");
|
||||
RETURN_CASE(RegisterId, EBX, "ebx");
|
||||
RETURN_CASE(RegisterId, ESP, "esp");
|
||||
RETURN_CASE(RegisterId, EBP, "ebp");
|
||||
RETURN_CASE(RegisterId, ESI, "esi");
|
||||
RETURN_CASE(RegisterId, EDI, "edi");
|
||||
RETURN_CASE(RegisterId, ES, "es");
|
||||
RETURN_CASE(RegisterId, CS, "cs");
|
||||
RETURN_CASE(RegisterId, SS, "ss");
|
||||
RETURN_CASE(RegisterId, DS, "ds");
|
||||
RETURN_CASE(RegisterId, FS, "fs");
|
||||
RETURN_CASE(RegisterId, GS, "gs");
|
||||
RETURN_CASE(RegisterId, IP, "ip");
|
||||
RETURN_CASE(RegisterId, RAX, "rax");
|
||||
RETURN_CASE(RegisterId, RBX, "rbx");
|
||||
RETURN_CASE(RegisterId, RCX, "rcx");
|
||||
RETURN_CASE(RegisterId, RDX, "rdx");
|
||||
RETURN_CASE(RegisterId, RSI, "rsi");
|
||||
RETURN_CASE(RegisterId, RDI, "rdi");
|
||||
RETURN_CASE(RegisterId, RBP, "rbp");
|
||||
RETURN_CASE(RegisterId, RSP, "rsp");
|
||||
RETURN_CASE(RegisterId, R8, "r8");
|
||||
RETURN_CASE(RegisterId, R9, "r9");
|
||||
RETURN_CASE(RegisterId, R10, "r10");
|
||||
RETURN_CASE(RegisterId, R11, "r11");
|
||||
RETURN_CASE(RegisterId, R12, "r12");
|
||||
RETURN_CASE(RegisterId, R13, "r13");
|
||||
RETURN_CASE(RegisterId, R14, "r14");
|
||||
RETURN_CASE(RegisterId, R15, "r15");
|
||||
default:
|
||||
return formatUnknownEnum(Id);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string formatRange(LocalVariableAddrRange Range) {
|
||||
return formatv("[{0},+{1})",
|
||||
formatSegmentOffset(Range.ISectStart, Range.OffsetStart),
|
||||
Range.Range)
|
||||
.str();
|
||||
}
|
||||
|
||||
static std::string formatGaps(uint32_t IndentLevel,
|
||||
ArrayRef<LocalVariableAddrGap> Gaps) {
|
||||
std::vector<std::string> GapStrs;
|
||||
for (const auto &G : Gaps) {
|
||||
GapStrs.push_back(formatv("({0},{1})", G.GapStartOffset, G.Range).str());
|
||||
}
|
||||
return typesetItemList(GapStrs, 7, IndentLevel, ", ");
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitSymbolBegin(codeview::CVSymbol &Record) {
|
||||
// formatLine puts the newline at the beginning, so we use formatLine here
|
||||
// to start a new line, and then individual visit methods use format to
|
||||
// append to the existing line.
|
||||
P.formatLine("- {0} [size = {1}]", getSymbolKindName(Record.Type),
|
||||
Record.length());
|
||||
P.Indent();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitSymbolEnd(CVSymbol &Record) {
|
||||
P.Unindent();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
std::string MinimalSymbolDumper::typeIndex(TypeIndex TI) const {
|
||||
if (TI.isSimple())
|
||||
return formatv("{0}", TI).str();
|
||||
StringRef Name = Types.getTypeName(TI);
|
||||
if (Name.size() > 32) {
|
||||
Name = Name.take_front(32);
|
||||
return formatv("{0} ({1}...)", TI, Name);
|
||||
} else
|
||||
return formatv("{0} ({1})", TI, Name);
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
|
||||
P.format(" `{0}`", Block.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("parent = {0}, addr = {1}", Block.Parent,
|
||||
formatSegmentOffset(Block.Segment, Block.CodeOffset));
|
||||
P.formatLine("code size = {0}, end = {1}", Block.CodeSize, Block.End);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
|
||||
P.format(" `{0}`", Thunk.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("parent = {0}, addr = {1}", Thunk.Parent,
|
||||
formatSegmentOffset(Thunk.Segment, Thunk.Offset));
|
||||
P.formatLine("kind = {0}, size = {1}, end = {2}, next = {3}",
|
||||
formatThunkOrdinal(Thunk.Thunk), Thunk.Length, Thunk.End,
|
||||
Thunk.Next);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
TrampolineSym &Tramp) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, size = {1}, source = {2}, target = {3}",
|
||||
formatTrampolineType(Tramp.Type), Tramp.Size,
|
||||
formatSegmentOffset(Tramp.ThunkSection, Tramp.ThunkOffset),
|
||||
formatSegmentOffset(Tramp.TargetSection, Tramp.ThunkOffset));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
SectionSym &Section) {
|
||||
P.format(" `{0}`", Section.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("length = {0}, alignment = {1}, rva = {2}, section # = {3}, "
|
||||
"characteristics = {4}",
|
||||
Section.Length, Section.Alignment, Section.Rva,
|
||||
Section.SectionNumber, Section.Characteristics);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CoffGroupSym &CG) {
|
||||
P.format(" `{0}`", CG.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("length = {0}, addr = {1}, characteristics = {2}", CG.Size,
|
||||
formatSegmentOffset(CG.Segment, CG.Offset), CG.Characteristics);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
BPRelativeSym &BPRel) {
|
||||
P.format(" `{0}`", BPRel.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, offset = {1}", typeIndex(BPRel.Type), BPRel.Offset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
BuildInfoSym &BuildInfo) {
|
||||
P.format(" BuildId = `{0}`", BuildInfo.BuildId);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
CallSiteInfoSym &CSI) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, addr = {1}", typeIndex(CSI.Type),
|
||||
formatSegmentOffset(CSI.Segment, CSI.CodeOffset));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
EnvBlockSym &EnvBlock) {
|
||||
for (const auto &Entry : EnvBlock.Fields) {
|
||||
P.formatLine("- {0}", Entry);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FileStaticSym &FS) {
|
||||
P.format(" `{0}`", FS.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, file name offset = {1}, flags = {2}",
|
||||
typeIndex(FS.Index), FS.ModFilenameOffset,
|
||||
formatLocalSymFlags(P.getIndentLevel() + 9, FS.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
|
||||
P.format(" `{0}`", Export.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("ordinal = {0}, flags = {1}", Export.Ordinal,
|
||||
formatExportFlags(P.getIndentLevel() + 9, Export.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
Compile2Sym &Compile2) {
|
||||
AutoIndent Indent(P);
|
||||
SourceLanguage Lang = static_cast<SourceLanguage>(
|
||||
Compile2.Flags & CompileSym2Flags::SourceLanguageMask);
|
||||
P.formatLine("machine = {0}, ver = {1}, language = {2}",
|
||||
formatMachineType(Compile2.Machine), Compile2.Version,
|
||||
formatSourceLanguage(Lang));
|
||||
P.formatLine("frontend = {0}.{1}.{2}, backend = {3}.{4}.{5}",
|
||||
Compile2.VersionFrontendMajor, Compile2.VersionFrontendMinor,
|
||||
Compile2.VersionFrontendBuild, Compile2.VersionBackendMajor,
|
||||
Compile2.VersionBackendMinor, Compile2.VersionBackendBuild);
|
||||
P.formatLine("flags = {0}",
|
||||
formatCompileSym2Flags(P.getIndentLevel() + 9, Compile2.Flags));
|
||||
P.formatLine(
|
||||
"extra strings = {0}",
|
||||
typesetStringList(P.getIndentLevel() + 9 + 2, Compile2.ExtraStrings));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
Compile3Sym &Compile3) {
|
||||
AutoIndent Indent(P);
|
||||
SourceLanguage Lang = static_cast<SourceLanguage>(
|
||||
Compile3.Flags & CompileSym3Flags::SourceLanguageMask);
|
||||
P.formatLine("machine = {0}, Ver = {1}, language = {2}",
|
||||
formatMachineType(Compile3.Machine), Compile3.Version,
|
||||
formatSourceLanguage(Lang));
|
||||
P.formatLine("frontend = {0}.{1}.{2}.{3}, backend = {4}.{5}.{6}.{7}",
|
||||
Compile3.VersionFrontendMajor, Compile3.VersionFrontendMinor,
|
||||
Compile3.VersionFrontendBuild, Compile3.VersionFrontendQFE,
|
||||
Compile3.VersionBackendMajor, Compile3.VersionBackendMinor,
|
||||
Compile3.VersionBackendBuild, Compile3.VersionBackendQFE);
|
||||
P.formatLine("flags = {0}",
|
||||
formatCompileSym3Flags(P.getIndentLevel() + 9, Compile3.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
ConstantSym &Constant) {
|
||||
P.format(" `{0}`", Constant.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, value = {1}", typeIndex(Constant.Type),
|
||||
Constant.Value.toString(10));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
|
||||
P.format(" `{0}`", Data.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
|
||||
formatSegmentOffset(Data.Segment, Data.DataOffset));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(
|
||||
CVSymbol &CVR, DefRangeFramePointerRelFullScopeSym &Def) {
|
||||
P.format(" offset = {0}", Def.Offset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
DefRangeFramePointerRelSym &Def) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("offset = {0}, range = {1}", Def.Offset, formatRange(Def.Range));
|
||||
P.formatLine("gaps = {2}", Def.Offset,
|
||||
formatGaps(P.getIndentLevel() + 9, Def.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
DefRangeRegisterRelSym &Def) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("register = {0}, base ptr = {1}, offset in parent = {2}, has "
|
||||
"spilled udt = {3}",
|
||||
uint16_t(Def.Hdr.Register), int32_t(Def.Hdr.BasePointerOffset),
|
||||
Def.offsetInParent(), Def.hasSpilledUDTMember());
|
||||
P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
|
||||
formatGaps(P.getIndentLevel() + 9, Def.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(
|
||||
CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("register = {0}, may have no name = {1}, range start = "
|
||||
"{2}, length = {3}",
|
||||
uint16_t(DefRangeRegister.Hdr.Register),
|
||||
uint16_t(DefRangeRegister.Hdr.MayHaveNoName),
|
||||
formatSegmentOffset(DefRangeRegister.Range.ISectStart,
|
||||
DefRangeRegister.Range.OffsetStart),
|
||||
DefRangeRegister.Range.Range);
|
||||
P.formatLine("gaps = [{0}]",
|
||||
formatGaps(P.getIndentLevel() + 9, DefRangeRegister.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
DefRangeSubfieldRegisterSym &Def) {
|
||||
AutoIndent Indent(P);
|
||||
bool NoName = !!(Def.Hdr.MayHaveNoName == 0);
|
||||
P.formatLine("register = {0}, may have no name = {1}, offset in parent = {2}",
|
||||
uint16_t(Def.Hdr.Register), NoName,
|
||||
uint32_t(Def.Hdr.OffsetInParent));
|
||||
P.formatLine("range = {0}, gaps = {1}", formatRange(Def.Range),
|
||||
formatGaps(P.getIndentLevel() + 9, Def.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
DefRangeSubfieldSym &Def) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("program = {0}, offset in parent = {1}, range = {2}",
|
||||
Def.Program, Def.OffsetInParent, formatRange(Def.Range));
|
||||
P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, DefRangeSym &Def) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("program = {0}, range = {1}", Def.Program,
|
||||
formatRange(Def.Range));
|
||||
P.formatLine("gaps = {0}", formatGaps(P.getIndentLevel() + 9, Def.Gaps));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameCookieSym &FC) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("code offset = {0}, Register = {1}, kind = {2}, flags = {3}",
|
||||
FC.CodeOffset, FC.Register, formatCookieKind(FC.CookieKind),
|
||||
FC.Flags);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, FrameProcSym &FP) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("size = {0}, padding size = {1}, offset to padding = {2}",
|
||||
FP.TotalFrameBytes, FP.PaddingFrameBytes, FP.OffsetToPadding);
|
||||
P.formatLine("bytes of callee saved registers = {0}, exception handler addr "
|
||||
"= {1}",
|
||||
FP.BytesOfCalleeSavedRegisters,
|
||||
formatSegmentOffset(FP.SectionIdOfExceptionHandler,
|
||||
FP.OffsetOfExceptionHandler));
|
||||
P.formatLine("flags = {0}",
|
||||
formatFrameProcedureOptions(P.getIndentLevel() + 9, FP.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
HeapAllocationSiteSym &HAS) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, addr = {1} call size = {2}", typeIndex(HAS.Type),
|
||||
formatSegmentOffset(HAS.Segment, HAS.CodeOffset),
|
||||
HAS.CallInstructionSize);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, InlineSiteSym &IS) {
|
||||
AutoIndent Indent(P);
|
||||
auto Bytes = makeArrayRef(IS.AnnotationData);
|
||||
StringRef Annotations(reinterpret_cast<const char *>(Bytes.begin()),
|
||||
Bytes.size());
|
||||
|
||||
P.formatLine("inlinee = {0}, parent = {1}, end = {2}", typeIndex(IS.Inlinee),
|
||||
IS.Parent, IS.End);
|
||||
P.formatLine("annotations = {0}", toHex(Annotations));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
RegisterSym &Register) {
|
||||
P.format(" `{0}`", Register.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("register = {0}, type = {1}",
|
||||
formatRegisterId(Register.Register), typeIndex(Register.Index));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
PublicSym32 &Public) {
|
||||
P.format(" `{0}`", Public.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, addr = {1}", typeIndex(Public.Index),
|
||||
formatSegmentOffset(Public.Segment, Public.Offset));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcRefSym &PR) {
|
||||
P.format(" `{0}`", PR.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("module = {0}, sum name = {1}, offset = {2}", PR.Module,
|
||||
PR.SumName, PR.SymOffset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
|
||||
P.format(" `{0}` (addr = {1})", Label.Name,
|
||||
formatSegmentOffset(Label.Segment, Label.CodeOffset));
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("flags = {0}",
|
||||
formatProcSymFlags(P.getIndentLevel() + 9, Label.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
|
||||
P.format(" `{0}`", Local.Name);
|
||||
AutoIndent Indent(P);
|
||||
|
||||
std::string FlagStr =
|
||||
formatLocalSymFlags(P.getIndentLevel() + 9, Local.Flags);
|
||||
P.formatLine("type={0}, flags = {1}", typeIndex(Local.Type), FlagStr);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
ObjNameSym &ObjName) {
|
||||
P.format(" sig={0}, `{1}`", ObjName.Signature, ObjName.Name);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
|
||||
P.format(" `{0}`", Proc.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("parent = {0}, addr = {1}, code size = {2}, end = {3}",
|
||||
Proc.Parent, formatSegmentOffset(Proc.Segment, Proc.CodeOffset),
|
||||
Proc.CodeSize, Proc.End);
|
||||
P.formatLine("debug start = {0}, debug end = {1}, flags = {2}", Proc.DbgStart,
|
||||
Proc.DbgEnd,
|
||||
formatProcSymFlags(P.getIndentLevel() + 9, Proc.Flags));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
ScopeEndSym &ScopeEnd) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
|
||||
AutoIndent Indent(P);
|
||||
for (const auto &I : Caller.Indices) {
|
||||
P.formatLine("callee: {0}", typeIndex(I));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
RegRelativeSym &RegRel) {
|
||||
P.format(" `{0}`", RegRel.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, register = {1}, offset = {2}",
|
||||
typeIndex(RegRel.Type), formatRegisterId(RegRel.Register),
|
||||
RegRel.Offset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR,
|
||||
ThreadLocalDataSym &Data) {
|
||||
P.format(" `{0}`", Data.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, addr = {1}", typeIndex(Data.Type),
|
||||
formatSegmentOffset(Data.Segment, Data.DataOffset));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalSymbolDumper::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
|
||||
P.format(" `{0}`", UDT.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("original type = {0}", UDT.Type);
|
||||
return Error::success();
|
||||
}
|
47
tools/llvm-pdbutil/MinimalSymbolDumper.h
Normal file
47
tools/llvm-pdbutil/MinimalSymbolDumper.h
Normal file
@ -0,0 +1,47 @@
|
||||
//===- MinimalSymbolDumper.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_TOOLS_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_SYMBOL_DUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
class LazyRandomTypeCollection;
|
||||
}
|
||||
|
||||
namespace pdb {
|
||||
class LinePrinter;
|
||||
|
||||
class MinimalSymbolDumper : public codeview::SymbolVisitorCallbacks {
|
||||
public:
|
||||
MinimalSymbolDumper(LinePrinter &P, bool RecordBytes,
|
||||
codeview::LazyRandomTypeCollection &Types)
|
||||
: P(P), Types(Types) {}
|
||||
|
||||
Error visitSymbolBegin(codeview::CVSymbol &Record) override;
|
||||
Error visitSymbolEnd(codeview::CVSymbol &Record) override;
|
||||
|
||||
#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
|
||||
virtual Error visitKnownRecord(codeview::CVSymbol &CVR, \
|
||||
codeview::Name &Record) override;
|
||||
#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
|
||||
|
||||
private:
|
||||
std::string typeIndex(codeview::TypeIndex TI) const;
|
||||
|
||||
LinePrinter &P;
|
||||
codeview::LazyRandomTypeCollection &Types;
|
||||
};
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
532
tools/llvm-pdbutil/MinimalTypeDumper.cpp
Normal file
532
tools/llvm-pdbutil/MinimalTypeDumper.cpp
Normal file
@ -0,0 +1,532 @@
|
||||
//===- MinimalTypeDumper.cpp ---------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MinimalTypeDumper.h"
|
||||
|
||||
#include "FormatUtil.h"
|
||||
#include "LinePrinter.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CVRecord.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/CodeView.h"
|
||||
#include "llvm/DebugInfo/CodeView/Formatters.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
static StringRef getLeafTypeName(TypeLeafKind K) {
|
||||
switch (K) {
|
||||
#define TYPE_RECORD(EnumName, value, name) \
|
||||
case EnumName: \
|
||||
return #EnumName;
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
default:
|
||||
llvm_unreachable("Unknown type leaf kind!");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string formatClassOptions(uint32_t IndentLevel,
|
||||
ClassOptions Options) {
|
||||
std::vector<std::string> Opts;
|
||||
PUSH_FLAG(ClassOptions, HasConstructorOrDestructor, Options,
|
||||
"has ctor / dtor");
|
||||
PUSH_FLAG(ClassOptions, ContainsNestedClass, Options,
|
||||
"contains nested class");
|
||||
PUSH_FLAG(ClassOptions, HasConversionOperator, Options,
|
||||
"conversion operator");
|
||||
PUSH_FLAG(ClassOptions, ForwardReference, Options, "forward ref");
|
||||
PUSH_FLAG(ClassOptions, HasUniqueName, Options, "has unique name");
|
||||
PUSH_FLAG(ClassOptions, Intrinsic, Options, "intrin");
|
||||
PUSH_FLAG(ClassOptions, Nested, Options, "is nested");
|
||||
PUSH_FLAG(ClassOptions, HasOverloadedOperator, Options,
|
||||
"overloaded operator");
|
||||
PUSH_FLAG(ClassOptions, HasOverloadedAssignmentOperator, Options,
|
||||
"overloaded operator=");
|
||||
PUSH_FLAG(ClassOptions, Packed, Options, "packed");
|
||||
PUSH_FLAG(ClassOptions, Scoped, Options, "scoped");
|
||||
PUSH_FLAG(ClassOptions, Sealed, Options, "sealed");
|
||||
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string pointerOptions(PointerOptions Options) {
|
||||
std::vector<std::string> Opts;
|
||||
PUSH_FLAG(PointerOptions, Flat32, Options, "flat32");
|
||||
PUSH_FLAG(PointerOptions, Volatile, Options, "volatile");
|
||||
PUSH_FLAG(PointerOptions, Const, Options, "const");
|
||||
PUSH_FLAG(PointerOptions, Unaligned, Options, "unaligned");
|
||||
PUSH_FLAG(PointerOptions, Restrict, Options, "restrict");
|
||||
PUSH_FLAG(PointerOptions, WinRTSmartPointer, Options, "winrt");
|
||||
if (Opts.empty())
|
||||
return "None";
|
||||
return join(Opts, " | ");
|
||||
}
|
||||
|
||||
static std::string modifierOptions(ModifierOptions Options) {
|
||||
std::vector<std::string> Opts;
|
||||
PUSH_FLAG(ModifierOptions, Const, Options, "const");
|
||||
PUSH_FLAG(ModifierOptions, Volatile, Options, "volatile");
|
||||
PUSH_FLAG(ModifierOptions, Unaligned, Options, "unaligned");
|
||||
if (Opts.empty())
|
||||
return "None";
|
||||
return join(Opts, " | ");
|
||||
}
|
||||
|
||||
static std::string formatCallingConvention(CallingConvention Convention) {
|
||||
switch (Convention) {
|
||||
RETURN_CASE(CallingConvention, AlphaCall, "alphacall");
|
||||
RETURN_CASE(CallingConvention, AM33Call, "am33call");
|
||||
RETURN_CASE(CallingConvention, ArmCall, "armcall");
|
||||
RETURN_CASE(CallingConvention, ClrCall, "clrcall");
|
||||
RETURN_CASE(CallingConvention, FarC, "far cdecl");
|
||||
RETURN_CASE(CallingConvention, FarFast, "far fastcall");
|
||||
RETURN_CASE(CallingConvention, FarPascal, "far pascal");
|
||||
RETURN_CASE(CallingConvention, FarStdCall, "far stdcall");
|
||||
RETURN_CASE(CallingConvention, FarSysCall, "far syscall");
|
||||
RETURN_CASE(CallingConvention, Generic, "generic");
|
||||
RETURN_CASE(CallingConvention, Inline, "inline");
|
||||
RETURN_CASE(CallingConvention, M32RCall, "m32rcall");
|
||||
RETURN_CASE(CallingConvention, MipsCall, "mipscall");
|
||||
RETURN_CASE(CallingConvention, NearC, "cdecl");
|
||||
RETURN_CASE(CallingConvention, NearFast, "fastcall");
|
||||
RETURN_CASE(CallingConvention, NearPascal, "pascal");
|
||||
RETURN_CASE(CallingConvention, NearStdCall, "stdcall");
|
||||
RETURN_CASE(CallingConvention, NearSysCall, "near syscall");
|
||||
RETURN_CASE(CallingConvention, NearVector, "vectorcall");
|
||||
RETURN_CASE(CallingConvention, PpcCall, "ppccall");
|
||||
RETURN_CASE(CallingConvention, SHCall, "shcall");
|
||||
RETURN_CASE(CallingConvention, SH5Call, "sh5call");
|
||||
RETURN_CASE(CallingConvention, ThisCall, "thiscall");
|
||||
RETURN_CASE(CallingConvention, TriCall, "tricall");
|
||||
}
|
||||
return formatUnknownEnum(Convention);
|
||||
}
|
||||
|
||||
static std::string formatPointerMode(PointerMode Mode) {
|
||||
switch (Mode) {
|
||||
RETURN_CASE(PointerMode, LValueReference, "ref");
|
||||
RETURN_CASE(PointerMode, Pointer, "pointer");
|
||||
RETURN_CASE(PointerMode, PointerToDataMember, "data member pointer");
|
||||
RETURN_CASE(PointerMode, PointerToMemberFunction, "member fn pointer");
|
||||
RETURN_CASE(PointerMode, RValueReference, "rvalue ref");
|
||||
}
|
||||
return formatUnknownEnum(Mode);
|
||||
}
|
||||
|
||||
static std::string memberAccess(MemberAccess Access) {
|
||||
switch (Access) {
|
||||
RETURN_CASE(MemberAccess, None, "");
|
||||
RETURN_CASE(MemberAccess, Private, "private");
|
||||
RETURN_CASE(MemberAccess, Protected, "protected");
|
||||
RETURN_CASE(MemberAccess, Public, "public");
|
||||
}
|
||||
return formatUnknownEnum(Access);
|
||||
}
|
||||
|
||||
static std::string methodKind(MethodKind Kind) {
|
||||
switch (Kind) {
|
||||
RETURN_CASE(MethodKind, Vanilla, "");
|
||||
RETURN_CASE(MethodKind, Virtual, "virtual");
|
||||
RETURN_CASE(MethodKind, Static, "static");
|
||||
RETURN_CASE(MethodKind, Friend, "friend");
|
||||
RETURN_CASE(MethodKind, IntroducingVirtual, "intro virtual");
|
||||
RETURN_CASE(MethodKind, PureVirtual, "pure virtual");
|
||||
RETURN_CASE(MethodKind, PureIntroducingVirtual, "pure intro virtual");
|
||||
}
|
||||
return formatUnknownEnum(Kind);
|
||||
}
|
||||
|
||||
static std::string pointerKind(PointerKind Kind) {
|
||||
switch (Kind) {
|
||||
RETURN_CASE(PointerKind, Near16, "ptr16");
|
||||
RETURN_CASE(PointerKind, Far16, "far ptr16");
|
||||
RETURN_CASE(PointerKind, Huge16, "huge ptr16");
|
||||
RETURN_CASE(PointerKind, BasedOnSegment, "segment based");
|
||||
RETURN_CASE(PointerKind, BasedOnValue, "value based");
|
||||
RETURN_CASE(PointerKind, BasedOnSegmentValue, "segment value based");
|
||||
RETURN_CASE(PointerKind, BasedOnAddress, "address based");
|
||||
RETURN_CASE(PointerKind, BasedOnSegmentAddress, "segment address based");
|
||||
RETURN_CASE(PointerKind, BasedOnType, "type based");
|
||||
RETURN_CASE(PointerKind, BasedOnSelf, "self based");
|
||||
RETURN_CASE(PointerKind, Near32, "ptr32");
|
||||
RETURN_CASE(PointerKind, Far32, "far ptr32");
|
||||
RETURN_CASE(PointerKind, Near64, "ptr64");
|
||||
}
|
||||
return formatUnknownEnum(Kind);
|
||||
}
|
||||
|
||||
static std::string memberAttributes(const MemberAttributes &Attrs) {
|
||||
std::vector<std::string> Opts;
|
||||
std::string Access = memberAccess(Attrs.getAccess());
|
||||
std::string Kind = methodKind(Attrs.getMethodKind());
|
||||
if (!Access.empty())
|
||||
Opts.push_back(Access);
|
||||
if (!Kind.empty())
|
||||
Opts.push_back(Kind);
|
||||
MethodOptions Flags = Attrs.getFlags();
|
||||
PUSH_FLAG(MethodOptions, Pseudo, Flags, "pseudo");
|
||||
PUSH_FLAG(MethodOptions, NoInherit, Flags, "noinherit");
|
||||
PUSH_FLAG(MethodOptions, NoConstruct, Flags, "noconstruct");
|
||||
PUSH_FLAG(MethodOptions, CompilerGenerated, Flags, "compiler-generated");
|
||||
PUSH_FLAG(MethodOptions, Sealed, Flags, "sealed");
|
||||
return join(Opts, " ");
|
||||
}
|
||||
|
||||
static std::string formatPointerAttrs(const PointerRecord &Record) {
|
||||
PointerMode Mode = Record.getMode();
|
||||
PointerOptions Opts = Record.getOptions();
|
||||
PointerKind Kind = Record.getPointerKind();
|
||||
return formatv("mode = {0}, opts = {1}, kind = {2}", formatPointerMode(Mode),
|
||||
pointerOptions(Opts), pointerKind(Kind));
|
||||
}
|
||||
|
||||
static std::string formatFunctionOptions(FunctionOptions Options) {
|
||||
std::vector<std::string> Opts;
|
||||
|
||||
PUSH_FLAG(FunctionOptions, CxxReturnUdt, Options, "returns cxx udt");
|
||||
PUSH_FLAG(FunctionOptions, ConstructorWithVirtualBases, Options,
|
||||
"constructor with virtual bases");
|
||||
PUSH_FLAG(FunctionOptions, Constructor, Options, "constructor");
|
||||
if (Opts.empty())
|
||||
return "None";
|
||||
return join(Opts, " | ");
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
|
||||
// formatLine puts the newline at the beginning, so we use formatLine here
|
||||
// to start a new line, and then individual visit methods use format to
|
||||
// append to the existing line.
|
||||
P.formatLine("{0} | {1} [size = {2}]",
|
||||
fmt_align(Index, AlignStyle::Right, Width),
|
||||
getLeafTypeName(Record.Type), Record.length());
|
||||
P.Indent(Width + 3);
|
||||
return Error::success();
|
||||
}
|
||||
Error MinimalTypeDumpVisitor::visitTypeEnd(CVType &Record) {
|
||||
P.Unindent(Width + 3);
|
||||
if (RecordBytes) {
|
||||
AutoIndent Indent(P, 9);
|
||||
P.formatBinary("Bytes", Record.RecordData, 0);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
|
||||
P.formatLine("- {0}", getLeafTypeName(Record.Kind));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
|
||||
if (RecordBytes) {
|
||||
AutoIndent Indent(P, 2);
|
||||
P.formatBinary("Bytes", Record.Data, 0);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
StringRef MinimalTypeDumpVisitor::getTypeName(TypeIndex TI) const {
|
||||
if (TI.isNoneType())
|
||||
return "";
|
||||
return Types.getTypeName(TI);
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
FieldListRecord &FieldList) {
|
||||
if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
|
||||
return EC;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
StringIdRecord &String) {
|
||||
P.format(" ID: {0}, String: {1}", String.getId(), String.getString());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
ArgListRecord &Args) {
|
||||
auto Indices = Args.getIndices();
|
||||
if (Indices.empty())
|
||||
return Error::success();
|
||||
|
||||
auto Max = std::max_element(Indices.begin(), Indices.end());
|
||||
uint32_t W = NumDigits(Max->getIndex()) + 2;
|
||||
|
||||
for (auto I : Indices)
|
||||
P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
|
||||
getTypeName(I));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
StringListRecord &Strings) {
|
||||
auto Indices = Strings.getIndices();
|
||||
if (Indices.empty())
|
||||
return Error::success();
|
||||
|
||||
auto Max = std::max_element(Indices.begin(), Indices.end());
|
||||
uint32_t W = NumDigits(Max->getIndex()) + 2;
|
||||
|
||||
for (auto I : Indices)
|
||||
P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
|
||||
getTypeName(I));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
ClassRecord &Class) {
|
||||
P.formatLine("class name: `{0}`", Class.Name);
|
||||
if (Class.hasUniqueName())
|
||||
P.formatLine("unique name: `{0}`", Class.UniqueName);
|
||||
P.formatLine("vtable: {0}, base list: {1}, field list: {2}",
|
||||
Class.VTableShape, Class.DerivationList, Class.FieldList);
|
||||
P.formatLine("options: {0}",
|
||||
formatClassOptions(P.getIndentLevel(), Class.Options));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
UnionRecord &Union) {
|
||||
P.formatLine("class name: `{0}`", Union.Name);
|
||||
if (Union.hasUniqueName())
|
||||
P.formatLine("unique name: `{0}`", Union.UniqueName);
|
||||
P.formatLine("field list: {0}", Union.FieldList);
|
||||
P.formatLine("options: {0}",
|
||||
formatClassOptions(P.getIndentLevel(), Union.Options));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
|
||||
P.formatLine("name: `{0}`", Enum.Name);
|
||||
if (Enum.hasUniqueName())
|
||||
P.formatLine("unique name: `{0}`", Enum.UniqueName);
|
||||
P.formatLine("field list: {0}, underlying type: {1}", Enum.FieldList,
|
||||
Enum.UnderlyingType);
|
||||
P.formatLine("options: {0}",
|
||||
formatClassOptions(P.getIndentLevel(), Enum.Options));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
|
||||
if (AT.Name.empty()) {
|
||||
P.formatLine("size: {0}, index type: {1}, element type: {2}", AT.Size,
|
||||
AT.IndexType, AT.ElementType);
|
||||
} else {
|
||||
P.formatLine("name: {0}, size: {1}, index type: {2}, element type: {3}",
|
||||
AT.Name, AT.Size, AT.IndexType, AT.ElementType);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
VFTableRecord &VFT) {
|
||||
P.formatLine("offset: {0}, complete class: {1}, overridden vftable: {2}",
|
||||
VFT.VFPtrOffset, VFT.CompleteClass, VFT.OverriddenVFTable);
|
||||
P.formatLine("method names: ");
|
||||
if (!VFT.MethodNames.empty()) {
|
||||
std::string Sep =
|
||||
formatv("\n{0}",
|
||||
fmt_repeat(' ', P.getIndentLevel() + strlen("method names: ")))
|
||||
.str();
|
||||
P.print(join(VFT.MethodNames, Sep));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
MemberFuncIdRecord &Id) {
|
||||
P.formatLine("name = {0}, type = {1}, class type = {2}", Id.Name,
|
||||
Id.FunctionType, Id.ClassType);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
ProcedureRecord &Proc) {
|
||||
P.formatLine("return type = {0}, # args = {1}, param list = {2}",
|
||||
Proc.ReturnType, Proc.ParameterCount, Proc.ArgumentList);
|
||||
P.formatLine("calling conv = {0}, options = {1}",
|
||||
formatCallingConvention(Proc.CallConv),
|
||||
formatFunctionOptions(Proc.Options));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
MemberFunctionRecord &MF) {
|
||||
P.formatLine("return type = {0}, # args = {1}, param list = {2}",
|
||||
MF.ParameterCount, MF.ArgumentList, MF.ReturnType);
|
||||
P.formatLine("class type = {0}, this type = {1}, this adjust = {2}",
|
||||
MF.ClassType, MF.ThisType, MF.ThisPointerAdjustment);
|
||||
P.formatLine("calling conv = {0}, options = {1}",
|
||||
formatCallingConvention(MF.CallConv),
|
||||
formatFunctionOptions(MF.Options));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
FuncIdRecord &Func) {
|
||||
P.formatLine("name = {0}, type = {1}, parent scope = {2}", Func.Name,
|
||||
Func.FunctionType, Func.ParentScope);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
TypeServer2Record &TS) {
|
||||
P.formatLine("name = {0}, age = {1}, guid = {2}", TS.Name, TS.Age,
|
||||
fmt_guid(TS.Guid));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
PointerRecord &Ptr) {
|
||||
P.formatLine("referent = {0}, {1}", Ptr.ReferentType,
|
||||
formatPointerAttrs(Ptr));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
ModifierRecord &Mod) {
|
||||
P.formatLine("referent = {0}, modifiers = {1}", Mod.ModifiedType,
|
||||
modifierOptions(Mod.Modifiers));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
VFTableShapeRecord &Shape) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
UdtModSourceLineRecord &U) {
|
||||
P.formatLine("udt = {0}, mod = {1}, file = {2}, line = {3}", U.UDT, U.Module,
|
||||
U.SourceFile.getIndex(), U.LineNumber);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
UdtSourceLineRecord &U) {
|
||||
P.formatLine("udt = {0}, file = {1}, line = {2}", U.UDT,
|
||||
U.SourceFile.getIndex(), U.LineNumber);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
BitFieldRecord &BF) {
|
||||
P.formatLine("type = {0}, bit offset = {1}, # bits = {2}", BF.Type,
|
||||
BF.BitOffset, BF.BitSize);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(
|
||||
CVType &CVR, MethodOverloadListRecord &Overloads) {
|
||||
for (auto &M : Overloads.Methods)
|
||||
P.formatLine("- Method [type = {0}, vftable offset = {1}, attrs = {2}]",
|
||||
M.Type, M.VFTableOffset, memberAttributes(M.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR,
|
||||
BuildInfoRecord &BI) {
|
||||
auto Indices = BI.ArgIndices;
|
||||
if (Indices.empty())
|
||||
return Error::success();
|
||||
|
||||
auto Max = std::max_element(Indices.begin(), Indices.end());
|
||||
uint32_t W = NumDigits(Max->getIndex()) + 2;
|
||||
|
||||
for (auto I : Indices)
|
||||
P.formatLine("{0}: `{1}`", fmt_align(I, AlignStyle::Right, W),
|
||||
getTypeName(I));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &R) {
|
||||
std::string Type = (R.Mode == LabelType::Far) ? "far" : "near";
|
||||
P.format(" type = {0}", Type);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
NestedTypeRecord &Nested) {
|
||||
P.format(" [name = `{0}`, parent = {1}]", Nested.Name, Nested.Type);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
OneMethodRecord &Method) {
|
||||
P.format(" [name = `{0}`]", Method.Name);
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, vftable offset = {1}, attrs = {2}", Method.Type,
|
||||
Method.VFTableOffset, memberAttributes(Method.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
OverloadedMethodRecord &Method) {
|
||||
P.format(" [name = `{0}`, # overloads = {1}, overload list = {2}]",
|
||||
Method.Name, Method.NumOverloads, Method.MethodList);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
DataMemberRecord &Field) {
|
||||
P.format(" [name = `{0}`, Type = {1}, offset = {2}, attrs = {3}]", Field.Name,
|
||||
Field.Type, Field.FieldOffset, memberAttributes(Field.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
StaticDataMemberRecord &Field) {
|
||||
P.format(" [name = `{0}`, type = {1}, attrs = {2}]", Field.Name, Field.Type,
|
||||
memberAttributes(Field.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
EnumeratorRecord &Enum) {
|
||||
P.format(" [{0} = {1}]", Enum.Name,
|
||||
Enum.Value.toString(10, Enum.Value.isSigned()));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
BaseClassRecord &Base) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("type = {0}, offset = {1}, attrs = {2}", Base.Type, Base.Offset,
|
||||
memberAttributes(Base.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
VirtualBaseClassRecord &Base) {
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine(
|
||||
"base = {0}, vbptr = {1}, vbptr offset = {2}, vtable index = {3}",
|
||||
Base.BaseType, Base.VBPtrType, Base.VBPtrOffset, Base.VTableIndex);
|
||||
P.formatLine("attrs = {0}", memberAttributes(Base.Attrs));
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
ListContinuationRecord &Cont) {
|
||||
P.format(" continuation = {0}", Cont.ContinuationIndex);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error MinimalTypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
|
||||
VFPtrRecord &VFP) {
|
||||
P.format(" type = {0}", VFP.Type);
|
||||
return Error::success();
|
||||
}
|
56
tools/llvm-pdbutil/MinimalTypeDumper.h
Normal file
56
tools/llvm-pdbutil/MinimalTypeDumper.h
Normal file
@ -0,0 +1,56 @@
|
||||
//===- MinimalTypeDumper.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_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
|
||||
#define LLVM_TOOLS_LLVMPDBUTIL_MINIMAL_TYPE_DUMPER_H
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace codeview {
|
||||
class LazyRandomTypeCollection;
|
||||
}
|
||||
|
||||
namespace pdb {
|
||||
class LinePrinter;
|
||||
|
||||
class MinimalTypeDumpVisitor : public codeview::TypeVisitorCallbacks {
|
||||
public:
|
||||
MinimalTypeDumpVisitor(LinePrinter &P, uint32_t Width, bool RecordBytes,
|
||||
codeview::LazyRandomTypeCollection &Types)
|
||||
: P(P), Width(Width), RecordBytes(RecordBytes), Types(Types) {}
|
||||
|
||||
Error visitTypeBegin(codeview::CVType &Record,
|
||||
codeview::TypeIndex Index) override;
|
||||
Error visitTypeEnd(codeview::CVType &Record) override;
|
||||
Error visitMemberBegin(codeview::CVMemberRecord &Record) override;
|
||||
Error visitMemberEnd(codeview::CVMemberRecord &Record) override;
|
||||
|
||||
#define TYPE_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownRecord(codeview::CVType &CVR, \
|
||||
codeview::Name##Record &Record) override;
|
||||
#define MEMBER_RECORD(EnumName, EnumVal, Name) \
|
||||
Error visitKnownMember(codeview::CVMemberRecord &CVR, \
|
||||
codeview::Name##Record &Record) override;
|
||||
#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
|
||||
#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
|
||||
|
||||
private:
|
||||
StringRef getTypeName(codeview::TypeIndex TI) const;
|
||||
|
||||
LinePrinter &P;
|
||||
uint32_t Width;
|
||||
bool RecordBytes = false;
|
||||
codeview::LazyRandomTypeCollection &Types;
|
||||
};
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
669
tools/llvm-pdbutil/RawOutputStyle.cpp
Normal file
669
tools/llvm-pdbutil/RawOutputStyle.cpp
Normal file
@ -0,0 +1,669 @@
|
||||
//===- RawOutputStyle.cpp ------------------------------------ *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RawOutputStyle.h"
|
||||
|
||||
#include "CompactTypeDumpVisitor.h"
|
||||
#include "FormatUtil.h"
|
||||
#include "MinimalSymbolDumper.h"
|
||||
#include "MinimalTypeDumper.h"
|
||||
#include "StreamUtil.h"
|
||||
#include "llvm-pdbutil.h"
|
||||
|
||||
#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
|
||||
#include "llvm/DebugInfo/CodeView/EnumTables.h"
|
||||
#include "llvm/DebugInfo/CodeView/Formatters.h"
|
||||
#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
|
||||
#include "llvm/DebugInfo/CodeView/Line.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolDumper.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
|
||||
#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/EnumTables.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
|
||||
#include "llvm/DebugInfo/PDB/PDBExtras.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
RawOutputStyle::RawOutputStyle(PDBFile &File)
|
||||
: File(File), P(2, false, outs()) {}
|
||||
|
||||
Error RawOutputStyle::dump() {
|
||||
if (opts::raw::DumpSummary) {
|
||||
if (auto EC = dumpFileSummary())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::raw::DumpStreams) {
|
||||
if (auto EC = dumpStreamSummary())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::raw::DumpBlockRange.hasValue()) {
|
||||
if (auto EC = dumpBlockRanges())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (!opts::raw::DumpStreamData.empty()) {
|
||||
if (auto EC = dumpStreamBytes())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::raw::DumpStringTable) {
|
||||
if (auto EC = dumpStringTable())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::raw::DumpModules) {
|
||||
if (auto EC = dumpModules())
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpTypes) {
|
||||
if (auto EC = dumpTpiStream(StreamTPI))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpIds) {
|
||||
if (auto EC = dumpTpiStream(StreamIPI))
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpPublics) {
|
||||
if (auto EC = dumpPublics())
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpSymbols) {
|
||||
if (auto EC = dumpModuleSyms())
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpSectionContribs) {
|
||||
if (auto EC = dumpSectionContribs())
|
||||
return EC;
|
||||
}
|
||||
|
||||
if (opts::raw::DumpSectionMap) {
|
||||
if (auto EC = dumpSectionMap())
|
||||
return EC;
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static void printHeader(LinePrinter &P, const Twine &S) {
|
||||
P.NewLine();
|
||||
P.formatLine("{0,=60}", S);
|
||||
P.formatLine("{0}", fmt_repeat('=', 60));
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpFileSummary() {
|
||||
printHeader(P, "Summary");
|
||||
|
||||
ExitOnError Err("Invalid PDB Format");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
P.formatLine("Block Size: {0}", File.getBlockSize());
|
||||
P.formatLine("Number of blocks: {0}", File.getBlockCount());
|
||||
P.formatLine("Number of streams: {0}", File.getNumStreams());
|
||||
|
||||
auto &PS = Err(File.getPDBInfoStream());
|
||||
P.formatLine("Signature: {0}", PS.getSignature());
|
||||
P.formatLine("Age: {0}", PS.getAge());
|
||||
P.formatLine("GUID: {0}", fmt_guid(PS.getGuid().Guid));
|
||||
P.formatLine("Features: {0:x+}", static_cast<uint32_t>(PS.getFeatures()));
|
||||
P.formatLine("Has Debug Info: {0}", File.hasPDBDbiStream());
|
||||
P.formatLine("Has Types: {0}", File.hasPDBTpiStream());
|
||||
P.formatLine("Has IDs: {0}", File.hasPDBIpiStream());
|
||||
P.formatLine("Has Globals: {0}", File.hasPDBGlobalsStream());
|
||||
P.formatLine("Has Publics: {0}", File.hasPDBPublicsStream());
|
||||
if (File.hasPDBDbiStream()) {
|
||||
auto &DBI = Err(File.getPDBDbiStream());
|
||||
P.formatLine("Is incrementally linked: {0}", DBI.isIncrementallyLinked());
|
||||
P.formatLine("Has conflicting types: {0}", DBI.hasCTypes());
|
||||
P.formatLine("Is stripped: {0}", DBI.isStripped());
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpStreamSummary() {
|
||||
printHeader(P, "Streams");
|
||||
|
||||
if (StreamPurposes.empty())
|
||||
discoverStreamPurposes(File, StreamPurposes);
|
||||
|
||||
AutoIndent Indent(P);
|
||||
uint32_t StreamCount = File.getNumStreams();
|
||||
|
||||
for (uint16_t StreamIdx = 0; StreamIdx < StreamCount; ++StreamIdx) {
|
||||
P.formatLine(
|
||||
"Stream {0}: [{1}] ({2} bytes)",
|
||||
fmt_align(StreamIdx, AlignStyle::Right, NumDigits(StreamCount)),
|
||||
StreamPurposes[StreamIdx], File.getStreamByteSize(StreamIdx));
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpBlockRanges() {
|
||||
printHeader(P, "MSF Blocks");
|
||||
|
||||
auto &R = *opts::raw::DumpBlockRange;
|
||||
uint32_t Max = R.Max.getValueOr(R.Min);
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (Max < R.Min)
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Max < Min",
|
||||
std::make_error_code(std::errc::bad_address));
|
||||
if (Max >= File.getBlockCount())
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Requested block out of bounds",
|
||||
std::make_error_code(std::errc::bad_address));
|
||||
|
||||
for (uint32_t I = R.Min; I <= Max; ++I) {
|
||||
auto ExpectedData = File.getBlockData(I, File.getBlockSize());
|
||||
if (!ExpectedData)
|
||||
return ExpectedData.takeError();
|
||||
std::string Label = formatv("Block {0}", I).str();
|
||||
P.formatBinary(Label, *ExpectedData, 0);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
|
||||
uint32_t &Size) {
|
||||
if (Str.consumeInteger(0, SI))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
if (Str.consume_front(":")) {
|
||||
if (Str.consumeInteger(0, Offset))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
if (Str.consume_front("@")) {
|
||||
if (Str.consumeInteger(0, Size))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
if (!Str.empty())
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpStreamBytes() {
|
||||
if (StreamPurposes.empty())
|
||||
discoverStreamPurposes(File, StreamPurposes);
|
||||
|
||||
printHeader(P, "Stream Data");
|
||||
ExitOnError Err("Unexpected error reading stream data");
|
||||
|
||||
for (auto &Str : opts::raw::DumpStreamData) {
|
||||
uint32_t SI = 0;
|
||||
uint32_t Begin = 0;
|
||||
uint32_t Size = 0;
|
||||
uint32_t End = 0;
|
||||
|
||||
if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
|
||||
return EC;
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (SI >= File.getNumStreams()) {
|
||||
P.formatLine("Stream {0}: Not present", SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto S = MappedBlockStream::createIndexedStream(
|
||||
File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
|
||||
if (!S) {
|
||||
P.NewLine();
|
||||
P.formatLine("Stream {0}: Not present", SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Size == 0)
|
||||
End = S->getLength();
|
||||
else
|
||||
End = std::min(Begin + Size, S->getLength());
|
||||
|
||||
P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
|
||||
StreamPurposes[SI]);
|
||||
AutoIndent Indent2(P);
|
||||
|
||||
BinaryStreamReader R(*S);
|
||||
ArrayRef<uint8_t> StreamData;
|
||||
Err(R.readBytes(StreamData, S->getLength()));
|
||||
Size = End - Begin;
|
||||
StreamData = StreamData.slice(Begin, Size);
|
||||
P.formatBinary("Data", StreamData, Begin);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpModules() {
|
||||
printHeader(P, "Modules");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!File.hasPDBDbiStream()) {
|
||||
P.formatLine("DBI Stream not present");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ExitOnError Err("Unexpected error processing symbols");
|
||||
|
||||
auto &Stream = Err(File.getPDBDbiStream());
|
||||
|
||||
const DbiModuleList &Modules = Stream.modules();
|
||||
uint32_t Count = Modules.getModuleCount();
|
||||
uint32_t Digits = NumDigits(Count);
|
||||
for (uint32_t I = 0; I < Count; ++I) {
|
||||
auto Modi = Modules.getModuleDescriptor(I);
|
||||
P.formatLine("Mod {0:4} | Name: `{1}`: ",
|
||||
fmt_align(I, AlignStyle::Right, Digits), Modi.getModuleName());
|
||||
P.formatLine(" Obj: `{0}`: ", Modi.getObjFileName());
|
||||
P.formatLine(" debug stream: {0}, # files: {1}, has ec info: {2}",
|
||||
Modi.getModuleStreamIndex(), Modi.getNumberOfFiles(),
|
||||
Modi.hasECInfo());
|
||||
if (opts::raw::DumpModuleFiles) {
|
||||
P.formatLine(" contributing source files:");
|
||||
for (const auto &F : Modules.source_files(I)) {
|
||||
P.formatLine(" - {0}", F);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
Error RawOutputStyle::dumpStringTable() {
|
||||
printHeader(P, "String Table");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
auto IS = File.getStringTable();
|
||||
if (!IS) {
|
||||
P.formatLine("Not present in file");
|
||||
consumeError(IS.takeError());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
if (IS->name_ids().empty()) {
|
||||
P.formatLine("Empty");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
auto MaxID = std::max_element(IS->name_ids().begin(), IS->name_ids().end());
|
||||
uint32_t Digits = NumDigits(*MaxID);
|
||||
|
||||
P.formatLine("{0} | {1}", fmt_align("ID", AlignStyle::Right, Digits),
|
||||
"String");
|
||||
|
||||
std::vector<uint32_t> SortedIDs(IS->name_ids().begin(), IS->name_ids().end());
|
||||
std::sort(SortedIDs.begin(), SortedIDs.end());
|
||||
for (uint32_t I : SortedIDs) {
|
||||
auto ES = IS->getStringForID(I);
|
||||
llvm::SmallString<32> Str;
|
||||
if (!ES) {
|
||||
consumeError(ES.takeError());
|
||||
Str = "Error reading string";
|
||||
} else if (!ES->empty()) {
|
||||
Str.append("'");
|
||||
Str.append(*ES);
|
||||
Str.append("'");
|
||||
}
|
||||
|
||||
if (!Str.empty())
|
||||
P.formatLine("{0} | {1}", fmt_align(I, AlignStyle::Right, Digits), Str);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpTpiStream(uint32_t StreamIdx) {
|
||||
assert(StreamIdx == StreamTPI || StreamIdx == StreamIPI);
|
||||
|
||||
bool Present = false;
|
||||
bool DumpBytes = false;
|
||||
if (StreamIdx == StreamTPI) {
|
||||
printHeader(P, "Types (TPI Stream)");
|
||||
Present = File.hasPDBTpiStream();
|
||||
DumpBytes = opts::raw::DumpTypeData;
|
||||
} else if (StreamIdx == StreamIPI) {
|
||||
printHeader(P, "Types (IPI Stream)");
|
||||
Present = File.hasPDBIpiStream();
|
||||
DumpBytes = opts::raw::DumpIdData;
|
||||
}
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!Present) {
|
||||
P.formatLine("Stream not present");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ExitOnError Err("Unexpected error processing types");
|
||||
|
||||
auto &Stream = Err((StreamIdx == StreamTPI) ? File.getPDBTpiStream()
|
||||
: File.getPDBIpiStream());
|
||||
|
||||
auto &Types = Err(initializeTypeDatabase(StreamIdx));
|
||||
|
||||
P.formatLine("Showing {0:N} records", Stream.getNumTypeRecords());
|
||||
uint32_t Width =
|
||||
NumDigits(TypeIndex::FirstNonSimpleIndex + Stream.getNumTypeRecords());
|
||||
|
||||
MinimalTypeDumpVisitor V(P, Width + 2, DumpBytes, Types);
|
||||
|
||||
Optional<TypeIndex> I = Types.getFirst();
|
||||
if (auto EC = codeview::visitTypeStream(Types, V)) {
|
||||
P.formatLine("An error occurred dumping type records: {0}",
|
||||
toString(std::move(EC)));
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<codeview::LazyRandomTypeCollection &>
|
||||
RawOutputStyle::initializeTypeDatabase(uint32_t SN) {
|
||||
auto &TypeCollection = (SN == StreamTPI) ? TpiTypes : IpiTypes;
|
||||
auto Tpi =
|
||||
(SN == StreamTPI) ? File.getPDBTpiStream() : File.getPDBIpiStream();
|
||||
if (!Tpi)
|
||||
return Tpi.takeError();
|
||||
|
||||
if (!TypeCollection) {
|
||||
auto &Types = Tpi->typeArray();
|
||||
uint32_t Count = Tpi->getNumTypeRecords();
|
||||
auto Offsets = Tpi->getTypeIndexOffsets();
|
||||
TypeCollection =
|
||||
llvm::make_unique<LazyRandomTypeCollection>(Types, Count, Offsets);
|
||||
}
|
||||
|
||||
return *TypeCollection;
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpModuleSyms() {
|
||||
printHeader(P, "Symbols");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!File.hasPDBDbiStream()) {
|
||||
P.formatLine("DBI Stream not present");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ExitOnError Err("Unexpected error processing symbols");
|
||||
|
||||
auto &Stream = Err(File.getPDBDbiStream());
|
||||
|
||||
auto &Types = Err(initializeTypeDatabase(StreamTPI));
|
||||
|
||||
const DbiModuleList &Modules = Stream.modules();
|
||||
uint32_t Count = Modules.getModuleCount();
|
||||
uint32_t Digits = NumDigits(Count);
|
||||
for (uint32_t I = 0; I < Count; ++I) {
|
||||
auto Modi = Modules.getModuleDescriptor(I);
|
||||
P.formatLine("Mod {0:4} | `{1}`: ", fmt_align(I, AlignStyle::Right, Digits),
|
||||
Modi.getModuleName());
|
||||
uint16_t ModiStream = Modi.getModuleStreamIndex();
|
||||
if (ModiStream == kInvalidStreamIndex) {
|
||||
P.formatLine(" <symbols not present>");
|
||||
continue;
|
||||
}
|
||||
auto ModStreamData = MappedBlockStream::createIndexedStream(
|
||||
File.getMsfLayout(), File.getMsfBuffer(), ModiStream,
|
||||
File.getAllocator());
|
||||
|
||||
ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
|
||||
if (auto EC = ModS.reload()) {
|
||||
P.formatLine("Error loading module stream {0}. {1}", I,
|
||||
toString(std::move(EC)));
|
||||
continue;
|
||||
}
|
||||
|
||||
SymbolVisitorCallbackPipeline Pipeline;
|
||||
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
|
||||
MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
|
||||
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
Pipeline.addCallbackToPipeline(Dumper);
|
||||
CVSymbolVisitor Visitor(Pipeline);
|
||||
if (auto EC = Visitor.visitSymbolStream(ModS.getSymbolArray())) {
|
||||
P.formatLine("Error while processing symbol records. {0}",
|
||||
toString(std::move(EC)));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpPublics() {
|
||||
printHeader(P, "Public Symbols");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!File.hasPDBPublicsStream()) {
|
||||
P.formatLine("Publics stream not present");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
ExitOnError Err("Error dumping publics stream");
|
||||
|
||||
auto &Types = Err(initializeTypeDatabase(StreamTPI));
|
||||
auto &Publics = Err(File.getPDBPublicsStream());
|
||||
SymbolVisitorCallbackPipeline Pipeline;
|
||||
SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb);
|
||||
MinimalSymbolDumper Dumper(P, opts::raw::DumpSymRecordBytes, Types);
|
||||
|
||||
Pipeline.addCallbackToPipeline(Deserializer);
|
||||
Pipeline.addCallbackToPipeline(Dumper);
|
||||
CVSymbolVisitor Visitor(Pipeline);
|
||||
auto ExpectedSymbols = Publics.getSymbolArray();
|
||||
if (!ExpectedSymbols) {
|
||||
P.formatLine("Could not read public symbol record stream");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
if (auto EC = Visitor.visitSymbolStream(*ExpectedSymbols))
|
||||
P.formatLine("Error while processing public symbol records. {0}",
|
||||
toString(std::move(EC)));
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static std::string formatSectionCharacteristics(uint32_t IndentLevel,
|
||||
uint32_t C) {
|
||||
using SC = COFF::SectionCharacteristics;
|
||||
std::vector<std::string> Opts;
|
||||
if (C == COFF::SC_Invalid)
|
||||
return "invalid";
|
||||
if (C == 0)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(SC, IMAGE_SCN_TYPE_NOLOAD, C, "IMAGE_SCN_TYPE_NOLOAD");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_TYPE_NO_PAD, C, "IMAGE_SCN_TYPE_NO_PAD");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_CNT_CODE, C, "IMAGE_SCN_CNT_CODE");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_CNT_INITIALIZED_DATA, C,
|
||||
"IMAGE_SCN_CNT_INITIALIZED_DATA");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_CNT_UNINITIALIZED_DATA, C,
|
||||
"IMAGE_SCN_CNT_UNINITIALIZED_DATA");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_LNK_OTHER, C, "IMAGE_SCN_LNK_OTHER");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_LNK_INFO, C, "IMAGE_SCN_LNK_INFO");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_LNK_REMOVE, C, "IMAGE_SCN_LNK_REMOVE");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_LNK_COMDAT, C, "IMAGE_SCN_LNK_COMDAT");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_PURGEABLE, C, "IMAGE_SCN_MEM_PURGEABLE");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_16BIT, C, "IMAGE_SCN_MEM_16BIT");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_LOCKED, C, "IMAGE_SCN_MEM_LOCKED");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_PRELOAD, C, "IMAGE_SCN_MEM_PRELOAD");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_GPREL, C, "IMAGE_SCN_GPREL");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_1BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_2BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_4BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_8BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_16BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_16BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_32BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_32BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_64BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_64BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_128BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_128BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_256BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_256BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_512BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_512BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_1024BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_1024BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_2048BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_2048BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_4096BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_4096BYTES");
|
||||
PUSH_MASKED_FLAG(SC, 0xF00000, IMAGE_SCN_ALIGN_8192BYTES, C,
|
||||
"IMAGE_SCN_ALIGN_8192BYTES");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_LNK_NRELOC_OVFL, C, "IMAGE_SCN_LNK_NRELOC_OVFL");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_DISCARDABLE, C, "IMAGE_SCN_MEM_DISCARDABLE");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_CACHED, C, "IMAGE_SCN_MEM_NOT_CACHED");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_NOT_PAGED, C, "IMAGE_SCN_MEM_NOT_PAGED");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_SHARED, C, "IMAGE_SCN_MEM_SHARED");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_EXECUTE, C, "IMAGE_SCN_MEM_EXECUTE");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_READ, C, "IMAGE_SCN_MEM_READ");
|
||||
PUSH_FLAG(SC, IMAGE_SCN_MEM_WRITE, C, "IMAGE_SCN_MEM_WRITE");
|
||||
return typesetItemList(Opts, 3, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
static std::string formatSegMapDescriptorFlag(uint32_t IndentLevel,
|
||||
OMFSegDescFlags Flags) {
|
||||
std::vector<std::string> Opts;
|
||||
if (Flags == OMFSegDescFlags::None)
|
||||
return "none";
|
||||
|
||||
PUSH_FLAG(OMFSegDescFlags, Read, Flags, "read");
|
||||
PUSH_FLAG(OMFSegDescFlags, Write, Flags, "write");
|
||||
PUSH_FLAG(OMFSegDescFlags, Execute, Flags, "execute");
|
||||
PUSH_FLAG(OMFSegDescFlags, AddressIs32Bit, Flags, "32 bit addr");
|
||||
PUSH_FLAG(OMFSegDescFlags, IsSelector, Flags, "selector");
|
||||
PUSH_FLAG(OMFSegDescFlags, IsAbsoluteAddress, Flags, "absolute addr");
|
||||
PUSH_FLAG(OMFSegDescFlags, IsGroup, Flags, "group");
|
||||
return typesetItemList(Opts, 4, IndentLevel, " | ");
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpSectionContribs() {
|
||||
printHeader(P, "Section Contributions");
|
||||
ExitOnError Err("Error dumping publics stream");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!File.hasPDBDbiStream()) {
|
||||
P.formatLine(
|
||||
"Section contribs require a DBI Stream, which could not be loaded");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
auto &Dbi = Err(File.getPDBDbiStream());
|
||||
|
||||
class Visitor : public ISectionContribVisitor {
|
||||
public:
|
||||
Visitor(LinePrinter &P) : P(P) {}
|
||||
void visit(const SectionContrib &SC) override {
|
||||
P.formatLine(
|
||||
"SC | mod = {2}, {0}, size = {1}, data crc = {3}, reloc crc = {4}",
|
||||
formatSegmentOffset(SC.ISect, SC.Off), fmtle(SC.Size), fmtle(SC.Imod),
|
||||
fmtle(SC.DataCrc), fmtle(SC.RelocCrc));
|
||||
P.formatLine(" {0}",
|
||||
formatSectionCharacteristics(P.getIndentLevel() + 6,
|
||||
SC.Characteristics));
|
||||
}
|
||||
void visit(const SectionContrib2 &SC) override {
|
||||
P.formatLine("SC2 | mod = {2}, {0}, size = {1}, data crc = {3}, reloc "
|
||||
"crc = {4}, coff section = {5}",
|
||||
formatSegmentOffset(SC.Base.ISect, SC.Base.Off),
|
||||
fmtle(SC.Base.Size), fmtle(SC.Base.Imod),
|
||||
fmtle(SC.Base.DataCrc), fmtle(SC.Base.RelocCrc),
|
||||
fmtle(SC.ISectCoff));
|
||||
P.formatLine(" {0}",
|
||||
formatSectionCharacteristics(P.getIndentLevel() + 6,
|
||||
SC.Base.Characteristics));
|
||||
}
|
||||
|
||||
private:
|
||||
LinePrinter &P;
|
||||
};
|
||||
|
||||
Visitor V(P);
|
||||
Dbi.visitSectionContributions(V);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error RawOutputStyle::dumpSectionMap() {
|
||||
printHeader(P, "Section Map");
|
||||
ExitOnError Err("Error dumping section map");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (!File.hasPDBDbiStream()) {
|
||||
P.formatLine("Dumping the section map requires a DBI Stream, which could "
|
||||
"not be loaded");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
auto &Dbi = Err(File.getPDBDbiStream());
|
||||
|
||||
uint32_t I = 0;
|
||||
for (auto &M : Dbi.getSectionMap()) {
|
||||
P.formatLine(
|
||||
"Section {0:4} | ovl = {0}, group = {1}, frame = {2}, name = {3}", I,
|
||||
fmtle(M.Ovl), fmtle(M.Group), fmtle(M.Frame), fmtle(M.SecName));
|
||||
P.formatLine(" class = {0}, offset = {1}, size = {2}",
|
||||
fmtle(M.ClassName), fmtle(M.Offset), fmtle(M.SecByteLength));
|
||||
P.formatLine(" flags = {0}",
|
||||
formatSegMapDescriptorFlag(
|
||||
P.getIndentLevel() + 13,
|
||||
static_cast<OMFSegDescFlags>(uint16_t(M.Flags))));
|
||||
++I;
|
||||
}
|
||||
return Error::success();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===//
|
||||
//===- RawOutputStyle.h -------------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
@ -7,15 +7,15 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_LLVMOUTPUTSTYLE_H
|
||||
#ifndef LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_RAWOUTPUTSTYLE_H
|
||||
|
||||
#include "LinePrinter.h"
|
||||
#include "OutputStyle.h"
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/DebugInfo/CodeView/TypeDatabase.h"
|
||||
#include "llvm/Support/ScopedPrinter.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -27,9 +27,9 @@ class LazyRandomTypeCollection;
|
||||
}
|
||||
|
||||
namespace pdb {
|
||||
class LLVMOutputStyle : public OutputStyle {
|
||||
class RawOutputStyle : public OutputStyle {
|
||||
public:
|
||||
LLVMOutputStyle(PDBFile &File);
|
||||
RawOutputStyle(PDBFile &File);
|
||||
|
||||
Error dump() override;
|
||||
|
||||
@ -37,34 +37,25 @@ private:
|
||||
Expected<codeview::LazyRandomTypeCollection &>
|
||||
initializeTypeDatabase(uint32_t SN);
|
||||
|
||||
Error dumpFileHeaders();
|
||||
Error dumpFileSummary();
|
||||
Error dumpStreamSummary();
|
||||
Error dumpFreePageMap();
|
||||
Error dumpBlockRanges();
|
||||
Error dumpGlobalsStream();
|
||||
Error dumpStreamBytes();
|
||||
Error dumpStreamBlocks();
|
||||
Error dumpStringTable();
|
||||
Error dumpInfoStream();
|
||||
Error dumpTpiStream(uint32_t StreamIdx);
|
||||
Error dumpDbiStream();
|
||||
Error dumpModules();
|
||||
Error dumpModuleSyms();
|
||||
Error dumpPublics();
|
||||
Error dumpSectionContribs();
|
||||
Error dumpSectionMap();
|
||||
Error dumpPublicsStream();
|
||||
Error dumpSectionHeaders();
|
||||
Error dumpFpoStream();
|
||||
|
||||
void dumpBitVector(StringRef Name, const BitVector &V);
|
||||
|
||||
void flush();
|
||||
|
||||
PDBFile &File;
|
||||
ScopedPrinter P;
|
||||
LinePrinter P;
|
||||
std::unique_ptr<codeview::LazyRandomTypeCollection> TpiTypes;
|
||||
std::unique_ptr<codeview::LazyRandomTypeCollection> IpiTypes;
|
||||
SmallVector<std::string, 32> StreamPurposes;
|
||||
};
|
||||
}
|
||||
}
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -32,6 +32,13 @@ using namespace llvm;
|
||||
using namespace llvm::codeview;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
static bool checkModuleSubsection(opts::ModuleSubsection MS) {
|
||||
return any_of(opts::pdb2yaml::DumpModuleSubsections,
|
||||
[=](opts::ModuleSubsection M) {
|
||||
return M == MS || M == opts::ModuleSubsection::All;
|
||||
});
|
||||
}
|
||||
|
||||
YAMLOutputStyle::YAMLOutputStyle(PDBFile &File)
|
||||
: File(File), Out(outs()), Obj(File.getAllocator()) {
|
||||
Out.setWriteDefaultValues(!opts::pdb2yaml::Minimal);
|
||||
@ -93,8 +100,8 @@ Error YAMLOutputStyle::dumpFileHeaders() {
|
||||
}
|
||||
|
||||
Error YAMLOutputStyle::dumpStringTable() {
|
||||
bool RequiresStringTable = opts::shared::DumpModuleFiles ||
|
||||
!opts::shared::DumpModuleSubsections.empty();
|
||||
bool RequiresStringTable = opts::pdb2yaml::DumpModuleFiles ||
|
||||
!opts::pdb2yaml::DumpModuleSubsections.empty();
|
||||
bool RequestedStringTable = opts::pdb2yaml::StringTable;
|
||||
if (!RequiresStringTable && !RequestedStringTable)
|
||||
return Error::success();
|
||||
@ -201,7 +208,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
|
||||
Obj.DbiStream->PdbDllRbld = DS.getPdbDllRbld();
|
||||
Obj.DbiStream->PdbDllVersion = DS.getPdbDllVersion();
|
||||
Obj.DbiStream->VerHeader = DS.getDbiVersion();
|
||||
if (opts::shared::DumpModules) {
|
||||
if (opts::pdb2yaml::DumpModules) {
|
||||
const auto &Modules = DS.modules();
|
||||
for (uint32_t I = 0; I < Modules.getModuleCount(); ++I) {
|
||||
DbiModuleDescriptor MI = Modules.getModuleDescriptor(I);
|
||||
@ -211,7 +218,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
|
||||
|
||||
DMI.Mod = MI.getModuleName();
|
||||
DMI.Obj = MI.getObjFileName();
|
||||
if (opts::shared::DumpModuleFiles) {
|
||||
if (opts::pdb2yaml::DumpModuleFiles) {
|
||||
auto Files = Modules.source_files(I);
|
||||
DMI.SourceFiles.assign(Files.begin(), Files.end());
|
||||
}
|
||||
@ -231,7 +238,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
|
||||
auto ExpectedST = File.getStringTable();
|
||||
if (!ExpectedST)
|
||||
return ExpectedST.takeError();
|
||||
if (!opts::shared::DumpModuleSubsections.empty() &&
|
||||
if (!opts::pdb2yaml::DumpModuleSubsections.empty() &&
|
||||
ModS.hasDebugSubsections()) {
|
||||
auto ExpectedChecksums = ModS.findChecksumsSubsection();
|
||||
if (!ExpectedChecksums)
|
||||
@ -242,7 +249,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
|
||||
|
||||
for (const auto &SS : ModS.subsections()) {
|
||||
opts::ModuleSubsection OptionKind = convertSubsectionKind(SS.kind());
|
||||
if (!opts::checkModuleSubsection(OptionKind))
|
||||
if (!checkModuleSubsection(OptionKind))
|
||||
continue;
|
||||
|
||||
auto Converted =
|
||||
@ -253,7 +260,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::shared::DumpModuleSyms) {
|
||||
if (opts::pdb2yaml::DumpModuleSyms) {
|
||||
DMI.Modi.emplace();
|
||||
|
||||
DMI.Modi->Signature = ModS.signature();
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "Analyze.h"
|
||||
#include "Diff.h"
|
||||
#include "LLVMOutputStyle.h"
|
||||
#include "LinePrinter.h"
|
||||
#include "OutputStyle.h"
|
||||
#include "PrettyCompilandDumper.h"
|
||||
@ -23,6 +22,7 @@
|
||||
#include "PrettyFunctionDumper.h"
|
||||
#include "PrettyTypeDumper.h"
|
||||
#include "PrettyVariableDumper.h"
|
||||
#include "RawOutputStyle.h"
|
||||
#include "YAMLOutputStyle.h"
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
@ -266,6 +266,8 @@ cl::list<std::string> InputFilenames(cl::Positional,
|
||||
cl::OneOrMore, cl::sub(DiffSubcommand));
|
||||
}
|
||||
|
||||
cl::OptionCategory FileOptions("Module & File Options");
|
||||
|
||||
namespace raw {
|
||||
|
||||
cl::OptionCategory MsfOptions("MSF Container Options");
|
||||
@ -274,18 +276,11 @@ cl::OptionCategory SymbolOptions("Symbol Options");
|
||||
cl::OptionCategory MiscOptions("Miscellaneous Options");
|
||||
|
||||
// MSF OPTIONS
|
||||
cl::opt<bool> DumpHeaders("headers", cl::desc("dump PDB headers"),
|
||||
cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpStreams("streams",
|
||||
cl::desc("dump summary of the PDB streams"),
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpStreamBlocks("stream-blocks",
|
||||
cl::desc("dump PDB stream blocks"),
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpStreamSummary("stream-summary",
|
||||
cl::desc("dump summary of the PDB streams"),
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpPageStats(
|
||||
"page-stats",
|
||||
cl::desc("dump allocation stats of the pages in the MSF file"),
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<std::string>
|
||||
DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
|
||||
cl::desc("Dump binary data from specified range."),
|
||||
@ -299,40 +294,45 @@ cl::list<std::string>
|
||||
cl::cat(MsfOptions), cl::sub(RawSubcommand));
|
||||
|
||||
// TYPE OPTIONS
|
||||
cl::opt<bool>
|
||||
CompactRecords("compact-records",
|
||||
cl::desc("Dump type and symbol records with less detail"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
|
||||
cl::opt<bool>
|
||||
DumpTpiRecords("tpi-records",
|
||||
cl::desc("dump CodeView type records from TPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpTpiRecordBytes(
|
||||
"tpi-record-bytes",
|
||||
cl::opt<bool> DumpTypes("types",
|
||||
cl::desc("dump CodeView type records from TPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpTypeData(
|
||||
"type-data",
|
||||
cl::desc("dump CodeView type record raw bytes from TPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpTpiHash("tpi-hash", cl::desc("dump CodeView TPI hash stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
|
||||
cl::opt<bool> DumpTypeHashes("type-hash",
|
||||
cl::desc("dump CodeView TPI hash stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
|
||||
cl::opt<bool> DumpIds("ids",
|
||||
cl::desc("dump CodeView type records from IPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool>
|
||||
DumpIpiRecords("ipi-records",
|
||||
cl::desc("dump CodeView type records from IPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpIpiRecordBytes(
|
||||
"ipi-record-bytes",
|
||||
cl::desc("dump CodeView type record raw bytes from IPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
DumpIdData("id-data",
|
||||
cl::desc("dump CodeView type record raw bytes from IPI stream"),
|
||||
cl::cat(TypeOptions), cl::sub(RawSubcommand));
|
||||
|
||||
// SYMBOL OPTIONS
|
||||
cl::opt<bool> DumpGlobals("globals", cl::desc("dump globals stream data"),
|
||||
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpPublics("publics", cl::desc("dump Publics stream data"),
|
||||
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpSymbols("symbols", cl::desc("dump module symbols"),
|
||||
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
||||
|
||||
cl::opt<bool>
|
||||
DumpSymRecordBytes("sym-record-bytes",
|
||||
DumpSymRecordBytes("sym-data",
|
||||
cl::desc("dump CodeView symbol record raw bytes"),
|
||||
cl::cat(SymbolOptions), cl::sub(RawSubcommand));
|
||||
|
||||
// MODULE & FILE OPTIONS
|
||||
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpModuleFiles(
|
||||
"files",
|
||||
cl::desc("for each module dumped, dump the contributing source files"),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand));
|
||||
|
||||
// MISCELLANEOUS OPTIONS
|
||||
cl::opt<bool> DumpStringTable("string-table", cl::desc("dump PDB String Table"),
|
||||
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
||||
@ -342,11 +342,6 @@ cl::opt<bool> DumpSectionContribs("section-contribs",
|
||||
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpSectionMap("section-map", cl::desc("dump section map"),
|
||||
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpSectionHeaders("section-headers",
|
||||
cl::desc("dump section headers"),
|
||||
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
||||
cl::opt<bool> DumpFpo("fpo", cl::desc("dump FPO records"), cl::cat(MiscOptions),
|
||||
cl::sub(RawSubcommand));
|
||||
|
||||
cl::opt<bool> RawAll("all", cl::desc("Implies most other options."),
|
||||
cl::cat(MiscOptions), cl::sub(RawSubcommand));
|
||||
@ -404,20 +399,11 @@ cl::opt<bool> IpiStream("ipi-stream",
|
||||
cl::desc("Dump the IPI Stream (Stream 5)"),
|
||||
cl::sub(PdbToYamlSubcommand), cl::init(false));
|
||||
|
||||
cl::list<std::string> InputFilename(cl::Positional,
|
||||
cl::desc("<input PDB file>"), cl::Required,
|
||||
cl::sub(PdbToYamlSubcommand));
|
||||
}
|
||||
|
||||
namespace shared {
|
||||
cl::OptionCategory FileOptions("Module & File Options");
|
||||
|
||||
// MODULE & FILE OPTIONS
|
||||
cl::opt<bool> DumpModules("modules", cl::desc("dump compiland information"),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand),
|
||||
cl::sub(PdbToYamlSubcommand));
|
||||
cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
|
||||
cl::opt<bool> DumpModuleFiles("module-files", cl::desc("dump file information"),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand),
|
||||
cl::cat(FileOptions),
|
||||
cl::sub(PdbToYamlSubcommand));
|
||||
cl::list<ModuleSubsection> DumpModuleSubsections(
|
||||
"subsections", cl::ZeroOrMore, cl::CommaSeparated,
|
||||
@ -448,11 +434,15 @@ cl::list<ModuleSubsection> DumpModuleSubsections(
|
||||
clEnumValN(ModuleSubsection::Unknown, "unknown",
|
||||
"Any subsection not covered by another option"),
|
||||
clEnumValN(ModuleSubsection::All, "all", "All known subsections")),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand), cl::sub(PdbToYamlSubcommand));
|
||||
cl::cat(FileOptions), cl::sub(PdbToYamlSubcommand));
|
||||
cl::opt<bool> DumpModuleSyms("module-syms", cl::desc("dump module symbols"),
|
||||
cl::cat(FileOptions), cl::sub(RawSubcommand),
|
||||
cl::cat(FileOptions),
|
||||
cl::sub(PdbToYamlSubcommand));
|
||||
} // namespace shared
|
||||
|
||||
cl::list<std::string> InputFilename(cl::Positional,
|
||||
cl::desc("<input PDB file>"), cl::Required,
|
||||
cl::sub(PdbToYamlSubcommand));
|
||||
} // namespace pdb2yaml
|
||||
|
||||
namespace analyze {
|
||||
cl::opt<bool> StringTable("hash-collisions", cl::desc("Find hash collisions"),
|
||||
@ -474,13 +464,6 @@ cl::opt<std::string>
|
||||
|
||||
static ExitOnError ExitOnErr;
|
||||
|
||||
bool opts::checkModuleSubsection(opts::ModuleSubsection MS) {
|
||||
return any_of(opts::shared::DumpModuleSubsections,
|
||||
[=](opts::ModuleSubsection M) {
|
||||
return M == MS || M == opts::ModuleSubsection::All;
|
||||
});
|
||||
}
|
||||
|
||||
static void yamlToPdb(StringRef Path) {
|
||||
BumpPtrAllocator Allocator;
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
|
||||
@ -611,7 +594,7 @@ static void dumpRaw(StringRef Path) {
|
||||
std::unique_ptr<IPDBSession> Session;
|
||||
auto &File = loadPDB(Path, Session);
|
||||
|
||||
auto O = llvm::make_unique<LLVMOutputStyle>(File);
|
||||
auto O = llvm::make_unique<RawOutputStyle>(File);
|
||||
|
||||
ExitOnErr(O->dump());
|
||||
}
|
||||
@ -904,49 +887,21 @@ int main(int argc_, const char *argv_[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if ((opts::RawSubcommand && opts::raw::RawAll) ||
|
||||
(opts::PdbToYamlSubcommand && opts::pdb2yaml::All)) {
|
||||
opts::shared::DumpModules = true;
|
||||
opts::shared::DumpModuleFiles = true;
|
||||
opts::shared::DumpModuleSyms = true;
|
||||
opts::shared::DumpModuleSubsections.push_back(opts::ModuleSubsection::All);
|
||||
if (llvm::is_contained(opts::shared::DumpModuleSubsections,
|
||||
opts::ModuleSubsection::All)) {
|
||||
opts::shared::DumpModuleSubsections.reset();
|
||||
opts::shared::DumpModuleSubsections.push_back(
|
||||
opts::ModuleSubsection::All);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::shared::DumpModuleSyms || opts::shared::DumpModuleFiles)
|
||||
opts::shared::DumpModules = true;
|
||||
|
||||
if (opts::shared::DumpModules)
|
||||
opts::pdb2yaml::DbiStream = true;
|
||||
|
||||
if (opts::RawSubcommand) {
|
||||
if (opts::raw::RawAll) {
|
||||
opts::raw::DumpHeaders = true;
|
||||
opts::raw::DumpGlobals = true;
|
||||
opts::raw::DumpIds = true;
|
||||
opts::raw::DumpPublics = true;
|
||||
opts::raw::DumpSectionHeaders = true;
|
||||
opts::raw::DumpStreamSummary = true;
|
||||
opts::raw::DumpPageStats = true;
|
||||
opts::raw::DumpStreamBlocks = true;
|
||||
opts::raw::DumpTpiRecords = true;
|
||||
opts::raw::DumpTpiHash = true;
|
||||
opts::raw::DumpIpiRecords = true;
|
||||
opts::raw::DumpSectionMap = true;
|
||||
opts::raw::DumpSectionContribs = true;
|
||||
opts::raw::DumpFpo = true;
|
||||
opts::raw::DumpSectionMap = true;
|
||||
opts::raw::DumpStreams = true;
|
||||
opts::raw::DumpStringTable = true;
|
||||
}
|
||||
|
||||
if (opts::raw::CompactRecords &&
|
||||
(opts::raw::DumpTpiRecordBytes || opts::raw::DumpIpiRecordBytes)) {
|
||||
errs() << "-compact-records is incompatible with -tpi-record-bytes and "
|
||||
"-ipi-record-bytes.\n";
|
||||
exit(1);
|
||||
opts::raw::DumpSummary = true;
|
||||
opts::raw::DumpSymbols = true;
|
||||
opts::raw::DumpIds = true;
|
||||
opts::raw::DumpTypes = true;
|
||||
opts::raw::DumpTypeHashes = true;
|
||||
opts::raw::DumpModules = true;
|
||||
opts::raw::DumpModuleFiles = true;
|
||||
}
|
||||
}
|
||||
if (opts::PdbToYamlSubcommand) {
|
||||
@ -958,7 +913,24 @@ int main(int argc_, const char *argv_[]) {
|
||||
opts::pdb2yaml::DbiStream = true;
|
||||
opts::pdb2yaml::TpiStream = true;
|
||||
opts::pdb2yaml::IpiStream = true;
|
||||
opts::pdb2yaml::DumpModules = true;
|
||||
opts::pdb2yaml::DumpModuleFiles = true;
|
||||
opts::pdb2yaml::DumpModuleSyms = true;
|
||||
opts::pdb2yaml::DumpModuleSubsections.push_back(
|
||||
opts::ModuleSubsection::All);
|
||||
if (llvm::is_contained(opts::pdb2yaml::DumpModuleSubsections,
|
||||
opts::ModuleSubsection::All)) {
|
||||
opts::pdb2yaml::DumpModuleSubsections.reset();
|
||||
opts::pdb2yaml::DumpModuleSubsections.push_back(
|
||||
opts::ModuleSubsection::All);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts::pdb2yaml::DumpModuleSyms || opts::pdb2yaml::DumpModuleFiles)
|
||||
opts::pdb2yaml::DumpModules = true;
|
||||
|
||||
if (opts::pdb2yaml::DumpModules)
|
||||
opts::pdb2yaml::DbiStream = true;
|
||||
}
|
||||
|
||||
llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
|
||||
|
@ -27,6 +27,8 @@ uint32_t getTypeLength(const PDBSymbolData &Symbol);
|
||||
|
||||
namespace opts {
|
||||
|
||||
enum class DumpLevel { None, Basic, Verbose };
|
||||
|
||||
enum class ModuleSubsection {
|
||||
Unknown,
|
||||
Lines,
|
||||
@ -41,15 +43,6 @@ enum class ModuleSubsection {
|
||||
All
|
||||
};
|
||||
|
||||
bool checkModuleSubsection(ModuleSubsection Kind);
|
||||
|
||||
template <typename... Ts>
|
||||
bool checkModuleSubsection(ModuleSubsection K1, ModuleSubsection K2,
|
||||
Ts &&... Rest) {
|
||||
return checkModuleSubsection(K1) ||
|
||||
checkModuleSubsection(K2, std::forward<Ts>(Rest)...);
|
||||
}
|
||||
|
||||
namespace pretty {
|
||||
|
||||
enum class ClassDefinitionFormat { None, Layout, All };
|
||||
@ -105,27 +98,24 @@ struct BlockRange {
|
||||
llvm::Optional<uint32_t> Max;
|
||||
};
|
||||
|
||||
extern llvm::cl::opt<bool> DumpSummary;
|
||||
extern llvm::cl::opt<bool> DumpStreams;
|
||||
extern llvm::Optional<BlockRange> DumpBlockRange;
|
||||
extern llvm::cl::list<std::string> DumpStreamData;
|
||||
|
||||
extern llvm::cl::opt<bool> CompactRecords;
|
||||
extern llvm::cl::opt<bool> DumpGlobals;
|
||||
extern llvm::cl::opt<bool> DumpHeaders;
|
||||
extern llvm::cl::opt<bool> DumpStreamBlocks;
|
||||
extern llvm::cl::opt<bool> DumpStreamSummary;
|
||||
extern llvm::cl::opt<bool> DumpPageStats;
|
||||
extern llvm::cl::opt<bool> DumpTpiHash;
|
||||
extern llvm::cl::opt<bool> DumpTpiRecordBytes;
|
||||
extern llvm::cl::opt<bool> DumpTpiRecords;
|
||||
extern llvm::cl::opt<bool> DumpIpiRecords;
|
||||
extern llvm::cl::opt<bool> DumpIpiRecordBytes;
|
||||
extern llvm::cl::opt<bool> DumpStringTable;
|
||||
extern llvm::cl::opt<bool> DumpTypes;
|
||||
extern llvm::cl::opt<bool> DumpTypeData;
|
||||
extern llvm::cl::opt<bool> DumpTypeHashes;
|
||||
extern llvm::cl::opt<bool> DumpIds;
|
||||
extern llvm::cl::opt<bool> DumpIdData;
|
||||
extern llvm::cl::opt<bool> DumpSymbols;
|
||||
extern llvm::cl::opt<bool> DumpSymRecordBytes;
|
||||
extern llvm::cl::opt<bool> DumpPublics;
|
||||
extern llvm::cl::opt<bool> DumpSectionContribs;
|
||||
extern llvm::cl::opt<bool> DumpSectionMap;
|
||||
extern llvm::cl::opt<bool> DumpSymRecordBytes;
|
||||
extern llvm::cl::opt<bool> DumpSectionHeaders;
|
||||
extern llvm::cl::opt<bool> DumpFpo;
|
||||
extern llvm::cl::opt<bool> DumpStringTable;
|
||||
extern llvm::cl::opt<bool> DumpModules;
|
||||
extern llvm::cl::opt<bool> DumpModuleFiles;
|
||||
extern llvm::cl::opt<bool> RawAll;
|
||||
}
|
||||
|
||||
namespace diff {
|
||||
@ -144,14 +134,11 @@ extern llvm::cl::opt<bool> DbiStream;
|
||||
extern llvm::cl::opt<bool> TpiStream;
|
||||
extern llvm::cl::opt<bool> IpiStream;
|
||||
extern llvm::cl::list<std::string> InputFilename;
|
||||
}
|
||||
|
||||
namespace shared {
|
||||
extern llvm::cl::opt<bool> DumpModules;
|
||||
extern llvm::cl::opt<bool> DumpModuleFiles;
|
||||
extern llvm::cl::list<ModuleSubsection> DumpModuleSubsections;
|
||||
extern llvm::cl::opt<bool> DumpModuleSyms;
|
||||
} // namespace shared
|
||||
} // namespace pdb2yaml
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user