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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26