/[gxemul]/upstream/0.3.1/src/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 /upstream/0.3.1/src/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 47145 byte(s)
0.3.1
1 /*
2 * Copyright (C) 2003-2005 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.98 2005/03/20 20:27:26 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 * More generic expression evaluator (for example + - * / between multiple
40 * terms), including _TAB COMPLETION_ of symbols and register names!
41 *
42 * Nicer looking output of register dumps, floating point registers,
43 * etc. Warn about weird/invalid register contents.
44 *
45 * Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)...
46 *
47 * Many other TODOs.
48 */
49
50 #include <ctype.h>
51 #include <signal.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56
57 #include "console.h"
58 #include "cpu.h"
59 #include "device.h"
60 #include "debugger.h"
61 #include "diskimage.h"
62 #include "emul.h"
63 #include "machine.h"
64 #include "memory.h"
65 #include "misc.h"
66 #include "net.h"
67 #include "x11.h"
68
69
70 extern int extra_argc;
71 extern char **extra_argv;
72
73 extern int quiet_mode;
74
75
76 /*
77 * Global debugger variables:
78 */
79
80 volatile int single_step = 0;
81 int force_debugger_at_exit = 0;
82 int show_opcode_statistics = 0;
83
84 int old_instruction_trace = 0;
85 int old_quiet_mode = 0;
86 int old_show_trace_tree = 0;
87
88
89 /*
90 * Private (global) debugger variables:
91 */
92
93 static volatile int ctrl_c;
94
95 static int debugger_n_emuls;
96 static struct emul **debugger_emuls;
97 static struct emul *debugger_emul;
98 static struct machine *debugger_machine;
99
100 static int exit_debugger;
101 static int n_steps_left_before_interaction = 0;
102
103 #define MAX_CMD_LEN 70
104 #define N_PREVIOUS_CMDS 150
105 static char *last_cmd[N_PREVIOUS_CMDS];
106 static int last_cmd_index;
107
108 static char repeat_cmd[MAX_CMD_LEN + 1];
109
110 #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL
111
112 static uint64_t last_dump_addr = MAGIC_UNTOUCHED;
113 static uint64_t last_unasm_addr = MAGIC_UNTOUCHED;
114
115
116 /*
117 * debugger_activate():
118 *
119 * This is a signal handler for CTRL-C. It shouldn't be called directly,
120 * but setup code in emul.c sets the CTRL-C signal handler to use this
121 * function.
122 */
123 void debugger_activate(int x)
124 {
125 ctrl_c = 1;
126
127 if (single_step) {
128 /* Already in the debugger. Do nothing. */
129 int i;
130 for (i=0; i<MAX_CMD_LEN+1; i++)
131 console_makeavail(MAIN_CONSOLE, '\b');
132 console_makeavail(MAIN_CONSOLE, ' ');
133 console_makeavail(MAIN_CONSOLE, '\n');
134 printf("^C");
135 fflush(stdout);
136 } else {
137 /* Enter the single step debugger. */
138 single_step = 1;
139
140 /* Discard any chars in the input queue: */
141 while (console_charavail(MAIN_CONSOLE))
142 console_readchar(MAIN_CONSOLE);
143 }
144
145 /* Clear the repeat-command buffer: */
146 repeat_cmd[0] = '\0';
147
148 /* Reactivate the signal handler: */
149 signal(SIGINT, debugger_activate);
150 }
151
152
153 /*
154 * debugger_parse_name():
155 *
156 * This function reads a string, and tries to match it to a register name,
157 * a symbol, or treat it as a decimal numeric value.
158 *
159 * Some examples:
160 *
161 * "0x7fff1234" ==> numeric value (hex, in this case)
162 * "pc", "r5", "hi", "t4" ==> register (CPU dependant)
163 * "memcpy+64" ==> symbol (plus offset)
164 *
165 * Register names can be preceeded by "x:" where x is the CPU number. (CPU
166 * 0 is assumed by default.)
167 *
168 * To force detection of different types, a character can be added in front of
169 * the name: "$" for numeric values, "%" for registers, and "@" for symbols.
170 *
171 * Return value is:
172 *
173 * NAME_PARSE_NOMATCH no match
174 * NAME_PARSE_MULTIPLE multiple matches
175 *
176 * or one of these (and then *valuep is read or written, depending on
177 * the writeflag):
178 *
179 * NAME_PARSE_REGISTER a register
180 * NAME_PARSE_NUMBER a hex number
181 * NAME_PARSE_SYMBOL a symbol
182 */
183 #define NAME_PARSE_NOMATCH 0
184 #define NAME_PARSE_MULTIPLE 1
185 #define NAME_PARSE_REGISTER 2
186 #define NAME_PARSE_NUMBER 3
187 #define NAME_PARSE_SYMBOL 4
188 static int debugger_parse_name(struct machine *m, char *name, int writeflag,
189 uint64_t *valuep)
190 {
191 int match_register = 0, match_symbol = 0, match_numeric = 0;
192 int skip_register, skip_numeric, skip_symbol;
193
194 if (m == NULL || name == NULL) {
195 fprintf(stderr, "debugger_parse_name(): NULL ptr\n");
196 exit(1);
197 }
198
199 /* Warn about non-signextended values: */
200 if (writeflag &&
201 ((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
202 printf("WARNING: The value is not sign-extended. "
203 "Is this what you intended?\n");
204
205 skip_register = name[0] == '$' || name[0] == '@';
206 skip_numeric = name[0] == '%' || name[0] == '@';
207 skip_symbol = name[0] == '$' || name[0] == '%';
208
209 /* Check for a register match: */
210 if (!skip_register && strlen(name) >= 1)
211 cpu_register_match(m, name, writeflag, valuep,
212 &match_register);
213
214 /* Check for a number match: */
215 if (!skip_numeric && isdigit((int)name[0])) {
216 uint64_t x;
217 x = strtoull(name, NULL, 0);
218 if (writeflag) {
219 printf("You cannot assign like that.\n");
220 } else
221 *valuep = x;
222 match_numeric = 1;
223 }
224
225 /* Check for a symbol match: */
226 if (!skip_symbol) {
227 int res;
228 char *p, *sn;
229 uint64_t newaddr, ofs = 0;
230
231 sn = malloc(strlen(name) + 1);
232 if (sn == NULL) {
233 fprintf(stderr, "out of memory in debugger\n");
234 exit(1);
235 }
236 strcpy(sn, name);
237
238 /* Is there a '+' in there? Then treat that as an offset: */
239 p = strchr(sn, '+');
240 if (p != NULL) {
241 *p = '\0';
242 ofs = strtoull(p+1, NULL, 0);
243 }
244
245 res = get_symbol_addr(&m->symbol_context, sn, &newaddr);
246 if (res) {
247 if (writeflag) {
248 printf("You cannot assign like that.\n");
249 } else
250 *valuep = newaddr + ofs;
251 match_symbol = 1;
252 }
253
254 free(sn);
255 }
256
257 if (match_register + match_symbol + match_numeric > 1)
258 return NAME_PARSE_MULTIPLE;
259
260 if (match_register)
261 return NAME_PARSE_REGISTER;
262 if (match_numeric)
263 return NAME_PARSE_NUMBER;
264 if (match_symbol)
265 return NAME_PARSE_SYMBOL;
266
267 return NAME_PARSE_NOMATCH;
268 }
269
270
271 /*
272 * show_breakpoint():
273 */
274 static void show_breakpoint(struct machine *m, int i)
275 {
276 printf("%3i: 0x%016llx", i,
277 (long long)m->breakpoint_addr[i]);
278 if (m->breakpoint_string[i] != NULL)
279 printf(" (%s)", m->breakpoint_string[i]);
280 if (m->breakpoint_flags[i])
281 printf(": flags=0x%x", m->breakpoint_flags[i]);
282 printf("\n");
283 }
284
285
286 /****************************************************************************/
287
288
289 /*
290 * debugger_cmd_breakpoint():
291 *
292 * TODO: automagic "expansion" for the subcommand names (s => show).
293 */
294 static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line)
295 {
296 int i, res;
297
298 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
299 cmd_line ++;
300
301 if (cmd_line[0] == '\0') {
302 printf("syntax: breakpoint subcmd [args...]\n");
303 printf("Available subcmds (and args) are:\n");
304 printf(" add addr add a breakpoint for address addr\n");
305 printf(" delete x delete breakpoint nr x\n");
306 printf(" show show current breakpoints\n");
307 return;
308 }
309
310 if (strcmp(cmd_line, "show") == 0) {
311 if (m->n_breakpoints == 0)
312 printf("No breakpoints set.\n");
313 for (i=0; i<m->n_breakpoints; i++)
314 show_breakpoint(m, i);
315 return;
316 }
317
318 if (strncmp(cmd_line, "delete ", 7) == 0) {
319 int x = atoi(cmd_line + 7);
320
321 if (m->n_breakpoints == 0) {
322 printf("No breakpoints set.\n");
323 return;
324 }
325 if (x < 0 || x >= m->n_breakpoints) {
326 printf("Invalid breakpoint nr %i. Use 'breakpoint "
327 "show' to see the current breakpoints.\n", x);
328 return;
329 }
330
331 free(m->breakpoint_string[x]);
332
333 for (i=x; i<m->n_breakpoints-1; i++) {
334 m->breakpoint_addr[i] = m->breakpoint_addr[i+1];
335 m->breakpoint_string[i] = m->breakpoint_string[i+1];
336 m->breakpoint_flags[i] = m->breakpoint_flags[i+1];
337 }
338 m->n_breakpoints --;
339 return;
340 }
341
342 if (strncmp(cmd_line, "add ", 4) == 0) {
343 uint64_t tmp;
344
345 if (m->n_breakpoints >= MAX_BREAKPOINTS) {
346 printf("Too many breakpoints. (You need to recompile"
347 " gxemul to increase this. Max = %i.)\n",
348 MAX_BREAKPOINTS);
349 return;
350 }
351
352 i = m->n_breakpoints;
353
354 res = debugger_parse_name(m, cmd_line + 4, 0, &tmp);
355 if (!res) {
356 printf("Couldn't parse '%s'\n", cmd_line + 4);
357 return;
358 }
359
360 m->breakpoint_string[i] = malloc(strlen(cmd_line+4) + 1);
361 if (m->breakpoint_string[i] == NULL) {
362 printf("out of memory in debugger_cmd_breakpoint()\n");
363 exit(1);
364 }
365 strcpy(m->breakpoint_string[i], cmd_line+4);
366 m->breakpoint_addr[i] = tmp;
367 m->breakpoint_flags[i] = 0;
368
369 m->n_breakpoints ++;
370 show_breakpoint(m, i);
371 return;
372 }
373
374 printf("Unknown breakpoint subcommand.\n");
375 }
376
377
378 /*
379 * debugger_cmd_bintrans():
380 */
381 static void debugger_cmd_bintrans(struct machine *m, char *cmd_line)
382 {
383 if (*cmd_line == '\0')
384 goto printstate;
385
386 if (!m->bintrans_enabled_from_start) {
387 printf("You must have enabled bintrans from the start of the "
388 "simulation.\nIt is not possible to turn on afterwards.\n");
389 return;
390 }
391
392 while (*cmd_line == ' ')
393 cmd_line++;
394
395 /* Note: len 3 and 4, to include the NUL char. */
396 if (strncasecmp(cmd_line, "on", 3) == 0)
397 m->bintrans_enable = 1;
398 else if (strncasecmp(cmd_line, "off", 4) == 0)
399 m->bintrans_enable = 0;
400 else
401 printf("syntax: bintrans [on|off]\n");
402
403 printstate:
404 printf("bintrans is now %s%s\n",
405 m->bintrans_enable? "ENABLED" : "disabled",
406 m->old_bintrans_enable? " (using the OLD bintrans system)" : "");
407 }
408
409
410 /*
411 * debugger_cmd_continue():
412 */
413 static void debugger_cmd_continue(struct machine *m, char *cmd_line)
414 {
415 if (*cmd_line) {
416 printf("syntax: continue\n");
417 return;
418 }
419
420 exit_debugger = 1;
421 }
422
423
424 /*
425 * debugger_cmd_device():
426 */
427 static void debugger_cmd_device(struct machine *m, char *cmd_line)
428 {
429 int i, j;
430 struct memory *mem;
431 struct cpu *c;
432
433 if (cmd_line[0] == '\0')
434 goto return_help;
435
436 if (m->cpus == NULL) {
437 printf("No cpus (?)\n");
438 return;
439 }
440 c = m->cpus[m->bootstrap_cpu];
441 if (c == NULL) {
442 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
443 return;
444 }
445 mem = m->cpus[m->bootstrap_cpu]->mem;
446
447 if (m->cpus == NULL) {
448 printf("No cpus (?)\n");
449 return;
450 }
451 c = m->cpus[m->bootstrap_cpu];
452 if (c == NULL) {
453 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
454 return;
455 }
456 mem = m->cpus[m->bootstrap_cpu]->mem;
457
458 if (strcmp(cmd_line, "all") == 0) {
459 device_dumplist();
460 } else if (strncmp(cmd_line, "add ", 4) == 0) {
461 device_add(m, cmd_line+4);
462 } else if (strncmp(cmd_line, "remove ", 7) == 0) {
463 i = atoi(cmd_line + 7);
464 if (i==0 && cmd_line[7]!='0') {
465 printf("Weird device number. Use 'device list'.\n");
466 } else
467 memory_device_remove(m->memory, i);
468 } else if (strncmp(cmd_line, "state ", 6) == 0) {
469 i = atoi(cmd_line + 6);
470 if (i < 0 || i >= mem->n_mmapped_devices) {
471 printf("No devices with that id.\n");
472 return;
473 }
474
475 if (mem->dev_f_state[i] == NULL) {
476 printf("No state function has been implemented yet "
477 "for that device type.\n");
478 return;
479 }
480
481 for (j=0; ; j++) {
482 int type;
483 char *name;
484 void *data;
485 size_t len;
486 int res = mem->dev_f_state[i](c, mem,
487 mem->dev_extra[i], 0, j, &type, &name, &data, &len);
488 if (!res)
489 break;
490 printf("%2i:%30s = (", j, name);
491 switch (type) {
492 case DEVICE_STATE_TYPE_INT:
493 printf("int) %i", *((int *)data));
494 break;
495 default:
496 printf("unknown)");
497 }
498 printf("\n");
499 }
500 } else if (strcmp(cmd_line, "list") == 0) {
501 if (mem->n_mmapped_devices == 0)
502 printf("No memory-mapped devices in this machine.\n");
503
504 for (i=0; i<mem->n_mmapped_devices; i++) {
505 printf("%2i: %25s @ 0x%011llx, len = 0x%llx",
506 i, mem->dev_name[i],
507 (long long)mem->dev_baseaddr[i],
508 (long long)mem->dev_length[i]);
509 if (mem->dev_flags[i]) {
510 printf(" (");
511 if (mem->dev_flags[i] & MEM_BINTRANS_OK)
512 printf("BINTRANS R");
513 if (mem->dev_flags[i] & MEM_BINTRANS_WRITE_OK)
514 printf("+W");
515 printf(")");
516 }
517 printf("\n");
518 }
519 } else
520 goto return_help;
521
522 return;
523
524 return_help:
525 printf("syntax: devices cmd [...]\n");
526 printf("Available cmds are:\n");
527 printf(" add name_and_params add a device to the current "
528 "machine\n");
529 printf(" all list all registered devices\n");
530 printf(" list list memory-mapped devices in the"
531 " current machine\n");
532 printf(" remove x remove device nr x from the "
533 "current machine\n");
534 printf(" state x show state of device nr x in"
535 " the current machine\n");
536 }
537
538
539 /*
540 * debugger_cmd_dump():
541 *
542 * Dump emulated memory in hex and ASCII.
543 *
544 * syntax: dump [addr [endaddr]]
545 */
546 static void debugger_cmd_dump(struct machine *m, char *cmd_line)
547 {
548 uint64_t addr, addr_start, addr_end;
549 struct cpu *c;
550 struct memory *mem;
551 char *p = NULL;
552 int x, r;
553
554 if (cmd_line[0] != '\0') {
555 uint64_t tmp;
556 char *tmps = strdup(cmd_line);
557
558 /* addr: */
559 p = strchr(tmps, ' ');
560 if (p != NULL)
561 *p = '\0';
562 r = debugger_parse_name(m, tmps, 0, &tmp);
563 free(tmps);
564
565 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
566 printf("Unparsable address: %s\n", cmd_line);
567 return;
568 } else {
569 last_dump_addr = tmp;
570 }
571
572 p = strchr(cmd_line, ' ');
573 }
574
575 addr_start = last_dump_addr;
576
577 if (addr_start == MAGIC_UNTOUCHED) {
578 uint64_t tmp;
579 int match_register = 0;
580 cpu_register_match(m, "pc", 0, &tmp, &match_register);
581 if (match_register) {
582 addr_start = tmp;
583 } else {
584 printf("No starting address.\n");
585 return;
586 }
587 }
588
589 addr_end = addr_start + 16 * 16;
590
591 /* endaddr: */
592 if (p != NULL) {
593 while (*p == ' ' && *p)
594 p++;
595 r = debugger_parse_name(m, p, 0, &addr_end);
596 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
597 printf("Unparsable address: %s\n", cmd_line);
598 return;
599 }
600 }
601
602 if (m->cpus == NULL) {
603 printf("No cpus (?)\n");
604 return;
605 }
606 c = m->cpus[m->bootstrap_cpu];
607 if (c == NULL) {
608 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
609 return;
610 }
611 mem = m->cpus[m->bootstrap_cpu]->mem;
612
613 addr = addr_start & ~0xf;
614
615 ctrl_c = 0;
616
617 while (addr < addr_end) {
618 unsigned char buf[16];
619 memset(buf, 0, sizeof(buf));
620 r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf),
621 MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
622
623 printf("0x%016llx ", (long long)addr);
624
625 if (r == MEMORY_ACCESS_FAILED)
626 printf("(memory access failed)\n");
627 else {
628 for (x=0; x<16; x++) {
629 if (addr + x >= addr_start &&
630 addr + x < addr_end)
631 printf("%02x%s", buf[x],
632 (x&3)==3? " " : "");
633 else
634 printf(" %s", (x&3)==3? " " : "");
635 }
636 printf(" ");
637 for (x=0; x<16; x++) {
638 if (addr + x >= addr_start &&
639 addr + x < addr_end)
640 printf("%c", (buf[x]>=' ' &&
641 buf[x]<127)? buf[x] : '.');
642 else
643 printf(" ");
644 }
645 printf("\n");
646 }
647
648 if (ctrl_c)
649 return;
650
651 addr += sizeof(buf);
652 }
653
654 last_dump_addr = addr_end;
655
656 strcpy(repeat_cmd, "dump");
657 }
658
659
660 /*
661 * debugger_cmd_emuls():
662 *
663 * Dump info about all current emuls.
664 */
665 static void debugger_cmd_emuls(struct machine *m, char *cmd_line)
666 {
667 int i, iadd = 4;
668
669 if (*cmd_line) {
670 printf("syntax: emuls\n");
671 return;
672 }
673
674 for (i=0; i<debugger_n_emuls; i++) {
675 struct emul *e = debugger_emuls[i];
676
677 if (e == NULL)
678 continue;
679
680 debug("emulation %i: \"%s\"\n", i,
681 e->name == NULL? "(no name)" : e->name);
682 debug_indentation(iadd);
683
684 emul_dumpinfo(e);
685
686 debug_indentation(-iadd);
687 }
688 }
689
690
691 /*
692 * debugger_cmd_focus():
693 *
694 * Changes focus to specific machine (in a specific emulation).
695 */
696 static void debugger_cmd_focus(struct machine *m, char *cmd_line)
697 {
698 int x = -1, y = -1;
699 char *p;
700
701 if (!cmd_line[0]) {
702 printf("syntax: focus x[,y]\n");
703 printf("where x and y are integers as reported by the"
704 " 'emuls' command\n");
705 goto print_current_focus_and_return;
706 }
707
708 x = atoi(cmd_line);
709 p = strchr(cmd_line, ',');
710 if (p == cmd_line) {
711 printf("No machine number specified?\n");
712 printf("syntax: focus x[,y]\n");
713 return;
714 }
715
716 if (p != NULL)
717 y = atoi(p + 1);
718
719 if (y != -1) {
720 /* Change emul: */
721 if (y < 0 || y >= debugger_n_emuls) {
722 printf("Invalid emul number: %i\n", y);
723 return;
724 }
725
726 debugger_emul = debugger_emuls[y];
727
728 /* This is just in case the machine change below fails... */
729 debugger_machine = debugger_emul->machines[0];
730 }
731
732 /* Change machine: */
733 if (x < 0 || x >= debugger_emul->n_machines) {
734 printf("Invalid machine number: %i\n", x);
735 return;
736 }
737
738 debugger_machine = debugger_emul->machines[x];
739
740 print_current_focus_and_return:
741 printf("current emul: \"%s\"\n", debugger_emul->name == NULL?
742 "(no name)" : debugger_emul->name);
743 printf("current machine: \"%s\"\n", debugger_machine->name == NULL?
744 "(no name)" : debugger_machine->name);
745 }
746
747
748 /* This is defined below. */
749 static void debugger_cmd_help(struct machine *m, char *cmd_line);
750
751
752 /*
753 * debugger_cmd_itrace():
754 */
755 static void debugger_cmd_itrace(struct machine *m, char *cmd_line)
756 {
757 if (*cmd_line) {
758 printf("syntax: itrace\n");
759 return;
760 }
761
762 old_instruction_trace = 1 - old_instruction_trace;
763 printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF");
764 /* TODO: how to preserve quiet_mode? */
765 old_quiet_mode = 0;
766 printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
767 }
768
769
770 /*
771 * debugger_cmd_lookup():
772 */
773 static void debugger_cmd_lookup(struct machine *m, char *cmd_line)
774 {
775 uint64_t addr;
776 int res;
777 char *symbol;
778 uint64_t offset;
779
780 if (cmd_line[0] == '\0') {
781 printf("syntax: lookup name|addr\n");
782 return;
783
784 }
785
786 /* Addresses never need to be given in decimal form anyway,
787 so assuming hex here will be ok. */
788 addr = strtoull(cmd_line, NULL, 16);
789
790 if (addr == 0) {
791 uint64_t newaddr;
792 res = get_symbol_addr(&m->symbol_context,
793 cmd_line, &newaddr);
794 if (!res) {
795 printf("lookup for '%s' failed\n", cmd_line);
796 return;
797 }
798 printf("%s = 0x%016llx\n", cmd_line, (long long)newaddr);
799 return;
800 }
801
802 symbol = get_symbol_name(&m->symbol_context, addr, &offset);
803
804 if (symbol != NULL)
805 printf("0x%016llx = %s\n", (long long)addr, symbol);
806 else
807 printf("lookup for '%s' failed\n", cmd_line);
808 }
809
810
811 /*
812 * debugger_cmd_machine():
813 *
814 * Dump info about the currently focused machine.
815 */
816 static void debugger_cmd_machine(struct machine *m, char *cmd_line)
817 {
818 int iadd = 4;
819
820 if (*cmd_line) {
821 printf("syntax: machine\n");
822 return;
823 }
824
825 debug("machine \"%s\":\n", m->name);
826 debug_indentation(iadd);
827 machine_dumpinfo(m);
828 debug_indentation(-iadd);
829 }
830
831
832 /*
833 * debugger_cmd_opcodestats():
834 */
835 static void debugger_cmd_opcodestats(struct machine *m, char *cmd_line)
836 {
837 if (*cmd_line) {
838 printf("syntax: opcodestats\n");
839 return;
840 }
841
842 if (!show_opcode_statistics) {
843 printf("You need to start the emulator "
844 "with -s, if you want to gather statistics.\n");
845 } else
846 cpu_show_full_statistics(m);
847 }
848
849
850 /*
851 * debugger_cmd_pause():
852 */
853 static void debugger_cmd_pause(struct machine *m, char *cmd_line)
854 {
855 int cpuid = -1;
856
857 if (cmd_line[0] != '\0')
858 cpuid = atoi(cmd_line);
859 else {
860 printf("syntax: pause cpuid\n");
861 return;
862 }
863
864 if (cpuid < 0 || cpuid >= m->ncpus) {
865 printf("cpu%i doesn't exist.\n", cpuid);
866 return;
867 }
868
869 m->cpus[cpuid]->running ^= 1;
870
871 printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid,
872 m->cpus[cpuid]->name, m->name,
873 m->cpus[cpuid]->running? "RUNNING" : "STOPPED");
874 }
875
876
877 /*
878 * debugger_cmd_print():
879 */
880 static void debugger_cmd_print(struct machine *m, char *cmd_line)
881 {
882 int res;
883 uint64_t tmp;
884
885 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
886 cmd_line ++;
887
888 if (cmd_line[0] == '\0') {
889 printf("syntax: print expr\n");
890 return;
891 }
892
893 res = debugger_parse_name(m, cmd_line, 0, &tmp);
894 switch (res) {
895 case NAME_PARSE_NOMATCH:
896 printf("No match.\n");
897 break;
898 case NAME_PARSE_MULTIPLE:
899 printf("Multiple matches. Try prefixing with %%, $, or @.\n");
900 break;
901 case NAME_PARSE_REGISTER:
902 case NAME_PARSE_SYMBOL:
903 printf("%s = 0x%016llx\n", cmd_line, (long long)tmp);
904 break;
905 case NAME_PARSE_NUMBER:
906 printf("0x%016llx\n", (long long)tmp);
907 break;
908 }
909 }
910
911
912 /*
913 * debugger_cmd_put():
914 */
915 static void debugger_cmd_put(struct machine *m, char *cmd_line)
916 {
917 static char put_type = ' '; /* Remembered across multiple calls. */
918 char copy[200];
919 int res, syntax_ok = 0;
920 char *p, *p2, *q = NULL;
921 uint64_t addr, data;
922 unsigned char a_byte;
923
924 strncpy(copy, cmd_line, sizeof(copy));
925 copy[sizeof(copy)-1] = '\0';
926
927 /* syntax: put [b|h|w|d|q] addr, data */
928
929 p = strchr(copy, ',');
930 if (p != NULL) {
931 *p++ = '\0';
932 while (*p == ' ' && *p)
933 p++;
934 while (strlen(copy) >= 1 &&
935 copy[strlen(copy) - 1] == ' ')
936 copy[strlen(copy) - 1] = '\0';
937
938 /* printf("L = '%s', R = '%s'\n", copy, p); */
939
940 q = copy;
941 p2 = strchr(q, ' ');
942
943 if (p2 != NULL) {
944 *p2 = '\0';
945 if (strlen(q) != 1) {
946 printf("Invalid type '%s'\n", q);
947 return;
948 }
949 put_type = *q;
950 q = p2 + 1;
951 }
952
953 /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
954 syntax_ok = 1;
955 }
956
957 if (!syntax_ok) {
958 printf("syntax: put [b|h|w|d|q] addr, data\n");
959 printf(" b byte (8 bits)\n");
960 printf(" h half-word (16 bits)\n");
961 printf(" w word (32 bits)\n");
962 printf(" d doubleword (64 bits)\n");
963 printf(" q quad-word (128 bits)\n");
964 return;
965 }
966
967 if (put_type == ' ') {
968 printf("No type specified.\n");
969 return;
970 }
971
972 /* here: q is the address, p is the data. */
973
974 res = debugger_parse_name(m, q, 0, &addr);
975 switch (res) {
976 case NAME_PARSE_NOMATCH:
977 printf("Couldn't parse the address.\n");
978 return;
979 case NAME_PARSE_MULTIPLE:
980 printf("Multiple matches for the address."
981 " Try prefixing with %%, $, or @.\n");
982 return;
983 case NAME_PARSE_REGISTER:
984 case NAME_PARSE_SYMBOL:
985 case NAME_PARSE_NUMBER:
986 break;
987 default:
988 printf("INTERNAL ERROR in debugger.c.\n");
989 return;
990 }
991
992 res = debugger_parse_name(m, p, 0, &data);
993 switch (res) {
994 case NAME_PARSE_NOMATCH:
995 printf("Couldn't parse the data.\n");
996 return;
997 case NAME_PARSE_MULTIPLE:
998 printf("Multiple matches for the data value."
999 " Try prefixing with %%, $, or @.\n");
1000 return;
1001 case NAME_PARSE_REGISTER:
1002 case NAME_PARSE_SYMBOL:
1003 case NAME_PARSE_NUMBER:
1004 break;
1005 default:
1006 printf("INTERNAL ERROR in debugger.c.\n");
1007 return;
1008 }
1009
1010 /* TODO: haha, maybe this should be refactored */
1011
1012 switch (put_type) {
1013 case 'b':
1014 a_byte = data;
1015 printf("0x%016llx: %02x", (long long)addr, a_byte);
1016 if (data > 255)
1017 printf(" (NOTE: truncating %0llx)", (long long)data);
1018 res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
1019 &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
1020 if (!res)
1021 printf(" FAILED!\n");
1022 printf("\n");
1023 return;
1024 case 'h':
1025 if ((data & 1) != 0)
1026 printf("WARNING: address isn't aligned\n");
1027 printf("0x%016llx: %04x", (long long)addr, (int)data);
1028 if (data > 0xffff)
1029 printf(" (NOTE: truncating %0llx)", (long long)data);
1030 res = store_16bit_word(m->cpus[0], addr, data);
1031 if (!res)
1032 printf(" FAILED!\n");
1033 printf("\n");
1034 return;
1035 case 'w':
1036 if ((data & 3) != 0)
1037 printf("WARNING: address isn't aligned\n");
1038 printf("0x%016llx: %08x", (long long)addr, (int)data);
1039 if (data > 0xffffffff && (data >> 32) != 0
1040 && (data >> 32) != 0xffffffff)
1041 printf(" (NOTE: truncating %0llx)", (long long)data);
1042 res = store_32bit_word(m->cpus[0], addr, data);
1043 if (!res)
1044 printf(" FAILED!\n");
1045 printf("\n");
1046 return;
1047 case 'd':
1048 if ((data & 7) != 0)
1049 printf("WARNING: address isn't aligned\n");
1050 printf("0x%016llx: %016llx", (long long)addr, (long long)data);
1051 res = store_64bit_word(m->cpus[0], addr, data);
1052 if (!res)
1053 printf(" FAILED!\n");
1054 printf("\n");
1055 return;
1056 case 'q':
1057 printf("quad-words: TODO\n");
1058 /* TODO */
1059 return;
1060 default:
1061 printf("Unimplemented type '%c'\n", put_type);
1062 return;
1063 }
1064 }
1065
1066
1067 /*
1068 * debugger_cmd_quiet():
1069 */
1070 static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
1071 {
1072 int toggle = 1;
1073 int previous_mode = old_quiet_mode;
1074
1075 if (cmd_line[0] != '\0') {
1076 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1077 cmd_line ++;
1078 switch (cmd_line[0]) {
1079 case '0':
1080 toggle = 0;
1081 old_quiet_mode = 0;
1082 break;
1083 case '1':
1084 toggle = 0;
1085 old_quiet_mode = 1;
1086 break;
1087 case 'o':
1088 case 'O':
1089 toggle = 0;
1090 switch (cmd_line[1]) {
1091 case 'n':
1092 case 'N':
1093 old_quiet_mode = 1;
1094 break;
1095 default:
1096 old_quiet_mode = 0;
1097 }
1098 break;
1099 default:
1100 printf("syntax: quiet [on|off]\n");
1101 return;
1102 }
1103 }
1104
1105 if (toggle)
1106 old_quiet_mode = 1 - old_quiet_mode;
1107
1108 printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
1109 if (old_quiet_mode != previous_mode)
1110 printf(" (was: %s)", previous_mode? "ON" : "OFF");
1111 printf("\n");
1112 }
1113
1114
1115 /*
1116 * debugger_cmd_quit():
1117 */
1118 static void debugger_cmd_quit(struct machine *m, char *cmd_line)
1119 {
1120 int i, j, k;
1121 struct emul *e;
1122
1123 if (*cmd_line) {
1124 printf("syntax: quit\n");
1125 return;
1126 }
1127
1128 for (i=0; i<debugger_n_emuls; i++) {
1129 single_step = 0;
1130
1131 e = debugger_emuls[i];
1132 force_debugger_at_exit = 0;
1133
1134 for (j=0; j<e->n_machines; j++) {
1135 struct machine *m = e->machines[j];
1136
1137 for (k=0; k<m->ncpus; k++)
1138 m->cpus[k]->running = 0;
1139
1140 m->exit_without_entering_debugger = 1;
1141 }
1142 }
1143
1144 exit_debugger = 1;
1145 }
1146
1147
1148 /*
1149 * debugger_cmd_reg():
1150 */
1151 static void debugger_cmd_reg(struct machine *m, char *cmd_line)
1152 {
1153 int i, cpuid = -1, coprocnr = -1;
1154 int gprs, coprocs;
1155 char *p;
1156
1157 /* [cpuid][,c] */
1158 if (cmd_line[0] != '\0') {
1159 if (cmd_line[0] != ',') {
1160 cpuid = strtoull(cmd_line, NULL, 0);
1161 if (cpuid < 0 || cpuid >= m->ncpus) {
1162 printf("cpu%i doesn't exist.\n", cpuid);
1163 return;
1164 }
1165 }
1166 p = strchr(cmd_line, ',');
1167 if (p != NULL) {
1168 coprocnr = atoi(p + 1);
1169 if (coprocnr < 0 || coprocnr >= 4) {
1170 printf("Invalid coprocessor number.\n");
1171 return;
1172 }
1173 }
1174 }
1175
1176 gprs = (coprocnr == -1)? 1 : 0;
1177 coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
1178
1179 for (i=0; i<m->ncpus; i++)
1180 if (cpuid == -1 || i == cpuid)
1181 cpu_register_dump(m, m->cpus[i], gprs, coprocs);
1182 }
1183
1184
1185 /*
1186 * debugger_cmd_step():
1187 */
1188 static void debugger_cmd_step(struct machine *m, char *cmd_line)
1189 {
1190 int n = 1;
1191
1192 if (cmd_line[0] != '\0') {
1193 n = strtoull(cmd_line, NULL, 0);
1194 if (n < 1) {
1195 printf("invalid nr of steps\n");
1196 return;
1197 }
1198 }
1199
1200 n_steps_left_before_interaction = n - 1;
1201
1202 /* Special hack, see debugger() for more info. */
1203 exit_debugger = -1;
1204
1205 strcpy(repeat_cmd, "step");
1206 }
1207
1208
1209 /*
1210 * debugger_cmd_tlbdump():
1211 *
1212 * Dump each CPU's TLB contents.
1213 */
1214 static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
1215 {
1216 int x = -1;
1217 int rawflag = 0;
1218
1219 if (cmd_line[0] != '\0') {
1220 char *p;
1221 if (cmd_line[0] != ',') {
1222 x = strtoull(cmd_line, NULL, 0);
1223 if (x < 0 || x >= m->ncpus) {
1224 printf("cpu%i doesn't exist.\n", x);
1225 return;
1226 }
1227 }
1228 p = strchr(cmd_line, ',');
1229 if (p != NULL) {
1230 switch (p[1]) {
1231 case 'r':
1232 case 'R':
1233 rawflag = 1;
1234 break;
1235 default:
1236 printf("Unknown tlbdump flag.\n");
1237 printf("syntax: tlbdump [cpuid][,r]\n");
1238 return;
1239 }
1240 }
1241 }
1242
1243 cpu_tlbdump(m, x, rawflag);
1244 }
1245
1246
1247 /*
1248 * debugger_cmd_trace():
1249 */
1250 static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1251 {
1252 if (*cmd_line) {
1253 printf("syntax: trace\n");
1254 return;
1255 }
1256
1257 old_show_trace_tree = 1 - old_show_trace_tree;
1258 printf("show_trace_tree = %s\n", old_show_trace_tree? "ON" : "OFF");
1259
1260 if (m->bintrans_enable && old_show_trace_tree)
1261 printf("NOTE: the trace tree functionality doesn't "
1262 "work very well with bintrans!\n");
1263
1264 /* TODO: how to preserve quiet_mode? */
1265 old_quiet_mode = 0;
1266 printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
1267 }
1268
1269
1270 /*
1271 * debugger_cmd_unassemble():
1272 *
1273 * Dump emulated memory as instructions.
1274 *
1275 * syntax: unassemble [addr [endaddr]]
1276 */
1277 static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1278 {
1279 uint64_t addr, addr_start, addr_end;
1280 struct cpu *c;
1281 struct memory *mem;
1282 char *p = NULL;
1283 int r, lines_left = -1;
1284
1285 if (cmd_line[0] != '\0') {
1286 uint64_t tmp;
1287 char *tmps = strdup(cmd_line);
1288
1289 /* addr: */
1290 p = strchr(tmps, ' ');
1291 if (p != NULL)
1292 *p = '\0';
1293 r = debugger_parse_name(m, tmps, 0, &tmp);
1294 free(tmps);
1295
1296 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1297 printf("Unparsable address: %s\n", cmd_line);
1298 return;
1299 } else {
1300 last_unasm_addr = tmp;
1301 }
1302
1303 p = strchr(cmd_line, ' ');
1304 }
1305
1306 addr_start = last_unasm_addr;
1307
1308 if (addr_start == MAGIC_UNTOUCHED) {
1309 uint64_t tmp;
1310 int match_register = 0;
1311 cpu_register_match(m, "pc", 0, &tmp, &match_register);
1312 if (match_register) {
1313 addr_start = tmp;
1314 } else {
1315 printf("No starting address.\n");
1316 return;
1317 }
1318 }
1319
1320 addr_end = addr_start + 1000;
1321
1322 /* endaddr: */
1323 if (p != NULL) {
1324 while (*p == ' ' && *p)
1325 p++;
1326 r = debugger_parse_name(m, p, 0, &addr_end);
1327 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1328 printf("Unparsable address: %s\n", cmd_line);
1329 return;
1330 }
1331 } else
1332 lines_left = 20;
1333
1334 if (m->cpus == NULL) {
1335 printf("No cpus (?)\n");
1336 return;
1337 }
1338 c = m->cpus[m->bootstrap_cpu];
1339 if (c == NULL) {
1340 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1341 return;
1342 }
1343 mem = m->cpus[m->bootstrap_cpu]->mem;
1344
1345 addr = addr_start;
1346
1347 if ((addr & 3) != 0)
1348 printf("WARNING! You entered an unaligned address.\n");
1349
1350 ctrl_c = 0;
1351
1352 while (addr < addr_end) {
1353 int i, len;
1354 unsigned char buf[25]; /* TODO: How long can an
1355 instruction be, on weird archs? */
1356 memset(buf, 0, sizeof(buf));
1357
1358 for (i=0; i<sizeof(buf); i++)
1359 c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1360 CACHE_NONE | NO_EXCEPTIONS);
1361
1362 len = cpu_disassemble_instr(m, c, buf, 0, addr, 0);
1363
1364 if (ctrl_c)
1365 return;
1366 if (len == 0)
1367 break;
1368
1369 addr += len;
1370
1371 if (lines_left != -1) {
1372 lines_left --;
1373 if (lines_left == 0)
1374 break;
1375 }
1376 }
1377
1378 last_unasm_addr = addr;
1379
1380 strcpy(repeat_cmd, "unassemble");
1381 }
1382
1383
1384 /*
1385 * debugger_cmd_version():
1386 */
1387 static void debugger_cmd_version(struct machine *m, char *cmd_line)
1388 {
1389 if (*cmd_line) {
1390 printf("syntax: version\n");
1391 return;
1392 }
1393
1394 #ifdef VERSION
1395 printf("%s, %s\n", VERSION, COMPILE_DATE);
1396 #else
1397 printf("(no version), %s\n", COMPILE_DATE);
1398 #endif
1399 }
1400
1401
1402 struct cmd {
1403 char *name;
1404 char *args;
1405 int tmp_flag;
1406 void (*f)(struct machine *, char *cmd_line);
1407 char *description;
1408 };
1409
1410 static struct cmd cmds[] = {
1411 { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1412 "manipulate breakpoints" },
1413
1414 { "bintrans", "[on|off]", 0, debugger_cmd_bintrans,
1415 "toggle bintrans on or off" },
1416
1417 /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1418 available as a one-letter command is very convenient. */
1419
1420 { "continue", "", 0, debugger_cmd_continue,
1421 "continue execution" },
1422
1423 { "device", "...", 0, debugger_cmd_device,
1424 "show info about (or manipulate) devices" },
1425
1426 { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1427 "dump memory contents in hex and ASCII" },
1428
1429 { "emuls", "", 0, debugger_cmd_emuls,
1430 "print a summary of all current emuls" },
1431
1432 { "focus", "x[,y]", 0, debugger_cmd_focus,
1433 "changes focus to machine x (in emul y)" },
1434
1435 { "help", "", 0, debugger_cmd_help,
1436 "print this help message" },
1437
1438 { "itrace", "", 0, debugger_cmd_itrace,
1439 "toggle instruction_trace on or off" },
1440
1441 { "lookup", "name|addr", 0, debugger_cmd_lookup,
1442 "lookup a symbol by name or address" },
1443
1444 { "machine", "", 0, debugger_cmd_machine,
1445 "print a summary of the current machine" },
1446
1447 { "opcodestats", "", 0, debugger_cmd_opcodestats,
1448 "show opcode statistics" },
1449
1450 { "pause", "cpuid", 0, debugger_cmd_pause,
1451 "pause (or unpause) a CPU" },
1452
1453 { "print", "expr", 0, debugger_cmd_print,
1454 "evaluate an expression without side-effects" },
1455
1456 { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1457 "modify emulated memory contents" },
1458
1459 { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1460 "toggle quiet_mode on or off" },
1461
1462 { "quit", "", 0, debugger_cmd_quit,
1463 "quit the emulator" },
1464
1465 { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1466 "show GPRs (or coprocessor c's registers)" },
1467
1468 /* NOTE: Try to keep 's' down to only one command. Having 'step'
1469 available as a one-letter command is very convenient. */
1470
1471 { "step", "[n]", 0, debugger_cmd_step,
1472 "single-step one (or n) instruction(s)" },
1473
1474 { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1475 "dump TLB contents (add ',r' for raw data)" },
1476
1477 { "trace", "", 0, debugger_cmd_trace,
1478 "toggle show_trace_tree on or off" },
1479
1480 { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1481 "dump memory contents as instructions" },
1482
1483 { "version", "", 0, debugger_cmd_version,
1484 "print version information" },
1485
1486 { NULL, NULL, 0, NULL, NULL }
1487 };
1488
1489
1490 /*
1491 * debugger_cmd_help():
1492 *
1493 * Print a list of available commands.
1494 *
1495 * NOTE: This is placed after the cmds[] array, because it needs to
1496 * access it.
1497 */
1498 static void debugger_cmd_help(struct machine *m, char *cmd_line)
1499 {
1500 int i, j, max_name_len = 0;
1501
1502 i = 0;
1503 while (cmds[i].name != NULL) {
1504 int a = strlen(cmds[i].name);
1505 if (cmds[i].args != NULL)
1506 a += 1 + strlen(cmds[i].args);
1507 if (a > max_name_len)
1508 max_name_len = a;
1509 i++;
1510 }
1511
1512 printf("Available commands:\n");
1513
1514 i = 0;
1515 while (cmds[i].name != NULL) {
1516 char buf[100];
1517 snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1518 if (cmds[i].args != NULL)
1519 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1520 " %s", cmds[i].args);
1521
1522 printf(" ");
1523 for (j=0; j<max_name_len; j++)
1524 if (j < strlen(buf))
1525 printf("%c", buf[j]);
1526 else
1527 printf(" ");
1528
1529 printf(" %s\n", cmds[i].description);
1530 i++;
1531 }
1532
1533 printf("Generic assignments: x = expr\n");
1534 printf("where x must be a register, and expr can be a register, a "
1535 "numeric value, or\na symbol name (+ an optional numeric offset)."
1536 " In case there are multiple\nmatches (ie a symbol that has the "
1537 "same name as a register), you may add a\nprefix character as a "
1538 "hint: '%%' for registers, '@' for symbols, and\n'$' for numeric"
1539 " values. Use 0x for hexadecimal values.\n");
1540 }
1541
1542
1543 /****************************************************************************/
1544
1545
1546 /*
1547 * debugger_assignment():
1548 *
1549 * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
1550 */
1551 void debugger_assignment(struct machine *m, char *cmd)
1552 {
1553 char *left, *right;
1554 int res_left, res_right;
1555 uint64_t tmp;
1556
1557 left = malloc(strlen(cmd) + 1);
1558 if (left == NULL) {
1559 fprintf(stderr, "out of memory in debugger_assignment()\n");
1560 exit(1);
1561 }
1562 strcpy(left, cmd);
1563 right = strchr(left, '=');
1564 if (right == NULL) {
1565 fprintf(stderr, "internal error in the debugger\n");
1566 exit(1);
1567 }
1568 *right = '\0';
1569
1570 /* Remove trailing spaces in left: */
1571 while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
1572 left[strlen(left)-1] = '\0';
1573
1574 /* Remove leading spaces in right: */
1575 right++;
1576 while (*right == ' ' && *right != '\0')
1577 right++;
1578
1579 /* printf("left = '%s'\nright = '%s'\n", left, right); */
1580
1581 res_right = debugger_parse_name(m, right, 0, &tmp);
1582 switch (res_right) {
1583 case NAME_PARSE_NOMATCH:
1584 printf("No match for the right-hand side of the assignment.\n");
1585 break;
1586 case NAME_PARSE_MULTIPLE:
1587 printf("Multiple matches for the right-hand side of the "
1588 "assignment.\n");
1589 break;
1590 default:
1591 res_left = debugger_parse_name(m, left, 1, &tmp);
1592 switch (res_left) {
1593 case NAME_PARSE_NOMATCH:
1594 printf("No match for the left-hand side of the "
1595 "assignment.\n");
1596 break;
1597 case NAME_PARSE_MULTIPLE:
1598 printf("Multiple matches for the left-hand side "
1599 "of the assignment.\n");
1600 break;
1601 default:
1602 debugger_cmd_print(m, left);
1603 }
1604 }
1605
1606 free(left);
1607 }
1608
1609
1610 /*
1611 * debugger_readline():
1612 *
1613 * Read a line from the terminal.
1614 */
1615 static char *debugger_readline(void)
1616 {
1617 int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
1618 int read_from_index = last_cmd_index;
1619 char *cmd = last_cmd[last_cmd_index];
1620
1621 cmd_len = 0; cmd[0] = '\0';
1622 printf("GXemul> ");
1623 fflush(stdout);
1624
1625 ch = '\0';
1626 cmd_len = 0;
1627 cursor_pos = 0;
1628
1629 while (ch != '\n') {
1630 /*
1631 * TODO: This uses up 100% CPU, maybe that isn't too good.
1632 * The usleep() call might make it a tiny bit nicer on other
1633 * running processes, but it is still very ugly.
1634 */
1635 while ((ch = console_readchar(MAIN_CONSOLE)) < 0) {
1636 x11_check_event(debugger_emuls, debugger_n_emuls);
1637 usleep(2);
1638 }
1639
1640 if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
1641 /* Backspace. */
1642 cursor_pos --;
1643 cmd_len --;
1644 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1645 cmd_len);
1646 cmd[cmd_len] = '\0';
1647 printf("\b");
1648 for (i=cursor_pos; i<cmd_len; i++)
1649 printf("%c", cmd[i]);
1650 printf(" \b");
1651 for (i=cursor_pos; i<cmd_len; i++)
1652 printf("\b");
1653 } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
1654 /* CTRL-D: Delete. */
1655 cmd_len --;
1656 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1657 cmd_len);
1658 cmd[cmd_len] = '\0';
1659 for (i=cursor_pos; i<cmd_len; i++)
1660 printf("%c", cmd[i]);
1661 printf(" \b");
1662 for (i=cursor_pos; i<cmd_len; i++)
1663 printf("\b");
1664 } else if (ch == 1) {
1665 /* CTRL-A: Start of line. */
1666 while (cursor_pos > 0) {
1667 cursor_pos --;
1668 printf("\b");
1669 }
1670 } else if (ch == 2) {
1671 /* CTRL-B: Backwards one character. */
1672 if (cursor_pos > 0) {
1673 printf("\b");
1674 cursor_pos --;
1675 }
1676 } else if (ch == 5) {
1677 /* CTRL-E: End of line. */
1678 while (cursor_pos < cmd_len) {
1679 printf("%c", cmd[cursor_pos]);
1680 cursor_pos ++;
1681 }
1682 } else if (ch == 6) {
1683 /* CTRL-F: Forward one character. */
1684 if (cursor_pos < cmd_len) {
1685 printf("%c",
1686 cmd[cursor_pos]);
1687 cursor_pos ++;
1688 }
1689 } else if (ch == 11) {
1690 /* CTRL-K: Kill to end of line. */
1691 for (i=0; i<MAX_CMD_LEN; i++)
1692 console_makeavail(MAIN_CONSOLE, 4); /* :-) */
1693 } else if (ch == 14 || ch == 16) {
1694 /* CTRL-P: Previous line in the command history,
1695 CTRL-N: next line */
1696 do {
1697 if (ch == 14 &&
1698 read_from_index == last_cmd_index)
1699 break;
1700 if (ch == 16)
1701 i = read_from_index - 1;
1702 else
1703 i = read_from_index + 1;
1704
1705 if (i < 0)
1706 i = N_PREVIOUS_CMDS - 1;
1707 if (i >= N_PREVIOUS_CMDS)
1708 i = 0;
1709
1710 /* Special case: pressing 'down'
1711 to reach last_cmd_index: */
1712 if (i == last_cmd_index) {
1713 read_from_index = i;
1714 for (i=cursor_pos; i<cmd_len;
1715 i++)
1716 printf(" ");
1717 for (i=cmd_len-1; i>=0; i--)
1718 printf("\b \b");
1719 cmd[0] = '\0';
1720 cmd_len = cursor_pos = 0;
1721 } else if (last_cmd[i][0] != '\0') {
1722 /* Copy from old line: */
1723 read_from_index = i;
1724 for (i=cursor_pos; i<cmd_len;
1725 i++)
1726 printf(" ");
1727 for (i=cmd_len-1; i>=0; i--)
1728 printf("\b \b");
1729 strcpy(cmd,
1730 last_cmd[read_from_index]);
1731 cmd_len = strlen(cmd);
1732 printf("%s", cmd);
1733 cursor_pos = cmd_len;
1734 }
1735 } while (0);
1736 } else if (ch >= ' ' && cmd_len < MAX_CMD_LEN) {
1737 /* Visible character: */
1738 memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
1739 cmd_len - cursor_pos);
1740 cmd[cursor_pos] = ch;
1741 cmd_len ++;
1742 cursor_pos ++;
1743 cmd[cmd_len] = '\0';
1744 printf("%c", ch);
1745 for (i=cursor_pos; i<cmd_len; i++)
1746 printf("%c", cmd[i]);
1747 for (i=cursor_pos; i<cmd_len; i++)
1748 printf("\b");
1749 } else if (ch == '\r' || ch == '\n') {
1750 ch = '\n';
1751 printf("\n");
1752 } else if (ch == '\t') {
1753 /* Super-simple tab-completion: */
1754 i = 0;
1755 while (cmds[i].name != NULL)
1756 cmds[i++].tmp_flag = 0;
1757
1758 /* Check for a (partial) command match: */
1759 n = i = i_match = 0;
1760 while (cmds[i].name != NULL) {
1761 if (strncasecmp(cmds[i].name, cmd,
1762 cmd_len) == 0) {
1763 cmds[i].tmp_flag = 1;
1764 i_match = i;
1765 n++;
1766 }
1767 i++;
1768 }
1769
1770 switch (n) {
1771 case 0: /* Beep. */
1772 printf("\a");
1773 break;
1774 case 1: /* Add the rest of the command: */
1775 reallen = strlen(cmds[i_match].name);
1776 for (i=cmd_len; i<reallen; i++)
1777 console_makeavail(MAIN_CONSOLE,
1778 cmds[i_match].name[i]);
1779 /* ... and a space, if the command takes
1780 any arguments: */
1781 if (cmds[i_match].args != NULL &&
1782 cmds[i_match].args[0] != '\0')
1783 console_makeavail(MAIN_CONSOLE, ' ');
1784 break;
1785 default:
1786 /* Show all possible commands: */
1787 printf("\a\n"); /* Beep. :-) */
1788 i = 0; /* i = cmds index */
1789 j = 0; /* j = # of cmds printed */
1790 while (cmds[i].name != NULL) {
1791 if (cmds[i].tmp_flag) {
1792 int q;
1793 if (j == 0)
1794 printf(" ");
1795 printf("%s",
1796 cmds[i].name);
1797 j++;
1798 if (j != 6)
1799 for (q=0; q<13-strlen(
1800 cmds[i].name); q++)
1801 printf(" ");
1802 if (j == 6) {
1803 printf("\n");
1804 j = 0;
1805 }
1806 }
1807 i++;
1808 }
1809 if (j != 0)
1810 printf("\n");
1811 printf("GXemul> ");
1812 for (i=0; i<cmd_len; i++)
1813 printf("%c", cmd[i]);
1814 }
1815 } else if (ch == 27) {
1816 /* Escape codes: (cursor keys etc) */
1817 while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
1818 usleep(1);
1819 if (ch == '[' || ch == 'O') {
1820 while ((ch = console_readchar(MAIN_CONSOLE))
1821 < 0)
1822 usleep(1);
1823 switch (ch) {
1824 case '2': /* 2~ = ins */
1825 case '5': /* 5~ = pgup */
1826 case '6': /* 6~ = pgdn */
1827 /* TODO: Ugly hack, but might work. */
1828 while ((ch = console_readchar(
1829 MAIN_CONSOLE)) < 0)
1830 usleep(1);
1831 /* Do nothing for these keys. */
1832 break;
1833 case '3': /* 3~ = delete */
1834 /* TODO: Ugly hack, but might work. */
1835 while ((ch = console_readchar(
1836 MAIN_CONSOLE)) < 0)
1837 usleep(1);
1838 console_makeavail(MAIN_CONSOLE, '\b');
1839 break;
1840 case 'A': /* Up. */
1841 /* Up cursor ==> CTRL-P */
1842 console_makeavail(MAIN_CONSOLE, 16);
1843 break;
1844 case 'B': /* Down. */
1845 /* Down cursor ==> CTRL-N */
1846 console_makeavail(MAIN_CONSOLE, 14);
1847 break;
1848 case 'C':
1849 /* Right cursor ==> CTRL-F */
1850 console_makeavail(MAIN_CONSOLE, 6);
1851 break;
1852 case 'D': /* Left */
1853 /* Left cursor ==> CTRL-B */
1854 console_makeavail(MAIN_CONSOLE, 2);
1855 break;
1856 case 'F':
1857 /* End ==> CTRL-E */
1858 console_makeavail(MAIN_CONSOLE, 5);
1859 break;
1860 case 'H':
1861 /* Home ==> CTRL-A */
1862 console_makeavail(MAIN_CONSOLE, 1);
1863 break;
1864 }
1865 }
1866 }
1867
1868 fflush(stdout);
1869 }
1870
1871 return cmd;
1872 }
1873
1874
1875 /*
1876 * debugger():
1877 *
1878 * This is a loop, which reads a command from the terminal, and executes it.
1879 */
1880 void debugger(void)
1881 {
1882 int i, n, i_match, matchlen, cmd_len;
1883 char *cmd;
1884
1885 if (n_steps_left_before_interaction > 0) {
1886 n_steps_left_before_interaction --;
1887 return;
1888 }
1889
1890 exit_debugger = 0;
1891
1892 while (!exit_debugger) {
1893 /* Read a line from the terminal: */
1894 cmd = debugger_readline();
1895 cmd_len = strlen(cmd);
1896
1897 /* Remove spaces: */
1898 while (cmd_len > 0 && cmd[0]==' ')
1899 memmove(cmd, cmd+1, cmd_len --);
1900 while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
1901 cmd[(cmd_len--)-1] = '\0';
1902
1903 /* No command? Then try reading another line. */
1904 if (cmd_len == 0) {
1905 /* Special case for repeated commands: */
1906 if (repeat_cmd[0] != '\0')
1907 strcpy(cmd, repeat_cmd);
1908 else
1909 continue;
1910 } else {
1911 last_cmd_index ++;
1912 if (last_cmd_index >= N_PREVIOUS_CMDS)
1913 last_cmd_index = 0;
1914
1915 repeat_cmd[0] = '\0';
1916 }
1917
1918 /*
1919 * Is there a '=' on the command line? Then try to do an
1920 * assignment. (Only if there is just one word, followed
1921 * by the '=' sign. This makes it possible to use commands
1922 * such as "device add name addr=xyz".)
1923 */
1924 if (strchr(cmd, '=') != NULL) {
1925 /* Count the nr of words: */
1926 int nw = 0, inword = 0;
1927 char *p = cmd;
1928 while (*p) {
1929 if (*p == '=')
1930 break;
1931 if (*p != ' ') {
1932 if (!inword)
1933 nw ++;
1934 inword = 1;
1935 } else
1936 inword = 0;
1937 p++;
1938 }
1939
1940 if (nw == 1) {
1941 debugger_assignment(debugger_machine, cmd);
1942 continue;
1943 }
1944 }
1945
1946 i = 0;
1947 while (cmds[i].name != NULL)
1948 cmds[i++].tmp_flag = 0;
1949
1950 /* How many chars in cmd to match against: */
1951 matchlen = 0;
1952 while (isalpha((int)cmd[matchlen]))
1953 matchlen ++;
1954
1955 /* Check for a command name match: */
1956 n = i = i_match = 0;
1957 while (cmds[i].name != NULL) {
1958 if (strncasecmp(cmds[i].name, cmd, matchlen) == 0) {
1959 cmds[i].tmp_flag = 1;
1960 i_match = i;
1961 n++;
1962 }
1963 i++;
1964 }
1965
1966 /* No match? */
1967 if (n == 0) {
1968 printf("Unknown command '%s'. "
1969 "Type 'help' for help.\n", cmd);
1970 continue;
1971 }
1972
1973 /* More than one match? */
1974 if (n > 1) {
1975 printf("Ambiguous command '%s': ", cmd);
1976 i = 0;
1977 while (cmds[i].name != NULL) {
1978 if (cmds[i].tmp_flag)
1979 printf(" %s", cmds[i].name);
1980 i++;
1981 }
1982 printf("\n");
1983 continue;
1984 }
1985
1986 /* Exactly one match: */
1987 if (cmds[i_match].f != NULL) {
1988 char *p = cmd + matchlen;
1989 /* Remove leading whitespace from the args... */
1990 while (*p != '\0' && *p == ' ')
1991 p++;
1992
1993 /* ... and run the command: */
1994 cmds[i_match].f(debugger_machine, p);
1995 } else
1996 printf("FATAL ERROR: internal error in debugger.c:"
1997 " no handler for this command?\n");
1998
1999 /* Special hack for the "step" command: */
2000 if (exit_debugger == -1)
2001 return;
2002 }
2003
2004 single_step = 0;
2005 debugger_machine->instruction_trace = old_instruction_trace;
2006 debugger_machine->show_trace_tree = old_show_trace_tree;
2007 quiet_mode = old_quiet_mode;
2008 }
2009
2010
2011 /*
2012 * debugger_reset():
2013 *
2014 * This function should be called before calling debugger(), when it is
2015 * absolutely necessary that debugger() is interactive. Otherwise, it might
2016 * return without doing anything, such as when single-stepping multiple
2017 * instructions at a time.
2018 */
2019 void debugger_reset(void)
2020 {
2021 n_steps_left_before_interaction = 0;
2022 }
2023
2024
2025 /*
2026 * debugger_init():
2027 *
2028 * Must be called before any other debugger function is used.
2029 */
2030 void debugger_init(struct emul **emuls, int n_emuls)
2031 {
2032 int i;
2033
2034 debugger_n_emuls = n_emuls;
2035 debugger_emuls = emuls;
2036
2037 if (n_emuls < 1) {
2038 fprintf(stderr, "\nERROR: No emuls (?)\n");
2039 exit(1);
2040 }
2041
2042 debugger_emul = emuls[0];
2043 if (emuls[0]->n_machines < 1) {
2044 fprintf(stderr, "\nERROR: No machines in emuls[0], "
2045 "cannot handle this situation yet.\n\n");
2046 exit(1);
2047 }
2048
2049 debugger_machine = emuls[0]->machines[0];
2050
2051 for (i=0; i<N_PREVIOUS_CMDS; i++) {
2052 last_cmd[i] = malloc(MAX_CMD_LEN + 1);
2053 if (last_cmd[i] == NULL) {
2054 fprintf(stderr, "debugger_init(): out of memory\n");
2055 exit(1);
2056 }
2057 last_cmd[i][0] = '\0';
2058 }
2059
2060 last_cmd_index = 0;
2061 repeat_cmd[0] = '\0';
2062 }
2063

  ViewVC Help
Powered by ViewVC 1.1.26