/[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 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 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 /*
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.12 2006/06/25 01:25:32 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 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 if (single_step != NOT_SINGLE_STEPPING) {
172 /* 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 single_step = ENTER_SINGLE_STEPPING;
183
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 if (debugger_machine->cpus[i]->translation_cache != NULL) {
796 cpu_create_or_reset_tc(debugger_machine->cpus[i]);
797 debugger_machine->cpus[i]->
798 invalidate_translation_caches(
799 debugger_machine->cpus[i], 0, INVALIDATE_ALL);
800 }
801
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 single_step = NOT_SINGLE_STEPPING;
866 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