/[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 10 - (hide annotations)
Mon Oct 8 16:18:27 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 47953 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.815 2005/06/27 23:04:35 debug Exp $
20050617	Experimenting some more with netbooting OpenBSD/sgi. Adding
		a hack which allows emulated ethernet networks to be
		distributed across multiple emulator processes.
20050618	Minor updates (documentation, dummy YAMON emulation, etc).
20050620	strcpy/strcat -> strlcpy/strlcat updates.
		Some more progress on evbmips (Malta).
20050621	Adding a section to doc/configfiles.html about ethernet
		emulation across multiple hosts.
		Beginning the work on the ARM translation engine (using the
		dynamic-but-not-binary translation method).
		Fixing a bintrans bug: 0x9fc00000 should always be treated as
		PROM area, just as 0xbfc00000 is.
		Minor progress on Malta emulation (the PCI-ISA bus).
20050622	NetBSD/evbmips can now be installed (using another emulated
		machine) and run (including userland and so on). :-)
		Spliting up the bintrans haddr_entry field into two (one for
		read, one for write). Probably not much of a speed increase,
		though.
		Updating some NetBSD 2.0 -> 2.0.2 in the documentation.
20050623	Minor updates (documentation, the TODO file, etc).
		gzipped kernels are now always automagically gunzipped when
		loaded.
20050624	Adding a dummy Playstation Portable (PSP) mode, just barely
		enough to run Hello World (in weird colors :-).
		Removing the -b command line option; old bintrans is enabled
		by default instead. It makes more sense.
		Trying to finally fix the non-working performance measurement
		thing (instr/second etc).
20050625	Continuing on the essential basics for ARM emulation. Two
		instructions seem to work, a branch and a simple "mov". (The
		mov arguments are not correct yet.) Performance is definitely
		reasonable.
		Various other minor updates.
		Adding the ARM "bl" instruction.
		Adding support for combining multiple ARM instructions into one
		function call. ("mov" + "mov" is the only one implemented so
		far, but it seems to work.)
		Cleaning up some IP32 interrupt things (crime/mace); disabling
		the PS/2 keyboard controller on IP32, so that NetBSD/sgimips
		boots into userland again.
20050626	Finally! NetBSD/sgimips netboots. Adding instructions to
		doc/guestoses.html on how to set up an nfs server etc.
		Various other minor fixes.
		Playstation Portable ".pbp" files can now be used directly.
		(The ELF part of the .pbp is extracted transparently.)
		Converting some sprintf -> snprintf.
		Adding some more instructions to the ARM disassembler.
20050627	More ARM updates. Adding some simple ldr(b), str(b),
		cmps, and conditional branch instructions, enough to run
		a simple Hello World program.
		All ARM instructions are now inlined/generated for all possible
		condition codes.
		Adding add and sub, and more load/store instructions.
		Removing dummy files: cpu_alpha.c, cpu_hppa.c, and cpu_sparc.c.
		Some minor documentation updates; preparing for a 0.3.4
		release. Updating some URLs.

==============  RELEASE 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