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

Annotation of /upstream/0.3.3.1/src/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26