From bbb9ea7b70971df53eedfb42fc9cb606f815eaaa Mon Sep 17 00:00:00 2001 From: "Michael J. Spencer" Date: Mon, 11 Oct 2010 19:55:38 +0000 Subject: Add KillTheDoctor. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116216 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/KillTheDoctor/CMakeLists.txt | 6 + utils/KillTheDoctor/KillTheDoctor.cpp | 600 ++++++++++++++++++++++++++++++ utils/KillTheDoctor/system_error.cpp | 287 +++++++++++++++ utils/KillTheDoctor/system_error.h | 662 ++++++++++++++++++++++++++++++++++ 4 files changed, 1555 insertions(+) create mode 100644 utils/KillTheDoctor/CMakeLists.txt create mode 100644 utils/KillTheDoctor/KillTheDoctor.cpp create mode 100644 utils/KillTheDoctor/system_error.cpp create mode 100644 utils/KillTheDoctor/system_error.h (limited to 'utils/KillTheDoctor') diff --git a/utils/KillTheDoctor/CMakeLists.txt b/utils/KillTheDoctor/CMakeLists.txt new file mode 100644 index 0000000000..32e481cbea --- /dev/null +++ b/utils/KillTheDoctor/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(KillTheDoctor + KillTheDoctor.cpp + system_error.cpp + ) + +target_link_libraries(KillTheDoctor LLVMSupport LLVMSystem) diff --git a/utils/KillTheDoctor/KillTheDoctor.cpp b/utils/KillTheDoctor/KillTheDoctor.cpp new file mode 100644 index 0000000000..c0bf437a72 --- /dev/null +++ b/utils/KillTheDoctor/KillTheDoctor.cpp @@ -0,0 +1,600 @@ +//===- KillTheDoctor - Prevent Dr. Watson from stopping tests ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program provides an extremely hacky way to stop Dr. Watson from starting +// due to unhandled exceptions in child processes. +// +// This simply starts the program named in the first positional argument with +// the arguments following it under a debugger. All this debugger does is catch +// any unhandled exceptions thrown in the child process and close the program +// (and hopefully tells someone about it). +// +// This also provides another really hacky method to prevent assert dialog boxes +// from poping up. When --no-user32 is passed, if any process loads user32.dll, +// we assume it is trying to call MessageBoxEx and terminate it. The proper way +// to do this would be to actually set a break point, but there's quite a bit +// of code involved to get the address of MessageBoxEx in the remote process's +// address space due to Address space layout randomization (ASLR). This can be +// added if it's ever actually needed. +// +// If the subprocess exits for any reason other than sucessful termination, -1 +// is returned. If the process exits normally the value it returned is returned. +// +// I hate Windows. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/type_traits.h" +#include "llvm/System/Signals.h" +#include "system_error.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace llvm; + +#undef max + +namespace { + cl::opt ProgramToRun(cl::Positional, + cl::desc("")); + cl::list Argv(cl::ConsumeAfter, + cl::desc("...")); + cl::opt TraceExecution("x", + cl::desc("Print detailed output about what is being run to stderr.")); + cl::opt Timeout("t", cl::init(0), + cl::desc("Set maximum runtime in seconds. Defaults to infinite.")); + cl::opt NoUser32("no-user32", + cl::desc("Terminate process if it loads user32.dll.")); + + StringRef ToolName; + + template + class ScopedHandle { + typedef typename HandleType::handle_type handle_type; + + handle_type Handle; + + public: + ScopedHandle() + : Handle(HandleType::GetInvalidHandle()) {} + + explicit ScopedHandle(handle_type handle) + : Handle(handle) {} + + ~ScopedHandle() { + HandleType::Destruct(Handle); + } + + ScopedHandle& operator=(handle_type handle) { + // Cleanup current handle. + if (!HandleType::isValid(Handle)) + HandleType::Destruct(Handle); + Handle = handle; + return *this; + } + + operator bool() const { + return HandleType::isValid(Handle); + } + + operator handle_type() { + return Handle; + } + }; + + // This implements the most common handle in the Windows API. + struct CommonHandle { + typedef HANDLE handle_type; + + static handle_type GetInvalidHandle() { + return INVALID_HANDLE_VALUE; + } + + static void Destruct(handle_type Handle) { + ::CloseHandle(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct FileMappingHandle { + typedef HANDLE handle_type; + + static handle_type GetInvalidHandle() { + return NULL; + } + + static void Destruct(handle_type Handle) { + ::CloseHandle(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct MappedViewOfFileHandle { + typedef LPVOID handle_type; + + static handle_type GetInvalidHandle() { + return NULL; + } + + static void Destruct(handle_type Handle) { + ::UnmapViewOfFile(Handle); + } + + static bool isValid(handle_type Handle) { + return Handle != GetInvalidHandle(); + } + }; + + struct ProcessHandle : CommonHandle {}; + struct ThreadHandle : CommonHandle {}; + struct TokenHandle : CommonHandle {}; + struct FileHandle : CommonHandle {}; + + typedef ScopedHandle FileMappingScopedHandle; + typedef ScopedHandle MappedViewOfFileScopedHandle; + typedef ScopedHandle ProcessScopedHandle; + typedef ScopedHandle ThreadScopedHandle; + typedef ScopedHandle TokenScopedHandle; + typedef ScopedHandle FileScopedHandle; + + error_code get_windows_last_error() { + return make_error_code(windows_error(::GetLastError())); + } +} + +static error_code GetFileNameFromHandle(HANDLE FileHandle, + std::string& Name) { + char Filename[MAX_PATH+1]; + bool Sucess = false; + Name.clear(); + + // Get the file size. + LARGE_INTEGER FileSize; + Sucess = ::GetFileSizeEx(FileHandle, &FileSize); + + if (!Sucess) + return get_windows_last_error(); + + // Create a file mapping object. + FileMappingScopedHandle FileMapping( + ::CreateFileMappingA(FileHandle, + NULL, + PAGE_READONLY, + 0, + 1, + NULL)); + + if (!FileMapping) + return get_windows_last_error(); + + // Create a file mapping to get the file name. + MappedViewOfFileScopedHandle MappedFile( + ::MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 1)); + + if (!MappedFile) + return get_windows_last_error(); + + Sucess = ::GetMappedFileNameA(::GetCurrentProcess(), + MappedFile, + Filename, + array_lengthof(Filename) - 1); + + if (!Sucess) + return get_windows_last_error(); + else { + Name = Filename; + return windows_error::success; + } +} + +static std::string QuoteProgramPathIfNeeded(StringRef Command) { + if (Command.find_first_of(' ') == StringRef::npos) + return Command; + else { + std::string ret; + ret.reserve(Command.size() + 3); + ret.push_back('"'); + ret.append(Command.begin(), Command.end()); + ret.push_back('"'); + return ret; + } +} + +/// @brief Find program using shell lookup rules. +/// @param Program This is either an absolute path, relative path, or simple a +/// program name. Look in PATH for any programs that match. If no +/// extension is present, try all extensions in PATHEXT. +/// @return If ec == errc::success, The absolute path to the program. Otherwise +/// the return value is undefined. +static std::string FindProgram(const std::string &Program, error_code &ec) { + char PathName[MAX_PATH + 1]; + typedef SmallVector pathext_t; + pathext_t pathext; + // Check for the program without an extension (in case it already has one). + pathext.push_back(""); + SplitString(std::getenv("PATHEXT"), pathext, ";"); + + for (pathext_t::iterator i = pathext.begin(), e = pathext.end(); i != e; ++i){ + SmallString<5> ext; + for (std::size_t ii = 0, e = i->size(); ii != e; ++ii) + ext.push_back(::tolower((*i)[ii])); + LPCSTR Extension = NULL; + if (ext.size() && ext[0] == '.') + Extension = ext.c_str(); + DWORD length = ::SearchPathA(NULL, + Program.c_str(), + Extension, + array_lengthof(PathName), + PathName, + NULL); + if (length == 0) + ec = get_windows_last_error(); + else if (length > array_lengthof(PathName)) { + // This may have been the file, return with error. + ec = error_code(windows_error::buffer_overflow); + break; + } else { + // We found the path! Return it. + ec = windows_error::success; + break; + } + } + + // Make sure PathName is valid. + PathName[MAX_PATH] = 0; + return PathName; +} + +static error_code EnableDebugPrivileges() { + HANDLE TokenHandle; + BOOL success = ::OpenProcessToken(::GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &TokenHandle); + if (!success) + return error_code(::GetLastError(), system_category()); + + TokenScopedHandle Token(TokenHandle); + TOKEN_PRIVILEGES TokenPrivileges; + LUID LocallyUniqueID; + + success = ::LookupPrivilegeValueA(NULL, + SE_DEBUG_NAME, + &LocallyUniqueID); + if (!success) + return error_code(::GetLastError(), system_category()); + + TokenPrivileges.PrivilegeCount = 1; + TokenPrivileges.Privileges[0].Luid = LocallyUniqueID; + TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + success = ::AdjustTokenPrivileges(Token, + FALSE, + &TokenPrivileges, + sizeof(TOKEN_PRIVILEGES), + NULL, + NULL); + // The value of success is basically useless. Either way we are just returning + // the value of ::GetLastError(). + return error_code(::GetLastError(), system_category()); +} + +static StringRef ExceptionCodeToString(DWORD ExceptionCode) { + switch(ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; + case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; + case EXCEPTION_DATATYPE_MISALIGNMENT: + return "EXCEPTION_DATATYPE_MISALIGNMENT"; + case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; + case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; + case EXCEPTION_FLT_INVALID_OPERATION: + return "EXCEPTION_FLT_INVALID_OPERATION"; + case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; + case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; + case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; + case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; + case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; + case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; + case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; + case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; + case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; + case EXCEPTION_SINGLE_STEP: return "EXCEPTION_SINGLE_STEP"; + case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; + default: return ""; + } +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + ToolName = argv[0]; + + cl::ParseCommandLineOptions(argc, argv, "Dr. Watson Assassin.\n"); + if (ProgramToRun.size() == 0) { + cl::PrintHelpMessage(); + return -1; + } + + if (Timeout > std::numeric_limits::max() / 1000) { + errs() << ToolName << ": Timeout value too large, must be less than: " + << std::numeric_limits::max() / 1000 + << '\n'; + return -1; + } + + std::string CommandLine(ProgramToRun); + + error_code ec; + ProgramToRun = FindProgram(ProgramToRun, ec); + if (ec) { + errs() << ToolName << ": Failed to find program: '" << CommandLine + << "': " << ec.message() << '\n'; + return -1; + } + + if (TraceExecution) + errs() << ToolName << ": Found Program: " << ProgramToRun << '\n'; + + for (std::vector::iterator i = Argv.begin(), + e = Argv.end(); + i != e; ++i) { + CommandLine.push_back(' '); + CommandLine.append(*i); + } + + if (TraceExecution) + errs() << ToolName << ": Program Image Path: " << ProgramToRun << '\n' + << ToolName << ": Command Line: " << CommandLine << '\n'; + + STARTUPINFO StartupInfo; + PROCESS_INFORMATION ProcessInfo; + std::memset(&StartupInfo, 0, sizeof(StartupInfo)); + StartupInfo.cb = sizeof(StartupInfo); + std::memset(&ProcessInfo, 0, sizeof(ProcessInfo)); + + // Set error mode to not display any message boxes. The child process inherets + // this. + ::SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX); + ::_set_error_mode(_OUT_TO_STDERR); + + BOOL success = ::CreateProcessA(ProgramToRun.c_str(), + LPSTR(CommandLine.c_str()), + NULL, + NULL, + FALSE, + DEBUG_PROCESS, + NULL, + NULL, + &StartupInfo, + &ProcessInfo); + if (!success) { + errs() << ToolName << ": Failed to run program: '" << ProgramToRun + << "': " << error_code(::GetLastError(), system_category()).message() + << '\n'; + return -1; + } + + // Make sure ::CloseHandle is called on exit. + std::map ProcessIDToHandle; + + DEBUG_EVENT DebugEvent; + std::memset(&DebugEvent, 0, sizeof(DebugEvent)); + DWORD dwContinueStatus = DBG_CONTINUE; + + // Run the program under the debugger until either it exits, or throws an + // exception. + if (TraceExecution) + errs() << ToolName << ": Debugging...\n"; + + while(true) { + DWORD TimeLeft = INFINITE; + if (Timeout > 0) { + FILETIME CreationTime, ExitTime, KernelTime, UserTime; + ULARGE_INTEGER a, b; + success = ::GetProcessTimes(ProcessInfo.hProcess, + &CreationTime, + &ExitTime, + &KernelTime, + &UserTime); + if (!success) { + ec = error_code(::GetLastError(), system_category()); + + errs() << ToolName << ": Failed to get process times: " + << ec.message() << '\n'; + return -1; + } + a.LowPart = KernelTime.dwLowDateTime; + a.HighPart = KernelTime.dwHighDateTime; + b.LowPart = UserTime.dwLowDateTime; + b.HighPart = UserTime.dwHighDateTime; + // Convert 100-nanosecond units to miliseconds. + uint64_t TotalTimeMiliseconds = (a.QuadPart + b.QuadPart) / 10000; + // Handle the case where the process has been running for more than 49 + // days. + if (TotalTimeMiliseconds > std::numeric_limits::max()) { + errs() << ToolName << ": Timeout Failed: Process has been running for" + "more than 49 days.\n"; + return -1; + } + + // We check with > instead of using Timeleft because if + // TotalTimeMiliseconds is greater than Timeout * 1000, TimeLeft would + // underflow. + if (TotalTimeMiliseconds > (Timeout * 1000)) { + errs() << ToolName << ": Process timed out.\n"; + ::TerminateProcess(ProcessInfo.hProcess, -1); + // Otherwise other stuff starts failing... + return -1; + } + + TimeLeft = (Timeout * 1000) - static_cast(TotalTimeMiliseconds); + } + success = WaitForDebugEvent(&DebugEvent, TimeLeft); + + if (!success) { + ec = error_code(::GetLastError(), system_category()); + + if (ec == error_condition(errc::timed_out)) { + errs() << ToolName << ": Process timed out.\n"; + ::TerminateProcess(ProcessInfo.hProcess, -1); + // Otherwise other stuff starts failing... + return -1; + } + + errs() << ToolName << ": Failed to wait for debug event in program: '" + << ProgramToRun << "': " << ec.message() << '\n'; + return -1; + } + + switch(DebugEvent.dwDebugEventCode) { + case CREATE_PROCESS_DEBUG_EVENT: + // Make sure we remove the handle on exit. + if (TraceExecution) + errs() << ToolName << ": Debug Event: CREATE_PROCESS_DEBUG_EVENT\n"; + ProcessIDToHandle[DebugEvent.dwProcessId] = + DebugEvent.u.CreateProcessInfo.hProcess; + ::CloseHandle(DebugEvent.u.CreateProcessInfo.hFile); + break; + case EXIT_PROCESS_DEBUG_EVENT: { + if (TraceExecution) + errs() << ToolName << ": Debug Event: EXIT_PROCESS_DEBUG_EVENT\n"; + + // If this is the process we origionally created, exit with its exit + // code. + if (DebugEvent.dwProcessId == ProcessInfo.dwProcessId) + return DebugEvent.u.ExitProcess.dwExitCode; + + // Otherwise cleanup any resources we have for it. + std::map::iterator ExitingProcess = + ProcessIDToHandle.find(DebugEvent.dwProcessId); + if (ExitingProcess == ProcessIDToHandle.end()) { + errs() << ToolName << ": Got unknown process id!\n"; + return -1; + } + ::CloseHandle(ExitingProcess->second); + ProcessIDToHandle.erase(ExitingProcess); + } + break; + case CREATE_THREAD_DEBUG_EVENT: + ::CloseHandle(DebugEvent.u.CreateThread.hThread); + break; + case LOAD_DLL_DEBUG_EVENT: { + // Cleanup the file handle. + FileScopedHandle DLLFile(DebugEvent.u.LoadDll.hFile); + std::string DLLName; + ec = GetFileNameFromHandle(DLLFile, DLLName); + if (ec) { + DLLName = " : "; + DLLName += ec.message(); + } + if (TraceExecution) { + errs() << ToolName << ": Debug Event: LOAD_DLL_DEBUG_EVENT\n"; + errs().indent(ToolName.size()) << ": DLL Name : " << DLLName << '\n'; + } + + if (NoUser32 && sys::Path(DLLName).getBasename() == "user32") { + // Program is loading user32.dll, in the applications we are testing, + // this only happens if an assert has fired. By now the message has + // already been printed, so simply close the program. + errs() << ToolName << ": user32.dll loaded!\n"; + errs().indent(ToolName.size()) + << ": This probably means that assert was called. Closing " + "program to prevent message box from poping up.\n"; + dwContinueStatus = DBG_CONTINUE; + ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1); + return -1; + } + } + break; + case EXCEPTION_DEBUG_EVENT: { + // Close the application if this exception will not be handled by the + // child application. + if (TraceExecution) + errs() << ToolName << ": Debug Event: EXCEPTION_DEBUG_EVENT\n"; + + EXCEPTION_DEBUG_INFO &Exception = DebugEvent.u.Exception; + if (Exception.dwFirstChance > 0) { + if (TraceExecution) { + errs().indent(ToolName.size()) << ": Debug Info : "; + errs() << "First chance exception at " + << Exception.ExceptionRecord.ExceptionAddress + << ", exception code: " + << ExceptionCodeToString( + Exception.ExceptionRecord.ExceptionCode) + << " (" << Exception.ExceptionRecord.ExceptionCode << ")\n"; + } + dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED; + } else { + errs() << ToolName << ": Unhandled exception in: " << ProgramToRun + << "!\n"; + errs().indent(ToolName.size()) << ": location: "; + errs() << Exception.ExceptionRecord.ExceptionAddress + << ", exception code: " + << ExceptionCodeToString( + Exception.ExceptionRecord.ExceptionCode) + << " (" << Exception.ExceptionRecord.ExceptionCode + << ")\n"; + dwContinueStatus = DBG_CONTINUE; + ::TerminateProcess(ProcessIDToHandle[DebugEvent.dwProcessId], -1); + return -1; + } + } + break; + default: + // Do nothing. + if (TraceExecution) + errs() << ToolName << ": Debug Event: \n"; + break; + } + + success = ContinueDebugEvent(DebugEvent.dwProcessId, + DebugEvent.dwThreadId, + dwContinueStatus); + if (!success) { + ec = error_code(::GetLastError(), system_category()); + errs() << ToolName << ": Failed to continue debugging program: '" + << ProgramToRun << "': " << ec.message() << '\n'; + return -1; + } + + dwContinueStatus = DBG_CONTINUE; + } + + assert(0 && "Fell out of debug loop. This shouldn't be possible!"); + return -1; +} diff --git a/utils/KillTheDoctor/system_error.cpp b/utils/KillTheDoctor/system_error.cpp new file mode 100644 index 0000000000..0e78fb379e --- /dev/null +++ b/utils/KillTheDoctor/system_error.cpp @@ -0,0 +1,287 @@ +//===---------------------- system_error.cpp ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" +#include "system_error.h" +#include +#include + +namespace llvm { + +// class error_category + +error_category::error_category() { +} + +error_category::~error_category() { +} + +error_condition +error_category::default_error_condition(int ev) const { + return error_condition(ev, *this); +} + +bool +error_category::equivalent(int code, const error_condition& condition) const { + return default_error_condition(code) == condition; +} + +bool +error_category::equivalent(const error_code& code, int condition) const { + return *this == code.category() && code.value() == condition; +} + +std::string +_do_message::message(int ev) const { + return std::string(std::strerror(ev)); +} + +class _generic_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; +}; + +const char* +_generic_error_category::name() const { + return "generic"; +} + +std::string +_generic_error_category::message(int ev) const { +#ifdef ELAST + if (ev > ELAST) + return std::string("unspecified generic_category error"); +#endif // ELAST + return _do_message::message(ev); +} + +const error_category& +generic_category() { + static _generic_error_category s; + return s; +} + +class _system_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; + +const char* +_system_error_category::name() const { + return "system"; +} + +// std::string _system_error_category::message(int ev) const { +// Is in Platform/system_error.inc + +// error_condition _system_error_category::default_error_condition(int ev) const +// Is in Platform/system_error.inc + +const error_category& +system_category() { + static _system_error_category s; + return s; +} + +// error_condition + +std::string +error_condition::message() const { + return _cat_->message(_val_); +} + +// error_code + +std::string +error_code::message() const { + return _cat_->message(_val_); +} + +// system_error + +std::string +system_error::_init(const error_code& ec, std::string what_arg) { + if (ec) + { + if (!what_arg.empty()) + what_arg += ": "; + what_arg += ec.message(); + } + return what_arg; +} + +system_error::system_error(error_code ec, const std::string& what_arg) + : runtime_error(_init(ec, what_arg)), _ec_(ec) { +} + +system_error::system_error(error_code ec, const char* what_arg) + : runtime_error(_init(ec, what_arg)), _ec_(ec) { +} + +system_error::system_error(error_code ec) + : runtime_error(_init(ec, "")), _ec_(ec) { +} + +system_error::system_error(int ev, const error_category& ecat, + const std::string& what_arg) + : runtime_error(_init(error_code(ev, ecat), what_arg)) + , _ec_(error_code(ev, ecat)) { +} + +system_error::system_error(int ev, const error_category& ecat, + const char* what_arg) + : runtime_error(_init(error_code(ev, ecat), what_arg)) + , _ec_(error_code(ev, ecat)) { +} + +system_error::system_error(int ev, const error_category& ecat) + : runtime_error(_init(error_code(ev, ecat), "")), _ec_(error_code(ev, ecat)) { +} + +system_error::~system_error() throw() { +} + +void +_throw_system_error(int ev, const char* what_arg) { + throw system_error(error_code(ev, system_category()), what_arg); +} + +} // end namespace llvm + +#ifdef LLVM_ON_WIN32 +#include +#include + +namespace llvm { + +std::string +_system_error_category::message(int ev) const { + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL); + if (retval == 0) { + ::LocalFree(lpMsgBuf); + return std::string("Unknown error"); + } + + std::string str( static_cast(lpMsgBuf) ); + ::LocalFree(lpMsgBuf); + + while (str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r')) + str.erase( str.size()-1 ); + if (str.size() && str[str.size()-1] == '.') + str.erase( str.size()-1 ); + return str; +} + +error_condition +_system_error_category::default_error_condition(int ev) const { + switch (ev) + { + case 0: return make_error_condition(errc::success); + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + case ERROR_ACCESS_DENIED: return make_error_condition(errc::permission_denied); + case ERROR_ALREADY_EXISTS: return make_error_condition(errc::file_exists); + case ERROR_BAD_UNIT: return make_error_condition(errc::no_such_device); + case ERROR_BUFFER_OVERFLOW: return make_error_condition(errc::filename_too_long); + case ERROR_BUSY: return make_error_condition(errc::device_or_resource_busy); + case ERROR_BUSY_DRIVE: return make_error_condition(errc::device_or_resource_busy); + case ERROR_CANNOT_MAKE: return make_error_condition(errc::permission_denied); + case ERROR_CANTOPEN: return make_error_condition(errc::io_error); + case ERROR_CANTREAD: return make_error_condition(errc::io_error); + case ERROR_CANTWRITE: return make_error_condition(errc::io_error); + case ERROR_CURRENT_DIRECTORY: return make_error_condition(errc::permission_denied); + case ERROR_DEV_NOT_EXIST: return make_error_condition(errc::no_such_device); + case ERROR_DEVICE_IN_USE: return make_error_condition(errc::device_or_resource_busy); + case ERROR_DIR_NOT_EMPTY: return make_error_condition(errc::directory_not_empty); + case ERROR_DIRECTORY: return make_error_condition(errc::invalid_argument); + case ERROR_DISK_FULL: return make_error_condition(errc::no_space_on_device); + case ERROR_FILE_EXISTS: return make_error_condition(errc::file_exists); + case ERROR_FILE_NOT_FOUND: return make_error_condition(errc::no_such_file_or_directory); + case ERROR_HANDLE_DISK_FULL: return make_error_condition(errc::no_space_on_device); + case ERROR_INVALID_ACCESS: return make_error_condition(errc::permission_denied); + case ERROR_INVALID_DRIVE: return make_error_condition(errc::no_such_device); + case ERROR_INVALID_FUNCTION: return make_error_condition(errc::function_not_supported); + case ERROR_INVALID_HANDLE: return make_error_condition(errc::invalid_argument); + case ERROR_INVALID_NAME: return make_error_condition(errc::invalid_argument); + case ERROR_LOCK_VIOLATION: return make_error_condition(errc::no_lock_available); + case ERROR_LOCKED: return make_error_condition(errc::no_lock_available); + case ERROR_NEGATIVE_SEEK: return make_error_condition(errc::invalid_argument); + case ERROR_NOACCESS: return make_error_condition(errc::permission_denied); + case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition(errc::not_enough_memory); + case ERROR_NOT_READY: return make_error_condition(errc::resource_unavailable_try_again); + case ERROR_NOT_SAME_DEVICE: return make_error_condition(errc::cross_device_link); + case ERROR_OPEN_FAILED: return make_error_condition(errc::io_error); + case ERROR_OPEN_FILES: return make_error_condition(errc::device_or_resource_busy); + case ERROR_OPERATION_ABORTED: return make_error_condition(errc::operation_canceled); + case ERROR_OUTOFMEMORY: return make_error_condition(errc::not_enough_memory); + case ERROR_PATH_NOT_FOUND: return make_error_condition(errc::no_such_file_or_directory); + case ERROR_READ_FAULT: return make_error_condition(errc::io_error); + case ERROR_RETRY: return make_error_condition(errc::resource_unavailable_try_again); + case ERROR_SEEK: return make_error_condition(errc::io_error); + case ERROR_SHARING_VIOLATION: return make_error_condition(errc::permission_denied); + case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition(errc::too_many_files_open); + case ERROR_WRITE_FAULT: return make_error_condition(errc::io_error); + case ERROR_WRITE_PROTECT: return make_error_condition(errc::permission_denied); + case ERROR_SEM_TIMEOUT: return make_error_condition(errc::timed_out); + case WSAEACCES: return make_error_condition(errc::permission_denied); + case WSAEADDRINUSE: return make_error_condition(errc::address_in_use); + case WSAEADDRNOTAVAIL: return make_error_condition(errc::address_not_available); + case WSAEAFNOSUPPORT: return make_error_condition(errc::address_family_not_supported); + case WSAEALREADY: return make_error_condition(errc::connection_already_in_progress); + case WSAEBADF: return make_error_condition(errc::bad_file_descriptor); + case WSAECONNABORTED: return make_error_condition(errc::connection_aborted); + case WSAECONNREFUSED: return make_error_condition(errc::connection_refused); + case WSAECONNRESET: return make_error_condition(errc::connection_reset); + case WSAEDESTADDRREQ: return make_error_condition(errc::destination_address_required); + case WSAEFAULT: return make_error_condition(errc::bad_address); + case WSAEHOSTUNREACH: return make_error_condition(errc::host_unreachable); + case WSAEINPROGRESS: return make_error_condition(errc::operation_in_progress); + case WSAEINTR: return make_error_condition(errc::interrupted); + case WSAEINVAL: return make_error_condition(errc::invalid_argument); + case WSAEISCONN: return make_error_condition(errc::already_connected); + case WSAEMFILE: return make_error_condition(errc::too_many_files_open); + case WSAEMSGSIZE: return make_error_condition(errc::message_size); + case WSAENAMETOOLONG: return make_error_condition(errc::filename_too_long); + case WSAENETDOWN: return make_error_condition(errc::network_down); + case WSAENETRESET: return make_error_condition(errc::network_reset); + case WSAENETUNREACH: return make_error_condition(errc::network_unreachable); + case WSAENOBUFS: return make_error_condition(errc::no_buffer_space); + case WSAENOPROTOOPT: return make_error_condition(errc::no_protocol_option); + case WSAENOTCONN: return make_error_condition(errc::not_connected); + case WSAENOTSOCK: return make_error_condition(errc::not_a_socket); + case WSAEOPNOTSUPP: return make_error_condition(errc::operation_not_supported); + case WSAEPROTONOSUPPORT: return make_error_condition(errc::protocol_not_supported); + case WSAEPROTOTYPE: return make_error_condition(errc::wrong_protocol_type); + case WSAETIMEDOUT: return make_error_condition(errc::timed_out); + case WSAEWOULDBLOCK: return make_error_condition(errc::operation_would_block); + default: return error_condition(ev, system_category()); + } +} + +} // end namespace llvm + +#endif // LLVM_ON_WIN32 diff --git a/utils/KillTheDoctor/system_error.h b/utils/KillTheDoctor/system_error.h new file mode 100644 index 0000000000..941341270d --- /dev/null +++ b/utils/KillTheDoctor/system_error.h @@ -0,0 +1,662 @@ +//===---------------------------- system_error ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This was lifted from libc++ and modified for C++03. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SYSTEM_SYSTEM_ERROR_H +#define LLVM_SYSTEM_SYSTEM_ERROR_H + +/* + system_error synopsis + +namespace std +{ + +class error_category +{ +public: + virtual ~error_category(); + + error_category(const error_category&) = delete; + error_category& operator=(const error_category&) = delete; + + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int ev) const; + virtual bool equivalent(int code, const error_condition& condition) const; + virtual bool equivalent(const error_code& code, int condition) const; + virtual std::string message(int ev) const = 0; + + bool operator==(const error_category& rhs) const; + bool operator!=(const error_category& rhs) const; + bool operator<(const error_category& rhs) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +template struct is_error_code_enum + : public false_type {}; + +template struct is_error_condition_enum + : public false_type {}; + +class error_code +{ +public: + // constructors: + error_code(); + error_code(int val, const error_category& cat); + template + error_code(ErrorCodeEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template + error_code& operator=(ErrorCodeEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + error_condition default_error_condition() const; + std::string message() const; + explicit operator bool() const; +}; + +// non-member functions: +bool operator<(const error_code& lhs, const error_code& rhs); +template + basic_ostream& + operator<<(basic_ostream& os, const error_code& ec); + +class error_condition +{ +public: + // constructors: + error_condition(); + error_condition(int val, const error_category& cat); + template + error_condition(ErrorConditionEnum e); + + // modifiers: + void assign(int val, const error_category& cat); + template + error_condition& operator=(ErrorConditionEnum e); + void clear(); + + // observers: + int value() const; + const error_category& category() const; + std::string message() const; + explicit operator bool() const; +}; + +bool operator<(const error_condition& lhs, const error_condition& rhs); + +class system_error + : public runtime_error +{ +public: + system_error(error_code ec, const std::string& what_arg); + system_error(error_code ec, const char* what_arg); + system_error(error_code ec); + system_error(int ev, const error_category& ecat, const std::string& what_arg); + system_error(int ev, const error_category& ecat, const char* what_arg); + system_error(int ev, const error_category& ecat); + + const error_code& code() const throw(); + const char* what() const throw(); +}; + +enum class errc +{ + address_family_not_supported, // EAFNOSUPPORT + address_in_use, // EADDRINUSE + address_not_available, // EADDRNOTAVAIL + already_connected, // EISCONN + argument_list_too_long, // E2BIG + argument_out_of_domain, // EDOM + bad_address, // EFAULT + bad_file_descriptor, // EBADF + bad_message, // EBADMSG + broken_pipe, // EPIPE + connection_aborted, // ECONNABORTED + connection_already_in_progress, // EALREADY + connection_refused, // ECONNREFUSED + connection_reset, // ECONNRESET + cross_device_link, // EXDEV + destination_address_required, // EDESTADDRREQ + device_or_resource_busy, // EBUSY + directory_not_empty, // ENOTEMPTY + executable_format_error, // ENOEXEC + file_exists, // EEXIST + file_too_large, // EFBIG + filename_too_long, // ENAMETOOLONG + function_not_supported, // ENOSYS + host_unreachable, // EHOSTUNREACH + identifier_removed, // EIDRM + illegal_byte_sequence, // EILSEQ + inappropriate_io_control_operation, // ENOTTY + interrupted, // EINTR + invalid_argument, // EINVAL + invalid_seek, // ESPIPE + io_error, // EIO + is_a_directory, // EISDIR + message_size, // EMSGSIZE + network_down, // ENETDOWN + network_reset, // ENETRESET + network_unreachable, // ENETUNREACH + no_buffer_space, // ENOBUFS + no_child_process, // ECHILD + no_link, // ENOLINK + no_lock_available, // ENOLCK + no_message_available, // ENODATA + no_message, // ENOMSG + no_protocol_option, // ENOPROTOOPT + no_space_on_device, // ENOSPC + no_stream_resources, // ENOSR + no_such_device_or_address, // ENXIO + no_such_device, // ENODEV + no_such_file_or_directory, // ENOENT + no_such_process, // ESRCH + not_a_directory, // ENOTDIR + not_a_socket, // ENOTSOCK + not_a_stream, // ENOSTR + not_connected, // ENOTCONN + not_enough_memory, // ENOMEM + not_supported, // ENOTSUP + operation_canceled, // ECANCELED + operation_in_progress, // EINPROGRESS + operation_not_permitted, // EPERM + operation_not_supported, // EOPNOTSUPP + operation_would_block, // EWOULDBLOCK + owner_dead, // EOWNERDEAD + permission_denied, // EACCES + protocol_error, // EPROTO + protocol_not_supported, // EPROTONOSUPPORT + read_only_file_system, // EROFS + resource_deadlock_would_occur, // EDEADLK + resource_unavailable_try_again, // EAGAIN + result_out_of_range, // ERANGE + state_not_recoverable, // ENOTRECOVERABLE + stream_timeout, // ETIME + text_file_busy, // ETXTBSY + timed_out, // ETIMEDOUT + too_many_files_open_in_system, // ENFILE + too_many_files_open, // EMFILE + too_many_links, // EMLINK + too_many_symbolic_link_levels, // ELOOP + value_too_large, // EOVERFLOW + wrong_protocol_type // EPROTOTYPE +}; + +template <> struct is_error_condition_enum : true_type { } + +error_code make_error_code(errc e); +error_condition make_error_condition(errc e); + +// Comparison operators: +bool operator==(const error_code& lhs, const error_code& rhs); +bool operator==(const error_code& lhs, const error_condition& rhs); +bool operator==(const error_condition& lhs, const error_code& rhs); +bool operator==(const error_condition& lhs, const error_condition& rhs); +bool operator!=(const error_code& lhs, const error_code& rhs); +bool operator!=(const error_code& lhs, const error_condition& rhs); +bool operator!=(const error_condition& lhs, const error_code& rhs); +bool operator!=(const error_condition& lhs, const error_condition& rhs); + +template <> struct hash; + +} // std + +*/ + +#include "llvm/Config/config.h" +#include "llvm/Support/type_traits.h" +#include +#include + +namespace llvm { + +template +struct integral_constant { + typedef T value_type; + static const value_type value = v; + typedef integral_constant type; + operator value_type() { return value; } +}; + +typedef integral_constant true_type; +typedef integral_constant false_type; + +// is_error_code_enum + +template struct is_error_code_enum : public false_type {}; + +// is_error_condition_enum + +template struct is_error_condition_enum : public false_type {}; + +// Some error codes are not present on all platforms, so we provide equivalents +// for them: + +//enum class errc +struct errc { +enum _ { + success = 0, + address_family_not_supported = EAFNOSUPPORT, + address_in_use = EADDRINUSE, + address_not_available = EADDRNOTAVAIL, + already_connected = EISCONN, + argument_list_too_long = E2BIG, + argument_out_of_domain = EDOM, + bad_address = EFAULT, + bad_file_descriptor = EBADF, + bad_message = EBADMSG, + broken_pipe = EPIPE, + connection_aborted = ECONNABORTED, + connection_already_in_progress = EALREADY, + connection_refused = ECONNREFUSED, + connection_reset = ECONNRESET, + cross_device_link = EXDEV, + destination_address_required = EDESTADDRREQ, + device_or_resource_busy = EBUSY, + directory_not_empty = ENOTEMPTY, + executable_format_error = ENOEXEC, + file_exists = EEXIST, + file_too_large = EFBIG, + filename_too_long = ENAMETOOLONG, + function_not_supported = ENOSYS, + host_unreachable = EHOSTUNREACH, + identifier_removed = EIDRM, + illegal_byte_sequence = EILSEQ, + inappropriate_io_control_operation = ENOTTY, + interrupted = EINTR, + invalid_argument = EINVAL, + invalid_seek = ESPIPE, + io_error = EIO, + is_a_directory = EISDIR, + message_size = EMSGSIZE, + network_down = ENETDOWN, + network_reset = ENETRESET, + network_unreachable = ENETUNREACH, + no_buffer_space = ENOBUFS, + no_child_process = ECHILD, + no_link = ENOLINK, + no_lock_available = ENOLCK, +#ifdef ENODATA + no_message_available = ENODATA, +#else + no_message_available = ENOMSG, +#endif + no_message = ENOMSG, + no_protocol_option = ENOPROTOOPT, + no_space_on_device = ENOSPC, +#ifdef ENOSR + no_stream_resources = ENOSR, +#else + no_stream_resources = ENOMEM, +#endif + no_such_device_or_address = ENXIO, + no_such_device = ENODEV, + no_such_file_or_directory = ENOENT, + no_such_process = ESRCH, + not_a_directory = ENOTDIR, + not_a_socket = ENOTSOCK, +#ifdef ENOSTR + not_a_stream = ENOSTR, +#else + not_a_stream = EINVAL, +#endif + not_connected = ENOTCONN, + not_enough_memory = ENOMEM, + not_supported = ENOTSUP, + operation_canceled = ECANCELED, + operation_in_progress = EINPROGRESS, + operation_not_permitted = EPERM, + operation_not_supported = EOPNOTSUPP, + operation_would_block = EWOULDBLOCK, + owner_dead = EOWNERDEAD, + permission_denied = EACCES, + protocol_error = EPROTO, + protocol_not_supported = EPROTONOSUPPORT, + read_only_file_system = EROFS, + resource_deadlock_would_occur = EDEADLK, + resource_unavailable_try_again = EAGAIN, + result_out_of_range = ERANGE, + state_not_recoverable = ENOTRECOVERABLE, +#ifdef ETIME + stream_timeout = ETIME, +#else + stream_timeout = ETIMEDOUT, +#endif + text_file_busy = ETXTBSY, + timed_out = ETIMEDOUT, + too_many_files_open_in_system = ENFILE, + too_many_files_open = EMFILE, + too_many_links = EMLINK, + too_many_symbolic_link_levels = ELOOP, + value_too_large = EOVERFLOW, + wrong_protocol_type = EPROTOTYPE +}; + + _ v_; + + errc(_ v) : v_(v) {} + operator int() const {return v_;} +}; + +template <> struct is_error_condition_enum : true_type { }; + +template <> struct is_error_condition_enum : true_type { }; + +class error_condition; +class error_code; + +// class error_category + +class _do_message; + +class error_category +{ +public: + virtual ~error_category(); + +private: + error_category(); + error_category(const error_category&);// = delete; + error_category& operator=(const error_category&);// = delete; + +public: + virtual const char* name() const = 0; + virtual error_condition default_error_condition(int _ev) const; + virtual bool equivalent(int _code, const error_condition& _condition) const; + virtual bool equivalent(const error_code& _code, int _condition) const; + virtual std::string message(int _ev) const = 0; + + bool operator==(const error_category& _rhs) const {return this == &_rhs;} + + bool operator!=(const error_category& _rhs) const {return !(*this == _rhs);} + + bool operator< (const error_category& _rhs) const {return this < &_rhs;} + + friend class _do_message; +}; + +class _do_message : public error_category +{ +public: + virtual std::string message(int ev) const; +}; + +const error_category& generic_category(); +const error_category& system_category(); + +class error_condition +{ + int _val_; + const error_category* _cat_; +public: + error_condition() : _val_(0), _cat_(&generic_category()) {} + + error_condition(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template + error_condition(E _e, typename enable_if_c< + is_error_condition_enum::value + >::type* = 0) + {*this = make_error_condition(_e);} + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template + typename enable_if_c + < + is_error_condition_enum::value, + error_condition& + >::type + operator=(E _e) + {*this = make_error_condition(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &generic_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + std::string message() const; + + // explicit + operator bool() const {return _val_ != 0;} +}; + +inline error_condition make_error_condition(errc _e) { + return error_condition(static_cast(_e), generic_category()); +} + +inline bool operator<(const error_condition& _x, const error_condition& _y) { + return _x.category() < _y.category() + || _x.category() == _y.category() && _x.value() < _y.value(); +} + +// error_code + +class error_code { + int _val_; + const error_category* _cat_; +public: + error_code() : _val_(0), _cat_(&system_category()) {} + + error_code(int _val, const error_category& _cat) + : _val_(_val), _cat_(&_cat) {} + + template + error_code(E _e, typename enable_if_c< + is_error_code_enum::value + >::type* = 0) { + *this = make_error_code(_e); + } + + void assign(int _val, const error_category& _cat) { + _val_ = _val; + _cat_ = &_cat; + } + + template + typename enable_if_c + < + is_error_code_enum::value, + error_code& + >::type + operator=(E _e) + {*this = make_error_code(_e); return *this;} + + void clear() { + _val_ = 0; + _cat_ = &system_category(); + } + + int value() const {return _val_;} + + const error_category& category() const {return *_cat_;} + + error_condition default_error_condition() const + {return _cat_->default_error_condition(_val_);} + + std::string message() const; + + // explicit + operator bool() const {return _val_ != 0;} +}; + +inline error_code make_error_code(errc _e) { + return error_code(static_cast(_e), generic_category()); +} + +inline bool operator<(const error_code& _x, const error_code& _y) { + return _x.category() < _y.category() + || _x.category() == _y.category() && _x.value() < _y.value(); +} + +inline bool operator==(const error_code& _x, const error_code& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator==(const error_code& _x, const error_condition& _y) { + return _x.category().equivalent(_x.value(), _y) + || _y.category().equivalent(_x, _y.value()); +} + +inline bool operator==(const error_condition& _x, const error_code& _y) { + return _y == _x; +} + +inline bool operator==(const error_condition& _x, const error_condition& _y) { + return _x.category() == _y.category() && _x.value() == _y.value(); +} + +inline bool operator!=(const error_code& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_code& _x, const error_condition& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_code& _y) { + return !(_x == _y); +} + +inline bool operator!=(const error_condition& _x, const error_condition& _y) { + return !(_x == _y); +} + +// system_error + +class system_error : public std::runtime_error { + error_code _ec_; +public: + system_error(error_code _ec, const std::string& _what_arg); + system_error(error_code _ec, const char* _what_arg); + system_error(error_code _ec); + system_error(int _ev, const error_category& _ecat, + const std::string& _what_arg); + system_error(int _ev, const error_category& _ecat, const char* _what_arg); + system_error(int _ev, const error_category& _ecat); + ~system_error() throw(); + + const error_code& code() const throw() {return _ec_;} + +private: + static std::string _init(const error_code&, std::string); +}; + +void _throw_system_error(int ev, const char* what_arg); + +} // end namespace llvm + +#ifdef LLVM_ON_WIN32 +#include +#include + +namespace llvm { + +// To construct an error_code after a API error: +// +// error_code( ::GetLastError(), system_category() ) +struct windows_error { +enum _ { + success = 0, + // These names and values are based on Windows winerror.h + invalid_function = ERROR_INVALID_FUNCTION, + file_not_found = ERROR_FILE_NOT_FOUND, + path_not_found = ERROR_PATH_NOT_FOUND, + too_many_open_files = ERROR_TOO_MANY_OPEN_FILES, + access_denied = ERROR_ACCESS_DENIED, + invalid_handle = ERROR_INVALID_HANDLE, + arena_trashed = ERROR_ARENA_TRASHED, + not_enough_memory = ERROR_NOT_ENOUGH_MEMORY, + invalid_block = ERROR_INVALID_BLOCK, + bad_environment = ERROR_BAD_ENVIRONMENT, + bad_format = ERROR_BAD_FORMAT, + invalid_access = ERROR_INVALID_ACCESS, + outofmemory = ERROR_OUTOFMEMORY, + invalid_drive = ERROR_INVALID_DRIVE, + current_directory = ERROR_CURRENT_DIRECTORY, + not_same_device = ERROR_NOT_SAME_DEVICE, + no_more_files = ERROR_NO_MORE_FILES, + write_protect = ERROR_WRITE_PROTECT, + bad_unit = ERROR_BAD_UNIT, + not_ready = ERROR_NOT_READY, + bad_command = ERROR_BAD_COMMAND, + crc = ERROR_CRC, + bad_length = ERROR_BAD_LENGTH, + seek = ERROR_SEEK, + not_dos_disk = ERROR_NOT_DOS_DISK, + sector_not_found = ERROR_SECTOR_NOT_FOUND, + out_of_paper = ERROR_OUT_OF_PAPER, + write_fault = ERROR_WRITE_FAULT, + read_fault = ERROR_READ_FAULT, + gen_failure = ERROR_GEN_FAILURE, + sharing_violation = ERROR_SHARING_VIOLATION, + lock_violation = ERROR_LOCK_VIOLATION, + wrong_disk = ERROR_WRONG_DISK, + sharing_buffer_exceeded = ERROR_SHARING_BUFFER_EXCEEDED, + handle_eof = ERROR_HANDLE_EOF, + handle_disk_full= ERROR_HANDLE_DISK_FULL, + rem_not_list = ERROR_REM_NOT_LIST, + dup_name = ERROR_DUP_NAME, + bad_net_path = ERROR_BAD_NETPATH, + network_busy = ERROR_NETWORK_BUSY, + // ... + file_exists = ERROR_FILE_EXISTS, + cannot_make = ERROR_CANNOT_MAKE, + // ... + broken_pipe = ERROR_BROKEN_PIPE, + open_failed = ERROR_OPEN_FAILED, + buffer_overflow = ERROR_BUFFER_OVERFLOW, + disk_full= ERROR_DISK_FULL, + // ... + lock_failed = ERROR_LOCK_FAILED, + busy = ERROR_BUSY, + cancel_violation = ERROR_CANCEL_VIOLATION, + already_exists = ERROR_ALREADY_EXISTS + // ... + + // TODO: add more Windows errors +}; + _ v_; + + windows_error(_ v) : v_(v) {} + explicit windows_error(DWORD v) : v_(_(v)) {} + operator int() const {return v_;} +}; + + +template <> struct is_error_code_enum : true_type { }; + +template <> struct is_error_code_enum : true_type { }; + +inline error_code make_error_code(windows_error e) { + return error_code(static_cast(e), system_category()); +} + +} // end namespace llvm + +#endif // LLVM_ON_WINDOWS + +#endif -- cgit v1.2.3