/[gxemul]/upstream/0.3.7/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

Contents of /upstream/0.3.7/src/debugger.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26