qemu-log.c 4.8 KB

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