mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-18 20:20:05 +00:00
Merge pull request #4127 from FearlessTobi/port-929
Port #929 from yuzu: "gdbstub: Minor changes "
This commit is contained in:
commit
83cc398514
@ -39,36 +39,38 @@
|
|||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/memory.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 = '$';
|
constexpr char GDB_STUB_START = '$';
|
||||||
const char GDB_STUB_END = '#';
|
constexpr char GDB_STUB_END = '#';
|
||||||
const char GDB_STUB_ACK = '+';
|
constexpr char GDB_STUB_ACK = '+';
|
||||||
const char GDB_STUB_NACK = '-';
|
constexpr char GDB_STUB_NACK = '-';
|
||||||
|
|
||||||
#ifndef SIGTRAP
|
#ifndef SIGTRAP
|
||||||
const u32 SIGTRAP = 5;
|
constexpr u32 SIGTRAP = 5;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SIGTERM
|
#ifndef SIGTERM
|
||||||
const u32 SIGTERM = 15;
|
constexpr u32 SIGTERM = 15;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MSG_WAITALL
|
#ifndef MSG_WAITALL
|
||||||
const u32 MSG_WAITALL = 8;
|
constexpr u32 MSG_WAITALL = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const u32 SP_REGISTER = 13;
|
constexpr u32 SP_REGISTER = 13;
|
||||||
const u32 LR_REGISTER = 14;
|
constexpr u32 LR_REGISTER = 14;
|
||||||
const u32 PC_REGISTER = 15;
|
constexpr u32 PC_REGISTER = 15;
|
||||||
const u32 CPSR_REGISTER = 25;
|
constexpr u32 CPSR_REGISTER = 25;
|
||||||
const u32 D0_REGISTER = 26;
|
constexpr u32 D0_REGISTER = 26;
|
||||||
const u32 FPSCR_REGISTER = 42;
|
constexpr u32 FPSCR_REGISTER = 42;
|
||||||
|
|
||||||
// For sample XML files see the GDB source /gdb/features
|
// For sample XML files see the GDB source /gdb/features
|
||||||
// GDB also wants the l character at the start
|
// GDB also wants the l character at the start
|
||||||
// This XML defines what the registers are for this specific ARM device
|
// This XML defines what the registers are for this specific ARM device
|
||||||
static const char* target_xml =
|
constexpr char target_xml[] =
|
||||||
R"(l<?xml version="1.0"?>
|
R"(l<?xml version="1.0"?>
|
||||||
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
<!DOCTYPE target SYSTEM "gdb-target.dtd">
|
||||||
<target version="1.0">
|
<target version="1.0">
|
||||||
@ -118,29 +120,27 @@ static const char* target_xml =
|
|||||||
</target>
|
</target>
|
||||||
)";
|
)";
|
||||||
|
|
||||||
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];
|
u32 latest_signal = 0;
|
||||||
static u32 command_length;
|
bool memory_break = false;
|
||||||
|
|
||||||
static u32 latest_signal = 0;
|
|
||||||
static bool memory_break = false;
|
|
||||||
|
|
||||||
static Kernel::Thread* current_thread = nullptr;
|
static Kernel::Thread* current_thread = nullptr;
|
||||||
|
|
||||||
// Binding to a port within the reserved ports range (0-1023) requires root permissions,
|
// Binding to a port within the reserved ports range (0-1023) requires root permissions,
|
||||||
// so default to a port outside of that range.
|
// so default to a port outside of that range.
|
||||||
static u16 gdbstub_port = 24689;
|
u16 gdbstub_port = 24689;
|
||||||
|
|
||||||
static bool halt_loop = true;
|
bool halt_loop = true;
|
||||||
static bool step_loop = false;
|
bool step_loop = false;
|
||||||
static bool send_trap = false;
|
bool send_trap = false;
|
||||||
|
|
||||||
// If set to false, the server will never be started and no
|
// If set to false, the server will never be started and no
|
||||||
// gdbstub-related functions will be executed.
|
// gdbstub-related functions will be executed.
|
||||||
static std::atomic<bool> server_enabled(false);
|
std::atomic<bool> server_enabled(false);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA InitData;
|
WSADATA InitData;
|
||||||
@ -148,14 +148,16 @@ WSADATA InitData;
|
|||||||
|
|
||||||
struct Breakpoint {
|
struct Breakpoint {
|
||||||
bool active;
|
bool active;
|
||||||
PAddr addr;
|
VAddr addr;
|
||||||
u32 len;
|
u32 len;
|
||||||
std::array<u8, 4> inst;
|
std::array<u8, 4> inst;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::map<u32, Breakpoint> breakpoints_execute;
|
using BreakpointMap = std::map<VAddr, Breakpoint>;
|
||||||
static std::map<u32, Breakpoint> breakpoints_read;
|
BreakpointMap breakpoints_execute;
|
||||||
static std::map<u32, Breakpoint> breakpoints_write;
|
BreakpointMap breakpoints_read;
|
||||||
|
BreakpointMap breakpoints_write;
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
static Kernel::Thread* FindThreadById(int id) {
|
static Kernel::Thread* FindThreadById(int id) {
|
||||||
const auto& threads = Kernel::GetThreadList();
|
const auto& threads = Kernel::GetThreadList();
|
||||||
@ -374,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<u32, Breakpoint>& GetBreakpointList(BreakpointType type) {
|
static BreakpointMap& GetBreakpointMap(BreakpointType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BreakpointType::Execute:
|
case BreakpointType::Execute:
|
||||||
return breakpoints_execute;
|
return breakpoints_execute;
|
||||||
@ -397,22 +399,24 @@ static std::map<u32, Breakpoint>& GetBreakpointList(BreakpointType type) {
|
|||||||
* @param type Type of breakpoint.
|
* @param type Type of breakpoint.
|
||||||
* @param addr Address of breakpoint.
|
* @param addr Address of breakpoint.
|
||||||
*/
|
*/
|
||||||
static void RemoveBreakpoint(BreakpointType type, PAddr addr) {
|
static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
|
||||||
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
|
BreakpointMap& p = GetBreakpointMap(type);
|
||||||
|
|
||||||
auto bp = p.find(addr);
|
const auto bp = p.find(addr);
|
||||||
if (bp != p.end()) {
|
if (bp == p.end()) {
|
||||||
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}\n",
|
return;
|
||||||
bp->second.len, bp->second.addr, static_cast<int>(type));
|
|
||||||
Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
|
|
||||||
Core::CPU().ClearInstructionCache();
|
|
||||||
p.erase(addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}",
|
||||||
|
bp->second.len, bp->second.addr, static_cast<int>(type));
|
||||||
|
Memory::WriteBlock(bp->second.addr, bp->second.inst.data(), bp->second.inst.size());
|
||||||
|
Core::CPU().ClearInstructionCache();
|
||||||
|
p.erase(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) {
|
BreakpointAddress GetNextBreakpointFromAddress(VAddr addr, BreakpointType type) {
|
||||||
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
|
const BreakpointMap& p = GetBreakpointMap(type);
|
||||||
auto next_breakpoint = p.lower_bound(addr);
|
const auto next_breakpoint = p.lower_bound(addr);
|
||||||
BreakpointAddress breakpoint;
|
BreakpointAddress breakpoint;
|
||||||
|
|
||||||
if (next_breakpoint != p.end()) {
|
if (next_breakpoint != p.end()) {
|
||||||
@ -426,35 +430,38 @@ BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type)
|
|||||||
return breakpoint;
|
return breakpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckBreakpoint(PAddr addr, BreakpointType type) {
|
bool CheckBreakpoint(VAddr addr, BreakpointType type) {
|
||||||
if (!IsConnected()) {
|
if (!IsConnected()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<u32, Breakpoint>& p = GetBreakpointList(type);
|
const BreakpointMap& p = GetBreakpointMap(type);
|
||||||
|
const auto bp = p.find(addr);
|
||||||
|
|
||||||
auto bp = p.find(addr);
|
if (bp == p.end()) {
|
||||||
if (bp != p.end()) {
|
return false;
|
||||||
u32 len = bp->second.len;
|
}
|
||||||
|
|
||||||
// IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
|
u32 len = bp->second.len;
|
||||||
// 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)) {
|
// IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints
|
||||||
LOG_DEBUG(Debug_GDBStub,
|
// no matter if it's a 4-byte or 2-byte instruction. When you execute a
|
||||||
"Found breakpoint type {} @ {:08x}, range: {:08x} - {:08x} ({} bytes)\n",
|
// Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on
|
||||||
static_cast<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
|
// two instructions instead of the single instruction you placed the breakpoint
|
||||||
return true;
|
// 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<int>(type), addr, bp->second.addr, bp->second.addr + len, len);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -895,8 +902,8 @@ static void Continue() {
|
|||||||
* @param addr Address of breakpoint.
|
* @param addr Address of breakpoint.
|
||||||
* @param len Length 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<u32, Breakpoint>& p = GetBreakpointList(type);
|
BreakpointMap& p = GetBreakpointMap(type);
|
||||||
|
|
||||||
Breakpoint breakpoint;
|
Breakpoint breakpoint;
|
||||||
breakpoint.active = true;
|
breakpoint.active = true;
|
||||||
@ -939,7 +946,7 @@ static void AddBreakpoint() {
|
|||||||
|
|
||||||
auto start_offset = command_buffer + 3;
|
auto start_offset = command_buffer + 3;
|
||||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||||
|
|
||||||
start_offset = addr_pos + 1;
|
start_offset = addr_pos + 1;
|
||||||
u32 len =
|
u32 len =
|
||||||
@ -988,7 +995,7 @@ static void RemoveBreakpoint() {
|
|||||||
|
|
||||||
auto start_offset = command_buffer + 3;
|
auto start_offset = command_buffer + 3;
|
||||||
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
|
||||||
PAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
VAddr addr = HexToInt(start_offset, static_cast<u32>(addr_pos - start_offset));
|
||||||
|
|
||||||
if (type == BreakpointType::Access) {
|
if (type == BreakpointType::Access) {
|
||||||
// Access is made up of Read and Write types, so add both breakpoints
|
// Access is made up of Read and Write types, so add both breakpoints
|
||||||
|
@ -21,7 +21,7 @@ enum class BreakpointType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BreakpointAddress {
|
struct BreakpointAddress {
|
||||||
PAddr address;
|
VAddr address;
|
||||||
BreakpointType type;
|
BreakpointType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,7 +70,7 @@ void HandlePacket();
|
|||||||
* @param addr Address to search from.
|
* @param addr Address to search from.
|
||||||
* @param type Type of breakpoint.
|
* @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.
|
* 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 addr Address of breakpoint.
|
||||||
* @param type Type 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.
|
// If set to true, the CPU will halt at the beginning of the next CPU loop.
|
||||||
bool GetCpuHaltFlag();
|
bool GetCpuHaltFlag();
|
||||||
|
Loading…
Reference in New Issue
Block a user