]> git.proxmox.com Git - qemu.git/blame - monitor.c
fixed invalid command test
[qemu.git] / monitor.c
CommitLineData
9dc39cba
FB
1/*
2 * QEMU monitor
3 *
4 * Copyright (c) 2003-2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
9dc39cba 24#include "vl.h"
9307c4c1 25#include "disas.h"
9dc39cba
FB
26
27//#define DEBUG
28
9307c4c1
FB
29#ifndef offsetof
30#define offsetof(type, field) ((size_t) &((type *)0)->field)
31#endif
32
9dc39cba 33#define TERM_CMD_BUF_SIZE 4095
aa455485 34#define TERM_MAX_CMDS 64
9dc39cba
FB
35
36#define IS_NORM 0
37#define IS_ESC 1
38#define IS_CSI 2
39
40#define printf do_not_use_printf
41
42static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
43static int term_cmd_buf_index;
44static int term_cmd_buf_size;
45static int term_esc_state;
46static int term_esc_param;
47
aa455485
FB
48static char *term_history[TERM_MAX_CMDS];
49static int term_hist_entry;
50
9307c4c1
FB
51/*
52 * Supported types:
53 *
54 * 'F' filename
55 * 's' string (accept optional quote)
56 * 'i' integer
57 * '/' optional gdb-like print format (like "/10x")
58 *
59 * '?' optional type (for 'F', 's' and 'i')
60 *
61 */
62
9dc39cba
FB
63typedef struct term_cmd_t {
64 const char *name;
9307c4c1
FB
65 const char *args_type;
66 void (*handler)();
9dc39cba
FB
67 const char *params;
68 const char *help;
69} term_cmd_t;
70
71static term_cmd_t term_cmds[];
72static term_cmd_t info_cmds[];
73
74void term_printf(const char *fmt, ...)
75{
76 va_list ap;
77 va_start(ap, fmt);
78 vprintf(fmt, ap);
79 va_end(ap);
80}
81
82void term_flush(void)
83{
84 fflush(stdout);
85}
86
87static int compare_cmd(const char *name, const char *list)
88{
89 const char *p, *pstart;
90 int len;
91 len = strlen(name);
92 p = list;
93 for(;;) {
94 pstart = p;
95 p = strchr(p, '|');
96 if (!p)
97 p = pstart + strlen(pstart);
98 if ((p - pstart) == len && !memcmp(pstart, name, len))
99 return 1;
100 if (*p == '\0')
101 break;
102 p++;
103 }
104 return 0;
105}
106
107static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
108{
109 term_cmd_t *cmd;
110
111 for(cmd = cmds; cmd->name != NULL; cmd++) {
112 if (!name || !strcmp(name, cmd->name))
113 term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
114 }
115}
116
117static void help_cmd(const char *name)
118{
119 if (name && !strcmp(name, "info")) {
120 help_cmd1(info_cmds, "info ", NULL);
121 } else {
122 help_cmd1(term_cmds, "", name);
f193c797
FB
123 if (name && !strcmp(name, "log")) {
124 CPULogItem *item;
125 term_printf("Log items (comma separated):\n");
126 term_printf("%-10s %s\n", "none", "remove all logs");
127 for(item = cpu_log_items; item->mask != 0; item++) {
128 term_printf("%-10s %s\n", item->name, item->help);
129 }
130 }
9dc39cba
FB
131 }
132}
133
9307c4c1 134static void do_help(const char *name)
9dc39cba 135{
9307c4c1 136 help_cmd(name);
9dc39cba
FB
137}
138
9307c4c1 139static void do_commit(void)
9dc39cba
FB
140{
141 int i;
142
143 for (i = 0; i < MAX_DISKS; i++) {
144 if (bs_table[i])
145 bdrv_commit(bs_table[i]);
146 }
147}
148
9307c4c1 149static void do_info(const char *item)
9dc39cba
FB
150{
151 term_cmd_t *cmd;
9dc39cba 152
9307c4c1 153 if (!item)
9dc39cba 154 goto help;
9dc39cba 155 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
9307c4c1 156 if (compare_cmd(item, cmd->name))
9dc39cba
FB
157 goto found;
158 }
159 help:
9307c4c1 160 help_cmd("info");
9dc39cba
FB
161 return;
162 found:
9307c4c1 163 cmd->handler();
9dc39cba
FB
164}
165
9307c4c1 166static void do_info_network(void)
9dc39cba
FB
167{
168 int i, j;
169 NetDriverState *nd;
170
171 for(i = 0; i < nb_nics; i++) {
172 nd = &nd_table[i];
173 term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
174 for(j = 0; j < 6; j++) {
175 if (j > 0)
176 term_printf(":");
177 term_printf("%02x", nd->macaddr[j]);
178 }
179 term_printf("\n");
180 }
181}
182
9307c4c1 183static void do_info_block(void)
9dc39cba
FB
184{
185 bdrv_info();
186}
187
9307c4c1
FB
188static void do_info_registers(void)
189{
190#ifdef TARGET_I386
191 cpu_dump_state(cpu_single_env, stdout, X86_DUMP_FPU | X86_DUMP_CCOP);
192#else
193 cpu_dump_state(cpu_single_env, stdout, 0);
194#endif
195}
196
aa455485
FB
197static void do_info_history (void)
198{
199 int i;
200
201 for (i = 0; i < TERM_MAX_CMDS; i++) {
202 if (term_history[i] == NULL)
203 break;
204 term_printf("%d: '%s'\n", i, term_history[i]);
205 }
206}
207
9307c4c1 208static void do_quit(void)
9dc39cba
FB
209{
210 exit(0);
211}
212
213static int eject_device(BlockDriverState *bs, int force)
214{
215 if (bdrv_is_inserted(bs)) {
216 if (!force) {
217 if (!bdrv_is_removable(bs)) {
218 term_printf("device is not removable\n");
219 return -1;
220 }
221 if (bdrv_is_locked(bs)) {
222 term_printf("device is locked\n");
223 return -1;
224 }
225 }
226 bdrv_close(bs);
227 }
228 return 0;
229}
230
9307c4c1 231static void do_eject(int force, const char *filename)
9dc39cba
FB
232{
233 BlockDriverState *bs;
9dc39cba 234
9307c4c1
FB
235 term_printf("%d %s\n", force, filename);
236
237 bs = bdrv_find(filename);
9dc39cba
FB
238 if (!bs) {
239 term_printf("device not found\n");
240 return;
241 }
242 eject_device(bs, force);
243}
244
9307c4c1 245static void do_change(const char *device, const char *filename)
9dc39cba
FB
246{
247 BlockDriverState *bs;
248
9307c4c1 249 bs = bdrv_find(device);
9dc39cba
FB
250 if (!bs) {
251 term_printf("device not found\n");
252 return;
253 }
254 if (eject_device(bs, 0) < 0)
255 return;
9307c4c1 256 bdrv_open(bs, filename, 0);
9dc39cba
FB
257}
258
9307c4c1 259static void do_screen_dump(const char *filename)
59a983b9 260{
9307c4c1 261 vga_screen_dump(filename);
59a983b9
FB
262}
263
9307c4c1 264static void do_log(const char *items)
f193c797
FB
265{
266 int mask;
267
9307c4c1 268 if (!strcmp(items, "none")) {
f193c797
FB
269 mask = 0;
270 } else {
9307c4c1 271 mask = cpu_str_to_log_mask(items);
f193c797 272 if (!mask) {
9307c4c1 273 help_cmd("log");
f193c797
FB
274 return;
275 }
276 }
277 cpu_set_log(mask);
278}
279
9307c4c1 280static void do_savevm(const char *filename)
8a7ddc38 281{
9307c4c1
FB
282 if (qemu_savevm(filename) < 0)
283 term_printf("I/O error when saving VM to '%s'\n", filename);
8a7ddc38
FB
284}
285
9307c4c1 286static void do_loadvm(const char *filename)
8a7ddc38 287{
9307c4c1
FB
288 if (qemu_loadvm(filename) < 0)
289 term_printf("I/O error when loading VM from '%s'\n", filename);
8a7ddc38
FB
290}
291
9307c4c1 292static void do_stop(void)
8a7ddc38
FB
293{
294 vm_stop(EXCP_INTERRUPT);
295}
296
9307c4c1 297static void do_cont(void)
8a7ddc38
FB
298{
299 vm_start();
300}
301
67b915a5 302#ifdef CONFIG_GDBSTUB
9307c4c1 303static void do_gdbserver(int has_port, int port)
8a7ddc38 304{
9307c4c1
FB
305 if (!has_port)
306 port = DEFAULT_GDBSTUB_PORT;
8a7ddc38
FB
307 if (gdbserver_start(port) < 0) {
308 qemu_printf("Could not open gdbserver socket on port %d\n", port);
309 } else {
310 qemu_printf("Waiting gdb connection on port %d\n", port);
311 }
312}
67b915a5 313#endif
8a7ddc38 314
9307c4c1
FB
315static void term_printc(int c)
316{
317 term_printf("'");
318 switch(c) {
319 case '\'':
320 term_printf("\\'");
321 break;
322 case '\\':
323 term_printf("\\\\");
324 break;
325 case '\n':
326 term_printf("\\n");
327 break;
328 case '\r':
329 term_printf("\\r");
330 break;
331 default:
332 if (c >= 32 && c <= 126) {
333 term_printf("%c", c);
334 } else {
335 term_printf("\\x%02x", c);
336 }
337 break;
338 }
339 term_printf("'");
340}
341
342static void memory_dump(int count, int format, int wsize,
343 target_ulong addr, int is_physical)
344{
345 int nb_per_line, l, line_size, i, max_digits, len;
346 uint8_t buf[16];
347 uint64_t v;
348
349 if (format == 'i') {
350 int flags;
351 flags = 0;
352#ifdef TARGET_I386
353 /* we use the current CS size */
354 if (!(cpu_single_env->segs[R_CS].flags & DESC_B_MASK))
355 flags = 1;
356#endif
357 monitor_disas(addr, count, is_physical, flags);
358 return;
359 }
360
361 len = wsize * count;
362 if (wsize == 1)
363 line_size = 8;
364 else
365 line_size = 16;
366 nb_per_line = line_size / wsize;
367 max_digits = 0;
368
369 switch(format) {
370 case 'o':
371 max_digits = (wsize * 8 + 2) / 3;
372 break;
373 default:
374 case 'x':
375 max_digits = (wsize * 8) / 4;
376 break;
377 case 'u':
378 case 'd':
379 max_digits = (wsize * 8 * 10 + 32) / 33;
380 break;
381 case 'c':
382 wsize = 1;
383 break;
384 }
385
386 while (len > 0) {
387 term_printf("0x%08x:", addr);
388 l = len;
389 if (l > line_size)
390 l = line_size;
391 if (is_physical) {
392 cpu_physical_memory_rw(addr, buf, l, 0);
393 } else {
394 cpu_memory_rw_debug(cpu_single_env, addr, buf, l, 0);
395 }
396 i = 0;
397 while (i < l) {
398 switch(wsize) {
399 default:
400 case 1:
401 v = ldub_raw(buf + i);
402 break;
403 case 2:
404 v = lduw_raw(buf + i);
405 break;
406 case 4:
407 v = ldl_raw(buf + i);
408 break;
409 case 8:
410 v = ldq_raw(buf + i);
411 break;
412 }
413 term_printf(" ");
414 switch(format) {
415 case 'o':
416 term_printf("%#*llo", max_digits, v);
417 break;
418 case 'x':
419 term_printf("0x%0*llx", max_digits, v);
420 break;
421 case 'u':
422 term_printf("%*llu", max_digits, v);
423 break;
424 case 'd':
425 term_printf("%*lld", max_digits, v);
426 break;
427 case 'c':
428 term_printc(v);
429 break;
430 }
431 i += wsize;
432 }
433 term_printf("\n");
434 addr += l;
435 len -= l;
436 }
437}
438
439static void do_memory_dump(int count, int format, int size, int addr)
440{
441 memory_dump(count, format, size, addr, 0);
442}
443
444static void do_physical_memory_dump(int count, int format, int size, int addr)
445{
446 memory_dump(count, format, size, addr, 1);
447}
448
449static void do_print(int count, int format, int size, int val)
450{
451 switch(format) {
452 case 'o':
453 term_printf("%#o", val);
454 break;
455 case 'x':
456 term_printf("%#x", val);
457 break;
458 case 'u':
459 term_printf("%u", val);
460 break;
461 default:
462 case 'd':
463 term_printf("%d", val);
464 break;
465 case 'c':
466 term_printc(val);
467 break;
468 }
469 term_printf("\n");
470}
471
9dc39cba 472static term_cmd_t term_cmds[] = {
9307c4c1 473 { "help|?", "s?", do_help,
9dc39cba 474 "[cmd]", "show the help" },
9307c4c1 475 { "commit", "", do_commit,
9dc39cba 476 "", "commit changes to the disk images (if -snapshot is used)" },
9307c4c1 477 { "info", "s?", do_info,
9dc39cba 478 "subcommand", "show various information about the system state" },
9307c4c1 479 { "q|quit", "", do_quit,
9dc39cba 480 "", "quit the emulator" },
9307c4c1 481 { "eject", "-fs", do_eject,
9dc39cba 482 "[-f] device", "eject a removable media (use -f to force it)" },
9307c4c1 483 { "change", "sF", do_change,
9dc39cba 484 "device filename", "change a removable media" },
9307c4c1 485 { "screendump", "F", do_screen_dump,
59a983b9 486 "filename", "save screen into PPM image 'filename'" },
9307c4c1 487 { "log", "s", do_log,
f193c797 488 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
9307c4c1 489 { "savevm", "F", do_savevm,
8a7ddc38 490 "filename", "save the whole virtual machine state to 'filename'" },
9307c4c1 491 { "loadvm", "F", do_loadvm,
8a7ddc38 492 "filename", "restore the whole virtual machine state from 'filename'" },
9307c4c1
FB
493 { "stop", "", do_stop,
494 "", "stop emulation", },
495 { "c|cont", "", do_cont,
496 "", "resume emulation", },
67b915a5 497#ifdef CONFIG_GDBSTUB
9307c4c1
FB
498 { "gdbserver", "i?", do_gdbserver,
499 "[port]", "start gdbserver session (default port=1234)", },
67b915a5 500#endif
9307c4c1
FB
501 { "x", "/i", do_memory_dump,
502 "/fmt addr", "virtual memory dump starting at 'addr'", },
503 { "xp", "/i", do_physical_memory_dump,
504 "/fmt addr", "physical memory dump starting at 'addr'", },
505 { "p|print", "/i", do_print,
506 "/fmt expr", "print expression value (use $reg for CPU register access)", },
f193c797 507 { NULL, NULL, },
9dc39cba
FB
508};
509
510static term_cmd_t info_cmds[] = {
9307c4c1 511 { "network", "", do_info_network,
9dc39cba 512 "", "show the network state" },
9307c4c1 513 { "block", "", do_info_block,
9dc39cba 514 "", "show the block devices" },
9307c4c1
FB
515 { "registers", "", do_info_registers,
516 "", "show the cpu registers" },
aa455485
FB
517 { "history", "", do_info_history,
518 "", "show the command line history", },
9dc39cba
FB
519 { NULL, NULL, },
520};
521
9307c4c1
FB
522/*******************************************************************/
523
524static const char *pch;
525static jmp_buf expr_env;
526
527typedef struct MonitorDef {
528 const char *name;
529 int offset;
530 int (*get_value)(struct MonitorDef *md);
531} MonitorDef;
532
533static MonitorDef monitor_defs[] = {
534#ifdef TARGET_I386
535 { "eax", offsetof(CPUState, regs[0]) },
536 { "ecx", offsetof(CPUState, regs[1]) },
537 { "edx", offsetof(CPUState, regs[2]) },
538 { "ebx", offsetof(CPUState, regs[3]) },
539 { "esp|sp", offsetof(CPUState, regs[4]) },
540 { "ebp|fp", offsetof(CPUState, regs[5]) },
541 { "esi", offsetof(CPUState, regs[6]) },
542 { "esi", offsetof(CPUState, regs[7]) },
543 { "eflags", offsetof(CPUState, eflags) },
544 { "eip|pc", offsetof(CPUState, eip) },
545#endif
546 { NULL },
547};
548
549static void expr_error(const char *fmt)
9dc39cba 550{
9307c4c1
FB
551 term_printf(fmt);
552 term_printf("\n");
553 longjmp(expr_env, 1);
554}
555
556static int get_monitor_def(int *pval, const char *name)
557{
558 MonitorDef *md;
559 for(md = monitor_defs; md->name != NULL; md++) {
560 if (compare_cmd(name, md->name)) {
561 if (md->get_value) {
562 *pval = md->get_value(md);
563 } else {
564 *pval = *(uint32_t *)((uint8_t *)cpu_single_env + md->offset);
565 }
566 return 0;
567 }
568 }
569 return -1;
570}
571
572static void next(void)
573{
574 if (pch != '\0') {
575 pch++;
576 while (isspace(*pch))
577 pch++;
578 }
579}
580
581static int expr_sum(void);
582
583static int expr_unary(void)
584{
585 int n;
586 char *p;
587
588 switch(*pch) {
589 case '+':
590 next();
591 n = expr_unary();
592 break;
593 case '-':
594 next();
595 n = -expr_unary();
596 break;
597 case '~':
598 next();
599 n = ~expr_unary();
600 break;
601 case '(':
602 next();
603 n = expr_sum();
604 if (*pch != ')') {
605 expr_error("')' expected");
606 }
607 next();
608 break;
609 case '$':
610 {
611 char buf[128], *q;
612
613 pch++;
614 q = buf;
615 while ((*pch >= 'a' && *pch <= 'z') ||
616 (*pch >= 'A' && *pch <= 'Z') ||
617 (*pch >= '0' && *pch <= '9') ||
618 *pch == '_') {
619 if ((q - buf) < sizeof(buf) - 1)
620 *q++ = *pch;
621 pch++;
622 }
623 while (isspace(*pch))
624 pch++;
625 *q = 0;
626 if (get_monitor_def(&n, buf))
627 expr_error("unknown register");
628 }
629 break;
630 case '\0':
631 expr_error("unexpected end of expression");
632 n = 0;
633 break;
634 default:
635 n = strtoul(pch, &p, 0);
636 if (pch == p) {
637 expr_error("invalid char in expression");
638 }
639 pch = p;
640 while (isspace(*pch))
641 pch++;
642 break;
643 }
644 return n;
645}
646
647
648static int expr_prod(void)
649{
650 int val, val2, op;
651
652 val = expr_unary();
653 for(;;) {
654 op = *pch;
655 if (op != '*' && op != '/' && op != '%')
656 break;
657 next();
658 val2 = expr_unary();
659 switch(op) {
660 default:
661 case '*':
662 val *= val2;
663 break;
664 case '/':
665 case '%':
666 if (val2 == 0)
667 expr_error("divison by zero");
668 if (op == '/')
669 val /= val2;
670 else
671 val %= val2;
672 break;
673 }
674 }
675 return val;
676}
677
678static int expr_logic(void)
679{
680 int val, val2, op;
681
682 val = expr_prod();
683 for(;;) {
684 op = *pch;
685 if (op != '&' && op != '|' && op != '^')
686 break;
687 next();
688 val2 = expr_prod();
689 switch(op) {
690 default:
691 case '&':
692 val &= val2;
693 break;
694 case '|':
695 val |= val2;
696 break;
697 case '^':
698 val ^= val2;
699 break;
700 }
701 }
702 return val;
703}
704
705static int expr_sum(void)
706{
707 int val, val2, op;
708
709 val = expr_logic();
710 for(;;) {
711 op = *pch;
712 if (op != '+' && op != '-')
713 break;
714 next();
715 val2 = expr_logic();
716 if (op == '+')
717 val += val2;
718 else
719 val -= val2;
720 }
721 return val;
722}
723
724static int get_expr(int *pval, const char **pp)
725{
726 pch = *pp;
727 if (setjmp(expr_env)) {
728 *pp = pch;
729 return -1;
730 }
731 while (isspace(*pch))
732 pch++;
733 *pval = expr_sum();
734 *pp = pch;
735 return 0;
736}
737
738static int get_str(char *buf, int buf_size, const char **pp)
739{
740 const char *p;
741 char *q;
742 int c;
743
744 p = *pp;
745 while (isspace(*p))
746 p++;
747 if (*p == '\0') {
748 fail:
749 *pp = p;
750 return -1;
751 }
752 q = buf;
753 if (*p == '\"') {
754 p++;
755 while (*p != '\0' && *p != '\"') {
756 if (*p == '\\') {
757 p++;
758 c = *p++;
759 switch(c) {
760 case 'n':
761 c = '\n';
762 break;
763 case 'r':
764 c = '\r';
765 break;
766 case '\\':
767 case '\'':
768 case '\"':
769 break;
770 default:
771 qemu_printf("unsupported escape code: '\\%c'\n", c);
772 goto fail;
773 }
774 if ((q - buf) < buf_size - 1) {
775 *q++ = c;
776 }
777 } else {
778 if ((q - buf) < buf_size - 1) {
779 *q++ = *p;
780 }
781 p++;
782 }
783 }
784 if (*p != '\"') {
785 qemu_printf("untermintated string\n");
786 goto fail;
787 }
788 p++;
789 } else {
790 while (*p != '\0' && !isspace(*p)) {
791 if ((q - buf) < buf_size - 1) {
792 *q++ = *p;
793 }
794 p++;
795 }
796 *q = '\0';
797 }
798 *pp = p;
799 return 0;
800}
801
802static int default_fmt_format = 'x';
803static int default_fmt_size = 4;
804
805#define MAX_ARGS 16
806
807static void term_handle_command(const char *cmdline)
808{
809 const char *p, *pstart, *typestr;
810 char *q;
811 int c, nb_args, len, i, has_arg;
9dc39cba 812 term_cmd_t *cmd;
9307c4c1
FB
813 char cmdname[256];
814 char buf[1024];
815 void *str_allocated[MAX_ARGS];
816 void *args[MAX_ARGS];
9dc39cba
FB
817
818#ifdef DEBUG
819 term_printf("command='%s'\n", cmdline);
820#endif
821
9307c4c1 822 /* extract the command name */
9dc39cba 823 p = cmdline;
9307c4c1
FB
824 q = cmdname;
825 while (isspace(*p))
826 p++;
827 if (*p == '\0')
828 return;
829 pstart = p;
830 while (*p != '\0' && *p != '/' && !isspace(*p))
831 p++;
832 len = p - pstart;
833 if (len > sizeof(cmdname) - 1)
834 len = sizeof(cmdname) - 1;
835 memcpy(cmdname, pstart, len);
836 cmdname[len] = '\0';
837
838 /* find the command */
839 for(cmd = term_cmds; cmd->name != NULL; cmd++) {
840 if (compare_cmd(cmdname, cmd->name))
841 goto found;
842 }
843 term_printf("unknown command: '%s'\n", cmdname);
844 return;
845 found:
846
847 for(i = 0; i < MAX_ARGS; i++)
848 str_allocated[i] = NULL;
849
850 /* parse the parameters */
851 typestr = cmd->args_type;
852 nb_args = 0;
9dc39cba 853 for(;;) {
9307c4c1
FB
854 c = *typestr;
855 if (c == '\0')
9dc39cba 856 break;
9307c4c1
FB
857 typestr++;
858 switch(c) {
859 case 'F':
860 case 's':
861 {
862 int ret;
863 char *str;
864
865 while (isspace(*p))
866 p++;
867 if (*typestr == '?') {
868 typestr++;
869 if (*p == '\0') {
870 /* no optional string: NULL argument */
871 str = NULL;
872 goto add_str;
873 }
874 }
875 ret = get_str(buf, sizeof(buf), &p);
876 if (ret < 0) {
877 if (c == 'F')
878 term_printf("%s: filename expected\n", cmdname);
879 else
880 term_printf("%s: string expected\n", cmdname);
881 goto fail;
882 }
883 str = qemu_malloc(strlen(buf) + 1);
884 strcpy(str, buf);
885 str_allocated[nb_args] = str;
886 add_str:
887 if (nb_args >= MAX_ARGS) {
888 error_args:
889 term_printf("%s: too many arguments\n", cmdname);
890 goto fail;
891 }
892 args[nb_args++] = str;
893 }
9dc39cba 894 break;
9307c4c1
FB
895 case '/':
896 {
897 int count, format, size;
898
899 while (isspace(*p))
900 p++;
901 if (*p == '/') {
902 /* format found */
903 p++;
904 count = 1;
905 if (isdigit(*p)) {
906 count = 0;
907 while (isdigit(*p)) {
908 count = count * 10 + (*p - '0');
909 p++;
910 }
911 }
912 size = -1;
913 format = -1;
914 for(;;) {
915 switch(*p) {
916 case 'o':
917 case 'd':
918 case 'u':
919 case 'x':
920 case 'i':
921 case 'c':
922 format = *p++;
923 break;
924 case 'b':
925 size = 1;
926 p++;
927 break;
928 case 'h':
929 size = 2;
930 p++;
931 break;
932 case 'w':
933 size = 4;
934 p++;
935 break;
936 case 'g':
937 case 'L':
938 size = 8;
939 p++;
940 break;
941 default:
942 goto next;
943 }
944 }
945 next:
946 if (*p != '\0' && !isspace(*p)) {
947 term_printf("invalid char in format: '%c'\n", *p);
948 goto fail;
949 }
950 if (size < 0)
951 size = default_fmt_size;
952 if (format < 0)
953 format = default_fmt_format;
954 default_fmt_size = size;
955 default_fmt_format = format;
956 } else {
957 count = 1;
958 format = default_fmt_format;
959 size = default_fmt_size;
960 }
961 if (nb_args + 3 > MAX_ARGS)
962 goto error_args;
963 args[nb_args++] = (void*)count;
964 args[nb_args++] = (void*)format;
965 args[nb_args++] = (void*)size;
966 }
9dc39cba 967 break;
9307c4c1
FB
968 case 'i':
969 {
970 int val;
971 while (isspace(*p))
972 p++;
973 if (*typestr == '?') {
974 typestr++;
975 if (*p == '\0')
976 has_arg = 0;
977 else
978 has_arg = 1;
979 if (nb_args >= MAX_ARGS)
980 goto error_args;
981 args[nb_args++] = (void *)has_arg;
982 if (!has_arg) {
983 if (nb_args >= MAX_ARGS)
984 goto error_args;
985 val = -1;
986 goto add_num;
987 }
988 }
989 if (get_expr(&val, &p))
990 goto fail;
991 add_num:
992 if (nb_args >= MAX_ARGS)
993 goto error_args;
994 args[nb_args++] = (void *)val;
995 }
996 break;
997 case '-':
998 {
999 int has_option;
1000 /* option */
1001
1002 c = *typestr++;
1003 if (c == '\0')
1004 goto bad_type;
1005 while (isspace(*p))
1006 p++;
1007 has_option = 0;
1008 if (*p == '-') {
1009 p++;
1010 if (*p != c) {
1011 term_printf("%s: unsupported option -%c\n",
1012 cmdname, *p);
1013 goto fail;
1014 }
1015 p++;
1016 has_option = 1;
1017 }
1018 if (nb_args >= MAX_ARGS)
1019 goto error_args;
1020 args[nb_args++] = (void *)has_option;
1021 }
1022 break;
1023 default:
1024 bad_type:
1025 term_printf("%s: unknown type '%c'\n", cmdname, c);
1026 goto fail;
1027 }
9dc39cba 1028 }
9307c4c1
FB
1029 /* check that all arguments were parsed */
1030 while (isspace(*p))
1031 p++;
1032 if (*p != '\0') {
1033 term_printf("%s: extraneous characters at the end of line\n",
1034 cmdname);
1035 goto fail;
9dc39cba 1036 }
9307c4c1
FB
1037
1038 switch(nb_args) {
1039 case 0:
1040 cmd->handler();
1041 break;
1042 case 1:
1043 cmd->handler(args[0]);
1044 break;
1045 case 2:
1046 cmd->handler(args[0], args[1]);
1047 break;
1048 case 3:
1049 cmd->handler(args[0], args[1], args[2]);
1050 break;
1051 case 4:
1052 cmd->handler(args[0], args[1], args[2], args[3]);
1053 break;
1054 case 5:
1055 cmd->handler(args[0], args[1], args[2], args[3], args[4]);
1056 break;
1057 default:
1058 term_printf("unsupported number of arguments: %d\n", nb_args);
1059 goto fail;
9dc39cba 1060 }
9307c4c1
FB
1061 fail:
1062 for(i = 0; i < MAX_ARGS; i++)
1063 qemu_free(str_allocated[i]);
9dc39cba 1064 return;
9dc39cba
FB
1065}
1066
1067static void term_show_prompt(void)
1068{
1069 term_printf("(qemu) ");
1070 fflush(stdout);
1071 term_cmd_buf_index = 0;
1072 term_cmd_buf_size = 0;
1073 term_esc_state = IS_NORM;
1074}
1075
aa455485
FB
1076static void term_print_cmdline (const char *cmdline)
1077{
1078 term_show_prompt();
1079 term_printf(cmdline);
1080 term_flush();
1081}
1082
9dc39cba
FB
1083static void term_insert_char(int ch)
1084{
1085 if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
1086 memmove(term_cmd_buf + term_cmd_buf_index + 1,
1087 term_cmd_buf + term_cmd_buf_index,
1088 term_cmd_buf_size - term_cmd_buf_index);
1089 term_cmd_buf[term_cmd_buf_index] = ch;
1090 term_cmd_buf_size++;
1091 term_printf("\033[@%c", ch);
1092 term_cmd_buf_index++;
1093 term_flush();
1094 }
1095}
1096
1097static void term_backward_char(void)
1098{
1099 if (term_cmd_buf_index > 0) {
1100 term_cmd_buf_index--;
1101 term_printf("\033[D");
1102 term_flush();
1103 }
1104}
1105
1106static void term_forward_char(void)
1107{
1108 if (term_cmd_buf_index < term_cmd_buf_size) {
1109 term_cmd_buf_index++;
1110 term_printf("\033[C");
1111 term_flush();
1112 }
1113}
1114
1115static void term_delete_char(void)
1116{
1117 if (term_cmd_buf_index < term_cmd_buf_size) {
1118 memmove(term_cmd_buf + term_cmd_buf_index,
1119 term_cmd_buf + term_cmd_buf_index + 1,
1120 term_cmd_buf_size - term_cmd_buf_index - 1);
1121 term_printf("\033[P");
1122 term_cmd_buf_size--;
1123 term_flush();
1124 }
1125}
1126
1127static void term_backspace(void)
1128{
1129 if (term_cmd_buf_index > 0) {
1130 term_backward_char();
1131 term_delete_char();
1132 }
1133}
1134
1135static void term_bol(void)
1136{
1137 while (term_cmd_buf_index > 0)
1138 term_backward_char();
1139}
1140
1141static void term_eol(void)
1142{
1143 while (term_cmd_buf_index < term_cmd_buf_size)
1144 term_forward_char();
1145}
1146
aa455485
FB
1147static void term_up_char(void)
1148{
1149 int idx;
1150
1151 if (term_hist_entry == 0)
1152 return;
1153 if (term_hist_entry == -1) {
1154 /* Find latest entry */
1155 for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
1156 if (term_history[idx] == NULL)
1157 break;
1158 }
1159 term_hist_entry = idx;
1160 }
1161 term_hist_entry--;
1162 if (term_hist_entry >= 0) {
1163 strcpy(term_cmd_buf, term_history[term_hist_entry]);
1164 term_printf("\n");
1165 term_print_cmdline(term_cmd_buf);
1166 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
1167 }
1168}
1169
1170static void term_down_char(void)
1171{
1172 if (term_hist_entry == TERM_MAX_CMDS - 1 || term_hist_entry == -1)
1173 return;
1174 if (term_history[++term_hist_entry] != NULL) {
1175 strcpy(term_cmd_buf, term_history[term_hist_entry]);
1176 } else {
1177 term_hist_entry = -1;
1178 }
1179 term_printf("\n");
1180 term_print_cmdline(term_cmd_buf);
1181 term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
1182}
1183
1184static void term_hist_add(const char *cmdline)
1185{
1186 char *hist_entry, *new_entry;
1187 int idx;
1188
1189 if (cmdline[0] == '\0')
1190 return;
1191 new_entry = NULL;
1192 if (term_hist_entry != -1) {
1193 /* We were editing an existing history entry: replace it */
1194 hist_entry = term_history[term_hist_entry];
1195 idx = term_hist_entry;
1196 if (strcmp(hist_entry, cmdline) == 0) {
1197 goto same_entry;
1198 }
1199 }
1200 /* Search cmdline in history buffers */
1201 for (idx = 0; idx < TERM_MAX_CMDS; idx++) {
1202 hist_entry = term_history[idx];
1203 if (hist_entry == NULL)
1204 break;
1205 if (strcmp(hist_entry, cmdline) == 0) {
1206 same_entry:
1207 new_entry = hist_entry;
1208 /* Put this entry at the end of history */
1209 memmove(&term_history[idx], &term_history[idx + 1],
1210 &term_history[TERM_MAX_CMDS] - &term_history[idx + 1]);
1211 term_history[TERM_MAX_CMDS - 1] = NULL;
1212 for (; idx < TERM_MAX_CMDS; idx++) {
1213 if (term_history[idx] == NULL)
1214 break;
1215 }
1216 break;
1217 }
1218 }
1219 if (idx == TERM_MAX_CMDS) {
1220 /* Need to get one free slot */
1221 free(term_history[0]);
1222 memcpy(term_history, &term_history[1],
1223 &term_history[TERM_MAX_CMDS] - &term_history[1]);
1224 term_history[TERM_MAX_CMDS - 1] = NULL;
1225 idx = TERM_MAX_CMDS - 1;
1226 }
1227 if (new_entry == NULL)
1228 new_entry = strdup(cmdline);
1229 term_history[idx] = new_entry;
1230 term_hist_entry = -1;
1231}
1232
9dc39cba
FB
1233/* return true if command handled */
1234static void term_handle_byte(int ch)
1235{
1236 switch(term_esc_state) {
1237 case IS_NORM:
1238 switch(ch) {
1239 case 1:
1240 term_bol();
1241 break;
1242 case 5:
1243 term_eol();
1244 break;
1245 case 10:
1246 case 13:
1247 term_cmd_buf[term_cmd_buf_size] = '\0';
aa455485 1248 term_hist_add(term_cmd_buf);
9dc39cba
FB
1249 term_printf("\n");
1250 term_handle_command(term_cmd_buf);
1251 term_show_prompt();
1252 break;
1253 case 27:
1254 term_esc_state = IS_ESC;
1255 break;
1256 case 127:
1257 case 8:
1258 term_backspace();
1259 break;
aa455485
FB
1260 case 155:
1261 term_esc_state = IS_CSI;
1262 break;
9dc39cba
FB
1263 default:
1264 if (ch >= 32) {
1265 term_insert_char(ch);
1266 }
1267 break;
1268 }
1269 break;
1270 case IS_ESC:
1271 if (ch == '[') {
1272 term_esc_state = IS_CSI;
1273 term_esc_param = 0;
1274 } else {
1275 term_esc_state = IS_NORM;
1276 }
1277 break;
1278 case IS_CSI:
1279 switch(ch) {
aa455485
FB
1280 case 'A':
1281 case 'F':
1282 term_up_char();
1283 break;
1284 case 'B':
1285 case 'E':
1286 term_down_char();
1287 break;
9dc39cba
FB
1288 case 'D':
1289 term_backward_char();
1290 break;
1291 case 'C':
1292 term_forward_char();
1293 break;
1294 case '0' ... '9':
1295 term_esc_param = term_esc_param * 10 + (ch - '0');
1296 goto the_end;
1297 case '~':
1298 switch(term_esc_param) {
1299 case 1:
1300 term_bol();
1301 break;
1302 case 3:
1303 term_delete_char();
1304 break;
1305 case 4:
1306 term_eol();
1307 break;
1308 }
1309 break;
1310 default:
1311 break;
1312 }
1313 term_esc_state = IS_NORM;
1314 the_end:
1315 break;
1316 }
1317}
1318
1319/*************************************************************/
1320/* serial console support */
1321
1322#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
1323
1324static int term_got_escape, term_command;
1325
1326void term_print_help(void)
1327{
1328 term_printf("\n"
1329 "C-a h print this help\n"
1330 "C-a x exit emulatior\n"
9dc39cba
FB
1331 "C-a s save disk data back to file (if -snapshot)\n"
1332 "C-a b send break (magic sysrq)\n"
1333 "C-a c switch between console and monitor\n"
1334 "C-a C-a send C-a\n"
1335 );
1336}
1337
1338/* called when a char is received */
1339static void term_received_byte(int ch)
1340{
1341 if (!serial_console) {
1342 /* if no serial console, handle every command */
1343 term_handle_byte(ch);
1344 } else {
1345 if (term_got_escape) {
1346 term_got_escape = 0;
1347 switch(ch) {
1348 case 'h':
1349 term_print_help();
1350 break;
1351 case 'x':
1352 exit(0);
1353 break;
1354 case 's':
1355 {
1356 int i;
1357 for (i = 0; i < MAX_DISKS; i++) {
1358 if (bs_table[i])
1359 bdrv_commit(bs_table[i]);
1360 }
1361 }
1362 break;
1363 case 'b':
1364 if (serial_console)
1365 serial_receive_break(serial_console);
1366 break;
1367 case 'c':
1368 if (!term_command) {
1369 term_show_prompt();
1370 term_command = 1;
1371 } else {
1372 term_command = 0;
1373 }
1374 break;
9dc39cba
FB
1375 case TERM_ESCAPE:
1376 goto send_char;
1377 }
1378 } else if (ch == TERM_ESCAPE) {
1379 term_got_escape = 1;
1380 } else {
1381 send_char:
1382 if (term_command) {
1383 term_handle_byte(ch);
1384 } else {
1385 if (serial_console)
1386 serial_receive_byte(serial_console, ch);
1387 }
1388 }
1389 }
1390}
1391
1392static int term_can_read(void *opaque)
1393{
1394 if (serial_console) {
1395 return serial_can_receive(serial_console);
1396 } else {
f193c797 1397 return 128;
9dc39cba
FB
1398 }
1399}
1400
1401static void term_read(void *opaque, const uint8_t *buf, int size)
1402{
1403 int i;
1404 for(i = 0; i < size; i++)
1405 term_received_byte(buf[i]);
1406}
1407
1408void monitor_init(void)
1409{
1410 if (!serial_console) {
1411 term_printf("QEMU %s monitor - type 'help' for more information\n",
1412 QEMU_VERSION);
1413 term_show_prompt();
1414 }
aa455485 1415 term_hist_entry = -1;
8a7ddc38 1416 qemu_add_fd_read_handler(0, term_can_read, term_read, NULL);
9dc39cba 1417}