From 8e716a3a7eec9f03ab42b78d27a362b9bce2817d Mon Sep 17 00:00:00 2001 From: "Dr. Chat" Date: Fri, 11 Sep 2015 17:07:12 -0500 Subject: [PATCH] Exception handler abstraction class --- src/xenia/base/exception_handler.h | 49 ++++++++++++++++++++ src/xenia/base/exception_handler_win.cc | 59 +++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/xenia/base/exception_handler.h create mode 100644 src/xenia/base/exception_handler_win.cc diff --git a/src/xenia/base/exception_handler.h b/src/xenia/base/exception_handler.h new file mode 100644 index 000000000..8c387eb12 --- /dev/null +++ b/src/xenia/base/exception_handler.h @@ -0,0 +1,49 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_BASE_EXCEPTION_HANDLER_H_ +#define XENIA_BASE_EXCEPTION_HANDLER_H_ + +#include +#include + +namespace xe { +class ExceptionHandler { + public: + struct Info { + enum { + kInvalidException = 0, + kAccessViolation, + } code = kInvalidException; + + uint64_t pc = 0; // Program counter address. RIP on x64. + uint64_t fault_address = + 0; // In case of AV, address that was read from/written to. + + void* thread_context = nullptr; // Platform-specific thread context info. + }; + typedef std::function Handler; + + // Static initialization. Only call this once! + static bool Initialize(); + + // Install an exception handler. Returns an ID which you can save to remove + // this later. This will install the exception handler in the last place + // on Windows. + static uint32_t Install(Handler fn); + static bool Remove(uint32_t id); + + static const std::vector& handlers() { return handlers_; } + + private: + static std::vector handlers_; +}; +}; // namespace xe + +#endif // XENIA_BASE_EXCEPTION_HANDLER_H_ \ No newline at end of file diff --git a/src/xenia/base/exception_handler_win.cc b/src/xenia/base/exception_handler_win.cc new file mode 100644 index 000000000..0c432ace3 --- /dev/null +++ b/src/xenia/base/exception_handler_win.cc @@ -0,0 +1,59 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2015 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/base/exception_handler.h" + +#include "xenia/base/platform_win.h" + +namespace xe { +std::vector ExceptionHandler::handlers_; + +LONG CALLBACK ExceptionHandlerCallback(PEXCEPTION_POINTERS ex_info) { + // Visual Studio SetThreadName + if (ex_info->ExceptionRecord->ExceptionCode == 0x406D1388) { + return EXCEPTION_CONTINUE_SEARCH; + } + + auto code = ex_info->ExceptionRecord->ExceptionCode; + ExceptionHandler::Info info; + info.pc = ex_info->ContextRecord->Rip; + info.thread_context = ex_info->ContextRecord; + + switch (code) { + case STATUS_ACCESS_VIOLATION: + info.code = ExceptionHandler::Info::kAccessViolation; + info.fault_address = ex_info->ExceptionRecord->ExceptionInformation[1]; + break; + } + + // Only call a handler if we support this type of exception. + if (info.code != ExceptionHandler::Info::kInvalidException) { + for (auto handler : ExceptionHandler::handlers()) { + if (handler(&info)) { + // Exception handled. + return EXCEPTION_CONTINUE_EXECUTION; + } + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +bool ExceptionHandler::Initialize() { + AddVectoredExceptionHandler(0, ExceptionHandlerCallback); + + // TODO: Do we need a continue handler if a debugger is attached? + return true; +} + +uint32_t ExceptionHandler::Install(std::function fn) { + handlers_.push_back(fn); + return 0; +} +} \ No newline at end of file