Plumbing breakpoints down into alloy Debugger interface.
This commit is contained in:
parent
e45a7afabc
commit
7098ed3b02
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <alloy/runtime/debugger.h>
|
||||
|
||||
using namespace alloy;
|
||||
using namespace alloy::runtime;
|
||||
|
||||
|
||||
Breakpoint::Breakpoint(Type type, uint64_t address) :
|
||||
type_(type), address_(address) {
|
||||
}
|
||||
|
||||
Breakpoint::~Breakpoint() {
|
||||
}
|
||||
|
||||
Debugger::Debugger(Runtime* runtime) :
|
||||
runtime_(runtime) {
|
||||
}
|
||||
|
||||
Debugger::~Debugger() {
|
||||
}
|
||||
|
||||
int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Debugger::RemoveAllBreakpoints() {
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* Xenia : Xbox 360 Emulator Research Project *
|
||||
******************************************************************************
|
||||
* Copyright 2013 Ben Vanik. All rights reserved. *
|
||||
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef ALLOY_RUNTIME_DEBUGGER_H_
|
||||
#define ALLOY_RUNTIME_DEBUGGER_H_
|
||||
|
||||
#include <alloy/core.h>
|
||||
|
||||
|
||||
namespace alloy {
|
||||
namespace runtime {
|
||||
|
||||
class Runtime;
|
||||
|
||||
|
||||
class Breakpoint {
|
||||
public:
|
||||
enum Type {
|
||||
TEMP_TYPE,
|
||||
CODE_TYPE,
|
||||
};
|
||||
public:
|
||||
Breakpoint(Type type, uint64_t address);
|
||||
~Breakpoint();
|
||||
|
||||
Type type() const { return type_; }
|
||||
uint64_t address() const { return address_; }
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
uint64_t address_;
|
||||
};
|
||||
|
||||
|
||||
class Debugger {
|
||||
public:
|
||||
Debugger(Runtime* runtime);
|
||||
~Debugger();
|
||||
|
||||
Runtime* runtime() const { return runtime_; }
|
||||
|
||||
int AddBreakpoint(Breakpoint* breakpoint);
|
||||
int RemoveBreakpoint(Breakpoint* breakpoint);
|
||||
int RemoveAllBreakpoints();
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace runtime
|
||||
} // namespace alloy
|
||||
|
||||
|
||||
#endif // ALLOY_RUNTIME_DEBUGGER_H_
|
|
@ -25,7 +25,7 @@ DEFINE_string(runtime_backend, "any",
|
|||
|
||||
|
||||
Runtime::Runtime(Memory* memory) :
|
||||
memory_(memory), backend_(0), frontend_(0),
|
||||
memory_(memory), debugger_(0), backend_(0), frontend_(0),
|
||||
access_callbacks_(0) {
|
||||
tracing::Initialize();
|
||||
modules_lock_ = AllocMutex(10000);
|
||||
|
@ -51,6 +51,7 @@ Runtime::~Runtime() {
|
|||
|
||||
delete frontend_;
|
||||
delete backend_;
|
||||
delete debugger_;
|
||||
|
||||
tracing::Flush();
|
||||
}
|
||||
|
@ -67,6 +68,9 @@ int Runtime::Initialize(Frontend* frontend, Backend* backend) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// Create debugger first. Other types hook up to it.
|
||||
debugger_ = new Debugger(this);
|
||||
|
||||
if (frontend_ || backend_) {
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <alloy/memory.h>
|
||||
#include <alloy/backend/backend.h>
|
||||
#include <alloy/frontend/frontend.h>
|
||||
#include <alloy/runtime/debugger.h>
|
||||
#include <alloy/runtime/entry_table.h>
|
||||
#include <alloy/runtime/module.h>
|
||||
#include <alloy/runtime/register_access.h>
|
||||
|
@ -34,6 +35,7 @@ public:
|
|||
virtual ~Runtime();
|
||||
|
||||
Memory* memory() const { return memory_; }
|
||||
Debugger* debugger() const { return debugger_; }
|
||||
frontend::Frontend* frontend() const { return frontend_; }
|
||||
backend::Backend* backend() const { return backend_; }
|
||||
RegisterAccessCallbacks* access_callbacks() const {
|
||||
|
@ -62,6 +64,8 @@ private:
|
|||
protected:
|
||||
Memory* memory_;
|
||||
|
||||
Debugger* debugger_;
|
||||
|
||||
frontend::Frontend* frontend_;
|
||||
backend::Backend* backend_;
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'simple_context.cc',
|
||||
'simple_context.h',
|
||||
'simple_memory.cc',
|
||||
'simple_memory.h',
|
||||
'simple_runtime.cc',
|
||||
'simple_runtime.h',
|
||||
'simple_thread_state.cc',
|
||||
'simple_thread_state.h',
|
||||
],
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
'sources': [
|
||||
'debug_info.cc',
|
||||
'debug_info.h',
|
||||
'debugger.cc',
|
||||
'debugger.h',
|
||||
'entry_table.cc',
|
||||
'entry_table.h',
|
||||
'function.cc',
|
||||
|
@ -22,6 +24,5 @@
|
|||
],
|
||||
|
||||
'includes': [
|
||||
#'simple/sources.gypi',
|
||||
],
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <jansson.h>
|
||||
|
||||
#include <alloy/runtime/debugger.h>
|
||||
#include <xenia/emulator.h>
|
||||
#include <xenia/cpu/xenon_memory.h>
|
||||
#include <xenia/cpu/xenon_runtime.h>
|
||||
|
@ -55,6 +56,7 @@ Processor::Processor(Emulator* emulator) :
|
|||
runtime_(0), memory_(emulator->memory()),
|
||||
interrupt_thread_lock_(NULL), interrupt_thread_state_(NULL),
|
||||
interrupt_thread_block_(0),
|
||||
breakpoints_lock_(0),
|
||||
DebugTarget(emulator->debug_server()) {
|
||||
InitializeIfNeeded();
|
||||
|
||||
|
@ -64,6 +66,15 @@ Processor::Processor(Emulator* emulator) :
|
|||
Processor::~Processor() {
|
||||
emulator_->debug_server()->RemoveTarget("cpu");
|
||||
|
||||
xe_mutex_lock(breakpoints_lock_);
|
||||
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
||||
Breakpoint* breakpoint = it->second;
|
||||
delete breakpoint;
|
||||
}
|
||||
breakpoints_.clear();
|
||||
xe_mutex_unlock(breakpoints_lock_);
|
||||
xe_mutex_free(breakpoints_lock_);
|
||||
|
||||
if (interrupt_thread_block_) {
|
||||
memory_->HeapFree(interrupt_thread_block_, 2048);
|
||||
delete interrupt_thread_state_;
|
||||
|
@ -98,6 +109,8 @@ int Processor::Setup() {
|
|||
0, 2048, MEMORY_FLAG_ZERO);
|
||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
||||
|
||||
breakpoints_lock_ = xe_mutex_alloc(10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -280,12 +293,94 @@ json_t* Processor::OnDebugRequest(
|
|||
|
||||
return fn_json;
|
||||
} else if (xestrcmpa(command, "add_breakpoints") == 0) {
|
||||
// breakpoints: []
|
||||
// breakpoints: [{}]
|
||||
json_t* breakpoints_json = json_object_get(request, "breakpoints");
|
||||
if (!breakpoints_json || !json_is_array(breakpoints_json)) {
|
||||
succeeded = false;
|
||||
return json_string("Breakpoints not specified");
|
||||
}
|
||||
if (!json_array_size(breakpoints_json)) {
|
||||
// No-op;
|
||||
return json_null();
|
||||
}
|
||||
for (size_t n = 0; n < json_array_size(breakpoints_json); n++) {
|
||||
json_t* breakpoint_json = json_array_get(breakpoints_json, n);
|
||||
if (!breakpoint_json || !json_is_object(breakpoint_json)) {
|
||||
succeeded = false;
|
||||
return json_string("Invalid breakpoint type");
|
||||
}
|
||||
|
||||
json_t* breakpoint_id_json = json_object_get(breakpoint_json, "id");
|
||||
json_t* type_json = json_object_get(breakpoint_json, "type");
|
||||
json_t* address_json = json_object_get(breakpoint_json, "address");
|
||||
if (!breakpoint_id_json || !json_is_string(breakpoint_id_json) ||
|
||||
!type_json || !json_is_string(type_json) ||
|
||||
!address_json || !json_is_number(address_json)) {
|
||||
succeeded = false;
|
||||
return json_string("Invalid breakpoint members");
|
||||
}
|
||||
const char* breakpoint_id = json_string_value(breakpoint_id_json);
|
||||
const char* type_str = json_string_value(type_json);
|
||||
uint64_t address = (uint64_t)json_number_value(address_json);
|
||||
Breakpoint::Type type;
|
||||
if (xestrcmpa(type_str, "temp") == 0) {
|
||||
type = Breakpoint::TEMP_TYPE;
|
||||
} else if (xestrcmpa(type_str, "code") == 0) {
|
||||
type = Breakpoint::CODE_TYPE;
|
||||
} else {
|
||||
succeeded = false;
|
||||
return json_string("Unknown breakpoint type");
|
||||
}
|
||||
|
||||
Breakpoint* breakpoint = new Breakpoint(
|
||||
type, address);
|
||||
xe_mutex_lock(breakpoints_lock_);
|
||||
breakpoints_[breakpoint_id] = breakpoint;
|
||||
int result = runtime_->debugger()->AddBreakpoint(breakpoint);
|
||||
xe_mutex_unlock(breakpoints_lock_);
|
||||
if (result) {
|
||||
succeeded = false;
|
||||
return json_string("Error adding breakpoint");
|
||||
}
|
||||
}
|
||||
return json_null();
|
||||
} else if (xestrcmpa(command, "remove_breakpoints") == 0) {
|
||||
// breakpointIds: ['id']
|
||||
json_t* breakpoint_ids_json = json_object_get(request, "breakpointIds");
|
||||
if (!breakpoint_ids_json || !json_is_array(breakpoint_ids_json)) {
|
||||
succeeded = false;
|
||||
return json_string("Breakpoint IDs not specified");
|
||||
}
|
||||
if (!json_array_size(breakpoint_ids_json)) {
|
||||
// No-op;
|
||||
return json_null();
|
||||
}
|
||||
for (size_t n = 0; n < json_array_size(breakpoint_ids_json); n++) {
|
||||
json_t* breakpoint_id_json = json_array_get(breakpoint_ids_json, n);
|
||||
if (!breakpoint_id_json || !json_is_string(breakpoint_id_json)) {
|
||||
succeeded = false;
|
||||
return json_string("Invalid breakpoint ID type");
|
||||
}
|
||||
const char* breakpoint_id = json_string_value(breakpoint_id_json);
|
||||
xe_mutex_lock(breakpoints_lock_);
|
||||
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
|
||||
if (breakpoint) {
|
||||
breakpoints_.erase(breakpoint_id);
|
||||
runtime_->debugger()->RemoveBreakpoint(breakpoint);
|
||||
delete breakpoint;
|
||||
}
|
||||
xe_mutex_unlock(breakpoints_lock_);
|
||||
}
|
||||
return json_null();
|
||||
} else if (xestrcmpa(command, "remove_all_breakpoints") == 0) {
|
||||
xe_mutex_lock(breakpoints_lock_);
|
||||
runtime_->debugger()->RemoveAllBreakpoints();
|
||||
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
||||
Breakpoint* breakpoint = it->second;
|
||||
delete breakpoint;
|
||||
}
|
||||
breakpoints_.clear();
|
||||
xe_mutex_unlock(breakpoints_lock_);
|
||||
return json_null();
|
||||
} else {
|
||||
succeeded = false;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
XEDECLARECLASS2(alloy, runtime, Breakpoint);
|
||||
XEDECLARECLASS1(xe, Emulator);
|
||||
XEDECLARECLASS1(xe, ExportResolver);
|
||||
XEDECLARECLASS2(xe, cpu, XenonMemory);
|
||||
|
@ -69,6 +70,10 @@ private:
|
|||
xe_mutex_t* interrupt_thread_lock_;
|
||||
XenonThreadState* interrupt_thread_state_;
|
||||
uint64_t interrupt_thread_block_;
|
||||
|
||||
xe_mutex_t* breakpoints_lock_;
|
||||
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
|
||||
BreakpointMap breakpoints_;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue