/[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 10 - (show annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47953 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 0.3.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26