llvm.org GIT mirror llvm / 6be3e7c
[pdb] Use MsfBuilder to handle the writing PDBs. Previously we would read a PDB, then write some of it back out, but write the directory, super block, and other pertinent metadata back out unchanged. This generates incorrect PDBs since the amount of data written was not always the same as the amount of data read. This patch changes things to use the newly introduced `MsfBuilder` class to write out a correct and accurate set of Msf metadata for the data *actually* written, which opens up the door for adding and removing type records, symbol records, and other types of data to an existing PDB. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@275627 91177308-0d34-0410-b5e6-96231b3b80d8 Zachary Turner 4 years ago
26 changed file(s) with 344 addition(s) and 238 deletion(s). Raw diff Collapse all Expand all
111111 VarStreamArrayIterator(const ArrayType &Array, const Extractor &E,
112112 bool *HadError = nullptr)
113113 : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) {
114 auto EC = Extract(IterRef, ThisLen, ThisValue);
115 if (EC) {
116 consumeError(std::move(EC));
117 markError();
114 if (IterRef.getLength() == 0)
115 moveToEnd();
116 else {
117 auto EC = Extract(IterRef, ThisLen, ThisValue);
118 if (EC) {
119 consumeError(std::move(EC));
120 markError();
121 }
118122 }
119123 }
120124 VarStreamArrayIterator() {}
2323
2424 class DbiStreamBuilder {
2525 public:
26 DbiStreamBuilder(PDBFile &File);
26 DbiStreamBuilder();
2727
2828 DbiStreamBuilder(const DbiStreamBuilder &) = delete;
2929 DbiStreamBuilder &operator=(const DbiStreamBuilder &) = delete;
3636 void setFlags(uint16_t F);
3737 void setMachineType(PDB_Machine M);
3838
39 Expected> build();
39 uint32_t calculateSerializedLength() const;
40
41 Expected> build(PDBFile &File);
4042
4143 private:
42 PDBFile &File;
4344 Optional VerHeader;
4445 uint32_t Age;
4546 uint16_t BuildNumber;
2626 class InfoStream {
2727 friend class InfoStreamBuilder;
2828
29 struct Header {
29 struct HeaderInfo {
3030 support::ulittle32_t Version;
3131 support::ulittle32_t Signature;
3232 support::ulittle32_t Age;
1313 #include "llvm/Support/Error.h"
1414
1515 #include "llvm/DebugInfo/PDB/PDBTypes.h"
16 #include "llvm/DebugInfo/PDB/Raw/NameMap.h"
16 #include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h"
1717 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1818 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1919
2020 namespace llvm {
2121 namespace pdb {
22 class NameMap;
2322 class PDBFile;
2423
2524 class InfoStreamBuilder {
2625 public:
27 InfoStreamBuilder(IPDBFile &File);
26 InfoStreamBuilder();
2827 InfoStreamBuilder(const InfoStreamBuilder &) = delete;
2928 InfoStreamBuilder &operator=(const InfoStreamBuilder &) = delete;
3029
3332 void setAge(uint32_t A);
3433 void setGuid(PDB_UniqueId G);
3534
36 Expected> build();
35 uint32_t calculateSerializedLength() const;
36
37 Expected> build(PDBFile &File);
3738
3839 private:
39 IPDBFile &File;
4040 Optional Ver;
4141 Optional Sig;
4242 Optional Age;
4343 Optional Guid;
44 Optional NamedStreams;
44
45 NameMapBuilder NamedStreams;
4546 };
4647 }
4748 }
6262 /// Request the block map to be at a specific block address. This is useful
6363 /// when editing a PDB and you want the layout to be as stable as possible.
6464 Error setBlockMapAddr(uint32_t Addr);
65 Error setDirectoryBlocksHint(ArrayRef DirBlocks);
66 void setUnknown0(uint32_t Unk0);
67 void setUnknown1(uint32_t Unk1);
6568
6669 /// Add a stream to the MSF file with the given size, occupying the given
6770 /// list of blocks. This is useful when reading a PDB file and you want a
122125 BumpPtrAllocator &Allocator;
123126
124127 bool IsGrowable;
128 uint32_t Unknown0;
129 uint32_t Unknown1;
125130 uint32_t BlockSize;
126131 uint32_t MininumBlocks;
127132 uint32_t BlockMapAddr;
0 //===- NameMapBuilder.h - PDB Name Map Builder ------------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H
10 #define LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H
11
12 #include "llvm/Support/Error.h"
13
14 #include
15 #include
16
17 namespace llvm {
18 namespace pdb {
19 class NameMap;
20
21 class NameMapBuilder {
22 public:
23 NameMapBuilder();
24
25 Expected> build();
26
27 uint32_t calculateSerializedLength() const;
28 };
29
30 } // end namespace pdb
31 } // end namespace llvm
32
33 #endif // LLVM_DEBUGINFO_PDB_RAW_PDBNAMEMAPBUILDER_H
1313 #include "llvm/DebugInfo/CodeView/StreamArray.h"
1414 #include "llvm/DebugInfo/CodeView/StreamInterface.h"
1515 #include "llvm/DebugInfo/PDB/Raw/IPDBFile.h"
16 #include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
1617 #include "llvm/Support/Allocator.h"
1718 #include "llvm/Support/Endian.h"
1819 #include "llvm/Support/Error.h"
3637 class SymbolStream;
3738 class TpiStream;
3839
39 static const char MsfMagic[] = {'M', 'i', 'c', 'r', 'o', 's', 'o', 'f',
40 't', ' ', 'C', '/', 'C', '+', '+', ' ',
41 'M', 'S', 'F', ' ', '7', '.', '0', '0',
42 '\r', '\n', '\x1a', 'D', 'S', '\0', '\0', '\0'};
43
4440 class PDBFile : public IPDBFile {
4541 friend PDBFileBuilder;
4642
4743 public:
48 // The superblock is overlaid at the beginning of the file (offset 0).
49 // It starts with a magic header and is followed by information which
50 // describes the layout of the file system.
51 struct SuperBlock {
52 char MagicBytes[sizeof(MsfMagic)];
53 // The file system is split into a variable number of fixed size elements.
54 // These elements are referred to as blocks. The size of a block may vary
55 // from system to system.
56 support::ulittle32_t BlockSize;
57 // This field's purpose is not yet known.
58 support::ulittle32_t Unknown0;
59 // This contains the number of blocks resident in the file system. In
60 // practice, NumBlocks * BlockSize is equivalent to the size of the PDB
61 // file.
62 support::ulittle32_t NumBlocks;
63 // This contains the number of bytes which make up the directory.
64 support::ulittle32_t NumDirectoryBytes;
65 // This field's purpose is not yet known.
66 support::ulittle32_t Unknown1;
67 // This contains the block # of the block map.
68 support::ulittle32_t BlockMapAddr;
69 };
70
7144 explicit PDBFile(std::unique_ptr PdbFileBuffer);
7245 ~PDBFile() override;
7346
10275 Error parseFileHeaders();
10376 Error parseStreamData();
10477
105 static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) {
106 return alignTo(NumBytes, BlockSize) / BlockSize;
107 }
108
109 static uint64_t blockToOffset(uint64_t BlockNumber, uint64_t BlockSize) {
110 return BlockNumber * BlockSize;
111 }
112
11378 Expected getPDBInfoStream();
11479 Expected getPDBDbiStream();
11580 Expected getPDBTpiStream();
12186 Error commit();
12287
12388 private:
124 Error setSuperBlock(const SuperBlock *Block);
89 Error setSuperBlock(const msf::SuperBlock *Block);
12590
12691 BumpPtrAllocator Allocator;
12792
12893 std::unique_ptr Buffer;
129 const PDBFile::SuperBlock *SB;
94 const msf::SuperBlock *SB;
13095 ArrayRef StreamSizes;
13196 ArrayRef DirectoryBlocks;
13297 std::vector> StreamMap;
1010 #define LLVM_DEBUGINFO_PDB_RAW_PDBFILEBUILDER_H
1111
1212 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/BitVector.h"
1314 #include "llvm/ADT/Optional.h"
1415 #include "llvm/Support/Endian.h"
1516 #include "llvm/Support/Error.h"
1617
18 #include "llvm/DebugInfo/PDB/Raw/MsfBuilder.h"
1719 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1820
1921 #include
3133 class PDBFileBuilder {
3234 public:
3335 explicit PDBFileBuilder(
34 std::unique_ptr PdbFileBuffer);
36 std::unique_ptr FileBuffer);
3537 PDBFileBuilder(const PDBFileBuilder &) = delete;
3638 PDBFileBuilder &operator=(const PDBFileBuilder &) = delete;
3739
38 Error setSuperBlock(const PDBFile::SuperBlock &B);
39 void setStreamSizes(ArrayRef S);
40 void setDirectoryBlocks(ArrayRef D);
41 void setStreamMap(const std::vector> &S);
42 Error generateSimpleStreamMap();
40 Error initialize(const msf::SuperBlock &Super);
4341
42 MsfBuilder &getMsfBuilder();
4443 InfoStreamBuilder &getInfoBuilder();
4544 DbiStreamBuilder &getDbiBuilder();
4645
4746 Expected> build();
4847
4948 private:
50 std::unique_ptr PdbFileBuffer;
5149 std::unique_ptr Info;
5250 std::unique_ptr Dbi;
5351
5452 std::unique_ptr File;
53 std::unique_ptr Msf;
5554 };
5655 }
5756 }
4141 Raw/MsfCommon.cpp
4242 Raw/NameHashTable.cpp
4343 Raw/NameMap.cpp
44 Raw/NameMapBuilder.cpp
4445 Raw/PDBFile.cpp
4546 Raw/PDBFileBuilder.cpp
4647 Raw/PublicsStream.cpp
181181 return make_error(raw_error_code::corrupt_file,
182182 "Found unexpected bytes in DBI Stream.");
183183
184 StreamReader ECReader(ECSubstream);
185 if (auto EC = ECNames.load(ECReader))
186 return EC;
184 if (ECSubstream.getLength() > 0) {
185 StreamReader ECReader(ECSubstream);
186 if (auto EC = ECNames.load(ECReader))
187 return EC;
188 }
187189
188190 return Error::success();
189191 }
266268 }
267269
268270 Error DbiStream::initializeSectionContributionData() {
271 if (SecContrSubstream.getLength() == 0)
272 return Error::success();
273
269274 StreamReader SCReader(SecContrSubstream);
270275 if (auto EC = SCReader.readEnum(SectionContribVersion))
271276 return EC;
281286
282287 // Initializes this->SectionHeaders.
283288 Error DbiStream::initializeSectionHeadersData() {
289 if (DbgStreams.size() == 0)
290 return Error::success();
291
284292 uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::SectionHdr);
285293 if (StreamNum >= Pdb.getNumStreams())
286294 return make_error(raw_error_code::no_stream);
306314
307315 // Initializes this->Fpos.
308316 Error DbiStream::initializeFpoRecords() {
317 if (DbgStreams.size() == 0)
318 return Error::success();
319
309320 uint32_t StreamNum = getDebugStreamIndex(DbgHeaderType::NewFPO);
310321
311322 // This means there is no FPO data.
334345 }
335346
336347 Error DbiStream::initializeSectionMapData() {
348 if (SecMapSubstream.getLength() == 0)
349 return Error::success();
350
337351 StreamReader SMReader(SecMapSubstream);
338352 const SecMapHeader *Header;
339353 if (auto EC = SMReader.readObject(Header))
356370 // with the caveat that `NumSourceFiles` cannot be trusted, so
357371 // it is computed by summing `ModFileCounts`.
358372 //
373 if (FileInfoSubstream.getLength() == 0)
374 return Error::success();
375
359376 const FileInfoSubstreamHeader *FH;
360377 StreamReader FISR(FileInfoSubstream);
361378 if (auto EC = FISR.readObject(FH))
435452 return Name;
436453 }
437454
438 Error DbiStream::commit() { return Error::success(); }
455 Error DbiStream::commit() {
456 StreamWriter Writer(*Stream);
457 if (auto EC = Writer.writeObject(*Header))
458 return EC;
459
460 return Error::success();
461 }
1717 using namespace llvm::codeview;
1818 using namespace llvm::pdb;
1919
20 DbiStreamBuilder::DbiStreamBuilder(PDBFile &File)
21 : File(File), Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0),
22 Flags(0), MachineType(PDB_Machine::x86) {}
20 DbiStreamBuilder::DbiStreamBuilder()
21 : Age(1), BuildNumber(0), PdbDllVersion(0), PdbDllRbld(0), Flags(0),
22 MachineType(PDB_Machine::x86) {}
2323
2424 void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
2525
3535
3636 void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
3737
38 Expected> DbiStreamBuilder::build() {
38 uint32_t DbiStreamBuilder::calculateSerializedLength() const {
39 // For now we only support serializing the header.
40 return sizeof(DbiStream::HeaderInfo);
41 }
42
43 Expected> DbiStreamBuilder::build(PDBFile &File) {
3944 if (!VerHeader.hasValue())
4045 return make_error(raw_error_code::unspecified,
4146 "Missing DBI Stream Version");
2626 Error InfoStream::reload() {
2727 codeview::StreamReader Reader(*Stream);
2828
29 const Header *H;
29 const HeaderInfo *H;
3030 if (auto EC = Reader.readObject(H))
3131 return joinErrors(
3232 std::move(EC),
7777 Error InfoStream::commit() {
7878 StreamWriter Writer(*Stream);
7979
80 Header H;
80 HeaderInfo H;
8181 H.Age = Age;
8282 H.Signature = Signature;
8383 H.Version = Version;
8686 return EC;
8787
8888 return NamedStreams.commit(Writer);
89 }
89 }
1717 using namespace llvm::codeview;
1818 using namespace llvm::pdb;
1919
20 InfoStreamBuilder::InfoStreamBuilder(IPDBFile &File) : File(File) {}
20 InfoStreamBuilder::InfoStreamBuilder() {}
2121
2222 void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; }
2323
2727
2828 void InfoStreamBuilder::setGuid(PDB_UniqueId G) { Guid = G; }
2929
30 Expected> InfoStreamBuilder::build() {
30 uint32_t InfoStreamBuilder::calculateSerializedLength() const {
31 return sizeof(InfoStream::HeaderInfo) +
32 NamedStreams.calculateSerializedLength();
33 }
34
35 Expected> InfoStreamBuilder::build(PDBFile &File) {
3136 if (!Ver.hasValue())
3237 return make_error(raw_error_code::unspecified,
3338 "Missing PDB Stream Version");
2323 BumpPtrAllocator &Allocator)
2424 : Allocator(Allocator), IsGrowable(CanGrow), BlockSize(BlockSize),
2525 MininumBlocks(MinBlockCount), BlockMapAddr(kDefaultBlockMapAddr),
26 FreeBlocks(MinBlockCount + 2U, true) {
26 FreeBlocks(std::max(MinBlockCount, 2U), true) {
2727 FreeBlocks[kSuperBlockBlock] = false;
2828 FreeBlocks[BlockMapAddr] = false;
2929 }
5555 FreeBlocks[BlockMapAddr] = true;
5656 FreeBlocks[Addr] = false;
5757 BlockMapAddr = Addr;
58 return Error::success();
59 }
60
61 void MsfBuilder::setUnknown0(uint32_t Unk0) { Unknown0 = Unk0; }
62
63 void MsfBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; }
64
65 Error MsfBuilder::setDirectoryBlocksHint(ArrayRef DirBlocks) {
66 for (auto B : DirectoryBlocks)
67 FreeBlocks[B] = true;
68 for (auto B : DirBlocks) {
69 if (!isBlockFree(B)) {
70 return make_error(raw_error_code::unspecified,
71 "Attempt to reuse an allocated block");
72 }
73 FreeBlocks[B] = false;
74 }
75
76 DirectoryBlocks = DirBlocks;
5877 return Error::success();
5978 }
6079
197216 L.SB->BlockMapAddr = BlockMapAddr;
198217 L.SB->BlockSize = BlockSize;
199218 L.SB->NumDirectoryBytes = computeDirectoryByteSize();
200 L.SB->Unknown0 = 0;
201 L.SB->Unknown1 = 0;
219 L.SB->Unknown0 = Unknown0;
220 L.SB->Unknown1 = Unknown1;
202221
203222 uint32_t NumDirectoryBlocks =
204223 bytesToBlocks(L.SB->NumDirectoryBytes, BlockSize);
205 // The directory blocks should be re-allocated as a stable pointer.
206 std::vector DirectoryBlocks;
207 DirectoryBlocks.resize(NumDirectoryBlocks);
208 if (auto EC = allocateBlocks(NumDirectoryBlocks, DirectoryBlocks))
209 return std::move(EC);
224 if (NumDirectoryBlocks > DirectoryBlocks.size()) {
225 // Our hint wasn't enough to satisfy the entire directory. Allocate
226 // remaining pages.
227 std::vector ExtraBlocks;
228 uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size();
229 ExtraBlocks.resize(NumExtraBlocks);
230 if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks))
231 return std::move(EC);
232 DirectoryBlocks.insert(DirectoryBlocks.end(), ExtraBlocks.begin(),
233 ExtraBlocks.end());
234 } else if (NumDirectoryBlocks < DirectoryBlocks.size()) {
235 uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks;
236 for (auto B :
237 ArrayRef(DirectoryBlocks).drop_back(NumUnnecessaryBlocks))
238 FreeBlocks[B] = true;
239 DirectoryBlocks.resize(NumDirectoryBlocks);
240 }
210241
211242 // Don't set the number of blocks in the file until after allocating Blocks
212243 // for
0 //===- NameMapBuilder.cpp - PDB Name Map Builder ----------------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/DebugInfo/PDB/Raw/NameMapBuilder.h"
10
11 #include "llvm/DebugInfo/PDB/Raw/NameMap.h"
12
13 using namespace llvm;
14 using namespace llvm::pdb;
15
16 NameMapBuilder::NameMapBuilder() {}
17
18 Expected> NameMapBuilder::build() {
19 return llvm::make_unique();
20 }
21
22 uint32_t NameMapBuilder::calculateSerializedLength() const {
23 // For now we write an empty name map, nothing else.
24 return 5 * sizeof(uint32_t);
25 }
5252 uint32_t PDBFile::getUnknown1() const { return SB->Unknown1; }
5353
5454 uint32_t PDBFile::getNumDirectoryBlocks() const {
55 return bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
55 return msf::bytesToBlocks(SB->NumDirectoryBytes, SB->BlockSize);
5656 }
5757
5858 uint64_t PDBFile::getBlockMapOffset() const {
7474
7575 Expected> PDBFile::getBlockData(uint32_t BlockIndex,
7676 uint32_t NumBytes) const {
77 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
77 uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
7878
7979 ArrayRef Result;
8080 if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
9393 raw_error_code::invalid_block_address,
9494 "setBlockData attempted to write out of block bounds.");
9595
96 uint64_t StreamBlockOffset = blockToOffset(BlockIndex, getBlockSize());
96 uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
9797 StreamBlockOffset += Offset;
9898 return Buffer->writeBytes(StreamBlockOffset, Data);
9999 }
142142 uint32_t StreamSize = getStreamByteSize(I);
143143 // FIXME: What does StreamSize ~0U mean?
144144 uint64_t NumExpectedStreamBlocks =
145 StreamSize == UINT32_MAX ? 0 : bytesToBlocks(StreamSize, SB->BlockSize);
145 StreamSize == UINT32_MAX ? 0 : msf::bytesToBlocks(StreamSize,
146 SB->BlockSize);
146147
147148 // For convenience, we store the block array contiguously. This is because
148149 // if someone calls setStreamMap(), it is more convenient to be able to call
292293 return *StringTable;
293294 }
294295
295 Error PDBFile::setSuperBlock(const SuperBlock *Block) {
296 SB = Block;
297
298 // Check the magic bytes.
299 if (memcmp(SB->MagicBytes, MsfMagic, sizeof(MsfMagic)) != 0)
300 return make_error(raw_error_code::corrupt_file,
301 "MSF magic header doesn't match");
302
303 // We don't support blocksizes which aren't a multiple of four bytes.
304 if (SB->BlockSize % sizeof(support::ulittle32_t) != 0)
305 return make_error(raw_error_code::corrupt_file,
306 "Block size is not multiple of 4.");
307
308 switch (SB->BlockSize) {
309 case 512:
310 case 1024:
311 case 2048:
312 case 4096:
313 break;
314 default:
315 // An invalid block size suggests a corrupt PDB file.
316 return make_error(raw_error_code::corrupt_file,
317 "Unsupported block size.");
318 }
296 Error PDBFile::setSuperBlock(const msf::SuperBlock *Block) {
297 if (auto EC = msf::validateSuperBlock(*Block))
298 return EC;
319299
320300 if (Buffer->getLength() % SB->BlockSize != 0)
321301 return make_error(raw_error_code::corrupt_file,
322302 "File size is not a multiple of block size");
323303
324 // We don't support directories whose sizes aren't a multiple of four bytes.
325 if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
326 return make_error(raw_error_code::corrupt_file,
327 "Directory size is not multiple of 4.");
328
329 // The number of blocks which comprise the directory is a simple function of
330 // the number of bytes it contains.
331 uint64_t NumDirectoryBlocks = getNumDirectoryBlocks();
332
333 // The directory, as we understand it, is a block which consists of a list of
334 // block numbers. It is unclear what would happen if the number of blocks
335 // couldn't fit on a single block.
336 if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t))
337 return make_error(raw_error_code::corrupt_file,
338 "Too many directory blocks.");
339
304 SB = Block;
340305 return Error::success();
341306 }
342307
77 //===----------------------------------------------------------------------===//
88
99 #include "llvm/DebugInfo/PDB/Raw/PDBFileBuilder.h"
10
11 #include "llvm/ADT/BitVector.h"
1012
1113 #include "llvm/DebugInfo/CodeView/StreamInterface.h"
1214 #include "llvm/DebugInfo/CodeView/StreamWriter.h"
1921 using namespace llvm;
2022 using namespace llvm::codeview;
2123 using namespace llvm::pdb;
24 using namespace llvm::support;
2225
2326 PDBFileBuilder::PDBFileBuilder(
24 std::unique_ptr PdbFileBuffer)
25 : File(llvm::make_unique(std::move(PdbFileBuffer))) {}
27 std::unique_ptr FileBuffer)
28 : File(llvm::make_unique(std::move(FileBuffer))) {}
2629
27 Error PDBFileBuilder::setSuperBlock(const PDBFile::SuperBlock &B) {
28 auto SB = static_cast(
29 File->Allocator.Allocate(sizeof(PDBFile::SuperBlock),
30 llvm::AlignOf::Alignment));
31 ::memcpy(SB, &B, sizeof(PDBFile::SuperBlock));
32 return File->setSuperBlock(SB);
33 }
30 Error PDBFileBuilder::initialize(const msf::SuperBlock &Super) {
31 auto ExpectedMsf =
32 MsfBuilder::create(File->Allocator, Super.BlockSize, Super.NumBlocks);
33 if (!ExpectedMsf)
34 return ExpectedMsf.takeError();
3435
35 void PDBFileBuilder::setStreamSizes(ArrayRef S) {
36 File->StreamSizes = S;
37 }
38
39 void PDBFileBuilder::setDirectoryBlocks(ArrayRef D) {
40 File->DirectoryBlocks = D;
41 }
42
43 void PDBFileBuilder::setStreamMap(
44 const std::vector> &S) {
45 File->StreamMap = S;
46 }
47
48 Error PDBFileBuilder::generateSimpleStreamMap() {
49 if (File->StreamSizes.empty())
50 return Error::success();
51
52 static std::vector> StaticMap;
53 File->StreamMap.clear();
54 StaticMap.clear();
55
56 // Figure out how many blocks are needed for all streams, and set the first
57 // used block to the highest block so that we can write the rest of the
58 // blocks contiguously.
59 uint32_t TotalFileBlocks = File->getBlockCount();
60 std::vector ReservedBlocks;
61 ReservedBlocks.push_back(support::ulittle32_t(0));
62 ReservedBlocks.push_back(File->SB->BlockMapAddr);
63 ReservedBlocks.insert(ReservedBlocks.end(), File->DirectoryBlocks.begin(),
64 File->DirectoryBlocks.end());
65
66 uint32_t BlocksNeeded = 0;
67 for (auto Size : File->StreamSizes)
68 BlocksNeeded += File->bytesToBlocks(Size, File->getBlockSize());
69
70 support::ulittle32_t NextBlock(TotalFileBlocks - BlocksNeeded -
71 ReservedBlocks.size());
72
73 StaticMap.resize(File->StreamSizes.size());
74 for (uint32_t S = 0; S < File->StreamSizes.size(); ++S) {
75 uint32_t Size = File->StreamSizes[S];
76 uint32_t NumBlocks = File->bytesToBlocks(Size, File->getBlockSize());
77 auto &ThisStream = StaticMap[S];
78 for (uint32_t I = 0; I < NumBlocks;) {
79 NextBlock += 1;
80 if (std::find(ReservedBlocks.begin(), ReservedBlocks.end(), NextBlock) !=
81 ReservedBlocks.end())
82 continue;
83
84 ++I;
85 assert(NextBlock < File->getBlockCount());
86 ThisStream.push_back(NextBlock);
87 }
88 File->StreamMap.push_back(ThisStream);
89 }
36 auto &MsfResult = *ExpectedMsf;
37 if (auto EC = MsfResult.setBlockMapAddr(Super.BlockMapAddr))
38 return EC;
39 MsfResult.setUnknown0(Super.Unknown0);
40 MsfResult.setUnknown1(Super.Unknown1);
41 Msf = llvm::make_unique(std::move(MsfResult));
9042 return Error::success();
9143 }
9244
45 MsfBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
46
9347 InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
9448 if (!Info)
95 Info = llvm::make_unique(*File);
49 Info = llvm::make_unique();
9650 return *Info;
9751 }
9852
9953 DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
10054 if (!Dbi)
101 Dbi = llvm::make_unique(*File);
55 Dbi = llvm::make_unique();
10256 return *Dbi;
10357 }
10458
10559 Expected> PDBFileBuilder::build() {
10660 if (Info) {
107 auto ExpectedInfo = Info->build();
61 uint32_t Length = Info->calculateSerializedLength();
62 if (auto EC = Msf->setStreamSize(StreamPDB, Length))
63 return std::move(EC);
64 }
65 if (Dbi) {
66 uint32_t Length = Dbi->calculateSerializedLength();
67 if (auto EC = Msf->setStreamSize(StreamDBI, Length))
68 return std::move(EC);
69 }
70
71 auto ExpectedLayout = Msf->build();
72 if (!ExpectedLayout)
73 return ExpectedLayout.takeError();
74
75 const msf::Layout &L = *ExpectedLayout;
76 File->StreamMap = L.StreamMap;
77 File->StreamSizes = L.StreamSizes;
78 File->DirectoryBlocks = L.DirectoryBlocks;
79 File->SB = L.SB;
80
81 if (Info) {
82 auto ExpectedInfo = Info->build(*File);
10883 if (!ExpectedInfo)
10984 return ExpectedInfo.takeError();
11085 File->Info = std::move(*ExpectedInfo);
11186 }
11287
11388 if (Dbi) {
114 auto ExpectedDbi = Dbi->build();
89 auto ExpectedDbi = Dbi->build(*File);
11590 if (!ExpectedDbi)
11691 return ExpectedDbi.takeError();
11792 File->Dbi = std::move(*ExpectedDbi);
1515 ; EMPTY-NEXT: Unknown1: 0
1616 ; EMPTY-NEXT: BlockMapAddr: 24
1717 ; EMPTY-NEXT: NumDirectoryBlocks: 1
18 ; EMPTY-NEXT: BlockMapOffset: 98304
1918 ; EMPTY-NEXT: DirectoryBlocks: [23]
2019 ; EMPTY-NEXT: NumStreams: 17
2120 ; EMPTY-NEXT: }
951950 ; ALL: Unknown1: 0
952951 ; ALL: BlockMapAddr: 24
953952 ; ALL: NumDirectoryBlocks: 1
954 ; ALL: BlockMapOffset: 98304
955953 ; ALL: DirectoryBlocks: [23]
956954 ; ALL: NumStreams: 17
957955 ; ALL: }
16671665 ; BIG-NEXT: Unknown1: 0
16681666 ; BIG-NEXT: BlockMapAddr: 97
16691667 ; BIG-NEXT: NumDirectoryBlocks: 1
1670 ; BIG-NEXT: BlockMapOffset: 397312
16711668 ; BIG-NEXT: DirectoryBlocks: [96]
16721669 ; BIG-NEXT: NumStreams: 64
16731670 ; BIG-NEXT: }
44 ; the YAML, the PDB might be missing data required for any standard tool
55 ; to recognize it. Finally, it dumps the same set of fields from the newly
66 ; constructed PDB to YAML, and verifies that the YAML is the same as the
7 ; original YAML generated from the good PDB.
7 ; original YAML generated from the good PDB. Note that when doing the
8 ; final comparison it must dump the original and the new pdb without any
9 ; stream metadata, since the layout of the MSF file might be different
10 ; (for example if we don't write the entire stream)
811 ;
912 ; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream %p/Inputs/empty.pdb > %t.1
1013 ; RUN: llvm-pdbdump yaml2pdb -pdb=%t.2 %t.1
11 ; RUN: llvm-pdbdump pdb2yaml -stream-metadata -stream-directory -pdb-stream %t.2 > %t.3
12 ; RUN: diff %t.1 %t.3
14 ; RUN: llvm-pdbdump pdb2yaml -pdb-stream %p/Inputs/empty.pdb > %t.3
15 ; RUN: llvm-pdbdump pdb2yaml -pdb-stream %t.2 > %t.4
16 ; RUN: diff %t.3 %t.4
1212 ; YAML-NEXT: Unknown1: 0
1313 ; YAML-NEXT: BlockMapAddr: 24
1414 ; YAML-NEXT: NumDirectoryBlocks: 1
15 ; YAML-NEXT: BlockMapOffset: 98304
1615 ; YAML-NEXT: DirectoryBlocks:
1716 ; YAML-NEXT: - 23
1817 ; YAML-NEXT: NumStreams: 17
100100 P.printNumber("Unknown1", File.getUnknown1());
101101 P.printNumber("BlockMapAddr", File.getBlockMapIndex());
102102 P.printNumber("NumDirectoryBlocks", File.getNumDirectoryBlocks());
103 P.printNumber("BlockMapOffset", File.getBlockMapOffset());
104103
105104 // The directory is not contiguous. Instead, the block map contains a
106105 // contiguous list of block numbers whose contents, when concatenated in
114114 void MappingTraits::mapping(IO &IO, MsfHeaders &Obj) {
115115 IO.mapRequired("SuperBlock", Obj.SuperBlock);
116116 IO.mapRequired("NumDirectoryBlocks", Obj.NumDirectoryBlocks);
117 IO.mapRequired("BlockMapOffset", Obj.BlockMapOffset);
118117 IO.mapRequired("DirectoryBlocks", Obj.DirectoryBlocks);
119118 IO.mapRequired("NumStreams", Obj.NumStreams);
120119 IO.mapRequired("FileSize", Obj.FileSize);
121120 }
122121
123 void MappingTraits::mapping(IO &IO,
124 PDBFile::SuperBlock &SB) {
122 void MappingTraits::mapping(IO &IO, msf::SuperBlock &SB) {
125123 if (!IO.outputting()) {
126 ::memcpy(SB.MagicBytes, MsfMagic, sizeof(MsfMagic));
124 ::memcpy(SB.MagicBytes, msf::Magic, sizeof(msf::Magic));
127125 }
128126
129127 IO.mapRequired("BlockSize", SB.BlockSize);
1313
1414 #include "llvm/ADT/Optional.h"
1515 #include "llvm/DebugInfo/PDB/PDBTypes.h"
16 #include "llvm/DebugInfo/PDB/Raw/MsfCommon.h"
1617 #include "llvm/DebugInfo/PDB/Raw/PDBFile.h"
1718 #include "llvm/DebugInfo/PDB/Raw/RawConstants.h"
1819 #include "llvm/Support/Endian.h"
2526
2627 namespace yaml {
2728 struct MsfHeaders {
28 PDBFile::SuperBlock SuperBlock;
29 msf::SuperBlock SuperBlock;
2930 uint32_t NumDirectoryBlocks;
30 uint32_t BlockMapOffset;
31 std::vector<support::ulittle32_t> DirectoryBlocks;
31 std::vector<uint32_t> DirectoryBlocks;
3232 uint32_t NumStreams;
3333 uint32_t FileSize;
3434 };
3535
3636 struct StreamBlockList {
37 std::vector<support::ulittle32_t> Blocks;
37 std::vector<uint32_t> Blocks;
3838 };
3939
4040 struct PdbInfoStream {
5656
5757 struct PdbObject {
5858 Optional Headers;
59 Optionalsupport::ulittle32_t>> StreamSizes;
59 Optionaluint32_t>> StreamSizes;
6060 Optional> StreamMap;
6161 Optional PdbStream;
6262 Optional DbiStream;
7676 static void mapping(IO &IO, pdb::yaml::MsfHeaders &Obj);
7777 };
7878
79 template <> struct MappingTraits {
80 static void mapping(IO &IO, pdb::PDBFile::SuperBlock &SB);
79 template <> struct MappingTraits {
80 static void mapping(IO &IO, pdb::msf::SuperBlock &SB);
8181 };
8282
8383 template <> struct MappingTraits {
9494 }
9595 }
9696
97 LLVM_YAML_IS_SEQUENCE_VECTOR(support::ulittle32_t)
97 LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t)
9898 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::pdb::yaml::StreamBlockList)
9999
100100 #endif // LLVM_TOOLS_LLVMPDBDUMP_PDBYAML_H
2222 YAMLOutputStyle::YAMLOutputStyle(PDBFile &File) : File(File), Out(outs()) {}
2323
2424 Error YAMLOutputStyle::dump() {
25 if (opts::pdb2yaml::StreamDirectory || opts::pdb2yaml::PdbStream ||
26 opts::pdb2yaml::DbiStream)
25 if (opts::pdb2yaml::StreamDirectory)
2726 opts::pdb2yaml::StreamMetadata = true;
2827
2928 if (auto EC = dumpFileHeaders())
5352 Obj.Headers.emplace();
5453 Obj.Headers->SuperBlock.NumBlocks = File.getBlockCount();
5554 Obj.Headers->SuperBlock.BlockMapAddr = File.getBlockMapIndex();
56 Obj.Headers->BlockMapOffset = File.getBlockMapOffset();
5755 Obj.Headers->SuperBlock.BlockSize = File.getBlockSize();
5856 auto Blocks = File.getDirectoryBlockArray();
5957 Obj.Headers->DirectoryBlocks.assign(Blocks.begin(), Blocks.end());
7270 if (!opts::pdb2yaml::StreamMetadata)
7371 return Error::success();
7472
75 Obj.StreamSizes = File.getStreamSizes();
73 Obj.StreamSizes.emplace();
74 Obj.StreamSizes->assign(File.getStreamSizes().begin(),
75 File.getStreamSizes().end());
7676 return Error::success();
7777 }
7878
8484 Obj.StreamMap.emplace();
8585 for (auto &Stream : StreamMap) {
8686 pdb::yaml::StreamBlockList BlockList;
87 BlockList.Blocks = Stream;
87 BlockList.Blocks.assign(Stream.begin(), Stream.end());
8888 Obj.StreamMap->push_back(BlockList);
8989 }
9090
278278 "stream-directory",
279279 cl::desc("Dump each stream's block map (implies -stream-metadata)"),
280280 cl::sub(PdbToYamlSubcommand), cl::init(false));
281 cl::opt PdbStream(
282 "pdb-stream",
283 cl::desc("Dump the PDB Stream (Stream 1) (implies -stream-metadata)"),
284 cl::sub(PdbToYamlSubcommand), cl::init(false));
285 cl::opt DbiStream(
286 "dbi-stream",
287 cl::desc("Dump the DBI Stream (Stream 2) (implies -stream-metadata)"),
288 cl::sub(PdbToYamlSubcommand), cl::init(false));
281 cl::opt PdbStream("pdb-stream",
282 cl::desc("Dump the PDB Stream (Stream 1)"),
283 cl::sub(PdbToYamlSubcommand), cl::init(false));
284 cl::opt DbiStream("dbi-stream",
285 cl::desc("Dump the DBI Stream (Stream 2)"),
286 cl::sub(PdbToYamlSubcommand), cl::init(false));
289287
290288 cl::list InputFilename(cl::Positional,
291289 cl::desc(""), cl::Required,
323321 llvm::make_unique(std::move(*OutFileOrError));
324322 PDBFileBuilder Builder(std::move(FileByteStream));
325323
326 ExitOnErr(Builder.setSuperBlock(YamlObj.Headers->SuperBlock));
327 if (YamlObj.StreamSizes.hasValue()) {
328 Builder.setStreamSizes(YamlObj.StreamSizes.getValue());
329 }
330 Builder.setDirectoryBlocks(YamlObj.Headers->DirectoryBlocks);
324 ExitOnErr(Builder.initialize(YamlObj.Headers->SuperBlock));
325 ExitOnErr(Builder.getMsfBuilder().setDirectoryBlocksHint(
326 YamlObj.Headers->DirectoryBlocks));
327 if (!YamlObj.StreamSizes.hasValue()) {
328 ExitOnErr(make_error(
329 generic_error_code::unspecified,
330 "Cannot generate a PDB when stream sizes are not known"));
331 }
331332
332333 if (YamlObj.StreamMap.hasValue()) {
333 std::vector> StreamMap;
334 for (auto &E : YamlObj.StreamMap.getValue()) {
335 StreamMap.push_back(E.Blocks);
336 }
337 Builder.setStreamMap(StreamMap);
334 if (YamlObj.StreamMap->size() != YamlObj.StreamSizes->size()) {
335 ExitOnErr(make_error(generic_error_code::unspecified,
336 "YAML specifies different number of "
337 "streams in stream sizes and stream "
338 "map"));
339 }
340
341 auto &Sizes = *YamlObj.StreamSizes;
342 auto &Map = *YamlObj.StreamMap;
343 for (uint32_t I = 0; I < Sizes.size(); ++I) {
344 uint32_t Size = Sizes[I];
345 std::vector Blocks;
346 for (auto E : Map[I].Blocks)
347 Blocks.push_back(E);
348 ExitOnErr(Builder.getMsfBuilder().addStream(Size, Blocks));
349 }
338350 } else {
339 ExitOnErr(Builder.generateSimpleStreamMap());
351 auto &Sizes = *YamlObj.StreamSizes;
352 for (auto S : Sizes) {
353 ExitOnErr(Builder.getMsfBuilder().addStream(S));
354 }
340355 }
341356
342357 if (YamlObj.PdbStream.hasValue()) {
8383 // Allocate some extra blocks at the end so we can verify that they're free
8484 // after the initialization.
8585 std::vector Blocks = {2, 3, 4, 5, 6, 7, 8, 9, 10};
86 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096, Blocks.size() + 10);
86 auto ExpectedMsf =
87 MsfBuilder::create(Allocator, 4096, 2 + Blocks.size() + 10);
8788 EXPECT_EXPECTED(ExpectedMsf);
8889 auto &Msf = *ExpectedMsf;
8990
266267 }
267268 }
268269
269 TEST_F(MsfBuilderTest, TestBuildMsfLayout) {
270 TEST_F(MsfBuilderTest, BuildMsfLayout) {
270271 // Test that we can generate an Msf Layout structure from a valid layout
271272 // specification.
272273 auto ExpectedMsf = MsfBuilder::create(Allocator, 4096);
297298 EXPECT_EQ(ExpectedNumBlocks, L.StreamMap[I].size());
298299 }
299300 }
301
302 TEST_F(MsfBuilderTest, UseDirectoryBlockHint) {
303 Expected ExpectedMsf =
304 MsfBuilder::create(Allocator, 4096, 4, false);
305 EXPECT_EXPECTED(ExpectedMsf);
306 auto &Msf = *ExpectedMsf;
307
308 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
309 EXPECT_NO_ERROR(Msf.addStream(2048, {3}));
310
311 auto ExpectedLayout = Msf.build();
312 EXPECT_EXPECTED(ExpectedLayout);
313 Layout &L = *ExpectedLayout;
314 EXPECT_EQ(4U, L.SB->NumBlocks);
315 EXPECT_EQ(1U, L.DirectoryBlocks.size());
316 EXPECT_EQ(1U, L.StreamMap[0].size());
317
318 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
319 EXPECT_EQ(3U, L.StreamMap[0].front());
320 }
321
322 TEST_F(MsfBuilderTest, DirectoryBlockHintInsufficient) {
323 Expected ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
324 EXPECT_EXPECTED(ExpectedMsf);
325 auto &Msf = *ExpectedMsf;
326
327 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2}));
328
329 uint32_t Size = 4096 * 4096 / 4;
330 EXPECT_NO_ERROR(Msf.addStream(Size));
331
332 auto ExpectedLayout = Msf.build();
333 EXPECT_EXPECTED(ExpectedLayout);
334 Layout &L = *ExpectedLayout;
335 EXPECT_EQ(2U, L.DirectoryBlocks.size());
336 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
337 }
338
339 TEST_F(MsfBuilderTest, DirectoryBlockHintOverestimated) {
340 Expected ExpectedMsf = MsfBuilder::create(Allocator, 4096, 4);
341 EXPECT_EXPECTED(ExpectedMsf);
342 auto &Msf = *ExpectedMsf;
343
344 EXPECT_NO_ERROR(Msf.setDirectoryBlocksHint({2, 3}));
345
346 EXPECT_NO_ERROR(Msf.addStream(2048));
347
348 auto ExpectedLayout = Msf.build();
349 EXPECT_EXPECTED(ExpectedLayout);
350 Layout &L = *ExpectedLayout;
351 EXPECT_EQ(1U, L.DirectoryBlocks.size());
352 EXPECT_EQ(2U, L.DirectoryBlocks[0]);
353 }