mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-24 04:45:00 +00:00
[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:
parent
c69ac41c5b
commit
0875a2f99e
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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))
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user