/[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 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31568 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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