/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 18133 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26