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

Contents of /upstream/0.3.3.1/src/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Mon Oct 8 16:18:14 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 47221 byte(s)
0.3.3.1
1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: debugger.c,v 1.103 2005/05/13 14:26:29 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 printf("%s = 0x%llx\n", cmd_line, (long long)tmp);
908 break;
909 case NAME_PARSE_SYMBOL:
910 printf("%s = 0x%016llx\n", cmd_line, (long long)tmp);
911 break;
912 case NAME_PARSE_NUMBER:
913 printf("0x%llx\n", (long long)tmp);
914 break;
915 }
916 }
917
918
919 /*
920 * debugger_cmd_put():
921 */
922 static void debugger_cmd_put(struct machine *m, char *cmd_line)
923 {
924 static char put_type = ' '; /* Remembered across multiple calls. */
925 char copy[200];
926 int res, syntax_ok = 0;
927 char *p, *p2, *q = NULL;
928 uint64_t addr, data;
929 unsigned char a_byte;
930
931 strncpy(copy, cmd_line, sizeof(copy));
932 copy[sizeof(copy)-1] = '\0';
933
934 /* syntax: put [b|h|w|d|q] addr, data */
935
936 p = strchr(copy, ',');
937 if (p != NULL) {
938 *p++ = '\0';
939 while (*p == ' ' && *p)
940 p++;
941 while (strlen(copy) >= 1 &&
942 copy[strlen(copy) - 1] == ' ')
943 copy[strlen(copy) - 1] = '\0';
944
945 /* printf("L = '%s', R = '%s'\n", copy, p); */
946
947 q = copy;
948 p2 = strchr(q, ' ');
949
950 if (p2 != NULL) {
951 *p2 = '\0';
952 if (strlen(q) != 1) {
953 printf("Invalid type '%s'\n", q);
954 return;
955 }
956 put_type = *q;
957 q = p2 + 1;
958 }
959
960 /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
961 syntax_ok = 1;
962 }
963
964 if (!syntax_ok) {
965 printf("syntax: put [b|h|w|d|q] addr, data\n");
966 printf(" b byte (8 bits)\n");
967 printf(" h half-word (16 bits)\n");
968 printf(" w word (32 bits)\n");
969 printf(" d doubleword (64 bits)\n");
970 printf(" q quad-word (128 bits)\n");
971 return;
972 }
973
974 if (put_type == ' ') {
975 printf("No type specified.\n");
976 return;
977 }
978
979 /* here: q is the address, p is the data. */
980
981 res = debugger_parse_name(m, q, 0, &addr);
982 switch (res) {
983 case NAME_PARSE_NOMATCH:
984 printf("Couldn't parse the address.\n");
985 return;
986 case NAME_PARSE_MULTIPLE:
987 printf("Multiple matches for the address."
988 " Try prefixing with %%, $, or @.\n");
989 return;
990 case NAME_PARSE_REGISTER:
991 case NAME_PARSE_SYMBOL:
992 case NAME_PARSE_NUMBER:
993 break;
994 default:
995 printf("INTERNAL ERROR in debugger.c.\n");
996 return;
997 }
998
999 res = debugger_parse_name(m, p, 0, &data);
1000 switch (res) {
1001 case NAME_PARSE_NOMATCH:
1002 printf("Couldn't parse the data.\n");
1003 return;
1004 case NAME_PARSE_MULTIPLE:
1005 printf("Multiple matches for the data value."
1006 " Try prefixing with %%, $, or @.\n");
1007 return;
1008 case NAME_PARSE_REGISTER:
1009 case NAME_PARSE_SYMBOL:
1010 case NAME_PARSE_NUMBER:
1011 break;
1012 default:
1013 printf("INTERNAL ERROR in debugger.c.\n");
1014 return;
1015 }
1016
1017 /* TODO: haha, maybe this should be refactored */
1018
1019 switch (put_type) {
1020 case 'b':
1021 a_byte = data;
1022 printf("0x%016llx: %02x", (long long)addr, a_byte);
1023 if (data > 255)
1024 printf(" (NOTE: truncating %0llx)", (long long)data);
1025 res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
1026 &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
1027 if (!res)
1028 printf(" FAILED!\n");
1029 printf("\n");
1030 return;
1031 case 'h':
1032 if ((data & 1) != 0)
1033 printf("WARNING: address isn't aligned\n");
1034 printf("0x%016llx: %04x", (long long)addr, (int)data);
1035 if (data > 0xffff)
1036 printf(" (NOTE: truncating %0llx)", (long long)data);
1037 res = store_16bit_word(m->cpus[0], addr, data);
1038 if (!res)
1039 printf(" FAILED!\n");
1040 printf("\n");
1041 return;
1042 case 'w':
1043 if ((data & 3) != 0)
1044 printf("WARNING: address isn't aligned\n");
1045 printf("0x%016llx: %08x", (long long)addr, (int)data);
1046 if (data > 0xffffffff && (data >> 32) != 0
1047 && (data >> 32) != 0xffffffff)
1048 printf(" (NOTE: truncating %0llx)", (long long)data);
1049 res = store_32bit_word(m->cpus[0], addr, data);
1050 if (!res)
1051 printf(" FAILED!\n");
1052 printf("\n");
1053 return;
1054 case 'd':
1055 if ((data & 7) != 0)
1056 printf("WARNING: address isn't aligned\n");
1057 printf("0x%016llx: %016llx", (long long)addr, (long long)data);
1058 res = store_64bit_word(m->cpus[0], addr, data);
1059 if (!res)
1060 printf(" FAILED!\n");
1061 printf("\n");
1062 return;
1063 case 'q':
1064 printf("quad-words: TODO\n");
1065 /* TODO */
1066 return;
1067 default:
1068 printf("Unimplemented type '%c'\n", put_type);
1069 return;
1070 }
1071 }
1072
1073
1074 /*
1075 * debugger_cmd_quiet():
1076 */
1077 static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
1078 {
1079 int toggle = 1;
1080 int previous_mode = old_quiet_mode;
1081
1082 if (cmd_line[0] != '\0') {
1083 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1084 cmd_line ++;
1085 switch (cmd_line[0]) {
1086 case '0':
1087 toggle = 0;
1088 old_quiet_mode = 0;
1089 break;
1090 case '1':
1091 toggle = 0;
1092 old_quiet_mode = 1;
1093 break;
1094 case 'o':
1095 case 'O':
1096 toggle = 0;
1097 switch (cmd_line[1]) {
1098 case 'n':
1099 case 'N':
1100 old_quiet_mode = 1;
1101 break;
1102 default:
1103 old_quiet_mode = 0;
1104 }
1105 break;
1106 default:
1107 printf("syntax: quiet [on|off]\n");
1108 return;
1109 }
1110 }
1111
1112 if (toggle)
1113 old_quiet_mode = 1 - old_quiet_mode;
1114
1115 printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
1116 if (old_quiet_mode != previous_mode)
1117 printf(" (was: %s)", previous_mode? "ON" : "OFF");
1118 printf("\n");
1119 }
1120
1121
1122 /*
1123 * debugger_cmd_quit():
1124 */
1125 static void debugger_cmd_quit(struct machine *m, char *cmd_line)
1126 {
1127 int i, j, k;
1128 struct emul *e;
1129
1130 if (*cmd_line) {
1131 printf("syntax: quit\n");
1132 return;
1133 }
1134
1135 for (i=0; i<debugger_n_emuls; i++) {
1136 single_step = 0;
1137
1138 e = debugger_emuls[i];
1139 force_debugger_at_exit = 0;
1140
1141 for (j=0; j<e->n_machines; j++) {
1142 struct machine *m = e->machines[j];
1143
1144 for (k=0; k<m->ncpus; k++)
1145 m->cpus[k]->running = 0;
1146
1147 m->exit_without_entering_debugger = 1;
1148 }
1149 }
1150
1151 exit_debugger = 1;
1152 }
1153
1154
1155 /*
1156 * debugger_cmd_reg():
1157 */
1158 static void debugger_cmd_reg(struct machine *m, char *cmd_line)
1159 {
1160 int i, cpuid = -1, coprocnr = -1;
1161 int gprs, coprocs;
1162 char *p;
1163
1164 /* [cpuid][,c] */
1165 if (cmd_line[0] != '\0') {
1166 if (cmd_line[0] != ',') {
1167 cpuid = strtoull(cmd_line, NULL, 0);
1168 if (cpuid < 0 || cpuid >= m->ncpus) {
1169 printf("cpu%i doesn't exist.\n", cpuid);
1170 return;
1171 }
1172 }
1173 p = strchr(cmd_line, ',');
1174 if (p != NULL) {
1175 coprocnr = atoi(p + 1);
1176 if (coprocnr < 0 || coprocnr >= 4) {
1177 printf("Invalid coprocessor number.\n");
1178 return;
1179 }
1180 }
1181 }
1182
1183 gprs = (coprocnr == -1)? 1 : 0;
1184 coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
1185
1186 for (i=0; i<m->ncpus; i++)
1187 if (cpuid == -1 || i == cpuid)
1188 cpu_register_dump(m, m->cpus[i], gprs, coprocs);
1189 }
1190
1191
1192 /*
1193 * debugger_cmd_step():
1194 */
1195 static void debugger_cmd_step(struct machine *m, char *cmd_line)
1196 {
1197 int n = 1;
1198
1199 if (cmd_line[0] != '\0') {
1200 n = strtoull(cmd_line, NULL, 0);
1201 if (n < 1) {
1202 printf("invalid nr of steps\n");
1203 return;
1204 }
1205 }
1206
1207 n_steps_left_before_interaction = n - 1;
1208
1209 /* Special hack, see debugger() for more info. */
1210 exit_debugger = -1;
1211
1212 strcpy(repeat_cmd, "step");
1213 }
1214
1215
1216 /*
1217 * debugger_cmd_tlbdump():
1218 *
1219 * Dump each CPU's TLB contents.
1220 */
1221 static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
1222 {
1223 int x = -1;
1224 int rawflag = 0;
1225
1226 if (cmd_line[0] != '\0') {
1227 char *p;
1228 if (cmd_line[0] != ',') {
1229 x = strtoull(cmd_line, NULL, 0);
1230 if (x < 0 || x >= m->ncpus) {
1231 printf("cpu%i doesn't exist.\n", x);
1232 return;
1233 }
1234 }
1235 p = strchr(cmd_line, ',');
1236 if (p != NULL) {
1237 switch (p[1]) {
1238 case 'r':
1239 case 'R':
1240 rawflag = 1;
1241 break;
1242 default:
1243 printf("Unknown tlbdump flag.\n");
1244 printf("syntax: tlbdump [cpuid][,r]\n");
1245 return;
1246 }
1247 }
1248 }
1249
1250 cpu_tlbdump(m, x, rawflag);
1251 }
1252
1253
1254 /*
1255 * debugger_cmd_trace():
1256 */
1257 static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1258 {
1259 if (*cmd_line) {
1260 printf("syntax: trace\n");
1261 return;
1262 }
1263
1264 old_show_trace_tree = 1 - old_show_trace_tree;
1265 printf("show_trace_tree = %s\n", old_show_trace_tree? "ON" : "OFF");
1266
1267 if (m->bintrans_enable && old_show_trace_tree)
1268 printf("NOTE: the trace tree functionality doesn't "
1269 "work very well with bintrans!\n");
1270
1271 /* TODO: how to preserve quiet_mode? */
1272 old_quiet_mode = 0;
1273 printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
1274 }
1275
1276
1277 /*
1278 * debugger_cmd_unassemble():
1279 *
1280 * Dump emulated memory as instructions.
1281 *
1282 * syntax: unassemble [addr [endaddr]]
1283 */
1284 static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1285 {
1286 uint64_t addr, addr_start, addr_end;
1287 struct cpu *c;
1288 struct memory *mem;
1289 char *p = NULL;
1290 int r, lines_left = -1;
1291
1292 if (cmd_line[0] != '\0') {
1293 uint64_t tmp;
1294 char *tmps = strdup(cmd_line);
1295
1296 /* addr: */
1297 p = strchr(tmps, ' ');
1298 if (p != NULL)
1299 *p = '\0';
1300 r = debugger_parse_name(m, tmps, 0, &tmp);
1301 free(tmps);
1302
1303 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1304 printf("Unparsable address: %s\n", cmd_line);
1305 return;
1306 } else {
1307 last_unasm_addr = tmp;
1308 }
1309
1310 p = strchr(cmd_line, ' ');
1311 }
1312
1313 addr_start = last_unasm_addr;
1314
1315 if (addr_start == MAGIC_UNTOUCHED) {
1316 uint64_t tmp;
1317 int match_register = 0;
1318 cpu_register_match(m, "pc", 0, &tmp, &match_register);
1319 if (match_register) {
1320 addr_start = tmp;
1321 } else {
1322 printf("No starting address.\n");
1323 return;
1324 }
1325 }
1326
1327 addr_end = addr_start + 1000;
1328
1329 /* endaddr: */
1330 if (p != NULL) {
1331 while (*p == ' ' && *p)
1332 p++;
1333 r = debugger_parse_name(m, p, 0, &addr_end);
1334 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1335 printf("Unparsable address: %s\n", cmd_line);
1336 return;
1337 }
1338 } else
1339 lines_left = 20;
1340
1341 if (m->cpus == NULL) {
1342 printf("No cpus (?)\n");
1343 return;
1344 }
1345 c = m->cpus[m->bootstrap_cpu];
1346 if (c == NULL) {
1347 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1348 return;
1349 }
1350 mem = m->cpus[m->bootstrap_cpu]->mem;
1351
1352 addr = addr_start;
1353
1354 ctrl_c = 0;
1355
1356 while (addr < addr_end) {
1357 int i, len;
1358 unsigned char buf[32]; /* TODO: How long can an
1359 instruction be, on weird archs? */
1360 memset(buf, 0, sizeof(buf));
1361
1362 for (i=0; i<sizeof(buf); i++)
1363 c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1364 CACHE_NONE | NO_EXCEPTIONS);
1365
1366 len = cpu_disassemble_instr(m, c, buf, 0, addr, 0);
1367
1368 if (ctrl_c)
1369 return;
1370 if (len == 0)
1371 break;
1372
1373 addr += len;
1374
1375 if (lines_left != -1) {
1376 lines_left --;
1377 if (lines_left == 0)
1378 break;
1379 }
1380 }
1381
1382 last_unasm_addr = addr;
1383
1384 strcpy(repeat_cmd, "unassemble");
1385 }
1386
1387
1388 /*
1389 * debugger_cmd_version():
1390 */
1391 static void debugger_cmd_version(struct machine *m, char *cmd_line)
1392 {
1393 if (*cmd_line) {
1394 printf("syntax: version\n");
1395 return;
1396 }
1397
1398 #ifdef VERSION
1399 printf("%s, %s\n", VERSION, COMPILE_DATE);
1400 #else
1401 printf("(no version), %s\n", COMPILE_DATE);
1402 #endif
1403 }
1404
1405
1406 struct cmd {
1407 char *name;
1408 char *args;
1409 int tmp_flag;
1410 void (*f)(struct machine *, char *cmd_line);
1411 char *description;
1412 };
1413
1414 static struct cmd cmds[] = {
1415 { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1416 "manipulate breakpoints" },
1417
1418 { "bintrans", "[on|off]", 0, debugger_cmd_bintrans,
1419 "toggle bintrans on or off" },
1420
1421 /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1422 available as a one-letter command is very convenient. */
1423
1424 { "continue", "", 0, debugger_cmd_continue,
1425 "continue execution" },
1426
1427 { "device", "...", 0, debugger_cmd_device,
1428 "show info about (or manipulate) devices" },
1429
1430 { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1431 "dump memory contents in hex and ASCII" },
1432
1433 { "emuls", "", 0, debugger_cmd_emuls,
1434 "print a summary of all current emuls" },
1435
1436 { "focus", "x[,y]", 0, debugger_cmd_focus,
1437 "changes focus to machine x (in emul y)" },
1438
1439 { "help", "", 0, debugger_cmd_help,
1440 "print this help message" },
1441
1442 { "itrace", "", 0, debugger_cmd_itrace,
1443 "toggle instruction_trace on or off" },
1444
1445 { "lookup", "name|addr", 0, debugger_cmd_lookup,
1446 "lookup a symbol by name or address" },
1447
1448 { "machine", "", 0, debugger_cmd_machine,
1449 "print a summary of the current machine" },
1450
1451 { "opcodestats", "", 0, debugger_cmd_opcodestats,
1452 "show opcode statistics" },
1453
1454 { "pause", "cpuid", 0, debugger_cmd_pause,
1455 "pause (or unpause) a CPU" },
1456
1457 { "print", "expr", 0, debugger_cmd_print,
1458 "evaluate an expression without side-effects" },
1459
1460 { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1461 "modify emulated memory contents" },
1462
1463 { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1464 "toggle quiet_mode on or off" },
1465
1466 { "quit", "", 0, debugger_cmd_quit,
1467 "quit the emulator" },
1468
1469 { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1470 "show GPRs (or coprocessor c's registers)" },
1471
1472 /* NOTE: Try to keep 's' down to only one command. Having 'step'
1473 available as a one-letter command is very convenient. */
1474
1475 { "step", "[n]", 0, debugger_cmd_step,
1476 "single-step one (or n) instruction(s)" },
1477
1478 { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1479 "dump TLB contents (add ',r' for raw data)" },
1480
1481 { "trace", "", 0, debugger_cmd_trace,
1482 "toggle show_trace_tree on or off" },
1483
1484 { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1485 "dump memory contents as instructions" },
1486
1487 { "version", "", 0, debugger_cmd_version,
1488 "print version information" },
1489
1490 { NULL, NULL, 0, NULL, NULL }
1491 };
1492
1493
1494 /*
1495 * debugger_cmd_help():
1496 *
1497 * Print a list of available commands.
1498 *
1499 * NOTE: This is placed after the cmds[] array, because it needs to
1500 * access it.
1501 */
1502 static void debugger_cmd_help(struct machine *m, char *cmd_line)
1503 {
1504 int i, j, max_name_len = 0;
1505
1506 i = 0;
1507 while (cmds[i].name != NULL) {
1508 int a = strlen(cmds[i].name);
1509 if (cmds[i].args != NULL)
1510 a += 1 + strlen(cmds[i].args);
1511 if (a > max_name_len)
1512 max_name_len = a;
1513 i++;
1514 }
1515
1516 printf("Available commands:\n");
1517
1518 i = 0;
1519 while (cmds[i].name != NULL) {
1520 char buf[100];
1521 snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1522 if (cmds[i].args != NULL)
1523 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1524 " %s", cmds[i].args);
1525
1526 printf(" ");
1527 for (j=0; j<max_name_len; j++)
1528 if (j < strlen(buf))
1529 printf("%c", buf[j]);
1530 else
1531 printf(" ");
1532
1533 printf(" %s\n", cmds[i].description);
1534 i++;
1535 }
1536
1537 printf("Generic assignments: x = expr\n");
1538 printf("where x must be a register, and expr can be a register, a "
1539 "numeric value, or\na symbol name (+ an optional numeric offset)."
1540 " In case there are multiple\nmatches (ie a symbol that has the "
1541 "same name as a register), you may add a\nprefix character as a "
1542 "hint: '%%' for registers, '@' for symbols, and\n'$' for numeric"
1543 " values. Use 0x for hexadecimal values.\n");
1544 }
1545
1546
1547 /****************************************************************************/
1548
1549
1550 /*
1551 * debugger_assignment():
1552 *
1553 * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
1554 */
1555 void debugger_assignment(struct machine *m, char *cmd)
1556 {
1557 char *left, *right;
1558 int res_left, res_right;
1559 uint64_t tmp;
1560
1561 left = malloc(strlen(cmd) + 1);
1562 if (left == NULL) {
1563 fprintf(stderr, "out of memory in debugger_assignment()\n");
1564 exit(1);
1565 }
1566 strcpy(left, cmd);
1567 right = strchr(left, '=');
1568 if (right == NULL) {
1569 fprintf(stderr, "internal error in the debugger\n");
1570 exit(1);
1571 }
1572 *right = '\0';
1573
1574 /* Remove trailing spaces in left: */
1575 while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
1576 left[strlen(left)-1] = '\0';
1577
1578 /* Remove leading spaces in right: */
1579 right++;
1580 while (*right == ' ' && *right != '\0')
1581 right++;
1582
1583 /* printf("left = '%s'\nright = '%s'\n", left, right); */
1584
1585 res_right = debugger_parse_name(m, right, 0, &tmp);
1586 switch (res_right) {
1587 case NAME_PARSE_NOMATCH:
1588 printf("No match for the right-hand side of the assignment.\n");
1589 break;
1590 case NAME_PARSE_MULTIPLE:
1591 printf("Multiple matches for the right-hand side of the "
1592 "assignment.\n");
1593 break;
1594 default:
1595 res_left = debugger_parse_name(m, left, 1, &tmp);
1596 switch (res_left) {
1597 case NAME_PARSE_NOMATCH:
1598 printf("No match for the left-hand side of the "
1599 "assignment.\n");
1600 break;
1601 case NAME_PARSE_MULTIPLE:
1602 printf("Multiple matches for the left-hand side "
1603 "of the assignment.\n");
1604 break;
1605 default:
1606 debugger_cmd_print(m, left);
1607 }
1608 }
1609
1610 free(left);
1611 }
1612
1613
1614 /*
1615 * debugger_readline():
1616 *
1617 * Read a line from the terminal.
1618 */
1619 static char *debugger_readline(void)
1620 {
1621 int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
1622 int read_from_index = last_cmd_index;
1623 char *cmd = last_cmd[last_cmd_index];
1624
1625 cmd_len = 0; cmd[0] = '\0';
1626 printf("GXemul> ");
1627 fflush(stdout);
1628
1629 ch = '\0';
1630 cmd_len = 0;
1631 cursor_pos = 0;
1632
1633 while (ch != '\n') {
1634 /*
1635 * TODO: This uses up 100% CPU, maybe that isn't too good.
1636 * The usleep() call might make it a tiny bit nicer on other
1637 * running processes, but it is still very ugly.
1638 */
1639 while ((ch = console_readchar(MAIN_CONSOLE)) < 0) {
1640 x11_check_event(debugger_emuls, debugger_n_emuls);
1641 usleep(2);
1642 }
1643
1644 if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
1645 /* Backspace. */
1646 cursor_pos --;
1647 cmd_len --;
1648 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1649 cmd_len);
1650 cmd[cmd_len] = '\0';
1651 printf("\b");
1652 for (i=cursor_pos; i<cmd_len; i++)
1653 printf("%c", cmd[i]);
1654 printf(" \b");
1655 for (i=cursor_pos; i<cmd_len; i++)
1656 printf("\b");
1657 } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
1658 /* CTRL-D: Delete. */
1659 cmd_len --;
1660 memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1661 cmd_len);
1662 cmd[cmd_len] = '\0';
1663 for (i=cursor_pos; i<cmd_len; i++)
1664 printf("%c", cmd[i]);
1665 printf(" \b");
1666 for (i=cursor_pos; i<cmd_len; i++)
1667 printf("\b");
1668 } else if (ch == 1) {
1669 /* CTRL-A: Start of line. */
1670 while (cursor_pos > 0) {
1671 cursor_pos --;
1672 printf("\b");
1673 }
1674 } else if (ch == 2) {
1675 /* CTRL-B: Backwards one character. */
1676 if (cursor_pos > 0) {
1677 printf("\b");
1678 cursor_pos --;
1679 }
1680 } else if (ch == 5) {
1681 /* CTRL-E: End of line. */
1682 while (cursor_pos < cmd_len) {
1683 printf("%c", cmd[cursor_pos]);
1684 cursor_pos ++;
1685 }
1686 } else if (ch == 6) {
1687 /* CTRL-F: Forward one character. */
1688 if (cursor_pos < cmd_len) {
1689 printf("%c",
1690 cmd[cursor_pos]);
1691 cursor_pos ++;
1692 }
1693 } else if (ch == 11) {
1694 /* CTRL-K: Kill to end of line. */
1695 for (i=0; i<MAX_CMD_LEN; i++)
1696 console_makeavail(MAIN_CONSOLE, 4); /* :-) */
1697 } else if (ch == 14 || ch == 16) {
1698 /* CTRL-P: Previous line in the command history,
1699 CTRL-N: next line */
1700 do {
1701 if (ch == 14 &&
1702 read_from_index == last_cmd_index)
1703 break;
1704 if (ch == 16)
1705 i = read_from_index - 1;
1706 else
1707 i = read_from_index + 1;
1708
1709 if (i < 0)
1710 i = N_PREVIOUS_CMDS - 1;
1711 if (i >= N_PREVIOUS_CMDS)
1712 i = 0;
1713
1714 /* Special case: pressing 'down'
1715 to reach last_cmd_index: */
1716 if (i == last_cmd_index) {
1717 read_from_index = i;
1718 for (i=cursor_pos; i<cmd_len;
1719 i++)
1720 printf(" ");
1721 for (i=cmd_len-1; i>=0; i--)
1722 printf("\b \b");
1723 cmd[0] = '\0';
1724 cmd_len = cursor_pos = 0;
1725 } else if (last_cmd[i][0] != '\0') {
1726 /* Copy from old line: */
1727 read_from_index = i;
1728 for (i=cursor_pos; i<cmd_len;
1729 i++)
1730 printf(" ");
1731 for (i=cmd_len-1; i>=0; i--)
1732 printf("\b \b");
1733 strcpy(cmd,
1734 last_cmd[read_from_index]);
1735 cmd_len = strlen(cmd);
1736 printf("%s", cmd);
1737 cursor_pos = cmd_len;
1738 }
1739 } while (0);
1740 } else if (ch >= ' ' && cmd_len < MAX_CMD_LEN) {
1741 /* Visible character: */
1742 memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
1743 cmd_len - cursor_pos);
1744 cmd[cursor_pos] = ch;
1745 cmd_len ++;
1746 cursor_pos ++;
1747 cmd[cmd_len] = '\0';
1748 printf("%c", ch);
1749 for (i=cursor_pos; i<cmd_len; i++)
1750 printf("%c", cmd[i]);
1751 for (i=cursor_pos; i<cmd_len; i++)
1752 printf("\b");
1753 } else if (ch == '\r' || ch == '\n') {
1754 ch = '\n';
1755 printf("\n");
1756 } else if (ch == '\t') {
1757 /* Super-simple tab-completion: */
1758 i = 0;
1759 while (cmds[i].name != NULL)
1760 cmds[i++].tmp_flag = 0;
1761
1762 /* Check for a (partial) command match: */
1763 n = i = i_match = 0;
1764 while (cmds[i].name != NULL) {
1765 if (strncasecmp(cmds[i].name, cmd,
1766 cmd_len) == 0) {
1767 cmds[i].tmp_flag = 1;
1768 i_match = i;
1769 n++;
1770 }
1771 i++;
1772 }
1773
1774 switch (n) {
1775 case 0: /* Beep. */
1776 printf("\a");
1777 break;
1778 case 1: /* Add the rest of the command: */
1779 reallen = strlen(cmds[i_match].name);
1780 for (i=cmd_len; i<reallen; i++)
1781 console_makeavail(MAIN_CONSOLE,
1782 cmds[i_match].name[i]);
1783 /* ... and a space, if the command takes
1784 any arguments: */
1785 if (cmds[i_match].args != NULL &&
1786 cmds[i_match].args[0] != '\0')
1787 console_makeavail(MAIN_CONSOLE, ' ');
1788 break;
1789 default:
1790 /* Show all possible commands: */
1791 printf("\a\n"); /* Beep. :-) */
1792 i = 0; /* i = cmds index */
1793 j = 0; /* j = # of cmds printed */
1794 while (cmds[i].name != NULL) {
1795 if (cmds[i].tmp_flag) {
1796 int q;
1797 if (j == 0)
1798 printf(" ");
1799 printf("%s",
1800 cmds[i].name);
1801 j++;
1802 if (j != 6)
1803 for (q=0; q<13-strlen(
1804 cmds[i].name); q++)
1805 printf(" ");
1806 if (j == 6) {
1807 printf("\n");
1808 j = 0;
1809 }
1810 }
1811 i++;
1812 }
1813 if (j != 0)
1814 printf("\n");
1815 printf("GXemul> ");
1816 for (i=0; i<cmd_len; i++)
1817 printf("%c", cmd[i]);
1818 }
1819 } else if (ch == 27) {
1820 /* Escape codes: (cursor keys etc) */
1821 while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
1822 usleep(1);
1823 if (ch == '[' || ch == 'O') {
1824 while ((ch = console_readchar(MAIN_CONSOLE))
1825 < 0)
1826 usleep(1);
1827 switch (ch) {
1828 case '2': /* 2~ = ins */
1829 case '5': /* 5~ = pgup */
1830 case '6': /* 6~ = pgdn */
1831 /* TODO: Ugly hack, but might work. */
1832 while ((ch = console_readchar(
1833 MAIN_CONSOLE)) < 0)
1834 usleep(1);
1835 /* Do nothing for these keys. */
1836 break;
1837 case '3': /* 3~ = delete */
1838 /* TODO: Ugly hack, but might work. */
1839 while ((ch = console_readchar(
1840 MAIN_CONSOLE)) < 0)
1841 usleep(1);
1842 console_makeavail(MAIN_CONSOLE, '\b');
1843 break;
1844 case 'A': /* Up. */
1845 /* Up cursor ==> CTRL-P */
1846 console_makeavail(MAIN_CONSOLE, 16);
1847 break;
1848 case 'B': /* Down. */
1849 /* Down cursor ==> CTRL-N */
1850 console_makeavail(MAIN_CONSOLE, 14);
1851 break;
1852 case 'C':
1853 /* Right cursor ==> CTRL-F */
1854 console_makeavail(MAIN_CONSOLE, 6);
1855 break;
1856 case 'D': /* Left */
1857 /* Left cursor ==> CTRL-B */
1858 console_makeavail(MAIN_CONSOLE, 2);
1859 break;
1860 case 'F':
1861 /* End ==> CTRL-E */
1862 console_makeavail(MAIN_CONSOLE, 5);
1863 break;
1864 case 'H':
1865 /* Home ==> CTRL-A */
1866 console_makeavail(MAIN_CONSOLE, 1);
1867 break;
1868 }
1869 }
1870 }
1871
1872 fflush(stdout);
1873 }
1874
1875 return cmd;
1876 }
1877
1878
1879 /*
1880 * debugger():
1881 *
1882 * This is a loop, which reads a command from the terminal, and executes it.
1883 */
1884 void debugger(void)
1885 {
1886 int i, n, i_match, matchlen, cmd_len;
1887 char *cmd;
1888
1889 if (n_steps_left_before_interaction > 0) {
1890 n_steps_left_before_interaction --;
1891 return;
1892 }
1893
1894 exit_debugger = 0;
1895
1896 while (!exit_debugger) {
1897 /* Read a line from the terminal: */
1898 cmd = debugger_readline();
1899 cmd_len = strlen(cmd);
1900
1901 /* Remove spaces: */
1902 while (cmd_len > 0 && cmd[0]==' ')
1903 memmove(cmd, cmd+1, cmd_len --);
1904 while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
1905 cmd[(cmd_len--)-1] = '\0';
1906
1907 /* No command? Then try reading another line. */
1908 if (cmd_len == 0) {
1909 /* Special case for repeated commands: */
1910 if (repeat_cmd[0] != '\0')
1911 strcpy(cmd, repeat_cmd);
1912 else
1913 continue;
1914 } else {
1915 last_cmd_index ++;
1916 if (last_cmd_index >= N_PREVIOUS_CMDS)
1917 last_cmd_index = 0;
1918
1919 repeat_cmd[0] = '\0';
1920 }
1921
1922 /*
1923 * Is there a '=' on the command line? Then try to do an
1924 * assignment. (Only if there is just one word, followed
1925 * by the '=' sign. This makes it possible to use commands
1926 * such as "device add name addr=xyz".)
1927 */
1928 if (strchr(cmd, '=') != NULL) {
1929 /* Count the nr of words: */
1930 int nw = 0, inword = 0;
1931 char *p = cmd;
1932 while (*p) {
1933 if (*p == '=')
1934 break;
1935 if (*p != ' ') {
1936 if (!inword)
1937 nw ++;
1938 inword = 1;
1939 } else
1940 inword = 0;
1941 p++;
1942 }
1943
1944 if (nw == 1) {
1945 debugger_assignment(debugger_machine, cmd);
1946 continue;
1947 }
1948 }
1949
1950 i = 0;
1951 while (cmds[i].name != NULL)
1952 cmds[i++].tmp_flag = 0;
1953
1954 /* How many chars in cmd to match against: */
1955 matchlen = 0;
1956 while (isalpha((int)cmd[matchlen]))
1957 matchlen ++;
1958
1959 /* Check for a command name match: */
1960 n = i = i_match = 0;
1961 while (cmds[i].name != NULL) {
1962 if (strncasecmp(cmds[i].name, cmd, matchlen) == 0) {
1963 cmds[i].tmp_flag = 1;
1964 i_match = i;
1965 n++;
1966 }
1967 i++;
1968 }
1969
1970 /* No match? */
1971 if (n == 0) {
1972 printf("Unknown command '%s'. "
1973 "Type 'help' for help.\n", cmd);
1974 continue;
1975 }
1976
1977 /* More than one match? */
1978 if (n > 1) {
1979 printf("Ambiguous command '%s': ", cmd);
1980 i = 0;
1981 while (cmds[i].name != NULL) {
1982 if (cmds[i].tmp_flag)
1983 printf(" %s", cmds[i].name);
1984 i++;
1985 }
1986 printf("\n");
1987 continue;
1988 }
1989
1990 /* Exactly one match: */
1991 if (cmds[i_match].f != NULL) {
1992 char *p = cmd + matchlen;
1993 /* Remove leading whitespace from the args... */
1994 while (*p != '\0' && *p == ' ')
1995 p++;
1996
1997 /* ... and run the command: */
1998 cmds[i_match].f(debugger_machine, p);
1999 } else
2000 printf("FATAL ERROR: internal error in debugger.c:"
2001 " no handler for this command?\n");
2002
2003 /* Special hack for the "step" command: */
2004 if (exit_debugger == -1)
2005 return;
2006 }
2007
2008 single_step = 0;
2009 debugger_machine->instruction_trace = old_instruction_trace;
2010 debugger_machine->show_trace_tree = old_show_trace_tree;
2011 quiet_mode = old_quiet_mode;
2012 }
2013
2014
2015 /*
2016 * debugger_reset():
2017 *
2018 * This function should be called before calling debugger(), when it is
2019 * absolutely necessary that debugger() is interactive. Otherwise, it might
2020 * return without doing anything, such as when single-stepping multiple
2021 * instructions at a time.
2022 */
2023 void debugger_reset(void)
2024 {
2025 n_steps_left_before_interaction = 0;
2026 }
2027
2028
2029 /*
2030 * debugger_init():
2031 *
2032 * Must be called before any other debugger function is used.
2033 */
2034 void debugger_init(struct emul **emuls, int n_emuls)
2035 {
2036 int i;
2037
2038 debugger_n_emuls = n_emuls;
2039 debugger_emuls = emuls;
2040
2041 if (n_emuls < 1) {
2042 fprintf(stderr, "\nERROR: No emuls (?)\n");
2043 exit(1);
2044 }
2045
2046 debugger_emul = emuls[0];
2047 if (emuls[0]->n_machines < 1) {
2048 fprintf(stderr, "\nERROR: No machines in emuls[0], "
2049 "cannot handle this situation yet.\n\n");
2050 exit(1);
2051 }
2052
2053 debugger_machine = emuls[0]->machines[0];
2054
2055 for (i=0; i<N_PREVIOUS_CMDS; i++) {
2056 last_cmd[i] = malloc(MAX_CMD_LEN + 1);
2057 if (last_cmd[i] == NULL) {
2058 fprintf(stderr, "debugger_init(): out of memory\n");
2059 exit(1);
2060 }
2061 last_cmd[i][0] = '\0';
2062 }
2063
2064 last_cmd_index = 0;
2065 repeat_cmd[0] = '\0';
2066 }
2067

  ViewVC Help
Powered by ViewVC 1.1.26