X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/b91be0033265b5b6bd716bd39cb0971da41906c4..7804c2dae30700296c3205aaf7f546f491999bf4:/lunaix-os/debug/gdbstub.c diff --git a/lunaix-os/debug/gdbstub.c b/lunaix-os/debug/gdbstub.c deleted file mode 100644 index 38d35ad..0000000 --- a/lunaix-os/debug/gdbstub.c +++ /dev/null @@ -1,1325 +0,0 @@ -/** - * @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) io_outb(port, val) -#define gdb_x86_io_read_8(port) io_inb(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; -} \ No newline at end of file