Switching debugger to not retain XThreads.
This commit is contained in:
parent
1b487b67c9
commit
07ba1be7f5
|
@ -183,10 +183,9 @@ std::vector<ThreadExecutionInfo*> Debugger::QueryThreadExecutionInfos() {
|
|||
return result;
|
||||
}
|
||||
|
||||
ThreadExecutionInfo* Debugger::QueryThreadExecutionInfo(
|
||||
uint32_t thread_handle) {
|
||||
ThreadExecutionInfo* Debugger::QueryThreadExecutionInfo(uint32_t thread_id) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
const auto& it = thread_execution_infos_.find(thread_handle);
|
||||
const auto& it = thread_execution_infos_.find(thread_id);
|
||||
if (it == thread_execution_infos_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -232,8 +231,7 @@ bool Debugger::SuspendAllThreads() {
|
|||
// Thread is a host thread, and we aren't suspending those (for now).
|
||||
continue;
|
||||
} else if (XThread::IsInThread() &&
|
||||
thread_info->thread_handle ==
|
||||
XThread::GetCurrentThreadHandle()) {
|
||||
thread_info->thread_id == XThread::GetCurrentThreadId()) {
|
||||
// Can't suspend ourselves.
|
||||
continue;
|
||||
}
|
||||
|
@ -244,9 +242,9 @@ bool Debugger::SuspendAllThreads() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::ResumeThread(uint32_t thread_handle) {
|
||||
bool Debugger::ResumeThread(uint32_t thread_id) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = thread_execution_infos_.find(thread_handle);
|
||||
auto it = thread_execution_infos_.find(thread_id);
|
||||
if (it == thread_execution_infos_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -273,8 +271,7 @@ bool Debugger::ResumeAllThreads() {
|
|||
// Thread is a host thread, and we aren't suspending those (for now).
|
||||
continue;
|
||||
} else if (XThread::IsInThread() &&
|
||||
thread_info->thread_handle ==
|
||||
XThread::GetCurrentThreadHandle()) {
|
||||
thread_info->thread_id == XThread::GetCurrentThreadId()) {
|
||||
// Can't resume ourselves.
|
||||
continue;
|
||||
}
|
||||
|
@ -285,7 +282,7 @@ bool Debugger::ResumeAllThreads() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Debugger::UpdateThreadExecutionStates(uint32_t override_handle,
|
||||
void Debugger::UpdateThreadExecutionStates(uint32_t override_thread_id,
|
||||
X64Context* override_context) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto stack_walker = emulator_->processor()->stack_walker();
|
||||
|
@ -310,7 +307,7 @@ void Debugger::UpdateThreadExecutionStates(uint32_t override_handle,
|
|||
// Grab stack trace and X64 context then resolve all symbols.
|
||||
uint64_t hash;
|
||||
X64Context* in_host_context = nullptr;
|
||||
if (override_handle == thread_info->thread_handle) {
|
||||
if (override_thread_id == thread_info->thread_id) {
|
||||
// If we were passed an override context we use that. Otherwise, ask the
|
||||
// stack walker for a new context.
|
||||
in_host_context = override_context;
|
||||
|
@ -392,12 +389,12 @@ void Debugger::Continue() {
|
|||
}
|
||||
}
|
||||
|
||||
void Debugger::StepGuestInstruction(uint32_t thread_handle) {
|
||||
void Debugger::StepGuestInstruction(uint32_t thread_id) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
assert_true(execution_state_ == ExecutionState::kPaused);
|
||||
execution_state_ = ExecutionState::kStepping;
|
||||
|
||||
auto thread_info = thread_execution_infos_[thread_handle].get();
|
||||
auto thread_info = thread_execution_infos_[thread_id].get();
|
||||
|
||||
uint32_t next_pc = CalculateNextGuestInstruction(
|
||||
thread_info, thread_info->frames[0].guest_pc);
|
||||
|
@ -409,15 +406,15 @@ void Debugger::StepGuestInstruction(uint32_t thread_handle) {
|
|||
thread_info->step_breakpoint->Resume();
|
||||
|
||||
// ResumeAllBreakpoints();
|
||||
ResumeThread(thread_handle);
|
||||
ResumeThread(thread_id);
|
||||
}
|
||||
|
||||
void Debugger::StepHostInstruction(uint32_t thread_handle) {
|
||||
void Debugger::StepHostInstruction(uint32_t thread_id) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
assert_true(execution_state_ == ExecutionState::kPaused);
|
||||
execution_state_ = ExecutionState::kStepping;
|
||||
|
||||
auto thread_info = thread_execution_infos_[thread_handle].get();
|
||||
auto thread_info = thread_execution_infos_[thread_id].get();
|
||||
uint64_t new_host_pc =
|
||||
CalculateNextHostInstruction(thread_info, thread_info->frames[0].host_pc);
|
||||
|
||||
|
@ -428,23 +425,24 @@ void Debugger::StepHostInstruction(uint32_t thread_handle) {
|
|||
thread_info->step_breakpoint->Resume();
|
||||
|
||||
// ResumeAllBreakpoints();
|
||||
ResumeThread(thread_handle);
|
||||
ResumeThread(thread_id);
|
||||
}
|
||||
|
||||
void Debugger::OnThreadCreated(XThread* thread) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto thread_info = std::make_unique<ThreadExecutionInfo>();
|
||||
thread_info->thread_handle = thread->handle();
|
||||
thread_info->thread_id = thread->thread_id();
|
||||
thread_info->thread = thread;
|
||||
thread_info->state = ThreadExecutionInfo::State::kAlive;
|
||||
thread_info->suspended = false;
|
||||
thread_execution_infos_.emplace(thread_info->thread_handle,
|
||||
thread_execution_infos_.emplace(thread_info->thread_id,
|
||||
std::move(thread_info));
|
||||
}
|
||||
|
||||
void Debugger::OnThreadExit(XThread* thread) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = thread_execution_infos_.find(thread->handle());
|
||||
auto it = thread_execution_infos_.find(thread->thread_id());
|
||||
assert_true(it != thread_execution_infos_.end());
|
||||
auto thread_info = it->second.get();
|
||||
thread_info->state = ThreadExecutionInfo::State::kExited;
|
||||
|
@ -452,7 +450,7 @@ void Debugger::OnThreadExit(XThread* thread) {
|
|||
|
||||
void Debugger::OnThreadDestroyed(XThread* thread) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = thread_execution_infos_.find(thread->handle());
|
||||
auto it = thread_execution_infos_.find(thread->thread_id());
|
||||
assert_true(it != thread_execution_infos_.end());
|
||||
auto thread_info = it->second.get();
|
||||
// TODO(benvanik): retain the thread?
|
||||
|
@ -462,7 +460,7 @@ void Debugger::OnThreadDestroyed(XThread* thread) {
|
|||
|
||||
void Debugger::OnThreadEnteringWait(XThread* thread) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = thread_execution_infos_.find(thread->handle());
|
||||
auto it = thread_execution_infos_.find(thread->thread_id());
|
||||
assert_true(it != thread_execution_infos_.end());
|
||||
auto thread_info = it->second.get();
|
||||
thread_info->state = ThreadExecutionInfo::State::kWaiting;
|
||||
|
@ -470,7 +468,7 @@ void Debugger::OnThreadEnteringWait(XThread* thread) {
|
|||
|
||||
void Debugger::OnThreadLeavingWait(XThread* thread) {
|
||||
auto global_lock = global_critical_region_.Acquire();
|
||||
auto it = thread_execution_infos_.find(thread->handle());
|
||||
auto it = thread_execution_infos_.find(thread->thread_id());
|
||||
assert_true(it != thread_execution_infos_.end());
|
||||
auto thread_info = it->second.get();
|
||||
if (thread_info->state == ThreadExecutionInfo::State::kWaiting) {
|
||||
|
@ -531,7 +529,7 @@ bool Debugger::ExceptionCallback(Exception* ex) {
|
|||
SuspendAllThreads();
|
||||
|
||||
// Lookup thread info block.
|
||||
auto it = thread_execution_infos_.find(XThread::GetCurrentThreadHandle());
|
||||
auto it = thread_execution_infos_.find(XThread::GetCurrentThreadId());
|
||||
if (it == thread_execution_infos_.end()) {
|
||||
// Not found - exception on a thread we don't know about?
|
||||
assert_always("UD2 on a thread we don't track");
|
||||
|
@ -548,7 +546,7 @@ bool Debugger::ExceptionCallback(Exception* ex) {
|
|||
// Update all thread states with their latest values, using the context we got
|
||||
// from the exception instead of a sampled value (as it would just show the
|
||||
// exception handler).
|
||||
UpdateThreadExecutionStates(thread_info->thread_handle, ex->thread_context());
|
||||
UpdateThreadExecutionStates(thread_info->thread_id, ex->thread_context());
|
||||
|
||||
// Whether we should block waiting for a continue event.
|
||||
bool wait_for_continue = false;
|
||||
|
@ -673,7 +671,7 @@ bool Debugger::OnUnhandledException(Exception* ex) {
|
|||
// Suspend all guest threads (but this one).
|
||||
SuspendAllThreads();
|
||||
|
||||
UpdateThreadExecutionStates(XThread::GetCurrentThreadHandle(),
|
||||
UpdateThreadExecutionStates(XThread::GetCurrentThreadId(),
|
||||
ex->thread_context());
|
||||
|
||||
// Stop and notify the listener.
|
||||
|
|
|
@ -74,7 +74,10 @@ struct ThreadExecutionInfo {
|
|||
kZombie,
|
||||
};
|
||||
|
||||
// XThread::thread_id(), unique to the thread for the run of the emulator.
|
||||
uint32_t thread_id = 0;
|
||||
// XThread::handle() of the thread.
|
||||
// This will be invalidated when the thread dies.
|
||||
uint32_t thread_handle = 0;
|
||||
// Target XThread, if it has not been destroyed.
|
||||
// TODO(benvanik): hold a ref here to keep zombie threads around?
|
||||
|
@ -203,7 +206,7 @@ class Debugger {
|
|||
// the kernel.
|
||||
std::vector<ThreadExecutionInfo*> QueryThreadExecutionInfos();
|
||||
// Returns the debugger info for the given thread.
|
||||
ThreadExecutionInfo* QueryThreadExecutionInfo(uint32_t thread_handle);
|
||||
ThreadExecutionInfo* QueryThreadExecutionInfo(uint32_t thread_id);
|
||||
|
||||
// Adds a breakpoint to the debugger and activates it (if enabled).
|
||||
// The given breakpoint will not be owned by the debugger and must remain
|
||||
|
@ -230,10 +233,10 @@ class Debugger {
|
|||
|
||||
// Steps the given thread a single PPC guest instruction.
|
||||
// If the step is over a branch the branch will be followed.
|
||||
void StepGuestInstruction(uint32_t thread_handle);
|
||||
void StepGuestInstruction(uint32_t thread_id);
|
||||
// Steps the given thread a single x64 host instruction.
|
||||
// If the step is over a branch the branch will be followed.
|
||||
void StepHostInstruction(uint32_t thread_handle);
|
||||
void StepHostInstruction(uint32_t thread_id);
|
||||
|
||||
public:
|
||||
// TODO(benvanik): hide.
|
||||
|
@ -254,7 +257,7 @@ class Debugger {
|
|||
// Suspends all known threads (except the caller).
|
||||
bool SuspendAllThreads();
|
||||
// Resumes the given thread.
|
||||
bool ResumeThread(uint32_t thread_handle);
|
||||
bool ResumeThread(uint32_t thread_id);
|
||||
// Resumes all known threads (except the caller).
|
||||
bool ResumeAllThreads();
|
||||
// Updates all cached thread execution info (state, call stacks, etc).
|
||||
|
|
|
@ -293,8 +293,8 @@ void DebugWindow::DrawToolbar() {
|
|||
if (ImGui::Combo("##thread_combo", ¤t_thread_index,
|
||||
thread_combo.GetString(), 10)) {
|
||||
// Thread changed.
|
||||
SelectThreadStackFrame(
|
||||
cache_.thread_execution_infos[current_thread_index]->thread, 0, true);
|
||||
SelectThreadStackFrame(cache_.thread_execution_infos[current_thread_index],
|
||||
0, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,12 +347,12 @@ void DebugWindow::DrawSourcePane() {
|
|||
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushButtonRepeat(true);
|
||||
bool can_step = !cache_.is_running && state_.thread;
|
||||
bool can_step = !cache_.is_running && state_.thread_info;
|
||||
if (ImGui::ButtonEx("Step PPC", ImVec2(0, 0),
|
||||
can_step ? 0 : ImGuiButtonFlags_Disabled)) {
|
||||
// By enabling the button when stepping we allow repeat behavior.
|
||||
if (debugger_->execution_state() != ExecutionState::kStepping) {
|
||||
debugger_->StepGuestInstruction(state_.thread->handle());
|
||||
debugger_->StepGuestInstruction(state_.thread_info->thread_id);
|
||||
}
|
||||
}
|
||||
ImGui::PopButtonRepeat();
|
||||
|
@ -370,7 +370,7 @@ void DebugWindow::DrawSourcePane() {
|
|||
can_step ? 0 : ImGuiButtonFlags_Disabled)) {
|
||||
// By enabling the button when stepping we allow repeat behavior.
|
||||
if (debugger_->execution_state() != ExecutionState::kStepping) {
|
||||
debugger_->StepHostInstruction(state_.thread->handle());
|
||||
debugger_->StepHostInstruction(state_.thread_info->thread_id);
|
||||
}
|
||||
}
|
||||
ImGui::PopButtonRepeat();
|
||||
|
@ -993,8 +993,8 @@ void DebugWindow::DrawThreadsPane() {
|
|||
ImGui::BeginChild("##threads_listing");
|
||||
for (size_t i = 0; i < cache_.thread_execution_infos.size(); ++i) {
|
||||
auto thread_info = cache_.thread_execution_infos[i];
|
||||
bool is_current_thread = thread_info == state_.thread_info;
|
||||
auto thread = thread_info->thread;
|
||||
bool is_current_thread = thread == state_.thread;
|
||||
if (!thread) {
|
||||
// TODO(benvanik): better display of zombie thread states.
|
||||
continue;
|
||||
|
@ -1009,7 +1009,7 @@ void DebugWindow::DrawThreadsPane() {
|
|||
ImGui::PushStyleColor(ImGuiCol_Header,
|
||||
ImGui::GetStyle().Colors[ImGuiCol_HeaderActive]);
|
||||
}
|
||||
ImGui::PushID(thread);
|
||||
ImGui::PushID(thread_info);
|
||||
if (is_current_thread) {
|
||||
ImGui::SetNextTreeNodeOpened(true, ImGuiSetCond_Always);
|
||||
}
|
||||
|
@ -1049,7 +1049,7 @@ void DebugWindow::DrawThreadsPane() {
|
|||
frame.host_pc, &frame);
|
||||
if (ImGui::Selectable(host_label, is_current_frame,
|
||||
ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
SelectThreadStackFrame(thread, j, true);
|
||||
SelectThreadStackFrame(thread_info, j, true);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(8, 0));
|
||||
|
@ -1386,21 +1386,13 @@ void DebugWindow::DrawLogPane() {
|
|||
// if big, click to open dialog with contents
|
||||
}
|
||||
|
||||
void DebugWindow::SelectThreadStackFrame(XThread* thread,
|
||||
void DebugWindow::SelectThreadStackFrame(ThreadExecutionInfo* thread_info,
|
||||
size_t stack_frame_index,
|
||||
bool always_navigate) {
|
||||
state_.has_changed_thread = false;
|
||||
if (thread != state_.thread) {
|
||||
if (thread_info != state_.thread_info) {
|
||||
state_.has_changed_thread = true;
|
||||
state_.thread = thread;
|
||||
|
||||
state_.thread_info = nullptr;
|
||||
for (auto thread_info : cache_.thread_execution_infos) {
|
||||
if (thread_info->thread == thread) {
|
||||
state_.thread_info = thread_info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
state_.thread_info = thread_info;
|
||||
}
|
||||
if (state_.thread_info) {
|
||||
stack_frame_index =
|
||||
|
@ -1469,7 +1461,8 @@ void DebugWindow::UpdateCache() {
|
|||
|
||||
cache_.thread_execution_infos = debugger_->QueryThreadExecutionInfos();
|
||||
|
||||
SelectThreadStackFrame(state_.thread, state_.thread_stack_frame_index, false);
|
||||
SelectThreadStackFrame(state_.thread_info, state_.thread_stack_frame_index,
|
||||
false);
|
||||
}
|
||||
|
||||
void DebugWindow::CreateCodeBreakpoint(CodeBreakpoint::AddressType address_type,
|
||||
|
@ -1582,14 +1575,16 @@ void DebugWindow::OnExecutionEnded() {
|
|||
|
||||
void DebugWindow::OnStepCompleted(xe::kernel::XThread* thread) {
|
||||
UpdateCache();
|
||||
SelectThreadStackFrame(thread, 0, true);
|
||||
auto thread_info = debugger_->QueryThreadExecutionInfo(thread->thread_id());
|
||||
SelectThreadStackFrame(thread_info, 0, true);
|
||||
loop_->Post([this]() { window_->set_focus(true); });
|
||||
}
|
||||
|
||||
void DebugWindow::OnBreakpointHit(Breakpoint* breakpoint,
|
||||
xe::kernel::XThread* thread) {
|
||||
UpdateCache();
|
||||
SelectThreadStackFrame(thread, 0, true);
|
||||
auto thread_info = debugger_->QueryThreadExecutionInfo(thread->thread_id());
|
||||
SelectThreadStackFrame(thread_info, 0, true);
|
||||
loop_->Post([this]() { window_->set_focus(true); });
|
||||
}
|
||||
|
||||
|
|
|
@ -69,8 +69,8 @@ class DebugWindow : public DebugListener {
|
|||
void DrawBreakpointsPane();
|
||||
void DrawLogPane();
|
||||
|
||||
void SelectThreadStackFrame(kernel::XThread* thread, size_t stack_frame_index,
|
||||
bool always_navigate);
|
||||
void SelectThreadStackFrame(ThreadExecutionInfo* thread_info,
|
||||
size_t stack_frame_index, bool always_navigate);
|
||||
void NavigateToFunction(cpu::Function* function, uint32_t guest_pc = 0,
|
||||
uint64_t host_pc = 0);
|
||||
// void NavigateToMemory(uint64_t address, uint64_t length = 0);
|
||||
|
@ -117,7 +117,6 @@ class DebugWindow : public DebugListener {
|
|||
static const int kRightPaneMemory = 1;
|
||||
int right_pane_tab = kRightPaneThreads;
|
||||
|
||||
xe::kernel::XThread* thread = nullptr;
|
||||
ThreadExecutionInfo* thread_info = nullptr;
|
||||
size_t thread_stack_frame_index = 0;
|
||||
bool has_changed_thread = false;
|
||||
|
|
Loading…
Reference in New Issue