From a78a5003fa6dcdbc80b11b2bff73d47ae948cea6 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 16:03:01 +0100 Subject: [PATCH 01/71] GDB Stub should work now. --- src/core/arm/unicorn/arm_unicorn.cpp | 42 ++++- src/core/gdbstub/gdbstub.cpp | 249 +++++++++++++++++++++++---- src/core/gdbstub/gdbstub.h | 2 + 3 files changed, 258 insertions(+), 35 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index c0cc62f03a..79def5007b 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -10,6 +10,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/svc.h" +#include "core/gdbstub/gdbstub.h" // Load Unicorn DLL once on Windows using RAII #ifdef _MSC_VER @@ -35,6 +36,19 @@ LoadDll LoadDll::g_load_dll; } \ } while (0) +static GDBStub::BreakpointAddress bkpt = {0}; +static bool bkptHit = false; + +static void CodeHook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); + if(GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) + { + bkptHit = true; + uc_emu_stop(uc); + } +} + static void InterruptHook(uc_engine* uc, u32 intNo, void* user_data) { u32 esr{}; CHECKED(uc_reg_read(uc, UC_ARM64_REG_ESR, &esr)); @@ -67,6 +81,10 @@ ARM_Unicorn::ARM_Unicorn() { uc_hook hook{}; CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); + if(GDBStub::IsServerEnabled()) + { + CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); + } } ARM_Unicorn::~ARM_Unicorn() { @@ -155,7 +173,14 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) { } void ARM_Unicorn::Run() { - ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); + if(GDBStub::IsServerEnabled()) + { + ExecuteInstructions(std::max(4000000, 0)); + } + else + { + ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); + } } void ARM_Unicorn::Step() { @@ -168,6 +193,21 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); + if(GDBStub::IsServerEnabled()) + { + if(bkptHit) + { + uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); + } + Kernel::Thread *thread = Kernel::GetCurrentThread(); + SaveContext(thread->context); + if(bkptHit) + { + bkptHit = false; + GDBStub::Break(); + } + GDBStub::SendSig(thread, 5); + } } void ARM_Unicorn::SaveContext(ARM_Interface::ThreadContext& ctx) { diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 6c5a40ba8c..aca7bc7a6b 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -16,6 +16,7 @@ #include #ifdef _WIN32 +#define NTDDI_VERSION NTDDI_WIN8 #include // winsock2.h needs to be included first to prevent winsock.h being included by other includes #include @@ -31,12 +32,19 @@ #endif #include "common/logging/log.h" +//#undef NGLOG_INFO +//#define NGLOG_INFO NGLOG_ERROR +//#undef NGLOG_DEBUG +//#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/core_cpu.h" #include "core/gdbstub/gdbstub.h" #include "core/loader/loader.h" #include "core/memory.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" const int GDB_BUFFER_SIZE = 10000; @@ -137,9 +145,11 @@ static u8 command_buffer[GDB_BUFFER_SIZE]; static u32 command_length; static u32 latest_signal = 0; -static bool step_break = false; static bool memory_break = false; +Kernel::Thread *thread = nullptr; +int current_core = 0; + // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. static u16 gdbstub_port = 24689; @@ -165,6 +175,79 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; +Kernel::Thread *FindThread(int id, int& current_core) +{ + Kernel::Thread *thread = nullptr; + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto it = list.begin(); it != list.end(); it++) + { + if((*it)->GetThreadId() == id) + { + thread = &(*(*it)); + current_core = core; + break; + } + } + } + return thread; +} + +static u64 regr(int id, Kernel::Thread *thread = nullptr) +{ + if(!thread) + { + return 0; + } + + if(id < SP_REGISTER) + { + return thread->context.cpu_registers[id]; + } + else if(id == SP_REGISTER) + { + return thread->context.sp; + } + else if(id == PC_REGISTER) + { + return thread->context.pc; + } + else if(id == CPSR_REGISTER) + { + return thread->context.cpsr; + } + else + { + return 0; + } +} + +static void regw(int id, u64 val, Kernel::Thread *thread = nullptr) +{ + if(!thread) + { + return; + } + + if(id < SP_REGISTER) + { + thread->context.cpu_registers[id] = val; + } + else if(id == SP_REGISTER) + { + thread->context.sp = val; + } + else if(id == PC_REGISTER) + { + thread->context.pc = val; + } + else if(id == CPSR_REGISTER) + { + thread->context.cpsr = val; + } +} + /** * Turns hex string character into the equivalent byte. * @@ -193,7 +276,7 @@ static u8 NibbleToHex(u8 n) { if (n < 0xA) { return '0' + n; } else { - return 'A' + n - 0xA; + return 'a' + n - 0xA; } } @@ -439,6 +522,8 @@ static void SendReply(const char* reply) { return; } + NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); + memset(command_buffer, 0, sizeof(command_buffer)); command_length = static_cast(strlen(reply)); @@ -470,31 +555,99 @@ static void SendReply(const char* reply) { } /// Handle query command from gdb client. -static void HandleQuery() { +static void HandleQuery() +{ NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); const char* query = reinterpret_cast(command_buffer + 1); - if (strcmp(query, "TStatus") == 0) { + if(strcmp(query, "TStatus") == 0) + { SendReply("T0"); - } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { + } + else if(strncmp(query, "Supported", strlen("Supported")) == 0) + { // PacketSize needs to be large enough for target xml SendReply("PacketSize=2000;qXfer:features:read+"); - } else if (strncmp(query, "Xfer:features:read:target.xml:", - strlen("Xfer:features:read:target.xml:")) == 0) { + } + else if(strncmp(query, "Xfer:features:read:target.xml:", + strlen("Xfer:features:read:target.xml:")) == 0) + { SendReply(target_xml); - } else { + } + else if(strncmp(query, "Offsets", strlen("Offsets")) == 0) + { + std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); + SendReply(buffer.c_str()); + } + else if(strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) + { + std::string val = "m"; + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto it = list.begin(); it != list.end(); it++) + { + char tmp[17] = {0}; + memset(tmp, 0, sizeof(tmp)); + sprintf(tmp, "%x", (*it)->GetThreadId()); + val += (char*)tmp; + val += ","; + } + } + val.pop_back(); + SendReply(val.c_str()); + } + else if(strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) + { + SendReply("l"); + } + else + { SendReply(""); } } /// Handle set thread command from gdb client. -static void HandleSetThread() { - if (memcmp(command_buffer, "Hg0", 3) == 0 || memcmp(command_buffer, "Hc-1", 4) == 0 || - memcmp(command_buffer, "Hc0", 4) == 0 || memcmp(command_buffer, "Hc1", 4) == 0) { - return SendReply("OK"); +static void HandleSetThread() +{ + if(memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) + { + int threadid = -1; + if(command_buffer[2] != '-') + { + threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); + } + if(threadid >= 1) + { + thread = FindThread(threadid, current_core); + } + if(!thread) + { + threadid = 1; + thread = FindThread(threadid, current_core); + } + if(thread) + { + SendReply("OK"); + return; + } } + SendReply("E01"); +} +static void isThreadAlive() +{ + int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); + if(threadid == 0) + { + threadid = 1; + } + if(FindThread(threadid, current_core)) + { + SendReply("OK"); + return; + } SendReply("E01"); } @@ -503,15 +656,29 @@ static void HandleSetThread() { * * @param signal Signal to be sent to client. */ -static void SendSignal(u32 signal) { - if (gdbserver_socket == -1) { +static void SendSignal(Kernel::Thread *thread, u32 signal, bool full = true) +{ + if(gdbserver_socket == -1) + { return; } latest_signal = signal; - std::string buffer = fmt::format("T{:02x}", latest_signal); - NGLOG_DEBUG(Debug_GDBStub, "Response: {}", buffer); + std::string buffer; + if(full) + { + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, htonll(regr(PC_REGISTER, thread)), SP_REGISTER, htonll(regr(SP_REGISTER, thread))); + } + else + { + buffer = fmt::format("T{:02x};", latest_signal); + } + + buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + + //NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); + SendReply(buffer.c_str()); } @@ -527,7 +694,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(SIGTRAP); + SendSignal(thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -598,11 +765,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, Core::CurrentArmInterface().GetReg(static_cast(id))); + LongToGdbHex(reply, regr(id, thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, Core::CurrentArmInterface().GetPC()); + LongToGdbHex(reply, regr(id, thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, Core::CurrentArmInterface().GetCPSR()); + IntToGdbHex(reply, (u32)regr(id, thread)); } else { return SendReply("E01"); } @@ -618,16 +785,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, Core::CurrentArmInterface().GetReg(reg)); + LongToGdbHex(bufptr + reg * 16, regr(reg, thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, Core::CurrentArmInterface().GetPC()); + LongToGdbHex(bufptr, regr(PC_REGISTER, thread)); bufptr += 16; - IntToGdbHex(bufptr, Core::CurrentArmInterface().GetCPSR()); + IntToGdbHex(bufptr, (u32)regr(CPSR_REGISTER, thread)); bufptr += 8; @@ -646,11 +813,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - Core::CurrentArmInterface().SetReg(id, GdbHexToLong(buffer_ptr)); + regw(id, GdbHexToLong(buffer_ptr), thread); } else if (id == PC_REGISTER) { - Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr)); + regw(id, GdbHexToLong(buffer_ptr), thread); } else if (id == CPSR_REGISTER) { - Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr)); + regw(id, GdbHexToInt(buffer_ptr), thread); } else { return SendReply("E01"); } @@ -667,11 +834,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - Core::CurrentArmInterface().SetReg(reg, GdbHexToLong(buffer_ptr + i * 16)); + regw(reg, GdbHexToLong(buffer_ptr + i * 16), thread); } else if (reg == PC_REGISTER) { - Core::CurrentArmInterface().SetPC(GdbHexToLong(buffer_ptr + i * 16)); + regw(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), thread); } else if (reg == CPSR_REGISTER) { - Core::CurrentArmInterface().SetCPSR(GdbHexToInt(buffer_ptr + i * 16)); + regw(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), thread); } else { UNIMPLEMENTED(); } @@ -731,10 +898,13 @@ static void WriteMemory() { SendReply("OK"); } +bool send_trap = false; + void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; - SendSignal(SIGTRAP); + //SendSignal(SIGTRAP); + send_trap = true; } memory_break = is_memory_break; @@ -744,8 +914,8 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; - step_break = true; - SendSignal(SIGTRAP); + //SendSignal(SIGTRAP); + send_trap = true; } bool IsMemoryBreak() { @@ -759,7 +929,6 @@ bool IsMemoryBreak() { /// Tell the CPU to continue executing. static void Continue() { memory_break = false; - step_break = false; step_loop = false; halt_loop = false; } @@ -898,7 +1067,7 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(latest_signal); + SendSignal(thread, latest_signal); break; case 'k': Shutdown(); @@ -935,6 +1104,9 @@ void HandlePacket() { case 'Z': AddBreakpoint(); break; + case 'T': + isThreadAlive(); + break; default: SendReply(""); break; @@ -1079,4 +1251,13 @@ bool GetCpuStepFlag() { void SetCpuStepFlag(bool is_step) { step_loop = is_step; } + +void SendSig(void *_thread, int sig) +{ + if(send_trap) + { + send_trap = false; + SendSignal((Kernel::Thread *)_thread, sig); + } +} }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 201fca0957..357510e33e 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -91,4 +91,6 @@ bool GetCpuStepFlag(); * @param is_step */ void SetCpuStepFlag(bool is_step); + +void SendSig(void *thread, int sig); } // namespace GDBStub From 62fd45d0409ce609fd90ed7f01a824f177e5a3d5 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 16:46:08 +0100 Subject: [PATCH 02/71] Applied clang-format. --- src/core/arm/unicorn/arm_unicorn.cpp | 30 ++--- src/core/gdbstub/gdbstub.cpp | 168 +++++++++------------------ src/core/gdbstub/gdbstub.h | 2 +- 3 files changed, 69 insertions(+), 131 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 79def5007b..8e122c3d73 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -9,8 +9,8 @@ #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hle/kernel/svc.h" #include "core/gdbstub/gdbstub.h" +#include "core/hle/kernel/svc.h" // Load Unicorn DLL once on Windows using RAII #ifdef _MSC_VER @@ -39,11 +39,10 @@ LoadDll LoadDll::g_load_dll; static GDBStub::BreakpointAddress bkpt = {0}; static bool bkptHit = false; -static void CodeHook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ +static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); - if(GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) - { + if (GDBStub::IsMemoryBreak() || + (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { bkptHit = true; uc_emu_stop(uc); } @@ -81,8 +80,7 @@ ARM_Unicorn::ARM_Unicorn() { uc_hook hook{}; CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); - if(GDBStub::IsServerEnabled()) - { + if (GDBStub::IsServerEnabled()) { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); } } @@ -173,12 +171,9 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) { } void ARM_Unicorn::Run() { - if(GDBStub::IsServerEnabled()) - { + if (GDBStub::IsServerEnabled()) { ExecuteInstructions(std::max(4000000, 0)); - } - else - { + } else { ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); } } @@ -193,16 +188,13 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); - if(GDBStub::IsServerEnabled()) - { - if(bkptHit) - { + if (GDBStub::IsServerEnabled()) { + if (bkptHit) { uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); } - Kernel::Thread *thread = Kernel::GetCurrentThread(); + Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if(bkptHit) - { + if (bkptHit) { bkptHit = false; GDBStub::Break(); } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index aca7bc7a6b..e23152876c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -41,10 +41,10 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/gdbstub/gdbstub.h" -#include "core/loader/loader.h" -#include "core/memory.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/scheduler.h" +#include "core/loader/loader.h" +#include "core/memory.h" const int GDB_BUFFER_SIZE = 10000; @@ -147,7 +147,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -Kernel::Thread *thread = nullptr; +Kernel::Thread* thread = nullptr; int current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, @@ -175,75 +175,51 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; -Kernel::Thread *FindThread(int id, int& current_core) -{ - Kernel::Thread *thread = nullptr; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { +Kernel::Thread* FindThread(int id, int& current_core) { + Kernel::Thread* thread = nullptr; + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto it = list.begin(); it != list.end(); it++) - { - if((*it)->GetThreadId() == id) - { - thread = &(*(*it)); - current_core = core; - break; + for (auto it = list.begin(); it != list.end(); it++) { + if ((*it)->GetThreadId() == id) { + thread = &(*(*it)); + current_core = core; + break; } } } return thread; } -static u64 regr(int id, Kernel::Thread *thread = nullptr) -{ - if(!thread) - { +static u64 regr(int id, Kernel::Thread* thread = nullptr) { + if (!thread) { return 0; } - if(id < SP_REGISTER) - { + if (id < SP_REGISTER) { return thread->context.cpu_registers[id]; - } - else if(id == SP_REGISTER) - { + } else if (id == SP_REGISTER) { return thread->context.sp; - } - else if(id == PC_REGISTER) - { + } else if (id == PC_REGISTER) { return thread->context.pc; - } - else if(id == CPSR_REGISTER) - { + } else if (id == CPSR_REGISTER) { return thread->context.cpsr; - } - else - { + } else { return 0; } } -static void regw(int id, u64 val, Kernel::Thread *thread = nullptr) -{ - if(!thread) - { +static void regw(int id, u64 val, Kernel::Thread* thread = nullptr) { + if (!thread) { return; } - if(id < SP_REGISTER) - { + if (id < SP_REGISTER) { thread->context.cpu_registers[id] = val; - } - else if(id == SP_REGISTER) - { + } else if (id == SP_REGISTER) { thread->context.sp = val; - } - else if(id == PC_REGISTER) - { + } else if (id == PC_REGISTER) { thread->context.pc = val; - } - else if(id == CPSR_REGISTER) - { + } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; } } @@ -555,39 +531,27 @@ static void SendReply(const char* reply) { } /// Handle query command from gdb client. -static void HandleQuery() -{ +static void HandleQuery() { NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); const char* query = reinterpret_cast(command_buffer + 1); - if(strcmp(query, "TStatus") == 0) - { + if (strcmp(query, "TStatus") == 0) { SendReply("T0"); - } - else if(strncmp(query, "Supported", strlen("Supported")) == 0) - { + } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml SendReply("PacketSize=2000;qXfer:features:read+"); - } - else if(strncmp(query, "Xfer:features:read:target.xml:", - strlen("Xfer:features:read:target.xml:")) == 0) - { + } else if (strncmp(query, "Xfer:features:read:target.xml:", + strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); - } - else if(strncmp(query, "Offsets", strlen("Offsets")) == 0) - { + } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); - } - else if(strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) - { + } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto it = list.begin(); it != list.end(); it++) - { + for (auto it = list.begin(); it != list.end(); it++) { char tmp[17] = {0}; memset(tmp, 0, sizeof(tmp)); sprintf(tmp, "%x", (*it)->GetThreadId()); @@ -597,38 +561,28 @@ static void HandleQuery() } val.pop_back(); SendReply(val.c_str()); - } - else if(strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) - { + } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } - else - { + } else { SendReply(""); } } /// Handle set thread command from gdb client. -static void HandleSetThread() -{ - if(memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) - { +static void HandleSetThread() { + if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { int threadid = -1; - if(command_buffer[2] != '-') - { + if (command_buffer[2] != '-') { threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); } - if(threadid >= 1) - { + if (threadid >= 1) { thread = FindThread(threadid, current_core); } - if(!thread) - { + if (!thread) { threadid = 1; thread = FindThread(threadid, current_core); } - if(thread) - { + if (thread) { SendReply("OK"); return; } @@ -636,15 +590,12 @@ static void HandleSetThread() SendReply("E01"); } -static void isThreadAlive() -{ +static void isThreadAlive() { int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); - if(threadid == 0) - { + if (threadid == 0) { threadid = 1; } - if(FindThread(threadid, current_core)) - { + if (FindThread(threadid, current_core)) { SendReply("OK"); return; } @@ -656,28 +607,25 @@ static void isThreadAlive() * * @param signal Signal to be sent to client. */ -static void SendSignal(Kernel::Thread *thread, u32 signal, bool full = true) -{ - if(gdbserver_socket == -1) - { +static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { + if (gdbserver_socket == -1) { return; } latest_signal = signal; std::string buffer; - if(full) - { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, htonll(regr(PC_REGISTER, thread)), SP_REGISTER, htonll(regr(SP_REGISTER, thread))); - } - else - { + if (full) { + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, + htonll(regr(PC_REGISTER, thread)), SP_REGISTER, + htonll(regr(SP_REGISTER, thread))); + } else { buffer = fmt::format("T{:02x};", latest_signal); } buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - //NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); + // NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -903,7 +851,7 @@ bool send_trap = false; void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; - //SendSignal(SIGTRAP); + // SendSignal(SIGTRAP); send_trap = true; } @@ -914,7 +862,7 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; - //SendSignal(SIGTRAP); + // SendSignal(SIGTRAP); send_trap = true; } @@ -1252,12 +1200,10 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -void SendSig(void *_thread, int sig) -{ - if(send_trap) - { +void SendSig(void* _thread, int sig) { + if (send_trap) { send_trap = false; - SendSignal((Kernel::Thread *)_thread, sig); + SendSignal((Kernel::Thread*)_thread, sig); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 357510e33e..6f998fb28f 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -92,5 +92,5 @@ bool GetCpuStepFlag(); */ void SetCpuStepFlag(bool is_step); -void SendSig(void *thread, int sig); +void SendSig(void* thread, int sig); } // namespace GDBStub From f417fbcd47f0a9850abee5a3ae049a47a9573135 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 17:05:07 +0100 Subject: [PATCH 03/71] Replaced htonll with swap64. --- src/core/gdbstub/gdbstub.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e23152876c..97c0d8ca6c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -16,7 +16,6 @@ #include #ifdef _WIN32 -#define NTDDI_VERSION NTDDI_WIN8 #include // winsock2.h needs to be included first to prevent winsock.h being included by other includes #include @@ -37,6 +36,7 @@ //#undef NGLOG_DEBUG //#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" +#include "common/swap.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_cpu.h" @@ -617,8 +617,8 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - htonll(regr(PC_REGISTER, thread)), SP_REGISTER, - htonll(regr(SP_REGISTER, thread))); + Common::swap64(regr(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(regr(SP_REGISTER, thread))); } else { buffer = fmt::format("T{:02x};", latest_signal); } From f3ea3523b284f35a17532365941e4fd8c1eb5500 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 5 Jun 2018 12:56:02 +0100 Subject: [PATCH 04/71] Tidy up. --- src/core/arm/unicorn/arm_unicorn.cpp | 26 +++--- src/core/arm/unicorn/arm_unicorn.h | 4 + src/core/gdbstub/gdbstub.cpp | 113 ++++++++++++--------------- src/core/gdbstub/gdbstub.h | 9 ++- 4 files changed, 79 insertions(+), 73 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 8e122c3d73..ce6c5616d6 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -9,7 +9,6 @@ #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/svc.h" // Load Unicorn DLL once on Windows using RAII @@ -36,14 +35,13 @@ LoadDll LoadDll::g_load_dll; } \ } while (0) -static GDBStub::BreakpointAddress bkpt = {0}; -static bool bkptHit = false; - static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { - bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); + GDBStub::BreakpointAddress bkpt = + GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); if (GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { - bkptHit = true; + auto core = static_cast(user_data); + core->RecordBreak(bkpt); uc_emu_stop(uc); } } @@ -82,6 +80,7 @@ ARM_Unicorn::ARM_Unicorn() { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); if (GDBStub::IsServerEnabled()) { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); + last_bkpt_hit = false; } } @@ -189,16 +188,16 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { - if (bkptHit) { - uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); + if (last_bkpt_hit) { + uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (bkptHit) { - bkptHit = false; + if (last_bkpt_hit) { + last_bkpt_hit = false; GDBStub::Break(); } - GDBStub::SendSig(thread, 5); + GDBStub::SendTrap(thread, 5); } } @@ -265,3 +264,8 @@ void ARM_Unicorn::PrepareReschedule() { } void ARM_Unicorn::ClearInstructionCache() {} + +void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) { + last_bkpt = bkpt; + last_bkpt_hit = true; +} diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index b99b58e4c6..a482a2aa36 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -7,6 +7,7 @@ #include #include "common/common_types.h" #include "core/arm/arm_interface.h" +#include "core/gdbstub/gdbstub.h" class ARM_Unicorn final : public ARM_Interface { public: @@ -35,7 +36,10 @@ public: void Step() override; void ClearInstructionCache() override; void PageTableChanged() override{}; + void RecordBreak(GDBStub::BreakpointAddress bkpt); private: uc_engine* uc{}; + GDBStub::BreakpointAddress last_bkpt{}; + bool last_bkpt_hit; }; diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 97c0d8ca6c..2603192fea 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -31,10 +31,6 @@ #endif #include "common/logging/log.h" -//#undef NGLOG_INFO -//#define NGLOG_INFO NGLOG_ERROR -//#undef NGLOG_DEBUG -//#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" #include "common/swap.h" #include "core/arm/arm_interface.h" @@ -147,8 +143,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -Kernel::Thread* thread = nullptr; -int current_core = 0; +static Kernel::Thread* current_thread = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -156,6 +151,7 @@ static u16 gdbstub_port = 24689; static bool halt_loop = true; static bool step_loop = false; +static bool send_trap = false; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. @@ -175,22 +171,20 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; -Kernel::Thread* FindThread(int id, int& current_core) { - Kernel::Thread* thread = nullptr; +static Kernel::Thread* FindThreadById(int id) { for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto it = list.begin(); it != list.end(); it++) { - if ((*it)->GetThreadId() == id) { - thread = &(*(*it)); - current_core = core; - break; + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (auto thread : threads) { + if (thread->GetThreadId() == id) { + current_thread = thread.get(); + return current_thread; } } } - return thread; + return nullptr; } -static u64 regr(int id, Kernel::Thread* thread = nullptr) { +static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { if (!thread) { return 0; } @@ -208,7 +202,7 @@ static u64 regr(int id, Kernel::Thread* thread = nullptr) { } } -static void regw(int id, u64 val, Kernel::Thread* thread = nullptr) { +static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { if (!thread) { return; } @@ -550,12 +544,9 @@ static void HandleQuery() { } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto it = list.begin(); it != list.end(); it++) { - char tmp[17] = {0}; - memset(tmp, 0, sizeof(tmp)); - sprintf(tmp, "%x", (*it)->GetThreadId()); - val += (char*)tmp; + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (auto thread : threads) { + val += fmt::format("{:x}", thread->GetThreadId()); val += ","; } } @@ -571,18 +562,20 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int threadid = -1; + int thread_id = -1; if (command_buffer[2] != '-') { - threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); + thread_id = static_cast(HexToInt( + command_buffer + 2, + command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); } - if (threadid >= 1) { - thread = FindThread(threadid, current_core); + if (thread_id >= 1) { + current_thread = FindThreadById(thread_id); } - if (!thread) { - threadid = 1; - thread = FindThread(threadid, current_core); + if (!current_thread) { + thread_id = 1; + current_thread = FindThreadById(thread_id); } - if (thread) { + if (current_thread) { SendReply("OK"); return; } @@ -590,12 +583,15 @@ static void HandleSetThread() { SendReply("E01"); } -static void isThreadAlive() { - int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); - if (threadid == 0) { - threadid = 1; +/// Handle thread alive command from gdb client. +static void HandleThreadAlive() { + int thread_id = static_cast( + HexToInt(command_buffer + 1, + command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); + if (thread_id == 0) { + thread_id = 1; } - if (FindThread(threadid, current_core)) { + if (FindThreadById(thread_id)) { SendReply("OK"); return; } @@ -617,16 +613,14 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - Common::swap64(regr(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(regr(SP_REGISTER, thread))); + Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(RegRead(SP_REGISTER, thread))); } else { buffer = fmt::format("T{:02x};", latest_signal); } buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - // NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); - SendReply(buffer.c_str()); } @@ -642,7 +636,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(thread, SIGTRAP); + SendSignal(current_thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -713,11 +707,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, regr(id, thread)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, regr(id, thread)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)regr(id, thread)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread)); } else { return SendReply("E01"); } @@ -733,16 +727,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, regr(reg, thread)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, regr(PC_REGISTER, thread)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); bufptr += 16; - IntToGdbHex(bufptr, (u32)regr(CPSR_REGISTER, thread)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); bufptr += 8; @@ -761,11 +755,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - regw(id, GdbHexToLong(buffer_ptr), thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == PC_REGISTER) { - regw(id, GdbHexToLong(buffer_ptr), thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { - regw(id, GdbHexToInt(buffer_ptr), thread); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); } else { return SendReply("E01"); } @@ -782,11 +776,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - regw(reg, GdbHexToLong(buffer_ptr + i * 16), thread); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { - regw(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), thread); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { - regw(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), thread); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } @@ -846,12 +840,9 @@ static void WriteMemory() { SendReply("OK"); } -bool send_trap = false; - void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; - // SendSignal(SIGTRAP); send_trap = true; } @@ -862,10 +853,10 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; - // SendSignal(SIGTRAP); send_trap = true; } +/// Tell the CPU if we hit a memory breakpoint. bool IsMemoryBreak() { if (IsConnected()) { return false; @@ -1015,7 +1006,7 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(thread, latest_signal); + SendSignal(current_thread, latest_signal); break; case 'k': Shutdown(); @@ -1053,7 +1044,7 @@ void HandlePacket() { AddBreakpoint(); break; case 'T': - isThreadAlive(); + HandleThreadAlive(); break; default: SendReply(""); @@ -1200,10 +1191,10 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -void SendSig(void* _thread, int sig) { +void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { send_trap = false; - SendSignal((Kernel::Thread*)_thread, sig); + SendSignal(thread, trap); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 6f998fb28f..f2418c9e44 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -7,6 +7,7 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/thread.h" namespace GDBStub { @@ -92,5 +93,11 @@ bool GetCpuStepFlag(); */ void SetCpuStepFlag(bool is_step); -void SendSig(void* thread, int sig); +/** + * Send trap signal from thread back to the gdbstub server. + * + * @param thread Sending thread. + * @param trap Trap no. + */ +void SendTrap(Kernel::Thread* thread, int trap); } // namespace GDBStub From 2f61f8ff13a4ac6ad451f98c0c62c3842617472b Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 6 Jun 2018 15:05:23 +0100 Subject: [PATCH 05/71] Only send traps from GDB's current thread, otherwise we will always be thrown back to main thread when stepping. --- src/core/gdbstub/gdbstub.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 2603192fea..10755abc1e 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,6 +144,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; +static int thread_id = -1; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -562,11 +563,9 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; + thread_id = -1; if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt( - command_buffer + 2, - command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); + thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } if (thread_id >= 1) { current_thread = FindThreadById(thread_id); @@ -585,9 +584,7 @@ static void HandleSetThread() { /// Handle thread alive command from gdb client. static void HandleThreadAlive() { - int thread_id = static_cast( - HexToInt(command_buffer + 1, - command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); + int thread_id = static_cast(HexToInt(command_buffer + 1, command_length - 1)); if (thread_id == 0) { thread_id = 1; } @@ -1192,7 +1189,9 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - if (send_trap) { + //NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), thread_id, trap, + // send_trap); + if (send_trap && (thread == current_thread)) { send_trap = false; SendSignal(thread, trap); } From 5ce0d95f1c394680888f2f9e5c8cdc17a7ad8292 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 7 Jun 2018 18:20:33 +0100 Subject: [PATCH 06/71] Looking for a thread by its id should _not_ set it as a current thread! Returning proper list of threads for better integration with VS debugger. --- src/core/gdbstub/gdbstub.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 10755abc1e..27bdf2c2a7 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,7 +144,6 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; -static int thread_id = -1; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -177,8 +176,7 @@ static Kernel::Thread* FindThreadById(int id) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { - current_thread = thread.get(); - return current_thread; + return thread.get(); } } } @@ -535,7 +533,7 @@ static void HandleQuery() { SendReply("T0"); } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml - SendReply("PacketSize=2000;qXfer:features:read+"); + SendReply("PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"); } else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); @@ -555,7 +553,32 @@ static void HandleQuery() { SendReply(val.c_str()); } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } else { + } + else if(strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) + { + std::string buffer; + buffer += "l"; + buffer += ""; + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto thread : threads) + { + //buffer += fmt::format(R"*()*", + // thread->GetThreadId(), + // core, + // reinterpret_cast(thread.get()), + // thread->GetThreadId()); + buffer += fmt::format(R"*()*", + thread->GetThreadId(), + core, + thread->GetThreadId()); + } + } + buffer += ""; + SendReply(buffer.c_str()); + } + else { SendReply(""); } } @@ -563,7 +586,7 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - thread_id = -1; + int thread_id = -1; if (command_buffer[2] != '-') { thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } From 56a5d60276a4aceb60a37d6e44fca571ced6da97 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 7 Jun 2018 23:40:03 +0100 Subject: [PATCH 07/71] In step mode only signal trap from current thread, in run mode signal always. --- src/core/gdbstub/gdbstub.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 27bdf2c2a7..9c2f7935e2 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -553,32 +553,27 @@ static void HandleQuery() { SendReply(val.c_str()); } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } - else if(strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) - { + } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { std::string buffer; buffer += "l"; buffer += ""; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto thread : threads) - { - //buffer += fmt::format(R"*()*", + for (auto thread : threads) { + // buffer += fmt::format(R"*()*", // thread->GetThreadId(), // core, // reinterpret_cast(thread.get()), // thread->GetThreadId()); - buffer += fmt::format(R"*()*", - thread->GetThreadId(), - core, - thread->GetThreadId()); + buffer += + fmt::format(R"*()*", + thread->GetThreadId(), core, thread->GetThreadId()); } } buffer += ""; SendReply(buffer.c_str()); - } - else { + } else { SendReply(""); } } @@ -641,6 +636,8 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + SendReply(buffer.c_str()); } @@ -862,7 +859,7 @@ static void WriteMemory() { void Break(bool is_memory_break) { if (!halt_loop) { - halt_loop = true; + // halt_loop = true; send_trap = true; } @@ -1212,10 +1209,12 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - //NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), thread_id, trap, - // send_trap); - if (send_trap && (thread == current_thread)) { + // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {} {}", send_trap, thread->GetThreadId(), + // current_thread->GetThreadId(), halt_loop, step_loop); + if (send_trap && (!halt_loop || (thread == current_thread))) { send_trap = false; + halt_loop = true; + // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); SendSignal(thread, trap); } } From d0d834ad2d70c2178bebdc95d96d883e8cd6a5eb Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Fri, 8 Jun 2018 01:03:24 +0100 Subject: [PATCH 08/71] Extra diagnostics for multi-threaded breaks. --- src/core/gdbstub/gdbstub.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 9c2f7935e2..a9f4cc008a 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -636,7 +636,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -1209,13 +1209,15 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {} {}", send_trap, thread->GetThreadId(), - // current_thread->GetThreadId(), halt_loop, step_loop); - if (send_trap && (!halt_loop || (thread == current_thread))) { - send_trap = false; - halt_loop = true; - // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - SendSignal(thread, trap); + if (send_trap) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + current_thread->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (thread == current_thread)) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + halt_loop = true; + send_trap = false; + SendSignal(thread, trap); + } } } }; // namespace GDBStub From 1c002e1accf467bcc4a8dfe402221b67e63354b5 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Fri, 8 Jun 2018 18:35:34 +0100 Subject: [PATCH 09/71] Work towards improving handling of threads in GDBStub. --- src/core/core.cpp | 5 +++ src/core/gdbstub/gdbstub.cpp | 87 +++++++++++++++++++++++++----------- src/core/gdbstub/gdbstub.h | 7 ++- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 84ab876cc1..4e96231119 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -76,6 +76,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } + if(GDBStub::IsServerEnabled()) + { + GDBStub::FlushTraps(); + } + return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index a9f4cc008a..6ed727f109 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -143,7 +143,8 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -static Kernel::Thread* current_thread = nullptr; +static Kernel::Thread* current_thread_c = nullptr; +static Kernel::Thread* current_thread_g = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -582,6 +583,7 @@ static void HandleQuery() { static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { int thread_id = -1; + static Kernel::Thread* current_thread; if (command_buffer[2] != '-') { thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } @@ -593,6 +595,14 @@ static void HandleSetThread() { current_thread = FindThreadById(thread_id); } if (current_thread) { + if(command_buffer[1] == 'c') + { + current_thread_c = current_thread; + } + else + { + current_thread_g = current_thread; + } SendReply("OK"); return; } @@ -627,16 +637,16 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, Common::swap64(RegRead(SP_REGISTER, thread))); } else { - buffer = fmt::format("T{:02x};", latest_signal); + buffer = fmt::format("T{:02x}", latest_signal); } - buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); - NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + //NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -653,7 +663,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(current_thread, SIGTRAP); + SendSignal(current_thread_c, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -724,11 +734,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, RegRead(id, current_thread_g)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, RegRead(id, current_thread_g)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread_g)); } else { return SendReply("E01"); } @@ -744,16 +754,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread_g)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread_g)); bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread_g)); bufptr += 8; @@ -772,11 +782,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); } else if (id == PC_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); } else if (id == CPSR_REGISTER) { - RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread_g); } else { return SendReply("E01"); } @@ -793,11 +803,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); } else if (reg == PC_REGISTER) { - RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread_g); } else { UNIMPLEMENTED(); } @@ -1023,7 +1033,11 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(current_thread, latest_signal); + if(!current_thread_c) + { + current_thread_c = current_thread_g; + } + SendSignal(current_thread_c, latest_signal); break; case 'k': Shutdown(); @@ -1208,16 +1222,37 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } +struct Trap +{ + Kernel::Thread* thread; + int trap; +}; + +static std::vector traps; + void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - current_thread->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (thread == current_thread)) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - halt_loop = true; - send_trap = false; - SendSignal(thread, trap); + traps.push_back(Trap{thread, trap}); + } +} + +void FlushTraps() +{ + if(traps.size()) + { + halt_loop = true; + send_trap = false; + for(auto& trap : traps) + { + if(trap.thread == current_thread_c) + { + SendSignal(trap.thread, trap.trap); + traps.resize(0); + return; + } } + SendSignal(traps[0].thread, traps[0].trap); + traps.resize(0); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index f2418c9e44..e86bcdb4e5 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -80,10 +80,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy */ bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); -// If set to true, the CPU will halt at the beginning of the next CPU loop. +/// If set to true, the CPU will halt at the beginning of the next CPU loop. bool GetCpuHaltFlag(); -// If set to true and the CPU is halted, the CPU will step one instruction. +/// If set to true and the CPU is halted, the CPU will step one instruction. bool GetCpuStepFlag(); /** @@ -100,4 +100,7 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); + +/// Flush all pending trap signals gathered by SendTrap above. +void FlushTraps(); } // namespace GDBStub From 2adb30a13743aaa943f5e14844d2f51ccd5b20f2 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 10:24:55 +0100 Subject: [PATCH 10/71] More improvements and diagnostics for GDBStub. --- src/core/core.cpp | 5 ---- src/core/gdbstub/gdbstub.cpp | 58 ++++++++++++------------------------ src/core/gdbstub/gdbstub.h | 3 -- 3 files changed, 19 insertions(+), 47 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 4e96231119..84ab876cc1 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -76,11 +76,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } - if(GDBStub::IsServerEnabled()) - { - GDBStub::FlushTraps(); - } - return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 6ed727f109..b3830d3ea8 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -595,12 +595,9 @@ static void HandleSetThread() { current_thread = FindThreadById(thread_id); } if (current_thread) { - if(command_buffer[1] == 'c') - { + if (command_buffer[1] == 'c') { current_thread_c = current_thread; - } - else - { + } else { current_thread_g = current_thread; } SendReply("OK"); @@ -635,6 +632,11 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { latest_signal = signal; + if(!thread) + { + full = false; + } + std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, @@ -644,9 +646,12 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer = fmt::format("T{:02x}", latest_signal); } - buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); + if(thread) + { + buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); + } - //NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -1033,10 +1038,6 @@ void HandlePacket() { HandleSetThread(); break; case '?': - if(!current_thread_c) - { - current_thread_c = current_thread_g; - } SendSignal(current_thread_c, latest_signal); break; case 'k': @@ -1222,37 +1223,16 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -struct Trap -{ - Kernel::Thread* thread; - int trap; -}; - -static std::vector traps; - void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - traps.push_back(Trap{thread, trap}); - } -} - -void FlushTraps() -{ - if(traps.size()) - { - halt_loop = true; - send_trap = false; - for(auto& trap : traps) - { - if(trap.thread == current_thread_c) - { - SendSignal(trap.thread, trap.trap); - traps.resize(0); - return; - } + NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + current_thread_c->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (thread == current_thread_c)) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + halt_loop = true; + send_trap = false; + SendSignal(thread, trap); } - SendSignal(traps[0].thread, traps[0].trap); - traps.resize(0); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index e86bcdb4e5..efd5018843 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -100,7 +100,4 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); - -/// Flush all pending trap signals gathered by SendTrap above. -void FlushTraps(); } // namespace GDBStub From 806de51c6a3a6ac18ea244559c1179404cbc3089 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 10:58:18 +0100 Subject: [PATCH 11/71] More improvements and diagnostics for GDBStub. --- src/core/gdbstub/gdbstub.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index b3830d3ea8..e8ada3ffad 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -61,7 +61,7 @@ const u32 SIGTERM = 15; const u32 MSG_WAITALL = 8; #endif -const u32 X30_REGISTER = 30; +const u32 LR_REGISTER = 30; const u32 SP_REGISTER = 31; const u32 PC_REGISTER = 32; const u32 CPSR_REGISTER = 33; @@ -632,22 +632,21 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { latest_signal = signal; - if(!thread) - { + if (!thread) { full = false; } std::string buffer; if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, - Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(RegRead(SP_REGISTER, thread))); + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, + PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, + Common::swap64(RegRead(LR_REGISTER, thread))); } else { buffer = fmt::format("T{:02x}", latest_signal); } - if(thread) - { + if (thread) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } From e0ceb4ed7025c9ad812831f9faae90ce1e94bfcf Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 15:16:56 +0100 Subject: [PATCH 12/71] More improvements and diagnostics for GDBStub. --- src/core/arm/unicorn/arm_unicorn.cpp | 4 ++-- src/core/gdbstub/gdbstub.cpp | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d6..f239cf0eaa 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit) { + if (last_bkpt_hit || (num_instructions == 1)) { last_bkpt_hit = false; GDBStub::Break(); + GDBStub::SendTrap(thread, 5); } - GDBStub::SendTrap(thread, 5); } } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e8ada3ffad..e1bd0bf9c5 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -650,7 +650,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } - NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -872,10 +872,11 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - if (!halt_loop) { - // halt_loop = true; - send_trap = true; - } + // if (!halt_loop) { + // halt_loop = true; + //} + + send_trap = true; memory_break = is_memory_break; } @@ -1224,14 +1225,15 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - current_thread_c->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (thread == current_thread_c)) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - halt_loop = true; - send_trap = false; + // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + // current_thread_c->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (current_thread_c == thread)) { + // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + current_thread_c = thread; SendSignal(thread, trap); } + halt_loop = true; + send_trap = false; } } }; // namespace GDBStub From 6b376341752246a902bf722c5f2368d6824e3f02 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 15:16:56 +0100 Subject: [PATCH 13/71] More improvements and diagnostics for GDBStub. --- src/core/arm/unicorn/arm_unicorn.cpp | 4 +- src/core/gdbstub/gdbstub.cpp | 97 ++++++++++++---------------- 2 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d6..f239cf0eaa 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit) { + if (last_bkpt_hit || (num_instructions == 1)) { last_bkpt_hit = false; GDBStub::Break(); + GDBStub::SendTrap(thread, 5); } - GDBStub::SendTrap(thread, 5); } } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e8ada3ffad..a06f19fd67 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -143,8 +143,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -static Kernel::Thread* current_thread_c = nullptr; -static Kernel::Thread* current_thread_g = nullptr; +static Kernel::Thread* current_thread = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -561,12 +560,6 @@ static void HandleQuery() { for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { - // buffer += fmt::format(R"*()*", - // thread->GetThreadId(), - // core, - // reinterpret_cast(thread.get()), - // thread->GetThreadId()); buffer += fmt::format(R"*()*", thread->GetThreadId(), core, thread->GetThreadId()); @@ -581,28 +574,20 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { - if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; - static Kernel::Thread* current_thread; - if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); - } - if (thread_id >= 1) { - current_thread = FindThreadById(thread_id); - } - if (!current_thread) { - thread_id = 1; - current_thread = FindThreadById(thread_id); - } - if (current_thread) { - if (command_buffer[1] == 'c') { - current_thread_c = current_thread; - } else { - current_thread_g = current_thread; - } - SendReply("OK"); - return; - } + int thread_id = -1; + if (command_buffer[2] != '-') { + thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); + } + if (thread_id >= 1) { + current_thread = FindThreadById(thread_id); + } + if (!current_thread) { + thread_id = 1; + current_thread = FindThreadById(thread_id); + } + if (current_thread) { + SendReply("OK"); + return; } SendReply("E01"); } @@ -650,7 +635,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } - NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -667,7 +652,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(current_thread_c, SIGTRAP); + SendSignal(current_thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -738,11 +723,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread_g)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread_g)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread_g)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread)); } else { return SendReply("E01"); } @@ -758,16 +743,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread_g)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread_g)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread_g)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); bufptr += 8; @@ -786,11 +771,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == PC_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { - RegWrite(id, GdbHexToInt(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); } else { return SendReply("E01"); } @@ -807,11 +792,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { - RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread_g); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } @@ -872,10 +857,11 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - if (!halt_loop) { - // halt_loop = true; - send_trap = true; - } + // if (!halt_loop) { + // halt_loop = true; + //} + + send_trap = true; memory_break = is_memory_break; } @@ -1037,7 +1023,7 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(current_thread_c, latest_signal); + SendSignal(current_thread, latest_signal); break; case 'k': Shutdown(); @@ -1224,14 +1210,15 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - current_thread_c->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (thread == current_thread_c)) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - halt_loop = true; - send_trap = false; + // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + // current_thread->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (current_thread == thread)) { + // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + current_thread = thread; SendSignal(thread, trap); } + halt_loop = true; + send_trap = false; } } }; // namespace GDBStub From 01c168a4600316497d601d0e9e7dc39a2be737dd Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 11 Jun 2018 09:50:40 +0100 Subject: [PATCH 14/71] Tidy up. --- src/core/gdbstub/gdbstub.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index a06f19fd67..f5a266eb28 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -635,8 +635,6 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } - // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); - SendReply(buffer.c_str()); } @@ -857,10 +855,6 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - // if (!halt_loop) { - // halt_loop = true; - //} - send_trap = true; memory_break = is_memory_break; @@ -1210,10 +1204,7 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - // current_thread->GetThreadId(), halt_loop, step_loop); if (!halt_loop || (current_thread == thread)) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); current_thread = thread; SendSignal(thread, trap); } From c40e897bc029ad68bb40bb83c641b692d8dff670 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 11 Jun 2018 14:53:47 +0100 Subject: [PATCH 15/71] Reload registers from thread context after they have been changed in GDBStub. --- src/core/gdbstub/gdbstub.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index f5a266eb28..0f8ec5809d 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,6 +144,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; +static unsigned current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -172,10 +173,11 @@ static std::map breakpoints_read; static std::map breakpoints_write; static Kernel::Thread* FindThreadById(int id) { - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { + for (unsigned core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { + current_core = core; return thread.get(); } } @@ -778,6 +780,8 @@ static void WriteRegister() { return SendReply("E01"); } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -800,6 +804,8 @@ static void WriteRegisters() { } } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -862,6 +868,10 @@ void Break(bool is_memory_break) { /// Tell the CPU that it should perform a single step. static void Step() { + if (command_length > 1) { + RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + } step_loop = true; halt_loop = true; send_trap = true; From 538418e4b0a3d2b06ec2c20b2e01ba54138dd546 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sun, 24 Jun 2018 23:06:07 +0100 Subject: [PATCH 16/71] Initial support for floating point registers (wip). --- src/core/gdbstub/gdbstub.cpp | 104 ++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 0f8ec5809d..a63a1fc498 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -65,6 +65,8 @@ const u32 LR_REGISTER = 30; const u32 SP_REGISTER = 31; const u32 PC_REGISTER = 32; const u32 CPSR_REGISTER = 33; +const u32 UC_ARM64_REG_Q0 = 34; +const u32 FPSCR_REGISTER = 66; // For sample XML files see the GDB source /gdb/features // GDB also wants the l character at the start @@ -130,6 +132,41 @@ static const char* target_xml = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )"; @@ -198,6 +235,8 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { return thread->context.pc; } else if (id == CPSR_REGISTER) { return thread->context.cpsr; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + return thread->context.fpu_registers[id-UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -216,6 +255,8 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { thread->context.pc = val; } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + thread->context.fpu_registers[id-(CPSR_REGISTER+1)][0] = val; } } @@ -336,6 +377,21 @@ static void LongToGdbHex(u8* dest, u64 v) { } } +/** + * Convert a u128 into a gdb-formatted hex string. + * + * @param dest Pointer to buffer to store output hex string characters. + * @param v Value to convert. + */ +// static void LongLongToGdbHex(u8* dest, u128 v) +//{ +// for(int i = 0; i < 32; i += 2) +// { +// dest[i + 1] = NibbleToHex(static_cast(v >> (4 * i))); +// dest[i] = NibbleToHex(static_cast(v >> (4 * (i + 1)))); +// } +//} + /** * Convert a gdb-formatted hex string into a u32. * @@ -368,6 +424,24 @@ static u64 GdbHexToLong(const u8* src) { return output; } +/** + * Convert a gdb-formatted hex string into a u128. + * + * @param src Pointer to hex string. + */ +// static u128 GdbHexToLong(const u8* src) +//{ +// u128 output = 0; +// +// for(int i = 0; i < 32; i += 2) +// { +// output = (output << 4) | HexCharToValue(src[15 - i - 1]); +// output = (output << 4) | HexCharToValue(src[15 - i]); +// } +// +// return output; +//} + /// Read a byte from the gdb client. static u8 ReadByte() { u8 c; @@ -728,8 +802,13 @@ static void ReadRegister() { LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(id, current_thread)); + } else if (id == FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(998, current_thread)); } else { - return SendReply("E01"); + //return SendReply("E01"); + LongToGdbHex(reply, RegRead(997, current_thread)); } SendReply(reinterpret_cast(reply)); @@ -756,6 +835,16 @@ static void ReadRegisters() { bufptr += 8; + for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + } + + bufptr += (32 * 32); + + LongToGdbHex(bufptr, RegRead(998, current_thread)); + + bufptr += 8; + SendReply(reinterpret_cast(buffer)); } @@ -776,8 +865,13 @@ static void WriteRegister() { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + } else if (id == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - return SendReply("E01"); + //return SendReply("E01"); + RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); @@ -792,13 +886,17 @@ static void WriteRegisters() { if (command_buffer[0] != 'G') return SendReply("E01"); - for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { + for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + } else if (reg == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } From 1a18c59964ec8a5a93d288de38486cde1378e6e8 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 16:22:30 +0100 Subject: [PATCH 17/71] Add support for NSO modules. --- src/core/gdbstub/gdbstub.cpp | 51 +++++++++++++++++-- src/core/gdbstub/gdbstub.h | 3 ++ .../loader/deconstructed_rom_directory.cpp | 2 + 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 0f8ec5809d..069f5c2cf1 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -172,6 +172,22 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; +struct Module { + char name[128]; + PAddr beg; + PAddr end; +}; + +static std::vector modules; + +void RegisterModule(const char* name, PAddr beg, PAddr end) { + Module module; + strncpy(module.name, name, sizeof(module.name)); + module.beg = beg; + module.end = end; + modules.push_back(module); +} + static Kernel::Thread* FindThreadById(int id) { for (unsigned core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); @@ -535,12 +551,28 @@ static void HandleQuery() { SendReply("T0"); } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml - SendReply("PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"); + std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; + if (modules.size()) { + buffer += ";qXfer:libraries:read+"; + } + SendReply(buffer.c_str()); } else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { - std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); + std::string buffer; + // if(modules.size()) + //{ + // for(auto module : modules) + // { + // if(stricmp(module.name, "main") == 0) + // { + // buffer = fmt::format("TextSeg={:0x}", module.beg); + // } + // } + //} + // else + { buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); } SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; @@ -569,6 +601,17 @@ static void HandleQuery() { } buffer += ""; SendReply(buffer.c_str()); + } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { + std::string buffer; + buffer += "l"; + buffer += ""; + for (auto module : modules) { + buffer += + fmt::format(R"*("
)*", + module.name, module.beg); + } + buffer += ""; + SendReply(buffer.c_str()); } else { SendReply(""); } @@ -827,7 +870,7 @@ static void ReadMemory() { SendReply("E01"); } - if (!Memory::IsValidVirtualAddress(addr)) { + if (!Memory::IsValidVirtualAddress(addr) && (addr < Memory::STACK_AREA_VADDR)) { return SendReply("E00"); } @@ -1112,6 +1155,8 @@ static void Init(u16 port) { breakpoints_read.clear(); breakpoints_write.clear(); + modules.clear(); + // Start gdb server NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index efd5018843..2c17a7275b 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -51,6 +51,9 @@ bool IsServerEnabled(); /// Returns true if there is an active socket connection. bool IsConnected(); +/// Register module. +void RegisterModule(const char* name, PAddr beg, PAddr end); + /** * Signal to the gdbstub server that it should halt CPU execution. * diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index b01b2caf63..a9f232c0f9 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -133,6 +134,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + GDBStub::RegisterModule(module, load_addr, next_load_addr); } else { next_load_addr = load_addr; } From 82058c727599521718101880aeb077c2ef4fc064 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 17:35:57 +0100 Subject: [PATCH 18/71] Some cleanup. --- src/core/gdbstub/gdbstub.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 069f5c2cf1..3a33d75be0 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -561,18 +561,7 @@ static void HandleQuery() { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { std::string buffer; - // if(modules.size()) - //{ - // for(auto module : modules) - // { - // if(stricmp(module.name, "main") == 0) - // { - // buffer = fmt::format("TextSeg={:0x}", module.beg); - // } - // } - //} - // else - { buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); } + buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; From 917db5cafee98c0e55a69856f2881ac4edacb2e2 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 23:47:27 +0100 Subject: [PATCH 19/71] Fix splitpath on Windows. --- src/common/string_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 646400db0e..d57a4af958 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -134,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ size_t dir_end = full_path.find_last_of("/" // windows needs the : included for something like just "C:" to be considered a directory #ifdef _WIN32 - ":" + "\\:" #endif ); if (std::string::npos == dir_end) From e7b518e8dd56682e8f145d2a9b0874cc28000575 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 23:47:51 +0100 Subject: [PATCH 20/71] Register NRO module. --- src/core/loader/nro.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 3853cfa1a9..f9f47db019 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nro.h" @@ -115,6 +116,10 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + std::string filename; + Common::SplitPath(path, nullptr, &filename, nullptr); + GDBStub::RegisterModule((filename+".elf").c_str(), load_base, load_base); + return true; } From 1cb53177cc3f0c87f4ecc8434a9593a6ecaced3d Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 2 Jul 2018 00:15:21 +0100 Subject: [PATCH 21/71] Fix handler for libraries query. --- src/core/gdbstub/gdbstub.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 7776249c8f..9493327198 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -670,7 +670,7 @@ static void HandleQuery() { buffer += ""; for (auto module : modules) { buffer += - fmt::format(R"*("
)*", + fmt::format(R"*(")*", module.name, module.beg); } buffer += ""; From c3e39280e684d3477700d057d1d3a5143656fff5 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 3 Jul 2018 09:59:38 +0100 Subject: [PATCH 22/71] Register module with GDBStub. --- src/core/loader/deconstructed_rom_directory.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index eb7feb617e..a7de6f1c36 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -133,6 +134,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + GDBStub::RegisterModule(module, load_addr, next_load_addr); } else { next_load_addr = load_addr; } From 813fab2046c0354ea9d1afe6bc54a78ab1fbad70 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 10:25:34 +0100 Subject: [PATCH 23/71] Avoid crash in IsValidVirtualAddress() --- externals/dynarmic | 2 +- src/core/gdbstub/gdbstub.cpp | 14 +++++++++----- src/core/loader/nro.cpp | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/externals/dynarmic b/externals/dynarmic index f7d11baa1c..990a569b7a 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit f7d11baa1cba82f7926058bebdeb6b1c23cff8eb +Subproject commit 990a569b7a5f2518fe08682f5ebf8536e5388d66 diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 718ebb1e80..4d4176ff2f 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -252,7 +252,7 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { } else if (id == CPSR_REGISTER) { return thread->context.cpsr; } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - return thread->context.fpu_registers[id-UC_ARM64_REG_Q0][0]; + return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -272,7 +272,7 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - thread->context.fpu_registers[id-(CPSR_REGISTER+1)][0] = val; + thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; } } @@ -838,7 +838,7 @@ static void ReadRegister() { } else if (id == FPSCR_REGISTER) { LongToGdbHex(reply, RegRead(998, current_thread)); } else { - //return SendReply("E01"); + // return SendReply("E01"); LongToGdbHex(reply, RegRead(997, current_thread)); } @@ -901,7 +901,7 @@ static void WriteRegister() { } else if (id == FPSCR_REGISTER) { RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - //return SendReply("E01"); + // return SendReply("E01"); RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } @@ -956,7 +956,11 @@ static void ReadMemory() { SendReply("E01"); } - if (!Memory::IsValidVirtualAddress(addr) && (addr < Memory::STACK_AREA_VADDR)) { + if ((addr < Memory::PROCESS_IMAGE_VADDR) || (addr >= Memory::MAP_REGION_VADDR_END)) { + return SendReply("E00"); + } + + if (!Memory::IsValidVirtualAddress(addr)) { return SendReply("E00"); } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index e02a1bb729..6326bd4900 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -118,7 +118,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { std::string filename; Common::SplitPath(codeset->name, nullptr, &filename, nullptr); - GDBStub::RegisterModule((filename+".elf").c_str(), load_base, load_base); + GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); return true; } From bee01b8e6c49885f4a3186e5dbb8784a832973ef Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 11:02:34 +0100 Subject: [PATCH 24/71] Register all loaded modules with GDBStub --- src/core/loader/deconstructed_rom_directory.cpp | 3 +++ src/core/loader/nca.cpp | 3 +++ src/core/loader/nro.cpp | 1 + src/core/loader/nso.cpp | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index eb7feb617e..68f2f30073 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -133,6 +134,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index da064f8e39..e530f1d4b3 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -11,6 +11,7 @@ #include "core/core.h" #include "core/file_sys/program_metadata.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -259,6 +260,8 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 6326bd4900..f8172819ac 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -116,6 +116,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub std::string filename; Common::SplitPath(codeset->name, nullptr, &filename, nullptr); GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f84e4b1be..6a8fecd37e 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nso.h" @@ -147,6 +148,11 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector& codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub + std::string filename; + Common::SplitPath(codeset->name, nullptr, &filename, nullptr); + GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); + return load_base + image_size; } From 31bc72dd5b9bd65fc05ce361d6e7797c05ae3ee9 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 11:28:36 +0100 Subject: [PATCH 25/71] Compile fixes for Linux and macOS --- src/core/loader/nca.cpp | 1 + src/core/loader/nro.cpp | 1 + src/core/loader/nso.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index e530f1d4b3..baa448956d 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f8172819ac..01c2138ae1 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 6a8fecd37e..82d3c93a57 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -8,6 +8,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" From 341517a5f2d18aaf80f2b30fed6488bf627d510e Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 16:03:01 +0100 Subject: [PATCH 26/71] GDB Stub should work now. --- src/core/arm/unicorn/arm_unicorn.cpp | 50 +++-- src/core/gdbstub/gdbstub.cpp | 306 ++++++++++++++++----------- src/core/gdbstub/gdbstub.h | 9 +- 3 files changed, 213 insertions(+), 152 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d6..79def5007b 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -10,6 +10,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/kernel/svc.h" +#include "core/gdbstub/gdbstub.h" // Load Unicorn DLL once on Windows using RAII #ifdef _MSC_VER @@ -35,13 +36,15 @@ LoadDll LoadDll::g_load_dll; } \ } while (0) -static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { - GDBStub::BreakpointAddress bkpt = - GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); - if (GDBStub::IsMemoryBreak() || - (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { - auto core = static_cast(user_data); - core->RecordBreak(bkpt); +static GDBStub::BreakpointAddress bkpt = {0}; +static bool bkptHit = false; + +static void CodeHook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); + if(GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) + { + bkptHit = true; uc_emu_stop(uc); } } @@ -78,9 +81,9 @@ ARM_Unicorn::ARM_Unicorn() { uc_hook hook{}; CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); - if (GDBStub::IsServerEnabled()) { + if(GDBStub::IsServerEnabled()) + { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); - last_bkpt_hit = false; } } @@ -170,9 +173,12 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) { } void ARM_Unicorn::Run() { - if (GDBStub::IsServerEnabled()) { + if(GDBStub::IsServerEnabled()) + { ExecuteInstructions(std::max(4000000, 0)); - } else { + } + else + { ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); } } @@ -187,17 +193,20 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); - if (GDBStub::IsServerEnabled()) { - if (last_bkpt_hit) { - uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); + if(GDBStub::IsServerEnabled()) + { + if(bkptHit) + { + uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); } - Kernel::Thread* thread = Kernel::GetCurrentThread(); + Kernel::Thread *thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit) { - last_bkpt_hit = false; + if(bkptHit) + { + bkptHit = false; GDBStub::Break(); } - GDBStub::SendTrap(thread, 5); + GDBStub::SendSig(thread, 5); } } @@ -264,8 +273,3 @@ void ARM_Unicorn::PrepareReschedule() { } void ARM_Unicorn::ClearInstructionCache() {} - -void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) { - last_bkpt = bkpt; - last_bkpt_hit = true; -} diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 938852a1a2..aca7bc7a6b 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -16,6 +16,7 @@ #include #ifdef _WIN32 +#define NTDDI_VERSION NTDDI_WIN8 #include // winsock2.h needs to be included first to prevent winsock.h being included by other includes #include @@ -31,16 +32,19 @@ #endif #include "common/logging/log.h" +//#undef NGLOG_INFO +//#define NGLOG_INFO NGLOG_ERROR +//#undef NGLOG_DEBUG +//#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" -#include "common/swap.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_cpu.h" #include "core/gdbstub/gdbstub.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/scheduler.h" #include "core/loader/loader.h" #include "core/memory.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/scheduler.h" const int GDB_BUFFER_SIZE = 10000; @@ -143,7 +147,8 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -static Kernel::Thread* current_thread = nullptr; +Kernel::Thread *thread = nullptr; +int current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -151,7 +156,6 @@ static u16 gdbstub_port = 24689; static bool halt_loop = true; static bool step_loop = false; -static bool send_trap = false; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. @@ -171,49 +175,75 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; -static Kernel::Thread* FindThreadById(int id) { - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { - if (thread->GetThreadId() == id) { - current_thread = thread.get(); - return current_thread; +Kernel::Thread *FindThread(int id, int& current_core) +{ + Kernel::Thread *thread = nullptr; + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto it = list.begin(); it != list.end(); it++) + { + if((*it)->GetThreadId() == id) + { + thread = &(*(*it)); + current_core = core; + break; } } } - return nullptr; + return thread; } -static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { - if (!thread) { +static u64 regr(int id, Kernel::Thread *thread = nullptr) +{ + if(!thread) + { return 0; } - if (id < SP_REGISTER) { + if(id < SP_REGISTER) + { return thread->context.cpu_registers[id]; - } else if (id == SP_REGISTER) { + } + else if(id == SP_REGISTER) + { return thread->context.sp; - } else if (id == PC_REGISTER) { + } + else if(id == PC_REGISTER) + { return thread->context.pc; - } else if (id == CPSR_REGISTER) { + } + else if(id == CPSR_REGISTER) + { return thread->context.cpsr; - } else { + } + else + { return 0; } } -static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { - if (!thread) { +static void regw(int id, u64 val, Kernel::Thread *thread = nullptr) +{ + if(!thread) + { return; } - if (id < SP_REGISTER) { + if(id < SP_REGISTER) + { thread->context.cpu_registers[id] = val; - } else if (id == SP_REGISTER) { + } + else if(id == SP_REGISTER) + { thread->context.sp = val; - } else if (id == PC_REGISTER) { + } + else if(id == PC_REGISTER) + { thread->context.pc = val; - } else if (id == CPSR_REGISTER) { + } + else if(id == CPSR_REGISTER) + { thread->context.cpsr = val; } } @@ -232,7 +262,7 @@ static u8 HexCharToValue(u8 hex) { return hex - 'A' + 0xA; } - LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); + NGLOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); return 0; } @@ -372,7 +402,7 @@ static u8 ReadByte() { u8 c; size_t received_size = recv(gdbserver_socket, reinterpret_cast(&c), 1, MSG_WAITALL); if (received_size != 1) { - LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); + NGLOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); Shutdown(); } @@ -413,8 +443,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { auto bp = p.find(static_cast(addr)); if (bp != p.end()) { - LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", - bp->second.len, bp->second.addr, static_cast(type)); + NGLOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", + bp->second.len, bp->second.addr, static_cast(type)); p.erase(static_cast(addr)); } } @@ -459,10 +489,10 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { } if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { - LOG_DEBUG(Debug_GDBStub, - "Found breakpoint type {} @ {:016X}, range: {:016X}" - " - {:016X} ({:X} bytes)", - static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); + NGLOG_DEBUG(Debug_GDBStub, + "Found breakpoint type {} @ {:016X}, range: {:016X}" + " - {:016X} ({:X} bytes)", + static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); return true; } } @@ -478,7 +508,7 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { static void SendPacket(const char packet) { size_t sent_size = send(gdbserver_socket, &packet, 1, 0); if (sent_size != 1) { - LOG_ERROR(Debug_GDBStub, "send failed"); + NGLOG_ERROR(Debug_GDBStub, "send failed"); } } @@ -492,13 +522,13 @@ static void SendReply(const char* reply) { return; } - LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); + NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); memset(command_buffer, 0, sizeof(command_buffer)); command_length = static_cast(strlen(reply)); if (command_length + 4 > sizeof(command_buffer)) { - LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); + NGLOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); return; } @@ -515,7 +545,7 @@ static void SendReply(const char* reply) { while (left > 0) { int sent_size = send(gdbserver_socket, reinterpret_cast(ptr), left, 0); if (sent_size < 0) { - LOG_ERROR(Debug_GDBStub, "gdb: send failed"); + NGLOG_ERROR(Debug_GDBStub, "gdb: send failed"); return Shutdown(); } @@ -525,57 +555,80 @@ static void SendReply(const char* reply) { } /// Handle query command from gdb client. -static void HandleQuery() { - LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); +static void HandleQuery() +{ + NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); const char* query = reinterpret_cast(command_buffer + 1); - if (strcmp(query, "TStatus") == 0) { + if(strcmp(query, "TStatus") == 0) + { SendReply("T0"); - } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { + } + else if(strncmp(query, "Supported", strlen("Supported")) == 0) + { // PacketSize needs to be large enough for target xml SendReply("PacketSize=2000;qXfer:features:read+"); - } else if (strncmp(query, "Xfer:features:read:target.xml:", - strlen("Xfer:features:read:target.xml:")) == 0) { + } + else if(strncmp(query, "Xfer:features:read:target.xml:", + strlen("Xfer:features:read:target.xml:")) == 0) + { SendReply(target_xml); - } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { + } + else if(strncmp(query, "Offsets", strlen("Offsets")) == 0) + { std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); - } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { + } + else if(strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) + { std::string val = "m"; - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { - val += fmt::format("{:x}", thread->GetThreadId()); + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto it = list.begin(); it != list.end(); it++) + { + char tmp[17] = {0}; + memset(tmp, 0, sizeof(tmp)); + sprintf(tmp, "%x", (*it)->GetThreadId()); + val += (char*)tmp; val += ","; } } val.pop_back(); SendReply(val.c_str()); - } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { + } + else if(strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) + { SendReply("l"); - } else { + } + else + { SendReply(""); } } /// Handle set thread command from gdb client. -static void HandleSetThread() { - if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; - if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt( - command_buffer + 2, - command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); +static void HandleSetThread() +{ + if(memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) + { + int threadid = -1; + if(command_buffer[2] != '-') + { + threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); } - if (thread_id >= 1) { - current_thread = FindThreadById(thread_id); + if(threadid >= 1) + { + thread = FindThread(threadid, current_core); } - if (!current_thread) { - thread_id = 1; - current_thread = FindThreadById(thread_id); + if(!thread) + { + threadid = 1; + thread = FindThread(threadid, current_core); } - if (current_thread) { + if(thread) + { SendReply("OK"); return; } @@ -583,15 +636,15 @@ static void HandleSetThread() { SendReply("E01"); } -/// Handle thread alive command from gdb client. -static void HandleThreadAlive() { - int thread_id = static_cast( - HexToInt(command_buffer + 1, - command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); - if (thread_id == 0) { - thread_id = 1; +static void isThreadAlive() +{ + int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); + if(threadid == 0) + { + threadid = 1; } - if (FindThreadById(thread_id)) { + if(FindThread(threadid, current_core)) + { SendReply("OK"); return; } @@ -603,24 +656,29 @@ static void HandleThreadAlive() { * * @param signal Signal to be sent to client. */ -static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { - if (gdbserver_socket == -1) { +static void SendSignal(Kernel::Thread *thread, u32 signal, bool full = true) +{ + if(gdbserver_socket == -1) + { return; } latest_signal = signal; std::string buffer; - if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(RegRead(SP_REGISTER, thread))); - } else { + if(full) + { + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, htonll(regr(PC_REGISTER, thread)), SP_REGISTER, htonll(regr(SP_REGISTER, thread))); + } + else + { buffer = fmt::format("T{:02x};", latest_signal); } buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + //NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); + SendReply(buffer.c_str()); } @@ -634,18 +692,18 @@ static void ReadCommand() { // ignore ack return; } else if (c == 0x03) { - LOG_INFO(Debug_GDBStub, "gdb: found break command"); + NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(current_thread, SIGTRAP); + SendSignal(thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { - LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); + NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); return; } while ((c = ReadByte()) != GDB_STUB_END) { if (command_length >= sizeof(command_buffer)) { - LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); + NGLOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); SendPacket(GDB_STUB_NACK); return; } @@ -658,9 +716,10 @@ static void ReadCommand() { u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); if (checksum_received != checksum_calculated) { - LOG_ERROR(Debug_GDBStub, - "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", - checksum_calculated, checksum_received, command_buffer, command_length); + NGLOG_ERROR( + Debug_GDBStub, + "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", + checksum_calculated, checksum_received, command_buffer, command_length); command_length = 0; @@ -687,7 +746,7 @@ static bool IsDataAvailable() { t.tv_usec = 0; if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { - LOG_ERROR(Debug_GDBStub, "select failed"); + NGLOG_ERROR(Debug_GDBStub, "select failed"); return false; } @@ -706,11 +765,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, regr(id, thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, regr(id, thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + IntToGdbHex(reply, (u32)regr(id, thread)); } else { return SendReply("E01"); } @@ -726,16 +785,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + LongToGdbHex(bufptr + reg * 16, regr(reg, thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); + LongToGdbHex(bufptr, regr(PC_REGISTER, thread)); bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); + IntToGdbHex(bufptr, (u32)regr(CPSR_REGISTER, thread)); bufptr += 8; @@ -754,11 +813,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + regw(id, GdbHexToLong(buffer_ptr), thread); } else if (id == PC_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + regw(id, GdbHexToLong(buffer_ptr), thread); } else if (id == CPSR_REGISTER) { - RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + regw(id, GdbHexToInt(buffer_ptr), thread); } else { return SendReply("E01"); } @@ -775,11 +834,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + regw(reg, GdbHexToLong(buffer_ptr + i * 16), thread); } else if (reg == PC_REGISTER) { - RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); + regw(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), thread); } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + regw(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), thread); } else { UNIMPLEMENTED(); } @@ -800,7 +859,7 @@ static void ReadMemory() { u64 len = HexToLong(start_offset, static_cast((command_buffer + command_length) - start_offset)); - LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); + NGLOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); if (len * 2 > sizeof(reply)) { SendReply("E01"); @@ -839,9 +898,12 @@ static void WriteMemory() { SendReply("OK"); } +bool send_trap = false; + void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; + //SendSignal(SIGTRAP); send_trap = true; } @@ -852,10 +914,10 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; + //SendSignal(SIGTRAP); send_trap = true; } -/// Tell the CPU if we hit a memory breakpoint. bool IsMemoryBreak() { if (IsConnected()) { return false; @@ -887,8 +949,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { breakpoint.len = len; p.insert({addr, breakpoint}); - LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", - static_cast(type), breakpoint.len, breakpoint.addr); + NGLOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", + static_cast(type), breakpoint.len, breakpoint.addr); return true; } @@ -995,7 +1057,7 @@ void HandlePacket() { return; } - LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); + NGLOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); switch (command_buffer[0]) { case 'q': @@ -1005,11 +1067,11 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(current_thread, latest_signal); + SendSignal(thread, latest_signal); break; case 'k': Shutdown(); - LOG_INFO(Debug_GDBStub, "killed by gdb"); + NGLOG_INFO(Debug_GDBStub, "killed by gdb"); return; case 'g': ReadRegisters(); @@ -1043,7 +1105,7 @@ void HandlePacket() { AddBreakpoint(); break; case 'T': - HandleThreadAlive(); + isThreadAlive(); break; default: SendReply(""); @@ -1091,7 +1153,7 @@ static void Init(u16 port) { breakpoints_write.clear(); // Start gdb server - LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); + NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); sockaddr_in saddr_server = {}; saddr_server.sin_family = AF_INET; @@ -1104,28 +1166,28 @@ static void Init(u16 port) { int tmpsock = static_cast(socket(PF_INET, SOCK_STREAM, 0)); if (tmpsock == -1) { - LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); + NGLOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); } // Set socket to SO_REUSEADDR so it can always bind on the same port int reuse_enabled = 1; if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, sizeof(reuse_enabled)) < 0) { - LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); + NGLOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); } const sockaddr* server_addr = reinterpret_cast(&saddr_server); socklen_t server_addrlen = sizeof(saddr_server); if (bind(tmpsock, server_addr, server_addrlen) < 0) { - LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); + NGLOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); } if (listen(tmpsock, 1) < 0) { - LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); + NGLOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); } // Wait for gdb to connect - LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); + NGLOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); sockaddr_in saddr_client; sockaddr* client_addr = reinterpret_cast(&saddr_client); socklen_t client_addrlen = sizeof(saddr_client); @@ -1136,9 +1198,9 @@ static void Init(u16 port) { halt_loop = false; step_loop = false; - LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); + NGLOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); } else { - LOG_INFO(Debug_GDBStub, "Client connected."); + NGLOG_INFO(Debug_GDBStub, "Client connected."); saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); } @@ -1157,7 +1219,7 @@ void Shutdown() { return; } - LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); + NGLOG_INFO(Debug_GDBStub, "Stopping GDB ..."); if (gdbserver_socket != -1) { shutdown(gdbserver_socket, SHUT_RDWR); gdbserver_socket = -1; @@ -1167,7 +1229,7 @@ void Shutdown() { WSACleanup(); #endif - LOG_INFO(Debug_GDBStub, "GDB stopped."); + NGLOG_INFO(Debug_GDBStub, "GDB stopped."); } bool IsServerEnabled() { @@ -1190,10 +1252,12 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -void SendTrap(Kernel::Thread* thread, int trap) { - if (send_trap) { +void SendSig(void *_thread, int sig) +{ + if(send_trap) + { send_trap = false; - SendSignal(thread, trap); + SendSignal((Kernel::Thread *)_thread, sig); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index f2418c9e44..357510e33e 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -7,7 +7,6 @@ #pragma once #include "common/common_types.h" -#include "core/hle/kernel/thread.h" namespace GDBStub { @@ -93,11 +92,5 @@ bool GetCpuStepFlag(); */ void SetCpuStepFlag(bool is_step); -/** - * Send trap signal from thread back to the gdbstub server. - * - * @param thread Sending thread. - * @param trap Trap no. - */ -void SendTrap(Kernel::Thread* thread, int trap); +void SendSig(void *thread, int sig); } // namespace GDBStub From 7212fd5227b88c13ae383cea43a2f16558c2d2f3 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 16:46:08 +0100 Subject: [PATCH 27/71] Applied clang-format. --- src/core/arm/unicorn/arm_unicorn.cpp | 30 ++--- src/core/gdbstub/gdbstub.cpp | 168 +++++++++------------------ src/core/gdbstub/gdbstub.h | 2 +- 3 files changed, 69 insertions(+), 131 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 79def5007b..8e122c3d73 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -9,8 +9,8 @@ #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hle/kernel/svc.h" #include "core/gdbstub/gdbstub.h" +#include "core/hle/kernel/svc.h" // Load Unicorn DLL once on Windows using RAII #ifdef _MSC_VER @@ -39,11 +39,10 @@ LoadDll LoadDll::g_load_dll; static GDBStub::BreakpointAddress bkpt = {0}; static bool bkptHit = false; -static void CodeHook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) -{ +static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); - if(GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) - { + if (GDBStub::IsMemoryBreak() || + (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { bkptHit = true; uc_emu_stop(uc); } @@ -81,8 +80,7 @@ ARM_Unicorn::ARM_Unicorn() { uc_hook hook{}; CHECKED(uc_hook_add(uc, &hook, UC_HOOK_INTR, (void*)InterruptHook, this, 0, -1)); CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); - if(GDBStub::IsServerEnabled()) - { + if (GDBStub::IsServerEnabled()) { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); } } @@ -173,12 +171,9 @@ void ARM_Unicorn::SetTlsAddress(VAddr base) { } void ARM_Unicorn::Run() { - if(GDBStub::IsServerEnabled()) - { + if (GDBStub::IsServerEnabled()) { ExecuteInstructions(std::max(4000000, 0)); - } - else - { + } else { ExecuteInstructions(std::max(CoreTiming::GetDowncount(), 0)); } } @@ -193,16 +188,13 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); - if(GDBStub::IsServerEnabled()) - { - if(bkptHit) - { + if (GDBStub::IsServerEnabled()) { + if (bkptHit) { uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); } - Kernel::Thread *thread = Kernel::GetCurrentThread(); + Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if(bkptHit) - { + if (bkptHit) { bkptHit = false; GDBStub::Break(); } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index aca7bc7a6b..e23152876c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -41,10 +41,10 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/gdbstub/gdbstub.h" -#include "core/loader/loader.h" -#include "core/memory.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/scheduler.h" +#include "core/loader/loader.h" +#include "core/memory.h" const int GDB_BUFFER_SIZE = 10000; @@ -147,7 +147,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -Kernel::Thread *thread = nullptr; +Kernel::Thread* thread = nullptr; int current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, @@ -175,75 +175,51 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; -Kernel::Thread *FindThread(int id, int& current_core) -{ - Kernel::Thread *thread = nullptr; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { +Kernel::Thread* FindThread(int id, int& current_core) { + Kernel::Thread* thread = nullptr; + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto it = list.begin(); it != list.end(); it++) - { - if((*it)->GetThreadId() == id) - { - thread = &(*(*it)); - current_core = core; - break; + for (auto it = list.begin(); it != list.end(); it++) { + if ((*it)->GetThreadId() == id) { + thread = &(*(*it)); + current_core = core; + break; } } } return thread; } -static u64 regr(int id, Kernel::Thread *thread = nullptr) -{ - if(!thread) - { +static u64 regr(int id, Kernel::Thread* thread = nullptr) { + if (!thread) { return 0; } - if(id < SP_REGISTER) - { + if (id < SP_REGISTER) { return thread->context.cpu_registers[id]; - } - else if(id == SP_REGISTER) - { + } else if (id == SP_REGISTER) { return thread->context.sp; - } - else if(id == PC_REGISTER) - { + } else if (id == PC_REGISTER) { return thread->context.pc; - } - else if(id == CPSR_REGISTER) - { + } else if (id == CPSR_REGISTER) { return thread->context.cpsr; - } - else - { + } else { return 0; } } -static void regw(int id, u64 val, Kernel::Thread *thread = nullptr) -{ - if(!thread) - { +static void regw(int id, u64 val, Kernel::Thread* thread = nullptr) { + if (!thread) { return; } - if(id < SP_REGISTER) - { + if (id < SP_REGISTER) { thread->context.cpu_registers[id] = val; - } - else if(id == SP_REGISTER) - { + } else if (id == SP_REGISTER) { thread->context.sp = val; - } - else if(id == PC_REGISTER) - { + } else if (id == PC_REGISTER) { thread->context.pc = val; - } - else if(id == CPSR_REGISTER) - { + } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; } } @@ -555,39 +531,27 @@ static void SendReply(const char* reply) { } /// Handle query command from gdb client. -static void HandleQuery() -{ +static void HandleQuery() { NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); const char* query = reinterpret_cast(command_buffer + 1); - if(strcmp(query, "TStatus") == 0) - { + if (strcmp(query, "TStatus") == 0) { SendReply("T0"); - } - else if(strncmp(query, "Supported", strlen("Supported")) == 0) - { + } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml SendReply("PacketSize=2000;qXfer:features:read+"); - } - else if(strncmp(query, "Xfer:features:read:target.xml:", - strlen("Xfer:features:read:target.xml:")) == 0) - { + } else if (strncmp(query, "Xfer:features:read:target.xml:", + strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); - } - else if(strncmp(query, "Offsets", strlen("Offsets")) == 0) - { + } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); - } - else if(strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) - { + } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto it = list.begin(); it != list.end(); it++) - { + for (auto it = list.begin(); it != list.end(); it++) { char tmp[17] = {0}; memset(tmp, 0, sizeof(tmp)); sprintf(tmp, "%x", (*it)->GetThreadId()); @@ -597,38 +561,28 @@ static void HandleQuery() } val.pop_back(); SendReply(val.c_str()); - } - else if(strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) - { + } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } - else - { + } else { SendReply(""); } } /// Handle set thread command from gdb client. -static void HandleSetThread() -{ - if(memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) - { +static void HandleSetThread() { + if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { int threadid = -1; - if(command_buffer[2] != '-') - { + if (command_buffer[2] != '-') { threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); } - if(threadid >= 1) - { + if (threadid >= 1) { thread = FindThread(threadid, current_core); } - if(!thread) - { + if (!thread) { threadid = 1; thread = FindThread(threadid, current_core); } - if(thread) - { + if (thread) { SendReply("OK"); return; } @@ -636,15 +590,12 @@ static void HandleSetThread() SendReply("E01"); } -static void isThreadAlive() -{ +static void isThreadAlive() { int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); - if(threadid == 0) - { + if (threadid == 0) { threadid = 1; } - if(FindThread(threadid, current_core)) - { + if (FindThread(threadid, current_core)) { SendReply("OK"); return; } @@ -656,28 +607,25 @@ static void isThreadAlive() * * @param signal Signal to be sent to client. */ -static void SendSignal(Kernel::Thread *thread, u32 signal, bool full = true) -{ - if(gdbserver_socket == -1) - { +static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { + if (gdbserver_socket == -1) { return; } latest_signal = signal; std::string buffer; - if(full) - { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, htonll(regr(PC_REGISTER, thread)), SP_REGISTER, htonll(regr(SP_REGISTER, thread))); - } - else - { + if (full) { + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, + htonll(regr(PC_REGISTER, thread)), SP_REGISTER, + htonll(regr(SP_REGISTER, thread))); + } else { buffer = fmt::format("T{:02x};", latest_signal); } buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - //NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); + // NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -903,7 +851,7 @@ bool send_trap = false; void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; - //SendSignal(SIGTRAP); + // SendSignal(SIGTRAP); send_trap = true; } @@ -914,7 +862,7 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; - //SendSignal(SIGTRAP); + // SendSignal(SIGTRAP); send_trap = true; } @@ -1252,12 +1200,10 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -void SendSig(void *_thread, int sig) -{ - if(send_trap) - { +void SendSig(void* _thread, int sig) { + if (send_trap) { send_trap = false; - SendSignal((Kernel::Thread *)_thread, sig); + SendSignal((Kernel::Thread*)_thread, sig); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 357510e33e..6f998fb28f 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -92,5 +92,5 @@ bool GetCpuStepFlag(); */ void SetCpuStepFlag(bool is_step); -void SendSig(void *thread, int sig); +void SendSig(void* thread, int sig); } // namespace GDBStub From fdf73c177b94c60dbb77df43f2012d90d4414f78 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 4 Jun 2018 17:05:07 +0100 Subject: [PATCH 28/71] Replaced htonll with swap64. --- src/core/gdbstub/gdbstub.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e23152876c..97c0d8ca6c 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -16,7 +16,6 @@ #include #ifdef _WIN32 -#define NTDDI_VERSION NTDDI_WIN8 #include // winsock2.h needs to be included first to prevent winsock.h being included by other includes #include @@ -37,6 +36,7 @@ //#undef NGLOG_DEBUG //#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" +#include "common/swap.h" #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/core_cpu.h" @@ -617,8 +617,8 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - htonll(regr(PC_REGISTER, thread)), SP_REGISTER, - htonll(regr(SP_REGISTER, thread))); + Common::swap64(regr(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(regr(SP_REGISTER, thread))); } else { buffer = fmt::format("T{:02x};", latest_signal); } From f8f0913e2eb68d34ce1c7524cbf60a1128bb82b6 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 5 Jun 2018 12:56:02 +0100 Subject: [PATCH 29/71] Tidy up. --- src/core/arm/unicorn/arm_unicorn.cpp | 26 +++--- src/core/gdbstub/gdbstub.cpp | 113 ++++++++++++--------------- src/core/gdbstub/gdbstub.h | 9 ++- 3 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 8e122c3d73..ce6c5616d6 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -9,7 +9,6 @@ #include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/svc.h" // Load Unicorn DLL once on Windows using RAII @@ -36,14 +35,13 @@ LoadDll LoadDll::g_load_dll; } \ } while (0) -static GDBStub::BreakpointAddress bkpt = {0}; -static bool bkptHit = false; - static void CodeHook(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) { - bkpt = GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); + GDBStub::BreakpointAddress bkpt = + GDBStub::GetNextBreakpointFromAddress(address, GDBStub::BreakpointType::Execute); if (GDBStub::IsMemoryBreak() || (bkpt.type != GDBStub::BreakpointType::None && address == bkpt.address)) { - bkptHit = true; + auto core = static_cast(user_data); + core->RecordBreak(bkpt); uc_emu_stop(uc); } } @@ -82,6 +80,7 @@ ARM_Unicorn::ARM_Unicorn() { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_MEM_INVALID, (void*)UnmappedMemoryHook, this, 0, -1)); if (GDBStub::IsServerEnabled()) { CHECKED(uc_hook_add(uc, &hook, UC_HOOK_CODE, (void*)CodeHook, this, 0, -1)); + last_bkpt_hit = false; } } @@ -189,16 +188,16 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { - if (bkptHit) { - uc_reg_write(uc, UC_ARM64_REG_PC, &bkpt.address); + if (last_bkpt_hit) { + uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (bkptHit) { - bkptHit = false; + if (last_bkpt_hit) { + last_bkpt_hit = false; GDBStub::Break(); } - GDBStub::SendSig(thread, 5); + GDBStub::SendTrap(thread, 5); } } @@ -265,3 +264,8 @@ void ARM_Unicorn::PrepareReschedule() { } void ARM_Unicorn::ClearInstructionCache() {} + +void ARM_Unicorn::RecordBreak(GDBStub::BreakpointAddress bkpt) { + last_bkpt = bkpt; + last_bkpt_hit = true; +} diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 97c0d8ca6c..2603192fea 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -31,10 +31,6 @@ #endif #include "common/logging/log.h" -//#undef NGLOG_INFO -//#define NGLOG_INFO NGLOG_ERROR -//#undef NGLOG_DEBUG -//#define NGLOG_DEBUG NGLOG_ERROR #include "common/string_util.h" #include "common/swap.h" #include "core/arm/arm_interface.h" @@ -147,8 +143,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -Kernel::Thread* thread = nullptr; -int current_core = 0; +static Kernel::Thread* current_thread = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -156,6 +151,7 @@ static u16 gdbstub_port = 24689; static bool halt_loop = true; static bool step_loop = false; +static bool send_trap = false; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. @@ -175,22 +171,20 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; -Kernel::Thread* FindThread(int id, int& current_core) { - Kernel::Thread* thread = nullptr; +static Kernel::Thread* FindThreadById(int id) { for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto it = list.begin(); it != list.end(); it++) { - if ((*it)->GetThreadId() == id) { - thread = &(*(*it)); - current_core = core; - break; + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (auto thread : threads) { + if (thread->GetThreadId() == id) { + current_thread = thread.get(); + return current_thread; } } } - return thread; + return nullptr; } -static u64 regr(int id, Kernel::Thread* thread = nullptr) { +static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { if (!thread) { return 0; } @@ -208,7 +202,7 @@ static u64 regr(int id, Kernel::Thread* thread = nullptr) { } } -static void regw(int id, u64 val, Kernel::Thread* thread = nullptr) { +static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { if (!thread) { return; } @@ -550,12 +544,9 @@ static void HandleQuery() { } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto list = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto it = list.begin(); it != list.end(); it++) { - char tmp[17] = {0}; - memset(tmp, 0, sizeof(tmp)); - sprintf(tmp, "%x", (*it)->GetThreadId()); - val += (char*)tmp; + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (auto thread : threads) { + val += fmt::format("{:x}", thread->GetThreadId()); val += ","; } } @@ -571,18 +562,20 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int threadid = -1; + int thread_id = -1; if (command_buffer[2] != '-') { - threadid = (int)HexToInt(command_buffer + 2, strlen((char*)command_buffer + 2)); + thread_id = static_cast(HexToInt( + command_buffer + 2, + command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); } - if (threadid >= 1) { - thread = FindThread(threadid, current_core); + if (thread_id >= 1) { + current_thread = FindThreadById(thread_id); } - if (!thread) { - threadid = 1; - thread = FindThread(threadid, current_core); + if (!current_thread) { + thread_id = 1; + current_thread = FindThreadById(thread_id); } - if (thread) { + if (current_thread) { SendReply("OK"); return; } @@ -590,12 +583,15 @@ static void HandleSetThread() { SendReply("E01"); } -static void isThreadAlive() { - int threadid = (int)HexToInt(command_buffer + 1, strlen((char*)command_buffer + 1)); - if (threadid == 0) { - threadid = 1; +/// Handle thread alive command from gdb client. +static void HandleThreadAlive() { + int thread_id = static_cast( + HexToInt(command_buffer + 1, + command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); + if (thread_id == 0) { + thread_id = 1; } - if (FindThread(threadid, current_core)) { + if (FindThreadById(thread_id)) { SendReply("OK"); return; } @@ -617,16 +613,14 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - Common::swap64(regr(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(regr(SP_REGISTER, thread))); + Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(RegRead(SP_REGISTER, thread))); } else { buffer = fmt::format("T{:02x};", latest_signal); } buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - // NGLOG_ERROR(Debug_GDBStub, "Sig: {}", buffer.c_str()); - SendReply(buffer.c_str()); } @@ -642,7 +636,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(thread, SIGTRAP); + SendSignal(current_thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -713,11 +707,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, regr(id, thread)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, regr(id, thread)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)regr(id, thread)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread)); } else { return SendReply("E01"); } @@ -733,16 +727,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, regr(reg, thread)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, regr(PC_REGISTER, thread)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); bufptr += 16; - IntToGdbHex(bufptr, (u32)regr(CPSR_REGISTER, thread)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); bufptr += 8; @@ -761,11 +755,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - regw(id, GdbHexToLong(buffer_ptr), thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == PC_REGISTER) { - regw(id, GdbHexToLong(buffer_ptr), thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { - regw(id, GdbHexToInt(buffer_ptr), thread); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); } else { return SendReply("E01"); } @@ -782,11 +776,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - regw(reg, GdbHexToLong(buffer_ptr + i * 16), thread); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { - regw(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), thread); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { - regw(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), thread); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } @@ -846,12 +840,9 @@ static void WriteMemory() { SendReply("OK"); } -bool send_trap = false; - void Break(bool is_memory_break) { if (!halt_loop) { halt_loop = true; - // SendSignal(SIGTRAP); send_trap = true; } @@ -862,10 +853,10 @@ void Break(bool is_memory_break) { static void Step() { step_loop = true; halt_loop = true; - // SendSignal(SIGTRAP); send_trap = true; } +/// Tell the CPU if we hit a memory breakpoint. bool IsMemoryBreak() { if (IsConnected()) { return false; @@ -1015,7 +1006,7 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(thread, latest_signal); + SendSignal(current_thread, latest_signal); break; case 'k': Shutdown(); @@ -1053,7 +1044,7 @@ void HandlePacket() { AddBreakpoint(); break; case 'T': - isThreadAlive(); + HandleThreadAlive(); break; default: SendReply(""); @@ -1200,10 +1191,10 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -void SendSig(void* _thread, int sig) { +void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { send_trap = false; - SendSignal((Kernel::Thread*)_thread, sig); + SendSignal(thread, trap); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 6f998fb28f..f2418c9e44 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -7,6 +7,7 @@ #pragma once #include "common/common_types.h" +#include "core/hle/kernel/thread.h" namespace GDBStub { @@ -92,5 +93,11 @@ bool GetCpuStepFlag(); */ void SetCpuStepFlag(bool is_step); -void SendSig(void* thread, int sig); +/** + * Send trap signal from thread back to the gdbstub server. + * + * @param thread Sending thread. + * @param trap Trap no. + */ +void SendTrap(Kernel::Thread* thread, int trap); } // namespace GDBStub From 008a2d35d88b17eebe8bb5d96e915723b3e039f4 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 6 Jun 2018 15:05:23 +0100 Subject: [PATCH 30/71] Only send traps from GDB's current thread, otherwise we will always be thrown back to main thread when stepping. --- src/core/gdbstub/gdbstub.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 2603192fea..10755abc1e 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,6 +144,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; +static int thread_id = -1; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -562,11 +563,9 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; + thread_id = -1; if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt( - command_buffer + 2, - command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); + thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } if (thread_id >= 1) { current_thread = FindThreadById(thread_id); @@ -585,9 +584,7 @@ static void HandleSetThread() { /// Handle thread alive command from gdb client. static void HandleThreadAlive() { - int thread_id = static_cast( - HexToInt(command_buffer + 1, - command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); + int thread_id = static_cast(HexToInt(command_buffer + 1, command_length - 1)); if (thread_id == 0) { thread_id = 1; } @@ -1192,7 +1189,9 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - if (send_trap) { + //NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), thread_id, trap, + // send_trap); + if (send_trap && (thread == current_thread)) { send_trap = false; SendSignal(thread, trap); } From b5e29babc56ffc4608b087f5f515f05201a24e91 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 7 Jun 2018 18:20:33 +0100 Subject: [PATCH 31/71] Looking for a thread by its id should _not_ set it as a current thread! Returning proper list of threads for better integration with VS debugger. --- src/core/gdbstub/gdbstub.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 10755abc1e..27bdf2c2a7 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,7 +144,6 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; -static int thread_id = -1; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -177,8 +176,7 @@ static Kernel::Thread* FindThreadById(int id) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { - current_thread = thread.get(); - return current_thread; + return thread.get(); } } } @@ -535,7 +533,7 @@ static void HandleQuery() { SendReply("T0"); } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml - SendReply("PacketSize=2000;qXfer:features:read+"); + SendReply("PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"); } else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); @@ -555,7 +553,32 @@ static void HandleQuery() { SendReply(val.c_str()); } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } else { + } + else if(strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) + { + std::string buffer; + buffer += "l"; + buffer += ""; + for(int core = 0; core < Core::NUM_CPU_CORES; core++) + { + auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for(auto thread : threads) + { + //buffer += fmt::format(R"*()*", + // thread->GetThreadId(), + // core, + // reinterpret_cast(thread.get()), + // thread->GetThreadId()); + buffer += fmt::format(R"*()*", + thread->GetThreadId(), + core, + thread->GetThreadId()); + } + } + buffer += ""; + SendReply(buffer.c_str()); + } + else { SendReply(""); } } @@ -563,7 +586,7 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - thread_id = -1; + int thread_id = -1; if (command_buffer[2] != '-') { thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } From 7f342ce73654e16387d08502c9c86e7b0c746b3b Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 7 Jun 2018 23:40:03 +0100 Subject: [PATCH 32/71] In step mode only signal trap from current thread, in run mode signal always. --- src/core/gdbstub/gdbstub.cpp | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 27bdf2c2a7..9c2f7935e2 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -553,32 +553,27 @@ static void HandleQuery() { SendReply(val.c_str()); } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); - } - else if(strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) - { + } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { std::string buffer; buffer += "l"; buffer += ""; - for(int core = 0; core < Core::NUM_CPU_CORES; core++) - { + for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for(auto thread : threads) - { - //buffer += fmt::format(R"*()*", + for (auto thread : threads) { + // buffer += fmt::format(R"*()*", // thread->GetThreadId(), // core, // reinterpret_cast(thread.get()), // thread->GetThreadId()); - buffer += fmt::format(R"*()*", - thread->GetThreadId(), - core, - thread->GetThreadId()); + buffer += + fmt::format(R"*()*", + thread->GetThreadId(), core, thread->GetThreadId()); } } buffer += ""; SendReply(buffer.c_str()); - } - else { + } else { SendReply(""); } } @@ -641,6 +636,8 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + SendReply(buffer.c_str()); } @@ -862,7 +859,7 @@ static void WriteMemory() { void Break(bool is_memory_break) { if (!halt_loop) { - halt_loop = true; + // halt_loop = true; send_trap = true; } @@ -1212,10 +1209,12 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - //NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), thread_id, trap, - // send_trap); - if (send_trap && (thread == current_thread)) { + // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {} {}", send_trap, thread->GetThreadId(), + // current_thread->GetThreadId(), halt_loop, step_loop); + if (send_trap && (!halt_loop || (thread == current_thread))) { send_trap = false; + halt_loop = true; + // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); SendSignal(thread, trap); } } From b412594127a3edc1d58e3a98db814b99e9f59cfc Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Fri, 8 Jun 2018 01:03:24 +0100 Subject: [PATCH 33/71] Extra diagnostics for multi-threaded breaks. --- src/core/gdbstub/gdbstub.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 9c2f7935e2..a9f4cc008a 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -636,7 +636,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format("thread:{:x};", thread->GetThreadId()); - // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -1209,13 +1209,15 @@ void SetCpuStepFlag(bool is_step) { } void SendTrap(Kernel::Thread* thread, int trap) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {} {}", send_trap, thread->GetThreadId(), - // current_thread->GetThreadId(), halt_loop, step_loop); - if (send_trap && (!halt_loop || (thread == current_thread))) { - send_trap = false; - halt_loop = true; - // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - SendSignal(thread, trap); + if (send_trap) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + current_thread->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (thread == current_thread)) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + halt_loop = true; + send_trap = false; + SendSignal(thread, trap); + } } } }; // namespace GDBStub From 6bd605cb618cecdc992fca1a48ac74284bca9f28 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Fri, 8 Jun 2018 18:35:34 +0100 Subject: [PATCH 34/71] Work towards improving handling of threads in GDBStub. --- src/core/core.cpp | 5 +++ src/core/gdbstub/gdbstub.cpp | 87 +++++++++++++++++++++++++----------- src/core/gdbstub/gdbstub.h | 7 ++- 3 files changed, 71 insertions(+), 28 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index 8335d502e3..e7c16d1b98 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -76,6 +76,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } + if(GDBStub::IsServerEnabled()) + { + GDBStub::FlushTraps(); + } + return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index a9f4cc008a..6ed727f109 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -143,7 +143,8 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -static Kernel::Thread* current_thread = nullptr; +static Kernel::Thread* current_thread_c = nullptr; +static Kernel::Thread* current_thread_g = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -582,6 +583,7 @@ static void HandleQuery() { static void HandleSetThread() { if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { int thread_id = -1; + static Kernel::Thread* current_thread; if (command_buffer[2] != '-') { thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); } @@ -593,6 +595,14 @@ static void HandleSetThread() { current_thread = FindThreadById(thread_id); } if (current_thread) { + if(command_buffer[1] == 'c') + { + current_thread_c = current_thread; + } + else + { + current_thread_g = current_thread; + } SendReply("OK"); return; } @@ -627,16 +637,16 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { std::string buffer; if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, Common::swap64(RegRead(SP_REGISTER, thread))); } else { - buffer = fmt::format("T{:02x};", latest_signal); + buffer = fmt::format("T{:02x}", latest_signal); } - buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); - NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + //NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -653,7 +663,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(current_thread, SIGTRAP); + SendSignal(current_thread_c, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -724,11 +734,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, RegRead(id, current_thread_g)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread)); + LongToGdbHex(reply, RegRead(id, current_thread_g)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread_g)); } else { return SendReply("E01"); } @@ -744,16 +754,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread_g)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread_g)); bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread_g)); bufptr += 8; @@ -772,11 +782,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); } else if (id == PC_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); } else if (id == CPSR_REGISTER) { - RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread_g); } else { return SendReply("E01"); } @@ -793,11 +803,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); } else if (reg == PC_REGISTER) { - RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread_g); } else { UNIMPLEMENTED(); } @@ -1023,7 +1033,11 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(current_thread, latest_signal); + if(!current_thread_c) + { + current_thread_c = current_thread_g; + } + SendSignal(current_thread_c, latest_signal); break; case 'k': Shutdown(); @@ -1208,16 +1222,37 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } +struct Trap +{ + Kernel::Thread* thread; + int trap; +}; + +static std::vector traps; + void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - current_thread->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (thread == current_thread)) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - halt_loop = true; - send_trap = false; - SendSignal(thread, trap); + traps.push_back(Trap{thread, trap}); + } +} + +void FlushTraps() +{ + if(traps.size()) + { + halt_loop = true; + send_trap = false; + for(auto& trap : traps) + { + if(trap.thread == current_thread_c) + { + SendSignal(trap.thread, trap.trap); + traps.resize(0); + return; + } } + SendSignal(traps[0].thread, traps[0].trap); + traps.resize(0); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index f2418c9e44..e86bcdb4e5 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -80,10 +80,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy */ bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); -// If set to true, the CPU will halt at the beginning of the next CPU loop. +/// If set to true, the CPU will halt at the beginning of the next CPU loop. bool GetCpuHaltFlag(); -// If set to true and the CPU is halted, the CPU will step one instruction. +/// If set to true and the CPU is halted, the CPU will step one instruction. bool GetCpuStepFlag(); /** @@ -100,4 +100,7 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); + +/// Flush all pending trap signals gathered by SendTrap above. +void FlushTraps(); } // namespace GDBStub From 7e7f94f5591d61f68863f6a7ea02f6db24a70039 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 10:24:55 +0100 Subject: [PATCH 35/71] More improvements and diagnostics for GDBStub. --- src/core/core.cpp | 5 ---- src/core/gdbstub/gdbstub.cpp | 58 ++++++++++++------------------------ src/core/gdbstub/gdbstub.h | 3 -- 3 files changed, 19 insertions(+), 47 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index e7c16d1b98..8335d502e3 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -76,11 +76,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } - if(GDBStub::IsServerEnabled()) - { - GDBStub::FlushTraps(); - } - return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 6ed727f109..b3830d3ea8 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -595,12 +595,9 @@ static void HandleSetThread() { current_thread = FindThreadById(thread_id); } if (current_thread) { - if(command_buffer[1] == 'c') - { + if (command_buffer[1] == 'c') { current_thread_c = current_thread; - } - else - { + } else { current_thread_g = current_thread; } SendReply("OK"); @@ -635,6 +632,11 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { latest_signal = signal; + if(!thread) + { + full = false; + } + std::string buffer; if (full) { buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, @@ -644,9 +646,12 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer = fmt::format("T{:02x}", latest_signal); } - buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); + if(thread) + { + buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); + } - //NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -1033,10 +1038,6 @@ void HandlePacket() { HandleSetThread(); break; case '?': - if(!current_thread_c) - { - current_thread_c = current_thread_g; - } SendSignal(current_thread_c, latest_signal); break; case 'k': @@ -1222,37 +1223,16 @@ void SetCpuStepFlag(bool is_step) { step_loop = is_step; } -struct Trap -{ - Kernel::Thread* thread; - int trap; -}; - -static std::vector traps; - void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - traps.push_back(Trap{thread, trap}); - } -} - -void FlushTraps() -{ - if(traps.size()) - { - halt_loop = true; - send_trap = false; - for(auto& trap : traps) - { - if(trap.thread == current_thread_c) - { - SendSignal(trap.thread, trap.trap); - traps.resize(0); - return; - } + NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + current_thread_c->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (thread == current_thread_c)) { + NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + halt_loop = true; + send_trap = false; + SendSignal(thread, trap); } - SendSignal(traps[0].thread, traps[0].trap); - traps.resize(0); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index e86bcdb4e5..efd5018843 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -100,7 +100,4 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); - -/// Flush all pending trap signals gathered by SendTrap above. -void FlushTraps(); } // namespace GDBStub From c3ec14616f9539d75f02b705c8f27285570f01dd Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 10:58:18 +0100 Subject: [PATCH 36/71] More improvements and diagnostics for GDBStub. --- src/core/gdbstub/gdbstub.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index b3830d3ea8..e8ada3ffad 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -61,7 +61,7 @@ const u32 SIGTERM = 15; const u32 MSG_WAITALL = 8; #endif -const u32 X30_REGISTER = 30; +const u32 LR_REGISTER = 30; const u32 SP_REGISTER = 31; const u32 PC_REGISTER = 32; const u32 CPSR_REGISTER = 33; @@ -632,22 +632,21 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { latest_signal = signal; - if(!thread) - { + if (!thread) { full = false; } std::string buffer; if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x}", latest_signal, PC_REGISTER, - Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(RegRead(SP_REGISTER, thread))); + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, + PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, + Common::swap64(RegRead(LR_REGISTER, thread))); } else { buffer = fmt::format("T{:02x}", latest_signal); } - if(thread) - { + if (thread) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } From 2f465d7572f1e7d4decbd359e71724393e67c993 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 15:16:56 +0100 Subject: [PATCH 37/71] More improvements and diagnostics for GDBStub. --- src/core/arm/unicorn/arm_unicorn.cpp | 4 ++-- src/core/gdbstub/gdbstub.cpp | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d6..f239cf0eaa 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit) { + if (last_bkpt_hit || (num_instructions == 1)) { last_bkpt_hit = false; GDBStub::Break(); + GDBStub::SendTrap(thread, 5); } - GDBStub::SendTrap(thread, 5); } } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e8ada3ffad..e1bd0bf9c5 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -650,7 +650,7 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } - NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); + // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); SendReply(buffer.c_str()); } @@ -872,10 +872,11 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - if (!halt_loop) { - // halt_loop = true; - send_trap = true; - } + // if (!halt_loop) { + // halt_loop = true; + //} + + send_trap = true; memory_break = is_memory_break; } @@ -1224,14 +1225,15 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - current_thread_c->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (thread == current_thread_c)) { - NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - halt_loop = true; - send_trap = false; + // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), + // current_thread_c->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (current_thread_c == thread)) { + // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); + current_thread_c = thread; SendSignal(thread, trap); } + halt_loop = true; + send_trap = false; } } }; // namespace GDBStub From 68e5f369c13077c38e29cd36413871213a82dd3e Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 9 Jun 2018 15:16:56 +0100 Subject: [PATCH 38/71] More improvements and diagnostics for GDBStub. --- src/core/gdbstub/gdbstub.cpp | 79 +++++++++++++++--------------------- 1 file changed, 32 insertions(+), 47 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index e1bd0bf9c5..a06f19fd67 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -143,8 +143,7 @@ static u32 command_length; static u32 latest_signal = 0; static bool memory_break = false; -static Kernel::Thread* current_thread_c = nullptr; -static Kernel::Thread* current_thread_g = nullptr; +static Kernel::Thread* current_thread = nullptr; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -561,12 +560,6 @@ static void HandleQuery() { for (int core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { - // buffer += fmt::format(R"*()*", - // thread->GetThreadId(), - // core, - // reinterpret_cast(thread.get()), - // thread->GetThreadId()); buffer += fmt::format(R"*()*", thread->GetThreadId(), core, thread->GetThreadId()); @@ -581,28 +574,20 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { - if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; - static Kernel::Thread* current_thread; - if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); - } - if (thread_id >= 1) { - current_thread = FindThreadById(thread_id); - } - if (!current_thread) { - thread_id = 1; - current_thread = FindThreadById(thread_id); - } - if (current_thread) { - if (command_buffer[1] == 'c') { - current_thread_c = current_thread; - } else { - current_thread_g = current_thread; - } - SendReply("OK"); - return; - } + int thread_id = -1; + if (command_buffer[2] != '-') { + thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); + } + if (thread_id >= 1) { + current_thread = FindThreadById(thread_id); + } + if (!current_thread) { + thread_id = 1; + current_thread = FindThreadById(thread_id); + } + if (current_thread) { + SendReply("OK"); + return; } SendReply("E01"); } @@ -667,7 +652,7 @@ static void ReadCommand() { } else if (c == 0x03) { NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; - SendSignal(current_thread_c, SIGTRAP); + SendSignal(current_thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); @@ -738,11 +723,11 @@ static void ReadRegister() { } if (id <= SP_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread_g)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == PC_REGISTER) { - LongToGdbHex(reply, RegRead(id, current_thread_g)); + LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { - IntToGdbHex(reply, (u32)RegRead(id, current_thread_g)); + IntToGdbHex(reply, (u32)RegRead(id, current_thread)); } else { return SendReply("E01"); } @@ -758,16 +743,16 @@ static void ReadRegisters() { u8* bufptr = buffer; for (int reg = 0; reg <= SP_REGISTER; reg++) { - LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread_g)); + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } bufptr += (32 * 16); - LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread_g)); + LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); bufptr += 16; - IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread_g)); + IntToGdbHex(bufptr, (u32)RegRead(CPSR_REGISTER, current_thread)); bufptr += 8; @@ -786,11 +771,11 @@ static void WriteRegister() { } if (id <= SP_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == PC_REGISTER) { - RegWrite(id, GdbHexToLong(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { - RegWrite(id, GdbHexToInt(buffer_ptr), current_thread_g); + RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); } else { return SendReply("E01"); } @@ -807,11 +792,11 @@ static void WriteRegisters() { for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { - RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { - RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread_g); + RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { - RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread_g); + RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } @@ -1038,7 +1023,7 @@ void HandlePacket() { HandleSetThread(); break; case '?': - SendSignal(current_thread_c, latest_signal); + SendSignal(current_thread, latest_signal); break; case 'k': Shutdown(); @@ -1226,10 +1211,10 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - // current_thread_c->GetThreadId(), halt_loop, step_loop); - if (!halt_loop || (current_thread_c == thread)) { + // current_thread->GetThreadId(), halt_loop, step_loop); + if (!halt_loop || (current_thread == thread)) { // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); - current_thread_c = thread; + current_thread = thread; SendSignal(thread, trap); } halt_loop = true; From fb8e336e95baddfb43ddd176d18516bd6e65314f Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 11 Jun 2018 09:50:40 +0100 Subject: [PATCH 39/71] Tidy up. --- src/core/gdbstub/gdbstub.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index a06f19fd67..f5a266eb28 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -635,8 +635,6 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); } - // NGLOG_ERROR(Debug_GDBStub, "{}", buffer.c_str()); - SendReply(buffer.c_str()); } @@ -857,10 +855,6 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - // if (!halt_loop) { - // halt_loop = true; - //} - send_trap = true; memory_break = is_memory_break; @@ -1210,10 +1204,7 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap {} {} {} {}", thread->GetThreadId(), - // current_thread->GetThreadId(), halt_loop, step_loop); if (!halt_loop || (current_thread == thread)) { - // NGLOG_ERROR(Debug_GDBStub, "SendTrap Fired!"); current_thread = thread; SendSignal(thread, trap); } From 625558e7b0bb4b0e30a832e82b845adf64cb3d8b Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 11 Jun 2018 14:53:47 +0100 Subject: [PATCH 40/71] Reload registers from thread context after they have been changed in GDBStub. --- src/core/gdbstub/gdbstub.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index f5a266eb28..0f8ec5809d 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -144,6 +144,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; +static unsigned current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -172,10 +173,11 @@ static std::map breakpoints_read; static std::map breakpoints_write; static Kernel::Thread* FindThreadById(int id) { - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { + for (unsigned core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { + current_core = core; return thread.get(); } } @@ -778,6 +780,8 @@ static void WriteRegister() { return SendReply("E01"); } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -800,6 +804,8 @@ static void WriteRegisters() { } } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -862,6 +868,10 @@ void Break(bool is_memory_break) { /// Tell the CPU that it should perform a single step. static void Step() { + if (command_length > 1) { + RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + } step_loop = true; halt_loop = true; send_trap = true; From c2ad530279bc70e1272dd798e31a0b4eb4bc2d2c Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sun, 24 Jun 2018 23:06:07 +0100 Subject: [PATCH 41/71] Initial support for floating point registers (wip). --- src/core/gdbstub/gdbstub.cpp | 104 ++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 0f8ec5809d..a63a1fc498 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -65,6 +65,8 @@ const u32 LR_REGISTER = 30; const u32 SP_REGISTER = 31; const u32 PC_REGISTER = 32; const u32 CPSR_REGISTER = 33; +const u32 UC_ARM64_REG_Q0 = 34; +const u32 FPSCR_REGISTER = 66; // For sample XML files see the GDB source /gdb/features // GDB also wants the l character at the start @@ -130,6 +132,41 @@ static const char* target_xml = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )"; @@ -198,6 +235,8 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { return thread->context.pc; } else if (id == CPSR_REGISTER) { return thread->context.cpsr; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + return thread->context.fpu_registers[id-UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -216,6 +255,8 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { thread->context.pc = val; } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + thread->context.fpu_registers[id-(CPSR_REGISTER+1)][0] = val; } } @@ -336,6 +377,21 @@ static void LongToGdbHex(u8* dest, u64 v) { } } +/** + * Convert a u128 into a gdb-formatted hex string. + * + * @param dest Pointer to buffer to store output hex string characters. + * @param v Value to convert. + */ +// static void LongLongToGdbHex(u8* dest, u128 v) +//{ +// for(int i = 0; i < 32; i += 2) +// { +// dest[i + 1] = NibbleToHex(static_cast(v >> (4 * i))); +// dest[i] = NibbleToHex(static_cast(v >> (4 * (i + 1)))); +// } +//} + /** * Convert a gdb-formatted hex string into a u32. * @@ -368,6 +424,24 @@ static u64 GdbHexToLong(const u8* src) { return output; } +/** + * Convert a gdb-formatted hex string into a u128. + * + * @param src Pointer to hex string. + */ +// static u128 GdbHexToLong(const u8* src) +//{ +// u128 output = 0; +// +// for(int i = 0; i < 32; i += 2) +// { +// output = (output << 4) | HexCharToValue(src[15 - i - 1]); +// output = (output << 4) | HexCharToValue(src[15 - i]); +// } +// +// return output; +//} + /// Read a byte from the gdb client. static u8 ReadByte() { u8 c; @@ -728,8 +802,13 @@ static void ReadRegister() { LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(id, current_thread)); + } else if (id == FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(998, current_thread)); } else { - return SendReply("E01"); + //return SendReply("E01"); + LongToGdbHex(reply, RegRead(997, current_thread)); } SendReply(reinterpret_cast(reply)); @@ -756,6 +835,16 @@ static void ReadRegisters() { bufptr += 8; + for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + } + + bufptr += (32 * 32); + + LongToGdbHex(bufptr, RegRead(998, current_thread)); + + bufptr += 8; + SendReply(reinterpret_cast(buffer)); } @@ -776,8 +865,13 @@ static void WriteRegister() { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + } else if (id == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - return SendReply("E01"); + //return SendReply("E01"); + RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); @@ -792,13 +886,17 @@ static void WriteRegisters() { if (command_buffer[0] != 'G') return SendReply("E01"); - for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { + for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + } else if (reg == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } From 1ffd10ce182fadc61a0b7e1641b8caadb2332475 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 16:22:30 +0100 Subject: [PATCH 42/71] Add support for NSO modules. --- src/core/gdbstub/gdbstub.cpp | 51 +++++++++++++++++-- src/core/gdbstub/gdbstub.h | 3 ++ .../loader/deconstructed_rom_directory.cpp | 10 ++-- 3 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index a63a1fc498..04523a4289 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -209,6 +209,22 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; +struct Module { + char name[128]; + PAddr beg; + PAddr end; +}; + +static std::vector modules; + +void RegisterModule(const char* name, PAddr beg, PAddr end) { + Module module; + strncpy(module.name, name, sizeof(module.name)); + module.beg = beg; + module.end = end; + modules.push_back(module); +} + static Kernel::Thread* FindThreadById(int id) { for (unsigned core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); @@ -609,12 +625,28 @@ static void HandleQuery() { SendReply("T0"); } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml - SendReply("PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"); + std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; + if (modules.size()) { + buffer += ";qXfer:libraries:read+"; + } + SendReply(buffer.c_str()); } else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { - std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); + std::string buffer; + // if(modules.size()) + //{ + // for(auto module : modules) + // { + // if(stricmp(module.name, "main") == 0) + // { + // buffer = fmt::format("TextSeg={:0x}", module.beg); + // } + // } + //} + // else + { buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); } SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; @@ -643,6 +675,17 @@ static void HandleQuery() { } buffer += ""; SendReply(buffer.c_str()); + } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { + std::string buffer; + buffer += "l"; + buffer += ""; + for (auto module : modules) { + buffer += + fmt::format(R"*("
)*", + module.name, module.beg); + } + buffer += ""; + SendReply(buffer.c_str()); } else { SendReply(""); } @@ -925,7 +968,7 @@ static void ReadMemory() { SendReply("E01"); } - if (!Memory::IsValidVirtualAddress(addr)) { + if (!Memory::IsValidVirtualAddress(addr) && (addr < Memory::STACK_AREA_VADDR)) { return SendReply("E00"); } @@ -1210,6 +1253,8 @@ static void Init(u16 port) { breakpoints_read.clear(); breakpoints_write.clear(); + modules.clear(); + // Start gdb server NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index efd5018843..2c17a7275b 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -51,6 +51,9 @@ bool IsServerEnabled(); /// Returns true if there is an active socket connection. bool IsConnected(); +/// Register module. +void RegisterModule(const char* name, PAddr beg, PAddr end); + /** * Signal to the gdbstub server that it should halt CPU execution. * diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index eb7feb617e..a9f232c0f9 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -132,7 +133,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( const VAddr load_addr = next_load_addr; next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + GDBStub::RegisterModule(module, load_addr, next_load_addr); } else { next_load_addr = load_addr; } @@ -163,7 +165,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( std::shared_ptr& romfs_file, u64& offset, u64& size) { if (filepath_romfs.empty()) { - LOG_DEBUG(Loader, "No RomFS available"); + NGLOG_DEBUG(Loader, "No RomFS available"); return ResultStatus::ErrorNotUsed; } @@ -176,8 +178,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( offset = 0; size = romfs_file->GetSize(); - LOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); - LOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); + NGLOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); + NGLOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); // Reset read pointer file.Seek(0, SEEK_SET); From f7e6e204dafcef7dd68898ea9dfc9b01f6bf9085 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 17:35:57 +0100 Subject: [PATCH 43/71] Some cleanup. --- src/core/gdbstub/gdbstub.cpp | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 04523a4289..7776249c8f 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -635,18 +635,7 @@ static void HandleQuery() { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { std::string buffer; - // if(modules.size()) - //{ - // for(auto module : modules) - // { - // if(stricmp(module.name, "main") == 0) - // { - // buffer = fmt::format("TextSeg={:0x}", module.beg); - // } - // } - //} - // else - { buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); } + buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; From 430903a1ba30020df80c06c7a6f2aa979d1ef9d5 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 23:47:27 +0100 Subject: [PATCH 44/71] Fix splitpath on Windows. --- src/common/string_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index ea9d8f77c5..0027888c7e 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -134,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ size_t dir_end = full_path.find_last_of("/" // windows needs the : included for something like just "C:" to be considered a directory #ifdef _WIN32 - ":" + "\\:" #endif ); if (std::string::npos == dir_end) From 490893f119cd0a03c6e2db435964b04922ce2d90 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Wed, 27 Jun 2018 23:47:51 +0100 Subject: [PATCH 45/71] Register NRO module. --- src/core/loader/nro.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 3853cfa1a9..f9f47db019 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nro.h" @@ -115,6 +116,10 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + std::string filename; + Common::SplitPath(path, nullptr, &filename, nullptr); + GDBStub::RegisterModule((filename+".elf").c_str(), load_base, load_base); + return true; } From 20a3fbcc5a71ce3a1e36542bcb2013d394756014 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 2 Jul 2018 00:15:21 +0100 Subject: [PATCH 46/71] Fix handler for libraries query. --- src/core/gdbstub/gdbstub.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 7776249c8f..9493327198 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -670,7 +670,7 @@ static void HandleQuery() { buffer += ""; for (auto module : modules) { buffer += - fmt::format(R"*("
)*", + fmt::format(R"*(")*", module.name, module.beg); } buffer += ""; From 4a657f5fb647b77e458c90e44a98374468515444 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 3 Jul 2018 09:59:38 +0100 Subject: [PATCH 47/71] Register module with GDBStub. --- src/core/loader/deconstructed_rom_directory.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index a9f232c0f9..a7de6f1c36 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -133,7 +133,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( const VAddr load_addr = next_load_addr; next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { - NGLOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); GDBStub::RegisterModule(module, load_addr, next_load_addr); } else { next_load_addr = load_addr; @@ -165,7 +165,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( std::shared_ptr& romfs_file, u64& offset, u64& size) { if (filepath_romfs.empty()) { - NGLOG_DEBUG(Loader, "No RomFS available"); + LOG_DEBUG(Loader, "No RomFS available"); return ResultStatus::ErrorNotUsed; } @@ -178,8 +178,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( offset = 0; size = romfs_file->GetSize(); - NGLOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); - NGLOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); + LOG_DEBUG(Loader, "RomFS offset: 0x{:016X}", offset); + LOG_DEBUG(Loader, "RomFS size: 0x{:016X}", size); // Reset read pointer file.Seek(0, SEEK_SET); From 9cb1f759ca85ee38f0e7e82a7f86aae3d05baeaf Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 10:25:34 +0100 Subject: [PATCH 48/71] Avoid crash in IsValidVirtualAddress() --- src/core/gdbstub/gdbstub.cpp | 14 +++++++++----- src/core/loader/nro.cpp | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 9493327198..50f6de6107 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -252,7 +252,7 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { } else if (id == CPSR_REGISTER) { return thread->context.cpsr; } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - return thread->context.fpu_registers[id-UC_ARM64_REG_Q0][0]; + return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -272,7 +272,7 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { - thread->context.fpu_registers[id-(CPSR_REGISTER+1)][0] = val; + thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; } } @@ -839,7 +839,7 @@ static void ReadRegister() { } else if (id == FPSCR_REGISTER) { LongToGdbHex(reply, RegRead(998, current_thread)); } else { - //return SendReply("E01"); + // return SendReply("E01"); LongToGdbHex(reply, RegRead(997, current_thread)); } @@ -902,7 +902,7 @@ static void WriteRegister() { } else if (id == FPSCR_REGISTER) { RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - //return SendReply("E01"); + // return SendReply("E01"); RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } @@ -957,7 +957,11 @@ static void ReadMemory() { SendReply("E01"); } - if (!Memory::IsValidVirtualAddress(addr) && (addr < Memory::STACK_AREA_VADDR)) { + if ((addr < Memory::PROCESS_IMAGE_VADDR) || (addr >= Memory::MAP_REGION_VADDR_END)) { + return SendReply("E00"); + } + + if (!Memory::IsValidVirtualAddress(addr)) { return SendReply("E00"); } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f9f47db019..6326bd4900 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -117,8 +117,8 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { Core::CurrentProcess()->LoadModule(codeset, load_base); std::string filename; - Common::SplitPath(path, nullptr, &filename, nullptr); - GDBStub::RegisterModule((filename+".elf").c_str(), load_base, load_base); + Common::SplitPath(codeset->name, nullptr, &filename, nullptr); + GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); return true; } From e652110fda997079e7fb48187beea35fa254fc0a Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 11:02:34 +0100 Subject: [PATCH 49/71] Register all loaded modules with GDBStub --- src/core/loader/deconstructed_rom_directory.cpp | 3 ++- src/core/loader/nca.cpp | 3 +++ src/core/loader/nro.cpp | 1 + src/core/loader/nso.cpp | 6 ++++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index a7de6f1c36..68f2f30073 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -134,7 +134,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); - GDBStub::RegisterModule(module, load_addr, next_load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index da064f8e39..e530f1d4b3 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -11,6 +11,7 @@ #include "core/core.h" #include "core/file_sys/program_metadata.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -259,6 +260,8 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 6326bd4900..f8172819ac 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -116,6 +116,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub std::string filename; Common::SplitPath(codeset->name, nullptr, &filename, nullptr); GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f84e4b1be..6a8fecd37e 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nso.h" @@ -147,6 +148,11 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector& codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub + std::string filename; + Common::SplitPath(codeset->name, nullptr, &filename, nullptr); + GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); + return load_base + image_size; } From 4b22a64d637a090ded7a4dc42eabaec6169027cb Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 11:28:36 +0100 Subject: [PATCH 50/71] Compile fixes for Linux and macOS --- src/core/loader/nca.cpp | 1 + src/core/loader/nro.cpp | 1 + src/core/loader/nso.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index e530f1d4b3..baa448956d 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f8172819ac..01c2138ae1 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -7,6 +7,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 6a8fecd37e..82d3c93a57 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -8,6 +8,7 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" From 198805b0fa9ad8c39d22727368a03e0a1d8b3db3 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Tue, 10 Jul 2018 17:22:24 +0100 Subject: [PATCH 51/71] Revert bad merge/rebase --- src/core/gdbstub/gdbstub.cpp | 71 ++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 50f6de6107..4d4176ff2f 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -290,7 +290,7 @@ static u8 HexCharToValue(u8 hex) { return hex - 'A' + 0xA; } - NGLOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); + LOG_ERROR(Debug_GDBStub, "Invalid nibble: {} ({:02X})", hex, hex); return 0; } @@ -463,7 +463,7 @@ static u8 ReadByte() { u8 c; size_t received_size = recv(gdbserver_socket, reinterpret_cast(&c), 1, MSG_WAITALL); if (received_size != 1) { - NGLOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); + LOG_ERROR(Debug_GDBStub, "recv failed: {}", received_size); Shutdown(); } @@ -504,8 +504,8 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { auto bp = p.find(static_cast(addr)); if (bp != p.end()) { - NGLOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", - bp->second.len, bp->second.addr, static_cast(type)); + LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", + bp->second.len, bp->second.addr, static_cast(type)); p.erase(static_cast(addr)); } } @@ -550,10 +550,10 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { } if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { - NGLOG_DEBUG(Debug_GDBStub, - "Found breakpoint type {} @ {:016X}, range: {:016X}" - " - {:016X} ({:X} bytes)", - static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); + LOG_DEBUG(Debug_GDBStub, + "Found breakpoint type {} @ {:016X}, range: {:016X}" + " - {:016X} ({:X} bytes)", + static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); return true; } } @@ -569,7 +569,7 @@ bool CheckBreakpoint(PAddr addr, BreakpointType type) { static void SendPacket(const char packet) { size_t sent_size = send(gdbserver_socket, &packet, 1, 0); if (sent_size != 1) { - NGLOG_ERROR(Debug_GDBStub, "send failed"); + LOG_ERROR(Debug_GDBStub, "send failed"); } } @@ -583,13 +583,13 @@ static void SendReply(const char* reply) { return; } - NGLOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); + LOG_DEBUG(Debug_GDBStub, "Reply: {}", reply); memset(command_buffer, 0, sizeof(command_buffer)); command_length = static_cast(strlen(reply)); if (command_length + 4 > sizeof(command_buffer)) { - NGLOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); + LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); return; } @@ -606,7 +606,7 @@ static void SendReply(const char* reply) { while (left > 0) { int sent_size = send(gdbserver_socket, reinterpret_cast(ptr), left, 0); if (sent_size < 0) { - NGLOG_ERROR(Debug_GDBStub, "gdb: send failed"); + LOG_ERROR(Debug_GDBStub, "gdb: send failed"); return Shutdown(); } @@ -617,7 +617,7 @@ static void SendReply(const char* reply) { /// Handle query command from gdb client. static void HandleQuery() { - NGLOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); + LOG_DEBUG(Debug_GDBStub, "gdb: query '{}'", command_buffer + 1); const char* query = reinterpret_cast(command_buffer + 1); @@ -756,18 +756,18 @@ static void ReadCommand() { // ignore ack return; } else if (c == 0x03) { - NGLOG_INFO(Debug_GDBStub, "gdb: found break command"); + LOG_INFO(Debug_GDBStub, "gdb: found break command"); halt_loop = true; SendSignal(current_thread, SIGTRAP); return; } else if (c != GDB_STUB_START) { - NGLOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); + LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte {:02X}", c); return; } while ((c = ReadByte()) != GDB_STUB_END) { if (command_length >= sizeof(command_buffer)) { - NGLOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); + LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow"); SendPacket(GDB_STUB_NACK); return; } @@ -780,10 +780,9 @@ static void ReadCommand() { u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); if (checksum_received != checksum_calculated) { - NGLOG_ERROR( - Debug_GDBStub, - "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", - checksum_calculated, checksum_received, command_buffer, command_length); + LOG_ERROR(Debug_GDBStub, + "gdb: invalid checksum: calculated {:02X} and read {:02X} for ${}# (length: {})", + checksum_calculated, checksum_received, command_buffer, command_length); command_length = 0; @@ -810,7 +809,7 @@ static bool IsDataAvailable() { t.tv_usec = 0; if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { - NGLOG_ERROR(Debug_GDBStub, "select failed"); + LOG_ERROR(Debug_GDBStub, "select failed"); return false; } @@ -951,7 +950,7 @@ static void ReadMemory() { u64 len = HexToLong(start_offset, static_cast((command_buffer + command_length) - start_offset)); - NGLOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); + LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); if (len * 2 > sizeof(reply)) { SendReply("E01"); @@ -1043,8 +1042,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { breakpoint.len = len; p.insert({addr, breakpoint}); - NGLOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", - static_cast(type), breakpoint.len, breakpoint.addr); + LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", + static_cast(type), breakpoint.len, breakpoint.addr); return true; } @@ -1151,7 +1150,7 @@ void HandlePacket() { return; } - NGLOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); + LOG_DEBUG(Debug_GDBStub, "Packet: {}", command_buffer); switch (command_buffer[0]) { case 'q': @@ -1165,7 +1164,7 @@ void HandlePacket() { break; case 'k': Shutdown(); - NGLOG_INFO(Debug_GDBStub, "killed by gdb"); + LOG_INFO(Debug_GDBStub, "killed by gdb"); return; case 'g': ReadRegisters(); @@ -1249,7 +1248,7 @@ static void Init(u16 port) { modules.clear(); // Start gdb server - NGLOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); + LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); sockaddr_in saddr_server = {}; saddr_server.sin_family = AF_INET; @@ -1262,28 +1261,28 @@ static void Init(u16 port) { int tmpsock = static_cast(socket(PF_INET, SOCK_STREAM, 0)); if (tmpsock == -1) { - NGLOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); + LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); } // Set socket to SO_REUSEADDR so it can always bind on the same port int reuse_enabled = 1; if (setsockopt(tmpsock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_enabled, sizeof(reuse_enabled)) < 0) { - NGLOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); + LOG_ERROR(Debug_GDBStub, "Failed to set gdb socket option"); } const sockaddr* server_addr = reinterpret_cast(&saddr_server); socklen_t server_addrlen = sizeof(saddr_server); if (bind(tmpsock, server_addr, server_addrlen) < 0) { - NGLOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); + LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); } if (listen(tmpsock, 1) < 0) { - NGLOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); + LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); } // Wait for gdb to connect - NGLOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); + LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect..."); sockaddr_in saddr_client; sockaddr* client_addr = reinterpret_cast(&saddr_client); socklen_t client_addrlen = sizeof(saddr_client); @@ -1294,9 +1293,9 @@ static void Init(u16 port) { halt_loop = false; step_loop = false; - NGLOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); + LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); } else { - NGLOG_INFO(Debug_GDBStub, "Client connected."); + LOG_INFO(Debug_GDBStub, "Client connected."); saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); } @@ -1315,7 +1314,7 @@ void Shutdown() { return; } - NGLOG_INFO(Debug_GDBStub, "Stopping GDB ..."); + LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); if (gdbserver_socket != -1) { shutdown(gdbserver_socket, SHUT_RDWR); gdbserver_socket = -1; @@ -1325,7 +1324,7 @@ void Shutdown() { WSACleanup(); #endif - NGLOG_INFO(Debug_GDBStub, "GDB stopped."); + LOG_INFO(Debug_GDBStub, "GDB stopped."); } bool IsServerEnabled() { From 33ac8e9a8532656146663f49df9a380ac8d02907 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 12:23:12 +0100 Subject: [PATCH 52/71] Tidy up as per comments on pull request --- src/core/gdbstub/gdbstub.cpp | 94 ++++--------------- src/core/gdbstub/gdbstub.h | 3 +- .../loader/deconstructed_rom_directory.cpp | 2 +- src/core/loader/nca.cpp | 2 +- src/core/loader/nro.cpp | 5 +- src/core/loader/nso.cpp | 5 +- 6 files changed, 22 insertions(+), 89 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 4d4176ff2f..31764ef1c5 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -133,39 +133,6 @@ static const char* target_xml = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - )"; @@ -181,7 +148,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; -static unsigned current_core = 0; +static u32 current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -210,23 +177,28 @@ static std::map breakpoints_read; static std::map breakpoints_write; struct Module { - char name[128]; + std::string name; PAddr beg; PAddr end; }; static std::vector modules; -void RegisterModule(const char* name, PAddr beg, PAddr end) { +void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { Module module; - strncpy(module.name, name, sizeof(module.name)); + if (add_elf_ext) { + Common::SplitPath(name, nullptr, &module.name, nullptr); + module.name += ".elf"; + } else { + module.name = std::move(name); + } module.beg = beg; module.end = end; - modules.push_back(module); + modules.push_back(std::move(module)); } static Kernel::Thread* FindThreadById(int id) { - for (unsigned core = 0; core < Core::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { @@ -393,21 +365,6 @@ static void LongToGdbHex(u8* dest, u64 v) { } } -/** - * Convert a u128 into a gdb-formatted hex string. - * - * @param dest Pointer to buffer to store output hex string characters. - * @param v Value to convert. - */ -// static void LongLongToGdbHex(u8* dest, u128 v) -//{ -// for(int i = 0; i < 32; i += 2) -// { -// dest[i + 1] = NibbleToHex(static_cast(v >> (4 * i))); -// dest[i] = NibbleToHex(static_cast(v >> (4 * (i + 1)))); -// } -//} - /** * Convert a gdb-formatted hex string into a u32. * @@ -440,24 +397,6 @@ static u64 GdbHexToLong(const u8* src) { return output; } -/** - * Convert a gdb-formatted hex string into a u128. - * - * @param src Pointer to hex string. - */ -// static u128 GdbHexToLong(const u8* src) -//{ -// u128 output = 0; -// -// for(int i = 0; i < 32; i += 2) -// { -// output = (output << 4) | HexCharToValue(src[15 - i - 1]); -// output = (output << 4) | HexCharToValue(src[15 - i]); -// } -// -// return output; -//} - /// Read a byte from the gdb client. static u8 ReadByte() { u8 c; @@ -634,8 +573,7 @@ static void HandleQuery() { strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { - std::string buffer; - buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); + std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; @@ -856,7 +794,7 @@ static void ReadRegisters() { LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } - bufptr += (32 * 16); + bufptr += 32 * 16; LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); @@ -870,7 +808,7 @@ static void ReadRegisters() { LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } - bufptr += (32 * 32); + bufptr += 32 * 32; LongToGdbHex(bufptr, RegRead(998, current_thread)); @@ -956,7 +894,7 @@ static void ReadMemory() { SendReply("E01"); } - if ((addr < Memory::PROCESS_IMAGE_VADDR) || (addr >= Memory::MAP_REGION_VADDR_END)) { + if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { return SendReply("E00"); } @@ -1349,7 +1287,7 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { - if (!halt_loop || (current_thread == thread)) { + if (!halt_loop || current_thread == thread) { current_thread = thread; SendSignal(thread, trap); } diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 2c17a7275b..a6b50c26cf 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -6,6 +6,7 @@ #pragma once +#include #include "common/common_types.h" #include "core/hle/kernel/thread.h" @@ -52,7 +53,7 @@ bool IsServerEnabled(); bool IsConnected(); /// Register module. -void RegisterModule(const char* name, PAddr beg, PAddr end); +void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true); /** * Signal to the gdbstub server that it should halt CPU execution. diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 68f2f30073..5fdb1d2893 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -135,7 +135,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); // Register module with GDBStub - GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index baa448956d..0fd930ae20 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -262,7 +262,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); // Register module with GDBStub - GDBStub::RegisterModule(module, load_addr, next_load_addr - 1); + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 01c2138ae1..4d7c69a228 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -7,7 +7,6 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" @@ -118,9 +117,7 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { Core::CurrentProcess()->LoadModule(codeset, load_base); // Register module with GDBStub - std::string filename; - Common::SplitPath(codeset->name, nullptr, &filename, nullptr); - GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); + GDBStub::RegisterModule(codeset->name, load_base, load_base); return true; } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 82d3c93a57..1c629e21f3 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -8,7 +8,6 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/gdbstub/gdbstub.h" @@ -150,9 +149,7 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector& Core::CurrentProcess()->LoadModule(codeset, load_base); // Register module with GDBStub - std::string filename; - Common::SplitPath(codeset->name, nullptr, &filename, nullptr); - GDBStub::RegisterModule((filename + ".elf").c_str(), load_base, load_base); + GDBStub::RegisterModule(codeset->name, load_base, load_base); return load_base + image_size; } From 21a2512cfb439c0efd2555db2835fffe31a2c6a9 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 15:46:31 +0100 Subject: [PATCH 53/71] More tidy up as per comments on pull request --- src/core/gdbstub/gdbstub.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 31764ef1c5..d293bf194f 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -199,7 +199,7 @@ void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { static Kernel::Thread* FindThreadById(int id) { for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { if (thread->GetThreadId() == id) { current_core = core; @@ -577,8 +577,8 @@ static void HandleQuery() { SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { val += fmt::format("{:x}", thread->GetThreadId()); val += ","; @@ -593,7 +593,7 @@ static void HandleQuery() { buffer += "l"; buffer += ""; for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); for (auto thread : threads) { buffer += fmt::format(R"*()*", @@ -606,7 +606,7 @@ static void HandleQuery() { std::string buffer; buffer += "l"; buffer += ""; - for (auto module : modules) { + for (const auto& module : modules) { buffer += fmt::format(R"*(")*", module.name, module.beg); From 5a9ba8342fd7c07371dc934fcab32382b26e3839 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 17:41:14 +0100 Subject: [PATCH 54/71] More tidy up as per comments on pull request --- src/core/gdbstub/gdbstub.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index d293bf194f..c7146983bd 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -200,7 +200,7 @@ void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { static Kernel::Thread* FindThreadById(int id) { for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { + for (const auto& thread : threads) { if (thread->GetThreadId() == id) { current_core = core; return thread.get(); @@ -579,7 +579,7 @@ static void HandleQuery() { std::string val = "m"; for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { + for (const auto& thread : threads) { val += fmt::format("{:x}", thread->GetThreadId()); val += ","; } @@ -592,9 +592,9 @@ static void HandleQuery() { std::string buffer; buffer += "l"; buffer += ""; - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { + for (const auto& thread : threads) { buffer += fmt::format(R"*()*", thread->GetThreadId(), core, thread->GetThreadId()); From 85d02d07fc96c3e4a4653dbd1b896a38b2959769 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 17:53:47 +0100 Subject: [PATCH 55/71] This auto should not actually be const --- src/core/gdbstub/gdbstub.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index c7146983bd..b78d8c0076 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -200,7 +200,7 @@ void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { static Kernel::Thread* FindThreadById(int id) { for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (const auto& thread : threads) { + for (auto& thread : threads) { if (thread->GetThreadId() == id) { current_core = core; return thread.get(); From 7b4cd8f895db65da14e2c9c3c26609110582812e Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 20:09:20 +0100 Subject: [PATCH 56/71] More improvements to GDBStub - Debugging of threads should work correctly with source and assembly level stepping and modifying registers and memory, meaning threads and callstacks are fully clickable in VS. - List of modules is available to the client, with assumption that .nro and .nso are backed up by an .elf with symbols, while deconstructed ROMs keep N names. - Initial support for floating point registers. --- src/common/string_util.cpp | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 4 +- src/core/gdbstub/gdbstub.cpp | 195 +++++++++++++----- src/core/gdbstub/gdbstub.h | 8 +- .../loader/deconstructed_rom_directory.cpp | 3 + src/core/loader/nca.cpp | 4 + src/core/loader/nro.cpp | 4 + src/core/loader/nso.cpp | 4 + 8 files changed, 171 insertions(+), 53 deletions(-) diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index ea9d8f77c5..0027888c7e 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -134,7 +134,7 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _ size_t dir_end = full_path.find_last_of("/" // windows needs the : included for something like just "C:" to be considered a directory #ifdef _WIN32 - ":" + "\\:" #endif ); if (std::string::npos == dir_end) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index ce6c5616d6..f239cf0eaa 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -193,11 +193,11 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit) { + if (last_bkpt_hit || (num_instructions == 1)) { last_bkpt_hit = false; GDBStub::Break(); + GDBStub::SendTrap(thread, 5); } - GDBStub::SendTrap(thread, 5); } } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 938852a1a2..b78d8c0076 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -61,10 +61,12 @@ const u32 SIGTERM = 15; const u32 MSG_WAITALL = 8; #endif -const u32 X30_REGISTER = 30; +const u32 LR_REGISTER = 30; const u32 SP_REGISTER = 31; const u32 PC_REGISTER = 32; const u32 CPSR_REGISTER = 33; +const u32 UC_ARM64_REG_Q0 = 34; +const u32 FPSCR_REGISTER = 66; // For sample XML files see the GDB source /gdb/features // GDB also wants the l character at the start @@ -130,6 +132,8 @@ static const char* target_xml = + + )"; @@ -144,6 +148,7 @@ static u32 latest_signal = 0; static bool memory_break = false; static Kernel::Thread* current_thread = nullptr; +static u32 current_core = 0; // Binding to a port within the reserved ports range (0-1023) requires root permissions, // so default to a port outside of that range. @@ -171,13 +176,34 @@ static std::map breakpoints_execute; static std::map breakpoints_read; static std::map breakpoints_write; +struct Module { + std::string name; + PAddr beg; + PAddr end; +}; + +static std::vector modules; + +void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext) { + Module module; + if (add_elf_ext) { + Common::SplitPath(name, nullptr, &module.name, nullptr); + module.name += ".elf"; + } else { + module.name = std::move(name); + } + module.beg = beg; + module.end = end; + modules.push_back(std::move(module)); +} + static Kernel::Thread* FindThreadById(int id) { - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (auto& thread : threads) { if (thread->GetThreadId() == id) { - current_thread = thread.get(); - return current_thread; + current_core = core; + return thread.get(); } } } @@ -197,6 +223,8 @@ static u64 RegRead(int id, Kernel::Thread* thread = nullptr) { return thread->context.pc; } else if (id == CPSR_REGISTER) { return thread->context.cpsr; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + return thread->context.fpu_registers[id - UC_ARM64_REG_Q0][0]; } else { return 0; } @@ -215,6 +243,8 @@ static void RegWrite(int id, u64 val, Kernel::Thread* thread = nullptr) { thread->context.pc = val; } else if (id == CPSR_REGISTER) { thread->context.cpsr = val; + } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { + thread->context.fpu_registers[id - (CPSR_REGISTER + 1)][0] = val; } } @@ -534,7 +564,11 @@ static void HandleQuery() { SendReply("T0"); } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml - SendReply("PacketSize=2000;qXfer:features:read+"); + std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; + if (modules.size()) { + buffer += ";qXfer:libraries:read+"; + } + SendReply(buffer.c_str()); } else if (strncmp(query, "Xfer:features:read:target.xml:", strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); @@ -543,9 +577,9 @@ static void HandleQuery() { SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; - for (int core = 0; core < Core::NUM_CPU_CORES; core++) { - auto threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); - for (auto thread : threads) { + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (const auto& thread : threads) { val += fmt::format("{:x}", thread->GetThreadId()); val += ","; } @@ -554,6 +588,31 @@ static void HandleQuery() { SendReply(val.c_str()); } else if (strncmp(query, "sThreadInfo", strlen("sThreadInfo")) == 0) { SendReply("l"); + } else if (strncmp(query, "Xfer:threads:read", strlen("Xfer:threads:read")) == 0) { + std::string buffer; + buffer += "l"; + buffer += ""; + for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { + const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); + for (const auto& thread : threads) { + buffer += + fmt::format(R"*()*", + thread->GetThreadId(), core, thread->GetThreadId()); + } + } + buffer += ""; + SendReply(buffer.c_str()); + } else if (strncmp(query, "Xfer:libraries:read", strlen("Xfer:libraries:read")) == 0) { + std::string buffer; + buffer += "l"; + buffer += ""; + for (const auto& module : modules) { + buffer += + fmt::format(R"*(")*", + module.name, module.beg); + } + buffer += ""; + SendReply(buffer.c_str()); } else { SendReply(""); } @@ -561,33 +620,27 @@ static void HandleQuery() { /// Handle set thread command from gdb client. static void HandleSetThread() { - if (memcmp(command_buffer, "Hc", 2) == 0 || memcmp(command_buffer, "Hg", 2) == 0) { - int thread_id = -1; - if (command_buffer[2] != '-') { - thread_id = static_cast(HexToInt( - command_buffer + 2, - command_length - 2 /*strlen(reinterpret_cast(command_buffer) + 2)*/)); - } - if (thread_id >= 1) { - current_thread = FindThreadById(thread_id); - } - if (!current_thread) { - thread_id = 1; - current_thread = FindThreadById(thread_id); - } - if (current_thread) { - SendReply("OK"); - return; - } + int thread_id = -1; + if (command_buffer[2] != '-') { + thread_id = static_cast(HexToInt(command_buffer + 2, command_length - 2)); + } + if (thread_id >= 1) { + current_thread = FindThreadById(thread_id); + } + if (!current_thread) { + thread_id = 1; + current_thread = FindThreadById(thread_id); + } + if (current_thread) { + SendReply("OK"); + return; } SendReply("E01"); } /// Handle thread alive command from gdb client. static void HandleThreadAlive() { - int thread_id = static_cast( - HexToInt(command_buffer + 1, - command_length - 1 /*strlen(reinterpret_cast(command_buffer) + 1)*/)); + int thread_id = static_cast(HexToInt(command_buffer + 1, command_length - 1)); if (thread_id == 0) { thread_id = 1; } @@ -610,16 +663,23 @@ static void SendSignal(Kernel::Thread* thread, u32 signal, bool full = true) { latest_signal = signal; - std::string buffer; - if (full) { - buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};", latest_signal, PC_REGISTER, - Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, - Common::swap64(RegRead(SP_REGISTER, thread))); - } else { - buffer = fmt::format("T{:02x};", latest_signal); + if (!thread) { + full = false; } - buffer += fmt::format("thread:{:x};", thread->GetThreadId()); + std::string buffer; + if (full) { + buffer = fmt::format("T{:02x}{:02x}:{:016x};{:02x}:{:016x};{:02x}:{:016x}", latest_signal, + PC_REGISTER, Common::swap64(RegRead(PC_REGISTER, thread)), SP_REGISTER, + Common::swap64(RegRead(SP_REGISTER, thread)), LR_REGISTER, + Common::swap64(RegRead(LR_REGISTER, thread))); + } else { + buffer = fmt::format("T{:02x}", latest_signal); + } + + if (thread) { + buffer += fmt::format(";thread:{:x};", thread->GetThreadId()); + } SendReply(buffer.c_str()); } @@ -711,8 +771,13 @@ static void ReadRegister() { LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == CPSR_REGISTER) { IntToGdbHex(reply, (u32)RegRead(id, current_thread)); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(id, current_thread)); + } else if (id == FPSCR_REGISTER) { + LongToGdbHex(reply, RegRead(998, current_thread)); } else { - return SendReply("E01"); + // return SendReply("E01"); + LongToGdbHex(reply, RegRead(997, current_thread)); } SendReply(reinterpret_cast(reply)); @@ -729,7 +794,7 @@ static void ReadRegisters() { LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); } - bufptr += (32 * 16); + bufptr += 32 * 16; LongToGdbHex(bufptr, RegRead(PC_REGISTER, current_thread)); @@ -739,6 +804,16 @@ static void ReadRegisters() { bufptr += 8; + for (int reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { + LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); + } + + bufptr += 32 * 32; + + LongToGdbHex(bufptr, RegRead(998, current_thread)); + + bufptr += 8; + SendReply(reinterpret_cast(buffer)); } @@ -759,10 +834,17 @@ static void WriteRegister() { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == CPSR_REGISTER) { RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); + } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { + RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); + } else if (id == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - return SendReply("E01"); + // return SendReply("E01"); + RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -773,18 +855,24 @@ static void WriteRegisters() { if (command_buffer[0] != 'G') return SendReply("E01"); - for (int i = 0, reg = 0; reg <= CPSR_REGISTER; i++, reg++) { + for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { if (reg <= SP_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == PC_REGISTER) { RegWrite(PC_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == CPSR_REGISTER) { RegWrite(CPSR_REGISTER, GdbHexToInt(buffer_ptr + i * 16), current_thread); + } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { + RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); + } else if (reg == FPSCR_REGISTER) { + RegWrite(998, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } } + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + SendReply("OK"); } @@ -806,6 +894,10 @@ static void ReadMemory() { SendReply("E01"); } + if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { + return SendReply("E00"); + } + if (!Memory::IsValidVirtualAddress(addr)) { return SendReply("E00"); } @@ -840,16 +932,17 @@ static void WriteMemory() { } void Break(bool is_memory_break) { - if (!halt_loop) { - halt_loop = true; - send_trap = true; - } + send_trap = true; memory_break = is_memory_break; } /// Tell the CPU that it should perform a single step. static void Step() { + if (command_length > 1) { + RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); + Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); + } step_loop = true; halt_loop = true; send_trap = true; @@ -1090,6 +1183,8 @@ static void Init(u16 port) { breakpoints_read.clear(); breakpoints_write.clear(); + modules.clear(); + // Start gdb server LOG_INFO(Debug_GDBStub, "Starting GDB server on port {}...", port); @@ -1192,8 +1287,12 @@ void SetCpuStepFlag(bool is_step) { void SendTrap(Kernel::Thread* thread, int trap) { if (send_trap) { + if (!halt_loop || current_thread == thread) { + current_thread = thread; + SendSignal(thread, trap); + } + halt_loop = true; send_trap = false; - SendSignal(thread, trap); } } }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index f2418c9e44..a6b50c26cf 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -6,6 +6,7 @@ #pragma once +#include #include "common/common_types.h" #include "core/hle/kernel/thread.h" @@ -51,6 +52,9 @@ bool IsServerEnabled(); /// Returns true if there is an active socket connection. bool IsConnected(); +/// Register module. +void RegisterModule(std::string name, PAddr beg, PAddr end, bool add_elf_ext = true); + /** * Signal to the gdbstub server that it should halt CPU execution. * @@ -80,10 +84,10 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, GDBStub::BreakpointTy */ bool CheckBreakpoint(PAddr addr, GDBStub::BreakpointType type); -// If set to true, the CPU will halt at the beginning of the next CPU loop. +/// If set to true, the CPU will halt at the beginning of the next CPU loop. bool GetCpuHaltFlag(); -// If set to true and the CPU is halted, the CPU will step one instruction. +/// If set to true and the CPU is halted, the CPU will step one instruction. bool GetCpuStepFlag(); /** diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index eb7feb617e..5fdb1d2893 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -133,6 +134,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index da064f8e39..0fd930ae20 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -7,10 +7,12 @@ #include "common/common_funcs.h" #include "common/file_util.h" #include "common/logging/log.h" +#include "common/string_util.h" #include "common/swap.h" #include "core/core.h" #include "core/file_sys/program_metadata.h" #include "core/file_sys/romfs_factory.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" @@ -259,6 +261,8 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr& process) { next_load_addr = AppLoader_NSO::LoadModule(module, nca->GetExeFsFile(module), load_addr); if (next_load_addr) { LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr); + // Register module with GDBStub + GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false); } else { next_load_addr = load_addr; } diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 3853cfa1a9..4d7c69a228 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nro.h" @@ -115,6 +116,9 @@ bool AppLoader_NRO::LoadNro(const std::string& path, VAddr load_base) { codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub + GDBStub::RegisterModule(codeset->name, load_base, load_base); + return true; } diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 7f84e4b1be..1c629e21f3 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -10,6 +10,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/nso.h" @@ -147,6 +148,9 @@ VAddr AppLoader_NSO::LoadModule(const std::string& name, const std::vector& codeset->memory = std::make_shared>(std::move(program_image)); Core::CurrentProcess()->LoadModule(codeset, load_base); + // Register module with GDBStub + GDBStub::RegisterModule(codeset->name, load_base, load_base); + return load_base + image_size; } From 2db0203317876af3cde41a6a56876d6e92403869 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 21:18:09 +0100 Subject: [PATCH 57/71] Tidy up as requested in PR feedback --- src/core/gdbstub/gdbstub.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index b78d8c0076..5fba669e40 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -565,7 +565,7 @@ static void HandleQuery() { } else if (strncmp(query, "Supported", strlen("Supported")) == 0) { // PacketSize needs to be large enough for target xml std::string buffer = "PacketSize=2000;qXfer:features:read+;qXfer:threads:read+"; - if (modules.size()) { + if (!modules.empty()) { buffer += ";qXfer:libraries:read+"; } SendReply(buffer.c_str()); @@ -776,7 +776,6 @@ static void ReadRegister() { } else if (id == FPSCR_REGISTER) { LongToGdbHex(reply, RegRead(998, current_thread)); } else { - // return SendReply("E01"); LongToGdbHex(reply, RegRead(997, current_thread)); } @@ -839,10 +838,10 @@ static void WriteRegister() { } else if (id == FPSCR_REGISTER) { RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); } else { - // return SendReply("E01"); RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); } + // Update Unicorn context skipping scheduler, no running threads at this point Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); SendReply("OK"); @@ -871,6 +870,7 @@ static void WriteRegisters() { } } + // Update Unicorn context skipping scheduler, no running threads at this point Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); SendReply("OK"); @@ -941,6 +941,7 @@ void Break(bool is_memory_break) { static void Step() { if (command_length > 1) { RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); + // Update Unicorn context skipping scheduler, no running threads at this point Core::System::GetInstance().ArmInterface(current_core).LoadContext(current_thread->context); } step_loop = true; From d69a2d0e6af24771b58858c5479893762de61f85 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 12 Jul 2018 22:55:27 +0100 Subject: [PATCH 58/71] Tidy up as requested in PR feedback --- src/core/gdbstub/gdbstub.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 5fba669e40..6062de13ce 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -68,6 +68,10 @@ const u32 CPSR_REGISTER = 33; const u32 UC_ARM64_REG_Q0 = 34; const u32 FPSCR_REGISTER = 66; +// TODO/WiP - Used while working on support for FPU +const u32 TODO_DUMMY_REG_997 = 997; +const u32 TODO_DUMMY_REG_998 = 998; + // For sample XML files see the GDB source /gdb/features // GDB also wants the l character at the start // This XML defines what the registers are for this specific ARM device @@ -774,9 +778,9 @@ static void ReadRegister() { } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { LongToGdbHex(reply, RegRead(id, current_thread)); } else if (id == FPSCR_REGISTER) { - LongToGdbHex(reply, RegRead(998, current_thread)); + LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); } else { - LongToGdbHex(reply, RegRead(997, current_thread)); + LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); } SendReply(reinterpret_cast(reply)); @@ -809,7 +813,7 @@ static void ReadRegisters() { bufptr += 32 * 32; - LongToGdbHex(bufptr, RegRead(998, current_thread)); + LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); bufptr += 8; @@ -836,9 +840,9 @@ static void WriteRegister() { } else if (id >= UC_ARM64_REG_Q0 && id < FPSCR_REGISTER) { RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); } else if (id == FPSCR_REGISTER) { - RegWrite(998, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); } else { - RegWrite(997, GdbHexToLong(buffer_ptr), current_thread); + RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); } // Update Unicorn context skipping scheduler, no running threads at this point @@ -864,7 +868,7 @@ static void WriteRegisters() { } else if (reg >= UC_ARM64_REG_Q0 && reg < FPSCR_REGISTER) { RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else if (reg == FPSCR_REGISTER) { - RegWrite(998, GdbHexToLong(buffer_ptr + i * 16), current_thread); + RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); } else { UNIMPLEMENTED(); } From 6662a695e9f6c3a5693d0ba43fd00ae76e9abe89 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 19 Jul 2018 17:43:18 +0100 Subject: [PATCH 59/71] Work towards interfacing with Dynarmic. --- src/core/arm/unicorn/arm_unicorn.cpp | 8 +++++++- src/core/gdbstub/gdbstub.cpp | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index d2d699e9bd..5225f60308 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -188,12 +188,18 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { + //u64 pc = GetPC(); + //GDBStub::BreakpointAddress bkpt = GDBStub::GetNextBreakpointFromAddress(pc, GDBStub::BreakpointType::Execute); + //if(bkpt.type != GDBStub::BreakpointType::None && bkpt.address == pc) + //{ + // RecordBreak(bkpt); + //} if (last_bkpt_hit) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit || (num_instructions == 1)) { + if (last_bkpt_hit || (num_instructions == 1 && GDBStub::GetCpuHaltFlag())) { last_bkpt_hit = false; GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 6062de13ce..9561755c07 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -174,6 +174,7 @@ struct Breakpoint { bool active; PAddr addr; u64 len; + u8 old[4]; }; static std::map breakpoints_execute; @@ -449,6 +450,7 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { if (bp != p.end()) { LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", bp->second.len, bp->second.addr, static_cast(type)); + Memory::WriteBlock(bp->second.addr, bp->second.old, 4); p.erase(static_cast(addr)); } } @@ -983,6 +985,9 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { breakpoint.active = true; breakpoint.addr = addr; breakpoint.len = len; + Memory::ReadBlock(addr, breakpoint.old, 4); + static const u8 bkpt0[] = {0xd4, 0x20, 0x00, 0x00}; + Memory::WriteBlock(addr, bkpt0, 4); p.insert({addr, breakpoint}); LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", From ccd787b88ab1cfc6368bb7e0fc97aa66649d86b9 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sun, 22 Jul 2018 21:24:30 +0100 Subject: [PATCH 60/71] Updated externals --- externals/catch | 2 +- externals/dynarmic | 2 +- externals/fmt | 2 +- externals/unicorn | 2 +- externals/xbyak | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/externals/catch b/externals/catch index d2a130f243..797d3b04df 160000 --- a/externals/catch +++ b/externals/catch @@ -1 +1 @@ -Subproject commit d2a130f2433aeaca070e3e4d6298a80049d21cfc +Subproject commit 797d3b04dfab2bcfb4d2da17c6649727c60f49f1 diff --git a/externals/dynarmic b/externals/dynarmic index fc6b73bd85..5213fb670d 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit fc6b73bd855d0b87b6d78ba859732a4616e5a856 +Subproject commit 5213fb670d1391e0ca632ccd1345f9ca6fbe08eb diff --git a/externals/fmt b/externals/fmt index 5859e58ba1..d778bded95 160000 --- a/externals/fmt +++ b/externals/fmt @@ -1 +1 @@ -Subproject commit 5859e58ba17073cf1c16536205450528f3530df0 +Subproject commit d778bded95b08da16067da4d56eb151279985df8 diff --git a/externals/unicorn b/externals/unicorn index 73f4573535..11948dd1cc 160000 --- a/externals/unicorn +++ b/externals/unicorn @@ -1 +1 @@ -Subproject commit 73f45735354396766a4bfb26d0b96b06e5cf31b2 +Subproject commit 11948dd1cc4350bd855ddd0cfdfc93fef33ee67b diff --git a/externals/xbyak b/externals/xbyak index 71b75f653f..2794cde79e 160000 --- a/externals/xbyak +++ b/externals/xbyak @@ -1 +1 @@ -Subproject commit 71b75f653f3858403eb33d48f6346eef34b837fe +Subproject commit 2794cde79eb71e86490061cac9622ad0067b8d15 From c2d6c6a3d439205b03e8c7d764405bd8bca4aaca Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 23 Jul 2018 15:08:25 +0100 Subject: [PATCH 61/71] Interfacing GDBStub with Dynarmic wip. --- externals/dynarmic | 2 +- src/core/arm/dynarmic/arm_dynarmic.cpp | 1 + src/core/arm/unicorn/arm_unicorn.cpp | 42 +++++++++++++++++++++----- src/core/gdbstub/gdbstub.cpp | 8 +++-- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/externals/dynarmic b/externals/dynarmic index fc6b73bd85..5a91c94dca 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit fc6b73bd855d0b87b6d78ba859732a4616e5a856 +Subproject commit 5a91c94dca47c9702dee20fbd5ae1f4c07eef9df diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 83c09db2b6..bb82463522 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -136,6 +136,7 @@ void ARM_Dynarmic::Run() { void ARM_Dynarmic::Step() { cb->InterpreterFallback(jit->GetPC(), 1); + ClearInstructionCache(); } ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr exclusive_monitor, size_t core_index) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index b068ac6191..491349ee2d 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -195,21 +195,49 @@ MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); + //if (GDBStub::IsServerEnabled()) { + // GDBStub::BreakpointAddress bkpt; + // bkpt.address = GetPC(); + // bkpt.type = GDBStub::BreakpointType::Execute; + // u8 opcode[4]; + // Memory::ReadBlock(bkpt.address, opcode, 4); + // static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; + // if (memcmp(opcode, btrap, 4) == 0) { + // if(!last_bkpt_hit) + // { + // LOG_ERROR(Debug_GDBStub, "btrap detected at {:16x}!", bkpt.address); + // RecordBreak(bkpt); + // uc_emu_stop(uc); + // } + // } + //} CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { - //u64 pc = GetPC(); - //GDBStub::BreakpointAddress bkpt = GDBStub::GetNextBreakpointFromAddress(pc, GDBStub::BreakpointType::Execute); - //if(bkpt.type != GDBStub::BreakpointType::None && bkpt.address == pc) - //{ - // RecordBreak(bkpt); - //} if (last_bkpt_hit) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } + //else + //{ + // GDBStub::BreakpointAddress bkpt; + // bkpt.address = GetPC(); + // bkpt.type = GDBStub::BreakpointType::Execute; + // u8 opcode[4]; + // Memory::ReadBlock(bkpt.address, opcode, 4); + // static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; + // if(memcmp(opcode, btrap, 4) == 0) + // { + // if(!last_bkpt_hit) + // { + // LOG_ERROR(Debug_GDBStub, "btrap detected at {:16x}!", bkpt.address); + // RecordBreak(bkpt); + // uc_emu_stop(uc); + // } + // } + //} Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit || (num_instructions == 1 && GDBStub::GetCpuHaltFlag())) { + if (last_bkpt_hit || (num_instructions == 1)) { last_bkpt_hit = false; GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 00d57d110d..033588f1e9 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -31,6 +31,10 @@ #endif #include "common/logging/log.h" +#undef LOG_DEBUG +#undef LOG_INFO +#define LOG_DEBUG LOG_ERROR +#define LOG_INFO LOG_ERROR #include "common/string_util.h" #include "common/swap.h" #include "core/arm/arm_interface.h" @@ -986,8 +990,8 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { breakpoint.addr = addr; breakpoint.len = len; Memory::ReadBlock(addr, breakpoint.old, 4); - static const u8 bkpt0[] = {0xd4, 0x20, 0x00, 0x00}; - Memory::WriteBlock(addr, bkpt0, 4); + static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; + Memory::WriteBlock(addr, btrap, 4); p.insert({addr, breakpoint}); LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", From bf147035c8a5315653b013ea1f8e3a42b1bc7ab2 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Thu, 26 Jul 2018 18:22:53 +0100 Subject: [PATCH 62/71] Invalidate instruction cache on GDB events for Dynarmic --- src/core/arm/dynarmic/arm_dynarmic.cpp | 10 +++++++++- src/core/arm/unicorn/arm_unicorn.cpp | 4 ++-- src/core/core.cpp | 5 +++++ src/core/gdbstub/gdbstub.cpp | 22 ++++++++++++++++++---- src/core/gdbstub/gdbstub.h | 6 ++++++ 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index c52aee1efa..0352d17692 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -10,6 +10,7 @@ #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/memory.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" @@ -131,12 +132,19 @@ std::unique_ptr ARM_Dynarmic::MakeJit() const { void ARM_Dynarmic::Run() { ASSERT(Memory::GetCurrentPageTable() == current_page_table); + if(!GDBStub::GetInstCacheValidity()) + { + ClearInstructionCache(); + } jit->Run(); } void ARM_Dynarmic::Step() { + if(!GDBStub::GetInstCacheValidity()) + { + ClearInstructionCache(); + } cb->InterpreterFallback(jit->GetPC(), 1); - ClearInstructionCache(); } ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr exclusive_monitor, size_t core_index) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 491349ee2d..c5946611f1 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -195,7 +195,7 @@ MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); - //if (GDBStub::IsServerEnabled()) { + // if (GDBStub::IsServerEnabled()) { // GDBStub::BreakpointAddress bkpt; // bkpt.address = GetPC(); // bkpt.type = GDBStub::BreakpointType::Execute; @@ -217,7 +217,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { if (last_bkpt_hit) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } - //else + // else //{ // GDBStub::BreakpointAddress bkpt; // bkpt.address = GetPC(); diff --git a/src/core/core.cpp b/src/core/core.cpp index b7f4b45323..595cf7fa24 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -79,6 +79,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } + if(GDBStub::IsServerEnabled()) + { + GDBStub::SetInstCacheValidity(true); + } + return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 033588f1e9..5b9703a432 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -31,10 +31,10 @@ #endif #include "common/logging/log.h" -#undef LOG_DEBUG -#undef LOG_INFO -#define LOG_DEBUG LOG_ERROR -#define LOG_INFO LOG_ERROR +//#undef LOG_DEBUG +//#undef LOG_INFO +//#define LOG_DEBUG LOG_ERROR +//#define LOG_INFO LOG_ERROR #include "common/string_util.h" #include "common/swap.h" #include "core/arm/arm_interface.h" @@ -165,6 +165,7 @@ static u16 gdbstub_port = 24689; static bool halt_loop = true; static bool step_loop = false; static bool send_trap = false; +static bool inst_cache_valid = true; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. @@ -455,6 +456,7 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", bp->second.len, bp->second.addr, static_cast(type)); Memory::WriteBlock(bp->second.addr, bp->second.old, 4); + GDBStub::SetInstCacheValidity(false); p.erase(static_cast(addr)); } } @@ -938,6 +940,7 @@ static void WriteMemory() { GdbHexToMem(data.data(), len_pos + 1, len); Memory::WriteBlock(addr, data.data(), len); + GDBStub::SetInstCacheValidity(false); SendReply("OK"); } @@ -957,6 +960,7 @@ static void Step() { step_loop = true; halt_loop = true; send_trap = true; + GDBStub::SetInstCacheValidity(false); } /// Tell the CPU if we hit a memory breakpoint. @@ -973,6 +977,7 @@ static void Continue() { memory_break = false; step_loop = false; halt_loop = false; + GDBStub::SetInstCacheValidity(false); } /** @@ -992,6 +997,7 @@ static bool CommitBreakpoint(BreakpointType type, PAddr addr, u64 len) { Memory::ReadBlock(addr, breakpoint.old, 4); static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; Memory::WriteBlock(addr, btrap, 4); + GDBStub::SetInstCacheValidity(false); p.insert({addr, breakpoint}); LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", @@ -1309,4 +1315,12 @@ void SendTrap(Kernel::Thread* thread, int trap) { send_trap = false; } } + +void SetInstCacheValidity(bool validity) { + inst_cache_valid = validity; +} + +bool GetInstCacheValidity() { + return inst_cache_valid; +} }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index a6b50c26cf..40b806125a 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -104,4 +104,10 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); + +/// Set instruction cache validity. +void SetInstCacheValidity(bool validity); + +/// Get instruction cache validity. +bool GetInstCacheValidity(); } // namespace GDBStub From 0017aff7fb55cc4015843dc0bba8c808e34f8757 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Fri, 27 Jul 2018 10:12:40 +0100 Subject: [PATCH 63/71] Use flag rather than instruction count to handle step mode. --- src/core/arm/unicorn/arm_unicorn.cpp | 2 +- src/core/core.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index c5946611f1..8b6da233a2 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -237,7 +237,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { //} Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit || (num_instructions == 1)) { + if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { last_bkpt_hit = false; GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/core.cpp b/src/core/core.cpp index 595cf7fa24..4c6b81ed83 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -63,7 +63,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) { // execute. Otherwise, get out of the loop function. if (GDBStub::GetCpuHaltFlag()) { if (GDBStub::GetCpuStepFlag()) { - GDBStub::SetCpuStepFlag(false); tight_loop = false; } else { return ResultStatus::Success; @@ -81,6 +80,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) { if(GDBStub::IsServerEnabled()) { + GDBStub::SetCpuStepFlag(false); GDBStub::SetInstCacheValidity(true); } From bfcad07dc00bf40623a5f543eeadd9318c169472 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 28 Jul 2018 09:51:15 +0100 Subject: [PATCH 64/71] Enable RomFS for NROs plus some minor formatting. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 6 ++---- src/core/core.cpp | 3 +-- src/core/hle/service/filesystem/filesystem.cpp | 4 ++++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 0352d17692..84fe915205 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -132,16 +132,14 @@ std::unique_ptr ARM_Dynarmic::MakeJit() const { void ARM_Dynarmic::Run() { ASSERT(Memory::GetCurrentPageTable() == current_page_table); - if(!GDBStub::GetInstCacheValidity()) - { + if (!GDBStub::GetInstCacheValidity()) { ClearInstructionCache(); } jit->Run(); } void ARM_Dynarmic::Step() { - if(!GDBStub::GetInstCacheValidity()) - { + if (!GDBStub::GetInstCacheValidity()) { ClearInstructionCache(); } cb->InterpreterFallback(jit->GetPC(), 1); diff --git a/src/core/core.cpp b/src/core/core.cpp index b3245b49b9..828e8795a0 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -78,8 +78,7 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } - if(GDBStub::IsServerEnabled()) - { + if (GDBStub::IsServerEnabled()) { GDBStub::SetCpuStepFlag(false); GDBStub::SetInstCacheValidity(true); } diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index fdd2fda182..b5babee139 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -294,6 +294,10 @@ void RegisterFileSystems() { auto sdcard = std::make_unique(std::move(sd_directory)); sdmc_factory = std::move(sdcard); + + auto romfs = + std::make_unique(Core::System::GetInstance().GetAppLoader()); + romfs_factory = std::move(romfs); } void InstallInterfaces(SM::ServiceManager& service_manager) { From 2c3069f59031b68a58b04411c9dd705d7adbf66d Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sat, 28 Jul 2018 13:18:34 +0100 Subject: [PATCH 65/71] Temporary hack to let app finish even if it is calling unimplemented transaction --- src/core/hle/service/vi/vi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index 993f1e65a2..a1157ce6a7 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp @@ -551,7 +551,7 @@ private: } else if (transaction == TransactionId::CancelBuffer) { LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); } else { - ASSERT_MSG(false, "Unimplemented"); + UNIMPLEMENTED(); } IPC::ResponseBuilder rb{ctx, 2}; From 0321cd69fad7762169e4323cd8e5cdba8e7be2ec Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Sun, 5 Aug 2018 03:02:48 +0100 Subject: [PATCH 66/71] Fix for bad merge --- src/core/arm/dynarmic/arm_dynarmic.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 6cc48be6cf..695f2c2057 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -11,7 +11,6 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/gdbstub/gdbstub.h" -#include "core/hle/kernel/memory.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" From 01095d8f9f7c1b34bd720e8c270dec56ad68de7d Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 6 Aug 2018 12:43:05 +0100 Subject: [PATCH 67/71] Tidy up --- src/core/gdbstub/gdbstub.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 27e82c3c18..8a6f7f1d73 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -31,10 +31,6 @@ #endif #include "common/logging/log.h" -//#undef LOG_DEBUG -//#undef LOG_INFO -//#define LOG_DEBUG LOG_ERROR -//#define LOG_INFO LOG_ERROR #include "common/string_util.h" #include "common/swap.h" #include "core/arm/arm_interface.h" @@ -178,7 +174,7 @@ struct Breakpoint { bool active; VAddr addr; u64 len; - u8 old[4]; + u8 instr[4]; }; using BreakpointMap = std::map; @@ -459,7 +455,7 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) { LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", bp->second.len, bp->second.addr, static_cast(type)); - Memory::WriteBlock(bp->second.addr, bp->second.old, 4); + Memory::WriteBlock(bp->second.addr, bp->second.instr, 4); GDBStub::SetInstCacheValidity(false); p.erase(addr); } @@ -999,7 +995,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.active = true; breakpoint.addr = addr; breakpoint.len = len; - Memory::ReadBlock(addr, breakpoint.old, 4); + Memory::ReadBlock(addr, breakpoint.instr, 4); static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; Memory::WriteBlock(addr, btrap, 4); GDBStub::SetInstCacheValidity(false); From 350870a498867a76b62ebeaac67f561c68d5d8f9 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 6 Aug 2018 13:36:55 +0100 Subject: [PATCH 68/71] GDBStub works with both Unicorn and Dynarmic now --- src/core/arm/dynarmic/arm_dynarmic.cpp | 13 +++++++++++++ src/core/arm/unicorn/arm_unicorn.cpp | 2 +- src/core/core.cpp | 6 +++++- src/core/gdbstub/gdbstub.cpp | 19 +++++++++++++++++++ src/core/gdbstub/gdbstub.h | 6 ++++++ src/yuzu/configuration/configure_debug.ui | 7 ------- 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index ceb3f76835..18faf23226 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -10,6 +10,7 @@ #include "core/arm/dynarmic/arm_dynarmic.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" #include "core/memory.h" @@ -131,10 +132,22 @@ std::unique_ptr ARM_Dynarmic::MakeJit() const { void ARM_Dynarmic::Run() { ASSERT(Memory::GetCurrentPageTable() == current_page_table); + if (GDBStub::IsServerEnabled()) { + if (!GDBStub::GetInstCacheValidity()) { + ClearInstructionCache(); + } + } + jit->Run(); } void ARM_Dynarmic::Step() { + if (GDBStub::IsServerEnabled()) { + if (!GDBStub::GetInstCacheValidity()) { + ClearInstructionCache(); + } + } + cb->InterpreterFallback(jit->GetPC(), 1); } diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 4c11f35a49..6bc3494601 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -203,7 +203,7 @@ void ARM_Unicorn::ExecuteInstructions(int num_instructions) { } Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); - if (last_bkpt_hit || (num_instructions == 1)) { + if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { last_bkpt_hit = false; GDBStub::Break(); GDBStub::SendTrap(thread, 5); diff --git a/src/core/core.cpp b/src/core/core.cpp index e01c45cddc..4ac22e44f6 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -62,7 +62,6 @@ System::ResultStatus System::RunLoop(bool tight_loop) { // execute. Otherwise, get out of the loop function. if (GDBStub::GetCpuHaltFlag()) { if (GDBStub::GetCpuStepFlag()) { - GDBStub::SetCpuStepFlag(false); tight_loop = false; } else { return ResultStatus::Success; @@ -78,6 +77,11 @@ System::ResultStatus System::RunLoop(bool tight_loop) { } } + if (GDBStub::IsServerEnabled()) { + GDBStub::SetCpuStepFlag(false); + GDBStub::SetInstCacheValidity(true); + } + return status; } diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 884e64e994..ba7efb2c01 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -160,6 +160,7 @@ u16 gdbstub_port = 24689; bool halt_loop = true; bool step_loop = false; bool send_trap = false; +static bool inst_cache_valid = true; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. @@ -173,6 +174,7 @@ struct Breakpoint { bool active; VAddr addr; u64 len; + u8 inst[4]; }; using BreakpointMap = std::map; @@ -453,6 +455,8 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) { LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:016X} bytes at {:016X} of type {}", bp->second.len, bp->second.addr, static_cast(type)); + Memory::WriteBlock(bp->second.addr, bp->second.inst, 4); + GDBStub::SetInstCacheValidity(false); p.erase(addr); } @@ -937,6 +941,7 @@ static void WriteMemory() { GdbHexToMem(data.data(), len_pos + 1, len); Memory::WriteBlock(addr, data.data(), len); + GDBStub::SetInstCacheValidity(false); SendReply("OK"); } @@ -956,6 +961,7 @@ static void Step() { step_loop = true; halt_loop = true; send_trap = true; + GDBStub::SetInstCacheValidity(false); } /// Tell the CPU if we hit a memory breakpoint. @@ -972,6 +978,7 @@ static void Continue() { memory_break = false; step_loop = false; halt_loop = false; + GDBStub::SetInstCacheValidity(false); } /** @@ -988,6 +995,10 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { breakpoint.active = true; breakpoint.addr = addr; breakpoint.len = len; + Memory::ReadBlock(addr, breakpoint.inst, 4); + static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; + Memory::WriteBlock(addr, btrap, 4); + GDBStub::SetInstCacheValidity(false); p.insert({addr, breakpoint}); LOG_DEBUG(Debug_GDBStub, "gdb: added {} breakpoint: {:016X} bytes at {:016X}", @@ -1305,4 +1316,12 @@ void SendTrap(Kernel::Thread* thread, int trap) { send_trap = false; } } + +void SetInstCacheValidity(bool validity) { + inst_cache_valid = validity; +} + +bool GetInstCacheValidity() { + return inst_cache_valid; +} }; // namespace GDBStub diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 5a36524b2e..0e516a4af8 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -104,4 +104,10 @@ void SetCpuStepFlag(bool is_step); * @param trap Trap no. */ void SendTrap(Kernel::Thread* thread, int trap); + +/// Set instruction cache validity. +void SetInstCacheValidity(bool validity); + +/// Get instruction cache validity. +bool GetInstCacheValidity(); } // namespace GDBStub diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 118e91cf1b..5ae7276bd2 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui @@ -22,13 +22,6 @@ GDB - - - - The GDB Stub only works correctly when the CPU JIT is off. - - - From adccf27874eba5c09d4794c5bc6cd789593aa846 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 6 Aug 2018 13:42:42 +0100 Subject: [PATCH 69/71] Remove no longer needed static keyword --- src/core/gdbstub/gdbstub.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index ba7efb2c01..9214f48c07 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -160,7 +160,7 @@ u16 gdbstub_port = 24689; bool halt_loop = true; bool step_loop = false; bool send_trap = false; -static bool inst_cache_valid = true; +bool inst_cache_valid = true; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. From 9a3de91a5221c7acd086badc7671313a412a8860 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 6 Aug 2018 16:00:44 +0100 Subject: [PATCH 70/71] Refactor invalidation and check for instruction cache validity as suggested in PR thread --- src/core/arm/dynarmic/arm_dynarmic.cpp | 12 --------- src/core/arm/unicorn/arm_unicorn.cpp | 34 -------------------------- src/core/core.h | 11 +++++++++ src/core/gdbstub/gdbstub.cpp | 7 ++++-- src/core/gdbstub/gdbstub.h | 2 +- 5 files changed, 17 insertions(+), 49 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 18faf23226..73a83f2ef3 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -132,22 +132,10 @@ std::unique_ptr ARM_Dynarmic::MakeJit() const { void ARM_Dynarmic::Run() { ASSERT(Memory::GetCurrentPageTable() == current_page_table); - if (GDBStub::IsServerEnabled()) { - if (!GDBStub::GetInstCacheValidity()) { - ClearInstructionCache(); - } - } - jit->Run(); } void ARM_Dynarmic::Step() { - if (GDBStub::IsServerEnabled()) { - if (!GDBStub::GetInstCacheValidity()) { - ClearInstructionCache(); - } - } - cb->InterpreterFallback(jit->GetPC(), 1); } diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 8b6da233a2..6bc3494601 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -195,46 +195,12 @@ MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64)); void ARM_Unicorn::ExecuteInstructions(int num_instructions) { MICROPROFILE_SCOPE(ARM_Jit); - // if (GDBStub::IsServerEnabled()) { - // GDBStub::BreakpointAddress bkpt; - // bkpt.address = GetPC(); - // bkpt.type = GDBStub::BreakpointType::Execute; - // u8 opcode[4]; - // Memory::ReadBlock(bkpt.address, opcode, 4); - // static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; - // if (memcmp(opcode, btrap, 4) == 0) { - // if(!last_bkpt_hit) - // { - // LOG_ERROR(Debug_GDBStub, "btrap detected at {:16x}!", bkpt.address); - // RecordBreak(bkpt); - // uc_emu_stop(uc); - // } - // } - //} CHECKED(uc_emu_start(uc, GetPC(), 1ULL << 63, 0, num_instructions)); CoreTiming::AddTicks(num_instructions); if (GDBStub::IsServerEnabled()) { if (last_bkpt_hit) { uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); } - // else - //{ - // GDBStub::BreakpointAddress bkpt; - // bkpt.address = GetPC(); - // bkpt.type = GDBStub::BreakpointType::Execute; - // u8 opcode[4]; - // Memory::ReadBlock(bkpt.address, opcode, 4); - // static const u8 btrap[] = {0xd4, 0x20, 0x7d, 0x00}; - // if(memcmp(opcode, btrap, 4) == 0) - // { - // if(!last_bkpt_hit) - // { - // LOG_ERROR(Debug_GDBStub, "btrap detected at {:16x}!", bkpt.address); - // RecordBreak(bkpt); - // uc_emu_stop(uc); - // } - // } - //} Kernel::Thread* thread = Kernel::GetCurrentThread(); SaveContext(thread->context); if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) { diff --git a/src/core/core.h b/src/core/core.h index a3be88aa8a..868f1b7660 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -82,6 +82,17 @@ public: */ ResultStatus SingleStep(); + /** + * Invalidate CPU instruction caches + * This function should only be used by GDBStub which is supposed to keep things + * synch'ed to its internal instruction cache validity flag. + */ + void InvalidateCpuInstructionCaches() { + for (auto& cpu : cpu_cores) { + cpu->ArmInterface().ClearInstructionCache(); + } + } + /// Shutdown the emulated system. void Shutdown(); diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 9214f48c07..3daff2dc32 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -1317,8 +1317,11 @@ void SendTrap(Kernel::Thread* thread, int trap) { } } -void SetInstCacheValidity(bool validity) { - inst_cache_valid = validity; +void SetInstCacheValidity(bool is_valid) { + inst_cache_valid = is_valid; + if (!inst_cache_valid) { + Core::System::GetInstance().InvalidateCpuInstructionCaches(); + } } bool GetInstCacheValidity() { diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 0e516a4af8..ca58392f84 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -106,7 +106,7 @@ void SetCpuStepFlag(bool is_step); void SendTrap(Kernel::Thread* thread, int trap); /// Set instruction cache validity. -void SetInstCacheValidity(bool validity); +void SetInstCacheValidity(bool is_valid); /// Get instruction cache validity. bool GetInstCacheValidity(); From 1f15c33c603040384a8f82b120b1ab019ec0ff38 Mon Sep 17 00:00:00 2001 From: Jarek Syrylak Date: Mon, 6 Aug 2018 16:57:35 +0100 Subject: [PATCH 71/71] Fix typo --- src/core/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core.h b/src/core/core.h index 868f1b7660..677665caec 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -83,7 +83,7 @@ public: ResultStatus SingleStep(); /** - * Invalidate CPU instruction caches + * Invalidate the CPU instruction caches * This function should only be used by GDBStub which is supposed to keep things * synch'ed to its internal instruction cache validity flag. */