/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 51672 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26