/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 22785 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

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

  ViewVC Help
Powered by ViewVC 1.1.26