/[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 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 22817 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 dpavlin 24 /*
2     * Copyright (C) 2004-2006 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 dpavlin 26 * $Id: debugger.c,v 1.12 2006/06/25 01:25:32 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     * More generic expression evaluator (for example + - * / between multiple
42     * terms), including _TAB COMPLETION_ of symbols and register names!
43     * Must be possible to reach any emul, any machine in any emul, any
44     * cpu in any machine, other variables in the emulator, and so forth.
45     * Perhaps a "settable variables registry" somewhere?
46     *
47     * Nicer looking output of register dumps, floating point registers,
48     * etc. Warn about weird/invalid register contents.
49     *
50     * Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)...
51     *
52     * Many other TODOs.
53     */
54    
55     #include <ctype.h>
56     #include <signal.h>
57     #include <stdio.h>
58     #include <stdlib.h>
59     #include <string.h>
60     #include <unistd.h>
61    
62     #include "console.h"
63     #include "cpu.h"
64     #include "device.h"
65     #include "debugger.h"
66     #include "debugger_gdb.h"
67     #include "diskimage.h"
68     #include "emul.h"
69     #include "machine.h"
70     #include "memory.h"
71     #include "misc.h"
72     #include "net.h"
73     #include "settings.h"
74     #include "x11.h"
75    
76    
77     extern int extra_argc;
78     extern char **extra_argv;
79     extern struct settings *global_settings;
80     extern int quiet_mode;
81    
82    
83     /*
84     * Global debugger variables:
85     *
86     * TODO: Some of these should be moved to some other place!
87     */
88    
89 dpavlin 26 volatile int single_step = NOT_SINGLE_STEPPING;
90 dpavlin 24 volatile int exit_debugger;
91     int force_debugger_at_exit = 0;
92     int show_opcode_statistics = 0;
93    
94     volatile int single_step_breakpoint = 0;
95     int debugger_n_steps_left_before_interaction = 0;
96    
97     int old_instruction_trace = 0;
98     int old_quiet_mode = 0;
99     int old_show_trace_tree = 0;
100    
101    
102     /*
103     * Private (global) debugger variables:
104     */
105    
106     static volatile int ctrl_c;
107    
108     static int debugger_n_emuls;
109     static struct emul **debugger_emuls;
110     static struct emul *debugger_emul;
111     static struct machine *debugger_machine;
112    
113     #define MAX_CMD_BUFLEN 72
114     #define N_PREVIOUS_CMDS 150
115     static char *last_cmd[N_PREVIOUS_CMDS];
116     static int last_cmd_index;
117    
118     static char repeat_cmd[MAX_CMD_BUFLEN];
119    
120     #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL
121    
122     static uint64_t last_dump_addr = MAGIC_UNTOUCHED;
123     static uint64_t last_unasm_addr = MAGIC_UNTOUCHED;
124    
125    
126     /*
127     * debugger_readchar():
128     */
129     char debugger_readchar(void)
130     {
131     int ch, i, j;
132    
133     while ((ch = console_readchar(MAIN_CONSOLE)) < 0 && !exit_debugger) {
134     /* Check for X11 events: */
135     x11_check_event(debugger_emuls, debugger_n_emuls);
136    
137     /* Check for incoming GDB packets: */
138     for (i=0; i<debugger_n_emuls; i++) {
139     struct emul *e = debugger_emuls[i];
140     if (e == NULL)
141     continue;
142    
143     for (j=0; j<e->n_machines; j++) {
144     if (e->machines[j]->gdb.port > 0)
145     debugger_gdb_check_incoming(
146     e->machines[j]);
147     }
148     }
149    
150     /* TODO: The X11 and GDB checks above should probably
151     be factored out... */
152    
153     /* Give up some CPU time: */
154     usleep(1);
155     }
156     return ch;
157     }
158    
159    
160     /*
161     * debugger_activate():
162     *
163     * This is a signal handler for CTRL-C. It shouldn't be called directly,
164     * but setup code in emul.c sets the CTRL-C signal handler to use this
165     * function.
166     */
167     void debugger_activate(int x)
168     {
169     ctrl_c = 1;
170    
171 dpavlin 26 if (single_step != NOT_SINGLE_STEPPING) {
172 dpavlin 24 /* Already in the debugger. Do nothing. */
173     int i;
174     for (i=0; i<MAX_CMD_BUFLEN; i++)
175     console_makeavail(MAIN_CONSOLE, '\b');
176     console_makeavail(MAIN_CONSOLE, ' ');
177     console_makeavail(MAIN_CONSOLE, '\n');
178     printf("^C");
179     fflush(stdout);
180     } else {
181     /* Enter the single step debugger. */
182 dpavlin 26 single_step = ENTER_SINGLE_STEPPING;
183 dpavlin 24
184     /* Discard any chars in the input queue: */
185     while (console_charavail(MAIN_CONSOLE))
186     console_readchar(MAIN_CONSOLE);
187     }
188    
189     /* Clear the repeat-command buffer: */
190     repeat_cmd[0] = '\0';
191    
192     /* Reactivate the signal handler: */
193     signal(SIGINT, debugger_activate);
194     }
195    
196    
197     /*
198     * debugger_parse_name():
199     *
200     * This function reads a string, and tries to match it to a register name,
201     * a symbol, or treat it as a decimal numeric value.
202     *
203     * Some examples:
204     *
205     * "0x7fff1234" ==> numeric value (hex, in this case)
206     * "pc", "r5", "hi", "t4" ==> register (CPU dependent)
207     * "memcpy+64" ==> symbol (plus offset)
208     *
209     * Register names can be preceeded by "x:" where x is the CPU number. (CPU
210     * 0 is assumed by default.)
211     *
212     * To force detection of different types, a character can be added in front of
213     * the name: "$" for numeric values, "%" for registers, and "@" for symbols.
214     *
215     * Return value is:
216     *
217     * NAME_PARSE_NOMATCH no match
218     * NAME_PARSE_MULTIPLE multiple matches
219     *
220     * or one of these (and then *valuep is read or written, depending on
221     * the writeflag):
222     *
223     * NAME_PARSE_REGISTER a register
224     * NAME_PARSE_NUMBER a hex number
225     * NAME_PARSE_SYMBOL a symbol
226     */
227     #define NAME_PARSE_NOMATCH 0
228     #define NAME_PARSE_MULTIPLE 1
229     #define NAME_PARSE_REGISTER 2
230     #define NAME_PARSE_NUMBER 3
231     #define NAME_PARSE_SYMBOL 4
232     static int debugger_parse_name(struct machine *m, char *name, int writeflag,
233     uint64_t *valuep)
234     {
235     int match_register = 0, match_symbol = 0, match_numeric = 0;
236     int skip_register, skip_numeric, skip_symbol;
237    
238     if (m == NULL || name == NULL) {
239     fprintf(stderr, "debugger_parse_name(): NULL ptr\n");
240     exit(1);
241     }
242    
243     /* Warn about non-signextended values: */
244     if (writeflag) {
245     if (m->cpus[0]->is_32bit) {
246     /* Automagically sign-extend. TODO: Is this good? */
247     if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
248     (*valuep) |= 0xffffffff00000000ULL;
249     } else {
250     if (((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
251     printf("WARNING: The value is not sign-extende"
252     "d. Is this what you intended?\n");
253     }
254     }
255    
256     skip_register = name[0] == '$' || name[0] == '@';
257     skip_numeric = name[0] == '%' || name[0] == '@';
258     skip_symbol = name[0] == '$' || name[0] == '%';
259    
260     /* Check for a register match: */
261     if (!skip_register && strlen(name) >= 1)
262     cpu_register_match(m, name, writeflag, valuep,
263     &match_register);
264    
265     /* Check for a number match: */
266     if (!skip_numeric && isdigit((int)name[0])) {
267     uint64_t x;
268     x = strtoull(name, NULL, 0);
269     if (writeflag) {
270     printf("You cannot assign like that.\n");
271     } else
272     *valuep = x;
273     match_numeric = 1;
274     }
275    
276     /* Check for a symbol match: */
277     if (!skip_symbol) {
278     int res;
279     char *p, *sn;
280     uint64_t newaddr, ofs = 0;
281    
282     sn = malloc(strlen(name) + 1);
283     if (sn == NULL) {
284     fprintf(stderr, "out of memory in debugger\n");
285     exit(1);
286     }
287     strlcpy(sn, name, strlen(name)+1);
288    
289     /* Is there a '+' in there? Then treat that as an offset: */
290     p = strchr(sn, '+');
291     if (p != NULL) {
292     *p = '\0';
293     ofs = strtoull(p+1, NULL, 0);
294     }
295    
296     res = get_symbol_addr(&m->symbol_context, sn, &newaddr);
297     if (res) {
298     if (writeflag) {
299     printf("You cannot assign like that.\n");
300     } else
301     *valuep = newaddr + ofs;
302     match_symbol = 1;
303     }
304    
305     free(sn);
306     }
307    
308     if (match_register + match_symbol + match_numeric > 1)
309     return NAME_PARSE_MULTIPLE;
310    
311     if (match_register)
312     return NAME_PARSE_REGISTER;
313     if (match_numeric)
314     return NAME_PARSE_NUMBER;
315     if (match_symbol)
316     return NAME_PARSE_SYMBOL;
317    
318     return NAME_PARSE_NOMATCH;
319     }
320    
321    
322     /*
323     * show_breakpoint():
324     */
325     static void show_breakpoint(struct machine *m, int i)
326     {
327     printf("%3i: 0x", i);
328     if (m->cpus[0]->is_32bit)
329     printf("%08"PRIx32, (uint32_t) m->breakpoint_addr[i]);
330     else
331     printf("%016"PRIx64, (uint64_t) m->breakpoint_addr[i]);
332     if (m->breakpoint_string[i] != NULL)
333     printf(" (%s)", m->breakpoint_string[i]);
334     if (m->breakpoint_flags[i])
335     printf(": flags=0x%x", m->breakpoint_flags[i]);
336     printf("\n");
337     }
338    
339    
340     /****************************************************************************/
341    
342    
343     #include "debugger_cmds.c"
344    
345    
346     /****************************************************************************/
347    
348    
349     /*
350     * debugger_assignment():
351     *
352     * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
353     */
354     void debugger_assignment(struct machine *m, char *cmd)
355     {
356     char *left, *right;
357     int res_left, res_right;
358     uint64_t tmp;
359     uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */
360    
361     left = malloc(MAX_CMD_BUFLEN);
362     if (left == NULL) {
363     fprintf(stderr, "out of memory in debugger_assignment()\n");
364     exit(1);
365     }
366     strlcpy(left, cmd, MAX_CMD_BUFLEN);
367     right = strchr(left, '=');
368     if (right == NULL) {
369     fprintf(stderr, "internal error in the debugger\n");
370     exit(1);
371     }
372     *right = '\0';
373    
374     /* Remove trailing spaces in left: */
375     while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
376     left[strlen(left)-1] = '\0';
377    
378     /* Remove leading spaces in right: */
379     right++;
380     while (*right == ' ' && *right != '\0')
381     right++;
382    
383     /* printf("left = '%s'\nright = '%s'\n", left, right); */
384    
385     res_right = debugger_parse_name(m, right, 0, &tmp);
386     switch (res_right) {
387     case NAME_PARSE_NOMATCH:
388     printf("No match for the right-hand side of the assignment.\n");
389     break;
390     case NAME_PARSE_MULTIPLE:
391     printf("Multiple matches for the right-hand side of the "
392     "assignment.\n");
393     break;
394     default:
395     res_left = debugger_parse_name(m, left, 1, &tmp);
396     switch (res_left) {
397     case NAME_PARSE_NOMATCH:
398     printf("No match for the left-hand side of the "
399     "assignment.\n");
400     break;
401     case NAME_PARSE_MULTIPLE:
402     printf("Multiple matches for the left-hand side "
403     "of the assignment.\n");
404     break;
405     default:
406     debugger_cmd_print(m, left);
407     }
408     }
409    
410     /*
411     * If the PC has changed, then release any breakpoint we were
412     * currently stopped at.
413     *
414     * TODO: multiple cpus?
415     */
416     if (old_pc != m->cpus[0]->pc)
417     single_step_breakpoint = 0;
418    
419     free(left);
420     }
421    
422    
423     /*
424     * debugger_execute_cmd():
425     */
426     void debugger_execute_cmd(char *cmd, int cmd_len)
427     {
428     int i, n, i_match, matchlen;
429    
430     /*
431     * Is there a '=' on the command line? Then try to do an
432     * assignment. (Only if there is just one word, followed
433     * by the '=' sign. This makes it possible to use commands
434     * such as "device add name addr=xyz".)
435     */
436     if (strchr(cmd, '=') != NULL) {
437     /* Count the nr of words: */
438     int nw = 0, inword = 0;
439     char *p = cmd;
440     while (*p) {
441     if (*p == '=')
442     break;
443     if (*p != ' ') {
444     if (!inword)
445     nw ++;
446     inword = 1;
447     } else
448     inword = 0;
449     p++;
450     }
451    
452     if (nw == 1) {
453     debugger_assignment(debugger_machine, cmd);
454     return;
455     }
456     }
457    
458     i = 0;
459     while (cmds[i].name != NULL)
460     cmds[i++].tmp_flag = 0;
461    
462     /* How many chars in cmd to match against: */
463     matchlen = 0;
464     while (isalpha((int)cmd[matchlen]))
465     matchlen ++;
466    
467     /* Check for a command name match: */
468     n = i = i_match = 0;
469     while (cmds[i].name != NULL) {
470     if (strncasecmp(cmds[i].name, cmd, matchlen) == 0
471     && cmds[i].f != NULL) {
472     cmds[i].tmp_flag = 1;
473     i_match = i;
474     n++;
475     }
476     i++;
477     }
478    
479     /* No match? */
480     if (n == 0) {
481     printf("Unknown command '%s'. Type 'help' for help.\n", cmd);
482     return;
483     }
484    
485     /* More than one match? */
486     if (n > 1) {
487     printf("Ambiguous command '%s': ", cmd);
488     i = 0;
489     while (cmds[i].name != NULL) {
490     if (cmds[i].tmp_flag)
491     printf(" %s", cmds[i].name);
492     i++;
493     }
494     printf("\n");
495     return;
496     }
497    
498     /* Exactly one match: */
499     if (cmds[i_match].f != NULL) {
500     char *p = cmd + matchlen;
501     /* Remove leading whitespace from the args... */
502     while (*p != '\0' && *p == ' ')
503     p++;
504    
505     /* ... and run the command: */
506     cmds[i_match].f(debugger_machine, p);
507     } else
508     printf("FATAL ERROR: internal error in debugger.c:"
509     " no handler for this command?\n");
510     }
511    
512    
513     /*
514     * debugger_readline():
515     *
516     * Read a line from the terminal.
517     */
518     static char *debugger_readline(void)
519     {
520     int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
521     int read_from_index = last_cmd_index;
522     char *cmd = last_cmd[last_cmd_index];
523    
524     cmd_len = 0; cmd[0] = '\0';
525     printf("GXemul> ");
526     fflush(stdout);
527    
528     ch = '\0';
529     cmd_len = 0;
530     cursor_pos = 0;
531    
532     while (ch != '\n' && !exit_debugger) {
533     ch = debugger_readchar();
534    
535     if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
536     /* Backspace. */
537     cursor_pos --;
538     cmd_len --;
539     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
540     cmd_len);
541     cmd[cmd_len] = '\0';
542     printf("\b");
543     for (i=cursor_pos; i<cmd_len; i++)
544     printf("%c", cmd[i]);
545     printf(" \b");
546     for (i=cursor_pos; i<cmd_len; i++)
547     printf("\b");
548     } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
549     /* CTRL-D: Delete. */
550     cmd_len --;
551     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
552     cmd_len);
553     cmd[cmd_len] = '\0';
554     for (i=cursor_pos; i<cmd_len; i++)
555     printf("%c", cmd[i]);
556     printf(" \b");
557     for (i=cursor_pos; i<cmd_len; i++)
558     printf("\b");
559     } else if (ch == 1) {
560     /* CTRL-A: Start of line. */
561     while (cursor_pos > 0) {
562     cursor_pos --;
563     printf("\b");
564     }
565     } else if (ch == 2) {
566     /* CTRL-B: Backwards one character. */
567     if (cursor_pos > 0) {
568     printf("\b");
569     cursor_pos --;
570     }
571     } else if (ch == 5) {
572     /* CTRL-E: End of line. */
573     while (cursor_pos < cmd_len) {
574     printf("%c", cmd[cursor_pos]);
575     cursor_pos ++;
576     }
577     } else if (ch == 6) {
578     /* CTRL-F: Forward one character. */
579     if (cursor_pos < cmd_len) {
580     printf("%c",
581     cmd[cursor_pos]);
582     cursor_pos ++;
583     }
584     } else if (ch == 11) {
585     /* CTRL-K: Kill to end of line. */
586     for (i=0; i<MAX_CMD_BUFLEN; i++)
587     console_makeavail(MAIN_CONSOLE, 4); /* :-) */
588     } else if (ch == 14 || ch == 16) {
589     /* CTRL-P: Previous line in the command history,
590     CTRL-N: next line */
591     do {
592     if (ch == 14 &&
593     read_from_index == last_cmd_index)
594     break;
595     if (ch == 16)
596     i = read_from_index - 1;
597     else
598     i = read_from_index + 1;
599    
600     if (i < 0)
601     i = N_PREVIOUS_CMDS - 1;
602     if (i >= N_PREVIOUS_CMDS)
603     i = 0;
604    
605     /* Special case: pressing 'down'
606     to reach last_cmd_index: */
607     if (i == last_cmd_index) {
608     read_from_index = i;
609     for (i=cursor_pos; i<cmd_len;
610     i++)
611     printf(" ");
612     for (i=cmd_len-1; i>=0; i--)
613     printf("\b \b");
614     cmd[0] = '\0';
615     cmd_len = cursor_pos = 0;
616     } else if (last_cmd[i][0] != '\0') {
617     /* Copy from old line: */
618     read_from_index = i;
619     for (i=cursor_pos; i<cmd_len;
620     i++)
621     printf(" ");
622     for (i=cmd_len-1; i>=0; i--)
623     printf("\b \b");
624     strlcpy(cmd,
625     last_cmd[read_from_index],
626     MAX_CMD_BUFLEN);
627     cmd_len = strlen(cmd);
628     printf("%s", cmd);
629     cursor_pos = cmd_len;
630     }
631     } while (0);
632     } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) {
633     /* Visible character: */
634     memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
635     cmd_len - cursor_pos);
636     cmd[cursor_pos] = ch;
637     cmd_len ++;
638     cursor_pos ++;
639     cmd[cmd_len] = '\0';
640     printf("%c", ch);
641     for (i=cursor_pos; i<cmd_len; i++)
642     printf("%c", cmd[i]);
643     for (i=cursor_pos; i<cmd_len; i++)
644     printf("\b");
645     } else if (ch == '\r' || ch == '\n') {
646     ch = '\n';
647     printf("\n");
648     } else if (ch == '\t') {
649     /* Super-simple tab-completion: */
650     i = 0;
651     while (cmds[i].name != NULL)
652     cmds[i++].tmp_flag = 0;
653    
654     /* Check for a (partial) command match: */
655     n = i = i_match = 0;
656     while (cmds[i].name != NULL) {
657     if (strncasecmp(cmds[i].name, cmd,
658     cmd_len) == 0) {
659     cmds[i].tmp_flag = 1;
660     i_match = i;
661     n++;
662     }
663     i++;
664     }
665    
666     switch (n) {
667     case 0: /* Beep. */
668     printf("\a");
669     break;
670     case 1: /* Add the rest of the command: */
671     reallen = strlen(cmds[i_match].name);
672     for (i=cmd_len; i<reallen; i++)
673     console_makeavail(MAIN_CONSOLE,
674     cmds[i_match].name[i]);
675     /* ... and a space, if the command takes
676     any arguments: */
677     if (cmds[i_match].args != NULL &&
678     cmds[i_match].args[0] != '\0')
679     console_makeavail(MAIN_CONSOLE, ' ');
680     break;
681     default:
682     /* Show all possible commands: */
683     printf("\a\n"); /* Beep. :-) */
684     i = 0; /* i = cmds index */
685     j = 0; /* j = # of cmds printed */
686     while (cmds[i].name != NULL) {
687     if (cmds[i].tmp_flag) {
688     size_t q;
689     if (j == 0)
690     printf(" ");
691     printf("%s",
692     cmds[i].name);
693     j++;
694     if (j != 6)
695     for (q=0; q<13-strlen(
696     cmds[i].name); q++)
697     printf(" ");
698     if (j == 6) {
699     printf("\n");
700     j = 0;
701     }
702     }
703     i++;
704     }
705     if (j != 0)
706     printf("\n");
707     printf("GXemul> ");
708     for (i=0; i<cmd_len; i++)
709     printf("%c", cmd[i]);
710     }
711     } else if (ch == 27) {
712     /* Escape codes: (cursor keys etc) */
713     while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
714     usleep(1);
715     if (ch == '[' || ch == 'O') {
716     while ((ch = console_readchar(MAIN_CONSOLE))
717     < 0)
718     usleep(1);
719     switch (ch) {
720     case '2': /* 2~ = ins */
721     case '5': /* 5~ = pgup */
722     case '6': /* 6~ = pgdn */
723     /* TODO: Ugly hack, but might work. */
724     while ((ch = console_readchar(
725     MAIN_CONSOLE)) < 0)
726     usleep(1);
727     /* Do nothing for these keys. */
728     break;
729     case '3': /* 3~ = delete */
730     /* TODO: Ugly hack, but might work. */
731     while ((ch = console_readchar(
732     MAIN_CONSOLE)) < 0)
733     usleep(1);
734     console_makeavail(MAIN_CONSOLE, '\b');
735     break;
736     case 'A': /* Up. */
737     /* Up cursor ==> CTRL-P */
738     console_makeavail(MAIN_CONSOLE, 16);
739     break;
740     case 'B': /* Down. */
741     /* Down cursor ==> CTRL-N */
742     console_makeavail(MAIN_CONSOLE, 14);
743     break;
744     case 'C':
745     /* Right cursor ==> CTRL-F */
746     console_makeavail(MAIN_CONSOLE, 6);
747     break;
748     case 'D': /* Left */
749     /* Left cursor ==> CTRL-B */
750     console_makeavail(MAIN_CONSOLE, 2);
751     break;
752     case 'F':
753     /* End ==> CTRL-E */
754     console_makeavail(MAIN_CONSOLE, 5);
755     break;
756     case 'H':
757     /* Home ==> CTRL-A */
758     console_makeavail(MAIN_CONSOLE, 1);
759     break;
760     }
761     }
762     }
763    
764     fflush(stdout);
765     }
766    
767     if (exit_debugger)
768     cmd[0] = '\0';
769    
770     return cmd;
771     }
772    
773    
774     /*
775     * debugger():
776     *
777     * This is a loop, which reads a command from the terminal, and executes it.
778     */
779     void debugger(void)
780     {
781     int i, cmd_len;
782     char *cmd;
783    
784     if (debugger_n_steps_left_before_interaction > 0) {
785     debugger_n_steps_left_before_interaction --;
786     return;
787     }
788    
789     /*
790     * Clear all dyntrans translations, because otherwise things would
791     * become to complex to keep in sync.
792     */
793     /* TODO: In all machines */
794     for (i=0; i<debugger_machine->ncpus; i++)
795 dpavlin 26 if (debugger_machine->cpus[i]->translation_cache != NULL) {
796 dpavlin 24 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
797 dpavlin 26 debugger_machine->cpus[i]->
798     invalidate_translation_caches(
799     debugger_machine->cpus[i], 0, INVALIDATE_ALL);
800     }
801 dpavlin 24
802     /*
803     * Ugly GDB hack: After single stepping, we need to send back
804     * status to GDB:
805     */
806     if (exit_debugger == -1) {
807     int i, j;
808     for (i=0; i<debugger_n_emuls; i++) {
809     struct emul *e = debugger_emuls[i];
810     if (e == NULL)
811     continue;
812    
813     for (j=0; j<e->n_machines; j++) {
814     if (e->machines[j]->gdb.port > 0)
815     debugger_gdb_after_singlestep(
816     e->machines[j]);
817     }
818     }
819     }
820    
821    
822     exit_debugger = 0;
823    
824     while (!exit_debugger) {
825     /* Read a line from the terminal: */
826     cmd = debugger_readline();
827    
828     /* Special hack for the "step" _GDB_ command: */
829     if (exit_debugger == -1)
830     return;
831    
832     cmd_len = strlen(cmd);
833    
834     /* Remove spaces: */
835     while (cmd_len > 0 && cmd[0]==' ')
836     memmove(cmd, cmd+1, cmd_len --);
837     while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
838     cmd[(cmd_len--)-1] = '\0';
839    
840     /* No command? Then try reading another line. */
841     if (cmd_len == 0) {
842     /* Special case for repeated commands: */
843     if (repeat_cmd[0] != '\0')
844     strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN);
845     else
846     continue;
847     } else {
848     last_cmd_index ++;
849     if (last_cmd_index >= N_PREVIOUS_CMDS)
850     last_cmd_index = 0;
851    
852     repeat_cmd[0] = '\0';
853     }
854    
855     debugger_execute_cmd(cmd, cmd_len);
856    
857     /* Special hack for the "step" command: */
858     if (exit_debugger == -1)
859     return;
860     }
861    
862     gettimeofday(&debugger_machine->starttime, NULL);
863     debugger_machine->ncycles_since_gettimeofday = 0;
864    
865 dpavlin 26 single_step = NOT_SINGLE_STEPPING;
866 dpavlin 24 debugger_machine->instruction_trace = old_instruction_trace;
867     debugger_machine->show_trace_tree = old_show_trace_tree;
868     quiet_mode = old_quiet_mode;
869     }
870    
871    
872     /*
873     * debugger_reset():
874     *
875     * This function should be called before calling debugger(), when it is
876     * absolutely necessary that debugger() is interactive. Otherwise, it might
877     * return without doing anything, such as when single-stepping multiple
878     * instructions at a time.
879     */
880     void debugger_reset(void)
881     {
882     debugger_n_steps_left_before_interaction = 0;
883     }
884    
885    
886     /*
887     * debugger_init():
888     *
889     * Must be called before any other debugger function is used.
890     */
891     void debugger_init(struct emul **emuls, int n_emuls)
892     {
893     int i, j;
894    
895     debugger_n_emuls = n_emuls;
896     debugger_emuls = emuls;
897    
898     if (n_emuls < 1) {
899     fprintf(stderr, "\nERROR: No emuls (?)\n");
900     exit(1);
901     }
902    
903     debugger_emul = emuls[0];
904     if (emuls[0]->n_machines < 1) {
905     fprintf(stderr, "\nERROR: No machines in emuls[0], "
906     "cannot handle this situation yet.\n\n");
907     exit(1);
908     }
909    
910     for (i=0; i<n_emuls; i++)
911     for (j=0; j<emuls[i]->n_machines; j++)
912     debugger_gdb_init(emuls[i]->machines[j]);
913    
914     debugger_machine = emuls[0]->machines[0];
915    
916     for (i=0; i<N_PREVIOUS_CMDS; i++) {
917     last_cmd[i] = malloc(MAX_CMD_BUFLEN);
918     if (last_cmd[i] == NULL) {
919     fprintf(stderr, "debugger_init(): out of memory\n");
920     exit(1);
921     }
922     last_cmd[i][0] = '\0';
923     }
924    
925     last_cmd_index = 0;
926     repeat_cmd[0] = '\0';
927     }
928    

  ViewVC Help
Powered by ViewVC 1.1.26