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
91
92
93
94
95
96
97
98
99
100
101
102#include <linux/kernel.h>
103#include <linux/string.h>
104#include <linux/mm.h>
105#include <linux/smp.h>
106#include <linux/smp_lock.h>
107
108#include <asm/system.h>
109#include <asm/signal.h>
110#include <asm/kgdb.h>
111#include <asm/pgtable.h>
112#include <asm/ptrace.h>
113
114void breakinst(void);
115
116
117
118
119
120#define BUFMAX 2048
121static char remcomInBuffer[BUFMAX];
122static char remcomOutBuffer[BUFMAX];
123
124static int initialized = 0;
125static int kgdb_active = 0;
126static u_int fault_jmp_buf[100];
127static int kdebug;
128
129static const char hexchars[]="0123456789abcdef";
130
131
132
133
134
135#if 0
136
137static void exceptionHandler(int tnum, unsigned int *tfunc)
138{
139
140}
141#endif
142
143int
144kgdb_setjmp(long *buf)
145{
146 asm ("mflr 0; stw 0,0(%0);"
147 "stw 1,4(%0); stw 2,8(%0);"
148 "mfcr 0; stw 0,12(%0);"
149 "stmw 13,16(%0)"
150 : : "r" (buf));
151
152 return 0;
153}
154void
155kgdb_longjmp(long *buf, int val)
156{
157 if (val == 0)
158 val = 1;
159 asm ("lmw 13,16(%0);"
160 "lwz 0,12(%0); mtcrf 0x38,0;"
161 "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);"
162 "mtlr 0; mr 3,%1"
163 : : "r" (buf), "r" (val));
164}
165
166static int
167hex(unsigned char ch)
168{
169 if (ch >= 'a' && ch <= 'f')
170 return ch-'a'+10;
171 if (ch >= '0' && ch <= '9')
172 return ch-'0';
173 if (ch >= 'A' && ch <= 'F')
174 return ch-'A'+10;
175 return -1;
176}
177
178
179
180
181
182static unsigned char *
183mem2hex(char *mem, char *buf, int count)
184{
185 unsigned char ch;
186
187 if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
188 debugger_fault_handler = kgdb_fault_handler;
189 while (count-- > 0) {
190 ch = *mem++;
191 *buf++ = hexchars[ch >> 4];
192 *buf++ = hexchars[ch & 0xf];
193 }
194 } else {
195
196 }
197 debugger_fault_handler = 0;
198 *buf = 0;
199 return buf;
200}
201
202
203
204
205static char *
206hex2mem(char *buf, char *mem, int count)
207{
208 int i;
209 unsigned char ch;
210
211 if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
212 debugger_fault_handler = kgdb_fault_handler;
213 for (i=0; i<count; i++) {
214 ch = hex(*buf++) << 4;
215 ch |= hex(*buf++);
216 *mem++ = ch;
217 }
218 flush_icache_range((int)mem, (int)mem+count);
219 } else {
220
221 }
222 debugger_fault_handler = 0;
223 return mem;
224}
225
226
227
228
229
230static int
231hexToInt(char **ptr, int *intValue)
232{
233 int numChars = 0;
234 int hexValue;
235
236 *intValue = 0;
237
238 if (kgdb_setjmp((long*)fault_jmp_buf) == 0) {
239 debugger_fault_handler = kgdb_fault_handler;
240 while (**ptr) {
241 hexValue = hex(**ptr);
242 if (hexValue < 0)
243 break;
244
245 *intValue = (*intValue << 4) | hexValue;
246 numChars ++;
247
248 (*ptr)++;
249 }
250 } else {
251
252 }
253 debugger_fault_handler = 0;
254
255 return (numChars);
256}
257
258
259static void
260getpacket(char *buffer)
261{
262 unsigned char checksum;
263 unsigned char xmitcsum;
264 int i;
265 int count;
266 unsigned char ch;
267
268 do {
269
270
271 while ((ch = (getDebugChar() & 0x7f)) != '$') ;
272
273 checksum = 0;
274 xmitcsum = -1;
275
276 count = 0;
277
278
279 while (count < BUFMAX) {
280 ch = getDebugChar() & 0x7f;
281 if (ch == '#')
282 break;
283 checksum = checksum + ch;
284 buffer[count] = ch;
285 count = count + 1;
286 }
287
288 if (count >= BUFMAX)
289 continue;
290
291 buffer[count] = 0;
292
293 if (ch == '#') {
294 xmitcsum = hex(getDebugChar() & 0x7f) << 4;
295 xmitcsum |= hex(getDebugChar() & 0x7f);
296 if (checksum != xmitcsum)
297 putDebugChar('-');
298 else {
299 putDebugChar('+');
300
301 if (buffer[2] == ':') {
302 putDebugChar(buffer[0]);
303 putDebugChar(buffer[1]);
304
305 count = strlen(buffer);
306 for (i=3; i <= count; i++)
307 buffer[i-3] = buffer[i];
308 }
309 }
310 }
311 } while (checksum != xmitcsum);
312}
313
314
315static void putpacket(unsigned char *buffer)
316{
317 unsigned char checksum;
318 int count;
319 unsigned char ch, recv;
320
321
322 do {
323 putDebugChar('$');
324 checksum = 0;
325 count = 0;
326
327 while ((ch = buffer[count])) {
328 putDebugChar(ch);
329 checksum += ch;
330 count += 1;
331 }
332
333 putDebugChar('#');
334 putDebugChar(hexchars[checksum >> 4]);
335 putDebugChar(hexchars[checksum & 0xf]);
336 recv = getDebugChar();
337 } while ((recv & 0x7f) != '+');
338}
339
340static void kgdb_flush_cache_all(void)
341{
342 flush_instruction_cache();
343}
344
345static inline int get_msr()
346{
347 int msr;
348 asm volatile("mfmsr %0" : "=r" (msr):);
349 return msr;
350}
351
352static inline void set_msr(int msr)
353{
354 asm volatile("mtmsr %0" : : "r" (msr));
355}
356
357
358
359
360void set_debug_traps(void)
361{
362#if 0
363 unsigned char c;
364
365 save_and_cli(flags);
366
367
368
369
370
371
372
373
374
375 while((c = getDebugChar()) != '$');
376 while((c = getDebugChar()) != '#');
377 c = getDebugChar();
378 c = getDebugChar();
379 putDebugChar('+');
380#endif
381 debugger = kgdb;
382 debugger_bpt = kgdb_bpt;
383 debugger_sstep = kgdb_sstep;
384 debugger_iabr_match = kgdb_iabr_match;
385 debugger_dabr_match = kgdb_dabr_match;
386
387 initialized = 1;
388}
389
390static void kgdb_fault_handler(struct pt_regs *regs)
391{
392 kgdb_longjmp((long*)fault_jmp_buf, 1);
393}
394
395int kgdb_bpt(struct pt_regs *regs)
396{
397 handle_exception(regs);
398 return 1;
399}
400
401int kgdb_sstep(struct pt_regs *regs)
402{
403 handle_exception(regs);
404 return 1;
405}
406
407void kgdb(struct pt_regs *regs)
408{
409 handle_exception(regs);
410}
411
412int kgdb_iabr_match(struct pt_regs *regs)
413{
414 printk("kgdb doesn't support iabr, what?!?\n");
415 handle_exception(regs);
416 return 1;
417}
418
419int kgdb_dabr_match(struct pt_regs *regs)
420{
421 printk("kgdb doesn't support dabr, what?!?\n");
422 handle_exception(regs);
423 return 1;
424}
425
426
427
428
429
430
431static struct hard_trap_info
432{
433 unsigned int tt;
434 unsigned char signo;
435} hard_trap_info[] = {
436 { 0x200, SIGSEGV },
437 { 0x300, SIGSEGV },
438 { 0x400, SIGBUS },
439 { 0x500, SIGINT },
440 { 0x600, SIGBUS },
441 { 0x700, SIGILL },
442 { 0x800, SIGFPE },
443 { 0x900, SIGALRM },
444 { 0xa00, SIGILL },
445 { 0xb00, SIGILL },
446 { 0xc00, SIGCHLD },
447 { 0xd00, SIGINT },
448 { 0xe00, SIGFPE },
449 { 0, 0}
450};
451
452static int computeSignal(unsigned int tt)
453{
454 struct hard_trap_info *ht;
455
456 for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
457 if (ht->tt == tt)
458 return ht->signo;
459
460 return SIGHUP;
461}
462
463
464
465
466static void
467handle_exception (struct pt_regs *regs)
468{
469 int sigval;
470 int addr;
471 int length;
472 char *ptr;
473 unsigned int msr;
474
475 if (debugger_fault_handler) {
476 debugger_fault_handler(regs);
477 panic("kgdb longjump failed!\n");
478 }
479 if (kgdb_active) {
480 printk("interrupt while in kgdb, returning\n");
481 return;
482 }
483 kgdb_active = 1;
484
485 printk("kgdb: entering handle_exception; trap [0x%x]\n",
486 (unsigned int)regs->trap);
487
488 kgdb_interruptible(0);
489 lock_kernel();
490 msr = get_msr();
491 set_msr(msr & ~MSR_EE);
492
493 if (regs->nip == (unsigned long)breakinst) {
494
495 regs->nip += 4;
496 }
497
498
499 sigval = computeSignal(regs->trap);
500 ptr = remcomOutBuffer;
501
502 *ptr++ = 'S';
503 *ptr++ = hexchars[sigval >> 4];
504 *ptr++ = hexchars[sigval & 0xf];
505
506 *ptr++ = 0;
507
508 putpacket(remcomOutBuffer);
509
510
511
512
513
514
515 while (1) {
516 remcomOutBuffer[0] = 0;
517
518 getpacket(remcomInBuffer);
519 switch (remcomInBuffer[0]) {
520 case '?':
521 remcomOutBuffer[0] = 'S';
522 remcomOutBuffer[1] = hexchars[sigval >> 4];
523 remcomOutBuffer[2] = hexchars[sigval & 0xf];
524 remcomOutBuffer[3] = 0;
525 break;
526#if 0
527 case 'q':
528 {
529 extern long _start, sdata, __bss_start;
530
531 ptr = &remcomInBuffer[1];
532 if (strncmp(ptr, "Offsets", 7) != 0)
533 break;
534
535 ptr = remcomOutBuffer;
536 sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x",
537 &_start, &sdata, &__bss_start);
538 break;
539 }
540#endif
541 case 'd':
542
543 kdebug ^= 1;
544 break;
545
546 case 'g':
547
548
549
550
551
552
553
554
555
556 {
557 int i;
558 ptr = remcomOutBuffer;
559
560 ptr = mem2hex((char *)regs, ptr, 32 * 4);
561
562
563 for(i=0; i<(32*8*2); i++) {
564 ptr[i] = '0';
565 }
566 ptr += 32*8*2;
567
568 ptr = mem2hex((char *)®s->nip, ptr, 4);
569 ptr = mem2hex((char *)®s->msr, ptr, 4);
570 ptr = mem2hex((char *)®s->ccr, ptr, 4);
571 ptr = mem2hex((char *)®s->link, ptr, 4);
572 ptr = mem2hex((char *)®s->ctr, ptr, 4);
573 ptr = mem2hex((char *)®s->xer, ptr, 4);
574 }
575 break;
576
577 case 'G':
578 {
579 ptr = &remcomInBuffer[1];
580
581
582
583
584
585
586
587 hex2mem(ptr, (char *)regs, 32 * 4);
588
589
590
591 ptr += 32*8*2;
592
593
594 ptr = hex2mem(ptr, (char *)®s->nip, 4);
595 ptr = hex2mem(ptr, (char *)®s->msr, 4);
596 ptr = hex2mem(ptr, (char *)®s->ccr, 4);
597 ptr = hex2mem(ptr, (char *)®s->link, 4);
598 ptr = hex2mem(ptr, (char *)®s->ctr, 4);
599 ptr = hex2mem(ptr, (char *)®s->xer, 4);
600
601 strcpy(remcomOutBuffer,"OK");
602 }
603 break;
604 case 'H':
605
606 hexToInt(&ptr, &addr);
607 strcpy(remcomOutBuffer,"OK");
608 break;
609
610 case 'm':
611
612
613 ptr = &remcomInBuffer[1];
614
615 if (hexToInt(&ptr, &addr)
616 && *ptr++ == ','
617 && hexToInt(&ptr, &length)) {
618 if (mem2hex((char *)addr, remcomOutBuffer,length))
619 break;
620 strcpy (remcomOutBuffer, "E03");
621 } else {
622 strcpy(remcomOutBuffer,"E01");
623 }
624 break;
625
626 case 'M':
627
628
629 ptr = &remcomInBuffer[1];
630
631 if (hexToInt(&ptr, &addr)
632 && *ptr++ == ','
633 && hexToInt(&ptr, &length)
634 && *ptr++ == ':') {
635 if (hex2mem(ptr, (char *)addr, length)) {
636 strcpy(remcomOutBuffer, "OK");
637 } else {
638 strcpy(remcomOutBuffer, "E03");
639 }
640 } else {
641 strcpy(remcomOutBuffer, "E02");
642 }
643 break;
644
645
646 case 'k':
647 case 'c':
648
649
650 ptr = &remcomInBuffer[1];
651 if (hexToInt(&ptr, &addr)) {
652 regs->nip = addr;
653 }
654
655
656
657
658
659 kgdb_flush_cache_all();
660 set_msr(msr);
661 kgdb_interruptible(1);
662 unlock_kernel();
663 kgdb_active = 0;
664 return;
665
666 case 's':
667 kgdb_flush_cache_all();
668 regs->msr |= MSR_SE;
669 set_msr(msr | MSR_SE);
670 unlock_kernel();
671 kgdb_active = 0;
672 return;
673
674 case 'r':
675 panic("kgdb reset.");
676 break;
677 }
678 if (remcomOutBuffer[0] && kdebug) {
679 printk("remcomInBuffer: %s\n", remcomInBuffer);
680 printk("remcomOutBuffer: %s\n", remcomOutBuffer);
681 }
682
683 putpacket(remcomOutBuffer);
684 }
685}
686
687
688
689
690
691
692void
693breakpoint(void)
694{
695 if (!initialized) {
696 printk("breakpoint() called b4 kgdb init\n");
697 return;
698 }
699
700 asm(" .globl breakinst
701 breakinst: trap
702 ");
703}
704