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 1 /* General "disassemble this chunk" code. Used for debugging. */
2 2 #include "config.h"
3 3 #include "dis-asm.h"
4   -#include "disas.h"
5 4 #include "elf.h"
6 5 #include <errno.h>
7 6  
8 7 #include "cpu.h"
9 8 #include "exec-all.h"
  9 +#include "disas.h"
10 10  
11 11 /* Filled in by elfload.c. Simplistic, but will do for now. */
12 12 unsigned int disas_num_syms;
... ... @@ -219,3 +219,71 @@ const char *lookup_symbol(void *orig_addr)
219 219 }
220 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 3  
4 4 /* Disassemble this for me please... (debugging). */
5 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 8 /* Look up symbol for debugging purpose. Returns "" if unknown. */
8 9 const char *lookup_symbol(void *orig_addr);
... ...
monitor.c
... ... @@ -22,11 +22,15 @@
22 22 * THE SOFTWARE.
23 23 */
24 24 #include "vl.h"
  25 +#include "disas.h"
25 26  
26 27 //#define DEBUG
27 28  
  29 +#ifndef offsetof
  30 +#define offsetof(type, field) ((size_t) &((type *)0)->field)
  31 +#endif
  32 +
28 33 #define TERM_CMD_BUF_SIZE 4095
29   -#define MAX_ARGS 64
30 34  
31 35 #define IS_NORM 0
32 36 #define IS_ESC 1
... ... @@ -40,9 +44,22 @@ static int term_cmd_buf_size;
40 44 static int term_esc_state;
41 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 59 typedef struct term_cmd_t {
44 60 const char *name;
45   - void (*handler)(int argc, const char **argv);
  61 + const char *args_type;
  62 + void (*handler)();
46 63 const char *params;
47 64 const char *help;
48 65 } term_cmd_t;
... ... @@ -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 137 int i;
121 138  
... ... @@ -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 147 term_cmd_t *cmd;
131   - const char *item;
132 148  
133   - if (argc < 2)
  149 + if (!item)
134 150 goto help;
135   - item = argv[1];
136 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 153 goto found;
139 154 }
140 155 help:
141   - help_cmd(argv[0]);
  156 + help_cmd("info");
142 157 return;
143 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 164 int i, j;
150 165 NetDriverState *nd;
... ... @@ -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 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 195 exit(0);
172 196 }
... ... @@ -189,26 +213,13 @@ static int eject_device(BlockDriverState *bs, int force)
189 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 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 223 if (!bs) {
213 224 term_printf("device not found\n");
214 225 return;
... ... @@ -216,90 +227,68 @@ static void do_eject(int argc, const char **argv)
216 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 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 235 if (!bs) {
229 236 term_printf("device not found\n");
230 237 return;
231 238 }
232 239 if (eject_device(bs, 0) < 0)
233 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 251 int mask;
249 252  
250   - if (argc != 2)
251   - goto help;
252   - if (!strcmp(argv[1], "none")) {
  253 + if (!strcmp(items, "none")) {
253 254 mask = 0;
254 255 } else {
255   - mask = cpu_str_to_log_mask(argv[1]);
  256 + mask = cpu_str_to_log_mask(items);
256 257 if (!mask) {
257   - help:
258   - help_cmd(argv[0]);
  258 + help_cmd("log");
259 259 return;
260 260 }
261 261 }
262 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 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 284 vm_start();
293 285 }
294 286  
295 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 292 if (gdbserver_start(port) < 0) {
304 293 qemu_printf("Could not open gdbserver socket on port %d\n", port);
305 294 } else {
... ... @@ -308,90 +297,754 @@ static void do_gdbserver(int argc, const char **argv)
308 297 }
309 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 457 static term_cmd_t term_cmds[] = {
312   - { "help|?", do_help,
  458 + { "help|?", "s?", do_help,
313 459 "[cmd]", "show the help" },
314   - { "commit", do_commit,
  460 + { "commit", "", do_commit,
315 461 "", "commit changes to the disk images (if -snapshot is used)" },
316   - { "info", do_info,
  462 + { "info", "s?", do_info,
317 463 "subcommand", "show various information about the system state" },
318   - { "q|quit", do_quit,
  464 + { "q|quit", "", do_quit,
319 465 "", "quit the emulator" },
320   - { "eject", do_eject,
  466 + { "eject", "-fs", do_eject,
321 467 "[-f] device", "eject a removable media (use -f to force it)" },
322   - { "change", do_change,
  468 + { "change", "sF", do_change,
323 469 "device filename", "change a removable media" },
324   - { "screendump", do_screen_dump,
  470 + { "screendump", "F", do_screen_dump,
325 471 "filename", "save screen into PPM image 'filename'" },
326   - { "log", do_log,
  472 + { "log", "s", do_log,
327 473 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
328   - { "savevm", do_savevm,
  474 + { "savevm", "F", do_savevm,
329 475 "filename", "save the whole virtual machine state to 'filename'" },
330   - { "loadvm", do_loadvm,
  476 + { "loadvm", "F", do_loadvm,
331 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 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 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 492 { NULL, NULL, },
338 493 };
339 494  
340 495 static term_cmd_t info_cmds[] = {
341   - { "network", do_info_network,
  496 + { "network", "", do_info_network,
342 497 "", "show the network state" },
343   - { "block", do_info_block,
  498 + { "block", "", do_info_block,
344 499 "", "show the block devices" },
  500 + { "registers", "", do_info_registers,
  501 + "", "show the cpu registers" },
345 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 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 801 #ifdef DEBUG
356 802 term_printf("command='%s'\n", cmdline);
357 803 #endif
358 804  
359   - /* split command in words */
360   - argc = 0;
  805 + /* extract the command name */
361 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 836 for(;;) {
363   - while (isspace(*p))
364   - p++;
365   - if (*p == '\0')
  837 + c = *typestr;
  838 + if (c == '\0')
366 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 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 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 1047 return;
393   - found:
394   - cmd->handler(argc, args);
395 1048 }
396 1049  
397 1050 static void term_show_prompt(void)
... ...