gdb: support 'C' packet for resuming with signals

It's not super useful as a feature but it means that a naive "continue"
after e.g. a segfault will kill the program and not confusingly go into
an infinite loop.
This commit is contained in:
Lephe 2024-04-01 00:49:52 +02:00
parent 2755596d59
commit b4c0fc7cea
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
1 changed files with 39 additions and 4 deletions

View File

@ -220,10 +220,14 @@ static void gdb_handle_qXfer_packet(const char* packet, const char* data, size_t
static const char gdb_memory_map_xml[] = "<?xml version=\"1.0\"?>"
"<!DOCTYPE memory-map PUBLIC \"+//IDN gnu.org//DTD GDB Memory Map V1.0//EN\" \"http://sourceware.org/gdb/gdb-memory-map.dtd\">"
"<memory-map>"
"<memory type=\"rom\" start=\"0x00300000\" length=\"0x00200000\"/>" // add-in rom
"<memory type=\"ram\" start=\"0x08100000\" length=\"0x00080000\"/>" // add-in ram
"<memory type=\"ram\" start=\"0x8c000000\" length=\"0x01000000\"/>" // fx-CG50 stack
"<memory type=\"ram\" start=\"0x88000000\" length=\"0x01000000\"/>" // Prizm stack
// P0 mapping of add-in file
"<memory type=\"rom\" start=\"0x00300000\" length=\"0x00200000\"/>"
// P0 mapping of user RAM area
"<memory type=\"ram\" start=\"0x08100000\" length=\"0x00080000\"/>"
// Physical mapping of RAM chip (fx-CG 50)
"<memory type=\"ram\" start=\"0x8c000000\" length=\"0x01000000\"/>"
// Physical mapping of RAM chip (fx-CG 10/20 + emulator)
"<memory type=\"ram\" start=\"0x88000000\" length=\"0x01000000\"/>"
"</memory-map>";
static void gdb_handle_query_packet(const char* packet)
@ -479,6 +483,33 @@ static void gdb_handle_remove_hardware_breakpoint(const char* packet)
gdb_send_packet("OK", 2);
}
static void gdb_handle_continue_with_signal(gdb_cpu_state_t* cpu_state,
const char* packet)
{
packet++; // consume 'C'
int signal = gdb_unhexlify_sized(packet, 2);
char exit[4] = { 'X', packet[0], packet[1], 0 };
packet += 2;
if(*packet == ';')
cpu_state->reg.pc = gdb_unhexlify(packet + 1);
// TODO: This is a heuristic replacing the normal signal system
uint32_t kills =
(1 << 4) /* SIGILL */
+ (1 << 6) /* SIGABRT */
+ (1 << 7) /* SIGEMT */
+ (1 << 8) /* SIGFPE */
+ (1 << 9) /* SIGKILL */
+ (1 << 11) /* SIGSEGV */
+ (1 << 15); /* SIGTERM */
// Abort if the signal is kill by default
if((uint)signal < 32 && (kills >> signal) & 1) {
gdb_send_packet(exit, 3);
abort();
}
}
static struct {
bool single_stepped;
bool channel0_used;
@ -579,6 +610,10 @@ void gdb_main(gdb_cpu_state_t* cpu_state)
goto ret;
case 'c': // Continue
goto ret;
case 'C': // Continue with signal
gdb_handle_continue_with_signal(cpu_state, packet_buffer);
// We'll often abort() at the signal rather than continuing
goto ret;
default: // Unsupported packet
gdb_send_packet(NULL, 0);