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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26