25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: debugger.c,v 1.21 2006/12/30 13:30:56 debug Exp $ |
* $Id: debugger.c,v 1.26 2007/06/15 17:02:39 debug Exp $ |
29 |
* |
* |
30 |
* Single-step debugger. |
* Single-step debugger. |
31 |
* |
* |
32 |
* |
* |
33 |
* TODO: |
* This entire module is very much non-reentrant. :-/ TODO: Fix. |
|
* |
|
|
* This entire module is very much non-reentrant. :-/ |
|
|
* |
|
|
* Add more functionality that already exists elsewhere in the emulator. |
|
|
* |
|
|
* Call stack display (back-trace)? |
|
|
* |
|
|
* Nicer looking output of register dumps, floating point registers, |
|
|
* etc. Warn about weird/invalid register contents. |
|
|
* |
|
|
* Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)... |
|
|
* |
|
|
* Many other TODOs. |
|
34 |
*/ |
*/ |
35 |
|
|
36 |
#include <ctype.h> |
#include <ctype.h> |
44 |
#include "cpu.h" |
#include "cpu.h" |
45 |
#include "device.h" |
#include "device.h" |
46 |
#include "debugger.h" |
#include "debugger.h" |
|
#include "debugger_gdb.h" |
|
47 |
#include "diskimage.h" |
#include "diskimage.h" |
48 |
#include "emul.h" |
#include "emul.h" |
49 |
#include "machine.h" |
#include "machine.h" |
113 |
*/ |
*/ |
114 |
char debugger_readchar(void) |
char debugger_readchar(void) |
115 |
{ |
{ |
116 |
int ch, i, j; |
int ch; |
117 |
|
|
118 |
while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) { |
while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) { |
119 |
/* Check for X11 events: */ |
/* Check for X11 events: */ |
120 |
x11_check_event(debugger_emuls, debugger_n_emuls); |
x11_check_event(debugger_emuls, debugger_n_emuls); |
121 |
|
|
|
/* Check for incoming GDB packets: */ |
|
|
for (i=0; i<debugger_n_emuls; i++) { |
|
|
struct emul *e = debugger_emuls[i]; |
|
|
if (e == NULL) |
|
|
continue; |
|
|
|
|
|
for (j=0; j<e->n_machines; j++) { |
|
|
if (e->machines[j]->gdb.port > 0) |
|
|
debugger_gdb_check_incoming( |
|
|
e->machines[j]); |
|
|
} |
|
|
} |
|
|
|
|
|
/* TODO: The X11 and GDB checks above should probably |
|
|
be factored out... */ |
|
|
|
|
122 |
/* Give up some CPU time: */ |
/* Give up some CPU time: */ |
123 |
usleep(10000); |
usleep(10000); |
124 |
} |
} |
170 |
{ |
{ |
171 |
printf("%3i: 0x", i); |
printf("%3i: 0x", i); |
172 |
if (m->cpus[0]->is_32bit) |
if (m->cpus[0]->is_32bit) |
173 |
printf("%08"PRIx32, (uint32_t) m->breakpoint_addr[i]); |
printf("%08"PRIx32, (uint32_t) m->breakpoints.addr[i]); |
174 |
else |
else |
175 |
printf("%016"PRIx64, (uint64_t) m->breakpoint_addr[i]); |
printf("%016"PRIx64, (uint64_t) m->breakpoints.addr[i]); |
176 |
if (m->breakpoint_string[i] != NULL) |
if (m->breakpoints.string[i] != NULL) |
177 |
printf(" (%s)", m->breakpoint_string[i]); |
printf(" (%s)", m->breakpoints.string[i]); |
|
if (m->breakpoint_flags[i]) |
|
|
printf(": flags=0x%x", m->breakpoint_flags[i]); |
|
178 |
printf("\n"); |
printf("\n"); |
179 |
} |
} |
180 |
|
|
200 |
uint64_t tmp; |
uint64_t tmp; |
201 |
uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */ |
uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */ |
202 |
|
|
203 |
left = malloc(MAX_CMD_BUFLEN); |
CHECK_ALLOCATION(left = malloc(MAX_CMD_BUFLEN)); |
|
if (left == NULL) { |
|
|
fprintf(stderr, "out of memory in debugger_assignment()\n"); |
|
|
exit(1); |
|
|
} |
|
204 |
strlcpy(left, cmd, MAX_CMD_BUFLEN); |
strlcpy(left, cmd, MAX_CMD_BUFLEN); |
205 |
right = strchr(left, '='); |
right = strchr(left, '='); |
206 |
if (right == NULL) { |
if (right == NULL) { |
637 |
debugger_machine->cpus[i], 0, INVALIDATE_ALL); |
debugger_machine->cpus[i], 0, INVALIDATE_ALL); |
638 |
} |
} |
639 |
|
|
|
/* |
|
|
* Ugly GDB hack: After single stepping, we need to send back |
|
|
* status to GDB: |
|
|
*/ |
|
|
if (exit_debugger == -1) { |
|
|
int i, j; |
|
|
for (i=0; i<debugger_n_emuls; i++) { |
|
|
struct emul *e = debugger_emuls[i]; |
|
|
if (e == NULL) |
|
|
continue; |
|
|
|
|
|
for (j=0; j<e->n_machines; j++) { |
|
|
if (e->machines[j]->gdb.port > 0) |
|
|
debugger_gdb_after_singlestep( |
|
|
e->machines[j]); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
640 |
/* Stop timers while interacting with the user: */ |
/* Stop timers while interacting with the user: */ |
641 |
timer_stop(); |
timer_stop(); |
642 |
|
|
646 |
/* Read a line from the terminal: */ |
/* Read a line from the terminal: */ |
647 |
cmd = debugger_readline(); |
cmd = debugger_readline(); |
648 |
|
|
|
/* Special hack for the "step" _GDB_ command: */ |
|
|
if (exit_debugger == -1) |
|
|
return; |
|
|
|
|
649 |
cmd_len = strlen(cmd); |
cmd_len = strlen(cmd); |
650 |
|
|
651 |
/* Remove spaces: */ |
/* Remove spaces: */ |
681 |
|
|
682 |
/* ... and reset starttime, so that nr of instructions per second |
/* ... and reset starttime, so that nr of instructions per second |
683 |
can be calculated correctly: */ |
can be calculated correctly: */ |
684 |
gettimeofday(&debugger_machine->starttime, NULL); |
for (i=0; i<debugger_machine->ncpus; i++) { |
685 |
debugger_machine->ninstrs_since_gettimeofday = 0; |
gettimeofday(&debugger_machine->cpus[i]->starttime, NULL); |
686 |
|
debugger_machine->cpus[i]->ninstrs_since_gettimeofday = 0; |
687 |
|
} |
688 |
|
|
689 |
single_step = NOT_SINGLE_STEPPING; |
single_step = NOT_SINGLE_STEPPING; |
690 |
debugger_machine->instruction_trace = old_instruction_trace; |
debugger_machine->instruction_trace = old_instruction_trace; |
714 |
*/ |
*/ |
715 |
void debugger_init(struct emul **emuls, int n_emuls) |
void debugger_init(struct emul **emuls, int n_emuls) |
716 |
{ |
{ |
717 |
int i, j; |
int i; |
718 |
|
|
719 |
debugger_n_emuls = n_emuls; |
debugger_n_emuls = n_emuls; |
720 |
debugger_emuls = emuls; |
debugger_emuls = emuls; |
731 |
exit(1); |
exit(1); |
732 |
} |
} |
733 |
|
|
|
for (i=0; i<n_emuls; i++) |
|
|
for (j=0; j<emuls[i]->n_machines; j++) |
|
|
debugger_gdb_init(emuls[i]->machines[j]); |
|
|
|
|
734 |
debugger_machine = emuls[0]->machines[0]; |
debugger_machine = emuls[0]->machines[0]; |
735 |
|
|
736 |
debugger_cur_cpu = 0; |
debugger_cur_cpu = 0; |
738 |
debugger_cur_emul = 0; |
debugger_cur_emul = 0; |
739 |
|
|
740 |
for (i=0; i<N_PREVIOUS_CMDS; i++) { |
for (i=0; i<N_PREVIOUS_CMDS; i++) { |
741 |
last_cmd[i] = malloc(MAX_CMD_BUFLEN); |
CHECK_ALLOCATION(last_cmd[i] = malloc(MAX_CMD_BUFLEN)); |
|
if (last_cmd[i] == NULL) { |
|
|
fprintf(stderr, "debugger_init(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
742 |
last_cmd[i][0] = '\0'; |
last_cmd[i][0] = '\0'; |
743 |
} |
} |
744 |
|
|