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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 52084 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26