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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26