/** * @file gdbstub.h * @author Lunaixsky () * @brief GDB Stub implementation (https://github.com/mborgerson/gdbstub). * Ported for LunaixOS * @version 0.1 * @date 2022-10-18 * * @copyright Copyright (c) 2022 Lunaixsky & (See license below) * */ /* * Copyright (c) 2016-2022 Matt Borgerson * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include /***************************************************************************** * Types ****************************************************************************/ #ifndef GDBSTUB_DONT_DEFINE_STDINT_TYPES typedef unsigned char u8_t; typedef unsigned short u16_t; typedef unsigned long uint32_t; #endif typedef unsigned int address; typedef unsigned int reg; enum GDB_REGISTER { GDB_CPU_I386_REG_EAX = 0, GDB_CPU_I386_REG_ECX = 1, GDB_CPU_I386_REG_EDX = 2, GDB_CPU_I386_REG_EBX = 3, GDB_CPU_I386_REG_ESP = 4, GDB_CPU_I386_REG_EBP = 5, GDB_CPU_I386_REG_ESI = 6, GDB_CPU_I386_REG_EDI = 7, GDB_CPU_I386_REG_PC = 8, GDB_CPU_I386_REG_PS = 9, GDB_CPU_I386_REG_CS = 10, GDB_CPU_I386_REG_SS = 11, GDB_CPU_I386_REG_DS = 12, GDB_CPU_I386_REG_ES = 13, GDB_CPU_I386_REG_FS = 14, GDB_CPU_I386_REG_GS = 15, GDB_CPU_NUM_REGISTERS = 16 }; struct gdb_state { int signum; reg registers[GDB_CPU_NUM_REGISTERS]; }; /***************************************************************************** * * GDB Remote Serial Protocol * ****************************************************************************/ /***************************************************************************** * Macros ****************************************************************************/ #define GDB_PRINT(...) #define COM_PORT SERIAL_COM1 #define GDB_EOF (-1) #ifndef NULL #define NULL ((void*)0) #endif #ifndef GDB_ASSERT #define GDB_ASSERT(x) \ do { \ } while (0) #endif /***************************************************************************** * Prototypes ****************************************************************************/ int gdb_main(struct gdb_state* state); /* System functions, supported by all stubs */ void gdb_sys_init(void); int gdb_sys_getc(struct gdb_state* state); int gdb_sys_putchar(struct gdb_state* state, int ch); int gdb_sys_mem_readb(struct gdb_state* state, address addr, char* val); int gdb_sys_mem_writeb(struct gdb_state* state, address addr, char val); int gdb_sys_continue(struct gdb_state* state); int gdb_sys_step(struct gdb_state* state); /***************************************************************************** * Types ****************************************************************************/ typedef int (*gdb_enc_func)(char* buf, unsigned int buf_len, const char* data, unsigned int data_len); typedef int (*gdb_dec_func)(const char* buf, unsigned int buf_len, char* data, unsigned int data_len); /***************************************************************************** * Const Data ****************************************************************************/ static const char digits[] = "0123456789abcdef"; /***************************************************************************** * Prototypes ****************************************************************************/ /* Communication functions */ static int gdb_write(struct gdb_state* state, const char* buf, unsigned int len); static int gdb_read(struct gdb_state* state, char* buf, unsigned int buf_len, unsigned int len); /* String processing helper functions */ static int gdb_strlen(const char* ch); static char gdb_get_digit(int val); static int gdb_get_val(char digit, int base); static int gdb_strtol(const char* str, unsigned int len, int base, const char** endptr); /* Packet functions */ static int gdb_send_packet(struct gdb_state* state, const char* pkt, unsigned int pkt_len); static int gdb_recv_packet(struct gdb_state* state, char* pkt_buf, unsigned int pkt_buf_len, unsigned int* pkt_len); static int gdb_checksum(const char* buf, unsigned int len); static int gdb_recv_ack(struct gdb_state* state); /* Data encoding/decoding */ static int gdb_enc_hex(char* buf, unsigned int buf_len, const char* data, unsigned int data_len); static int gdb_dec_hex(const char* buf, unsigned int buf_len, char* data, unsigned int data_len); static int gdb_enc_bin(char* buf, unsigned int buf_len, const char* data, unsigned int data_len); static int gdb_dec_bin(const char* buf, unsigned int buf_len, char* data, unsigned int data_len); /* Packet creation helpers */ static int gdb_send_ok_packet(struct gdb_state* state, char* buf, unsigned int buf_len); static int gdb_send_conmsg_packet(struct gdb_state* state, char* buf, unsigned int buf_len, const char* msg); static int gdb_send_signal_packet(struct gdb_state* state, char* buf, unsigned int buf_len, char signal); static int gdb_send_error_packet(struct gdb_state* state, char* buf, unsigned int buf_len, char error); /* Command functions */ static int gdb_mem_read(struct gdb_state* state, char* buf, unsigned int buf_len, address addr, unsigned int len, gdb_enc_func enc); static int gdb_mem_write(struct gdb_state* state, const char* buf, unsigned int buf_len, address addr, unsigned int len, gdb_dec_func dec); static int gdb_continue(struct gdb_state* state); static int gdb_step(struct gdb_state* state); /***************************************************************************** * String Processing Helper Functions ****************************************************************************/ /* * Get null-terminated string length. */ static int gdb_strlen(const char* ch) { int len; len = 0; while (*ch++) { len += 1; } return len; } /* * Get integer value for a string representation. * * If the string starts with + or -, it will be signed accordingly. * * If base == 0, the base will be determined: * base 16 if the string starts with 0x or 0X, * base 10 otherwise * * If endptr is specified, it will point to the last non-digit in the * string. If there are no digits in the string, it will be set to NULL. */ static int gdb_strtol(const char* str, unsigned int len, int base, const char** endptr) { unsigned int pos; int sign, tmp, value, valid; value = 0; pos = 0; sign = 1; valid = 0; if (endptr) { *(endptr) = 0; } if (len < 1) { return 0; } /* Detect negative numbers */ if (str[pos] == '-') { sign = -1; pos += 1; } else if (str[pos] == '+') { sign = 1; pos += 1; } /* Detect '0x' hex prefix */ if ((pos + 2 < len) && (str[pos] == '0') && ((str[pos + 1] == 'x') || (str[pos + 1] == 'X'))) { base = 16; pos += 2; } if (base == 0) { base = 10; } for (; (pos < len) && (str[pos] != '\x00'); pos++) { tmp = gdb_get_val(str[pos], base); if (tmp == GDB_EOF) { break; } value = value * base + tmp; valid = 1; /* At least one digit is valid */ } if (!valid) { return 0; } if (endptr) { *endptr = str + pos; } value *= sign; return value; } /* * Get the corresponding ASCII hex digit character for a value. */ static char gdb_get_digit(int val) { if ((val >= 0) && (val <= 0xf)) { return digits[val]; } else { return GDB_EOF; } } /* * Get the corresponding value for a ASCII digit character. * * Supports bases 2-16. */ static int gdb_get_val(char digit, int base) { int value; if ((digit >= '0') && (digit <= '9')) { value = digit - '0'; } else if ((digit >= 'a') && (digit <= 'f')) { value = digit - 'a' + 0xa; } else if ((digit >= 'A') && (digit <= 'F')) { value = digit - 'A' + 0xa; } else { return GDB_EOF; } return (value < base) ? value : GDB_EOF; } /***************************************************************************** * Packet Functions ****************************************************************************/ /* * Receive a packet acknowledgment * * Returns: * 0 if an ACK (+) was received * 1 if a NACK (-) was received * GDB_EOF otherwise */ static int gdb_recv_ack(struct gdb_state* state) { int response; /* Wait for packet ack */ switch (response = gdb_sys_getc(state)) { case '+': /* Packet acknowledged */ return 0; case '-': /* Packet negative acknowledged */ return 1; default: /* Bad response! */ GDB_PRINT("received bad packet response: 0x%2x\n", response); return GDB_EOF; } } /* * Calculate 8-bit checksum of a buffer. * * Returns: * 8-bit checksum. */ static int gdb_checksum(const char* buf, unsigned int len) { unsigned char csum; csum = 0; while (len--) { csum += *buf++; } return csum; } /* * Transmits a packet of data. * Packets are of the form: $# * * Returns: * 0 if the packet was transmitted and acknowledged * 1 if the packet was transmitted but not acknowledged * GDB_EOF otherwise */ static int gdb_send_packet(struct gdb_state* state, const char* pkt_data, unsigned int pkt_len) { char buf[3]; char csum; /* Send packet start */ if (gdb_sys_putchar(state, '$') == GDB_EOF) { return GDB_EOF; } /* Send packet data */ if (gdb_write(state, pkt_data, pkt_len) == GDB_EOF) { return GDB_EOF; } /* Send the checksum */ buf[0] = '#'; csum = gdb_checksum(pkt_data, pkt_len); if ((gdb_enc_hex(buf + 1, sizeof(buf) - 1, &csum, 1) == GDB_EOF) || (gdb_write(state, buf, sizeof(buf)) == GDB_EOF)) { return GDB_EOF; } return gdb_recv_ack(state); } /* * Receives a packet of data, assuming a 7-bit clean connection. * * Returns: * 0 if the packet was received * GDB_EOF otherwise */ static int gdb_recv_packet(struct gdb_state* state, char* pkt_buf, unsigned int pkt_buf_len, unsigned int* pkt_len) { int data; char expected_csum, actual_csum; char buf[2]; /* Wait for packet start */ actual_csum = 0; while (1) { data = gdb_sys_getc(state); if (data == GDB_EOF) { return GDB_EOF; } else if (data == '$') { /* Detected start of packet. */ break; } } /* Read until checksum */ *pkt_len = 0; while (1) { data = gdb_sys_getc(state); if (data == GDB_EOF) { /* Error receiving character */ return GDB_EOF; } else if (data == '#') { /* End of packet */ break; } else { /* Check for space */ if (*pkt_len >= pkt_buf_len) { GDB_PRINT("packet buffer overflow\n"); return GDB_EOF; } /* Store character and update checksum */ pkt_buf[(*pkt_len)++] = (char)data; } } /* Receive the checksum */ if ((gdb_read(state, buf, sizeof(buf), 2) == GDB_EOF) || (gdb_dec_hex(buf, 2, &expected_csum, 1) == GDB_EOF)) { return GDB_EOF; } /* Verify checksum */ actual_csum = gdb_checksum(pkt_buf, *pkt_len); if (actual_csum != expected_csum) { /* Send packet nack */ GDB_PRINT("received packet with bad checksum\n"); gdb_sys_putchar(state, '-'); return GDB_EOF; } /* Send packet ack */ gdb_sys_putchar(state, '+'); return 0; } /***************************************************************************** * Data Encoding/Decoding ****************************************************************************/ /* * Encode data to its hex-value representation in a buffer. * * Returns: * 0+ number of bytes written to buf * GDB_EOF if the buffer is too small */ static int gdb_enc_hex(char* buf, unsigned int buf_len, const char* data, unsigned int data_len) { unsigned int pos; if (buf_len < data_len * 2) { /* Buffer too small */ return GDB_EOF; } for (pos = 0; pos < data_len; pos++) { *buf++ = gdb_get_digit((data[pos] >> 4) & 0xf); *buf++ = gdb_get_digit((data[pos]) & 0xf); } return data_len * 2; } /* * Decode data from its hex-value representation to a buffer. * * Returns: * 0 if successful * GDB_EOF if the buffer is too small */ static int gdb_dec_hex(const char* buf, unsigned int buf_len, char* data, unsigned int data_len) { unsigned int pos; int tmp; if (buf_len != data_len * 2) { /* Buffer too small */ return GDB_EOF; } for (pos = 0; pos < data_len; pos++) { /* Decode high nibble */ tmp = gdb_get_val(*buf++, 16); if (tmp == GDB_EOF) { /* Buffer contained junk. */ GDB_ASSERT(0); return GDB_EOF; } data[pos] = tmp << 4; /* Decode low nibble */ tmp = gdb_get_val(*buf++, 16); if (tmp == GDB_EOF) { /* Buffer contained junk. */ GDB_ASSERT(0); return GDB_EOF; } data[pos] |= tmp; } return 0; } /* * Encode data to its binary representation in a buffer. * * Returns: * 0+ number of bytes written to buf * GDB_EOF if the buffer is too small */ static int gdb_enc_bin(char* buf, unsigned int buf_len, const char* data, unsigned int data_len) { unsigned int buf_pos, data_pos; for (buf_pos = 0, data_pos = 0; data_pos < data_len; data_pos++) { if (data[data_pos] == '$' || data[data_pos] == '#' || data[data_pos] == '}' || data[data_pos] == '*') { if (buf_pos + 1 >= buf_len) { GDB_ASSERT(0); return GDB_EOF; } buf[buf_pos++] = '}'; buf[buf_pos++] = data[data_pos] ^ 0x20; } else { if (buf_pos >= buf_len) { GDB_ASSERT(0); return GDB_EOF; } buf[buf_pos++] = data[data_pos]; } } return buf_pos; } /* * Decode data from its bin-value representation to a buffer. * * Returns: * 0+ if successful, number of bytes decoded * GDB_EOF if the buffer is too small */ static int gdb_dec_bin(const char* buf, unsigned int buf_len, char* data, unsigned int data_len) { unsigned int buf_pos, data_pos; for (buf_pos = 0, data_pos = 0; buf_pos < buf_len; buf_pos++) { if (data_pos >= data_len) { /* Output buffer overflow */ GDB_ASSERT(0); return GDB_EOF; } if (buf[buf_pos] == '}') { /* The next byte is escaped! */ if (buf_pos + 1 >= buf_len) { /* There's an escape character, but no escaped character * following the escape character. */ GDB_ASSERT(0); return GDB_EOF; } buf_pos += 1; data[data_pos++] = buf[buf_pos] ^ 0x20; } else { data[data_pos++] = buf[buf_pos]; } } return data_pos; } /***************************************************************************** * Command Functions ****************************************************************************/ /* * Read from memory and encode into buf. * * Returns: * 0+ number of bytes written to buf * GDB_EOF if the buffer is too small */ static int gdb_mem_read(struct gdb_state* state, char* buf, unsigned int buf_len, address addr, unsigned int len, gdb_enc_func enc) { char data[64]; unsigned int pos; if (len > sizeof(data)) { return GDB_EOF; } /* Read from system memory */ for (pos = 0; pos < len; pos++) { if (gdb_sys_mem_readb(state, addr + pos, &data[pos])) { /* Failed to read */ return GDB_EOF; } } /* Encode data */ return enc(buf, buf_len, data, len); } /* * Write to memory from encoded buf. */ static int gdb_mem_write(struct gdb_state* state, const char* buf, unsigned int buf_len, address addr, unsigned int len, gdb_dec_func dec) { char data[64]; unsigned int pos; if (len > sizeof(data)) { return GDB_EOF; } /* Decode data */ if (dec(buf, buf_len, data, len) == GDB_EOF) { return GDB_EOF; } /* Write to system memory */ for (pos = 0; pos < len; pos++) { if (gdb_sys_mem_writeb(state, addr + pos, data[pos])) { /* Failed to write */ return GDB_EOF; } } return 0; } /* * Continue program execution at PC. */ int gdb_continue(struct gdb_state* state) { gdb_sys_continue(state); return 0; } /* * Step one instruction. */ int gdb_step(struct gdb_state* state) { gdb_sys_step(state); return 0; } /***************************************************************************** * Packet Creation Helpers ****************************************************************************/ /* * Send OK packet */ static int gdb_send_ok_packet(struct gdb_state* state, char* buf, unsigned int buf_len) { return gdb_send_packet(state, "OK", 2); } /* * Send a message to the debugging console (via O XX... packet) */ static int gdb_send_conmsg_packet(struct gdb_state* state, char* buf, unsigned int buf_len, const char* msg) { unsigned int size; int status; if (buf_len < 2) { /* Buffer too small */ return GDB_EOF; } buf[0] = 'O'; status = gdb_enc_hex(&buf[1], buf_len - 1, msg, gdb_strlen(msg)); if (status == GDB_EOF) { return GDB_EOF; } size = 1 + status; return gdb_send_packet(state, buf, size); } /* * Send a signal packet (S AA). */ static int gdb_send_signal_packet(struct gdb_state* state, char* buf, unsigned int buf_len, char signal) { unsigned int size; int status; if (buf_len < 4) { /* Buffer too small */ return GDB_EOF; } buf[0] = 'S'; status = gdb_enc_hex(&buf[1], buf_len - 1, &signal, 1); if (status == GDB_EOF) { return GDB_EOF; } size = 1 + status; return gdb_send_packet(state, buf, size); } /* * Send a error packet (E AA). */ static int gdb_send_error_packet(struct gdb_state* state, char* buf, unsigned int buf_len, char error) { unsigned int size; int status; if (buf_len < 4) { /* Buffer too small */ return GDB_EOF; } buf[0] = 'E'; status = gdb_enc_hex(&buf[1], buf_len - 1, &error, 1); if (status == GDB_EOF) { return GDB_EOF; } size = 1 + status; return gdb_send_packet(state, buf, size); } /***************************************************************************** * Communication Functions ****************************************************************************/ /* * Write a sequence of bytes. * * Returns: * 0 if successful * GDB_EOF if failed to write all bytes */ static int gdb_write(struct gdb_state* state, const char* buf, unsigned int len) { while (len--) { if (gdb_sys_putchar(state, *buf++) == GDB_EOF) { return GDB_EOF; } } return 0; } /* * Read a sequence of bytes. * * Returns: * 0 if successfully read len bytes * GDB_EOF if failed to read all bytes */ static int gdb_read(struct gdb_state* state, char* buf, unsigned int buf_len, unsigned int len) { char c; if (buf_len < len) { /* Buffer too small */ return GDB_EOF; } while (len--) { if ((c = gdb_sys_getc(state)) == GDB_EOF) { return GDB_EOF; } *buf++ = c; } return 0; } /***************************************************************************** * Main Loop ****************************************************************************/ /* * Main debug loop. Handles commands. */ int gdb_main(struct gdb_state* state) { address addr; char pkt_buf[256]; int status; unsigned int length; unsigned int pkt_len; const char* ptr_next; gdb_send_signal_packet(state, pkt_buf, sizeof(pkt_buf), state->signum); while (1) { /* Receive the next packet */ status = gdb_recv_packet(state, pkt_buf, sizeof(pkt_buf), &pkt_len); if (status == GDB_EOF) { break; } if (pkt_len == 0) { /* Received empty packet.. */ continue; } ptr_next = pkt_buf; /* * Handle one letter commands */ switch (pkt_buf[0]) { /* Calculate remaining space in packet from ptr_next position. */ #define token_remaining_buf (pkt_len - (ptr_next - pkt_buf)) /* Expecting a seperator. If not present, go to error */ #define token_expect_seperator(c) \ { \ if (!ptr_next || *ptr_next != c) { \ goto error; \ } else { \ ptr_next += 1; \ } \ } /* Expecting an integer argument. If not present, go to error */ #define token_expect_integer_arg(arg) \ { \ arg = gdb_strtol(ptr_next, token_remaining_buf, 16, &ptr_next); \ if (!ptr_next) { \ goto error; \ } \ } /* * Read Registers * Command Format: g */ case 'g': /* Encode registers */ status = gdb_enc_hex(pkt_buf, sizeof(pkt_buf), (char*)&(state->registers), sizeof(state->registers)); if (status == GDB_EOF) { goto error; } pkt_len = status; gdb_send_packet(state, pkt_buf, pkt_len); break; /* * Write Registers * Command Format: G XX... */ case 'G': status = gdb_dec_hex(pkt_buf + 1, pkt_len - 1, (char*)&(state->registers), sizeof(state->registers)); if (status == GDB_EOF) { goto error; } gdb_send_ok_packet(state, pkt_buf, sizeof(pkt_buf)); break; /* * Read a Register * Command Format: p n */ case 'p': ptr_next += 1; token_expect_integer_arg(addr); if (addr >= GDB_CPU_NUM_REGISTERS) { goto error; } /* Read Register */ status = gdb_enc_hex(pkt_buf, sizeof(pkt_buf), (char*)&(state->registers[addr]), sizeof(state->registers[addr])); if (status == GDB_EOF) { goto error; } gdb_send_packet(state, pkt_buf, status); break; /* * Write a Register * Command Format: P n...=r... */ case 'P': ptr_next += 1; token_expect_integer_arg(addr); token_expect_seperator('='); if (addr < GDB_CPU_NUM_REGISTERS) { status = gdb_dec_hex(ptr_next, token_remaining_buf, (char*)&(state->registers[addr]), sizeof(state->registers[addr])); if (status == GDB_EOF) { goto error; } } gdb_send_ok_packet(state, pkt_buf, sizeof(pkt_buf)); break; /* * Read Memory * Command Format: m addr,length */ case 'm': ptr_next += 1; token_expect_integer_arg(addr); token_expect_seperator(','); token_expect_integer_arg(length); /* Read Memory */ status = gdb_mem_read( state, pkt_buf, sizeof(pkt_buf), addr, length, gdb_enc_hex); if (status == GDB_EOF) { goto error; } gdb_send_packet(state, pkt_buf, status); break; /* * Write Memory * Command Format: M addr,length:XX.. */ case 'M': ptr_next += 1; token_expect_integer_arg(addr); token_expect_seperator(','); token_expect_integer_arg(length); token_expect_seperator(':'); /* Write Memory */ status = gdb_mem_write(state, ptr_next, token_remaining_buf, addr, length, gdb_dec_hex); if (status == GDB_EOF) { goto error; } gdb_send_ok_packet(state, pkt_buf, sizeof(pkt_buf)); break; /* * Write Memory (Binary) * Command Format: X addr,length:XX.. */ case 'X': ptr_next += 1; token_expect_integer_arg(addr); token_expect_seperator(','); token_expect_integer_arg(length); token_expect_seperator(':'); /* Write Memory */ status = gdb_mem_write(state, ptr_next, token_remaining_buf, addr, length, gdb_dec_bin); if (status == GDB_EOF) { goto error; } gdb_send_ok_packet(state, pkt_buf, sizeof(pkt_buf)); break; /* * Continue, Kill (also treated as continue!) * Command Format: c [addr] */ case 'c': case 'C': case 'k': gdb_continue(state); return 0; /* * Single-step * Command Format: s [addr] */ case 's': case 'S': gdb_step(state); return 0; case '?': gdb_send_signal_packet( state, pkt_buf, sizeof(pkt_buf), state->signum); break; /* * Unsupported Command */ default: gdb_send_packet(state, 0, 0); } continue; error: gdb_send_error_packet(state, pkt_buf, sizeof(pkt_buf), 0x00); #undef token_remaining_buf #undef token_expect_seperator #undef token_expect_integer_arg } return 0; } /***************************************************************************** * Types ****************************************************************************/ struct gdb_idtr { u16_t len; uint32_t offset; } __attribute__((packed)); struct gdb_idt_gate { u16_t offset_low; u16_t segment; u16_t flags; u16_t offset_high; } __attribute__((packed)); /***************************************************************************** * Prototypes ****************************************************************************/ #define gdb_x86_io_write_8(port, val) port_wrbyte(port, val) #define gdb_x86_io_read_8(port) port_rdbyte(port) #define gdb_x86_serial_getc() serial_rx_byte(COM_PORT) #define gdb_x86_serial_putchar(ch) serial_tx_byte(COM_PORT, ch) #ifdef __STRICT_ANSI__ #define asm __asm__ #endif static struct gdb_state gdb_state; static volatile int start_debugging = 0; /* * Debug interrupt handler. */ void gdbstub_loop(isr_param* param) { /* Translate vector to signal */ switch (param->execp->vector) { case 1: gdb_state.signum = 5; break; case 3: gdb_state.signum = 5; break; default: gdb_state.signum = 7; } /* Load Registers */ gdb_state.registers[GDB_CPU_I386_REG_EAX] = param->registers.eax; gdb_state.registers[GDB_CPU_I386_REG_ECX] = param->registers.ecx; gdb_state.registers[GDB_CPU_I386_REG_EDX] = param->registers.edx; gdb_state.registers[GDB_CPU_I386_REG_EBX] = param->registers.ebx; gdb_state.registers[GDB_CPU_I386_REG_ESP] = param->esp; gdb_state.registers[GDB_CPU_I386_REG_EBP] = param->registers.ebp; gdb_state.registers[GDB_CPU_I386_REG_ESI] = param->registers.esi; gdb_state.registers[GDB_CPU_I386_REG_EDI] = param->registers.edi; gdb_state.registers[GDB_CPU_I386_REG_PC] = param->execp->eip; gdb_state.registers[GDB_CPU_I386_REG_CS] = param->execp->cs; gdb_state.registers[GDB_CPU_I386_REG_PS] = param->execp->eflags; gdb_state.registers[GDB_CPU_I386_REG_SS] = param->execp->ss; gdb_state.registers[GDB_CPU_I386_REG_DS] = param->registers.ds; gdb_state.registers[GDB_CPU_I386_REG_ES] = param->registers.es; gdb_state.registers[GDB_CPU_I386_REG_FS] = param->registers.fs; gdb_state.registers[GDB_CPU_I386_REG_GS] = param->registers.gs; gdb_main(&gdb_state); /* Restore Registers */ param->registers.eax = gdb_state.registers[GDB_CPU_I386_REG_EAX]; param->registers.ecx = gdb_state.registers[GDB_CPU_I386_REG_ECX]; param->registers.edx = gdb_state.registers[GDB_CPU_I386_REG_EDX]; param->registers.ebx = gdb_state.registers[GDB_CPU_I386_REG_EBX]; param->esp = gdb_state.registers[GDB_CPU_I386_REG_ESP]; param->registers.ebp = gdb_state.registers[GDB_CPU_I386_REG_EBP]; param->registers.esi = gdb_state.registers[GDB_CPU_I386_REG_ESI]; param->registers.edi = gdb_state.registers[GDB_CPU_I386_REG_EDI]; param->execp->eip = gdb_state.registers[GDB_CPU_I386_REG_PC]; param->execp->cs = gdb_state.registers[GDB_CPU_I386_REG_CS]; param->execp->eflags = gdb_state.registers[GDB_CPU_I386_REG_PS]; param->execp->ss = gdb_state.registers[GDB_CPU_I386_REG_SS]; param->registers.ds = gdb_state.registers[GDB_CPU_I386_REG_DS]; param->registers.es = gdb_state.registers[GDB_CPU_I386_REG_ES]; param->registers.fs = gdb_state.registers[GDB_CPU_I386_REG_FS]; param->registers.gs = gdb_state.registers[GDB_CPU_I386_REG_GS]; } /***************************************************************************** * Debugging System Functions ****************************************************************************/ /* * Write one character to the debugging stream. */ int gdb_sys_putchar(struct gdb_state* state, int ch) { gdb_x86_serial_putchar(ch); return ch; } /* * Read one character from the debugging stream. */ int gdb_sys_getc(struct gdb_state* state) { return gdb_x86_serial_getc() & 0xff; } /* * Read one byte from memory. */ int gdb_sys_mem_readb(struct gdb_state* state, address addr, char* val) { *val = *(volatile char*)addr; return 0; } /* * Write one byte to memory. */ int gdb_sys_mem_writeb(struct gdb_state* state, address addr, char val) { *(volatile char*)addr = val; return 0; } /* * Continue program execution. */ int gdb_sys_continue(struct gdb_state* state) { gdb_state.registers[GDB_CPU_I386_REG_PS] &= ~(1 << 8); return 0; } /* * Single step the next instruction. */ int gdb_sys_step(struct gdb_state* state) { gdb_state.registers[GDB_CPU_I386_REG_PS] |= 1 << 8; return 0; }