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 #ifdef CONFIG_TRACE_LOG 55 qemu_loglevel |= LOG_TRACE; 56 #endif 57 if (qemu_loglevel && !qemu_logfile) { 58 if (logfilename) { 59 qemu_logfile = fopen(logfilename, log_append ? "a" : "w"); 60 if (!qemu_logfile) { 61 perror(logfilename); 62 _exit(1); 63 } 64 } else { 65 /* Default to stderr if no log file specified */ 66 qemu_logfile = stderr; 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 qemu_log_close(); 85 } 86 } 87 88 void qemu_set_log_filename(const char *filename) 89 { 90 g_free(logfilename); 91 logfilename = g_strdup(filename); 92 qemu_log_close(); 93 qemu_set_log(qemu_loglevel); 94 } 95 96 const QEMULogItem qemu_log_items[] = { 97 { CPU_LOG_TB_OUT_ASM, "out_asm", 98 "show generated host assembly code for each compiled TB" }, 99 { CPU_LOG_TB_IN_ASM, "in_asm", 100 "show target assembly code for each compiled TB" }, 101 { CPU_LOG_TB_OP, "op", 102 "show micro ops for each compiled TB" }, 103 { CPU_LOG_TB_OP_OPT, "op_opt", 104 "show micro ops (x86 only: before eflags optimization) and\n" 105 "after liveness analysis" }, 106 { CPU_LOG_INT, "int", 107 "show interrupts/exceptions in short format" }, 108 { CPU_LOG_EXEC, "exec", 109 "show trace before each executed TB (lots of logs)" }, 110 { CPU_LOG_TB_CPU, "cpu", 111 "show CPU state before block translation" }, 112 { CPU_LOG_MMU, "mmu", 113 "log MMU-related activities" }, 114 { CPU_LOG_PCALL, "pcall", 115 "x86 only: show protected mode far calls/returns/exceptions" }, 116 { CPU_LOG_RESET, "cpu_reset", 117 "show CPU state before CPU resets" }, 118 { LOG_UNIMP, "unimp", 119 "log unimplemented functionality" }, 120 { LOG_GUEST_ERROR, "guest_errors", 121 "log when the guest OS does something invalid (eg accessing a\n" 122 "non-existent register)" }, 123 { CPU_LOG_PAGE, "page", 124 "dump pages at beginning of user mode emulation" }, 125 { CPU_LOG_TB_NOCHAIN, "nochain", 126 "do not chain compiled TBs so that \"exec\" and \"cpu\" show\n" 127 "complete traces" }, 128 { 0, NULL, NULL }, 129 }; 130 131 static int cmp1(const char *s1, int n, const char *s2) 132 { 133 if (strlen(s2) != n) { 134 return 0; 135 } 136 return memcmp(s1, s2, n) == 0; 137 } 138 139 /* takes a comma separated list of log masks. Return 0 if error. */ 140 int qemu_str_to_log_mask(const char *str) 141 { 142 const QEMULogItem *item; 143 int mask; 144 const char *p, *p1; 145 146 p = str; 147 mask = 0; 148 for (;;) { 149 p1 = strchr(p, ','); 150 if (!p1) { 151 p1 = p + strlen(p); 152 } 153 if (cmp1(p,p1-p,"all")) { 154 for (item = qemu_log_items; item->mask != 0; item++) { 155 mask |= item->mask; 156 } 157 } else { 158 for (item = qemu_log_items; item->mask != 0; item++) { 159 if (cmp1(p, p1 - p, item->name)) { 160 goto found; 161 } 162 } 163 return 0; 164 } 165 found: 166 mask |= item->mask; 167 if (*p1 != ',') { 168 break; 169 } 170 p = p1 + 1; 171 } 172 return mask; 173 } 174 175 void qemu_print_log_usage(FILE *f) 176 { 177 const QEMULogItem *item; 178 fprintf(f, "Log items (comma separated):\n"); 179 for (item = qemu_log_items; item->mask != 0; item++) { 180 fprintf(f, "%-10s %s\n", item->name, item->help); 181 } 182 } 183