diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -31,6 +31,7 @@ #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/MSF/MSFError.h" #include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" @@ -1687,6 +1688,12 @@ // the user can see the output of /time and /summary, which is very helpful // when trying to figure out why a PDB file is too large. if (Error e = builder.commit(ctx.config.pdbPath, guid)) { + e = handleErrors(std::move(e), + [](const llvm::msf::MSFError &me) { + error(me.message()); + if (me.isPageOverflow()) + error("try setting a larger /pdbpagesize"); + }); checkError(std::move(e)); error("failed to write PDB file " + Twine(ctx.config.pdbPath)); } diff --git a/llvm/include/llvm/DebugInfo/MSF/MSFError.h b/llvm/include/llvm/DebugInfo/MSF/MSFError.h --- a/llvm/include/llvm/DebugInfo/MSF/MSFError.h +++ b/llvm/include/llvm/DebugInfo/MSF/MSFError.h @@ -16,14 +16,15 @@ enum class msf_error_code { unspecified = 1, insufficient_buffer, + not_writable, + no_stream, + invalid_format, + block_in_use, size_overflow_4096, size_overflow_8192, size_overflow_16384, size_overflow_32768, - not_writable, - no_stream, - invalid_format, - block_in_use + stream_directory_overflow, }; } // namespace msf } // namespace llvm @@ -46,6 +47,25 @@ public: using ErrorInfo::ErrorInfo; // inherit constructors MSFError(const Twine &S) : ErrorInfo(S, msf_error_code::unspecified) {} + + bool isPageOverflow() const { + switch (static_cast(convertToErrorCode().value())) { + case msf_error_code::unspecified: + case msf_error_code::insufficient_buffer: + case msf_error_code::not_writable: + case msf_error_code::no_stream: + case msf_error_code::invalid_format: + case msf_error_code::block_in_use: + return false; + case msf_error_code::size_overflow_4096: + case msf_error_code::size_overflow_8192: + case msf_error_code::size_overflow_16384: + case msf_error_code::size_overflow_32768: + case msf_error_code::stream_directory_overflow: + return true; + } + } + static char ID; }; } // namespace msf diff --git a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp --- a/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp +++ b/llvm/lib/DebugInfo/MSF/MSFBuilder.cpp @@ -364,6 +364,18 @@ FileSize, Layout.SB->BlockSize)); } + uint64_t NumDirectoryBlocks = + bytesToBlocks(Layout.SB->NumDirectoryBytes, Layout.SB->BlockSize); + uint64_t DirectoryBlockMapSize = + NumDirectoryBlocks * sizeof(support::ulittle32_t); + if (DirectoryBlockMapSize > Layout.SB->BlockSize) { + return make_error(msf_error_code::stream_directory_overflow, + formatv("The directory block map ({0} bytes) " + "doesn't fit in a block ({1} bytes)", + DirectoryBlockMapSize, + Layout.SB->BlockSize)); + } + auto OutFileOrError = FileOutputBuffer::create(Path, FileSize); if (auto EC = OutFileOrError.takeError()) return std::move(EC); diff --git a/llvm/lib/DebugInfo/MSF/MSFError.cpp b/llvm/lib/DebugInfo/MSF/MSFError.cpp --- a/llvm/lib/DebugInfo/MSF/MSFError.cpp +++ b/llvm/lib/DebugInfo/MSF/MSFError.cpp @@ -43,6 +43,8 @@ return "The data is in an unexpected format."; case msf_error_code::block_in_use: return "The block is already in use."; + case msf_error_code::stream_directory_overflow: + return "PDB stream directory too large."; } llvm_unreachable("Unrecognized msf_error_code"); }