Exception handler abstraction class

This commit is contained in:
Dr. Chat 2015-09-11 17:07:12 -05:00
parent edef57065b
commit 8e716a3a7e
2 changed files with 108 additions and 0 deletions

View File

@ -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 <functional>
#include <vector>
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<bool(Info* ex_info)> 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<Handler>& handlers() { return handlers_; }
private:
static std::vector<Handler> handlers_;
};
}; // namespace xe
#endif // XENIA_BASE_EXCEPTION_HANDLER_H_

View File

@ -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::Handler> 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<bool(Info* ex_info)> fn) {
handlers_.push_back(fn);
return 0;
}
}