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