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

Contents of /trunk/src/debugger/debugger_cmds.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 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 /*
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