diff options
Diffstat (limited to 'qemu-log.c')
-rw-r--r-- | qemu-log.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/qemu-log.c b/qemu-log.c new file mode 100644 index 0000000000..4d7499fdf5 --- /dev/null +++ b/qemu-log.c @@ -0,0 +1,146 @@ +/* + * Logging support + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu-common.h" +#include "qemu-log.h" + +#ifdef WIN32 +static const char *logfilename = "qemu.log"; +#else +static const char *logfilename = "/tmp/qemu.log"; +#endif +FILE *logfile; +int loglevel; +static int log_append = 0; + +/* enable or disable low levels log */ +void cpu_set_log(int log_flags) +{ + loglevel = log_flags; + if (loglevel && !logfile) { + logfile = fopen(logfilename, log_append ? "a" : "w"); + if (!logfile) { + perror(logfilename); + _exit(1); + } +#if !defined(CONFIG_SOFTMMU) + /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ + { + static char logfile_buf[4096]; + setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); + } +#elif defined(_WIN32) + /* Win32 doesn't support line-buffering, so use unbuffered output. */ + setvbuf(logfile, NULL, _IONBF, 0); +#else + setvbuf(logfile, NULL, _IOLBF, 0); +#endif + log_append = 1; + } + if (!loglevel && logfile) { + fclose(logfile); + logfile = NULL; + } +} + +void cpu_set_log_filename(const char *filename) +{ + logfilename = strdup(filename); + if (logfile) { + fclose(logfile); + logfile = NULL; + } + cpu_set_log(loglevel); +} + +const CPULogItem cpu_log_items[] = { + { CPU_LOG_TB_OUT_ASM, "out_asm", + "show generated host assembly code for each compiled TB" }, + { CPU_LOG_TB_IN_ASM, "in_asm", + "show target assembly code for each compiled TB" }, + { CPU_LOG_TB_OP, "op", + "show micro ops for each compiled TB" }, + { CPU_LOG_TB_OP_OPT, "op_opt", + "show micro ops " +#ifdef TARGET_I386 + "before eflags optimization and " +#endif + "after liveness analysis" }, + { CPU_LOG_INT, "int", + "show interrupts/exceptions in short format" }, + { CPU_LOG_EXEC, "exec", + "show trace before each executed TB (lots of logs)" }, + { CPU_LOG_TB_CPU, "cpu", + "show CPU state before block translation" }, +#ifdef TARGET_I386 + { CPU_LOG_PCALL, "pcall", + "show protected mode far calls/returns/exceptions" }, + { CPU_LOG_RESET, "cpu_reset", + "show CPU state before CPU resets" }, +#endif +#ifdef DEBUG_IOPORT + { CPU_LOG_IOPORT, "ioport", + "show all i/o ports accesses" }, +#endif + { 0, NULL, NULL }, +}; + +static int cmp1(const char *s1, int n, const char *s2) +{ + if (strlen(s2) != n) { + return 0; + } + return memcmp(s1, s2, n) == 0; +} + +/* takes a comma separated list of log masks. Return 0 if error. */ +int cpu_str_to_log_mask(const char *str) +{ + const CPULogItem *item; + int mask; + const char *p, *p1; + + p = str; + mask = 0; + for (;;) { + p1 = strchr(p, ','); + if (!p1) { + p1 = p + strlen(p); + } + if (cmp1(p,p1-p,"all")) { + for (item = cpu_log_items; item->mask != 0; item++) { + mask |= item->mask; + } + } else { + for (item = cpu_log_items; item->mask != 0; item++) { + if (cmp1(p, p1 - p, item->name)) { + goto found; + } + } + return 0; + } + found: + mask |= item->mask; + if (*p1 != ',') { + break; + } + p = p1 + 1; + } + return mask; +} |