diff --git a/debugger/src/session.js b/debugger/src/session.js index 6395f33a2..ed92fdf00 100644 --- a/debugger/src/session.js +++ b/debugger/src/session.js @@ -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)); diff --git a/src/alloy/runtime/debugger.cc b/src/alloy/runtime/debugger.cc index 8ce4c02b4..28f9c51c0 100644 --- a/src/alloy/runtime/debugger.cc +++ b/src/alloy/runtime/debugger.cc @@ -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; } diff --git a/src/alloy/runtime/debugger.h b/src/alloy/runtime/debugger.h index b371c85e3..afe007a8a 100644 --- a/src/alloy/runtime/debugger.h +++ b/src/alloy/runtime/debugger.h @@ -47,7 +47,6 @@ public: int AddBreakpoint(Breakpoint* breakpoint); int RemoveBreakpoint(Breakpoint* breakpoint); - int RemoveAllBreakpoints(); private: Runtime* runtime_; diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 8dbd17528..8da21c26a 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -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; +} diff --git a/src/xenia/cpu/processor.h b/src/xenia/cpu/processor.h index 72b4d1963..866d0683b 100644 --- a/src/xenia/cpu/processor.h +++ b/src/xenia/cpu/processor.h @@ -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 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 BreakpointMap; + BreakpointMap breakpoints_; + }; + typedef std::unordered_map DebugClientStateMap; + DebugClientStateMap debug_client_states_; }; diff --git a/src/xenia/debug/debug_client.cc b/src/xenia/debug/debug_client.cc index c5343bbb9..40d482664 100644 --- a/src/xenia/debug/debug_client.cc +++ b/src/xenia/debug/debug_client.cc @@ -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; } diff --git a/src/xenia/debug/debug_client.h b/src/xenia/debug/debug_client.h index 0db1d3b15..62a741566 100644 --- a/src/xenia/debug/debug_client.h +++ b/src/xenia/debug/debug_client.h @@ -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_; }; diff --git a/src/xenia/debug/debug_server.cc b/src/xenia/debug/debug_server.cc index fc2546182..a97d67c36 100644 --- a/src/xenia/debug/debug_server.cc +++ b/src/xenia/debug/debug_server.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -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::iterator it = clients_.begin(); it != clients_.end(); ++it) { if (*it == debug_client) { diff --git a/src/xenia/debug/debug_server.h b/src/xenia/debug/debug_server.h index 0780f4f2e..030568e18 100644 --- a/src/xenia/debug/debug_server.h +++ b/src/xenia/debug/debug_server.h @@ -47,6 +47,7 @@ public: private: void AddClient(DebugClient* debug_client); + void ReadyClient(DebugClient* debug_client); void RemoveClient(DebugClient* debug_client); friend class DebugClient; diff --git a/src/xenia/debug/debug_target.h b/src/xenia/debug/debug_target.h index 4a95f805f..7f202757f 100644 --- a/src/xenia/debug/debug_target.h +++ b/src/xenia/debug/debug_target.h @@ -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_; diff --git a/src/xenia/debug/protocols/ws/ws_client.cc b/src/xenia/debug/protocols/ws/ws_client.cc index fd0d7c5af..50fc100a9 100644 --- a/src/xenia/debug/protocols/ws/ws_client.cc +++ b/src/xenia/debug/protocols/ws/ws_client.cc @@ -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); }