/[gxemul]/trunk/src/debugger.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.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47162 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 0.3.2  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2003-2005 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 4 * $Id: debugger.c,v 1.101 2005/04/18 21:41:19 debug Exp $
29 dpavlin 2 *
30     * Single-step debugger.
31     *
32     *
33     * TODO:
34     *
35     * This entire module is very much non-reentrant. :-/
36     *
37     * Add more functionality that already exists elsewhere in the emulator.
38     *
39     * More generic expression evaluator (for example + - * / between multiple
40     * terms), including _TAB COMPLETION_ of symbols and register names!
41     *
42     * Nicer looking output of register dumps, floating point registers,
43     * etc. Warn about weird/invalid register contents.
44     *
45     * Ctrl-C doesn't enter the debugger on some OSes (HP-UX?)...
46     *
47     * Many other TODOs.
48     */
49    
50     #include <ctype.h>
51     #include <signal.h>
52     #include <stdio.h>
53     #include <stdlib.h>
54     #include <string.h>
55     #include <unistd.h>
56    
57 dpavlin 4 #include "bintrans.h"
58 dpavlin 2 #include "console.h"
59     #include "cpu.h"
60     #include "device.h"
61     #include "debugger.h"
62     #include "diskimage.h"
63     #include "emul.h"
64     #include "machine.h"
65     #include "memory.h"
66     #include "misc.h"
67     #include "net.h"
68     #include "x11.h"
69    
70    
71     extern int extra_argc;
72     extern char **extra_argv;
73    
74     extern int quiet_mode;
75    
76    
77     /*
78     * Global debugger variables:
79     */
80    
81     volatile int single_step = 0;
82     int force_debugger_at_exit = 0;
83     int show_opcode_statistics = 0;
84    
85     int old_instruction_trace = 0;
86     int old_quiet_mode = 0;
87     int old_show_trace_tree = 0;
88    
89    
90     /*
91     * Private (global) debugger variables:
92     */
93    
94     static volatile int ctrl_c;
95    
96     static int debugger_n_emuls;
97     static struct emul **debugger_emuls;
98     static struct emul *debugger_emul;
99     static struct machine *debugger_machine;
100    
101     static int exit_debugger;
102     static int n_steps_left_before_interaction = 0;
103    
104     #define MAX_CMD_LEN 70
105     #define N_PREVIOUS_CMDS 150
106     static char *last_cmd[N_PREVIOUS_CMDS];
107     static int last_cmd_index;
108    
109     static char repeat_cmd[MAX_CMD_LEN + 1];
110    
111     #define MAGIC_UNTOUCHED 0x98ca76c2ffcc0011ULL
112    
113     static uint64_t last_dump_addr = MAGIC_UNTOUCHED;
114     static uint64_t last_unasm_addr = MAGIC_UNTOUCHED;
115    
116    
117     /*
118     * debugger_activate():
119     *
120     * This is a signal handler for CTRL-C. It shouldn't be called directly,
121     * but setup code in emul.c sets the CTRL-C signal handler to use this
122     * function.
123     */
124     void debugger_activate(int x)
125     {
126     ctrl_c = 1;
127    
128     if (single_step) {
129     /* Already in the debugger. Do nothing. */
130     int i;
131     for (i=0; i<MAX_CMD_LEN+1; i++)
132     console_makeavail(MAIN_CONSOLE, '\b');
133     console_makeavail(MAIN_CONSOLE, ' ');
134     console_makeavail(MAIN_CONSOLE, '\n');
135     printf("^C");
136     fflush(stdout);
137     } else {
138     /* Enter the single step debugger. */
139     single_step = 1;
140    
141     /* Discard any chars in the input queue: */
142     while (console_charavail(MAIN_CONSOLE))
143     console_readchar(MAIN_CONSOLE);
144     }
145    
146     /* Clear the repeat-command buffer: */
147     repeat_cmd[0] = '\0';
148    
149     /* Reactivate the signal handler: */
150     signal(SIGINT, debugger_activate);
151     }
152    
153    
154     /*
155     * debugger_parse_name():
156     *
157     * This function reads a string, and tries to match it to a register name,
158     * a symbol, or treat it as a decimal numeric value.
159     *
160     * Some examples:
161     *
162     * "0x7fff1234" ==> numeric value (hex, in this case)
163     * "pc", "r5", "hi", "t4" ==> register (CPU dependant)
164     * "memcpy+64" ==> symbol (plus offset)
165     *
166     * Register names can be preceeded by "x:" where x is the CPU number. (CPU
167     * 0 is assumed by default.)
168     *
169     * To force detection of different types, a character can be added in front of
170     * the name: "$" for numeric values, "%" for registers, and "@" for symbols.
171     *
172     * Return value is:
173     *
174     * NAME_PARSE_NOMATCH no match
175     * NAME_PARSE_MULTIPLE multiple matches
176     *
177     * or one of these (and then *valuep is read or written, depending on
178     * the writeflag):
179     *
180     * NAME_PARSE_REGISTER a register
181     * NAME_PARSE_NUMBER a hex number
182     * NAME_PARSE_SYMBOL a symbol
183     */
184     #define NAME_PARSE_NOMATCH 0
185     #define NAME_PARSE_MULTIPLE 1
186     #define NAME_PARSE_REGISTER 2
187     #define NAME_PARSE_NUMBER 3
188     #define NAME_PARSE_SYMBOL 4
189     static int debugger_parse_name(struct machine *m, char *name, int writeflag,
190     uint64_t *valuep)
191     {
192     int match_register = 0, match_symbol = 0, match_numeric = 0;
193     int skip_register, skip_numeric, skip_symbol;
194    
195     if (m == NULL || name == NULL) {
196     fprintf(stderr, "debugger_parse_name(): NULL ptr\n");
197     exit(1);
198     }
199    
200     /* Warn about non-signextended values: */
201     if (writeflag &&
202     ((*valuep) >> 32) == 0 && (*valuep) & 0x80000000ULL)
203     printf("WARNING: The value is not sign-extended. "
204     "Is this what you intended?\n");
205    
206     skip_register = name[0] == '$' || name[0] == '@';
207     skip_numeric = name[0] == '%' || name[0] == '@';
208     skip_symbol = name[0] == '$' || name[0] == '%';
209    
210     /* Check for a register match: */
211     if (!skip_register && strlen(name) >= 1)
212     cpu_register_match(m, name, writeflag, valuep,
213     &match_register);
214    
215     /* Check for a number match: */
216     if (!skip_numeric && isdigit((int)name[0])) {
217     uint64_t x;
218     x = strtoull(name, NULL, 0);
219     if (writeflag) {
220     printf("You cannot assign like that.\n");
221     } else
222     *valuep = x;
223     match_numeric = 1;
224     }
225    
226     /* Check for a symbol match: */
227     if (!skip_symbol) {
228     int res;
229     char *p, *sn;
230     uint64_t newaddr, ofs = 0;
231    
232     sn = malloc(strlen(name) + 1);
233     if (sn == NULL) {
234     fprintf(stderr, "out of memory in debugger\n");
235     exit(1);
236     }
237     strcpy(sn, name);
238    
239     /* Is there a '+' in there? Then treat that as an offset: */
240     p = strchr(sn, '+');
241     if (p != NULL) {
242     *p = '\0';
243     ofs = strtoull(p+1, NULL, 0);
244     }
245    
246     res = get_symbol_addr(&m->symbol_context, sn, &newaddr);
247     if (res) {
248     if (writeflag) {
249     printf("You cannot assign like that.\n");
250     } else
251     *valuep = newaddr + ofs;
252     match_symbol = 1;
253     }
254    
255     free(sn);
256     }
257    
258     if (match_register + match_symbol + match_numeric > 1)
259     return NAME_PARSE_MULTIPLE;
260    
261     if (match_register)
262     return NAME_PARSE_REGISTER;
263     if (match_numeric)
264     return NAME_PARSE_NUMBER;
265     if (match_symbol)
266     return NAME_PARSE_SYMBOL;
267    
268     return NAME_PARSE_NOMATCH;
269     }
270    
271    
272     /*
273     * show_breakpoint():
274     */
275     static void show_breakpoint(struct machine *m, int i)
276     {
277     printf("%3i: 0x%016llx", i,
278     (long long)m->breakpoint_addr[i]);
279     if (m->breakpoint_string[i] != NULL)
280     printf(" (%s)", m->breakpoint_string[i]);
281     if (m->breakpoint_flags[i])
282     printf(": flags=0x%x", m->breakpoint_flags[i]);
283     printf("\n");
284     }
285    
286    
287     /****************************************************************************/
288    
289    
290     /*
291     * debugger_cmd_breakpoint():
292     *
293     * TODO: automagic "expansion" for the subcommand names (s => show).
294     */
295     static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line)
296     {
297     int i, res;
298    
299     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
300     cmd_line ++;
301    
302     if (cmd_line[0] == '\0') {
303     printf("syntax: breakpoint subcmd [args...]\n");
304     printf("Available subcmds (and args) are:\n");
305     printf(" add addr add a breakpoint for address addr\n");
306     printf(" delete x delete breakpoint nr x\n");
307     printf(" show show current breakpoints\n");
308     return;
309     }
310    
311     if (strcmp(cmd_line, "show") == 0) {
312     if (m->n_breakpoints == 0)
313     printf("No breakpoints set.\n");
314     for (i=0; i<m->n_breakpoints; i++)
315     show_breakpoint(m, i);
316     return;
317     }
318    
319     if (strncmp(cmd_line, "delete ", 7) == 0) {
320     int x = atoi(cmd_line + 7);
321    
322     if (m->n_breakpoints == 0) {
323     printf("No breakpoints set.\n");
324     return;
325     }
326     if (x < 0 || x >= m->n_breakpoints) {
327     printf("Invalid breakpoint nr %i. Use 'breakpoint "
328     "show' to see the current breakpoints.\n", x);
329     return;
330     }
331    
332     free(m->breakpoint_string[x]);
333    
334     for (i=x; i<m->n_breakpoints-1; i++) {
335     m->breakpoint_addr[i] = m->breakpoint_addr[i+1];
336     m->breakpoint_string[i] = m->breakpoint_string[i+1];
337     m->breakpoint_flags[i] = m->breakpoint_flags[i+1];
338     }
339     m->n_breakpoints --;
340     return;
341     }
342    
343     if (strncmp(cmd_line, "add ", 4) == 0) {
344     uint64_t tmp;
345    
346     if (m->n_breakpoints >= MAX_BREAKPOINTS) {
347     printf("Too many breakpoints. (You need to recompile"
348     " gxemul to increase this. Max = %i.)\n",
349     MAX_BREAKPOINTS);
350     return;
351     }
352    
353     i = m->n_breakpoints;
354    
355     res = debugger_parse_name(m, cmd_line + 4, 0, &tmp);
356     if (!res) {
357     printf("Couldn't parse '%s'\n", cmd_line + 4);
358     return;
359     }
360    
361     m->breakpoint_string[i] = malloc(strlen(cmd_line+4) + 1);
362     if (m->breakpoint_string[i] == NULL) {
363     printf("out of memory in debugger_cmd_breakpoint()\n");
364     exit(1);
365     }
366     strcpy(m->breakpoint_string[i], cmd_line+4);
367     m->breakpoint_addr[i] = tmp;
368     m->breakpoint_flags[i] = 0;
369    
370     m->n_breakpoints ++;
371     show_breakpoint(m, i);
372     return;
373     }
374    
375     printf("Unknown breakpoint subcommand.\n");
376     }
377    
378    
379     /*
380     * debugger_cmd_bintrans():
381     */
382     static void debugger_cmd_bintrans(struct machine *m, char *cmd_line)
383     {
384 dpavlin 4 int i;
385    
386 dpavlin 2 if (*cmd_line == '\0')
387     goto printstate;
388    
389     if (!m->bintrans_enabled_from_start) {
390     printf("You must have enabled bintrans from the start of the "
391     "simulation.\nIt is not possible to turn on afterwards.\n");
392     return;
393     }
394    
395     while (*cmd_line == ' ')
396     cmd_line++;
397    
398     /* Note: len 3 and 4, to include the NUL char. */
399 dpavlin 4 if (strncasecmp(cmd_line, "on", 3) == 0) {
400 dpavlin 2 m->bintrans_enable = 1;
401 dpavlin 4 for (i=0; i<m->ncpus; i++)
402     bintrans_restart(m->cpus[i]);
403     } else if (strncasecmp(cmd_line, "off", 4) == 0)
404 dpavlin 2 m->bintrans_enable = 0;
405     else
406     printf("syntax: bintrans [on|off]\n");
407    
408     printstate:
409     printf("bintrans is now %s%s\n",
410     m->bintrans_enable? "ENABLED" : "disabled",
411     m->old_bintrans_enable? " (using the OLD bintrans system)" : "");
412     }
413    
414    
415     /*
416     * debugger_cmd_continue():
417     */
418     static void debugger_cmd_continue(struct machine *m, char *cmd_line)
419     {
420     if (*cmd_line) {
421     printf("syntax: continue\n");
422     return;
423     }
424    
425     exit_debugger = 1;
426     }
427    
428    
429     /*
430     * debugger_cmd_device():
431     */
432     static void debugger_cmd_device(struct machine *m, char *cmd_line)
433     {
434     int i, j;
435     struct memory *mem;
436     struct cpu *c;
437    
438     if (cmd_line[0] == '\0')
439     goto return_help;
440    
441     if (m->cpus == NULL) {
442     printf("No cpus (?)\n");
443     return;
444     }
445     c = m->cpus[m->bootstrap_cpu];
446     if (c == NULL) {
447     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
448     return;
449     }
450     mem = m->cpus[m->bootstrap_cpu]->mem;
451    
452     if (m->cpus == NULL) {
453     printf("No cpus (?)\n");
454     return;
455     }
456     c = m->cpus[m->bootstrap_cpu];
457     if (c == NULL) {
458     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
459     return;
460     }
461     mem = m->cpus[m->bootstrap_cpu]->mem;
462    
463     if (strcmp(cmd_line, "all") == 0) {
464     device_dumplist();
465     } else if (strncmp(cmd_line, "add ", 4) == 0) {
466     device_add(m, cmd_line+4);
467     } else if (strncmp(cmd_line, "remove ", 7) == 0) {
468     i = atoi(cmd_line + 7);
469     if (i==0 && cmd_line[7]!='0') {
470     printf("Weird device number. Use 'device list'.\n");
471     } else
472     memory_device_remove(m->memory, i);
473     } else if (strncmp(cmd_line, "state ", 6) == 0) {
474     i = atoi(cmd_line + 6);
475     if (i < 0 || i >= mem->n_mmapped_devices) {
476     printf("No devices with that id.\n");
477     return;
478     }
479    
480     if (mem->dev_f_state[i] == NULL) {
481     printf("No state function has been implemented yet "
482     "for that device type.\n");
483     return;
484     }
485    
486     for (j=0; ; j++) {
487     int type;
488     char *name;
489     void *data;
490     size_t len;
491     int res = mem->dev_f_state[i](c, mem,
492     mem->dev_extra[i], 0, j, &type, &name, &data, &len);
493     if (!res)
494     break;
495     printf("%2i:%30s = (", j, name);
496     switch (type) {
497     case DEVICE_STATE_TYPE_INT:
498     printf("int) %i", *((int *)data));
499     break;
500     default:
501     printf("unknown)");
502     }
503     printf("\n");
504     }
505     } else if (strcmp(cmd_line, "list") == 0) {
506     if (mem->n_mmapped_devices == 0)
507     printf("No memory-mapped devices in this machine.\n");
508    
509     for (i=0; i<mem->n_mmapped_devices; i++) {
510     printf("%2i: %25s @ 0x%011llx, len = 0x%llx",
511     i, mem->dev_name[i],
512     (long long)mem->dev_baseaddr[i],
513     (long long)mem->dev_length[i]);
514     if (mem->dev_flags[i]) {
515     printf(" (");
516     if (mem->dev_flags[i] & MEM_BINTRANS_OK)
517     printf("BINTRANS R");
518     if (mem->dev_flags[i] & MEM_BINTRANS_WRITE_OK)
519     printf("+W");
520     printf(")");
521     }
522     printf("\n");
523     }
524     } else
525     goto return_help;
526    
527     return;
528    
529     return_help:
530     printf("syntax: devices cmd [...]\n");
531     printf("Available cmds are:\n");
532     printf(" add name_and_params add a device to the current "
533     "machine\n");
534     printf(" all list all registered devices\n");
535     printf(" list list memory-mapped devices in the"
536     " current machine\n");
537     printf(" remove x remove device nr x from the "
538     "current machine\n");
539     printf(" state x show state of device nr x in"
540     " the current machine\n");
541     }
542    
543    
544     /*
545     * debugger_cmd_dump():
546     *
547     * Dump emulated memory in hex and ASCII.
548     *
549     * syntax: dump [addr [endaddr]]
550     */
551     static void debugger_cmd_dump(struct machine *m, char *cmd_line)
552     {
553     uint64_t addr, addr_start, addr_end;
554     struct cpu *c;
555     struct memory *mem;
556     char *p = NULL;
557     int x, r;
558    
559     if (cmd_line[0] != '\0') {
560     uint64_t tmp;
561     char *tmps = strdup(cmd_line);
562    
563     /* addr: */
564     p = strchr(tmps, ' ');
565     if (p != NULL)
566     *p = '\0';
567     r = debugger_parse_name(m, tmps, 0, &tmp);
568     free(tmps);
569    
570     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
571     printf("Unparsable address: %s\n", cmd_line);
572     return;
573     } else {
574     last_dump_addr = tmp;
575     }
576    
577     p = strchr(cmd_line, ' ');
578     }
579    
580     addr_start = last_dump_addr;
581    
582     if (addr_start == MAGIC_UNTOUCHED) {
583     uint64_t tmp;
584     int match_register = 0;
585     cpu_register_match(m, "pc", 0, &tmp, &match_register);
586     if (match_register) {
587     addr_start = tmp;
588     } else {
589     printf("No starting address.\n");
590     return;
591     }
592     }
593    
594     addr_end = addr_start + 16 * 16;
595    
596     /* endaddr: */
597     if (p != NULL) {
598     while (*p == ' ' && *p)
599     p++;
600     r = debugger_parse_name(m, p, 0, &addr_end);
601     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
602     printf("Unparsable address: %s\n", cmd_line);
603     return;
604     }
605     }
606    
607     if (m->cpus == NULL) {
608     printf("No cpus (?)\n");
609     return;
610     }
611     c = m->cpus[m->bootstrap_cpu];
612     if (c == NULL) {
613     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
614     return;
615     }
616     mem = m->cpus[m->bootstrap_cpu]->mem;
617    
618     addr = addr_start & ~0xf;
619    
620     ctrl_c = 0;
621    
622     while (addr < addr_end) {
623     unsigned char buf[16];
624     memset(buf, 0, sizeof(buf));
625     r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf),
626     MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
627    
628     printf("0x%016llx ", (long long)addr);
629    
630     if (r == MEMORY_ACCESS_FAILED)
631     printf("(memory access failed)\n");
632     else {
633     for (x=0; x<16; x++) {
634     if (addr + x >= addr_start &&
635     addr + x < addr_end)
636     printf("%02x%s", buf[x],
637     (x&3)==3? " " : "");
638     else
639     printf(" %s", (x&3)==3? " " : "");
640     }
641     printf(" ");
642     for (x=0; x<16; x++) {
643     if (addr + x >= addr_start &&
644     addr + x < addr_end)
645     printf("%c", (buf[x]>=' ' &&
646     buf[x]<127)? buf[x] : '.');
647     else
648     printf(" ");
649     }
650     printf("\n");
651     }
652    
653     if (ctrl_c)
654     return;
655    
656     addr += sizeof(buf);
657     }
658    
659     last_dump_addr = addr_end;
660    
661     strcpy(repeat_cmd, "dump");
662     }
663    
664    
665     /*
666     * debugger_cmd_emuls():
667     *
668     * Dump info about all current emuls.
669     */
670     static void debugger_cmd_emuls(struct machine *m, char *cmd_line)
671     {
672     int i, iadd = 4;
673    
674     if (*cmd_line) {
675     printf("syntax: emuls\n");
676     return;
677     }
678    
679     for (i=0; i<debugger_n_emuls; i++) {
680     struct emul *e = debugger_emuls[i];
681    
682     if (e == NULL)
683     continue;
684    
685     debug("emulation %i: \"%s\"\n", i,
686     e->name == NULL? "(no name)" : e->name);
687     debug_indentation(iadd);
688    
689     emul_dumpinfo(e);
690    
691     debug_indentation(-iadd);
692     }
693     }
694    
695    
696     /*
697     * debugger_cmd_focus():
698     *
699     * Changes focus to specific machine (in a specific emulation).
700     */
701     static void debugger_cmd_focus(struct machine *m, char *cmd_line)
702     {
703     int x = -1, y = -1;
704     char *p;
705    
706     if (!cmd_line[0]) {
707     printf("syntax: focus x[,y]\n");
708     printf("where x and y are integers as reported by the"
709     " 'emuls' command\n");
710     goto print_current_focus_and_return;
711     }
712    
713     x = atoi(cmd_line);
714     p = strchr(cmd_line, ',');
715     if (p == cmd_line) {
716     printf("No machine number specified?\n");
717     printf("syntax: focus x[,y]\n");
718     return;
719     }
720    
721     if (p != NULL)
722     y = atoi(p + 1);
723    
724     if (y != -1) {
725     /* Change emul: */
726     if (y < 0 || y >= debugger_n_emuls) {
727     printf("Invalid emul number: %i\n", y);
728     return;
729     }
730    
731     debugger_emul = debugger_emuls[y];
732    
733     /* This is just in case the machine change below fails... */
734     debugger_machine = debugger_emul->machines[0];
735     }
736    
737     /* Change machine: */
738     if (x < 0 || x >= debugger_emul->n_machines) {
739     printf("Invalid machine number: %i\n", x);
740     return;
741     }
742    
743     debugger_machine = debugger_emul->machines[x];
744    
745     print_current_focus_and_return:
746     printf("current emul: \"%s\"\n", debugger_emul->name == NULL?
747     "(no name)" : debugger_emul->name);
748     printf("current machine: \"%s\"\n", debugger_machine->name == NULL?
749     "(no name)" : debugger_machine->name);
750     }
751    
752    
753     /* This is defined below. */
754     static void debugger_cmd_help(struct machine *m, char *cmd_line);
755    
756    
757     /*
758     * debugger_cmd_itrace():
759     */
760     static void debugger_cmd_itrace(struct machine *m, char *cmd_line)
761     {
762     if (*cmd_line) {
763     printf("syntax: itrace\n");
764     return;
765     }
766    
767     old_instruction_trace = 1 - old_instruction_trace;
768     printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF");
769     /* TODO: how to preserve quiet_mode? */
770     old_quiet_mode = 0;
771     printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
772     }
773    
774    
775     /*
776     * debugger_cmd_lookup():
777     */
778     static void debugger_cmd_lookup(struct machine *m, char *cmd_line)
779     {
780     uint64_t addr;
781     int res;
782     char *symbol;
783     uint64_t offset;
784    
785     if (cmd_line[0] == '\0') {
786     printf("syntax: lookup name|addr\n");
787     return;
788    
789     }
790    
791     /* Addresses never need to be given in decimal form anyway,
792     so assuming hex here will be ok. */
793     addr = strtoull(cmd_line, NULL, 16);
794    
795     if (addr == 0) {
796     uint64_t newaddr;
797     res = get_symbol_addr(&m->symbol_context,
798     cmd_line, &newaddr);
799     if (!res) {
800     printf("lookup for '%s' failed\n", cmd_line);
801     return;
802     }
803     printf("%s = 0x%016llx\n", cmd_line, (long long)newaddr);
804     return;
805     }
806    
807     symbol = get_symbol_name(&m->symbol_context, addr, &offset);
808    
809     if (symbol != NULL)
810     printf("0x%016llx = %s\n", (long long)addr, symbol);
811     else
812     printf("lookup for '%s' failed\n", cmd_line);
813     }
814    
815    
816     /*
817     * debugger_cmd_machine():
818     *
819     * Dump info about the currently focused machine.
820     */
821     static void debugger_cmd_machine(struct machine *m, char *cmd_line)
822     {
823     int iadd = 4;
824    
825     if (*cmd_line) {
826     printf("syntax: machine\n");
827     return;
828     }
829    
830     debug("machine \"%s\":\n", m->name);
831     debug_indentation(iadd);
832     machine_dumpinfo(m);
833     debug_indentation(-iadd);
834     }
835    
836    
837     /*
838     * debugger_cmd_opcodestats():
839     */
840     static void debugger_cmd_opcodestats(struct machine *m, char *cmd_line)
841     {
842     if (*cmd_line) {
843     printf("syntax: opcodestats\n");
844     return;
845     }
846    
847     if (!show_opcode_statistics) {
848     printf("You need to start the emulator "
849     "with -s, if you want to gather statistics.\n");
850     } else
851     cpu_show_full_statistics(m);
852     }
853    
854    
855     /*
856     * debugger_cmd_pause():
857     */
858     static void debugger_cmd_pause(struct machine *m, char *cmd_line)
859     {
860     int cpuid = -1;
861    
862     if (cmd_line[0] != '\0')
863     cpuid = atoi(cmd_line);
864     else {
865     printf("syntax: pause cpuid\n");
866     return;
867     }
868    
869     if (cpuid < 0 || cpuid >= m->ncpus) {
870     printf("cpu%i doesn't exist.\n", cpuid);
871     return;
872     }
873    
874     m->cpus[cpuid]->running ^= 1;
875    
876     printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid,
877     m->cpus[cpuid]->name, m->name,
878     m->cpus[cpuid]->running? "RUNNING" : "STOPPED");
879     }
880    
881    
882     /*
883     * debugger_cmd_print():
884     */
885     static void debugger_cmd_print(struct machine *m, char *cmd_line)
886     {
887     int res;
888     uint64_t tmp;
889    
890     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
891     cmd_line ++;
892    
893     if (cmd_line[0] == '\0') {
894     printf("syntax: print expr\n");
895     return;
896     }
897    
898     res = debugger_parse_name(m, cmd_line, 0, &tmp);
899     switch (res) {
900     case NAME_PARSE_NOMATCH:
901     printf("No match.\n");
902     break;
903     case NAME_PARSE_MULTIPLE:
904     printf("Multiple matches. Try prefixing with %%, $, or @.\n");
905     break;
906     case NAME_PARSE_REGISTER:
907     case NAME_PARSE_SYMBOL:
908     printf("%s = 0x%016llx\n", cmd_line, (long long)tmp);
909     break;
910     case NAME_PARSE_NUMBER:
911     printf("0x%016llx\n", (long long)tmp);
912     break;
913     }
914     }
915    
916    
917     /*
918     * debugger_cmd_put():
919     */
920     static void debugger_cmd_put(struct machine *m, char *cmd_line)
921     {
922     static char put_type = ' '; /* Remembered across multiple calls. */
923     char copy[200];
924     int res, syntax_ok = 0;
925     char *p, *p2, *q = NULL;
926     uint64_t addr, data;
927     unsigned char a_byte;
928    
929     strncpy(copy, cmd_line, sizeof(copy));
930     copy[sizeof(copy)-1] = '\0';
931    
932     /* syntax: put [b|h|w|d|q] addr, data */
933    
934     p = strchr(copy, ',');
935     if (p != NULL) {
936     *p++ = '\0';
937     while (*p == ' ' && *p)
938     p++;
939     while (strlen(copy) >= 1 &&
940     copy[strlen(copy) - 1] == ' ')
941     copy[strlen(copy) - 1] = '\0';
942    
943     /* printf("L = '%s', R = '%s'\n", copy, p); */
944    
945     q = copy;
946     p2 = strchr(q, ' ');
947    
948     if (p2 != NULL) {
949     *p2 = '\0';
950     if (strlen(q) != 1) {
951     printf("Invalid type '%s'\n", q);
952     return;
953     }
954     put_type = *q;
955     q = p2 + 1;
956     }
957    
958     /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
959     syntax_ok = 1;
960     }
961    
962     if (!syntax_ok) {
963     printf("syntax: put [b|h|w|d|q] addr, data\n");
964     printf(" b byte (8 bits)\n");
965     printf(" h half-word (16 bits)\n");
966     printf(" w word (32 bits)\n");
967     printf(" d doubleword (64 bits)\n");
968     printf(" q quad-word (128 bits)\n");
969     return;
970     }
971    
972     if (put_type == ' ') {
973     printf("No type specified.\n");
974     return;
975     }
976    
977     /* here: q is the address, p is the data. */
978    
979     res = debugger_parse_name(m, q, 0, &addr);
980     switch (res) {
981     case NAME_PARSE_NOMATCH:
982     printf("Couldn't parse the address.\n");
983     return;
984     case NAME_PARSE_MULTIPLE:
985     printf("Multiple matches for the address."
986     " Try prefixing with %%, $, or @.\n");
987     return;
988     case NAME_PARSE_REGISTER:
989     case NAME_PARSE_SYMBOL:
990     case NAME_PARSE_NUMBER:
991     break;
992     default:
993     printf("INTERNAL ERROR in debugger.c.\n");
994     return;
995     }
996    
997     res = debugger_parse_name(m, p, 0, &data);
998     switch (res) {
999     case NAME_PARSE_NOMATCH:
1000     printf("Couldn't parse the data.\n");
1001     return;
1002     case NAME_PARSE_MULTIPLE:
1003     printf("Multiple matches for the data value."
1004     " Try prefixing with %%, $, or @.\n");
1005     return;
1006     case NAME_PARSE_REGISTER:
1007     case NAME_PARSE_SYMBOL:
1008     case NAME_PARSE_NUMBER:
1009     break;
1010     default:
1011     printf("INTERNAL ERROR in debugger.c.\n");
1012     return;
1013     }
1014    
1015     /* TODO: haha, maybe this should be refactored */
1016    
1017     switch (put_type) {
1018     case 'b':
1019     a_byte = data;
1020     printf("0x%016llx: %02x", (long long)addr, a_byte);
1021     if (data > 255)
1022     printf(" (NOTE: truncating %0llx)", (long long)data);
1023     res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
1024     &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
1025     if (!res)
1026     printf(" FAILED!\n");
1027     printf("\n");
1028     return;
1029     case 'h':
1030     if ((data & 1) != 0)
1031     printf("WARNING: address isn't aligned\n");
1032     printf("0x%016llx: %04x", (long long)addr, (int)data);
1033     if (data > 0xffff)
1034     printf(" (NOTE: truncating %0llx)", (long long)data);
1035     res = store_16bit_word(m->cpus[0], addr, data);
1036     if (!res)
1037     printf(" FAILED!\n");
1038     printf("\n");
1039     return;
1040     case 'w':
1041     if ((data & 3) != 0)
1042     printf("WARNING: address isn't aligned\n");
1043     printf("0x%016llx: %08x", (long long)addr, (int)data);
1044     if (data > 0xffffffff && (data >> 32) != 0
1045     && (data >> 32) != 0xffffffff)
1046     printf(" (NOTE: truncating %0llx)", (long long)data);
1047     res = store_32bit_word(m->cpus[0], addr, data);
1048     if (!res)
1049     printf(" FAILED!\n");
1050     printf("\n");
1051     return;
1052     case 'd':
1053     if ((data & 7) != 0)
1054     printf("WARNING: address isn't aligned\n");
1055     printf("0x%016llx: %016llx", (long long)addr, (long long)data);
1056     res = store_64bit_word(m->cpus[0], addr, data);
1057     if (!res)
1058     printf(" FAILED!\n");
1059     printf("\n");
1060     return;
1061     case 'q':
1062     printf("quad-words: TODO\n");
1063     /* TODO */
1064     return;
1065     default:
1066     printf("Unimplemented type '%c'\n", put_type);
1067     return;
1068     }
1069     }
1070    
1071    
1072     /*
1073     * debugger_cmd_quiet():
1074     */
1075     static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
1076     {
1077     int toggle = 1;
1078     int previous_mode = old_quiet_mode;
1079    
1080     if (cmd_line[0] != '\0') {
1081     while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1082     cmd_line ++;
1083     switch (cmd_line[0]) {
1084     case '0':
1085     toggle = 0;
1086     old_quiet_mode = 0;
1087     break;
1088     case '1':
1089     toggle = 0;
1090     old_quiet_mode = 1;
1091     break;
1092     case 'o':
1093     case 'O':
1094     toggle = 0;
1095     switch (cmd_line[1]) {
1096     case 'n':
1097     case 'N':
1098     old_quiet_mode = 1;
1099     break;
1100     default:
1101     old_quiet_mode = 0;
1102     }
1103     break;
1104     default:
1105     printf("syntax: quiet [on|off]\n");
1106     return;
1107     }
1108     }
1109    
1110     if (toggle)
1111     old_quiet_mode = 1 - old_quiet_mode;
1112    
1113     printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
1114     if (old_quiet_mode != previous_mode)
1115     printf(" (was: %s)", previous_mode? "ON" : "OFF");
1116     printf("\n");
1117     }
1118    
1119    
1120     /*
1121     * debugger_cmd_quit():
1122     */
1123     static void debugger_cmd_quit(struct machine *m, char *cmd_line)
1124     {
1125     int i, j, k;
1126     struct emul *e;
1127    
1128     if (*cmd_line) {
1129     printf("syntax: quit\n");
1130     return;
1131     }
1132    
1133     for (i=0; i<debugger_n_emuls; i++) {
1134     single_step = 0;
1135    
1136     e = debugger_emuls[i];
1137     force_debugger_at_exit = 0;
1138    
1139     for (j=0; j<e->n_machines; j++) {
1140     struct machine *m = e->machines[j];
1141    
1142     for (k=0; k<m->ncpus; k++)
1143     m->cpus[k]->running = 0;
1144    
1145     m->exit_without_entering_debugger = 1;
1146     }
1147     }
1148    
1149     exit_debugger = 1;
1150     }
1151    
1152    
1153     /*
1154     * debugger_cmd_reg():
1155     */
1156     static void debugger_cmd_reg(struct machine *m, char *cmd_line)
1157     {
1158     int i, cpuid = -1, coprocnr = -1;
1159     int gprs, coprocs;
1160     char *p;
1161    
1162     /* [cpuid][,c] */
1163     if (cmd_line[0] != '\0') {
1164     if (cmd_line[0] != ',') {
1165     cpuid = strtoull(cmd_line, NULL, 0);
1166     if (cpuid < 0 || cpuid >= m->ncpus) {
1167     printf("cpu%i doesn't exist.\n", cpuid);
1168     return;
1169     }
1170     }
1171     p = strchr(cmd_line, ',');
1172     if (p != NULL) {
1173     coprocnr = atoi(p + 1);
1174     if (coprocnr < 0 || coprocnr >= 4) {
1175     printf("Invalid coprocessor number.\n");
1176     return;
1177     }
1178     }
1179     }
1180    
1181     gprs = (coprocnr == -1)? 1 : 0;
1182     coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
1183    
1184     for (i=0; i<m->ncpus; i++)
1185     if (cpuid == -1 || i == cpuid)
1186     cpu_register_dump(m, m->cpus[i], gprs, coprocs);
1187     }
1188    
1189    
1190     /*
1191     * debugger_cmd_step():
1192     */
1193     static void debugger_cmd_step(struct machine *m, char *cmd_line)
1194     {
1195     int n = 1;
1196    
1197     if (cmd_line[0] != '\0') {
1198     n = strtoull(cmd_line, NULL, 0);
1199     if (n < 1) {
1200     printf("invalid nr of steps\n");
1201     return;
1202     }
1203     }
1204    
1205     n_steps_left_before_interaction = n - 1;
1206    
1207     /* Special hack, see debugger() for more info. */
1208     exit_debugger = -1;
1209    
1210     strcpy(repeat_cmd, "step");
1211     }
1212    
1213    
1214     /*
1215     * debugger_cmd_tlbdump():
1216     *
1217     * Dump each CPU's TLB contents.
1218     */
1219     static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
1220     {
1221     int x = -1;
1222     int rawflag = 0;
1223    
1224     if (cmd_line[0] != '\0') {
1225     char *p;
1226     if (cmd_line[0] != ',') {
1227     x = strtoull(cmd_line, NULL, 0);
1228     if (x < 0 || x >= m->ncpus) {
1229     printf("cpu%i doesn't exist.\n", x);
1230     return;
1231     }
1232     }
1233     p = strchr(cmd_line, ',');
1234     if (p != NULL) {
1235     switch (p[1]) {
1236     case 'r':
1237     case 'R':
1238     rawflag = 1;
1239     break;
1240     default:
1241     printf("Unknown tlbdump flag.\n");
1242     printf("syntax: tlbdump [cpuid][,r]\n");
1243     return;
1244     }
1245     }
1246     }
1247    
1248     cpu_tlbdump(m, x, rawflag);
1249     }
1250    
1251    
1252     /*
1253     * debugger_cmd_trace():
1254     */
1255     static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1256     {
1257     if (*cmd_line) {
1258     printf("syntax: trace\n");
1259     return;
1260     }
1261    
1262     old_show_trace_tree = 1 - old_show_trace_tree;
1263     printf("show_trace_tree = %s\n", old_show_trace_tree? "ON" : "OFF");
1264    
1265     if (m->bintrans_enable && old_show_trace_tree)
1266     printf("NOTE: the trace tree functionality doesn't "
1267     "work very well with bintrans!\n");
1268    
1269     /* TODO: how to preserve quiet_mode? */
1270     old_quiet_mode = 0;
1271     printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
1272     }
1273    
1274    
1275     /*
1276     * debugger_cmd_unassemble():
1277     *
1278     * Dump emulated memory as instructions.
1279     *
1280     * syntax: unassemble [addr [endaddr]]
1281     */
1282     static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1283     {
1284     uint64_t addr, addr_start, addr_end;
1285     struct cpu *c;
1286     struct memory *mem;
1287     char *p = NULL;
1288     int r, lines_left = -1;
1289    
1290     if (cmd_line[0] != '\0') {
1291     uint64_t tmp;
1292     char *tmps = strdup(cmd_line);
1293    
1294     /* addr: */
1295     p = strchr(tmps, ' ');
1296     if (p != NULL)
1297     *p = '\0';
1298     r = debugger_parse_name(m, tmps, 0, &tmp);
1299     free(tmps);
1300    
1301     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1302     printf("Unparsable address: %s\n", cmd_line);
1303     return;
1304     } else {
1305     last_unasm_addr = tmp;
1306     }
1307    
1308     p = strchr(cmd_line, ' ');
1309     }
1310    
1311     addr_start = last_unasm_addr;
1312    
1313     if (addr_start == MAGIC_UNTOUCHED) {
1314     uint64_t tmp;
1315     int match_register = 0;
1316     cpu_register_match(m, "pc", 0, &tmp, &match_register);
1317     if (match_register) {
1318     addr_start = tmp;
1319     } else {
1320     printf("No starting address.\n");
1321     return;
1322     }
1323     }
1324    
1325     addr_end = addr_start + 1000;
1326    
1327     /* endaddr: */
1328     if (p != NULL) {
1329     while (*p == ' ' && *p)
1330     p++;
1331     r = debugger_parse_name(m, p, 0, &addr_end);
1332     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1333     printf("Unparsable address: %s\n", cmd_line);
1334     return;
1335     }
1336     } else
1337     lines_left = 20;
1338    
1339     if (m->cpus == NULL) {
1340     printf("No cpus (?)\n");
1341     return;
1342     }
1343     c = m->cpus[m->bootstrap_cpu];
1344     if (c == NULL) {
1345     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1346     return;
1347     }
1348     mem = m->cpus[m->bootstrap_cpu]->mem;
1349    
1350     addr = addr_start;
1351    
1352     ctrl_c = 0;
1353    
1354     while (addr < addr_end) {
1355     int i, len;
1356 dpavlin 4 unsigned char buf[32]; /* TODO: How long can an
1357 dpavlin 2 instruction be, on weird archs? */
1358     memset(buf, 0, sizeof(buf));
1359    
1360     for (i=0; i<sizeof(buf); i++)
1361     c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1362     CACHE_NONE | NO_EXCEPTIONS);
1363    
1364     len = cpu_disassemble_instr(m, c, buf, 0, addr, 0);
1365    
1366     if (ctrl_c)
1367     return;
1368     if (len == 0)
1369     break;
1370    
1371     addr += len;
1372    
1373     if (lines_left != -1) {
1374     lines_left --;
1375     if (lines_left == 0)
1376     break;
1377     }
1378     }
1379    
1380     last_unasm_addr = addr;
1381    
1382     strcpy(repeat_cmd, "unassemble");
1383     }
1384    
1385    
1386     /*
1387     * debugger_cmd_version():
1388     */
1389     static void debugger_cmd_version(struct machine *m, char *cmd_line)
1390     {
1391     if (*cmd_line) {
1392     printf("syntax: version\n");
1393     return;
1394     }
1395    
1396     #ifdef VERSION
1397     printf("%s, %s\n", VERSION, COMPILE_DATE);
1398     #else
1399     printf("(no version), %s\n", COMPILE_DATE);
1400     #endif
1401     }
1402    
1403    
1404     struct cmd {
1405     char *name;
1406     char *args;
1407     int tmp_flag;
1408     void (*f)(struct machine *, char *cmd_line);
1409     char *description;
1410     };
1411    
1412     static struct cmd cmds[] = {
1413     { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1414     "manipulate breakpoints" },
1415    
1416     { "bintrans", "[on|off]", 0, debugger_cmd_bintrans,
1417     "toggle bintrans on or off" },
1418    
1419     /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1420     available as a one-letter command is very convenient. */
1421    
1422     { "continue", "", 0, debugger_cmd_continue,
1423     "continue execution" },
1424    
1425     { "device", "...", 0, debugger_cmd_device,
1426     "show info about (or manipulate) devices" },
1427    
1428     { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1429     "dump memory contents in hex and ASCII" },
1430    
1431     { "emuls", "", 0, debugger_cmd_emuls,
1432     "print a summary of all current emuls" },
1433    
1434     { "focus", "x[,y]", 0, debugger_cmd_focus,
1435     "changes focus to machine x (in emul y)" },
1436    
1437     { "help", "", 0, debugger_cmd_help,
1438     "print this help message" },
1439    
1440     { "itrace", "", 0, debugger_cmd_itrace,
1441     "toggle instruction_trace on or off" },
1442    
1443     { "lookup", "name|addr", 0, debugger_cmd_lookup,
1444     "lookup a symbol by name or address" },
1445    
1446     { "machine", "", 0, debugger_cmd_machine,
1447     "print a summary of the current machine" },
1448    
1449     { "opcodestats", "", 0, debugger_cmd_opcodestats,
1450     "show opcode statistics" },
1451    
1452     { "pause", "cpuid", 0, debugger_cmd_pause,
1453     "pause (or unpause) a CPU" },
1454    
1455     { "print", "expr", 0, debugger_cmd_print,
1456     "evaluate an expression without side-effects" },
1457    
1458     { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1459     "modify emulated memory contents" },
1460    
1461     { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1462     "toggle quiet_mode on or off" },
1463    
1464     { "quit", "", 0, debugger_cmd_quit,
1465     "quit the emulator" },
1466    
1467     { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1468     "show GPRs (or coprocessor c's registers)" },
1469    
1470     /* NOTE: Try to keep 's' down to only one command. Having 'step'
1471     available as a one-letter command is very convenient. */
1472    
1473     { "step", "[n]", 0, debugger_cmd_step,
1474     "single-step one (or n) instruction(s)" },
1475    
1476     { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1477     "dump TLB contents (add ',r' for raw data)" },
1478    
1479     { "trace", "", 0, debugger_cmd_trace,
1480     "toggle show_trace_tree on or off" },
1481    
1482     { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1483     "dump memory contents as instructions" },
1484    
1485     { "version", "", 0, debugger_cmd_version,
1486     "print version information" },
1487    
1488     { NULL, NULL, 0, NULL, NULL }
1489     };
1490    
1491    
1492     /*
1493     * debugger_cmd_help():
1494     *
1495     * Print a list of available commands.
1496     *
1497     * NOTE: This is placed after the cmds[] array, because it needs to
1498     * access it.
1499     */
1500     static void debugger_cmd_help(struct machine *m, char *cmd_line)
1501     {
1502     int i, j, max_name_len = 0;
1503    
1504     i = 0;
1505     while (cmds[i].name != NULL) {
1506     int a = strlen(cmds[i].name);
1507     if (cmds[i].args != NULL)
1508     a += 1 + strlen(cmds[i].args);
1509     if (a > max_name_len)
1510     max_name_len = a;
1511     i++;
1512     }
1513    
1514     printf("Available commands:\n");
1515    
1516     i = 0;
1517     while (cmds[i].name != NULL) {
1518     char buf[100];
1519     snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1520     if (cmds[i].args != NULL)
1521     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1522     " %s", cmds[i].args);
1523    
1524     printf(" ");
1525     for (j=0; j<max_name_len; j++)
1526     if (j < strlen(buf))
1527     printf("%c", buf[j]);
1528     else
1529     printf(" ");
1530    
1531     printf(" %s\n", cmds[i].description);
1532     i++;
1533     }
1534    
1535     printf("Generic assignments: x = expr\n");
1536     printf("where x must be a register, and expr can be a register, a "
1537     "numeric value, or\na symbol name (+ an optional numeric offset)."
1538     " In case there are multiple\nmatches (ie a symbol that has the "
1539     "same name as a register), you may add a\nprefix character as a "
1540     "hint: '%%' for registers, '@' for symbols, and\n'$' for numeric"
1541     " values. Use 0x for hexadecimal values.\n");
1542     }
1543    
1544    
1545     /****************************************************************************/
1546    
1547    
1548     /*
1549     * debugger_assignment():
1550     *
1551     * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
1552     */
1553     void debugger_assignment(struct machine *m, char *cmd)
1554     {
1555     char *left, *right;
1556     int res_left, res_right;
1557     uint64_t tmp;
1558    
1559     left = malloc(strlen(cmd) + 1);
1560     if (left == NULL) {
1561     fprintf(stderr, "out of memory in debugger_assignment()\n");
1562     exit(1);
1563     }
1564     strcpy(left, cmd);
1565     right = strchr(left, '=');
1566     if (right == NULL) {
1567     fprintf(stderr, "internal error in the debugger\n");
1568     exit(1);
1569     }
1570     *right = '\0';
1571    
1572     /* Remove trailing spaces in left: */
1573     while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
1574     left[strlen(left)-1] = '\0';
1575    
1576     /* Remove leading spaces in right: */
1577     right++;
1578     while (*right == ' ' && *right != '\0')
1579     right++;
1580    
1581     /* printf("left = '%s'\nright = '%s'\n", left, right); */
1582    
1583     res_right = debugger_parse_name(m, right, 0, &tmp);
1584     switch (res_right) {
1585     case NAME_PARSE_NOMATCH:
1586     printf("No match for the right-hand side of the assignment.\n");
1587     break;
1588     case NAME_PARSE_MULTIPLE:
1589     printf("Multiple matches for the right-hand side of the "
1590     "assignment.\n");
1591     break;
1592     default:
1593     res_left = debugger_parse_name(m, left, 1, &tmp);
1594     switch (res_left) {
1595     case NAME_PARSE_NOMATCH:
1596     printf("No match for the left-hand side of the "
1597     "assignment.\n");
1598     break;
1599     case NAME_PARSE_MULTIPLE:
1600     printf("Multiple matches for the left-hand side "
1601     "of the assignment.\n");
1602     break;
1603     default:
1604     debugger_cmd_print(m, left);
1605     }
1606     }
1607    
1608     free(left);
1609     }
1610    
1611    
1612     /*
1613     * debugger_readline():
1614     *
1615     * Read a line from the terminal.
1616     */
1617     static char *debugger_readline(void)
1618     {
1619     int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
1620     int read_from_index = last_cmd_index;
1621     char *cmd = last_cmd[last_cmd_index];
1622    
1623     cmd_len = 0; cmd[0] = '\0';
1624     printf("GXemul> ");
1625     fflush(stdout);
1626    
1627     ch = '\0';
1628     cmd_len = 0;
1629     cursor_pos = 0;
1630    
1631     while (ch != '\n') {
1632     /*
1633     * TODO: This uses up 100% CPU, maybe that isn't too good.
1634     * The usleep() call might make it a tiny bit nicer on other
1635     * running processes, but it is still very ugly.
1636     */
1637     while ((ch = console_readchar(MAIN_CONSOLE)) < 0) {
1638     x11_check_event(debugger_emuls, debugger_n_emuls);
1639     usleep(2);
1640     }
1641    
1642     if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
1643     /* Backspace. */
1644     cursor_pos --;
1645     cmd_len --;
1646     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1647     cmd_len);
1648     cmd[cmd_len] = '\0';
1649     printf("\b");
1650     for (i=cursor_pos; i<cmd_len; i++)
1651     printf("%c", cmd[i]);
1652     printf(" \b");
1653     for (i=cursor_pos; i<cmd_len; i++)
1654     printf("\b");
1655     } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
1656     /* CTRL-D: Delete. */
1657     cmd_len --;
1658     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1659     cmd_len);
1660     cmd[cmd_len] = '\0';
1661     for (i=cursor_pos; i<cmd_len; i++)
1662     printf("%c", cmd[i]);
1663     printf(" \b");
1664     for (i=cursor_pos; i<cmd_len; i++)
1665     printf("\b");
1666     } else if (ch == 1) {
1667     /* CTRL-A: Start of line. */
1668     while (cursor_pos > 0) {
1669     cursor_pos --;
1670     printf("\b");
1671     }
1672     } else if (ch == 2) {
1673     /* CTRL-B: Backwards one character. */
1674     if (cursor_pos > 0) {
1675     printf("\b");
1676     cursor_pos --;
1677     }
1678     } else if (ch == 5) {
1679     /* CTRL-E: End of line. */
1680     while (cursor_pos < cmd_len) {
1681     printf("%c", cmd[cursor_pos]);
1682     cursor_pos ++;
1683     }
1684     } else if (ch == 6) {
1685     /* CTRL-F: Forward one character. */
1686     if (cursor_pos < cmd_len) {
1687     printf("%c",
1688     cmd[cursor_pos]);
1689     cursor_pos ++;
1690     }
1691     } else if (ch == 11) {
1692     /* CTRL-K: Kill to end of line. */
1693     for (i=0; i<MAX_CMD_LEN; i++)
1694     console_makeavail(MAIN_CONSOLE, 4); /* :-) */
1695     } else if (ch == 14 || ch == 16) {
1696     /* CTRL-P: Previous line in the command history,
1697     CTRL-N: next line */
1698     do {
1699     if (ch == 14 &&
1700     read_from_index == last_cmd_index)
1701     break;
1702     if (ch == 16)
1703     i = read_from_index - 1;
1704     else
1705     i = read_from_index + 1;
1706    
1707     if (i < 0)
1708     i = N_PREVIOUS_CMDS - 1;
1709     if (i >= N_PREVIOUS_CMDS)
1710     i = 0;
1711    
1712     /* Special case: pressing 'down'
1713     to reach last_cmd_index: */
1714     if (i == last_cmd_index) {
1715     read_from_index = i;
1716     for (i=cursor_pos; i<cmd_len;
1717     i++)
1718     printf(" ");
1719     for (i=cmd_len-1; i>=0; i--)
1720     printf("\b \b");
1721     cmd[0] = '\0';
1722     cmd_len = cursor_pos = 0;
1723     } else if (last_cmd[i][0] != '\0') {
1724     /* Copy from old line: */
1725     read_from_index = i;
1726     for (i=cursor_pos; i<cmd_len;
1727     i++)
1728     printf(" ");
1729     for (i=cmd_len-1; i>=0; i--)
1730     printf("\b \b");
1731     strcpy(cmd,
1732     last_cmd[read_from_index]);
1733     cmd_len = strlen(cmd);
1734     printf("%s", cmd);
1735     cursor_pos = cmd_len;
1736     }
1737     } while (0);
1738     } else if (ch >= ' ' && cmd_len < MAX_CMD_LEN) {
1739     /* Visible character: */
1740     memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
1741     cmd_len - cursor_pos);
1742     cmd[cursor_pos] = ch;
1743     cmd_len ++;
1744     cursor_pos ++;
1745     cmd[cmd_len] = '\0';
1746     printf("%c", ch);
1747     for (i=cursor_pos; i<cmd_len; i++)
1748     printf("%c", cmd[i]);
1749     for (i=cursor_pos; i<cmd_len; i++)
1750     printf("\b");
1751     } else if (ch == '\r' || ch == '\n') {
1752     ch = '\n';
1753     printf("\n");
1754     } else if (ch == '\t') {
1755     /* Super-simple tab-completion: */
1756     i = 0;
1757     while (cmds[i].name != NULL)
1758     cmds[i++].tmp_flag = 0;
1759    
1760     /* Check for a (partial) command match: */
1761     n = i = i_match = 0;
1762     while (cmds[i].name != NULL) {
1763     if (strncasecmp(cmds[i].name, cmd,
1764     cmd_len) == 0) {
1765     cmds[i].tmp_flag = 1;
1766     i_match = i;
1767     n++;
1768     }
1769     i++;
1770     }
1771    
1772     switch (n) {
1773     case 0: /* Beep. */
1774     printf("\a");
1775     break;
1776     case 1: /* Add the rest of the command: */
1777     reallen = strlen(cmds[i_match].name);
1778     for (i=cmd_len; i<reallen; i++)
1779     console_makeavail(MAIN_CONSOLE,
1780     cmds[i_match].name[i]);
1781     /* ... and a space, if the command takes
1782     any arguments: */
1783     if (cmds[i_match].args != NULL &&
1784     cmds[i_match].args[0] != '\0')
1785     console_makeavail(MAIN_CONSOLE, ' ');
1786     break;
1787     default:
1788     /* Show all possible commands: */
1789     printf("\a\n"); /* Beep. :-) */
1790     i = 0; /* i = cmds index */
1791     j = 0; /* j = # of cmds printed */
1792     while (cmds[i].name != NULL) {
1793     if (cmds[i].tmp_flag) {
1794     int q;
1795     if (j == 0)
1796     printf(" ");
1797     printf("%s",
1798     cmds[i].name);
1799     j++;
1800     if (j != 6)
1801     for (q=0; q<13-strlen(
1802     cmds[i].name); q++)
1803     printf(" ");
1804     if (j == 6) {
1805     printf("\n");
1806     j = 0;
1807     }
1808     }
1809     i++;
1810     }
1811     if (j != 0)
1812     printf("\n");
1813     printf("GXemul> ");
1814     for (i=0; i<cmd_len; i++)
1815     printf("%c", cmd[i]);
1816     }
1817     } else if (ch == 27) {
1818     /* Escape codes: (cursor keys etc) */
1819     while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
1820     usleep(1);
1821     if (ch == '[' || ch == 'O') {
1822     while ((ch = console_readchar(MAIN_CONSOLE))
1823     < 0)
1824     usleep(1);
1825     switch (ch) {
1826     case '2': /* 2~ = ins */
1827     case '5': /* 5~ = pgup */
1828     case '6': /* 6~ = pgdn */
1829     /* TODO: Ugly hack, but might work. */
1830     while ((ch = console_readchar(
1831     MAIN_CONSOLE)) < 0)
1832     usleep(1);
1833     /* Do nothing for these keys. */
1834     break;
1835     case '3': /* 3~ = delete */
1836     /* TODO: Ugly hack, but might work. */
1837     while ((ch = console_readchar(
1838     MAIN_CONSOLE)) < 0)
1839     usleep(1);
1840     console_makeavail(MAIN_CONSOLE, '\b');
1841     break;
1842     case 'A': /* Up. */
1843     /* Up cursor ==> CTRL-P */
1844     console_makeavail(MAIN_CONSOLE, 16);
1845     break;
1846     case 'B': /* Down. */
1847     /* Down cursor ==> CTRL-N */
1848     console_makeavail(MAIN_CONSOLE, 14);
1849     break;
1850     case 'C':
1851     /* Right cursor ==> CTRL-F */
1852     console_makeavail(MAIN_CONSOLE, 6);
1853     break;
1854     case 'D': /* Left */
1855     /* Left cursor ==> CTRL-B */
1856     console_makeavail(MAIN_CONSOLE, 2);
1857     break;
1858     case 'F':
1859     /* End ==> CTRL-E */
1860     console_makeavail(MAIN_CONSOLE, 5);
1861     break;
1862     case 'H':
1863     /* Home ==> CTRL-A */
1864     console_makeavail(MAIN_CONSOLE, 1);
1865     break;
1866     }
1867     }
1868     }
1869    
1870     fflush(stdout);
1871     }
1872    
1873     return cmd;
1874     }
1875    
1876    
1877     /*
1878     * debugger():
1879     *
1880     * This is a loop, which reads a command from the terminal, and executes it.
1881     */
1882     void debugger(void)
1883     {
1884     int i, n, i_match, matchlen, cmd_len;
1885     char *cmd;
1886    
1887     if (n_steps_left_before_interaction > 0) {
1888     n_steps_left_before_interaction --;
1889     return;
1890     }
1891    
1892     exit_debugger = 0;
1893    
1894     while (!exit_debugger) {
1895     /* Read a line from the terminal: */
1896     cmd = debugger_readline();
1897     cmd_len = strlen(cmd);
1898    
1899     /* Remove spaces: */
1900     while (cmd_len > 0 && cmd[0]==' ')
1901     memmove(cmd, cmd+1, cmd_len --);
1902     while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
1903     cmd[(cmd_len--)-1] = '\0';
1904    
1905     /* No command? Then try reading another line. */
1906     if (cmd_len == 0) {
1907     /* Special case for repeated commands: */
1908     if (repeat_cmd[0] != '\0')
1909     strcpy(cmd, repeat_cmd);
1910     else
1911     continue;
1912     } else {
1913     last_cmd_index ++;
1914     if (last_cmd_index >= N_PREVIOUS_CMDS)
1915     last_cmd_index = 0;
1916    
1917     repeat_cmd[0] = '\0';
1918     }
1919    
1920     /*
1921     * Is there a '=' on the command line? Then try to do an
1922     * assignment. (Only if there is just one word, followed
1923     * by the '=' sign. This makes it possible to use commands
1924     * such as "device add name addr=xyz".)
1925     */
1926     if (strchr(cmd, '=') != NULL) {
1927     /* Count the nr of words: */
1928     int nw = 0, inword = 0;
1929     char *p = cmd;
1930     while (*p) {
1931     if (*p == '=')
1932     break;
1933     if (*p != ' ') {
1934     if (!inword)
1935     nw ++;
1936     inword = 1;
1937     } else
1938     inword = 0;
1939     p++;
1940     }
1941    
1942     if (nw == 1) {
1943     debugger_assignment(debugger_machine, cmd);
1944     continue;
1945     }
1946     }
1947    
1948     i = 0;
1949     while (cmds[i].name != NULL)
1950     cmds[i++].tmp_flag = 0;
1951    
1952     /* How many chars in cmd to match against: */
1953     matchlen = 0;
1954     while (isalpha((int)cmd[matchlen]))
1955     matchlen ++;
1956    
1957     /* Check for a command name match: */
1958     n = i = i_match = 0;
1959     while (cmds[i].name != NULL) {
1960     if (strncasecmp(cmds[i].name, cmd, matchlen) == 0) {
1961     cmds[i].tmp_flag = 1;
1962     i_match = i;
1963     n++;
1964     }
1965     i++;
1966     }
1967    
1968     /* No match? */
1969     if (n == 0) {
1970     printf("Unknown command '%s'. "
1971     "Type 'help' for help.\n", cmd);
1972     continue;
1973     }
1974    
1975     /* More than one match? */
1976     if (n > 1) {
1977     printf("Ambiguous command '%s': ", cmd);
1978     i = 0;
1979     while (cmds[i].name != NULL) {
1980     if (cmds[i].tmp_flag)
1981     printf(" %s", cmds[i].name);
1982     i++;
1983     }
1984     printf("\n");
1985     continue;
1986     }
1987    
1988     /* Exactly one match: */
1989     if (cmds[i_match].f != NULL) {
1990     char *p = cmd + matchlen;
1991     /* Remove leading whitespace from the args... */
1992     while (*p != '\0' && *p == ' ')
1993     p++;
1994    
1995     /* ... and run the command: */
1996     cmds[i_match].f(debugger_machine, p);
1997     } else
1998     printf("FATAL ERROR: internal error in debugger.c:"
1999     " no handler for this command?\n");
2000    
2001     /* Special hack for the "step" command: */
2002     if (exit_debugger == -1)
2003     return;
2004     }
2005    
2006     single_step = 0;
2007     debugger_machine->instruction_trace = old_instruction_trace;
2008     debugger_machine->show_trace_tree = old_show_trace_tree;
2009     quiet_mode = old_quiet_mode;
2010     }
2011    
2012    
2013     /*
2014     * debugger_reset():
2015     *
2016     * This function should be called before calling debugger(), when it is
2017     * absolutely necessary that debugger() is interactive. Otherwise, it might
2018     * return without doing anything, such as when single-stepping multiple
2019     * instructions at a time.
2020     */
2021     void debugger_reset(void)
2022     {
2023     n_steps_left_before_interaction = 0;
2024     }
2025    
2026    
2027     /*
2028     * debugger_init():
2029     *
2030     * Must be called before any other debugger function is used.
2031     */
2032     void debugger_init(struct emul **emuls, int n_emuls)
2033     {
2034     int i;
2035    
2036     debugger_n_emuls = n_emuls;
2037     debugger_emuls = emuls;
2038    
2039     if (n_emuls < 1) {
2040     fprintf(stderr, "\nERROR: No emuls (?)\n");
2041     exit(1);
2042     }
2043    
2044     debugger_emul = emuls[0];
2045     if (emuls[0]->n_machines < 1) {
2046     fprintf(stderr, "\nERROR: No machines in emuls[0], "
2047     "cannot handle this situation yet.\n\n");
2048     exit(1);
2049     }
2050    
2051     debugger_machine = emuls[0]->machines[0];
2052    
2053     for (i=0; i<N_PREVIOUS_CMDS; i++) {
2054     last_cmd[i] = malloc(MAX_CMD_LEN + 1);
2055     if (last_cmd[i] == NULL) {
2056     fprintf(stderr, "debugger_init(): out of memory\n");
2057     exit(1);
2058     }
2059     last_cmd[i][0] = '\0';
2060     }
2061    
2062     last_cmd_index = 0;
2063     repeat_cmd[0] = '\0';
2064     }
2065    

  ViewVC Help
Powered by ViewVC 1.1.26