--- trunk/src/debugger.c 2007/10/08 16:18:31 11 +++ trunk/src/debugger.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: debugger.c,v 1.106 2005/06/26 11:36:27 debug Exp $ + * $Id: debugger.c,v 1.122 2005/08/11 09:43:40 debug Exp $ * * Single-step debugger. * @@ -82,6 +82,9 @@ int force_debugger_at_exit = 0; int show_opcode_statistics = 0; +volatile int single_step_breakpoint = 0; +int debugger_n_steps_left_before_interaction = 0; + int old_instruction_trace = 0; int old_quiet_mode = 0; int old_show_trace_tree = 0; @@ -99,7 +102,6 @@ static struct machine *debugger_machine; static int exit_debugger; -static int n_steps_left_before_interaction = 0; #define MAX_CMD_BUFLEN 72 #define N_PREVIOUS_CMDS 150 @@ -115,6 +117,24 @@ /* + * debugger_readchar(): + * + * TODO: This uses up 100% CPU, maybe that isn't too good. The usleep() call + * might make it a tiny bit nicer on other running processes, but it + * is still very ugly. + */ +char debugger_readchar(void) +{ + int ch; + while ((ch = console_readchar(MAIN_CONSOLE)) < 0) { + x11_check_event(debugger_emuls, debugger_n_emuls); + usleep(1); + } + return ch; +} + + +/* * debugger_activate(): * * This is a signal handler for CTRL-C. It shouldn't be called directly, @@ -198,10 +218,17 @@ } /* Warn about non-signextended values: */ - if (writeflag && - ((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL) - printf("WARNING: The value is not sign-extended. " - "Is this what you intended?\n"); + 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] == '@'; @@ -274,8 +301,11 @@ */ static void show_breakpoint(struct machine *m, int i) { - printf("%3i: 0x%016llx", i, - (long long)m->breakpoint_addr[i]); + printf("%3i: 0x", i); + if (m->cpus[0]->is_32bit) + printf("%08x", (int)m->breakpoint_addr[i]); + else + printf("%016llx", (long long)m->breakpoint_addr[i]); if (m->breakpoint_string[i] != NULL) printf(" (%s)", m->breakpoint_string[i]); if (m->breakpoint_flags[i]) @@ -337,6 +367,11 @@ m->breakpoint_flags[i] = m->breakpoint_flags[i+1]; } m->n_breakpoints --; + + /* Clear translations: */ + for (i=0; incpus; i++) + if (m->cpus[i]->translation_cache != NULL) + cpu_create_or_reset_tc(m->cpus[i]); return; } @@ -372,6 +407,11 @@ m->n_breakpoints ++; show_breakpoint(m, i); + + /* Clear translations: */ + for (i=0; incpus; i++) + if (m->cpus[i]->translation_cache != NULL) + cpu_create_or_reset_tc(m->cpus[i]); return; } @@ -516,9 +556,9 @@ (long long)mem->dev_length[i]); if (mem->dev_flags[i]) { printf(" ("); - if (mem->dev_flags[i] & MEM_BINTRANS_OK) - printf("BINTRANS R"); - if (mem->dev_flags[i] & MEM_BINTRANS_WRITE_OK) + if (mem->dev_flags[i] & MEM_DYNTRANS_OK) + printf("DYNTRANS R"); + if (mem->dev_flags[i] & MEM_DYNTRANS_WRITE_OK) printf("+W"); printf(")"); } @@ -628,7 +668,10 @@ r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf), MEM_READ, CACHE_NONE | NO_EXCEPTIONS); - printf("0x%016llx ", (long long)addr); + if (c->is_32bit) + printf("0x%08x ", (int)addr); + else + printf("0x%016llx ", (long long)addr); if (r == MEMORY_ACCESS_FAILED) printf("(memory access failed)\n"); @@ -803,15 +846,23 @@ printf("lookup for '%s' failed\n", cmd_line); return; } - printf("%s = 0x%016llx\n", cmd_line, (long long)newaddr); + printf("%s = 0x", cmd_line); + if (m->cpus[0]->is_32bit) + printf("%08x\n", (int)newaddr); + else + printf("%016llx\n", (long long)newaddr); return; } symbol = get_symbol_name(&m->symbol_context, addr, &offset); - if (symbol != NULL) - printf("0x%016llx = %s\n", (long long)addr, symbol); - else + if (symbol != NULL) { + if (m->cpus[0]->is_32bit) + printf("0x%08x", (int)addr); + else + printf("0x%016llx", (long long)addr); + printf(" = %s\n", symbol); + } else printf("lookup for '%s' failed\n", cmd_line); } @@ -838,6 +889,55 @@ /* + * debugger_cmd_ninstrs(): + */ +static void debugger_cmd_ninstrs(struct machine *m, char *cmd_line) +{ + int toggle = 1; + int previous_mode = m->show_nr_of_instructions; + + if (cmd_line[0] != '\0') { + while (cmd_line[0] != '\0' && cmd_line[0] == ' ') + cmd_line ++; + switch (cmd_line[0]) { + case '0': + toggle = 0; + m->show_nr_of_instructions = 0; + break; + case '1': + toggle = 0; + m->show_nr_of_instructions = 1; + break; + case 'o': + case 'O': + toggle = 0; + switch (cmd_line[1]) { + case 'n': + case 'N': + m->show_nr_of_instructions = 1; + break; + default: + m->show_nr_of_instructions = 0; + } + break; + default: + printf("syntax: trace [on|off]\n"); + return; + } + } + + if (toggle) + m->show_nr_of_instructions = !m->show_nr_of_instructions; + + printf("show_nr_of_instructions = %s", + m->show_nr_of_instructions? "ON" : "OFF"); + if (m->show_nr_of_instructions != previous_mode) + printf(" (was: %s)", previous_mode? "ON" : "OFF"); + printf("\n"); +} + + +/* * debugger_cmd_opcodestats(): */ static void debugger_cmd_opcodestats(struct machine *m, char *cmd_line) @@ -910,7 +1010,10 @@ printf("%s = 0x%llx\n", cmd_line, (long long)tmp); break; case NAME_PARSE_SYMBOL: - printf("%s = 0x%016llx\n", cmd_line, (long long)tmp); + if (m->cpus[0]->is_32bit) + printf("%s = 0x%08x\n", cmd_line, (int)tmp); + else + printf("%s = 0x%016llx\n", cmd_line, (long long)tmp); break; case NAME_PARSE_NUMBER: printf("0x%llx\n", (long long)tmp); @@ -1022,7 +1125,11 @@ switch (put_type) { case 'b': a_byte = data; - printf("0x%016llx: %02x", (long long)addr, a_byte); + if (m->cpus[0]->is_32bit) + printf("0x%08x", (int)addr); + else + printf("0x%016llx", (long long)addr); + printf(": %02x", a_byte); if (data > 255) printf(" (NOTE: truncating %0llx)", (long long)data); res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr, @@ -1034,7 +1141,11 @@ case 'h': if ((data & 1) != 0) printf("WARNING: address isn't aligned\n"); - printf("0x%016llx: %04x", (long long)addr, (int)data); + if (m->cpus[0]->is_32bit) + printf("0x%08x", (int)addr); + else + printf("0x%016llx", (long long)addr); + printf(": %04x", (int)data); if (data > 0xffff) printf(" (NOTE: truncating %0llx)", (long long)data); res = store_16bit_word(m->cpus[0], addr, data); @@ -1045,7 +1156,11 @@ case 'w': if ((data & 3) != 0) printf("WARNING: address isn't aligned\n"); - printf("0x%016llx: %08x", (long long)addr, (int)data); + if (m->cpus[0]->is_32bit) + printf("0x%08x", (int)addr); + else + printf("0x%016llx", (long long)addr); + printf(": %08x", (int)data); if (data > 0xffffffff && (data >> 32) != 0 && (data >> 32) != 0xffffffff) printf(" (NOTE: truncating %0llx)", (long long)data); @@ -1057,7 +1172,11 @@ case 'd': if ((data & 7) != 0) printf("WARNING: address isn't aligned\n"); - printf("0x%016llx: %016llx", (long long)addr, (long long)data); + if (m->cpus[0]->is_32bit) + printf("0x%08x", (int)addr); + else + printf("0x%016llx", (long long)addr); + printf(": %016llx", (long long)data); res = store_64bit_word(m->cpus[0], addr, data); if (!res) printf(" FAILED!\n"); @@ -1207,7 +1326,7 @@ } } - n_steps_left_before_interaction = n - 1; + debugger_n_steps_left_before_interaction = n - 1; /* Special hack, see debugger() for more info. */ exit_debugger = -1; @@ -1259,21 +1378,55 @@ */ static void debugger_cmd_trace(struct machine *m, char *cmd_line) { - if (*cmd_line) { - printf("syntax: trace\n"); - return; + int i, toggle = 1; + int previous_mode = old_show_trace_tree; + + if (cmd_line[0] != '\0') { + while (cmd_line[0] != '\0' && cmd_line[0] == ' ') + cmd_line ++; + switch (cmd_line[0]) { + case '0': + toggle = 0; + old_show_trace_tree = 0; + break; + case '1': + toggle = 0; + old_show_trace_tree = 1; + break; + case 'o': + case 'O': + toggle = 0; + switch (cmd_line[1]) { + case 'n': + case 'N': + old_show_trace_tree = 1; + break; + default: + old_show_trace_tree = 0; + } + break; + default: + printf("syntax: trace [on|off]\n"); + return; + } } - old_show_trace_tree = 1 - old_show_trace_tree; - printf("show_trace_tree = %s\n", old_show_trace_tree? "ON" : "OFF"); + if (toggle) + old_show_trace_tree = 1 - old_show_trace_tree; + + printf("show_trace_tree = %s", old_show_trace_tree? "ON" : "OFF"); + if (old_show_trace_tree != previous_mode) + printf(" (was: %s)", previous_mode? "ON" : "OFF"); + printf("\n"); if (m->bintrans_enable && old_show_trace_tree) printf("NOTE: the trace tree functionality doesn't " "work very well with bintrans!\n"); - /* TODO: how to preserve quiet_mode? */ - old_quiet_mode = 0; - printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF"); + /* Clear translations: */ + for (i=0; incpus; i++) + if (m->cpus[i]->translation_cache != NULL) + cpu_create_or_reset_tc(m->cpus[i]); } @@ -1357,8 +1510,8 @@ ctrl_c = 0; while (addr < addr_end) { - int i, len; - unsigned char buf[32]; /* TODO: How long can an + unsigned int i, len; + unsigned char buf[17]; /* TODO: How long can an instruction be, on weird archs? */ memset(buf, 0, sizeof(buf)); @@ -1451,6 +1604,9 @@ { "machine", "", 0, debugger_cmd_machine, "print a summary of the current machine" }, + { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs, + "toggle (set or unset) show_nr_of_instructions" }, + { "opcodestats", "", 0, debugger_cmd_opcodestats, "show opcode statistics" }, @@ -1481,7 +1637,7 @@ { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump, "dump TLB contents (add ',r' for raw data)" }, - { "trace", "", 0, debugger_cmd_trace, + { "trace", "[on|off]", 0, debugger_cmd_trace, "toggle show_trace_tree on or off" }, { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble, @@ -1490,6 +1646,9 @@ { "version", "", 0, debugger_cmd_version, "print version information" }, + /* Note: NULL handler. */ + { "x = expr", "", 0, NULL, "generic assignment" }, + { NULL, NULL, 0, NULL, NULL } }; @@ -1506,7 +1665,10 @@ */ static void debugger_cmd_help(struct machine *m, char *cmd_line) { - int i, j, max_name_len = 0, only_one = 0, only_one_match = 0; + int i, max_name_len = 0, only_one = 0, only_one_match = 0; + char *nlines_env = getenv("LINES"); + int nlines = atoi(nlines_env != NULL? nlines_env : "999999"); + int j, curlines; if (cmd_line[0] != '\0') { only_one = 1; @@ -1522,8 +1684,11 @@ i++; } - if (!only_one) + curlines = 0; + if (!only_one) { printf("Available commands:\n"); + curlines++; + } i = 0; while (cmds[i].name != NULL) { @@ -1551,6 +1716,17 @@ printf(" %s\n", cmds[i].description); i++; + + curlines ++; + if (curlines >= nlines - 1) { + char ch; + printf("-- more --"); fflush(stdout); + ch = debugger_readchar(); + printf("\n"); + if (ch == 'q' || ch == 'Q') + return; + curlines = 0; + } } if (only_one) { @@ -1559,13 +1735,24 @@ return; } - printf("Generic assignments: x = expr\n"); - printf("where x must be a register, and expr can be a register, a " - "numeric value, or\na symbol name (+ an optional numeric offset)." - " In case there are multiple\nmatches (ie a symbol that has the " - "same name as a register), you may add a\nprefix character as a " - "hint: '%%' for registers, '@' for symbols, and\n'$' for numeric" - " values. Use 0x for hexadecimal values.\n"); + /* TODO: generalize/refactor */ + curlines += 8; + if (curlines > nlines - 1) { + char ch; + printf("-- more --"); fflush(stdout); + ch = debugger_readchar(); + printf("\n"); + if (ch == 'q' || ch == 'Q') + return; + curlines = 0; + } + + printf("\nIn generic assignments, x must be a register, and expr can be" + " a register, a\nnumeric value, or a symbol name (+ an optional " + "numeric offset). In case there\nare multiple matches (i.e. a " + "symbol that has the same name as a register), you\nmay add a " + "prefix character as a hint: '%%' for registers, '@' for symbols," + " and\n'$' for numeric values. Use 0x for hexadecimal values.\n"); } @@ -1582,6 +1769,7 @@ char *left, *right; int res_left, res_right; uint64_t tmp; + uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */ left = malloc(MAX_CMD_BUFLEN); if (left == NULL) { @@ -1632,6 +1820,15 @@ } } + /* + * If the PC has changed, then release any breakpoint we were + * currently stopped at. + * + * TODO: multiple cpus? + */ + if (old_pc != m->cpus[0]->pc) + single_step_breakpoint = 0; + free(left); } @@ -1656,15 +1853,7 @@ cursor_pos = 0; while (ch != '\n') { - /* - * TODO: This uses up 100% CPU, maybe that isn't too good. - * The usleep() call might make it a tiny bit nicer on other - * running processes, but it is still very ugly. - */ - while ((ch = console_readchar(MAIN_CONSOLE)) < 0) { - x11_check_event(debugger_emuls, debugger_n_emuls); - usleep(2); - } + ch = debugger_readchar(); if ((ch == '\b' || ch == 127) && cursor_pos > 0) { /* Backspace. */ @@ -1912,8 +2101,8 @@ int i, n, i_match, matchlen, cmd_len; char *cmd; - if (n_steps_left_before_interaction > 0) { - n_steps_left_before_interaction --; + if (debugger_n_steps_left_before_interaction > 0) { + debugger_n_steps_left_before_interaction --; return; } @@ -1985,7 +2174,8 @@ /* Check for a command name match: */ n = i = i_match = 0; while (cmds[i].name != NULL) { - if (strncasecmp(cmds[i].name, cmd, matchlen) == 0) { + if (strncasecmp(cmds[i].name, cmd, matchlen) == 0 + && cmds[i].f != NULL) { cmds[i].tmp_flag = 1; i_match = i; n++; @@ -2051,7 +2241,7 @@ */ void debugger_reset(void) { - n_steps_left_before_interaction = 0; + debugger_n_steps_left_before_interaction = 0; }