Home | History | Annotate | Download | only in qemu
      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 static char *logfilename;
     24 FILE *qemu_logfile;
     25 int qemu_loglevel;
     26 static int log_append = 0;
     27 
     28 void qemu_log(const char *fmt, ...)
     29 {
     30     va_list ap;
     31 
     32     va_start(ap, fmt);
     33     if (qemu_logfile) {
     34         vfprintf(qemu_logfile, fmt, ap);
     35     }
     36     va_end(ap);
     37 }
     38 
     39 void qemu_log_mask(int mask, const char *fmt, ...)
     40 {
     41     va_list ap;
     42 
     43     va_start(ap, fmt);
     44     if ((qemu_loglevel & mask) && qemu_logfile) {
     45         vfprintf(qemu_logfile, fmt, ap);
     46     }
     47     va_end(ap);
     48 }
     49 
     50 /* enable or disable low levels log */
     51 void do_qemu_set_log(int log_flags, bool use_own_buffers)
     52 {
     53     qemu_loglevel = log_flags;
     54     if (qemu_loglevel && !qemu_logfile) {
     55         if (logfilename) {
     56             qemu_logfile = fopen(logfilename, log_append ? "a" : "w");
     57             if (!qemu_logfile) {
     58                 perror(logfilename);
     59                 _exit(1);
     60             }
     61         } else {
     62             /* Default to stderr if no log file specified */
     63             qemu_logfile = stderr;
     64         }
     65         /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
     66         if (use_own_buffers) {
     67             static char logfile_buf[4096];
     68 
     69             setvbuf(qemu_logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
     70         } else {
     71 #if defined(_WIN32)
     72             /* Win32 doesn't support line-buffering, so use unbuffered output. */
     73             setvbuf(qemu_logfile, NULL, _IONBF, 0);
     74 #else
     75             setvbuf(qemu_logfile, NULL, _IOLBF, 0);
     76 #endif
     77             log_append = 1;
     78         }
     79     }
     80     if (!qemu_loglevel && qemu_logfile) {
     81         qemu_log_close();
     82     }
     83 }
     84 
     85 void qemu_set_log_filename(const char *filename)
     86 {
     87     g_free(logfilename);
     88     logfilename = g_strdup(filename);
     89     qemu_log_close();
     90     qemu_set_log(qemu_loglevel);
     91 }
     92 
     93 const QEMULogItem qemu_log_items[] = {
     94     { CPU_LOG_TB_OUT_ASM, "out_asm",
     95       "show generated host assembly code for each compiled TB" },
     96     { CPU_LOG_TB_IN_ASM, "in_asm",
     97       "show target assembly code for each compiled TB" },
     98     { CPU_LOG_TB_OP, "op",
     99       "show micro ops for each compiled TB" },
    100     { CPU_LOG_TB_OP_OPT, "op_opt",
    101       "show micro ops (x86 only: before eflags optimization) and\n"
    102       "after liveness analysis" },
    103     { CPU_LOG_INT, "int",
    104       "show interrupts/exceptions in short format" },
    105     { CPU_LOG_EXEC, "exec",
    106       "show trace before each executed TB (lots of logs)" },
    107     { CPU_LOG_TB_CPU, "cpu",
    108       "show CPU state before block translation" },
    109     { CPU_LOG_PCALL, "pcall",
    110       "x86 only: show protected mode far calls/returns/exceptions" },
    111     { CPU_LOG_RESET, "cpu_reset",
    112       "x86 only: show CPU state before CPU resets" },
    113     { CPU_LOG_IOPORT, "ioport",
    114       "show all i/o ports accesses" },
    115     { LOG_UNIMP, "unimp",
    116       "log unimplemented functionality" },
    117     { LOG_GUEST_ERROR, "guest_errors",
    118       "log when the guest OS does something invalid (eg accessing a\n"
    119       "non-existent register)" },
    120     { 0, NULL, NULL },
    121 };
    122 
    123 static int cmp1(const char *s1, int n, const char *s2)
    124 {
    125     if (strlen(s2) != n) {
    126         return 0;
    127     }
    128     return memcmp(s1, s2, n) == 0;
    129 }
    130 
    131 /* takes a comma separated list of log masks. Return 0 if error. */
    132 int qemu_str_to_log_mask(const char *str)
    133 {
    134     const QEMULogItem *item;
    135     int mask;
    136     const char *p, *p1;
    137 
    138     p = str;
    139     mask = 0;
    140     for (;;) {
    141         p1 = strchr(p, ',');
    142         if (!p1) {
    143             p1 = p + strlen(p);
    144         }
    145         if (cmp1(p,p1-p,"all")) {
    146             for (item = qemu_log_items; item->mask != 0; item++) {
    147                 mask |= item->mask;
    148             }
    149         } else {
    150             for (item = qemu_log_items; item->mask != 0; item++) {
    151                 if (cmp1(p, p1 - p, item->name)) {
    152                     goto found;
    153                 }
    154             }
    155             return 0;
    156         }
    157     found:
    158         mask |= item->mask;
    159         if (*p1 != ',') {
    160             break;
    161         }
    162         p = p1 + 1;
    163     }
    164     return mask;
    165 }
    166 
    167 void qemu_print_log_usage(FILE *f)
    168 {
    169     const QEMULogItem *item;
    170     fprintf(f, "Log items (comma separated):\n");
    171     for (item = qemu_log_items; item->mask != 0; item++) {
    172         fprintf(f, "%-10s %s\n", item->name, item->help);
    173     }
    174 }
    175