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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26