/[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 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31312 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


1 dpavlin 24 /*
2     * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28     * $Id: debugger_cmds.c,v 1.4 2006/06/16 18:31:26 debug Exp $
29     *
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     res = debugger_parse_name(m, cmd_line + 4, 0, &tmp);
115     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     i, mem->dev_name[i],
212     (uint64_t) mem->dev_baseaddr[i],
213     (uint64_t) mem->dev_length[i]);
214    
215     if (mem->dev_flags[i]) {
216     printf(" (");
217     if (mem->dev_flags[i] & DM_DYNTRANS_OK)
218     printf("DYNTRANS R");
219     if (mem->dev_flags[i] & DM_DYNTRANS_WRITE_OK)
220     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     r = debugger_parse_name(m, tmps, 0, &tmp);
268     free(tmps);
269    
270     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
271     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     addr_start = last_dump_addr;
281    
282     if (addr_start == MAGIC_UNTOUCHED) {
283     uint64_t tmp;
284     int match_register = 0;
285     cpu_register_match(m, "pc", 0, &tmp, &match_register);
286     if (match_register) {
287     addr_start = tmp;
288     } else {
289     printf("No starting address.\n");
290     return;
291     }
292     }
293    
294     addr_end = addr_start + 16 * 16;
295    
296     /* endaddr: */
297     if (p != NULL) {
298     while (*p == ' ' && *p)
299     p++;
300     r = debugger_parse_name(m, p, 0, &addr_end);
301     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
302     printf("Unparsable address: %s\n", cmd_line);
303     return;
304     }
305     }
306    
307     if (m->cpus == NULL) {
308     printf("No cpus (?)\n");
309     return;
310     }
311     c = m->cpus[m->bootstrap_cpu];
312     if (c == NULL) {
313     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
314     return;
315     }
316     mem = m->cpus[m->bootstrap_cpu]->mem;
317    
318     addr = addr_start & ~0xf;
319    
320     ctrl_c = 0;
321    
322     while (addr < addr_end) {
323     unsigned char buf[16];
324     memset(buf, 0, sizeof(buf));
325     r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf),
326     MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
327    
328     if (c->is_32bit)
329     printf("0x%08"PRIx32" ", (uint32_t) addr);
330     else
331     printf("0x%016"PRIx64" ", (uint64_t) addr);
332    
333     if (r == MEMORY_ACCESS_FAILED)
334     printf("(memory access failed)\n");
335     else {
336     for (x=0; x<16; x++) {
337     if (addr + x >= addr_start &&
338     addr + x < addr_end)
339     printf("%02x%s", buf[x],
340     (x&3)==3? " " : "");
341     else
342     printf(" %s", (x&3)==3? " " : "");
343     }
344     printf(" ");
345     for (x=0; x<16; x++) {
346     if (addr + x >= addr_start &&
347     addr + x < addr_end)
348     printf("%c", (buf[x]>=' ' &&
349     buf[x]<127)? buf[x] : '.');
350     else
351     printf(" ");
352     }
353     printf("\n");
354     }
355    
356     if (ctrl_c)
357     return;
358    
359     addr += sizeof(buf);
360     }
361    
362     last_dump_addr = addr_end;
363    
364     strlcpy(repeat_cmd, "dump", MAX_CMD_BUFLEN);
365     }
366    
367    
368     /*
369     * debugger_cmd_emuls():
370     *
371     * Dump info about all current emuls.
372     */
373     static void debugger_cmd_emuls(struct machine *m, char *cmd_line)
374     {
375     int i, iadd = DEBUG_INDENTATION;
376    
377     if (*cmd_line) {
378     printf("syntax: emuls\n");
379     return;
380     }
381    
382     for (i=0; i<debugger_n_emuls; i++) {
383     struct emul *e = debugger_emuls[i];
384    
385     if (e == NULL)
386     continue;
387    
388     debug("emulation %i: \"%s\"\n", i,
389     e->name == NULL? "(no name)" : e->name);
390     debug_indentation(iadd);
391    
392     emul_dumpinfo(e);
393    
394     debug_indentation(-iadd);
395     }
396     }
397    
398    
399     /*
400     * debugger_cmd_focus():
401     *
402     * Changes focus to specific machine (in a specific emulation).
403     */
404     static void debugger_cmd_focus(struct machine *m, char *cmd_line)
405     {
406     int x = -1, y = -1;
407     char *p;
408    
409     if (!cmd_line[0]) {
410     printf("syntax: focus x[,y]\n");
411     printf("where x and y are integers as reported by the"
412     " 'emuls' command\n");
413     goto print_current_focus_and_return;
414     }
415    
416     x = atoi(cmd_line);
417     p = strchr(cmd_line, ',');
418     if (p == cmd_line) {
419     printf("No machine number specified?\n");
420     printf("syntax: focus x[,y]\n");
421     return;
422     }
423    
424     if (p != NULL)
425     y = atoi(p + 1);
426    
427     if (y != -1) {
428     /* Change emul: */
429     if (y < 0 || y >= debugger_n_emuls) {
430     printf("Invalid emul number: %i\n", y);
431     return;
432     }
433    
434     debugger_emul = debugger_emuls[y];
435    
436     /* This is just in case the machine change below fails... */
437     debugger_machine = debugger_emul->machines[0];
438     }
439    
440     /* Change machine: */
441     if (x < 0 || x >= debugger_emul->n_machines) {
442     printf("Invalid machine number: %i\n", x);
443     return;
444     }
445    
446     debugger_machine = debugger_emul->machines[x];
447    
448     print_current_focus_and_return:
449     printf("current emul: \"%s\"\n", debugger_emul->name == NULL?
450     "(no name)" : debugger_emul->name);
451     printf("current machine: \"%s\"\n", debugger_machine->name == NULL?
452     "(no name)" : debugger_machine->name);
453     }
454    
455    
456     /* This is defined below. */
457     static void debugger_cmd_help(struct machine *m, char *cmd_line);
458    
459    
460     /*
461     * debugger_cmd_itrace():
462     */
463     static void debugger_cmd_itrace(struct machine *m, char *cmd_line)
464     {
465     if (*cmd_line) {
466     printf("syntax: itrace\n");
467     return;
468     }
469    
470     old_instruction_trace = 1 - old_instruction_trace;
471     printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF");
472     /* TODO: how to preserve quiet_mode? */
473     old_quiet_mode = 0;
474     printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
475     }
476    
477    
478     /*
479     * debugger_cmd_lookup():
480     */
481     static void debugger_cmd_lookup(struct machine *m, char *cmd_line)
482     {
483     uint64_t addr;
484     int res;
485     char *symbol;
486     uint64_t offset;
487    
488     if (cmd_line[0] == '\0') {
489     printf("syntax: lookup name|addr\n");
490     return;
491    
492     }
493    
494     /* Addresses never need to be given in decimal form anyway,
495     so assuming hex here will be ok. */
496     addr = strtoull(cmd_line, NULL, 16);
497    
498     if (addr == 0) {
499     uint64_t newaddr;
500     res = get_symbol_addr(&m->symbol_context,
501     cmd_line, &newaddr);
502     if (!res) {
503     printf("lookup for '%s' failed\n", cmd_line);
504     return;
505     }
506     printf("%s = 0x", cmd_line);
507     if (m->cpus[0]->is_32bit)
508     printf("%08"PRIx32"\n", (uint32_t) newaddr);
509     else
510     printf("%016"PRIx64"\n", (uint64_t) newaddr);
511     return;
512     }
513    
514     symbol = get_symbol_name(&m->symbol_context, addr, &offset);
515    
516     if (symbol != NULL) {
517     if (m->cpus[0]->is_32bit)
518     printf("0x%08"PRIx32, (uint32_t) addr);
519     else
520     printf("0x%016"PRIx64, (uint64_t) addr);
521     printf(" = %s\n", symbol);
522     } else
523     printf("lookup for '%s' failed\n", cmd_line);
524     }
525    
526    
527     /*
528     * debugger_cmd_machine():
529     *
530     * Dump info about the currently focused machine.
531     */
532     static void debugger_cmd_machine(struct machine *m, char *cmd_line)
533     {
534     int iadd = DEBUG_INDENTATION;
535    
536     if (*cmd_line) {
537     printf("syntax: machine\n");
538     return;
539     }
540    
541     debug("machine \"%s\":\n", m->name);
542     debug_indentation(iadd);
543     machine_dumpinfo(m);
544     debug_indentation(-iadd);
545     }
546    
547    
548     /*
549     * debugger_cmd_ninstrs():
550     */
551     static void debugger_cmd_ninstrs(struct machine *m, char *cmd_line)
552     {
553     int toggle = 1;
554     int previous_mode = m->show_nr_of_instructions;
555    
556     if (cmd_line[0] != '\0') {
557     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
558     cmd_line ++;
559     switch (cmd_line[0]) {
560     case '0':
561     toggle = 0;
562     m->show_nr_of_instructions = 0;
563     break;
564     case '1':
565     toggle = 0;
566     m->show_nr_of_instructions = 1;
567     break;
568     case 'o':
569     case 'O':
570     toggle = 0;
571     switch (cmd_line[1]) {
572     case 'n':
573     case 'N':
574     m->show_nr_of_instructions = 1;
575     break;
576     default:
577     m->show_nr_of_instructions = 0;
578     }
579     break;
580     default:
581     printf("syntax: trace [on|off]\n");
582     return;
583     }
584     }
585    
586     if (toggle)
587     m->show_nr_of_instructions = !m->show_nr_of_instructions;
588    
589     printf("show_nr_of_instructions = %s",
590     m->show_nr_of_instructions? "ON" : "OFF");
591     if (m->show_nr_of_instructions != previous_mode)
592     printf(" (was: %s)", previous_mode? "ON" : "OFF");
593     printf("\n");
594     }
595    
596    
597     /*
598     * debugger_cmd_pause():
599     */
600     static void debugger_cmd_pause(struct machine *m, char *cmd_line)
601     {
602     int cpuid = -1;
603    
604     if (cmd_line[0] != '\0')
605     cpuid = atoi(cmd_line);
606     else {
607     printf("syntax: pause cpuid\n");
608     return;
609     }
610    
611     if (cpuid < 0 || cpuid >= m->ncpus) {
612     printf("cpu%i doesn't exist.\n", cpuid);
613     return;
614     }
615    
616     m->cpus[cpuid]->running ^= 1;
617    
618     printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid,
619     m->cpus[cpuid]->name, m->name,
620     m->cpus[cpuid]->running? "RUNNING" : "STOPPED");
621     }
622    
623    
624     /*
625     * debugger_cmd_print():
626     */
627     static void debugger_cmd_print(struct machine *m, char *cmd_line)
628     {
629     int res;
630     uint64_t tmp;
631    
632     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
633     cmd_line ++;
634    
635     if (cmd_line[0] == '\0') {
636     printf("syntax: print expr\n");
637     return;
638     }
639    
640     res = debugger_parse_name(m, cmd_line, 0, &tmp);
641     switch (res) {
642     case NAME_PARSE_NOMATCH:
643     printf("No match.\n");
644     break;
645     case NAME_PARSE_MULTIPLE:
646     printf("Multiple matches. Try prefixing with %%, $, or @.\n");
647     break;
648     case NAME_PARSE_REGISTER:
649     printf("%s = 0x%"PRIx64"\n", cmd_line, (uint64_t)tmp);
650     break;
651     case NAME_PARSE_SYMBOL:
652     if (m->cpus[0]->is_32bit)
653     printf("%s = 0x%08"PRIx32"\n", cmd_line, (uint32_t)tmp);
654     else
655     printf("%s = 0x%016"PRIx64"\n", cmd_line,(uint64_t)tmp);
656     break;
657     case NAME_PARSE_NUMBER:
658     printf("0x%"PRIx64"\n", (uint64_t) tmp);
659     break;
660     }
661     }
662    
663    
664     /*
665     * debugger_cmd_put():
666     */
667     static void debugger_cmd_put(struct machine *m, char *cmd_line)
668     {
669     static char put_type = ' '; /* Remembered across multiple calls. */
670     char copy[200];
671     int res, syntax_ok = 0;
672     char *p, *p2, *q = NULL;
673     uint64_t addr, data;
674     unsigned char a_byte;
675    
676     strncpy(copy, cmd_line, sizeof(copy));
677     copy[sizeof(copy)-1] = '\0';
678    
679     /* syntax: put [b|h|w|d|q] addr, data */
680    
681     p = strchr(copy, ',');
682     if (p != NULL) {
683     *p++ = '\0';
684     while (*p == ' ' && *p)
685     p++;
686     while (strlen(copy) >= 1 &&
687     copy[strlen(copy) - 1] == ' ')
688     copy[strlen(copy) - 1] = '\0';
689    
690     /* printf("L = '%s', R = '%s'\n", copy, p); */
691    
692     q = copy;
693     p2 = strchr(q, ' ');
694    
695     if (p2 != NULL) {
696     *p2 = '\0';
697     if (strlen(q) != 1) {
698     printf("Invalid type '%s'\n", q);
699     return;
700     }
701     put_type = *q;
702     q = p2 + 1;
703     }
704    
705     /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
706     syntax_ok = 1;
707     }
708    
709     if (!syntax_ok) {
710     printf("syntax: put [b|h|w|d|q] addr, data\n");
711     printf(" b byte (8 bits)\n");
712     printf(" h half-word (16 bits)\n");
713     printf(" w word (32 bits)\n");
714     printf(" d doubleword (64 bits)\n");
715     printf(" q quad-word (128 bits)\n");
716     return;
717     }
718    
719     if (put_type == ' ') {
720     printf("No type specified.\n");
721     return;
722     }
723    
724     /* here: q is the address, p is the data. */
725     res = debugger_parse_name(m, q, 0, &addr);
726     switch (res) {
727     case NAME_PARSE_NOMATCH:
728     printf("Couldn't parse the address.\n");
729     return;
730     case NAME_PARSE_MULTIPLE:
731     printf("Multiple matches for the address."
732     " Try prefixing with %%, $, or @.\n");
733     return;
734     case NAME_PARSE_REGISTER:
735     case NAME_PARSE_SYMBOL:
736     case NAME_PARSE_NUMBER:
737     break;
738     default:
739     printf("INTERNAL ERROR in debugger.c.\n");
740     return;
741     }
742    
743     res = debugger_parse_name(m, p, 0, &data);
744     switch (res) {
745     case NAME_PARSE_NOMATCH:
746     printf("Couldn't parse the data.\n");
747     return;
748     case NAME_PARSE_MULTIPLE:
749     printf("Multiple matches for the data value."
750     " Try prefixing with %%, $, or @.\n");
751     return;
752     case NAME_PARSE_REGISTER:
753     case NAME_PARSE_SYMBOL:
754     case NAME_PARSE_NUMBER:
755     break;
756     default:
757     printf("INTERNAL ERROR in debugger.c.\n");
758     return;
759     }
760    
761     /* TODO: haha, maybe this should be refactored */
762    
763     switch (put_type) {
764     case 'b':
765     a_byte = data;
766     if (m->cpus[0]->is_32bit)
767     printf("0x%08"PRIx32, (uint32_t) addr);
768     else
769     printf("0x%016"PRIx64, (uint64_t) addr);
770     printf(": %02x", a_byte);
771     if (data > 255)
772     printf(" (NOTE: truncating %0"PRIx64")",
773     (uint64_t) data);
774     res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
775     &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
776     if (!res)
777     printf(" FAILED!\n");
778     printf("\n");
779     return;
780     case 'h':
781     if ((addr & 1) != 0)
782     printf("WARNING: address isn't aligned\n");
783     if (m->cpus[0]->is_32bit)
784     printf("0x%08"PRIx32, (uint32_t) addr);
785     else
786     printf("0x%016"PRIx64, (uint64_t) addr);
787     printf(": %04x", (int)data);
788     if (data > 0xffff)
789     printf(" (NOTE: truncating %0"PRIx64")",
790     (uint64_t) data);
791     res = store_16bit_word(m->cpus[0], addr, data);
792     if (!res)
793     printf(" FAILED!\n");
794     printf("\n");
795     return;
796     case 'w':
797     if ((addr & 3) != 0)
798     printf("WARNING: address isn't aligned\n");
799     if (m->cpus[0]->is_32bit)
800     printf("0x%08"PRIx32, (uint32_t) addr);
801     else
802     printf("0x%016"PRIx64, (uint64_t) addr);
803    
804     printf(": %08x", (int)data);
805    
806     if (data > 0xffffffff && (data >> 32) != 0
807     && (data >> 32) != 0xffffffff)
808     printf(" (NOTE: truncating %0"PRIx64")",
809     (uint64_t) data);
810    
811     res = store_32bit_word(m->cpus[0], addr, data);
812     if (!res)
813     printf(" FAILED!\n");
814     printf("\n");
815     return;
816     case 'd':
817     if ((addr & 7) != 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(": %016"PRIx64, (uint64_t) data);
825    
826     res = store_64bit_word(m->cpus[0], addr, data);
827     if (!res)
828     printf(" FAILED!\n");
829     printf("\n");
830     return;
831     case 'q':
832     printf("quad-words: TODO\n");
833     /* TODO */
834     return;
835     default:
836     printf("Unimplemented type '%c'\n", put_type);
837     return;
838     }
839     }
840    
841    
842     /*
843     * debugger_cmd_quiet():
844     */
845     static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
846     {
847     int toggle = 1;
848     int previous_mode = old_quiet_mode;
849    
850     if (cmd_line[0] != '\0') {
851     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
852     cmd_line ++;
853     switch (cmd_line[0]) {
854     case '0':
855     toggle = 0;
856     old_quiet_mode = 0;
857     break;
858     case '1':
859     toggle = 0;
860     old_quiet_mode = 1;
861     break;
862     case 'o':
863     case 'O':
864     toggle = 0;
865     switch (cmd_line[1]) {
866     case 'n':
867     case 'N':
868     old_quiet_mode = 1;
869     break;
870     default:
871     old_quiet_mode = 0;
872     }
873     break;
874     default:
875     printf("syntax: quiet [on|off]\n");
876     return;
877     }
878     }
879    
880     if (toggle)
881     old_quiet_mode = 1 - old_quiet_mode;
882    
883     printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
884     if (old_quiet_mode != previous_mode)
885     printf(" (was: %s)", previous_mode? "ON" : "OFF");
886     printf("\n");
887     }
888    
889    
890     /*
891     * debugger_cmd_quit():
892     */
893     static void debugger_cmd_quit(struct machine *m, char *cmd_line)
894     {
895     int i, j, k;
896     struct emul *e;
897    
898     if (*cmd_line) {
899     printf("syntax: quit\n");
900     return;
901     }
902    
903     for (i=0; i<debugger_n_emuls; i++) {
904     single_step = 0;
905    
906     e = debugger_emuls[i];
907     force_debugger_at_exit = 0;
908    
909     for (j=0; j<e->n_machines; j++) {
910     struct machine *m = e->machines[j];
911    
912     for (k=0; k<m->ncpus; k++)
913     m->cpus[k]->running = 0;
914    
915     m->exit_without_entering_debugger = 1;
916     }
917     }
918    
919     exit_debugger = 1;
920     }
921    
922    
923     /*
924     * debugger_cmd_reg():
925     */
926     static void debugger_cmd_reg(struct machine *m, char *cmd_line)
927     {
928     int i, cpuid = -1, coprocnr = -1;
929     int gprs, coprocs;
930     char *p;
931    
932     /* [cpuid][,c] */
933     if (cmd_line[0] != '\0') {
934     if (cmd_line[0] != ',') {
935     cpuid = strtoull(cmd_line, NULL, 0);
936     if (cpuid < 0 || cpuid >= m->ncpus) {
937     printf("cpu%i doesn't exist.\n", cpuid);
938     return;
939     }
940     }
941     p = strchr(cmd_line, ',');
942     if (p != NULL) {
943     coprocnr = atoi(p + 1);
944     if (coprocnr < 0 || coprocnr >= 4) {
945     printf("Invalid coprocessor number.\n");
946     return;
947     }
948     }
949     }
950    
951     gprs = (coprocnr == -1)? 1 : 0;
952     coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
953    
954     for (i=0; i<m->ncpus; i++)
955     if (cpuid == -1 || i == cpuid)
956     cpu_register_dump(m, m->cpus[i], gprs, coprocs);
957     }
958    
959    
960     /*
961     * debugger_cmd_step():
962     */
963     static void debugger_cmd_step(struct machine *m, char *cmd_line)
964     {
965     int n = 1;
966    
967     if (cmd_line[0] != '\0') {
968     n = strtoull(cmd_line, NULL, 0);
969     if (n < 1) {
970     printf("invalid nr of steps\n");
971     return;
972     }
973     }
974    
975     debugger_n_steps_left_before_interaction = n - 1;
976    
977     /* Special hack, see debugger() for more info. */
978     exit_debugger = -1;
979    
980     strlcpy(repeat_cmd, "step", MAX_CMD_BUFLEN);
981     }
982    
983    
984     /*
985     * debugger_cmd_tlbdump():
986     *
987     * Dump each CPU's TLB contents.
988     */
989     static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
990     {
991     int x = -1;
992     int rawflag = 0;
993    
994     if (cmd_line[0] != '\0') {
995     char *p;
996     if (cmd_line[0] != ',') {
997     x = strtoull(cmd_line, NULL, 0);
998     if (x < 0 || x >= m->ncpus) {
999     printf("cpu%i doesn't exist.\n", x);
1000     return;
1001     }
1002     }
1003     p = strchr(cmd_line, ',');
1004     if (p != NULL) {
1005     switch (p[1]) {
1006     case 'r':
1007     case 'R':
1008     rawflag = 1;
1009     break;
1010     default:
1011     printf("Unknown tlbdump flag.\n");
1012     printf("syntax: tlbdump [cpuid][,r]\n");
1013     return;
1014     }
1015     }
1016     }
1017    
1018     cpu_tlbdump(m, x, rawflag);
1019     }
1020    
1021    
1022     /*
1023     * debugger_cmd_trace():
1024     */
1025     static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1026     {
1027     int toggle = 1;
1028     int previous_mode = old_show_trace_tree;
1029    
1030     if (cmd_line[0] != '\0') {
1031     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1032     cmd_line ++;
1033     switch (cmd_line[0]) {
1034     case '0':
1035     toggle = 0;
1036     old_show_trace_tree = 0;
1037     break;
1038     case '1':
1039     toggle = 0;
1040     old_show_trace_tree = 1;
1041     break;
1042     case 'o':
1043     case 'O':
1044     toggle = 0;
1045     switch (cmd_line[1]) {
1046     case 'n':
1047     case 'N':
1048     old_show_trace_tree = 1;
1049     break;
1050     default:
1051     old_show_trace_tree = 0;
1052     }
1053     break;
1054     default:
1055     printf("syntax: trace [on|off]\n");
1056     return;
1057     }
1058     }
1059    
1060     if (toggle)
1061     old_show_trace_tree = 1 - old_show_trace_tree;
1062    
1063     printf("show_trace_tree = %s", old_show_trace_tree? "ON" : "OFF");
1064     if (old_show_trace_tree != previous_mode)
1065     printf(" (was: %s)", previous_mode? "ON" : "OFF");
1066     printf("\n");
1067     }
1068    
1069    
1070     /*
1071     * debugger_cmd_unassemble():
1072     *
1073     * Dump emulated memory as instructions.
1074     *
1075     * syntax: unassemble [addr [endaddr]]
1076     */
1077     static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1078     {
1079     uint64_t addr, addr_start, addr_end;
1080     struct cpu *c;
1081     struct memory *mem;
1082     char *p = NULL;
1083     int r, lines_left = -1;
1084    
1085     if (cmd_line[0] != '\0') {
1086     uint64_t tmp;
1087     char *tmps = strdup(cmd_line);
1088    
1089     /* addr: */
1090     p = strchr(tmps, ' ');
1091     if (p != NULL)
1092     *p = '\0';
1093     r = debugger_parse_name(m, tmps, 0, &tmp);
1094     free(tmps);
1095    
1096     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1097     printf("Unparsable address: %s\n", cmd_line);
1098     return;
1099     } else {
1100     last_unasm_addr = tmp;
1101     }
1102    
1103     p = strchr(cmd_line, ' ');
1104     }
1105    
1106     addr_start = last_unasm_addr;
1107    
1108     if (addr_start == MAGIC_UNTOUCHED) {
1109     uint64_t tmp;
1110     int match_register = 0;
1111     cpu_register_match(m, "pc", 0, &tmp, &match_register);
1112     if (match_register) {
1113     addr_start = tmp;
1114     } else {
1115     printf("No starting address.\n");
1116     return;
1117     }
1118     }
1119    
1120     addr_end = addr_start + 1000;
1121    
1122     /* endaddr: */
1123     if (p != NULL) {
1124     while (*p == ' ' && *p)
1125     p++;
1126     r = debugger_parse_name(m, p, 0, &addr_end);
1127     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1128     printf("Unparsable address: %s\n", cmd_line);
1129     return;
1130     }
1131     } else
1132     lines_left = 20;
1133    
1134     if (m->cpus == NULL) {
1135     printf("No cpus (?)\n");
1136     return;
1137     }
1138     c = m->cpus[m->bootstrap_cpu];
1139     if (c == NULL) {
1140     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1141     return;
1142     }
1143     mem = m->cpus[m->bootstrap_cpu]->mem;
1144    
1145     addr = addr_start;
1146    
1147     ctrl_c = 0;
1148    
1149     while (addr < addr_end) {
1150     unsigned int i, len;
1151     int failed = 0;
1152     unsigned char buf[17]; /* TODO: How long can an
1153     instruction be, on weird archs? */
1154     memset(buf, 0, sizeof(buf));
1155    
1156     for (i=0; i<sizeof(buf); i++) {
1157     if (c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1158     CACHE_NONE | NO_EXCEPTIONS) == MEMORY_ACCESS_FAILED)
1159     failed ++;
1160     }
1161    
1162     if (failed == sizeof(buf)) {
1163     printf("(memory access failed)\n");
1164     break;
1165     }
1166    
1167     len = cpu_disassemble_instr(m, c, buf, 0, addr);
1168    
1169     if (ctrl_c)
1170     return;
1171     if (len == 0)
1172     break;
1173    
1174     addr += len;
1175    
1176     if (lines_left != -1) {
1177     lines_left --;
1178     if (lines_left == 0)
1179     break;
1180     }
1181     }
1182    
1183     last_unasm_addr = addr;
1184    
1185     strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN);
1186     }
1187    
1188    
1189     /*
1190     * debugger_cmd_version():
1191     */
1192     static void debugger_cmd_version(struct machine *m, char *cmd_line)
1193     {
1194     if (*cmd_line) {
1195     printf("syntax: version\n");
1196     return;
1197     }
1198    
1199     #ifdef VERSION
1200     printf("%s, %s\n", VERSION, COMPILE_DATE);
1201     #else
1202     printf("(no version), %s\n", COMPILE_DATE);
1203     #endif
1204     }
1205    
1206    
1207     /****************************************************************************/
1208    
1209    
1210     struct cmd {
1211     char *name;
1212     char *args;
1213     int tmp_flag;
1214     void (*f)(struct machine *, char *cmd_line);
1215     char *description;
1216     };
1217    
1218     static struct cmd cmds[] = {
1219     { "allsettings", "", 0, debugger_cmd_allsettings,
1220     "show all settings" },
1221    
1222     { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1223     "manipulate breakpoints" },
1224    
1225     /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1226     available as a one-letter command is very convenient. */
1227    
1228     { "continue", "", 0, debugger_cmd_continue,
1229     "continue execution" },
1230    
1231     { "device", "...", 0, debugger_cmd_device,
1232     "show info about (or manipulate) devices" },
1233    
1234     { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1235     "dump memory contents in hex and ASCII" },
1236    
1237     { "emuls", "", 0, debugger_cmd_emuls,
1238     "print a summary of all current emuls" },
1239    
1240     { "focus", "x[,y]", 0, debugger_cmd_focus,
1241     "changes focus to machine x (in emul y)" },
1242    
1243     { "help", "", 0, debugger_cmd_help,
1244     "print this help message" },
1245    
1246     { "itrace", "", 0, debugger_cmd_itrace,
1247     "toggle instruction_trace on or off" },
1248    
1249     { "lookup", "name|addr", 0, debugger_cmd_lookup,
1250     "lookup a symbol by name or address" },
1251    
1252     { "machine", "", 0, debugger_cmd_machine,
1253     "print a summary of the current machine" },
1254    
1255     { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs,
1256     "toggle (set or unset) show_nr_of_instructions" },
1257    
1258     { "pause", "cpuid", 0, debugger_cmd_pause,
1259     "pause (or unpause) a CPU" },
1260    
1261     { "print", "expr", 0, debugger_cmd_print,
1262     "evaluate an expression without side-effects" },
1263    
1264     { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1265     "modify emulated memory contents" },
1266    
1267     { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1268     "toggle quiet_mode on or off" },
1269    
1270     { "quit", "", 0, debugger_cmd_quit,
1271     "quit the emulator" },
1272    
1273     /* NOTE: Try to keep 'r' down to only one command. Having 'reg'
1274     available as a one-letter command is very convenient. */
1275    
1276     { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1277     "show GPRs (or coprocessor c's registers)" },
1278    
1279     /* NOTE: Try to keep 's' down to only one command. Having 'step'
1280     available as a one-letter command is very convenient. */
1281    
1282     { "step", "[n]", 0, debugger_cmd_step,
1283     "single-step one (or n) instruction(s)" },
1284    
1285     { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1286     "dump TLB contents (add ',r' for raw data)" },
1287    
1288     { "trace", "[on|off]", 0, debugger_cmd_trace,
1289     "toggle show_trace_tree on or off" },
1290    
1291     { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1292     "dump memory contents as instructions" },
1293    
1294     { "version", "", 0, debugger_cmd_version,
1295     "print version information" },
1296    
1297     /* Note: NULL handler. */
1298     { "x = expr", "", 0, NULL, "generic assignment" },
1299    
1300     { NULL, NULL, 0, NULL, NULL }
1301     };
1302    
1303    
1304     /*
1305     * debugger_cmd_help():
1306     *
1307     * Print a list of available commands.
1308     *
1309     * NOTE: This is placed after the cmds[] array, because it needs to
1310     * access it.
1311     *
1312     * TODO: Command completion (ie just type "help s" for "help step").
1313     */
1314     static void debugger_cmd_help(struct machine *m, char *cmd_line)
1315     {
1316     int only_one = 0, only_one_match = 0;
1317     char *nlines_env = getenv("LINES");
1318     int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines;
1319     size_t i, j, max_name_len = 0;
1320    
1321     if (cmd_line[0] != '\0') {
1322     only_one = 1;
1323     }
1324    
1325     i = 0;
1326     while (cmds[i].name != NULL) {
1327     size_t a = strlen(cmds[i].name);
1328     if (cmds[i].args != NULL)
1329     a += 1 + strlen(cmds[i].args);
1330     if (a > max_name_len)
1331     max_name_len = a;
1332     i++;
1333     }
1334    
1335     curlines = 0;
1336     if (!only_one) {
1337     printf("Available commands:\n");
1338     curlines++;
1339     }
1340    
1341     i = 0;
1342     while (cmds[i].name != NULL) {
1343     char buf[100];
1344     snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1345    
1346     if (only_one) {
1347     if (strcmp(cmds[i].name, cmd_line) != 0) {
1348     i++;
1349     continue;
1350     }
1351     only_one_match = 1;
1352     }
1353    
1354     if (cmds[i].args != NULL)
1355     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1356     " %s", cmds[i].args);
1357    
1358     printf(" ");
1359     for (j=0; j<max_name_len; j++)
1360     if (j < strlen(buf))
1361     printf("%c", buf[j]);
1362     else
1363     printf(" ");
1364    
1365     printf(" %s\n", cmds[i].description);
1366     i++;
1367    
1368     curlines ++;
1369     if (curlines >= nlines - 1) {
1370     char ch;
1371     printf("-- more --"); fflush(stdout);
1372     ch = debugger_readchar();
1373     printf("\n");
1374     if (ch == 'q' || ch == 'Q')
1375     return;
1376     curlines = 0;
1377     }
1378     }
1379    
1380     if (only_one) {
1381     if (!only_one_match)
1382     printf("%s: no such command\n", cmd_line);
1383     return;
1384     }
1385    
1386     /* TODO: generalize/refactor */
1387     curlines += 8;
1388     if (curlines > nlines - 1) {
1389     char ch;
1390     printf("-- more --"); fflush(stdout);
1391     ch = debugger_readchar();
1392     printf("\n");
1393     if (ch == 'q' || ch == 'Q')
1394     return;
1395     curlines = 0;
1396     }
1397    
1398     printf("\nIn generic assignments, x must be a register, and expr can be"
1399     " a register, a\nnumeric value, or a symbol name (+ an optional "
1400     "numeric offset). In case there\nare multiple matches (i.e. a "
1401     "symbol that has the same name as a register), you\nmay add a "
1402     "prefix character as a hint: '%%' for registers, '@' for symbols,"
1403     " and\n'$' for numeric values. Use 0x for hexadecimal values.\n");
1404     }
1405    

  ViewVC Help
Powered by ViewVC 1.1.26