qemu/qemu-log.c
<<
>>
Prefs
   1/*
   2 * Logging support
   3 *
   4 *  Copyright (c) 2003 Fabrice Bellard
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 */
  19
  20#include "qemu-common.h"
  21#include "qemu/log.h"
  22
  23#ifdef WIN32
  24#define DEFAULT_LOGFILENAME "qemu.log"
  25#else
  26#define DEFAULT_LOGFILENAME "/tmp/qemu.log"
  27#endif
  28
  29static char *logfilename;
  30FILE *qemu_logfile;
  31int qemu_loglevel;
  32static int log_append = 0;
  33
  34void qemu_log(const char *fmt, ...)
  35{
  36    va_list ap;
  37
  38    va_start(ap, fmt);
  39    if (qemu_logfile) {
  40        vfprintf(qemu_logfile, fmt, ap);
  41    }
  42    va_end(ap);
  43}
  44
  45void qemu_log_mask(int mask, const char *fmt, ...)
  46{
  47    va_list ap;
  48
  49    va_start(ap, fmt);
  50    if ((qemu_loglevel & mask) && qemu_logfile) {
  51        vfprintf(qemu_logfile, fmt, ap);
  52    }
  53    va_end(ap);
  54}
  55
  56/* enable or disable low levels log */
  57void qemu_set_log(int log_flags, bool use_own_buffers)
  58{
  59    const char *fname = logfilename ?: DEFAULT_LOGFILENAME;
  60
  61    qemu_loglevel = log_flags;
  62    if (qemu_loglevel && !qemu_logfile) {
  63        qemu_logfile = fopen(fname, log_append ? "a" : "w");
  64        if (!qemu_logfile) {
  65            perror(fname);
  66            _exit(1);
  67        }
  68        /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
  69        if (use_own_buffers) {
  70            static char logfile_buf[4096];
  71
  72            setvbuf(qemu_logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
  73        } else {
  74#if defined(_WIN32)
  75            /* Win32 doesn't support line-buffering, so use unbuffered output. */
  76            setvbuf(qemu_logfile, NULL, _IONBF, 0);
  77#else
  78            setvbuf(qemu_logfile, NULL, _IOLBF, 0);
  79#endif
  80            log_append = 1;
  81        }
  82    }
  83    if (!qemu_loglevel && qemu_logfile) {
  84        fclose(qemu_logfile);
  85        qemu_logfile = NULL;
  86    }
  87}
  88
  89void cpu_set_log_filename(const char *filename)
  90{
  91    g_free(logfilename);
  92    logfilename = g_strdup(filename);
  93    if (qemu_logfile) {
  94        fclose(qemu_logfile);
  95        qemu_logfile = NULL;
  96    }
  97    cpu_set_log(qemu_loglevel);
  98}
  99
 100const CPULogItem cpu_log_items[] = {
 101    { CPU_LOG_TB_OUT_ASM, "out_asm",
 102      "show generated host assembly code for each compiled TB" },
 103    { CPU_LOG_TB_IN_ASM, "in_asm",
 104      "show target assembly code for each compiled TB" },
 105    { CPU_LOG_TB_OP, "op",
 106      "show micro ops for each compiled TB" },
 107    { CPU_LOG_TB_OP_OPT, "op_opt",
 108      "show micro ops (x86 only: before eflags optimization) and\n"
 109      "after liveness analysis" },
 110    { CPU_LOG_INT, "int",
 111      "show interrupts/exceptions in short format" },
 112    { CPU_LOG_EXEC, "exec",
 113      "show trace before each executed TB (lots of logs)" },
 114    { CPU_LOG_TB_CPU, "cpu",
 115      "show CPU state before block translation" },
 116    { CPU_LOG_PCALL, "pcall",
 117      "x86 only: show protected mode far calls/returns/exceptions" },
 118    { CPU_LOG_RESET, "cpu_reset",
 119      "x86 only: show CPU state before CPU resets" },
 120    { CPU_LOG_IOPORT, "ioport",
 121      "show all i/o ports accesses" },
 122    { LOG_UNIMP, "unimp",
 123      "log unimplemented functionality" },
 124    { LOG_GUEST_ERROR, "guest_errors",
 125      "log when the guest OS does something invalid (eg accessing a\n"
 126      "non-existent register)" },
 127    { 0, NULL, NULL },
 128};
 129
 130static int cmp1(const char *s1, int n, const char *s2)
 131{
 132    if (strlen(s2) != n) {
 133        return 0;
 134    }
 135    return memcmp(s1, s2, n) == 0;
 136}
 137
 138/* takes a comma separated list of log masks. Return 0 if error. */
 139int cpu_str_to_log_mask(const char *str)
 140{
 141    const CPULogItem *item;
 142    int mask;
 143    const char *p, *p1;
 144
 145    p = str;
 146    mask = 0;
 147    for (;;) {
 148        p1 = strchr(p, ',');
 149        if (!p1) {
 150            p1 = p + strlen(p);
 151        }
 152        if (cmp1(p,p1-p,"all")) {
 153            for (item = cpu_log_items; item->mask != 0; item++) {
 154                mask |= item->mask;
 155            }
 156        } else {
 157            for (item = cpu_log_items; item->mask != 0; item++) {
 158                if (cmp1(p, p1 - p, item->name)) {
 159                    goto found;
 160                }
 161            }
 162            return 0;
 163        }
 164    found:
 165        mask |= item->mask;
 166        if (*p1 != ',') {
 167            break;
 168        }
 169        p = p1 + 1;
 170    }
 171    return mask;
 172}
 173