xref: /llvm-project/llvm/tools/llvm-pdbutil/ExplainOutputStyle.cpp (revision ea40f40e1b024598fb1dbd56211c2f24cb703df2)
1 //===- ExplainOutputStyle.cpp --------------------------------- *- C++ --*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "ExplainOutputStyle.h"
11 
12 #include "FormatUtil.h"
13 #include "StreamUtil.h"
14 #include "llvm-pdbutil.h"
15 
16 #include "llvm/DebugInfo/MSF/MappedBlockStream.h"
17 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18 
19 using namespace llvm;
20 using namespace llvm::codeview;
21 using namespace llvm::msf;
22 using namespace llvm::pdb;
23 
24 ExplainOutputStyle::ExplainOutputStyle(PDBFile &File, uint64_t FileOffset)
25     : File(File), FileOffset(FileOffset),
26       BlockIndex(FileOffset / File.getBlockSize()),
27       OffsetInBlock(FileOffset - BlockIndex * File.getBlockSize()),
28       P(2, false, outs()) {}
29 
30 Error ExplainOutputStyle::dump() {
31   P.formatLine("Explaining file offset {0} of file '{1}'.", FileOffset,
32                File.getFilePath());
33 
34   bool IsAllocated = explainBlockStatus();
35   if (!IsAllocated)
36     return Error::success();
37 
38   AutoIndent Indent(P);
39   if (isSuperBlock())
40     explainSuperBlockOffset();
41   else if (isFpmBlock())
42     explainFpmBlockOffset();
43   else if (isBlockMapBlock())
44     explainBlockMapOffset();
45   else if (isStreamDirectoryBlock())
46     explainStreamDirectoryOffset();
47   else if (auto Index = getBlockStreamIndex())
48     explainStreamOffset(*Index);
49   else
50     explainUnknownBlock();
51   return Error::success();
52 }
53 
54 bool ExplainOutputStyle::isSuperBlock() const { return BlockIndex == 0; }
55 
56 bool ExplainOutputStyle::isFpm1() const {
57   return ((BlockIndex - 1) % File.getBlockSize() == 0);
58 }
59 bool ExplainOutputStyle::isFpm2() const {
60   return ((BlockIndex - 2) % File.getBlockSize() == 0);
61 }
62 
63 bool ExplainOutputStyle::isFpmBlock() const { return isFpm1() || isFpm2(); }
64 
65 bool ExplainOutputStyle::isBlockMapBlock() const {
66   return BlockIndex == File.getBlockMapIndex();
67 }
68 
69 bool ExplainOutputStyle::isStreamDirectoryBlock() const {
70   const auto &Layout = File.getMsfLayout();
71   return llvm::is_contained(Layout.DirectoryBlocks, BlockIndex);
72 }
73 
74 Optional<uint32_t> ExplainOutputStyle::getBlockStreamIndex() const {
75   const auto &Layout = File.getMsfLayout();
76   for (const auto &Entry : enumerate(Layout.StreamMap)) {
77     if (!llvm::is_contained(Entry.value(), BlockIndex))
78       continue;
79     return Entry.index();
80   }
81   return None;
82 }
83 
84 bool ExplainOutputStyle::explainBlockStatus() {
85   if (FileOffset >= File.getFileSize()) {
86     P.formatLine("Address {0} is not in the file (file size = {1}).",
87                  FileOffset, File.getFileSize());
88     return false;
89   }
90   P.formatLine("Block:Offset = {2:X-}:{1:X-4}.", FileOffset, OffsetInBlock,
91                BlockIndex);
92 
93   bool IsFree = File.getMsfLayout().FreePageMap[BlockIndex];
94   P.formatLine("Address is in block {0} ({1}allocated).", BlockIndex,
95                IsFree ? "un" : "");
96   return !IsFree;
97 }
98 
99 void ExplainOutputStyle::explainSuperBlockOffset() {
100   P.formatLine("This corresponds to offset {0} of MSF super block, ",
101                OffsetInBlock);
102   if (OffsetInBlock < sizeof(msf::Magic))
103     P.printLine("which is part of the MSF file magic.");
104   else if (OffsetInBlock < offsetof(SuperBlock, BlockSize))
105     P.printLine("which contains the block size of the file.");
106   else if (OffsetInBlock < offsetof(SuperBlock, FreeBlockMapBlock))
107     P.printLine("which contains the index of the FPM block (e.g. 1 or 2).");
108   else if (OffsetInBlock < offsetof(SuperBlock, NumBlocks))
109     P.printLine("which contains the number of blocks in the file.");
110   else if (OffsetInBlock < offsetof(SuperBlock, NumDirectoryBytes))
111     P.printLine("which contains the number of bytes in the stream directory.");
112   else if (OffsetInBlock < offsetof(SuperBlock, Unknown1))
113     P.printLine("whose purpose is unknown.");
114   else if (OffsetInBlock < offsetof(SuperBlock, BlockMapAddr))
115     P.printLine("which contains the file offset of the block map.");
116   else {
117     assert(OffsetInBlock > sizeof(SuperBlock));
118     P.printLine(
119         "which is outside the range of valid data for the super block.");
120   }
121 }
122 
123 void ExplainOutputStyle::explainFpmBlockOffset() {
124   const MSFLayout &Layout = File.getMsfLayout();
125   uint32_t MainFpm = Layout.mainFpmBlock();
126   uint32_t AltFpm = Layout.alternateFpmBlock();
127 
128   assert(isFpmBlock());
129   uint32_t Fpm = isFpm1() ? 1 : 2;
130   uint32_t FpmChunk = BlockIndex / File.getBlockSize();
131   assert((Fpm == MainFpm) || (Fpm == AltFpm));
132   (void)AltFpm;
133   bool IsMain = (Fpm == MainFpm);
134   P.formatLine("Address is in FPM{0} ({1} FPM)", Fpm, IsMain ? "Main" : "Alt");
135   uint32_t DescribedBlockStart =
136       8 * (FpmChunk * File.getBlockSize() + OffsetInBlock);
137   if (DescribedBlockStart > File.getBlockCount()) {
138     P.printLine("Address is in extraneous FPM space.");
139     return;
140   }
141 
142   P.formatLine("Address describes the allocation status of blocks [{0},{1})",
143                DescribedBlockStart, DescribedBlockStart + 8);
144 }
145 
146 static bool offsetIsInBlock(const PDBFile &File, uint64_t Offset,
147                             uint32_t Block) {
148   uint64_t BlockOffset = uint64_t(Block) * File.getBlockSize();
149   uint64_t BlockOffset1 = BlockOffset + File.getBlockSize();
150   return (Offset >= BlockOffset && Offset < BlockOffset1);
151 }
152 
153 void ExplainOutputStyle::explainBlockMapOffset() {
154   assert(offsetIsInBlock(File, FileOffset, File.getBlockMapIndex()));
155   uint64_t BlockMapOffset = File.getBlockMapOffset();
156   uint32_t OffsetInBlock = FileOffset - BlockMapOffset;
157   P.formatLine("Address is at offset {0} of the directory block list",
158                OffsetInBlock);
159 }
160 
161 static uint32_t getOffsetInStream(ArrayRef<support::ulittle32_t> StreamBlocks,
162                                   uint64_t FileOffset, uint32_t BlockSize) {
163   uint32_t BlockIndex = FileOffset / BlockSize;
164   uint32_t OffsetInBlock = FileOffset - BlockIndex * BlockSize;
165 
166   auto Iter = llvm::find(StreamBlocks, BlockIndex);
167   assert(Iter != StreamBlocks.end());
168   uint32_t StreamBlockIndex = std::distance(StreamBlocks.begin(), Iter);
169   return StreamBlockIndex * BlockSize + OffsetInBlock;
170 }
171 
172 void ExplainOutputStyle::explainStreamOffset(uint32_t Stream) {
173   SmallVector<StreamInfo, 12> Streams;
174   discoverStreamPurposes(File, Streams);
175 
176   assert(Stream <= Streams.size());
177   const StreamInfo &S = Streams[Stream];
178   const auto &Layout = File.getStreamLayout(Stream);
179   uint32_t StreamOff =
180       getOffsetInStream(Layout.Blocks, FileOffset, File.getBlockSize());
181   P.formatLine("Address is at offset {0}/{1} of Stream {2} ({3}){4}.",
182                StreamOff, Layout.Length, Stream, S.getLongName(),
183                (StreamOff > Layout.Length) ? " in unused space" : "");
184 }
185 
186 void ExplainOutputStyle::explainStreamDirectoryOffset() {
187   auto DirectoryBlocks = File.getDirectoryBlockArray();
188   const auto &Layout = File.getMsfLayout();
189   uint32_t StreamOff =
190       getOffsetInStream(DirectoryBlocks, FileOffset, File.getBlockSize());
191   P.formatLine("Address is at offset {0}/{1} of Stream Directory{2}.",
192                StreamOff, uint32_t(Layout.SB->NumDirectoryBytes),
193                uint32_t(StreamOff > Layout.SB->NumDirectoryBytes)
194                    ? " in unused space"
195                    : "");
196 }
197 
198 void ExplainOutputStyle::explainUnknownBlock() {
199   P.formatLine("Address has unknown purpose.");
200 }
201