Client-specific debug state.
This commit is contained in:
parent
7098ed3b02
commit
5e9a2c6d27
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ public:
|
|||
|
||||
int AddBreakpoint(Breakpoint* breakpoint);
|
||||
int RemoveBreakpoint(Breakpoint* breakpoint);
|
||||
int RemoveAllBreakpoints();
|
||||
|
||||
private:
|
||||
Runtime* runtime_;
|
||||
|
|
|
@ -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,6 +367,44 @@ json_t* Processor::OnDebugRequest(
|
|||
return json_string("Invalid breakpoint ID type");
|
||||
}
|
||||
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_);
|
||||
Breakpoint* breakpoint = breakpoints_[breakpoint_id];
|
||||
if (breakpoint) {
|
||||
|
@ -370,20 +413,17 @@ json_t* Processor::OnDebugRequest(
|
|||
delete breakpoint;
|
||||
}
|
||||
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_);
|
||||
runtime_->debugger()->RemoveAllBreakpoints();
|
||||
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 json_null();
|
||||
} else {
|
||||
succeeded = false;
|
||||
return json_string("Unknown command");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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,10 +74,26 @@ private:
|
|||
XenonThreadState* interrupt_thread_state_;
|
||||
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_;
|
||||
typedef std::unordered_map<std::string, alloy::runtime::Breakpoint*> BreakpointMap;
|
||||
BreakpointMap breakpoints_;
|
||||
};
|
||||
typedef std::unordered_map<uint32_t, DebugClientState*> DebugClientStateMap;
|
||||
DebugClientStateMap debug_client_states_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace cpu
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
|
||||
private:
|
||||
void AddClient(DebugClient* debug_client);
|
||||
void ReadyClient(DebugClient* debug_client);
|
||||
void RemoveClient(DebugClient* debug_client);
|
||||
|
||||
friend class DebugClient;
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue