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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26