From db8ec37066e68c114b6e639a4b58cd5fe527c6d0 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 5 Aug 2018 15:55:57 -0400 Subject: [PATCH 1/4] gdbstub: Replace PAddr alias with VAddr In all cases, a virtual address is being passed in, not a physical one. --- src/core/gdbstub/gdbstub.cpp | 14 +++++++------- src/core/gdbstub/gdbstub.h | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 007f0688c..76902f467 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -148,7 +148,7 @@ WSADATA InitData; struct Breakpoint { bool active; - PAddr addr; + VAddr addr; u32 len; std::array inst; }; @@ -397,7 +397,7 @@ static std::map& GetBreakpointList(BreakpointType type) { * @param type Type of breakpoint. * @param addr Address of breakpoint. */ -static void RemoveBreakpoint(BreakpointType type, PAddr addr) { +static void RemoveBreakpoint(BreakpointType type, VAddr addr) { std::map& p = GetBreakpointList(type); auto bp = p.find(addr); @@ -410,7 +410,7 @@ static void RemoveBreakpoint(BreakpointType type, PAddr addr) { } } -BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) { +BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) { std::map& p = GetBreakpointList(type); auto next_breakpoint = p.lower_bound(addr); BreakpointAddress breakpoint; @@ -426,7 +426,7 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) return breakpoint; } -bool CheckBreakpoint(PAddr addr, BreakpointType type) { +bool CheckBreakpoint(VAddr addr, BreakpointType type) { if (!IsConnected()) { return false; } @@ -895,7 +895,7 @@ static void Continue() { * @param addr Address of breakpoint. * @param len Length of breakpoint. */ -static bool CommitBreakpoint(BreakpointType type, PAddr addr, u32 len) { +static bool CommitBreakpoint(BreakpointType type, VAddr addr, u32 len) { std::map& p = GetBreakpointList(type); Breakpoint breakpoint; @@ -939,7 +939,7 @@ static void AddBreakpoint() { auto start_offset = command_buffer + 3; auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); - PAddr addr = HexToInt(start_offset, static_cast(addr_pos - start_offset)); + VAddr addr = HexToInt(start_offset, static_cast(addr_pos - start_offset)); start_offset = addr_pos + 1; u32 len = @@ -988,7 +988,7 @@ static void RemoveBreakpoint() { auto start_offset = command_buffer + 3; auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); - PAddr addr = HexToInt(start_offset, static_cast(addr_pos - start_offset)); + VAddr addr = HexToInt(start_offset, static_cast(addr_pos - start_offset)); if (type == BreakpointType::Access) { // Access is made up of Read and Write types, so add both breakpoints diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h index 7f19fd33f..131b3f823 100644 --- a/src/core/gdbstub/gdbstub.h +++ b/src/core/gdbstub/gdbstub.h @@ -21,7 +21,7 @@ enum class BreakpointType { }; struct BreakpointAddress { - PAddr address; + VAddr address; BreakpointType type; }; @@ -70,7 +70,7 @@ void HandlePacket(); * @param addr Address to search from. * @param type Type of breakpoint. */ -BreakpointAddress GetNextBreakpointFromAddress(u32 addr, GDBStub::BreakpointType type); +BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, GDBStub::BreakpointType type); /** * Check if a breakpoint of the specified type exists at the given address. @@ -78,7 +78,7 @@ BreakpointAddress GetNextBreakpointFromAddress(u32 addr, GDBStub::BreakpointType * @param addr Address of breakpoint. * @param type Type of breakpoint. */ -bool CheckBreakpoint(u32 addr, GDBStub::BreakpointType type); +bool CheckBreakpoint(VAddr addr, GDBStub::BreakpointType type); // If set to true, the CPU will halt at the beginning of the next CPU loop. bool GetCpuHaltFlag(); From 8a109333b78457ba9f3903c56c1df28992ccd77f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 5 Aug 2018 15:59:53 -0400 Subject: [PATCH 2/4] gdbstub: Move all file-static variables into the GDBStub namespace Keeps everything under the same namespace. While we're at it, enclose them all within an inner anonymous namespace --- src/core/gdbstub/gdbstub.cpp | 62 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 76902f467..58b84c434 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -39,36 +39,38 @@ #include "core/loader/loader.h" #include "core/memory.h" -const int GDB_BUFFER_SIZE = 10000; +namespace GDBStub { +namespace { +constexpr int GDB_BUFFER_SIZE = 10000; -const char GDB_STUB_START = '$'; -const char GDB_STUB_END = '#'; -const char GDB_STUB_ACK = '+'; -const char GDB_STUB_NACK = '-'; +constexpr char GDB_STUB_START = '$'; +constexpr char GDB_STUB_END = '#'; +constexpr char GDB_STUB_ACK = '+'; +constexpr char GDB_STUB_NACK = '-'; #ifndef SIGTRAP -const u32 SIGTRAP = 5; +constexpr u32 SIGTRAP = 5; #endif #ifndef SIGTERM -const u32 SIGTERM = 15; +constexpr u32 SIGTERM = 15; #endif #ifndef MSG_WAITALL -const u32 MSG_WAITALL = 8; +constexpr u32 MSG_WAITALL = 8; #endif -const u32 SP_REGISTER = 13; -const u32 LR_REGISTER = 14; -const u32 PC_REGISTER = 15; -const u32 CPSR_REGISTER = 25; -const u32 D0_REGISTER = 26; -const u32 FPSCR_REGISTER = 42; +constexpr u32 SP_REGISTER = 13; +constexpr u32 LR_REGISTER = 14; +constexpr u32 PC_REGISTER = 15; +constexpr u32 CPSR_REGISTER = 25; +constexpr u32 D0_REGISTER = 26; +constexpr u32 FPSCR_REGISTER = 42; // 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 -static const char* target_xml = +constexpr char target_xml[] = R"(l @@ -118,29 +120,27 @@ static const char* target_xml = )"; -namespace GDBStub { +int gdbserver_socket = -1; -static int gdbserver_socket = -1; +u8 command_buffer[GDB_BUFFER_SIZE]; +u32 command_length; -static u8 command_buffer[GDB_BUFFER_SIZE]; -static u32 command_length; - -static u32 latest_signal = 0; -static bool memory_break = false; +u32 latest_signal = 0; +bool memory_break = false; 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. -static u16 gdbstub_port = 24689; +u16 gdbstub_port = 24689; -static bool halt_loop = true; -static bool step_loop = false; -static bool send_trap = false; +bool halt_loop = true; +bool step_loop = false; +bool send_trap = false; // If set to false, the server will never be started and no // gdbstub-related functions will be executed. -static std::atomic server_enabled(false); +std::atomic server_enabled(false); #ifdef _WIN32 WSADATA InitData; @@ -153,9 +153,11 @@ struct Breakpoint { std::array inst; }; -static std::map breakpoints_execute; -static std::map breakpoints_read; -static std::map breakpoints_write; +std::map breakpoints_execute; +std::map breakpoints_read; +std::map breakpoints_write; + +} // Anonymous namespace static Kernel::Thread* FindThreadById(int id) { const auto& threads = Kernel::GetThreadList(); From 80f1ffd8dc9f64cdbb3dcbd070a688ffd4699840 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Fri, 24 Aug 2018 15:45:19 +0200 Subject: [PATCH 3/4] Remove newline --- src/core/gdbstub/gdbstub.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 58b84c434..ce2351d7e 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -156,7 +156,6 @@ struct Breakpoint { std::map breakpoints_execute; std::map breakpoints_read; std::map breakpoints_write; - } // Anonymous namespace static Kernel::Thread* FindThreadById(int id) { From 91559bfdfe135789eb4a40d4d98ade8c7f10b89f Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sun, 5 Aug 2018 16:11:29 -0400 Subject: [PATCH 4/4] gdbstub: Use type alias for breakpoint maps Rather than having to type out the full std::map type signature, we can just use a straightforward alias. While we're at it, rename GetBreakpointList to GetBreakpointMap, which makes the name more accurate. We can also get rid of unnecessary u64 static_casts, since VAddr is an alias for a u64. --- src/core/gdbstub/gdbstub.cpp | 82 +++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index ce2351d7e..557c65ed2 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -153,9 +153,10 @@ struct Breakpoint { std::array inst; }; -std::map breakpoints_execute; -std::map breakpoints_read; -std::map breakpoints_write; +using BreakpointMap = std::map; +BreakpointMap breakpoints_execute; +BreakpointMap breakpoints_read; +BreakpointMap breakpoints_write; } // Anonymous namespace static Kernel::Thread* FindThreadById(int id) { @@ -375,11 +376,11 @@ static u8 CalculateChecksum(const u8* buffer, size_t length) { } /** - * Get the list of breakpoints for a given breakpoint type. + * Get the map of breakpoints for a given breakpoint type. * - * @param type Type of breakpoint list. + * @param type Type of breakpoint map. */ -static std::map& GetBreakpointList(BreakpointType type) { +static BreakpointMap& GetBreakpointMap(BreakpointType type) { switch (type) { case BreakpointType::Execute: return breakpoints_execute; @@ -399,21 +400,23 @@ static std::map& GetBreakpointList(BreakpointType type) { * @param addr Address of breakpoint. */ static void RemoveBreakpoint(BreakpointType type, VAddr addr) { - std::map& p = GetBreakpointList(type); + BreakpointMap& p = GetBreakpointMap(type); - auto bp = p.find(addr); - if (bp != p.end()) { - LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}\n", - bp->second.len, bp->second.addr, static_cast(type)); - Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); - Core::CPU().ClearInstructionCache(); - p.erase(addr); + const auto bp = p.find(addr); + if (bp == p.end()) { + return; } + + LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}", + bp->second.len, bp->second.addr, static_cast(type)); + Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size()); + Core::CPU().ClearInstructionCache(); + p.erase(addr); } BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) { - std::map& p = GetBreakpointList(type); - auto next_breakpoint = p.lower_bound(addr); + const BreakpointMap& p = GetBreakpointMap(type); + const auto next_breakpoint = p.lower_bound(addr); BreakpointAddress breakpoint; if (next_breakpoint != p.end()) { @@ -432,30 +435,33 @@ bool CheckBreakpoint(VAddr addr, BreakpointType type) { return false; } - std::map& p = GetBreakpointList(type); + const BreakpointMap& p = GetBreakpointMap(type); + const auto bp = p.find(addr); - auto bp = p.find(addr); - if (bp != p.end()) { - u32 len = bp->second.len; + if (bp == p.end()) { + return false; + } - // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints - // no matter if it's a 4-byte or 2-byte instruction. When you execute a - // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on - // two instructions instead of the single instruction you placed the breakpoint - // on. So, as a way to make sure that execution breakpoints are only breaking - // on the instruction that was specified, set the length of an execution - // breakpoint to 1. This should be fine since the CPU should never begin executing - // an instruction anywhere except the beginning of the instruction. - if (type == BreakpointType::Execute) { - len = 1; - } + u32 len = bp->second.len; - if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { - LOG_DEBUG(Debug_GDBStub, - "Found breakpoint type {} @ {:08x}, range: {:08x} - {:08x} ({} bytes)\n", - static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); - return true; - } + // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints + // no matter if it's a 4-byte or 2-byte instruction. When you execute a + // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on + // two instructions instead of the single instruction you placed the breakpoint + // on. So, as a way to make sure that execution breakpoints are only breaking + // on the instruction that was specified, set the length of an execution + // breakpoint to 1. This should be fine since the CPU should never begin executing + // an instruction anywhere except the beginning of the instruction. + if (type == BreakpointType::Execute) { + len = 1; + } + + if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { + LOG_DEBUG(Debug_GDBStub, + "Found breakpoint type {} @ {:08x}, range: {:08x}" + " - {:08x} ({:x} bytes)", + static_cast(type), addr, bp->second.addr, bp->second.addr + len, len); + return true; } return false; @@ -897,7 +903,7 @@ static void Continue() { * @param len Length of breakpoint. */ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u32 len) { - std::map& p = GetBreakpointList(type); + BreakpointMap& p = GetBreakpointMap(type); Breakpoint breakpoint; breakpoint.active = true;