1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90#include <common.h>
91
92#include <kgdb.h>
93#include <command.h>
94
95#undef KGDB_DEBUG
96
97
98
99
100#define BUFMAX 1024
101static char remcomInBuffer[BUFMAX];
102static char remcomOutBuffer[BUFMAX];
103static char remcomRegBuffer[BUFMAX];
104
105static int initialized = 0;
106static int kgdb_active;
107static struct pt_regs entry_regs;
108static long error_jmp_buf[BUFMAX/2];
109static int longjmp_on_fault = 0;
110#ifdef KGDB_DEBUG
111static int kdebug = 1;
112#endif
113
114static const char hexchars[]="0123456789abcdef";
115
116
117static int
118hex(unsigned char ch)
119{
120 if (ch >= 'a' && ch <= 'f')
121 return ch-'a'+10;
122 if (ch >= '0' && ch <= '9')
123 return ch-'0';
124 if (ch >= 'A' && ch <= 'F')
125 return ch-'A'+10;
126 return -1;
127}
128
129
130
131
132static unsigned char *
133mem2hex(char *mem, char *buf, int count)
134{
135 char *tmp;
136 unsigned char ch;
137
138
139
140
141
142 tmp = buf + count;
143 longjmp_on_fault = 1;
144
145 memcpy(tmp, mem, count);
146
147 while (count-- > 0) {
148 ch = *tmp++;
149 *buf++ = hexchars[ch >> 4];
150 *buf++ = hexchars[ch & 0xf];
151 }
152 *buf = 0;
153 longjmp_on_fault = 0;
154 return (unsigned char *)buf;
155}
156
157
158
159
160static char *
161hex2mem(char *buf, char *mem, int count)
162{
163 int hexValue;
164 char *tmp_raw, *tmp_hex;
165
166
167
168
169
170 tmp_raw = buf + count * 2;
171 tmp_hex = tmp_raw - 1;
172
173 longjmp_on_fault = 1;
174 while (tmp_hex >= buf) {
175 tmp_raw--;
176 hexValue = hex(*tmp_hex--);
177 if (hexValue < 0)
178 kgdb_error(KGDBERR_NOTHEXDIG);
179 *tmp_raw = hexValue;
180 hexValue = hex(*tmp_hex--);
181 if (hexValue < 0)
182 kgdb_error(KGDBERR_NOTHEXDIG);
183 *tmp_raw |= hexValue << 4;
184
185 }
186
187 memcpy(mem, tmp_raw, count);
188
189 kgdb_flush_cache_range((void *)mem, (void *)(mem+count));
190 longjmp_on_fault = 0;
191
192 return buf;
193}
194
195
196
197
198
199static int
200hexToInt(char **ptr, int *intValue)
201{
202 int numChars = 0;
203 int hexValue;
204
205 *intValue = 0;
206
207 longjmp_on_fault = 1;
208 while (**ptr) {
209 hexValue = hex(**ptr);
210 if (hexValue < 0)
211 break;
212
213 *intValue = (*intValue << 4) | hexValue;
214 numChars ++;
215
216 (*ptr)++;
217 }
218 longjmp_on_fault = 0;
219
220 return (numChars);
221}
222
223
224static void
225getpacket(char *buffer)
226{
227 unsigned char checksum;
228 unsigned char xmitcsum;
229 int i;
230 int count;
231 unsigned char ch;
232
233 do {
234
235
236 while ((ch = (getDebugChar() & 0x7f)) != '$') {
237#ifdef KGDB_DEBUG
238 if (kdebug)
239 putc(ch);
240#endif
241 ;
242 }
243
244 checksum = 0;
245 xmitcsum = -1;
246
247 count = 0;
248
249
250 while (count < BUFMAX) {
251 ch = getDebugChar() & 0x7f;
252 if (ch == '#')
253 break;
254 checksum = checksum + ch;
255 buffer[count] = ch;
256 count = count + 1;
257 }
258
259 if (count >= BUFMAX)
260 continue;
261
262 buffer[count] = 0;
263
264 if (ch == '#') {
265 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
266 xmitcsum |= hex(getDebugChar() & 0x7f);
267 if (checksum != xmitcsum)
268 putDebugChar('-');
269 else {
270 putDebugChar('+');
271
272 if (buffer[2] == ':') {
273 putDebugChar(buffer[0]);
274 putDebugChar(buffer[1]);
275
276 count = strlen(buffer);
277 for (i=3; i <= count; i++)
278 buffer[i-3] = buffer[i];
279 }
280 }
281 }
282 } while (checksum != xmitcsum);
283}
284
285
286static void
287putpacket(unsigned char *buffer)
288{
289 unsigned char checksum;
290 int count;
291 unsigned char ch, recv;
292
293
294 do {
295 putDebugChar('$');
296 checksum = 0;
297 count = 0;
298
299 while ((ch = buffer[count])) {
300 putDebugChar(ch);
301 checksum += ch;
302 count += 1;
303 }
304
305 putDebugChar('#');
306 putDebugChar(hexchars[checksum >> 4]);
307 putDebugChar(hexchars[checksum & 0xf]);
308 recv = getDebugChar();
309 } while ((recv & 0x7f) != '+');
310}
311
312
313
314
315static int
316handle_exception (struct pt_regs *regs)
317{
318 int addr;
319 int length;
320 char *ptr;
321 kgdb_data kd;
322 int i;
323
324 if (!initialized) {
325 printf("kgdb: exception before kgdb is initialized! huh?\n");
326 return (0);
327 }
328
329
330 if (longjmp_on_fault) {
331 longjmp_on_fault = 0;
332 kgdb_longjmp(error_jmp_buf, KGDBERR_MEMFAULT);
333 panic("kgdb longjump failed!\n");
334 }
335
336 if (kgdb_active) {
337 printf("kgdb: unexpected exception from within kgdb\n");
338 return (0);
339 }
340 kgdb_active = 1;
341
342 kgdb_interruptible(0);
343
344 printf("kgdb: handle_exception; trap [0x%x]\n", kgdb_trap(regs));
345
346 if (kgdb_setjmp(error_jmp_buf) != 0)
347 panic("kgdb: error or fault in entry init!\n");
348
349 kgdb_enter(regs, &kd);
350
351 entry_regs = *regs;
352
353 ptr = remcomOutBuffer;
354
355 *ptr++ = 'T';
356
357 *ptr++ = hexchars[kd.sigval >> 4];
358 *ptr++ = hexchars[kd.sigval & 0xf];
359
360 for (i = 0; i < kd.nregs; i++) {
361 kgdb_reg *rp = &kd.regs[i];
362
363 *ptr++ = hexchars[rp->num >> 4];
364 *ptr++ = hexchars[rp->num & 0xf];
365 *ptr++ = ':';
366 ptr = (char *)mem2hex((char *)&rp->val, ptr, 4);
367 *ptr++ = ';';
368 }
369
370 *ptr = 0;
371
372#ifdef KGDB_DEBUG
373 if (kdebug)
374 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
375#endif
376
377 putpacket((unsigned char *)&remcomOutBuffer);
378
379 while (1) {
380 volatile int errnum;
381
382 remcomOutBuffer[0] = 0;
383
384 getpacket(remcomInBuffer);
385 ptr = &remcomInBuffer[1];
386
387#ifdef KGDB_DEBUG
388 if (kdebug)
389 printf("kgdb: remcomInBuffer: %s\n", remcomInBuffer);
390#endif
391
392 errnum = kgdb_setjmp(error_jmp_buf);
393
394 if (errnum == 0) switch (remcomInBuffer[0]) {
395
396 case '?':
397 remcomOutBuffer[0] = 'S';
398 remcomOutBuffer[1] = hexchars[kd.sigval >> 4];
399 remcomOutBuffer[2] = hexchars[kd.sigval & 0xf];
400 remcomOutBuffer[3] = 0;
401 break;
402
403#ifdef KGDB_DEBUG
404 case 'd':
405
406 kdebug ^= 1;
407 break;
408#endif
409
410 case 'g':
411 length = kgdb_getregs(regs, remcomRegBuffer, BUFMAX);
412 mem2hex(remcomRegBuffer, remcomOutBuffer, length);
413 break;
414
415 case 'G':
416 length = strlen(ptr);
417 if ((length & 1) != 0) kgdb_error(KGDBERR_BADPARAMS);
418 hex2mem(ptr, remcomRegBuffer, length/2);
419 kgdb_putregs(regs, remcomRegBuffer, length/2);
420 strcpy(remcomOutBuffer,"OK");
421 break;
422
423 case 'm':
424
425
426 if (hexToInt(&ptr, &addr)
427 && *ptr++ == ','
428 && hexToInt(&ptr, &length)) {
429 mem2hex((char *)addr, remcomOutBuffer, length);
430 } else {
431 kgdb_error(KGDBERR_BADPARAMS);
432 }
433 break;
434
435 case 'M':
436
437
438 if (hexToInt(&ptr, &addr)
439 && *ptr++ == ','
440 && hexToInt(&ptr, &length)
441 && *ptr++ == ':') {
442 hex2mem(ptr, (char *)addr, length);
443 strcpy(remcomOutBuffer, "OK");
444 } else {
445 kgdb_error(KGDBERR_BADPARAMS);
446 }
447 break;
448
449
450 case 'k':
451 kd.extype = KGDBEXIT_KILL;
452 *regs = entry_regs;
453 goto doexit;
454
455 case 'C':
456 *ptr = '\0';
457
458
459 case 'c':
460
461 kd.extype = KGDBEXIT_CONTINUE;
462
463 if (hexToInt(&ptr, &addr)) {
464 kd.exaddr = addr;
465 kd.extype |= KGDBEXIT_WITHADDR;
466 }
467
468 goto doexit;
469
470 case 'S':
471 *ptr = '\0';
472
473
474 case 's':
475 kd.extype = KGDBEXIT_SINGLE;
476
477 if (hexToInt(&ptr, &addr)) {
478 kd.exaddr = addr;
479 kd.extype |= KGDBEXIT_WITHADDR;
480 }
481
482 doexit:
483
484
485
486
487 kgdb_flush_cache_all();
488 kgdb_exit(regs, &kd);
489 kgdb_active = 0;
490 kgdb_interruptible(1);
491 return (1);
492
493 case 'r':
494 panic("kgdb reset.");
495 break;
496
497 case 'P':
498 if (hexToInt(&ptr, &addr)
499 && *ptr++ == '='
500 && ((length = strlen(ptr)) & 1) == 0) {
501 hex2mem(ptr, remcomRegBuffer, length/2);
502 kgdb_putreg(regs, addr,
503 remcomRegBuffer, length/2);
504 strcpy(remcomOutBuffer,"OK");
505 } else {
506 kgdb_error(KGDBERR_BADPARAMS);
507 }
508 break;
509 }
510
511 if (errnum != 0)
512 sprintf(remcomOutBuffer, "E%02d", errnum);
513
514#ifdef KGDB_DEBUG
515 if (kdebug)
516 printf("kgdb: remcomOutBuffer: %s\n", remcomOutBuffer);
517#endif
518
519
520 putpacket((unsigned char *)&remcomOutBuffer);
521
522 }
523}
524
525
526
527
528
529void
530kgdb_init(void)
531{
532 kgdb_serial_init();
533 debugger_exception_handler = handle_exception;
534 initialized = 1;
535
536 putDebugStr("kgdb ready\n");
537 puts("ready\n");
538}
539
540void
541kgdb_error(int errnum)
542{
543 longjmp_on_fault = 0;
544 kgdb_longjmp(error_jmp_buf, errnum);
545 panic("kgdb_error: longjmp failed!\n");
546}
547
548
549
550int
551kgdb_output_string (const char* s, unsigned int count)
552{
553 char buffer[512];
554
555 count = (count <= (sizeof(buffer) / 2 - 2))
556 ? count : (sizeof(buffer) / 2 - 2);
557
558 buffer[0] = 'O';
559 mem2hex ((char *)s, &buffer[1], count);
560 putpacket((unsigned char *)&buffer);
561
562 return 1;
563}
564
565void
566breakpoint(void)
567{
568 if (!initialized) {
569 printf("breakpoint() called b4 kgdb init\n");
570 return;
571 }
572
573 kgdb_breakpoint(0, 0);
574}
575
576int
577do_kgdb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
578{
579 printf("Entering KGDB mode via exception handler...\n\n");
580 kgdb_breakpoint(argc - 1, argv + 1);
581 printf("\nReturned from KGDB mode\n");
582 return 0;
583}
584
585U_BOOT_CMD(
586 kgdb, CONFIG_SYS_MAXARGS, 1, do_kgdb,
587 "enter gdb remote debug mode",
588 "[arg0 arg1 .. argN]\n"
589 " - executes a breakpoint so that kgdb mode is\n"
590 " entered via the exception handler. To return\n"
591 " to the monitor, the remote gdb debugger must\n"
592 " execute a \"continue\" or \"quit\" command.\n"
593 "\n"
594 " if a program is loaded by the remote gdb, any args\n"
595 " passed to the kgdb command are given to the loaded\n"
596 " program if it is executed (see the \"hello_world\"\n"
597 " example program in the U-Boot examples directory)."
598);
599