/[gxemul]/trunk/src/debugger/debugger_cmds.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (show annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 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 /*
2 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: debugger_cmds.c,v 1.12 2007/06/15 17:02:39 debug Exp $
29 *
30 * Debugger commands. Included from debugger.c.
31 */
32
33
34 /*
35 * debugger_cmd_allsettings():
36 */
37 static void debugger_cmd_allsettings(struct machine *m, char *cmd_line)
38 {
39 settings_debugdump(global_settings, GLOBAL_SETTINGS_NAME, 1);
40 }
41
42
43 /*
44 * debugger_cmd_breakpoint():
45 *
46 * TODO: automagic "expansion" for the subcommand names (s => show).
47 */
48 static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line)
49 {
50 int i, res;
51
52 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
53 cmd_line ++;
54
55 if (cmd_line[0] == '\0') {
56 printf("syntax: breakpoint subcmd [args...]\n");
57 printf("Available subcmds (and args) are:\n");
58 printf(" add addr add a breakpoint for address addr\n");
59 printf(" delete x delete breakpoint nr x\n");
60 printf(" show show current breakpoints\n");
61 return;
62 }
63
64 if (strcmp(cmd_line, "show") == 0) {
65 if (m->breakpoints.n == 0)
66 printf("No breakpoints set.\n");
67 for (i=0; i<m->breakpoints.n; 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->breakpoints.n == 0) {
76 printf("No breakpoints set.\n");
77 return;
78 }
79 if (x < 0 || x > m->breakpoints.n) {
80 printf("Invalid breakpoint nr %i. Use 'breakpoint "
81 "show' to see the current breakpoints.\n", x);
82 return;
83 }
84
85 free(m->breakpoints.string[x]);
86
87 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 }
91 m->breakpoints.n --;
92
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 i = m->breakpoints.n;
105
106 res = debugger_parse_expression(m, cmd_line + 4, 0, &tmp);
107 if (!res) {
108 printf("Couldn't parse '%s'\n", cmd_line + 4);
109 return;
110 }
111
112 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 breakpoint_buf_len = strlen(cmd_line+4) + 1;
120
121 CHECK_ALLOCATION(m->breakpoints.string[i] =
122 malloc(breakpoint_buf_len));
123 strlcpy(m->breakpoints.string[i], cmd_line+4,
124 breakpoint_buf_len);
125 m->breakpoints.addr[i] = tmp;
126
127 m->breakpoints.n ++;
128 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 i, mem->devices[i].name,
208 (uint64_t) mem->devices[i].baseaddr,
209 (uint64_t) mem->devices[i].length);
210
211 if (mem->devices[i].flags) {
212 printf(" (");
213 if (mem->devices[i].flags & DM_DYNTRANS_OK)
214 printf("DYNTRANS R");
215 if (mem->devices[i].flags &DM_DYNTRANS_WRITE_OK)
216 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 char *tmps;
258
259 CHECK_ALLOCATION(tmps = strdup(cmd_line));
260
261 /* addr: */
262 p = strchr(tmps, ' ');
263 if (p != NULL)
264 *p = '\0';
265 r = debugger_parse_expression(m, tmps, 0, &tmp);
266 free(tmps);
267
268 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
269 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 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 addr_start = last_dump_addr;
290
291 if (addr_start == MAGIC_UNTOUCHED)
292 addr_start = c->pc;
293
294 addr_end = addr_start + 16 * 16;
295
296 /* endaddr: */
297 if (p != NULL) {
298 while (*p == ' ' && *p)
299 p++;
300 r = debugger_parse_expression(m, p, 0, &addr_end);
301 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
302 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 * Changes focus to specific cpu, in a specific machine (in a specific
392 * emulation).
393 */
394 static void debugger_cmd_focus(struct machine *m, char *cmd_line)
395 {
396 int x = -1, y = -1, z = -1;
397 char *p, *p2;
398
399 if (!cmd_line[0]) {
400 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 goto print_current_focus_and_return;
405 }
406
407 x = atoi(cmd_line);
408 p = strchr(cmd_line, ',');
409 if (p == cmd_line) {
410 printf("No cpu number specified?\n");
411 return;
412 }
413
414 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
422 if (p2 != NULL)
423 z = atoi(p2 + 1);
424 }
425
426 if (z != -1) {
427 /* Change emul: */
428 if (z < 0 || z >= debugger_n_emuls) {
429 printf("Invalid emul number: %i\n", z);
430 return;
431 }
432
433 debugger_cur_emul = z;
434 debugger_emul = debugger_emuls[z];
435
436 /* This is just in case the machine change below fails... */
437 debugger_machine = debugger_emul->machines[0];
438 }
439
440 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 return;
455 }
456
457 debugger_cur_cpu = x;
458
459 print_current_focus_and_return:
460 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 }
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 res = debugger_parse_expression(m, cmd_line, 0, &tmp);
659 switch (res) {
660 case PARSE_NOMATCH:
661 printf("No match.\n");
662 break;
663 case PARSE_MULTIPLE:
664 printf("Multiple matches. Try prefixing with %%, $, or @.\n");
665 break;
666 case PARSE_SETTINGS:
667 printf("%s = 0x%"PRIx64"\n", cmd_line, (uint64_t)tmp);
668 break;
669 case PARSE_SYMBOL:
670 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 case PARSE_NUMBER:
676 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 res = debugger_parse_expression(m, q, 0, &addr);
744 switch (res) {
745 case PARSE_NOMATCH:
746 printf("Couldn't parse the address.\n");
747 return;
748 case PARSE_MULTIPLE:
749 printf("Multiple matches for the address."
750 " Try prefixing with %%, $, or @.\n");
751 return;
752 case PARSE_SETTINGS:
753 case PARSE_SYMBOL:
754 case PARSE_NUMBER:
755 break;
756 default:
757 printf("INTERNAL ERROR in debugger.c.\n");
758 return;
759 }
760
761 res = debugger_parse_expression(m, p, 0, &data);
762 switch (res) {
763 case PARSE_NOMATCH:
764 printf("Couldn't parse the data.\n");
765 return;
766 case PARSE_MULTIPLE:
767 printf("Multiple matches for the data value."
768 " Try prefixing with %%, $, or @.\n");
769 return;
770 case PARSE_SETTINGS:
771 case PARSE_SYMBOL:
772 case PARSE_NUMBER:
773 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 single_step = NOT_SINGLE_STEPPING;
923
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 int cpuid = debugger_cur_cpu, coprocnr = -1;
947 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 cpu_register_dump(m, m->cpus[cpuid], gprs, coprocs);
973 }
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 char *tmps;
1104
1105 CHECK_ALLOCATION(tmps = strdup(cmd_line));
1106
1107 /* addr: */
1108 p = strchr(tmps, ' ');
1109 if (p != NULL)
1110 *p = '\0';
1111 r = debugger_parse_expression(m, tmps, 0, &tmp);
1112 free(tmps);
1113
1114 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1115 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 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 addr_start = last_unasm_addr;
1136
1137 if (addr_start == MAGIC_UNTOUCHED)
1138 addr_start = c->pc;
1139
1140 addr_end = addr_start + 1000;
1141
1142 /* endaddr: */
1143 if (p != NULL) {
1144 while (*p == ' ' && *p)
1145 p++;
1146 r = debugger_parse_expression(m, p, 0, &addr_end);
1147 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1148 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 { "focus", "x[,y[,z]]", 0, debugger_cmd_focus,
1250 "changes focus to cpu x, machine x, emul z" },
1251
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 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 }
1416

  ViewVC Help
Powered by ViewVC 1.1.26