1 //===- PDBFile.cpp - Low level interface to a PDB file ----------*- 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 "llvm/DebugInfo/PDB/Raw/PDBFile.h" 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/DebugInfo/CodeView/StreamArray.h" 14 #include "llvm/DebugInfo/CodeView/StreamInterface.h" 15 #include "llvm/DebugInfo/CodeView/StreamReader.h" 16 #include "llvm/DebugInfo/CodeView/StreamWriter.h" 17 #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" 18 #include "llvm/DebugInfo/PDB/Raw/DirectoryStreamData.h" 19 #include "llvm/DebugInfo/PDB/Raw/IndexedStreamData.h" 20 #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" 21 #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" 22 #include "llvm/DebugInfo/PDB/Raw/PublicsStream.h" 23 #include "llvm/DebugInfo/PDB/Raw/RawError.h" 24 #include "llvm/DebugInfo/PDB/Raw/SymbolStream.h" 25 #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" 26 #include "llvm/Support/Endian.h" 27 #include "llvm/Support/FileOutputBuffer.h" 28 #include "llvm/Support/MemoryBuffer.h" 29 30 using namespace llvm; 31 using namespace llvm::codeview; 32 using namespace llvm::pdb; 33 34 namespace { 35 typedef FixedStreamArray<support::ulittle32_t> ulittle_array; 36 } 37 38 PDBFile::PDBFile(std::unique_ptr<StreamInterface> PdbFileBuffer) 39 : Buffer(std::move(PdbFileBuffer)), SB(nullptr) {} 40 41 PDBFile::~PDBFile() {} 42 43 uint32_t PDBFile::getBlockSize() const { return SB->BlockSize; } 44 45 uint32_t PDBFile::getUnknown0() const { return SB->Unknown0; } 46 47 uint32_t PDBFile::getBlockCount() const { return SB->NumBlocks; } 48 49 uint32_t PDBFile::getNumDirectoryBytes() const { return SB->NumDirectoryBytes; } 50 51 uint32_t PDBFile::getBlockMapIndex() const { return SB->BlockMapAddr; } 52 53 uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; } 54 55 uint32_t PDBFile::getNumDirectoryBlocks() const { 56 return bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize); 57 } 58 59 uint64_t PDBFile::getBlockMapOffset() const { 60 return (uint64_t)SB->BlockMapAddr * SB->BlockSize; 61 } 62 63 uint32_t PDBFile::getNumStreams() const { return StreamSizes.size(); } 64 65 uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const { 66 return StreamSizes[StreamIndex]; 67 } 68 69 ArrayRef<support::ulittle32_t> 70 PDBFile::getStreamBlockList(uint32_t StreamIndex) const { 71 return StreamMap[StreamIndex]; 72 } 73 74 uint32_t PDBFile::getFileSize() const { return Buffer->getLength(); } 75 76 Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex, 77 uint32_t NumBytes) const { 78 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize()); 79 80 ArrayRef<uint8_t> Result; 81 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result)) 82 return std::move(EC); 83 return Result; 84 } 85 86 Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset, 87 ArrayRef<uint8_t> Data) const { 88 if (Offset >= getBlockSize()) 89 return make_error<RawError>( 90 raw_error_code::invalid_block_address, 91 "setBlockData attempted to write out of block bounds."); 92 if (Data.size() > getBlockSize() - Offset) 93 return make_error<RawError>( 94 raw_error_code::invalid_block_address, 95 "setBlockData attempted to write out of block bounds."); 96 97 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize()); 98 StreamBlockOffset += Offset; 99 return Buffer->writeBytes(StreamBlockOffset, Data); 100 } 101 102 Error PDBFile::parseFileHeaders() { 103 StreamReader Reader(*Buffer); 104 105 if (auto EC = Reader.readObject(SB)) { 106 consumeError(std::move(EC)); 107 return make_error<RawError>(raw_error_code::corrupt_file, 108 "Does not contain superblock"); 109 } 110 111 if (auto EC = setSuperBlock(SB)) 112 return EC; 113 114 Reader.setOffset(getBlockMapOffset()); 115 if (auto EC = Reader.readArray(DirectoryBlocks, getNumDirectoryBlocks())) 116 return EC; 117 118 return Error::success(); 119 } 120 121 Error PDBFile::parseStreamData() { 122 assert(SB); 123 if (DirectoryStream) 124 return Error::success(); 125 126 uint32_t NumStreams = 0; 127 128 // Normally you can't use a MappedBlockStream without having fully parsed the 129 // PDB file, because it accesses the directory and various other things, which 130 // is exactly what we are attempting to parse. By specifying a custom 131 // subclass of IPDBStreamData which only accesses the fields that have already 132 // been parsed, we can avoid this and reuse MappedBlockStream. 133 auto DS = MappedBlockStream::createDirectoryStream(*this); 134 if (!DS) 135 return DS.takeError(); 136 StreamReader Reader(**DS); 137 if (auto EC = Reader.readInteger(NumStreams)) 138 return EC; 139 140 if (auto EC = Reader.readArray(StreamSizes, NumStreams)) 141 return EC; 142 for (uint32_t I = 0; I < NumStreams; ++I) { 143 uint32_t StreamSize = getStreamByteSize(I); 144 // FIXME: What does StreamSize ~0U mean? 145 uint64_t NumExpectedStreamBlocks = 146 StreamSize == UINT32_MAX ? 0 : bytesToBlocks(StreamSize, SB->BlockSize); 147 148 // For convenience, we store the block array contiguously. This is because 149 // if someone calls setStreamMap(), it is more convenient to be able to call 150 // it with an ArrayRef instead of setting up a StreamRef. Since the 151 // DirectoryStream is cached in the class and thus lives for the life of the 152 // class, we can be guaranteed that readArray() will return a stable 153 // reference, even if it has to allocate from its internal pool. 154 ArrayRef<support::ulittle32_t> Blocks; 155 if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks)) 156 return EC; 157 for (uint32_t Block : Blocks) { 158 uint64_t BlockEndOffset = (uint64_t)(Block + 1) * SB->BlockSize; 159 if (BlockEndOffset > getFileSize()) 160 return make_error<RawError>(raw_error_code::corrupt_file, 161 "Stream block map is corrupt."); 162 } 163 StreamMap.push_back(Blocks); 164 } 165 166 // We should have read exactly SB->NumDirectoryBytes bytes. 167 assert(Reader.bytesRemaining() == 0); 168 DirectoryStream = std::move(*DS); 169 return Error::success(); 170 } 171 172 llvm::ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const { 173 return DirectoryBlocks; 174 } 175 176 Expected<InfoStream &> PDBFile::getPDBInfoStream() { 177 if (!Info) { 178 auto InfoS = MappedBlockStream::createIndexedStream(StreamPDB, *this); 179 if (!InfoS) 180 return InfoS.takeError(); 181 auto TempInfo = llvm::make_unique<InfoStream>(std::move(*InfoS)); 182 if (auto EC = TempInfo->reload()) 183 return std::move(EC); 184 Info = std::move(TempInfo); 185 } 186 return *Info; 187 } 188 189 Expected<DbiStream &> PDBFile::getPDBDbiStream() { 190 if (!Dbi) { 191 auto DbiS = MappedBlockStream::createIndexedStream(StreamDBI, *this); 192 if (!DbiS) 193 return DbiS.takeError(); 194 auto TempDbi = llvm::make_unique<DbiStream>(*this, std::move(*DbiS)); 195 if (auto EC = TempDbi->reload()) 196 return std::move(EC); 197 Dbi = std::move(TempDbi); 198 } 199 return *Dbi; 200 } 201 202 Expected<TpiStream &> PDBFile::getPDBTpiStream() { 203 if (!Tpi) { 204 auto TpiS = MappedBlockStream::createIndexedStream(StreamTPI, *this); 205 if (!TpiS) 206 return TpiS.takeError(); 207 auto TempTpi = llvm::make_unique<TpiStream>(*this, std::move(*TpiS)); 208 if (auto EC = TempTpi->reload()) 209 return std::move(EC); 210 Tpi = std::move(TempTpi); 211 } 212 return *Tpi; 213 } 214 215 Expected<TpiStream &> PDBFile::getPDBIpiStream() { 216 if (!Ipi) { 217 auto IpiS = MappedBlockStream::createIndexedStream(StreamIPI, *this); 218 if (!IpiS) 219 return IpiS.takeError(); 220 auto TempIpi = llvm::make_unique<TpiStream>(*this, std::move(*IpiS)); 221 if (auto EC = TempIpi->reload()) 222 return std::move(EC); 223 Ipi = std::move(TempIpi); 224 } 225 return *Ipi; 226 } 227 228 Expected<PublicsStream &> PDBFile::getPDBPublicsStream() { 229 if (!Publics) { 230 auto DbiS = getPDBDbiStream(); 231 if (!DbiS) 232 return DbiS.takeError(); 233 234 uint32_t PublicsStreamNum = DbiS->getPublicSymbolStreamIndex(); 235 236 auto PublicS = 237 MappedBlockStream::createIndexedStream(PublicsStreamNum, *this); 238 if (!PublicS) 239 return PublicS.takeError(); 240 auto TempPublics = 241 llvm::make_unique<PublicsStream>(*this, std::move(*PublicS)); 242 if (auto EC = TempPublics->reload()) 243 return std::move(EC); 244 Publics = std::move(TempPublics); 245 } 246 return *Publics; 247 } 248 249 Expected<SymbolStream &> PDBFile::getPDBSymbolStream() { 250 if (!Symbols) { 251 auto DbiS = getPDBDbiStream(); 252 if (!DbiS) 253 return DbiS.takeError(); 254 255 uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex(); 256 257 auto SymbolS = 258 MappedBlockStream::createIndexedStream(SymbolStreamNum, *this); 259 if (!SymbolS) 260 return SymbolS.takeError(); 261 auto TempSymbols = llvm::make_unique<SymbolStream>(std::move(*SymbolS)); 262 if (auto EC = TempSymbols->reload()) 263 return std::move(EC); 264 Symbols = std::move(TempSymbols); 265 } 266 return *Symbols; 267 } 268 269 Expected<NameHashTable &> PDBFile::getStringTable() { 270 if (!StringTable || !StringTableStream) { 271 auto IS = getPDBInfoStream(); 272 if (!IS) 273 return IS.takeError(); 274 275 uint32_t NameStreamIndex = IS->getNamedStreamIndex("/names"); 276 277 if (NameStreamIndex == 0) 278 return make_error<RawError>(raw_error_code::no_stream); 279 if (NameStreamIndex >= getNumStreams()) 280 return make_error<RawError>(raw_error_code::no_stream); 281 282 auto NS = MappedBlockStream::createIndexedStream(NameStreamIndex, *this); 283 if (!NS) 284 return NS.takeError(); 285 286 StreamReader Reader(**NS); 287 auto N = llvm::make_unique<NameHashTable>(); 288 if (auto EC = N->load(Reader)) 289 return std::move(EC); 290 StringTable = std::move(N); 291 StringTableStream = std::move(*NS); 292 } 293 return *StringTable; 294 } 295 296 Error PDBFile::setSuperBlock(const SuperBlock *Block) { 297 SB = Block; 298 299 // Check the magic bytes. 300 if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0) 301 return make_error<RawError>(raw_error_code::corrupt_file, 302 "MSF magic header doesn't match"); 303 304 // We don't support blocksizes which aren't a multiple of four bytes. 305 if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) 306 return make_error<RawError>(raw_error_code::corrupt_file, 307 "Block size is not multiple of 4."); 308 309 switch (SB->BlockSize) { 310 case 512: 311 case 1024: 312 case 2048: 313 case 4096: 314 break; 315 default: 316 // An invalid block size suggests a corrupt PDB file. 317 return make_error<RawError>(raw_error_code::corrupt_file, 318 "Unsupported block size."); 319 } 320 321 if (Buffer->getLength() % SB->BlockSize != 0) 322 return make_error<RawError>(raw_error_code::corrupt_file, 323 "File size is not a multiple of block size"); 324 325 // We don't support directories whose sizes aren't a multiple of four bytes. 326 if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) 327 return make_error<RawError>(raw_error_code::corrupt_file, 328 "Directory size is not multiple of 4."); 329 330 // The number of blocks which comprise the directory is a simple function of 331 // the number of bytes it contains. 332 uint64_t NumDirectoryBlocks = getNumDirectoryBlocks(); 333 334 // The directory, as we understand it, is a block which consists of a list of 335 // block numbers. It is unclear what would happen if the number of blocks 336 // couldn't fit on a single block. 337 if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) 338 return make_error<RawError>(raw_error_code::corrupt_file, 339 "Too many directory blocks."); 340 341 return Error::success(); 342 } 343 344 Error PDBFile::commit() { 345 StreamWriter Writer(*Buffer); 346 347 if (auto EC = Writer.writeObject(*SB)) 348 return EC; 349 Writer.setOffset(getBlockMapOffset()); 350 if (auto EC = Writer.writeArray(DirectoryBlocks)) 351 return EC; 352 353 auto DS = MappedBlockStream::createDirectoryStream(*this); 354 if (!DS) 355 return DS.takeError(); 356 auto DirStream = std::move(*DS); 357 StreamWriter DW(*DirStream); 358 if (auto EC = DW.writeInteger(this->getNumStreams())) 359 return EC; 360 361 if (auto EC = DW.writeArray(StreamSizes)) 362 return EC; 363 364 for (const auto &Blocks : StreamMap) { 365 if (auto EC = DW.writeArray(Blocks)) 366 return EC; 367 } 368 369 if (Info) { 370 if (auto EC = Info->commit()) 371 return EC; 372 } 373 374 if (Dbi) { 375 if (auto EC = Dbi->commit()) 376 return EC; 377 } 378 379 if (Symbols) { 380 if (auto EC = Symbols->commit()) 381 return EC; 382 } 383 384 if (Publics) { 385 if (auto EC = Publics->commit()) 386 return EC; 387 } 388 389 if (Tpi) { 390 if (auto EC = Tpi->commit()) 391 return EC; 392 } 393 394 if (Ipi) { 395 if (auto EC = Ipi->commit()) 396 return EC; 397 } 398 399 return Buffer->commit(); 400 } 401