Client-specific debug state.

This commit is contained in:
Ben Vanik 2013-12-22 19:58:00 -08:00
parent 7098ed3b02
commit 5e9a2c6d27
11 changed files with 138 additions and 51 deletions

View File

@ -142,7 +142,10 @@ module.service('Session', function(
// Add breakpoints.
var breakpointList = [];
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));

View File

@ -28,13 +28,9 @@ Debugger::~Debugger() {
}
int Debugger::AddBreakpoint(Breakpoint* breakpoint) {
return 1;
return 0;
}
int Debugger::RemoveBreakpoint(Breakpoint* breakpoint) {
return 1;
}
int Debugger::RemoveAllBreakpoints() {
return 1;
return 0;
}

View File

@ -47,7 +47,6 @@ public:
int AddBreakpoint(Breakpoint* breakpoint);
int RemoveBreakpoint(Breakpoint* breakpoint);
int RemoveAllBreakpoints();
private:
Runtime* runtime_;

View File

@ -56,7 +56,6 @@ 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();
@ -66,14 +65,12 @@ 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;
for (auto it = debug_client_states_.begin();
it != debug_client_states_.end(); ++it) {
DebugClientState* client_state = it->second;
delete client_state;
}
breakpoints_.clear();
xe_mutex_unlock(breakpoints_lock_);
xe_mutex_free(breakpoints_lock_);
debug_client_states_.clear();
if (interrupt_thread_block_) {
memory_->HeapFree(interrupt_thread_block_, 2048);
@ -109,8 +106,6 @@ 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;
}
@ -180,8 +175,22 @@ uint64_t Processor::ExecuteInterrupt(
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(
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;
if (xestrcmpa(command, "get_module_list") == 0) {
json_t* list = json_array();
@ -334,11 +343,7 @@ json_t* Processor::OnDebugRequest(
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) {
if (client_state->AddBreakpoint(breakpoint_id, breakpoint)) {
succeeded = false;
return json_string("Error adding breakpoint");
}
@ -362,28 +367,63 @@ json_t* Processor::OnDebugRequest(
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;
if (client_state->RemoveBreakpoint(breakpoint_id)) {
succeeded = false;
return json_string("Unable to remove breakpoints");
}
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;
if (client_state->RemoveAllBreakpoints()) {
succeeded = false;
return json_string("Unable to remove breakpoints");
}
breakpoints_.clear();
xe_mutex_unlock(breakpoints_lock_);
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_);
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
if (breakpoint) {
breakpoints_.erase(breakpoint_id);
runtime_->debugger()->RemoveBreakpoint(breakpoint);
delete breakpoint;
}
xe_mutex_unlock(breakpoints_lock_);
return 0;
}
int Processor::DebugClientState::RemoveAllBreakpoints() {
xe_mutex_lock(breakpoints_lock_);
for (auto it = breakpoints_.begin(); it != breakpoints_.end(); ++it) {
Breakpoint* breakpoint = it->second;
runtime_->debugger()->RemoveBreakpoint(breakpoint);
delete breakpoint;
}
breakpoints_.clear();
xe_mutex_unlock(breakpoints_lock_);
return 0;
}

View File

@ -57,8 +57,11 @@ public:
uint64_t ExecuteInterrupt(
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(
const char* command, json_t* request, bool& succeeded);
uint32_t client_id, const char* command, json_t* request,
bool& succeeded);
private:
Emulator* emulator_;
@ -71,9 +74,25 @@ private:
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_;
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_;
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
BreakpointMap breakpoints_;
};
typedef std::unordered_map<uint32_t, DebugClientState*> DebugClientStateMap;
DebugClientStateMap debug_client_states_;
};

View File

@ -16,8 +16,14 @@ using namespace xe;
using namespace xe::debug;
uint32_t DebugClient::next_client_id_ = 1;
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() {
@ -25,5 +31,9 @@ DebugClient::~DebugClient() {
}
void DebugClient::MakeReady() {
debug_server_->AddClient(this);
if (readied_) {
return;
}
debug_server_->ReadyClient(this);
readied_ = true;
}

View File

@ -26,6 +26,8 @@ public:
DebugClient(DebugServer* debug_server);
virtual ~DebugClient();
uint32_t client_id() const { return client_id_; }
virtual int Setup() = 0;
virtual void Close() = 0;
@ -33,7 +35,11 @@ protected:
void MakeReady();
protected:
static uint32_t next_client_id_;
DebugServer* debug_server_;
uint32_t client_id_;
bool readied_;
};

View File

@ -13,6 +13,7 @@
#include <xenia/emulator.h>
#include <xenia/debug/debug_client.h>
#include <xenia/debug/debug_target.h>
#include <xenia/debug/protocol.h>
#include <xenia/debug/protocols/gdb/gdb_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);
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_);
}
void DebugServer::RemoveClient(DebugClient* debug_client) {
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();
it != clients_.end(); ++it) {
if (*it == debug_client) {

View File

@ -47,6 +47,7 @@ public:
private:
void AddClient(DebugClient* debug_client);
void ReadyClient(DebugClient* debug_client);
void RemoveClient(DebugClient* debug_client);
friend class DebugClient;

View File

@ -30,8 +30,11 @@ public:
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(
const char* command, json_t* request, bool& succeeded) = 0;
uint32_t client_id, const char* command, json_t* request,
bool& succeeded) = 0;
protected:
DebugServer* debug_server_;

View File

@ -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) {
//
const char* s = (const char*)data;
printf(s);
// command
// requestId
json_error_t error;
json_t* request = json_loadb(
@ -522,5 +518,6 @@ json_t* WSClient::HandleMessage(const char* command, json_t* request,
}
// Dispatch.
return target->OnDebugRequest(sub_command, request, succeeded);
return target->OnDebugRequest(
client_id(), sub_command, request, succeeded);
}