411 changes: 87 additions & 324 deletions lld/test/COFF/pdb.test

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions llvm/include/llvm/DebugInfo/CodeView/CodeView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
17 changes: 17 additions & 0 deletions llvm/include/llvm/DebugInfo/CodeView/Formatters.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
10 changes: 5 additions & 5 deletions llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ class PublicSym32 : public SymbolRecord {
: SymbolRecord(SymbolRecordKind::PublicSym32),
RecordOffset(RecordOffset) {}

uint32_t Index;
TypeIndex Index;
uint32_t Offset;
uint16_t Segment;
StringRef Name;
Expand All @@ -379,7 +379,7 @@ class RegisterSym : public SymbolRecord {
: SymbolRecord(SymbolRecordKind::RegisterSym),
RecordOffset(RecordOffset) {}

uint32_t Index;
TypeIndex Index;
RegisterId Register;
StringRef Name;

Expand Down Expand Up @@ -679,7 +679,7 @@ class FileStaticSym : public SymbolRecord {
: SymbolRecord(SymbolRecordKind::FileStaticSym),
RecordOffset(RecordOffset) {}

uint32_t Index;
TypeIndex Index;
uint32_t ModFilenameOffset;
LocalSymFlags Flags;
StringRef Name;
Expand Down Expand Up @@ -814,7 +814,7 @@ class FrameCookieSym : public SymbolRecord {

uint32_t CodeOffset;
uint16_t Register;
uint8_t CookieKind;
FrameCookieKind CookieKind;
uint8_t Flags;

uint32_t RecordOffset;
Expand Down Expand Up @@ -871,7 +871,7 @@ class RegRelativeSym : public SymbolRecord {

uint32_t Offset;
TypeIndex Type;
uint16_t Register;
RegisterId Register;
StringRef Name;

uint32_t RecordOffset;
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/DebugInfo/CodeView/TypeIndex.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ class TypeIndex {
return A.toArrayIndex() - B.toArrayIndex();
}

static StringRef simpleTypeName(TypeIndex TI);

private:
support::ulittle32_t Index;
};
Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/PDB/Native/ModuleDebugStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class ModuleDebugStreamRef {
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;
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/DebugInfo/PDB/Native/PublicsStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class PublicsStream {
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 {
Expand Down
6 changes: 5 additions & 1 deletion llvm/include/llvm/DebugInfo/PDB/Native/RawConstants.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/DebugInfo/PDB/Native/SymbolStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class SymbolStream {
~SymbolStream();
Error reload();

const codeview::CVSymbolArray &getSymbolArray() const {
return SymbolRecords;
}

iterator_range<codeview::CVSymbolArray::Iterator>
getSymbols(bool *HadError) const;

Expand Down
6 changes: 6 additions & 0 deletions llvm/include/llvm/Support/BinaryStreamArray.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,12 @@ template <typename T> class FixedStreamArray {
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:
Expand Down
14 changes: 14 additions & 0 deletions llvm/include/llvm/Support/FormatProviders.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FormatVariadicDetails.h"
#include "llvm/Support/NativeFormatting.h"

Expand Down Expand Up @@ -150,6 +151,19 @@ struct format_provider<
}
};

template <typename T, llvm::support::endianness E, int alignment>
struct format_provider<
support::detail::packed_endian_specific_integral<T, E, alignment>> {
using Type =
support::detail::packed_endian_specific_integral<T, E, alignment>;

public:
static void format(const Type &V, llvm::raw_ostream &Stream,
StringRef Style) {
format_provider<T>::format(static_cast<T>(V), Stream, Style);
}
};

/// Implementation of format_provider<T> for integral pointer types.
///
/// The options string of a pointer type has the grammar:
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/DebugInfo/CodeView/SymbolDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -516,15 +516,15 @@ 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();
}

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);
Expand Down Expand Up @@ -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();
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
71 changes: 2 additions & 69 deletions llvm/lib/DebugInfo/CodeView/TypeDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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()];
Expand Down
81 changes: 79 additions & 2 deletions llvm/lib/DebugInfo/CodeView/TypeIndex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions llvm/lib/DebugInfo/PDB/Native/PublicsStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }
10 changes: 10 additions & 0 deletions llvm/lib/ObjectYAML/CodeViewYAMLSymbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down
74 changes: 0 additions & 74 deletions llvm/test/DebugInfo/PDB/pdb-yaml-types.test

This file was deleted.

146 changes: 1 addition & 145 deletions llvm/test/DebugInfo/PDB/pdbdump-debug-subsections.test
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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: }
3,982 changes: 1,087 additions & 2,895 deletions llvm/test/DebugInfo/PDB/pdbdump-headers.test

Large diffs are not rendered by default.

106 changes: 46 additions & 60 deletions llvm/test/DebugInfo/PDB/pdbdump-merge-ids-and-types.test
Original file line number Diff line number Diff line change
@@ -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
43 changes: 18 additions & 25 deletions llvm/test/DebugInfo/PDB/pdbdump-mergeids.test
Original file line number Diff line number Diff line change
@@ -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
60 changes: 36 additions & 24 deletions llvm/test/DebugInfo/PDB/pdbdump-mergetypes.test
Original file line number Diff line number Diff line change
@@ -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
64 changes: 29 additions & 35 deletions llvm/test/DebugInfo/PDB/pdbdump-raw-blocks.test
Original file line number Diff line number Diff line change
@@ -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.
51 changes: 28 additions & 23 deletions llvm/test/DebugInfo/PDB/pdbdump-raw-stream.test
Original file line number Diff line number Diff line change
@@ -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
73 changes: 29 additions & 44 deletions llvm/test/DebugInfo/PDB/pdbdump-readwrite.test
Original file line number Diff line number Diff line change
Expand Up @@ -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
47 changes: 0 additions & 47 deletions llvm/test/tools/llvm-pdbdump/raw-stream-data.test

This file was deleted.

5 changes: 4 additions & 1 deletion llvm/tools/llvm-pdbutil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -25,6 +27,7 @@ add_llvm_tool(llvm-pdbutil
PrettyTypeDumper.cpp
PrettyTypedefDumper.cpp
PrettyVariableDumper.cpp
RawOutputStyle.cpp
StreamUtil.cpp
YAMLOutputStyle.cpp
)
Expand Down
49 changes: 49 additions & 0 deletions llvm/tools/llvm-pdbutil/FormatUtil.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
92 changes: 92 additions & 0 deletions llvm/tools/llvm-pdbutil/FormatUtil.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
//===- 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/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<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 llvm
#endif
1,198 changes: 0 additions & 1,198 deletions llvm/tools/llvm-pdbutil/LLVMOutputStyle.cpp

This file was deleted.

33 changes: 30 additions & 3 deletions llvm/tools/llvm-pdbutil/LinePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -60,17 +61,30 @@ 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() {
OS << "\n";
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;
Expand All @@ -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;
Expand Down
31 changes: 28 additions & 3 deletions llvm/tools/llvm-pdbutil/LinePrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>

Expand All @@ -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; }
Expand Down Expand Up @@ -63,6 +77,17 @@ class LinePrinter {
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;
Expand Down
753 changes: 753 additions & 0 deletions llvm/tools/llvm-pdbutil/MinimalSymbolDumper.cpp

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions llvm/tools/llvm-pdbutil/MinimalSymbolDumper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//===- 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), RecordBytes(RecordBytes), Types(Types) {}

virtual Error visitSymbolBegin(codeview::CVSymbol &Record);
virtual Error visitSymbolEnd(codeview::CVSymbol &Record);

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

uint32_t Width;
LinePrinter &P;
bool RecordBytes = false;
codeview::LazyRandomTypeCollection &Types;
};
} // namespace pdb
} // namespace llvm

#endif
535 changes: 535 additions & 0 deletions llvm/tools/llvm-pdbutil/MinimalTypeDumper.cpp

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions llvm/tools/llvm-pdbutil/MinimalTypeDumper.h
Original file line number Diff line number Diff line change
@@ -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;

uint32_t Width;
LinePrinter &P;
bool RecordBytes = false;
codeview::LazyRandomTypeCollection &Types;
};
} // namespace pdb
} // namespace llvm

#endif
669 changes: 669 additions & 0 deletions llvm/tools/llvm-pdbutil/RawOutputStyle.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===- LLVMOutputStyle.h -------------------------------------- *- C++ --*-===//
//===- RawOutputStyle.h -------------------------------------- *- C++ --*-===//
//
// The LLVM Compiler Infrastructure
//
Expand All @@ -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>

Expand All @@ -27,44 +27,35 @@ class LazyRandomTypeCollection;
}

namespace pdb {
class LLVMOutputStyle : public OutputStyle {
class RawOutputStyle : public OutputStyle {
public:
LLVMOutputStyle(PDBFile &File);
RawOutputStyle(PDBFile &File);

Error dump() override;

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
21 changes: 14 additions & 7 deletions llvm/tools/llvm-pdbutil/YAMLOutputStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand All @@ -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());
}
Expand All @@ -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)
Expand All @@ -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 =
Expand All @@ -253,7 +260,7 @@ Error YAMLOutputStyle::dumpDbiStream() {
}
}

if (opts::shared::DumpModuleSyms) {
if (opts::pdb2yaml::DumpModuleSyms) {
DMI.Modi.emplace();

DMI.Modi->Signature = ModS.signature();
Expand Down
172 changes: 72 additions & 100 deletions llvm/tools/llvm-pdbutil/llvm-pdbutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

#include "Analyze.h"
#include "Diff.h"
#include "LLVMOutputStyle.h"
#include "LinePrinter.h"
#include "OutputStyle.h"
#include "PrettyCompilandDumper.h"
#include "PrettyExternalSymbolDumper.h"
#include "PrettyFunctionDumper.h"
#include "PrettyTypeDumper.h"
#include "PrettyVariableDumper.h"
#include "RawOutputStyle.h"
#include "YAMLOutputStyle.h"

#include "llvm/ADT/ArrayRef.h"
Expand Down Expand Up @@ -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");
Expand All @@ -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."),
Expand All @@ -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));
Expand All @@ -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));
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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"),
Expand All @@ -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 =
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
45 changes: 16 additions & 29 deletions llvm/tools/llvm-pdbutil/llvm-pdbutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ uint32_t getTypeLength(const PDBSymbolData &Symbol);

namespace opts {

enum class DumpLevel { None, Basic, Verbose };

enum class ModuleSubsection {
Unknown,
Lines,
Expand All @@ -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 };
Expand Down Expand Up @@ -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 {
Expand All @@ -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