Client-specific debug state.
This commit is contained in:
parent
7098ed3b02
commit
5e9a2c6d27
|
@ -142,7 +142,10 @@ module.service('Session', function(
|
||||||
// Add breakpoints.
|
// Add breakpoints.
|
||||||
var breakpointList = [];
|
var breakpointList = [];
|
||||||
for (var key in this.breakpoints) {
|
for (var key in this.breakpoints) {
|
||||||
breakpointList.push(this.breakpoints[key]);
|
var breakpoint = this.breakpoints[key];
|
||||||
|
if (breakpoint.enabled) {
|
||||||
|
breakpointList.push(breakpoint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ps.push(this.dataSource.addBreakpoints(breakpointList));
|
ps.push(this.dataSource.addBreakpoints(breakpointList));
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,9 @@ Debugger::~Debugger() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
|
int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
|
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
|
||||||
return 1;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
int Debugger::RemoveAllBreakpoints() {
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,6 @@ public:
|
||||||
|
|
||||||
int AddBreakpoint(Breakpoint* breakpoint);
|
int AddBreakpoint(Breakpoint* breakpoint);
|
||||||
int RemoveBreakpoint(Breakpoint* breakpoint);
|
int RemoveBreakpoint(Breakpoint* breakpoint);
|
||||||
int RemoveAllBreakpoints();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Runtime* runtime_;
|
Runtime* runtime_;
|
||||||
|
|
|
@ -56,7 +56,6 @@ Processor::Processor(Emulator* emulator) :
|
||||||
runtime_(0), memory_(emulator->memory()),
|
runtime_(0), memory_(emulator->memory()),
|
||||||
interrupt_thread_lock_(NULL), interrupt_thread_state_(NULL),
|
interrupt_thread_lock_(NULL), interrupt_thread_state_(NULL),
|
||||||
interrupt_thread_block_(0),
|
interrupt_thread_block_(0),
|
||||||
breakpoints_lock_(0),
|
|
||||||
DebugTarget(emulator->debug_server()) {
|
DebugTarget(emulator->debug_server()) {
|
||||||
InitializeIfNeeded();
|
InitializeIfNeeded();
|
||||||
|
|
||||||
|
@ -66,14 +65,12 @@ Processor::Processor(Emulator* emulator) :
|
||||||
Processor::~Processor() {
|
Processor::~Processor() {
|
||||||
emulator_->debug_server()->RemoveTarget("cpu");
|
emulator_->debug_server()->RemoveTarget("cpu");
|
||||||
|
|
||||||
xe_mutex_lock(breakpoints_lock_);
|
for (auto it = debug_client_states_.begin();
|
||||||
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
it != debug_client_states_.end(); ++it) {
|
||||||
Breakpoint* breakpoint = it->second;
|
DebugClientState* client_state = it->second;
|
||||||
delete breakpoint;
|
delete client_state;
|
||||||
}
|
}
|
||||||
breakpoints_.clear();
|
debug_client_states_.clear();
|
||||||
xe_mutex_unlock(breakpoints_lock_);
|
|
||||||
xe_mutex_free(breakpoints_lock_);
|
|
||||||
|
|
||||||
if (interrupt_thread_block_) {
|
if (interrupt_thread_block_) {
|
||||||
memory_->HeapFree(interrupt_thread_block_, 2048);
|
memory_->HeapFree(interrupt_thread_block_, 2048);
|
||||||
|
@ -109,8 +106,6 @@ int Processor::Setup() {
|
||||||
0, 2048, MEMORY_FLAG_ZERO);
|
0, 2048, MEMORY_FLAG_ZERO);
|
||||||
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
|
||||||
|
|
||||||
breakpoints_lock_ = xe_mutex_alloc(10000);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,8 +175,22 @@ uint64_t Processor::ExecuteInterrupt(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Processor::OnDebugClientConnected(uint32_t client_id) {
|
||||||
|
DebugClientState* client_state = new DebugClientState(runtime_);
|
||||||
|
debug_client_states_[client_id] = client_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Processor::OnDebugClientDisconnected(uint32_t client_id) {
|
||||||
|
DebugClientState* client_state = debug_client_states_[client_id];
|
||||||
|
debug_client_states_.erase(client_id);
|
||||||
|
delete client_state;
|
||||||
|
}
|
||||||
|
|
||||||
json_t* Processor::OnDebugRequest(
|
json_t* Processor::OnDebugRequest(
|
||||||
const char* command, json_t* request, bool& succeeded) {
|
uint32_t client_id, const char* command, json_t* request,
|
||||||
|
bool& succeeded) {
|
||||||
|
DebugClientState* client_state = debug_client_states_[client_id];
|
||||||
|
|
||||||
succeeded = true;
|
succeeded = true;
|
||||||
if (xestrcmpa(command, "get_module_list") == 0) {
|
if (xestrcmpa(command, "get_module_list") == 0) {
|
||||||
json_t* list = json_array();
|
json_t* list = json_array();
|
||||||
|
@ -334,11 +343,7 @@ json_t* Processor::OnDebugRequest(
|
||||||
|
|
||||||
Breakpoint* breakpoint = new Breakpoint(
|
Breakpoint* breakpoint = new Breakpoint(
|
||||||
type, address);
|
type, address);
|
||||||
xe_mutex_lock(breakpoints_lock_);
|
if (client_state->AddBreakpoint(breakpoint_id, breakpoint)) {
|
||||||
breakpoints_[breakpoint_id] = breakpoint;
|
|
||||||
int result = runtime_->debugger()->AddBreakpoint(breakpoint);
|
|
||||||
xe_mutex_unlock(breakpoints_lock_);
|
|
||||||
if (result) {
|
|
||||||
succeeded = false;
|
succeeded = false;
|
||||||
return json_string("Error adding breakpoint");
|
return json_string("Error adding breakpoint");
|
||||||
}
|
}
|
||||||
|
@ -362,6 +367,44 @@ json_t* Processor::OnDebugRequest(
|
||||||
return json_string("Invalid breakpoint ID type");
|
return json_string("Invalid breakpoint ID type");
|
||||||
}
|
}
|
||||||
const char* breakpoint_id = json_string_value(breakpoint_id_json);
|
const char* breakpoint_id = json_string_value(breakpoint_id_json);
|
||||||
|
if (client_state->RemoveBreakpoint(breakpoint_id)) {
|
||||||
|
succeeded = false;
|
||||||
|
return json_string("Unable to remove breakpoints");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json_null();
|
||||||
|
} else if (xestrcmpa(command, "remove_all_breakpoints") == 0) {
|
||||||
|
if (client_state->RemoveAllBreakpoints()) {
|
||||||
|
succeeded = false;
|
||||||
|
return json_string("Unable to remove breakpoints");
|
||||||
|
}
|
||||||
|
return json_null();
|
||||||
|
} else {
|
||||||
|
succeeded = false;
|
||||||
|
return json_string("Unknown command");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor::DebugClientState::DebugClientState(XenonRuntime* runtime) :
|
||||||
|
runtime_(runtime) {
|
||||||
|
breakpoints_lock_ = xe_mutex_alloc(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor::DebugClientState::~DebugClientState() {
|
||||||
|
RemoveAllBreakpoints();
|
||||||
|
xe_mutex_free(breakpoints_lock_);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::DebugClientState::AddBreakpoint(
|
||||||
|
const char* breakpoint_id, Breakpoint* breakpoint) {
|
||||||
|
xe_mutex_lock(breakpoints_lock_);
|
||||||
|
breakpoints_[breakpoint_id] = breakpoint;
|
||||||
|
int result = runtime_->debugger()->AddBreakpoint(breakpoint);
|
||||||
|
xe_mutex_unlock(breakpoints_lock_);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Processor::DebugClientState::RemoveBreakpoint(const char* breakpoint_id) {
|
||||||
xe_mutex_lock(breakpoints_lock_);
|
xe_mutex_lock(breakpoints_lock_);
|
||||||
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
|
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
|
||||||
if (breakpoint) {
|
if (breakpoint) {
|
||||||
|
@ -370,20 +413,17 @@ json_t* Processor::OnDebugRequest(
|
||||||
delete breakpoint;
|
delete breakpoint;
|
||||||
}
|
}
|
||||||
xe_mutex_unlock(breakpoints_lock_);
|
xe_mutex_unlock(breakpoints_lock_);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return json_null();
|
|
||||||
} else if (xestrcmpa(command, "remove_all_breakpoints") == 0) {
|
int Processor::DebugClientState::RemoveAllBreakpoints() {
|
||||||
xe_mutex_lock(breakpoints_lock_);
|
xe_mutex_lock(breakpoints_lock_);
|
||||||
runtime_->debugger()->RemoveAllBreakpoints();
|
|
||||||
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
|
||||||
Breakpoint* breakpoint = it->second;
|
Breakpoint* breakpoint = it->second;
|
||||||
|
runtime_->debugger()->RemoveBreakpoint(breakpoint);
|
||||||
delete breakpoint;
|
delete breakpoint;
|
||||||
}
|
}
|
||||||
breakpoints_.clear();
|
breakpoints_.clear();
|
||||||
xe_mutex_unlock(breakpoints_lock_);
|
xe_mutex_unlock(breakpoints_lock_);
|
||||||
return json_null();
|
return 0;
|
||||||
} else {
|
|
||||||
succeeded = false;
|
|
||||||
return json_string("Unknown command");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,8 +57,11 @@ public:
|
||||||
uint64_t ExecuteInterrupt(
|
uint64_t ExecuteInterrupt(
|
||||||
uint32_t cpu, uint64_t address, uint64_t arg0, uint64_t arg1);
|
uint32_t cpu, uint64_t address, uint64_t arg0, uint64_t arg1);
|
||||||
|
|
||||||
|
virtual void OnDebugClientConnected(uint32_t client_id);
|
||||||
|
virtual void OnDebugClientDisconnected(uint32_t client_id);
|
||||||
virtual json_t* OnDebugRequest(
|
virtual json_t* OnDebugRequest(
|
||||||
const char* command, json_t* request, bool& succeeded);
|
uint32_t client_id, const char* command, json_t* request,
|
||||||
|
bool& succeeded);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator* emulator_;
|
Emulator* emulator_;
|
||||||
|
@ -71,10 +74,26 @@ private:
|
||||||
XenonThreadState* interrupt_thread_state_;
|
XenonThreadState* interrupt_thread_state_;
|
||||||
uint64_t interrupt_thread_block_;
|
uint64_t interrupt_thread_block_;
|
||||||
|
|
||||||
|
class DebugClientState {
|
||||||
|
public:
|
||||||
|
DebugClientState(XenonRuntime* runtime);
|
||||||
|
~DebugClientState();
|
||||||
|
|
||||||
|
int AddBreakpoint(const char* breakpoint_id,
|
||||||
|
alloy::runtime::Breakpoint* breakpoint);
|
||||||
|
int RemoveBreakpoint(const char* breakpoint_id);
|
||||||
|
int RemoveAllBreakpoints();
|
||||||
|
|
||||||
|
private:
|
||||||
|
XenonRuntime* runtime_;
|
||||||
|
|
||||||
xe_mutex_t* breakpoints_lock_;
|
xe_mutex_t* breakpoints_lock_;
|
||||||
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
|
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
|
||||||
BreakpointMap breakpoints_;
|
BreakpointMap breakpoints_;
|
||||||
};
|
};
|
||||||
|
typedef std::unordered_map<uint32_t, DebugClientState*> DebugClientStateMap;
|
||||||
|
DebugClientStateMap debug_client_states_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
|
|
|
@ -16,8 +16,14 @@ using namespace xe;
|
||||||
using namespace xe::debug;
|
using namespace xe::debug;
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t DebugClient::next_client_id_ = 1;
|
||||||
|
|
||||||
|
|
||||||
DebugClient::DebugClient(DebugServer* debug_server) :
|
DebugClient::DebugClient(DebugServer* debug_server) :
|
||||||
debug_server_(debug_server) {
|
debug_server_(debug_server),
|
||||||
|
readied_(false) {
|
||||||
|
client_id_ = next_client_id_++;
|
||||||
|
debug_server_->AddClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugClient::~DebugClient() {
|
DebugClient::~DebugClient() {
|
||||||
|
@ -25,5 +31,9 @@ DebugClient::~DebugClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugClient::MakeReady() {
|
void DebugClient::MakeReady() {
|
||||||
debug_server_->AddClient(this);
|
if (readied_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug_server_->ReadyClient(this);
|
||||||
|
readied_ = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
DebugClient(DebugServer* debug_server);
|
DebugClient(DebugServer* debug_server);
|
||||||
virtual ~DebugClient();
|
virtual ~DebugClient();
|
||||||
|
|
||||||
|
uint32_t client_id() const { return client_id_; }
|
||||||
|
|
||||||
virtual int Setup() = 0;
|
virtual int Setup() = 0;
|
||||||
virtual void Close() = 0;
|
virtual void Close() = 0;
|
||||||
|
|
||||||
|
@ -33,7 +35,11 @@ protected:
|
||||||
void MakeReady();
|
void MakeReady();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
static uint32_t next_client_id_;
|
||||||
|
|
||||||
DebugServer* debug_server_;
|
DebugServer* debug_server_;
|
||||||
|
uint32_t client_id_;
|
||||||
|
bool readied_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <xenia/emulator.h>
|
#include <xenia/emulator.h>
|
||||||
#include <xenia/debug/debug_client.h>
|
#include <xenia/debug/debug_client.h>
|
||||||
|
#include <xenia/debug/debug_target.h>
|
||||||
#include <xenia/debug/protocol.h>
|
#include <xenia/debug/protocol.h>
|
||||||
#include <xenia/debug/protocols/gdb/gdb_protocol.h>
|
#include <xenia/debug/protocols/gdb/gdb_protocol.h>
|
||||||
#include <xenia/debug/protocols/ws/ws_protocol.h>
|
#include <xenia/debug/protocols/ws/ws_protocol.h>
|
||||||
|
@ -144,14 +145,26 @@ void DebugServer::AddClient(DebugClient* debug_client) {
|
||||||
|
|
||||||
clients_.push_back(debug_client);
|
clients_.push_back(debug_client);
|
||||||
|
|
||||||
xe_mutex_unlock(lock_);
|
// Notify targets.
|
||||||
|
for (auto it = targets_.begin(); it != targets_.end(); ++it) {
|
||||||
|
it->second->OnDebugClientConnected(debug_client->client_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
xe_mutex_unlock(lock_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugServer::ReadyClient(DebugClient* debug_client) {
|
||||||
SetEvent(client_event_);
|
SetEvent(client_event_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugServer::RemoveClient(DebugClient* debug_client) {
|
void DebugServer::RemoveClient(DebugClient* debug_client) {
|
||||||
xe_mutex_lock(lock_);
|
xe_mutex_lock(lock_);
|
||||||
|
|
||||||
|
// Notify targets.
|
||||||
|
for (auto it = targets_.begin(); it != targets_.end(); ++it) {
|
||||||
|
it->second->OnDebugClientDisconnected(debug_client->client_id());
|
||||||
|
}
|
||||||
|
|
||||||
for (std::vector<DebugClient*>::iterator it = clients_.begin();
|
for (std::vector<DebugClient*>::iterator it = clients_.begin();
|
||||||
it != clients_.end(); ++it) {
|
it != clients_.end(); ++it) {
|
||||||
if (*it == debug_client) {
|
if (*it == debug_client) {
|
||||||
|
|
|
@ -47,6 +47,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AddClient(DebugClient* debug_client);
|
void AddClient(DebugClient* debug_client);
|
||||||
|
void ReadyClient(DebugClient* debug_client);
|
||||||
void RemoveClient(DebugClient* debug_client);
|
void RemoveClient(DebugClient* debug_client);
|
||||||
|
|
||||||
friend class DebugClient;
|
friend class DebugClient;
|
||||||
|
|
|
@ -30,8 +30,11 @@ public:
|
||||||
|
|
||||||
DebugServer* debug_server() const { return debug_server_; }
|
DebugServer* debug_server() const { return debug_server_; }
|
||||||
|
|
||||||
|
virtual void OnDebugClientConnected(uint32_t client_id) {}
|
||||||
|
virtual void OnDebugClientDisconnected(uint32_t client_id) {}
|
||||||
virtual json_t* OnDebugRequest(
|
virtual json_t* OnDebugRequest(
|
||||||
const char* command, json_t* request, bool& succeeded) = 0;
|
uint32_t client_id, const char* command, json_t* request,
|
||||||
|
bool& succeeded) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DebugServer* debug_server_;
|
DebugServer* debug_server_;
|
||||||
|
|
|
@ -428,11 +428,7 @@ void WSClient::Write(const uint8_t** buffers, size_t* lengths, size_t count,
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSClient::OnMessage(const uint8_t* data, size_t length) {
|
void WSClient::OnMessage(const uint8_t* data, size_t length) {
|
||||||
//
|
|
||||||
const char* s = (const char*)data;
|
const char* s = (const char*)data;
|
||||||
printf(s);
|
|
||||||
// command
|
|
||||||
// requestId
|
|
||||||
|
|
||||||
json_error_t error;
|
json_error_t error;
|
||||||
json_t* request = json_loadb(
|
json_t* request = json_loadb(
|
||||||
|
@ -522,5 +518,6 @@ json_t* WSClient::HandleMessage(const char* command, json_t* request,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch.
|
// Dispatch.
|
||||||
return target->OnDebugRequest(sub_command, request, succeeded);
|
return target->OnDebugRequest(
|
||||||
|
client_id(), sub_command, request, succeeded);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue