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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (hide annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 52084 byte(s)
0.3.6.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 dpavlin 12 * $Id: debugger.c,v 1.122 2005/08/11 09:43:40 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     * "pc", "r5", "hi", "t4" ==> register (CPU dependant)
184     * "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 12 if (mem->dev_flags[i] & MEM_DYNTRANS_OK)
560     printf("DYNTRANS R");
561     if (mem->dev_flags[i] & MEM_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 12 int i, toggle = 1;
1382     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 dpavlin 12 /* Clear translations: */
1427     for (i=0; i<m->ncpus; i++)
1428     if (m->cpus[i]->translation_cache != NULL)
1429     cpu_create_or_reset_tc(m->cpus[i]);
1430 dpavlin 2 }
1431    
1432    
1433     /*
1434     * debugger_cmd_unassemble():
1435     *
1436     * Dump emulated memory as instructions.
1437     *
1438     * syntax: unassemble [addr [endaddr]]
1439     */
1440     static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1441     {
1442     uint64_t addr, addr_start, addr_end;
1443     struct cpu *c;
1444     struct memory *mem;
1445     char *p = NULL;
1446     int r, lines_left = -1;
1447    
1448     if (cmd_line[0] != '\0') {
1449     uint64_t tmp;
1450     char *tmps = strdup(cmd_line);
1451    
1452     /* addr: */
1453     p = strchr(tmps, ' ');
1454     if (p != NULL)
1455     *p = '\0';
1456     r = debugger_parse_name(m, tmps, 0, &tmp);
1457     free(tmps);
1458    
1459     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1460     printf("Unparsable address: %s\n", cmd_line);
1461     return;
1462     } else {
1463     last_unasm_addr = tmp;
1464     }
1465    
1466     p = strchr(cmd_line, ' ');
1467     }
1468    
1469     addr_start = last_unasm_addr;
1470    
1471     if (addr_start == MAGIC_UNTOUCHED) {
1472     uint64_t tmp;
1473     int match_register = 0;
1474     cpu_register_match(m, "pc", 0, &tmp, &match_register);
1475     if (match_register) {
1476     addr_start = tmp;
1477     } else {
1478     printf("No starting address.\n");
1479     return;
1480     }
1481     }
1482    
1483     addr_end = addr_start + 1000;
1484    
1485     /* endaddr: */
1486     if (p != NULL) {
1487     while (*p == ' ' && *p)
1488     p++;
1489     r = debugger_parse_name(m, p, 0, &addr_end);
1490     if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1491     printf("Unparsable address: %s\n", cmd_line);
1492     return;
1493     }
1494     } else
1495     lines_left = 20;
1496    
1497     if (m->cpus == NULL) {
1498     printf("No cpus (?)\n");
1499     return;
1500     }
1501     c = m->cpus[m->bootstrap_cpu];
1502     if (c == NULL) {
1503     printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1504     return;
1505     }
1506     mem = m->cpus[m->bootstrap_cpu]->mem;
1507    
1508     addr = addr_start;
1509    
1510     ctrl_c = 0;
1511    
1512     while (addr < addr_end) {
1513 dpavlin 12 unsigned int i, len;
1514     unsigned char buf[17]; /* TODO: How long can an
1515 dpavlin 2 instruction be, on weird archs? */
1516     memset(buf, 0, sizeof(buf));
1517    
1518     for (i=0; i<sizeof(buf); i++)
1519     c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1520     CACHE_NONE | NO_EXCEPTIONS);
1521    
1522     len = cpu_disassemble_instr(m, c, buf, 0, addr, 0);
1523    
1524     if (ctrl_c)
1525     return;
1526     if (len == 0)
1527     break;
1528    
1529     addr += len;
1530    
1531     if (lines_left != -1) {
1532     lines_left --;
1533     if (lines_left == 0)
1534     break;
1535     }
1536     }
1537    
1538     last_unasm_addr = addr;
1539    
1540 dpavlin 10 strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN);
1541 dpavlin 2 }
1542    
1543    
1544     /*
1545     * debugger_cmd_version():
1546     */
1547     static void debugger_cmd_version(struct machine *m, char *cmd_line)
1548     {
1549     if (*cmd_line) {
1550     printf("syntax: version\n");
1551     return;
1552     }
1553    
1554     #ifdef VERSION
1555     printf("%s, %s\n", VERSION, COMPILE_DATE);
1556     #else
1557     printf("(no version), %s\n", COMPILE_DATE);
1558     #endif
1559     }
1560    
1561    
1562     struct cmd {
1563     char *name;
1564     char *args;
1565     int tmp_flag;
1566     void (*f)(struct machine *, char *cmd_line);
1567     char *description;
1568     };
1569    
1570     static struct cmd cmds[] = {
1571     { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1572     "manipulate breakpoints" },
1573    
1574     { "bintrans", "[on|off]", 0, debugger_cmd_bintrans,
1575     "toggle bintrans on or off" },
1576    
1577     /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1578     available as a one-letter command is very convenient. */
1579    
1580     { "continue", "", 0, debugger_cmd_continue,
1581     "continue execution" },
1582    
1583     { "device", "...", 0, debugger_cmd_device,
1584     "show info about (or manipulate) devices" },
1585    
1586     { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1587     "dump memory contents in hex and ASCII" },
1588    
1589     { "emuls", "", 0, debugger_cmd_emuls,
1590     "print a summary of all current emuls" },
1591    
1592     { "focus", "x[,y]", 0, debugger_cmd_focus,
1593     "changes focus to machine x (in emul y)" },
1594    
1595     { "help", "", 0, debugger_cmd_help,
1596     "print this help message" },
1597    
1598     { "itrace", "", 0, debugger_cmd_itrace,
1599     "toggle instruction_trace on or off" },
1600    
1601     { "lookup", "name|addr", 0, debugger_cmd_lookup,
1602     "lookup a symbol by name or address" },
1603    
1604     { "machine", "", 0, debugger_cmd_machine,
1605     "print a summary of the current machine" },
1606    
1607 dpavlin 12 { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs,
1608     "toggle (set or unset) show_nr_of_instructions" },
1609    
1610 dpavlin 2 { "opcodestats", "", 0, debugger_cmd_opcodestats,
1611     "show opcode statistics" },
1612    
1613     { "pause", "cpuid", 0, debugger_cmd_pause,
1614     "pause (or unpause) a CPU" },
1615    
1616     { "print", "expr", 0, debugger_cmd_print,
1617     "evaluate an expression without side-effects" },
1618    
1619     { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1620     "modify emulated memory contents" },
1621    
1622     { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1623     "toggle quiet_mode on or off" },
1624    
1625     { "quit", "", 0, debugger_cmd_quit,
1626     "quit the emulator" },
1627    
1628     { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1629     "show GPRs (or coprocessor c's registers)" },
1630    
1631     /* NOTE: Try to keep 's' down to only one command. Having 'step'
1632     available as a one-letter command is very convenient. */
1633    
1634     { "step", "[n]", 0, debugger_cmd_step,
1635     "single-step one (or n) instruction(s)" },
1636    
1637     { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1638     "dump TLB contents (add ',r' for raw data)" },
1639    
1640 dpavlin 12 { "trace", "[on|off]", 0, debugger_cmd_trace,
1641 dpavlin 2 "toggle show_trace_tree on or off" },
1642    
1643     { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1644     "dump memory contents as instructions" },
1645    
1646     { "version", "", 0, debugger_cmd_version,
1647     "print version information" },
1648    
1649 dpavlin 12 /* Note: NULL handler. */
1650     { "x = expr", "", 0, NULL, "generic assignment" },
1651    
1652 dpavlin 2 { NULL, NULL, 0, NULL, NULL }
1653     };
1654    
1655    
1656     /*
1657     * debugger_cmd_help():
1658     *
1659     * Print a list of available commands.
1660     *
1661     * NOTE: This is placed after the cmds[] array, because it needs to
1662     * access it.
1663 dpavlin 10 *
1664     * TODO: Command completion (ie just type "help s" for "help step").
1665 dpavlin 2 */
1666     static void debugger_cmd_help(struct machine *m, char *cmd_line)
1667     {
1668 dpavlin 12 int i, max_name_len = 0, only_one = 0, only_one_match = 0;
1669     char *nlines_env = getenv("LINES");
1670     int nlines = atoi(nlines_env != NULL? nlines_env : "999999");
1671     int j, curlines;
1672 dpavlin 2
1673 dpavlin 10 if (cmd_line[0] != '\0') {
1674     only_one = 1;
1675     }
1676    
1677 dpavlin 2 i = 0;
1678     while (cmds[i].name != NULL) {
1679     int a = strlen(cmds[i].name);
1680     if (cmds[i].args != NULL)
1681     a += 1 + strlen(cmds[i].args);
1682     if (a > max_name_len)
1683     max_name_len = a;
1684     i++;
1685     }
1686    
1687 dpavlin 12 curlines = 0;
1688     if (!only_one) {
1689 dpavlin 10 printf("Available commands:\n");
1690 dpavlin 12 curlines++;
1691     }
1692 dpavlin 2
1693     i = 0;
1694     while (cmds[i].name != NULL) {
1695     char buf[100];
1696     snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1697 dpavlin 10
1698     if (only_one) {
1699     if (strcmp(cmds[i].name, cmd_line) != 0) {
1700     i++;
1701     continue;
1702     }
1703     only_one_match = 1;
1704     }
1705    
1706 dpavlin 2 if (cmds[i].args != NULL)
1707     snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1708     " %s", cmds[i].args);
1709    
1710     printf(" ");
1711     for (j=0; j<max_name_len; j++)
1712     if (j < strlen(buf))
1713     printf("%c", buf[j]);
1714     else
1715     printf(" ");
1716    
1717     printf(" %s\n", cmds[i].description);
1718     i++;
1719 dpavlin 12
1720     curlines ++;
1721     if (curlines >= nlines - 1) {
1722     char ch;
1723     printf("-- more --"); fflush(stdout);
1724     ch = debugger_readchar();
1725     printf("\n");
1726     if (ch == 'q' || ch == 'Q')
1727     return;
1728     curlines = 0;
1729     }
1730 dpavlin 2 }
1731    
1732 dpavlin 10 if (only_one) {
1733     if (!only_one_match)
1734     printf("%s: no such command\n", cmd_line);
1735     return;
1736     }
1737    
1738 dpavlin 12 /* TODO: generalize/refactor */
1739     curlines += 8;
1740     if (curlines > nlines - 1) {
1741     char ch;
1742     printf("-- more --"); fflush(stdout);
1743     ch = debugger_readchar();
1744     printf("\n");
1745     if (ch == 'q' || ch == 'Q')
1746     return;
1747     curlines = 0;
1748     }
1749    
1750     printf("\nIn generic assignments, x must be a register, and expr can be"
1751     " a register, a\nnumeric value, or a symbol name (+ an optional "
1752     "numeric offset). In case there\nare multiple matches (i.e. a "
1753     "symbol that has the same name as a register), you\nmay add a "
1754     "prefix character as a hint: '%%' for registers, '@' for symbols,"
1755     " and\n'$' for numeric values. Use 0x for hexadecimal values.\n");
1756 dpavlin 2 }
1757    
1758    
1759     /****************************************************************************/
1760    
1761    
1762     /*
1763     * debugger_assignment():
1764     *
1765     * cmd contains something like "pc=0x80001000", or "r31=memcpy+0x40".
1766     */
1767     void debugger_assignment(struct machine *m, char *cmd)
1768     {
1769     char *left, *right;
1770     int res_left, res_right;
1771     uint64_t tmp;
1772 dpavlin 12 uint64_t old_pc = m->cpus[0]->pc; /* TODO: multiple cpus? */
1773 dpavlin 2
1774 dpavlin 10 left = malloc(MAX_CMD_BUFLEN);
1775 dpavlin 2 if (left == NULL) {
1776     fprintf(stderr, "out of memory in debugger_assignment()\n");
1777     exit(1);
1778     }
1779 dpavlin 10 strlcpy(left, cmd, MAX_CMD_BUFLEN);
1780 dpavlin 2 right = strchr(left, '=');
1781     if (right == NULL) {
1782     fprintf(stderr, "internal error in the debugger\n");
1783     exit(1);
1784     }
1785     *right = '\0';
1786    
1787     /* Remove trailing spaces in left: */
1788     while (strlen(left) >= 1 && left[strlen(left)-1] == ' ')
1789     left[strlen(left)-1] = '\0';
1790    
1791     /* Remove leading spaces in right: */
1792     right++;
1793     while (*right == ' ' && *right != '\0')
1794     right++;
1795    
1796     /* printf("left = '%s'\nright = '%s'\n", left, right); */
1797    
1798     res_right = debugger_parse_name(m, right, 0, &tmp);
1799     switch (res_right) {
1800     case NAME_PARSE_NOMATCH:
1801     printf("No match for the right-hand side of the assignment.\n");
1802     break;
1803     case NAME_PARSE_MULTIPLE:
1804     printf("Multiple matches for the right-hand side of the "
1805     "assignment.\n");
1806     break;
1807     default:
1808     res_left = debugger_parse_name(m, left, 1, &tmp);
1809     switch (res_left) {
1810     case NAME_PARSE_NOMATCH:
1811     printf("No match for the left-hand side of the "
1812     "assignment.\n");
1813     break;
1814     case NAME_PARSE_MULTIPLE:
1815     printf("Multiple matches for the left-hand side "
1816     "of the assignment.\n");
1817     break;
1818     default:
1819     debugger_cmd_print(m, left);
1820     }
1821     }
1822    
1823 dpavlin 12 /*
1824     * If the PC has changed, then release any breakpoint we were
1825     * currently stopped at.
1826     *
1827     * TODO: multiple cpus?
1828     */
1829     if (old_pc != m->cpus[0]->pc)
1830     single_step_breakpoint = 0;
1831    
1832 dpavlin 2 free(left);
1833     }
1834    
1835    
1836     /*
1837     * debugger_readline():
1838     *
1839     * Read a line from the terminal.
1840     */
1841     static char *debugger_readline(void)
1842     {
1843     int ch, i, j, n, i_match, reallen, cmd_len, cursor_pos;
1844     int read_from_index = last_cmd_index;
1845     char *cmd = last_cmd[last_cmd_index];
1846    
1847     cmd_len = 0; cmd[0] = '\0';
1848     printf("GXemul> ");
1849     fflush(stdout);
1850    
1851     ch = '\0';
1852     cmd_len = 0;
1853     cursor_pos = 0;
1854    
1855     while (ch != '\n') {
1856 dpavlin 12 ch = debugger_readchar();
1857 dpavlin 2
1858     if ((ch == '\b' || ch == 127) && cursor_pos > 0) {
1859     /* Backspace. */
1860     cursor_pos --;
1861     cmd_len --;
1862     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1863     cmd_len);
1864     cmd[cmd_len] = '\0';
1865     printf("\b");
1866     for (i=cursor_pos; i<cmd_len; i++)
1867     printf("%c", cmd[i]);
1868     printf(" \b");
1869     for (i=cursor_pos; i<cmd_len; i++)
1870     printf("\b");
1871     } else if (ch == 4 && cmd_len > 0 && cursor_pos < cmd_len) {
1872     /* CTRL-D: Delete. */
1873     cmd_len --;
1874     memmove(cmd + cursor_pos, cmd + cursor_pos + 1,
1875     cmd_len);
1876     cmd[cmd_len] = '\0';
1877     for (i=cursor_pos; i<cmd_len; i++)
1878     printf("%c", cmd[i]);
1879     printf(" \b");
1880     for (i=cursor_pos; i<cmd_len; i++)
1881     printf("\b");
1882     } else if (ch == 1) {
1883     /* CTRL-A: Start of line. */
1884     while (cursor_pos > 0) {
1885     cursor_pos --;
1886     printf("\b");
1887     }
1888     } else if (ch == 2) {
1889     /* CTRL-B: Backwards one character. */
1890     if (cursor_pos > 0) {
1891     printf("\b");
1892     cursor_pos --;
1893     }
1894     } else if (ch == 5) {
1895     /* CTRL-E: End of line. */
1896     while (cursor_pos < cmd_len) {
1897     printf("%c", cmd[cursor_pos]);
1898     cursor_pos ++;
1899     }
1900     } else if (ch == 6) {
1901     /* CTRL-F: Forward one character. */
1902     if (cursor_pos < cmd_len) {
1903     printf("%c",
1904     cmd[cursor_pos]);
1905     cursor_pos ++;
1906     }
1907     } else if (ch == 11) {
1908     /* CTRL-K: Kill to end of line. */
1909 dpavlin 10 for (i=0; i<MAX_CMD_BUFLEN; i++)
1910 dpavlin 2 console_makeavail(MAIN_CONSOLE, 4); /* :-) */
1911     } else if (ch == 14 || ch == 16) {
1912     /* CTRL-P: Previous line in the command history,
1913     CTRL-N: next line */
1914     do {
1915     if (ch == 14 &&
1916     read_from_index == last_cmd_index)
1917     break;
1918     if (ch == 16)
1919     i = read_from_index - 1;
1920     else
1921     i = read_from_index + 1;
1922    
1923     if (i < 0)
1924     i = N_PREVIOUS_CMDS - 1;
1925     if (i >= N_PREVIOUS_CMDS)
1926     i = 0;
1927    
1928     /* Special case: pressing 'down'
1929     to reach last_cmd_index: */
1930     if (i == last_cmd_index) {
1931     read_from_index = i;
1932     for (i=cursor_pos; i<cmd_len;
1933     i++)
1934     printf(" ");
1935     for (i=cmd_len-1; i>=0; i--)
1936     printf("\b \b");
1937     cmd[0] = '\0';
1938     cmd_len = cursor_pos = 0;
1939     } else if (last_cmd[i][0] != '\0') {
1940     /* Copy from old line: */
1941     read_from_index = i;
1942     for (i=cursor_pos; i<cmd_len;
1943     i++)
1944     printf(" ");
1945     for (i=cmd_len-1; i>=0; i--)
1946     printf("\b \b");
1947 dpavlin 10 strlcpy(cmd,
1948     last_cmd[read_from_index],
1949     MAX_CMD_BUFLEN);
1950 dpavlin 2 cmd_len = strlen(cmd);
1951     printf("%s", cmd);
1952     cursor_pos = cmd_len;
1953     }
1954     } while (0);
1955 dpavlin 10 } else if (ch >= ' ' && cmd_len < MAX_CMD_BUFLEN-1) {
1956 dpavlin 2 /* Visible character: */
1957     memmove(cmd + cursor_pos + 1, cmd + cursor_pos,
1958     cmd_len - cursor_pos);
1959     cmd[cursor_pos] = ch;
1960     cmd_len ++;
1961     cursor_pos ++;
1962     cmd[cmd_len] = '\0';
1963     printf("%c", ch);
1964     for (i=cursor_pos; i<cmd_len; i++)
1965     printf("%c", cmd[i]);
1966     for (i=cursor_pos; i<cmd_len; i++)
1967     printf("\b");
1968     } else if (ch == '\r' || ch == '\n') {
1969     ch = '\n';
1970     printf("\n");
1971     } else if (ch == '\t') {
1972     /* Super-simple tab-completion: */
1973     i = 0;
1974     while (cmds[i].name != NULL)
1975     cmds[i++].tmp_flag = 0;
1976    
1977     /* Check for a (partial) command match: */
1978     n = i = i_match = 0;
1979     while (cmds[i].name != NULL) {
1980     if (strncasecmp(cmds[i].name, cmd,
1981     cmd_len) == 0) {
1982     cmds[i].tmp_flag = 1;
1983     i_match = i;
1984     n++;
1985     }
1986     i++;
1987     }
1988    
1989     switch (n) {
1990     case 0: /* Beep. */
1991     printf("\a");
1992     break;
1993     case 1: /* Add the rest of the command: */
1994     reallen = strlen(cmds[i_match].name);
1995     for (i=cmd_len; i<reallen; i++)
1996     console_makeavail(MAIN_CONSOLE,
1997     cmds[i_match].name[i]);
1998     /* ... and a space, if the command takes
1999     any arguments: */
2000     if (cmds[i_match].args != NULL &&
2001     cmds[i_match].args[0] != '\0')
2002     console_makeavail(MAIN_CONSOLE, ' ');
2003     break;
2004     default:
2005     /* Show all possible commands: */
2006     printf("\a\n"); /* Beep. :-) */
2007     i = 0; /* i = cmds index */
2008     j = 0; /* j = # of cmds printed */
2009     while (cmds[i].name != NULL) {
2010     if (cmds[i].tmp_flag) {
2011     int q;
2012     if (j == 0)
2013     printf(" ");
2014     printf("%s",
2015     cmds[i].name);
2016     j++;
2017     if (j != 6)
2018     for (q=0; q<13-strlen(
2019     cmds[i].name); q++)
2020     printf(" ");
2021     if (j == 6) {
2022     printf("\n");
2023     j = 0;
2024     }
2025     }
2026     i++;
2027     }
2028     if (j != 0)
2029     printf("\n");
2030     printf("GXemul> ");
2031     for (i=0; i<cmd_len; i++)
2032     printf("%c", cmd[i]);
2033     }
2034     } else if (ch == 27) {
2035     /* Escape codes: (cursor keys etc) */
2036     while ((ch = console_readchar(MAIN_CONSOLE)) < 0)
2037     usleep(1);
2038     if (ch == '[' || ch == 'O') {
2039     while ((ch = console_readchar(MAIN_CONSOLE))
2040     < 0)
2041     usleep(1);
2042     switch (ch) {
2043     case '2': /* 2~ = ins */
2044     case '5': /* 5~ = pgup */
2045     case '6': /* 6~ = pgdn */
2046     /* TODO: Ugly hack, but might work. */
2047     while ((ch = console_readchar(
2048     MAIN_CONSOLE)) < 0)
2049     usleep(1);
2050     /* Do nothing for these keys. */
2051     break;
2052     case '3': /* 3~ = delete */
2053     /* TODO: Ugly hack, but might work. */
2054     while ((ch = console_readchar(
2055     MAIN_CONSOLE)) < 0)
2056     usleep(1);
2057     console_makeavail(MAIN_CONSOLE, '\b');
2058     break;
2059     case 'A': /* Up. */
2060     /* Up cursor ==> CTRL-P */
2061     console_makeavail(MAIN_CONSOLE, 16);
2062     break;
2063     case 'B': /* Down. */
2064     /* Down cursor ==> CTRL-N */
2065     console_makeavail(MAIN_CONSOLE, 14);
2066     break;
2067     case 'C':
2068     /* Right cursor ==> CTRL-F */
2069     console_makeavail(MAIN_CONSOLE, 6);
2070     break;
2071     case 'D': /* Left */
2072     /* Left cursor ==> CTRL-B */
2073     console_makeavail(MAIN_CONSOLE, 2);
2074     break;
2075     case 'F':
2076     /* End ==> CTRL-E */
2077     console_makeavail(MAIN_CONSOLE, 5);
2078     break;
2079     case 'H':
2080     /* Home ==> CTRL-A */
2081     console_makeavail(MAIN_CONSOLE, 1);
2082     break;
2083     }
2084     }
2085     }
2086    
2087     fflush(stdout);
2088     }
2089    
2090     return cmd;
2091     }
2092    
2093    
2094     /*
2095     * debugger():
2096     *
2097     * This is a loop, which reads a command from the terminal, and executes it.
2098     */
2099     void debugger(void)
2100     {
2101     int i, n, i_match, matchlen, cmd_len;
2102     char *cmd;
2103    
2104 dpavlin 12 if (debugger_n_steps_left_before_interaction > 0) {
2105     debugger_n_steps_left_before_interaction --;
2106 dpavlin 2 return;
2107     }
2108    
2109     exit_debugger = 0;
2110    
2111     while (!exit_debugger) {
2112     /* Read a line from the terminal: */
2113     cmd = debugger_readline();
2114     cmd_len = strlen(cmd);
2115    
2116     /* Remove spaces: */
2117     while (cmd_len > 0 && cmd[0]==' ')
2118     memmove(cmd, cmd+1, cmd_len --);
2119     while (cmd_len > 0 && cmd[cmd_len-1] == ' ')
2120     cmd[(cmd_len--)-1] = '\0';
2121    
2122     /* No command? Then try reading another line. */
2123     if (cmd_len == 0) {
2124     /* Special case for repeated commands: */
2125     if (repeat_cmd[0] != '\0')
2126 dpavlin 10 strlcpy(cmd, repeat_cmd, MAX_CMD_BUFLEN);
2127 dpavlin 2 else
2128     continue;
2129     } else {
2130     last_cmd_index ++;
2131     if (last_cmd_index >= N_PREVIOUS_CMDS)
2132     last_cmd_index = 0;
2133    
2134     repeat_cmd[0] = '\0';
2135     }
2136    
2137     /*
2138     * Is there a '=' on the command line? Then try to do an
2139     * assignment. (Only if there is just one word, followed
2140     * by the '=' sign. This makes it possible to use commands
2141     * such as "device add name addr=xyz".)
2142     */
2143     if (strchr(cmd, '=') != NULL) {
2144     /* Count the nr of words: */
2145     int nw = 0, inword = 0;
2146     char *p = cmd;
2147     while (*p) {
2148     if (*p == '=')
2149     break;
2150     if (*p != ' ') {
2151     if (!inword)
2152     nw ++;
2153     inword = 1;
2154     } else
2155     inword = 0;
2156     p++;
2157     }
2158    
2159     if (nw == 1) {
2160     debugger_assignment(debugger_machine, cmd);
2161     continue;
2162     }
2163     }
2164    
2165     i = 0;
2166     while (cmds[i].name != NULL)
2167     cmds[i++].tmp_flag = 0;
2168    
2169     /* How many chars in cmd to match against: */
2170     matchlen = 0;
2171     while (isalpha((int)cmd[matchlen]))
2172     matchlen ++;
2173    
2174     /* Check for a command name match: */
2175     n = i = i_match = 0;
2176     while (cmds[i].name != NULL) {
2177 dpavlin 12 if (strncasecmp(cmds[i].name, cmd, matchlen) == 0
2178     && cmds[i].f != NULL) {
2179 dpavlin 2 cmds[i].tmp_flag = 1;
2180     i_match = i;
2181     n++;
2182     }
2183     i++;
2184     }
2185    
2186     /* No match? */
2187     if (n == 0) {
2188     printf("Unknown command '%s'. "
2189     "Type 'help' for help.\n", cmd);
2190     continue;
2191     }
2192    
2193     /* More than one match? */
2194     if (n > 1) {
2195     printf("Ambiguous command '%s': ", cmd);
2196     i = 0;
2197     while (cmds[i].name != NULL) {
2198     if (cmds[i].tmp_flag)
2199     printf(" %s", cmds[i].name);
2200     i++;
2201     }
2202     printf("\n");
2203     continue;
2204     }
2205    
2206     /* Exactly one match: */
2207     if (cmds[i_match].f != NULL) {
2208     char *p = cmd + matchlen;
2209     /* Remove leading whitespace from the args... */
2210     while (*p != '\0' && *p == ' ')
2211     p++;
2212    
2213     /* ... and run the command: */
2214     cmds[i_match].f(debugger_machine, p);
2215     } else
2216     printf("FATAL ERROR: internal error in debugger.c:"
2217     " no handler for this command?\n");
2218    
2219     /* Special hack for the "step" command: */
2220     if (exit_debugger == -1)
2221     return;
2222     }
2223    
2224 dpavlin 10 gettimeofday(&debugger_machine->starttime, NULL);
2225     debugger_machine->ncycles_since_gettimeofday = 0;
2226    
2227 dpavlin 2 single_step = 0;
2228     debugger_machine->instruction_trace = old_instruction_trace;
2229     debugger_machine->show_trace_tree = old_show_trace_tree;
2230     quiet_mode = old_quiet_mode;
2231     }
2232    
2233    
2234     /*
2235     * debugger_reset():
2236     *
2237     * This function should be called before calling debugger(), when it is
2238     * absolutely necessary that debugger() is interactive. Otherwise, it might
2239     * return without doing anything, such as when single-stepping multiple
2240     * instructions at a time.
2241     */
2242     void debugger_reset(void)
2243     {
2244 dpavlin 12 debugger_n_steps_left_before_interaction = 0;
2245 dpavlin 2 }
2246    
2247    
2248     /*
2249     * debugger_init():
2250     *
2251     * Must be called before any other debugger function is used.
2252     */
2253     void debugger_init(struct emul **emuls, int n_emuls)
2254     {
2255     int i;
2256    
2257     debugger_n_emuls = n_emuls;
2258     debugger_emuls = emuls;
2259    
2260     if (n_emuls < 1) {
2261     fprintf(stderr, "\nERROR: No emuls (?)\n");
2262     exit(1);
2263     }
2264    
2265     debugger_emul = emuls[0];
2266     if (emuls[0]->n_machines < 1) {
2267     fprintf(stderr, "\nERROR: No machines in emuls[0], "
2268     "cannot handle this situation yet.\n\n");
2269     exit(1);
2270     }
2271    
2272     debugger_machine = emuls[0]->machines[0];
2273    
2274     for (i=0; i<N_PREVIOUS_CMDS; i++) {
2275 dpavlin 10 last_cmd[i] = malloc(MAX_CMD_BUFLEN);
2276 dpavlin 2 if (last_cmd[i] == NULL) {
2277     fprintf(stderr, "debugger_init(): out of memory\n");
2278     exit(1);
2279     }
2280     last_cmd[i][0] = '\0';
2281     }
2282    
2283     last_cmd_index = 0;
2284     repeat_cmd[0] = '\0';
2285     }
2286    

  ViewVC Help
Powered by ViewVC 1.1.26