/[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

Annotation of /trunk/src/debugger/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 38 - (hide annotations)
Mon Oct 8 16:21:53 2007 UTC (16 years, 6 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 dpavlin 24 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 24 *
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 dpavlin 38 * $Id: debugger.c,v 1.22 2007/03/26 02:01:36 debug Exp $
29 dpavlin 24 *
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 dpavlin 32 #include "timer.h"
68 dpavlin 24 #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 dpavlin 26 volatile int single_step = NOT_SINGLE_STEPPING;
84 dpavlin 24 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 dpavlin 32
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 dpavlin 24 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 dpavlin 38 int ch;
130 dpavlin 24
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 dpavlin 32 usleep(10000);
137 dpavlin 24 }
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 dpavlin 26 if (single_step != NOT_SINGLE_STEPPING) {
154 dpavlin 24 /* 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 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
165 dpavlin 24
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 dpavlin 32 res_right = debugger_parse_expression(m, right, 0, &tmp);
243 dpavlin 24 switch (res_right) {
244 dpavlin 32 case PARSE_NOMATCH:
245 dpavlin 24 printf("No match for the right-hand side of the assignment.\n");
246     break;
247 dpavlin 32 case PARSE_MULTIPLE:
248 dpavlin 24 printf("Multiple matches for the right-hand side of the "
249     "assignment.\n");
250     break;
251     default:
252 dpavlin 32 res_left = debugger_parse_expression(m, left, 1, &tmp);
253 dpavlin 24 switch (res_left) {
254 dpavlin 32 case PARSE_NOMATCH:
255 dpavlin 24 printf("No match for the left-hand side of the "
256     "assignment.\n");
257     break;
258 dpavlin 32 case PARSE_MULTIPLE:
259 dpavlin 24 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 dpavlin 32 usleep(10000);
572 dpavlin 24 if (ch == '[' || ch == 'O') {
573     while ((ch = console_readchar(MAIN_CONSOLE))
574     < 0)
575 dpavlin 32 usleep(10000);
576 dpavlin 24 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 dpavlin 32 usleep(10000);
584 dpavlin 24 /* 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 dpavlin 32 usleep(10000);
591 dpavlin 24 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 dpavlin 26 if (debugger_machine->cpus[i]->translation_cache != NULL) {
653 dpavlin 24 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
654 dpavlin 26 debugger_machine->cpus[i]->
655     invalidate_translation_caches(
656     debugger_machine->cpus[i], 0, INVALIDATE_ALL);
657     }
658 dpavlin 24
659 dpavlin 32 /* Stop timers while interacting with the user: */
660     timer_stop();
661    
662 dpavlin 24 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 dpavlin 32 /* 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 dpavlin 24 gettimeofday(&debugger_machine->starttime, NULL);
704 dpavlin 28 debugger_machine->ninstrs_since_gettimeofday = 0;
705 dpavlin 24
706 dpavlin 26 single_step = NOT_SINGLE_STEPPING;
707 dpavlin 24 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 dpavlin 38 int i;
735 dpavlin 24
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 dpavlin 32 debugger_cur_cpu = 0;
754     debugger_cur_machine = 0;
755     debugger_cur_emul = 0;
756    
757 dpavlin 24 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