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