Commit 9307c4c1d93939db9b04117b654253af5113dc21

Authored by bellard
1 parent 40c3bac3

improved monitor: type check, expression evaluator, memory dump, disassembly


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@703 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 3 changed files with 843 additions and 121 deletions
1 /* General "disassemble this chunk" code. Used for debugging. */ 1 /* General "disassemble this chunk" code. Used for debugging. */
2 #include "config.h" 2 #include "config.h"
3 #include "dis-asm.h" 3 #include "dis-asm.h"
4 -#include "disas.h"  
5 #include "elf.h" 4 #include "elf.h"
6 #include <errno.h> 5 #include <errno.h>
7 6
8 #include "cpu.h" 7 #include "cpu.h"
9 #include "exec-all.h" 8 #include "exec-all.h"
  9 +#include "disas.h"
10 10
11 /* Filled in by elfload.c. Simplistic, but will do for now. */ 11 /* Filled in by elfload.c. Simplistic, but will do for now. */
12 unsigned int disas_num_syms; 12 unsigned int disas_num_syms;
@@ -219,3 +219,71 @@ const char *lookup_symbol(void *orig_addr) @@ -219,3 +219,71 @@ const char *lookup_symbol(void *orig_addr)
219 } 219 }
220 return ""; 220 return "";
221 } 221 }
  222 +
  223 +#if !defined(CONFIG_USER_ONLY)
  224 +
  225 +static int monitor_disas_is_physical;
  226 +
  227 +static int
  228 +monitor_read_memory (memaddr, myaddr, length, info)
  229 + bfd_vma memaddr;
  230 + bfd_byte *myaddr;
  231 + int length;
  232 + struct disassemble_info *info;
  233 +{
  234 + if (monitor_disas_is_physical) {
  235 + cpu_physical_memory_rw(memaddr, myaddr, length, 0);
  236 + } else {
  237 + cpu_memory_rw_debug(cpu_single_env, memaddr,myaddr, length, 0);
  238 + }
  239 + return 0;
  240 +}
  241 +
  242 +void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
  243 +{
  244 + FILE *out;
  245 + int count, i;
  246 + struct disassemble_info disasm_info;
  247 + int (*print_insn)(bfd_vma pc, disassemble_info *info);
  248 +
  249 + out = stdout;
  250 +
  251 + INIT_DISASSEMBLE_INFO(disasm_info, out, fprintf);
  252 +
  253 + monitor_disas_is_physical = is_physical;
  254 + disasm_info.read_memory_func = monitor_read_memory;
  255 +
  256 + disasm_info.buffer_vma = pc;
  257 +
  258 +#ifdef TARGET_WORDS_BIGENDIAN
  259 + disasm_info.endian = BFD_ENDIAN_BIG;
  260 +#else
  261 + disasm_info.endian = BFD_ENDIAN_LITTLE;
  262 +#endif
  263 +#if defined(TARGET_I386)
  264 + if (!flags)
  265 + disasm_info.mach = bfd_mach_i386_i386;
  266 + else
  267 + disasm_info.mach = bfd_mach_i386_i8086;
  268 + print_insn = print_insn_i386;
  269 +#elif defined(TARGET_ARM)
  270 + print_insn = print_insn_arm;
  271 +#elif defined(TARGET_SPARC)
  272 + print_insn = print_insn_sparc;
  273 +#elif defined(TARGET_PPC)
  274 + print_insn = print_insn_ppc;
  275 +#else
  276 + fprintf(out, "Asm output not supported on this arch\n");
  277 + return;
  278 +#endif
  279 +
  280 + for(i = 0; i < nb_insn; i++) {
  281 + fprintf(out, "0x%08lx: ", (unsigned long)pc);
  282 + count = print_insn(pc, &disasm_info);
  283 + fprintf(out, "\n");
  284 + if (count < 0)
  285 + break;
  286 + pc += count;
  287 + }
  288 +}
  289 +#endif
@@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
3 3
4 /* Disassemble this for me please... (debugging). */ 4 /* Disassemble this for me please... (debugging). */
5 void disas(FILE *out, void *code, unsigned long size, int is_host, int flags); 5 void disas(FILE *out, void *code, unsigned long size, int is_host, int flags);
  6 +void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags);
6 7
7 /* Look up symbol for debugging purpose. Returns "" if unknown. */ 8 /* Look up symbol for debugging purpose. Returns "" if unknown. */
8 const char *lookup_symbol(void *orig_addr); 9 const char *lookup_symbol(void *orig_addr);
monitor.c
@@ -22,11 +22,15 @@ @@ -22,11 +22,15 @@
22 * THE SOFTWARE. 22 * THE SOFTWARE.
23 */ 23 */
24 #include "vl.h" 24 #include "vl.h"
  25 +#include "disas.h"
25 26
26 //#define DEBUG 27 //#define DEBUG
27 28
  29 +#ifndef offsetof
  30 +#define offsetof(type, field) ((size_t) &((type *)0)->field)
  31 +#endif
  32 +
28 #define TERM_CMD_BUF_SIZE 4095 33 #define TERM_CMD_BUF_SIZE 4095
29 -#define MAX_ARGS 64  
30 34
31 #define IS_NORM 0 35 #define IS_NORM 0
32 #define IS_ESC 1 36 #define IS_ESC 1
@@ -40,9 +44,22 @@ static int term_cmd_buf_size; @@ -40,9 +44,22 @@ static int term_cmd_buf_size;
40 static int term_esc_state; 44 static int term_esc_state;
41 static int term_esc_param; 45 static int term_esc_param;
42 46
  47 +/*
  48 + * Supported types:
  49 + *
  50 + * 'F' filename
  51 + * 's' string (accept optional quote)
  52 + * 'i' integer
  53 + * '/' optional gdb-like print format (like "/10x")
  54 + *
  55 + * '?' optional type (for 'F', 's' and 'i')
  56 + *
  57 + */
  58 +
43 typedef struct term_cmd_t { 59 typedef struct term_cmd_t {
44 const char *name; 60 const char *name;
45 - void (*handler)(int argc, const char **argv); 61 + const char *args_type;
  62 + void (*handler)();
46 const char *params; 63 const char *params;
47 const char *help; 64 const char *help;
48 } term_cmd_t; 65 } term_cmd_t;
@@ -110,12 +127,12 @@ static void help_cmd(const char *name) @@ -110,12 +127,12 @@ static void help_cmd(const char *name)
110 } 127 }
111 } 128 }
112 129
113 -static void do_help(int argc, const char **argv) 130 +static void do_help(const char *name)
114 { 131 {
115 - help_cmd(argv[1]); 132 + help_cmd(name);
116 } 133 }
117 134
118 -static void do_commit(int argc, const char **argv) 135 +static void do_commit(void)
119 { 136 {
120 int i; 137 int i;
121 138
@@ -125,26 +142,24 @@ static void do_commit(int argc, const char **argv) @@ -125,26 +142,24 @@ static void do_commit(int argc, const char **argv)
125 } 142 }
126 } 143 }
127 144
128 -static void do_info(int argc, const char **argv) 145 +static void do_info(const char *item)
129 { 146 {
130 term_cmd_t *cmd; 147 term_cmd_t *cmd;
131 - const char *item;  
132 148
133 - if (argc < 2) 149 + if (!item)
134 goto help; 150 goto help;
135 - item = argv[1];  
136 for(cmd = info_cmds; cmd->name != NULL; cmd++) { 151 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
137 - if (compare_cmd(argv[1], cmd->name)) 152 + if (compare_cmd(item, cmd->name))
138 goto found; 153 goto found;
139 } 154 }
140 help: 155 help:
141 - help_cmd(argv[0]); 156 + help_cmd("info");
142 return; 157 return;
143 found: 158 found:
144 - cmd->handler(argc, argv); 159 + cmd->handler();
145 } 160 }
146 161
147 -static void do_info_network(int argc, const char **argv) 162 +static void do_info_network(void)
148 { 163 {
149 int i, j; 164 int i, j;
150 NetDriverState *nd; 165 NetDriverState *nd;
@@ -161,12 +176,21 @@ static void do_info_network(int argc, const char **argv) @@ -161,12 +176,21 @@ static void do_info_network(int argc, const char **argv)
161 } 176 }
162 } 177 }
163 178
164 -static void do_info_block(int argc, const char **argv) 179 +static void do_info_block(void)
165 { 180 {
166 bdrv_info(); 181 bdrv_info();
167 } 182 }
168 183
169 -static void do_quit(int argc, const char **argv) 184 +static void do_info_registers(void)
  185 +{
  186 +#ifdef TARGET_I386
  187 + cpu_dump_state(cpu_single_env, stdout, X86_DUMP_FPU | X86_DUMP_CCOP);
  188 +#else
  189 + cpu_dump_state(cpu_single_env, stdout, 0);
  190 +#endif
  191 +}
  192 +
  193 +static void do_quit(void)
170 { 194 {
171 exit(0); 195 exit(0);
172 } 196 }
@@ -189,26 +213,13 @@ static int eject_device(BlockDriverState *bs, int force) @@ -189,26 +213,13 @@ static int eject_device(BlockDriverState *bs, int force)
189 return 0; 213 return 0;
190 } 214 }
191 215
192 -static void do_eject(int argc, const char **argv) 216 +static void do_eject(int force, const char *filename)
193 { 217 {
194 BlockDriverState *bs; 218 BlockDriverState *bs;
195 - const char **parg;  
196 - int force;  
197 219
198 - parg = argv + 1;  
199 - if (!*parg) {  
200 - fail:  
201 - help_cmd(argv[0]);  
202 - return;  
203 - }  
204 - force = 0;  
205 - if (!strcmp(*parg, "-f")) {  
206 - force = 1;  
207 - parg++;  
208 - }  
209 - if (!*parg)  
210 - goto fail;  
211 - bs = bdrv_find(*parg); 220 + term_printf("%d %s\n", force, filename);
  221 +
  222 + bs = bdrv_find(filename);
212 if (!bs) { 223 if (!bs) {
213 term_printf("device not found\n"); 224 term_printf("device not found\n");
214 return; 225 return;
@@ -216,90 +227,68 @@ static void do_eject(int argc, const char **argv) @@ -216,90 +227,68 @@ static void do_eject(int argc, const char **argv)
216 eject_device(bs, force); 227 eject_device(bs, force);
217 } 228 }
218 229
219 -static void do_change(int argc, const char **argv) 230 +static void do_change(const char *device, const char *filename)
220 { 231 {
221 BlockDriverState *bs; 232 BlockDriverState *bs;
222 233
223 - if (argc != 3) {  
224 - help_cmd(argv[0]);  
225 - return;  
226 - }  
227 - bs = bdrv_find(argv[1]); 234 + bs = bdrv_find(device);
228 if (!bs) { 235 if (!bs) {
229 term_printf("device not found\n"); 236 term_printf("device not found\n");
230 return; 237 return;
231 } 238 }
232 if (eject_device(bs, 0) < 0) 239 if (eject_device(bs, 0) < 0)
233 return; 240 return;
234 - bdrv_open(bs, argv[2], 0); 241 + bdrv_open(bs, filename, 0);
235 } 242 }
236 243
237 -static void do_screen_dump(int argc, const char **argv) 244 +static void do_screen_dump(const char *filename)
238 { 245 {
239 - if (argc != 2) {  
240 - help_cmd(argv[0]);  
241 - return;  
242 - }  
243 - vga_screen_dump(argv[1]); 246 + vga_screen_dump(filename);
244 } 247 }
245 248
246 -static void do_log(int argc, const char **argv) 249 +static void do_log(const char *items)
247 { 250 {
248 int mask; 251 int mask;
249 252
250 - if (argc != 2)  
251 - goto help;  
252 - if (!strcmp(argv[1], "none")) { 253 + if (!strcmp(items, "none")) {
253 mask = 0; 254 mask = 0;
254 } else { 255 } else {
255 - mask = cpu_str_to_log_mask(argv[1]); 256 + mask = cpu_str_to_log_mask(items);
256 if (!mask) { 257 if (!mask) {
257 - help:  
258 - help_cmd(argv[0]); 258 + help_cmd("log");
259 return; 259 return;
260 } 260 }
261 } 261 }
262 cpu_set_log(mask); 262 cpu_set_log(mask);
263 } 263 }
264 264
265 -static void do_savevm(int argc, const char **argv) 265 +static void do_savevm(const char *filename)
266 { 266 {
267 - if (argc != 2) {  
268 - help_cmd(argv[0]);  
269 - return;  
270 - }  
271 - if (qemu_savevm(argv[1]) < 0)  
272 - term_printf("I/O error when saving VM to '%s'\n", argv[1]); 267 + if (qemu_savevm(filename) < 0)
  268 + term_printf("I/O error when saving VM to '%s'\n", filename);
273 } 269 }
274 270
275 -static void do_loadvm(int argc, const char **argv) 271 +static void do_loadvm(const char *filename)
276 { 272 {
277 - if (argc != 2) {  
278 - help_cmd(argv[0]);  
279 - return;  
280 - }  
281 - if (qemu_loadvm(argv[1]) < 0)  
282 - term_printf("I/O error when loading VM from '%s'\n", argv[1]); 273 + if (qemu_loadvm(filename) < 0)
  274 + term_printf("I/O error when loading VM from '%s'\n", filename);
283 } 275 }
284 276
285 -static void do_stop(int argc, const char **argv) 277 +static void do_stop(void)
286 { 278 {
287 vm_stop(EXCP_INTERRUPT); 279 vm_stop(EXCP_INTERRUPT);
288 } 280 }
289 281
290 -static void do_cont(int argc, const char **argv) 282 +static void do_cont(void)
291 { 283 {
292 vm_start(); 284 vm_start();
293 } 285 }
294 286
295 #ifdef CONFIG_GDBSTUB 287 #ifdef CONFIG_GDBSTUB
296 -static void do_gdbserver(int argc, const char **argv) 288 +static void do_gdbserver(int has_port, int port)
297 { 289 {
298 - int port;  
299 -  
300 - port = DEFAULT_GDBSTUB_PORT;  
301 - if (argc >= 2)  
302 - port = atoi(argv[1]); 290 + if (!has_port)
  291 + port = DEFAULT_GDBSTUB_PORT;
303 if (gdbserver_start(port) < 0) { 292 if (gdbserver_start(port) < 0) {
304 qemu_printf("Could not open gdbserver socket on port %d\n", port); 293 qemu_printf("Could not open gdbserver socket on port %d\n", port);
305 } else { 294 } else {
@@ -308,90 +297,754 @@ static void do_gdbserver(int argc, const char **argv) @@ -308,90 +297,754 @@ static void do_gdbserver(int argc, const char **argv)
308 } 297 }
309 #endif 298 #endif
310 299
  300 +static void term_printc(int c)
  301 +{
  302 + term_printf("'");
  303 + switch(c) {
  304 + case '\'':
  305 + term_printf("\\'");
  306 + break;
  307 + case '\\':
  308 + term_printf("\\\\");
  309 + break;
  310 + case '\n':
  311 + term_printf("\\n");
  312 + break;
  313 + case '\r':
  314 + term_printf("\\r");
  315 + break;
  316 + default:
  317 + if (c >= 32 && c <= 126) {
  318 + term_printf("%c", c);
  319 + } else {
  320 + term_printf("\\x%02x", c);
  321 + }
  322 + break;
  323 + }
  324 + term_printf("'");
  325 +}
  326 +
  327 +static void memory_dump(int count, int format, int wsize,
  328 + target_ulong addr, int is_physical)
  329 +{
  330 + int nb_per_line, l, line_size, i, max_digits, len;
  331 + uint8_t buf[16];
  332 + uint64_t v;
  333 +
  334 + if (format == 'i') {
  335 + int flags;
  336 + flags = 0;
  337 +#ifdef TARGET_I386
  338 + /* we use the current CS size */
  339 + if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK))
  340 + flags = 1;
  341 +#endif
  342 + monitor_disas(addr, count, is_physical, flags);
  343 + return;
  344 + }
  345 +
  346 + len = wsize * count;
  347 + if (wsize == 1)
  348 + line_size = 8;
  349 + else
  350 + line_size = 16;
  351 + nb_per_line = line_size / wsize;
  352 + max_digits = 0;
  353 +
  354 + switch(format) {
  355 + case 'o':
  356 + max_digits = (wsize * 8 + 2) / 3;
  357 + break;
  358 + default:
  359 + case 'x':
  360 + max_digits = (wsize * 8) / 4;
  361 + break;
  362 + case 'u':
  363 + case 'd':
  364 + max_digits = (wsize * 8 * 10 + 32) / 33;
  365 + break;
  366 + case 'c':
  367 + wsize = 1;
  368 + break;
  369 + }
  370 +
  371 + while (len > 0) {
  372 + term_printf("0x%08x:", addr);
  373 + l = len;
  374 + if (l > line_size)
  375 + l = line_size;
  376 + if (is_physical) {
  377 + cpu_physical_memory_rw(addr, buf, l, 0);
  378 + } else {
  379 + cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0);
  380 + }
  381 + i = 0;
  382 + while (i < l) {
  383 + switch(wsize) {
  384 + default:
  385 + case 1:
  386 + v = ldub_raw(buf + i);
  387 + break;
  388 + case 2:
  389 + v = lduw_raw(buf + i);
  390 + break;
  391 + case 4:
  392 + v = ldl_raw(buf + i);
  393 + break;
  394 + case 8:
  395 + v = ldq_raw(buf + i);
  396 + break;
  397 + }
  398 + term_printf(" ");
  399 + switch(format) {
  400 + case 'o':
  401 + term_printf("%#*llo", max_digits, v);
  402 + break;
  403 + case 'x':
  404 + term_printf("0x%0*llx", max_digits, v);
  405 + break;
  406 + case 'u':
  407 + term_printf("%*llu", max_digits, v);
  408 + break;
  409 + case 'd':
  410 + term_printf("%*lld", max_digits, v);
  411 + break;
  412 + case 'c':
  413 + term_printc(v);
  414 + break;
  415 + }
  416 + i += wsize;
  417 + }
  418 + term_printf("\n");
  419 + addr += l;
  420 + len -= l;
  421 + }
  422 +}
  423 +
  424 +static void do_memory_dump(int count, int format, int size, int addr)
  425 +{
  426 + memory_dump(count, format, size, addr, 0);
  427 +}
  428 +
  429 +static void do_physical_memory_dump(int count, int format, int size, int addr)
  430 +{
  431 + memory_dump(count, format, size, addr, 1);
  432 +}
  433 +
  434 +static void do_print(int count, int format, int size, int val)
  435 +{
  436 + switch(format) {
  437 + case 'o':
  438 + term_printf("%#o", val);
  439 + break;
  440 + case 'x':
  441 + term_printf("%#x", val);
  442 + break;
  443 + case 'u':
  444 + term_printf("%u", val);
  445 + break;
  446 + default:
  447 + case 'd':
  448 + term_printf("%d", val);
  449 + break;
  450 + case 'c':
  451 + term_printc(val);
  452 + break;
  453 + }
  454 + term_printf("\n");
  455 +}
  456 +
311 static term_cmd_t term_cmds[] = { 457 static term_cmd_t term_cmds[] = {
312 - { "help|?", do_help, 458 + { "help|?", "s?", do_help,
313 "[cmd]", "show the help" }, 459 "[cmd]", "show the help" },
314 - { "commit", do_commit, 460 + { "commit", "", do_commit,
315 "", "commit changes to the disk images (if -snapshot is used)" }, 461 "", "commit changes to the disk images (if -snapshot is used)" },
316 - { "info", do_info, 462 + { "info", "s?", do_info,
317 "subcommand", "show various information about the system state" }, 463 "subcommand", "show various information about the system state" },
318 - { "q|quit", do_quit, 464 + { "q|quit", "", do_quit,
319 "", "quit the emulator" }, 465 "", "quit the emulator" },
320 - { "eject", do_eject, 466 + { "eject", "-fs", do_eject,
321 "[-f] device", "eject a removable media (use -f to force it)" }, 467 "[-f] device", "eject a removable media (use -f to force it)" },
322 - { "change", do_change, 468 + { "change", "sF", do_change,
323 "device filename", "change a removable media" }, 469 "device filename", "change a removable media" },
324 - { "screendump", do_screen_dump, 470 + { "screendump", "F", do_screen_dump,
325 "filename", "save screen into PPM image 'filename'" }, 471 "filename", "save screen into PPM image 'filename'" },
326 - { "log", do_log, 472 + { "log", "s", do_log,
327 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, 473 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
328 - { "savevm", do_savevm, 474 + { "savevm", "F", do_savevm,
329 "filename", "save the whole virtual machine state to 'filename'" }, 475 "filename", "save the whole virtual machine state to 'filename'" },
330 - { "loadvm", do_loadvm, 476 + { "loadvm", "F", do_loadvm,
331 "filename", "restore the whole virtual machine state from 'filename'" }, 477 "filename", "restore the whole virtual machine state from 'filename'" },
332 - { "stop", do_stop, "", "stop emulation", },  
333 - { "c|cont", do_cont, "", "resume emulation", }, 478 + { "stop", "", do_stop,
  479 + "", "stop emulation", },
  480 + { "c|cont", "", do_cont,
  481 + "", "resume emulation", },
334 #ifdef CONFIG_GDBSTUB 482 #ifdef CONFIG_GDBSTUB
335 - { "gdbserver", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", }, 483 + { "gdbserver", "i?", do_gdbserver,
  484 + "[port]", "start gdbserver session (default port=1234)", },
336 #endif 485 #endif
  486 + { "x", "/i", do_memory_dump,
  487 + "/fmt addr", "virtual memory dump starting at 'addr'", },
  488 + { "xp", "/i", do_physical_memory_dump,
  489 + "/fmt addr", "physical memory dump starting at 'addr'", },
  490 + { "p|print", "/i", do_print,
  491 + "/fmt expr", "print expression value (use $reg for CPU register access)", },
337 { NULL, NULL, }, 492 { NULL, NULL, },
338 }; 493 };
339 494
340 static term_cmd_t info_cmds[] = { 495 static term_cmd_t info_cmds[] = {
341 - { "network", do_info_network, 496 + { "network", "", do_info_network,
342 "", "show the network state" }, 497 "", "show the network state" },
343 - { "block", do_info_block, 498 + { "block", "", do_info_block,
344 "", "show the block devices" }, 499 "", "show the block devices" },
  500 + { "registers", "", do_info_registers,
  501 + "", "show the cpu registers" },
345 { NULL, NULL, }, 502 { NULL, NULL, },
346 }; 503 };
347 504
348 -static void term_handle_command(char *cmdline) 505 +/*******************************************************************/
  506 +
  507 +static const char *pch;
  508 +static jmp_buf expr_env;
  509 +
  510 +typedef struct MonitorDef {
  511 + const char *name;
  512 + int offset;
  513 + int (*get_value)(struct MonitorDef *md);
  514 +} MonitorDef;
  515 +
  516 +static MonitorDef monitor_defs[] = {
  517 +#ifdef TARGET_I386
  518 + { "eax", offsetof(CPUState, regs[0]) },
  519 + { "ecx", offsetof(CPUState, regs[1]) },
  520 + { "edx", offsetof(CPUState, regs[2]) },
  521 + { "ebx", offsetof(CPUState, regs[3]) },
  522 + { "esp|sp", offsetof(CPUState, regs[4]) },
  523 + { "ebp|fp", offsetof(CPUState, regs[5]) },
  524 + { "esi", offsetof(CPUState, regs[6]) },
  525 + { "esi", offsetof(CPUState, regs[7]) },
  526 + { "eflags", offsetof(CPUState, eflags) },
  527 + { "eip|pc", offsetof(CPUState, eip) },
  528 +#endif
  529 + { NULL },
  530 +};
  531 +
  532 +static void expr_error(const char *fmt)
  533 +{
  534 + term_printf(fmt);
  535 + term_printf("\n");
  536 + longjmp(expr_env, 1);
  537 +}
  538 +
  539 +static int get_monitor_def(int *pval, const char *name)
  540 +{
  541 + MonitorDef *md;
  542 + for(md = monitor_defs; md->name != NULL; md++) {
  543 + if (compare_cmd(name, md->name)) {
  544 + if (md->get_value) {
  545 + *pval = md->get_value(md);
  546 + } else {
  547 + *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset);
  548 + }
  549 + return 0;
  550 + }
  551 + }
  552 + return -1;
  553 +}
  554 +
  555 +static void next(void)
  556 +{
  557 + if (pch != '\0') {
  558 + pch++;
  559 + while (isspace(*pch))
  560 + pch++;
  561 + }
  562 +}
  563 +
  564 +static int expr_sum(void);
  565 +
  566 +static int expr_unary(void)
  567 +{
  568 + int n;
  569 + char *p;
  570 +
  571 + switch(*pch) {
  572 + case '+':
  573 + next();
  574 + n = expr_unary();
  575 + break;
  576 + case '-':
  577 + next();
  578 + n = -expr_unary();
  579 + break;
  580 + case '~':
  581 + next();
  582 + n = ~expr_unary();
  583 + break;
  584 + case '(':
  585 + next();
  586 + n = expr_sum();
  587 + if (*pch != ')') {
  588 + expr_error("')' expected");
  589 + }
  590 + next();
  591 + break;
  592 + case '$':
  593 + {
  594 + char buf[128], *q;
  595 +
  596 + pch++;
  597 + q = buf;
  598 + while ((*pch >= 'a' && *pch <= 'z') ||
  599 + (*pch >= 'A' && *pch <= 'Z') ||
  600 + (*pch >= '0' && *pch <= '9') ||
  601 + *pch == '_') {
  602 + if ((q - buf) < sizeof(buf) - 1)
  603 + *q++ = *pch;
  604 + pch++;
  605 + }
  606 + while (isspace(*pch))
  607 + pch++;
  608 + *q = 0;
  609 + if (get_monitor_def(&n, buf))
  610 + expr_error("unknown register");
  611 + }
  612 + break;
  613 + case '\0':
  614 + expr_error("unexpected end of expression");
  615 + n = 0;
  616 + break;
  617 + default:
  618 + n = strtoul(pch, &p, 0);
  619 + if (pch == p) {
  620 + expr_error("invalid char in expression");
  621 + }
  622 + pch = p;
  623 + while (isspace(*pch))
  624 + pch++;
  625 + break;
  626 + }
  627 + return n;
  628 +}
  629 +
  630 +
  631 +static int expr_prod(void)
  632 +{
  633 + int val, val2, op;
  634 +
  635 + val = expr_unary();
  636 + for(;;) {
  637 + op = *pch;
  638 + if (op != '*' && op != '/' && op != '%')
  639 + break;
  640 + next();
  641 + val2 = expr_unary();
  642 + switch(op) {
  643 + default:
  644 + case '*':
  645 + val *= val2;
  646 + break;
  647 + case '/':
  648 + case '%':
  649 + if (val2 == 0)
  650 + expr_error("divison by zero");
  651 + if (op == '/')
  652 + val /= val2;
  653 + else
  654 + val %= val2;
  655 + break;
  656 + }
  657 + }
  658 + return val;
  659 +}
  660 +
  661 +static int expr_logic(void)
  662 +{
  663 + int val, val2, op;
  664 +
  665 + val = expr_prod();
  666 + for(;;) {
  667 + op = *pch;
  668 + if (op != '&' && op != '|' && op != '^')
  669 + break;
  670 + next();
  671 + val2 = expr_prod();
  672 + switch(op) {
  673 + default:
  674 + case '&':
  675 + val &= val2;
  676 + break;
  677 + case '|':
  678 + val |= val2;
  679 + break;
  680 + case '^':
  681 + val ^= val2;
  682 + break;
  683 + }
  684 + }
  685 + return val;
  686 +}
  687 +
  688 +static int expr_sum(void)
349 { 689 {
350 - char *p, *pstart;  
351 - int argc;  
352 - const char *args[MAX_ARGS + 1]; 690 + int val, val2, op;
  691 +
  692 + val = expr_logic();
  693 + for(;;) {
  694 + op = *pch;
  695 + if (op != '+' && op != '-')
  696 + break;
  697 + next();
  698 + val2 = expr_logic();
  699 + if (op == '+')
  700 + val += val2;
  701 + else
  702 + val -= val2;
  703 + }
  704 + return val;
  705 +}
  706 +
  707 +static int get_expr(int *pval, const char **pp)
  708 +{
  709 + pch = *pp;
  710 + if (setjmp(expr_env)) {
  711 + *pp = pch;
  712 + return -1;
  713 + }
  714 + while (isspace(*pch))
  715 + pch++;
  716 + *pval = expr_sum();
  717 + *pp = pch;
  718 + return 0;
  719 +}
  720 +
  721 +static int get_str(char *buf, int buf_size, const char **pp)
  722 +{
  723 + const char *p;
  724 + char *q;
  725 + int c;
  726 +
  727 + p = *pp;
  728 + while (isspace(*p))
  729 + p++;
  730 + if (*p == '\0') {
  731 + fail:
  732 + *pp = p;
  733 + return -1;
  734 + }
  735 + q = buf;
  736 + if (*p == '\"') {
  737 + p++;
  738 + while (*p != '\0' && *p != '\"') {
  739 + if (*p == '\\') {
  740 + p++;
  741 + c = *p++;
  742 + switch(c) {
  743 + case 'n':
  744 + c = '\n';
  745 + break;
  746 + case 'r':
  747 + c = '\r';
  748 + break;
  749 + case '\\':
  750 + case '\'':
  751 + case '\"':
  752 + break;
  753 + default:
  754 + qemu_printf("unsupported escape code: '\\%c'\n", c);
  755 + goto fail;
  756 + }
  757 + if ((q - buf) < buf_size - 1) {
  758 + *q++ = c;
  759 + }
  760 + } else {
  761 + if ((q - buf) < buf_size - 1) {
  762 + *q++ = *p;
  763 + }
  764 + p++;
  765 + }
  766 + }
  767 + if (*p != '\"') {
  768 + qemu_printf("untermintated string\n");
  769 + goto fail;
  770 + }
  771 + p++;
  772 + } else {
  773 + while (*p != '\0' && !isspace(*p)) {
  774 + if ((q - buf) < buf_size - 1) {
  775 + *q++ = *p;
  776 + }
  777 + p++;
  778 + }
  779 + *q = '\0';
  780 + }
  781 + *pp = p;
  782 + return 0;
  783 +}
  784 +
  785 +static int default_fmt_format = 'x';
  786 +static int default_fmt_size = 4;
  787 +
  788 +#define MAX_ARGS 16
  789 +
  790 +static void term_handle_command(const char *cmdline)
  791 +{
  792 + const char *p, *pstart, *typestr;
  793 + char *q;
  794 + int c, nb_args, len, i, has_arg;
353 term_cmd_t *cmd; 795 term_cmd_t *cmd;
  796 + char cmdname[256];
  797 + char buf[1024];
  798 + void *str_allocated[MAX_ARGS];
  799 + void *args[MAX_ARGS];
354 800
355 #ifdef DEBUG 801 #ifdef DEBUG
356 term_printf("command='%s'\n", cmdline); 802 term_printf("command='%s'\n", cmdline);
357 #endif 803 #endif
358 804
359 - /* split command in words */  
360 - argc = 0; 805 + /* extract the command name */
361 p = cmdline; 806 p = cmdline;
  807 + q = cmdname;
  808 + while (isspace(*p))
  809 + p++;
  810 + if (*p == '\0')
  811 + return;
  812 + pstart = p;
  813 + while (*p != '\0' && *p != '/' && !isspace(*p))
  814 + p++;
  815 + len = p - pstart;
  816 + if (len > sizeof(cmdname) - 1)
  817 + len = sizeof(cmdname) - 1;
  818 + memcpy(cmdname, pstart, len);
  819 + cmdname[len] = '\0';
  820 +
  821 + /* find the command */
  822 + for(cmd = term_cmds; cmd->name != NULL; cmd++) {
  823 + if (compare_cmd(cmdname, cmd->name))
  824 + goto found;
  825 + }
  826 + term_printf("unknown command: '%s'\n", cmdname);
  827 + return;
  828 + found:
  829 +
  830 + for(i = 0; i < MAX_ARGS; i++)
  831 + str_allocated[i] = NULL;
  832 +
  833 + /* parse the parameters */
  834 + typestr = cmd->args_type;
  835 + nb_args = 0;
362 for(;;) { 836 for(;;) {
363 - while (isspace(*p))  
364 - p++;  
365 - if (*p == '\0') 837 + c = *typestr;
  838 + if (c == '\0')
366 break; 839 break;
367 - pstart = p;  
368 - while (*p != '\0' && !isspace(*p))  
369 - p++;  
370 - args[argc] = pstart;  
371 - argc++;  
372 - if (argc >= MAX_ARGS) 840 + typestr++;
  841 + switch(c) {
  842 + case 'F':
  843 + case 's':
  844 + {
  845 + int ret;
  846 + char *str;
  847 +
  848 + while (isspace(*p))
  849 + p++;
  850 + if (*typestr == '?') {
  851 + typestr++;
  852 + if (*p == '\0') {
  853 + /* no optional string: NULL argument */
  854 + str = NULL;
  855 + goto add_str;
  856 + }
  857 + }
  858 + ret = get_str(buf, sizeof(buf), &p);
  859 + if (ret < 0) {
  860 + if (c == 'F')
  861 + term_printf("%s: filename expected\n", cmdname);
  862 + else
  863 + term_printf("%s: string expected\n", cmdname);
  864 + goto fail;
  865 + }
  866 + str = qemu_malloc(strlen(buf) + 1);
  867 + strcpy(str, buf);
  868 + str_allocated[nb_args] = str;
  869 + add_str:
  870 + if (nb_args >= MAX_ARGS) {
  871 + error_args:
  872 + term_printf("%s: too many arguments\n", cmdname);
  873 + goto fail;
  874 + }
  875 + args[nb_args++] = str;
  876 + }
373 break; 877 break;
374 - if (*p == '\0') 878 + case '/':
  879 + {
  880 + int count, format, size;
  881 +
  882 + while (isspace(*p))
  883 + p++;
  884 + if (*p == '/') {
  885 + /* format found */
  886 + p++;
  887 + count = 1;
  888 + if (isdigit(*p)) {
  889 + count = 0;
  890 + while (isdigit(*p)) {
  891 + count = count * 10 + (*p - '0');
  892 + p++;
  893 + }
  894 + }
  895 + size = -1;
  896 + format = -1;
  897 + for(;;) {
  898 + switch(*p) {
  899 + case 'o':
  900 + case 'd':
  901 + case 'u':
  902 + case 'x':
  903 + case 'i':
  904 + case 'c':
  905 + format = *p++;
  906 + break;
  907 + case 'b':
  908 + size = 1;
  909 + p++;
  910 + break;
  911 + case 'h':
  912 + size = 2;
  913 + p++;
  914 + break;
  915 + case 'w':
  916 + size = 4;
  917 + p++;
  918 + break;
  919 + case 'g':
  920 + case 'L':
  921 + size = 8;
  922 + p++;
  923 + break;
  924 + default:
  925 + goto next;
  926 + }
  927 + }
  928 + next:
  929 + if (*p != '\0' && !isspace(*p)) {
  930 + term_printf("invalid char in format: '%c'\n", *p);
  931 + goto fail;
  932 + }
  933 + if (size < 0)
  934 + size = default_fmt_size;
  935 + if (format < 0)
  936 + format = default_fmt_format;
  937 + default_fmt_size = size;
  938 + default_fmt_format = format;
  939 + } else {
  940 + count = 1;
  941 + format = default_fmt_format;
  942 + size = default_fmt_size;
  943 + }
  944 + if (nb_args + 3 > MAX_ARGS)
  945 + goto error_args;
  946 + args[nb_args++] = (void*)count;
  947 + args[nb_args++] = (void*)format;
  948 + args[nb_args++] = (void*)size;
  949 + }
  950 + break;
  951 + case 'i':
  952 + {
  953 + int val;
  954 + while (isspace(*p))
  955 + p++;
  956 + if (*typestr == '?') {
  957 + typestr++;
  958 + if (*p == '\0')
  959 + has_arg = 0;
  960 + else
  961 + has_arg = 1;
  962 + if (nb_args >= MAX_ARGS)
  963 + goto error_args;
  964 + args[nb_args++] = (void *)has_arg;
  965 + if (!has_arg) {
  966 + if (nb_args >= MAX_ARGS)
  967 + goto error_args;
  968 + val = -1;
  969 + goto add_num;
  970 + }
  971 + }
  972 + if (get_expr(&val, &p))
  973 + goto fail;
  974 + add_num:
  975 + if (nb_args >= MAX_ARGS)
  976 + goto error_args;
  977 + args[nb_args++] = (void *)val;
  978 + }
375 break; 979 break;
376 - *p++ = '\0'; 980 + case '-':
  981 + {
  982 + int has_option;
  983 + /* option */
  984 +
  985 + c = *typestr++;
  986 + if (c == '\0')
  987 + goto bad_type;
  988 + while (isspace(*p))
  989 + p++;
  990 + has_option = 0;
  991 + if (*p == '-') {
  992 + p++;
  993 + if (*p != c) {
  994 + term_printf("%s: unsupported option -%c\n",
  995 + cmdname, *p);
  996 + goto fail;
  997 + }
  998 + p++;
  999 + has_option = 1;
  1000 + }
  1001 + if (nb_args >= MAX_ARGS)
  1002 + goto error_args;
  1003 + args[nb_args++] = (void *)has_option;
  1004 + }
  1005 + break;
  1006 + default:
  1007 + bad_type:
  1008 + term_printf("%s: unknown type '%c'\n", cmdname, c);
  1009 + goto fail;
  1010 + }
377 } 1011 }
378 - args[argc] = NULL;  
379 -#ifdef DEBUG  
380 - for(i=0;i<argc;i++) {  
381 - term_printf(" '%s'", args[i]); 1012 + /* check that all arguments were parsed */
  1013 + while (isspace(*p))
  1014 + p++;
  1015 + if (*p != '\0') {
  1016 + term_printf("%s: extraneous characters at the end of line\n",
  1017 + cmdname);
  1018 + goto fail;
382 } 1019 }
383 - term_printf("\n");  
384 -#endif  
385 - if (argc <= 0)  
386 - return;  
387 - for(cmd = term_cmds; cmd->name != NULL; cmd++) {  
388 - if (compare_cmd(args[0], cmd->name))  
389 - goto found; 1020 +
  1021 + switch(nb_args) {
  1022 + case 0:
  1023 + cmd->handler();
  1024 + break;
  1025 + case 1:
  1026 + cmd->handler(args[0]);
  1027 + break;
  1028 + case 2:
  1029 + cmd->handler(args[0], args[1]);
  1030 + break;
  1031 + case 3:
  1032 + cmd->handler(args[0], args[1], args[2]);
  1033 + break;
  1034 + case 4:
  1035 + cmd->handler(args[0], args[1], args[2], args[3]);
  1036 + break;
  1037 + case 5:
  1038 + cmd->handler(args[0], args[1], args[2], args[3], args[4]);
  1039 + break;
  1040 + default:
  1041 + term_printf("unsupported number of arguments: %d\n", nb_args);
  1042 + goto fail;
390 } 1043 }
391 - term_printf("unknown command: '%s'\n", args[0]); 1044 + fail:
  1045 + for(i = 0; i < MAX_ARGS; i++)
  1046 + qemu_free(str_allocated[i]);
392 return; 1047 return;
393 - found:  
394 - cmd->handler(argc, args);  
395 } 1048 }
396 1049
397 static void term_show_prompt(void) 1050 static void term_show_prompt(void)