1d890d50dSDenis V. Lunev /* 2d890d50dSDenis V. Lunev * Logging support 3d890d50dSDenis V. Lunev * 4d890d50dSDenis V. Lunev * Copyright (c) 2003 Fabrice Bellard 5d890d50dSDenis V. Lunev * 6d890d50dSDenis V. Lunev * This library is free software; you can redistribute it and/or 7d890d50dSDenis V. Lunev * modify it under the terms of the GNU Lesser General Public 8d890d50dSDenis V. Lunev * License as published by the Free Software Foundation; either 961f3c91aSChetan Pant * version 2.1 of the License, or (at your option) any later version. 10d890d50dSDenis V. Lunev * 11d890d50dSDenis V. Lunev * This library is distributed in the hope that it will be useful, 12d890d50dSDenis V. Lunev * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d890d50dSDenis V. Lunev * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14d890d50dSDenis V. Lunev * Lesser General Public License for more details. 15d890d50dSDenis V. Lunev * 16d890d50dSDenis V. Lunev * You should have received a copy of the GNU Lesser General Public 17d890d50dSDenis V. Lunev * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18d890d50dSDenis V. Lunev */ 19d890d50dSDenis V. Lunev 20d38ea87aSPeter Maydell #include "qemu/osdep.h" 21d890d50dSDenis V. Lunev #include "qemu/log.h" 223514552eSAlex Bennée #include "qemu/range.h" 233514552eSAlex Bennée #include "qemu/error-report.h" 24bd6fee9fSMarkus Armbruster #include "qapi/error.h" 253514552eSAlex Bennée #include "qemu/cutils.h" 26c84ea00dSPaolo Bonzini #include "trace/control.h" 27b8121fe7SRobert Foley #include "qemu/thread.h" 286e8a355dSDaniel Brodsky #include "qemu/lockable.h" 297fc493f8SRichard Henderson #include "qemu/rcu.h" 304e51069dSRichard Henderson #ifdef CONFIG_LINUX 314e51069dSRichard Henderson #include <sys/syscall.h> 324e51069dSRichard Henderson #endif 337fc493f8SRichard Henderson 347fc493f8SRichard Henderson 35d5f55fffSRichard Henderson typedef struct RCUCloseFILE { 367fc493f8SRichard Henderson struct rcu_head rcu; 377fc493f8SRichard Henderson FILE *fd; 38d5f55fffSRichard Henderson } RCUCloseFILE; 39d890d50dSDenis V. Lunev 40702979f7SRichard Henderson /* Mutex covering the other global_* variables. */ 41702979f7SRichard Henderson static QemuMutex global_mutex; 4242266464SRichard Henderson static char *global_filename; 4330f5a73aSRichard Henderson static FILE *global_file; 444e51069dSRichard Henderson static __thread FILE *thread_file; 45eff3de52SGreg Kurz static __thread Notifier qemu_log_thread_cleanup_notifier; 46702979f7SRichard Henderson 47d890d50dSDenis V. Lunev int qemu_loglevel; 484e51069dSRichard Henderson static bool log_append; 494e51069dSRichard Henderson static bool log_per_thread; 503514552eSAlex Bennée static GArray *debug_regions; 51d890d50dSDenis V. Lunev 527fc493f8SRichard Henderson /* Returns true if qemu_log() will really write somewhere. */ 537fc493f8SRichard Henderson bool qemu_log_enabled(void) 547fc493f8SRichard Henderson { 554e51069dSRichard Henderson return log_per_thread || qatomic_read(&global_file) != NULL; 567fc493f8SRichard Henderson } 577fc493f8SRichard Henderson 587fc493f8SRichard Henderson /* Returns true if qemu_log() will write somewhere other than stderr. */ 597fc493f8SRichard Henderson bool qemu_log_separate(void) 607fc493f8SRichard Henderson { 614e51069dSRichard Henderson if (log_per_thread) { 624e51069dSRichard Henderson return true; 634e51069dSRichard Henderson } else { 6430f5a73aSRichard Henderson FILE *logfile = qatomic_read(&global_file); 6530f5a73aSRichard Henderson return logfile && logfile != stderr; 667fc493f8SRichard Henderson } 674e51069dSRichard Henderson } 684e51069dSRichard Henderson 694e51069dSRichard Henderson static int log_thread_id(void) 704e51069dSRichard Henderson { 714e51069dSRichard Henderson #ifdef CONFIG_GETTID 724e51069dSRichard Henderson return gettid(); 734e51069dSRichard Henderson #elif defined(SYS_gettid) 744e51069dSRichard Henderson return syscall(SYS_gettid); 754e51069dSRichard Henderson #else 764e51069dSRichard Henderson static int counter; 774e51069dSRichard Henderson return qatomic_fetch_inc(&counter); 784e51069dSRichard Henderson #endif 794e51069dSRichard Henderson } 807fc493f8SRichard Henderson 81eff3de52SGreg Kurz static void qemu_log_thread_cleanup(Notifier *n, void *unused) 82eff3de52SGreg Kurz { 83eff3de52SGreg Kurz fclose(thread_file); 84eff3de52SGreg Kurz thread_file = NULL; 85eff3de52SGreg Kurz } 86eff3de52SGreg Kurz 87c59fe6e5SRichard Henderson /* Lock/unlock output. */ 88c59fe6e5SRichard Henderson 89c60f599bSRichard Henderson FILE *qemu_log_trylock(void) 90c59fe6e5SRichard Henderson { 9130f5a73aSRichard Henderson FILE *logfile; 92c60f599bSRichard Henderson 934e51069dSRichard Henderson logfile = thread_file; 944e51069dSRichard Henderson if (!logfile) { 954e51069dSRichard Henderson if (log_per_thread) { 964e51069dSRichard Henderson g_autofree char *filename 974e51069dSRichard Henderson = g_strdup_printf(global_filename, log_thread_id()); 984e51069dSRichard Henderson logfile = fopen(filename, "w"); 994e51069dSRichard Henderson if (!logfile) { 1004e51069dSRichard Henderson return NULL; 1014e51069dSRichard Henderson } 1024e51069dSRichard Henderson thread_file = logfile; 103eff3de52SGreg Kurz qemu_log_thread_cleanup_notifier.notify = qemu_log_thread_cleanup; 104eff3de52SGreg Kurz qemu_thread_atexit_add(&qemu_log_thread_cleanup_notifier); 1054e51069dSRichard Henderson } else { 106c59fe6e5SRichard Henderson rcu_read_lock(); 10730f5a73aSRichard Henderson /* 10830f5a73aSRichard Henderson * FIXME: typeof_strip_qual, as used by qatomic_rcu_read, 10930f5a73aSRichard Henderson * does not work with pointers to undefined structures, 11030f5a73aSRichard Henderson * such as we have with struct _IO_FILE and musl libc. 11130f5a73aSRichard Henderson * Since all we want is a read of a pointer, cast to void**, 11230f5a73aSRichard Henderson * which does work with typeof_strip_qual. 11330f5a73aSRichard Henderson */ 11430f5a73aSRichard Henderson logfile = qatomic_rcu_read((void **)&global_file); 1154e51069dSRichard Henderson if (!logfile) { 116c60f599bSRichard Henderson rcu_read_unlock(); 1174e51069dSRichard Henderson return NULL; 118c59fe6e5SRichard Henderson } 1194e51069dSRichard Henderson } 1204e51069dSRichard Henderson } 1214e51069dSRichard Henderson 1224e51069dSRichard Henderson qemu_flockfile(logfile); 12330f5a73aSRichard Henderson return logfile; 124c59fe6e5SRichard Henderson } 125c59fe6e5SRichard Henderson 12630f5a73aSRichard Henderson void qemu_log_unlock(FILE *logfile) 127c59fe6e5SRichard Henderson { 12830f5a73aSRichard Henderson if (logfile) { 12930f5a73aSRichard Henderson fflush(logfile); 13030f5a73aSRichard Henderson qemu_funlockfile(logfile); 1314e51069dSRichard Henderson if (!log_per_thread) { 132c59fe6e5SRichard Henderson rcu_read_unlock(); 133c59fe6e5SRichard Henderson } 134c60f599bSRichard Henderson } 1354e51069dSRichard Henderson } 136c59fe6e5SRichard Henderson 1373c06a417SRichard Henderson void qemu_log(const char *fmt, ...) 138d890d50dSDenis V. Lunev { 139095e9855SRichard Henderson FILE *f = qemu_log_trylock(); 140095e9855SRichard Henderson if (f) { 141bdfb460eSRichard Henderson va_list ap; 142095e9855SRichard Henderson 143bdfb460eSRichard Henderson va_start(ap, fmt); 1443c06a417SRichard Henderson vfprintf(f, fmt, ap); 145d890d50dSDenis V. Lunev va_end(ap); 146095e9855SRichard Henderson qemu_log_unlock(f); 147bdfb460eSRichard Henderson } 148bdfb460eSRichard Henderson } 149d890d50dSDenis V. Lunev 150702979f7SRichard Henderson static void __attribute__((__constructor__)) startup(void) 151b8121fe7SRobert Foley { 152702979f7SRichard Henderson qemu_mutex_init(&global_mutex); 153b8121fe7SRobert Foley } 154b8121fe7SRobert Foley 155d5f55fffSRichard Henderson static void rcu_close_file(RCUCloseFILE *r) 1567606488cSRobert Foley { 157d5f55fffSRichard Henderson fclose(r->fd); 158d5f55fffSRichard Henderson g_free(r); 1597606488cSRobert Foley } 1607606488cSRobert Foley 1614e51069dSRichard Henderson /** 1624e51069dSRichard Henderson * valid_filename_template: 163e144a605SSalvador Fandino * 1644e51069dSRichard Henderson * Validate the filename template. Require %d if per_thread, allow it 1654e51069dSRichard Henderson * otherwise; require no other % within the template. 166f6880b7fSAlex Bennée */ 1674e51069dSRichard Henderson 1684e51069dSRichard Henderson typedef enum { 1694e51069dSRichard Henderson vft_error, 1704e51069dSRichard Henderson vft_stderr, 1714e51069dSRichard Henderson vft_strdup, 1724e51069dSRichard Henderson vft_pid_printf, 1734e51069dSRichard Henderson } ValidFilenameTemplateResult; 1744e51069dSRichard Henderson 1754e51069dSRichard Henderson static ValidFilenameTemplateResult 1764e51069dSRichard Henderson valid_filename_template(const char *filename, bool per_thread, Error **errp) 1774e51069dSRichard Henderson { 178e144a605SSalvador Fandino if (filename) { 179e144a605SSalvador Fandino char *pidstr = strstr(filename, "%"); 180144539d3SRichard Henderson 181f6880b7fSAlex Bennée if (pidstr) { 182f6880b7fSAlex Bennée /* We only accept one %d, no other format strings */ 183f6880b7fSAlex Bennée if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) { 1844e51069dSRichard Henderson error_setg(errp, "Bad logfile template: %s", filename); 1854e51069dSRichard Henderson return 0; 1864e51069dSRichard Henderson } 1874e51069dSRichard Henderson return per_thread ? vft_strdup : vft_pid_printf; 1884e51069dSRichard Henderson } 1894e51069dSRichard Henderson } 1904e51069dSRichard Henderson if (per_thread) { 1914e51069dSRichard Henderson error_setg(errp, "Filename template with '%%d' required for 'tid'"); 1924e51069dSRichard Henderson return vft_error; 1934e51069dSRichard Henderson } 1944e51069dSRichard Henderson return filename ? vft_strdup : vft_stderr; 1954e51069dSRichard Henderson } 1964e51069dSRichard Henderson 1974e51069dSRichard Henderson /* enable or disable low levels log */ 1984e51069dSRichard Henderson static bool qemu_set_log_internal(const char *filename, bool changed_name, 1994e51069dSRichard Henderson int log_flags, Error **errp) 2004e51069dSRichard Henderson { 2014e51069dSRichard Henderson bool need_to_open_file; 2024e51069dSRichard Henderson bool daemonized; 2034e51069dSRichard Henderson bool per_thread; 2044e51069dSRichard Henderson FILE *logfile; 2054e51069dSRichard Henderson 2064e51069dSRichard Henderson QEMU_LOCK_GUARD(&global_mutex); 2074e51069dSRichard Henderson logfile = global_file; 2084e51069dSRichard Henderson 209*479b350eSGreg Kurz /* The per-thread flag is immutable. */ 210*479b350eSGreg Kurz if (log_per_thread) { 211*479b350eSGreg Kurz log_flags |= LOG_PER_THREAD; 212*479b350eSGreg Kurz } 213*479b350eSGreg Kurz 2144e51069dSRichard Henderson per_thread = log_flags & LOG_PER_THREAD; 2154e51069dSRichard Henderson 2164e51069dSRichard Henderson if (changed_name) { 2174e51069dSRichard Henderson char *newname = NULL; 2184e51069dSRichard Henderson 2194e51069dSRichard Henderson /* 2204e51069dSRichard Henderson * Once threads start opening their own log files, we have no 2214e51069dSRichard Henderson * easy mechanism to tell them all to close and re-open. 2224e51069dSRichard Henderson * There seems little cause to do so either -- this option 2234e51069dSRichard Henderson * will most often be used at user-only startup. 2244e51069dSRichard Henderson */ 2254e51069dSRichard Henderson if (log_per_thread) { 2264e51069dSRichard Henderson error_setg(errp, "Cannot change log filename after setting 'tid'"); 227e2c7c6a4SRichard Henderson return false; 228f6880b7fSAlex Bennée } 2294e51069dSRichard Henderson 2304e51069dSRichard Henderson switch (valid_filename_template(filename, per_thread, errp)) { 2314e51069dSRichard Henderson case vft_error: 2324e51069dSRichard Henderson return false; 2334e51069dSRichard Henderson case vft_stderr: 2344e51069dSRichard Henderson break; 2354e51069dSRichard Henderson case vft_strdup: 236144539d3SRichard Henderson newname = g_strdup(filename); 2374e51069dSRichard Henderson break; 2384e51069dSRichard Henderson case vft_pid_printf: 2394e51069dSRichard Henderson newname = g_strdup_printf(filename, getpid()); 2404e51069dSRichard Henderson break; 241e144a605SSalvador Fandino } 242e144a605SSalvador Fandino 24342266464SRichard Henderson g_free(global_filename); 24442266464SRichard Henderson global_filename = newname; 245144539d3SRichard Henderson filename = newname; 246144539d3SRichard Henderson } else { 24742266464SRichard Henderson filename = global_filename; 2484e51069dSRichard Henderson if (per_thread && 2494e51069dSRichard Henderson valid_filename_template(filename, true, errp) == vft_error) { 2504e51069dSRichard Henderson return false; 2514e51069dSRichard Henderson } 252144539d3SRichard Henderson } 253144539d3SRichard Henderson 2544e51069dSRichard Henderson /* Once the per-thread flag is set, it cannot be unset. */ 2554e51069dSRichard Henderson if (per_thread) { 2564e51069dSRichard Henderson log_per_thread = true; 2574e51069dSRichard Henderson } 2584e51069dSRichard Henderson /* The flag itself is not relevant for need_to_open_file. */ 2594e51069dSRichard Henderson log_flags &= ~LOG_PER_THREAD; 260144539d3SRichard Henderson #ifdef CONFIG_TRACE_LOG 261144539d3SRichard Henderson log_flags |= LOG_TRACE; 262144539d3SRichard Henderson #endif 263144539d3SRichard Henderson qemu_loglevel = log_flags; 264144539d3SRichard Henderson 265144539d3SRichard Henderson /* 266144539d3SRichard Henderson * In all cases we only log if qemu_loglevel is set. 267144539d3SRichard Henderson * Also: 2684e51069dSRichard Henderson * If per-thread, open the file for each thread in qemu_log_lock. 269144539d3SRichard Henderson * If not daemonized we will always log either to stderr 27042266464SRichard Henderson * or to a file (if there is a filename). 27142266464SRichard Henderson * If we are daemonized, we will only log if there is a filename. 272144539d3SRichard Henderson */ 273beab3447SRichard Henderson daemonized = is_daemonized(); 2744e51069dSRichard Henderson need_to_open_file = log_flags && !per_thread && (!daemonized || filename); 275144539d3SRichard Henderson 27692b24cb7SRichard Henderson if (logfile && (!need_to_open_file || changed_name)) { 2778ae58d60SRichard Henderson qatomic_rcu_set(&global_file, NULL); 27830f5a73aSRichard Henderson if (logfile != stderr) { 27930f5a73aSRichard Henderson RCUCloseFILE *r = g_new0(RCUCloseFILE, 1); 28030f5a73aSRichard Henderson r->fd = logfile; 28130f5a73aSRichard Henderson call_rcu(r, rcu_close_file, rcu); 28230f5a73aSRichard Henderson } 28392b24cb7SRichard Henderson logfile = NULL; 284144539d3SRichard Henderson } 28592b24cb7SRichard Henderson 286144539d3SRichard Henderson if (!logfile && need_to_open_file) { 287144539d3SRichard Henderson if (filename) { 28830f5a73aSRichard Henderson logfile = fopen(filename, log_append ? "a" : "w"); 28930f5a73aSRichard Henderson if (!logfile) { 290144539d3SRichard Henderson error_setg_errno(errp, errno, "Error opening logfile %s", 291144539d3SRichard Henderson filename); 292144539d3SRichard Henderson return false; 293144539d3SRichard Henderson } 294144539d3SRichard Henderson /* In case we are a daemon redirect stderr to logfile */ 295beab3447SRichard Henderson if (daemonized) { 29630f5a73aSRichard Henderson dup2(fileno(logfile), STDERR_FILENO); 29730f5a73aSRichard Henderson fclose(logfile); 298d5f55fffSRichard Henderson /* This will skip closing logfile in rcu_close_file. */ 29930f5a73aSRichard Henderson logfile = stderr; 300144539d3SRichard Henderson } 301144539d3SRichard Henderson } else { 302144539d3SRichard Henderson /* Default to stderr if no log file specified */ 303beab3447SRichard Henderson assert(!daemonized); 30430f5a73aSRichard Henderson logfile = stderr; 305144539d3SRichard Henderson } 306144539d3SRichard Henderson 307144539d3SRichard Henderson log_append = 1; 308144539d3SRichard Henderson 3098ae58d60SRichard Henderson qatomic_rcu_set(&global_file, logfile); 310144539d3SRichard Henderson } 311144539d3SRichard Henderson return true; 312144539d3SRichard Henderson } 313144539d3SRichard Henderson 314144539d3SRichard Henderson bool qemu_set_log(int log_flags, Error **errp) 315144539d3SRichard Henderson { 316144539d3SRichard Henderson return qemu_set_log_internal(NULL, false, log_flags, errp); 317144539d3SRichard Henderson } 318144539d3SRichard Henderson 319144539d3SRichard Henderson bool qemu_set_log_filename(const char *filename, Error **errp) 320144539d3SRichard Henderson { 321144539d3SRichard Henderson return qemu_set_log_internal(filename, true, qemu_loglevel, errp); 322144539d3SRichard Henderson } 323144539d3SRichard Henderson 324144539d3SRichard Henderson bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp) 325144539d3SRichard Henderson { 326144539d3SRichard Henderson return qemu_set_log_internal(name, true, flags, errp); 327d890d50dSDenis V. Lunev } 328d890d50dSDenis V. Lunev 3293514552eSAlex Bennée /* Returns true if addr is in our debug filter or no filter defined 3303514552eSAlex Bennée */ 3313514552eSAlex Bennée bool qemu_log_in_addr_range(uint64_t addr) 3323514552eSAlex Bennée { 3333514552eSAlex Bennée if (debug_regions) { 3343514552eSAlex Bennée int i = 0; 3353514552eSAlex Bennée for (i = 0; i < debug_regions->len; i++) { 33658e19e6eSMarkus Armbruster Range *range = &g_array_index(debug_regions, Range, i); 337a0efbf16SMarkus Armbruster if (range_contains(range, addr)) { 3383514552eSAlex Bennée return true; 3393514552eSAlex Bennée } 3403514552eSAlex Bennée } 3413514552eSAlex Bennée return false; 3423514552eSAlex Bennée } else { 3433514552eSAlex Bennée return true; 3443514552eSAlex Bennée } 3453514552eSAlex Bennée } 3463514552eSAlex Bennée 3473514552eSAlex Bennée 348bd6fee9fSMarkus Armbruster void qemu_set_dfilter_ranges(const char *filter_spec, Error **errp) 3493514552eSAlex Bennée { 3503514552eSAlex Bennée gchar **ranges = g_strsplit(filter_spec, ",", 0); 351bd6fee9fSMarkus Armbruster int i; 3522ec62faeSMarkus Armbruster 3532ec62faeSMarkus Armbruster if (debug_regions) { 3542ec62faeSMarkus Armbruster g_array_unref(debug_regions); 3552ec62faeSMarkus Armbruster debug_regions = NULL; 3562ec62faeSMarkus Armbruster } 3572ec62faeSMarkus Armbruster 3583514552eSAlex Bennée debug_regions = g_array_sized_new(FALSE, FALSE, 3593514552eSAlex Bennée sizeof(Range), g_strv_length(ranges)); 360bd6fee9fSMarkus Armbruster for (i = 0; ranges[i]; i++) { 361bd6fee9fSMarkus Armbruster const char *r = ranges[i]; 362bd6fee9fSMarkus Armbruster const char *range_op, *r2, *e; 36358e19e6eSMarkus Armbruster uint64_t r1val, r2val, lob, upb; 364bd6fee9fSMarkus Armbruster struct Range range; 365bd6fee9fSMarkus Armbruster 366bd6fee9fSMarkus Armbruster range_op = strstr(r, "-"); 367bd6fee9fSMarkus Armbruster r2 = range_op ? range_op + 1 : NULL; 3683514552eSAlex Bennée if (!range_op) { 3693514552eSAlex Bennée range_op = strstr(r, "+"); 3703514552eSAlex Bennée r2 = range_op ? range_op + 1 : NULL; 3713514552eSAlex Bennée } 3723514552eSAlex Bennée if (!range_op) { 3733514552eSAlex Bennée range_op = strstr(r, ".."); 3743514552eSAlex Bennée r2 = range_op ? range_op + 2 : NULL; 3753514552eSAlex Bennée } 376bd6fee9fSMarkus Armbruster if (!range_op) { 377bd6fee9fSMarkus Armbruster error_setg(errp, "Bad range specifier"); 378bd6fee9fSMarkus Armbruster goto out; 379bd6fee9fSMarkus Armbruster } 3803514552eSAlex Bennée 381b30d1886SMarkus Armbruster if (qemu_strtou64(r, &e, 0, &r1val) 382bd6fee9fSMarkus Armbruster || e != range_op) { 383bd6fee9fSMarkus Armbruster error_setg(errp, "Invalid number to the left of %.*s", 384bd6fee9fSMarkus Armbruster (int)(r2 - range_op), range_op); 385bd6fee9fSMarkus Armbruster goto out; 386bd6fee9fSMarkus Armbruster } 387b30d1886SMarkus Armbruster if (qemu_strtou64(r2, NULL, 0, &r2val)) { 388bd6fee9fSMarkus Armbruster error_setg(errp, "Invalid number to the right of %.*s", 389bd6fee9fSMarkus Armbruster (int)(r2 - range_op), range_op); 390bd6fee9fSMarkus Armbruster goto out; 391bd6fee9fSMarkus Armbruster } 3923514552eSAlex Bennée 3933514552eSAlex Bennée switch (*range_op) { 3943514552eSAlex Bennée case '+': 39558e19e6eSMarkus Armbruster lob = r1val; 39658e19e6eSMarkus Armbruster upb = r1val + r2val - 1; 3973514552eSAlex Bennée break; 3983514552eSAlex Bennée case '-': 39958e19e6eSMarkus Armbruster upb = r1val; 40058e19e6eSMarkus Armbruster lob = r1val - (r2val - 1); 4013514552eSAlex Bennée break; 4023514552eSAlex Bennée case '.': 40358e19e6eSMarkus Armbruster lob = r1val; 40458e19e6eSMarkus Armbruster upb = r2val; 4053514552eSAlex Bennée break; 4063514552eSAlex Bennée default: 4073514552eSAlex Bennée g_assert_not_reached(); 4083514552eSAlex Bennée } 40958eeb83cSMarkus Armbruster if (lob > upb) { 41058e19e6eSMarkus Armbruster error_setg(errp, "Invalid range"); 41158e19e6eSMarkus Armbruster goto out; 41258e19e6eSMarkus Armbruster } 413a0efbf16SMarkus Armbruster range_set_bounds(&range, lob, upb); 4143514552eSAlex Bennée g_array_append_val(debug_regions, range); 4153514552eSAlex Bennée } 416bd6fee9fSMarkus Armbruster out: 4173514552eSAlex Bennée g_strfreev(ranges); 4183514552eSAlex Bennée } 4193514552eSAlex Bennée 420d890d50dSDenis V. Lunev const QEMULogItem qemu_log_items[] = { 421d890d50dSDenis V. Lunev { CPU_LOG_TB_OUT_ASM, "out_asm", 422d890d50dSDenis V. Lunev "show generated host assembly code for each compiled TB" }, 423d890d50dSDenis V. Lunev { CPU_LOG_TB_IN_ASM, "in_asm", 424d890d50dSDenis V. Lunev "show target assembly code for each compiled TB" }, 425d890d50dSDenis V. Lunev { CPU_LOG_TB_OP, "op", 426d890d50dSDenis V. Lunev "show micro ops for each compiled TB" }, 427d890d50dSDenis V. Lunev { CPU_LOG_TB_OP_OPT, "op_opt", 4285a18407fSRichard Henderson "show micro ops after optimization" }, 4295a18407fSRichard Henderson { CPU_LOG_TB_OP_IND, "op_ind", 4305a18407fSRichard Henderson "show micro ops before indirect lowering" }, 431d890d50dSDenis V. Lunev { CPU_LOG_INT, "int", 432d890d50dSDenis V. Lunev "show interrupts/exceptions in short format" }, 433d890d50dSDenis V. Lunev { CPU_LOG_EXEC, "exec", 434d890d50dSDenis V. Lunev "show trace before each executed TB (lots of logs)" }, 435d890d50dSDenis V. Lunev { CPU_LOG_TB_CPU, "cpu", 43654195736SAlex Bennée "show CPU registers before entering a TB (lots of logs)" }, 437ae765180SPeter Maydell { CPU_LOG_TB_FPU, "fpu", 438ae765180SPeter Maydell "include FPU registers in the 'cpu' logging" }, 439d890d50dSDenis V. Lunev { CPU_LOG_MMU, "mmu", 440d890d50dSDenis V. Lunev "log MMU-related activities" }, 441d890d50dSDenis V. Lunev { CPU_LOG_PCALL, "pcall", 442d890d50dSDenis V. Lunev "x86 only: show protected mode far calls/returns/exceptions" }, 443d890d50dSDenis V. Lunev { CPU_LOG_RESET, "cpu_reset", 444d890d50dSDenis V. Lunev "show CPU state before CPU resets" }, 445d890d50dSDenis V. Lunev { LOG_UNIMP, "unimp", 446d890d50dSDenis V. Lunev "log unimplemented functionality" }, 447d890d50dSDenis V. Lunev { LOG_GUEST_ERROR, "guest_errors", 448d890d50dSDenis V. Lunev "log when the guest OS does something invalid (eg accessing a\n" 449d890d50dSDenis V. Lunev "non-existent register)" }, 450d890d50dSDenis V. Lunev { CPU_LOG_PAGE, "page", 451d890d50dSDenis V. Lunev "dump pages at beginning of user mode emulation" }, 452d890d50dSDenis V. Lunev { CPU_LOG_TB_NOCHAIN, "nochain", 453d890d50dSDenis V. Lunev "do not chain compiled TBs so that \"exec\" and \"cpu\" show\n" 454d890d50dSDenis V. Lunev "complete traces" }, 455ca76a669SAlex Bennée #ifdef CONFIG_PLUGIN 456ca76a669SAlex Bennée { CPU_LOG_PLUGIN, "plugin", "output from TCG plugins\n"}, 457ca76a669SAlex Bennée #endif 4584b25a506SJosh Kunz { LOG_STRACE, "strace", 4594b25a506SJosh Kunz "log every user-mode syscall, its input, and its result" }, 4604e51069dSRichard Henderson { LOG_PER_THREAD, "tid", 4614e51069dSRichard Henderson "open a separate log file per thread; filename must contain '%d'" }, 462d890d50dSDenis V. Lunev { 0, NULL, NULL }, 463d890d50dSDenis V. Lunev }; 464d890d50dSDenis V. Lunev 465d890d50dSDenis V. Lunev /* takes a comma separated list of log masks. Return 0 if error. */ 466d890d50dSDenis V. Lunev int qemu_str_to_log_mask(const char *str) 467d890d50dSDenis V. Lunev { 468d890d50dSDenis V. Lunev const QEMULogItem *item; 46989d0a64fSDaniel P. Berrange int mask = 0; 47089d0a64fSDaniel P. Berrange char **parts = g_strsplit(str, ",", 0); 47189d0a64fSDaniel P. Berrange char **tmp; 472d890d50dSDenis V. Lunev 47389d0a64fSDaniel P. Berrange for (tmp = parts; tmp && *tmp; tmp++) { 47489d0a64fSDaniel P. Berrange if (g_str_equal(*tmp, "all")) { 475d890d50dSDenis V. Lunev for (item = qemu_log_items; item->mask != 0; item++) { 476d890d50dSDenis V. Lunev mask |= item->mask; 477d890d50dSDenis V. Lunev } 478c84ea00dSPaolo Bonzini #ifdef CONFIG_TRACE_LOG 47989d0a64fSDaniel P. Berrange } else if (g_str_has_prefix(*tmp, "trace:") && (*tmp)[6] != '\0') { 48089d0a64fSDaniel P. Berrange trace_enable_events((*tmp) + 6); 481c84ea00dSPaolo Bonzini mask |= LOG_TRACE; 482c84ea00dSPaolo Bonzini #endif 483d890d50dSDenis V. Lunev } else { 484d890d50dSDenis V. Lunev for (item = qemu_log_items; item->mask != 0; item++) { 48589d0a64fSDaniel P. Berrange if (g_str_equal(*tmp, item->name)) { 486d890d50dSDenis V. Lunev goto found; 487d890d50dSDenis V. Lunev } 488d890d50dSDenis V. Lunev } 48989d0a64fSDaniel P. Berrange goto error; 490d890d50dSDenis V. Lunev found: 491d890d50dSDenis V. Lunev mask |= item->mask; 492c84ea00dSPaolo Bonzini } 493d890d50dSDenis V. Lunev } 49489d0a64fSDaniel P. Berrange 49589d0a64fSDaniel P. Berrange g_strfreev(parts); 496d890d50dSDenis V. Lunev return mask; 49789d0a64fSDaniel P. Berrange 49889d0a64fSDaniel P. Berrange error: 49989d0a64fSDaniel P. Berrange g_strfreev(parts); 50089d0a64fSDaniel P. Berrange return 0; 501d890d50dSDenis V. Lunev } 502d890d50dSDenis V. Lunev 503d890d50dSDenis V. Lunev void qemu_print_log_usage(FILE *f) 504d890d50dSDenis V. Lunev { 505d890d50dSDenis V. Lunev const QEMULogItem *item; 506d890d50dSDenis V. Lunev fprintf(f, "Log items (comma separated):\n"); 507d890d50dSDenis V. Lunev for (item = qemu_log_items; item->mask != 0; item++) { 508c84ea00dSPaolo Bonzini fprintf(f, "%-15s %s\n", item->name, item->help); 509d890d50dSDenis V. Lunev } 510c84ea00dSPaolo Bonzini #ifdef CONFIG_TRACE_LOG 511c84ea00dSPaolo Bonzini fprintf(f, "trace:PATTERN enable trace events\n"); 512c84ea00dSPaolo Bonzini fprintf(f, "\nUse \"-d trace:help\" to get a list of trace events.\n\n"); 513c84ea00dSPaolo Bonzini #endif 514d890d50dSDenis V. Lunev } 515