/[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

Annotation of /trunk/src/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months 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 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 22 * $Id: debugger.c,v 1.132 2006/02/04 11:10:58 debug Exp $
29 dpavlin 2 *
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 dpavlin 22 * Call stack display?
40     *
41 dpavlin 2 * 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 dpavlin 4 #include "bintrans.h"
60 dpavlin 2 #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 dpavlin 12 volatile int single_step_breakpoint = 0;
88     int debugger_n_steps_left_before_interaction = 0;
89    
90 dpavlin 2 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 dpavlin 10 #define MAX_CMD_BUFLEN 72
109 dpavlin 2 #define N_PREVIOUS_CMDS 150
110     static char *last_cmd[N_PREVIOUS_CMDS];
111     static int last_cmd_index;
112    
113 dpavlin 10 static char repeat_cmd[MAX_CMD_BUFLEN];
114 dpavlin 2
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 dpavlin 12 * 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 dpavlin 2 * 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 dpavlin 10 for (i=0; i<MAX_CMD_BUFLEN; i++)
154 dpavlin 2 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 dpavlin 18 * "pc", "r5", "hi", "t4" ==> register (CPU dependent)
186 dpavlin 2 * "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 dpavlin 12 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 dpavlin 2
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 dpavlin 10 strlcpy(sn, name, strlen(name)+1);
267 dpavlin 2
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 dpavlin 12 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 dpavlin 2 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 dpavlin 12
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 dpavlin 2 return;
378     }
379    
380     if (strncmp(cmd_line, "add ", 4) == 0) {
381     uint64_t tmp;
382 dpavlin 10 size_t breakpoint_buf_len;
383 dpavlin 2
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 dpavlin 10 breakpoint_buf_len = strlen(cmd_line+4) + 1;
400     m->breakpoint_string[i] = malloc(breakpoint_buf_len);
401 dpavlin 2 if (m->breakpoint_string[i] == NULL) {
402     printf("out of memory in debugger_cmd_breakpoint()\n");
403     exit(1);
404     }
405 dpavlin 10 strlcpy(m->breakpoint_string[i], cmd_line+4,
406     breakpoint_buf_len);
407 dpavlin 2 m->breakpoint_addr[i] = tmp;
408     m->breakpoint_flags[i] = 0;
409    
410     m->n_breakpoints ++;
411     show_breakpoint(m, i);
412 dpavlin 12
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 dpavlin 2 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 dpavlin 4 int i;
430    
431 dpavlin 2 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 dpavlin 4 if (strncasecmp(cmd_line, "on", 3) == 0) {
445 dpavlin 2 m->bintrans_enable = 1;
446 dpavlin 4 for (i=0; i<m->ncpus; i++)
447     bintrans_restart(m->cpus[i]);
448     } else if (strncasecmp(cmd_line, "off", 4) == 0)
449 dpavlin 2 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 dpavlin 22 int i;
480 dpavlin 2 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 dpavlin 22 } else if (strcmp(cmd_line, "consoles") == 0) {
513     console_debug_dump(m);
514 dpavlin 2 } 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 dpavlin 20 if (mem->dev_flags[i] & DM_DYNTRANS_OK)
532 dpavlin 12 printf("DYNTRANS R");
533 dpavlin 20 if (mem->dev_flags[i] & DM_DYNTRANS_WRITE_OK)
534 dpavlin 2 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 dpavlin 22 printf(" consoles list all slave consoles\n");
551 dpavlin 2 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 dpavlin 12 if (c->is_32bit)
643     printf("0x%08x ", (int)addr);
644     else
645     printf("0x%016llx ", (long long)addr);
646 dpavlin 2
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 dpavlin 10 strlcpy(repeat_cmd, "dump", MAX_CMD_BUFLEN);
679 dpavlin 2 }
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 dpavlin 22 int i, iadd = DEBUG_INDENTATION;
690 dpavlin 2
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 dpavlin 12 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 dpavlin 2 return;
826     }
827    
828     symbol = get_symbol_name(&m->symbol_context, addr, &offset);
829    
830 dpavlin 12 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 dpavlin 2 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 dpavlin 22 int iadd = DEBUG_INDENTATION;
849 dpavlin 2
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 dpavlin 12 * 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 dpavlin 2 * 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 dpavlin 6 printf("%s = 0x%llx\n", cmd_line, (long long)tmp);
982     break;
983 dpavlin 2 case NAME_PARSE_SYMBOL:
984 dpavlin 12 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 dpavlin 2 break;
989     case NAME_PARSE_NUMBER:
990 dpavlin 6 printf("0x%llx\n", (long long)tmp);
991 dpavlin 2 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 dpavlin 12 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 dpavlin 2 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 dpavlin 22 if ((addr & 1) != 0)
1113 dpavlin 2 printf("WARNING: address isn't aligned\n");
1114 dpavlin 12 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 dpavlin 2 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 dpavlin 22 if ((addr & 3) != 0)
1128 dpavlin 2 printf("WARNING: address isn't aligned\n");
1129 dpavlin 12 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 dpavlin 2 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 dpavlin 22 if ((addr & 7) != 0)
1144 dpavlin 2 printf("WARNING: address isn't aligned\n");
1145 dpavlin 12 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 dpavlin 2 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 dpavlin 12 debugger_n_steps_left_before_interaction = n - 1;
1300 dpavlin 2
1301     /* Special hack, see debugger() for more info. */
1302     exit_debugger = -1;
1303    
1304 dpavlin 10 strlcpy(repeat_cmd, "step", MAX_CMD_BUFLEN);
1305 dpavlin 2 }
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 dpavlin 20 int toggle = 1;
1352 dpavlin 12 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 dpavlin 2 }
1383    
1384 dpavlin 12 if (toggle)
1385     old_show_trace_tree = 1 - old_show_trace_tree;
1386 dpavlin 2
1387 dpavlin 12 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 dpavlin 2 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 dpavlin 12 unsigned int i, len;
1479     unsigned char buf[17]; /* TODO: How long can an
1480 dpavlin 2 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 dpavlin 10 strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN);
1506 dpavlin 2 }
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 dpavlin 12 { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs,
1573     "toggle (set or unset) show_nr_of_instructions" },
1574    
1575 dpavlin 2 { "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 dpavlin 12 { "trace", "[on|off]", 0, debugger_cmd_trace,
1606 dpavlin 2 "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 dpavlin 12 /* Note: NULL handler. */
1615     { "x = expr", "", 0, NULL, "generic assignment" },
1616    
1617 dpavlin 2 { 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 dpavlin 10 *
1629     * TODO: Command completion (ie just type "help s" for "help step").
1630 dpavlin 2 */
1631     static void debugger_cmd_help(struct machine *m, char *cmd_line)
1632     {
1633 dpavlin 22 int only_one = 0, only_one_match = 0;
1634 dpavlin 12 char *nlines_env = getenv("LINES");
1635 dpavlin 22 int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines;
1636     size_t i, j, max_name_len = 0;
1637 dpavlin 2
1638 dpavlin 10 if (cmd_line[0] != '\0') {
1639     only_one = 1;
1640     }
1641    
1642 dpavlin 2 i = 0;
1643     while (cmds[i].name != NULL) {
1644 dpavlin 22 size_t a = strlen(cmds[i].name);
1645 dpavlin 2 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 dpavlin 12 curlines = 0;
1653     if (!only_one) {
1654 dpavlin 10 printf("Available commands:\n");
1655 dpavlin 12 curlines++;
1656     }
1657 dpavlin 2
1658     i = 0;
1659     while (cmds[i].name != NULL) {
1660     char buf[100];
1661     snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1662 dpavlin 10
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 dpavlin 2 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 dpavlin 12
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 dpavlin 2 }
1696    
1697 dpavlin 10 if (only_one) {
1698     if (!only_one_match)
1699     printf("%s: no such command\n", cmd_line);
1700     return;
1701     }
1702    
1703 dpavlin 12 /* 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 dpavlin 2 }
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 dpavlin 12 uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */
1738 dpavlin 2
1739 dpavlin 10 left = malloc(MAX_CMD_BUFLEN);
1740 dpavlin 2 if (left == NULL) {
1741     fprintf(stderr, "out of memory in debugger_assignment()\n");
1742     exit(1);
1743     }
1744 dpavlin 10 strlcpy(left, cmd, MAX_CMD_BUFLEN);
1745 dpavlin 2 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 dpavlin 12 /*
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 dpavlin 2 free(left);
1798     }
1799    
1800    
1801     /*
1802 dpavlin 22 * 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 dpavlin 2 * 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 dpavlin 12 ch = debugger_readchar();
1912 dpavlin 2
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 dpavlin 10 for (i=0; i<MAX_CMD_BUFLEN; i++)
1965 dpavlin 2 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 dpavlin 10 strlcpy(cmd,
2003     last_cmd[read_from_index],
2004     MAX_CMD_BUFLEN);
2005 dpavlin 2 cmd_len = strlen(cmd);
2006     printf("%s", cmd);
2007     cursor_pos = cmd_len;
2008     }
2009     } while (0);
2010 dpavlin 10 } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) {
2011 dpavlin 2 /* 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 dpavlin 22 size_t q;
2067 dpavlin 2 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 dpavlin 22 int i, cmd_len;
2157 dpavlin 2 char *cmd;
2158    
2159 dpavlin 12 if (debugger_n_steps_left_before_interaction > 0) {
2160     debugger_n_steps_left_before_interaction --;
2161 dpavlin 2 return;
2162     }
2163    
2164 dpavlin 20 /*
2165     * Clear all dyntrans translations, because otherwise things would
2166     * become to complex to keep in sync.
2167     */
2168 dpavlin 22 /* TODO: In all machines */
2169 dpavlin 20 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 dpavlin 2 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 dpavlin 10 strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN);
2191 dpavlin 2 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 dpavlin 22 debugger_execute_cmd(cmd, cmd_len);
2202 dpavlin 2
2203     /* Special hack for the "step" command: */
2204     if (exit_debugger == -1)
2205     return;
2206     }
2207    
2208 dpavlin 10 gettimeofday(&debugger_machine->starttime, NULL);
2209     debugger_machine->ncycles_since_gettimeofday = 0;
2210    
2211 dpavlin 2 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 dpavlin 12 debugger_n_steps_left_before_interaction = 0;
2229 dpavlin 2 }
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 dpavlin 10 last_cmd[i] = malloc(MAX_CMD_BUFLEN);
2260 dpavlin 2 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