Browse Source

[gdb] Add support for x86_64

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 8 years ago
parent
commit
311a5732c8

+ 8
- 20
src/arch/i386/core/gdbidt.S View File

@@ -15,41 +15,29 @@
15 15
 /* POSIX signal numbers for reporting traps to GDB */
16 16
 #define SIGILL 4
17 17
 #define SIGTRAP 5
18
-#define SIGBUS 7
19 18
 #define SIGFPE 8
20
-#define SIGSEGV 11
21 19
 #define SIGSTKFLT 16
22 20
 
23
-	.globl	gdbmach_nocode_sigfpe
24
-gdbmach_nocode_sigfpe:
21
+	.globl	gdbmach_sigfpe
22
+gdbmach_sigfpe:
25 23
 	pushl	$SIGFPE
26 24
 	jmp	gdbmach_interrupt
27 25
 
28
-	.globl	gdbmach_nocode_sigtrap
29
-gdbmach_nocode_sigtrap:
26
+	.globl	gdbmach_sigtrap
27
+gdbmach_sigtrap:
30 28
 	pushl	$SIGTRAP
31 29
 	jmp	gdbmach_interrupt
32 30
 
33
-	.globl	gdbmach_nocode_sigstkflt
34
-gdbmach_nocode_sigstkflt:
31
+	.globl	gdbmach_sigstkflt
32
+gdbmach_sigstkflt:
35 33
 	pushl	$SIGSTKFLT
36 34
 	jmp	gdbmach_interrupt
37 35
 
38
-	.globl	gdbmach_nocode_sigill
39
-gdbmach_nocode_sigill:
36
+	.globl	gdbmach_sigill
37
+gdbmach_sigill:
40 38
 	pushl	$SIGILL
41 39
 	jmp	gdbmach_interrupt
42 40
 
43
-	.globl	gdbmach_withcode_sigbus
44
-gdbmach_withcode_sigbus:
45
-	movl	$SIGBUS, (%esp)
46
-	jmp	gdbmach_interrupt
47
-
48
-	.globl	gdbmach_withcode_sigsegv
49
-gdbmach_withcode_sigsegv:
50
-	movl	$SIGSEGV, (%esp)
51
-	jmp	gdbmach_interrupt
52
-
53 41
 /* When invoked, the stack contains: eflags, cs, eip, signo. */
54 42
 #define IH_OFFSET_GDB_REGS ( 0 )
55 43
 #define IH_OFFSET_GDB_EIP ( IH_OFFSET_GDB_REGS + SIZEOF_I386_REGS )

+ 0
- 184
src/arch/i386/core/gdbmach.c View File

@@ -1,184 +0,0 @@
1
-/*
2
- * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
3
- *
4
- * This program is free software; you can redistribute it and/or
5
- * modify it under the terms of the GNU General Public License as
6
- * published by the Free Software Foundation; either version 2 of the
7
- * License, or any later version.
8
- *
9
- * This program is distributed in the hope that it will be useful, but
10
- * WITHOUT ANY WARRANTY; without even the implied warranty of
11
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
- * General Public License for more details.
13
- *
14
- * You should have received a copy of the GNU General Public License
15
- * along with this program; if not, write to the Free Software
16
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
- * 02110-1301, USA.
18
- *
19
- * You can also choose to distribute this program under the terms of
20
- * the Unmodified Binary Distribution Licence (as given in the file
21
- * COPYING.UBDL), provided that you have satisfied its requirements.
22
- */
23
-
24
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
-
26
-#include <stddef.h>
27
-#include <stdio.h>
28
-#include <assert.h>
29
-#include <ipxe/uaccess.h>
30
-#include <ipxe/gdbstub.h>
31
-#include <librm.h>
32
-#include <gdbmach.h>
33
-
34
-/** @file
35
- *
36
- * GDB architecture-specific bits for i386
37
- *
38
- */
39
-
40
-enum {
41
-	DR7_CLEAR = 0x00000400,    /* disable hardware breakpoints */
42
-	DR6_CLEAR = 0xffff0ff0,    /* clear breakpoint status */
43
-};
44
-
45
-/** Hardware breakpoint, fields stored in x86 bit pattern form */
46
-struct hwbp {
47
-	int type;           /* type (1=write watchpoint, 3=access watchpoint) */
48
-	unsigned long addr; /* linear address */
49
-	size_t len;         /* length (0=1-byte, 1=2-byte, 3=4-byte) */
50
-	int enabled;
51
-};
52
-
53
-static struct hwbp hwbps [ 4 ];
54
-static gdbreg_t dr7 = DR7_CLEAR;
55
-
56
-static struct hwbp *gdbmach_find_hwbp ( int type, unsigned long addr, size_t len ) {
57
-	struct hwbp *available = NULL;
58
-	unsigned int i;
59
-	for ( i = 0; i < sizeof hwbps / sizeof hwbps [ 0 ]; i++ ) {
60
-		if ( hwbps [ i ].type == type && hwbps [ i ].addr == addr && hwbps [ i ].len == len ) {
61
-			return &hwbps [ i ];
62
-		}
63
-		if ( !hwbps [ i ].enabled ) {
64
-			available = &hwbps [ i ];
65
-		}
66
-	}
67
-	return available;
68
-}
69
-
70
-static void gdbmach_commit_hwbp ( struct hwbp *bp ) {
71
-	unsigned int regnum = bp - hwbps;
72
-
73
-	/* Set breakpoint address */
74
-	assert ( regnum < ( sizeof hwbps / sizeof hwbps [ 0 ] ) );
75
-	switch ( regnum ) {
76
-		case 0:
77
-			__asm__ __volatile__ ( "movl %0, %%dr0\n" : : "r" ( bp->addr ) );
78
-			break;
79
-		case 1:
80
-			__asm__ __volatile__ ( "movl %0, %%dr1\n" : : "r" ( bp->addr ) );
81
-			break;
82
-		case 2:
83
-			__asm__ __volatile__ ( "movl %0, %%dr2\n" : : "r" ( bp->addr ) );
84
-			break;
85
-		case 3:
86
-			__asm__ __volatile__ ( "movl %0, %%dr3\n" : : "r" ( bp->addr ) );
87
-			break;
88
-	}
89
-
90
-	/* Set type */
91
-	dr7 &= ~( 0x3 << ( 16 + 4 * regnum ) );
92
-	dr7 |= bp->type << ( 16 + 4 * regnum );
93
-
94
-	/* Set length */
95
-	dr7 &= ~( 0x3 << ( 18 + 4 * regnum ) );
96
-	dr7 |= bp->len << ( 18 + 4 * regnum );
97
-
98
-	/* Set/clear local enable bit */
99
-	dr7 &= ~( 0x3 << 2 * regnum );
100
- 	dr7 |= bp->enabled << 2 * regnum;
101
-}
102
-
103
-int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable ) {
104
-	struct hwbp *bp;
105
-	
106
-	/* Check and convert breakpoint type to x86 type */
107
-	switch ( type ) {
108
-		case GDBMACH_WATCH:
109
-			type = 0x1;
110
-			break;
111
-		case GDBMACH_AWATCH:
112
-			type = 0x3;
113
-			break;
114
-		default:
115
-			return 0; /* unsupported breakpoint type */
116
-	}
117
-
118
-	/* Only lengths 1, 2, and 4 are supported */
119
-	if ( len != 2 && len != 4 ) {
120
-		len = 1;
121
-	}
122
-	len--; /* convert to x86 breakpoint length bit pattern */
123
-
124
-	/* Calculate linear address by adding segment base */
125
-	addr += virt_offset;
126
-
127
-	/* Set up the breakpoint */
128
-	bp = gdbmach_find_hwbp ( type, addr, len );
129
-	if ( !bp ) {
130
-		return 0; /* ran out of hardware breakpoints */
131
-	}
132
-	bp->type = type;
133
-	bp->addr = addr;
134
-	bp->len = len;
135
-	bp->enabled = enable;
136
-	gdbmach_commit_hwbp ( bp );
137
-	return 1;
138
-}
139
-
140
-static void gdbmach_disable_hwbps ( void ) {
141
-	/* Store and clear hardware breakpoints */
142
-	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( DR7_CLEAR ) );
143
-}
144
-
145
-static void gdbmach_enable_hwbps ( void ) {
146
-	/* Clear breakpoint status register */
147
-	__asm__ __volatile__ ( "movl %0, %%dr6\n" : : "r" ( DR6_CLEAR ) );
148
-
149
-	/* Restore hardware breakpoints */
150
-	__asm__ __volatile__ ( "movl %0, %%dr7\n" : : "r" ( dr7 ) );
151
-}
152
-
153
-__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
154
-	gdbmach_disable_hwbps();
155
-	gdbstub_handler ( signo, regs );
156
-	gdbmach_enable_hwbps();
157
-}
158
-
159
-static void * gdbmach_interrupt_vectors[] = {
160
-	gdbmach_nocode_sigfpe,		/* Divide by zero */
161
-	gdbmach_nocode_sigtrap,		/* Debug trap */
162
-	NULL,				/* Non-maskable interrupt */
163
-	gdbmach_nocode_sigtrap,		/* Breakpoint */
164
-	gdbmach_nocode_sigstkflt,	/* Overflow */
165
-	gdbmach_nocode_sigstkflt,	/* Bound range exceeded */
166
-	gdbmach_nocode_sigill,		/* Invalid opcode */
167
-	NULL,				/* Device not available */
168
-	gdbmach_withcode_sigbus,	/* Double fault */
169
-	NULL,				/* Coprocessor segment overrun */
170
-	gdbmach_withcode_sigsegv,	/* Invalid TSS */
171
-	gdbmach_withcode_sigsegv,	/* Segment not present */
172
-	gdbmach_withcode_sigsegv,	/* Stack segment fault */
173
-	gdbmach_withcode_sigsegv,	/* General protection fault */
174
-	gdbmach_withcode_sigsegv,	/* Page fault */
175
-};
176
-
177
-void gdbmach_init ( void ) {
178
-	unsigned int i;
179
-
180
-	for ( i = 0 ; i < ( sizeof ( gdbmach_interrupt_vectors ) /
181
-			    sizeof ( gdbmach_interrupt_vectors[0] ) ) ; i++ ) {
182
-		set_interrupt_vector ( i, gdbmach_interrupt_vectors[i] );
183
-	}
184
-}

+ 4
- 6
src/arch/i386/include/gdbmach.h View File

@@ -47,12 +47,10 @@ enum {
47 47
 };
48 48
 
49 49
 /* Interrupt vectors */
50
-extern void gdbmach_nocode_sigfpe ( void );
51
-extern void gdbmach_nocode_sigtrap ( void );
52
-extern void gdbmach_nocode_sigstkflt ( void );
53
-extern void gdbmach_nocode_sigill ( void );
54
-extern void gdbmach_withcode_sigbus ( void );
55
-extern void gdbmach_withcode_sigsegv ( void );
50
+extern void gdbmach_sigfpe ( void );
51
+extern void gdbmach_sigtrap ( void );
52
+extern void gdbmach_sigstkflt ( void );
53
+extern void gdbmach_sigill ( void );
56 54
 
57 55
 static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
58 56
 	regs [ GDBMACH_EIP ] = pc;

+ 251
- 0
src/arch/x86/core/gdbmach.c View File

@@ -0,0 +1,251 @@
1
+/*
2
+ * Copyright (C) 2008 Stefan Hajnoczi <stefanha@gmail.com>.
3
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
4
+ *
5
+ * This program is free software; you can redistribute it and/or
6
+ * modify it under the terms of the GNU General Public License as
7
+ * published by the Free Software Foundation; either version 2 of the
8
+ * License, or any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful, but
11
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
+ * General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with this program; if not, write to the Free Software
17
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18
+ * 02110-1301, USA.
19
+ *
20
+ * You can also choose to distribute this program under the terms of
21
+ * the Unmodified Binary Distribution Licence (as given in the file
22
+ * COPYING.UBDL), provided that you have satisfied its requirements.
23
+ */
24
+
25
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
26
+
27
+#include <stddef.h>
28
+#include <stdio.h>
29
+#include <errno.h>
30
+#include <assert.h>
31
+#include <ipxe/uaccess.h>
32
+#include <ipxe/gdbstub.h>
33
+#include <librm.h>
34
+#include <gdbmach.h>
35
+
36
+/** @file
37
+ *
38
+ * GDB architecture-specific bits for x86
39
+ *
40
+ */
41
+
42
+/** Number of hardware breakpoints */
43
+#define NUM_HWBP 4
44
+
45
+/** Debug register 7: Global breakpoint enable */
46
+#define DR7_G( bp ) ( 2 << ( 2 * (bp) ) )
47
+
48
+/** Debug register 7: Global exact breakpoint enable */
49
+#define DR7_GE ( 1 << 9 )
50
+
51
+/** Debug register 7: Break on data writes */
52
+#define DR7_RWLEN_WRITE 0x11110000
53
+
54
+/** Debug register 7: Break on data access */
55
+#define DR7_RWLEN_ACCESS 0x33330000
56
+
57
+/** Debug register 7: One-byte length */
58
+#define DR7_RWLEN_1 0x00000000
59
+
60
+/** Debug register 7: Two-byte length */
61
+#define DR7_RWLEN_2 0x44440000
62
+
63
+/** Debug register 7: Four-byte length */
64
+#define DR7_RWLEN_4 0xcccc0000
65
+
66
+/** Debug register 7: Eight-byte length */
67
+#define DR7_RWLEN_8 0x88880000
68
+
69
+/** Debug register 7: Breakpoint R/W and length mask */
70
+#define DR7_RWLEN_MASK( bp ) ( 0xf0000 << ( 4 * (bp) ) )
71
+
72
+/** Hardware breakpoint addresses (debug registers 0-3) */
73
+static unsigned long dr[NUM_HWBP];
74
+
75
+/** Active value of debug register 7 */
76
+static unsigned long dr7 = DR7_GE;
77
+
78
+/**
79
+ * Update debug registers
80
+ *
81
+ */
82
+static void gdbmach_update ( void ) {
83
+
84
+	/* Set debug registers */
85
+	__asm__ __volatile__ ( "mov %0, %%dr0" : : "r" ( dr[0] ) );
86
+	__asm__ __volatile__ ( "mov %0, %%dr1" : : "r" ( dr[1] ) );
87
+	__asm__ __volatile__ ( "mov %0, %%dr2" : : "r" ( dr[2] ) );
88
+	__asm__ __volatile__ ( "mov %0, %%dr3" : : "r" ( dr[3] ) );
89
+	__asm__ __volatile__ ( "mov %0, %%dr7" : : "r" ( dr7 ) );
90
+}
91
+
92
+/**
93
+ * Find reusable or available hardware breakpoint
94
+ *
95
+ * @v addr		Linear address
96
+ * @v rwlen		Control bits
97
+ * @ret bp		Hardware breakpoint, or negative error
98
+ */
99
+static int gdbmach_find ( unsigned long addr, unsigned int rwlen ) {
100
+	unsigned int i;
101
+	int bp = -ENOENT;
102
+
103
+	/* Look for a reusable or available breakpoint */
104
+	for ( i = 0 ; i < NUM_HWBP ; i++ ) {
105
+
106
+		/* If breakpoint is not enabled, then it is available */
107
+		if ( ! ( dr7 & DR7_G ( i ) ) ) {
108
+			bp = i;
109
+			continue;
110
+		}
111
+
112
+		/* If breakpoint is enabled and has the same address
113
+		 * and control bits, then reuse it.
114
+		 */
115
+		if ( ( dr[i] == addr ) &&
116
+		     ( ( ( dr7 ^ rwlen ) & DR7_RWLEN_MASK ( i ) ) == 0 ) ) {
117
+			bp = i;
118
+			break;
119
+		}
120
+	}
121
+
122
+	return bp;
123
+}
124
+
125
+/**
126
+ * Set hardware breakpoint
127
+ *
128
+ * @v type		GDB breakpoint type
129
+ * @v addr		Virtual address
130
+ * @v len		Length
131
+ * @v enable		Enable (not disable) breakpoint
132
+ * @ret rc		Return status code
133
+ */
134
+int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
135
+			     int enable ) {
136
+	unsigned int rwlen;
137
+	unsigned long mask;
138
+	int bp;
139
+
140
+	/* Parse breakpoint type */
141
+	switch ( type ) {
142
+	case GDBMACH_WATCH:
143
+		rwlen = DR7_RWLEN_WRITE;
144
+		break;
145
+	case GDBMACH_AWATCH:
146
+		rwlen = DR7_RWLEN_ACCESS;
147
+		break;
148
+	default:
149
+		return -ENOTSUP;
150
+	}
151
+
152
+	/* Parse breakpoint length */
153
+	switch ( len ) {
154
+	case 1:
155
+		rwlen |= DR7_RWLEN_1;
156
+		break;
157
+	case 2:
158
+		rwlen |= DR7_RWLEN_2;
159
+		break;
160
+	case 4:
161
+		rwlen |= DR7_RWLEN_4;
162
+		break;
163
+	case 8:
164
+		rwlen |= DR7_RWLEN_8;
165
+		break;
166
+	default:
167
+		return -ENOTSUP;
168
+	}
169
+
170
+	/* Convert to linear address */
171
+	if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
172
+		addr = virt_to_phys ( ( void * ) addr );
173
+
174
+	/* Find reusable or available hardware breakpoint */
175
+	bp = gdbmach_find ( addr, rwlen );
176
+	if ( bp < 0 )
177
+		return ( enable ? -ENOBUFS : 0 );
178
+
179
+	/* Configure this breakpoint */
180
+	DBGC ( &dr[0], "GDB bp %d at %p+%zx type %d (%sabled)\n",
181
+	       bp, ( ( void * ) addr ), len, type, ( enable ? "en" : "dis" ) );
182
+	dr[bp] = addr;
183
+	mask = DR7_RWLEN_MASK ( bp );
184
+	dr7 = ( ( dr7 & ~mask ) | ( rwlen & mask ) );
185
+	mask = DR7_G ( bp );
186
+	dr7 &= ~mask;
187
+	if ( enable )
188
+		dr7 |= mask;
189
+
190
+	/* Update debug registers */
191
+	gdbmach_update();
192
+
193
+	return 0;
194
+}
195
+
196
+/**
197
+ * Handle exception
198
+ *
199
+ * @v signo		GDB signal number
200
+ * @v regs		Register dump
201
+ */
202
+__asmcall void gdbmach_handler ( int signo, gdbreg_t *regs ) {
203
+	unsigned long dr7_disabled = DR7_GE;
204
+	unsigned long dr6_clear = 0;
205
+
206
+	/* Temporarily disable breakpoints */
207
+	__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7_disabled ) );
208
+
209
+	/* Handle exception */
210
+	DBGC ( &dr[0], "GDB signal %d\n", signo );
211
+	DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
212
+	gdbstub_handler ( signo, regs );
213
+	DBGC ( &dr[0], "GDB signal %d returning\n", signo );
214
+	DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
215
+
216
+	/* Clear breakpoint status register */
217
+	__asm__ __volatile__ ( "mov %0, %%dr6\n" : : "r" ( dr6_clear ) );
218
+
219
+	/* Re-enable breakpoints */
220
+	__asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7 ) );
221
+}
222
+
223
+/**
224
+ * CPU exception vectors
225
+ *
226
+ * Note that we cannot intercept anything from INT8 (double fault)
227
+ * upwards, since these overlap by default with IRQ0-7.
228
+ */
229
+static void * gdbmach_vectors[] = {
230
+	gdbmach_sigfpe,		/* Divide by zero */
231
+	gdbmach_sigtrap,	/* Debug trap */
232
+	NULL,			/* Non-maskable interrupt */
233
+	gdbmach_sigtrap,	/* Breakpoint */
234
+	gdbmach_sigstkflt,	/* Overflow */
235
+	gdbmach_sigstkflt,	/* Bound range exceeded */
236
+	gdbmach_sigill,		/* Invalid opcode */
237
+};
238
+
239
+/**
240
+ * Initialise GDB
241
+ */
242
+void gdbmach_init ( void ) {
243
+	unsigned int i;
244
+
245
+	/* Hook CPU exception vectors */
246
+	for ( i = 0 ; i < ( sizeof ( gdbmach_vectors ) /
247
+			    sizeof ( gdbmach_vectors[0] ) ) ; i++ ) {
248
+		if ( gdbmach_vectors[i] )
249
+			set_interrupt_vector ( i, gdbmach_vectors[i] );
250
+	}
251
+}

+ 1
- 0
src/arch/x86/include/bits/errfile.h View File

@@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
22 22
 #define ERRFILE_apm		( ERRFILE_ARCH | ERRFILE_CORE | 0x000b0000 )
23 23
 #define ERRFILE_vesafb		( ERRFILE_ARCH | ERRFILE_CORE | 0x000c0000 )
24 24
 #define ERRFILE_int13con	( ERRFILE_ARCH | ERRFILE_CORE | 0x000d0000 )
25
+#define ERRFILE_gdbmach		( ERRFILE_ARCH | ERRFILE_CORE | 0x000e0000 )
25 26
 
26 27
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
27 28
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

+ 168
- 0
src/arch/x86_64/core/gdbidt.S View File

@@ -0,0 +1,168 @@
1
+/*
2
+ * Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/** @file
27
+ *
28
+ * GDB exception handlers
29
+ *
30
+ */
31
+
32
+/* Size of a register */
33
+#define SIZEOF_REG 8
34
+
35
+/* POSIX signal numbers for reporting traps to GDB */
36
+#define SIGILL 4
37
+#define SIGTRAP 5
38
+#define SIGFPE 8
39
+#define SIGSTKFLT 16
40
+
41
+	.section ".text.gdbmach_interrupt", "ax", @progbits
42
+	.code64
43
+
44
+	.struct 0
45
+/* Register dump created for GDB stub */
46
+regs:
47
+regs_rax:	.space	SIZEOF_REG
48
+regs_rbx:	.space	SIZEOF_REG
49
+regs_rcx:	.space	SIZEOF_REG
50
+regs_rdx:	.space	SIZEOF_REG
51
+regs_rsi:	.space	SIZEOF_REG
52
+regs_rdi:	.space	SIZEOF_REG
53
+regs_rbp:	.space	SIZEOF_REG
54
+regs_rsp:	.space	SIZEOF_REG
55
+regs_r8:	.space	SIZEOF_REG
56
+regs_r9:	.space	SIZEOF_REG
57
+regs_r10:	.space	SIZEOF_REG
58
+regs_r11:	.space	SIZEOF_REG
59
+regs_r12:	.space	SIZEOF_REG
60
+regs_r13:	.space	SIZEOF_REG
61
+regs_r14:	.space	SIZEOF_REG
62
+regs_r15:	.space	SIZEOF_REG
63
+regs_rip:	.space	SIZEOF_REG
64
+regs_rflags:	.space	SIZEOF_REG
65
+regs_cs:	.space	SIZEOF_REG
66
+regs_ss:	.space	SIZEOF_REG
67
+regs_ds:	.space	SIZEOF_REG
68
+regs_es:	.space	SIZEOF_REG
69
+regs_fs:	.space	SIZEOF_REG
70
+regs_gs:	.space	SIZEOF_REG
71
+regs_end:
72
+/* GDB signal code */
73
+gdb:
74
+gdb_code:	.space	SIZEOF_REG
75
+gdb_end:
76
+/* Long-mode exception frame */
77
+frame:
78
+frame_rip:	.space	SIZEOF_REG
79
+frame_cs:	.space	SIZEOF_REG
80
+frame_rflags:	.space	SIZEOF_REG
81
+frame_rsp:	.space	SIZEOF_REG
82
+frame_ss:	.space	SIZEOF_REG
83
+frame_end:
84
+	.previous
85
+
86
+	.globl	gdbmach_sigfpe
87
+gdbmach_sigfpe:
88
+	push	$SIGFPE
89
+	jmp	gdbmach_interrupt
90
+
91
+	.globl	gdbmach_sigtrap
92
+gdbmach_sigtrap:
93
+	push	$SIGTRAP
94
+	jmp	gdbmach_interrupt
95
+
96
+	.globl	gdbmach_sigstkflt
97
+gdbmach_sigstkflt:
98
+	push	$SIGSTKFLT
99
+	jmp	gdbmach_interrupt
100
+
101
+	.globl	gdbmach_sigill
102
+gdbmach_sigill:
103
+	push	$SIGILL
104
+	jmp	gdbmach_interrupt
105
+
106
+gdbmach_interrupt:
107
+
108
+	/* Create register dump */
109
+	pushq	%gs
110
+	pushq	%fs
111
+	pushq	$0		/* %es unused in long mode */
112
+	pushq	$0		/* %ds unused in long mode */
113
+	pushq	( frame_ss	- regs_ss	- SIZEOF_REG )(%rsp)
114
+	pushq	( frame_cs	- regs_cs	- SIZEOF_REG )(%rsp)
115
+	pushq	( frame_rflags	- regs_rflags	- SIZEOF_REG )(%rsp)
116
+	pushq	( frame_rip	- regs_rip	- SIZEOF_REG )(%rsp)
117
+	pushq	%r15
118
+	pushq	%r14
119
+	pushq	%r13
120
+	pushq	%r12
121
+	pushq	%r11
122
+	pushq	%r10
123
+	pushq	%r9
124
+	pushq	%r8
125
+	pushq	( frame_rsp	- regs_rsp	- SIZEOF_REG )(%rsp)
126
+	pushq	%rbp
127
+	pushq	%rdi
128
+	pushq	%rsi
129
+	pushq	%rdx
130
+	pushq	%rcx
131
+	pushq	%rbx
132
+	pushq	%rax
133
+
134
+	/* Call GDB stub exception handler */
135
+	movq	gdb_code(%rsp), %rdi
136
+	movq	%rsp, %rsi
137
+	call	gdbmach_handler
138
+
139
+	/* Restore from register dump */
140
+	popq	%rax
141
+	popq	%rbx
142
+	popq	%rcx
143
+	popq	%rdx
144
+	popq	%rsi
145
+	popq	%rdi
146
+	popq	%rbp
147
+	popq	( frame_rsp	- regs_rsp	- SIZEOF_REG )(%rsp)
148
+	popq	%r8
149
+	popq	%r9
150
+	popq	%r10
151
+	popq	%r11
152
+	popq	%r12
153
+	popq	%r13
154
+	popq	%r14
155
+	popq	%r15
156
+	popq	( frame_rip	- regs_rip	- SIZEOF_REG )(%rsp)
157
+	popq	( frame_rflags	- regs_rflags	- SIZEOF_REG )(%rsp)
158
+	popq	( frame_cs	- regs_cs	- SIZEOF_REG )(%rsp)
159
+	popq	( frame_ss	- regs_ss	- SIZEOF_REG )(%rsp)
160
+	addq	$( regs_fs - regs_ds ), %rsp	/* skip %ds, %es */
161
+	popq	%fs
162
+	popq	%gs
163
+
164
+	/* Skip code */
165
+	addq	$( gdb_end - gdb_code ), %rsp	/* skip code */
166
+
167
+	/* Return */
168
+	iretq

+ 38
- 11
src/arch/x86_64/include/gdbmach.h View File

@@ -14,16 +14,37 @@
14 14
 
15 15
 typedef unsigned long gdbreg_t;
16 16
 
17
-/* The register snapshot, this must be in sync with interrupt handler and the
18
- * GDB protocol. */
17
+/* Register snapshot */
19 18
 enum {
20
-	// STUB: don't expect this to work!
21
-	GDBMACH_EIP,
22
-	GDBMACH_EFLAGS,
19
+	GDBMACH_RAX,
20
+	GDBMACH_RBX,
21
+	GDBMACH_RCX,
22
+	GDBMACH_RDX,
23
+	GDBMACH_RSI,
24
+	GDBMACH_RDI,
25
+	GDBMACH_RBP,
26
+	GDBMACH_RSP,
27
+	GDBMACH_R8,
28
+	GDBMACH_R9,
29
+	GDBMACH_R10,
30
+	GDBMACH_R11,
31
+	GDBMACH_R12,
32
+	GDBMACH_R13,
33
+	GDBMACH_R14,
34
+	GDBMACH_R15,
35
+	GDBMACH_RIP,
36
+	GDBMACH_RFLAGS,
37
+	GDBMACH_CS,
38
+	GDBMACH_SS,
39
+	GDBMACH_DS,
40
+	GDBMACH_ES,
41
+	GDBMACH_FS,
42
+	GDBMACH_GS,
23 43
 	GDBMACH_NREGS,
24
-	GDBMACH_SIZEOF_REGS = GDBMACH_NREGS * sizeof ( gdbreg_t )
25 44
 };
26 45
 
46
+#define GDBMACH_SIZEOF_REGS ( GDBMACH_NREGS * sizeof ( gdbreg_t ) )
47
+
27 48
 /* Breakpoint types */
28 49
 enum {
29 50
 	GDBMACH_BPMEM,
@@ -33,21 +54,27 @@ enum {
33 54
 	GDBMACH_AWATCH,
34 55
 };
35 56
 
57
+/* Exception vectors */
58
+extern void gdbmach_sigfpe ( void );
59
+extern void gdbmach_sigtrap ( void );
60
+extern void gdbmach_sigstkflt ( void );
61
+extern void gdbmach_sigill ( void );
62
+
36 63
 static inline void gdbmach_set_pc ( gdbreg_t *regs, gdbreg_t pc ) {
37
-	regs [ GDBMACH_EIP ] = pc;
64
+	regs[GDBMACH_RIP] = pc;
38 65
 }
39 66
 
40 67
 static inline void gdbmach_set_single_step ( gdbreg_t *regs, int step ) {
41
-	regs [ GDBMACH_EFLAGS ] &= ~( 1 << 8 ); /* Trace Flag (TF) */
42
-	regs [ GDBMACH_EFLAGS ] |= ( step << 8 );
68
+	regs[GDBMACH_RFLAGS] &= ~( 1 << 8 ); /* Trace Flag (TF) */
69
+	regs[GDBMACH_RFLAGS] |= ( step << 8 );
43 70
 }
44 71
 
45 72
 static inline void gdbmach_breakpoint ( void ) {
46 73
 	__asm__ __volatile__ ( "int $3\n" );
47 74
 }
48 75
 
49
-extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len, int enable );
50
-
76
+extern int gdbmach_set_breakpoint ( int type, unsigned long addr, size_t len,
77
+				    int enable );
51 78
 extern void gdbmach_init ( void );
52 79
 
53 80
 #endif /* GDBMACH_H */

+ 7
- 4
src/core/gdbstub.c View File

@@ -40,7 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
40 40
 
41 41
 enum {
42 42
 	POSIX_EINVAL = 0x1c,  /* used to report bad arguments to GDB */
43
-	SIZEOF_PAYLOAD = 256, /* buffer size of GDB payload data */
43
+	SIZEOF_PAYLOAD = 512, /* buffer size of GDB payload data */
44 44
 };
45 45
 
46 46
 struct gdbstub {
@@ -255,17 +255,20 @@ static void gdbstub_continue ( struct gdbstub *stub, int single_step ) {
255 255
 static void gdbstub_breakpoint ( struct gdbstub *stub ) {
256 256
 	unsigned long args [ 3 ];
257 257
 	int enable = stub->payload [ 0 ] == 'Z' ? 1 : 0;
258
+	int rc;
259
+
258 260
 	if ( !gdbstub_get_packet_args ( stub, args, sizeof args / sizeof args [ 0 ], NULL ) ) {
259 261
 		gdbstub_send_errno ( stub, POSIX_EINVAL );
260 262
 		return;
261 263
 	}
262
-	if ( gdbmach_set_breakpoint ( args [ 0 ], args [ 1 ], args [ 2 ], enable ) ) {
263
-		gdbstub_send_ok ( stub );
264
-	} else {
264
+	if ( ( rc = gdbmach_set_breakpoint ( args [ 0 ], args [ 1 ],
265
+					     args [ 2 ], enable ) ) != 0 ) {
265 266
 		/* Not supported */
266 267
 		stub->len = 0;
267 268
 		gdbstub_tx_packet ( stub );
269
+		return;
268 270
 	}
271
+	gdbstub_send_ok ( stub );
269 272
 }
270 273
 
271 274
 static void gdbstub_rx_packet ( struct gdbstub *stub ) {

Loading…
Cancel
Save