comparison debug.c @ 829:cc05444a4a4e

WIP debugger improvements. Partial support for display command in 68K debugger. Minor refactor to support commands on a breakpoint.
author Michael Pavone <pavone@retrodev.com>
date Fri, 25 Sep 2015 18:12:55 -0700
parents 792be135d3af
children 5a3ac6093ea2
comparison
equal deleted inserted replaced
828:22c3c52b9871 829:cc05444a4a4e
84 if (*buf == '\n') { 84 if (*buf == '\n') {
85 *buf = 0; 85 *buf = 0;
86 return; 86 return;
87 } 87 }
88 } 88 }
89 }
90
91 void debugger_print(m68k_context *context, char format_char, char *param)
92 {
93 uint32_t value;
94 char format[8];
95 strcpy(format, "%s: %d\n");
96 switch (format_char)
97 {
98 case 'x':
99 case 'X':
100 case 'd':
101 case 'c':
102 format[5] = format_char;
103 break;
104 case '\0':
105 break;
106 default:
107 fprintf(stderr, "Unrecognized format character: %c\n", format_char);
108 }
109 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
110 value = context->dregs[param[1]-'0'];
111 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
112 value = context->aregs[param[1]-'0'];
113 } else if (param[0] == 'S' && param[1] == 'R') {
114 value = (context->status << 8);
115 for (int flag = 0; flag < 5; flag++) {
116 value |= context->flags[flag] << (4-flag);
117 }
118 } else if(param[0] == 'c') {
119 value = context->current_cycle;
120 } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
121 uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), NULL, 16);
122 if ((p_addr & 0xFFFFFF) == 0xC00004) {
123 genesis_context * gen = context->system;
124 value = vdp_hv_counter_read(gen->vdp);
125 } else {
126 value = read_dma_value(p_addr/2);
127 }
128 } else {
129 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
130 return;
131 }
132 printf(format, param, value);
89 } 133 }
90 134
91 #ifndef NO_Z80 135 #ifndef NO_Z80
92 136
93 void zdebugger_print(z80_context * context, char format_char, char * param) 137 void zdebugger_print(z80_context * context, char format_char, char * param)
466 return context; 510 return context;
467 } 511 }
468 512
469 #endif 513 #endif
470 514
515 static uint32_t branch_t;
516 static uint32_t branch_f;
517
518 int run_debugger_command(m68k_context *context, char *input_buf)
519 {
520 m68kinst inst;
521 char * param;
522 char format_char;
523 uint32_t value, after;
524 bp_def *new_bp, **this_bp;
525 switch(input_buf[0])
526 {
527 case 'c':
528 printf("%X, %X\n", input_buf[1], input_buf[2]);
529 puts("Continuing");
530 return 0;
531 case 'b':
532 if (input_buf[1] == 't') {
533 uint32_t stack = context->aregs[7];
534 if (stack >= 0xE00000) {
535 stack &= 0xFFFF;
536 uint8_t non_adr_count = 0;
537 do {
538 uint32_t bt_address = ram[stack/2] << 16 | ram[stack/2+1];
539 bt_address = get_instruction_start(context->native_code_map, bt_address - 2);
540 if (bt_address) {
541 stack += 4;
542 non_adr_count = 0;
543 uint16_t *bt_pc = NULL;
544 if (bt_address < 0x400000) {
545 bt_pc = cart + bt_address/2;
546 } else if(bt_address > 0xE00000) {
547 bt_pc = ram + (bt_address & 0xFFFF)/2;
548 }
549 m68k_decode(bt_pc, &inst, bt_address);
550 m68k_disasm(&inst, input_buf);
551 printf("%X: %s\n", bt_address, input_buf);
552 } else {
553 //non-return address value on stack can be word wide
554 stack += 2;
555 non_adr_count++;
556 }
557 stack &= 0xFFFF;
558 } while (stack && non_adr_count < 6);
559 }
560 } else {
561 param = find_param(input_buf);
562 if (!param) {
563 fputs("b command requires a parameter\n", stderr);
564 break;
565 }
566 value = strtol(param, NULL, 16);
567 insert_breakpoint(context, value, (uint8_t *)debugger);
568 new_bp = malloc(sizeof(bp_def));
569 new_bp->next = breakpoints;
570 new_bp->address = value;
571 new_bp->index = bp_index++;
572 breakpoints = new_bp;
573 printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
574 }
575 break;
576 case 'a':
577 param = find_param(input_buf);
578 if (!param) {
579 fputs("a command requires a parameter\n", stderr);
580 break;
581 }
582 value = strtol(param, NULL, 16);
583 insert_breakpoint(context, value, (uint8_t *)debugger);
584 return 0;
585 case 'd':
586 if (input_buf[1] == 'i') {
587 format_char = 0;
588 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
589 if (input_buf[i] == '/') {
590 format_char = input_buf[i+1];
591 break;
592 }
593 }
594 param = find_param(input_buf);
595 if (!param) {
596 fputs("display command requires a parameter\n", stderr);
597 break;
598 }
599 debugger_print(context, format_char, param);
600 add_display(&displays, &disp_index, format_char, param);
601 } else {
602 param = find_param(input_buf);
603 if (!param) {
604 fputs("d command requires a parameter\n", stderr);
605 break;
606 }
607 value = atoi(param);
608 this_bp = find_breakpoint_idx(&breakpoints, value);
609 if (!*this_bp) {
610 fprintf(stderr, "Breakpoint %d does not exist\n", value);
611 break;
612 }
613 new_bp = *this_bp;
614 *this_bp = (*this_bp)->next;
615 free(new_bp);
616 }
617 break;
618 case 'p':
619 format_char = 0;
620 for(int i = 2; input_buf[i] != 0 && input_buf[i] != ' '; i++) {
621 if (input_buf[i] == '/') {
622 format_char = input_buf[i+1];
623 break;
624 }
625 }
626 param = find_param(input_buf);
627 if (!param) {
628 fputs("p command requires a parameter\n", stderr);
629 break;
630 }
631 debugger_print(context, format_char, param);
632 break;
633 case 'n':
634 if (inst.op == M68K_RTS) {
635 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
636 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
637 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
638 } else if(m68k_is_noncall_branch(&inst)) {
639 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
640 branch_f = after;
641 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
642 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
643 } else if(inst.op == M68K_DBCC) {
644 if ( inst.extra.cond == COND_FALSE) {
645 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
646 after = m68k_branch_target(&inst, context->dregs, context->aregs);
647 }
648 } else {
649 branch_t = after;
650 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
651 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
652 }
653 } else {
654 after = m68k_branch_target(&inst, context->dregs, context->aregs);
655 }
656 }
657 insert_breakpoint(context, after, (uint8_t *)debugger);
658 return 0;
659 case 'o':
660 if (inst.op == M68K_RTS) {
661 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
662 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
663 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
664 } else if(m68k_is_noncall_branch(&inst)) {
665 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
666 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
667 if (branch_t < after) {
668 branch_t = 0;
669 } else {
670 branch_f = after;
671 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
672 }
673 } else if(inst.op == M68K_DBCC) {
674 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
675 if (target > after) {
676 if (inst.extra.cond == COND_FALSE) {
677 after = target;
678 } else {
679 branch_f = target;
680 branch_t = after;
681 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
682 }
683 }
684 } else {
685 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
686 }
687 }
688 insert_breakpoint(context, after, (uint8_t *)debugger);
689 return 0;
690 case 's':
691 if (inst.op == M68K_RTS) {
692 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
693 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
694 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
695 } else if(m68k_is_branch(&inst)) {
696 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
697 branch_f = after;
698 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
699 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
700 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
701 branch_t = after;
702 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
703 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
704 } else {
705 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
706 }
707 }
708 insert_breakpoint(context, after, (uint8_t *)debugger);
709 return 0;
710 case 'v': {
711 genesis_context * gen = context->system;
712 //VDP debug commands
713 switch(input_buf[1])
714 {
715 case 's':
716 vdp_print_sprite_table(gen->vdp);
717 break;
718 case 'r':
719 vdp_print_reg_explain(gen->vdp);
720 break;
721 }
722 break;
723 }
724 case 'y': {
725 genesis_context * gen = context->system;
726 //YM-2612 debug commands
727 switch(input_buf[1])
728 {
729 case 'c':
730 if (input_buf[2] == ' ') {
731 int channel = atoi(input_buf+3)-1;
732 ym_print_channel_info(gen->ym, channel);
733 } else {
734 for (int i = 0; i < 6; i++) {
735 ym_print_channel_info(gen->ym, i);
736 }
737 }
738 }
739 break;
740 }
741 #ifndef NO_Z80
742 case 'z': {
743 genesis_context * gen = context->system;
744 //Z80 debug commands
745 switch(input_buf[1])
746 {
747 case 'b':
748 param = find_param(input_buf);
749 if (!param) {
750 fputs("zb command requires a parameter\n", stderr);
751 break;
752 }
753 value = strtol(param, NULL, 16);
754 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
755 new_bp = malloc(sizeof(bp_def));
756 new_bp->next = zbreakpoints;
757 new_bp->address = value;
758 new_bp->index = zbp_index++;
759 zbreakpoints = new_bp;
760 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
761 break;
762 case 'p':
763 param = find_param(input_buf);
764 if (!param) {
765 fputs("zp command requires a parameter\n", stderr);
766 break;
767 }
768 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
769 }
770 break;
771 }
772 #endif
773 case 'q':
774 puts("Quitting");
775 exit(0);
776 break;
777 default:
778 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
779 break;
780 }
781 return 1;
782 }
783
784
471 m68k_context * debugger(m68k_context * context, uint32_t address) 785 m68k_context * debugger(m68k_context * context, uint32_t address)
472 { 786 {
473 static char last_cmd[1024]; 787 static char last_cmd[1024];
474 char input_buf[1024]; 788 char input_buf[1024];
475 static uint32_t branch_t;
476 static uint32_t branch_f;
477 m68kinst inst; 789 m68kinst inst;
478 790
479 init_terminal(); 791 init_terminal();
480 792
481 sync_components(context, 0); 793 sync_components(context, 0);
498 bp_def ** this_bp = find_breakpoint(&breakpoints, address); 810 bp_def ** this_bp = find_breakpoint(&breakpoints, address);
499 if (*this_bp) { 811 if (*this_bp) {
500 printf("68K Breakpoint %d hit\n", (*this_bp)->index); 812 printf("68K Breakpoint %d hit\n", (*this_bp)->index);
501 } else { 813 } else {
502 remove_breakpoint(context, address); 814 remove_breakpoint(context, address);
815 }
816 for (disp_def * cur = displays; cur; cur = cur->next) {
817 debugger_print(context, cur->format_char, cur->param);
503 } 818 }
504 uint16_t * pc; 819 uint16_t * pc;
505 if (address < 0x400000) { 820 if (address < 0x400000) {
506 pc = cart + address/2; 821 pc = cart + address/2;
507 } else if(address > 0xE00000) { 822 } else if(address > 0xE00000) {
548 if (input_buf[0]) { 863 if (input_buf[0]) {
549 strcpy(last_cmd, input_buf); 864 strcpy(last_cmd, input_buf);
550 } else { 865 } else {
551 strcpy(input_buf, last_cmd); 866 strcpy(input_buf, last_cmd);
552 } 867 }
553 char * param; 868 debugging = run_debugger_command(context, input_buf);
554 char format[8];
555 uint32_t value;
556 bp_def * new_bp;
557 switch(input_buf[0])
558 {
559 case 'c':
560 puts("Continuing");
561 debugging = 0;
562 break;
563 case 'b':
564 if (input_buf[1] == 't') {
565 uint32_t stack = context->aregs[7];
566 if (stack >= 0xE00000) {
567 stack &= 0xFFFF;
568 uint8_t non_adr_count = 0;
569 do {
570 uint32_t bt_address = ram[stack/2] << 16 | ram[stack/2+1];
571 bt_address = get_instruction_start(context->native_code_map, bt_address - 2);
572 if (bt_address) {
573 stack += 4;
574 non_adr_count = 0;
575 uint16_t *bt_pc = NULL;
576 if (bt_address < 0x400000) {
577 bt_pc = cart + bt_address/2;
578 } else if(bt_address > 0xE00000) {
579 bt_pc = ram + (bt_address & 0xFFFF)/2;
580 }
581 m68k_decode(bt_pc, &inst, bt_address);
582 m68k_disasm(&inst, input_buf);
583 printf("%X: %s\n", bt_address, input_buf);
584 } else {
585 //non-return address value on stack can be word wide
586 stack += 2;
587 non_adr_count++;
588 }
589 stack &= 0xFFFF;
590 } while (stack && non_adr_count < 6);
591 }
592 } else {
593 param = find_param(input_buf);
594 if (!param) {
595 fputs("b command requires a parameter\n", stderr);
596 break;
597 }
598 value = strtol(param, NULL, 16);
599 insert_breakpoint(context, value, (uint8_t *)debugger);
600 new_bp = malloc(sizeof(bp_def));
601 new_bp->next = breakpoints;
602 new_bp->address = value;
603 new_bp->index = bp_index++;
604 breakpoints = new_bp;
605 printf("68K Breakpoint %d set at %X\n", new_bp->index, value);
606 }
607 break;
608 case 'a':
609 param = find_param(input_buf);
610 if (!param) {
611 fputs("a command requires a parameter\n", stderr);
612 break;
613 }
614 value = strtol(param, NULL, 16);
615 insert_breakpoint(context, value, (uint8_t *)debugger);
616 debugging = 0;
617 break;
618 case 'd':
619 param = find_param(input_buf);
620 if (!param) {
621 fputs("d command requires a parameter\n", stderr);
622 break;
623 }
624 value = atoi(param);
625 this_bp = find_breakpoint_idx(&breakpoints, value);
626 if (!*this_bp) {
627 fprintf(stderr, "Breakpoint %d does not exist\n", value);
628 break;
629 }
630 new_bp = *this_bp;
631 *this_bp = (*this_bp)->next;
632 free(new_bp);
633 break;
634 case 'p':
635 strcpy(format, "%s: %d\n");
636 if (input_buf[1] == '/') {
637 switch (input_buf[2])
638 {
639 case 'x':
640 case 'X':
641 case 'd':
642 case 'c':
643 format[5] = input_buf[2];
644 break;
645 default:
646 fprintf(stderr, "Unrecognized format character: %c\n", input_buf[2]);
647 }
648 }
649 param = find_param(input_buf);
650 if (!param) {
651 fputs("p command requires a parameter\n", stderr);
652 break;
653 }
654 if (param[0] == 'd' && param[1] >= '0' && param[1] <= '7') {
655 value = context->dregs[param[1]-'0'];
656 } else if (param[0] == 'a' && param[1] >= '0' && param[1] <= '7') {
657 value = context->aregs[param[1]-'0'];
658 } else if (param[0] == 'S' && param[1] == 'R') {
659 value = (context->status << 8);
660 for (int flag = 0; flag < 5; flag++) {
661 value |= context->flags[flag] << (4-flag);
662 }
663 } else if(param[0] == 'c') {
664 value = context->current_cycle;
665 } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') {
666 uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), NULL, 16);
667 if ((p_addr & 0xFFFFFF) == 0xC00004) {
668 genesis_context * gen = context->system;
669 value = vdp_hv_counter_read(gen->vdp);
670 } else {
671 value = read_dma_value(p_addr/2);
672 }
673 } else {
674 fprintf(stderr, "Unrecognized parameter to p: %s\n", param);
675 break;
676 }
677 printf(format, param, value);
678 break;
679 case 'n':
680 if (inst.op == M68K_RTS) {
681 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
682 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
683 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
684 } else if(m68k_is_noncall_branch(&inst)) {
685 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
686 branch_f = after;
687 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs);
688 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
689 } else if(inst.op == M68K_DBCC) {
690 if ( inst.extra.cond == COND_FALSE) {
691 if (context->dregs[inst.dst.params.regs.pri] & 0xFFFF) {
692 after = m68k_branch_target(&inst, context->dregs, context->aregs);
693 }
694 } else {
695 branch_t = after;
696 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs);
697 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
698 }
699 } else {
700 after = m68k_branch_target(&inst, context->dregs, context->aregs);
701 }
702 }
703 insert_breakpoint(context, after, (uint8_t *)debugger);
704 debugging = 0;
705 break;
706 case 'o':
707 if (inst.op == M68K_RTS) {
708 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
709 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
710 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
711 } else if(m68k_is_noncall_branch(&inst)) {
712 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
713 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
714 if (branch_t < after) {
715 branch_t = 0;
716 } else {
717 branch_f = after;
718 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
719 }
720 } else if(inst.op == M68K_DBCC) {
721 uint32_t target = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
722 if (target > after) {
723 if (inst.extra.cond == COND_FALSE) {
724 after = target;
725 } else {
726 branch_f = target;
727 branch_t = after;
728 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
729 }
730 }
731 } else {
732 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
733 }
734 }
735 insert_breakpoint(context, after, (uint8_t *)debugger);
736 debugging = 0;
737 break;
738 case 's':
739 if (inst.op == M68K_RTS) {
740 after = (read_dma_value(context->aregs[7]/2) << 16) | read_dma_value(context->aregs[7]/2 + 1);
741 } else if (inst.op == M68K_RTE || inst.op == M68K_RTR) {
742 after = (read_dma_value((context->aregs[7]+2)/2) << 16) | read_dma_value((context->aregs[7]+2)/2 + 1);
743 } else if(m68k_is_branch(&inst)) {
744 if (inst.op == M68K_BCC && inst.extra.cond != COND_TRUE) {
745 branch_f = after;
746 branch_t = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
747 insert_breakpoint(context, branch_t, (uint8_t *)debugger);
748 } else if(inst.op == M68K_DBCC && inst.extra.cond != COND_FALSE) {
749 branch_t = after;
750 branch_f = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
751 insert_breakpoint(context, branch_f, (uint8_t *)debugger);
752 } else {
753 after = m68k_branch_target(&inst, context->dregs, context->aregs) & 0xFFFFFF;
754 }
755 }
756 insert_breakpoint(context, after, (uint8_t *)debugger);
757 debugging = 0;
758 break;
759 case 'v': {
760 genesis_context * gen = context->system;
761 //VDP debug commands
762 switch(input_buf[1])
763 {
764 case 's':
765 vdp_print_sprite_table(gen->vdp);
766 break;
767 case 'r':
768 vdp_print_reg_explain(gen->vdp);
769 break;
770 }
771 break;
772 }
773 case 'y': {
774 genesis_context * gen = context->system;
775 //YM-2612 debug commands
776 switch(input_buf[1])
777 {
778 case 'c':
779 if (input_buf[2] == ' ') {
780 int channel = atoi(input_buf+3)-1;
781 ym_print_channel_info(gen->ym, channel);
782 } else {
783 for (int i = 0; i < 6; i++) {
784 ym_print_channel_info(gen->ym, i);
785 }
786 }
787 }
788 break;
789 }
790 #ifndef NO_Z80
791 case 'z': {
792 genesis_context * gen = context->system;
793 //Z80 debug commands
794 switch(input_buf[1])
795 {
796 case 'b':
797 param = find_param(input_buf);
798 if (!param) {
799 fputs("zb command requires a parameter\n", stderr);
800 break;
801 }
802 value = strtol(param, NULL, 16);
803 zinsert_breakpoint(gen->z80, value, (uint8_t *)zdebugger);
804 new_bp = malloc(sizeof(bp_def));
805 new_bp->next = zbreakpoints;
806 new_bp->address = value;
807 new_bp->index = zbp_index++;
808 zbreakpoints = new_bp;
809 printf("Z80 Breakpoint %d set at %X\n", new_bp->index, value);
810 break;
811 case 'p':
812 param = find_param(input_buf);
813 if (!param) {
814 fputs("zp command requires a parameter\n", stderr);
815 break;
816 }
817 zdebugger_print(gen->z80, input_buf[2] == '/' ? input_buf[3] : 0, param);
818 }
819 break;
820 }
821 #endif
822 case 'q':
823 puts("Quitting");
824 exit(0);
825 break;
826 default:
827 fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
828 break;
829 }
830 } 869 }
831 return context; 870 return context;
832 } 871 }