/[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 44 - (show annotations)
Mon Oct 8 16:22:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 30783 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1632 2007/09/11 21:46:35 debug Exp $
20070616	Implementing the MIPS32/64 revision 2 "ror" instruction.
20070617	Adding a struct for each physpage which keeps track of which
		ranges within that page (base offset, length) that are
		continuously translatable. When running with native code
		generation enabled (-b), a range is added after each read-
		ahead loop.
		Experimenting with using the physical program counter sample
		data (implemented 20070608) together with the "translatable
		range" information, to figure out which physical address ranges
		would be worth translating to native code (if the number of
		samples falling within a range is above a certain threshold).
20070618	Adding automagic building of .index comment files for
		src/file/, src/promemul/, src src/useremul/ as well.
		Adding a "has been translated" bit to the ranges, so that only
		not-yet-translated ranges will be sampled.
20070619	Moving src/cpu.c and src/memory_rw.c into src/cpus/,
		src/device.c into src/devices/, and src/machine.c into
		src/machines/.
		Creating a skeleton cc/ld native backend module; beginning on
		the function which will detect cc command line, etc.
20070620	Continuing on the native code generation infrastructure.
20070621	Moving src/x11.c and src/console.c into a new src/console/
		subdir (for everything that is console or framebuffer related).
		Moving src/symbol*.c into a new src/symbol/, which should
		contain anything that is symbol handling related.
20070624	Making the program counter sampling threshold a "settings
		variable" (sampling_threshold), i.e. it can now be changed
		during runtime.
		Switching the RELEASE notes format from plain text to HTML.
		If the TMPDIR environment variable is set, it is used instead
		of "/tmp" for temporary files.
		Continuing on the cc/ld backend: simple .c code is generated,
		the compiler and linker are called, etc.
		Adding detection of host architecture to the configure script
		(again), and adding icache invalidation support (only
		implemented for Alpha hosts so far).
20070625	Simplifying the program counter sampling mechanism.
20070626	Removing the cc/ld native code generation stuff, program
		counter sampling, etc; it would not have worked well in the
		general case.
20070627	Removing everything related to native code generation.
20070629	Removing the (practically unusable) support for multiple
		emulations. (The single emulation allowed now still supports
		multiple simultaneous machines, as before.)
		Beginning on PCCTWO and M88K interrupts.
20070723	Adding a dummy skeleton for emulation of M32R processors.
20070901	Fixing a warning found by "gcc version 4.3.0 20070817
		(experimental)" on amd64.
20070905	Removing some more traces of the old "multiple emulations"
		code.
		Also looking in /usr/local/include and /usr/local/lib for
		X11 libs, when running configure.
20070909	Minor updates to the guest OS install instructions, in
		preparation for the NetBSD 4.0 release.
20070918	More testing of NetBSD 4.0 RC1.

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

  ViewVC Help
Powered by ViewVC 1.1.26