#include "llvm/ADT/DenseMap.h"
#include "llvm/DebugInfo/MSF/IMSFFile.h"
#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/Endian.h"
ArrayRef<support::ulittle32_t> getDirectoryBlockArray() const;
+ msf::MSFStreamLayout getStreamLayout(uint32_t StreamIdx) const;
+
Error parseFileHeaders();
Error parseStreamData();
return ContainerLayout.DirectoryBlocks;
}
+MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
+ MSFStreamLayout Result;
+ auto Blocks = getStreamBlockList(StreamIdx);
+ Result.Blocks.assign(Blocks.begin(), Blocks.end());
+ Result.Length = getStreamByteSize(StreamIdx);
+ return Result;
+}
+
Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
if (!Globals) {
auto DbiS = getPDBDbiStream();
; 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
+; RUN: llvm-pdbutil bytes -stream-data=1:10 %p/Inputs/empty.pdb | FileCheck --check-prefix=OFFSET %s
+; RUN: llvm-pdbutil bytes -stream-data=1@20 %p/Inputs/empty.pdb | FileCheck --check-prefix=SIZED %s
+; RUN: llvm-pdbutil bytes -stream-data=1:8@20 %p/Inputs/empty.pdb | FileCheck --check-prefix=SLICE %s
+; RUN: llvm-pdbutil bytes -stream-data=1:0x8@0x14 %p/Inputs/empty.pdb | FileCheck --check-prefix=SLICE %s
+; RUN: llvm-pdbutil bytes -stream-data=2:4050@100 %p/Inputs/empty.pdb 2>&1 | FileCheck --check-prefix=DISCONTINUITY %s
+
STREAM: Stream Data
STREAM-NEXT: ============================================================
-STREAM-NEXT: Stream 1 (118 bytes): PDB Stream
+STREAM-NEXT: Stream 1: PDB Stream (dumping 118 / 118 bytes)
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: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
+STREAM-NEXT: 13020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
+STREAM-NEXT: 13040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
+STREAM-NEXT: 13060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
STREAM-NEXT: )
INVALIDSTREAM: Stream Data
BOTH: Stream Data
BOTH-NEXT: ============================================================
-BOTH-NEXT: Stream 1 (118 bytes): PDB Stream
+BOTH-NEXT: Stream 1: PDB Stream (dumping 118 / 118 bytes)
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: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 896F9988 FAE52FF0 22000000 |..1....T.....5VA...I.o..../."...|
+BOTH-NEXT: 13020: 2F4C696E 6B496E66 6F002F6E 616D6573 002F7372 632F6865 61646572 626C6F63 |/LinkInfo./names./src/headerbloc|
+BOTH-NEXT: 13040: 6B000300 00000600 00000100 00001A00 00000000 00001100 00000900 00000A00 |k...............................|
+BOTH-NEXT: 13060: 00000D00 00000000 00000500 00000000 00004191 3201 |..................A.2.|
BOTH-NEXT: )
BOTH-NEXT: Stream 100: Not present
+
+OFFSET: Stream Data
+OFFSET-NEXT: ============================================================
+OFFSET-NEXT: Stream 1: PDB Stream (dumping 108 / 118 bytes)
+OFFSET-NEXT: Data (
+OFFSET-NEXT: 1300A: 00000B35 564186A0 A249896F 9988FAE5 2FF02200 00002F4C 696E6B49 6E666F00 |...5VA...I.o..../.".../LinkInfo.|
+OFFSET-NEXT: 1302A: 2F6E616D 6573002F 7372632F 68656164 6572626C 6F636B00 03000000 06000000 |/names./src/headerblock.........|
+OFFSET-NEXT: 1304A: 01000000 1A000000 00000000 11000000 09000000 0A000000 0D000000 00000000 |................................|
+OFFSET-NEXT: 1306A: 05000000 00000000 41913201 |........A.2.|
+OFFSET-NEXT: )
+
+SIZED: Stream Data
+SIZED-NEXT: ============================================================
+SIZED-NEXT: Stream 1: PDB Stream (dumping 20 / 118 bytes)
+SIZED-NEXT: Data (
+SIZED-NEXT: 13000: 942E3101 E207E554 01000000 0B355641 86A0A249 |..1....T.....5VA...I|
+SIZED-NEXT: )
+
+SLICE: Stream Data
+SLICE-NEXT: ============================================================
+SLICE-NEXT: Stream 1: PDB Stream (dumping 20 / 118 bytes)
+SLICE-NEXT: Data (
+SLICE-NEXT: 13008: 01000000 0B355641 86A0A249 896F9988 FAE52FF0 |.....5VA...I.o..../.|
+SLICE-NEXT: )
+
+DISCONTINUITY: Stream Data
+DISCONTINUITY-NEXT: ============================================================
+DISCONTINUITY-NEXT: Stream 2: TPI Stream (dumping 100 / 5,392 bytes)
+DISCONTINUITY-NEXT: Data (
+DISCONTINUITY-NEXT: 12FD2: 65537472 75637455 73616765 00F10215 03000480 00002000 654C6F63 616C5573 |eStructUsage.......... .eLocalUs|
+DISCONTINUITY-NEXT: 12FF2: 61676500 F2F10215 03000480 0000 |age...........|
+DISCONTINUITY-NEXT: -------------------------------------------------<discontinuity>--------------------------------------------------
+DISCONTINUITY-NEXT: 11000: 40006550 726F7065 72747955 73616765 00F3F2F1 02150300 04800000 80006545 |@.ePropertyUsage..............eE|
+DISCONTINUITY-NEXT: 11020: 76656E74 55736167 6500F2F1 02150300 04800000 0001 |ventUsage.............|
+DISCONTINUITY-NEXT: )
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();
+ if (Spec.SI >= StreamPurposes.size()) {
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);
+ P.formatMsfStreamData("Data", File, Spec.SI, StreamPurposes[Spec.SI],
+ Spec.Begin, Spec.Size);
}
}
#include "llvm-pdbutil.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFStreamLayout.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
#include "llvm/DebugInfo/PDB/UDTLayout.h"
+#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
using namespace llvm;
+using namespace llvm::msf;
using namespace llvm::pdb;
namespace {
OS << ")";
}
+namespace {
+struct Run {
+ Run() = default;
+ explicit Run(uint32_t Block) : Block(Block) {}
+ uint32_t Block = 0;
+ uint32_t ByteLen = 0;
+};
+} // namespace
+
+static std::vector<Run> computeBlockRuns(uint32_t BlockSize,
+ const msf::MSFStreamLayout &Layout) {
+ std::vector<Run> Runs;
+ if (Layout.Length == 0)
+ return Runs;
+
+ ArrayRef<support::ulittle32_t> Blocks = Layout.Blocks;
+ assert(!Blocks.empty());
+ uint32_t StreamBytesRemaining = Layout.Length;
+ Runs.emplace_back(Blocks[0]);
+ while (!Blocks.empty()) {
+ Run *CurrentRun = &Runs.back();
+ uint32_t NextBlock = Blocks.front();
+ if (NextBlock < CurrentRun->Block || (NextBlock - CurrentRun->Block > 1)) {
+ Runs.emplace_back(NextBlock);
+ CurrentRun = &Runs.back();
+ }
+
+ uint32_t Used = std::min(BlockSize, StreamBytesRemaining);
+ CurrentRun->ByteLen += Used;
+ StreamBytesRemaining -= Used;
+ Blocks = Blocks.drop_front();
+ }
+ return Runs;
+}
+
+static std::pair<Run, uint32_t> findRun(uint32_t Offset, ArrayRef<Run> Runs) {
+ for (const auto &R : Runs) {
+ if (Offset < R.ByteLen)
+ return std::make_pair(R, Offset);
+ Offset -= R.ByteLen;
+ }
+ llvm_unreachable("Invalid offset!");
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size) {
+ if (StreamIdx >= File.getNumStreams()) {
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+ if (Size + Offset > File.getStreamByteSize(StreamIdx)) {
+ formatLine(
+ "Stream {0}: Invalid offset and size, range out of stream bounds",
+ StreamIdx);
+ return;
+ }
+
+ auto S = MappedBlockStream::createIndexedStream(
+ File.getMsfLayout(), File.getMsfBuffer(), StreamIdx, File.getAllocator());
+ if (!S) {
+ NewLine();
+ formatLine("Stream {0}: Not present", StreamIdx);
+ return;
+ }
+
+ uint32_t End =
+ (Size == 0) ? S->getLength() : std::min(Offset + Size, S->getLength());
+ Size = End - Offset;
+
+ formatLine("Stream {0}: {1} (dumping {2:N} / {3:N} bytes)", StreamIdx,
+ StreamPurpose, Size, S->getLength());
+ AutoIndent Indent(*this);
+ BinaryStreamRef Slice(*S);
+ Slice = Slice.keep_front(Offset + Size);
+ BinaryStreamReader Reader(Slice);
+ consumeError(Reader.skip(Offset));
+ auto Layout = File.getStreamLayout(StreamIdx);
+ formatMsfStreamData(Label, File, Layout, Reader);
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream) {
+ BinaryStreamReader Reader(Substream.StreamData);
+
+ consumeError(Reader.skip(Substream.Offset));
+ formatMsfStreamData(Label, File, Stream, Reader);
+}
+
+void LinePrinter::formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinaryStreamReader &Reader) {
+ auto Runs = computeBlockRuns(File.getBlockSize(), Stream);
+
+ NewLine();
+ OS << Label << " (";
+ while (Reader.bytesRemaining() > 0) {
+ OS << "\n";
+
+ Run FoundRun;
+ uint32_t RunOffset;
+ std::tie(FoundRun, RunOffset) = findRun(Reader.getOffset(), Runs);
+ assert(FoundRun.ByteLen >= RunOffset);
+ uint32_t Len = FoundRun.ByteLen - RunOffset;
+ Len = std::min(Len, Reader.bytesRemaining());
+ uint64_t Base = FoundRun.Block * File.getBlockSize() + RunOffset;
+ ArrayRef<uint8_t> Data;
+ consumeError(Reader.readBytes(Data, Len));
+ OS << format_bytes_with_ascii(Data, Base, 32, 4,
+ CurrentIndent + IndentSpaces, true);
+ if (Reader.bytesRemaining() > 0) {
+ NewLine();
+ OS << formatv(" {0}",
+ fmt_align("<discontinuity>", AlignStyle::Center, 114, '-'));
+ }
+ }
+ NewLine();
+ OS << ")";
+}
+
bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName, uint32_t Size) {
if (IsItemExcluded(TypeName, IncludeTypeFilters, ExcludeTypeFilters))
return true;
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
+#include "llvm/Support/BinaryStreamRef.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include <list>
namespace llvm {
+class BinaryStreamReader;
+namespace msf {
+class MSFStreamLayout;
+} // namespace msf
namespace pdb {
class ClassLayout;
+class PDBFile;
class LinePrinter {
friend class WithColor;
void formatBinary(StringRef Label, ArrayRef<uint8_t> Data, uint64_t BaseAddr,
uint32_t StartOffset);
+ void formatMsfStreamData(StringRef Label, PDBFile &File, uint32_t StreamIdx,
+ StringRef StreamPurpose, uint32_t Offset,
+ uint32_t Size);
+ void formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinarySubstreamRef Substream);
+ void formatMsfStreamData(StringRef Label, PDBFile &File,
+ const msf::MSFStreamLayout &Stream,
+ BinaryStreamReader &Reader);
+
bool hasColor() const { return UseColor; }
raw_ostream &getStream() { return OS; }
int getIndentLevel() const { return CurrentIndent; }