diff --git a/src/xenia/cpu/debug_listener.h b/src/xenia/cpu/debug_listener.h index 3e10321dbb2..6233e87fe41 100644 --- a/src/xenia/cpu/debug_listener.h +++ b/src/xenia/cpu/debug_listener.h @@ -30,6 +30,9 @@ class DebugListener { // end. virtual void OnDetached() = 0; + // Handles exception info (will be followed by OnExecutionPaused) + virtual void OnUnhandledException(Exception* ex) = 0; + // Handles execution being interrupted and transitioning to // ExceutionState::kPaused. virtual void OnExecutionPaused() = 0; diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index ee47e835b15..ae428ee92af 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -724,7 +724,7 @@ bool Processor::OnUnhandledException(Exception* ex) { execution_state_ = ExecutionState::kPaused; // Notify debugger that exceution stopped. - // debug_listener_->OnException(info); + debug_listener_->OnUnhandledException(ex); debug_listener_->OnExecutionPaused(); // Suspend self. diff --git a/src/xenia/debug/gdb/gdbstub.cc b/src/xenia/debug/gdb/gdbstub.cc index ae058b4b0e4..7798c6b7ec9 100644 --- a/src/xenia/debug/gdb/gdbstub.cc +++ b/src/xenia/debug/gdb/gdbstub.cc @@ -27,6 +27,7 @@ #include "xenia/cpu/breakpoint.h" #include "xenia/cpu/ppc/ppc_opcode_info.h" #include "xenia/cpu/stack_walker.h" +#include "xenia/cpu/thread.h" #include "xenia/kernel/xmodule.h" #include "xenia/kernel/xthread.h" @@ -50,7 +51,9 @@ enum class GdbStubControl : char { constexpr const char* kGdbReplyOK = "OK"; constexpr const char* kGdbReplyError = "E01"; -constexpr int kSignalSigtrap = 5; +constexpr int kSignalSigill = 4; // Illegal instruction +constexpr int kSignalSigtrap = 5; // Trace trap +constexpr int kSignalSigsegv = 11; // Segmentation fault // must start with l for debugger to accept it constexpr char kMemoryMapXml[] = @@ -222,12 +225,26 @@ void GDBStub::Listen(std::unique_ptr& client) { { std::unique_lock lock(mtx_); if (cache_.notify_stopped) { - if (cache_.notify_bp_thread_id != -1) { - cache_.cur_thread_id = cache_.notify_bp_thread_id; + if (cache_.notify_thread_id != -1) { + cache_.cur_thread_id = cache_.notify_thread_id; } - SendPacket(client, GetThreadStateReply(cache_.notify_bp_thread_id, - kSignalSigtrap)); - cache_.notify_bp_thread_id = -1; + + int sig_num = kSignalSigtrap; + if (cache_.notify_exception_code.has_value()) { + if (cache_.notify_exception_code == + xe::Exception::Code::kIllegalInstruction) { + sig_num = kSignalSigill; + } else { + sig_num = kSignalSigsegv; + } + + cache_.notify_exception_code.reset(); + cache_.notify_exception_access_violation.reset(); + } + + SendPacket(client, + GetThreadStateReply(cache_.notify_thread_id, sig_num)); + cache_.notify_thread_id = -1; cache_.notify_stopped = false; } } @@ -898,6 +915,17 @@ void GDBStub::OnDetached() { } } +void GDBStub::OnUnhandledException(Exception* ex) { +#ifdef DEBUG + debugging::DebugPrint("GDBStub: OnUnhandledException {} {}\n", + int(ex->code()), int(ex->access_violation_operation())); +#endif + std::unique_lock lock(mtx_); + cache_.notify_exception_code = ex->code(); + cache_.notify_exception_access_violation = ex->access_violation_operation(); + cache_.notify_thread_id = cpu::Thread::GetCurrentThreadId(); +} + void GDBStub::OnExecutionPaused() { #ifdef DEBUG debugging::DebugPrint("GDBStub: OnExecutionPaused\n"); @@ -925,7 +953,7 @@ void GDBStub::OnStepCompleted(cpu::ThreadDebugInfo* thread_info) { #endif // Some debuggers like IDA will remove the current breakpoint & step into next // instruction, only re-adding BP after it's told about the step - cache_.notify_bp_thread_id = thread_info->thread_id; + cache_.notify_thread_id = thread_info->thread_id; cache_.last_bp_thread_id = thread_info->thread_id; UpdateCache(); } @@ -938,7 +966,7 @@ void GDBStub::OnBreakpointHit(Breakpoint* breakpoint, #endif cache_.notify_bp_guest_address = breakpoint->address(); - cache_.notify_bp_thread_id = thread_info->thread_id; + cache_.notify_thread_id = thread_info->thread_id; cache_.last_bp_thread_id = thread_info->thread_id; UpdateCache(); } diff --git a/src/xenia/debug/gdb/gdbstub.h b/src/xenia/debug/gdb/gdbstub.h index d8e4b8a97ab..2e1d7f0966a 100644 --- a/src/xenia/debug/gdb/gdbstub.h +++ b/src/xenia/debug/gdb/gdbstub.h @@ -35,6 +35,7 @@ class GDBStub : public cpu::DebugListener { void OnFocus() override; void OnDetached() override; + void OnUnhandledException(Exception* ex) override; void OnExecutionPaused() override; void OnExecutionContinued() override; void OnExecutionEnded() override; @@ -100,9 +101,11 @@ class GDBStub : public cpu::DebugListener { uint32_t last_bp_thread_id = -1; uint64_t notify_bp_guest_address = -1; - uint32_t notify_bp_thread_id = -1; - std::vector notify_debug_messages; + uint32_t notify_thread_id = -1; bool notify_stopped = false; + std::optional + notify_exception_access_violation; + std::optional notify_exception_code; bool is_stopped = false; std::vector> modules; diff --git a/src/xenia/debug/ui/debug_window.cc b/src/xenia/debug/ui/debug_window.cc index d926874c5d4..83b076c46a9 100644 --- a/src/xenia/debug/ui/debug_window.cc +++ b/src/xenia/debug/ui/debug_window.cc @@ -1576,6 +1576,8 @@ void DebugWindow::OnDetached() { } } +void DebugWindow::OnUnhandledException(Exception* ex) {} + void DebugWindow::OnExecutionPaused() { UpdateCache(); Focus(); diff --git a/src/xenia/debug/ui/debug_window.h b/src/xenia/debug/ui/debug_window.h index d40ce484f05..c58a3d448fa 100644 --- a/src/xenia/debug/ui/debug_window.h +++ b/src/xenia/debug/ui/debug_window.h @@ -44,6 +44,7 @@ class DebugWindow : public cpu::DebugListener { void OnFocus() override; void OnDetached() override; + void OnUnhandledException(Exception* ex) override; void OnExecutionPaused() override; void OnExecutionContinued() override; void OnExecutionEnded() override;