Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 1 | //===- GlobalsStream.cpp - PDB Index of Symbols by Name ---- ----*- 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 | //===----------------------------------------------------------------------===// |
Reid Kleckner | 14d90fd | 2017-07-26 00:40:36 +0000 | [diff] [blame] | 9 | // |
| 10 | // The on-disk structores used in this file are based on the reference |
| 11 | // implementation which is available at |
| 12 | // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h |
| 13 | // |
| 14 | // When you are reading the reference source code, you'd find the |
| 15 | // information below useful. |
| 16 | // |
| 17 | // - ppdb1->m_fMinimalDbgInfo seems to be always true. |
| 18 | // - SMALLBUCKETS macro is defined. |
| 19 | // |
| 20 | //===----------------------------------------------------------------------===// |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 21 | |
Adrian McCarthy | 6b6b8c4 | 2017-01-25 22:38:55 +0000 | [diff] [blame] | 22 | #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" |
Reid Kleckner | 14d90fd | 2017-07-26 00:40:36 +0000 | [diff] [blame] | 23 | #include "llvm/DebugInfo/PDB/Native/RawError.h" |
Zachary Turner | d9dc282 | 2017-03-02 20:52:51 +0000 | [diff] [blame] | 24 | #include "llvm/Support/BinaryStreamReader.h" |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 25 | #include "llvm/Support/Error.h" |
Eugene Zelenko | 570e39a | 2016-11-23 23:16:32 +0000 | [diff] [blame] | 26 | #include <algorithm> |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 27 | |
| 28 | using namespace llvm; |
| 29 | using namespace llvm::msf; |
| 30 | using namespace llvm::pdb; |
| 31 | |
| 32 | GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream) |
| 33 | : Stream(std::move(Stream)) {} |
| 34 | |
Eugene Zelenko | 570e39a | 2016-11-23 23:16:32 +0000 | [diff] [blame] | 35 | GlobalsStream::~GlobalsStream() = default; |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 36 | |
| 37 | Error GlobalsStream::reload() { |
Zachary Turner | 120faca | 2017-02-27 22:11:43 +0000 | [diff] [blame] | 38 | BinaryStreamReader Reader(*Stream); |
Reid Kleckner | 14d90fd | 2017-07-26 00:40:36 +0000 | [diff] [blame] | 39 | if (auto E = GlobalsTable.read(Reader)) |
| 40 | return E; |
| 41 | return Error::success(); |
| 42 | } |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 43 | |
Reid Kleckner | 14d90fd | 2017-07-26 00:40:36 +0000 | [diff] [blame] | 44 | static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) { |
| 45 | if (HashHdr->VerHdr != GSIHashHeader::HdrVersion) |
| 46 | return make_error<RawError>( |
| 47 | raw_error_code::feature_unsupported, |
| 48 | "Encountered unsupported globals stream version."); |
Bob Haarman | 653baa2 | 2016-10-21 19:43:19 +0000 | [diff] [blame] | 49 | |
| 50 | return Error::success(); |
| 51 | } |
| 52 | |
Reid Kleckner | 14d90fd | 2017-07-26 00:40:36 +0000 | [diff] [blame] | 53 | static Error readGSIHashHeader(const GSIHashHeader *&HashHdr, |
| 54 | BinaryStreamReader &Reader) { |
| 55 | if (Reader.readObject(HashHdr)) |
| 56 | return make_error<RawError>(raw_error_code::corrupt_file, |
| 57 | "Stream does not contain a GSIHashHeader."); |
| 58 | |
| 59 | if (HashHdr->VerSignature != GSIHashHeader::HdrSignature) |
| 60 | return make_error<RawError>( |
| 61 | raw_error_code::feature_unsupported, |
| 62 | "GSIHashHeader signature (0xffffffff) not found."); |
| 63 | |
| 64 | return Error::success(); |
| 65 | } |
| 66 | |
| 67 | static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords, |
| 68 | const GSIHashHeader *HashHdr, |
| 69 | BinaryStreamReader &Reader) { |
| 70 | if (auto EC = checkHashHdrVersion(HashHdr)) |
| 71 | return EC; |
| 72 | |
| 73 | // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have. |
| 74 | // Verify that we can read them all. |
| 75 | if (HashHdr->HrSize % sizeof(PSHashRecord)) |
| 76 | return make_error<RawError>(raw_error_code::corrupt_file, |
| 77 | "Invalid HR array size."); |
| 78 | uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord); |
| 79 | if (auto EC = Reader.readArray(HashRecords, NumHashRecords)) |
| 80 | return joinErrors(std::move(EC), |
| 81 | make_error<RawError>(raw_error_code::corrupt_file, |
| 82 | "Error reading hash records.")); |
| 83 | |
| 84 | return Error::success(); |
| 85 | } |
| 86 | |
| 87 | static Error |
| 88 | readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets, |
| 89 | ArrayRef<uint8_t> &HashBitmap, const GSIHashHeader *HashHdr, |
| 90 | BinaryStreamReader &Reader) { |
| 91 | if (auto EC = checkHashHdrVersion(HashHdr)) |
| 92 | return EC; |
| 93 | |
| 94 | // Before the actual hash buckets, there is a bitmap of length determined by |
| 95 | // IPHR_HASH. |
| 96 | size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32); |
| 97 | uint32_t NumBitmapEntries = BitmapSizeInBits / 8; |
| 98 | if (auto EC = Reader.readBytes(HashBitmap, NumBitmapEntries)) |
| 99 | return joinErrors(std::move(EC), |
| 100 | make_error<RawError>(raw_error_code::corrupt_file, |
| 101 | "Could not read a bitmap.")); |
| 102 | uint32_t NumBuckets = 0; |
| 103 | for (uint8_t B : HashBitmap) |
| 104 | NumBuckets += countPopulation(B); |
| 105 | |
| 106 | // Hash buckets follow. |
| 107 | if (auto EC = Reader.readArray(HashBuckets, NumBuckets)) |
| 108 | return joinErrors(std::move(EC), |
| 109 | make_error<RawError>(raw_error_code::corrupt_file, |
| 110 | "Hash buckets corrupted.")); |
| 111 | |
| 112 | return Error::success(); |
| 113 | } |
| 114 | |
| 115 | Error GSIHashTable::read(BinaryStreamReader &Reader) { |
| 116 | if (auto EC = readGSIHashHeader(HashHdr, Reader)) |
| 117 | return EC; |
| 118 | if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader)) |
| 119 | return EC; |
| 120 | if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr, Reader)) |
| 121 | return EC; |
| 122 | return Error::success(); |
| 123 | } |