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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 31330 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 /*
2 * Copyright (C) 2004-2006 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_cmds.c,v 1.5 2006/06/24 19:52:28 debug Exp $
29 *
30 * Debugger commands. Included from debugger.c.
31 */
32
33
34 /*
35 * debugger_cmd_allsettings():
36 */
37 static void debugger_cmd_allsettings(struct machine *m, char *cmd_line)
38 {
39 settings_debugdump(global_settings, GLOBAL_SETTINGS_NAME, 1);
40 }
41
42
43 /*
44 * debugger_cmd_breakpoint():
45 *
46 * TODO: automagic "expansion" for the subcommand names (s => show).
47 */
48 static void debugger_cmd_breakpoint(struct machine *m, char *cmd_line)
49 {
50 int i, res;
51
52 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
53 cmd_line ++;
54
55 if (cmd_line[0] == '\0') {
56 printf("syntax: breakpoint subcmd [args...]\n");
57 printf("Available subcmds (and args) are:\n");
58 printf(" add addr add a breakpoint for address addr\n");
59 printf(" delete x delete breakpoint nr x\n");
60 printf(" show show current breakpoints\n");
61 return;
62 }
63
64 if (strcmp(cmd_line, "show") == 0) {
65 if (m->n_breakpoints == 0)
66 printf("No breakpoints set.\n");
67 for (i=0; i<m->n_breakpoints; i++)
68 show_breakpoint(m, i);
69 return;
70 }
71
72 if (strncmp(cmd_line, "delete ", 7) == 0) {
73 int x = atoi(cmd_line + 7);
74
75 if (m->n_breakpoints == 0) {
76 printf("No breakpoints set.\n");
77 return;
78 }
79 if (x < 0 || x >= m->n_breakpoints) {
80 printf("Invalid breakpoint nr %i. Use 'breakpoint "
81 "show' to see the current breakpoints.\n", x);
82 return;
83 }
84
85 free(m->breakpoint_string[x]);
86
87 for (i=x; i<m->n_breakpoints-1; i++) {
88 m->breakpoint_addr[i] = m->breakpoint_addr[i+1];
89 m->breakpoint_string[i] = m->breakpoint_string[i+1];
90 m->breakpoint_flags[i] = m->breakpoint_flags[i+1];
91 }
92 m->n_breakpoints --;
93
94 /* Clear translations: */
95 for (i=0; i<m->ncpus; i++)
96 if (m->cpus[i]->translation_cache != NULL)
97 cpu_create_or_reset_tc(m->cpus[i]);
98 return;
99 }
100
101 if (strncmp(cmd_line, "add ", 4) == 0) {
102 uint64_t tmp;
103 size_t breakpoint_buf_len;
104
105 if (m->n_breakpoints >= MAX_BREAKPOINTS) {
106 printf("Too many breakpoints. (You need to recompile"
107 " gxemul to increase this. Max = %i.)\n",
108 MAX_BREAKPOINTS);
109 return;
110 }
111
112 i = m->n_breakpoints;
113
114 res = debugger_parse_name(m, cmd_line + 4, 0, &tmp);
115 if (!res) {
116 printf("Couldn't parse '%s'\n", cmd_line + 4);
117 return;
118 }
119
120 breakpoint_buf_len = strlen(cmd_line+4) + 1;
121 m->breakpoint_string[i] = malloc(breakpoint_buf_len);
122 if (m->breakpoint_string[i] == NULL) {
123 printf("out of memory in debugger_cmd_breakpoint()\n");
124 exit(1);
125 }
126 strlcpy(m->breakpoint_string[i], cmd_line+4,
127 breakpoint_buf_len);
128 m->breakpoint_addr[i] = tmp;
129 m->breakpoint_flags[i] = 0;
130
131 m->n_breakpoints ++;
132 show_breakpoint(m, i);
133
134 /* Clear translations: */
135 for (i=0; i<m->ncpus; i++)
136 if (m->cpus[i]->translation_cache != NULL)
137 cpu_create_or_reset_tc(m->cpus[i]);
138 return;
139 }
140
141 printf("Unknown breakpoint subcommand.\n");
142 }
143
144
145 /*
146 * debugger_cmd_continue():
147 */
148 static void debugger_cmd_continue(struct machine *m, char *cmd_line)
149 {
150 if (*cmd_line) {
151 printf("syntax: continue\n");
152 return;
153 }
154
155 exit_debugger = 1;
156 }
157
158
159 /*
160 * debugger_cmd_device():
161 */
162 static void debugger_cmd_device(struct machine *m, char *cmd_line)
163 {
164 int i;
165 struct memory *mem;
166 struct cpu *c;
167
168 if (cmd_line[0] == '\0')
169 goto return_help;
170
171 if (m->cpus == NULL) {
172 printf("No cpus (?)\n");
173 return;
174 }
175 c = m->cpus[m->bootstrap_cpu];
176 if (c == NULL) {
177 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
178 return;
179 }
180 mem = m->cpus[m->bootstrap_cpu]->mem;
181
182 if (m->cpus == NULL) {
183 printf("No cpus (?)\n");
184 return;
185 }
186 c = m->cpus[m->bootstrap_cpu];
187 if (c == NULL) {
188 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
189 return;
190 }
191 mem = m->cpus[m->bootstrap_cpu]->mem;
192
193 if (strcmp(cmd_line, "all") == 0) {
194 device_dumplist();
195 } else if (strncmp(cmd_line, "add ", 4) == 0) {
196 device_add(m, cmd_line+4);
197 } else if (strcmp(cmd_line, "consoles") == 0) {
198 console_debug_dump(m);
199 } else if (strncmp(cmd_line, "remove ", 7) == 0) {
200 i = atoi(cmd_line + 7);
201 if (i==0 && cmd_line[7]!='0') {
202 printf("Weird device number. Use 'device list'.\n");
203 } else
204 memory_device_remove(m->memory, i);
205 } else if (strcmp(cmd_line, "list") == 0) {
206 if (mem->n_mmapped_devices == 0)
207 printf("No memory-mapped devices in this machine.\n");
208
209 for (i=0; i<mem->n_mmapped_devices; i++) {
210 printf("%2i: %25s @ 0x%011"PRIx64", len = 0x%"PRIx64,
211 i, mem->dev_name[i],
212 (uint64_t) mem->dev_baseaddr[i],
213 (uint64_t) mem->dev_length[i]);
214
215 if (mem->dev_flags[i]) {
216 printf(" (");
217 if (mem->dev_flags[i] & DM_DYNTRANS_OK)
218 printf("DYNTRANS R");
219 if (mem->dev_flags[i] & DM_DYNTRANS_WRITE_OK)
220 printf("+W");
221 printf(")");
222 }
223 printf("\n");
224 }
225 } else
226 goto return_help;
227
228 return;
229
230 return_help:
231 printf("syntax: devices cmd [...]\n");
232 printf("Available cmds are:\n");
233 printf(" add name_and_params add a device to the current "
234 "machine\n");
235 printf(" all list all registered devices\n");
236 printf(" consoles list all slave consoles\n");
237 printf(" list list memory-mapped devices in the"
238 " current machine\n");
239 printf(" remove x remove device nr x from the "
240 "current machine\n");
241 }
242
243
244 /*
245 * debugger_cmd_dump():
246 *
247 * Dump emulated memory in hex and ASCII.
248 *
249 * syntax: dump [addr [endaddr]]
250 */
251 static void debugger_cmd_dump(struct machine *m, char *cmd_line)
252 {
253 uint64_t addr, addr_start, addr_end;
254 struct cpu *c;
255 struct memory *mem;
256 char *p = NULL;
257 int x, r;
258
259 if (cmd_line[0] != '\0') {
260 uint64_t tmp;
261 char *tmps = strdup(cmd_line);
262
263 /* addr: */
264 p = strchr(tmps, ' ');
265 if (p != NULL)
266 *p = '\0';
267 r = debugger_parse_name(m, tmps, 0, &tmp);
268 free(tmps);
269
270 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
271 printf("Unparsable address: %s\n", cmd_line);
272 return;
273 } else {
274 last_dump_addr = tmp;
275 }
276
277 p = strchr(cmd_line, ' ');
278 }
279
280 addr_start = last_dump_addr;
281
282 if (addr_start == MAGIC_UNTOUCHED) {
283 uint64_t tmp;
284 int match_register = 0;
285 cpu_register_match(m, "pc", 0, &tmp, &match_register);
286 if (match_register) {
287 addr_start = tmp;
288 } else {
289 printf("No starting address.\n");
290 return;
291 }
292 }
293
294 addr_end = addr_start + 16 * 16;
295
296 /* endaddr: */
297 if (p != NULL) {
298 while (*p == ' ' && *p)
299 p++;
300 r = debugger_parse_name(m, p, 0, &addr_end);
301 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
302 printf("Unparsable address: %s\n", cmd_line);
303 return;
304 }
305 }
306
307 if (m->cpus == NULL) {
308 printf("No cpus (?)\n");
309 return;
310 }
311 c = m->cpus[m->bootstrap_cpu];
312 if (c == NULL) {
313 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
314 return;
315 }
316 mem = m->cpus[m->bootstrap_cpu]->mem;
317
318 addr = addr_start & ~0xf;
319
320 ctrl_c = 0;
321
322 while (addr < addr_end) {
323 unsigned char buf[16];
324 memset(buf, 0, sizeof(buf));
325 r = c->memory_rw(c, mem, addr, &buf[0], sizeof(buf),
326 MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
327
328 if (c->is_32bit)
329 printf("0x%08"PRIx32" ", (uint32_t) addr);
330 else
331 printf("0x%016"PRIx64" ", (uint64_t) addr);
332
333 if (r == MEMORY_ACCESS_FAILED)
334 printf("(memory access failed)\n");
335 else {
336 for (x=0; x<16; x++) {
337 if (addr + x >= addr_start &&
338 addr + x < addr_end)
339 printf("%02x%s", buf[x],
340 (x&3)==3? " " : "");
341 else
342 printf(" %s", (x&3)==3? " " : "");
343 }
344 printf(" ");
345 for (x=0; x<16; x++) {
346 if (addr + x >= addr_start &&
347 addr + x < addr_end)
348 printf("%c", (buf[x]>=' ' &&
349 buf[x]<127)? buf[x] : '.');
350 else
351 printf(" ");
352 }
353 printf("\n");
354 }
355
356 if (ctrl_c)
357 return;
358
359 addr += sizeof(buf);
360 }
361
362 last_dump_addr = addr_end;
363
364 strlcpy(repeat_cmd, "dump", MAX_CMD_BUFLEN);
365 }
366
367
368 /*
369 * debugger_cmd_emuls():
370 *
371 * Dump info about all current emuls.
372 */
373 static void debugger_cmd_emuls(struct machine *m, char *cmd_line)
374 {
375 int i, iadd = DEBUG_INDENTATION;
376
377 if (*cmd_line) {
378 printf("syntax: emuls\n");
379 return;
380 }
381
382 for (i=0; i<debugger_n_emuls; i++) {
383 struct emul *e = debugger_emuls[i];
384
385 if (e == NULL)
386 continue;
387
388 debug("emulation %i: \"%s\"\n", i,
389 e->name == NULL? "(no name)" : e->name);
390 debug_indentation(iadd);
391
392 emul_dumpinfo(e);
393
394 debug_indentation(-iadd);
395 }
396 }
397
398
399 /*
400 * debugger_cmd_focus():
401 *
402 * Changes focus to specific machine (in a specific emulation).
403 */
404 static void debugger_cmd_focus(struct machine *m, char *cmd_line)
405 {
406 int x = -1, y = -1;
407 char *p;
408
409 if (!cmd_line[0]) {
410 printf("syntax: focus x[,y]\n");
411 printf("where x and y are integers as reported by the"
412 " 'emuls' command\n");
413 goto print_current_focus_and_return;
414 }
415
416 x = atoi(cmd_line);
417 p = strchr(cmd_line, ',');
418 if (p == cmd_line) {
419 printf("No machine number specified?\n");
420 printf("syntax: focus x[,y]\n");
421 return;
422 }
423
424 if (p != NULL)
425 y = atoi(p + 1);
426
427 if (y != -1) {
428 /* Change emul: */
429 if (y < 0 || y >= debugger_n_emuls) {
430 printf("Invalid emul number: %i\n", y);
431 return;
432 }
433
434 debugger_emul = debugger_emuls[y];
435
436 /* This is just in case the machine change below fails... */
437 debugger_machine = debugger_emul->machines[0];
438 }
439
440 /* Change machine: */
441 if (x < 0 || x >= debugger_emul->n_machines) {
442 printf("Invalid machine number: %i\n", x);
443 return;
444 }
445
446 debugger_machine = debugger_emul->machines[x];
447
448 print_current_focus_and_return:
449 printf("current emul: \"%s\"\n", debugger_emul->name == NULL?
450 "(no name)" : debugger_emul->name);
451 printf("current machine: \"%s\"\n", debugger_machine->name == NULL?
452 "(no name)" : debugger_machine->name);
453 }
454
455
456 /* This is defined below. */
457 static void debugger_cmd_help(struct machine *m, char *cmd_line);
458
459
460 /*
461 * debugger_cmd_itrace():
462 */
463 static void debugger_cmd_itrace(struct machine *m, char *cmd_line)
464 {
465 if (*cmd_line) {
466 printf("syntax: itrace\n");
467 return;
468 }
469
470 old_instruction_trace = 1 - old_instruction_trace;
471 printf("instruction_trace = %s\n", old_instruction_trace? "ON":"OFF");
472 /* TODO: how to preserve quiet_mode? */
473 old_quiet_mode = 0;
474 printf("quiet_mode = %s\n", old_quiet_mode? "ON" : "OFF");
475 }
476
477
478 /*
479 * debugger_cmd_lookup():
480 */
481 static void debugger_cmd_lookup(struct machine *m, char *cmd_line)
482 {
483 uint64_t addr;
484 int res;
485 char *symbol;
486 uint64_t offset;
487
488 if (cmd_line[0] == '\0') {
489 printf("syntax: lookup name|addr\n");
490 return;
491
492 }
493
494 /* Addresses never need to be given in decimal form anyway,
495 so assuming hex here will be ok. */
496 addr = strtoull(cmd_line, NULL, 16);
497
498 if (addr == 0) {
499 uint64_t newaddr;
500 res = get_symbol_addr(&m->symbol_context,
501 cmd_line, &newaddr);
502 if (!res) {
503 printf("lookup for '%s' failed\n", cmd_line);
504 return;
505 }
506 printf("%s = 0x", cmd_line);
507 if (m->cpus[0]->is_32bit)
508 printf("%08"PRIx32"\n", (uint32_t) newaddr);
509 else
510 printf("%016"PRIx64"\n", (uint64_t) newaddr);
511 return;
512 }
513
514 symbol = get_symbol_name(&m->symbol_context, addr, &offset);
515
516 if (symbol != NULL) {
517 if (m->cpus[0]->is_32bit)
518 printf("0x%08"PRIx32, (uint32_t) addr);
519 else
520 printf("0x%016"PRIx64, (uint64_t) addr);
521 printf(" = %s\n", symbol);
522 } else
523 printf("lookup for '%s' failed\n", cmd_line);
524 }
525
526
527 /*
528 * debugger_cmd_machine():
529 *
530 * Dump info about the currently focused machine.
531 */
532 static void debugger_cmd_machine(struct machine *m, char *cmd_line)
533 {
534 int iadd = DEBUG_INDENTATION;
535
536 if (*cmd_line) {
537 printf("syntax: machine\n");
538 return;
539 }
540
541 debug("machine \"%s\":\n", m->name);
542 debug_indentation(iadd);
543 machine_dumpinfo(m);
544 debug_indentation(-iadd);
545 }
546
547
548 /*
549 * debugger_cmd_ninstrs():
550 */
551 static void debugger_cmd_ninstrs(struct machine *m, char *cmd_line)
552 {
553 int toggle = 1;
554 int previous_mode = m->show_nr_of_instructions;
555
556 if (cmd_line[0] != '\0') {
557 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
558 cmd_line ++;
559 switch (cmd_line[0]) {
560 case '0':
561 toggle = 0;
562 m->show_nr_of_instructions = 0;
563 break;
564 case '1':
565 toggle = 0;
566 m->show_nr_of_instructions = 1;
567 break;
568 case 'o':
569 case 'O':
570 toggle = 0;
571 switch (cmd_line[1]) {
572 case 'n':
573 case 'N':
574 m->show_nr_of_instructions = 1;
575 break;
576 default:
577 m->show_nr_of_instructions = 0;
578 }
579 break;
580 default:
581 printf("syntax: trace [on|off]\n");
582 return;
583 }
584 }
585
586 if (toggle)
587 m->show_nr_of_instructions = !m->show_nr_of_instructions;
588
589 printf("show_nr_of_instructions = %s",
590 m->show_nr_of_instructions? "ON" : "OFF");
591 if (m->show_nr_of_instructions != previous_mode)
592 printf(" (was: %s)", previous_mode? "ON" : "OFF");
593 printf("\n");
594 }
595
596
597 /*
598 * debugger_cmd_pause():
599 */
600 static void debugger_cmd_pause(struct machine *m, char *cmd_line)
601 {
602 int cpuid = -1;
603
604 if (cmd_line[0] != '\0')
605 cpuid = atoi(cmd_line);
606 else {
607 printf("syntax: pause cpuid\n");
608 return;
609 }
610
611 if (cpuid < 0 || cpuid >= m->ncpus) {
612 printf("cpu%i doesn't exist.\n", cpuid);
613 return;
614 }
615
616 m->cpus[cpuid]->running ^= 1;
617
618 printf("cpu%i (%s) in machine \"%s\" is now %s\n", cpuid,
619 m->cpus[cpuid]->name, m->name,
620 m->cpus[cpuid]->running? "RUNNING" : "STOPPED");
621 }
622
623
624 /*
625 * debugger_cmd_print():
626 */
627 static void debugger_cmd_print(struct machine *m, char *cmd_line)
628 {
629 int res;
630 uint64_t tmp;
631
632 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
633 cmd_line ++;
634
635 if (cmd_line[0] == '\0') {
636 printf("syntax: print expr\n");
637 return;
638 }
639
640 res = debugger_parse_name(m, cmd_line, 0, &tmp);
641 switch (res) {
642 case NAME_PARSE_NOMATCH:
643 printf("No match.\n");
644 break;
645 case NAME_PARSE_MULTIPLE:
646 printf("Multiple matches. Try prefixing with %%, $, or @.\n");
647 break;
648 case NAME_PARSE_REGISTER:
649 printf("%s = 0x%"PRIx64"\n", cmd_line, (uint64_t)tmp);
650 break;
651 case NAME_PARSE_SYMBOL:
652 if (m->cpus[0]->is_32bit)
653 printf("%s = 0x%08"PRIx32"\n", cmd_line, (uint32_t)tmp);
654 else
655 printf("%s = 0x%016"PRIx64"\n", cmd_line,(uint64_t)tmp);
656 break;
657 case NAME_PARSE_NUMBER:
658 printf("0x%"PRIx64"\n", (uint64_t) tmp);
659 break;
660 }
661 }
662
663
664 /*
665 * debugger_cmd_put():
666 */
667 static void debugger_cmd_put(struct machine *m, char *cmd_line)
668 {
669 static char put_type = ' '; /* Remembered across multiple calls. */
670 char copy[200];
671 int res, syntax_ok = 0;
672 char *p, *p2, *q = NULL;
673 uint64_t addr, data;
674 unsigned char a_byte;
675
676 strncpy(copy, cmd_line, sizeof(copy));
677 copy[sizeof(copy)-1] = '\0';
678
679 /* syntax: put [b|h|w|d|q] addr, data */
680
681 p = strchr(copy, ',');
682 if (p != NULL) {
683 *p++ = '\0';
684 while (*p == ' ' && *p)
685 p++;
686 while (strlen(copy) >= 1 &&
687 copy[strlen(copy) - 1] == ' ')
688 copy[strlen(copy) - 1] = '\0';
689
690 /* printf("L = '%s', R = '%s'\n", copy, p); */
691
692 q = copy;
693 p2 = strchr(q, ' ');
694
695 if (p2 != NULL) {
696 *p2 = '\0';
697 if (strlen(q) != 1) {
698 printf("Invalid type '%s'\n", q);
699 return;
700 }
701 put_type = *q;
702 q = p2 + 1;
703 }
704
705 /* printf("type '%c', L '%s', R '%s'\n", put_type, q, p); */
706 syntax_ok = 1;
707 }
708
709 if (!syntax_ok) {
710 printf("syntax: put [b|h|w|d|q] addr, data\n");
711 printf(" b byte (8 bits)\n");
712 printf(" h half-word (16 bits)\n");
713 printf(" w word (32 bits)\n");
714 printf(" d doubleword (64 bits)\n");
715 printf(" q quad-word (128 bits)\n");
716 return;
717 }
718
719 if (put_type == ' ') {
720 printf("No type specified.\n");
721 return;
722 }
723
724 /* here: q is the address, p is the data. */
725 res = debugger_parse_name(m, q, 0, &addr);
726 switch (res) {
727 case NAME_PARSE_NOMATCH:
728 printf("Couldn't parse the address.\n");
729 return;
730 case NAME_PARSE_MULTIPLE:
731 printf("Multiple matches for the address."
732 " Try prefixing with %%, $, or @.\n");
733 return;
734 case NAME_PARSE_REGISTER:
735 case NAME_PARSE_SYMBOL:
736 case NAME_PARSE_NUMBER:
737 break;
738 default:
739 printf("INTERNAL ERROR in debugger.c.\n");
740 return;
741 }
742
743 res = debugger_parse_name(m, p, 0, &data);
744 switch (res) {
745 case NAME_PARSE_NOMATCH:
746 printf("Couldn't parse the data.\n");
747 return;
748 case NAME_PARSE_MULTIPLE:
749 printf("Multiple matches for the data value."
750 " Try prefixing with %%, $, or @.\n");
751 return;
752 case NAME_PARSE_REGISTER:
753 case NAME_PARSE_SYMBOL:
754 case NAME_PARSE_NUMBER:
755 break;
756 default:
757 printf("INTERNAL ERROR in debugger.c.\n");
758 return;
759 }
760
761 /* TODO: haha, maybe this should be refactored */
762
763 switch (put_type) {
764 case 'b':
765 a_byte = data;
766 if (m->cpus[0]->is_32bit)
767 printf("0x%08"PRIx32, (uint32_t) addr);
768 else
769 printf("0x%016"PRIx64, (uint64_t) addr);
770 printf(": %02x", a_byte);
771 if (data > 255)
772 printf(" (NOTE: truncating %0"PRIx64")",
773 (uint64_t) data);
774 res = m->cpus[0]->memory_rw(m->cpus[0], m->cpus[0]->mem, addr,
775 &a_byte, 1, MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);
776 if (!res)
777 printf(" FAILED!\n");
778 printf("\n");
779 return;
780 case 'h':
781 if ((addr & 1) != 0)
782 printf("WARNING: address isn't aligned\n");
783 if (m->cpus[0]->is_32bit)
784 printf("0x%08"PRIx32, (uint32_t) addr);
785 else
786 printf("0x%016"PRIx64, (uint64_t) addr);
787 printf(": %04x", (int)data);
788 if (data > 0xffff)
789 printf(" (NOTE: truncating %0"PRIx64")",
790 (uint64_t) data);
791 res = store_16bit_word(m->cpus[0], addr, data);
792 if (!res)
793 printf(" FAILED!\n");
794 printf("\n");
795 return;
796 case 'w':
797 if ((addr & 3) != 0)
798 printf("WARNING: address isn't aligned\n");
799 if (m->cpus[0]->is_32bit)
800 printf("0x%08"PRIx32, (uint32_t) addr);
801 else
802 printf("0x%016"PRIx64, (uint64_t) addr);
803
804 printf(": %08x", (int)data);
805
806 if (data > 0xffffffff && (data >> 32) != 0
807 && (data >> 32) != 0xffffffff)
808 printf(" (NOTE: truncating %0"PRIx64")",
809 (uint64_t) data);
810
811 res = store_32bit_word(m->cpus[0], addr, data);
812 if (!res)
813 printf(" FAILED!\n");
814 printf("\n");
815 return;
816 case 'd':
817 if ((addr & 7) != 0)
818 printf("WARNING: address isn't aligned\n");
819 if (m->cpus[0]->is_32bit)
820 printf("0x%08"PRIx32, (uint32_t) addr);
821 else
822 printf("0x%016"PRIx64, (uint64_t) addr);
823
824 printf(": %016"PRIx64, (uint64_t) data);
825
826 res = store_64bit_word(m->cpus[0], addr, data);
827 if (!res)
828 printf(" FAILED!\n");
829 printf("\n");
830 return;
831 case 'q':
832 printf("quad-words: TODO\n");
833 /* TODO */
834 return;
835 default:
836 printf("Unimplemented type '%c'\n", put_type);
837 return;
838 }
839 }
840
841
842 /*
843 * debugger_cmd_quiet():
844 */
845 static void debugger_cmd_quiet(struct machine *m, char *cmd_line)
846 {
847 int toggle = 1;
848 int previous_mode = old_quiet_mode;
849
850 if (cmd_line[0] != '\0') {
851 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
852 cmd_line ++;
853 switch (cmd_line[0]) {
854 case '0':
855 toggle = 0;
856 old_quiet_mode = 0;
857 break;
858 case '1':
859 toggle = 0;
860 old_quiet_mode = 1;
861 break;
862 case 'o':
863 case 'O':
864 toggle = 0;
865 switch (cmd_line[1]) {
866 case 'n':
867 case 'N':
868 old_quiet_mode = 1;
869 break;
870 default:
871 old_quiet_mode = 0;
872 }
873 break;
874 default:
875 printf("syntax: quiet [on|off]\n");
876 return;
877 }
878 }
879
880 if (toggle)
881 old_quiet_mode = 1 - old_quiet_mode;
882
883 printf("quiet_mode = %s", old_quiet_mode? "ON" : "OFF");
884 if (old_quiet_mode != previous_mode)
885 printf(" (was: %s)", previous_mode? "ON" : "OFF");
886 printf("\n");
887 }
888
889
890 /*
891 * debugger_cmd_quit():
892 */
893 static void debugger_cmd_quit(struct machine *m, char *cmd_line)
894 {
895 int i, j, k;
896 struct emul *e;
897
898 if (*cmd_line) {
899 printf("syntax: quit\n");
900 return;
901 }
902
903 for (i=0; i<debugger_n_emuls; i++) {
904 single_step = NOT_SINGLE_STEPPING;
905
906 e = debugger_emuls[i];
907 force_debugger_at_exit = 0;
908
909 for (j=0; j<e->n_machines; j++) {
910 struct machine *m = e->machines[j];
911
912 for (k=0; k<m->ncpus; k++)
913 m->cpus[k]->running = 0;
914
915 m->exit_without_entering_debugger = 1;
916 }
917 }
918
919 exit_debugger = 1;
920 }
921
922
923 /*
924 * debugger_cmd_reg():
925 */
926 static void debugger_cmd_reg(struct machine *m, char *cmd_line)
927 {
928 int i, cpuid = -1, coprocnr = -1;
929 int gprs, coprocs;
930 char *p;
931
932 /* [cpuid][,c] */
933 if (cmd_line[0] != '\0') {
934 if (cmd_line[0] != ',') {
935 cpuid = strtoull(cmd_line, NULL, 0);
936 if (cpuid < 0 || cpuid >= m->ncpus) {
937 printf("cpu%i doesn't exist.\n", cpuid);
938 return;
939 }
940 }
941 p = strchr(cmd_line, ',');
942 if (p != NULL) {
943 coprocnr = atoi(p + 1);
944 if (coprocnr < 0 || coprocnr >= 4) {
945 printf("Invalid coprocessor number.\n");
946 return;
947 }
948 }
949 }
950
951 gprs = (coprocnr == -1)? 1 : 0;
952 coprocs = (coprocnr == -1)? 0x0 : (1 << coprocnr);
953
954 for (i=0; i<m->ncpus; i++)
955 if (cpuid == -1 || i == cpuid)
956 cpu_register_dump(m, m->cpus[i], gprs, coprocs);
957 }
958
959
960 /*
961 * debugger_cmd_step():
962 */
963 static void debugger_cmd_step(struct machine *m, char *cmd_line)
964 {
965 int n = 1;
966
967 if (cmd_line[0] != '\0') {
968 n = strtoull(cmd_line, NULL, 0);
969 if (n < 1) {
970 printf("invalid nr of steps\n");
971 return;
972 }
973 }
974
975 debugger_n_steps_left_before_interaction = n - 1;
976
977 /* Special hack, see debugger() for more info. */
978 exit_debugger = -1;
979
980 strlcpy(repeat_cmd, "step", MAX_CMD_BUFLEN);
981 }
982
983
984 /*
985 * debugger_cmd_tlbdump():
986 *
987 * Dump each CPU's TLB contents.
988 */
989 static void debugger_cmd_tlbdump(struct machine *m, char *cmd_line)
990 {
991 int x = -1;
992 int rawflag = 0;
993
994 if (cmd_line[0] != '\0') {
995 char *p;
996 if (cmd_line[0] != ',') {
997 x = strtoull(cmd_line, NULL, 0);
998 if (x < 0 || x >= m->ncpus) {
999 printf("cpu%i doesn't exist.\n", x);
1000 return;
1001 }
1002 }
1003 p = strchr(cmd_line, ',');
1004 if (p != NULL) {
1005 switch (p[1]) {
1006 case 'r':
1007 case 'R':
1008 rawflag = 1;
1009 break;
1010 default:
1011 printf("Unknown tlbdump flag.\n");
1012 printf("syntax: tlbdump [cpuid][,r]\n");
1013 return;
1014 }
1015 }
1016 }
1017
1018 cpu_tlbdump(m, x, rawflag);
1019 }
1020
1021
1022 /*
1023 * debugger_cmd_trace():
1024 */
1025 static void debugger_cmd_trace(struct machine *m, char *cmd_line)
1026 {
1027 int toggle = 1;
1028 int previous_mode = old_show_trace_tree;
1029
1030 if (cmd_line[0] != '\0') {
1031 while (cmd_line[0] != '\0' && cmd_line[0] == ' ')
1032 cmd_line ++;
1033 switch (cmd_line[0]) {
1034 case '0':
1035 toggle = 0;
1036 old_show_trace_tree = 0;
1037 break;
1038 case '1':
1039 toggle = 0;
1040 old_show_trace_tree = 1;
1041 break;
1042 case 'o':
1043 case 'O':
1044 toggle = 0;
1045 switch (cmd_line[1]) {
1046 case 'n':
1047 case 'N':
1048 old_show_trace_tree = 1;
1049 break;
1050 default:
1051 old_show_trace_tree = 0;
1052 }
1053 break;
1054 default:
1055 printf("syntax: trace [on|off]\n");
1056 return;
1057 }
1058 }
1059
1060 if (toggle)
1061 old_show_trace_tree = 1 - old_show_trace_tree;
1062
1063 printf("show_trace_tree = %s", old_show_trace_tree? "ON" : "OFF");
1064 if (old_show_trace_tree != previous_mode)
1065 printf(" (was: %s)", previous_mode? "ON" : "OFF");
1066 printf("\n");
1067 }
1068
1069
1070 /*
1071 * debugger_cmd_unassemble():
1072 *
1073 * Dump emulated memory as instructions.
1074 *
1075 * syntax: unassemble [addr [endaddr]]
1076 */
1077 static void debugger_cmd_unassemble(struct machine *m, char *cmd_line)
1078 {
1079 uint64_t addr, addr_start, addr_end;
1080 struct cpu *c;
1081 struct memory *mem;
1082 char *p = NULL;
1083 int r, lines_left = -1;
1084
1085 if (cmd_line[0] != '\0') {
1086 uint64_t tmp;
1087 char *tmps = strdup(cmd_line);
1088
1089 /* addr: */
1090 p = strchr(tmps, ' ');
1091 if (p != NULL)
1092 *p = '\0';
1093 r = debugger_parse_name(m, tmps, 0, &tmp);
1094 free(tmps);
1095
1096 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1097 printf("Unparsable address: %s\n", cmd_line);
1098 return;
1099 } else {
1100 last_unasm_addr = tmp;
1101 }
1102
1103 p = strchr(cmd_line, ' ');
1104 }
1105
1106 addr_start = last_unasm_addr;
1107
1108 if (addr_start == MAGIC_UNTOUCHED) {
1109 uint64_t tmp;
1110 int match_register = 0;
1111 cpu_register_match(m, "pc", 0, &tmp, &match_register);
1112 if (match_register) {
1113 addr_start = tmp;
1114 } else {
1115 printf("No starting address.\n");
1116 return;
1117 }
1118 }
1119
1120 addr_end = addr_start + 1000;
1121
1122 /* endaddr: */
1123 if (p != NULL) {
1124 while (*p == ' ' && *p)
1125 p++;
1126 r = debugger_parse_name(m, p, 0, &addr_end);
1127 if (r == NAME_PARSE_NOMATCH || r == NAME_PARSE_MULTIPLE) {
1128 printf("Unparsable address: %s\n", cmd_line);
1129 return;
1130 }
1131 } else
1132 lines_left = 20;
1133
1134 if (m->cpus == NULL) {
1135 printf("No cpus (?)\n");
1136 return;
1137 }
1138 c = m->cpus[m->bootstrap_cpu];
1139 if (c == NULL) {
1140 printf("m->cpus[m->bootstrap_cpu] = NULL\n");
1141 return;
1142 }
1143 mem = m->cpus[m->bootstrap_cpu]->mem;
1144
1145 addr = addr_start;
1146
1147 ctrl_c = 0;
1148
1149 while (addr < addr_end) {
1150 unsigned int i, len;
1151 int failed = 0;
1152 unsigned char buf[17]; /* TODO: How long can an
1153 instruction be, on weird archs? */
1154 memset(buf, 0, sizeof(buf));
1155
1156 for (i=0; i<sizeof(buf); i++) {
1157 if (c->memory_rw(c, mem, addr+i, buf+i, 1, MEM_READ,
1158 CACHE_NONE | NO_EXCEPTIONS) == MEMORY_ACCESS_FAILED)
1159 failed ++;
1160 }
1161
1162 if (failed == sizeof(buf)) {
1163 printf("(memory access failed)\n");
1164 break;
1165 }
1166
1167 len = cpu_disassemble_instr(m, c, buf, 0, addr);
1168
1169 if (ctrl_c)
1170 return;
1171 if (len == 0)
1172 break;
1173
1174 addr += len;
1175
1176 if (lines_left != -1) {
1177 lines_left --;
1178 if (lines_left == 0)
1179 break;
1180 }
1181 }
1182
1183 last_unasm_addr = addr;
1184
1185 strlcpy(repeat_cmd, "unassemble", MAX_CMD_BUFLEN);
1186 }
1187
1188
1189 /*
1190 * debugger_cmd_version():
1191 */
1192 static void debugger_cmd_version(struct machine *m, char *cmd_line)
1193 {
1194 if (*cmd_line) {
1195 printf("syntax: version\n");
1196 return;
1197 }
1198
1199 #ifdef VERSION
1200 printf("%s, %s\n", VERSION, COMPILE_DATE);
1201 #else
1202 printf("(no version), %s\n", COMPILE_DATE);
1203 #endif
1204 }
1205
1206
1207 /****************************************************************************/
1208
1209
1210 struct cmd {
1211 char *name;
1212 char *args;
1213 int tmp_flag;
1214 void (*f)(struct machine *, char *cmd_line);
1215 char *description;
1216 };
1217
1218 static struct cmd cmds[] = {
1219 { "allsettings", "", 0, debugger_cmd_allsettings,
1220 "show all settings" },
1221
1222 { "breakpoint", "...", 0, debugger_cmd_breakpoint,
1223 "manipulate breakpoints" },
1224
1225 /* NOTE: Try to keep 'c' down to only one command. Having 'continue'
1226 available as a one-letter command is very convenient. */
1227
1228 { "continue", "", 0, debugger_cmd_continue,
1229 "continue execution" },
1230
1231 { "device", "...", 0, debugger_cmd_device,
1232 "show info about (or manipulate) devices" },
1233
1234 { "dump", "[addr [endaddr]]", 0, debugger_cmd_dump,
1235 "dump memory contents in hex and ASCII" },
1236
1237 { "emuls", "", 0, debugger_cmd_emuls,
1238 "print a summary of all current emuls" },
1239
1240 { "focus", "x[,y]", 0, debugger_cmd_focus,
1241 "changes focus to machine x (in emul y)" },
1242
1243 { "help", "", 0, debugger_cmd_help,
1244 "print this help message" },
1245
1246 { "itrace", "", 0, debugger_cmd_itrace,
1247 "toggle instruction_trace on or off" },
1248
1249 { "lookup", "name|addr", 0, debugger_cmd_lookup,
1250 "lookup a symbol by name or address" },
1251
1252 { "machine", "", 0, debugger_cmd_machine,
1253 "print a summary of the current machine" },
1254
1255 { "ninstrs", "[on|off]", 0, debugger_cmd_ninstrs,
1256 "toggle (set or unset) show_nr_of_instructions" },
1257
1258 { "pause", "cpuid", 0, debugger_cmd_pause,
1259 "pause (or unpause) a CPU" },
1260
1261 { "print", "expr", 0, debugger_cmd_print,
1262 "evaluate an expression without side-effects" },
1263
1264 { "put", "[b|h|w|d|q] addr, data", 0, debugger_cmd_put,
1265 "modify emulated memory contents" },
1266
1267 { "quiet", "[on|off]", 0, debugger_cmd_quiet,
1268 "toggle quiet_mode on or off" },
1269
1270 { "quit", "", 0, debugger_cmd_quit,
1271 "quit the emulator" },
1272
1273 /* NOTE: Try to keep 'r' down to only one command. Having 'reg'
1274 available as a one-letter command is very convenient. */
1275
1276 { "reg", "[cpuid][,c]", 0, debugger_cmd_reg,
1277 "show GPRs (or coprocessor c's registers)" },
1278
1279 /* NOTE: Try to keep 's' down to only one command. Having 'step'
1280 available as a one-letter command is very convenient. */
1281
1282 { "step", "[n]", 0, debugger_cmd_step,
1283 "single-step one (or n) instruction(s)" },
1284
1285 { "tlbdump", "[cpuid][,r]", 0, debugger_cmd_tlbdump,
1286 "dump TLB contents (add ',r' for raw data)" },
1287
1288 { "trace", "[on|off]", 0, debugger_cmd_trace,
1289 "toggle show_trace_tree on or off" },
1290
1291 { "unassemble", "[addr [endaddr]]", 0, debugger_cmd_unassemble,
1292 "dump memory contents as instructions" },
1293
1294 { "version", "", 0, debugger_cmd_version,
1295 "print version information" },
1296
1297 /* Note: NULL handler. */
1298 { "x = expr", "", 0, NULL, "generic assignment" },
1299
1300 { NULL, NULL, 0, NULL, NULL }
1301 };
1302
1303
1304 /*
1305 * debugger_cmd_help():
1306 *
1307 * Print a list of available commands.
1308 *
1309 * NOTE: This is placed after the cmds[] array, because it needs to
1310 * access it.
1311 *
1312 * TODO: Command completion (ie just type "help s" for "help step").
1313 */
1314 static void debugger_cmd_help(struct machine *m, char *cmd_line)
1315 {
1316 int only_one = 0, only_one_match = 0;
1317 char *nlines_env = getenv("LINES");
1318 int nlines = atoi(nlines_env != NULL? nlines_env : "999999"), curlines;
1319 size_t i, j, max_name_len = 0;
1320
1321 if (cmd_line[0] != '\0') {
1322 only_one = 1;
1323 }
1324
1325 i = 0;
1326 while (cmds[i].name != NULL) {
1327 size_t a = strlen(cmds[i].name);
1328 if (cmds[i].args != NULL)
1329 a += 1 + strlen(cmds[i].args);
1330 if (a > max_name_len)
1331 max_name_len = a;
1332 i++;
1333 }
1334
1335 curlines = 0;
1336 if (!only_one) {
1337 printf("Available commands:\n");
1338 curlines++;
1339 }
1340
1341 i = 0;
1342 while (cmds[i].name != NULL) {
1343 char buf[100];
1344 snprintf(buf, sizeof(buf), "%s", cmds[i].name);
1345
1346 if (only_one) {
1347 if (strcmp(cmds[i].name, cmd_line) != 0) {
1348 i++;
1349 continue;
1350 }
1351 only_one_match = 1;
1352 }
1353
1354 if (cmds[i].args != NULL)
1355 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
1356 " %s", cmds[i].args);
1357
1358 printf(" ");
1359 for (j=0; j<max_name_len; j++)
1360 if (j < strlen(buf))
1361 printf("%c", buf[j]);
1362 else
1363 printf(" ");
1364
1365 printf(" %s\n", cmds[i].description);
1366 i++;
1367
1368 curlines ++;
1369 if (curlines >= nlines - 1) {
1370 char ch;
1371 printf("-- more --"); fflush(stdout);
1372 ch = debugger_readchar();
1373 printf("\n");
1374 if (ch == 'q' || ch == 'Q')
1375 return;
1376 curlines = 0;
1377 }
1378 }
1379
1380 if (only_one) {
1381 if (!only_one_match)
1382 printf("%s: no such command\n", cmd_line);
1383 return;
1384 }
1385
1386 /* TODO: generalize/refactor */
1387 curlines += 8;
1388 if (curlines > nlines - 1) {
1389 char ch;
1390 printf("-- more --"); fflush(stdout);
1391 ch = debugger_readchar();
1392 printf("\n");
1393 if (ch == 'q' || ch == 'Q')
1394 return;
1395 curlines = 0;
1396 }
1397
1398 printf("\nIn generic assignments, x must be a register, and expr can be"
1399 " a register, a\nnumeric value, or a symbol name (+ an optional "
1400 "numeric offset). In case there\nare multiple matches (i.e. a "
1401 "symbol that has the same name as a register), you\nmay add a "
1402 "prefix character as a hint: '%%' for registers, '@' for symbols,"
1403 " and\n'$' for numeric values. Use 0x for hexadecimal values.\n");
1404 }
1405

  ViewVC Help
Powered by ViewVC 1.1.26