kill command for the gdb stub to return to hbc
[libogc.git] / libdb / debug.c
blobc4fe39b1d26fbea1059b7ddbc37e11e658db6ae6
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, bool wait)
229 u8 recv;
230 u8 chksum,ch;
231 char *ptr;
232 const char *inp;
233 static char outbuf[2048];
235 outbuf[0] = '+';
236 do {
237 inp = buffer;
238 ptr = &outbuf[1];
240 *ptr++ = '$';
242 chksum = 0;
243 while((ch=*inp++)!='\0') {
244 *ptr++ = ch;
245 chksum += ch;
248 *ptr++ = '#';
249 *ptr++ = hexchars[chksum>>4];
250 *ptr++ = hexchars[chksum&0x0f];
251 *ptr = '\0';
253 putdbgstr(outbuf);
255 if(!wait)
256 break;
258 recv = getdbgchar();
259 } while((recv&0x7f)!='+');
262 static void getpacket(char *buffer)
264 char ch;
265 u8 chksum,xmitsum;
266 s32 i,cnt;
268 do {
269 while((ch=(getdbgchar()&0x7f))!='$');
271 cnt = 0;
272 chksum = 0;
273 xmitsum = -1;
275 while(cnt<BUFMAX) {
276 ch = getdbgchar()&0x7f;
277 if(ch=='#') break;
279 chksum += ch;
280 buffer[cnt] = ch;
281 cnt++;
283 if(cnt>=BUFMAX) continue;
285 buffer[cnt] = 0;
286 if(ch=='#') {
287 xmitsum = hex(getdbgchar()&0x7f)<<4;
288 xmitsum |= hex(getdbgchar()&0x7f);
290 if(chksum!=xmitsum) putdbgchar('-');
291 else {
292 if(buffer[2]==':') {
293 putdbgchar(buffer[0]);
294 putdbgchar(buffer[1]);
296 cnt = strlen((const char*)buffer);
297 for(i=3;i<=cnt;i++) buffer[i-3] = buffer[i];
301 } while(chksum!=xmitsum);
304 static void process_query(const char *inp,char *outp,s32 thread)
306 char *optr;
308 switch(inp[1]) {
309 case 'C':
310 optr = outp;
311 *optr++ = 'Q';
312 *optr++ = 'C';
313 optr = thread2vhstr(optr,thread);
314 *optr++ = 0;
315 break;
316 case 'P':
318 s32 ret,rthread,mask;
319 struct gdbstub_threadinfo info;
321 ret = parseqp(inp,&mask,&rthread);
322 if(!ret || mask&~0x1f) {
323 strcpy(outp,"E01");
324 break;
327 ret = gdbstub_getthreadinfo(rthread,&info);
328 if(!ret) {
329 strcpy(outp,"E02");
330 break;
332 packqq(outp,mask,rthread,&info);
334 break;
335 case 'L':
337 s32 ret,athread,first,max_cnt,i,done,rthread;
339 ret = parseql(inp,&first,&max_cnt,&athread);
340 if(!ret) {
341 strcpy(outp,"E02");
342 break;
344 if(max_cnt==0) {
345 strcpy(outp,"E02");
346 break;
348 if(max_cnt>QM_MAXTHREADS) max_cnt = QM_MAXTHREADS;
350 optr = reserve_qmheader(outp);
351 if(first) rthread = 0;
352 else rthread = athread;
354 done = 0;
355 for(i=0;i<max_cnt;i++) {
356 rthread = gdbstub_getnextthread(rthread);
357 if(rthread<=0) {
358 done = 1;
359 break;
361 optr = packqmthread(optr,rthread);
363 *optr = 0;
364 packqmheader(outp,i,done,athread);
366 break;
367 default:
368 break;
372 static s32 gdbstub_setthreadregs(s32 thread,frame_context *frame)
374 return 1;
377 static s32 gdbstub_getthreadregs(s32 thread,frame_context *frame)
379 lwp_cntrl *th;
381 th = gdbstub_indextoid(thread);
382 if(th) {
383 memcpy(frame->GPR,th->context.GPR,(32*4));
384 memcpy(frame->FPR,th->context.FPR,(32*8));
385 frame->SRR0 = th->context.LR;
386 frame->SRR1 = th->context.MSR;
387 frame->CR = th->context.CR;
388 frame->LR = th->context.LR;
389 frame->CTR = th->context.CTR;
390 frame->XER = th->context.XER;
391 frame->FPSCR = th->context.FPSCR;
392 return 1;
394 return 0;
397 static void gdbstub_report_exception(frame_context *frame,s32 thread)
399 s32 sigval;
400 char *ptr;
402 ptr = remcomOutBuffer;
403 sigval = computeSignal(frame->EXCPT_Number);
404 *ptr++ = 'T';
405 *ptr++ = highhex(sigval);
406 *ptr++ = lowhex(sigval);
407 *ptr++ = highhex(SP_REGNUM);
408 *ptr++ = lowhex(SP_REGNUM);
409 *ptr++ = ':';
410 ptr = mem2hstr(ptr,(char*)&frame->GPR[1],4);
411 *ptr++ = ';';
412 *ptr++ = highhex(PC_REGNUM);
413 *ptr++ = lowhex(PC_REGNUM);
414 *ptr++ = ':';
415 ptr = mem2hstr(ptr,(char*)&frame->SRR0,4);
416 *ptr++ = ';';
418 *ptr++ = 't';
419 *ptr++ = 'h';
420 *ptr++ = 'r';
421 *ptr++ = 'e';
422 *ptr++ = 'a';
423 *ptr++ = 'd';
424 *ptr++ = ':';
425 ptr = thread2vhstr(ptr,thread);
426 *ptr++ = ';';
428 *ptr++ = '\0';
433 void c_debug_handler(frame_context *frame)
435 char *ptr;
436 s32 addr,len;
437 s32 thread,current_thread;
438 s32 host_has_detached;
439 frame_context *regptr;
440 bool wait;
442 thread = gdbstub_getcurrentthread();
443 current_thread = thread;
445 if(current_device->open(current_device)<0) return;
447 if(dbg_active) {
448 gdbstub_report_exception(frame,thread);
449 putpacket(remcomOutBuffer, true);
452 if(frame->SRR0==(u32)__breakinst) frame->SRR0 += 4;
454 host_has_detached = 0;
455 while(!host_has_detached) {
456 wait = true;
457 remcomOutBuffer[0]= 0;
458 getpacket(remcomInBuffer);
459 switch(remcomInBuffer[0]) {
460 case '?':
461 gdbstub_report_exception(frame,thread);
462 break;
463 case 'D':
464 dbg_instep = 0;
465 dbg_active = 0;
466 frame->SRR1 &= ~MSR_SE;
467 strcpy(remcomOutBuffer,"OK");
468 host_has_detached = 1;
469 break;
470 case 'k':
471 dbg_instep = 0;
472 dbg_active = 0;
473 frame->SRR1 &= ~MSR_SE;
474 frame->SRR0 = 0x80001800;
475 host_has_detached = 1;
476 wait = false;
477 break;
478 case 'g':
479 regptr = frame;
480 ptr = remcomOutBuffer;
481 if(current_thread!=thread) regptr = &current_thread_registers;
483 ptr = mem2hstr(ptr,(char*)regptr->GPR,32*4);
484 ptr = mem2hstr(ptr,(char*)regptr->FPR,32*8);
485 ptr = mem2hstr(ptr,(char*)&regptr->SRR0,4);
486 ptr = mem2hstr(ptr,(char*)&regptr->SRR1,4);
487 ptr = mem2hstr(ptr,(char*)&regptr->CR,4);
488 ptr = mem2hstr(ptr,(char*)&regptr->LR,4);
489 ptr = mem2hstr(ptr,(char*)&regptr->CTR,4);
490 ptr = mem2hstr(ptr,(char*)&regptr->XER,4);
491 ptr = mem2hstr(ptr,(char*)&regptr->FPSCR,4);
492 break;
493 case 'm':
494 ptr = &remcomInBuffer[1];
495 if(hexToInt(&ptr,&addr) && ((addr&0xC0000000)==0xC0000000 || (addr&0xC0000000)==0x80000000)
496 && *ptr++==','
497 && hexToInt(&ptr,&len) && len<=((BUFMAX - 4)/2))
498 mem2hstr(remcomOutBuffer,(void*)addr,len);
499 else
500 strcpy(remcomOutBuffer,"E00");
501 break;
502 case 'q':
503 process_query(remcomInBuffer,remcomOutBuffer,thread);
504 break;
505 case 'c':
506 dbg_instep = 0;
507 dbg_active = 1;
508 frame->SRR1 &= ~MSR_SE;
509 current_device->wait(current_device);
510 goto exit;
511 case 's':
512 dbg_instep = 1;
513 dbg_active = 1;
514 frame->SRR1 |= MSR_SE;
515 current_device->wait(current_device);
516 goto exit;
517 case 'z':
519 s32 ret,type,len;
520 char *addr;
522 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
523 if(!ret) {
524 strcpy(remcomOutBuffer,"E01");
525 break;
527 if(type!=0) break;
529 if(len<4) {
530 strcpy(remcomOutBuffer,"E02");
531 break;
534 ret = remove_bp(addr);
535 if(!ret) {
536 strcpy(remcomOutBuffer,"E03");
537 break;
539 strcpy(remcomOutBuffer,"OK");
541 break;
542 case 'H':
543 if(remcomInBuffer[1]=='g')
545 s32 tmp,ret;
547 if(vhstr2thread(&remcomInBuffer[2],&tmp)==NULL) {
548 strcpy(remcomOutBuffer,"E01");
549 break;
551 if(!tmp) tmp = thread;
552 if(tmp==current_thread) {
553 strcpy(remcomOutBuffer,"OK");
554 break;
557 if(current_thread!=thread) ret = gdbstub_setthreadregs(current_thread,&current_thread_registers);
558 if(tmp!=thread) {
559 ret = gdbstub_getthreadregs(tmp,&current_thread_registers);
560 if(!ret) {
561 strcpy(remcomOutBuffer,"E02");
562 break;
565 current_thread= tmp;
567 strcpy(remcomOutBuffer,"OK");
568 break;
569 case 'T':
571 s32 tmp;
573 if(vhstr2thread(&remcomInBuffer[1],&tmp)==NULL) {
574 strcpy(remcomOutBuffer,"E01");
575 break;
577 if(gdbstub_indextoid(tmp)==NULL) strcpy(remcomOutBuffer,"E02");
578 else strcpy(remcomOutBuffer,"OK");
580 break;
581 case 'Z':
583 s32 ret,type,len;
584 char *addr;
586 ret = parsezbreak(remcomInBuffer,&type,&addr,&len);
587 if(!ret) {
588 strcpy(remcomOutBuffer,"E01");
589 break;
591 if(type!=0) {
592 strcpy(remcomOutBuffer,"E02");
593 break;
595 if(len<4) {
596 strcpy(remcomOutBuffer,"E03");
597 break;
600 ret = insert_bp(addr);
601 if(!ret) {
602 strcpy(remcomOutBuffer,"E04");
603 break;
605 strcpy(remcomOutBuffer,"OK");
607 break;
609 putpacket(remcomOutBuffer, wait);
611 current_device->close(current_device);
612 exit:
613 return;
616 void _break(void)
618 if(!dbg_initialized) return;
619 __asm__ __volatile__ (".globl __breakinst\n\
620 __breakinst: .long 0x7d821008");
623 void DEBUG_Init(s32 device_type,s32 channel_port)
625 u32 level;
626 struct uip_ip_addr localip,netmask,gateway;
628 UIP_LOG("DEBUG_Init()\n");
630 __lwp_thread_dispatchdisable();
632 bp_init();
634 if(device_type==GDBSTUB_DEVICE_USB) {
635 current_device = usb_init(channel_port);
636 } else {
637 localip.addr = uip_ipaddr((const u8_t*)tcp_localip);
638 netmask.addr = uip_ipaddr((const u8_t*)tcp_netmask);
639 gateway.addr = uip_ipaddr((const u8_t*)tcp_gateway);
641 current_device = tcpip_init(&localip,&netmask,&gateway,(u16)channel_port);
644 if(current_device!=NULL) {
645 _CPU_ISR_Disable(level);
646 __exception_sethandler(EX_DSI,dbg_exceptionhandler);
647 __exception_sethandler(EX_PRG,dbg_exceptionhandler);
648 __exception_sethandler(EX_TRACE,dbg_exceptionhandler);
649 __exception_sethandler(EX_IABR,dbg_exceptionhandler);
650 _CPU_ISR_Restore(level);
652 dbg_initialized = 1;
655 __lwp_thread_dispatchenable();