Add KillTheDoctor.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116216 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael J. Spencer 2010-10-11 19:55:38 +00:00
parent c4bd6fbf4b
commit bbb9ea7b70
5 changed files with 1560 additions and 0 deletions

View File

@ -389,6 +389,11 @@ if( LLVM_INCLUDE_TESTS )
add_subdirectory(test)
add_subdirectory(utils/unittest)
add_subdirectory(unittests)
if (WIN32)
# This utility is used to prevent chrashing tests from calling Dr. Watson on
# Windows.
add_subdirectory(utils/KillTheDoctor)
endif()
endif()
add_subdirectory(cmake/modules)

View File

@ -0,0 +1,6 @@
add_executable(KillTheDoctor
KillTheDoctor.cpp
system_error.cpp
)
target_link_libraries(KillTheDoctor LLVMSupport LLVMSystem)

View File

@ -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;
}

View File

@ -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

View File

@ -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