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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47162 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26