aboutsummaryrefslogtreecommitdiff
path: root/arch_x86
diff options
context:
space:
mode:
authorMatt Borgerson <contact@mborgerson.com>2019-12-17 19:47:47 -0700
committerMatt Borgerson <contact@mborgerson.com>2019-12-17 19:47:47 -0700
commit77eb93ce4eaf9667e1261fa7be0a9e9f8cc4d949 (patch)
tree98752e56525f9978d033beaf38f1c1471cd5e09b /arch_x86
parentaf1a586beb952808238834a4d65531936a97f0de (diff)
downloadgdbstub-77eb93ce4eaf9667e1261fa7be0a9e9f8cc4d949.tar.gz
Rename x86 dir to arch_x86
Diffstat (limited to 'arch_x86')
-rw-r--r--arch_x86/gdbstub_int.nasm110
-rw-r--r--arch_x86/gdbstub_sys.c350
-rw-r--r--arch_x86/gdbstub_sys.h138
3 files changed, 598 insertions, 0 deletions
diff --git a/arch_x86/gdbstub_int.nasm b/arch_x86/gdbstub_int.nasm
new file mode 100644
index 0000000..2495971
--- /dev/null
+++ b/arch_x86/gdbstub_int.nasm
@@ -0,0 +1,110 @@
+;
+; Copyright (c) 2016-2019 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.
+;
+
+bits 32
+
+%define NUM_HANDLERS 32
+
+section .data
+global dbg_int_handlers
+
+; Generate table of handlers
+dbg_int_handlers:
+%macro handler_addr 1
+ dd dbg_int_handler_%1
+%endmacro
+%assign i 0
+%rep NUM_HANDLERS
+ handler_addr i
+ %assign i i+1
+%endrep
+
+section .text
+extern dbg_int_handler
+
+%macro int 1
+dbg_int_handler_%1:
+ push 0 ; Dummy Error code
+ push %1 ; Interrupt Vector
+ jmp dbg_int_handler_common
+%endmacro
+
+%macro inte 1
+dbg_int_handler_%1:
+ ; Error code already on stack
+ push %1 ; Interrupt Vector
+ jmp dbg_int_handler_common
+%endmacro
+
+; Generate Interrupt Handlers
+%assign i 0
+%rep NUM_HANDLERS
+ %if (i == 8) || ((i >= 10) && (i <= 14)) || (i == 17)
+ inte i
+ %else
+ int i
+ %endif
+%assign i i+1
+%endrep
+
+; Common Interrupt Handler
+dbg_int_handler_common:
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ push ss
+ mov ebp, esp
+
+ ; Stack:
+ ; - EFLAGS
+ ; - CS
+ ; - EIP
+ ; - ERROR CODE
+ ; - VECTOR
+ ; - EAX
+ ; - ECX
+ ; - EDX
+ ; - EBX
+ ; - ESP
+ ; - EBP
+ ; - ESI
+ ; - EDI
+ ; - DS
+ ; - ES
+ ; - FS
+ ; - GS
+ ; - SS
+
+ push ebp
+ call dbg_int_handler
+
+ mov esp, ebp
+ pop ss
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ add esp, 8 ; Pop error & vector
+ iret
diff --git a/arch_x86/gdbstub_sys.c b/arch_x86/gdbstub_sys.c
new file mode 100644
index 0000000..a73bc52
--- /dev/null
+++ b/arch_x86/gdbstub_sys.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2016-2019 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 "gdbstub.h"
+
+#ifdef __STRICT_ANSI__
+#define asm __asm__
+#endif
+
+#define SERIAL_COM1 0x3f8
+#define SERIAL_COM2 0x2f8
+#define SERIAL_PORT SERIAL_COM1
+
+#define NUM_IDT_ENTRIES 32
+
+/*****************************************************************************
+ * BSS Data
+ ****************************************************************************/
+
+static struct dbg_idt_gate dbg_idt_gates[NUM_IDT_ENTRIES];
+static struct dbg_state dbg_state;
+
+/*****************************************************************************
+ * Misc. Functions
+ ****************************************************************************/
+
+void *dbg_sys_memset(void *ptr, int data, size_t len)
+{
+ char *p = ptr;
+
+ while (len--) {
+ *p++ = (char)data;
+ }
+
+ return ptr;
+}
+
+/*
+ * Get current code segment (CS register).
+ */
+uint32_t dbg_get_cs(void)
+{
+ uint32_t cs;
+
+ asm volatile (
+ "push %%cs;"
+ "pop %%eax;"
+ /* Outputs */ : "=a" (cs)
+ /* Inputs */ : /* None */
+ /* Clobbers */ : /* None */
+ );
+
+ return cs;
+}
+
+/*****************************************************************************
+ * Interrupt Management Functions
+ ****************************************************************************/
+
+/*
+ * Initialize idt_gates with the interrupt handlers.
+ */
+int dbg_init_gates(void)
+{
+ size_t i;
+ uint16_t cs;
+
+ cs = dbg_get_cs();
+ for (i = 0; i < NUM_IDT_ENTRIES; i++) {
+ dbg_idt_gates[i].flags = 0x8E00;
+ dbg_idt_gates[i].segment = cs;
+ dbg_idt_gates[i].offset_low =
+ ((uint32_t)dbg_int_handlers[i] ) & 0xffff;
+ dbg_idt_gates[i].offset_high =
+ ((uint32_t)dbg_int_handlers[i] >> 16) & 0xffff;
+ }
+
+ return 0;
+}
+
+/*
+ * Load a new IDT.
+ */
+int dbg_load_idt(struct dbg_idtr *idtr)
+{
+ asm volatile (
+ "lidt %0"
+ /* Outputs */ : /* None */
+ /* Inputs */ : "m" (*idtr)
+ /* Clobbers */ : /* None */
+ );
+
+ return 0;
+}
+
+/*
+ * Get current IDT.
+ */
+int dbg_store_idt(struct dbg_idtr *idtr)
+{
+ asm volatile (
+ "sidt %0"
+ /* Outputs */ : "=m" (*idtr)
+ /* Inputs */ : /* None */
+ /* Clobbers */ : /* None */
+ );
+
+ return 0;
+}
+
+/*
+ * Hook a vector of the current IDT.
+ */
+int dbg_hook_idt(uint8_t vector, const void *function)
+{
+ struct dbg_idtr idtr;
+ struct dbg_idt_gate *gates;
+
+ dbg_store_idt(&idtr);
+ gates = (struct dbg_idt_gate *)idtr.offset;
+ gates[vector].flags = 0x8E00;
+ gates[vector].segment = dbg_get_cs();
+ gates[vector].offset_low = (((uint32_t)function) ) & 0xffff;
+ gates[vector].offset_high = (((uint32_t)function) >> 16) & 0xffff;
+
+ return 0;
+}
+
+/*
+ * Initialize IDT gates and load the new IDT.
+ */
+int dbg_init_idt(void)
+{
+ struct dbg_idtr idtr;
+
+ dbg_init_gates();
+ idtr.len = sizeof(dbg_idt_gates)-1;
+ idtr.offset = (uint32_t)dbg_idt_gates;
+ dbg_load_idt(&idtr);
+
+ return 0;
+}
+
+/*
+ * Common interrupt handler routine.
+ */
+void dbg_int_handler(struct dbg_interrupt_state *istate)
+{
+ dbg_interrupt(istate);
+}
+
+/*
+ * Debug interrupt handler.
+ */
+void dbg_interrupt(struct dbg_interrupt_state *istate)
+{
+ dbg_sys_memset(&dbg_state.registers, 0, sizeof(dbg_state.registers));
+
+ /* Translate vector to signal */
+ switch (istate->vector) {
+ case 1: dbg_state.signum = 5; break;
+ case 3: dbg_state.signum = 5; break;
+ default: dbg_state.signum = 7;
+ }
+
+ /* Load Registers */
+ dbg_state.registers[DBG_CPU_I386_REG_EAX] = istate->eax;
+ dbg_state.registers[DBG_CPU_I386_REG_ECX] = istate->ecx;
+ dbg_state.registers[DBG_CPU_I386_REG_EDX] = istate->edx;
+ dbg_state.registers[DBG_CPU_I386_REG_EBX] = istate->ebx;
+ dbg_state.registers[DBG_CPU_I386_REG_ESP] = istate->esp;
+ dbg_state.registers[DBG_CPU_I386_REG_EBP] = istate->ebp;
+ dbg_state.registers[DBG_CPU_I386_REG_ESI] = istate->esi;
+ dbg_state.registers[DBG_CPU_I386_REG_EDI] = istate->edi;
+ dbg_state.registers[DBG_CPU_I386_REG_PC] = istate->eip;
+ dbg_state.registers[DBG_CPU_I386_REG_CS] = istate->cs;
+ dbg_state.registers[DBG_CPU_I386_REG_PS] = istate->eflags;
+ dbg_state.registers[DBG_CPU_I386_REG_SS] = istate->ss;
+ dbg_state.registers[DBG_CPU_I386_REG_DS] = istate->ds;
+ dbg_state.registers[DBG_CPU_I386_REG_ES] = istate->es;
+ dbg_state.registers[DBG_CPU_I386_REG_FS] = istate->fs;
+ dbg_state.registers[DBG_CPU_I386_REG_GS] = istate->gs;
+
+ dbg_main(&dbg_state);
+
+ /* Restore Registers */
+ istate->eax = dbg_state.registers[DBG_CPU_I386_REG_EAX];
+ istate->ecx = dbg_state.registers[DBG_CPU_I386_REG_ECX];
+ istate->edx = dbg_state.registers[DBG_CPU_I386_REG_EDX];
+ istate->ebx = dbg_state.registers[DBG_CPU_I386_REG_EBX];
+ istate->esp = dbg_state.registers[DBG_CPU_I386_REG_ESP];
+ istate->ebp = dbg_state.registers[DBG_CPU_I386_REG_EBP];
+ istate->esi = dbg_state.registers[DBG_CPU_I386_REG_ESI];
+ istate->edi = dbg_state.registers[DBG_CPU_I386_REG_EDI];
+ istate->eip = dbg_state.registers[DBG_CPU_I386_REG_PC];
+ istate->cs = dbg_state.registers[DBG_CPU_I386_REG_CS];
+ istate->eflags = dbg_state.registers[DBG_CPU_I386_REG_PS];
+ istate->ss = dbg_state.registers[DBG_CPU_I386_REG_SS];
+ istate->ds = dbg_state.registers[DBG_CPU_I386_REG_DS];
+ istate->es = dbg_state.registers[DBG_CPU_I386_REG_ES];
+ istate->fs = dbg_state.registers[DBG_CPU_I386_REG_FS];
+ istate->gs = dbg_state.registers[DBG_CPU_I386_REG_GS];
+}
+
+/*****************************************************************************
+ * I/O Functions
+ ****************************************************************************/
+
+/*
+ * Write to I/O port.
+ */
+void dbg_io_write_8(uint16_t port, uint8_t val)
+{
+ asm volatile (
+ "outb %%al, %%dx;"
+ /* Outputs */ : /* None */
+ /* Inputs */ : "a" (val), "d" (port)
+ /* Clobbers */ : /* None */
+ );
+}
+
+/*
+ * Read from I/O port.
+ */
+uint8_t dbg_io_read_8(uint16_t port)
+{
+ uint8_t val;
+
+ asm volatile (
+ "inb %%dx, %%al;"
+ /* Outputs */ : "=a" (val)
+ /* Inputs */ : "d" (port)
+ /* Clobbers */ : /* None */
+ );
+
+ return val;
+}
+
+/*****************************************************************************
+ * NS16550 Serial Port (IO)
+ ****************************************************************************/
+
+#define SERIAL_THR 0
+#define SERIAL_RBR 0
+#define SERIAL_LSR 5
+
+int dbg_serial_getc(void)
+{
+ /* Wait for data */
+ while ((dbg_io_read_8(SERIAL_PORT + SERIAL_LSR) & 1) == 0);
+ return dbg_io_read_8(SERIAL_PORT + SERIAL_RBR);
+}
+
+int dbg_serial_putchar(int ch)
+{
+ /* Wait for THRE (bit 5) to be high */
+ while ((dbg_io_read_8(SERIAL_PORT + SERIAL_LSR) & (1<<5)) == 0);
+ dbg_io_write_8(SERIAL_PORT + SERIAL_THR, ch);
+ return ch;
+}
+
+/*****************************************************************************
+ * Debugging System Functions
+ ****************************************************************************/
+
+/*
+ * Write one character to the debugging stream.
+ */
+int dbg_sys_putchar(int ch)
+{
+ return dbg_serial_putchar(ch);
+}
+
+/*
+ * Read one character from the debugging stream.
+ */
+int dbg_sys_getc(void)
+{
+ return dbg_serial_getc() & 0xff;
+}
+
+/*
+ * Read one byte from memory.
+ */
+int dbg_sys_mem_readb(address addr, char *val)
+{
+ *val = *(volatile char *)addr;
+ return 0;
+}
+
+/*
+ * Write one byte to memory.
+ */
+int dbg_sys_mem_writeb(address addr, char val)
+{
+ *(volatile char *)addr = val;
+ return 0;
+}
+
+/*
+ * Continue program execution.
+ */
+int dbg_sys_continue(void)
+{
+ dbg_state.registers[DBG_CPU_I386_REG_PS] &= ~(1<<8);
+ return 0;
+}
+
+/*
+ * Single step the next instruction.
+ */
+int dbg_sys_step(void)
+{
+ dbg_state.registers[DBG_CPU_I386_REG_PS] |= 1<<8;
+ return 0;
+}
+
+/*
+ * Debugger init function.
+ *
+ * Hooks the IDT to enable debugging.
+ */
+void dbg_start(void)
+{
+ /* Hook current IDT. */
+ dbg_hook_idt(1, dbg_int_handlers[1]);
+ dbg_hook_idt(3, dbg_int_handlers[3]);
+
+ /* Interrupt to start debugging. */
+ asm volatile ("int3");
+}
diff --git a/arch_x86/gdbstub_sys.h b/arch_x86/gdbstub_sys.h
new file mode 100644
index 0000000..82f7ca9
--- /dev/null
+++ b/arch_x86/gdbstub_sys.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016-2019 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.
+ */
+
+#ifndef _GDBSTUB_SYS_H_
+#define _GDBSTUB_SYS_H_
+
+/* Define the size_t type */
+#define DBG_DEFINE_SIZET 1
+
+/* Define required standard integer types (e.g. uint16_t) */
+#define DBG_DEFINE_STDINT 1
+
+/*****************************************************************************
+ * Types
+ ****************************************************************************/
+
+#if DBG_DEFINE_STDINT
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+#endif
+
+#if DBG_DEFINE_SIZET
+typedef unsigned int size_t;
+#endif
+
+typedef unsigned int address;
+typedef unsigned int reg;
+
+#pragma pack(1)
+struct dbg_interrupt_state {
+ uint32_t ss;
+ uint32_t gs;
+ uint32_t fs;
+ uint32_t es;
+ uint32_t ds;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ebx;
+ uint32_t edx;
+ uint32_t ecx;
+ uint32_t eax;
+ uint32_t vector;
+ uint32_t error_code;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct dbg_idtr
+{
+ uint16_t len;
+ uint32_t offset;
+};
+#pragma pack()
+
+#pragma pack(1)
+struct dbg_idt_gate
+{
+ uint16_t offset_low;
+ uint16_t segment;
+ uint16_t flags;
+ uint16_t offset_high;
+};
+#pragma pack()
+
+enum DBG_REGISTER {
+ DBG_CPU_I386_REG_EAX = 0,
+ DBG_CPU_I386_REG_ECX = 1,
+ DBG_CPU_I386_REG_EDX = 2,
+ DBG_CPU_I386_REG_EBX = 3,
+ DBG_CPU_I386_REG_ESP = 4,
+ DBG_CPU_I386_REG_EBP = 5,
+ DBG_CPU_I386_REG_ESI = 6,
+ DBG_CPU_I386_REG_EDI = 7,
+ DBG_CPU_I386_REG_PC = 8,
+ DBG_CPU_I386_REG_PS = 9,
+ DBG_CPU_I386_REG_CS = 10,
+ DBG_CPU_I386_REG_SS = 11,
+ DBG_CPU_I386_REG_DS = 12,
+ DBG_CPU_I386_REG_ES = 13,
+ DBG_CPU_I386_REG_FS = 14,
+ DBG_CPU_I386_REG_GS = 15,
+ DBG_CPU_I386_NUM_REGISTERS = 16
+};
+
+struct dbg_state {
+ int signum;
+ reg registers[DBG_CPU_I386_NUM_REGISTERS];
+};
+
+/*****************************************************************************
+ * Const Data
+ ****************************************************************************/
+
+extern void const * const dbg_int_handlers[];
+
+/*****************************************************************************
+ * Prototypes
+ ****************************************************************************/
+
+int dbg_hook_idt(uint8_t vector, const void *function);
+int dbg_init_gates(void);
+int dbg_init_idt(void);
+int dbg_load_idt(struct dbg_idtr *idtr);
+int dbg_store_idt(struct dbg_idtr *idtr);
+uint32_t dbg_get_cs(void);
+void dbg_int_handler(struct dbg_interrupt_state *istate);
+void dbg_interrupt(struct dbg_interrupt_state *istate);
+void dbg_start(void);
+void dbg_io_write_8(uint16_t port, uint8_t val);
+uint8_t dbg_io_read_8(uint16_t port);
+void *dbg_sys_memset(void *ptr, int data, size_t len);
+
+#endif