]> Git Repo - qemu.git/blob - monitor.c
improved monitor: type check, expression evaluator, memory dump, disassembly
[qemu.git] / monitor.c
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  */
24 #include "vl.h"
25 #include "disas.h"
26
27 //#define DEBUG
28
29 #ifndef offsetof
30 #define offsetof(type, field) ((size_t) &((type *)0)->field)
31 #endif
32
33 #define TERM_CMD_BUF_SIZE 4095
34
35 #define IS_NORM 0
36 #define IS_ESC  1
37 #define IS_CSI  2
38
39 #define printf do_not_use_printf
40
41 static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
42 static int term_cmd_buf_index;
43 static int term_cmd_buf_size;
44 static int term_esc_state;
45 static int term_esc_param;
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
59 typedef struct term_cmd_t {
60     const char *name;
61     const char *args_type;
62     void (*handler)();
63     const char *params;
64     const char *help;
65 } term_cmd_t;
66
67 static term_cmd_t term_cmds[];
68 static term_cmd_t info_cmds[];
69
70 void term_printf(const char *fmt, ...)
71 {
72     va_list ap;
73     va_start(ap, fmt);
74     vprintf(fmt, ap);
75     va_end(ap);
76 }
77
78 void term_flush(void)
79 {
80     fflush(stdout);
81 }
82
83 static int compare_cmd(const char *name, const char *list)
84 {
85     const char *p, *pstart;
86     int len;
87     len = strlen(name);
88     p = list;
89     for(;;) {
90         pstart = p;
91         p = strchr(p, '|');
92         if (!p)
93             p = pstart + strlen(pstart);
94         if ((p - pstart) == len && !memcmp(pstart, name, len))
95             return 1;
96         if (*p == '\0')
97             break;
98         p++;
99     }
100     return 0;
101 }
102
103 static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
104 {
105     term_cmd_t *cmd;
106
107     for(cmd = cmds; cmd->name != NULL; cmd++) {
108         if (!name || !strcmp(name, cmd->name))
109             term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
110     }
111 }
112
113 static void help_cmd(const char *name)
114 {
115     if (name && !strcmp(name, "info")) {
116         help_cmd1(info_cmds, "info ", NULL);
117     } else {
118         help_cmd1(term_cmds, "", name);
119         if (name && !strcmp(name, "log")) {
120             CPULogItem *item;
121             term_printf("Log items (comma separated):\n");
122             term_printf("%-10s %s\n", "none", "remove all logs");
123             for(item = cpu_log_items; item->mask != 0; item++) {
124                 term_printf("%-10s %s\n", item->name, item->help);
125             }
126         }
127     }
128 }
129
130 static void do_help(const char *name)
131 {
132     help_cmd(name);
133 }
134
135 static void do_commit(void)
136 {
137     int i;
138
139     for (i = 0; i < MAX_DISKS; i++) {
140         if (bs_table[i])
141             bdrv_commit(bs_table[i]);
142     }
143 }
144
145 static void do_info(const char *item)
146 {
147     term_cmd_t *cmd;
148
149     if (!item)
150         goto help;
151     for(cmd = info_cmds; cmd->name != NULL; cmd++) {
152         if (compare_cmd(item, cmd->name)) 
153             goto found;
154     }
155  help:
156     help_cmd("info");
157     return;
158  found:
159     cmd->handler();
160 }
161
162 static void do_info_network(void)
163 {
164     int i, j;
165     NetDriverState *nd;
166     
167     for(i = 0; i < nb_nics; i++) {
168         nd = &nd_table[i];
169         term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
170         for(j = 0; j < 6; j++) {
171             if (j > 0)
172                 term_printf(":");
173             term_printf("%02x", nd->macaddr[j]);
174         }
175         term_printf("\n");
176     }
177 }
178  
179 static void do_info_block(void)
180 {
181     bdrv_info();
182 }
183
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)
194 {
195     exit(0);
196 }
197
198 static int eject_device(BlockDriverState *bs, int force)
199 {
200     if (bdrv_is_inserted(bs)) {
201         if (!force) {
202             if (!bdrv_is_removable(bs)) {
203                 term_printf("device is not removable\n");
204                 return -1;
205             }
206             if (bdrv_is_locked(bs)) {
207                 term_printf("device is locked\n");
208                 return -1;
209             }
210         }
211         bdrv_close(bs);
212     }
213     return 0;
214 }
215
216 static void do_eject(int force, const char *filename)
217 {
218     BlockDriverState *bs;
219
220     term_printf("%d %s\n", force, filename);
221
222     bs = bdrv_find(filename);
223     if (!bs) {
224         term_printf("device not found\n");
225         return;
226     }
227     eject_device(bs, force);
228 }
229
230 static void do_change(const char *device, const char *filename)
231 {
232     BlockDriverState *bs;
233
234     bs = bdrv_find(device);
235     if (!bs) {
236         term_printf("device not found\n");
237         return;
238     }
239     if (eject_device(bs, 0) < 0)
240         return;
241     bdrv_open(bs, filename, 0);
242 }
243
244 static void do_screen_dump(const char *filename)
245 {
246     vga_screen_dump(filename);
247 }
248
249 static void do_log(const char *items)
250 {
251     int mask;
252     
253     if (!strcmp(items, "none")) {
254         mask = 0;
255     } else {
256         mask = cpu_str_to_log_mask(items);
257         if (!mask) {
258             help_cmd("log");
259             return;
260         }
261     }
262     cpu_set_log(mask);
263 }
264
265 static void do_savevm(const char *filename)
266 {
267     if (qemu_savevm(filename) < 0)
268         term_printf("I/O error when saving VM to '%s'\n", filename);
269 }
270
271 static void do_loadvm(const char *filename)
272 {
273     if (qemu_loadvm(filename) < 0) 
274         term_printf("I/O error when loading VM from '%s'\n", filename);
275 }
276
277 static void do_stop(void)
278 {
279     vm_stop(EXCP_INTERRUPT);
280 }
281
282 static void do_cont(void)
283 {
284     vm_start();
285 }
286
287 #ifdef CONFIG_GDBSTUB
288 static void do_gdbserver(int has_port, int port)
289 {
290     if (!has_port)
291         port = DEFAULT_GDBSTUB_PORT;
292     if (gdbserver_start(port) < 0) {
293         qemu_printf("Could not open gdbserver socket on port %d\n", port);
294     } else {
295         qemu_printf("Waiting gdb connection on port %d\n", port);
296     }
297 }
298 #endif
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
457 static term_cmd_t term_cmds[] = {
458     { "help|?", "s?", do_help, 
459       "[cmd]", "show the help" },
460     { "commit", "", do_commit, 
461       "", "commit changes to the disk images (if -snapshot is used)" },
462     { "info", "s?", do_info,
463       "subcommand", "show various information about the system state" },
464     { "q|quit", "", do_quit,
465       "", "quit the emulator" },
466     { "eject", "-fs", do_eject,
467       "[-f] device", "eject a removable media (use -f to force it)" },
468     { "change", "sF", do_change,
469       "device filename", "change a removable media" },
470     { "screendump", "F", do_screen_dump, 
471       "filename", "save screen into PPM image 'filename'" },
472     { "log", "s", do_log,
473       "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, 
474     { "savevm", "F", do_savevm,
475       "filename", "save the whole virtual machine state to 'filename'" }, 
476     { "loadvm", "F", do_loadvm,
477       "filename", "restore the whole virtual machine state from 'filename'" }, 
478     { "stop", "", do_stop, 
479       "", "stop emulation", },
480     { "c|cont", "", do_cont, 
481       "", "resume emulation", },
482 #ifdef CONFIG_GDBSTUB
483     { "gdbserver", "i?", do_gdbserver, 
484       "[port]", "start gdbserver session (default port=1234)", },
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)", },
492     { NULL, NULL, }, 
493 };
494
495 static term_cmd_t info_cmds[] = {
496     { "network", "", do_info_network,
497       "", "show the network state" },
498     { "block", "", do_info_block,
499       "", "show the block devices" },
500     { "registers", "", do_info_registers,
501       "", "show the cpu registers" },
502     { NULL, NULL, },
503 };
504
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)
689 {
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;
795     term_cmd_t *cmd;
796     char cmdname[256];
797     char buf[1024];
798     void *str_allocated[MAX_ARGS];
799     void *args[MAX_ARGS];
800
801 #ifdef DEBUG
802     term_printf("command='%s'\n", cmdline);
803 #endif
804     
805     /* extract the command name */
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;
836     for(;;) {
837         c = *typestr;
838         if (c == '\0')
839             break;
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             }
877             break;
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             }
979             break;
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         }
1011     }
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;
1019     }
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;
1043     }
1044  fail:
1045     for(i = 0; i < MAX_ARGS; i++)
1046         qemu_free(str_allocated[i]);
1047     return;
1048 }
1049
1050 static void term_show_prompt(void)
1051 {
1052     term_printf("(qemu) ");
1053     fflush(stdout);
1054     term_cmd_buf_index = 0;
1055     term_cmd_buf_size = 0;
1056     term_esc_state = IS_NORM;
1057 }
1058
1059 static void term_insert_char(int ch)
1060 {
1061     if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
1062         memmove(term_cmd_buf + term_cmd_buf_index + 1,
1063                 term_cmd_buf + term_cmd_buf_index,
1064                 term_cmd_buf_size - term_cmd_buf_index);
1065         term_cmd_buf[term_cmd_buf_index] = ch;
1066         term_cmd_buf_size++;
1067         term_printf("\033[@%c", ch);
1068         term_cmd_buf_index++;
1069         term_flush();
1070     }
1071 }
1072
1073 static void term_backward_char(void)
1074 {
1075     if (term_cmd_buf_index > 0) {
1076         term_cmd_buf_index--;
1077         term_printf("\033[D");
1078         term_flush();
1079     }
1080 }
1081
1082 static void term_forward_char(void)
1083 {
1084     if (term_cmd_buf_index < term_cmd_buf_size) {
1085         term_cmd_buf_index++;
1086         term_printf("\033[C");
1087         term_flush();
1088     }
1089 }
1090
1091 static void term_delete_char(void)
1092 {
1093     if (term_cmd_buf_index < term_cmd_buf_size) {
1094         memmove(term_cmd_buf + term_cmd_buf_index,
1095                 term_cmd_buf + term_cmd_buf_index + 1,
1096                 term_cmd_buf_size - term_cmd_buf_index - 1);
1097         term_printf("\033[P");
1098         term_cmd_buf_size--;
1099         term_flush();
1100     }
1101 }
1102
1103 static void term_backspace(void)
1104 {
1105     if (term_cmd_buf_index > 0) {
1106         term_backward_char();
1107         term_delete_char();
1108     }
1109 }
1110
1111 static void term_bol(void)
1112 {
1113     while (term_cmd_buf_index > 0)
1114         term_backward_char();
1115 }
1116
1117 static void term_eol(void)
1118 {
1119     while (term_cmd_buf_index < term_cmd_buf_size)
1120         term_forward_char();
1121 }
1122
1123 /* return true if command handled */
1124 static void term_handle_byte(int ch)
1125 {
1126     switch(term_esc_state) {
1127     case IS_NORM:
1128         switch(ch) {
1129         case 1:
1130             term_bol();
1131             break;
1132         case 5:
1133             term_eol();
1134             break;
1135         case 10:
1136         case 13:
1137             term_cmd_buf[term_cmd_buf_size] = '\0';
1138             term_printf("\n");
1139             term_handle_command(term_cmd_buf);
1140             term_show_prompt();
1141             break;
1142         case 27:
1143             term_esc_state = IS_ESC;
1144             break;
1145         case 127:
1146         case 8:
1147             term_backspace();
1148             break;
1149         default:
1150             if (ch >= 32) {
1151                 term_insert_char(ch);
1152             }
1153             break;
1154         }
1155         break;
1156     case IS_ESC:
1157         if (ch == '[') {
1158             term_esc_state = IS_CSI;
1159             term_esc_param = 0;
1160         } else {
1161             term_esc_state = IS_NORM;
1162         }
1163         break;
1164     case IS_CSI:
1165         switch(ch) {
1166         case 'D':
1167             term_backward_char();
1168             break;
1169         case 'C':
1170             term_forward_char();
1171             break;
1172         case '0' ... '9':
1173             term_esc_param = term_esc_param * 10 + (ch - '0');
1174             goto the_end;
1175         case '~':
1176             switch(term_esc_param) {
1177             case 1:
1178                 term_bol();
1179                 break;
1180             case 3:
1181                 term_delete_char();
1182                 break;
1183             case 4:
1184                 term_eol();
1185                 break;
1186             }
1187             break;
1188         default:
1189             break;
1190         }
1191         term_esc_state = IS_NORM;
1192     the_end:
1193         break;
1194     }
1195 }
1196
1197 /*************************************************************/
1198 /* serial console support */
1199
1200 #define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
1201
1202 static int term_got_escape, term_command;
1203
1204 void term_print_help(void)
1205 {
1206     term_printf("\n"
1207                 "C-a h    print this help\n"
1208                 "C-a x    exit emulatior\n"
1209                 "C-a s    save disk data back to file (if -snapshot)\n"
1210                 "C-a b    send break (magic sysrq)\n"
1211                 "C-a c    switch between console and monitor\n"
1212                 "C-a C-a  send C-a\n"
1213                 );
1214 }
1215
1216 /* called when a char is received */
1217 static void term_received_byte(int ch)
1218 {
1219     if (!serial_console) {
1220         /* if no serial console, handle every command */
1221         term_handle_byte(ch);
1222     } else {
1223         if (term_got_escape) {
1224             term_got_escape = 0;
1225             switch(ch) {
1226             case 'h':
1227                 term_print_help();
1228                 break;
1229             case 'x':
1230                 exit(0);
1231                 break;
1232             case 's': 
1233                 {
1234                     int i;
1235                     for (i = 0; i < MAX_DISKS; i++) {
1236                         if (bs_table[i])
1237                             bdrv_commit(bs_table[i]);
1238                     }
1239                 }
1240                 break;
1241             case 'b':
1242                 if (serial_console)
1243                     serial_receive_break(serial_console);
1244                 break;
1245             case 'c':
1246                 if (!term_command) {
1247                     term_show_prompt();
1248                     term_command = 1;
1249                 } else {
1250                     term_command = 0;
1251                 }
1252                 break;
1253             case TERM_ESCAPE:
1254                 goto send_char;
1255             }
1256         } else if (ch == TERM_ESCAPE) {
1257             term_got_escape = 1;
1258         } else {
1259         send_char:
1260             if (term_command) {
1261                 term_handle_byte(ch);
1262             } else {
1263                 if (serial_console)
1264                     serial_receive_byte(serial_console, ch);
1265             }
1266         }
1267     }
1268 }
1269
1270 static int term_can_read(void *opaque)
1271 {
1272     if (serial_console) {
1273         return serial_can_receive(serial_console);
1274     } else {
1275         return 128;
1276     }
1277 }
1278
1279 static void term_read(void *opaque, const uint8_t *buf, int size)
1280 {
1281     int i;
1282     for(i = 0; i < size; i++)
1283         term_received_byte(buf[i]);
1284 }
1285
1286 void monitor_init(void)
1287 {
1288     if (!serial_console) {
1289         term_printf("QEMU %s monitor - type 'help' for more information\n",
1290                     QEMU_VERSION);
1291         term_show_prompt();
1292     }
1293     qemu_add_fd_read_handler(0, term_can_read, term_read, NULL);
1294 }
This page took 0.094632 seconds and 4 git commands to generate.