mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 05:28:56 +02:00
Support vCont with specific threads to resume
(gdb) set scheduler-locking on (gdb) continue
This commit is contained in:
parent
6c21530e43
commit
0a5b92e821
4 changed files with 71 additions and 20 deletions
|
|
@ -247,6 +247,12 @@ private:
|
|||
case DebuggerAction::Continue:
|
||||
MarkResumed([&] { ResumeEmulation(); });
|
||||
break;
|
||||
case DebuggerAction::ContinueThreads: {
|
||||
auto* gdb = static_cast<GDBStub*>(frontend.get());
|
||||
auto threads = std::move(gdb->vcont_threads);
|
||||
MarkResumed([&] { ResumeThreads(threads); });
|
||||
break;
|
||||
}
|
||||
case DebuggerAction::StepThreadUnlocked:
|
||||
MarkResumed([&] {
|
||||
state->active_thread->SetStepState(Kernel::StepState::StepPending);
|
||||
|
|
@ -298,6 +304,19 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void ResumeThreads(const std::vector<Kernel::KThread*>& threads) {
|
||||
Kernel::KScopedLightLock ll{debug_process->GetListLock()};
|
||||
Kernel::KScopedSchedulerLock sl{system.Kernel()};
|
||||
|
||||
// Wake up only the specified threads.
|
||||
for (auto* thread : threads) {
|
||||
if (thread) {
|
||||
thread->SetStepState(Kernel::StepState::NotStepping);
|
||||
thread->Resume(Kernel::SuspendType::Debug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
void MarkResumed(Callback&& cb) {
|
||||
stopped = false;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
|
|
@ -22,6 +22,7 @@ namespace Core {
|
|||
enum class DebuggerAction {
|
||||
Interrupt, ///< Stop emulation as soon as possible.
|
||||
Continue, ///< Resume emulation.
|
||||
ContinueThreads, ///< Resume only specific threads (listed in frontend).
|
||||
StepThreadLocked, ///< Step the currently-active thread without resuming others.
|
||||
StepThreadUnlocked, ///< Step the currently-active thread and resume others.
|
||||
ShutdownEmulation, ///< Shut down the emulator.
|
||||
|
|
|
|||
|
|
@ -470,27 +470,57 @@ void GDBStub::HandleVCont(std::string_view sv, std::vector<DebuggerAction>& acti
|
|||
// Continuing and stepping are supported (signal is ignored, but required for GDB to use vCont)
|
||||
if (sv == "?") {
|
||||
SendReply("vCont;c;C;s;S");
|
||||
} else {
|
||||
Kernel::KThread* stepped_thread = nullptr;
|
||||
bool lock_execution = true;
|
||||
std::vector<std::string> entries;
|
||||
boost::split(entries, sv.substr(1), boost::is_any_of(";"));
|
||||
for (auto const& thread_action : entries) {
|
||||
std::vector<std::string> parts;
|
||||
boost::split(parts, thread_action, boost::is_any_of(":"));
|
||||
if (parts.size() == 1 && (parts[0] == "c" || parts[0].starts_with("C")))
|
||||
lock_execution = false;
|
||||
if (parts.size() == 2 && (parts[0] == "s" || parts[0].starts_with("S")))
|
||||
stepped_thread = GetThreadByID(strtoll(parts[1].data(), nullptr, 16));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (stepped_thread) {
|
||||
backend.SetActiveThread(stepped_thread);
|
||||
actions.push_back(lock_execution ? DebuggerAction::StepThreadLocked : DebuggerAction::StepThreadUnlocked);
|
||||
} else {
|
||||
actions.push_back(DebuggerAction::Continue);
|
||||
Kernel::KThread* stepped_thread = nullptr;
|
||||
bool has_default_continue = false;
|
||||
std::vector<Kernel::KThread*> continue_threads;
|
||||
|
||||
std::vector<std::string> entries;
|
||||
boost::split(entries, sv.substr(1), boost::is_any_of(";"));
|
||||
for (auto const& thread_action : entries) {
|
||||
std::vector<std::string> parts;
|
||||
boost::split(parts, thread_action, boost::is_any_of(":"));
|
||||
|
||||
const bool is_step = parts[0] == "s" || parts[0].starts_with("S");
|
||||
const bool is_continue = parts[0] == "c" || parts[0].starts_with("C");
|
||||
|
||||
if (parts.size() == 1) {
|
||||
// Bare action (no thread ID) = default for all unmentioned threads.
|
||||
if (is_continue)
|
||||
has_default_continue = true;
|
||||
} else if (parts.size() == 2) {
|
||||
auto* thread = GetThreadByID(strtoll(parts[1].data(), nullptr, 16));
|
||||
if (is_step && thread)
|
||||
stepped_thread = thread;
|
||||
else if (is_continue && thread)
|
||||
continue_threads.push_back(thread);
|
||||
}
|
||||
}
|
||||
|
||||
if (stepped_thread) {
|
||||
backend.SetActiveThread(stepped_thread);
|
||||
if (has_default_continue) {
|
||||
// Step one thread, continue all others (e.g. vCont;s:4c;c).
|
||||
actions.push_back(DebuggerAction::StepThreadUnlocked);
|
||||
} else if (!continue_threads.empty()) {
|
||||
// Step one thread, continue specific others.
|
||||
// For now, treat as step-unlocked since we resume the listed threads.
|
||||
vcont_threads = std::move(continue_threads);
|
||||
actions.push_back(DebuggerAction::StepThreadUnlocked);
|
||||
} else {
|
||||
// Step one thread, keep all others stopped (e.g. vCont;s:4c).
|
||||
actions.push_back(DebuggerAction::StepThreadLocked);
|
||||
}
|
||||
} else if (has_default_continue) {
|
||||
// Continue all threads.
|
||||
actions.push_back(DebuggerAction::Continue);
|
||||
} else if (!continue_threads.empty()) {
|
||||
// Continue only specific threads.
|
||||
vcont_threads = std::move(continue_threads);
|
||||
actions.push_back(DebuggerAction::ContinueThreads);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
|
|
@ -52,6 +52,7 @@ struct GDBStub : public DebuggerFrontend {
|
|||
std::unique_ptr<GDBStubArch> arch;
|
||||
std::vector<char> current_command;
|
||||
std::map<VAddr, u32> replaced_instructions;
|
||||
std::vector<Kernel::KThread*> vcont_threads;
|
||||
bool no_ack{};
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue