/[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 38 - (show annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 18632 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1515 2007/04/14 05:39:46 debug Exp $
20070324	Adding a "--debug" option to the configure script, to disable
		optimizations in unstable development builds.
		Moving out SCSI-specific stuff from diskimage.c into a new
		diskimage_scsicmd.c.
		Applying Hĺvard Eidnes' patch for SCSICDROM_READ_DISKINFO and
		SCSICDROM_READ_TRACKINFO. (Not really tested yet.)
		Implementing disk image "overlays" (to allow simple roll-back
		to previous disk state). Adding a 'V' disk flag for this, and
		updating the man page and misc.html.
20070325	Stability fix to cpu_dyntrans.c, when multiple physical pages
		share the same initial table entry. (The ppp == NULL check
		should be physpage_ofs == 0.) Bug found by analysing GXemul
		against a version patched for Godson.
		Fixing a second occurance of the same problem (also in
		cpu_dyntrans.c).
		Fixing a MAJOR physical page leak in cpu_dyntrans.c; pages
		weren't _added_ to the set of translated pages, they _replaced_
		all previous pages. It's amazing that this bug has been able
		to live for this long. (Triggered when emulating >128MB RAM.)
20070326	Removing the GDB debugging stub support; it was too hackish
		and ugly.
20070328	Moving around some native code generation skeleton code.
20070329	The -lm check in the configure script now also checks for sin()
		in addition to sqrt(). (Thanks to Nigel Horne for noticing that
		sqrt was not enough on Fedora Core 6.) (Not verified yet.)
20070330	Fixing an indexing bug in dev_sh4.c, found by using gcc version
		4.3.0 20070323.
20070331	Some more experimentation with native code generation.
20070404	Attempting to fix some more SH4 SCIF interrupt bugs; rewriting
		the SH interrupt assertion/deassertion code somewhat.
20070410	Splitting src/file.c into separate files in src/file/.
		Cleanup: Removing the dummy TS7200, Walnut, PB1000, and
		Meshcube emulation modes, and dev_epcom and dev_au1x00.
		Removing the experimental CHIP8/RCA180x code; it wasn't really
		working much lately, anyway. It was fun while it lasted.
		Also removing the experimental Transputer CPU support.
20070412	Moving the section about how the dynamic translation system
		works from intro.html to a separate translation.html file.
		Minor SH fixes; attempting to get OpenBSD/landisk to run
		without randomly bugging out, but no success yet.
20070413	SH SCI (serial bit interface) should now work together with a
		(new) RS5C313 clock device (for Landisk emulation).
20070414	Moving Redhat/MIPS down from supported to experimental, in
		guestoses.html.
		Preparing for a new release; doing some regression testing etc.

==============  RELEASE 0.4.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26