mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-12 13:30:51 +00:00
Add KillTheDoctor.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116216 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
c4bd6fbf4b
commit
bbb9ea7b70
@ -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)
|
||||
|
6
utils/KillTheDoctor/CMakeLists.txt
Normal file
6
utils/KillTheDoctor/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
add_executable(KillTheDoctor
|
||||
KillTheDoctor.cpp
|
||||
system_error.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(KillTheDoctor LLVMSupport LLVMSystem)
|
600
utils/KillTheDoctor/KillTheDoctor.cpp
Normal file
600
utils/KillTheDoctor/KillTheDoctor.cpp
Normal 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;
|
||||
}
|
287
utils/KillTheDoctor/system_error.cpp
Normal file
287
utils/KillTheDoctor/system_error.cpp
Normal 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
|
662
utils/KillTheDoctor/system_error.h
Normal file
662
utils/KillTheDoctor/system_error.h
Normal 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
|
Loading…
Reference in New Issue
Block a user