A new debugger.
Lots of bugs/rough edges/etc - issues will be filed. Old-style debugging still works (just use --emit_source_annotations to get the helpful movs back and --break_on_instruction will still fire).
This commit is contained in:
@@ -13,37 +13,61 @@
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/x64_context.h"
|
||||
|
||||
namespace xe {
|
||||
class ExceptionHandler {
|
||||
|
||||
class Exception {
|
||||
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.
|
||||
enum class Code {
|
||||
kInvalidException = 0,
|
||||
kAccessViolation,
|
||||
kIllegalInstruction,
|
||||
};
|
||||
typedef std::function<bool(Info* ex_info)> Handler;
|
||||
|
||||
// Static initialization. Only call this once!
|
||||
static bool Initialize();
|
||||
void InitializeAccessViolation(X64Context* thread_context,
|
||||
uint64_t fault_address) {
|
||||
code_ = Code::kAccessViolation;
|
||||
thread_context_ = thread_context;
|
||||
fault_address_ = fault_address;
|
||||
}
|
||||
void InitializeIllegalInstruction(X64Context* thread_context) {
|
||||
code_ = Code::kIllegalInstruction;
|
||||
thread_context_ = thread_context;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// TODO: ID support!
|
||||
static uint32_t Install(Handler fn);
|
||||
static bool Remove(uint32_t id);
|
||||
Code code() const { return code_; }
|
||||
|
||||
static const std::vector<Handler>& handlers() { return handlers_; }
|
||||
// Returns the platform-specific thread context info.
|
||||
X64Context* thread_context() const { return thread_context_; }
|
||||
|
||||
// Returns the program counter where the exception occurred.
|
||||
// RIP on x64.
|
||||
uint64_t pc() const { return thread_context_->rip; }
|
||||
// Sets the program counter where execution will resume.
|
||||
void set_resume_pc(uint64_t pc) { thread_context_->rip = pc; }
|
||||
|
||||
// In case of AV, address that was read from/written to.
|
||||
uint64_t fault_address() const { return fault_address_; }
|
||||
|
||||
private:
|
||||
static std::vector<Handler> handlers_;
|
||||
Code code_ = Code::kInvalidException;
|
||||
X64Context* thread_context_ = nullptr;
|
||||
uint64_t fault_address_ = 0;
|
||||
};
|
||||
}; // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_EXCEPTION_HANDLER_H_
|
||||
class ExceptionHandler {
|
||||
public:
|
||||
typedef bool (*Handler)(Exception* ex, void* data);
|
||||
|
||||
// Installs an exception handler.
|
||||
// Handlers are called in the order they are installed.
|
||||
static void Install(Handler fn, void* data);
|
||||
|
||||
// Uninstalls a previously-installed exception handler.
|
||||
static void Uninstall(Handler fn, void* data);
|
||||
};
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_EXCEPTION_HANDLER_H_
|
||||
|
||||
@@ -9,53 +9,118 @@
|
||||
|
||||
#include "xenia/base/exception_handler.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/math.h"
|
||||
#include "xenia/base/platform_win.h"
|
||||
|
||||
namespace xe {
|
||||
std::vector<ExceptionHandler::Handler> ExceptionHandler::handlers_;
|
||||
|
||||
// Handle of the added VectoredExceptionHandler.
|
||||
void* veh_handle_ = nullptr;
|
||||
// Handle of the added VectoredContinueHandler.
|
||||
void* vch_handle_ = nullptr;
|
||||
|
||||
// This can be as large as needed, but isn't often needed.
|
||||
// As we will be sometimes firing many exceptions we want to avoid having to
|
||||
// scan the table too much or invoke many custom handlers.
|
||||
constexpr size_t kMaxHandlerCount = 8;
|
||||
|
||||
// All custom handlers, left-aligned and null terminated.
|
||||
// Executed in order.
|
||||
std::pair<ExceptionHandler::Handler, void*> handlers_[kMaxHandlerCount];
|
||||
|
||||
LONG CALLBACK ExceptionHandlerCallback(PEXCEPTION_POINTERS ex_info) {
|
||||
// Visual Studio SetThreadName
|
||||
// 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;
|
||||
// TODO(benvanik): avoid this by mapping X64Context virtual?
|
||||
X64Context thread_context;
|
||||
thread_context.rip = ex_info->ContextRecord->Rip;
|
||||
thread_context.eflags = ex_info->ContextRecord->EFlags;
|
||||
std::memcpy(thread_context.int_registers, &ex_info->ContextRecord->Rax,
|
||||
sizeof(thread_context.int_registers));
|
||||
std::memcpy(thread_context.xmm_registers, &ex_info->ContextRecord->Xmm0,
|
||||
sizeof(thread_context.xmm_registers));
|
||||
|
||||
switch (code) {
|
||||
case STATUS_ACCESS_VIOLATION:
|
||||
info.code = ExceptionHandler::Info::kAccessViolation;
|
||||
info.fault_address = ex_info->ExceptionRecord->ExceptionInformation[1];
|
||||
// http://msdn.microsoft.com/en-us/library/ms679331(v=vs.85).aspx
|
||||
// http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx
|
||||
Exception ex;
|
||||
switch (ex_info->ExceptionRecord->ExceptionCode) {
|
||||
case STATUS_ILLEGAL_INSTRUCTION:
|
||||
ex.InitializeIllegalInstruction(&thread_context);
|
||||
break;
|
||||
case STATUS_ACCESS_VIOLATION:
|
||||
ex.InitializeAccessViolation(
|
||||
&thread_context, ex_info->ExceptionRecord->ExceptionInformation[1]);
|
||||
break;
|
||||
default:
|
||||
// Unknown/unhandled type.
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
for (size_t i = 0; i < xe::countof(handlers_) && handlers_[i].first; ++i) {
|
||||
if (handlers_[i].first(&ex, handlers_[i].second)) {
|
||||
// Exception handled.
|
||||
// TODO(benvanik): update all thread state? Dirty flags?
|
||||
ex_info->ContextRecord->Rip = thread_context.rip;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
bool ExceptionHandler::Initialize() {
|
||||
AddVectoredExceptionHandler(0, ExceptionHandlerCallback);
|
||||
void ExceptionHandler::Install(Handler fn, void* data) {
|
||||
if (!veh_handle_) {
|
||||
veh_handle_ = AddVectoredExceptionHandler(1, ExceptionHandlerCallback);
|
||||
|
||||
// TODO: Do we need a continue handler if a debugger is attached?
|
||||
return true;
|
||||
if (IsDebuggerPresent()) {
|
||||
// TODO(benvanik): do we need a continue handler if a debugger is
|
||||
// attached?
|
||||
// vch_handle_ = AddVectoredContinueHandler(1, ExceptionHandlerCallback);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < xe::countof(handlers_); ++i) {
|
||||
if (!handlers_[i].first) {
|
||||
handlers_[i].first = fn;
|
||||
handlers_[i].second = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert_always("Too many exception handlers installed");
|
||||
}
|
||||
|
||||
uint32_t ExceptionHandler::Install(std::function<bool(Info* ex_info)> fn) {
|
||||
handlers_.push_back(fn);
|
||||
void ExceptionHandler::Uninstall(Handler fn, void* data) {
|
||||
for (size_t i = 0; i < xe::countof(handlers_); ++i) {
|
||||
if (handlers_[i].first == fn && handlers_[i].second == data) {
|
||||
for (; i < xe::countof(handlers_) - 1; ++i) {
|
||||
handlers_[i] = handlers_[i + 1];
|
||||
}
|
||||
handlers_[i].first = nullptr;
|
||||
handlers_[i].second = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: ID support!
|
||||
return 0;
|
||||
bool has_any = false;
|
||||
for (size_t i = 0; i < xe::countof(handlers_); ++i) {
|
||||
if (handlers_[i].first) {
|
||||
has_any = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_any) {
|
||||
if (veh_handle_) {
|
||||
RemoveVectoredExceptionHandler(veh_handle_);
|
||||
veh_handle_ = nullptr;
|
||||
}
|
||||
if (vch_handle_) {
|
||||
RemoveVectoredContinueHandler(vch_handle_);
|
||||
vch_handle_ = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
@@ -179,6 +179,12 @@ inline uint64_t rotate_left(uint64_t v, uint8_t sh) {
|
||||
}
|
||||
#endif // XE_PLATFORM_WIN32
|
||||
|
||||
template <typename T>
|
||||
T clamp(T value, T min_value, T max_value) {
|
||||
const T t = value < min_value ? min_value : value;
|
||||
return t > max_value ? max_value : t;
|
||||
}
|
||||
|
||||
// Utilities for SSE values.
|
||||
template <int N>
|
||||
float m128_f32(const __m128& v) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <codecvt>
|
||||
#endif // XE_PLATFORM_LINUX
|
||||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
|
||||
@@ -25,7 +26,7 @@ std::string to_string(const std::wstring& source) {
|
||||
#if NO_CODECVT
|
||||
return std::string(source.begin(), source.end());
|
||||
#else
|
||||
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.to_bytes(source);
|
||||
#endif // XE_PLATFORM_LINUX
|
||||
}
|
||||
@@ -34,7 +35,7 @@ std::wstring to_wstring(const std::string& source) {
|
||||
#if NO_CODECVT
|
||||
return std::wstring(source.begin(), source.end());
|
||||
#else
|
||||
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t> > converter;
|
||||
static std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.from_bytes(source);
|
||||
#endif // XE_PLATFORM_LINUX
|
||||
}
|
||||
@@ -227,4 +228,40 @@ std::wstring find_base_path(const std::wstring& path, wchar_t sep) {
|
||||
}
|
||||
}
|
||||
|
||||
int fuzzy_match(const std::string& pattern, const char* value) {
|
||||
// https://github.com/mattyork/fuzzy/blob/master/lib/fuzzy.js
|
||||
// TODO(benvanik): look at https://github.com/atom/fuzzaldrin/tree/master/src
|
||||
// This does not weight complete substrings or prefixes right, which
|
||||
// kind of sucks.
|
||||
size_t pattern_index = 0;
|
||||
size_t value_length = std::strlen(value);
|
||||
int total_score = 0;
|
||||
int local_score = 0;
|
||||
for (size_t i = 0; i < value_length; ++i) {
|
||||
if (std::tolower(value[i]) == std::tolower(pattern[pattern_index])) {
|
||||
++pattern_index;
|
||||
local_score += 1 + local_score;
|
||||
} else {
|
||||
local_score = 0;
|
||||
}
|
||||
total_score += local_score;
|
||||
}
|
||||
return total_score;
|
||||
}
|
||||
|
||||
std::vector<std::pair<size_t, int>> fuzzy_filter(const std::string& pattern,
|
||||
const void* const* entries,
|
||||
size_t entry_count,
|
||||
size_t string_offset) {
|
||||
std::vector<std::pair<size_t, int>> results;
|
||||
results.reserve(entry_count);
|
||||
for (size_t i = 0; i < entry_count; ++i) {
|
||||
auto entry_value =
|
||||
reinterpret_cast<const char*>(entries[i]) + string_offset;
|
||||
int score = fuzzy_match(pattern, entry_value);
|
||||
results.emplace_back(i, score);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "xenia/base/platform.h"
|
||||
@@ -56,6 +57,27 @@ std::string find_base_path(const std::string& path,
|
||||
std::wstring find_base_path(const std::wstring& path,
|
||||
wchar_t sep = xe::kPathSeparator);
|
||||
|
||||
// Tests a match against a case-insensitive fuzzy filter.
|
||||
// Returns the score of the match or 0 if none.
|
||||
int fuzzy_match(const std::string& pattern, const char* value);
|
||||
|
||||
// Applies a case-insensitive fuzzy filter to the given entries and ranks
|
||||
// results.
|
||||
// Entries is a list of pointers to opaque structs, each of which contains a
|
||||
// char* string at the given offset.
|
||||
// Returns an unsorted list of {original index, score}.
|
||||
std::vector<std::pair<size_t, int>> fuzzy_filter(const std::string& pattern,
|
||||
const void* const* entries,
|
||||
size_t entry_count,
|
||||
size_t string_offset);
|
||||
template <typename T>
|
||||
std::vector<std::pair<size_t, int>> fuzzy_filter(const std::string& pattern,
|
||||
const std::vector<T>& entries,
|
||||
size_t string_offset) {
|
||||
return fuzzy_filter(pattern, reinterpret_cast<void* const*>(entries.data()),
|
||||
entries.size(), string_offset);
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_STRING_H_
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace xe {
|
||||
StringBuffer::StringBuffer(size_t initial_capacity) {
|
||||
buffer_capacity_ = std::max(initial_capacity, static_cast<size_t>(16 * 1024));
|
||||
buffer_ = reinterpret_cast<char*>(malloc(buffer_capacity_));
|
||||
buffer_[0] = 0;
|
||||
}
|
||||
|
||||
StringBuffer::~StringBuffer() {
|
||||
|
||||
@@ -33,6 +33,15 @@ inline std::string to_hex_string(uint64_t value) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
inline std::string to_hex_string(float value) {
|
||||
union {
|
||||
uint32_t ui;
|
||||
float flt;
|
||||
} v;
|
||||
v.flt = value;
|
||||
return to_hex_string(v.ui);
|
||||
}
|
||||
|
||||
inline std::string to_hex_string(double value) {
|
||||
union {
|
||||
uint64_t ui;
|
||||
@@ -57,12 +66,46 @@ inline std::string to_hex_string(const __m128& value) {
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
inline std::string to_string(const __m128& value) {
|
||||
char buffer[128];
|
||||
std::snprintf(buffer, sizeof(buffer), "(%F, %F, %F, %F)", value.m128_f32[0],
|
||||
value.m128_f32[1], value.m128_f32[2], value.m128_f32[3]);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T from_string(const char* value);
|
||||
inline T from_string(const char* value, bool force_hex = false);
|
||||
|
||||
template <>
|
||||
inline uint64_t from_string<uint64_t>(const char* value) {
|
||||
if (std::strchr(value, 'h') != nullptr) {
|
||||
inline int32_t from_string<int32_t>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strchr(value, 'h') != nullptr) {
|
||||
return std::strtol(value, nullptr, 16);
|
||||
} else {
|
||||
return std::strtol(value, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t from_string<uint32_t>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strchr(value, 'h') != nullptr) {
|
||||
return std::strtoul(value, nullptr, 16);
|
||||
} else {
|
||||
return std::strtoul(value, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int64_t from_string<int64_t>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strchr(value, 'h') != nullptr) {
|
||||
return std::strtoll(value, nullptr, 16);
|
||||
} else {
|
||||
return std::strtoll(value, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint64_t from_string<uint64_t>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strchr(value, 'h') != nullptr) {
|
||||
return std::strtoull(value, nullptr, 16);
|
||||
} else {
|
||||
return std::strtoull(value, nullptr, 0);
|
||||
@@ -70,23 +113,38 @@ inline uint64_t from_string<uint64_t>(const char* value) {
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double from_string<double>(const char* value) {
|
||||
if (std::strstr(value, "0x") == value || std::strchr(value, 'h') != nullptr) {
|
||||
inline float from_string<float>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strstr(value, "0x") == value ||
|
||||
std::strchr(value, 'h') != nullptr) {
|
||||
union {
|
||||
uint32_t ui;
|
||||
float flt;
|
||||
} v;
|
||||
v.ui = from_string<uint32_t>(value, force_hex);
|
||||
return v.flt;
|
||||
}
|
||||
return std::strtof(value, nullptr);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline double from_string<double>(const char* value, bool force_hex) {
|
||||
if (force_hex || std::strstr(value, "0x") == value ||
|
||||
std::strchr(value, 'h') != nullptr) {
|
||||
union {
|
||||
uint64_t ui;
|
||||
double dbl;
|
||||
} v;
|
||||
v.ui = from_string<uint64_t>(value);
|
||||
v.ui = from_string<uint64_t>(value, force_hex);
|
||||
return v.dbl;
|
||||
}
|
||||
return std::strtod(value, nullptr);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline vec128_t from_string<vec128_t>(const char* value) {
|
||||
inline vec128_t from_string<vec128_t>(const char* value, bool force_hex) {
|
||||
vec128_t v;
|
||||
char* p = const_cast<char*>(value);
|
||||
bool hex_mode = false;
|
||||
bool hex_mode = force_hex;
|
||||
if (*p == '[') {
|
||||
hex_mode = true;
|
||||
++p;
|
||||
@@ -119,10 +177,10 @@ inline vec128_t from_string<vec128_t>(const char* value) {
|
||||
}
|
||||
|
||||
template <>
|
||||
inline __m128 from_string<__m128>(const char* value) {
|
||||
inline __m128 from_string<__m128>(const char* value, bool force_hex) {
|
||||
__m128 v;
|
||||
char* p = const_cast<char*>(value);
|
||||
bool hex_mode = false;
|
||||
bool hex_mode = force_hex;
|
||||
if (*p == '[') {
|
||||
hex_mode = true;
|
||||
++p;
|
||||
@@ -155,8 +213,8 @@ inline __m128 from_string<__m128>(const char* value) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T from_string(const std::string& value) {
|
||||
return from_string<T>(value.c_str());
|
||||
inline T from_string(const std::string& value, bool force_hex = false) {
|
||||
return from_string<T>(value.c_str(), force_hex);
|
||||
}
|
||||
|
||||
} // namespace string_util
|
||||
|
||||
63
src/xenia/base/x64_context.cc
Normal file
63
src/xenia/base/x64_context.cc
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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/x64_context.h"
|
||||
|
||||
#include "xenia/base/assert.h"
|
||||
#include "xenia/base/string_util.h"
|
||||
|
||||
namespace xe {
|
||||
|
||||
// NOTE: this order matches 1:1 with the X64Register enum.
|
||||
static const char* kRegisterNames[] = {
|
||||
"rip", "eflags", "rax", "rcx", "rdx", "rbx", "rsp",
|
||||
"rbp", "rsi", "rdi", "r8", "r9", "r10", "r11",
|
||||
"r12", "r13", "r14", "r15", "xmm0", "xmm1", "xmm2",
|
||||
"xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9",
|
||||
"xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15",
|
||||
};
|
||||
|
||||
const char* X64Context::GetRegisterName(X64Register reg) {
|
||||
return kRegisterNames[static_cast<int>(reg)];
|
||||
}
|
||||
|
||||
std::string X64Context::GetStringFromValue(X64Register reg, bool hex) const {
|
||||
switch (reg) {
|
||||
case X64Register::kRip:
|
||||
return hex ? string_util::to_hex_string(rip) : std::to_string(rip);
|
||||
case X64Register::kEflags:
|
||||
return hex ? string_util::to_hex_string(eflags) : std::to_string(eflags);
|
||||
default:
|
||||
if (static_cast<int>(reg) >= static_cast<int>(X64Register::kRax) &&
|
||||
static_cast<int>(reg) <= static_cast<int>(X64Register::kR15)) {
|
||||
auto value = int_registers[static_cast<int>(reg) -
|
||||
static_cast<int>(X64Register::kRax)];
|
||||
return hex ? string_util::to_hex_string(value) : std::to_string(value);
|
||||
} else if (static_cast<int>(reg) >=
|
||||
static_cast<int>(X64Register::kXmm0) &&
|
||||
static_cast<int>(reg) <=
|
||||
static_cast<int>(X64Register::kXmm15)) {
|
||||
auto value = xmm_registers[static_cast<int>(reg) -
|
||||
static_cast<int>(X64Register::kXmm0)];
|
||||
return hex ? string_util::to_hex_string(value)
|
||||
: string_util::to_string(value);
|
||||
} else {
|
||||
assert_unhandled_case(reg);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X64Context::SetValueFromString(X64Register reg, std::string value,
|
||||
bool hex) {
|
||||
// TODO(benvanik): set value from string.
|
||||
assert_always(false);
|
||||
}
|
||||
|
||||
} // namespace xe
|
||||
112
src/xenia/base/x64_context.h
Normal file
112
src/xenia/base/x64_context.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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_X64_CONTEXT_H_
|
||||
#define XENIA_BASE_X64_CONTEXT_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace xe {
|
||||
|
||||
enum class X64Register {
|
||||
// NOTE: this order matches 1:1 with the order in the X64Context.
|
||||
// NOTE: this order matches 1:1 with a string table in the x64_context.cc.
|
||||
kRip,
|
||||
kEflags,
|
||||
kRax,
|
||||
kRcx,
|
||||
kRdx,
|
||||
kRbx,
|
||||
kRsp,
|
||||
kRbp,
|
||||
kRsi,
|
||||
kRdi,
|
||||
kR8,
|
||||
kR9,
|
||||
kR10,
|
||||
kR11,
|
||||
kR12,
|
||||
kR13,
|
||||
kR14,
|
||||
kR15,
|
||||
kXmm0,
|
||||
kXmm1,
|
||||
kXmm2,
|
||||
kXmm3,
|
||||
kXmm4,
|
||||
kXmm5,
|
||||
kXmm6,
|
||||
kXmm7,
|
||||
kXmm8,
|
||||
kXmm9,
|
||||
kXmm10,
|
||||
kXmm11,
|
||||
kXmm12,
|
||||
kXmm13,
|
||||
kXmm14,
|
||||
kXmm15,
|
||||
};
|
||||
|
||||
class X64Context {
|
||||
public:
|
||||
uint64_t rip;
|
||||
uint32_t eflags;
|
||||
union {
|
||||
struct {
|
||||
uint64_t rax;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rbx;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t rsi;
|
||||
uint64_t rdi;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
};
|
||||
uint64_t int_registers[16];
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
__m128 xmm0;
|
||||
__m128 xmm1;
|
||||
__m128 xmm2;
|
||||
__m128 xmm3;
|
||||
__m128 xmm4;
|
||||
__m128 xmm5;
|
||||
__m128 xmm6;
|
||||
__m128 xmm7;
|
||||
__m128 xmm8;
|
||||
__m128 xmm9;
|
||||
__m128 xmm10;
|
||||
__m128 xmm11;
|
||||
__m128 xmm12;
|
||||
__m128 xmm13;
|
||||
__m128 xmm14;
|
||||
__m128 xmm15;
|
||||
};
|
||||
__m128 xmm_registers[16];
|
||||
};
|
||||
|
||||
static const char* GetRegisterName(X64Register reg);
|
||||
std::string GetStringFromValue(X64Register reg, bool hex) const;
|
||||
void SetValueFromString(X64Register reg, std::string value, bool hex);
|
||||
};
|
||||
|
||||
} // namespace xe
|
||||
|
||||
#endif // XENIA_BASE_X64_CONTEXT_H_
|
||||
Reference in New Issue
Block a user