mirror of
https://github.com/azahar-emu/azahar.git
synced 2026-06-08 11:43:40 -04:00
gdb: Add pause process at start and minor fixes
This commit is contained in:
parent
795cc06672
commit
418a056147
7 changed files with 123 additions and 12 deletions
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <QDesktopServices>
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include "citra_qt/configuration/configuration_shared.h"
|
||||
#include "citra_qt/configuration/configure_debug.h"
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
#include "common/file_util.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/core.h"
|
||||
#include "ui_configure_debug.h"
|
||||
#ifdef ENABLE_VULKAN
|
||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||
|
|
@ -33,6 +35,17 @@ ConfigureDebug::ConfigureDebug(bool is_powered_on_, QWidget* parent)
|
|||
ui->setupUi(this);
|
||||
SetConfiguration();
|
||||
|
||||
connect(ui->toggle_gdbstub, &QCheckBox::clicked,
|
||||
[this](bool checked) { ui->debug_next_process->setEnabled(checked); });
|
||||
|
||||
connect(ui->debug_next_process, &QCheckBox::clicked, [](bool checked) {
|
||||
if (checked) {
|
||||
Core::System::GetInstance().SetDebugNextProcessFlag();
|
||||
} else {
|
||||
Core::System::GetInstance().ClearDebugNextProcessFlag();
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->open_log_button, &QPushButton::clicked, []() {
|
||||
QString path = QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LogDir));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||
|
|
@ -94,6 +107,9 @@ ConfigureDebug::~ConfigureDebug() = default;
|
|||
|
||||
void ConfigureDebug::SetConfiguration() {
|
||||
ui->toggle_gdbstub->setChecked(Settings::values.use_gdbstub.GetValue());
|
||||
if (!ui->toggle_gdbstub->isChecked()) {
|
||||
ui->debug_next_process->setEnabled(false);
|
||||
}
|
||||
ui->gdbport_spinbox->setEnabled(Settings::values.use_gdbstub.GetValue());
|
||||
ui->gdbport_spinbox->setValue(Settings::values.gdbstub_port.GetValue());
|
||||
ui->toggle_console->setEnabled(!is_powered_on);
|
||||
|
|
@ -135,6 +151,10 @@ void ConfigureDebug::SetConfiguration() {
|
|||
ui->clock_display_label->setText(
|
||||
QStringLiteral("%1%").arg(Settings::values.cpu_clock_percentage.GetValue()));
|
||||
ui->instant_debug_log->setChecked(Settings::values.instant_debug_log.GetValue());
|
||||
|
||||
if (Core::System::GetInstance().GetDebugNextProcessFlag()) {
|
||||
ui->debug_next_process->setChecked(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureDebug::ApplyConfiguration() {
|
||||
|
|
|
|||
|
|
@ -60,6 +60,13 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="debug_next_process">
|
||||
<property name="text">
|
||||
<string>Pause next non-sysmodule process at start</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -405,6 +405,18 @@ public:
|
|||
info_led_color_changed = func;
|
||||
}
|
||||
|
||||
void SetDebugNextProcessFlag() {
|
||||
debug_next_process = true;
|
||||
}
|
||||
|
||||
bool GetDebugNextProcessFlag() {
|
||||
return debug_next_process;
|
||||
}
|
||||
|
||||
void ClearDebugNextProcessFlag() {
|
||||
debug_next_process = false;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize the emulated system.
|
||||
|
|
@ -514,6 +526,8 @@ private:
|
|||
Common::Vec3<u8> info_led_color;
|
||||
std::function<void()> info_led_color_changed;
|
||||
|
||||
bool debug_next_process;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ constexpr u32 SIGSEGV = 11;
|
|||
using SOCKET = UINT_PTR;
|
||||
#else
|
||||
using SOCKET = int;
|
||||
#define closesocket(x) close(x)
|
||||
#endif // _WIN32
|
||||
|
||||
#define INVALID_SOCKET ((SOCKET)(~0))
|
||||
|
|
@ -161,6 +162,9 @@ u16 gdbstub_port = 24689;
|
|||
constexpr bool supports_extended_mode = true;
|
||||
bool is_extended_mode = false;
|
||||
|
||||
bool is_running = false;
|
||||
bool current_process_finished = false;
|
||||
|
||||
// If set to false, the server will never be started and no
|
||||
// gdbstub-related functions will be executed.
|
||||
std::atomic<bool> server_enabled(false);
|
||||
|
|
@ -202,6 +206,9 @@ static void ResetState() {
|
|||
|
||||
is_extended_mode = false;
|
||||
|
||||
is_running = false;
|
||||
current_process_finished = false;
|
||||
|
||||
accept_socket = INVALID_SOCKET;
|
||||
continue_thread = -1;
|
||||
|
||||
|
|
@ -452,11 +459,12 @@ static bool SetNonBlock(SOCKET socket, bool nonblock) {
|
|||
|
||||
/// Read a byte from the gdb client.
|
||||
static u8 ReadByte() {
|
||||
u8 c;
|
||||
u8 c{};
|
||||
std::size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL);
|
||||
if (received_size != 1) {
|
||||
LOG_ERROR(Debug_GDBStub, "recv failed : {}", GetErrno());
|
||||
Shutdown();
|
||||
ToggleServer(false);
|
||||
ToggleServer(true);
|
||||
}
|
||||
|
||||
return c;
|
||||
|
|
@ -656,7 +664,9 @@ void SendReply(const char* reply) {
|
|||
static_cast<s32>(send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0));
|
||||
if (sent_size < 0) {
|
||||
LOG_ERROR(Debug_GDBStub, "gdb: send failed");
|
||||
return Shutdown();
|
||||
ToggleServer(false);
|
||||
ToggleServer(true);
|
||||
return;
|
||||
}
|
||||
|
||||
left -= sent_size;
|
||||
|
|
@ -806,11 +816,16 @@ static void HandleExtendedMode() {
|
|||
*
|
||||
* @param signal Signal to be sent to client.
|
||||
*/
|
||||
static void SendTStopReply(Kernel::Thread* thread, u32 signal, bool full = true) {
|
||||
static void SendStopReply(Kernel::Thread* thread, u32 signal, bool full = true) {
|
||||
if (gdbserver_socket == INVALID_SOCKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (current_process_finished) {
|
||||
SendReply("W00");
|
||||
return;
|
||||
}
|
||||
|
||||
latest_signal = signal;
|
||||
|
||||
if (!thread) {
|
||||
|
|
@ -849,7 +864,7 @@ static void HandleGetStopReason() {
|
|||
// The process has not been selected yet.
|
||||
SendReply("W00");
|
||||
} else {
|
||||
SendTStopReply(current_thread, latest_signal);
|
||||
SendStopReply(current_thread, latest_signal);
|
||||
}
|
||||
} else {
|
||||
// In non extended mode, select the process corresponding to the "main"
|
||||
|
|
@ -861,8 +876,9 @@ static void HandleGetStopReason() {
|
|||
if (process->codeset->program_id == program_id) {
|
||||
current_process = process.get();
|
||||
current_process->SetDebugBreak(true);
|
||||
is_running = false;
|
||||
if (SetThread(0)) {
|
||||
SendTStopReply(current_thread, 0);
|
||||
SendStopReply(current_thread, 0);
|
||||
} else {
|
||||
// Should never happen
|
||||
SendReply("W00");
|
||||
|
|
@ -883,10 +899,11 @@ static void BreakImpl(int signal) {
|
|||
}
|
||||
|
||||
current_process->SetDebugBreak(true);
|
||||
is_running = false;
|
||||
|
||||
latest_signal = signal;
|
||||
|
||||
SendTStopReply(current_thread, signal);
|
||||
SendStopReply(current_thread, signal);
|
||||
}
|
||||
|
||||
/// Read command from gdb client.
|
||||
|
|
@ -1116,7 +1133,7 @@ static void WriteRegisters() {
|
|||
/// Read location in memory specified by gdb client.
|
||||
static void ReadMemory() {
|
||||
if (!current_process) {
|
||||
SendReply("E01");
|
||||
SendReply("");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1133,12 +1150,12 @@ static void ReadMemory() {
|
|||
LOG_DEBUG(Debug_GDBStub, "ReadMemory addr: {:08x} len: {:08x}", addr, len);
|
||||
|
||||
if (len * 2 > sizeof(reply)) {
|
||||
SendReply("E01");
|
||||
SendReply("");
|
||||
}
|
||||
|
||||
auto& memory = Core::System::GetInstance().Memory();
|
||||
if (!memory.IsValidVirtualAddress(*current_process, addr)) {
|
||||
return SendReply("E14");
|
||||
return SendReply("");
|
||||
}
|
||||
|
||||
std::vector<u8> data(len);
|
||||
|
|
@ -1170,7 +1187,7 @@ static void WriteMemory() {
|
|||
|
||||
auto& memory = Core::System::GetInstance().Memory();
|
||||
if (!memory.IsValidVirtualAddress(*current_process, addr)) {
|
||||
return SendReply("E00");
|
||||
return SendReply("E0E");
|
||||
}
|
||||
|
||||
std::vector<u8> data(len);
|
||||
|
|
@ -1230,6 +1247,8 @@ static void Continue() {
|
|||
}
|
||||
|
||||
current_process->SetDebugBreak(false, continue_list);
|
||||
is_running = true;
|
||||
|
||||
ClearAllInstructionCache();
|
||||
}
|
||||
|
||||
|
|
@ -1394,8 +1413,9 @@ void HandleVCommand() {
|
|||
} else {
|
||||
current_process = process.get();
|
||||
current_process->SetDebugBreak(true);
|
||||
is_running = false;
|
||||
if (SetThread(0)) {
|
||||
SendTStopReply(current_thread, 0);
|
||||
SendStopReply(current_thread, 0);
|
||||
} else {
|
||||
// Should never happen
|
||||
SendReply("W00");
|
||||
|
|
@ -1435,12 +1455,34 @@ void HandleVCommand() {
|
|||
}
|
||||
|
||||
current_process->SetDebugBreak(false, thread_ids);
|
||||
is_running = true;
|
||||
}
|
||||
} else {
|
||||
SendReply("");
|
||||
}
|
||||
}
|
||||
|
||||
void OnProcessExit(u32 process_id) {
|
||||
if (!GDBStub::IsConnected || !current_process || current_process->process_id != process_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_process_finished = true;
|
||||
if (is_running) {
|
||||
SendStopReply(nullptr, 0);
|
||||
}
|
||||
current_process = nullptr;
|
||||
current_thread = nullptr;
|
||||
}
|
||||
|
||||
void OnThreadExit(u32 thread_id) {
|
||||
if (!GDBStub::IsConnected || !current_thread || current_thread->thread_id != thread_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_thread = nullptr;
|
||||
}
|
||||
|
||||
void HandlePacket(Core::System& system) {
|
||||
|
||||
if (!IsConnected()) {
|
||||
|
|
@ -1475,6 +1517,7 @@ void HandlePacket(Core::System& system) {
|
|||
}
|
||||
|
||||
shutdown(accept_socket, SHUT_RDWR);
|
||||
closesocket(accept_socket);
|
||||
accept_socket = INVALID_SOCKET;
|
||||
}
|
||||
return;
|
||||
|
|
@ -1676,11 +1719,13 @@ void Shutdown() {
|
|||
LOG_INFO(Debug_GDBStub, "Stopping GDB ...");
|
||||
if (gdbserver_socket != INVALID_SOCKET) {
|
||||
shutdown(gdbserver_socket, SHUT_RDWR);
|
||||
closesocket(gdbserver_socket);
|
||||
gdbserver_socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (accept_socket != INVALID_SOCKET) {
|
||||
shutdown(accept_socket, SHUT_RDWR);
|
||||
closesocket(accept_socket);
|
||||
accept_socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,16 @@ bool IsConnected();
|
|||
*/
|
||||
void Break(int signal);
|
||||
|
||||
/**
|
||||
* Signal to the GDB stub that the specified process ID is exiting
|
||||
*/
|
||||
void OnProcessExit(u32 process_id);
|
||||
|
||||
/**
|
||||
* Signal to the GDB stub that the specified thread ID is exiting
|
||||
*/
|
||||
void OnThreadExit(u32 thread_id);
|
||||
|
||||
/// Read and handle packet from gdb client.
|
||||
void HandlePacket(Core::System& system);
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "common/logging/log.h"
|
||||
#include "common/serialization/boost_vector.hpp"
|
||||
#include "core/core.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
|
@ -260,9 +261,21 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
|||
|
||||
vm_manager.LogLayout(Common::Log::Level::Debug);
|
||||
Kernel::SetupMainThread(kernel, codeset->entrypoint, main_thread_priority, SharedFrom(this));
|
||||
|
||||
// Pause process at start if flag enabled and we are not a sysmodule
|
||||
if (Core::System::GetInstance().GetDebugNextProcessFlag() &&
|
||||
resource_limit->GetCategory() != Kernel::ResourceLimitCategory::Other) {
|
||||
if (GDBStub::IsServerEnabled()) {
|
||||
LOG_INFO(Loader, "Pausing process {} at start", process_id);
|
||||
SetDebugBreak(true);
|
||||
}
|
||||
Core::System::GetInstance().ClearDebugNextProcessFlag();
|
||||
}
|
||||
}
|
||||
|
||||
void Process::Exit() {
|
||||
GDBStub::OnProcessExit(process_id);
|
||||
|
||||
auto plgldr = Service::PLGLDR::GetService(Core::System::GetInstance());
|
||||
if (plgldr) {
|
||||
plgldr->OnProcessExit(*this, kernel);
|
||||
|
|
|
|||
|
|
@ -134,6 +134,8 @@ void Thread::Stop() {
|
|||
process->tls_slots[tls_page].reset(tls_slot);
|
||||
process->resource_limit->Release(ResourceLimitType::Thread, 1);
|
||||
}
|
||||
|
||||
GDBStub::OnThreadExit(thread_id);
|
||||
}
|
||||
|
||||
void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue