llvm.org GIT mirror llvm / 06e4df3
[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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@329207 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 1 year, 5 months ago
12 changed file(s) with 259 addition(s) and 145 deletion(s). Raw diff Collapse all Expand all
3737 friend class DbiStreamBuilder;
3838
3939 public:
40 DbiStream(PDBFile &File, std::unique_ptrStream> Stream);
40 explicit DbiStream(std::unique_ptrStream> Stream);
4141 ~DbiStream();
42 Error reload();
42 Error reload(PDBFile *Pdb);
4343
4444 PdbRaw_DbiVer getDbiVersion() const;
4545 uint32_t getAge() const;
8888
8989 private:
9090 Error initializeSectionContributionData();
91 Error initializeSectionHeadersData();
91 Error initializeSectionHeadersData(PDBFile *Pdb);
9292 Error initializeSectionMapData();
93 Error initializeFpoRecords();
93 Error initializeFpoRecords(PDBFile *Pdb);
9494
95 PDBFile &Pdb;
96 std::unique_ptr<msf::MappedBlockStream> Stream;
95 std::unique_ptr<BinaryStream> Stream;
9796
9897 PDBStringTable ECNames;
9998
2929 friend class InfoStreamBuilder;
3030
3131 public:
32 InfoStream(std::unique_ptr<msf::MappedBlockStream> Stream);
32 InfoStream(std::unique_ptr<BinaryStream> Stream);
3333
3434 Error reload();
3535
5555 StringMap named_streams() const;
5656
5757 private:
58 std::unique_ptr<msf::MappedBlockStream> Stream;
58 std::unique_ptr<BinaryStream> Stream;
5959
6060 const InfoStreamHeader *Header;
6161
111111
112112 static const uint16_t BuildMajorMask = 0x7F00;
113113 static const uint16_t BuildMajorShift = 8;
114
115 static const uint16_t NewVersionFormatMask = 0x8000;
114116 };
115117
116118 /// The fixed size header that appears at the beginning of the DBI Stream.
4444 return Error::success();
4545 }
4646
47 DbiStream::DbiStream(PDBFile &File, std::unique_ptr Stream)
48 : Pdb(File), Stream(std::move(Stream)), Header(nullptr) {}
47 DbiStream::DbiStream(std::unique_ptr Stream)
48 : Stream(std::move(Stream)), Header(nullptr) {}
4949
5050 DbiStream::~DbiStream() = default;
5151
52 Error DbiStream::reload() {
52 Error DbiStream::reload(PDBFile *Pdb) {
5353 BinaryStreamReader Reader(*Stream);
5454
5555 if (Stream->getLength() < sizeof(DbiStreamHeader))
122122
123123 if (auto EC = initializeSectionContributionData())
124124 return EC;
125 if (auto EC = initializeSectionHeadersData())
125 if (auto EC = initializeSectionHeadersData(Pdb))
126126 return EC;
127127 if (auto EC = initializeSectionMapData())
128128 return EC;
129 if (auto EC = initializeFpoRecords())
129 if (auto EC = initializeFpoRecords(Pdb))
130130 return EC;
131131
132132 if (Reader.bytesRemaining() > 0)
245245 }
246246
247247 // Initializes this->SectionHeaders.
248 Error DbiStream::initializeSectionHeadersData() {
248 Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) {
249 if (!Pdb)
250 return Error::success();
251
249252 if (DbgStreams.size() == 0)
250253 return Error::success();
251254
253256 if (StreamNum == kInvalidStreamIndex)
254257 return Error::success();
255258
256 if (StreamNum >= Pdb.getNumStreams())
259 if (StreamNum >= Pdb->getNumStreams())
257260 return make_error(raw_error_code::no_stream);
258261
259262 auto SHS = MappedBlockStream::createIndexedStream(
260 Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
263 Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator());
261264
262265 size_t StreamLen = SHS->getLength();
263266 if (StreamLen % sizeof(object::coff_section))
275278 }
276279
277280 // Initializes this->Fpos.
278 Error DbiStream::initializeFpoRecords() {
281 Error DbiStream::initializeFpoRecords(PDBFile *Pdb) {
282 if (!Pdb)
283 return Error::success();
284
279285 if (DbgStreams.size() == 0)
280286 return Error::success();
281287
285291 if (StreamNum == kInvalidStreamIndex)
286292 return Error::success();
287293
288 if (StreamNum >= Pdb.getNumStreams())
294 if (StreamNum >= Pdb->getNumStreams())
289295 return make_error(raw_error_code::no_stream);
290296
291297 auto FS = MappedBlockStream::createIndexedStream(
292 Pdb.getMsfLayout(), Pdb.getMsfBuffer(), StreamNum, Pdb.getAllocator());
298 Pdb->getMsfLayout(), Pdb->getMsfBuffer(), StreamNum, Pdb->getAllocator());
293299
294300 size_t StreamLen = FS->getLength();
295301 if (StreamLen % sizeof(object::FpoData))
1919 using namespace llvm::msf;
2020 using namespace llvm::pdb;
2121
22 InfoStream::InfoStream(std::unique_ptr<MappedBlockStream> Stream)
22 InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream)
2323 : Stream(std::move(Stream)), Header(nullptr) {}
2424
2525 Error InfoStream::reload() {
288288 auto DbiS = safelyCreateIndexedStream(ContainerLayout, *Buffer, StreamDBI);
289289 if (!DbiS)
290290 return DbiS.takeError();
291 auto TempDbi = llvm::make_unique(*this, std::move(*DbiS));
292 if (auto EC = TempDbi->reload())
291 auto TempDbi = llvm::make_unique(std::move(*DbiS));
292 if (auto EC = TempDbi->reload(this))
293293 return std::move(EC);
294294 Dbi = std::move(TempDbi);
295295 }
99 #include "ExplainOutputStyle.h"
1010
1111 #include "FormatUtil.h"
12 #include "InputFile.h"
1213 #include "StreamUtil.h"
1314 #include "llvm-pdbutil.h"
1415
1819 #include "llvm/DebugInfo/PDB/Native/InfoStream.h"
1920 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
2021 #include "llvm/DebugInfo/PDB/Native/RawTypes.h"
22 #include "llvm/Support/BinaryByteStream.h"
2123 #include "llvm/Support/BinaryStreamArray.h"
2224 #include "llvm/Support/Error.h"
2325
2628 using namespace llvm::msf;
2729 using namespace llvm::pdb;
2830
29 ExplainOutputStyle::ExplainOutputStyle(PDBFile &File, uint64_t FileOffset)
30 : File(File), FileOffset(FileOffset),
31 BlockIndex(FileOffset / File.getBlockSize()),
32 OffsetInBlock(FileOffset - BlockIndex * File.getBlockSize()),
33 P(2, false, outs()) {}
31 ExplainOutputStyle::ExplainOutputStyle(InputFile &File, uint64_t FileOffset)
32 : File(File), FileOffset(FileOffset), P(2, false, outs()) {}
3433
3534 Error ExplainOutputStyle::dump() {
3635 P.formatLine("Explaining file offset {0} of file '{1}'.", FileOffset,
3736 File.getFilePath());
3837
39 bool IsAllocated = explainBlockStatus();
38 if (File.isPdb())
39 return explainPdbFile();
40
41 return explainBinaryFile();
42 }
43
44 Error ExplainOutputStyle::explainPdbFile() {
45 bool IsAllocated = explainPdbBlockStatus();
4046 if (!IsAllocated)
4147 return Error::success();
4248
4349 AutoIndent Indent(P);
44 if (isSuperBlock())
45 explainSuperBlockOffset();
46 else if (isFpmBlock())
47 explainFpmBlockOffset();
48 else if (isBlockMapBlock())
49 explainBlockMapOffset();
50 else if (isStreamDirectoryBlock())
51 explainStreamDirectoryOffset();
52 else if (auto Index = getBlockStreamIndex())
53 explainStreamOffset(*Index);
50 if (isPdbSuperBlock())
51 explainPdbSuperBlockOffset();
52 else if (isPdbFpmBlock())
53 explainPdbFpmBlockOffset();
54 else if (isPdbBlockMapBlock())
55 explainPdbBlockMapOffset();
56 else if (isPdbStreamDirectoryBlock())
57 explainPdbStreamDirectoryOffset();
58 else if (auto Index = getPdbBlockStreamIndex())
59 explainPdbStreamOffset(*Index);
5460 else
55 explainUnknownBlock();
61 explainPdbUnknownBlock();
5662 return Error::success();
5763 }
5864
59 bool ExplainOutputStyle::isSuperBlock() const { return BlockIndex == 0; }
60
61 bool ExplainOutputStyle::isFpm1() const {
62 return ((BlockIndex - 1) % File.getBlockSize() == 0);
63 }
64 bool ExplainOutputStyle::isFpm2() const {
65 return ((BlockIndex - 2) % File.getBlockSize() == 0);
66 }
67
68 bool ExplainOutputStyle::isFpmBlock() const { return isFpm1() || isFpm2(); }
69
70 bool ExplainOutputStyle::isBlockMapBlock() const {
71 return BlockIndex == File.getBlockMapIndex();
72 }
73
74 bool ExplainOutputStyle::isStreamDirectoryBlock() const {
75 const auto &Layout = File.getMsfLayout();
76 return llvm::is_contained(Layout.DirectoryBlocks, BlockIndex);
77 }
78
79 Optional ExplainOutputStyle::getBlockStreamIndex() const {
80 const auto &Layout = File.getMsfLayout();
65 Error ExplainOutputStyle::explainBinaryFile() {
66 std::unique_ptr Stream =
67 llvm::make_unique(File.unknown().getBuffer(),
68 llvm::support::little);
69 switch (opts::explain::InputType) {
70 case opts::explain::InputFileType::DBIStream: {
71 DbiStream Dbi(std::move(Stream));
72 if (auto EC = Dbi.reload(nullptr))
73 return EC;
74 explainStreamOffset(Dbi, FileOffset);
75 break;
76 }
77 case opts::explain::InputFileType::PDBStream: {
78 InfoStream Info(std::move(Stream));
79 if (auto EC = Info.reload())
80 return EC;
81 explainStreamOffset(Info, FileOffset);
82 break;
83 }
84 default:
85 llvm_unreachable("Invalid input file type!");
86 }
87 return Error::success();
88 }
89
90 uint32_t ExplainOutputStyle::pdbBlockIndex() const {
91 return FileOffset / File.pdb().getBlockSize();
92 }
93
94 uint32_t ExplainOutputStyle::pdbBlockOffset() const {
95 uint64_t BlockStart = pdbBlockIndex() * File.pdb().getBlockSize();
96 assert(FileOffset >= BlockStart);
97 return FileOffset - BlockStart;
98 }
99
100 bool ExplainOutputStyle::isPdbSuperBlock() const {
101 return pdbBlockIndex() == 0;
102 }
103
104 bool ExplainOutputStyle::isPdbFpm1() const {
105 return ((pdbBlockIndex() - 1) % File.pdb().getBlockSize() == 0);
106 }
107 bool ExplainOutputStyle::isPdbFpm2() const {
108 return ((pdbBlockIndex() - 2) % File.pdb().getBlockSize() == 0);
109 }
110
111 bool ExplainOutputStyle::isPdbFpmBlock() const {
112 return isPdbFpm1() || isPdbFpm2();
113 }
114
115 bool ExplainOutputStyle::isPdbBlockMapBlock() const {
116 return pdbBlockIndex() == File.pdb().getBlockMapIndex();
117 }
118
119 bool ExplainOutputStyle::isPdbStreamDirectoryBlock() const {
120 const auto &Layout = File.pdb().getMsfLayout();
121 return llvm::is_contained(Layout.DirectoryBlocks, pdbBlockIndex());
122 }
123
124 Optional ExplainOutputStyle::getPdbBlockStreamIndex() const {
125 const auto &Layout = File.pdb().getMsfLayout();
81126 for (const auto &Entry : enumerate(Layout.StreamMap)) {
82 if (!llvm::is_contained(Entry.value(), BlockIndex))
127 if (!llvm::is_contained(Entry.value(), pdbBlockIndex()))
83128 continue;
84129 return Entry.index();
85130 }
86131 return None;
87132 }
88133
89 bool ExplainOutputStyle::explainBlockStatus() {
90 if (FileOffset >= File.getFileSize()) {
134 bool ExplainOutputStyle::explainPdbBlockStatus() {
135 if (FileOffset >= File.pdb().getFileSize()) {
91136 P.formatLine("Address {0} is not in the file (file size = {1}).",
92 FileOffset, File.getFileSize());
137 FileOffset, File.pdb().getFileSize());
93138 return false;
94139 }
95 P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, OffsetInBlock,
96 BlockIndex);
97
98 bool IsFree = File.getMsfLayout().FreePageMap[BlockIndex];
99 P.formatLine("Address is in block {0} ({1}allocated).", BlockIndex,
140 P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, pdbBlockOffset(),
141 pdbBlockIndex());
142
143 bool IsFree = File.pdb().getMsfLayout().FreePageMap[pdbBlockIndex()];
144 P.formatLine("Address is in block {0} ({1}allocated).", pdbBlockIndex(),
100145 IsFree ? "un" : "");
101146 return !IsFree;
102147 }
103148
104149 #define endof(Class, Field) (offsetof(Class, Field) + sizeof(Class::Field))
105150
106 void ExplainOutputStyle::explainSuperBlockOffset() {
151 void ExplainOutputStyle::explainPdbSuperBlockOffset() {
107152 P.formatLine("This corresponds to offset {0} of the MSF super block, ",
108 OffsetInBlock);
109 if (OffsetInBlock < endof(SuperBlock, MagicBytes))
153 pdbBlockOffset());
154 if (pdbBlockOffset() < endof(SuperBlock, MagicBytes))
110155 P.printLine("which is part of the MSF file magic.");
111 else if (OffsetInBlock < endof(SuperBlock, BlockSize)) {
156 else if (pdbBlockOffset() < endof(SuperBlock, BlockSize)) {
112157 P.printLine("which contains the block size of the file.");
113158 P.formatLine("The current value is {0}.",
114 uint32_t(File.getMsfLayout().SB->BlockSize));
115 } else if (OffsetInBlock < endof(SuperBlock, FreeBlockMapBlock)) {
159 uint32_t(File.pdb().getMsfLayout().SB->BlockSize));
160 } else if (pdbBlockOffset() < endof(SuperBlock, FreeBlockMapBlock)) {
116161 P.printLine("which contains the index of the FPM block (e.g. 1 or 2).");
117162 P.formatLine("The current value is {0}.",
118 uint32_t(File.getMsfLayout().SB->FreeBlockMapBlock));
119 } else if (OffsetInBlock < endof(SuperBlock, NumBlocks)) {
163 uint32_t(File.pdb().getMsfLayout().SB->FreeBlockMapBlock));
164 } else if (pdbBlockOffset() < endof(SuperBlock, NumBlocks)) {
120165 P.printLine("which contains the number of blocks in the file.");
121166 P.formatLine("The current value is {0}.",
122 uint32_t(File.getMsfLayout().SB->NumBlocks));
123 } else if (OffsetInBlock < endof(SuperBlock, NumDirectoryBytes)) {
167 uint32_t(File.pdb().getMsfLayout().SB->NumBlocks));
168 } else if (pdbBlockOffset() < endof(SuperBlock, NumDirectoryBytes)) {
124169 P.printLine("which contains the number of bytes in the stream directory.");
125170 P.formatLine("The current value is {0}.",
126 uint32_t(File.getMsfLayout().SB->NumDirectoryBytes));
127 } else if (OffsetInBlock < endof(SuperBlock, Unknown1)) {
171 uint32_t(File.pdb().getMsfLayout().SB->NumDirectoryBytes));
172 } else if (pdbBlockOffset() < endof(SuperBlock, Unknown1)) {
128173 P.printLine("whose purpose is unknown.");
129174 P.formatLine("The current value is {0}.",
130 uint32_t(File.getMsfLayout().SB->Unknown1));
131 } else if (OffsetInBlock < endof(SuperBlock, BlockMapAddr)) {
175 uint32_t(File.pdb().getMsfLayout().SB->Unknown1));
176 } else if (pdbBlockOffset() < endof(SuperBlock, BlockMapAddr)) {
132177 P.printLine("which contains the file offset of the block map.");
133178 P.formatLine("The current value is {0}.",
134 uint32_t(File.getMsfLayout().SB->BlockMapAddr));
179 uint32_t(File.pdb().getMsfLayout().SB->BlockMapAddr));
135180 } else {
136 assert(OffsetInBlock > sizeof(SuperBlock));
181 assert(pdbBlockOffset() > sizeof(SuperBlock));
137182 P.printLine(
138183 "which is outside the range of valid data for the super block.");
139184 }
149194 return std::string(Result);
150195 }
151196
152 void ExplainOutputStyle::explainFpmBlockOffset() {
153 const MSFLayout &Layout = File.getMsfLayout();
197 void ExplainOutputStyle::explainPdbFpmBlockOffset() {
198 const MSFLayout &Layout = File.pdb().getMsfLayout();
154199 uint32_t MainFpm = Layout.mainFpmBlock();
155200 uint32_t AltFpm = Layout.alternateFpmBlock();
156201
157 assert(isFpmBlock());
158 uint32_t Fpm = isFpm1() ? 1 : 2;
159 uint32_t FpmChunk = BlockIndex / File.getBlockSize();
202 assert(isPdbFpmBlock());
203 uint32_t Fpm = isPdbFpm1() ? 1 : 2;
204 uint32_t FpmChunk = pdbBlockIndex() / File.pdb().getBlockSize();
160205 assert((Fpm == MainFpm) || (Fpm == AltFpm));
161206 (void)AltFpm;
162207 bool IsMain = (Fpm == MainFpm);
163208 P.formatLine("Address is in FPM{0} ({1} FPM)", Fpm, IsMain ? "Main" : "Alt");
164209 uint32_t DescribedBlockStart =
165 8 * (FpmChunk * File.getBlockSize() + OffsetInBlock);
166 if (DescribedBlockStart > File.getBlockCount()) {
210 8 * (FpmChunk * File.pdb().getBlockSize() + pdbBlockOffset());
211 if (DescribedBlockStart > File.pdb().getBlockCount()) {
167212 P.printLine("Address is in extraneous FPM space.");
168213 return;
169214 }
171216 P.formatLine("Address describes the allocation status of blocks [{0},{1})",
172217 DescribedBlockStart, DescribedBlockStart + 8);
173218 ArrayRef Bytes;
174 cantFail(File.getMsfBuffer().readBytes(FileOffset, 1, Bytes));
219 cantFail(File.pdb().getMsfBuffer().readBytes(FileOffset, 1, Bytes));
175220 P.formatLine("Status = {0} (Note: 0 = allocated, 1 = free)",
176221 toBinaryString(Bytes[0]));
177222 }
178223
179 void ExplainOutputStyle::explainBlockMapOffset() {
180 uint64_t BlockMapOffset = File.getBlockMapOffset();
224 void ExplainOutputStyle::explainPdbBlockMapOffset() {
225 uint64_t BlockMapOffset = File.pdb().getBlockMapOffset();
181226 uint32_t OffsetInBlock = FileOffset - BlockMapOffset;
182227 P.formatLine("Address is at offset {0} of the directory block list",
183228 OffsetInBlock);
194239 return StreamBlockIndex * BlockSize + OffsetInBlock;
195240 }
196241
197 void ExplainOutputStyle::explainStreamOffset(uint32_t Stream) {
242 void ExplainOutputStyle::explainPdbStreamOffset(uint32_t Stream) {
198243 SmallVector Streams;
199 discoverStreamPurposes(File, Streams);
244 discoverStreamPurposes(File.pdb(), Streams);
200245
201246 assert(Stream <= Streams.size());
202247 const StreamInfo &S = Streams[Stream];
203 const auto &Layout = File.getStreamLayout(Stream);
248 const auto &Layout = File.pdb().getStreamLayout(Stream);
204249 uint32_t StreamOff =
205 getOffsetInStream(Layout.Blocks, FileOffset, File.getBlockSize());
250 getOffsetInStream(Layout.Blocks, FileOffset, File.pdb().getBlockSize());
206251 P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.",
207252 StreamOff, Layout.Length, Stream, S.getLongName(),
208253 (StreamOff > Layout.Length) ? " in unused space" : "");
209254 switch (S.getPurpose()) {
210 case StreamPurpose::DBI:
211 explainDbiStream(Stream, StreamOff);
255 case StreamPurpose::DBI: {
256 DbiStream &Dbi = cantFail(File.pdb().getPDBDbiStream());
257 explainStreamOffset(Dbi, StreamOff);
212258 break;
213 case StreamPurpose::PDB:
214 explainPdbStream(Stream, StreamOff);
259 }
260 case StreamPurpose::PDB: {
261 InfoStream &Info = cantFail(File.pdb().getPDBInfoStream());
262 explainStreamOffset(Info, StreamOff);
215263 break;
264 }
216265 case StreamPurpose::IPI:
217266 case StreamPurpose::TPI:
218267 case StreamPurpose::ModuleStream:
222271 }
223272 }
224273
225 void ExplainOutputStyle::explainStreamDirectoryOffset() {
226 auto DirectoryBlocks = File.getDirectoryBlockArray();
227 const auto &Layout = File.getMsfLayout();
274 void ExplainOutputStyle::explainPdbStreamDirectoryOffset() {
275 auto DirectoryBlocks = File.pdb().getDirectoryBlockArray();
276 const auto &Layout = File.pdb().getMsfLayout();
228277 uint32_t StreamOff =
229 getOffsetInStream(DirectoryBlocks, FileOffset, File.getBlockSize());
278 getOffsetInStream(DirectoryBlocks, FileOffset, File.pdb().getBlockSize());
230279 P.formatLine("Address is at offset {0}/{1} of Stream Directory{2}.",
231280 StreamOff, uint32_t(Layout.SB->NumDirectoryBytes),
232281 uint32_t(StreamOff > Layout.SB->NumDirectoryBytes)
234283 : "");
235284 }
236285
237 void ExplainOutputStyle::explainUnknownBlock() {
286 void ExplainOutputStyle::explainPdbUnknownBlock() {
238287 P.formatLine("Address has unknown purpose.");
239288 }
240289
351400 }
352401 }
353402
354 void ExplainOutputStyle::explainDbiStream(uint32_t StreamIdx,
355 uint32_t OffsetInStream) {
403 void ExplainOutputStyle::explainStreamOffset(DbiStream &Dbi,
404 uint32_t OffsetInStream) {
356405 P.printLine("Within the DBI stream:");
357 DbiStream &Dbi = cantFail(File.getPDBDbiStream());
358406 AutoIndent Indent(P);
359407 const DbiStreamHeader *Header = Dbi.getHeader();
360408 assert(Header != nullptr);
400448 printStructField(P, "the guid of the PDB", fmt_guid(Header->Guid.Guid));
401449 }
402450
403 void ExplainOutputStyle::explainPdbStream(uint32_t StreamIdx,
404 uint32_t OffsetInStream) {
451 void ExplainOutputStyle::explainStreamOffset(InfoStream &Info,
452 uint32_t OffsetInStream) {
405453 P.printLine("Within the PDB stream:");
406 InfoStream &Info = cantFail(File.getPDBInfoStream());
407454 AutoIndent Indent(P);
408455
409456 struct SubstreamInfo {
1919 namespace pdb {
2020
2121 class DbiStream;
22 class PDBFile;
22 class InfoStream;
23 class InputFile;
2324
2425 class ExplainOutputStyle : public OutputStyle {
2526
2627 public:
27 ExplainOutputStyle(PDBFile &File, uint64_t FileOffset);
28 ExplainOutputStyle(InputFile &File, uint64_t FileOffset);
2829
2930 Error dump() override;
3031
3132 private:
32 bool explainBlockStatus();
33 Error explainPdbFile();
34 Error explainBinaryFile();
3335
34 bool isFpm1() const;
35 bool isFpm2() const;
36 bool explainPdbBlockStatus();
3637
37 bool isSuperBlock() const;
38 bool isFpmBlock() const;
39 bool isBlockMapBlock() const;
40 bool isStreamDirectoryBlock() const;
41 Optional getBlockStreamIndex() const;
38 bool isPdbFpm1() const;
39 bool isPdbFpm2() const;
4240
43 void explainSuperBlockOffset();
44 void explainFpmBlockOffset();
45 void explainBlockMapOffset();
46 void explainStreamDirectoryOffset();
47 void explainStreamOffset(uint32_t Stream);
48 void explainUnknownBlock();
41 bool isPdbSuperBlock() const;
42 bool isPdbFpmBlock() const;
43 bool isPdbBlockMapBlock() const;
44 bool isPdbStreamDirectoryBlock() const;
45 Optional getPdbBlockStreamIndex() const;
4946
50 void explainDbiStream(uint32_t StreamIdx, uint32_t OffsetInStream);
51 void explainPdbStream(uint32_t StreamIdx, uint32_t OffsetInStream);
47 void explainPdbSuperBlockOffset();
48 void explainPdbFpmBlockOffset();
49 void explainPdbBlockMapOffset();
50 void explainPdbStreamDirectoryOffset();
51 void explainPdbStreamOffset(uint32_t Stream);
52 void explainPdbUnknownBlock();
5253
53 PDBFile &File;
54 void explainStreamOffset(DbiStream &Stream, uint32_t OffsetInStream);
55 void explainStreamOffset(InfoStream &Stream, uint32_t OffsetInStream);
56
57 uint32_t pdbBlockIndex() const;
58 uint32_t pdbBlockOffset() const;
59
60 InputFile &File;
5461 const uint64_t FileOffset;
55 const uint64_t BlockIndex;
56 const uint64_t OffsetInBlock;
5762 LinePrinter P;
5863 };
5964 } // namespace pdb
241241 }
242242 }
243243
244 Expected InputFile::open(StringRef Path) {
244 Expected InputFile::open(StringRef Path, bool AllowUnknownFile) {
245245 InputFile IF;
246246 if (!llvm::sys::fs::exists(Path))
247247 return make_error(formatv("File {0} not found", Path),
273273 return std::move(IF);
274274 }
275275
276 return make_error(
277 formatv("File {0} is not a supported file type", Path),
278 inconvertibleErrorCode());
276 if (!AllowUnknownFile)
277 return make_error(
278 formatv("File {0} is not a supported file type", Path),
279 inconvertibleErrorCode());
280
281 auto Result = MemoryBuffer::getFile(Path, -1i64, false);
282 if (!Result)
283 return make_error(
284 formatv("File {0} could not be opened", Path), Result.getError());
285
286 IF.UnknownFile = std::move(*Result);
287 IF.PdbOrObj = IF.UnknownFile.get();
288 return std::move(IF);
279289 }
280290
281291 PDBFile &InputFile::pdb() {
296306 const object::COFFObjectFile &InputFile::obj() const {
297307 assert(isObj());
298308 return *PdbOrObj.get();
309 }
310
311 MemoryBuffer &InputFile::unknown() {
312 assert(isUnknown());
313 return *PdbOrObj.get();
314 }
315
316 const MemoryBuffer &InputFile::unknown() const {
317 assert(isUnknown());
318 return *PdbOrObj.get();
319 }
320
321 StringRef InputFile::getFilePath() const {
322 if (isPdb())
323 return pdb().getFilePath();
324 if (isObj())
325 return obj().getFileName();
326 assert(isUnknown());
327 return unknown().getBufferIdentifier();
299328 }
300329
301330 bool InputFile::hasTypes() const {
321350 bool InputFile::isObj() const {
322351 return PdbOrObj.is();
323352 }
353
354 bool InputFile::isUnknown() const { return PdbOrObj.is(); }
324355
325356 codeview::LazyRandomTypeCollection &
326357 InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind) {
4242
4343 std::unique_ptr PdbSession;
4444 object::OwningBinary CoffObject;
45 PointerUnion PdbOrObj;
45 std::unique_ptr UnknownFile;
46 PointerUnion3 PdbOrObj;
4647
4748 using TypeCollectionPtr = std::unique_ptr;
4849
5758 ~InputFile();
5859 InputFile(InputFile &&Other) = default;
5960
60 static Expected open(StringRef Path);
61 static Expected open(StringRef Path,
62 bool AllowUnknownFile = false);
6163
6264 PDBFile &pdb();
6365 const PDBFile &pdb() const;
6466 object::COFFObjectFile &obj();
6567 const object::COFFObjectFile &obj() const;
68 MemoryBuffer &unknown();
69 const MemoryBuffer &unknown() const;
70
71 StringRef getFilePath() const;
6672
6773 bool hasTypes() const;
6874 bool hasIds() const;
7682
7783 bool isPdb() const;
7884 bool isObj() const;
85 bool isUnknown() const;
7986 };
8087
8188 class SymbolGroup {
620620
621621 cl::list Offsets("offset", cl::desc("The file offset to explain"),
622622 cl::sub(ExplainSubcommand), cl::OneOrMore);
623
624 cl::opt InputType(
625 "input-type", cl::desc("Specify how to interpret the input file"),
626 cl::init(InputFileType::PDBFile), cl::Optional, cl::sub(ExplainSubcommand),
627 cl::values(clEnumValN(InputFileType::PDBFile, "pdb-file",
628 "Treat input as a PDB file (default)"),
629 clEnumValN(InputFileType::PDBStream, "pdb-stream",
630 "Treat input as raw contents of PDB stream"),
631 clEnumValN(InputFileType::DBIStream, "dbi-stream",
632 "Treat input as raw contents of DBI stream"),
633 clEnumValN(InputFileType::Names, "names-stream",
634 "Treat input as raw contents of /names named stream"),
635 clEnumValN(InputFileType::ModuleStream, "mod-stream",
636 "Treat input as raw contents of a module stream")));
623637 } // namespace explain
624638
625639 namespace exportstream {
771785 }
772786
773787 static void dumpRaw(StringRef Path) {
774
775788 InputFile IF = ExitOnErr(InputFile::open(Path));
776789
777790 auto O = llvm::make_unique(IF);
11101123
11111124 static void explain() {
11121125 std::unique_ptr Session;
1113 PDBFile &File = loadPDB(opts::explain::InputFilename.front(), Session);
1126 InputFile IF =
1127 ExitOnErr(InputFile::open(opts::explain::InputFilename.front(), true));
11141128
11151129 for (uint64_t Off : opts::explain::Offsets) {
1116 auto O = llvm::make_unique(File, Off);
1130 auto O = llvm::make_unique(IF, Off);
11171131
11181132 ExitOnErr(O->dump());
11191133 }
189189 } // namespace pdb2yaml
190190
191191 namespace explain {
192 enum class InputFileType { PDBFile, PDBStream, DBIStream, Names, ModuleStream };
193
192194 extern llvm::cl::list InputFilename;
193195 extern llvm::cl::list Offsets;
196 extern llvm::cl::opt InputType;
194197 } // namespace explain
195198
196199 namespace exportstream {