/[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

Annotation of /trunk/src/debugger/debugger_cmds.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 44 - (hide 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 dpavlin 24 /*
2 dpavlin 34 * Copyright (C) 2004-2007 Anders Gavare. All rights reserved.
3 dpavlin 24 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 44 * $Id: debugger_cmds.c,v 1.14 2007/06/28 14:58:38 debug Exp $
29 dpavlin 24 *
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 dpavlin 42 if (m->breakpoints.n == 0)
66 dpavlin 24 printf("No breakpoints set.\n");
67 dpavlin 42 for (i=0; i<m->breakpoints.n; i++)
68 dpavlin 24 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 dpavlin 42 if (m->breakpoints.n == 0) {
76 dpavlin 24 printf("No breakpoints set.\n");
77     return;
78     }
79 dpavlin 42 if (x < 0 || x > m->breakpoints.n) {
80 dpavlin 24 printf("Invalid breakpoint nr %i. Use 'breakpoint "
81     "show' to see the current breakpoints.\n", x);
82     return;
83     }
84    
85 dpavlin 42 free(m->breakpoints.string[x]);
86 dpavlin 24
87 dpavlin 42 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 dpavlin 24 }
91 dpavlin 42 m->breakpoints.n --;
92 dpavlin 24
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 dpavlin 42 i = m->breakpoints.n;
105 dpavlin 24
106 dpavlin 32 res = debugger_parse_expression(m, cmd_line + 4, 0, &tmp);
107 dpavlin 24 if (!res) {
108     printf("Couldn't parse '%s'\n", cmd_line + 4);
109     return;
110     }
111    
112 dpavlin 42 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 dpavlin 24 breakpoint_buf_len = strlen(cmd_line+4) + 1;
120 dpavlin 42
121     CHECK_ALLOCATION(m->breakpoints.string[i] =
122     malloc(breakpoint_buf_len));
123     strlcpy(m->breakpoints.string[i], cmd_line+4,
124 dpavlin 24 breakpoint_buf_len);
125 dpavlin 42 m->breakpoints.addr[i] = tmp;
126 dpavlin 24
127 dpavlin 42 m->breakpoints.n ++;
128 dpavlin 24 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 dpavlin 32 i, mem->devices[i].name,
208     (uint64_t) mem->devices[i].baseaddr,
209     (uint64_t) mem->devices[i].length);
210 dpavlin 24
211 dpavlin 32 if (mem->devices[i].flags) {
212 dpavlin 24 printf(" (");
213 dpavlin 32 if (mem->devices[i].flags & DM_DYNTRANS_OK)
214 dpavlin 24 printf("DYNTRANS R");
215 dpavlin 32 if (mem->devices[i].flags &DM_DYNTRANS_WRITE_OK)
216 dpavlin 24 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 dpavlin 42 char *tmps;
258 dpavlin 24
259 dpavlin 42 CHECK_ALLOCATION(tmps = strdup(cmd_line));
260    
261 dpavlin 24 /* addr: */
262     p = strchr(tmps, ' ');
263     if (p != NULL)
264     *p = '\0';
265 dpavlin 32 r = debugger_parse_expression(m, tmps, 0, &tmp);
266 dpavlin 24 free(tmps);
267    
268 dpavlin 32 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
269 dpavlin 24 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 dpavlin 32 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 dpavlin 24 addr_start = last_dump_addr;
290    
291 dpavlin 32 if (addr_start == MAGIC_UNTOUCHED)
292     addr_start = c->pc;
293 dpavlin 24
294     addr_end = addr_start + 16 * 16;
295    
296     /* endaddr: */
297     if (p != NULL) {
298     while (*p == ' ' && *p)
299     p++;
300 dpavlin 32 r = debugger_parse_expression(m, p, 0, &addr_end);
301     if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
302 dpavlin 24 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 dpavlin 44 * debugger_cmd_emul():
359 dpavlin 24 *
360 dpavlin 44 * Dump info about the current emulation.
361 dpavlin 24 */
362 dpavlin 44 static void debugger_cmd_emul(struct machine *m, char *cmd_line)
363 dpavlin 24 {
364 dpavlin 44 int iadd = DEBUG_INDENTATION;
365 dpavlin 24
366     if (*cmd_line) {
367 dpavlin 44 printf("syntax: emul\n");
368 dpavlin 24 return;
369     }
370    
371 dpavlin 44 debug("emulation \"%s\":\n", debugger_emul->name == NULL?
372     "(simple setup)" : debugger_emul->name);
373 dpavlin 24
374 dpavlin 44 debug_indentation(iadd);
375     emul_dumpinfo(debugger_emul);
376     debug_indentation(-iadd);
377 dpavlin 24 }
378    
379    
380     /*
381     * debugger_cmd_focus():
382     *
383 dpavlin 32 * Changes focus to specific cpu, in a specific machine (in a specific
384     * emulation).
385 dpavlin 24 */
386     static void debugger_cmd_focus(struct machine *m, char *cmd_line)
387     {
388 dpavlin 44 int x = -1, y = -1;
389 dpavlin 32 char *p, *p2;
390 dpavlin 24
391     if (!cmd_line[0]) {
392 dpavlin 44 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 dpavlin 32 " command.\n");
396 dpavlin 24 goto print_current_focus_and_return;
397     }
398    
399     x = atoi(cmd_line);
400     p = strchr(cmd_line, ',');
401     if (p == cmd_line) {
402 dpavlin 32 printf("No cpu number specified?\n");
403 dpavlin 24 return;
404     }
405    
406 dpavlin 32 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 dpavlin 24 return;
430     }
431    
432 dpavlin 32 debugger_cur_cpu = x;
433 dpavlin 24
434     print_current_focus_and_return:
435 dpavlin 32 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 dpavlin 24 }
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 dpavlin 44 int iadd = 0;
523 dpavlin 24
524     if (*cmd_line) {
525     printf("syntax: machine\n");
526     return;
527     }
528    
529 dpavlin 44 if (m->name != NULL) {
530     debug("machine \"%s\":\n", m->name);
531     iadd = DEBUG_INDENTATION;
532     }
533    
534 dpavlin 24 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 dpavlin 32 res = debugger_parse_expression(m, cmd_line, 0, &tmp);
633 dpavlin 24 switch (res) {
634 dpavlin 32 case PARSE_NOMATCH:
635 dpavlin 24 printf("No match.\n");
636     break;
637 dpavlin 32 case PARSE_MULTIPLE:
638 dpavlin 24 printf("Multiple matches. Try prefixing with %%, $, or @.\n");
639     break;
640 dpavlin 32 case PARSE_SETTINGS:
641 dpavlin 24 printf("%s = 0x%"PRIx64"\n", cmd_line, (uint64_t)tmp);
642     break;
643 dpavlin 32 case PARSE_SYMBOL:
644 dpavlin 24 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 dpavlin 32 case PARSE_NUMBER:
650 dpavlin 24 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 dpavlin 32 res = debugger_parse_expression(m, q, 0, &addr);
718 dpavlin 24 switch (res) {
719 dpavlin 32 case PARSE_NOMATCH:
720 dpavlin 24 printf("Couldn't parse the address.\n");
721     return;
722 dpavlin 32 case PARSE_MULTIPLE:
723 dpavlin 24 printf("Multiple matches for the address."
724     " Try prefixing with %%, $, or @.\n");
725     return;
726 dpavlin 32 case PARSE_SETTINGS:
727     case PARSE_SYMBOL:
728     case PARSE_NUMBER:
729 dpavlin 24 break;
730     default:
731     printf("INTERNAL ERROR in debugger.c.\n");
732     return;
733     }
734    
735 dpavlin 32 res = debugger_parse_expression(m, p, 0, &data);
736 dpavlin 24 switch (res) {
737 dpavlin 32 case PARSE_NOMATCH:
738 dpavlin 24 printf("Couldn't parse the data.\n");
739     return;
740 dpavlin 32 case PARSE_MULTIPLE:
741 dpavlin 24 printf("Multiple matches for the data value."
742     " Try prefixing with %%, $, or @.\n");
743     return;
744 dpavlin 32 case PARSE_SETTINGS:
745     case PARSE_SYMBOL:
746     case PARSE_NUMBER:
747 dpavlin 24 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 dpavlin 44 int j, k;
888 dpavlin 24
889     if (*cmd_line) {
890     printf("syntax: quit\n");
891     return;
892     }
893    
894 dpavlin 44 single_step = NOT_SINGLE_STEPPING;
895 dpavlin 24
896 dpavlin 44 force_debugger_at_exit = 0;
897 dpavlin 24
898 dpavlin 44 for (j=0; j<debugger_emul->n_machines; j++) {
899     struct machine *m = debugger_emul->machines[j];
900 dpavlin 24
901 dpavlin 44 for (k=0; k<m->ncpus; k++)
902     m->cpus[k]->running = 0;
903 dpavlin 24
904 dpavlin 44 m->exit_without_entering_debugger = 1;
905 dpavlin 24 }
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 dpavlin 32 int cpuid = debugger_cur_cpu, coprocnr = -1;
917 dpavlin 24 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 dpavlin 32 cpu_register_dump(m, m->cpus[cpuid], gprs, coprocs);
943 dpavlin 24 }
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 dpavlin 42 char *tmps;
1074 dpavlin 24
1075 dpavlin 42 CHECK_ALLOCATION(tmps = strdup(cmd_line));
1076    
1077 dpavlin 24 /* addr: */
1078     p = strchr(tmps, ' ');
1079     if (p != NULL)
1080     *p = '\0';
1081 dpavlin 32 r = debugger_parse_expression(m, tmps, 0, &tmp);
1082 dpavlin 24 free(tmps);
1083    
1084 dpavlin 32 if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1085 dpavlin 24 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 dpavlin 32 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 dpavlin 24 addr_start = last_unasm_addr;
1106    
1107 dpavlin 32 if (addr_start == MAGIC_UNTOUCHED)
1108     addr_start = c->pc;
1109 dpavlin 24
1110     addr_end = addr_start + 1000;
1111    
1112     /* endaddr: */
1113     if (p != NULL) {
1114     while (*p == ' ' && *p)
1115     p++;
1116 dpavlin 32 r = debugger_parse_expression(m, p, 0, &addr_end);
1117     if (r == PARSE_NOMATCH || r == PARSE_MULTIPLE) {
1118 dpavlin 24 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 dpavlin 44 { "emul", "", 0, debugger_cmd_emul,
1213     "print a summary of the current emulation" },
1214 dpavlin 24
1215 dpavlin 32 { "focus", "x[,y[,z]]", 0, debugger_cmd_focus,
1216     "changes focus to cpu x, machine x, emul z" },
1217 dpavlin 24
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 dpavlin 32 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 dpavlin 34 " parenthesis and + - * / & %% ^ | operators.\nIn case there are"
1377 dpavlin 32 " 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 dpavlin 24 }
1382    

  ViewVC Help
Powered by ViewVC 1.1.26