Index: include/llvm/DebugInfo/PDB/DIA/DIASession.h =================================================================== --- include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -13,6 +13,8 @@ #include "DIASupport.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include + namespace llvm { class StringRef; @@ -21,10 +23,10 @@ public: explicit DIASession(CComPtr DiaSession); - static PDB_ErrorCode createFromPdb(StringRef Path, - std::unique_ptr &Session); - static PDB_ErrorCode createFromExe(StringRef Path, - std::unique_ptr &Session); + static std::error_code createFromPdb(StringRef Path, + std::unique_ptr &Session); + static std::error_code createFromExe(StringRef Path, + std::unique_ptr &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; Index: include/llvm/DebugInfo/PDB/Error.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Error.h @@ -0,0 +1,51 @@ +//===- Error.h - system_error extensions for PDB ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_DEBUGINFO_PDB_ERROR_H +#define LLVM_DEBUGINFO_PDB_ERROR_H + +#include + +namespace llvm { + namespace pdb { + const std::error_category &pdb_category(); + + enum class pdb_error { + // Error code 0 is absent. Use std::error_code() instead. + dia_not_present, + could_not_create_impl, + invalid_path, + invalid_file_format, + invalid_parameter, + already_loaded, + unknown_error, + no_memory, + debug_info_mismatch, + invalid_msf_header, + invalid_pdb_header, + invalid_dbi_header, + invalid_tpi_header, + unsupported_pdb_version, + unsupported_dbi_version, + unsupported_tpi_version, + unsupported_msf_block_size, + stream_not_aligned, + unexpected_stream_bytes, + corrupt_hash_table, + unsupported_hash_version, + corrupt_name_map, + corrupt_file, + }; + + inline std::error_code make_error_code(pdb_error e) { + return std::error_code(static_cast(e), pdb_category()); + } + } +} +#endif Index: include/llvm/DebugInfo/PDB/PDB.h =================================================================== --- include/llvm/DebugInfo/PDB/PDB.h +++ include/llvm/DebugInfo/PDB/PDB.h @@ -12,17 +12,18 @@ #include "PDBTypes.h" #include +#include namespace llvm { class StringRef; namespace pdb { -PDB_ErrorCode loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); +std::error_code loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session); -PDB_ErrorCode loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); +std::error_code loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session); } } #endif Index: include/llvm/DebugInfo/PDB/PDBTypes.h =================================================================== --- include/llvm/DebugInfo/PDB/PDBTypes.h +++ include/llvm/DebugInfo/PDB/PDBTypes.h @@ -318,19 +318,6 @@ enum class PDB_MemberAccess { Private = 1, Protected = 2, Public = 3 }; -enum class PDB_ErrorCode { - Success, - NoDiaSupport, - CouldNotCreateImpl, - InvalidPath, - InvalidFileFormat, - InvalidParameter, - AlreadyLoaded, - UnknownError, - NoMemory, - DebugInfoMismatch -}; - struct VersionInfo { uint32_t Major; uint32_t Minor; Index: include/llvm/DebugInfo/PDB/Raw/RawSession.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/RawSession.h +++ include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -13,6 +13,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include + namespace llvm { namespace pdb { class PDBFile; @@ -22,10 +24,10 @@ explicit RawSession(std::unique_ptr PdbFile); ~RawSession() override; - static PDB_ErrorCode createFromPdb(StringRef Path, - std::unique_ptr &Session); - static PDB_ErrorCode createFromExe(StringRef Path, - std::unique_ptr &Session); + static std::error_code createFromPdb(StringRef Path, + std::unique_ptr &Session); + static std::error_code createFromExe(StringRef Path, + std::unique_ptr &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -42,6 +42,7 @@ list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") add_llvm_library(LLVMDebugInfoPDB + Error.cpp IPDBSourceFile.cpp PDB.cpp PDBContext.cpp Index: lib/DebugInfo/PDB/DIA/DIASession.cpp =================================================================== --- lib/DebugInfo/PDB/DIA/DIASession.cpp +++ lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -7,13 +7,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumDebugStreams.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumLineNumbers.h" #include "llvm/DebugInfo/PDB/DIA/DIAEnumSourceFiles.h" #include "llvm/DebugInfo/PDB/DIA/DIARawSymbol.h" -#include "llvm/DebugInfo/PDB/DIA/DIASession.h" #include "llvm/DebugInfo/PDB/DIA/DIASourceFile.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/ConvertUTF.h" @@ -25,16 +26,16 @@ namespace { -PDB_ErrorCode LoadDIA(CComPtr &DiaDataSource) { +std::error_code LoadDIA(CComPtr &DiaDataSource) { if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, IID_IDiaDataSource, reinterpret_cast(&DiaDataSource)))) - return PDB_ErrorCode::Success; + return std::error_code(); // If the CoCreateInstance call above failed, msdia*.dll is not registered. // Try loading the DLL corresponding to the #included DIA SDK. #if !defined(_MSC_VER) - return PDB_ErrorCode::NoDiaSupport; + return make_error_code(pdb_error::dia_not_present); #endif const wchar_t *msdia_dll = nullptr; @@ -48,96 +49,98 @@ if (SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, reinterpret_cast(&DiaDataSource)))) - return PDB_ErrorCode::Success; + return std::error_code(); else - return PDB_ErrorCode::CouldNotCreateImpl; + return make_error_code(pdb_error::could_not_create_impl); } } DIASession::DIASession(CComPtr DiaSession) : Session(DiaSession) {} -PDB_ErrorCode DIASession::createFromPdb(StringRef Path, - std::unique_ptr &Session) { +std::error_code +DIASession::createFromPdb(StringRef Path, + std::unique_ptr &Session) { CComPtr DiaDataSource; CComPtr DiaSession; // We assume that CoInitializeEx has already been called by the executable. - PDB_ErrorCode result = LoadDIA(DiaDataSource); - if (result != PDB_ErrorCode::Success) + std::error_code result = LoadDIA(DiaDataSource); + if (result) return result; llvm::SmallVector Path16; if (!llvm::convertUTF8ToUTF16String(Path, Path16)) - return PDB_ErrorCode::InvalidPath; + return make_error_code(pdb_error::invalid_path); const wchar_t *Path16Str = reinterpret_cast(Path16.data()); HRESULT Result; if (FAILED(Result = DiaDataSource->loadDataFromPdb(Path16Str))) { if (Result == E_PDB_NOT_FOUND) - return PDB_ErrorCode::InvalidPath; + return make_error_code(pdb_error::invalid_path); else if (Result == E_PDB_FORMAT) - return PDB_ErrorCode::InvalidFileFormat; + return make_error_code(pdb_error::invalid_file_format); else if (Result == E_INVALIDARG) - return PDB_ErrorCode::InvalidParameter; + return make_error_code(pdb_error::invalid_parameter); else if (Result == E_UNEXPECTED) - return PDB_ErrorCode::AlreadyLoaded; + return make_error_code(pdb_error::already_loaded); else - return PDB_ErrorCode::UnknownError; + return make_error_code(pdb_error::unknown_error); } if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) { if (Result == E_OUTOFMEMORY) - return PDB_ErrorCode::NoMemory; + return make_error_code(pdb_error::no_memory); else - return PDB_ErrorCode::UnknownError; + return make_error_code(pdb_error::unknown_error); } Session.reset(new DIASession(DiaSession)); - return PDB_ErrorCode::Success; + return std::error_code(); } -PDB_ErrorCode DIASession::createFromExe(StringRef Path, - std::unique_ptr &Session) { +std::error_code +DIASession::createFromExe(StringRef Path, + std::unique_ptr &Session) { CComPtr DiaDataSource; CComPtr DiaSession; // We assume that CoInitializeEx has already been called by the executable. - PDB_ErrorCode result = LoadDIA(DiaDataSource); - if (result != PDB_ErrorCode::Success) + std::error_code result = LoadDIA(DiaDataSource); + if (result) return result; llvm::SmallVector Path16; if (!llvm::convertUTF8ToUTF16String(Path, Path16)) - return PDB_ErrorCode::InvalidPath; + return make_error_code(pdb_error::invalid_path); const wchar_t *Path16Str = reinterpret_cast(Path16.data()); HRESULT Result; if (FAILED(Result = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) { if (Result == E_PDB_NOT_FOUND) - return PDB_ErrorCode::InvalidPath; + return make_error_code(pdb_error::invalid_path); else if (Result == E_PDB_FORMAT) - return PDB_ErrorCode::InvalidFileFormat; + return make_error_code(pdb_error::invalid_file_format); else if (Result == E_PDB_INVALID_SIG || Result == E_PDB_INVALID_AGE) - return PDB_ErrorCode::DebugInfoMismatch; + return make_error_code(pdb_error::debug_info_mismatch); else if (Result == E_INVALIDARG) - return PDB_ErrorCode::InvalidParameter; + return make_error_code(pdb_error::invalid_parameter); else if (Result == E_UNEXPECTED) - return PDB_ErrorCode::AlreadyLoaded; + return make_error_code(pdb_error::already_loaded); else - return PDB_ErrorCode::UnknownError; + return make_error_code(pdb_error::unknown_error); } if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) { if (Result == E_OUTOFMEMORY) - return PDB_ErrorCode::NoMemory; + return make_error_code(pdb_error::no_memory); else - return PDB_ErrorCode::UnknownError; + return make_error_code(pdb_error::unknown_error); } Session.reset(new DIASession(DiaSession)); - return PDB_ErrorCode::Success; + return std::error_code(); } uint64_t DIASession::getLoadAddress() const { Index: lib/DebugInfo/PDB/Error.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/Error.cpp @@ -0,0 +1,88 @@ +//===- Error.cpp - system_error extensions for PDB --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/DebugInfo/PDB/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace pdb; + +namespace { +class _pdb_error_category : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override; + std::string message(int ev) const override; +}; +} + +const char *_pdb_error_category::name() const LLVM_NOEXCEPT { + return "llvm.pdb"; +} + +std::string _pdb_error_category::message(int EV) const { + pdb_error E = static_cast(EV); + switch (E) { + case pdb_error::dia_not_present: + return "LLVM was not compiled with support for DIA. This usually means " + "that either LLVM was not compiled with MSVC, or your MSVC " + "installation is corrupt."; + case pdb_error::could_not_create_impl: + return "Failed to connect to DIA at runtime. Verify that Visual Studio " + "is properly installed, or that msdiaXX.dll is in your PATH."; + case pdb_error::invalid_path: + return "Unable to load PDB. Check that the file exists and is readable."; + case pdb_error::invalid_file_format: + return "Unable to load PDB. The file has an unrecognized format."; + case pdb_error::invalid_parameter: + return "The parameter is incorrect."; + case pdb_error::already_loaded: + return "Unable to load the PDB or EXE, because it is already loaded."; + case pdb_error::unknown_error: + return "An unknown error occurred."; + case pdb_error::no_memory: + return "No memory available for the requested operation."; + case pdb_error::debug_info_mismatch: + return "The PDB file and the EXE file do not match."; + case pdb_error::invalid_msf_header: + return "The MSF superblock is in an invalid format."; + case pdb_error::invalid_pdb_header: + return "The PDB file superblock is in an unrecognized format."; + case pdb_error::invalid_dbi_header: + return "The DBI stream header is in an unrecognized format."; + case pdb_error::invalid_tpi_header: + return "The TPI stream header is in an unrecognized format."; + case pdb_error::unsupported_pdb_version: + return "The PDB stream is for an unsupported version."; + case pdb_error::unsupported_dbi_version: + return "The DBI stream is for an unsupported version."; + case pdb_error::unsupported_tpi_version: + return "The TPI stream is for an unsupported version."; + case pdb_error::corrupt_file: + return "The file is corrupted."; + case pdb_error::unsupported_msf_block_size: + return "The MSF file format does not support the specified block size."; + case pdb_error::stream_not_aligned: + return "A stream is not properly aligned."; + case pdb_error::unexpected_stream_bytes: + return "There were unexpected bytes at the end of a stream."; + case pdb_error::corrupt_hash_table: + return "The serialized hash table is corrupted."; + case pdb_error::corrupt_name_map: + return "The serialized name map is corrupted."; + case pdb_error::unsupported_hash_version: + return "The specified hash version is unsupported."; + } + llvm_unreachable("An enumerator of object_error does not have a message " + "defined."); +} + +static ManagedStatic<_pdb_error_category> error_category; + +const std::error_category &pdb::pdb_category() { return *error_category; } Index: lib/DebugInfo/PDB/PDB.cpp =================================================================== --- lib/DebugInfo/PDB/PDB.cpp +++ lib/DebugInfo/PDB/PDB.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" @@ -22,8 +23,9 @@ using namespace llvm; using namespace llvm::pdb; -PDB_ErrorCode llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session) { +std::error_code +llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session) { // Create the correct concrete instance type based on the value of Type. if (Type == PDB_ReaderType::Raw) return RawSession::createFromPdb(Path, Session); @@ -31,12 +33,13 @@ #if HAVE_DIA_SDK return DIASession::createFromPdb(Path, Session); #else - return PDB_ErrorCode::NoDiaSupport; + return make_error_code(pdb_error::dia_not_present); #endif } -PDB_ErrorCode llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session) { +std::error_code +llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session) { // Create the correct concrete instance type based on the value of Type. if (Type == PDB_ReaderType::Raw) return RawSession::createFromExe(Path, Session); @@ -44,6 +47,6 @@ #if HAVE_DIA_SDK return DIASession::createFromExe(Path, Session); #else - return PDB_ErrorCode::NoDiaSupport; + return make_error_code(pdb_error::dia_not_present); #endif } Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" + +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" @@ -83,43 +85,44 @@ Header.reset(new HeaderInfo()); if (Stream.getLength() < sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_dbi_header); Reader.readObject(Header.get()); if (Header->VersionSignature != -1) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_dbi_header); // Require at least version 7, which should be present in all PDBs // produced in the last decade and allows us to avoid having to // special case all kinds of complicated arcane formats. if (Header->VersionHeader < PdbDbiV70) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::unsupported_dbi_version); if (Header->Age != Pdb.getPDBInfoStream().getAge()) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_dbi_header); if (Stream.getLength() != sizeof(HeaderInfo) + Header->ModiSubstreamSize + Header->SecContrSubstreamSize + Header->SectionMapSize + Header->FileInfoSize + Header->TypeServerSize + Header->OptionalDbgHdrSize + Header->ECSubstreamSize) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_dbi_header); // Only certain substreams are guaranteed to be aligned. Validate // them here. if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::stream_not_aligned); if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::stream_not_aligned); if (Header->SectionMapSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::stream_not_aligned); if (Header->FileInfoSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::stream_not_aligned); if (Header->TypeServerSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::stream_not_aligned); std::error_code EC; - ModInfoSubstream.initialize(Reader, Header->ModiSubstreamSize); + if ((EC = ModInfoSubstream.initialize(Reader, Header->ModiSubstreamSize))) + return EC; // Since each ModInfo in the stream is a variable length, we have to iterate // them to know how many there actually are. @@ -147,7 +150,7 @@ return EC; if (Reader.bytesRemaining() > 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::unexpected_stream_bytes); StreamReader ECReader(ECSubstream); ECNames.load(ECReader); @@ -221,7 +224,7 @@ // The number of modules in the stream should be the same as reported by // the FileInfoSubstreamHeader. if (FI->NumModules != ModuleInfos.size()) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_dbi_header); // First is an array of `NumModules` module indices. This is not used for the // same reason that `NumSourceFiles` is not used. It's an array of uint16's, Index: lib/DebugInfo/PDB/Raw/InfoStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" @@ -29,19 +30,18 @@ }; Header H; - Reader.readObject(&H); + if (auto EC = Reader.readObject(&H)) + return make_error_code(pdb_error::invalid_pdb_header); if (H.Version < PdbRaw_ImplVer::PdbImplVC70) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::unsupported_pdb_version); Version = H.Version; Signature = H.Signature; Age = H.Age; Guid = H.Guid; - NamedStreams.load(Reader); - - return std::error_code(); + return NamedStreams.load(Reader); } uint32_t InfoStream::getNamedStreamIndex(llvm::StringRef Name) const { Index: lib/DebugInfo/PDB/Raw/NameHashTable.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -10,6 +10,7 @@ #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/ByteStream.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" #include "llvm/Support/Endian.h" @@ -90,22 +91,24 @@ Header H; Stream.readObject(&H); if (H.Signature != 0xEFFEEFFE) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::corrupt_hash_table); if (H.HashVersion != 1 && H.HashVersion != 2) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::unsupported_hash_version); Signature = H.Signature; HashVersion = H.HashVersion; - NamesBuffer.initialize(Stream, H.ByteSize); + if (auto EC = NamesBuffer.initialize(Stream, H.ByteSize)) + return make_error_code(pdb_error::corrupt_hash_table); support::ulittle32_t HashCount; Stream.readObject(&HashCount); std::vector BucketArray(HashCount); - Stream.readArray(BucketArray); + if (auto EC = Stream.readArray(BucketArray)) + return make_error_code(pdb_error::corrupt_hash_table); IDs.assign(BucketArray.begin(), BucketArray.end()); if (Stream.bytesRemaining() < sizeof(support::ulittle32_t)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::corrupt_hash_table); Stream.readInteger(NameCount); return std::error_code(); Index: lib/DebugInfo/PDB/Raw/NameMap.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/NameMap.cpp +++ lib/DebugInfo/PDB/Raw/NameMap.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Raw/NameMap.h" #include "llvm/ADT/BitVector.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" using namespace llvm; @@ -21,7 +22,10 @@ // This is some sort of weird string-set/hash table encoded in the stream. // It starts with the number of bytes in the table. uint32_t NumberOfBytes; - Stream.readInteger(NumberOfBytes); + if (Stream.readInteger(NumberOfBytes)) + return make_error_code(pdb_error::corrupt_name_map); + if (Stream.bytesRemaining() < NumberOfBytes) + return make_error_code(pdb_error::corrupt_name_map); // Following that field is the starting offset of strings in the name table. uint32_t StringsOffset = Stream.getOffset(); @@ -30,36 +34,44 @@ // This appears to be equivalent to the total number of strings *actually* // in the name table. uint32_t HashSize; - Stream.readInteger(HashSize); + if (Stream.readInteger(HashSize)) + return make_error_code(pdb_error::corrupt_name_map); // This appears to be an upper bound on the number of strings in the name // table. uint32_t MaxNumberOfStrings; - Stream.readInteger(MaxNumberOfStrings); + if (Stream.readInteger(MaxNumberOfStrings)) + return make_error_code(pdb_error::corrupt_name_map); // This appears to be a hash table which uses bitfields to determine whether // or not a bucket is 'present'. uint32_t NumPresentWords; - Stream.readInteger(NumPresentWords); + if (Stream.readInteger(NumPresentWords)) + return make_error_code(pdb_error::corrupt_name_map); // Store all the 'present' bits in a vector for later processing. SmallVector PresentWords; for (uint32_t I = 0; I != NumPresentWords; ++I) { uint32_t Word; - Stream.readInteger(Word); + if (Stream.readInteger(Word)) + return make_error_code(pdb_error::corrupt_name_map); + PresentWords.push_back(Word); } // This appears to be a hash table which uses bitfields to determine whether // or not a bucket is 'deleted'. uint32_t NumDeletedWords; - Stream.readInteger(NumDeletedWords); + if (Stream.readInteger(NumDeletedWords)) + return make_error_code(pdb_error::corrupt_name_map); // Store all the 'deleted' bits in a vector for later processing. SmallVector DeletedWords; for (uint32_t I = 0; I != NumDeletedWords; ++I) { uint32_t Word; - Stream.readInteger(Word); + if (Stream.readInteger(Word)) + return make_error_code(pdb_error::corrupt_name_map); + DeletedWords.push_back(Word); } @@ -79,11 +91,13 @@ // This appears to be an offset relative to the start of the strings. // It tells us where the null-terminated string begins. uint32_t NameOffset; - Stream.readInteger(NameOffset); + if (Stream.readInteger(NameOffset)) + return make_error_code(pdb_error::corrupt_name_map); // This appears to be a stream number into the stream directory. uint32_t NameIndex; - Stream.readInteger(NameIndex); + if (Stream.readInteger(NameIndex)) + return make_error_code(pdb_error::corrupt_name_map); // Compute the offset of the start of the string relative to the stream. uint32_t StringOffset = StringsOffset + NameOffset; @@ -91,7 +105,8 @@ // Pump out our c-string from the stream. std::string Str; Stream.setOffset(StringOffset); - Stream.readZeroString(Str); + if (Stream.readZeroString(Str)) + return make_error_code(pdb_error::corrupt_name_map); Stream.setOffset(OldOffset); // Add this to a string-map from name to stream number. Index: lib/DebugInfo/PDB/Raw/PDBFile.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" @@ -123,32 +124,33 @@ // Make sure the file is sufficiently large to hold a super block. // Do this before attempting to read the super block. if (BufferRef.getBufferSize() < sizeof(SuperBlock)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_msf_header); Context->SB = reinterpret_cast(BufferRef.getBufferStart()); const SuperBlock *SB = Context->SB; + if (BufferRef.getBufferSize() % SB->BlockSize != 0) + return make_error_code(pdb_error::invalid_msf_header); + + // Check the magic bytes. + if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) + return make_error_code(pdb_error::invalid_msf_header); + switch (SB->BlockSize) { case 512: case 1024: case 2048: case 4096: break; default: // An invalid block size suggests a corrupt PDB file. - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::unsupported_msf_block_size); } - if (BufferRef.getBufferSize() % SB->BlockSize != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); - - // Check the magic bytes. - if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); // We don't support blocksizes which aren't a multiple of four bytes. if (SB->BlockSize == 0 || SB->BlockSize % sizeof(support::ulittle32_t) != 0) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::unsupported_msf_block_size); // We don't support directories whose sizes aren't a multiple of four bytes. if (SB->NumDirectoryBytes % sizeof(support::ulittle32_t) != 0) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::invalid_msf_header); // The number of blocks which comprise the directory is a simple function of // the number of bytes it contains. @@ -159,7 +161,7 @@ // It is unclear what would happen if the number of blocks couldn't fit on a // single block. if (NumDirectoryBlocks > SB->BlockSize / sizeof(support::ulittle32_t)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_msf_header); return std::error_code(); } Index: lib/DebugInfo/PDB/Raw/RawSession.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/RawSession.cpp +++ lib/DebugInfo/PDB/Raw/RawSession.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/RawSession.h" + +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" @@ -25,8 +27,9 @@ RawSession::~RawSession() {} -PDB_ErrorCode RawSession::createFromPdb(StringRef Path, - std::unique_ptr &Session) { +std::error_code +RawSession::createFromPdb(StringRef Path, + std::unique_ptr &Session) { ErrorOr> ErrorOrBuffer = MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, @@ -34,24 +37,25 @@ std::error_code EC; if ((EC = ErrorOrBuffer.getError())) - return PDB_ErrorCode::CouldNotCreateImpl; + return make_error_code(pdb_error::invalid_path); std::unique_ptr &Buffer = ErrorOrBuffer.get(); std::unique_ptr File(new PDBFile(std::move(Buffer))); if ((EC = File->parseFileHeaders())) - return PDB_ErrorCode::InvalidFileFormat; + return EC; if ((EC = File->parseStreamData())) - return PDB_ErrorCode::InvalidFileFormat; + return EC; Session.reset(new RawSession(std::move(File))); - return PDB_ErrorCode::Success; + return std::error_code(); } -PDB_ErrorCode RawSession::createFromExe(StringRef Path, - std::unique_ptr &Session) { - return PDB_ErrorCode::CouldNotCreateImpl; +std::error_code +RawSession::createFromExe(StringRef Path, + std::unique_ptr &Session) { + return make_error_code(pdb_error::could_not_create_impl); } uint64_t RawSession::getLoadAddress() const { return 0; } Index: lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -11,6 +11,7 @@ #include "llvm/DebugInfo/CodeView/CodeView.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" +#include "llvm/DebugInfo/PDB/Error.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" @@ -64,23 +65,23 @@ StreamReader Reader(Stream); if (Reader.bytesRemaining() < sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_tpi_header); Header.reset(new HeaderInfo()); Reader.readObject(Header.get()); if (Header->Version != PdbTpiV80) - return std::make_error_code(std::errc::not_supported); + return make_error_code(pdb_error::unsupported_tpi_version); if (Header->HeaderSize != sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_tpi_header); if (Header->HashKeySize != sizeof(ulittle32_t)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_tpi_header); if (Header->NumHashBuckets < MinHashBuckets || Header->NumHashBuckets > MaxHashBuckets) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error_code(pdb_error::invalid_tpi_header); HashFunction = HashBufferV8; Index: lib/DebugInfo/Symbolize/Symbolize.cpp =================================================================== --- lib/DebugInfo/Symbolize/Symbolize.cpp +++ lib/DebugInfo/Symbolize/Symbolize.cpp @@ -371,9 +371,9 @@ // If this is a COFF object, assume it contains PDB debug information. If // we don't find any we will fall back to the DWARF case. std::unique_ptr Session; - PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA, - Objects.first->getFileName(), Session); - if (Error == PDB_ErrorCode::Success) { + std::error_code Error = loadDataForEXE( + PDB_ReaderType::DIA, Objects.first->getFileName(), Session); + if (!Error) { Context.reset(new PDBContext(*CoffObject, std::move(Session))); } } Index: test/DebugInfo/PDB/pdbdump-headers.test =================================================================== --- test/DebugInfo/PDB/pdbdump-headers.test +++ test/DebugInfo/PDB/pdbdump-headers.test @@ -1238,4 +1238,4 @@ ; BIG-NEXT: ] ; BIG-NEXT: } -; BAD-BLOCK-SIZE: The file has an unrecognized format. +; BAD-BLOCK-SIZE: The MSF superblock is in an invalid format. Index: tools/llvm-pdbdump/llvm-pdbdump.cpp =================================================================== --- tools/llvm-pdbdump/llvm-pdbdump.cpp +++ tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -356,50 +356,27 @@ dumpTpiStream(P, File); } -static void reportError(StringRef Path, PDB_ErrorCode Error) { - switch (Error) { - case PDB_ErrorCode::Success: - break; - case PDB_ErrorCode::NoDiaSupport: - outs() << "LLVM was not compiled with support for DIA. This usually means " - "that either LLVM was not compiled with MSVC, or your MSVC " - "installation is corrupt.\n"; - return; - case PDB_ErrorCode::CouldNotCreateImpl: - outs() << "Failed to connect to DIA at runtime. Verify that Visual Studio " - "is properly installed, or that msdiaXX.dll is in your PATH.\n"; - return; - case PDB_ErrorCode::InvalidPath: - outs() << "Unable to load PDB at '" << Path - << "'. Check that the file exists and is readable.\n"; - return; - case PDB_ErrorCode::InvalidFileFormat: - outs() << "Unable to load PDB at '" << Path - << "'. The file has an unrecognized format.\n"; - return; - default: - outs() << "Unable to load PDB at '" << Path - << "'. An unknown error occured.\n"; - return; - } +static void reportError(StringRef Path, std::error_code Error) { + if (Error) + outs() << "An error occurred on file '" << Path << "'. " << Error.message() + << "\n"; } static void dumpInput(StringRef Path) { std::unique_ptr Session; if (opts::DumpHeaders || !opts::DumpStreamData.empty()) { - PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::Raw, Path, Session); - if (Error == PDB_ErrorCode::Success) { + std::error_code Error = loadDataForPDB(PDB_ReaderType::Raw, Path, Session); + if (!Error) { RawSession *RS = static_cast(Session.get()); dumpStructure(*RS); } reportError(Path, Error); - outs().flush(); return; } - PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); - if (Error != PDB_ErrorCode::Success) { + std::error_code Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); + if (Error) { reportError(Path, Error); return; }