/[gxemul]/trunk/src/debugger/debugger.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/debugger/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 17862 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

1 /*
2 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: debugger.c,v 1.27 2007/06/28 14:58:38 debug Exp $
29 *
30 * Single-step debugger.
31 *
32 *
33 * This entire module is very much non-reentrant. :-/ TODO: Fix.
34 */
35
36 #include <ctype.h>
37 #include <signal.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "console.h"
44 #include "cpu.h"
45 #include "device.h"
46 #include "debugger.h"
47 #include "diskimage.h"
48 #include "emul.h"
49 #include "machine.h"
50 #include "memory.h"
51 #include "misc.h"
52 #include "net.h"
53 #include "settings.h"
54 #include "timer.h"
55 #include "x11.h"
56
57
58 extern int extra_argc;
59 extern char **extra_argv;
60 extern struct settings *global_settings;
61 extern int quiet_mode;
62
63
64 /*
65 * Global debugger variables:
66 *
67 * TODO: Some of these should be moved to some other place!
68 */
69
70 volatile int single_step = NOT_SINGLE_STEPPING;
71 volatile int exit_debugger;
72 int force_debugger_at_exit = 0;
73
74 volatile int single_step_breakpoint = 0;
75 int debugger_n_steps_left_before_interaction = 0;
76
77 int old_instruction_trace = 0;
78 int old_quiet_mode = 0;
79 int old_show_trace_tree = 0;
80
81
82 /*
83 * Private (global) debugger variables:
84 */
85
86 static volatile int ctrl_c;
87
88 static struct emul *debugger_emul;
89
90 /* Currently focused CPU, machine, and emulation: */
91 int debugger_cur_cpu;
92 int debugger_cur_machine;
93 static struct machine *debugger_machine;
94 static struct emul *debugger_emul;
95
96 #define MAX_CMD_BUFLEN 72
97 #define N_PREVIOUS_CMDS 150
98 static char *last_cmd[N_PREVIOUS_CMDS];
99 static int last_cmd_index;
100
101 static char repeat_cmd[MAX_CMD_BUFLEN];
102
103 #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL
104
105 static uint64_t last_dump_addr = MAGIC_UNTOUCHED;
106 static uint64_t last_unasm_addr = MAGIC_UNTOUCHED;
107
108
109 /*
110 * debugger_readchar():
111 */
112 char debugger_readchar(void)
113 {
114 int ch;
115
116 while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) {
117 /* Check for X11 events: */
118 x11_check_event(debugger_emul);
119
120 /* Give up some CPU time: */
121 usleep(10000);
122 }
123 return ch;
124 }
125
126
127 /*
128 * debugger_activate():
129 *
130 * This is a signal handler for CTRL-C. It shouldn't be called directly,
131 * but setup code in emul.c sets the CTRL-C signal handler to use this
132 * function.
133 */
134 void debugger_activate(int x)
135 {
136 ctrl_c = 1;
137
138 if (single_step != NOT_SINGLE_STEPPING) {
139 /* Already in the debugger. Do nothing. */
140 int i;
141 for (i=0; i<MAX_CMD_BUFLEN; i++)
142 console_makeavail(MAIN_CONSOLE, '\b');
143 console_makeavail(MAIN_CONSOLE, ' ');
144 console_makeavail(MAIN_CONSOLE, '\n');
145 printf("^C");
146 fflush(stdout);
147 } else {
148 /* Enter the single step debugger. */
149 single_step = ENTER_SINGLE_STEPPING;
150
151 /* Discard any chars in the input queue: */
152 while (console_charavail(MAIN_CONSOLE))
153 console_readchar(MAIN_CONSOLE);
154 }
155
156 /* Clear the repeat-command buffer: */
157 repeat_cmd[0] = '\0';
158
159 /* Reactivate the signal handler: */
160 signal(SIGINT, debugger_activate);
161 }
162
163
164 /*
165 * show_breakpoint():
166 */
167 static void show_breakpoint(struct machine *m, int i)
168 {
169 printf("%3i: 0x", i);
170 if (m->cpus[0]->is_32bit)
171 printf("%08"PRIx32, (uint32_t) m->breakpoints.addr[i]);
172 else
173 printf("%016"PRIx64, (uint64_t) m->breakpoints.addr[i]);
174 if (m->breakpoints.string[i] != NULL)
175 printf(" (%s)", m->breakpoints.string[i]);
176 printf("\n");
177 }
178
179
180 /****************************************************************************/
181
182
183 #include "debugger_cmds.c"
184
185
186 /****************************************************************************/
187
188
189 /*
190 * debugger_assignment():
191 *
192 * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
193 */
194 void debugger_assignment(struct machine *m, char *cmd)
195 {
196 char *left, *right;
197 int res_left, res_right;
198 uint64_t tmp;
199 uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */
200
201 CHECK_ALLOCATION(left = malloc(MAX_CMD_BUFLEN));
202 strlcpy(left, cmd, MAX_CMD_BUFLEN);
203 right = strchr(left, '=');
204 if (right == NULL) {
205 fprintf(stderr, "internal error in the debugger\n");
206 exit(1);
207 }
208 *right = '\0';
209
210 /* Remove trailing spaces in left: */
211 while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
212 left[strlen(left)-1] = '\0';
213
214 /* Remove leading spaces in right: */
215 right++;
216 while (*right == ' ' && *right != '\0')
217 right++;
218
219 /* printf("left = '%s'\nright = '%s'\n", left, right); */
220
221 res_right = debugger_parse_expression(m, right, 0, &tmp);
222 switch (res_right) {
223 case PARSE_NOMATCH:
224 printf("No match for the right-hand side of the assignment.\n");
225 break;
226 case PARSE_MULTIPLE:
227 printf("Multiple matches for the right-hand side of the "
228 "assignment.\n");
229 break;
230 default:
231 res_left = debugger_parse_expression(m, left, 1, &tmp);
232 switch (res_left) {
233 case PARSE_NOMATCH:
234 printf("No match for the left-hand side of the "
235 "assignment.\n");
236 break;
237 case PARSE_MULTIPLE:
238 printf("Multiple matches for the left-hand side "
239 "of the assignment.\n");
240 break;
241 default:
242 debugger_cmd_print(m, left);
243 }
244 }
245
246 /*
247 * If the PC has changed, then release any breakpoint we were
248 * currently stopped at.
249 *
250 * TODO: multiple cpus?
251 */
252 if (old_pc != m->cpus[0]->pc)
253 single_step_breakpoint = 0;
254
255 free(left);
256 }
257
258
259 /*
260 * debugger_execute_cmd():
261 */
262 void debugger_execute_cmd(char *cmd, int cmd_len)
263 {
264 int i, n, i_match, matchlen;
265
266 /*
267 * Is there a '=' on the command line? Then try to do an
268 * assignment. (Only if there is just one word, followed
269 * by the '=' sign. This makes it possible to use commands
270 * such as "device add name addr=xyz".)
271 */
272 if (strchr(cmd, '=') != NULL) {
273 /* Count the nr of words: */
274 int nw = 0, inword = 0;
275 char *p = cmd;
276 while (*p) {
277 if (*p == '=')
278 break;
279 if (*p != ' ') {
280 if (!inword)
281 nw ++;
282 inword = 1;
283 } else
284 inword = 0;
285 p++;
286 }
287
288 if (nw == 1) {
289 debugger_assignment(debugger_machine, cmd);
290 return;
291 }
292 }
293
294 i = 0;
295 while (cmds[i].name != NULL)
296 cmds[i++].tmp_flag = 0;
297
298 /* How many chars in cmd to match against: */
299 matchlen = 0;
300 while (isalpha((int)cmd[matchlen]))
301 matchlen ++;
302
303 /* Check for a command name match: */
304 n = i = i_match = 0;
305 while (cmds[i].name != NULL) {
306 if (strncasecmp(cmds[i].name, cmd, matchlen) == 0
307 && cmds[i].f != NULL) {
308 cmds[i].tmp_flag = 1;
309 i_match = i;
310 n++;
311 }
312 i++;
313 }
314
315 /* No match? */
316 if (n == 0) {
317 printf("Unknown command '%s'. Type 'help' for help.\n", cmd);
318 return;
319 }
320
321 /* More than one match? */
322 if (n > 1) {
323 printf("Ambiguous command '%s': ", cmd);
324 i = 0;
325 while (cmds[i].name != NULL) {
326 if (cmds[i].tmp_flag)
327 printf(" %s", cmds[i].name);
328 i++;
329 }
330 printf("\n");
331 return;
332 }
333
334 /* Exactly one match: */
335 if (cmds[i_match].f != NULL) {
336 char *p = cmd + matchlen;
337 /* Remove leading whitespace from the args... */
338 while (*p != '\0' && *p == ' ')
339 p++;
340
341 /* ... and run the command: */
342 cmds[i_match].f(debugger_machine, p);
343 } else
344 printf("FATAL ERROR: internal error in debugger.c:"
345 " no handler for this command?\n");
346 }
347
348
349 /*
350 * debugger_readline():
351 *
352 * Read a line from the terminal.
353 */
354 static char *debugger_readline(void)
355 {
356 int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
357 int read_from_index = last_cmd_index;
358 char *cmd = last_cmd[last_cmd_index];
359
360 cmd_len = 0; cmd[0] = '\0';
361 printf("GXemul> ");
362 fflush(stdout);
363
364 ch = '\0';
365 cmd_len = 0;
366 cursor_pos = 0;
367
368 while (ch != '\n' && !exit_debugger) {
369 ch = debugger_readchar();
370
371 if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
372 /* Backspace. */
373 cursor_pos --;
374 cmd_len --;
375 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
376 cmd_len);
377 cmd[cmd_len] = '\0';
378 printf("\b");
379 for (i=cursor_pos; i<cmd_len; i++)
380 printf("%c", cmd[i]);
381 printf(" \b");
382 for (i=cursor_pos; i<cmd_len; i++)
383 printf("\b");
384 } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
385 /* CTRL-D: Delete. */
386 cmd_len --;
387 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
388 cmd_len);
389 cmd[cmd_len] = '\0';
390 for (i=cursor_pos; i<cmd_len; i++)
391 printf("%c", cmd[i]);
392 printf(" \b");
393 for (i=cursor_pos; i<cmd_len; i++)
394 printf("\b");
395 } else if (ch == 1) {
396 /* CTRL-A: Start of line. */
397 while (cursor_pos > 0) {
398 cursor_pos --;
399 printf("\b");
400 }
401 } else if (ch == 2) {
402 /* CTRL-B: Backwards one character. */
403 if (cursor_pos > 0) {
404 printf("\b");
405 cursor_pos --;
406 }
407 } else if (ch == 5) {
408 /* CTRL-E: End of line. */
409 while (cursor_pos < cmd_len) {
410 printf("%c", cmd[cursor_pos]);
411 cursor_pos ++;
412 }
413 } else if (ch == 6) {
414 /* CTRL-F: Forward one character. */
415 if (cursor_pos < cmd_len) {
416 printf("%c",
417 cmd[cursor_pos]);
418 cursor_pos ++;
419 }
420 } else if (ch == 11) {
421 /* CTRL-K: Kill to end of line. */
422 for (i=0; i<MAX_CMD_BUFLEN; i++)
423 console_makeavail(MAIN_CONSOLE, 4); /* :-) */
424 } else if (ch == 14 || ch == 16) {
425 /* CTRL-P: Previous line in the command history,
426 CTRL-N: next line */
427 do {
428 if (ch == 14 &&
429 read_from_index == last_cmd_index)
430 break;
431 if (ch == 16)
432 i = read_from_index - 1;
433 else
434 i = read_from_index + 1;
435
436 if (i < 0)
437 i = N_PREVIOUS_CMDS - 1;
438 if (i >= N_PREVIOUS_CMDS)
439 i = 0;
440
441 /* Special case: pressing 'down'
442 to reach last_cmd_index: */
443 if (i == last_cmd_index) {
444 read_from_index = i;
445 for (i=cursor_pos; i<cmd_len;
446 i++)
447 printf(" ");
448 for (i=cmd_len-1; i>=0; i--)
449 printf("\b \b");
450 cmd[0] = '\0';
451 cmd_len = cursor_pos = 0;
452 } else if (last_cmd[i][0] != '\0') {
453 /* Copy from old line: */
454 read_from_index = i;
455 for (i=cursor_pos; i<cmd_len;
456 i++)
457 printf(" ");
458 for (i=cmd_len-1; i>=0; i--)
459 printf("\b \b");
460 strlcpy(cmd,
461 last_cmd[read_from_index],
462 MAX_CMD_BUFLEN);
463 cmd_len = strlen(cmd);
464 printf("%s", cmd);
465 cursor_pos = cmd_len;
466 }
467 } while (0);
468 } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) {
469 /* Visible character: */
470 memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
471 cmd_len - cursor_pos);
472 cmd[cursor_pos] = ch;
473 cmd_len ++;
474 cursor_pos ++;
475 cmd[cmd_len] = '\0';
476 printf("%c", ch);
477 for (i=cursor_pos; i<cmd_len; i++)
478 printf("%c", cmd[i]);
479 for (i=cursor_pos; i<cmd_len; i++)
480 printf("\b");
481 } else if (ch == '\r' || ch == '\n') {
482 ch = '\n';
483 printf("\n");
484 } else if (ch == '\t') {
485 /* Super-simple tab-completion: */
486 i = 0;
487 while (cmds[i].name != NULL)
488 cmds[i++].tmp_flag = 0;
489
490 /* Check for a (partial) command match: */
491 n = i = i_match = 0;
492 while (cmds[i].name != NULL) {
493 if (strncasecmp(cmds[i].name, cmd,
494 cmd_len) == 0) {
495 cmds[i].tmp_flag = 1;
496 i_match = i;
497 n++;
498 }
499 i++;
500 }
501
502 switch (n) {
503 case 0: /* Beep. */
504 printf("\a");
505 break;
506 case 1: /* Add the rest of the command: */
507 reallen = strlen(cmds[i_match].name);
508 for (i=cmd_len; i<reallen; i++)
509 console_makeavail(MAIN_CONSOLE,
510 cmds[i_match].name[i]);
511 /* ... and a space, if the command takes
512 any arguments: */
513 if (cmds[i_match].args != NULL &&
514 cmds[i_match].args[0] != '\0')
515 console_makeavail(MAIN_CONSOLE, ' ');
516 break;
517 default:
518 /* Show all possible commands: */
519 printf("\a\n"); /* Beep. :-) */
520 i = 0; /* i = cmds index */
521 j = 0; /* j = # of cmds printed */
522 while (cmds[i].name != NULL) {
523 if (cmds[i].tmp_flag) {
524 size_t q;
525 if (j == 0)
526 printf(" ");
527 printf("%s",
528 cmds[i].name);
529 j++;
530 if (j != 6)
531 for (q=0; q<13-strlen(
532 cmds[i].name); q++)
533 printf(" ");
534 if (j == 6) {
535 printf("\n");
536 j = 0;
537 }
538 }
539 i++;
540 }
541 if (j != 0)
542 printf("\n");
543 printf("GXemul> ");
544 for (i=0; i<cmd_len; i++)
545 printf("%c", cmd[i]);
546 }
547 } else if (ch == 27) {
548 /* Escape codes: (cursor keys etc) */
549 while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
550 usleep(10000);
551 if (ch == '[' || ch == 'O') {
552 while ((ch = console_readchar(MAIN_CONSOLE))
553 < 0)
554 usleep(10000);
555 switch (ch) {
556 case '2': /* 2~ = ins */
557 case '5': /* 5~ = pgup */
558 case '6': /* 6~ = pgdn */
559 /* TODO: Ugly hack, but might work. */
560 while ((ch = console_readchar(
561 MAIN_CONSOLE)) < 0)
562 usleep(10000);
563 /* Do nothing for these keys. */
564 break;
565 case '3': /* 3~ = delete */
566 /* TODO: Ugly hack, but might work. */
567 while ((ch = console_readchar(
568 MAIN_CONSOLE)) < 0)
569 usleep(10000);
570 console_makeavail(MAIN_CONSOLE, '\b');
571 break;
572 case 'A': /* Up. */
573 /* Up cursor ==> CTRL-P */
574 console_makeavail(MAIN_CONSOLE, 16);
575 break;
576 case 'B': /* Down. */
577 /* Down cursor ==> CTRL-N */
578 console_makeavail(MAIN_CONSOLE, 14);
579 break;
580 case 'C':
581 /* Right cursor ==> CTRL-F */
582 console_makeavail(MAIN_CONSOLE, 6);
583 break;
584 case 'D': /* Left */
585 /* Left cursor ==> CTRL-B */
586 console_makeavail(MAIN_CONSOLE, 2);
587 break;
588 case 'F':
589 /* End ==> CTRL-E */
590 console_makeavail(MAIN_CONSOLE, 5);
591 break;
592 case 'H':
593 /* Home ==> CTRL-A */
594 console_makeavail(MAIN_CONSOLE, 1);
595 break;
596 }
597 }
598 }
599
600 fflush(stdout);
601 }
602
603 if (exit_debugger)
604 cmd[0] = '\0';
605
606 return cmd;
607 }
608
609
610 /*
611 * debugger():
612 *
613 * This is a loop, which reads a command from the terminal, and executes it.
614 */
615 void debugger(void)
616 {
617 int i, cmd_len;
618 char *cmd;
619
620 if (debugger_n_steps_left_before_interaction > 0) {
621 debugger_n_steps_left_before_interaction --;
622 return;
623 }
624
625 /*
626 * Clear all dyntrans translations, because otherwise things would
627 * become to complex to keep in sync.
628 */
629 /* TODO: In all machines */
630 for (i=0; i<debugger_machine->ncpus; i++)
631 if (debugger_machine->cpus[i]->translation_cache != NULL) {
632 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
633 debugger_machine->cpus[i]->
634 invalidate_translation_caches(
635 debugger_machine->cpus[i], 0, INVALIDATE_ALL);
636 }
637
638 /* Stop timers while interacting with the user: */
639 timer_stop();
640
641 exit_debugger = 0;
642
643 while (!exit_debugger) {
644 /* Read a line from the terminal: */
645 cmd = debugger_readline();
646
647 cmd_len = strlen(cmd);
648
649 /* Remove spaces: */
650 while (cmd_len > 0 && cmd[0]==' ')
651 memmove(cmd, cmd+1, cmd_len --);
652 while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
653 cmd[(cmd_len--)-1] = '\0';
654
655 /* No command? Then try reading another line. */
656 if (cmd_len == 0) {
657 /* Special case for repeated commands: */
658 if (repeat_cmd[0] != '\0')
659 strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN);
660 else
661 continue;
662 } else {
663 last_cmd_index ++;
664 if (last_cmd_index >= N_PREVIOUS_CMDS)
665 last_cmd_index = 0;
666
667 repeat_cmd[0] = '\0';
668 }
669
670 debugger_execute_cmd(cmd, cmd_len);
671
672 /* Special hack for the "step" command: */
673 if (exit_debugger == -1)
674 return;
675 }
676
677 /* Start up timers again: */
678 timer_start();
679
680 /* ... and reset starttime, so that nr of instructions per second
681 can be calculated correctly: */
682 for (i=0; i<debugger_machine->ncpus; i++) {
683 gettimeofday(&debugger_machine->cpus[i]->starttime, NULL);
684 debugger_machine->cpus[i]->ninstrs_since_gettimeofday = 0;
685 }
686
687 single_step = NOT_SINGLE_STEPPING;
688 debugger_machine->instruction_trace = old_instruction_trace;
689 debugger_machine->show_trace_tree = old_show_trace_tree;
690 quiet_mode = old_quiet_mode;
691 }
692
693
694 /*
695 * debugger_reset():
696 *
697 * This function should be called before calling debugger(), when it is
698 * absolutely necessary that debugger() is interactive. Otherwise, it might
699 * return without doing anything, such as when single-stepping multiple
700 * instructions at a time.
701 */
702 void debugger_reset(void)
703 {
704 debugger_n_steps_left_before_interaction = 0;
705 }
706
707
708 /*
709 * debugger_init():
710 *
711 * Must be called before any other debugger function is used.
712 */
713 void debugger_init(struct emul *emul)
714 {
715 int i;
716
717 debugger_emul = emul;
718
719 if (emul->n_machines < 1) {
720 fprintf(stderr, "\nERROR: No machines, "
721 "cannot handle this situation yet.\n\n");
722 exit(1);
723 }
724
725 debugger_machine = emul->machines[0];
726
727 debugger_cur_cpu = 0;
728 debugger_cur_machine = 0;
729
730 for (i=0; i<N_PREVIOUS_CMDS; i++) {
731 CHECK_ALLOCATION(last_cmd[i] = malloc(MAX_CMD_BUFLEN));
732 last_cmd[i][0] = '\0';
733 }
734
735 last_cmd_index = 0;
736 repeat_cmd[0] = '\0';
737 }
738

  ViewVC Help
Powered by ViewVC 1.1.26