25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: debugger.c,v 1.14 2006/07/01 21:15:46 debug Exp $ |
* $Id: debugger.c,v 1.20 2006/10/29 05:17:21 debug Exp $ |
29 |
* |
* |
30 |
* Single-step debugger. |
* Single-step debugger. |
31 |
* |
* |
38 |
* |
* |
39 |
* Call stack display (back-trace)? |
* Call stack display (back-trace)? |
40 |
* |
* |
|
* More generic expression evaluator (for example + - * / between multiple |
|
|
* terms), including _TAB COMPLETION_ of symbols and register names! |
|
|
* Must be possible to reach any emul, any machine in any emul, any |
|
|
* cpu in any machine, other variables in the emulator, and so forth. |
|
|
* Perhaps a "settable variables registry" somewhere? |
|
|
* |
|
41 |
* Nicer looking output of register dumps, floating point registers, |
* Nicer looking output of register dumps, floating point registers, |
42 |
* etc. Warn about weird/invalid register contents. |
* etc. Warn about weird/invalid register contents. |
43 |
* |
* |
65 |
#include "misc.h" |
#include "misc.h" |
66 |
#include "net.h" |
#include "net.h" |
67 |
#include "settings.h" |
#include "settings.h" |
68 |
|
#include "timer.h" |
69 |
#include "x11.h" |
#include "x11.h" |
70 |
|
|
71 |
|
|
101 |
|
|
102 |
static int debugger_n_emuls; |
static int debugger_n_emuls; |
103 |
static struct emul **debugger_emuls; |
static struct emul **debugger_emuls; |
104 |
static struct emul *debugger_emul; |
|
105 |
|
/* Currently focused CPU, machine, and emulation: */ |
106 |
|
int debugger_cur_cpu; |
107 |
|
int debugger_cur_machine; |
108 |
|
int debugger_cur_emul; |
109 |
static struct machine *debugger_machine; |
static struct machine *debugger_machine; |
110 |
|
static struct emul *debugger_emul; |
111 |
|
|
112 |
#define MAX_CMD_BUFLEN 72 |
#define MAX_CMD_BUFLEN 72 |
113 |
#define N_PREVIOUS_CMDS 150 |
#define N_PREVIOUS_CMDS 150 |
150 |
be factored out... */ |
be factored out... */ |
151 |
|
|
152 |
/* Give up some CPU time: */ |
/* Give up some CPU time: */ |
153 |
usleep(1); |
usleep(10000); |
154 |
} |
} |
155 |
return ch; |
return ch; |
156 |
} |
} |
194 |
|
|
195 |
|
|
196 |
/* |
/* |
|
* debugger_parse_name(): |
|
|
* |
|
|
* This function reads a string, and tries to match it to a register name, |
|
|
* a symbol, or treat it as a decimal numeric value. |
|
|
* |
|
|
* Some examples: |
|
|
* |
|
|
* "0x7fff1234" ==> numeric value (hex, in this case) |
|
|
* "pc", "r5", "hi", "t4" ==> register (CPU dependent) |
|
|
* "memcpy+64" ==> symbol (plus offset) |
|
|
* |
|
|
* Register names can be preceeded by "x:" where x is the CPU number. (CPU |
|
|
* 0 is assumed by default.) |
|
|
* |
|
|
* To force detection of different types, a character can be added in front of |
|
|
* the name: "$" for numeric values, "%" for registers, and "@" for symbols. |
|
|
* |
|
|
* Return value is: |
|
|
* |
|
|
* NAME_PARSE_NOMATCH no match |
|
|
* NAME_PARSE_MULTIPLE multiple matches |
|
|
* |
|
|
* or one of these (and then *valuep is read or written, depending on |
|
|
* the writeflag): |
|
|
* |
|
|
* NAME_PARSE_REGISTER a register |
|
|
* NAME_PARSE_NUMBER a hex number |
|
|
* NAME_PARSE_SYMBOL a symbol |
|
|
*/ |
|
|
#define NAME_PARSE_NOMATCH 0 |
|
|
#define NAME_PARSE_MULTIPLE 1 |
|
|
#define NAME_PARSE_REGISTER 2 |
|
|
#define NAME_PARSE_NUMBER 3 |
|
|
#define NAME_PARSE_SYMBOL 4 |
|
|
static int debugger_parse_name(struct machine *m, char *name, int writeflag, |
|
|
uint64_t *valuep) |
|
|
{ |
|
|
int match_register = 0, match_symbol = 0, match_numeric = 0; |
|
|
int skip_register, skip_numeric, skip_symbol; |
|
|
|
|
|
if (m == NULL || name == NULL) { |
|
|
fprintf(stderr, "debugger_parse_name(): NULL ptr\n"); |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
/* Warn about non-signextended values: */ |
|
|
if (writeflag) { |
|
|
if (m->cpus[0]->is_32bit) { |
|
|
/* Automagically sign-extend. TODO: Is this good? */ |
|
|
if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL) |
|
|
(*valuep) |= 0xffffffff00000000ULL; |
|
|
} else { |
|
|
if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL) |
|
|
printf("WARNING: The value is not sign-extende" |
|
|
"d. Is this what you intended?\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
skip_register = name[0] == '$' || name[0] == '@'; |
|
|
skip_numeric = name[0] == '%' || name[0] == '@'; |
|
|
skip_symbol = name[0] == '$' || name[0] == '%'; |
|
|
|
|
|
/* Check for a register match: */ |
|
|
if (!skip_register && strlen(name) >= 1) |
|
|
cpu_register_match(m, name, writeflag, valuep, |
|
|
&match_register); |
|
|
|
|
|
/* Check for a number match: */ |
|
|
if (!skip_numeric && isdigit((int)name[0])) { |
|
|
uint64_t x; |
|
|
x = strtoull(name, NULL, 0); |
|
|
if (writeflag) { |
|
|
printf("You cannot assign like that.\n"); |
|
|
} else |
|
|
*valuep = x; |
|
|
match_numeric = 1; |
|
|
} |
|
|
|
|
|
/* Check for a symbol match: */ |
|
|
if (!skip_symbol) { |
|
|
int res; |
|
|
char *p, *sn; |
|
|
uint64_t newaddr, ofs = 0; |
|
|
|
|
|
sn = malloc(strlen(name) + 1); |
|
|
if (sn == NULL) { |
|
|
fprintf(stderr, "out of memory in debugger\n"); |
|
|
exit(1); |
|
|
} |
|
|
strlcpy(sn, name, strlen(name)+1); |
|
|
|
|
|
/* Is there a '+' in there? Then treat that as an offset: */ |
|
|
p = strchr(sn, '+'); |
|
|
if (p != NULL) { |
|
|
*p = '\0'; |
|
|
ofs = strtoull(p+1, NULL, 0); |
|
|
} |
|
|
|
|
|
res = get_symbol_addr(&m->symbol_context, sn, &newaddr); |
|
|
if (res) { |
|
|
if (writeflag) { |
|
|
printf("You cannot assign like that.\n"); |
|
|
} else |
|
|
*valuep = newaddr + ofs; |
|
|
match_symbol = 1; |
|
|
} |
|
|
|
|
|
free(sn); |
|
|
} |
|
|
|
|
|
if (match_register + match_symbol + match_numeric > 1) |
|
|
return NAME_PARSE_MULTIPLE; |
|
|
|
|
|
if (match_register) |
|
|
return NAME_PARSE_REGISTER; |
|
|
if (match_numeric) |
|
|
return NAME_PARSE_NUMBER; |
|
|
if (match_symbol) |
|
|
return NAME_PARSE_SYMBOL; |
|
|
|
|
|
return NAME_PARSE_NOMATCH; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
197 |
* show_breakpoint(): |
* show_breakpoint(): |
198 |
*/ |
*/ |
199 |
static void show_breakpoint(struct machine *m, int i) |
static void show_breakpoint(struct machine *m, int i) |
256 |
|
|
257 |
/* printf("left = '%s'\nright = '%s'\n", left, right); */ |
/* printf("left = '%s'\nright = '%s'\n", left, right); */ |
258 |
|
|
259 |
res_right = debugger_parse_name(m, right, 0, &tmp); |
res_right = debugger_parse_expression(m, right, 0, &tmp); |
260 |
switch (res_right) { |
switch (res_right) { |
261 |
case NAME_PARSE_NOMATCH: |
case PARSE_NOMATCH: |
262 |
printf("No match for the right-hand side of the assignment.\n"); |
printf("No match for the right-hand side of the assignment.\n"); |
263 |
break; |
break; |
264 |
case NAME_PARSE_MULTIPLE: |
case PARSE_MULTIPLE: |
265 |
printf("Multiple matches for the right-hand side of the " |
printf("Multiple matches for the right-hand side of the " |
266 |
"assignment.\n"); |
"assignment.\n"); |
267 |
break; |
break; |
268 |
default: |
default: |
269 |
res_left = debugger_parse_name(m, left, 1, &tmp); |
res_left = debugger_parse_expression(m, left, 1, &tmp); |
270 |
switch (res_left) { |
switch (res_left) { |
271 |
case NAME_PARSE_NOMATCH: |
case PARSE_NOMATCH: |
272 |
printf("No match for the left-hand side of the " |
printf("No match for the left-hand side of the " |
273 |
"assignment.\n"); |
"assignment.\n"); |
274 |
break; |
break; |
275 |
case NAME_PARSE_MULTIPLE: |
case PARSE_MULTIPLE: |
276 |
printf("Multiple matches for the left-hand side " |
printf("Multiple matches for the left-hand side " |
277 |
"of the assignment.\n"); |
"of the assignment.\n"); |
278 |
break; |
break; |
585 |
} else if (ch == 27) { |
} else if (ch == 27) { |
586 |
/* Escape codes: (cursor keys etc) */ |
/* Escape codes: (cursor keys etc) */ |
587 |
while ((ch = console_readchar(MAIN_CONSOLE)) < 0) |
while ((ch = console_readchar(MAIN_CONSOLE)) < 0) |
588 |
usleep(1); |
usleep(10000); |
589 |
if (ch == '[' || ch == 'O') { |
if (ch == '[' || ch == 'O') { |
590 |
while ((ch = console_readchar(MAIN_CONSOLE)) |
while ((ch = console_readchar(MAIN_CONSOLE)) |
591 |
< 0) |
< 0) |
592 |
usleep(1); |
usleep(10000); |
593 |
switch (ch) { |
switch (ch) { |
594 |
case '2': /* 2~ = ins */ |
case '2': /* 2~ = ins */ |
595 |
case '5': /* 5~ = pgup */ |
case '5': /* 5~ = pgup */ |
597 |
/* TODO: Ugly hack, but might work. */ |
/* TODO: Ugly hack, but might work. */ |
598 |
while ((ch = console_readchar( |
while ((ch = console_readchar( |
599 |
MAIN_CONSOLE)) < 0) |
MAIN_CONSOLE)) < 0) |
600 |
usleep(1); |
usleep(10000); |
601 |
/* Do nothing for these keys. */ |
/* Do nothing for these keys. */ |
602 |
break; |
break; |
603 |
case '3': /* 3~ = delete */ |
case '3': /* 3~ = delete */ |
604 |
/* TODO: Ugly hack, but might work. */ |
/* TODO: Ugly hack, but might work. */ |
605 |
while ((ch = console_readchar( |
while ((ch = console_readchar( |
606 |
MAIN_CONSOLE)) < 0) |
MAIN_CONSOLE)) < 0) |
607 |
usleep(1); |
usleep(10000); |
608 |
console_makeavail(MAIN_CONSOLE, '\b'); |
console_makeavail(MAIN_CONSOLE, '\b'); |
609 |
break; |
break; |
610 |
case 'A': /* Up. */ |
case 'A': /* Up. */ |
693 |
} |
} |
694 |
|
|
695 |
|
|
696 |
|
/* Stop timers while interacting with the user: */ |
697 |
|
timer_stop(); |
698 |
|
|
699 |
exit_debugger = 0; |
exit_debugger = 0; |
700 |
|
|
701 |
while (!exit_debugger) { |
while (!exit_debugger) { |
736 |
return; |
return; |
737 |
} |
} |
738 |
|
|
739 |
|
/* Start up timers again: */ |
740 |
|
timer_start(); |
741 |
|
|
742 |
|
/* ... and reset starttime, so that nr of instructions per second |
743 |
|
can be calculated correctly: */ |
744 |
gettimeofday(&debugger_machine->starttime, NULL); |
gettimeofday(&debugger_machine->starttime, NULL); |
745 |
debugger_machine->ninstrs_since_gettimeofday = 0; |
debugger_machine->ninstrs_since_gettimeofday = 0; |
746 |
|
|
795 |
|
|
796 |
debugger_machine = emuls[0]->machines[0]; |
debugger_machine = emuls[0]->machines[0]; |
797 |
|
|
798 |
|
debugger_cur_cpu = 0; |
799 |
|
debugger_cur_machine = 0; |
800 |
|
debugger_cur_emul = 0; |
801 |
|
|
802 |
for (i=0; i<N_PREVIOUS_CMDS; i++) { |
for (i=0; i<N_PREVIOUS_CMDS; i++) { |
803 |
last_cmd[i] = malloc(MAX_CMD_BUFLEN); |
last_cmd[i] = malloc(MAX_CMD_BUFLEN); |
804 |
if (last_cmd[i] == NULL) { |
if (last_cmd[i] == NULL) { |