/[gxemul]/trunk/src/debugger/debugger_cmds.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/debugger_cmds.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 34 - (hide annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31571 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


1 dpavlin 24 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 24 *
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 34 * $Id: debugger_cmds.c,v 1.10 2006/12/30 13:30:56 debug Exp $
29 dpavlin 24 *
30     * Debugger commands. Included from debugger.c.
31     */
32    
33    
34     /*
35     * debugger_cmd_allsettings():
36     */
37     static void debugger_cmd_allsettings(struct machine *m, char *cmd_line)
38     {
39     settings_debugdump(global_settings, GLOBAL_SETTINGS_NAME, 1);
40     }
41    
42    
43     /*
44     * debugger_cmd_breakpoint():
45     *
46     * TODO: automagic "expansion" for the subcommand names (s => show).
47     */
48     static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line)
49     {
50     int i, res;
51    
52     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
53     cmd_line ++;
54    
55     if (cmd_line[0] == '\0') {
56     printf("syntax: breakpoint subcmd [args...]\n");
57     printf("Available subcmds (and args) are:\n");
58     printf(" add addr add a breakpoint for address addr\n");
59     printf(" delete x delete breakpoint nr x\n");
60     printf(" show show current breakpoints\n");
61     return;
62     }
63    
64     if (strcmp(cmd_line, "show") == 0) {
65     if (m->n_breakpoints == 0)
66     printf("No breakpoints set.\n");
67     for (i=0; i<m->n_breakpoints; i++)
68     show_breakpoint(m, i);
69     return;
70     }
71    
72     if (strncmp(cmd_line, "delete ", 7) == 0) {
73     int x = atoi(cmd_line + 7);
74    
75     if (m->n_breakpoints == 0) {
76     printf("No breakpoints set.\n");
77     return;
78     }
79     if (x < 0 || x >= m->n_breakpoints) {
80     printf("Invalid breakpoint nr %i. Use 'breakpoint "
81     "show' to see the current breakpoints.\n", x);
82     return;
83     }
84    
85     free(m->breakpoint_string[x]);
86    
87     for (i=x; i<m->n_breakpoints-1; i++) {
88     m->breakpoint_addr[i] = m->breakpoint_addr[i+1];
89     m->breakpoint_string[i] = m->breakpoint_string[i+1];
90     m->breakpoint_flags[i] = m->breakpoint_flags[i+1];
91     }
92     m->n_breakpoints --;
93    
94     /* Clear translations: */
95     for (i=0; i<m->ncpus; i++)
96     if (m->cpus[i]->translation_cache != NULL)
97     cpu_create_or_reset_tc(m->cpus[i]);
98     return;
99     }
100    
101     if (strncmp(cmd_line, "add ", 4) == 0) {
102     uint64_t tmp;
103     size_t breakpoint_buf_len;
104    
105     if (m->n_breakpoints >= MAX_BREAKPOINTS) {
106     printf("Too many breakpoints. (You need to recompile"
107     " gxemul to increase this. Max = %i.)\n",
108     MAX_BREAKPOINTS);
109     return;
110     }
111    
112     i = m->n_breakpoints;
113    
114 dpavlin 32 res = debugger_parse_expression(m, cmd_line + 4, 0, &tmp);
115 dpavlin 24 if (!res) {
116     printf("Couldn't parse '%s'\n", cmd_line + 4);
117     return;
118     }
119    
120     breakpoint_buf_len = strlen(cmd_line+4) + 1;
121     m->breakpoint_string[i] = malloc(breakpoint_buf_len);
122     if (m->breakpoint_string[i] == NULL) {
123     printf("out of memory in debugger_cmd_breakpoint()\n");
124     exit(1);
125     }
126     strlcpy(m->breakpoint_string[i], cmd_line+4,
127     breakpoint_buf_len);
128     m->breakpoint_addr[i] = tmp;
129     m->breakpoint_flags[i] = 0;
130    
131     m->n_breakpoints ++;
132     show_breakpoint(m, i);
133    
134     /* Clear translations: */
135     for (i=0; i<m->ncpus; i++)
136     if (m->cpus[i]->translation_cache != NULL)
137     cpu_create_or_reset_tc(m->cpus[i]);
138     return;
139     }
140    
141     printf("Unknown breakpoint subcommand.\n");
142     }
143    
144    
145     /*
146     * debugger_cmd_continue():
147     */
148     static void debugger_cmd_continue(struct machine *m, char *cmd_line)
149     {
150     if (*cmd_line) {
151     printf("syntax: continue\n");
152     return;
153     }
154    
155     exit_debugger = 1;
156     }
157    
158    
159     /*
160     * debugger_cmd_device():
161     */
162     static void debugger_cmd_device(struct machine *m, char *cmd_line)
163     {
164     int i;
165     struct memory *mem;
166     struct cpu *c;
167    
168     if (cmd_line[0] == '\0')
169     goto return_help;
170    
171     if (m->cpus == NULL) {
172     printf("No cpus (?)\n");
173     return;
174     }
175     c = m->cpus[m->bootstrap_cpu];
176     if (c == NULL) {
177     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
178     return;
179     }
180     mem = m->cpus[m->bootstrap_cpu]->mem;
181    
182     if (m->cpus == NULL) {
183     printf("No cpus (?)\n");
184     return;
185     }
186     c = m->cpus[m->bootstrap_cpu];
187     if (c == NULL) {
188     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
189     return;
190     }
191     mem = m->cpus[m->bootstrap_cpu]->mem;
192    
193     if (strcmp(cmd_line, "all") == 0) {
194     device_dumplist();
195     } else if (strncmp(cmd_line, "add ", 4) == 0) {
196     device_add(m, cmd_line+4);
197     } else if (strcmp(cmd_line, "consoles") == 0) {
198     console_debug_dump(m);
199     } else if (strncmp(cmd_line, "remove ", 7) == 0) {
200     i = atoi(cmd_line + 7);
201     if (i==0 && cmd_line[7]!='0') {
202     printf("Weird device number. Use 'device list'.\n");
203     } else
204     memory_device_remove(m->memory, i);
205     } else if (strcmp(cmd_line, "list") == 0) {
206     if (mem->n_mmapped_devices == 0)
207     printf("No memory-mapped devices in this machine.\n");
208    
209     for (i=0; i<mem->n_mmapped_devices; i++) {
210     printf("%2i: %25s @ 0x%011"PRIx64", len = 0x%"PRIx64,
211 dpavlin 32 i, mem->devices[i].name,
212     (uint64_t) mem->devices[i].baseaddr,
213     (uint64_t) mem->devices[i].length);
214 dpavlin 24
215 dpavlin 32 if (mem->devices[i].flags) {
216 dpavlin 24 printf(" (");
217 dpavlin 32 if (mem->devices[i].flags & DM_DYNTRANS_OK)
218 dpavlin 24 printf("DYNTRANS R");
219 dpavlin 32 if (mem->devices[i].flags &DM_DYNTRANS_WRITE_OK)
220 dpavlin 24 printf("+W");
221     printf(")");
222     }
223     printf("\n");
224     }
225     } else
226     goto return_help;
227    
228     return;
229    
230     return_help:
231     printf("syntax: devices cmd [...]\n");
232     printf("Available cmds are:\n");
233     printf(" add name_and_params add a device to the current "
234     "machine\n");
235     printf(" all list all registered devices\n");
236     printf(" consoles list all slave consoles\n");
237     printf(" list list memory-mapped devices in the"
238     " current machine\n");
239     printf(" remove x remove device nr x from the "
240     "current machine\n");
241     }
242    
243    
244     /*
245     * debugger_cmd_dump():
246     *
247     * Dump emulated memory in hex and ASCII.
248     *
249     * syntax: dump [addr [endaddr]]
250     */
251     static void debugger_cmd_dump(struct machine *m, char *cmd_line)
252     {
253     uint64_t addr, addr_start, addr_end;
254     struct cpu *c;
255     struct memory *mem;
256     char *p = NULL;
257     int x, r;
258    
259     if (cmd_line[0] != '\0') {
260     uint64_t tmp;
261     char *tmps = strdup(cmd_line);
262    
263     /* addr: */
264     p = strchr(tmps, ' ');
265     if (p != NULL)
266     *p = '\0';
267 dpavlin 32 r = debugger_parse_expression(m, tmps, 0, &tmp);
268 dpavlin 24 free(tmps);
269    
270 dpavlin 32 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
271 dpavlin 24 printf("Unparsable address: %s\n", cmd_line);
272     return;
273     } else {
274     last_dump_addr = tmp;
275     }
276    
277     p = strchr(cmd_line, ' ');
278     }
279    
280 dpavlin 32 if (m->cpus == NULL) {
281     printf("No cpus (?)\n");
282     return;
283     }
284     c = m->cpus[m->bootstrap_cpu];
285     if (c == NULL) {
286     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
287     return;
288     }
289     mem = m->cpus[m->bootstrap_cpu]->mem;
290    
291 dpavlin 24 addr_start = last_dump_addr;
292    
293 dpavlin 32 if (addr_start == MAGIC_UNTOUCHED)
294     addr_start = c->pc;
295 dpavlin 24
296     addr_end = addr_start + 16 * 16;
297    
298     /* endaddr: */
299     if (p != NULL) {
300     while (*p == ' ' && *p)
301     p++;
302 dpavlin 32 r = debugger_parse_expression(m, p, 0, &addr_end);
303     if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
304 dpavlin 24 printf("Unparsable address: %s\n", cmd_line);
305     return;
306     }
307     }
308    
309     addr = addr_start & ~0xf;
310    
311     ctrl_c = 0;
312    
313     while (addr < addr_end) {
314     unsigned char buf[16];
315     memset(buf, 0, sizeof(buf));
316     r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf),
317     MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
318    
319     if (c->is_32bit)
320     printf("0x%08"PRIx32" ", (uint32_t) addr);
321     else
322     printf("0x%016"PRIx64" ", (uint64_t) addr);
323    
324     if (r == MEMORY_ACCESS_FAILED)
325     printf("(memory access failed)\n");
326     else {
327     for (x=0; x<16; x++) {
328     if (addr + x >= addr_start &&
329     addr + x < addr_end)
330     printf("%02x%s", buf[x],
331     (x&3)==3? " " : "");
332     else
333     printf(" %s", (x&3)==3? " " : "");
334     }
335     printf(" ");
336     for (x=0; x<16; x++) {
337     if (addr + x >= addr_start &&
338     addr + x < addr_end)
339     printf("%c", (buf[x]>=' ' &&
340     buf[x]<127)? buf[x] : '.');
341     else
342     printf(" ");
343     }
344     printf("\n");
345     }
346    
347     if (ctrl_c)
348     return;
349    
350     addr += sizeof(buf);
351     }
352    
353     last_dump_addr = addr_end;
354    
355     strlcpy(repeat_cmd, "dump", MAX_CMD_BUFLEN);
356     }
357    
358    
359     /*
360     * debugger_cmd_emuls():
361     *
362     * Dump info about all current emuls.
363     */
364     static void debugger_cmd_emuls(struct machine *m, char *cmd_line)
365     {
366     int i, iadd = DEBUG_INDENTATION;
367    
368     if (*cmd_line) {
369     printf("syntax: emuls\n");
370     return;
371     }
372    
373     for (i=0; i<debugger_n_emuls; i++) {
374     struct emul *e = debugger_emuls[i];
375    
376     if (e == NULL)
377     continue;
378    
379     debug("emulation %i: \"%s\"\n", i,
380     e->name == NULL? "(no name)" : e->name);
381     debug_indentation(iadd);
382    
383     emul_dumpinfo(e);
384    
385     debug_indentation(-iadd);
386     }
387     }
388    
389    
390     /*
391     * debugger_cmd_focus():
392     *
393 dpavlin 32 * Changes focus to specific cpu, in a specific machine (in a specific
394     * emulation).
395 dpavlin 24 */
396     static void debugger_cmd_focus(struct machine *m, char *cmd_line)
397     {
398 dpavlin 32 int x = -1, y = -1, z = -1;
399     char *p, *p2;
400 dpavlin 24
401     if (!cmd_line[0]) {
402 dpavlin 32 printf("syntax: focus x[,y,[,z]]\n");
403     printf("where x (cpu id), y (machine number), and z (emul "
404     "number) are integers as\nreported by the 'emuls'"
405     " command.\n");
406 dpavlin 24 goto print_current_focus_and_return;
407     }
408    
409     x = atoi(cmd_line);
410     p = strchr(cmd_line, ',');
411     if (p == cmd_line) {
412 dpavlin 32 printf("No cpu number specified?\n");
413 dpavlin 24 return;
414     }
415    
416 dpavlin 32 if (p != NULL) {
417     y = atoi(p+1);
418     p2 = strchr(p+1, ',');
419     if (p2 == p+1) {
420     printf("No machine number specified?\n");
421     return;
422     }
423 dpavlin 24
424 dpavlin 32 if (p2 != NULL)
425     z = atoi(p2 + 1);
426     }
427    
428     if (z != -1) {
429 dpavlin 24 /* Change emul: */
430 dpavlin 32 if (z < 0 || z >= debugger_n_emuls) {
431     printf("Invalid emul number: %i\n", z);
432 dpavlin 24 return;
433     }
434    
435 dpavlin 32 debugger_cur_emul = z;
436     debugger_emul = debugger_emuls[z];
437 dpavlin 24
438     /* This is just in case the machine change below fails... */
439     debugger_machine = debugger_emul->machines[0];
440     }
441    
442 dpavlin 32 if (y != -1) {
443     /* Change machine: */
444     if (y < 0 || y >= debugger_emul->n_machines) {
445     printf("Invalid machine number: %i\n", y);
446     return;
447     }
448    
449     debugger_cur_machine = y;
450     debugger_machine = debugger_emul->machines[y];
451     }
452    
453     /* Change cpu: */
454     if (x < 0 || x >= debugger_machine->ncpus) {
455     printf("Invalid cpu number: %i\n", x);
456 dpavlin 24 return;
457     }
458    
459 dpavlin 32 debugger_cur_cpu = x;
460 dpavlin 24
461     print_current_focus_and_return:
462 dpavlin 32 if (debugger_n_emuls > 1)
463     printf("current emul (%i): \"%s\"\n",
464     debugger_cur_emul, debugger_emul->name == NULL?
465     "(no name)" : debugger_emul->name);
466    
467     if (debugger_emul->n_machines > 1)
468     printf("current machine (%i): \"%s\"\n",
469     debugger_cur_machine, debugger_machine->name == NULL?
470     "(no name)" : debugger_machine->name);
471    
472     printf("current cpu (%i)\n", debugger_cur_cpu);
473 dpavlin 24 }
474    
475    
476     /* This is defined below. */
477     static void debugger_cmd_help(struct machine *m, char *cmd_line);
478    
479    
480     /*
481     * debugger_cmd_itrace():
482     */
483     static void debugger_cmd_itrace(struct machine *m, char *cmd_line)
484     {
485     if (*cmd_line) {
486     printf("syntax: itrace\n");
487     return;
488     }
489    
490     old_instruction_trace = 1 - old_instruction_trace;
491     printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF");
492     /* TODO: how to preserve quiet_mode? */
493     old_quiet_mode = 0;
494     printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
495     }
496    
497    
498     /*
499     * debugger_cmd_lookup():
500     */
501     static void debugger_cmd_lookup(struct machine *m, char *cmd_line)
502     {
503     uint64_t addr;
504     int res;
505     char *symbol;
506     uint64_t offset;
507    
508     if (cmd_line[0] == '\0') {
509     printf("syntax: lookup name|addr\n");
510     return;
511    
512     }
513    
514     /* Addresses never need to be given in decimal form anyway,
515     so assuming hex here will be ok. */
516     addr = strtoull(cmd_line, NULL, 16);
517    
518     if (addr == 0) {
519     uint64_t newaddr;
520     res = get_symbol_addr(&m->symbol_context,
521     cmd_line, &newaddr);
522     if (!res) {
523     printf("lookup for '%s' failed\n", cmd_line);
524     return;
525     }
526     printf("%s = 0x", cmd_line);
527     if (m->cpus[0]->is_32bit)
528     printf("%08"PRIx32"\n", (uint32_t) newaddr);
529     else
530     printf("%016"PRIx64"\n", (uint64_t) newaddr);
531     return;
532     }
533    
534     symbol = get_symbol_name(&m->symbol_context, addr, &offset);
535    
536     if (symbol != NULL) {
537     if (m->cpus[0]->is_32bit)
538     printf("0x%08"PRIx32, (uint32_t) addr);
539     else
540     printf("0x%016"PRIx64, (uint64_t) addr);
541     printf(" = %s\n", symbol);
542     } else
543     printf("lookup for '%s' failed\n", cmd_line);
544     }
545    
546    
547     /*
548     * debugger_cmd_machine():
549     *
550     * Dump info about the currently focused machine.
551     */
552     static void debugger_cmd_machine(struct machine *m, char *cmd_line)
553     {
554     int iadd = DEBUG_INDENTATION;
555    
556     if (*cmd_line) {
557     printf("syntax: machine\n");
558     return;
559     }
560    
561     debug("machine \"%s\":\n", m->name);
562     debug_indentation(iadd);
563     machine_dumpinfo(m);
564     debug_indentation(-iadd);
565     }
566    
567    
568     /*
569     * debugger_cmd_ninstrs():
570     */
571     static void debugger_cmd_ninstrs(struct machine *m, char *cmd_line)
572     {
573     int toggle = 1;
574     int previous_mode = m->show_nr_of_instructions;
575    
576     if (cmd_line[0] != '\0') {
577     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
578     cmd_line ++;
579     switch (cmd_line[0]) {
580     case '0':
581     toggle = 0;
582     m->show_nr_of_instructions = 0;
583     break;
584     case '1':
585     toggle = 0;
586     m->show_nr_of_instructions = 1;
587     break;
588     case 'o':
589     case 'O':
590     toggle = 0;
591     switch (cmd_line[1]) {
592     case 'n':
593     case 'N':
594     m->show_nr_of_instructions = 1;
595     break;
596     default:
597     m->show_nr_of_instructions = 0;
598     }
599     break;
600     default:
601     printf("syntax: trace [on|off]\n");
602     return;
603     }
604     }
605    
606     if (toggle)
607     m->show_nr_of_instructions = !m->show_nr_of_instructions;
608    
609     printf("show_nr_of_instructions = %s",
610     m->show_nr_of_instructions? "ON" : "OFF");
611     if (m->show_nr_of_instructions != previous_mode)
612     printf(" (was: %s)", previous_mode? "ON" : "OFF");
613     printf("\n");
614     }
615    
616    
617     /*
618     * debugger_cmd_pause():
619     */
620     static void debugger_cmd_pause(struct machine *m, char *cmd_line)
621     {
622     int cpuid = -1;
623    
624     if (cmd_line[0] != '\0')
625     cpuid = atoi(cmd_line);
626     else {
627     printf("syntax: pause cpuid\n");
628     return;
629     }
630    
631     if (cpuid < 0 || cpuid >= m->ncpus) {
632     printf("cpu%i doesn't exist.\n", cpuid);
633     return;
634     }
635    
636     m->cpus[cpuid]->running ^= 1;
637    
638     printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid,
639     m->cpus[cpuid]->name, m->name,
640     m->cpus[cpuid]->running? "RUNNING" : "STOPPED");
641     }
642    
643    
644     /*
645     * debugger_cmd_print():
646     */
647     static void debugger_cmd_print(struct machine *m, char *cmd_line)
648     {
649     int res;
650     uint64_t tmp;
651    
652     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
653     cmd_line ++;
654    
655     if (cmd_line[0] == '\0') {
656     printf("syntax: print expr\n");
657     return;
658     }
659    
660 dpavlin 32 res = debugger_parse_expression(m, cmd_line, 0, &tmp);
661 dpavlin 24 switch (res) {
662 dpavlin 32 case PARSE_NOMATCH:
663 dpavlin 24 printf("No match.\n");
664     break;
665 dpavlin 32 case PARSE_MULTIPLE:
666 dpavlin 24 printf("Multiple matches. Try prefixing with %%, $, or @.\n");
667     break;
668 dpavlin 32 case PARSE_SETTINGS:
669 dpavlin 24 printf("%s = 0x%"PRIx64"\n", cmd_line, (uint64_t)tmp);
670     break;
671 dpavlin 32 case PARSE_SYMBOL:
672 dpavlin 24 if (m->cpus[0]->is_32bit)
673     printf("%s = 0x%08"PRIx32"\n", cmd_line, (uint32_t)tmp);
674     else
675     printf("%s = 0x%016"PRIx64"\n", cmd_line,(uint64_t)tmp);
676     break;
677 dpavlin 32 case PARSE_NUMBER:
678 dpavlin 24 printf("0x%"PRIx64"\n", (uint64_t) tmp);
679     break;
680     }
681     }
682    
683    
684     /*
685     * debugger_cmd_put():
686     */
687     static void debugger_cmd_put(struct machine *m, char *cmd_line)
688     {
689     static char put_type = ' '; /* Remembered across multiple calls. */
690     char copy[200];
691     int res, syntax_ok = 0;
692     char *p, *p2, *q = NULL;
693     uint64_t addr, data;
694     unsigned char a_byte;
695    
696     strncpy(copy, cmd_line, sizeof(copy));
697     copy[sizeof(copy)-1] = '\0';
698    
699     /* syntax: put [b|h|w|d|q] addr, data */
700    
701     p = strchr(copy, ',');
702     if (p != NULL) {
703     *p++ = '\0';
704     while (*p == ' ' && *p)
705     p++;
706     while (strlen(copy) >= 1 &&
707     copy[strlen(copy) - 1] == ' ')
708     copy[strlen(copy) - 1] = '\0';
709    
710     /* printf("L = '%s', R = '%s'\n", copy, p); */
711    
712     q = copy;
713     p2 = strchr(q, ' ');
714    
715     if (p2 != NULL) {
716     *p2 = '\0';
717     if (strlen(q) != 1) {
718     printf("Invalid type '%s'\n", q);
719     return;
720     }
721     put_type = *q;
722     q = p2 + 1;
723     }
724    
725     /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
726     syntax_ok = 1;
727     }
728    
729     if (!syntax_ok) {
730     printf("syntax: put [b|h|w|d|q] addr, data\n");
731     printf(" b byte (8 bits)\n");
732     printf(" h half-word (16 bits)\n");
733     printf(" w word (32 bits)\n");
734     printf(" d doubleword (64 bits)\n");
735     printf(" q quad-word (128 bits)\n");
736     return;
737     }
738    
739     if (put_type == ' ') {
740     printf("No type specified.\n");
741     return;
742     }
743    
744     /* here: q is the address, p is the data. */
745 dpavlin 32 res = debugger_parse_expression(m, q, 0, &addr);
746 dpavlin 24 switch (res) {
747 dpavlin 32 case PARSE_NOMATCH:
748 dpavlin 24 printf("Couldn't parse the address.\n");
749     return;
750 dpavlin 32 case PARSE_MULTIPLE:
751 dpavlin 24 printf("Multiple matches for the address."
752     " Try prefixing with %%, $, or @.\n");
753     return;
754 dpavlin 32 case PARSE_SETTINGS:
755     case PARSE_SYMBOL:
756     case PARSE_NUMBER:
757 dpavlin 24 break;
758     default:
759     printf("INTERNAL ERROR in debugger.c.\n");
760     return;
761     }
762    
763 dpavlin 32 res = debugger_parse_expression(m, p, 0, &data);
764 dpavlin 24 switch (res) {
765 dpavlin 32 case PARSE_NOMATCH:
766 dpavlin 24 printf("Couldn't parse the data.\n");
767     return;
768 dpavlin 32 case PARSE_MULTIPLE:
769 dpavlin 24 printf("Multiple matches for the data value."
770     " Try prefixing with %%, $, or @.\n");
771     return;
772 dpavlin 32 case PARSE_SETTINGS:
773     case PARSE_SYMBOL:
774     case PARSE_NUMBER:
775 dpavlin 24 break;
776     default:
777     printf("INTERNAL ERROR in debugger.c.\n");
778     return;
779     }
780    
781     /* TODO: haha, maybe this should be refactored */
782    
783     switch (put_type) {
784     case 'b':
785     a_byte = data;
786     if (m->cpus[0]->is_32bit)
787     printf("0x%08"PRIx32, (uint32_t) addr);
788     else
789     printf("0x%016"PRIx64, (uint64_t) addr);
790     printf(": %02x", a_byte);
791     if (data > 255)
792     printf(" (NOTE: truncating %0"PRIx64")",
793     (uint64_t) data);
794     res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
795     &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
796     if (!res)
797     printf(" FAILED!\n");
798     printf("\n");
799     return;
800     case 'h':
801     if ((addr & 1) != 0)
802     printf("WARNING: address isn't aligned\n");
803     if (m->cpus[0]->is_32bit)
804     printf("0x%08"PRIx32, (uint32_t) addr);
805     else
806     printf("0x%016"PRIx64, (uint64_t) addr);
807     printf(": %04x", (int)data);
808     if (data > 0xffff)
809     printf(" (NOTE: truncating %0"PRIx64")",
810     (uint64_t) data);
811     res = store_16bit_word(m->cpus[0], addr, data);
812     if (!res)
813     printf(" FAILED!\n");
814     printf("\n");
815     return;
816     case 'w':
817     if ((addr & 3) != 0)
818     printf("WARNING: address isn't aligned\n");
819     if (m->cpus[0]->is_32bit)
820     printf("0x%08"PRIx32, (uint32_t) addr);
821     else
822     printf("0x%016"PRIx64, (uint64_t) addr);
823    
824     printf(": %08x", (int)data);
825    
826     if (data > 0xffffffff && (data >> 32) != 0
827     && (data >> 32) != 0xffffffff)
828     printf(" (NOTE: truncating %0"PRIx64")",
829     (uint64_t) data);
830    
831     res = store_32bit_word(m->cpus[0], addr, data);
832     if (!res)
833     printf(" FAILED!\n");
834     printf("\n");
835     return;
836     case 'd':
837     if ((addr & 7) != 0)
838     printf("WARNING: address isn't aligned\n");
839     if (m->cpus[0]->is_32bit)
840     printf("0x%08"PRIx32, (uint32_t) addr);
841     else
842     printf("0x%016"PRIx64, (uint64_t) addr);
843    
844     printf(": %016"PRIx64, (uint64_t) data);
845    
846     res = store_64bit_word(m->cpus[0], addr, data);
847     if (!res)
848     printf(" FAILED!\n");
849     printf("\n");
850     return;
851     case 'q':
852     printf("quad-words: TODO\n");
853     /* TODO */
854     return;
855     default:
856     printf("Unimplemented type '%c'\n", put_type);
857     return;
858     }
859     }
860    
861    
862     /*
863     * debugger_cmd_quiet():
864     */
865     static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
866     {
867     int toggle = 1;
868     int previous_mode = old_quiet_mode;
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     old_quiet_mode = 0;
877     break;
878     case '1':
879     toggle = 0;
880     old_quiet_mode = 1;
881     break;
882     case 'o':
883     case 'O':
884     toggle = 0;
885     switch (cmd_line[1]) {
886     case 'n':
887     case 'N':
888     old_quiet_mode = 1;
889     break;
890     default:
891     old_quiet_mode = 0;
892     }
893     break;
894     default:
895     printf("syntax: quiet [on|off]\n");
896     return;
897     }
898     }
899    
900     if (toggle)
901     old_quiet_mode = 1 - old_quiet_mode;
902    
903     printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
904     if (old_quiet_mode != previous_mode)
905     printf(" (was: %s)", previous_mode? "ON" : "OFF");
906     printf("\n");
907     }
908    
909    
910     /*
911     * debugger_cmd_quit():
912     */
913     static void debugger_cmd_quit(struct machine *m, char *cmd_line)
914     {
915     int i, j, k;
916     struct emul *e;
917    
918     if (*cmd_line) {
919     printf("syntax: quit\n");
920     return;
921     }
922    
923     for (i=0; i<debugger_n_emuls; i++) {
924 dpavlin 26 single_step = NOT_SINGLE_STEPPING;
925 dpavlin 24
926     e = debugger_emuls[i];
927     force_debugger_at_exit = 0;
928    
929     for (j=0; j<e->n_machines; j++) {
930     struct machine *m = e->machines[j];
931    
932     for (k=0; k<m->ncpus; k++)
933     m->cpus[k]->running = 0;
934    
935     m->exit_without_entering_debugger = 1;
936     }
937     }
938    
939     exit_debugger = 1;
940     }
941    
942    
943     /*
944     * debugger_cmd_reg():
945     */
946     static void debugger_cmd_reg(struct machine *m, char *cmd_line)
947     {
948 dpavlin 32 int cpuid = debugger_cur_cpu, coprocnr = -1;
949 dpavlin 24 int gprs, coprocs;
950     char *p;
951    
952     /* [cpuid][,c] */
953     if (cmd_line[0] != '\0') {
954     if (cmd_line[0] != ',') {
955     cpuid = strtoull(cmd_line, NULL, 0);
956     if (cpuid < 0 || cpuid >= m->ncpus) {
957     printf("cpu%i doesn't exist.\n", cpuid);
958     return;
959     }
960     }
961     p = strchr(cmd_line, ',');
962     if (p != NULL) {
963     coprocnr = atoi(p + 1);
964     if (coprocnr < 0 || coprocnr >= 4) {
965     printf("Invalid coprocessor number.\n");
966     return;
967     }
968     }
969     }
970    
971     gprs = (coprocnr == -1)? 1 : 0;
972     coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
973    
974 dpavlin 32 cpu_register_dump(m, m->cpus[cpuid], gprs, coprocs);
975 dpavlin 24 }
976    
977    
978     /*
979     * debugger_cmd_step():
980     */
981     static void debugger_cmd_step(struct machine *m, char *cmd_line)
982     {
983     int n = 1;
984    
985     if (cmd_line[0] != '\0') {
986     n = strtoull(cmd_line, NULL, 0);
987     if (n < 1) {
988     printf("invalid nr of steps\n");
989     return;
990     }
991     }
992    
993     debugger_n_steps_left_before_interaction = n - 1;
994    
995     /* Special hack, see debugger() for more info. */
996     exit_debugger = -1;
997    
998     strlcpy(repeat_cmd, "step", MAX_CMD_BUFLEN);
999     }
1000    
1001    
1002     /*
1003     * debugger_cmd_tlbdump():
1004     *
1005     * Dump each CPU's TLB contents.
1006     */
1007     static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
1008     {
1009     int x = -1;
1010     int rawflag = 0;
1011    
1012     if (cmd_line[0] != '\0') {
1013     char *p;
1014     if (cmd_line[0] != ',') {
1015     x = strtoull(cmd_line, NULL, 0);
1016     if (x < 0 || x >= m->ncpus) {
1017     printf("cpu%i doesn't exist.\n", x);
1018     return;
1019     }
1020     }
1021     p = strchr(cmd_line, ',');
1022     if (p != NULL) {
1023     switch (p[1]) {
1024     case 'r':
1025     case 'R':
1026     rawflag = 1;
1027     break;
1028     default:
1029     printf("Unknown tlbdump flag.\n");
1030     printf("syntax: tlbdump [cpuid][,r]\n");
1031     return;
1032     }
1033     }
1034     }
1035    
1036     cpu_tlbdump(m, x, rawflag);
1037     }
1038    
1039    
1040     /*
1041     * debugger_cmd_trace():
1042     */
1043     static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1044     {
1045     int toggle = 1;
1046     int previous_mode = old_show_trace_tree;
1047    
1048     if (cmd_line[0] != '\0') {
1049     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1050     cmd_line ++;
1051     switch (cmd_line[0]) {
1052     case '0':
1053     toggle = 0;
1054     old_show_trace_tree = 0;
1055     break;
1056     case '1':
1057     toggle = 0;
1058     old_show_trace_tree = 1;
1059     break;
1060     case 'o':
1061     case 'O':
1062     toggle = 0;
1063     switch (cmd_line[1]) {
1064     case 'n':
1065     case 'N':
1066     old_show_trace_tree = 1;
1067     break;
1068     default:
1069     old_show_trace_tree = 0;
1070     }
1071     break;
1072     default:
1073     printf("syntax: trace [on|off]\n");
1074     return;
1075     }
1076     }
1077    
1078     if (toggle)
1079     old_show_trace_tree = 1 - old_show_trace_tree;
1080    
1081     printf("show_trace_tree = %s", old_show_trace_tree? "ON" : "OFF");
1082     if (old_show_trace_tree != previous_mode)
1083     printf(" (was: %s)", previous_mode? "ON" : "OFF");
1084     printf("\n");
1085     }
1086    
1087    
1088     /*
1089     * debugger_cmd_unassemble():
1090     *
1091     * Dump emulated memory as instructions.
1092     *
1093     * syntax: unassemble [addr [endaddr]]
1094     */
1095     static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1096     {
1097     uint64_t addr, addr_start, addr_end;
1098     struct cpu *c;
1099     struct memory *mem;
1100     char *p = NULL;
1101     int r, lines_left = -1;
1102    
1103     if (cmd_line[0] != '\0') {
1104     uint64_t tmp;
1105     char *tmps = strdup(cmd_line);
1106    
1107     /* addr: */
1108     p = strchr(tmps, ' ');
1109     if (p != NULL)
1110     *p = '\0';
1111 dpavlin 32 r = debugger_parse_expression(m, tmps, 0, &tmp);
1112 dpavlin 24 free(tmps);
1113    
1114 dpavlin 32 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1115 dpavlin 24 printf("Unparsable address: %s\n", cmd_line);
1116     return;
1117     } else {
1118     last_unasm_addr = tmp;
1119     }
1120    
1121     p = strchr(cmd_line, ' ');
1122     }
1123    
1124 dpavlin 32 if (m->cpus == NULL) {
1125     printf("No cpus (?)\n");
1126     return;
1127     }
1128     c = m->cpus[m->bootstrap_cpu];
1129     if (c == NULL) {
1130     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1131     return;
1132     }
1133     mem = m->cpus[m->bootstrap_cpu]->mem;
1134    
1135 dpavlin 24 addr_start = last_unasm_addr;
1136    
1137 dpavlin 32 if (addr_start == MAGIC_UNTOUCHED)
1138     addr_start = c->pc;
1139 dpavlin 24
1140     addr_end = addr_start + 1000;
1141    
1142     /* endaddr: */
1143     if (p != NULL) {
1144     while (*p == ' ' && *p)
1145     p++;
1146 dpavlin 32 r = debugger_parse_expression(m, p, 0, &addr_end);
1147     if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1148 dpavlin 24 printf("Unparsable address: %s\n", cmd_line);
1149     return;
1150     }
1151     } else
1152     lines_left = 20;
1153    
1154     addr = addr_start;
1155    
1156     ctrl_c = 0;
1157    
1158     while (addr < addr_end) {
1159     unsigned int i, len;
1160     int failed = 0;
1161     unsigned char buf[17]; /* TODO: How long can an
1162     instruction be, on weird archs? */
1163     memset(buf, 0, sizeof(buf));
1164    
1165     for (i=0; i<sizeof(buf); i++) {
1166     if (c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1167     CACHE_NONE | NO_EXCEPTIONS) == MEMORY_ACCESS_FAILED)
1168     failed ++;
1169     }
1170    
1171     if (failed == sizeof(buf)) {
1172     printf("(memory access failed)\n");
1173     break;
1174     }
1175    
1176     len = cpu_disassemble_instr(m, c, buf, 0, addr);
1177    
1178     if (ctrl_c)
1179     return;
1180     if (len == 0)
1181     break;
1182    
1183     addr += len;
1184    
1185     if (lines_left != -1) {
1186     lines_left --;
1187     if (lines_left == 0)
1188     break;
1189     }
1190     }
1191    
1192     last_unasm_addr = addr;
1193    
1194     strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN);
1195     }
1196    
1197    
1198     /*
1199     * debugger_cmd_version():
1200     */
1201     static void debugger_cmd_version(struct machine *m, char *cmd_line)
1202     {
1203     if (*cmd_line) {
1204     printf("syntax: version\n");
1205     return;
1206     }
1207    
1208     #ifdef VERSION
1209     printf("%s, %s\n", VERSION, COMPILE_DATE);
1210     #else
1211     printf("(no version), %s\n", COMPILE_DATE);
1212     #endif
1213     }
1214    
1215    
1216     /****************************************************************************/
1217    
1218    
1219     struct cmd {
1220     char *name;
1221     char *args;
1222     int tmp_flag;
1223     void (*f)(struct machine *, char *cmd_line);
1224     char *description;
1225     };
1226    
1227     static struct cmd cmds[] = {
1228     { "allsettings", "", 0, debugger_cmd_allsettings,
1229     "show all settings" },
1230    
1231     { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1232     "manipulate breakpoints" },
1233    
1234     /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1235     available as a one-letter command is very convenient. */
1236    
1237     { "continue", "", 0, debugger_cmd_continue,
1238     "continue execution" },
1239    
1240     { "device", "...", 0, debugger_cmd_device,
1241     "show info about (or manipulate) devices" },
1242    
1243     { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1244     "dump memory contents in hex and ASCII" },
1245    
1246     { "emuls", "", 0, debugger_cmd_emuls,
1247     "print a summary of all current emuls" },
1248    
1249 dpavlin 32 { "focus", "x[,y[,z]]", 0, debugger_cmd_focus,
1250     "changes focus to cpu x, machine x, emul z" },
1251 dpavlin 24
1252     { "help", "", 0, debugger_cmd_help,
1253     "print this help message" },
1254    
1255     { "itrace", "", 0, debugger_cmd_itrace,
1256     "toggle instruction_trace on or off" },
1257    
1258     { "lookup", "name|addr", 0, debugger_cmd_lookup,
1259     "lookup a symbol by name or address" },
1260    
1261     { "machine", "", 0, debugger_cmd_machine,
1262     "print a summary of the current machine" },
1263    
1264     { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs,
1265     "toggle (set or unset) show_nr_of_instructions" },
1266    
1267     { "pause", "cpuid", 0, debugger_cmd_pause,
1268     "pause (or unpause) a CPU" },
1269    
1270     { "print", "expr", 0, debugger_cmd_print,
1271     "evaluate an expression without side-effects" },
1272    
1273     { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1274     "modify emulated memory contents" },
1275    
1276     { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1277     "toggle quiet_mode on or off" },
1278    
1279     { "quit", "", 0, debugger_cmd_quit,
1280     "quit the emulator" },
1281    
1282     /* NOTE: Try to keep 'r' down to only one command. Having 'reg'
1283     available as a one-letter command is very convenient. */
1284    
1285     { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1286     "show GPRs (or coprocessor c's registers)" },
1287    
1288     /* NOTE: Try to keep 's' down to only one command. Having 'step'
1289     available as a one-letter command is very convenient. */
1290    
1291     { "step", "[n]", 0, debugger_cmd_step,
1292     "single-step one (or n) instruction(s)" },
1293    
1294     { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1295     "dump TLB contents (add ',r' for raw data)" },
1296    
1297     { "trace", "[on|off]", 0, debugger_cmd_trace,
1298     "toggle show_trace_tree on or off" },
1299    
1300     { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1301     "dump memory contents as instructions" },
1302    
1303     { "version", "", 0, debugger_cmd_version,
1304     "print version information" },
1305    
1306     /* Note: NULL handler. */
1307     { "x = expr", "", 0, NULL, "generic assignment" },
1308    
1309     { NULL, NULL, 0, NULL, NULL }
1310     };
1311    
1312    
1313     /*
1314     * debugger_cmd_help():
1315     *
1316     * Print a list of available commands.
1317     *
1318     * NOTE: This is placed after the cmds[] array, because it needs to
1319     * access it.
1320     *
1321     * TODO: Command completion (ie just type "help s" for "help step").
1322     */
1323     static void debugger_cmd_help(struct machine *m, char *cmd_line)
1324     {
1325     int only_one = 0, only_one_match = 0;
1326     char *nlines_env = getenv("LINES");
1327     int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines;
1328     size_t i, j, max_name_len = 0;
1329    
1330     if (cmd_line[0] != '\0') {
1331     only_one = 1;
1332     }
1333    
1334     i = 0;
1335     while (cmds[i].name != NULL) {
1336     size_t a = strlen(cmds[i].name);
1337     if (cmds[i].args != NULL)
1338     a += 1 + strlen(cmds[i].args);
1339     if (a > max_name_len)
1340     max_name_len = a;
1341     i++;
1342     }
1343    
1344     curlines = 0;
1345     if (!only_one) {
1346     printf("Available commands:\n");
1347     curlines++;
1348     }
1349    
1350     i = 0;
1351     while (cmds[i].name != NULL) {
1352     char buf[100];
1353     snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1354    
1355     if (only_one) {
1356     if (strcmp(cmds[i].name, cmd_line) != 0) {
1357     i++;
1358     continue;
1359     }
1360     only_one_match = 1;
1361     }
1362    
1363     if (cmds[i].args != NULL)
1364     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1365     " %s", cmds[i].args);
1366    
1367     printf(" ");
1368     for (j=0; j<max_name_len; j++)
1369     if (j < strlen(buf))
1370     printf("%c", buf[j]);
1371     else
1372     printf(" ");
1373    
1374     printf(" %s\n", cmds[i].description);
1375     i++;
1376    
1377     curlines ++;
1378     if (curlines >= nlines - 1) {
1379     char ch;
1380     printf("-- more --"); fflush(stdout);
1381     ch = debugger_readchar();
1382     printf("\n");
1383     if (ch == 'q' || ch == 'Q')
1384     return;
1385     curlines = 0;
1386     }
1387     }
1388    
1389     if (only_one) {
1390     if (!only_one_match)
1391     printf("%s: no such command\n", cmd_line);
1392     return;
1393     }
1394    
1395     /* TODO: generalize/refactor */
1396     curlines += 8;
1397     if (curlines > nlines - 1) {
1398     char ch;
1399     printf("-- more --"); fflush(stdout);
1400     ch = debugger_readchar();
1401     printf("\n");
1402     if (ch == 'q' || ch == 'Q')
1403     return;
1404     curlines = 0;
1405     }
1406    
1407 dpavlin 32 printf("\nIn generic assignments, x must be a register or other "
1408     "writable settings\nvariable, and expr can contain registers/"
1409     "settings, numeric values, or symbol\nnames, in combination with"
1410 dpavlin 34 " parenthesis and + - * / & %% ^ | operators.\nIn case there are"
1411 dpavlin 32 " multiple matches (i.e. a symbol that has the same name as a\n"
1412     "register), you may add a prefix character as a hint: '#' for"
1413     " registers, '@'\nfor symbols, and '$' for numeric values. Use"
1414     " 0x for hexadecimal values.\n");
1415 dpavlin 24 }
1416    

  ViewVC Help
Powered by ViewVC 1.1.26