/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31522 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26