/[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 20 - (show annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 52213 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26