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:
Zachary Turner 2017-06-15 22:24:24 +00:00
parent 02688b00ef
commit 7e5d31edd7
40 changed files with 3828 additions and 4818 deletions

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -248,6 +248,8 @@ public:
return A.toArrayIndex() - B.toArrayIndex();
}
static StringRef simpleTypeName(TypeIndex TI);
private:
support::ulittle32_t Index;
};

View File

@ -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;

View File

@ -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 {

View File

@ -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

View File

@ -27,6 +27,10 @@ public:
~SymbolStream();
Error reload();
const codeview::CVSymbolArray &getSymbolArray() const {
return SymbolRecords;
}
iterator_range<codeview::CVSymbolArray::Iterator>
getSymbols(bool *HadError) const;

View File

@ -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:

View File

@ -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();
}

View File

@ -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();

View File

@ -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()];

View File

@ -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

View File

@ -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(); }

View File

@ -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 {

View File

@ -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: ]

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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:}

View File

@ -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
)

View 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);
}

View 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

View File

@ -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;

View File

@ -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;

View 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();
}

View 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

View 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();
}

View 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

View 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();
}

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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