summaryrefslogtreecommitdiffstats
path: root/src/arch/x86_64
diff options
context:
space:
mode:
authorMichael Brown2016-03-20 13:00:15 +0100
committerMichael Brown2016-03-22 09:44:32 +0100
commit311a5732c8baa7ceb4f23db51dcbb5015e2ef965 (patch)
treedcdb0f60b43c40b6512bb8a3fcd93e0e9478c41d /src/arch/x86_64
parent[build] Do not use "objcopy -O binary" for objects with relocation records (diff)
downloadipxe-311a5732c8baa7ceb4f23db51dcbb5015e2ef965.tar.gz
ipxe-311a5732c8baa7ceb4f23db51dcbb5015e2ef965.tar.xz
ipxe-311a5732c8baa7ceb4f23db51dcbb5015e2ef965.zip
[gdb] Add support for x86_64
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/arch/x86_64')
-rw-r--r--src/arch/x86_64/core/gdbidt.S168
-rw-r--r--src/arch/x86_64/include/gdbmach.h49
2 files changed, 206 insertions, 11 deletions
diff --git a/src/arch/x86_64/core/gdbidt.S b/src/arch/x86_64/core/gdbidt.S
new file mode 100644
index 00000000..89280bf8
--- /dev/null
+++ b/src/arch/x86_64/core/gdbidt.S
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** @file
+ *
+ * GDB exception handlers
+ *
+ */
+
+/* Size of a register */
+#define SIZEOF_REG 8
+
+/* POSIX signal numbers for reporting traps to GDB */
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGFPE 8
+#define SIGSTKFLT 16
+
+ .section ".text.gdbmach_interrupt", "ax", @progbits
+ .code64
+
+ .struct 0
+/* Register dump created for GDB stub */
+regs:
+regs_rax: .space SIZEOF_REG
+regs_rbx: .space SIZEOF_REG
+regs_rcx: .space SIZEOF_REG
+regs_rdx: .space SIZEOF_REG
+regs_rsi: .space SIZEOF_REG
+regs_rdi: .space SIZEOF_REG
+regs_rbp: .space SIZEOF_REG
+regs_rsp: .space SIZEOF_REG
+regs_r8: .space SIZEOF_REG
+regs_r9: .space SIZEOF_REG
+regs_r10: .space SIZEOF_REG
+regs_r11: .space SIZEOF_REG
+regs_r12: .space SIZEOF_REG
+regs_r13: .space SIZEOF_REG
+regs_r14: .space SIZEOF_REG
+regs_r15: .space SIZEOF_REG
+regs_rip: .space SIZEOF_REG
+regs_rflags: .space SIZEOF_REG
+regs_cs: .space SIZEOF_REG
+regs_ss: .space SIZEOF_REG
+regs_ds: .space SIZEOF_REG
+regs_es: .space SIZEOF_REG
+regs_fs: .space SIZEOF_REG
+regs_gs: .space SIZEOF_REG
+regs_end:
+/* GDB signal code */
+gdb:
+gdb_code: .space SIZEOF_REG
+gdb_end:
+/* Long-mode exception frame */
+frame:
+frame_rip: .space SIZEOF_REG
+frame_cs: .space SIZEOF_REG
+frame_rflags: .space SIZEOF_REG
+frame_rsp: .space SIZEOF_REG
+frame_ss: .space SIZEOF_REG
+frame_end:
+ .previous
+
+ .globl gdbmach_sigfpe
+gdbmach_sigfpe:
+ push $SIGFPE
+ jmp gdbmach_interrupt
+
+ .globl gdbmach_sigtrap
+gdbmach_sigtrap:
+ push $SIGTRAP
+ jmp gdbmach_interrupt
+
+ .globl gdbmach_sigstkflt
+gdbmach_sigstkflt:
+ push $SIGSTKFLT
+ jmp gdbmach_interrupt
+
+ .globl gdbmach_sigill
+gdbmach_sigill:
+ push $SIGILL
+ jmp gdbmach_interrupt
+
+gdbmach_interrupt:
+
+ /* Create register dump */
+ pushq %gs
+ pushq %fs
+ pushq $0 /* %es unused in long mode */
+ pushq $0 /* %ds unused in long mode */
+ pushq ( frame_ss - regs_ss - SIZEOF_REG )(%rsp)
+ pushq ( frame_cs - regs_cs - SIZEOF_REG )(%rsp)
+ pushq ( frame_rflags - regs_rflags - SIZEOF_REG )(%rsp)
+ pushq ( frame_rip - regs_rip - SIZEOF_REG )(%rsp)
+ pushq %r15
+ pushq %r14
+ pushq %r13
+ pushq %r12
+ pushq %r11
+ pushq %r10
+ pushq %r9
+ pushq %r8
+ pushq ( frame_rsp - regs_rsp - SIZEOF_REG )(%rsp)
+ pushq %rbp
+ pushq %rdi
+ pushq %rsi
+ pushq %rdx
+ pushq %rcx
+ pushq %rbx
+ pushq %rax
+
+ /* Call GDB stub exception handler */
+ movq gdb_code(%rsp), %rdi
+ movq %rsp, %rsi
+ call gdbmach_handler
+
+ /* Restore from register dump */
+ popq %rax
+ popq %rbx
+ popq %rcx
+ popq %rdx
+ popq %rsi
+ popq %rdi
+ popq %rbp
+ popq ( frame_rsp - regs_rsp - SIZEOF_REG )(%rsp)
+ popq %r8
+ popq %r9
+ popq %r10
+ popq %r11
+ popq %r12
+ popq %r13
+ popq %r14
+ popq %r15
+ popq ( frame_rip - regs_rip - SIZEOF_REG )(%rsp)
+ popq ( frame_rflags - regs_rflags - SIZEOF_REG )(%rsp)
+ popq ( frame_cs - regs_cs - SIZEOF_REG )(%rsp)
+ popq ( frame_ss - regs_ss - SIZEOF_REG )(%rsp)
+ addq $( regs_fs - regs_ds ), %rsp /* skip %ds, %es */
+ popq %fs
+ popq %gs
+
+ /* Skip code */
+ addq $( gdb_end - gdb_code ), %rsp /* skip code */
+
+ /* Return */
+ iretq
diff --git a/src/arch/x86_64/include/gdbmach.h b/src/arch/x86_64/include/gdbmach.h
index 6dadbbdd..367405fd 100644
--- a/src/arch/x86_64/include/gdbmach.h
+++ b/src/arch/x86_64/include/gdbmach.h
@@ -14,16 +14,37 @@
typedef unsigned long gdbreg_t;
-/* The register snapshot, this must be in sync with interrupt handler and the
- * GDB protocol. */
+/* Register snapshot */
enum {
- // STUB: don't expect this to work!
- GDBMACH_EIP,
- GDBMACH_EFLAGS,
+ GDBMACH_RAX,
+ GDBMACH_RBX,
+ GDBMACH_RCX,
+ GDBMACH_RDX,
+ GDBMACH_RSI,
+ GDBMACH_RDI,
+ GDBMACH_RBP,
+ GDBMACH_RSP,
+ GDBMACH_R8,
+ GDBMACH_R9,
+ GDBMACH_R10,
+ GDBMACH_R11,
+ GDBMACH_R12,
+ GDBMACH_R13,
+ GDBMACH_R14,
+ GDBMACH_R15,
+ GDBMACH_RIP,
+ GDBMACH_RFLAGS,
+ GDBMACH_CS,
+ GDBMACH_SS,
+ GDBMACH_DS,
+ GDBMACH_ES,
+ GDBMACH_FS,
+ GDBMACH_GS,
GDBMACH_NREGS,
- GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
};
+#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
+
/* Breakpoint types */
enum {
GDBMACH_BPMEM,
@@ -33,21 +54,27 @@ enum {
GDBMACH_AWATCH,
};
+/* Exception vectors */
+extern void gdbmach_sigfpe ( void );
+extern void gdbmach_sigtrap ( void );
+extern void gdbmach_sigstkflt ( void );
+extern void gdbmach_sigill ( void );
+
static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
- regs [ GDBMACH_EIP ] = pc;
+ regs[GDBMACH_RIP] = pc;
}
static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
- regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
- regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
+ regs[GDBMACH_RFLAGS] &= ~( 1 << 8 ); /* Trace Flag (TF) */
+ regs[GDBMACH_RFLAGS] |= ( step << 8 );
}
static inline void gdbmach_breakpoint ( void ) {
__asm__ __volatile__ ( "int $3\n" );
}
-extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
-
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
+ int enable );
extern void gdbmach_init ( void );
#endif /* GDBMACH_H */