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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26