summaryrefslogtreecommitdiff
path: root/utils/KillTheDoctor
diff options
context:
space:
mode:
authorMichael J. Spencer <bigcheesegs@gmail.com>2010-10-11 19:55:38 +0000
committerMichael J. Spencer <bigcheesegs@gmail.com>2010-10-11 19:55:38 +0000
commitbbb9ea7b70971df53eedfb42fc9cb606f815eaaa (patch)
treee898eff89f6d5f9e063c953545446a2aab89d788 /utils/KillTheDoctor
parentc4bd6fbf4bdf4dd3d9f69ec7bed1ea7ebfaab621 (diff)
downloadllvm-bbb9ea7b70971df53eedfb42fc9cb606f815eaaa.tar.gz
llvm-bbb9ea7b70971df53eedfb42fc9cb606f815eaaa.tar.bz2
llvm-bbb9ea7b70971df53eedfb42fc9cb606f815eaaa.tar.xz
Add KillTheDoctor.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116216 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/KillTheDoctor')
-rw-r--r--utils/KillTheDoctor/CMakeLists.txt6
-rw-r--r--utils/KillTheDoctor/KillTheDoctor.cpp600
-rw-r--r--utils/KillTheDoctor/system_error.cpp287
-rw-r--r--utils/KillTheDoctor/system_error.h662
4 files changed, 1555 insertions, 0 deletions
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 <algorithm>
+#include <cerrno>
+#include <cstdlib>
+#include <map>
+#include <string>
+#include <Windows.h>
+#include <WinError.h>
+#include <Dbghelp.h>
+#include <psapi.h>
+using namespace llvm;
+
+#undef max
+
+namespace {
+ cl::opt<std::string> ProgramToRun(cl::Positional,
+ cl::desc("<program to run>"));
+ cl::list<std::string> Argv(cl::ConsumeAfter,
+ cl::desc("<program arguments>..."));
+ cl::opt<bool> TraceExecution("x",
+ cl::desc("Print detailed output about what is being run to stderr."));
+ cl::opt<unsigned> Timeout("t", cl::init(0),
+ cl::desc("Set maximum runtime in seconds. Defaults to infinite."));
+ cl::opt<bool> NoUser32("no-user32",
+ cl::desc("Terminate process if it loads user32.dll."));
+
+ StringRef ToolName;
+
+ template <typename HandleType>
+ 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<FileMappingHandle> FileMappingScopedHandle;
+ typedef ScopedHandle<MappedViewOfFileHandle> MappedViewOfFileScopedHandle;
+ typedef ScopedHandle<ProcessHandle> ProcessScopedHandle;
+ typedef ScopedHandle<ThreadHandle> ThreadScopedHandle;
+ typedef ScopedHandle<TokenHandle> TokenScopedHandle;
+ typedef ScopedHandle<FileHandle> 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<StringRef, 12> 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 "<unknown>";
+ }
+}
+
+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<uint32_t>::max() / 1000) {
+ errs() << ToolName << ": Timeout value too large, must be less than: "
+ << std::numeric_limits<uint32_t>::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<std::string>::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<DWORD, HANDLE> 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<uint32_t>::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<uint32_t>(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<DWORD, HANDLE>::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 = "<failed to get file name from file handle> : ";
+ 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: <unknown>\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 <string>
+#include <cstring>
+
+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 <Windows.h>
+#include <WinError.h>
+
+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<LPCSTR>(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 <class T> struct is_error_code_enum
+ : public false_type {};
+
+template <class T> struct is_error_condition_enum
+ : public false_type {};
+
+class error_code
+{
+public:
+ // constructors:
+ error_code();
+ error_code(int val, const error_category& cat);
+ template <class ErrorCodeEnum>
+ error_code(ErrorCodeEnum e);
+
+ // modifiers:
+ void assign(int val, const error_category& cat);
+ template <class ErrorCodeEnum>
+ 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 <class charT, class traits>
+ basic_ostream<charT,traits>&
+ operator<<(basic_ostream<charT,traits>& os, const error_code& ec);
+
+class error_condition
+{
+public:
+ // constructors:
+ error_condition();
+ error_condition(int val, const error_category& cat);
+ template <class ErrorConditionEnum>
+ error_condition(ErrorConditionEnum e);
+
+ // modifiers:
+ void assign(int val, const error_category& cat);
+ template <class ErrorConditionEnum>
+ 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<errc> : 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::error_code>;
+
+} // std
+
+*/
+
+#include "llvm/Config/config.h"
+#include "llvm/Support/type_traits.h"
+#include <cerrno>
+#include <string>
+
+namespace llvm {
+
+template <class T, T v>
+struct integral_constant {
+ typedef T value_type;
+ static const value_type value = v;
+ typedef integral_constant<T,v> type;
+ operator value_type() { return value; }
+};
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+// is_error_code_enum
+
+template <class Tp> struct is_error_code_enum : public false_type {};
+
+// is_error_condition_enum
+
+template <class Tp> 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<errc> : true_type { };
+
+template <> struct is_error_condition_enum<errc::_> : 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 <class E>
+ error_condition(E _e, typename enable_if_c<
+ is_error_condition_enum<E>::value
+ >::type* = 0)
+ {*this = make_error_condition(_e);}
+
+ void assign(int _val, const error_category& _cat) {
+ _val_ = _val;
+ _cat_ = &_cat;
+ }
+
+ template <class E>
+ typename enable_if_c
+ <
+ is_error_condition_enum<E>::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<int>(_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 <class E>
+ error_code(E _e, typename enable_if_c<
+ is_error_code_enum<E>::value
+ >::type* = 0) {
+ *this = make_error_code(_e);
+ }
+
+ void assign(int _val, const error_category& _cat) {
+ _val_ = _val;
+ _cat_ = &_cat;
+ }
+
+ template <class E>
+ typename enable_if_c
+ <
+ is_error_code_enum<E>::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<int>(_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 <Windows.h>
+#include <WinError.h>
+
+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<windows_error> : true_type { };
+
+template <> struct is_error_code_enum<windows_error::_> : true_type { };
+
+inline error_code make_error_code(windows_error e) {
+ return error_code(static_cast<int>(e), system_category());
+}
+
+} // end namespace llvm
+
+#endif // LLVM_ON_WINDOWS
+
+#endif