mirror of
https://github.com/RPCSX/llvm.git
synced 2024-12-13 14:46:53 +00:00
[llvm-pdbutil] Create a "bytes" subcommand.
This idea originally came about when I was doing some deep investigation of why certain bytes in a PDB that we round-tripped differed from their original bytes in the source PDB. I found myself having to hack up the code in many places to dump the bytes of this substream, or that record. It would be nice if we could just do this for every possible stream, substream, debug chunk type, etc. It doesn't make sense to put this under dump because there's just so many options that would detract from the more common use case of just dumping deserialized records. So making a new subcommand seems like the most logical course of action. In doing so, we already have two command line options that are suitable for this new subcommand, so start out by moving them there. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306056 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
0895032e6e
commit
08bb54f87b
@ -1,7 +1,7 @@
|
||||
; RUN: llvm-pdbutil raw -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
|
||||
; RUN: llvm-pdbutil raw -summary -modules -files \
|
||||
; RUN: llvm-pdbutil dump -all %p/Inputs/empty.pdb | FileCheck -check-prefix=ALL %s
|
||||
; RUN: llvm-pdbutil dump -summary -modules -files \
|
||||
; RUN: %p/Inputs/big-read.pdb | FileCheck -check-prefix=BIG %s
|
||||
; RUN: not llvm-pdbutil raw -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
|
||||
; RUN: not llvm-pdbutil dump -summary %p/Inputs/bad-block-size.pdb 2>&1 | FileCheck -check-prefix=BAD-BLOCK-SIZE %s
|
||||
|
||||
ALL: Summary
|
||||
ALL-NEXT: ============================================================
|
||||
|
@ -1,8 +1,9 @@
|
||||
; RUN: llvm-pdbutil dump -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
|
||||
; RUN: llvm-pdbutil dump -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
|
||||
; RUN: not llvm-pdbutil dump -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil dump -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil dump -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: llvm-pdbutil bytes -block-data=0 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK0 %s
|
||||
; RUN: llvm-pdbutil bytes -block-data=0-1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
|
||||
; RUN: llvm-pdbutil bytes -block-data=0-0x1 %p/Inputs/empty.pdb | FileCheck --check-prefix=BLOCK01 %s
|
||||
; RUN: not llvm-pdbutil bytes -block-data=0,1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil bytes -block-data=0a1 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
; RUN: not llvm-pdbutil bytes -block-data=0- %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BADSYNTAX %s
|
||||
|
||||
BLOCK0: MSF Blocks
|
||||
BLOCK0-NEXT: ============================================================
|
||||
@ -21,9 +22,9 @@ BLOCK01-NEXT: 0020: 00100000 02000000 19000000 88000000 00000000 18000000 00
|
||||
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-NEXT: 1000: C0FCFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NEXT: 1020: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NEXT: 1040: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................................|
|
||||
BLOCK01-NOT: Block 2 (
|
||||
|
||||
BADSYNTAX: Argument '{{.*}}' invalid format.
|
||||
|
@ -1,6 +1,6 @@
|
||||
; RUN: llvm-pdbutil dump -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
|
||||
; RUN: llvm-pdbutil dump -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
|
||||
; RUN: llvm-pdbutil dump -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
|
||||
; RUN: llvm-pdbutil bytes -stream-data=1 %p/Inputs/empty.pdb | FileCheck --check-prefix=STREAM %s
|
||||
; RUN: llvm-pdbutil bytes -stream-data=100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=INVALIDSTREAM %s
|
||||
; RUN: llvm-pdbutil bytes -stream-data=1,100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=BOTH %s
|
||||
|
||||
STREAM: Stream Data
|
||||
STREAM-NEXT: ============================================================
|
||||
|
167
tools/llvm-pdbutil/BytesOutputStyle.cpp
Normal file
167
tools/llvm-pdbutil/BytesOutputStyle.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
//===- BytesOutputStyle.cpp ----------------------------------- *- C++ --*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BytesOutputStyle.h"
|
||||
|
||||
#include "StreamUtil.h"
|
||||
#include "llvm-pdbutil.h"
|
||||
|
||||
#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
|
||||
#include "llvm/DebugInfo/PDB/Native/RawError.h"
|
||||
#include "llvm/Support/BinaryStreamReader.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::msf;
|
||||
using namespace llvm::pdb;
|
||||
|
||||
namespace {
|
||||
struct StreamSpec {
|
||||
uint32_t SI = 0;
|
||||
uint32_t Begin = 0;
|
||||
uint32_t Size = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
static Expected<StreamSpec> parseStreamSpec(StringRef Str) {
|
||||
StreamSpec Result;
|
||||
if (Str.consumeInteger(0, Result.SI))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
if (Str.consume_front(":")) {
|
||||
if (Str.consumeInteger(0, Result.Begin))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
if (Str.consume_front("@")) {
|
||||
if (Str.consumeInteger(0, Result.Size))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
|
||||
if (!Str.empty())
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
return Result;
|
||||
}
|
||||
|
||||
static SmallVector<StreamSpec, 2> parseStreamSpecs(LinePrinter &P) {
|
||||
SmallVector<StreamSpec, 2> Result;
|
||||
|
||||
for (auto &Str : opts::bytes::DumpStreamData) {
|
||||
auto ESS = parseStreamSpec(Str);
|
||||
if (!ESS) {
|
||||
P.formatLine("Error parsing stream spec {0}: {1}", Str,
|
||||
toString(ESS.takeError()));
|
||||
continue;
|
||||
}
|
||||
Result.push_back(*ESS);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
static void printHeader(LinePrinter &P, const Twine &S) {
|
||||
P.NewLine();
|
||||
P.formatLine("{0,=60}", S);
|
||||
P.formatLine("{0}", fmt_repeat('=', 60));
|
||||
}
|
||||
|
||||
BytesOutputStyle::BytesOutputStyle(PDBFile &File)
|
||||
: File(File), P(2, false, outs()) {}
|
||||
|
||||
Error BytesOutputStyle::dump() {
|
||||
|
||||
if (opts::bytes::DumpBlockRange.hasValue()) {
|
||||
auto &R = *opts::bytes::DumpBlockRange;
|
||||
uint32_t Max = R.Max.getValueOr(R.Min);
|
||||
|
||||
if (Max < R.Min)
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Max < Min",
|
||||
inconvertibleErrorCode());
|
||||
if (Max >= File.getBlockCount())
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Requested block out of bounds",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
dumpBlockRanges(R.Min, Max);
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (!opts::bytes::DumpStreamData.empty()) {
|
||||
dumpStreamBytes();
|
||||
P.NewLine();
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void BytesOutputStyle::dumpBlockRanges(uint32_t Min, uint32_t Max) {
|
||||
printHeader(P, "MSF Blocks");
|
||||
|
||||
AutoIndent Indent(P);
|
||||
for (uint32_t I = Min; I <= Max; ++I) {
|
||||
uint64_t Base = I;
|
||||
Base *= File.getBlockSize();
|
||||
|
||||
auto ExpectedData = File.getBlockData(I, File.getBlockSize());
|
||||
if (!ExpectedData) {
|
||||
P.formatLine("Could not get block {0}. Reason = {1}", I,
|
||||
toString(ExpectedData.takeError()));
|
||||
continue;
|
||||
}
|
||||
std::string Label = formatv("Block {0}", I).str();
|
||||
P.formatBinary(Label, *ExpectedData, Base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BytesOutputStyle::dumpStreamBytes() {
|
||||
if (StreamPurposes.empty())
|
||||
discoverStreamPurposes(File, StreamPurposes);
|
||||
|
||||
printHeader(P, "Stream Data");
|
||||
ExitOnError Err("Unexpected error reading stream data");
|
||||
|
||||
auto Specs = parseStreamSpecs(P);
|
||||
|
||||
for (const auto &Spec : Specs) {
|
||||
uint32_t End = 0;
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (Spec.SI >= File.getNumStreams()) {
|
||||
P.formatLine("Stream {0}: Not present", Spec.SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto S = MappedBlockStream::createIndexedStream(
|
||||
File.getMsfLayout(), File.getMsfBuffer(), Spec.SI, File.getAllocator());
|
||||
if (!S) {
|
||||
P.NewLine();
|
||||
P.formatLine("Stream {0}: Not present", Spec.SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Spec.Size == 0)
|
||||
End = S->getLength();
|
||||
else
|
||||
End = std::min(Spec.Begin + Spec.Size, S->getLength());
|
||||
uint32_t Size = End - Spec.Begin;
|
||||
|
||||
P.formatLine("Stream {0} ({1:N} bytes): {2}", Spec.SI, S->getLength(),
|
||||
StreamPurposes[Spec.SI]);
|
||||
AutoIndent Indent2(P);
|
||||
|
||||
BinaryStreamReader R(*S);
|
||||
ArrayRef<uint8_t> StreamData;
|
||||
Err(R.readBytes(StreamData, S->getLength()));
|
||||
StreamData = StreamData.slice(Spec.Begin, Size);
|
||||
P.formatBinary("Data", StreamData, Spec.Begin);
|
||||
}
|
||||
}
|
41
tools/llvm-pdbutil/BytesOutputStyle.h
Normal file
41
tools/llvm-pdbutil/BytesOutputStyle.h
Normal file
@ -0,0 +1,41 @@
|
||||
//===- BytesOutputStyle.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_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
|
||||
#define LLVM_TOOLS_LLVMPDBDUMP_BYTESOUTPUTSTYLE_H
|
||||
|
||||
#include "LinePrinter.h"
|
||||
#include "OutputStyle.h"
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace pdb {
|
||||
|
||||
class PDBFile;
|
||||
|
||||
class BytesOutputStyle : public OutputStyle {
|
||||
public:
|
||||
BytesOutputStyle(PDBFile &File);
|
||||
|
||||
Error dump() override;
|
||||
|
||||
private:
|
||||
void dumpBlockRanges(uint32_t Min, uint32_t Max);
|
||||
void dumpStreamBytes();
|
||||
|
||||
PDBFile &File;
|
||||
LinePrinter P;
|
||||
SmallVector<std::string, 8> StreamPurposes;
|
||||
};
|
||||
} // namespace pdb
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
|
||||
|
||||
add_llvm_tool(llvm-pdbutil
|
||||
Analyze.cpp
|
||||
BytesOutputStyle.cpp
|
||||
Diff.cpp
|
||||
DumpOutputStyle.cpp
|
||||
llvm-pdbutil.cpp
|
||||
|
@ -80,18 +80,6 @@ Error DumpOutputStyle::dump() {
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::dump::DumpBlockRange.hasValue()) {
|
||||
if (auto EC = dumpBlockRanges())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (!opts::dump::DumpStreamData.empty()) {
|
||||
if (auto EC = dumpStreamBytes())
|
||||
return EC;
|
||||
P.NewLine();
|
||||
}
|
||||
|
||||
if (opts::dump::DumpStringTable) {
|
||||
if (auto EC = dumpStringTable())
|
||||
return EC;
|
||||
@ -216,103 +204,6 @@ Error DumpOutputStyle::dumpStreamSummary() {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DumpOutputStyle::dumpBlockRanges() {
|
||||
printHeader(P, "MSF Blocks");
|
||||
|
||||
auto &R = *opts::dump::DumpBlockRange;
|
||||
uint32_t Max = R.Max.getValueOr(R.Min);
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (Max < R.Min)
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Max < Min",
|
||||
std::make_error_code(std::errc::bad_address));
|
||||
if (Max >= File.getBlockCount())
|
||||
return make_error<StringError>(
|
||||
"Invalid block range specified. Requested block out of bounds",
|
||||
std::make_error_code(std::errc::bad_address));
|
||||
|
||||
for (uint32_t I = R.Min; I <= Max; ++I) {
|
||||
auto ExpectedData = File.getBlockData(I, File.getBlockSize());
|
||||
if (!ExpectedData)
|
||||
return ExpectedData.takeError();
|
||||
std::string Label = formatv("Block {0}", I).str();
|
||||
P.formatBinary(Label, *ExpectedData, 0);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error parseStreamSpec(StringRef Str, uint32_t &SI, uint32_t &Offset,
|
||||
uint32_t &Size) {
|
||||
if (Str.consumeInteger(0, SI))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
if (Str.consume_front(":")) {
|
||||
if (Str.consumeInteger(0, Offset))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
if (Str.consume_front("@")) {
|
||||
if (Str.consumeInteger(0, Size))
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
}
|
||||
if (!Str.empty())
|
||||
return make_error<RawError>(raw_error_code::invalid_format,
|
||||
"Invalid Stream Specification");
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error DumpOutputStyle::dumpStreamBytes() {
|
||||
if (StreamPurposes.empty())
|
||||
discoverStreamPurposes(File, StreamPurposes);
|
||||
|
||||
printHeader(P, "Stream Data");
|
||||
ExitOnError Err("Unexpected error reading stream data");
|
||||
|
||||
for (auto &Str : opts::dump::DumpStreamData) {
|
||||
uint32_t SI = 0;
|
||||
uint32_t Begin = 0;
|
||||
uint32_t Size = 0;
|
||||
uint32_t End = 0;
|
||||
|
||||
if (auto EC = parseStreamSpec(Str, SI, Begin, Size))
|
||||
return EC;
|
||||
|
||||
AutoIndent Indent(P);
|
||||
if (SI >= File.getNumStreams()) {
|
||||
P.formatLine("Stream {0}: Not present", SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto S = MappedBlockStream::createIndexedStream(
|
||||
File.getMsfLayout(), File.getMsfBuffer(), SI, File.getAllocator());
|
||||
if (!S) {
|
||||
P.NewLine();
|
||||
P.formatLine("Stream {0}: Not present", SI);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Size == 0)
|
||||
End = S->getLength();
|
||||
else
|
||||
End = std::min(Begin + Size, S->getLength());
|
||||
|
||||
P.formatLine("Stream {0} ({1:N} bytes): {2}", SI, S->getLength(),
|
||||
StreamPurposes[SI]);
|
||||
AutoIndent Indent2(P);
|
||||
|
||||
BinaryStreamReader R(*S);
|
||||
ArrayRef<uint8_t> StreamData;
|
||||
Err(R.readBytes(StreamData, S->getLength()));
|
||||
Size = End - Begin;
|
||||
StreamData = StreamData.slice(Begin, Size);
|
||||
P.formatBinary("Data", StreamData, Begin);
|
||||
}
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Expected<ModuleDebugStreamRef> getModuleDebugStream(PDBFile &File,
|
||||
uint32_t Index) {
|
||||
ExitOnError Err("Unexpected error");
|
||||
|
@ -106,6 +106,20 @@ void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
void LinePrinter::formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
|
||||
uint64_t Base, uint32_t StartOffset) {
|
||||
NewLine();
|
||||
OS << Label << " (";
|
||||
if (!Data.empty()) {
|
||||
OS << "\n";
|
||||
Base += StartOffset;
|
||||
OS << format_bytes_with_ascii(Data, Base, 32, 4,
|
||||
CurrentIndent + IndentSpaces, true);
|
||||
NewLine();
|
||||
}
|
||||
OS << ")";
|
||||
}
|
||||
|
||||
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
|
||||
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
|
||||
return true;
|
||||
|
@ -45,6 +45,8 @@ public:
|
||||
|
||||
void formatBinary(StringRef Label, ArrayRef<uint8_t> Data,
|
||||
uint32_t StartOffset);
|
||||
void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
|
||||
uint32_t StartOffset);
|
||||
|
||||
bool hasColor() const { return UseColor; }
|
||||
raw_ostream &getStream() { return OS; }
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "llvm-pdbutil.h"
|
||||
|
||||
#include "Analyze.h"
|
||||
#include "BytesOutputStyle.h"
|
||||
#include "Diff.h"
|
||||
#include "DumpOutputStyle.h"
|
||||
#include "LinePrinter.h"
|
||||
@ -87,6 +88,8 @@ using namespace llvm::pdb;
|
||||
namespace opts {
|
||||
|
||||
cl::SubCommand DumpSubcommand("dump", "Dump MSF and CodeView debug info");
|
||||
cl::SubCommand BytesSubcommand("bytes", "Dump raw bytes from the PDB file");
|
||||
|
||||
cl::SubCommand
|
||||
PrettySubcommand("pretty",
|
||||
"Dump semantic information about types and symbols");
|
||||
@ -263,6 +266,26 @@ cl::list<std::string> InputFilenames(cl::Positional,
|
||||
|
||||
cl::OptionCategory FileOptions("Module & File Options");
|
||||
|
||||
namespace bytes {
|
||||
llvm::Optional<BlockRange> DumpBlockRange;
|
||||
|
||||
cl::opt<std::string>
|
||||
DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
|
||||
cl::desc("Dump binary data from specified range."),
|
||||
cl::sub(BytesSubcommand));
|
||||
|
||||
cl::list<std::string>
|
||||
DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
|
||||
cl::desc("Dump binary data from specified streams. Format "
|
||||
"is SN[:Start][@Size]"),
|
||||
cl::sub(BytesSubcommand));
|
||||
|
||||
cl::list<std::string> InputFilenames(cl::Positional,
|
||||
cl::desc("<input PDB files>"),
|
||||
cl::OneOrMore, cl::sub(BytesSubcommand));
|
||||
|
||||
} // namespace bytes
|
||||
|
||||
namespace dump {
|
||||
|
||||
cl::OptionCategory MsfOptions("MSF Container Options");
|
||||
@ -276,17 +299,6 @@ cl::opt<bool> DumpSummary("summary", cl::desc("dump file summary"),
|
||||
cl::opt<bool> DumpStreams("streams",
|
||||
cl::desc("dump summary of the PDB streams"),
|
||||
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
||||
cl::opt<std::string>
|
||||
DumpBlockRangeOpt("block-data", cl::value_desc("start[-end]"),
|
||||
cl::desc("Dump binary data from specified range."),
|
||||
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
||||
llvm::Optional<BlockRange> DumpBlockRange;
|
||||
|
||||
cl::list<std::string>
|
||||
DumpStreamData("stream-data", cl::CommaSeparated, cl::ZeroOrMore,
|
||||
cl::desc("Dump binary data from specified streams. Format "
|
||||
"is SN[:Start][@Size]"),
|
||||
cl::cat(MsfOptions), cl::sub(DumpSubcommand));
|
||||
|
||||
// TYPE OPTIONS
|
||||
cl::opt<bool> DumpTypes("types",
|
||||
@ -626,6 +638,15 @@ static void dumpRaw(StringRef Path) {
|
||||
ExitOnErr(O->dump());
|
||||
}
|
||||
|
||||
static void dumpBytes(StringRef Path) {
|
||||
std::unique_ptr<IPDBSession> Session;
|
||||
auto &File = loadPDB(Path, Session);
|
||||
|
||||
auto O = llvm::make_unique<BytesOutputStyle>(File);
|
||||
|
||||
ExitOnErr(O->dump());
|
||||
}
|
||||
|
||||
static void dumpAnalysis(StringRef Path) {
|
||||
std::unique_ptr<IPDBSession> Session;
|
||||
auto &File = loadPDB(Path, Session);
|
||||
@ -882,6 +903,27 @@ static void mergePdbs() {
|
||||
ExitOnErr(Builder.commit(OutFile));
|
||||
}
|
||||
|
||||
static bool validateBlockRangeArgument() {
|
||||
if (opts::bytes::DumpBlockRangeOpt.empty())
|
||||
return true;
|
||||
|
||||
llvm::Regex R("^([^-]+)(-([^-]+))?$");
|
||||
llvm::SmallVector<llvm::StringRef, 2> Matches;
|
||||
if (!R.match(opts::bytes::DumpBlockRangeOpt, &Matches))
|
||||
return false;
|
||||
|
||||
opts::bytes::DumpBlockRange.emplace();
|
||||
if (!to_integer(Matches[1], opts::bytes::DumpBlockRange->Min))
|
||||
return false;
|
||||
|
||||
if (!Matches[3].empty()) {
|
||||
opts::bytes::DumpBlockRange->Max.emplace();
|
||||
if (!to_integer(Matches[3], *opts::bytes::DumpBlockRange->Max))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc_, const char *argv_[]) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal(argv_[0]);
|
||||
@ -897,21 +939,11 @@ int main(int argc_, const char *argv_[]) {
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
|
||||
if (!opts::dump::DumpBlockRangeOpt.empty()) {
|
||||
llvm::Regex R("^([0-9]+)(-([0-9]+))?$");
|
||||
llvm::SmallVector<llvm::StringRef, 2> Matches;
|
||||
if (!R.match(opts::dump::DumpBlockRangeOpt, &Matches)) {
|
||||
errs() << "Argument '" << opts::dump::DumpBlockRangeOpt
|
||||
<< "' invalid format.\n";
|
||||
errs().flush();
|
||||
exit(1);
|
||||
}
|
||||
opts::dump::DumpBlockRange.emplace();
|
||||
Matches[1].getAsInteger(10, opts::dump::DumpBlockRange->Min);
|
||||
if (!Matches[3].empty()) {
|
||||
opts::dump::DumpBlockRange->Max.emplace();
|
||||
Matches[3].getAsInteger(10, *opts::dump::DumpBlockRange->Max);
|
||||
}
|
||||
if (!validateBlockRangeArgument()) {
|
||||
errs() << "Argument '" << opts::bytes::DumpBlockRangeOpt
|
||||
<< "' invalid format.\n";
|
||||
errs().flush();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (opts::DumpSubcommand) {
|
||||
@ -1018,6 +1050,9 @@ int main(int argc_, const char *argv_[]) {
|
||||
} else if (opts::DumpSubcommand) {
|
||||
std::for_each(opts::dump::InputFilenames.begin(),
|
||||
opts::dump::InputFilenames.end(), dumpRaw);
|
||||
} else if (opts::BytesSubcommand) {
|
||||
std::for_each(opts::bytes::InputFilenames.begin(),
|
||||
opts::bytes::InputFilenames.end(), dumpBytes);
|
||||
} else if (opts::DiffSubcommand) {
|
||||
if (opts::diff::InputFilenames.size() != 2) {
|
||||
errs() << "diff subcommand expects exactly 2 arguments.\n";
|
||||
|
@ -92,16 +92,19 @@ extern llvm::cl::opt<ClassDefinitionFormat> ClassFormat;
|
||||
extern llvm::cl::opt<uint32_t> ClassRecursionDepth;
|
||||
}
|
||||
|
||||
namespace dump {
|
||||
namespace bytes {
|
||||
struct BlockRange {
|
||||
uint32_t Min;
|
||||
llvm::Optional<uint32_t> Max;
|
||||
};
|
||||
extern llvm::Optional<BlockRange> DumpBlockRange;
|
||||
extern llvm::cl::list<std::string> DumpStreamData;
|
||||
} // namespace bytes
|
||||
|
||||
namespace dump {
|
||||
|
||||
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> DumpLines;
|
||||
extern llvm::cl::opt<bool> DumpInlineeLines;
|
||||
|
Loading…
Reference in New Issue
Block a user