/[gxemul]/trunk/src/debugger/debugger.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/debugger/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 5 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 /*
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 * $Id: debugger.c,v 1.14 2006/07/01 21:15:46 debug Exp $
29 *
30 * Single-step debugger.
31 *
32 *
33 * TODO:
34 *
35 * This entire module is very much non-reentrant. :-/
36 *
37 * Add more functionality that already exists elsewhere in the emulator.
38 *
39 * Call stack display (back-trace)?
40 *
41 * 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 volatile int single_step = NOT_SINGLE_STEPPING;
90 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 if (single_step != NOT_SINGLE_STEPPING) {
171 /* 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 single_step = ENTER_SINGLE_STEPPING;
182
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 if (debugger_machine->cpus[i]->translation_cache != NULL) {
795 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
796 debugger_machine->cpus[i]->
797 invalidate_translation_caches(
798 debugger_machine->cpus[i], 0, INVALIDATE_ALL);
799 }
800
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 debugger_machine->ninstrs_since_gettimeofday = 0;
863
864 single_step = NOT_SINGLE_STEPPING;
865 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