1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <kernel_internal.h>
9 #include <ia32/exception.h>
10 #include <inttypes.h>
11 #include <zephyr/debug/gdbstub.h>
12 
13 
14 static struct gdb_ctx debug_ctx;
15 
16 /**
17  * Currently we just handle vectors 1 and 3 but lets keep it generic
18  * to be able to notify other exceptions in the future
19  */
get_exception(unsigned int vector)20 static unsigned int get_exception(unsigned int vector)
21 {
22 	unsigned int exception;
23 
24 	switch (vector) {
25 	case IV_DIVIDE_ERROR:
26 		exception = GDB_EXCEPTION_DIVIDE_ERROR;
27 		break;
28 	case IV_DEBUG:
29 		exception = GDB_EXCEPTION_BREAKPOINT;
30 		break;
31 	case IV_BREAKPOINT:
32 		exception = GDB_EXCEPTION_BREAKPOINT;
33 		break;
34 	case IV_OVERFLOW:
35 		exception = GDB_EXCEPTION_OVERFLOW;
36 		break;
37 	case IV_BOUND_RANGE:
38 		exception = GDB_EXCEPTION_OVERFLOW;
39 		break;
40 	case IV_INVALID_OPCODE:
41 		exception = GDB_EXCEPTION_INVALID_INSTRUCTION;
42 		break;
43 	case IV_DEVICE_NOT_AVAILABLE:
44 		exception = GDB_EXCEPTION_DIVIDE_ERROR;
45 		break;
46 	case IV_DOUBLE_FAULT:
47 		exception = GDB_EXCEPTION_MEMORY_FAULT;
48 		break;
49 	case IV_COPROC_SEGMENT_OVERRUN:
50 		exception = GDB_EXCEPTION_INVALID_MEMORY;
51 		break;
52 	case IV_INVALID_TSS:
53 		exception = GDB_EXCEPTION_INVALID_MEMORY;
54 		break;
55 	case IV_SEGMENT_NOT_PRESENT:
56 		exception = GDB_EXCEPTION_INVALID_MEMORY;
57 		break;
58 	case IV_STACK_FAULT:
59 		exception = GDB_EXCEPTION_INVALID_MEMORY;
60 		break;
61 	case IV_GENERAL_PROTECTION:
62 		exception = GDB_EXCEPTION_INVALID_MEMORY;
63 		break;
64 	case IV_PAGE_FAULT:
65 		exception = GDB_EXCEPTION_INVALID_MEMORY;
66 		break;
67 	case IV_X87_FPU_FP_ERROR:
68 		exception = GDB_EXCEPTION_MEMORY_FAULT;
69 		break;
70 	default:
71 		exception = GDB_EXCEPTION_MEMORY_FAULT;
72 		break;
73 	}
74 
75 	return exception;
76 }
77 
78 /*
79  * Debug exception handler.
80  */
z_gdb_interrupt(unsigned int vector,struct arch_esf * esf)81 static void z_gdb_interrupt(unsigned int vector, struct arch_esf *esf)
82 {
83 	debug_ctx.exception = get_exception(vector);
84 
85 	debug_ctx.registers[GDB_EAX] = esf->eax;
86 	debug_ctx.registers[GDB_ECX] = esf->ecx;
87 	debug_ctx.registers[GDB_EDX] = esf->edx;
88 	debug_ctx.registers[GDB_EBX] = esf->ebx;
89 	debug_ctx.registers[GDB_ESP] = esf->esp;
90 	debug_ctx.registers[GDB_EBP] = esf->ebp;
91 	debug_ctx.registers[GDB_ESI] = esf->esi;
92 	debug_ctx.registers[GDB_EDI] = esf->edi;
93 	debug_ctx.registers[GDB_PC] = esf->eip;
94 	debug_ctx.registers[GDB_CS] = esf->cs;
95 	debug_ctx.registers[GDB_EFLAGS]  = esf->eflags;
96 	debug_ctx.registers[GDB_SS] = esf->ss;
97 	debug_ctx.registers[GDB_DS] = esf->ds;
98 	debug_ctx.registers[GDB_ES] = esf->es;
99 	debug_ctx.registers[GDB_FS] = esf->fs;
100 	debug_ctx.registers[GDB_GS] = esf->gs;
101 
102 	z_gdb_main_loop(&debug_ctx);
103 
104 	esf->eax = debug_ctx.registers[GDB_EAX];
105 	esf->ecx = debug_ctx.registers[GDB_ECX];
106 	esf->edx = debug_ctx.registers[GDB_EDX];
107 	esf->ebx = debug_ctx.registers[GDB_EBX];
108 	esf->esp = debug_ctx.registers[GDB_ESP];
109 	esf->ebp = debug_ctx.registers[GDB_EBP];
110 	esf->esi = debug_ctx.registers[GDB_ESI];
111 	esf->edi = debug_ctx.registers[GDB_EDI];
112 	esf->eip = debug_ctx.registers[GDB_PC];
113 	esf->cs = debug_ctx.registers[GDB_CS];
114 	esf->eflags = debug_ctx.registers[GDB_EFLAGS];
115 	esf->ss = debug_ctx.registers[GDB_SS];
116 	esf->ds = debug_ctx.registers[GDB_DS];
117 	esf->es = debug_ctx.registers[GDB_ES];
118 	esf->fs = debug_ctx.registers[GDB_FS];
119 	esf->gs = debug_ctx.registers[GDB_GS];
120 }
121 
arch_gdb_continue(void)122 void arch_gdb_continue(void)
123 {
124 	/* Clear the TRAP FLAG bit */
125 	debug_ctx.registers[GDB_EFLAGS] &= ~BIT(8);
126 }
127 
arch_gdb_step(void)128 void arch_gdb_step(void)
129 {
130 	/* Set the TRAP FLAG bit */
131 	debug_ctx.registers[GDB_EFLAGS] |= BIT(8);
132 }
133 
arch_gdb_reg_readall(struct gdb_ctx * ctx,uint8_t * buf,size_t buflen)134 size_t arch_gdb_reg_readall(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen)
135 {
136 	size_t ret;
137 
138 	if (buflen < (sizeof(ctx->registers) * 2)) {
139 		ret = 0;
140 	} else {
141 		ret = bin2hex((const uint8_t *)&(ctx->registers),
142 			      sizeof(ctx->registers), buf, buflen);
143 	}
144 
145 	return ret;
146 }
147 
arch_gdb_reg_writeall(struct gdb_ctx * ctx,uint8_t * hex,size_t hexlen)148 size_t arch_gdb_reg_writeall(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen)
149 {
150 	size_t ret;
151 
152 	if (hexlen != (sizeof(ctx->registers) * 2)) {
153 		ret = 0;
154 	} else {
155 		ret = hex2bin(hex, hexlen,
156 			      (uint8_t *)&(ctx->registers),
157 			      sizeof(ctx->registers));
158 	}
159 
160 	return ret;
161 }
162 
arch_gdb_reg_readone(struct gdb_ctx * ctx,uint8_t * buf,size_t buflen,uint32_t regno)163 size_t arch_gdb_reg_readone(struct gdb_ctx *ctx, uint8_t *buf, size_t buflen,
164 			    uint32_t regno)
165 {
166 	size_t ret;
167 
168 	if (buflen < (sizeof(unsigned int) * 2)) {
169 		/* Make sure there is enough space to write hex string */
170 		ret = 0;
171 	} else if (regno >= GDB_STUB_NUM_REGISTERS) {
172 		/* Return hex string "xx" to tell GDB that this register
173 		 * is not available. So GDB will continue probing other
174 		 * registers instead of stopping in the middle of
175 		 * "info registers all".
176 		 */
177 		memcpy(buf, "xx", 2);
178 		ret = 2;
179 	} else {
180 		ret = bin2hex((const uint8_t *)&(ctx->registers[regno]),
181 			      sizeof(ctx->registers[regno]),
182 			      buf, buflen);
183 	}
184 
185 	return ret;
186 }
187 
arch_gdb_reg_writeone(struct gdb_ctx * ctx,uint8_t * hex,size_t hexlen,uint32_t regno)188 size_t arch_gdb_reg_writeone(struct gdb_ctx *ctx, uint8_t *hex, size_t hexlen,
189 			     uint32_t regno)
190 {
191 	size_t ret;
192 
193 	if (regno == GDB_ORIG_EAX) {
194 		/* GDB requires orig_eax that seems to be
195 		 * Linux specific. Unfortunately if we just
196 		 * return error, GDB will stop working.
197 		 * So just fake an OK response by saying
198 		 * that we have processed the hex string.
199 		 */
200 		ret = hexlen;
201 	} else if (regno >= GDB_STUB_NUM_REGISTERS) {
202 		ret = 0;
203 	} else if (hexlen != (sizeof(unsigned int) * 2)) {
204 		/* Make sure the input hex string matches register size */
205 		ret = 0;
206 	} else {
207 		ret = hex2bin(hex, hexlen,
208 			      (uint8_t *)&(ctx->registers[regno]),
209 			      sizeof(ctx->registers[regno]));
210 	}
211 
212 	return ret;
213 }
214 
z_gdb_debug_isr(struct arch_esf * esf)215 static __used void z_gdb_debug_isr(struct arch_esf *esf)
216 {
217 #ifdef CONFIG_GDBSTUB_TRACE
218 	printk("gdbstub:enter %s (IV_DEBUG)\n", __func__);
219 #endif
220 
221 	z_gdb_interrupt(IV_DEBUG, esf);
222 
223 #ifdef CONFIG_GDBSTUB_TRACE
224 	printk("gdbstub:exit %s (IV_DEBUG)\n", __func__);
225 #endif
226 }
227 
z_gdb_break_isr(struct arch_esf * esf)228 static __used void z_gdb_break_isr(struct arch_esf *esf)
229 {
230 #ifdef CONFIG_GDBSTUB_TRACE
231 	printk("gdbstub:enter %s (IV_BREAKPOINT)\n", __func__);
232 #endif
233 
234 	z_gdb_interrupt(IV_BREAKPOINT, esf);
235 
236 #ifdef CONFIG_GDBSTUB_TRACE
237 	printk("gdbstub:exit %s (IV_BREAKPOINT)\n", __func__);
238 #endif
239 }
240 
arch_gdb_init(void)241 void arch_gdb_init(void)
242 {
243 #ifdef CONFIG_GDBSTUB_TRACE
244 	printk("gdbstub:%s awaits GDB connection\n", __func__);
245 #endif
246 
247 	__asm__ volatile ("int3");
248 
249 #ifdef CONFIG_GDBSTUB_TRACE
250 	printk("gdbstub:%s GDB is connected\n", __func__);
251 #endif
252 }
253 
254 /* Hook current IDT. */
255 _EXCEPTION_CONNECT_NOCODE(z_gdb_debug_isr, IV_DEBUG, 3);
256 _EXCEPTION_CONNECT_NOCODE(z_gdb_break_isr, IV_BREAKPOINT, 3);
257