📄 monitor.c
字号:
/* * QEMU monitor * * Copyright (c) 2003-2004 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"#include "disas.h"#include <dirent.h>//#define DEBUG//#define DEBUG_COMPLETION#ifndef offsetof#define offsetof(type, field) ((size_t) &((type *)0)->field)#endif/* * Supported types: * * 'F' filename * 'B' block device name * 's' string (accept optional quote) * 'i' 32 bit integer * 'l' target long (32 or 64 bit) * '/' optional gdb-like print format (like "/10x") * * '?' optional type (for 'F', 's' and 'i') * */typedef struct term_cmd_t { const char *name; const char *args_type; void (*handler)(); const char *params; const char *help;} term_cmd_t;static CharDriverState *monitor_hd;static term_cmd_t term_cmds[];static term_cmd_t info_cmds[];static char term_outbuf[1024];static int term_outbuf_index;static void monitor_start_input(void);CPUState *mon_cpu = NULL;void term_flush(void){ if (term_outbuf_index > 0) { qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index); term_outbuf_index = 0; }}/* flush at every end of line or if the buffer is full */void term_puts(const char *str){ int c; for(;;) { c = *str++; if (c == '\0') break; term_outbuf[term_outbuf_index++] = c; if (term_outbuf_index >= sizeof(term_outbuf) || c == '\n') term_flush(); }}void term_vprintf(const char *fmt, va_list ap){ char buf[4096]; vsnprintf(buf, sizeof(buf), fmt, ap); term_puts(buf);}void term_printf(const char *fmt, ...){ va_list ap; va_start(ap, fmt); term_vprintf(fmt, ap); va_end(ap);}static int monitor_fprintf(FILE *stream, const char *fmt, ...){ va_list ap; va_start(ap, fmt); term_vprintf(fmt, ap); va_end(ap); return 0;}static int compare_cmd(const char *name, const char *list){ const char *p, *pstart; int len; len = strlen(name); p = list; for(;;) { pstart = p; p = strchr(p, '|'); if (!p) p = pstart + strlen(pstart); if ((p - pstart) == len && !memcmp(pstart, name, len)) return 1; if (*p == '\0') break; p++; } return 0;}static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name){ term_cmd_t *cmd; for(cmd = cmds; cmd->name != NULL; cmd++) { if (!name || !strcmp(name, cmd->name)) term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help); }}static void help_cmd(const char *name){ if (name && !strcmp(name, "info")) { help_cmd1(info_cmds, "info ", NULL); } else { help_cmd1(term_cmds, "", name); if (name && !strcmp(name, "log")) { CPULogItem *item; term_printf("Log items (comma separated):\n"); term_printf("%-10s %s\n", "none", "remove all logs"); for(item = cpu_log_items; item->mask != 0; item++) { term_printf("%-10s %s\n", item->name, item->help); } } }}static void do_help(const char *name){ help_cmd(name);}static void do_commit(void){ int i; for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { bdrv_commit(bs_table[i]); } }}static void do_info(const char *item){ term_cmd_t *cmd; if (!item) goto help; for(cmd = info_cmds; cmd->name != NULL; cmd++) { if (compare_cmd(item, cmd->name)) goto found; } help: help_cmd("info"); return; found: cmd->handler();}static void do_info_version(void){ term_printf("%s\n", QEMU_VERSION);}static void do_info_block(void){ bdrv_info();}/* get the current CPU defined by the user */int mon_set_cpu(int cpu_index){ CPUState *env; for(env = first_cpu; env != NULL; env = env->next_cpu) { if (env->cpu_index == cpu_index) { mon_cpu = env; return 0; } } return -1;}CPUState *mon_get_cpu(void){ if (!mon_cpu) { mon_set_cpu(0); } return mon_cpu;}static void do_info_registers(void){ CPUState *env; env = mon_get_cpu(); if (!env) return;#ifdef TARGET_I386 cpu_dump_state(env, NULL, monitor_fprintf, X86_DUMP_FPU);#else cpu_dump_state(env, NULL, monitor_fprintf, 0);#endif}static void do_info_cpus(void){ CPUState *env; /* just to set the default cpu if not already done */ mon_get_cpu(); for(env = first_cpu; env != NULL; env = env->next_cpu) { term_printf("%c CPU #%d:", (env == mon_cpu) ? '*' : ' ', env->cpu_index);#if defined(TARGET_I386) term_printf(" pc=0x" TARGET_FMT_lx, env->eip + env->segs[R_CS].base); if (env->hflags & HF_HALTED_MASK) term_printf(" (halted)");#elif defined(TARGET_PPC) term_printf(" nip=0x" TARGET_FMT_lx, env->nip); if (env->halted) term_printf(" (halted)");#elif defined(TARGET_SPARC) term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc); if (env->halted) term_printf(" (halted)");#endif term_printf("\n"); }}static void do_cpu_set(int index){ if (mon_set_cpu(index) < 0) term_printf("Invalid CPU index\n");}static void do_info_jit(void){ dump_exec_info(NULL, monitor_fprintf);}static void do_info_history (void){ int i; const char *str; i = 0; for(;;) { str = readline_get_history(i); if (!str) break; term_printf("%d: '%s'\n", i, str); i++; }}static void do_quit(void){ exit(0);}static int eject_device(BlockDriverState *bs, int force){ if (bdrv_is_inserted(bs)) { if (!force) { if (!bdrv_is_removable(bs)) { term_printf("device is not removable\n"); return -1; } if (bdrv_is_locked(bs)) { term_printf("device is locked\n"); return -1; } } bdrv_close(bs); } return 0;}static void do_eject(int force, const char *filename){ BlockDriverState *bs; bs = bdrv_find(filename); if (!bs) { term_printf("device not found\n"); return; } eject_device(bs, force);}static void do_change(const char *device, const char *filename){ BlockDriverState *bs; int i; char password[256]; bs = bdrv_find(device); if (!bs) { term_printf("device not found\n"); return; } if (eject_device(bs, 0) < 0) return; bdrv_open(bs, filename, 0); if (bdrv_is_encrypted(bs)) { term_printf("%s is encrypted.\n", device); for(i = 0; i < 3; i++) { monitor_readline("Password: ", 1, password, sizeof(password)); if (bdrv_set_key(bs, password) == 0) break; term_printf("invalid password\n"); } }}static void do_screen_dump(const char *filename){ vga_hw_screen_dump(filename);}static void do_log(const char *items){ int mask; if (!strcmp(items, "none")) { mask = 0; } else { mask = cpu_str_to_log_mask(items); if (!mask) { help_cmd("log"); return; } } cpu_set_log(mask);}static void do_savevm(const char *filename){ if (qemu_savevm(filename) < 0) term_printf("I/O error when saving VM to '%s'\n", filename);}static void do_loadvm(const char *filename){ if (qemu_loadvm(filename) < 0) term_printf("I/O error when loading VM from '%s'\n", filename);}static void do_stop(void){ vm_stop(EXCP_INTERRUPT);}static void do_cont(void){ vm_start();}#ifdef CONFIG_GDBSTUBstatic void do_gdbserver(int has_port, int port){ if (!has_port) port = DEFAULT_GDBSTUB_PORT; if (gdbserver_start(port) < 0) { qemu_printf("Could not open gdbserver socket on port %d\n", port); } else { qemu_printf("Waiting gdb connection on port %d\n", port); }}#endifstatic void term_printc(int c){ term_printf("'"); switch(c) { case '\'': term_printf("\\'"); break; case '\\': term_printf("\\\\"); break; case '\n': term_printf("\\n"); break; case '\r': term_printf("\\r"); break; default: if (c >= 32 && c <= 126) { term_printf("%c", c); } else { term_printf("\\x%02x", c); } break; } term_printf("'");}static void memory_dump(int count, int format, int wsize, target_ulong addr, int is_physical){ CPUState *env; int nb_per_line, l, line_size, i, max_digits, len; uint8_t buf[16]; uint64_t v; if (format == 'i') { int flags; flags = 0; env = mon_get_cpu(); if (!env && !is_physical) return;#ifdef TARGET_I386 if (wsize == 2) { flags = 1; } else if (wsize == 4) { flags = 0; } else { /* as default we use the current CS size */ flags = 0; if (env) {#ifdef TARGET_X86_64 if ((env->efer & MSR_EFER_LMA) && (env->segs[R_CS].flags & DESC_L_MASK)) flags = 2; else#endif if (!(env->segs[R_CS].flags & DESC_B_MASK)) flags = 1; } }#endif monitor_disas(env, addr, count, is_physical, flags); return; } len = wsize * count; if (wsize == 1) line_size = 8; else line_size = 16; nb_per_line = line_size / wsize; max_digits = 0; switch(format) { case 'o': max_digits = (wsize * 8 + 2) / 3; break; default: case 'x': max_digits = (wsize * 8) / 4; break; case 'u': case 'd': max_digits = (wsize * 8 * 10 + 32) / 33; break; case 'c': wsize = 1; break; } while (len > 0) { term_printf(TARGET_FMT_lx ":", addr); l = len; if (l > line_size) l = line_size; if (is_physical) { cpu_physical_memory_rw(addr, buf, l, 0); } else { env = mon_get_cpu(); if (!env) break; cpu_memory_rw_debug(env, addr, buf, l, 0); } i = 0; while (i < l) { switch(wsize) { default: case 1: v = ldub_raw(buf + i); break; case 2: v = lduw_raw(buf + i); break; case 4: v = (uint32_t)ldl_raw(buf + i); break; case 8: v = ldq_raw(buf + i); break; } term_printf(" "); switch(format) { case 'o': term_printf("%#*llo", max_digits, v); break; case 'x': term_printf("0x%0*llx", max_digits, v); break; case 'u': term_printf("%*llu", max_digits, v); break; case 'd': term_printf("%*lld", max_digits, v); break; case 'c': term_printc(v); break; } i += wsize; } term_printf("\n"); addr += l; len -= l; }}#if TARGET_LONG_BITS == 64#define GET_TLONG(h, l) (((uint64_t)(h) << 32) | (l))#else#define GET_TLONG(h, l) (l)#endifstatic void do_memory_dump(int count, int format, int size, uint32_t addrh, uint32_t addrl){ target_long addr = GET_TLONG(addrh, addrl); memory_dump(count, format, size, addr, 0);}static void do_physical_memory_dump(int count, int format, int size,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -