Index: include/llvm/DebugInfo/PDB/DIA/DIAError.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/DIA/DIAError.h @@ -0,0 +1,46 @@ +//===- DIAError.h - Error extensions for PDB DIA implementation -*- 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_DIA_DIAERROR_H +#define LLVM_DEBUGINFO_PDB_DIA_DIAERROR_H + +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace pdb { +enum class dia_error_code { + unspecified = 1, + could_not_create_impl, + invalid_file_format, + invalid_parameter, + already_loaded, + debug_info_mismatch, +}; + +/// Base class for errors originating in DIA SDK, e.g. COM calls +class DIAError : public ErrorInfo { +public: + static char ID; + DIAError(dia_error_code C); + DIAError(const std::string &Context); + DIAError(dia_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + dia_error_code Code; +}; +} +} +#endif Index: include/llvm/DebugInfo/PDB/DIA/DIASession.h =================================================================== --- include/llvm/DebugInfo/PDB/DIA/DIASession.h +++ include/llvm/DebugInfo/PDB/DIA/DIASession.h @@ -12,6 +12,9 @@ #include "DIASupport.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" + +#include namespace llvm { class StringRef; @@ -21,10 +24,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 Error createFromPdb(StringRef Path, + std::unique_ptr &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; Index: include/llvm/DebugInfo/PDB/DIA/DIASupport.h =================================================================== --- include/llvm/DebugInfo/PDB/DIA/DIASupport.h +++ include/llvm/DebugInfo/PDB/DIA/DIASupport.h @@ -22,6 +22,17 @@ #define NOMINMAX #endif +// llvm/Support/Debug.h unconditionally #defines DEBUG as a macro. +// DIA headers #define it if it is not already defined, so we have +// an order of includes problem. The real fix is to make LLVM use +// something less generic than DEBUG, such as LLVM_DEBUG(), but it's +// fairly prevalent. So for now, we save the definition state and +// restore it. +#if defined(DEBUG) +#define OLD_DEBUG DEBUG +#undef DEBUG +#endif + // atlbase.h has to come before windows.h #include #include @@ -29,5 +40,17 @@ // DIA headers must come after windows headers. #include #include +#include + +#if defined(OLD_DEBUG) +// Undef DIA's version of DEBUG, then redefine our saved off version. +#if defined(DEBUG) +#undef DEBUG +#endif +#define DEBUG OLD_DEBUG +#undef OLD_DEBUG +#else +#undef DEBUG +#endif #endif // LLVM_DEBUGINFO_PDB_DIA_DIASUPPORT_H Index: include/llvm/DebugInfo/PDB/GenericError.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/GenericError.h @@ -0,0 +1,42 @@ +//===- 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 "llvm/Support/Error.h" + +namespace llvm { +namespace pdb { + +enum class generic_error_code { + invalid_path = 1, + dia_sdk_not_present, + unspecified, +}; + +/// Base class for errors originating when parsing raw PDB files +class GenericError : public ErrorInfo { +public: + static char ID; + GenericError(generic_error_code C); + GenericError(const std::string &Context); + GenericError(generic_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + generic_error_code Code; +}; +} +} +#endif Index: include/llvm/DebugInfo/PDB/PDB.h =================================================================== --- include/llvm/DebugInfo/PDB/PDB.h +++ include/llvm/DebugInfo/PDB/PDB.h @@ -11,18 +11,20 @@ #define LLVM_DEBUGINFO_PDB_PDB_H #include "PDBTypes.h" +#include "llvm/Support/Error.h" #include +#include namespace llvm { class StringRef; namespace pdb { -PDB_ErrorCode loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); +Error loadDataForPDB(PDB_ReaderType Type, StringRef Path, + std::unique_ptr &Session); -PDB_ErrorCode loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session); +Error 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/ByteStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/ByteStream.h +++ include/llvm/DebugInfo/PDB/Raw/ByteStream.h @@ -31,13 +31,13 @@ void reset(); void initialize(MutableArrayRef Bytes); void initialize(uint32_t Length); - std::error_code initialize(StreamReader &Reader, uint32_t Length); + Error initialize(StreamReader &Reader, uint32_t Length); - std::error_code readBytes(uint32_t Offset, - MutableArrayRef Buffer) const override; + Error readBytes(uint32_t Offset, + MutableArrayRef Buffer) const override; - std::error_code getArrayRef(uint32_t Offset, ArrayRef &Buffer, - uint32_t Length) const override; + Error getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const override; uint32_t getLength() const override; Index: include/llvm/DebugInfo/PDB/Raw/DbiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/DbiStream.h +++ include/llvm/DebugInfo/PDB/Raw/DbiStream.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" namespace llvm { namespace pdb { @@ -28,7 +29,7 @@ public: DbiStream(PDBFile &File); ~DbiStream(); - std::error_code reload(); + Error reload(); PdbRaw_DbiVer getDbiVersion() const; uint32_t getAge() const; @@ -49,7 +50,7 @@ ArrayRef modules() const; private: - std::error_code initializeFileInfo(); + Error initializeFileInfo(); PDBFile &Pdb; MappedBlockStream Stream; Index: include/llvm/DebugInfo/PDB/Raw/InfoStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/InfoStream.h +++ include/llvm/DebugInfo/PDB/Raw/InfoStream.h @@ -17,6 +17,7 @@ #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" namespace llvm { namespace pdb { @@ -24,7 +25,7 @@ public: InfoStream(PDBFile &File); - std::error_code reload(); + Error reload(); PdbRaw_ImplVer getVersion() const; uint32_t getSignature() const; Index: include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h +++ include/llvm/DebugInfo/PDB/Raw/MappedBlockStream.h @@ -25,10 +25,10 @@ public: MappedBlockStream(uint32_t StreamIdx, const PDBFile &File); - std::error_code readBytes(uint32_t Offset, - MutableArrayRef Buffer) const override; - std::error_code getArrayRef(uint32_t Offset, ArrayRef &Buffer, - uint32_t Length) const override; + Error readBytes(uint32_t Offset, + MutableArrayRef Buffer) const override; + Error getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const override; uint32_t getLength() const override { return StreamLength; } Index: include/llvm/DebugInfo/PDB/Raw/NameHashTable.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/NameHashTable.h +++ include/llvm/DebugInfo/PDB/Raw/NameHashTable.h @@ -13,6 +13,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/Raw/ByteStream.h" +#include "llvm/Support/Error.h" #include #include @@ -24,7 +25,7 @@ public: NameHashTable(); - std::error_code load(StreamReader &Stream); + Error load(StreamReader &Stream); uint32_t getNameCount() const { return NameCount; } uint32_t getHashVersion() const { return HashVersion; } Index: include/llvm/DebugInfo/PDB/Raw/NameMap.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/NameMap.h +++ include/llvm/DebugInfo/PDB/Raw/NameMap.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" #include #include @@ -23,7 +24,7 @@ public: NameMap(); - std::error_code load(StreamReader &Stream); + Error load(StreamReader &Stream); bool tryGetValue(StringRef Name, uint32_t &Value) const; Index: include/llvm/DebugInfo/PDB/Raw/PDBFile.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/PDBFile.h +++ include/llvm/DebugInfo/PDB/Raw/PDBFile.h @@ -12,6 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include "llvm/Support/MathExtras.h" #include @@ -47,8 +48,8 @@ ArrayRef getDirectoryBlockArray(); - std::error_code parseFileHeaders(); - std::error_code parseStreamData(); + Error parseFileHeaders(); + Error parseStreamData(); static uint64_t bytesToBlocks(uint64_t NumBytes, uint64_t BlockSize) { return alignTo(NumBytes, BlockSize) / BlockSize; @@ -58,9 +59,9 @@ return BlockNumber * BlockSize; } - InfoStream &getPDBInfoStream(); - DbiStream &getPDBDbiStream(); - TpiStream &getPDBTpiStream(); + Expected getPDBInfoStream(); + Expected getPDBDbiStream(); + Expected getPDBTpiStream(); private: std::unique_ptr Context; Index: include/llvm/DebugInfo/PDB/Raw/RawError.h =================================================================== --- /dev/null +++ include/llvm/DebugInfo/PDB/Raw/RawError.h @@ -0,0 +1,44 @@ +//===- RawError.h - Error extensions for raw PDB implementation -*- 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_RAW_RAWERROR_H +#define LLVM_DEBUGINFO_PDB_RAW_RAWERROR_H + +#include "llvm/Support/Error.h" + +#include + +namespace llvm { +namespace pdb { +enum class raw_error_code { + unspecified = 1, + feature_unsupported, + corrupt_file, + insufficient_buffer, +}; + +/// Base class for errors originating when parsing raw PDB files +class RawError : public ErrorInfo { +public: + static char ID; + RawError(raw_error_code C); + RawError(const std::string &Context); + RawError(raw_error_code C, const std::string &Context); + + void log(raw_ostream &OS) const override; + const std::string &getErrorMessage() const; + std::error_code convertToErrorCode() const override; + +private: + std::string ErrMsg; + raw_error_code Code; +}; +} +} +#endif Index: include/llvm/DebugInfo/PDB/Raw/RawSession.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/RawSession.h +++ include/llvm/DebugInfo/PDB/Raw/RawSession.h @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/Support/Error.h" namespace llvm { namespace pdb { @@ -22,10 +23,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 Error createFromPdb(StringRef Path, + std::unique_ptr &Session); + static Error createFromExe(StringRef Path, + std::unique_ptr &Session); uint64_t getLoadAddress() const override; void setLoadAddress(uint64_t Address) override; Index: include/llvm/DebugInfo/PDB/Raw/StreamInterface.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/StreamInterface.h +++ include/llvm/DebugInfo/PDB/Raw/StreamInterface.h @@ -11,9 +11,9 @@ #define LLVM_DEBUGINFO_PDB_RAW_STREAMINTERFACE_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include -#include namespace llvm { namespace pdb { @@ -21,11 +21,10 @@ public: virtual ~StreamInterface() {} - virtual std::error_code readBytes(uint32_t Offset, - MutableArrayRef Buffer) const = 0; - virtual std::error_code getArrayRef(uint32_t Offset, - ArrayRef &Buffer, - uint32_t Length) const = 0; + virtual Error readBytes(uint32_t Offset, + MutableArrayRef Buffer) const = 0; + virtual Error getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const = 0; virtual uint32_t getLength() const = 0; }; Index: include/llvm/DebugInfo/PDB/Raw/StreamReader.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/StreamReader.h +++ include/llvm/DebugInfo/PDB/Raw/StreamReader.h @@ -13,9 +13,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/PDB/Raw/StreamInterface.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" #include -#include namespace llvm { namespace pdb { @@ -24,22 +24,22 @@ public: StreamReader(const StreamInterface &S); - std::error_code readBytes(MutableArrayRef Buffer); - std::error_code readInteger(uint32_t &Dest); - std::error_code readZeroString(std::string &Dest); + Error readBytes(MutableArrayRef Buffer); + Error readInteger(uint32_t &Dest); + Error readZeroString(std::string &Dest); - template std::error_code readObject(T *Dest) { + template Error readObject(T *Dest) { MutableArrayRef Buffer(reinterpret_cast(Dest), sizeof(T)); return readBytes(Buffer); } - template std::error_code readArray(MutableArrayRef Array) { + template Error readArray(MutableArrayRef Array) { MutableArrayRef Casted(reinterpret_cast(Array.data()), Array.size() * sizeof(T)); return readBytes(Casted); } - std::error_code getArrayRef(ArrayRef &Array, uint32_t Length); + Error getArrayRef(ArrayRef &Array, uint32_t Length); void setOffset(uint32_t Off) { Offset = Off; } uint32_t getOffset() const { return Offset; } Index: include/llvm/DebugInfo/PDB/Raw/TpiStream.h =================================================================== --- include/llvm/DebugInfo/PDB/Raw/TpiStream.h +++ include/llvm/DebugInfo/PDB/Raw/TpiStream.h @@ -16,6 +16,8 @@ #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/Support/Error.h" + namespace llvm { namespace pdb { class PDBFile; @@ -28,7 +30,7 @@ public: TpiStream(PDBFile &File); ~TpiStream(); - std::error_code reload(); + Error reload(); PdbRaw_TpiVer getTpiVersion() const; Index: lib/DebugInfo/PDB/CMakeLists.txt =================================================================== --- lib/DebugInfo/PDB/CMakeLists.txt +++ lib/DebugInfo/PDB/CMakeLists.txt @@ -17,6 +17,7 @@ DIA/DIAEnumLineNumbers.cpp DIA/DIAEnumSourceFiles.cpp DIA/DIAEnumSymbols.cpp + DIA/DIAError.cpp DIA/DIALineNumber.cpp DIA/DIARawSymbol.cpp DIA/DIASession.cpp @@ -35,6 +36,7 @@ Raw/InfoStream.cpp Raw/NameHashTable.cpp Raw/NameMap.cpp + Raw/RawError.cpp Raw/RawSession.cpp Raw/StreamReader.cpp Raw/TpiStream.cpp) @@ -42,6 +44,7 @@ list(APPEND LIBPDB_ADDITIONAL_HEADER_DIRS "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/PDB") add_llvm_library(LLVMDebugInfoPDB + GenericError.cpp IPDBSourceFile.cpp PDB.cpp PDBContext.cpp Index: lib/DebugInfo/PDB/DIA/DIAError.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/DIA/DIAError.cpp @@ -0,0 +1,56 @@ +#include "llvm/DebugInfo/PDB/DIA/DIAError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +class DIAErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.dia"; } + + std::string message(int Condition) const override { + switch (static_cast(Condition)) { + case dia_error_code::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 dia_error_code::invalid_file_format: + return "Unable to load PDB. The file has an unrecognized format."; + case dia_error_code::invalid_parameter: + return "The parameter is incorrect."; + case dia_error_code::already_loaded: + return "Unable to load the PDB or EXE, because it is already loaded."; + case dia_error_code::debug_info_mismatch: + return "The PDB file and the EXE file do not match."; + case dia_error_code::unspecified: + return "An unknown error has occurred."; + } + llvm_unreachable("Unrecognized DIAErrorCode"); + } +}; + +static ManagedStatic Category; + +char DIAError::ID = 0; + +DIAError::DIAError(dia_error_code C) : DIAError(C, "") {} + +DIAError::DIAError(const std::string &Context) + : DIAError(dia_error_code::unspecified, Context) {} + +DIAError::DIAError(dia_error_code C, const std::string &Context) : Code(C) { + ErrMsg = "DIA Error: "; + std::error_code EC = convertToErrorCode(); + if (Code != dia_error_code::unspecified) + ErrMsg += EC.message() + " "; + if (!Context.empty()) + ErrMsg += Context; +} + +void DIAError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +const std::string &DIAError::getErrorMessage() const { return ErrMsg; } + +std::error_code DIAError::convertToErrorCode() const { + return std::error_code(static_cast(Code), *Category); +} Index: lib/DebugInfo/PDB/DIA/DIASession.cpp =================================================================== --- lib/DebugInfo/PDB/DIA/DIASession.cpp +++ lib/DebugInfo/PDB/DIA/DIASession.cpp @@ -6,35 +6,55 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// - +#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/DIAError.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/DIA/DIASupport.h" +#include "llvm/DebugInfo/PDB/GenericError.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/Support/ConvertUTF.h" -#include - using namespace llvm; using namespace llvm::pdb; namespace { -PDB_ErrorCode LoadDIA(CComPtr &DiaDataSource) { +Error ErrorFromHResult(HRESULT Result) { + switch (Result) { + case E_PDB_NOT_FOUND: + return make_error(generic_error_code::invalid_path); + case E_PDB_FORMAT: + return make_error(dia_error_code::invalid_file_format); + case E_INVALIDARG: + return make_error(dia_error_code::invalid_parameter); + case E_UNEXPECTED: + return make_error(dia_error_code::already_loaded); + case E_PDB_INVALID_SIG: + case E_PDB_INVALID_AGE: + return make_error(dia_error_code::debug_info_mismatch); + default: + return make_error(dia_error_code::unspecified); + } +} + +Error LoadDIA(CComPtr &DiaDataSource) { if (SUCCEEDED(CoCreateInstance(CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, IID_IDiaDataSource, reinterpret_cast(&DiaDataSource)))) - return PDB_ErrorCode::Success; + return Error::success(); - // If the CoCreateInstance call above failed, msdia*.dll is not registered. - // Try loading the DLL corresponding to the #included DIA SDK. +// 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 llvm::make_error( + "DIA is only supported when using MSVC."); #endif const wchar_t *msdia_dll = nullptr; @@ -46,98 +66,65 @@ #error "Unknown Visual Studio version." #endif - if (SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, - reinterpret_cast(&DiaDataSource)))) - return PDB_ErrorCode::Success; - else - return PDB_ErrorCode::CouldNotCreateImpl; + HRESULT HR; + if (FAILED(HR = NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, + reinterpret_cast(&DiaDataSource)))) + return ErrorFromHResult(HR); + return Error::success(); } } DIASession::DIASession(CComPtr DiaSession) : Session(DiaSession) {} -PDB_ErrorCode DIASession::createFromPdb(StringRef Path, - std::unique_ptr &Session) { +Error 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) - return result; + if (auto E = LoadDIA(DiaDataSource)) + return E; llvm::SmallVector Path16; if (!llvm::convertUTF8ToUTF16String(Path, Path16)) - return PDB_ErrorCode::InvalidPath; + return make_error(generic_error_code::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; - else if (Result == E_PDB_FORMAT) - return PDB_ErrorCode::InvalidFileFormat; - else if (Result == E_INVALIDARG) - return PDB_ErrorCode::InvalidParameter; - else if (Result == E_UNEXPECTED) - return PDB_ErrorCode::AlreadyLoaded; - else - return PDB_ErrorCode::UnknownError; - } + HRESULT HR; + if (FAILED(HR = DiaDataSource->loadDataFromPdb(Path16Str))) + return ErrorFromHResult(HR); - if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) { - if (Result == E_OUTOFMEMORY) - return PDB_ErrorCode::NoMemory; - else - return PDB_ErrorCode::UnknownError; - } + if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) + return ErrorFromHResult(HR); Session.reset(new DIASession(DiaSession)); - return PDB_ErrorCode::Success; + return Error::success(); } -PDB_ErrorCode DIASession::createFromExe(StringRef Path, - std::unique_ptr &Session) { +Error 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) - return result; + if (auto EC = LoadDIA(DiaDataSource)) + return EC; llvm::SmallVector Path16; if (!llvm::convertUTF8ToUTF16String(Path, Path16)) - return PDB_ErrorCode::InvalidPath; + return make_error(generic_error_code::invalid_path, 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; - else if (Result == E_PDB_FORMAT) - return PDB_ErrorCode::InvalidFileFormat; - else if (Result == E_PDB_INVALID_SIG || Result == E_PDB_INVALID_AGE) - return PDB_ErrorCode::DebugInfoMismatch; - else if (Result == E_INVALIDARG) - return PDB_ErrorCode::InvalidParameter; - else if (Result == E_UNEXPECTED) - return PDB_ErrorCode::AlreadyLoaded; - else - return PDB_ErrorCode::UnknownError; - } + HRESULT HR; + if (FAILED(HR = DiaDataSource->loadDataForExe(Path16Str, nullptr, nullptr))) + return ErrorFromHResult(HR); - if (FAILED(Result = DiaDataSource->openSession(&DiaSession))) { - if (Result == E_OUTOFMEMORY) - return PDB_ErrorCode::NoMemory; - else - return PDB_ErrorCode::UnknownError; - } + if (FAILED(HR = DiaDataSource->openSession(&DiaSession))) + return ErrorFromHResult(HR); Session.reset(new DIASession(DiaSession)); - return PDB_ErrorCode::Success; + return Error::success(); } uint64_t DIASession::getLoadAddress() const { Index: lib/DebugInfo/PDB/GenericError.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/GenericError.cpp @@ -0,0 +1,62 @@ +//===- 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/GenericError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +class GenericErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb"; } + + std::string message(int Condition) const override { + switch (static_cast(Condition)) { + case generic_error_code::unspecified: + return "An unknown error has occurred."; + case generic_error_code::dia_sdk_not_present: + return "LLVM was not compiled with support for DIA. This usually means " + "that you are are not using MSVC, or your Visual Studio " + "installation " + "is corrupt."; + case generic_error_code::invalid_path: + return "Unable to load PDB. Make sure the file exists and is readable."; + } + llvm_unreachable("Unrecognized generic_error_code"); + } +}; + +static ManagedStatic Category; + +char GenericError::ID = 0; + +GenericError::GenericError(generic_error_code C) : GenericError(C, "") {} + +GenericError::GenericError(const std::string &Context) + : GenericError(generic_error_code::unspecified, Context) {} + +GenericError::GenericError(generic_error_code C, const std::string &Context) + : Code(C) { + ErrMsg = "PDB Error: "; + std::error_code EC = convertToErrorCode(); + if (Code != generic_error_code::unspecified) + ErrMsg += EC.message() + " "; + if (!Context.empty()) + ErrMsg += Context; +} + +void GenericError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +const std::string &GenericError::getErrorMessage() const { return ErrMsg; } + +std::error_code GenericError::convertToErrorCode() const { + return std::error_code(static_cast(Code), *Category); +} Index: lib/DebugInfo/PDB/PDB.cpp =================================================================== --- lib/DebugInfo/PDB/PDB.cpp +++ lib/DebugInfo/PDB/PDB.cpp @@ -13,17 +13,18 @@ #include "llvm/Config/config.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" - #if HAVE_DIA_SDK #include "llvm/DebugInfo/PDB/DIA/DIASession.h" #endif #include "llvm/DebugInfo/PDB/Raw/RawSession.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" using namespace llvm; using namespace llvm::pdb; -PDB_ErrorCode llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session) { +Error 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 +32,12 @@ #if HAVE_DIA_SDK return DIASession::createFromPdb(Path, Session); #else - return PDB_ErrorCode::NoDiaSupport; + return llvm::make_error("DIA is not installed on the system"); #endif } -PDB_ErrorCode llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path, - std::unique_ptr &Session) { +Error 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 +45,6 @@ #if HAVE_DIA_SDK return DIASession::createFromExe(Path, Session); #else - return PDB_ErrorCode::NoDiaSupport; + return llvm::make_error("DIA is not installed on the system"); #endif } Index: lib/DebugInfo/PDB/Raw/ByteStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/ByteStream.cpp +++ lib/DebugInfo/PDB/Raw/ByteStream.cpp @@ -42,29 +42,28 @@ Owned = true; } -std::error_code ByteStream::initialize(StreamReader &Reader, uint32_t Length) { +Error ByteStream::initialize(StreamReader &Reader, uint32_t Length) { initialize(Length); - std::error_code EC = Reader.readBytes(Data); + auto EC = Reader.readBytes(Data); if (EC) reset(); return EC; } -std::error_code ByteStream::readBytes(uint32_t Offset, - MutableArrayRef Buffer) const { +Error ByteStream::readBytes(uint32_t Offset, + MutableArrayRef Buffer) const { if (Data.size() < Buffer.size() + Offset) - return std::make_error_code(std::errc::bad_address); + return make_error(raw_error_code::insufficient_buffer); ::memcpy(Buffer.data(), Data.data() + Offset, Buffer.size()); - return std::error_code(); + return Error::success(); } -std::error_code ByteStream::getArrayRef(uint32_t Offset, - ArrayRef &Buffer, - uint32_t Length) const { +Error ByteStream::getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const { if (Data.size() < Length + Offset) - return std::make_error_code(std::errc::bad_address); + return make_error(raw_error_code::insufficient_buffer); Buffer = Data.slice(Offset, Length); - return std::error_code(); + return Error::success(); } uint32_t ByteStream::getLength() const { return Data.size(); } Index: lib/DebugInfo/PDB/Raw/DbiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/DbiStream.cpp +++ lib/DebugInfo/PDB/Raw/DbiStream.cpp @@ -8,11 +8,13 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" + #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" #include "llvm/DebugInfo/PDB/Raw/ModInfo.h" #include "llvm/DebugInfo/PDB/Raw/NameHashTable.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" using namespace llvm; @@ -77,49 +79,66 @@ DbiStream::~DbiStream() {} -std::error_code DbiStream::reload() { +Error DbiStream::reload() { StreamReader Reader(Stream); Header.reset(new HeaderInfo()); if (Stream.getLength() < sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); - Reader.readObject(Header.get()); + return make_error(raw_error_code::corrupt_file, + "DBI Stream does not contain a header."); + if (auto EC = Reader.readObject(Header.get())) + return make_error(raw_error_code::corrupt_file, + "DBI Stream does not contain a header."); if (Header->VersionSignature != -1) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "Invalid DBI version signature."); // 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(raw_error_code::corrupt_file, + "Unsupported DBI version."); + + auto InfoStream = Pdb.getPDBInfoStream(); + if (auto EC = InfoStream.takeError()) + return EC; - if (Header->Age != Pdb.getPDBInfoStream().getAge()) - return std::make_error_code(std::errc::illegal_byte_sequence); + if (Header->Age != InfoStream.get().getAge()) + return make_error(raw_error_code::corrupt_file, + "DBI Age does not match PDB Age."); 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(raw_error_code::corrupt_file, + "DBI Length does not equal sum of substreams."); // 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(raw_error_code::corrupt_file, + "DBI MODI substream not aligned."); if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error( + raw_error_code::corrupt_file, + "DBI section contribution substream not aligned."); if (Header->SectionMapSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "DBI section map substream not aligned."); if (Header->FileInfoSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "DBI file info substream not aligned."); if (Header->TypeServerSize % sizeof(uint32_t) != 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "DBI type server substream not aligned."); - std::error_code EC; - ModInfoSubstream.initialize(Reader, Header->ModiSubstreamSize); + if (auto 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. @@ -129,30 +148,33 @@ for (auto Info : Range) ModuleInfos.push_back(ModuleInfoEx(Info)); - if ((EC = - SecContrSubstream.initialize(Reader, Header->SecContrSubstreamSize))) + if (auto EC = + SecContrSubstream.initialize(Reader, Header->SecContrSubstreamSize)) return EC; - if ((EC = SecMapSubstream.initialize(Reader, Header->SectionMapSize))) + if (auto EC = SecMapSubstream.initialize(Reader, Header->SectionMapSize)) return EC; - if ((EC = FileInfoSubstream.initialize(Reader, Header->FileInfoSize))) + if (auto EC = FileInfoSubstream.initialize(Reader, Header->FileInfoSize)) return EC; - if ((EC = TypeServerMapSubstream.initialize(Reader, Header->TypeServerSize))) + if (auto EC = + TypeServerMapSubstream.initialize(Reader, Header->TypeServerSize)) return EC; - if ((EC = ECSubstream.initialize(Reader, Header->ECSubstreamSize))) + if (auto EC = ECSubstream.initialize(Reader, Header->ECSubstreamSize)) return EC; - if ((EC = DbgHeader.initialize(Reader, Header->OptionalDbgHdrSize))) + if (auto EC = DbgHeader.initialize(Reader, Header->OptionalDbgHdrSize)) return EC; - if ((EC = initializeFileInfo())) + if (auto EC = initializeFileInfo()) return EC; if (Reader.bytesRemaining() > 0) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "Found unexpected bytes in DBI Stream."); StreamReader ECReader(ECSubstream); - ECNames.load(ECReader); + if (auto EC = ECNames.load(ECReader)) + return EC; - return std::error_code(); + return Error::success(); } PdbRaw_DbiVer DbiStream::getDbiVersion() const { @@ -193,7 +215,7 @@ ArrayRef DbiStream::modules() const { return ModuleInfos; } -std::error_code DbiStream::initializeFileInfo() { +Error DbiStream::initializeFileInfo() { struct FileInfoSubstreamHeader { ulittle16_t NumModules; // Total # of modules, should match number of // records in the ModuleInfo substream. @@ -221,7 +243,8 @@ // 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(raw_error_code::corrupt_file, + "FileInfo substream count doesn't match DBI."); // 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, @@ -267,5 +290,5 @@ } } - return std::error_code(); + return Error::success(); } Index: lib/DebugInfo/PDB/Raw/InfoStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/InfoStream.cpp +++ lib/DebugInfo/PDB/Raw/InfoStream.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" using namespace llvm; @@ -18,7 +19,7 @@ InfoStream::InfoStream(PDBFile &File) : Pdb(File), Stream(StreamPDB, File) {} -std::error_code InfoStream::reload() { +Error InfoStream::reload() { StreamReader Reader(Stream); struct Header { @@ -29,19 +30,20 @@ }; Header H; - Reader.readObject(&H); + if (auto EC = Reader.readObject(&H)) + return make_error(raw_error_code::corrupt_file, + "PDB Stream does not contain a header."); if (H.Version < PdbRaw_ImplVer::PdbImplVC70) - return std::make_error_code(std::errc::not_supported); + return make_error(raw_error_code::corrupt_file, + "Unsupported PDB stream 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/MappedBlockStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp +++ lib/DebugInfo/PDB/Raw/MappedBlockStream.cpp @@ -9,6 +9,7 @@ #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::pdb; @@ -18,17 +19,16 @@ BlockList = Pdb.getStreamBlockList(StreamIdx); } -std::error_code -MappedBlockStream::readBytes(uint32_t Offset, - MutableArrayRef Buffer) const { +Error MappedBlockStream::readBytes(uint32_t Offset, + MutableArrayRef Buffer) const { uint32_t BlockNum = Offset / Pdb.getBlockSize(); uint32_t OffsetInBlock = Offset % Pdb.getBlockSize(); // Make sure we aren't trying to read beyond the end of the stream. if (Buffer.size() > StreamLength) - return std::make_error_code(std::errc::bad_address); + return make_error(raw_error_code::insufficient_buffer); if (Offset > StreamLength - Buffer.size()) - return std::make_error_code(std::errc::bad_address); + return make_error(raw_error_code::insufficient_buffer); uint32_t BytesLeft = Buffer.size(); uint32_t BytesWritten = 0; @@ -49,11 +49,10 @@ OffsetInBlock = 0; } - return std::error_code(); + return Error::success(); } -std::error_code MappedBlockStream::getArrayRef(uint32_t Offset, - ArrayRef &Buffer, - uint32_t Length) const { - return std::make_error_code(std::errc::not_supported); +Error MappedBlockStream::getArrayRef(uint32_t Offset, ArrayRef &Buffer, + uint32_t Length) const { + return make_error(raw_error_code::feature_unsupported); } Index: lib/DebugInfo/PDB/Raw/NameHashTable.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/NameHashTable.cpp +++ lib/DebugInfo/PDB/Raw/NameHashTable.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/PDB/Raw/ByteStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" #include "llvm/Support/Endian.h" @@ -18,9 +19,6 @@ using namespace llvm::support; using namespace llvm::pdb; -typedef uint32_t *PUL; -typedef uint16_t *PUS; - static inline uint32_t HashStringV1(StringRef Str) { uint32_t Result = 0; uint32_t Size = Str.size(); @@ -80,7 +78,7 @@ NameHashTable::NameHashTable() : Signature(0), HashVersion(0), NameCount(0) {} -std::error_code NameHashTable::load(StreamReader &Stream) { +Error NameHashTable::load(StreamReader &Stream) { struct Header { support::ulittle32_t Signature; support::ulittle32_t HashVersion; @@ -88,27 +86,39 @@ }; Header H; - Stream.readObject(&H); + if (auto EC = Stream.readObject(&H)) + return EC; + if (H.Signature != 0xEFFEEFFE) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "Invalid hash table signature"); if (H.HashVersion != 1 && H.HashVersion != 2) - return std::make_error_code(std::errc::not_supported); + return make_error(raw_error_code::corrupt_file, + "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(raw_error_code::corrupt_file, + "Invalid hash table byte length"); support::ulittle32_t HashCount; - Stream.readObject(&HashCount); + if (auto EC = Stream.readObject(&HashCount)) + return EC; + std::vector BucketArray(HashCount); - Stream.readArray(BucketArray); + if (auto EC = Stream.readArray(BucketArray)) + return make_error(raw_error_code::corrupt_file, + "Could not read bucket array"); 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(raw_error_code::corrupt_file, + "Missing name count"); - Stream.readInteger(NameCount); - return std::error_code(); + if (auto EC = Stream.readInteger(NameCount)) + return EC; + return Error::success(); } StringRef NameHashTable::getStringForID(uint32_t ID) const { 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/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" using namespace llvm; @@ -16,12 +17,17 @@ NameMap::NameMap() {} -std::error_code NameMap::load(StreamReader &Stream) { +Error NameMap::load(StreamReader &Stream) { // 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(raw_error_code::corrupt_file, + "Expected name map length"); + if (Stream.bytesRemaining() < NumberOfBytes) + return make_error(raw_error_code::corrupt_file, + "Invalid name map length"); // Following that field is the starting offset of strings in the name table. uint32_t StringsOffset = Stream.getOffset(); @@ -30,36 +36,50 @@ // 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(raw_error_code::corrupt_file, + "Expected name map hash size"); // 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(raw_error_code::corrupt_file, + "Expected name map max strings"); // 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(raw_error_code::corrupt_file, + "Expected name map num words"); // 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(raw_error_code::corrupt_file, + "Expected name map word"); + 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(raw_error_code::corrupt_file, + "Expected name map num deleted words"); // 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(raw_error_code::corrupt_file, + "Expected name map deleted word"); + DeletedWords.push_back(Word); } @@ -79,11 +99,15 @@ // 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(raw_error_code::corrupt_file, + "Expected name map name offset"); // This appears to be a stream number into the stream directory. uint32_t NameIndex; - Stream.readInteger(NameIndex); + if (Stream.readInteger(NameIndex)) + return make_error(raw_error_code::corrupt_file, + "Expected name map name index"); // Compute the offset of the start of the string relative to the stream. uint32_t StringOffset = StringsOffset + NameOffset; @@ -91,14 +115,16 @@ // Pump out our c-string from the stream. std::string Str; Stream.setOffset(StringOffset); - Stream.readZeroString(Str); + if (Stream.readZeroString(Str)) + return make_error(raw_error_code::corrupt_file, + "Expected name map name"); Stream.setOffset(OldOffset); // Add this to a string-map from name to stream number. Mapping.insert({Str, NameIndex}); } - return std::error_code(); + return Error::success(); } bool NameMap::tryGetValue(StringRef Name, uint32_t &Value) const { Index: lib/DebugInfo/PDB/Raw/PDBFile.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/PDBFile.cpp +++ lib/DebugInfo/PDB/Raw/PDBFile.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/DebugInfo/PDB/Raw/DbiStream.h" #include "llvm/DebugInfo/PDB/Raw/InfoStream.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/TpiStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" @@ -54,18 +55,19 @@ DenseMap> StreamMap; }; -static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, - const uint64_t Size) { +static Error checkOffset(MemoryBufferRef M, uintptr_t Addr, + const uint64_t Size) { if (Addr + Size < Addr || Addr + Size < Size || Addr + Size > uintptr_t(M.getBufferEnd()) || Addr < uintptr_t(M.getBufferStart())) { - return std::make_error_code(std::errc::bad_address); + return make_error(raw_error_code::corrupt_file, + "Invalid buffer address"); } - return std::error_code(); + return Error::success(); } template -static std::error_code checkOffset(MemoryBufferRef M, ArrayRef AR) { +static Error checkOffset(MemoryBufferRef M, ArrayRef AR) { return checkOffset(M, uintptr_t(AR.data()), (uint64_t)AR.size() * sizeof(T)); } @@ -117,38 +119,45 @@ NumBytes); } -std::error_code PDBFile::parseFileHeaders() { +Error PDBFile::parseFileHeaders() { std::error_code EC; MemoryBufferRef BufferRef = *Context->Buffer; // 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(raw_error_code::corrupt_file, + "Does not contain superblock"); Context->SB = reinterpret_cast(BufferRef.getBufferStart()); const SuperBlock *SB = Context->SB; + // Check the magic bytes. + if (memcmp(SB->MagicBytes, Magic, sizeof(Magic)) != 0) + return make_error(raw_error_code::corrupt_file, + "MSF magic header doesn't match"); + + if (BufferRef.getBufferSize() % SB->BlockSize != 0) + return make_error(raw_error_code::corrupt_file, + "File size is not a multiple of block size"); + 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(raw_error_code::corrupt_file, + "Unsupported 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); + if (SB->BlockSize % sizeof(support::ulittle32_t) != 0) + return make_error(raw_error_code::corrupt_file, + "Block size is not multiple of 4."); // 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(raw_error_code::corrupt_file, + "Directory size is not multiple of 4."); // The number of blocks which comprise the directory is a simple function of // the number of bytes it contains. @@ -159,12 +168,13 @@ // 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(raw_error_code::corrupt_file, + "Too many directory blocks."); - return std::error_code(); + return Error::success(); } -std::error_code PDBFile::parseStreamData() { +Error PDBFile::parseStreamData() { assert(Context && Context->SB); bool SeenNumStreams = false; @@ -237,7 +247,8 @@ // It seems this block doesn't belong to any stream? The stream is either // corrupt or something more mysterious is going on. if (StreamIdx == NumStreams) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "Orphaned block found?"); StreamBlocks->push_back(Data); } @@ -245,7 +256,7 @@ // We should have read exactly SB->NumDirectoryBytes bytes. assert(DirectoryBytesRead == SB->NumDirectoryBytes); - return std::error_code(); + return Error::success(); } llvm::ArrayRef PDBFile::getDirectoryBlockArray() { @@ -255,26 +266,29 @@ getNumDirectoryBlocks()); } -InfoStream &PDBFile::getPDBInfoStream() { +Expected PDBFile::getPDBInfoStream() { if (!Info) { Info.reset(new InfoStream(*this)); - Info->reload(); + if (auto EC = Info->reload()) + return std::move(EC); } return *Info; } -DbiStream &PDBFile::getPDBDbiStream() { +Expected PDBFile::getPDBDbiStream() { if (!Dbi) { Dbi.reset(new DbiStream(*this)); - Dbi->reload(); + if (auto EC = Dbi->reload()) + return std::move(EC); } return *Dbi; } -TpiStream &PDBFile::getPDBTpiStream() { +Expected PDBFile::getPDBTpiStream() { if (!Tpi) { Tpi.reset(new TpiStream(*this)); - Tpi->reload(); + if (auto EC = Tpi->reload()) + return std::move(EC); } return *Tpi; } Index: lib/DebugInfo/PDB/Raw/RawError.cpp =================================================================== --- /dev/null +++ lib/DebugInfo/PDB/Raw/RawError.cpp @@ -0,0 +1,52 @@ +#include "llvm/DebugInfo/PDB/Raw/RawError.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::pdb; + +class RawErrorCategory : public std::error_category { +public: + const char *name() const LLVM_NOEXCEPT override { return "llvm.pdb.raw"; } + + std::string message(int Condition) const override { + switch (static_cast(Condition)) { + case raw_error_code::unspecified: + return "An unknown error has occurred."; + case raw_error_code::feature_unsupported: + return "The feature is unsupported by the implementation."; + case raw_error_code::corrupt_file: + return "The PDB file is corrupt."; + case raw_error_code::insufficient_buffer: + return "The buffer is not large enough to read the requested number of " + "bytes."; + } + llvm_unreachable("Unrecognized raw_error_code"); + } +}; + +static ManagedStatic Category; + +char RawError::ID = 0; + +RawError::RawError(raw_error_code C) : RawError(C, "") {} + +RawError::RawError(const std::string &Context) + : RawError(raw_error_code::unspecified, Context) {} + +RawError::RawError(raw_error_code C, const std::string &Context) : Code(C) { + ErrMsg = "Native PDB Error: "; + std::error_code EC = convertToErrorCode(); + if (Code != raw_error_code::unspecified) + ErrMsg += EC.message() + " "; + if (!Context.empty()) + ErrMsg += Context; +} + +void RawError::log(raw_ostream &OS) const { OS << ErrMsg << "\n"; } + +const std::string &RawError::getErrorMessage() const { return ErrMsg; } + +std::error_code RawError::convertToErrorCode() const { + return std::error_code(static_cast(Code), *Category); +} Index: lib/DebugInfo/PDB/Raw/RawSession.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/RawSession.cpp +++ lib/DebugInfo/PDB/Raw/RawSession.cpp @@ -8,11 +8,14 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/RawSession.h" + +#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBSourceFile.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" #include "llvm/DebugInfo/PDB/Raw/PDBFile.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" @@ -25,33 +28,32 @@ RawSession::~RawSession() {} -PDB_ErrorCode RawSession::createFromPdb(StringRef Path, - std::unique_ptr &Session) { +Error RawSession::createFromPdb(StringRef Path, + std::unique_ptr &Session) { ErrorOr> ErrorOrBuffer = MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); - std::error_code EC; - if ((EC = ErrorOrBuffer.getError())) - return PDB_ErrorCode::CouldNotCreateImpl; + if (auto EC = ErrorOrBuffer.getError()) + return make_error(generic_error_code::invalid_path, Path); std::unique_ptr &Buffer = ErrorOrBuffer.get(); std::unique_ptr File(new PDBFile(std::move(Buffer))); - if ((EC = File->parseFileHeaders())) - return PDB_ErrorCode::InvalidFileFormat; - if ((EC = File->parseStreamData())) - return PDB_ErrorCode::InvalidFileFormat; + if (auto EC = File->parseFileHeaders()) + return EC; + if (auto EC = File->parseStreamData()) + return EC; Session.reset(new RawSession(std::move(File))); - return PDB_ErrorCode::Success; + return Error::success(); } -PDB_ErrorCode RawSession::createFromExe(StringRef Path, - std::unique_ptr &Session) { - return PDB_ErrorCode::CouldNotCreateImpl; +Error RawSession::createFromExe(StringRef Path, + std::unique_ptr &Session) { + return llvm::make_error(raw_error_code::feature_unsupported); } uint64_t RawSession::getLoadAddress() const { return 0; } Index: lib/DebugInfo/PDB/Raw/StreamReader.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/StreamReader.cpp +++ lib/DebugInfo/PDB/Raw/StreamReader.cpp @@ -8,42 +8,43 @@ //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" using namespace llvm; using namespace llvm::pdb; StreamReader::StreamReader(const StreamInterface &S) : Stream(S), Offset(0) {} -std::error_code StreamReader::readBytes(MutableArrayRef Buffer) { +Error StreamReader::readBytes(MutableArrayRef Buffer) { if (auto EC = Stream.readBytes(Offset, Buffer)) return EC; Offset += Buffer.size(); - return std::error_code(); + return Error::success(); } -std::error_code StreamReader::readInteger(uint32_t &Dest) { +Error StreamReader::readInteger(uint32_t &Dest) { support::ulittle32_t P; - if (std::error_code EC = readObject(&P)) + if (auto EC = readObject(&P)) return EC; Dest = P; - return std::error_code(); + return Error::success(); } -std::error_code StreamReader::readZeroString(std::string &Dest) { +Error StreamReader::readZeroString(std::string &Dest) { Dest.clear(); char C; do { - readObject(&C); + if (auto EC = readObject(&C)) + return EC; if (C != '\0') Dest.push_back(C); } while (C != '\0'); - return std::error_code(); + return Error::success(); } -std::error_code StreamReader::getArrayRef(ArrayRef &Array, - uint32_t Length) { +Error StreamReader::getArrayRef(ArrayRef &Array, uint32_t Length) { if (auto EC = Stream.getArrayRef(Offset, Array, Length)) return EC; Offset += Length; - return std::error_code(); + return Error::success(); } Index: lib/DebugInfo/PDB/Raw/TpiStream.cpp =================================================================== --- lib/DebugInfo/PDB/Raw/TpiStream.cpp +++ lib/DebugInfo/PDB/Raw/TpiStream.cpp @@ -13,6 +13,7 @@ #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/PDB/Raw/MappedBlockStream.h" #include "llvm/DebugInfo/PDB/Raw/RawConstants.h" +#include "llvm/DebugInfo/PDB/Raw/RawError.h" #include "llvm/DebugInfo/PDB/Raw/StreamReader.h" #include "llvm/Support/Endian.h" @@ -60,46 +61,59 @@ TpiStream::~TpiStream() {} -std::error_code TpiStream::reload() { +Error TpiStream::reload() { StreamReader Reader(Stream); if (Reader.bytesRemaining() < sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); Header.reset(new HeaderInfo()); - Reader.readObject(Header.get()); + if (Reader.readObject(Header.get())) + return make_error(raw_error_code::corrupt_file, + "TPI Stream does not contain a header."); if (Header->Version != PdbTpiV80) - return std::make_error_code(std::errc::not_supported); + return make_error(raw_error_code::corrupt_file, + "Unsupported TPI Version."); if (Header->HeaderSize != sizeof(HeaderInfo)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "Corrupt TPI Header size."); if (Header->HashKeySize != sizeof(ulittle32_t)) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "TPI Stream expected 4 byte hash key size."); if (Header->NumHashBuckets < MinHashBuckets || Header->NumHashBuckets > MaxHashBuckets) - return std::make_error_code(std::errc::illegal_byte_sequence); + return make_error(raw_error_code::corrupt_file, + "TPI Stream Invalid number of hash buckets."); HashFunction = HashBufferV8; // The actual type records themselves come from this stream - RecordsBuffer.initialize(Reader, Header->TypeRecordBytes); + if (auto EC = RecordsBuffer.initialize(Reader, Header->TypeRecordBytes)) + return EC; // Hash indices, hash values, etc come from the hash stream. MappedBlockStream HS(Header->HashStreamIndex, Pdb); StreamReader HSR(HS); HSR.setOffset(Header->HashValueBuffer.Off); - HashValuesBuffer.initialize(HSR, Header->HashValueBuffer.Length); + if (auto EC = + HashValuesBuffer.initialize(HSR, Header->HashValueBuffer.Length)) + return EC; HSR.setOffset(Header->HashAdjBuffer.Off); - HashAdjBuffer.initialize(HSR, Header->HashAdjBuffer.Length); + if (auto EC = HashAdjBuffer.initialize(HSR, Header->HashAdjBuffer.Length)) + return EC; HSR.setOffset(Header->IndexOffsetBuffer.Off); - TypeIndexOffsetBuffer.initialize(HSR, Header->IndexOffsetBuffer.Length); + if (auto EC = TypeIndexOffsetBuffer.initialize( + HSR, Header->IndexOffsetBuffer.Length)) + return EC; - return std::error_code(); + return Error::success(); } PdbRaw_TpiVer TpiStream::getTpiVersion() const { 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 @@ -26,6 +26,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/GenericError.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" #include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" @@ -157,9 +158,10 @@ cl::cat(FilterCategory)); } -static void dumpFileHeaders(ScopedPrinter &P, PDBFile &File) { +static Error dumpFileHeaders(ScopedPrinter &P, PDBFile &File) { if (!opts::DumpHeaders) - return; + return Error::success(); + DictScope D(P, "FileHeaders"); P.printNumber("BlockSize", File.getBlockSize()); P.printNumber("Unknown0", File.getUnknown0()); @@ -175,11 +177,12 @@ // order, make up the directory. P.printList("DirectoryBlocks", File.getDirectoryBlockArray()); P.printNumber("NumStreams", File.getNumStreams()); + return Error::success(); } -static void dumpStreamSizes(ScopedPrinter &P, PDBFile &File) { +static Error dumpStreamSizes(ScopedPrinter &P, PDBFile &File) { if (!opts::DumpStreamSizes) - return; + return Error::success(); ListScope L(P, "StreamSizes"); uint32_t StreamCount = File.getNumStreams(); @@ -188,11 +191,12 @@ Name += to_string(StreamIdx); P.printNumber(Name, File.getStreamByteSize(StreamIdx)); } + return Error::success(); } -static void dumpStreamBlocks(ScopedPrinter &P, PDBFile &File) { +static Error dumpStreamBlocks(ScopedPrinter &P, PDBFile &File) { if (!opts::DumpStreamBlocks) - return; + return Error::success(); ListScope L(P, "StreamBlocks"); uint32_t StreamCount = File.getNumStreams(); @@ -202,15 +206,16 @@ auto StreamBlocks = File.getStreamBlockList(StreamIdx); P.printList(Name, StreamBlocks); } + return Error::success(); } -static void dumpStreamData(ScopedPrinter &P, PDBFile &File) { +static Error dumpStreamData(ScopedPrinter &P, PDBFile &File) { uint32_t StreamCount = File.getNumStreams(); StringRef DumpStreamStr = opts::DumpStreamData; uint32_t DumpStreamNum; if (DumpStreamStr.getAsInteger(/*Radix=*/0U, DumpStreamNum) || DumpStreamNum >= StreamCount) - return; + return Error::success(); uint32_t StreamBytesRead = 0; uint32_t StreamSize = File.getStreamByteSize(DumpStreamNum); @@ -229,20 +234,31 @@ outs() << StreamBlockData; StreamBytesRead += StreamBlockData.size(); } + return Error::success(); } -static void dumpInfoStream(ScopedPrinter &P, PDBFile &File) { - InfoStream &IS = File.getPDBInfoStream(); +static Error dumpInfoStream(ScopedPrinter &P, PDBFile &File) { + auto InfoS = File.getPDBInfoStream(); + if (auto EC = InfoS.takeError()) + return EC; + + InfoStream &IS = InfoS.get(); DictScope D(P, "PDB Stream"); P.printNumber("Version", IS.getVersion()); P.printHex("Signature", IS.getSignature()); P.printNumber("Age", IS.getAge()); P.printObject("Guid", IS.getGuid()); + return Error::success(); } -static void dumpNamedStream(ScopedPrinter &P, PDBFile &File, StringRef Stream) { - InfoStream &IS = File.getPDBInfoStream(); +static Error dumpNamedStream(ScopedPrinter &P, PDBFile &File, + StringRef Stream) { + auto InfoS = File.getPDBInfoStream(); + if (auto EC = InfoS.takeError()) + return EC; + InfoStream &IS = InfoS.get(); + uint32_t NameStreamIndex = IS.getNamedStreamIndex(Stream); if (NameStreamIndex != 0) { @@ -256,7 +272,9 @@ StreamReader Reader(NameStream); NameHashTable NameTable; - NameTable.load(Reader); + if (auto EC = NameTable.load(Reader)) + return EC; + P.printHex("Signature", NameTable.getSignature()); P.printNumber("Version", NameTable.getHashVersion()); P.printNumber("Name Count", NameTable.getNameCount()); @@ -267,10 +285,14 @@ P.printString(Str); } } + return Error::success(); } -static void dumpDbiStream(ScopedPrinter &P, PDBFile &File) { - DbiStream &DS = File.getPDBDbiStream(); +static Error dumpDbiStream(ScopedPrinter &P, PDBFile &File) { + auto DbiS = File.getPDBDbiStream(); + if (auto EC = DbiS.takeError()) + return EC; + DbiStream &DS = DbiS.get(); DictScope D(P, "DBI Stream"); P.printNumber("Dbi Version", DS.getDbiVersion()); @@ -312,20 +334,25 @@ for (auto File : Modi.SourceFiles) P.printString(File); } + return Error::success(); } -static void dumpTpiStream(ScopedPrinter &P, PDBFile &File) { +static Error dumpTpiStream(ScopedPrinter &P, PDBFile &File) { if (!opts::DumpTypeStream) - return; + return Error::success(); DictScope D(P, "Type Info Stream"); - TpiStream &Tpi = File.getPDBTpiStream(); + auto TpiS = File.getPDBTpiStream(); + if (auto EC = TpiS.takeError()) + return EC; + TpiStream &Tpi = TpiS.get(); + P.printNumber("TPI Version", Tpi.getTpiVersion()); P.printNumber("Record count", Tpi.NumTypeRecords()); if (!opts::DumpTpiRecordBytes) - return; + return Error::success(); ListScope L(P, "Records"); for (auto &Type : Tpi.types()) { @@ -333,74 +360,57 @@ P.printHex("Kind", unsigned(Type.Leaf)); P.printBinaryBlock("Bytes", Type.LeafData); } + return Error::success(); } -static void dumpStructure(RawSession &RS) { +static Error dumpStructure(RawSession &RS) { PDBFile &File = RS.getPDBFile(); ScopedPrinter P(outs()); - dumpFileHeaders(P, File); + if (auto EC = dumpFileHeaders(P, File)) + return EC; - dumpStreamSizes(P, File); + if (auto EC = dumpStreamSizes(P, File)) + return EC; - dumpStreamBlocks(P, File); + if (auto EC = dumpStreamBlocks(P, File)) + return EC; - dumpStreamData(P, File); + if (auto EC = dumpStreamData(P, File)) + return EC; - dumpInfoStream(P, File); + if (auto EC = dumpInfoStream(P, File)) + return EC; - dumpNamedStream(P, File, "/names"); + if (auto EC = dumpNamedStream(P, File, "/names")) + return EC; - dumpDbiStream(P, File); + if (auto EC = dumpDbiStream(P, File)) + return EC; - 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; - } + if (auto EC = dumpTpiStream(P, File)) + return EC; + return Error::success(); } 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) { + auto E = loadDataForPDB(PDB_ReaderType::Raw, Path, Session); + if (!E) { RawSession *RS = static_cast(Session.get()); - dumpStructure(*RS); + E = dumpStructure(*RS); } - reportError(Path, Error); - outs().flush(); + if (E) + logAllUnhandledErrors(std::move(E), outs(), ""); + return; } - PDB_ErrorCode Error = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); - if (Error != PDB_ErrorCode::Success) { - reportError(Path, Error); + Error E = loadDataForPDB(PDB_ReaderType::DIA, Path, Session); + if (E) { + logAllUnhandledErrors(std::move(E), outs(), ""); return; } @@ -571,6 +581,6 @@ #if defined(HAVE_DIA_SDK) CoUninitialize(); #endif - + outs().flush(); return 0; }