From 0b0ae3586c50c110dad12cc04c029106e5f2eeb5 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sun, 25 Sep 2022 21:13:36 +0300 Subject: Break execution on bus fault, support GDB NoAck mode --- bus.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++--------- emulator.cpp | 77 ++++++++------------------------- gdbremote_parser.cpp | 5 +++ gdbremote_parser.hpp | 3 ++ 4 files changed, 124 insertions(+), 80 deletions(-) diff --git a/bus.cpp b/bus.cpp index f611eba..df44164 100644 --- a/bus.cpp +++ b/bus.cpp @@ -26,10 +26,6 @@ std::vector code_bkpts{}, read_bkpts{}, write_bkpts{}, access_bkpts{ static void exit_error(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); static bool in_error = false; if (in_error) { @@ -37,14 +33,35 @@ static void exit_error(const char* fmt, ...) return; } in_error = true; + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); fprintf(stderr, "\n"); unsigned int pc = m68k_get_reg(NULL, M68K_REG_PPC); - char buff[100]; + char buff[100]{}; m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000); fprintf(stderr, "%08x: %s\n", pc, buff); exit(EXIT_FAILURE); } +static void report_error(const char* fmt, ...) +{ + static bool in_error = false; + if (in_error) + return; + in_error = true; + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + unsigned int pc = m68k_get_reg(NULL, M68K_REG_PPC); + char buff[100]{}; + m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000); + fprintf(stderr, "%08x: %s\n", pc, buff); +} + static inline bool is_in_range(uint32_t value, uint32_t begin, uint32_t length) { return value >= begin && value <= begin + length; @@ -167,18 +184,68 @@ static inline bool memory_write( return false; } +static inline bool ranges_overlap( + const uint32_t a_start, + const uint32_t a_len, + const uint32_t b_start, + const uint32_t b_len) +{ + return (a_start < b_start + b_len && b_start < a_start + a_len); +} + +extern void m68k_breakpoint_callback(void); + #define MASK_24(X) ((X) & (0xFF << 24)) -extern void m68k_read_callback(const uint32_t address, const uint32_t size); -extern void m68k_write_callback(const uint32_t address, const uint32_t size); +static void m68k_read_callback(const uint32_t address, const uint32_t size) +{ + const auto access_it = std::find_if( + access_bkpts.begin(), + access_bkpts.end(), + [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); + if (access_it != access_bkpts.end()) { + m68k_breakpoint_callback(); + printf("Access watchpoint @ 0x%08x\n", address); + } + const auto it = std::find_if( + read_bkpts.begin(), + read_bkpts.end(), + [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); + if (it != read_bkpts.end()) { + m68k_breakpoint_callback(); + printf("Read watchpoint @ 0x%08x\n", address); + } +} + +static void m68k_write_callback(const uint32_t address, const uint32_t size) +{ + const auto access_it = std::find_if( + access_bkpts.begin(), + access_bkpts.end(), + [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); + if (access_it != access_bkpts.end()) { + m68k_breakpoint_callback(); + printf("Access watchpoint @ 0x%08x\n", address); + } + const auto it = std::find_if( + write_bkpts.begin(), + write_bkpts.end(), + [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); + if (it != write_bkpts.end()) { + m68k_breakpoint_callback(); + printf("Write watchpoint @ 0x%08x\n", address); + } +} unsigned int m68k_read_memory_8(unsigned int address) { assert(MASK_24(address) == 0); // Just curious m68k_read_callback(address, 4); const struct read_result ret = memory_read(BITNESS_8, address); - if (!ret.successful) - exit_error("Read error u8 @%08x", address); + if (!ret.successful) { + m68k_breakpoint_callback(); + report_error("Read error u8 @%08x", address); + } return ret.result; } @@ -187,8 +254,10 @@ unsigned int m68k_read_memory_16(unsigned int address) m68k_read_callback(address, 2); assert(MASK_24(address) == 0); // Just curious const struct read_result ret = memory_read(BITNESS_16, address); - if (!ret.successful) - exit_error("Read error u16 @%08x", address); + if (!ret.successful) { + m68k_breakpoint_callback(); + report_error("Read error u16 @%08x", address); + } return ret.result; } @@ -197,8 +266,10 @@ unsigned int m68k_read_memory_32(unsigned int address) m68k_read_callback(address, 1); assert(MASK_24(address) == 0); // Just curious const struct read_result ret = memory_read(BITNESS_32, address); - if (!ret.successful) - exit_error("Read error u32 @%08x", address); + if (!ret.successful) { + m68k_breakpoint_callback(); + report_error("Read error u32 @%08x", address); + } return ret.result; } @@ -206,7 +277,7 @@ unsigned int m68k_read_disassembler_16(unsigned int address) { assert(MASK_24(address) == 0); // Just curious const struct read_result ret = memory_read(BITNESS_16, address); - if (!ret.successful) + if (0 && !ret.successful) exit_error("Disasm read error u16 @0x%08x", address); return ret.result; } @@ -215,7 +286,7 @@ unsigned int m68k_read_disassembler_32(unsigned int address) { assert(MASK_24(address) == 0); // Just curious const struct read_result ret = memory_read(BITNESS_32, address); - if (!ret.successful) + if (0 && !ret.successful) exit_error("Disasm read error u32 @0x%08x", address); return ret.result; } @@ -225,8 +296,10 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) assert(MASK_24(address) == 0); // Just curious m68k_write_callback(address, 1); const bool successful = memory_write(BITNESS_8, address, value); - if (!successful) - exit_error("Attempted to write 0x%02x (u8) to address %08x", value&0xff, address); + if (!successful) { + m68k_breakpoint_callback(); + report_error("Attempted to write 0x%02x (u8) to address %08x", value&0xff, address); + } } void m68k_write_memory_16(unsigned int address, unsigned int value) @@ -234,8 +307,10 @@ void m68k_write_memory_16(unsigned int address, unsigned int value) assert(MASK_24(address) == 0); // Just curious m68k_write_callback(address, 2); const bool successful = memory_write(BITNESS_16, address, value); - if (!successful) - exit_error("Attempted to write 0x%04x (u16) to address %08x", value&0xffff, address); + if (!successful) { + m68k_breakpoint_callback(); + report_error("Attempted to write 0x%04x (u16) to address %08x", value&0xff, address); + } } void m68k_write_memory_32(unsigned int address, unsigned int value) @@ -243,6 +318,8 @@ void m68k_write_memory_32(unsigned int address, unsigned int value) assert(MASK_24(address) == 0); // Just curious m68k_write_callback(address, 4); const bool successful = memory_write(BITNESS_16, address, value); - if (!successful) - exit_error("Attempted to write 0x%08x (u32) to address %08x", value, address); + if (!successful) { + m68k_breakpoint_callback(); + report_error("Attempted to write 0x%08x (u32) to address %08x", value&0xff, address); + } } diff --git a/emulator.cpp b/emulator.cpp index 945a104..ceb4217 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -32,6 +32,7 @@ static constexpr struct timespec kOneMillisecond{0, 1000000}; char msg_buf[MESSAGE_BUFFER_SIZE]; M68KDebuggingControl g_m68k_debug{}; +bool g_no_ack_mode{}; static int set_socket_reuseaddr(const int socket_fd) { @@ -113,7 +114,14 @@ static std::string CreateResponse( case PacketType::kNone: break; case PacketType::kQuerySupported: - break; + return "PacketSize=400000" // PacketSize number is in HEX + // These commented-out options are from OpenOCD + // TODO ";qXfer:memory-map:read+" + // TODO ";qXfer:features:read+" + // TODO ";qXfer:threads:read+" + ";QStartNoAckMode+" // It makes GDB shit fast! + ";vContSupported+" // We support "vCont?" packet + ; case PacketType::kQueryHaltReason: return "S05"; // TODO real reason case PacketType::kQueryC: @@ -145,6 +153,9 @@ static std::string CreateResponse( } } break; + case PacketType::kQStartNoAckMode: + g_no_ack_mode = true; + return "OK"; case PacketType::kSetThreadForCont: return "OK"; case PacketType::kSetThreadForOps: @@ -287,63 +298,11 @@ int m68k_instr_callback(const int pc) return 0; } -static inline bool ranges_overlap( - const uint32_t a_start, - const uint32_t a_len, - const uint32_t b_start, - const uint32_t b_len) -{ - return (a_start < b_start + b_len && b_start < a_start + a_len); -} - -// XXX Maybe better move it to bus.cpp? -void m68k_read_callback(const uint32_t address, const uint32_t size) -{ - const auto access_it = std::find_if( - access_bkpts.begin(), - access_bkpts.end(), - [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); - if (access_it != access_bkpts.end()) { - g_m68k_debug.SetRunning(false); - g_m68k_debug.RaiseBreakpoint(); - m68k_end_timeslice(); - printf("Access watchpoint @ 0x%08x\n", address); - } - const auto it = std::find_if( - read_bkpts.begin(), - read_bkpts.end(), - [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); - if (it != read_bkpts.end()) { - g_m68k_debug.SetRunning(false); - g_m68k_debug.RaiseBreakpoint(); - m68k_end_timeslice(); - printf("Read watchpoint @ 0x%08x\n", address); - } -} - -// XXX Maybe better move it to bus.cpp? -void m68k_write_callback(const uint32_t address, const uint32_t size) +void m68k_breakpoint_callback(void) { - const auto access_it = std::find_if( - access_bkpts.begin(), - access_bkpts.end(), - [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); - if (access_it != access_bkpts.end()) { - g_m68k_debug.SetRunning(false); - g_m68k_debug.RaiseBreakpoint(); - m68k_end_timeslice(); - printf("Access watchpoint @ 0x%08x\n", address); - } - const auto it = std::find_if( - write_bkpts.begin(), - write_bkpts.end(), - [&](const Breakpoint& b) { return ranges_overlap(address, size, b.offset, b.length); }); - if (it != write_bkpts.end()) { - g_m68k_debug.SetRunning(false); - g_m68k_debug.RaiseBreakpoint(); - m68k_end_timeslice(); - printf("Write watchpoint @ 0x%08x\n", address); - } + g_m68k_debug.SetRunning(false); + g_m68k_debug.RaiseBreakpoint(); + m68k_end_timeslice(); } void ParseAndReact( @@ -363,7 +322,7 @@ void ParseAndReact( " Packet type: \"%s\"\n", GDBRemote::Packet::PacketTypeToString(packet.type)); } - if (res->ack.length() > 0) { + if (res->ack.length() > 0 && !g_no_ack_mode) { printf("-> \"%s\"\n", res->ack.c_str()); if (send(conn_fd, &res->ack[0], res->ack.length(), 0) == -1) perror("Send failed (ack/nak)"); @@ -428,7 +387,7 @@ int emulator(M68KDebuggingControl& m68k_debug) break; } if (m68k_debug.IsRunning()) { - m68k_execute(1000); + m68k_execute(10000); } if (m68k_debug.HasBreakpoint()) { m68k_debug.ResetPendingBreakpoint(); diff --git a/gdbremote_parser.cpp b/gdbremote_parser.cpp index 98533c5..2c13668 100644 --- a/gdbremote_parser.cpp +++ b/gdbremote_parser.cpp @@ -147,6 +147,10 @@ struct Command { std::make_unique(std::move(data)), }; } + static Packet parseQStartNoAckMode(const std::vector&&) + { + return Packet{PacketType::kQStartNoAckMode}; + } static Packet parseSetThreadForCont(const std::vector&&) { // TODO arguments @@ -286,6 +290,7 @@ static const Command commands[] = { { "qAttached", Command::parseQueryAttached }, { "qTStatus", Command::parseQueryTraceStatus }, { "qRcmd", Command::parseQueryRcmd }, + { "QStartNoAckMode", Command::parseQStartNoAckMode }, { "Hc", Command::parseSetThreadForCont }, { "Hg", Command::parseSetThreadForOps }, { "vMustReplyEmpty", Command::parseMustReplyEmpty }, diff --git a/gdbremote_parser.hpp b/gdbremote_parser.hpp index a6d76fc..d35d78e 100644 --- a/gdbremote_parser.hpp +++ b/gdbremote_parser.hpp @@ -52,6 +52,7 @@ enum class PacketType: int { kQueryAttached, kQueryTraceStatus, kQueryRcmd, + kQStartNoAckMode, kSetThreadForCont, kSetThreadForOps, kVMustReplyEmpty, @@ -155,6 +156,8 @@ struct Packet { return "qTStatus"; case PacketType::kQueryRcmd: return "qRcmd"; + case PacketType::kQStartNoAckMode: + return "QStartNoAckMode"; case PacketType::kSetThreadForCont: return "Hc"; case PacketType::kSetThreadForOps: -- cgit v1.2.3