xref: /openbmc/qemu/util/log.c (revision b23197f9)
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/osdep.h"
21 #include "qemu-common.h"
22 #include "qemu/log.h"
23 #include "trace/control.h"
24 
25 static char *logfilename;
26 FILE *qemu_logfile;
27 int qemu_loglevel;
28 static int log_append = 0;
29 
30 void qemu_log(const char *fmt, ...)
31 {
32     va_list ap;
33 
34     va_start(ap, fmt);
35     if (qemu_logfile) {
36         vfprintf(qemu_logfile, fmt, ap);
37     }
38     va_end(ap);
39 }
40 
41 void qemu_log_mask(int mask, const char *fmt, ...)
42 {
43     va_list ap;
44 
45     va_start(ap, fmt);
46     if ((qemu_loglevel & mask) && qemu_logfile) {
47         vfprintf(qemu_logfile, fmt, ap);
48     }
49     va_end(ap);
50 }
51 
52 /* enable or disable low levels log */
53 void do_qemu_set_log(int log_flags, bool use_own_buffers)
54 {
55     qemu_loglevel = log_flags;
56 #ifdef CONFIG_TRACE_LOG
57     qemu_loglevel |= LOG_TRACE;
58 #endif
59     if ((qemu_loglevel || is_daemonized()) && !qemu_logfile) {
60         if (logfilename) {
61             qemu_logfile = fopen(logfilename, log_append ? "a" : "w");
62             if (!qemu_logfile) {
63                 perror(logfilename);
64                 _exit(1);
65             }
66             /* In case we are a daemon redirect stderr to logfile */
67             if (is_daemonized()) {
68                 dup2(fileno(qemu_logfile), STDERR_FILENO);
69                 fclose(qemu_logfile);
70                 /* This will skip closing logfile in qemu_log_close() */
71                 qemu_logfile = stderr;
72             }
73         } else {
74             /* Default to stderr if no log file specified */
75             qemu_logfile = stderr;
76         }
77         /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
78         if (use_own_buffers) {
79             static char logfile_buf[4096];
80 
81             setvbuf(qemu_logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
82         } else {
83 #if defined(_WIN32)
84             /* Win32 doesn't support line-buffering, so use unbuffered output. */
85             setvbuf(qemu_logfile, NULL, _IONBF, 0);
86 #else
87             setvbuf(qemu_logfile, NULL, _IOLBF, 0);
88 #endif
89             log_append = 1;
90         }
91     }
92     if (!qemu_loglevel && !is_daemonized() && qemu_logfile) {
93         qemu_log_close();
94     }
95 }
96 
97 void qemu_set_log_filename(const char *filename)
98 {
99     g_free(logfilename);
100     logfilename = g_strdup(filename);
101     qemu_log_close();
102     qemu_set_log(qemu_loglevel);
103 }
104 
105 const QEMULogItem qemu_log_items[] = {
106     { CPU_LOG_TB_OUT_ASM, "out_asm",
107       "show generated host assembly code for each compiled TB" },
108     { CPU_LOG_TB_IN_ASM, "in_asm",
109       "show target assembly code for each compiled TB" },
110     { CPU_LOG_TB_OP, "op",
111       "show micro ops for each compiled TB" },
112     { CPU_LOG_TB_OP_OPT, "op_opt",
113       "show micro ops (x86 only: before eflags optimization) and\n"
114       "after liveness analysis" },
115     { CPU_LOG_INT, "int",
116       "show interrupts/exceptions in short format" },
117     { CPU_LOG_EXEC, "exec",
118       "show trace before each executed TB (lots of logs)" },
119     { CPU_LOG_TB_CPU, "cpu",
120       "show CPU state before block translation" },
121     { CPU_LOG_MMU, "mmu",
122       "log MMU-related activities" },
123     { CPU_LOG_PCALL, "pcall",
124       "x86 only: show protected mode far calls/returns/exceptions" },
125     { CPU_LOG_RESET, "cpu_reset",
126       "show CPU state before CPU resets" },
127     { LOG_UNIMP, "unimp",
128       "log unimplemented functionality" },
129     { LOG_GUEST_ERROR, "guest_errors",
130       "log when the guest OS does something invalid (eg accessing a\n"
131       "non-existent register)" },
132     { CPU_LOG_PAGE, "page",
133       "dump pages at beginning of user mode emulation" },
134     { CPU_LOG_TB_NOCHAIN, "nochain",
135       "do not chain compiled TBs so that \"exec\" and \"cpu\" show\n"
136       "complete traces" },
137     { 0, NULL, NULL },
138 };
139 
140 static int cmp1(const char *s1, int n, const char *s2)
141 {
142     if (strlen(s2) != n) {
143         return 0;
144     }
145     return memcmp(s1, s2, n) == 0;
146 }
147 
148 /* takes a comma separated list of log masks. Return 0 if error. */
149 int qemu_str_to_log_mask(const char *str)
150 {
151     const QEMULogItem *item;
152     int mask;
153     const char *p, *p1;
154 
155     p = str;
156     mask = 0;
157     for (;;) {
158         p1 = strchr(p, ',');
159         if (!p1) {
160             p1 = p + strlen(p);
161         }
162         if (cmp1(p,p1-p,"all")) {
163             for (item = qemu_log_items; item->mask != 0; item++) {
164                 mask |= item->mask;
165             }
166 #ifdef CONFIG_TRACE_LOG
167         } else if (strncmp(p, "trace:", 6) == 0 && p + 6 != p1) {
168             trace_enable_events(p + 6);
169             mask |= LOG_TRACE;
170 #endif
171         } else {
172             for (item = qemu_log_items; item->mask != 0; item++) {
173                 if (cmp1(p, p1 - p, item->name)) {
174                     goto found;
175                 }
176             }
177             return 0;
178         found:
179             mask |= item->mask;
180         }
181         if (*p1 != ',') {
182             break;
183         }
184         p = p1 + 1;
185     }
186     return mask;
187 }
188 
189 void qemu_print_log_usage(FILE *f)
190 {
191     const QEMULogItem *item;
192     fprintf(f, "Log items (comma separated):\n");
193     for (item = qemu_log_items; item->mask != 0; item++) {
194         fprintf(f, "%-15s %s\n", item->name, item->help);
195     }
196 #ifdef CONFIG_TRACE_LOG
197     fprintf(f, "trace:PATTERN   enable trace events\n");
198     fprintf(f, "\nUse \"-d trace:help\" to get a list of trace events.\n\n");
199 #endif
200 }
201