/[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 6 - (show annotations)
Mon Oct 8 16:18:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47221 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.772 2005/06/04 12:02:16 debug Exp $
20050428	Disabling the "-fmove-all-movables" option in the configure
		script, because it causes the compile to fail on OpenBSD/sgi.
20050502	Minor updates.
20050503	Removing the WRT54G mode (it was bogus anyway), and adding a
		comment about Windows NT for MIPS in doc/experiments.html.
		Minor updates to the x86 instruction decoding.
20050504	Adding some more x86 instructions.
		Adding support for reading files from ISO9660 CDROMs (including
		gzipped files). It's an ugly hack, but it seems to work.
		Various other minor updates (dev_vga.c, pc_bios.c etc).
20050505	Some more x86-related updates.
		Beginning (what I hope will be) a major code cleanup phase.
		"bootris" (an x86 bootsector) runs :-)
20050506	Adding some more x86 instructions.
20050507	tmpnam => mkstemp.
		Working on a hack to allow VGA charcells to be shown even when
		not running with X11.
		Adding more x86 instructions.
20050508	x86 32-bit SIB addressing fix, and more instructions.
20050509	Adding more x86 instructions.
20050510	Minor documentation updates, and other updates (x86 stuff etc.)
20050511	More x86-related updates.
20050513	Various updates, mostly x86-related. (Trying to fix flag 
		calculation, factoring out the ugly shift/rotate code, and
		some other things.)
20050514	Adding support for loading some old i386 a.out executables.
		Finally beginning the cleanup of machine/PROM/bios dependant
		info.
		Some minor documentation updates.
		Trying to clean up ARCBIOS stuff a little.
20050515	Trying to make it possible to actually use more than one disk
		type per machine (floppy, ide, scsi).
		Trying to clean up the kbd vs PROM console stuff. (For PC and
		ARC emulation modes, mostly.)
		Beginning to add an 8259 interrupt controller, and connecting
		it to the x86 emulation.
20050516	The first x86 interrupts seem to work (keyboard stuff).
		Adding a 8253/8254 programmable interval timer skeleton.
		FreeDOS now reaches a command prompt and can be interacted
		with.
20050517	After some bugfixes, MS-DOS also (sometimes) reaches a
		command prompt now.
		Trying to fix the pckbc to work with MS-DOS' keyb.com, but no
		success yet.
20050518	Adding a simple 32-bit x86 MMU skeleton.
20050519	Some more work on the x86 stuff. (Beginning the work on paging,
		and various other fixes).
20050520	More updates. Working on dev_vga (4-bit graphics modes), adding
		40 columns support to the PC bios emulation.
		Trying to add support for resizing windows when switching
		between graphics modes.
20050521	Many more x86-related updates.
20050522	Correcting the initial stack pointer's sign-extension for
		ARCBIOS emulation (thanks to Alec Voropay for noticing the
		error).
		Continuing on the cleanup (ARCBIOS etc).
		dev_vga updates.
20050523	More x86 updates: trying to add some support for protected mode
		interrupts (via gate descriptors) and many other fixes.
		More ARCBIOS cleanup.
		Adding a device flag which indicates that reads cause no
		side-effects. (Useful for the "dump" command in the debugger,
		and other things.)
		Adding support for directly starting up x86 ELFs, skipping the
		bootloader stage. (Most ELFs, however, are not suitable for
		this.)
20050524	Adding simple 32-bit x86 TSS task switching, but no privilege
		level support yet.
		More work on dev_vga. A small "Copper bars" demo works. :-)
		Adding support for Trap Flag (single-step exceptions), at least
		in real mode, and various other x86-related fixes.
20050525	Adding a new disk image prefix (gH;S;) which can be used to
		override the default nr of heads and sectors per track.
20050527	Various bug fixes, more work on the x86 mode (stack change on
		interrupts between different priv.levels), and some minor
		documentation updates.
20050528	Various fixes (x86 stuff).
20050529	More x86 fixes. An OpenBSD/i386 bootfloppy reaches userland
		and can be interacted with (although there are problems with
		key repetition). NetBSD/i386 triggers a serious CISC-related
		problem: instruction fetches across page boundaries, where
		the later part isn't actually part of the instruction.
20050530	Various minor updates. (Documentation updates, etc.)
20050531	Adding some experimental code (experiments/new_test_*) which
		could be useful for dynamic (but not binary) translation in
		the future.
20050602	Adding a dummy ARM skeleton.
		Fixing the pckbc key repetition problem (by adding release
		scancodes for all keypresses).
20050603	Minor updates for the next release.
20050604	Release testing. Minor updates.

==============  RELEASE 0.3.3  ==============

20050604	There'll probably be a 0.3.3.1 release soon, with some very
		very tiny updates.


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

  ViewVC Help
Powered by ViewVC 1.1.26