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