diff options
-rw-r--r-- | src/osd/modules/debugger/debuggdbstub.cpp | 184 |
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 ®: 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 ®: 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 ®: 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) |