summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorGravatarGravatar Ramiro Polla <ramiropolla@users.noreply.github.com>2019-08-31 22:34:59 +0200
committerGravatarGravatar R. Belmont <rb6502@users.noreply.github.com>2019-08-31 16:34:59 -0400
commitdeee2ce861609cedc675b90d43147f74fe33e9bd (patch)
tree7e539b6b870782d59c367cadbb1911c232745173
parentd673a392f177ba6ee8889493ae6c5c7d4e5271a4 (diff)
gdbstub: more improvements (#5569)
* gdbstub: small cleanup and clarification Old GDBs expected the regnum values for some registers to be hardcoded. This is no longer the case with GDB clients that support target.xml. We expect the GDB client to support target.xml (and won't support the 'g', 'G', 'p', and 'P' commands unless it is sent). * gdbstub: add mips (tested with indy_4610) * gdbstub: add m68k (tested with macii) * gdbstub: add support for executing MAME debugger commands from the GDB client It's now possible to send MAME debugger commands, such as "cheatinit", "snap", etc... Try not to use "bpset" and such commands, they may confuse the GDB client. Also don't use commands such as "step" and "go", they will definitely confuse the GDB client. * gdbstub: fatalerror() when socket can't be opened
-rw-r--r--src/osd/modules/debugger/debuggdbstub.cpp184
1 files changed, 155 insertions, 29 deletions
diff --git a/src/osd/modules/debugger/debuggdbstub.cpp b/src/osd/modules/debugger/debuggdbstub.cpp
index 1787d3857a6..4028dd3b994 100644
--- a/src/osd/modules/debugger/debuggdbstub.cpp
+++ b/src/osd/modules/debugger/debuggdbstub.cpp
@@ -7,7 +7,9 @@
//============================================================
#include "emu.h"
+#include "debug/debugcon.h"
#include "debug/debugcpu.h"
+#include "debug/textbuf.h"
#include "debug_module.h"
#include "debugger.h"
#include "modules/lib/osdobj_common.h"
@@ -42,6 +44,16 @@ struct gdb_register_map
const char *gdb_name;
bool stop_packet;
gdb_register_type gdb_type;
+ int override_bitsize;
+
+ gdb_register_description(const char *_state_name=nullptr, const char *_gdb_name=nullptr, bool _stop_packet=false, gdb_register_type _gdb_type=TYPE_INT, int _override_bitsize=-1)
+ : state_name(_state_name)
+ , gdb_name(_gdb_name)
+ , stop_packet(_stop_packet)
+ , gdb_type(_gdb_type)
+ , override_bitsize(_override_bitsize)
+ {
+ }
};
std::vector<gdb_register_description> registers;
};
@@ -167,6 +179,77 @@ static const gdb_register_map gdb_register_map_ppc601 =
};
//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_r4600 =
+{
+ "mips",
+ "org.gnu.gdb.mips.cpu",
+ {
+ { "zero", "r0", false, TYPE_INT, 32 },
+ { "at", "r1", false, TYPE_INT, 32 },
+ { "v0", "r2", false, TYPE_INT, 32 },
+ { "v1", "r3", false, TYPE_INT, 32 },
+ { "a0", "r4", false, TYPE_INT, 32 },
+ { "a1", "r5", false, TYPE_INT, 32 },
+ { "a2", "r6", false, TYPE_INT, 32 },
+ { "a3", "r7", false, TYPE_INT, 32 },
+ { "t0", "r8", false, TYPE_INT, 32 },
+ { "t1", "r9", false, TYPE_INT, 32 },
+ { "t2", "r10", false, TYPE_INT, 32 },
+ { "t3", "r11", false, TYPE_INT, 32 },
+ { "t4", "r12", false, TYPE_INT, 32 },
+ { "t5", "r13", false, TYPE_INT, 32 },
+ { "t6", "r14", false, TYPE_INT, 32 },
+ { "t7", "r15", false, TYPE_INT, 32 },
+ { "s0", "r16", false, TYPE_INT, 32 },
+ { "s1", "r17", false, TYPE_INT, 32 },
+ { "s2", "r18", false, TYPE_INT, 32 },
+ { "s3", "r19", false, TYPE_INT, 32 },
+ { "s4", "r20", false, TYPE_INT, 32 },
+ { "s5", "r21", false, TYPE_INT, 32 },
+ { "s6", "r22", false, TYPE_INT, 32 },
+ { "s7", "r23", false, TYPE_INT, 32 },
+ { "t8", "r24", false, TYPE_INT, 32 },
+ { "t9", "r25", false, TYPE_INT, 32 },
+ { "k0", "r26", false, TYPE_INT, 32 },
+ { "k1", "r27", false, TYPE_INT, 32 },
+ { "gp", "r28", false, TYPE_INT, 32 },
+ { "sp", "r29", false, TYPE_INT, 32 },
+ { "fp", "r30", false, TYPE_INT, 32 },
+ { "ra", "r31", false, TYPE_INT, 32 },
+ { "LO", "lo", false, TYPE_INT, 32 },
+ { "HI", "hi", false, TYPE_INT, 32 },
+ { "PC", "pc", true, TYPE_CODE_POINTER, 32 },
+ }
+};
+
+//-------------------------------------------------------------------------
+static const gdb_register_map gdb_register_map_m68020pmmu =
+{
+ "m68k",
+ "org.gnu.gdb.m68k.core",
+ {
+ { "D0", "d0", false, TYPE_INT },
+ { "D1", "d1", false, TYPE_INT },
+ { "D2", "d2", false, TYPE_INT },
+ { "D3", "d3", false, TYPE_INT },
+ { "D4", "d4", false, TYPE_INT },
+ { "D5", "d5", false, TYPE_INT },
+ { "D6", "d6", false, TYPE_INT },
+ { "D7", "d7", false, TYPE_INT },
+ { "A0", "a0", false, TYPE_INT },
+ { "A1", "a1", false, TYPE_INT },
+ { "A2", "a2", false, TYPE_INT },
+ { "A3", "a3", false, TYPE_INT },
+ { "A4", "a4", false, TYPE_INT },
+ { "A5", "a5", false, TYPE_INT },
+ { "A6", "fp", true, TYPE_INT },
+ { "A7", "sp", true, TYPE_INT },
+ { "SR", "ps", false, TYPE_INT }, // NOTE GDB named it ps, but it's actually sr
+ { "PC", "pc", true, TYPE_CODE_POINTER },
+ }
+};
+
+//-------------------------------------------------------------------------
static const gdb_register_map gdb_register_map_z80 =
{
"z80",
@@ -204,11 +287,13 @@ static const gdb_register_map gdb_register_map_m6502 =
//-------------------------------------------------------------------------
static const std::map<std::string, const gdb_register_map &> gdb_register_maps = {
- { "i486", gdb_register_map_i486 },
- { "arm7_le", gdb_register_map_arm7 },
- { "ppc601", gdb_register_map_ppc601 },
- { "z80", gdb_register_map_z80 },
- { "m6502", gdb_register_map_m6502 },
+ { "i486", gdb_register_map_i486 },
+ { "arm7_le", gdb_register_map_arm7 },
+ { "r4600", gdb_register_map_r4600 },
+ { "ppc601", gdb_register_map_ppc601 },
+ { "m68020pmmu", gdb_register_map_m68020pmmu },
+ { "z80", gdb_register_map_z80 },
+ { "m6502", gdb_register_map_m6502 },
};
//-------------------------------------------------------------------------
@@ -223,6 +308,7 @@ public:
m_memory(nullptr),
m_address_space(nullptr),
m_debugger_cpu(nullptr),
+ m_debugger_console(nullptr),
m_debugger_port(0),
m_socket(OPEN_FLAG_WRITE | OPEN_FLAG_CREATE),
m_is_be(false),
@@ -315,6 +401,7 @@ private:
device_memory_interface *m_memory;
address_space *m_address_space;
debugger_cpu *m_debugger_cpu;
+ debugger_console *m_debugger_console;
int m_debugger_port;
emu_file m_socket;
bool m_is_be;
@@ -322,7 +409,7 @@ private:
bool m_dettached;
bool m_extended_mode;
bool m_send_stop_packet;
- bool m_target_xml_sent;
+ bool m_target_xml_sent; // the 'g', 'G', 'p', and 'P' commands only work once target.xml has been sent
struct gdb_register
{
@@ -369,14 +456,7 @@ void debug_gdbstub::exit(void)
//-------------------------------------------------------------------------
void debug_gdbstub::init_debugger(running_machine &machine)
{
- std::string socket_name = string_format("socket.localhost:%d", m_debugger_port);
- osd_file::error filerr = m_socket.open(socket_name.c_str());
- if ( filerr != osd_file::error::NONE )
- return;
-
m_machine = &machine;
-
- osd_printf_info("gdbstub: listening on port %d\n", m_debugger_port);
}
//-------------------------------------------------------------------------
@@ -419,6 +499,8 @@ static std::string escape_packet(const std::string src)
//-------------------------------------------------------------------------
void debug_gdbstub::generate_target_xml(void)
{
+ // Note: we do not attempt to replicate the regnum values from old
+ // GDB clients that did not support target.xml.
std::string target_xml;
target_xml += "<?xml version=\"1.0\"?>\n";
target_xml += "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n";
@@ -426,8 +508,7 @@ void debug_gdbstub::generate_target_xml(void)
target_xml += string_format("<architecture>%s</architecture>\n", m_gdb_arch.c_str());
target_xml += string_format(" <feature name=\"%s\">\n", m_gdb_feature.c_str());
for ( const auto &reg: m_gdb_registers )
- if ( !reg.gdb_name.empty() )
- target_xml += string_format(" <reg name=\"%s\" bitsize=\"%d\" type=\"%s\"/>\n", reg.gdb_name.c_str(), reg.gdb_bitsize, gdb_register_type_str[reg.gdb_type]);
+ target_xml += string_format(" <reg name=\"%s\" bitsize=\"%d\" type=\"%s\"/>\n", reg.gdb_name.c_str(), reg.gdb_bitsize, gdb_register_type_str[reg.gdb_type]);
target_xml += " </feature>\n";
target_xml += "</target>\n";
m_target_xml = escape_packet(target_xml);
@@ -451,6 +532,7 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
m_memory = &m_maincpu->memory();
m_address_space = &m_memory->space(AS_PROGRAM);
m_debugger_cpu = &m_machine->debugger().cpu();
+ m_debugger_console = &m_machine->debugger().console();
m_is_be = m_address_space->endianness() == ENDIANNESS_BIG;
@@ -482,7 +564,10 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
new_reg.gdb_name = reg.gdb_name;
new_reg.gdb_regnum = cur_gdb_regnum;
new_reg.gdb_type = reg.gdb_type;
- new_reg.gdb_bitsize = entry->datasize() * 8;
+ if ( reg.override_bitsize != -1 )
+ new_reg.gdb_bitsize = reg.override_bitsize;
+ else
+ new_reg.gdb_bitsize = entry->datasize() * 8;
new_reg.state_index = entry->index();
m_gdb_registers.push_back(std::move(new_reg));
if ( reg.stop_packet )
@@ -498,10 +583,15 @@ void debug_gdbstub::wait_for_debugger(device_t &device, bool firststop)
#if 0
for ( const auto &reg: m_gdb_registers )
- if ( !reg.gdb_name.empty() )
- osd_printf_info(" %3d (%d) %d %d [%s]\n", reg.gdb_regnum, reg.state_index, reg.gdb_bitsize, reg.gdb_type, reg.gdb_name.c_str());
+ osd_printf_info(" %3d (%d) %d %d [%s]\n", reg.gdb_regnum, reg.state_index, reg.gdb_bitsize, reg.gdb_type, reg.gdb_name.c_str());
#endif
+ std::string socket_name = string_format("socket.localhost:%d", m_debugger_port);
+ osd_file::error filerr = m_socket.open(socket_name.c_str());
+ if ( filerr != osd_file::error::NONE )
+ fatalerror("gdbstub: failed to start listening on port %d\n", m_debugger_port);
+ osd_printf_info("gdbstub: listening on port %d\n", m_debugger_port);
+
m_initialized = true;
}
else
@@ -622,8 +712,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_g(const char *buf)
return REPLY_UNSUPPORTED;
std::string reply;
for ( const auto &reg: m_gdb_registers )
- if ( !reg.gdb_name.empty() )
- reply += get_register_string(reg.gdb_regnum);
+ reply += get_register_string(reg.gdb_regnum);
send_reply(reply.c_str());
return REPLY_NONE;
}
@@ -698,6 +787,22 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_m(const char *buf)
}
//-------------------------------------------------------------------------
+static bool hex_decode(std::vector<uint8_t> *_data, const char *buf, size_t length)
+{
+ std::vector<uint8_t> &data = *_data;
+ data.resize(length);
+ for ( int i = 0; i < length; i++ )
+ {
+ if ( sscanf(buf, "%02hhx", &data[i]) != 1 )
+ return false;
+ buf += 2;
+ }
+ if ( *buf != '\0' )
+ return false;
+ return true;
+}
+
+//-------------------------------------------------------------------------
// Write memory.
debug_gdbstub::cmd_reply debug_gdbstub::handle_M(const char *buf)
{
@@ -712,15 +817,7 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_M(const char *buf)
return REPLY_ENN;
std::vector<uint8_t> data;
- data.reserve(length);
- buf += buf_offset;
- for ( int i = 0; i < length; i++ )
- {
- if ( sscanf(buf, "%02hhx", &data[i]) != 1 )
- return REPLY_ENN;
- buf += 2;
- }
- if ( *buf != '\0' )
+ if ( !hex_decode(&data, buf + buf_offset, length) )
return REPLY_ENN;
for ( int i = 0; i < length; i++ )
@@ -783,6 +880,33 @@ debug_gdbstub::cmd_reply debug_gdbstub::handle_q(const char *buf)
return REPLY_UNSUPPORTED;
}
+ // Check packets that use qname,params convention.
+ if ( strncmp(buf, "Rcmd,", 5) == 0 )
+ {
+ buf += 5;
+ std::vector<uint8_t> data;
+ if ( !hex_decode(&data, buf, strlen(buf) / 2) )
+ return REPLY_ENN;
+ std::string command(data.begin(), data.end());
+ text_buffer *textbuf = m_debugger_console->get_console_textbuf();
+ text_buffer_clear(textbuf);
+ m_debugger_console->execute_command(command, false);
+ uint32_t nlines = text_buffer_num_lines(textbuf);
+ if ( nlines == 0 )
+ return REPLY_OK;
+ std::string reply;
+ for ( uint32_t i = 0; i < nlines; i++ )
+ {
+ const char *line = text_buffer_get_seqnum_line(textbuf, i);
+ reply.reserve(reply.length() + (strlen(line)+1)*2);
+ while ( *line != '\0' )
+ reply += string_format("%02x", *line++);
+ reply += "0A";
+ }
+ send_reply(reply.c_str());
+ return REPLY_NONE;
+ }
+
// Split name and parameters
const char *ptr = buf;
while ( *ptr != '\0' && *ptr != ':' )
@@ -1060,6 +1184,8 @@ std::string debug_gdbstub::get_register_string(int gdb_regnum)
: (reg.gdb_bitsize == 16) ? "%04" PRIx64
: "%02" PRIx64;
uint64_t value = m_state->state_int(reg.state_index);
+ if ( reg.gdb_bitsize < 64 )
+ value &= (1ULL << reg.gdb_bitsize) - 1;
if ( !m_is_be )
{
value = (reg.gdb_bitsize == 64) ? BYTESWAP_64(value)