/[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 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 52084 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

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

  ViewVC Help
Powered by ViewVC 1.1.26