fix while() stall. (shagkur)
[libogc.git] / libdb / debug.c
blob04ce172ee63143b6601a086f8e24b7ed64f1c6dd
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <signal.h>
6 #include "asm.h"
7 #include "processor.h"
8 #include "spinlock.h"
9 #include "lwp.h"
10 #include "lwp_threads.h"
11 #include "sys_state.h"
12 #include "context.h"
13 #include "cache.h"
14 #include "video.h"
15 #include "ogcsys.h"
17 #include "lwp_config.h"
19 #include "tcpip.h"
20 #include "geckousb.h"
21 #include "debug_if.h"
22 #include "debug_supp.h"
24 #define GEKKO_MAX_BP 256
26 #define SP_REGNUM 1 //register no. for stackpointer
27 #define PC_REGNUM 64 //register no. for programcounter (srr0)
29 #define BUFMAX 2048 //we take the same as in ppc-stub.c
31 #define BPCODE 0x7d821008
33 #define highhex(x) hexchars [((x)>>4)&0xf]
34 #define lowhex(x) hexchars [(x)&0xf]
36 #if UIP_LOGGING == 1
37 #include <stdio.h>
38 #define UIP_LOG(m) uip_log(__FILE__,__LINE__,m)
39 #else
40 #define UIP_LOG(m)
41 #endif /* UIP_LOGGING == 1 */
43 static s32 dbg_active = 0;
44 static s32 dbg_instep = 0;
45 static s32 dbg_initialized = 0;
47 static struct dbginterface *current_device = NULL;
49 static char remcomInBuffer[BUFMAX];
50 static char remcomOutBuffer[BUFMAX];
52 const char hexchars[]="0123456789abcdef";
54 static struct hard_trap_info {
55 u32 tt;
56 u8 signo;
57 } hard_trap_info[] = {
58 {EX_MACH_CHECK,SIGSEGV},/* Machine Check */
59 {EX_DSI,SIGSEGV}, /* Adress Error(store) DSI */
60 {EX_ISI,SIGBUS}, /* Instruction Bus Error ISI */
61 {EX_INT,SIGINT}, /* Interrupt */
62 {EX_ALIGN,SIGBUS}, /* Alignment */
63 {EX_PRG,SIGTRAP}, /* Breakpoint Trap */
64 {EX_FP,SIGFPE}, /* FPU unavail */
65 {EX_DEC,SIGALRM}, /* Decrementer */
66 {EX_SYS_CALL,SIGSYS}, /* System Call */
67 {EX_TRACE,SIGTRAP}, /* Singel-Step/Watch */
68 {0xB,SIGILL}, /* Reserved */
69 {EX_IABR,SIGTRAP}, /* Instruction Address Breakpoint (GEKKO) */
70 {0xD,SIGFPE}, /* FP assist */
71 {0,0} /* MUST be the last */
74 static struct bp_entry {
75 u32 *address;
76 u32 instr;
77 struct bp_entry *next;
78 } bp_entries[GEKKO_MAX_BP];
80 static struct bp_entry *p_bpentries = NULL;
81 static frame_context current_thread_registers;
83 void __breakinst();
84 void c_debug_handler(frame_context *ctx);
86 extern void dbg_exceptionhandler();
87 extern void __exception_sethandler(u32 nExcept, void (*pHndl)(frame_context*));
89 extern void __clr_iabr();
90 extern void __enable_iabr();
91 extern void __disable_iabr();
92 extern void __set_iabr(void *);
94 extern const char *tcp_localip;
95 extern const char *tcp_netmask;
96 extern const char *tcp_gateway;
97 extern u8 __text_start[],__data_start[],__bss_start[];
98 extern u8 __text_fstart[],__data_fstart[],__bss_fstart[];
100 static __inline__ void bp_init()
102 s32 i;
104 for(i=0;i<GEKKO_MAX_BP;i++) {
105 bp_entries[i].address = NULL;
106 bp_entries[i].instr = 0xffffffff;
107 bp_entries[i].next = NULL;
111 static s32 hex(char ch)
113 if (ch >= 'a' && ch <= 'f')
114 return ch-'a'+10;
115 if (ch >= '0' && ch <= '9')
116 return ch-'0';
117 if (ch >= 'A' && ch <= 'F')
118 return ch-'A'+10;
119 return -1;
122 static s32 hexToInt(char **ptr, s32 *ival)
124 s32 cnt;
125 s32 val,nibble;
127 val = 0;
128 cnt = 0;
129 while(**ptr) {
130 nibble = hex(**ptr);
131 if(nibble<0) break;
133 val = (val<<4)|nibble;
134 cnt++;
136 (*ptr)++;
138 *ival = val;
139 return cnt;
142 static s32 computeSignal(s32 excpt)
144 struct hard_trap_info *ht;
145 for(ht = hard_trap_info;ht->tt && ht->signo;ht++) {
146 if(ht->tt==excpt) return ht->signo;
148 return SIGHUP;
151 static u32 insert_bp(void *mem)
153 u32 i;
154 struct bp_entry *p;
156 for(i=0;i<GEKKO_MAX_BP;i++) {
157 if(bp_entries[i].address == NULL) break;
159 if(i==GEKKO_MAX_BP) return 0;
161 p = &bp_entries[i];
162 p->next = p_bpentries;
163 p->address = mem;
164 p_bpentries = p;
166 p->instr = *(p->address);
167 *(p->address) = BPCODE;
169 DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32);
170 ICInvalidateRange((void*)((u32)mem&~0x1f),32);
171 _sync();
173 return 1;
176 static u32 remove_bp(void *mem)
178 struct bp_entry *e = p_bpentries;
179 struct bp_entry *f = NULL;
181 if(!e) return 0;
182 if(e->address==mem) {
183 p_bpentries = e->next;
184 f = e;
185 } else {
186 for(;e->next;e=e->next) {
187 if(e->next->address==mem) {
188 f = e->next;
189 e->next = f->next;
190 break;
194 if(!f) return 0;
196 *(f->address) = f->instr;
197 f->instr = 0xffffffff;
198 f->address = NULL;
200 DCStoreRangeNoSync((void*)((u32)mem&~0x1f),32);
201 ICInvalidateRange((void*)((u32)mem&~0x1f),32);
202 _sync();
204 return 1;
207 static char getdbgchar()
209 char ch = 0;
210 s32 len = 0;
212 len = current_device->read(current_device,&ch,1);
214 return (len>0)?ch:0;
217 static void putdbgchar(char ch)
219 current_device->write(current_device,&ch,1);
222 static void putdbgstr(const char *str)
224 current_device->write(current_device,str,strlen(str));
227 static void putpacket(const char *buffer)
229 u8 recv;
230 u8 chksum,ch;
231 char *ptr;
232 const char *inp;
233 static char outbuf[2048];
235 do {
236 inp = buffer;
237 ptr = outbuf;
239 *ptr++ = '$';
241 chksum = 0;
242 while((ch=*inp++)!='\0') {
243 *ptr++ = ch;
244 chksum += ch;
247 *ptr++ = '#';
248 *ptr++ = hexchars[chksum>>4];
249 *ptr++ = hexchars[chksum&0x0f];
250 *ptr = '\0';
252 putdbgstr(outbuf);
254 recv = getdbgchar();
255 } while((recv&0x7f)!='+');
258 static void getpacket(char *buffer)
260 char ch;
261 u8 chksum,xmitsum;
262 s32 i,cnt;
264 do {
265 while((ch=(getdbgchar()&0x7f))!='$');
267 cnt = 0;
268 chksum = 0;
269 xmitsum = -1;
271 while(cnt<BUFMAX) {
272 ch = getdbgchar()&0x7f;
273 if(ch=='#') break;
275 chksum += ch;
276 buffer[cnt] = ch;
277 cnt++;
279 if(cnt>=BUFMAX) continue;
281 buffer[cnt] = 0;
282 if(ch=='#') {
283 xmitsum = hex(getdbgchar()&0x7f)<<4;
284 xmitsum |= hex(getdbgchar()&0x7f);
286 if(chksum!=xmitsum) putdbgchar('-');
287 else {
288 putdbgchar('+');
289 if(buffer[2]==':') {
290 putdbgchar(buffer[0]);
291 putdbgchar(buffer[1]);
293 cnt = strlen((const char*)buffer);
294 for(i=3;i<=cnt;i++) buffer[i-3] = buffer[i];
298 } while(chksum!=xmitsum);
301 static void process_query(const char *inp,char *outp,s32 thread)
303 char *optr;
305 switch(inp[1]) {
306 case 'C':
307 optr = outp;
308 *optr++ = 'Q';
309 *optr++ = 'C';
310 optr = thread2vhstr(optr,thread);
311 *optr++ = 0;
312 break;
313 case 'P':
315 s32 ret,rthread,mask;
316 struct gdbstub_threadinfo info;
318 ret = parseqp(inp,&mask,&rthread);
319 if(!ret || mask&~0x1f) {
320 strcpy(outp,"E01");
321 break;
324 ret = gdbstub_getthreadinfo(rthread,&info);
325 if(!ret) {
326 strcpy(outp,"E02");
327 break;
329 packqq(outp,mask,rthread,&info);
331 break;
332 case 'L':
334 s32 ret,athread,first,max_cnt,i,done,rthread;
336 ret = parseql(inp,&first,&max_cnt,&athread);
337 if(!ret) {
338 strcpy(outp,"E02");
339 break;
341 if(max_cnt==0) {
342 strcpy(outp,"E02");
343 break;
345 if(max_cnt>QM_MAXTHREADS) max_cnt = QM_MAXTHREADS;
347 optr = reserve_qmheader(outp);
348 if(first) rthread = 0;
349 else rthread = athread;
351 done = 0;
352 for(i=0;i<max_cnt;i++) {
353 rthread = gdbstub_getnextthread(rthread);
354 if(rthread<=0) {
355 done = 1;
356 break;
358 optr = packqmthread(optr,rthread);
360 *optr = 0;
361 packqmheader(outp,i,done,athread);
363 break;
364 default:
365 break;
369 static s32 gdbstub_setthreadregs(s32 thread,frame_context *frame)
371 return 1;
374 static s32 gdbstub_getthreadregs(s32 thread,frame_context *frame)
376 lwp_cntrl *th;
378 th = gdbstub_indextoid(thread);
379 if(th) {
380 memcpy(frame->GPR,th->context.GPR,(32*4));
381 memcpy(frame->FPR,th->context.FPR,(32*8));
382 frame->SRR0 = th->context.LR;
383 frame->SRR1 = th->context.MSR;
384 frame->CR = th->context.CR;
385 frame->LR = th->context.LR;
386 frame->CTR = th->context.CTR;
387 frame->XER = th->context.XER;
388 frame->FPSCR = th->context.FPSCR;
389 return 1;
391 return 0;
394 static void gdbstub_report_exception(frame_context *frame,s32 thread)
396 s32 sigval;
397 char *ptr;
399 ptr = remcomOutBuffer;
400 sigval = computeSignal(frame->EXCPT_Number);
401 *ptr++ = 'T';
402 *ptr++ = highhex(sigval);
403 *ptr++ = lowhex(sigval);
404 *ptr++ = highhex(SP_REGNUM);
405 *ptr++ = lowhex(SP_REGNUM);
406 *ptr++ = ':';
407 ptr = mem2hstr(ptr,(char*)&frame->GPR[1],4);
408 *ptr++ = ';';
409 *ptr++ = highhex(PC_REGNUM);
410 *ptr++ = lowhex(PC_REGNUM);
411 *ptr++ = ':';
412 ptr = mem2hstr(ptr,(char*)&frame->SRR0,4);
413 *ptr++ = ';';
415 *ptr++ = 't';
416 *ptr++ = 'h';
417 *ptr++ = 'r';
418 *ptr++ = 'e';
419 *ptr++ = 'a';
420 *ptr++ = 'd';
421 *ptr++ = ':';
422 ptr = thread2vhstr(ptr,thread);
423 *ptr++ = ';';
425 *ptr++ = '\0';
430 void c_debug_handler(frame_context *frame)
432 char *ptr;
433 s32 addr,len;
434 s32 thread,current_thread;
435 s32 host_has_detached;
436 frame_context *regptr;
438 thread = gdbstub_getcurrentthread();
439 current_thread = thread;
441 if(current_device->open(current_device)<0) return;
443 if(dbg_active) {
444 gdbstub_report_exception(frame,thread);
445 putpacket(remcomOutBuffer);
448 if(frame->SRR0==(u32)__breakinst) frame->SRR0 += 4;
450 host_has_detached = 0;
451 while(!host_has_detached) {
452 remcomOutBuffer[0]= 0;
453 getpacket(remcomInBuffer);
454 switch(remcomInBuffer[0]) {
455 case '?':
456 gdbstub_report_exception(frame,thread);
457 break;
458 case 'D':
459 dbg_instep = 0;
460 dbg_active = 0;
461 frame->SRR1 &= ~MSR_SE;
462 strcpy(remcomOutBuffer,"OK");
463 host_has_detached = 1;
464 break;
465 case 'k':
466 dbg_instep = 0;
467 dbg_active = 0;
468 frame->SRR1 &= ~MSR_SE;
469 frame->SRR0 = 0x80001800;
470 host_has_detached = 1;
471 goto exit;
472 case 'g':
473 regptr = frame;
474 ptr = remcomOutBuffer;
475 if(current_thread!=thread) regptr = &current_thread_registers;
477 ptr = mem2hstr(ptr,(char*)regptr->GPR,32*4);
478 ptr = mem2hstr(ptr,(char*)regptr->FPR,32*8);
479 ptr = mem2hstr(ptr,(char*)&regptr->SRR0,4);
480 ptr = mem2hstr(ptr,(char*)&regptr->SRR1,4);
481 ptr = mem2hstr(ptr,(char*)&regptr->CR,4);
482 ptr = mem2hstr(ptr,(char*)&regptr->LR,4);
483 ptr = mem2hstr(ptr,(char*)&regptr->CTR,4);
484 ptr = mem2hstr(ptr,(char*)&regptr->XER,4);
485 ptr = mem2hstr(ptr,(char*)&regptr->FPSCR,4);
486 break;
487 case 'm':
488 ptr = &remcomInBuffer[1];
489 if(hexToInt(&ptr,&addr) && ((addr&0xC0000000)==0xC0000000 || (addr&0xC0000000)==0x80000000)
490 && *ptr++==','
491 && hexToInt(&ptr,&len) && len<=((BUFMAX - 4)/2))
492 mem2hstr(remcomOutBuffer,(void*)addr,len);
493 else
494 strcpy(remcomOutBuffer,"E00");
495 break;
496 case 'q':
497 process_query(remcomInBuffer,remcomOutBuffer,thread);
498 break;
499 case 'c':
500 dbg_instep = 0;
501 dbg_active = 1;
502 frame->SRR1 &= ~MSR_SE;
503 current_device->wait(current_device);
504 goto exit;
505 case 's':
506 dbg_instep = 1;
507 dbg_active = 1;
508 frame->SRR1 |= MSR_SE;
509 current_device->wait(current_device);
510 goto exit;
511 case 'z':
513 s32 ret,type,len;
514 char *addr;
516 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
517 if(!ret) {
518 strcpy(remcomOutBuffer,"E01");
519 break;
521 if(type!=0) break;
523 if(len<4) {
524 strcpy(remcomOutBuffer,"E02");
525 break;
528 ret = remove_bp(addr);
529 if(!ret) {
530 strcpy(remcomOutBuffer,"E03");
531 break;
533 strcpy(remcomOutBuffer,"OK");
535 break;
536 case 'H':
537 if(remcomInBuffer[1]=='g')
539 s32 tmp,ret;
541 if(vhstr2thread(&remcomInBuffer[2],&tmp)==NULL) {
542 strcpy(remcomOutBuffer,"E01");
543 break;
545 if(!tmp) tmp = thread;
546 if(tmp==current_thread) {
547 strcpy(remcomOutBuffer,"OK");
548 break;
551 if(current_thread!=thread) ret = gdbstub_setthreadregs(current_thread,&current_thread_registers);
552 if(tmp!=thread) {
553 ret = gdbstub_getthreadregs(tmp,&current_thread_registers);
554 if(!ret) {
555 strcpy(remcomOutBuffer,"E02");
556 break;
559 current_thread= tmp;
561 strcpy(remcomOutBuffer,"OK");
562 break;
563 case 'T':
565 s32 tmp;
567 if(vhstr2thread(&remcomInBuffer[1],&tmp)==NULL) {
568 strcpy(remcomOutBuffer,"E01");
569 break;
571 if(gdbstub_indextoid(tmp)==NULL) strcpy(remcomOutBuffer,"E02");
572 else strcpy(remcomOutBuffer,"OK");
574 break;
575 case 'Z':
577 s32 ret,type,len;
578 char *addr;
580 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
581 if(!ret) {
582 strcpy(remcomOutBuffer,"E01");
583 break;
585 if(type!=0) {
586 strcpy(remcomOutBuffer,"E02");
587 break;
589 if(len<4) {
590 strcpy(remcomOutBuffer,"E03");
591 break;
594 ret = insert_bp(addr);
595 if(!ret) {
596 strcpy(remcomOutBuffer,"E04");
597 break;
599 strcpy(remcomOutBuffer,"OK");
601 break;
603 putpacket(remcomOutBuffer);
605 current_device->close(current_device);
606 exit:
607 return;
610 void _break(void)
612 if(!dbg_initialized) return;
613 __asm__ __volatile__ (".globl __breakinst\n\
614 __breakinst: .long 0x7d821008");
617 void DEBUG_Init(s32 device_type,s32 channel_port)
619 u32 level;
620 struct uip_ip_addr localip,netmask,gateway;
622 UIP_LOG("DEBUG_Init()\n");
624 __lwp_thread_dispatchdisable();
626 bp_init();
628 if(device_type==GDBSTUB_DEVICE_USB) {
629 current_device = usb_init(channel_port);
630 } else {
631 localip.addr = uip_ipaddr((const u8_t*)tcp_localip);
632 netmask.addr = uip_ipaddr((const u8_t*)tcp_netmask);
633 gateway.addr = uip_ipaddr((const u8_t*)tcp_gateway);
635 current_device = tcpip_init(&localip,&netmask,&gateway,(u16)channel_port);
638 if(current_device!=NULL) {
639 _CPU_ISR_Disable(level);
640 __exception_sethandler(EX_DSI,dbg_exceptionhandler);
641 __exception_sethandler(EX_PRG,dbg_exceptionhandler);
642 __exception_sethandler(EX_TRACE,dbg_exceptionhandler);
643 __exception_sethandler(EX_IABR,dbg_exceptionhandler);
644 _CPU_ISR_Restore(level);
646 dbg_initialized = 1;
649 __lwp_thread_dispatchenable();