control.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Interface for configuring and controlling the state of tracing events.
  3. *
  4. * Copyright (C) 2011-2016 Lluís Vilanova <vilanova@ac.upc.edu>
  5. *
  6. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  7. * See the COPYING file in the top-level directory.
  8. */
  9. #include "qemu/osdep.h"
  10. #include "trace/control.h"
  11. #include "qemu/help_option.h"
  12. #ifdef CONFIG_TRACE_SIMPLE
  13. #include "trace/simple.h"
  14. #endif
  15. #ifdef CONFIG_TRACE_FTRACE
  16. #include "trace/ftrace.h"
  17. #endif
  18. #ifdef CONFIG_TRACE_LOG
  19. #include "qemu/log.h"
  20. #endif
  21. #include "qapi/error.h"
  22. #include "qemu/error-report.h"
  23. #include "qemu/config-file.h"
  24. #include "monitor/monitor.h"
  25. int trace_events_enabled_count;
  26. /*
  27. * Interpretation depends on wether the event has the 'vcpu' property:
  28. * - false: Boolean value indicating whether the event is active.
  29. * - true : Integral counting the number of vCPUs that have this event enabled.
  30. */
  31. uint16_t trace_events_dstate[TRACE_EVENT_COUNT];
  32. /* Marks events for late vCPU state init */
  33. static bool trace_events_dstate_init[TRACE_EVENT_COUNT];
  34. QemuOptsList qemu_trace_opts = {
  35. .name = "trace",
  36. .implied_opt_name = "enable",
  37. .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
  38. .desc = {
  39. {
  40. .name = "enable",
  41. .type = QEMU_OPT_STRING,
  42. },
  43. {
  44. .name = "events",
  45. .type = QEMU_OPT_STRING,
  46. },{
  47. .name = "file",
  48. .type = QEMU_OPT_STRING,
  49. },
  50. { /* end of list */ }
  51. },
  52. };
  53. TraceEvent *trace_event_name(const char *name)
  54. {
  55. assert(name != NULL);
  56. TraceEventID i;
  57. for (i = 0; i < trace_event_count(); i++) {
  58. TraceEvent *ev = trace_event_id(i);
  59. if (strcmp(trace_event_get_name(ev), name) == 0) {
  60. return ev;
  61. }
  62. }
  63. return NULL;
  64. }
  65. static bool pattern_glob(const char *pat, const char *ev)
  66. {
  67. while (*pat != '\0' && *ev != '\0') {
  68. if (*pat == *ev) {
  69. pat++;
  70. ev++;
  71. }
  72. else if (*pat == '*') {
  73. if (pattern_glob(pat, ev+1)) {
  74. return true;
  75. } else if (pattern_glob(pat+1, ev)) {
  76. return true;
  77. } else {
  78. return false;
  79. }
  80. } else {
  81. return false;
  82. }
  83. }
  84. while (*pat == '*') {
  85. pat++;
  86. }
  87. if (*pat == '\0' && *ev == '\0') {
  88. return true;
  89. } else {
  90. return false;
  91. }
  92. }
  93. TraceEvent *trace_event_pattern(const char *pat, TraceEvent *ev)
  94. {
  95. assert(pat != NULL);
  96. TraceEventID i;
  97. if (ev == NULL) {
  98. i = -1;
  99. } else {
  100. i = trace_event_get_id(ev);
  101. }
  102. i++;
  103. while (i < trace_event_count()) {
  104. TraceEvent *res = trace_event_id(i);
  105. if (pattern_glob(pat, trace_event_get_name(res))) {
  106. return res;
  107. }
  108. i++;
  109. }
  110. return NULL;
  111. }
  112. void trace_list_events(void)
  113. {
  114. int i;
  115. for (i = 0; i < trace_event_count(); i++) {
  116. TraceEvent *res = trace_event_id(i);
  117. fprintf(stderr, "%s\n", trace_event_get_name(res));
  118. }
  119. }
  120. static void do_trace_enable_events(const char *line_buf)
  121. {
  122. const bool enable = ('-' != line_buf[0]);
  123. const char *line_ptr = enable ? line_buf : line_buf + 1;
  124. if (trace_event_is_pattern(line_ptr)) {
  125. TraceEvent *ev = NULL;
  126. while ((ev = trace_event_pattern(line_ptr, ev)) != NULL) {
  127. if (trace_event_get_state_static(ev)) {
  128. /* start tracing */
  129. trace_event_set_state_dynamic(ev, enable);
  130. /* mark for late vCPU init */
  131. trace_events_dstate_init[ev->id] = true;
  132. }
  133. }
  134. } else {
  135. TraceEvent *ev = trace_event_name(line_ptr);
  136. if (ev == NULL) {
  137. error_report("WARNING: trace event '%s' does not exist",
  138. line_ptr);
  139. } else if (!trace_event_get_state_static(ev)) {
  140. error_report("WARNING: trace event '%s' is not traceable",
  141. line_ptr);
  142. } else {
  143. /* start tracing */
  144. trace_event_set_state_dynamic(ev, enable);
  145. /* mark for late vCPU init */
  146. trace_events_dstate_init[ev->id] = true;
  147. }
  148. }
  149. }
  150. void trace_enable_events(const char *line_buf)
  151. {
  152. if (is_help_option(line_buf)) {
  153. trace_list_events();
  154. if (cur_mon == NULL) {
  155. exit(0);
  156. }
  157. } else {
  158. do_trace_enable_events(line_buf);
  159. }
  160. }
  161. static void trace_init_events(const char *fname)
  162. {
  163. Location loc;
  164. FILE *fp;
  165. char line_buf[1024];
  166. size_t line_idx = 0;
  167. if (fname == NULL) {
  168. return;
  169. }
  170. loc_push_none(&loc);
  171. loc_set_file(fname, 0);
  172. fp = fopen(fname, "r");
  173. if (!fp) {
  174. error_report("%s", strerror(errno));
  175. exit(1);
  176. }
  177. while (fgets(line_buf, sizeof(line_buf), fp)) {
  178. loc_set_file(fname, ++line_idx);
  179. size_t len = strlen(line_buf);
  180. if (len > 1) { /* skip empty lines */
  181. line_buf[len - 1] = '\0';
  182. if ('#' == line_buf[0]) { /* skip commented lines */
  183. continue;
  184. }
  185. trace_enable_events(line_buf);
  186. }
  187. }
  188. if (fclose(fp) != 0) {
  189. loc_set_file(fname, 0);
  190. error_report("%s", strerror(errno));
  191. exit(1);
  192. }
  193. loc_pop(&loc);
  194. }
  195. void trace_init_file(const char *file)
  196. {
  197. #ifdef CONFIG_TRACE_SIMPLE
  198. st_set_trace_file(file);
  199. #elif defined CONFIG_TRACE_LOG
  200. /* If both the simple and the log backends are enabled, "-trace file"
  201. * only applies to the simple backend; use "-D" for the log backend.
  202. */
  203. if (file) {
  204. qemu_set_log_filename(file, &error_fatal);
  205. }
  206. #else
  207. if (file) {
  208. fprintf(stderr, "error: -trace file=...: "
  209. "option not supported by the selected tracing backends\n");
  210. exit(1);
  211. }
  212. #endif
  213. }
  214. bool trace_init_backends(void)
  215. {
  216. #ifdef CONFIG_TRACE_SIMPLE
  217. if (!st_init()) {
  218. fprintf(stderr, "failed to initialize simple tracing backend.\n");
  219. return false;
  220. }
  221. #endif
  222. #ifdef CONFIG_TRACE_FTRACE
  223. if (!ftrace_init()) {
  224. fprintf(stderr, "failed to initialize ftrace backend.\n");
  225. return false;
  226. }
  227. #endif
  228. return true;
  229. }
  230. char *trace_opt_parse(const char *optarg)
  231. {
  232. char *trace_file;
  233. QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("trace"),
  234. optarg, true);
  235. if (!opts) {
  236. exit(1);
  237. }
  238. if (qemu_opt_get(opts, "enable")) {
  239. trace_enable_events(qemu_opt_get(opts, "enable"));
  240. }
  241. trace_init_events(qemu_opt_get(opts, "events"));
  242. trace_file = g_strdup(qemu_opt_get(opts, "file"));
  243. qemu_opts_del(opts);
  244. return trace_file;
  245. }
  246. void trace_init_vcpu_events(void)
  247. {
  248. TraceEvent *ev = NULL;
  249. while ((ev = trace_event_pattern("*", ev)) != NULL) {
  250. if (trace_event_is_vcpu(ev) &&
  251. trace_event_get_state_static(ev) &&
  252. trace_events_dstate_init[ev->id]) {
  253. trace_event_set_state_dynamic(ev, true);
  254. }
  255. }
  256. }