[llvm-pdbutil] Add the ability to explain binary files.

Using this, you can use llvm-pdbutil to export the contents of a
stream to a binary file, then run explain on the binary file so
that it treats the offset as an offset into the stream instead
of an offset into a file.  This makes it easy to compare the
contents of the same stream from two different files.

llvm-svn: 329207
This commit is contained in:
Zachary Turner 2018-04-04 17:29:09 +00:00
parent c69ac41c5b
commit 0875a2f99e
12 changed files with 252 additions and 138 deletions

View File

@ -38,9 +38,9 @@ class DbiStream {
friend class DbiStreamBuilder;
public:
DbiStream(PDBFile &File, std::unique_ptr<msf::MappedBlockStream> Stream);
explicit DbiStream(std::unique_ptr<BinaryStream> Stream);
~DbiStream();
Error reload();
Error reload(PDBFile *Pdb);
PdbRaw_DbiVer getDbiVersion() const;
uint32_t getAge() const;
@ -89,12 +89,11 @@ public:
private:
Error initializeSectionContributionData();
Error initializeSectionHeadersData();
Error initializeSectionHeadersData(PDBFile *Pdb);
Error initializeSectionMapData();
Error initializeFpoRecords();
Error initializeFpoRecords(PDBFile *Pdb);
PDBFile &Pdb;
std::unique_ptr<msf::MappedBlockStream> Stream;
std::unique_ptr<BinaryStream> Stream;
PDBStringTable ECNames;

View File

@ -30,7 +30,7 @@ class InfoStream {
friend class InfoStreamBuilder;
public:
InfoStream(std::unique_ptr<msf::MappedBlockStream> Stream);
InfoStream(std::unique_ptr<BinaryStream> Stream);
Error reload();
@ -56,7 +56,7 @@ public:
StringMap<uint32_t> named_streams() const;
private:
std::unique_ptr<msf::MappedBlockStream> Stream;
std::unique_ptr<BinaryStream> Stream;
const InfoStreamHeader *Header;

View File

@ -112,6 +112,8 @@ struct DbiBuildNo {
static const uint16_t BuildMajorMask = 0x7F00;
static const uint16_t BuildMajorShift = 8;
static const uint16_t NewVersionFormatMask = 0x8000;
};
/// The fixed size header that appears at the beginning of the DBI Stream.

View File

@ -45,12 +45,12 @@ static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
return Error::success();
}
DbiStream::DbiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
: Pdb(File), Stream(std::move(Stream)), Header(nullptr) {}
DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream)
: Stream(std::move(Stream)), Header(nullptr) {}
DbiStream::~DbiStream() = default;
Error DbiStream::reload() {
Error DbiStream::reload(PDBFile *Pdb) {
BinaryStreamReader Reader(*Stream);
if (Stream->getLength() < sizeof(DbiStreamHeader))
@ -123,11 +123,11 @@ Error DbiStream::reload() {
if (auto EC = initializeSectionContributionData())
return EC;
if (auto EC = initializeSectionHeadersData())
if (auto EC = initializeSectionHeadersData(Pdb))
return EC;
if (auto EC = initializeSectionMapData())
return EC;
if (auto EC = initializeFpoRecords())
if (auto EC = initializeFpoRecords(Pdb))
return EC;
if (Reader.bytesRemaining() > 0)
@ -246,7 +246,10 @@ Error DbiStream::initializeSectionContributionData() {
}
// Initializes this->SectionHeaders.
Error DbiStream::initializeSectionHeadersData() {
Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) {
if (!Pdb)
return Error::success();
if (DbgStreams.size() == 0)
return Error::success();
@ -254,11 +257,11 @@ Error DbiStream::initializeSectionHeadersData() {
if (StreamNum == kInvalidStreamIndex)
return Error::success();
if (StreamNum >= Pdb.getNumStreams())
if (StreamNum >= Pdb->getNumStreams())
return make_error<RawError>(raw_error_code::no_stream);
auto SHS = MappedBlockStream::createIndexedStream(
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator());
size_t StreamLen = SHS->getLength();
if (StreamLen % sizeof(object::coff_section))
@ -276,7 +279,10 @@ Error DbiStream::initializeSectionHeadersData() {
}
// Initializes this->Fpos.
Error DbiStream::initializeFpoRecords() {
Error DbiStream::initializeFpoRecords(PDBFile *Pdb) {
if (!Pdb)
return Error::success();
if (DbgStreams.size() == 0)
return Error::success();
@ -286,11 +292,11 @@ Error DbiStream::initializeFpoRecords() {
if (StreamNum == kInvalidStreamIndex)
return Error::success();
if (StreamNum >= Pdb.getNumStreams())
if (StreamNum >= Pdb->getNumStreams())
return make_error<RawError>(raw_error_code::no_stream);
auto FS = MappedBlockStream::createIndexedStream(
Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator());
size_t StreamLen = FS->getLength();
if (StreamLen % sizeof(object::FpoData))

View File

@ -20,7 +20,7 @@ using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream)
InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream)
: Stream(std::move(Stream)), Header(nullptr) {}
Error InfoStream::reload() {

View File

@ -289,8 +289,8 @@ Expected<DbiStream &> PDBFile::getPDBDbiStream() {
auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
if (!DbiS)
return DbiS.takeError();
auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS));
if (auto EC = TempDbi->reload())
auto TempDbi = llvm::make_unique<DbiStream>(std::move(*DbiS));
if (auto EC = TempDbi->reload(this))
return std::move(EC);
Dbi = std::move(TempDbi);
}

View File

@ -10,6 +10,7 @@
#include "ExplainOutputStyle.h"
#include "FormatUtil.h"
#include "InputFile.h"
#include "StreamUtil.h"
#include "llvm-pdbutil.h"
@ -19,6 +20,7 @@
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamArray.h"
#include "llvm/Support/Error.h"
@ -27,114 +29,157 @@ using namespace llvm::codeview;
using namespace llvm::msf;
using namespace llvm::pdb;
ExplainOutputStyle::ExplainOutputStyle(PDBFile &File, uint64_t FileOffset)
: File(File), FileOffset(FileOffset),
BlockIndex(FileOffset / File.getBlockSize()),
OffsetInBlock(FileOffset - BlockIndex * File.getBlockSize()),
P(2, false, outs()) {}
ExplainOutputStyle::ExplainOutputStyle(InputFile &File, uint64_t FileOffset)
: File(File), FileOffset(FileOffset), P(2, false, outs()) {}
Error ExplainOutputStyle::dump() {
P.formatLine("Explaining file offset {0} of file '{1}'.", FileOffset,
File.getFilePath());
bool IsAllocated = explainBlockStatus();
if (File.isPdb())
return explainPdbFile();
return explainBinaryFile();
}
Error ExplainOutputStyle::explainPdbFile() {
bool IsAllocated = explainPdbBlockStatus();
if (!IsAllocated)
return Error::success();
AutoIndent Indent(P);
if (isSuperBlock())
explainSuperBlockOffset();
else if (isFpmBlock())
explainFpmBlockOffset();
else if (isBlockMapBlock())
explainBlockMapOffset();
else if (isStreamDirectoryBlock())
explainStreamDirectoryOffset();
else if (auto Index = getBlockStreamIndex())
explainStreamOffset(*Index);
if (isPdbSuperBlock())
explainPdbSuperBlockOffset();
else if (isPdbFpmBlock())
explainPdbFpmBlockOffset();
else if (isPdbBlockMapBlock())
explainPdbBlockMapOffset();
else if (isPdbStreamDirectoryBlock())
explainPdbStreamDirectoryOffset();
else if (auto Index = getPdbBlockStreamIndex())
explainPdbStreamOffset(*Index);
else
explainUnknownBlock();
explainPdbUnknownBlock();
return Error::success();
}
bool ExplainOutputStyle::isSuperBlock() const { return BlockIndex == 0; }
bool ExplainOutputStyle::isFpm1() const {
return ((BlockIndex - 1) % File.getBlockSize() == 0);
}
bool ExplainOutputStyle::isFpm2() const {
return ((BlockIndex - 2) % File.getBlockSize() == 0);
Error ExplainOutputStyle::explainBinaryFile() {
std::unique_ptr<BinaryByteStream> Stream =
llvm::make_unique<BinaryByteStream>(File.unknown().getBuffer(),
llvm::support::little);
switch (opts::explain::InputType) {
case opts::explain::InputFileType::DBIStream: {
DbiStream Dbi(std::move(Stream));
if (auto EC = Dbi.reload(nullptr))
return EC;
explainStreamOffset(Dbi, FileOffset);
break;
}
case opts::explain::InputFileType::PDBStream: {
InfoStream Info(std::move(Stream));
if (auto EC = Info.reload())
return EC;
explainStreamOffset(Info, FileOffset);
break;
}
default:
llvm_unreachable("Invalid input file type!");
}
return Error::success();
}
bool ExplainOutputStyle::isFpmBlock() const { return isFpm1() || isFpm2(); }
bool ExplainOutputStyle::isBlockMapBlock() const {
return BlockIndex == File.getBlockMapIndex();
uint32_t ExplainOutputStyle::pdbBlockIndex() const {
return FileOffset / File.pdb().getBlockSize();
}
bool ExplainOutputStyle::isStreamDirectoryBlock() const {
const auto &Layout = File.getMsfLayout();
return llvm::is_contained(Layout.DirectoryBlocks, BlockIndex);
uint32_t ExplainOutputStyle::pdbBlockOffset() const {
uint64_t BlockStart = pdbBlockIndex() * File.pdb().getBlockSize();
assert(FileOffset >= BlockStart);
return FileOffset - BlockStart;
}
Optional<uint32_t> ExplainOutputStyle::getBlockStreamIndex() const {
const auto &Layout = File.getMsfLayout();
bool ExplainOutputStyle::isPdbSuperBlock() const {
return pdbBlockIndex() == 0;
}
bool ExplainOutputStyle::isPdbFpm1() const {
return ((pdbBlockIndex() - 1) % File.pdb().getBlockSize() == 0);
}
bool ExplainOutputStyle::isPdbFpm2() const {
return ((pdbBlockIndex() - 2) % File.pdb().getBlockSize() == 0);
}
bool ExplainOutputStyle::isPdbFpmBlock() const {
return isPdbFpm1() || isPdbFpm2();
}
bool ExplainOutputStyle::isPdbBlockMapBlock() const {
return pdbBlockIndex() == File.pdb().getBlockMapIndex();
}
bool ExplainOutputStyle::isPdbStreamDirectoryBlock() const {
const auto &Layout = File.pdb().getMsfLayout();
return llvm::is_contained(Layout.DirectoryBlocks, pdbBlockIndex());
}
Optional<uint32_t> ExplainOutputStyle::getPdbBlockStreamIndex() const {
const auto &Layout = File.pdb().getMsfLayout();
for (const auto &Entry : enumerate(Layout.StreamMap)) {
if (!llvm::is_contained(Entry.value(), BlockIndex))
if (!llvm::is_contained(Entry.value(), pdbBlockIndex()))
continue;
return Entry.index();
}
return None;
}
bool ExplainOutputStyle::explainBlockStatus() {
if (FileOffset >= File.getFileSize()) {
bool ExplainOutputStyle::explainPdbBlockStatus() {
if (FileOffset >= File.pdb().getFileSize()) {
P.formatLine("Address {0} is not in the file (file size = {1}).",
FileOffset, File.getFileSize());
FileOffset, File.pdb().getFileSize());
return false;
}
P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, OffsetInBlock,
BlockIndex);
P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, pdbBlockOffset(),
pdbBlockIndex());
bool IsFree = File.getMsfLayout().FreePageMap[BlockIndex];
P.formatLine("Address is in block {0} ({1}allocated).", BlockIndex,
bool IsFree = File.pdb().getMsfLayout().FreePageMap[pdbBlockIndex()];
P.formatLine("Address is in block {0} ({1}allocated).", pdbBlockIndex(),
IsFree ? "un" : "");
return !IsFree;
}
#define endof(Class, Field) (offsetof(Class, Field) + sizeof(Class::Field))
void ExplainOutputStyle::explainSuperBlockOffset() {
void ExplainOutputStyle::explainPdbSuperBlockOffset() {
P.formatLine("This corresponds to offset {0} of the MSF super block, ",
OffsetInBlock);
if (OffsetInBlock < endof(SuperBlock, MagicBytes))
pdbBlockOffset());
if (pdbBlockOffset() < endof(SuperBlock, MagicBytes))
P.printLine("which is part of the MSF file magic.");
else if (OffsetInBlock < endof(SuperBlock, BlockSize)) {
else if (pdbBlockOffset() < endof(SuperBlock, BlockSize)) {
P.printLine("which contains the block size of the file.");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->BlockSize));
} else if (OffsetInBlock < endof(SuperBlock, FreeBlockMapBlock)) {
uint32_t(File.pdb().getMsfLayout().SB->BlockSize));
} else if (pdbBlockOffset() < endof(SuperBlock, FreeBlockMapBlock)) {
P.printLine("which contains the index of the FPM block (e.g. 1 or 2).");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->FreeBlockMapBlock));
} else if (OffsetInBlock < endof(SuperBlock, NumBlocks)) {
uint32_t(File.pdb().getMsfLayout().SB->FreeBlockMapBlock));
} else if (pdbBlockOffset() < endof(SuperBlock, NumBlocks)) {
P.printLine("which contains the number of blocks in the file.");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->NumBlocks));
} else if (OffsetInBlock < endof(SuperBlock, NumDirectoryBytes)) {
uint32_t(File.pdb().getMsfLayout().SB->NumBlocks));
} else if (pdbBlockOffset() < endof(SuperBlock, NumDirectoryBytes)) {
P.printLine("which contains the number of bytes in the stream directory.");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->NumDirectoryBytes));
} else if (OffsetInBlock < endof(SuperBlock, Unknown1)) {
uint32_t(File.pdb().getMsfLayout().SB->NumDirectoryBytes));
} else if (pdbBlockOffset() < endof(SuperBlock, Unknown1)) {
P.printLine("whose purpose is unknown.");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->Unknown1));
} else if (OffsetInBlock < endof(SuperBlock, BlockMapAddr)) {
uint32_t(File.pdb().getMsfLayout().SB->Unknown1));
} else if (pdbBlockOffset() < endof(SuperBlock, BlockMapAddr)) {
P.printLine("which contains the file offset of the block map.");
P.formatLine("The current value is {0}.",
uint32_t(File.getMsfLayout().SB->BlockMapAddr));
uint32_t(File.pdb().getMsfLayout().SB->BlockMapAddr));
} else {
assert(OffsetInBlock > sizeof(SuperBlock));
assert(pdbBlockOffset() > sizeof(SuperBlock));
P.printLine(
"which is outside the range of valid data for the super block.");
}
@ -150,21 +195,21 @@ static std::string toBinaryString(uint8_t Byte) {
return std::string(Result);
}
void ExplainOutputStyle::explainFpmBlockOffset() {
const MSFLayout &Layout = File.getMsfLayout();
void ExplainOutputStyle::explainPdbFpmBlockOffset() {
const MSFLayout &Layout = File.pdb().getMsfLayout();
uint32_t MainFpm = Layout.mainFpmBlock();
uint32_t AltFpm = Layout.alternateFpmBlock();
assert(isFpmBlock());
uint32_t Fpm = isFpm1() ? 1 : 2;
uint32_t FpmChunk = BlockIndex / File.getBlockSize();
assert(isPdbFpmBlock());
uint32_t Fpm = isPdbFpm1() ? 1 : 2;
uint32_t FpmChunk = pdbBlockIndex() / File.pdb().getBlockSize();
assert((Fpm == MainFpm) || (Fpm == AltFpm));
(void)AltFpm;
bool IsMain = (Fpm == MainFpm);
P.formatLine("Address is in FPM{0} ({1} FPM)", Fpm, IsMain ? "Main" : "Alt");
uint32_t DescribedBlockStart =
8 * (FpmChunk * File.getBlockSize() + OffsetInBlock);
if (DescribedBlockStart > File.getBlockCount()) {
8 * (FpmChunk * File.pdb().getBlockSize() + pdbBlockOffset());
if (DescribedBlockStart > File.pdb().getBlockCount()) {
P.printLine("Address is in extraneous FPM space.");
return;
}
@ -172,13 +217,13 @@ void ExplainOutputStyle::explainFpmBlockOffset() {
P.formatLine("Address describes the allocation status of blocks [{0},{1})",
DescribedBlockStart, DescribedBlockStart + 8);
ArrayRef<uint8_t> Bytes;
cantFail(File.getMsfBuffer().readBytes(FileOffset, 1, Bytes));
cantFail(File.pdb().getMsfBuffer().readBytes(FileOffset, 1, Bytes));
P.formatLine("Status = {0} (Note: 0 = allocated, 1 = free)",
toBinaryString(Bytes[0]));
}
void ExplainOutputStyle::explainBlockMapOffset() {
uint64_t BlockMapOffset = File.getBlockMapOffset();
void ExplainOutputStyle::explainPdbBlockMapOffset() {
uint64_t BlockMapOffset = File.pdb().getBlockMapOffset();
uint32_t OffsetInBlock = FileOffset - BlockMapOffset;
P.formatLine("Address is at offset {0} of the directory block list",
OffsetInBlock);
@ -195,25 +240,29 @@ static uint32_t getOffsetInStream(ArrayRef<support::ulittle32_t> StreamBlocks,
return StreamBlockIndex * BlockSize + OffsetInBlock;
}
void ExplainOutputStyle::explainStreamOffset(uint32_t Stream) {
void ExplainOutputStyle::explainPdbStreamOffset(uint32_t Stream) {
SmallVector<StreamInfo, 12> Streams;
discoverStreamPurposes(File, Streams);
discoverStreamPurposes(File.pdb(), Streams);
assert(Stream <= Streams.size());
const StreamInfo &S = Streams[Stream];
const auto &Layout = File.getStreamLayout(Stream);
const auto &Layout = File.pdb().getStreamLayout(Stream);
uint32_t StreamOff =
getOffsetInStream(Layout.Blocks, FileOffset, File.getBlockSize());
getOffsetInStream(Layout.Blocks, FileOffset, File.pdb().getBlockSize());
P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.",
StreamOff, Layout.Length, Stream, S.getLongName(),
(StreamOff > Layout.Length) ? " in unused space" : "");
switch (S.getPurpose()) {
case StreamPurpose::DBI:
explainDbiStream(Stream, StreamOff);
case StreamPurpose::DBI: {
DbiStream &Dbi = cantFail(File.pdb().getPDBDbiStream());
explainStreamOffset(Dbi, StreamOff);
break;
case StreamPurpose::PDB:
explainPdbStream(Stream, StreamOff);
}
case StreamPurpose::PDB: {
InfoStream &Info = cantFail(File.pdb().getPDBInfoStream());
explainStreamOffset(Info, StreamOff);
break;
}
case StreamPurpose::IPI:
case StreamPurpose::TPI:
case StreamPurpose::ModuleStream:
@ -223,11 +272,11 @@ void ExplainOutputStyle::explainStreamOffset(uint32_t Stream) {
}
}
void ExplainOutputStyle::explainStreamDirectoryOffset() {
auto DirectoryBlocks = File.getDirectoryBlockArray();
const auto &Layout = File.getMsfLayout();
void ExplainOutputStyle::explainPdbStreamDirectoryOffset() {
auto DirectoryBlocks = File.pdb().getDirectoryBlockArray();
const auto &Layout = File.pdb().getMsfLayout();
uint32_t StreamOff =
getOffsetInStream(DirectoryBlocks, FileOffset, File.getBlockSize());
getOffsetInStream(DirectoryBlocks, FileOffset, File.pdb().getBlockSize());
P.formatLine("Address is at offset {0}/{1} of Stream Directory{2}.",
StreamOff, uint32_t(Layout.SB->NumDirectoryBytes),
uint32_t(StreamOff > Layout.SB->NumDirectoryBytes)
@ -235,7 +284,7 @@ void ExplainOutputStyle::explainStreamDirectoryOffset() {
: "");
}
void ExplainOutputStyle::explainUnknownBlock() {
void ExplainOutputStyle::explainPdbUnknownBlock() {
P.formatLine("Address has unknown purpose.");
}
@ -352,10 +401,9 @@ static void explainSubstreamOffset(LinePrinter &P, uint32_t OffsetInStream,
}
}
void ExplainOutputStyle::explainDbiStream(uint32_t StreamIdx,
uint32_t OffsetInStream) {
void ExplainOutputStyle::explainStreamOffset(DbiStream &Dbi,
uint32_t OffsetInStream) {
P.printLine("Within the DBI stream:");
DbiStream &Dbi = cantFail(File.getPDBDbiStream());
AutoIndent Indent(P);
const DbiStreamHeader *Header = Dbi.getHeader();
assert(Header != nullptr);
@ -401,10 +449,9 @@ static void explainPdbStreamHeaderOffset(LinePrinter &P, InfoStream &Info,
printStructField(P, "the guid of the PDB", fmt_guid(Header->Guid.Guid));
}
void ExplainOutputStyle::explainPdbStream(uint32_t StreamIdx,
uint32_t OffsetInStream) {
void ExplainOutputStyle::explainStreamOffset(InfoStream &Info,
uint32_t OffsetInStream) {
P.printLine("Within the PDB stream:");
InfoStream &Info = cantFail(File.getPDBInfoStream());
AutoIndent Indent(P);
struct SubstreamInfo {

View File

@ -20,41 +20,46 @@ namespace llvm {
namespace pdb {
class DbiStream;
class PDBFile;
class InfoStream;
class InputFile;
class ExplainOutputStyle : public OutputStyle {
public:
ExplainOutputStyle(PDBFile &File, uint64_t FileOffset);
ExplainOutputStyle(InputFile &File, uint64_t FileOffset);
Error dump() override;
private:
bool explainBlockStatus();
Error explainPdbFile();
Error explainBinaryFile();
bool isFpm1() const;
bool isFpm2() const;
bool explainPdbBlockStatus();
bool isSuperBlock() const;
bool isFpmBlock() const;
bool isBlockMapBlock() const;
bool isStreamDirectoryBlock() const;
Optional<uint32_t> getBlockStreamIndex() const;
bool isPdbFpm1() const;
bool isPdbFpm2() const;
void explainSuperBlockOffset();
void explainFpmBlockOffset();
void explainBlockMapOffset();
void explainStreamDirectoryOffset();
void explainStreamOffset(uint32_t Stream);
void explainUnknownBlock();
bool isPdbSuperBlock() const;
bool isPdbFpmBlock() const;
bool isPdbBlockMapBlock() const;
bool isPdbStreamDirectoryBlock() const;
Optional<uint32_t> getPdbBlockStreamIndex() const;
void explainDbiStream(uint32_t StreamIdx, uint32_t OffsetInStream);
void explainPdbStream(uint32_t StreamIdx, uint32_t OffsetInStream);
void explainPdbSuperBlockOffset();
void explainPdbFpmBlockOffset();
void explainPdbBlockMapOffset();
void explainPdbStreamDirectoryOffset();
void explainPdbStreamOffset(uint32_t Stream);
void explainPdbUnknownBlock();
PDBFile &File;
void explainStreamOffset(DbiStream &Stream, uint32_t OffsetInStream);
void explainStreamOffset(InfoStream &Stream, uint32_t OffsetInStream);
uint32_t pdbBlockIndex() const;
uint32_t pdbBlockOffset() const;
InputFile &File;
const uint64_t FileOffset;
const uint64_t BlockIndex;
const uint64_t OffsetInBlock;
LinePrinter P;
};
} // namespace pdb

View File

@ -242,7 +242,7 @@ void SymbolGroup::formatFromChecksumsOffset(LinePrinter &Printer,
}
}
Expected<InputFile> InputFile::open(StringRef Path) {
Expected<InputFile> InputFile::open(StringRef Path, bool AllowUnknownFile) {
InputFile IF;
if (!llvm::sys::fs::exists(Path))
return make_error<StringError>(formatv("File {0} not found", Path),
@ -274,9 +274,19 @@ Expected<InputFile> InputFile::open(StringRef Path) {
return std::move(IF);
}
return make_error<StringError>(
formatv("File {0} is not a supported file type", Path),
inconvertibleErrorCode());
if (!AllowUnknownFile)
return make_error<StringError>(
formatv("File {0} is not a supported file type", Path),
inconvertibleErrorCode());
auto Result = MemoryBuffer::getFile(Path, -1i64, false);
if (!Result)
return make_error<StringError>(
formatv("File {0} could not be opened", Path), Result.getError());
IF.UnknownFile = std::move(*Result);
IF.PdbOrObj = IF.UnknownFile.get();
return std::move(IF);
}
PDBFile &InputFile::pdb() {
@ -299,6 +309,25 @@ const object::COFFObjectFile &InputFile::obj() const {
return *PdbOrObj.get<object::COFFObjectFile *>();
}
MemoryBuffer &InputFile::unknown() {
assert(isUnknown());
return *PdbOrObj.get<MemoryBuffer *>();
}
const MemoryBuffer &InputFile::unknown() const {
assert(isUnknown());
return *PdbOrObj.get<MemoryBuffer *>();
}
StringRef InputFile::getFilePath() const {
if (isPdb())
return pdb().getFilePath();
if (isObj())
return obj().getFileName();
assert(isUnknown());
return unknown().getBufferIdentifier();
}
bool InputFile::hasTypes() const {
if (isPdb())
return pdb().hasPDBTpiStream();
@ -323,6 +352,8 @@ bool InputFile::isObj() const {
return PdbOrObj.is<object::COFFObjectFile *>();
}
bool InputFile::isUnknown() const { return PdbOrObj.is<MemoryBuffer *>(); }
codeview::LazyRandomTypeCollection &
InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) {
if (Types && Kind == kTypes)

View File

@ -43,7 +43,8 @@ class InputFile {
std::unique_ptr<NativeSession> PdbSession;
object::OwningBinary<object::Binary> CoffObject;
PointerUnion<PDBFile *, object::COFFObjectFile *> PdbOrObj;
std::unique_ptr<MemoryBuffer> UnknownFile;
PointerUnion3<PDBFile *, object::COFFObjectFile *, MemoryBuffer *> PdbOrObj;
using TypeCollectionPtr = std::unique_ptr<codeview::LazyRandomTypeCollection>;
@ -58,12 +59,17 @@ public:
~InputFile();
InputFile(InputFile &&Other) = default;
static Expected<InputFile> open(StringRef Path);
static Expected<InputFile> open(StringRef Path,
bool AllowUnknownFile = false);
PDBFile &pdb();
const PDBFile &pdb() const;
object::COFFObjectFile &obj();
const object::COFFObjectFile &obj() const;
MemoryBuffer &unknown();
const MemoryBuffer &unknown() const;
StringRef getFilePath() const;
bool hasTypes() const;
bool hasIds() const;
@ -77,6 +83,7 @@ public:
bool isPdb() const;
bool isObj() const;
bool isUnknown() const;
};
class SymbolGroup {

View File

@ -621,6 +621,20 @@ cl::list<std::string> InputFilename(cl::Positional,
cl::list<uint64_t> Offsets("offset", cl::desc("The file offset to explain"),
cl::sub(ExplainSubcommand), cl::OneOrMore);
cl::opt<InputFileType> InputType(
"input-type", cl::desc("Specify how to interpret the input file"),
cl::init(InputFileType::PDBFile), cl::Optional, cl::sub(ExplainSubcommand),
cl::values(clEnumValN(InputFileType::PDBFile, "pdb-file",
"Treat input as a PDB file (default)"),
clEnumValN(InputFileType::PDBStream, "pdb-stream",
"Treat input as raw contents of PDB stream"),
clEnumValN(InputFileType::DBIStream, "dbi-stream",
"Treat input as raw contents of DBI stream"),
clEnumValN(InputFileType::Names, "names-stream",
"Treat input as raw contents of /names named stream"),
clEnumValN(InputFileType::ModuleStream, "mod-stream",
"Treat input as raw contents of a module stream")));
} // namespace explain
namespace exportstream {
@ -772,7 +786,6 @@ static void pdb2Yaml(StringRef Path) {
}
static void dumpRaw(StringRef Path) {
InputFile IF = ExitOnErr(InputFile::open(Path));
auto O = llvm::make_unique<DumpOutputStyle>(IF);
@ -1111,10 +1124,11 @@ static void mergePdbs() {
static void explain() {
std::unique_ptr<IPDBSession> Session;
PDBFile &File = loadPDB(opts::explain::InputFilename.front(), Session);
InputFile IF =
ExitOnErr(InputFile::open(opts::explain::InputFilename.front(), true));
for (uint64_t Off : opts::explain::Offsets) {
auto O = llvm::make_unique<ExplainOutputStyle>(File, Off);
auto O = llvm::make_unique<ExplainOutputStyle>(IF, Off);
ExitOnErr(O->dump());
}

View File

@ -190,8 +190,11 @@ extern llvm::cl::opt<bool> DumpModuleSyms;
} // namespace pdb2yaml
namespace explain {
enum class InputFileType { PDBFile, PDBStream, DBIStream, Names, ModuleStream };
extern llvm::cl::list<std::string> InputFilename;
extern llvm::cl::list<uint64_t> Offsets;
extern llvm::cl::opt<InputFileType> InputType;
} // namespace explain
namespace exportstream {