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