1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: debugger.c,v 1.125 2005/11/13 00:14:06 debug Exp $ |
* $Id: debugger.c,v 1.132 2006/02/04 11:10:58 debug Exp $ |
29 |
* |
* |
30 |
* Single-step debugger. |
* Single-step debugger. |
31 |
* |
* |
36 |
* |
* |
37 |
* Add more functionality that already exists elsewhere in the emulator. |
* Add more functionality that already exists elsewhere in the emulator. |
38 |
* |
* |
39 |
|
* Call stack display? |
40 |
|
* |
41 |
* More generic expression evaluator (for example + - * / between multiple |
* More generic expression evaluator (for example + - * / between multiple |
42 |
* terms), including _TAB COMPLETION_ of symbols and register names! |
* terms), including _TAB COMPLETION_ of symbols and register names! |
43 |
* |
* |
476 |
*/ |
*/ |
477 |
static void debugger_cmd_device(struct machine *m, char *cmd_line) |
static void debugger_cmd_device(struct machine *m, char *cmd_line) |
478 |
{ |
{ |
479 |
int i, j; |
int i; |
480 |
struct memory *mem; |
struct memory *mem; |
481 |
struct cpu *c; |
struct cpu *c; |
482 |
|
|
509 |
device_dumplist(); |
device_dumplist(); |
510 |
} else if (strncmp(cmd_line, "add ", 4) == 0) { |
} else if (strncmp(cmd_line, "add ", 4) == 0) { |
511 |
device_add(m, cmd_line+4); |
device_add(m, cmd_line+4); |
512 |
|
} else if (strcmp(cmd_line, "consoles") == 0) { |
513 |
|
console_debug_dump(m); |
514 |
} else if (strncmp(cmd_line, "remove ", 7) == 0) { |
} else if (strncmp(cmd_line, "remove ", 7) == 0) { |
515 |
i = atoi(cmd_line + 7); |
i = atoi(cmd_line + 7); |
516 |
if (i==0 && cmd_line[7]!='0') { |
if (i==0 && cmd_line[7]!='0') { |
517 |
printf("Weird device number. Use 'device list'.\n"); |
printf("Weird device number. Use 'device list'.\n"); |
518 |
} else |
} else |
519 |
memory_device_remove(m->memory, i); |
memory_device_remove(m->memory, i); |
|
} else if (strncmp(cmd_line, "state ", 6) == 0) { |
|
|
i = atoi(cmd_line + 6); |
|
|
if (i < 0 || i >= mem->n_mmapped_devices) { |
|
|
printf("No devices with that id.\n"); |
|
|
return; |
|
|
} |
|
|
|
|
|
if (mem->dev_f_state[i] == NULL) { |
|
|
printf("No state function has been implemented yet " |
|
|
"for that device type.\n"); |
|
|
return; |
|
|
} |
|
|
|
|
|
for (j=0; ; j++) { |
|
|
int type; |
|
|
char *name; |
|
|
void *data; |
|
|
size_t len; |
|
|
int res = mem->dev_f_state[i](c, mem, |
|
|
mem->dev_extra[i], 0, j, &type, &name, &data, &len); |
|
|
if (!res) |
|
|
break; |
|
|
printf("%2i:%30s = (", j, name); |
|
|
switch (type) { |
|
|
case DEVICE_STATE_TYPE_INT: |
|
|
printf("int) %i", *((int *)data)); |
|
|
break; |
|
|
default: |
|
|
printf("unknown)"); |
|
|
} |
|
|
printf("\n"); |
|
|
} |
|
520 |
} else if (strcmp(cmd_line, "list") == 0) { |
} else if (strcmp(cmd_line, "list") == 0) { |
521 |
if (mem->n_mmapped_devices == 0) |
if (mem->n_mmapped_devices == 0) |
522 |
printf("No memory-mapped devices in this machine.\n"); |
printf("No memory-mapped devices in this machine.\n"); |
547 |
printf(" add name_and_params add a device to the current " |
printf(" add name_and_params add a device to the current " |
548 |
"machine\n"); |
"machine\n"); |
549 |
printf(" all list all registered devices\n"); |
printf(" all list all registered devices\n"); |
550 |
|
printf(" consoles list all slave consoles\n"); |
551 |
printf(" list list memory-mapped devices in the" |
printf(" list list memory-mapped devices in the" |
552 |
" current machine\n"); |
" current machine\n"); |
553 |
printf(" remove x remove device nr x from the " |
printf(" remove x remove device nr x from the " |
554 |
"current machine\n"); |
"current machine\n"); |
|
printf(" state x show state of device nr x in" |
|
|
" the current machine\n"); |
|
555 |
} |
} |
556 |
|
|
557 |
|
|
686 |
*/ |
*/ |
687 |
static void debugger_cmd_emuls(struct machine *m, char *cmd_line) |
static void debugger_cmd_emuls(struct machine *m, char *cmd_line) |
688 |
{ |
{ |
689 |
int i, iadd = 4; |
int i, iadd = DEBUG_INDENTATION; |
690 |
|
|
691 |
if (*cmd_line) { |
if (*cmd_line) { |
692 |
printf("syntax: emuls\n"); |
printf("syntax: emuls\n"); |
845 |
*/ |
*/ |
846 |
static void debugger_cmd_machine(struct machine *m, char *cmd_line) |
static void debugger_cmd_machine(struct machine *m, char *cmd_line) |
847 |
{ |
{ |
848 |
int iadd = 4; |
int iadd = DEBUG_INDENTATION; |
849 |
|
|
850 |
if (*cmd_line) { |
if (*cmd_line) { |
851 |
printf("syntax: machine\n"); |
printf("syntax: machine\n"); |
1054 |
} |
} |
1055 |
|
|
1056 |
/* here: q is the address, p is the data. */ |
/* here: q is the address, p is the data. */ |
|
|
|
1057 |
res = debugger_parse_name(m, q, 0, &addr); |
res = debugger_parse_name(m, q, 0, &addr); |
1058 |
switch (res) { |
switch (res) { |
1059 |
case NAME_PARSE_NOMATCH: |
case NAME_PARSE_NOMATCH: |
1109 |
printf("\n"); |
printf("\n"); |
1110 |
return; |
return; |
1111 |
case 'h': |
case 'h': |
1112 |
if ((data & 1) != 0) |
if ((addr & 1) != 0) |
1113 |
printf("WARNING: address isn't aligned\n"); |
printf("WARNING: address isn't aligned\n"); |
1114 |
if (m->cpus[0]->is_32bit) |
if (m->cpus[0]->is_32bit) |
1115 |
printf("0x%08x", (int)addr); |
printf("0x%08x", (int)addr); |
1124 |
printf("\n"); |
printf("\n"); |
1125 |
return; |
return; |
1126 |
case 'w': |
case 'w': |
1127 |
if ((data & 3) != 0) |
if ((addr & 3) != 0) |
1128 |
printf("WARNING: address isn't aligned\n"); |
printf("WARNING: address isn't aligned\n"); |
1129 |
if (m->cpus[0]->is_32bit) |
if (m->cpus[0]->is_32bit) |
1130 |
printf("0x%08x", (int)addr); |
printf("0x%08x", (int)addr); |
1140 |
printf("\n"); |
printf("\n"); |
1141 |
return; |
return; |
1142 |
case 'd': |
case 'd': |
1143 |
if ((data & 7) != 0) |
if ((addr & 7) != 0) |
1144 |
printf("WARNING: address isn't aligned\n"); |
printf("WARNING: address isn't aligned\n"); |
1145 |
if (m->cpus[0]->is_32bit) |
if (m->cpus[0]->is_32bit) |
1146 |
printf("0x%08x", (int)addr); |
printf("0x%08x", (int)addr); |
1630 |
*/ |
*/ |
1631 |
static void debugger_cmd_help(struct machine *m, char *cmd_line) |
static void debugger_cmd_help(struct machine *m, char *cmd_line) |
1632 |
{ |
{ |
1633 |
int i, max_name_len = 0, only_one = 0, only_one_match = 0; |
int only_one = 0, only_one_match = 0; |
1634 |
char *nlines_env = getenv("LINES"); |
char *nlines_env = getenv("LINES"); |
1635 |
int nlines = atoi(nlines_env != NULL? nlines_env : "999999"); |
int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines; |
1636 |
int j, curlines; |
size_t i, j, max_name_len = 0; |
1637 |
|
|
1638 |
if (cmd_line[0] != '\0') { |
if (cmd_line[0] != '\0') { |
1639 |
only_one = 1; |
only_one = 1; |
1641 |
|
|
1642 |
i = 0; |
i = 0; |
1643 |
while (cmds[i].name != NULL) { |
while (cmds[i].name != NULL) { |
1644 |
int a = strlen(cmds[i].name); |
size_t a = strlen(cmds[i].name); |
1645 |
if (cmds[i].args != NULL) |
if (cmds[i].args != NULL) |
1646 |
a += 1 + strlen(cmds[i].args); |
a += 1 + strlen(cmds[i].args); |
1647 |
if (a > max_name_len) |
if (a > max_name_len) |
1799 |
|
|
1800 |
|
|
1801 |
/* |
/* |
1802 |
|
* debugger_execute_cmd(): |
1803 |
|
*/ |
1804 |
|
void debugger_execute_cmd(char *cmd, int cmd_len) |
1805 |
|
{ |
1806 |
|
int i, n, i_match, matchlen; |
1807 |
|
|
1808 |
|
/* |
1809 |
|
* Is there a '=' on the command line? Then try to do an |
1810 |
|
* assignment. (Only if there is just one word, followed |
1811 |
|
* by the '=' sign. This makes it possible to use commands |
1812 |
|
* such as "device add name addr=xyz".) |
1813 |
|
*/ |
1814 |
|
if (strchr(cmd, '=') != NULL) { |
1815 |
|
/* Count the nr of words: */ |
1816 |
|
int nw = 0, inword = 0; |
1817 |
|
char *p = cmd; |
1818 |
|
while (*p) { |
1819 |
|
if (*p == '=') |
1820 |
|
break; |
1821 |
|
if (*p != ' ') { |
1822 |
|
if (!inword) |
1823 |
|
nw ++; |
1824 |
|
inword = 1; |
1825 |
|
} else |
1826 |
|
inword = 0; |
1827 |
|
p++; |
1828 |
|
} |
1829 |
|
|
1830 |
|
if (nw == 1) { |
1831 |
|
debugger_assignment(debugger_machine, cmd); |
1832 |
|
return; |
1833 |
|
} |
1834 |
|
} |
1835 |
|
|
1836 |
|
i = 0; |
1837 |
|
while (cmds[i].name != NULL) |
1838 |
|
cmds[i++].tmp_flag = 0; |
1839 |
|
|
1840 |
|
/* How many chars in cmd to match against: */ |
1841 |
|
matchlen = 0; |
1842 |
|
while (isalpha((int)cmd[matchlen])) |
1843 |
|
matchlen ++; |
1844 |
|
|
1845 |
|
/* Check for a command name match: */ |
1846 |
|
n = i = i_match = 0; |
1847 |
|
while (cmds[i].name != NULL) { |
1848 |
|
if (strncasecmp(cmds[i].name, cmd, matchlen) == 0 |
1849 |
|
&& cmds[i].f != NULL) { |
1850 |
|
cmds[i].tmp_flag = 1; |
1851 |
|
i_match = i; |
1852 |
|
n++; |
1853 |
|
} |
1854 |
|
i++; |
1855 |
|
} |
1856 |
|
|
1857 |
|
/* No match? */ |
1858 |
|
if (n == 0) { |
1859 |
|
printf("Unknown command '%s'. Type 'help' for help.\n", cmd); |
1860 |
|
return; |
1861 |
|
} |
1862 |
|
|
1863 |
|
/* More than one match? */ |
1864 |
|
if (n > 1) { |
1865 |
|
printf("Ambiguous command '%s': ", cmd); |
1866 |
|
i = 0; |
1867 |
|
while (cmds[i].name != NULL) { |
1868 |
|
if (cmds[i].tmp_flag) |
1869 |
|
printf(" %s", cmds[i].name); |
1870 |
|
i++; |
1871 |
|
} |
1872 |
|
printf("\n"); |
1873 |
|
return; |
1874 |
|
} |
1875 |
|
|
1876 |
|
/* Exactly one match: */ |
1877 |
|
if (cmds[i_match].f != NULL) { |
1878 |
|
char *p = cmd + matchlen; |
1879 |
|
/* Remove leading whitespace from the args... */ |
1880 |
|
while (*p != '\0' && *p == ' ') |
1881 |
|
p++; |
1882 |
|
|
1883 |
|
/* ... and run the command: */ |
1884 |
|
cmds[i_match].f(debugger_machine, p); |
1885 |
|
} else |
1886 |
|
printf("FATAL ERROR: internal error in debugger.c:" |
1887 |
|
" no handler for this command?\n"); |
1888 |
|
} |
1889 |
|
|
1890 |
|
|
1891 |
|
/* |
1892 |
* debugger_readline(): |
* debugger_readline(): |
1893 |
* |
* |
1894 |
* Read a line from the terminal. |
* Read a line from the terminal. |
2063 |
j = 0; /* j = # of cmds printed */ |
j = 0; /* j = # of cmds printed */ |
2064 |
while (cmds[i].name != NULL) { |
while (cmds[i].name != NULL) { |
2065 |
if (cmds[i].tmp_flag) { |
if (cmds[i].tmp_flag) { |
2066 |
int q; |
size_t q; |
2067 |
if (j == 0) |
if (j == 0) |
2068 |
printf(" "); |
printf(" "); |
2069 |
printf("%s", |
printf("%s", |
2153 |
*/ |
*/ |
2154 |
void debugger(void) |
void debugger(void) |
2155 |
{ |
{ |
2156 |
int i, n, i_match, matchlen, cmd_len; |
int i, cmd_len; |
2157 |
char *cmd; |
char *cmd; |
2158 |
|
|
2159 |
if (debugger_n_steps_left_before_interaction > 0) { |
if (debugger_n_steps_left_before_interaction > 0) { |
2165 |
* Clear all dyntrans translations, because otherwise things would |
* Clear all dyntrans translations, because otherwise things would |
2166 |
* become to complex to keep in sync. |
* become to complex to keep in sync. |
2167 |
*/ |
*/ |
2168 |
|
/* TODO: In all machines */ |
2169 |
for (i=0; i<debugger_machine->ncpus; i++) |
for (i=0; i<debugger_machine->ncpus; i++) |
2170 |
if (debugger_machine->cpus[i]->translation_cache != NULL) |
if (debugger_machine->cpus[i]->translation_cache != NULL) |
2171 |
cpu_create_or_reset_tc(debugger_machine->cpus[i]); |
cpu_create_or_reset_tc(debugger_machine->cpus[i]); |
2198 |
repeat_cmd[0] = '\0'; |
repeat_cmd[0] = '\0'; |
2199 |
} |
} |
2200 |
|
|
2201 |
/* |
debugger_execute_cmd(cmd, cmd_len); |
|
* Is there a '=' on the command line? Then try to do an |
|
|
* assignment. (Only if there is just one word, followed |
|
|
* by the '=' sign. This makes it possible to use commands |
|
|
* such as "device add name addr=xyz".) |
|
|
*/ |
|
|
if (strchr(cmd, '=') != NULL) { |
|
|
/* Count the nr of words: */ |
|
|
int nw = 0, inword = 0; |
|
|
char *p = cmd; |
|
|
while (*p) { |
|
|
if (*p == '=') |
|
|
break; |
|
|
if (*p != ' ') { |
|
|
if (!inword) |
|
|
nw ++; |
|
|
inword = 1; |
|
|
} else |
|
|
inword = 0; |
|
|
p++; |
|
|
} |
|
|
|
|
|
if (nw == 1) { |
|
|
debugger_assignment(debugger_machine, cmd); |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
i = 0; |
|
|
while (cmds[i].name != NULL) |
|
|
cmds[i++].tmp_flag = 0; |
|
|
|
|
|
/* How many chars in cmd to match against: */ |
|
|
matchlen = 0; |
|
|
while (isalpha((int)cmd[matchlen])) |
|
|
matchlen ++; |
|
|
|
|
|
/* Check for a command name match: */ |
|
|
n = i = i_match = 0; |
|
|
while (cmds[i].name != NULL) { |
|
|
if (strncasecmp(cmds[i].name, cmd, matchlen) == 0 |
|
|
&& cmds[i].f != NULL) { |
|
|
cmds[i].tmp_flag = 1; |
|
|
i_match = i; |
|
|
n++; |
|
|
} |
|
|
i++; |
|
|
} |
|
|
|
|
|
/* No match? */ |
|
|
if (n == 0) { |
|
|
printf("Unknown command '%s'. " |
|
|
"Type 'help' for help.\n", cmd); |
|
|
continue; |
|
|
} |
|
|
|
|
|
/* More than one match? */ |
|
|
if (n > 1) { |
|
|
printf("Ambiguous command '%s': ", cmd); |
|
|
i = 0; |
|
|
while (cmds[i].name != NULL) { |
|
|
if (cmds[i].tmp_flag) |
|
|
printf(" %s", cmds[i].name); |
|
|
i++; |
|
|
} |
|
|
printf("\n"); |
|
|
continue; |
|
|
} |
|
|
|
|
|
/* Exactly one match: */ |
|
|
if (cmds[i_match].f != NULL) { |
|
|
char *p = cmd + matchlen; |
|
|
/* Remove leading whitespace from the args... */ |
|
|
while (*p != '\0' && *p == ' ') |
|
|
p++; |
|
|
|
|
|
/* ... and run the command: */ |
|
|
cmds[i_match].f(debugger_machine, p); |
|
|
} else |
|
|
printf("FATAL ERROR: internal error in debugger.c:" |
|
|
" no handler for this command?\n"); |
|
2202 |
|
|
2203 |
/* Special hack for the "step" command: */ |
/* Special hack for the "step" command: */ |
2204 |
if (exit_debugger == -1) |
if (exit_debugger == -1) |