1 /*
2 * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2002, Manuel J. Petit. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
8
9 /** Contains the code to interface with a remote GDB */
10
11 #include "gdb.h"
12
13 #include <string.h>
14 #include <stdarg.h>
15 #include <stdio.h>
16
17 #include <ByteOrder.h>
18
19 #include <arch/debug.h>
20 #include <arch/debug_console.h>
21 #include <debug.h>
22 #include <elf.h>
23 #include <elf_priv.h>
24 #include <smp.h>
25 #include <vm/vm.h>
26
27
28 enum { INIT = 0, CMDREAD, CKSUM1, CKSUM2, WAITACK, QUIT, GDBSTATES };
29
30
31 static char sCommand[512];
32 static int sCommandIndex;
33 static int sCheckSum;
34
35 static char sReply[512];
36 static char sSafeMemory[512];
37
38
39 // utility functions
40
41
42 static int
parse_nibble(int input)43 parse_nibble(int input)
44 {
45 int nibble = 0xff;
46
47 if (input >= '0' && input <= '9')
48 nibble = input - '0';
49
50 if (input >= 'A' && input <= 'F')
51 nibble = 0x0a + input - 'A';
52
53 if (input >= 'a' && input <= 'f')
54 nibble = 0x0a + input - 'a';
55
56 return nibble;
57 }
58
59
60 // #pragma mark - GDB protocol
61
62
63 static void
gdb_ack(void)64 gdb_ack(void)
65 {
66 arch_debug_serial_putchar('+');
67 }
68
69
70 static void
gdb_nak(void)71 gdb_nak(void)
72 {
73 arch_debug_serial_putchar('-');
74 }
75
76
77 static void
gdb_resend_reply(void)78 gdb_resend_reply(void)
79 {
80 arch_debug_serial_puts(sReply);
81 }
82
83
84 static void
gdb_reply(char const * format,...)85 gdb_reply(char const* format, ...)
86 {
87 int i;
88 int len;
89 int sum;
90 va_list args;
91
92 va_start(args, format);
93 sReply[0] = '$';
94 vsprintf(sReply + 1, format, args);
95 va_end(args);
96
97 len = strlen(sReply);
98 sum = 0;
99 for (i = 1; i < len; i++) {
100 sum += sReply[i];
101 }
102 sum %= 256;
103
104 sprintf(sReply + len, "#%02x", sum);
105
106 gdb_resend_reply();
107 }
108
109
110 static void
gdb_regreply()111 gdb_regreply()
112 {
113 sReply[0] = '$';
114
115 // get registers (architecture specific)
116 ssize_t bytesWritten = arch_debug_gdb_get_registers(sReply + 1,
117 sizeof(sReply) - 1);
118 if (bytesWritten < 0) {
119 gdb_reply("E01");
120 return;
121 }
122
123 // add 1 for the leading '$'
124 bytesWritten++;
125
126 // compute check sum
127 int sum = 0;
128 for (int32 i = 1; i < bytesWritten; i++)
129 sum += sReply[i];
130 sum %= 256;
131
132 // print check sum
133 int result = snprintf(sReply + bytesWritten, sizeof(sReply) - bytesWritten,
134 "#%02x", sum);
135 if (result >= (ssize_t)sizeof(sReply) - bytesWritten) {
136 gdb_reply("E01");
137 return;
138 }
139
140 gdb_resend_reply();
141 }
142
143
144 static void
gdb_memreply(char const * bytes,int numbytes)145 gdb_memreply(char const* bytes, int numbytes)
146 {
147 int i;
148 int len;
149 int sum;
150
151 sReply[0] = '$';
152 for (i = 0; i < numbytes; i++)
153 sprintf(sReply + 1 + 2 * i, "%02x", (uint8)bytes[i]);
154
155 len = strlen(sReply);
156 sum = 0;
157 for (i = 1; i < len; i++)
158 sum += sReply[i];
159 sum %= 256;
160
161 sprintf(sReply + len, "#%02x", sum);
162
163 gdb_resend_reply();
164 }
165
166
167 // #pragma mark - checksum verification
168
169
170 static int
gdb_verify_checksum(void)171 gdb_verify_checksum(void)
172 {
173 int i;
174 int len;
175 int sum;
176
177 len = strlen(sCommand);
178 sum = 0;
179 for (i = 0; i < len; i++)
180 sum += sCommand[i];
181 sum %= 256;
182
183 return (sum == sCheckSum) ? 1 : 0;
184 }
185
186
187 // #pragma mark - command parsing
188
189
190 static int
gdb_parse_command(void)191 gdb_parse_command(void)
192 {
193 if (!gdb_verify_checksum()) {
194 gdb_nak();
195 return INIT;
196 } else
197 gdb_ack();
198
199 switch (sCommand[0]) {
200 case '?':
201 // command '?' is used for retrieving the signal
202 // that stopped the program. Fully implemeting
203 // this command requires help from the debugger,
204 // by now we just fake a SIGKILL
205 gdb_reply("S09"); /* SIGKILL = 9 */
206 break;
207
208 case 'H':
209 // Command H (actually Hct) is used to select
210 // the current thread (-1 meaning all threads)
211 // We just fake we recognize the the command
212 // and send an 'OK' response.
213 gdb_reply("OK");
214 break;
215
216 case 'q':
217 {
218 // query commands
219
220 if (strcmp(sCommand + 1, "Supported") == 0) {
221 // get the supported features
222 gdb_reply("");
223 } else if (strcmp(sCommand + 1, "Offsets") == 0) {
224 // get the segment offsets
225 elf_image_info* kernelImage = elf_get_kernel_image();
226 gdb_reply("Text=%lx;Data=%lx;Bss=%lx",
227 kernelImage->text_region.delta,
228 kernelImage->data_region.delta,
229 kernelImage->data_region.delta);
230 } else
231 gdb_reply("");
232
233 break;
234 }
235
236 case 'c':
237 // continue at address
238 // TODO: Parse the address and resume there!
239 return QUIT;
240
241 case 'g':
242 gdb_regreply();
243 break;
244
245 case 'G':
246 // write registers
247 // TODO: Implement!
248 gdb_reply("E01");
249 break;
250
251
252 case 'm':
253 {
254 char* ptr;
255 addr_t address;
256 size_t len;
257
258 // The 'm' command has the form mAAA,LLL
259 // where AAA is the address and LLL is the
260 // number of bytes.
261 ptr = sCommand + 1;
262 address = 0;
263 len = 0;
264 while (ptr && *ptr && (*ptr != ',')) {
265 address <<= 4;
266 address += parse_nibble(*ptr);
267 ptr += 1;
268 }
269 if (*ptr == ',')
270 ptr += 1;
271
272 while (ptr && *ptr) {
273 len <<= 4;
274 len += parse_nibble(*ptr);
275 ptr += 1;
276 }
277
278 if (len > 128)
279 len = 128;
280
281 // We cannot directly access the requested memory
282 // for gdb may be trying to access an stray pointer
283 // We copy the memory to a safe buffer using
284 // the bulletproof debug_memcpy().
285 if (debug_memcpy(B_CURRENT_TEAM, sSafeMemory, (char*)address, len)
286 < 0) {
287 gdb_reply("E02");
288 } else
289 gdb_memreply(sSafeMemory, len);
290
291 break;
292 }
293
294 case 'D':
295 // detach
296 return QUIT;
297
298 case 'k':
299 // Command 'k' actual semantics is 'kill the damn thing'.
300 // However gdb sends that command when you disconnect
301 // from a debug session. I guess that 'kill' for the
302 // kernel would map to reboot... however that's a
303 // a very mean thing to do, instead we just quit
304 // the gdb state machine and fallback to the regular
305 // kernel debugger command prompt.
306 return QUIT;
307
308 case 's':
309 // "step" -- resume (?) at address
310 // TODO: Implement!
311 gdb_reply("E01");
312 break;
313
314 default:
315 gdb_reply("");
316 break;
317 }
318
319 return WAITACK;
320 }
321
322
323 // #pragma mark - protocol state machine
324
325
326 static int
gdb_init_handler(int input)327 gdb_init_handler(int input)
328 {
329 switch (input) {
330 case '$':
331 memset(sCommand, 0, sizeof(sCommand));
332 sCommandIndex = 0;
333 return CMDREAD;
334
335 default:
336 #if 0
337 gdb_nak();
338 #else
339 // looks to me like we should send
340 // a NAK here but it kinda works
341 // better if we just gobble all
342 // junk chars silently
343 #endif
344 return INIT;
345 }
346 }
347
348
349 static int
gdb_cmdread_handler(int input)350 gdb_cmdread_handler(int input)
351 {
352 switch (input) {
353 case '#':
354 return CKSUM1;
355
356 default:
357 sCommand[sCommandIndex] = input;
358 sCommandIndex += 1;
359 return CMDREAD;
360 }
361 }
362
363
364 static int
gdb_cksum1_handler(int input)365 gdb_cksum1_handler(int input)
366 {
367 int nibble = parse_nibble(input);
368
369 if (nibble == 0xff) {
370 #if 0
371 gdb_nak();
372 return INIT;
373 #else
374 // looks to me like we should send
375 // a NAK here but it kinda works
376 // better if we just gobble all
377 // junk chars silently
378 #endif
379 }
380
381 sCheckSum = nibble << 4;
382
383 return CKSUM2;
384 }
385
386
387 static int
gdb_cksum2_handler(int input)388 gdb_cksum2_handler(int input)
389 {
390 int nibble = parse_nibble(input);
391
392 if (nibble == 0xff) {
393 #if 0
394 gdb_nak();
395 return INIT;
396 #else
397 // looks to me like we should send
398 // a NAK here but it kinda works
399 // better if we just gobble all
400 // junk chars silently
401 #endif
402 }
403
404 sCheckSum += nibble;
405
406 return gdb_parse_command();
407 }
408
409
410 static int
gdb_waitack_handler(int input)411 gdb_waitack_handler(int input)
412 {
413 switch (input) {
414 case '+':
415 return INIT;
416 case '-':
417 gdb_resend_reply();
418 return WAITACK;
419
420 default:
421 // looks like gdb and us are out of sync,
422 // send a NAK and retry from INIT state.
423 gdb_nak();
424 return INIT;
425 }
426 }
427
428
429 static int
gdb_quit_handler(int input)430 gdb_quit_handler(int input)
431 {
432 (void)(input);
433
434 // actually we should never be here
435 return QUIT;
436 }
437
438
439 static int (*dispatch_table[GDBSTATES])(int) = {
440 &gdb_init_handler,
441 &gdb_cmdread_handler,
442 &gdb_cksum1_handler,
443 &gdb_cksum2_handler,
444 &gdb_waitack_handler,
445 &gdb_quit_handler
446 };
447
448
449 static int
gdb_state_dispatch(int curr,int input)450 gdb_state_dispatch(int curr, int input)
451 {
452 if (curr < INIT || curr >= GDBSTATES)
453 return QUIT;
454
455 return dispatch_table[curr](input);
456 }
457
458
459 static int
gdb_state_machine(void)460 gdb_state_machine(void)
461 {
462 int state = INIT;
463 int c;
464
465 while (state != QUIT) {
466 c = arch_debug_serial_getchar();
467 state = gdb_state_dispatch(state, c);
468 }
469
470 return 0;
471 }
472
473
474 // #pragma mark -
475
476
477 int
cmd_gdb(int argc,char ** argv)478 cmd_gdb(int argc, char** argv)
479 {
480 (void)(argc);
481 (void)(argv);
482
483 return gdb_state_machine();
484 }
485