diff --git a/configure b/configure index 6729dbe0bb..5afb3b5ef1 100755 --- a/configure +++ b/configure @@ -2468,6 +2468,9 @@ bsd) esac echo "TRACE_BACKEND=$trace_backend" >> $config_host_mak +if test "$trace_backend" = "simple"; then + echo "CONFIG_SIMPLE_TRACE=y" >> $config_host_mak +fi echo "TOOLS=$tools" >> $config_host_mak echo "ROMS=$roms" >> $config_host_mak echo "MAKE=$make" >> $config_host_mak diff --git a/monitor.c b/monitor.c index e27f8d8d3b..0e69bc8b9d 100644 --- a/monitor.c +++ b/monitor.c @@ -56,6 +56,9 @@ #include "json-parser.h" #include "osdep.h" #include "exec-all.h" +#ifdef CONFIG_SIMPLE_TRACE +#include "trace.h" +#endif //#define DEBUG //#define DEBUG_COMPLETION @@ -539,6 +542,15 @@ static void do_help_cmd(Monitor *mon, const QDict *qdict) help_cmd(mon, qdict_get_try_str(qdict, "name")); } +#ifdef CONFIG_SIMPLE_TRACE +static void do_change_trace_event_state(Monitor *mon, const QDict *qdict) +{ + const char *tp_name = qdict_get_str(qdict, "name"); + bool new_state = qdict_get_bool(qdict, "option"); + st_change_trace_event_state(tp_name, new_state); +} +#endif + static void user_monitor_complete(void *opaque, QObject *ret_data) { MonitorCompletionData *data = (MonitorCompletionData *)opaque; @@ -938,6 +950,18 @@ static void do_info_cpu_stats(Monitor *mon) } #endif +#if defined(CONFIG_SIMPLE_TRACE) +static void do_info_trace(Monitor *mon) +{ + st_print_trace((FILE *)mon, &monitor_fprintf); +} + +static void do_info_trace_events(Monitor *mon) +{ + st_print_trace_events((FILE *)mon, &monitor_fprintf); +} +#endif + /** * do_quit(): Quit QEMU execution */ @@ -2594,6 +2618,22 @@ static const mon_cmd_t info_cmds[] = { .help = "show roms", .mhandler.info = do_info_roms, }, +#if defined(CONFIG_SIMPLE_TRACE) + { + .name = "trace", + .args_type = "", + .params = "", + .help = "show current contents of trace buffer", + .mhandler.info = do_info_trace, + }, + { + .name = "trace-events", + .args_type = "", + .params = "", + .help = "show available trace-events & their state", + .mhandler.info = do_info_trace_events, + }, +#endif { .name = NULL, }, diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 5c1da3398e..c264c7d539 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -281,6 +281,22 @@ STEXI Output logs to @var{filename}. ETEXI +#ifdef CONFIG_SIMPLE_TRACE + { + .name = "trace-event", + .args_type = "name:s,option:b", + .params = "name on|off", + .help = "changes status of a specific trace event", + .mhandler.cmd = do_change_trace_event_state, + }, + +STEXI +@item trace-event +@findex trace-event +changes status of a trace event +ETEXI +#endif + { .name = "log", .args_type = "items:s", @@ -2529,6 +2545,15 @@ show roms @end table ETEXI +#ifdef CONFIG_SIMPLE_TRACE +STEXI +@item info trace +show contents of trace buffer +@item info trace-events +show available trace events and their state +ETEXI +#endif + HXCOMM DO NOT add new commands after 'info', move your addition before it! STEXI diff --git a/simpletrace.c b/simpletrace.c index 477730871c..688959a9fe 100644 --- a/simpletrace.c +++ b/simpletrace.c @@ -101,6 +101,10 @@ static void trace(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, */ clock_gettime(CLOCK_MONOTONIC, &ts); + if (!trace_list[event].state) { + return; + } + rec->event = event; rec->timestamp_ns = ts.tv_sec * 1000000000LL + ts.tv_nsec; rec->x1 = x1; @@ -157,3 +161,50 @@ static void __attribute__((constructor)) st_init(void) { atexit(st_flush_trace_buffer); } + +void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < trace_idx; i++) { + stream_printf(stream, "Event %lu : %lx %lx %lx %lx %lx\n", + trace_buf[i].event, trace_buf[i].x1, trace_buf[i].x2, + trace_buf[i].x3, trace_buf[i].x4, trace_buf[i].x5); + } +} + +void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)) +{ + unsigned int i; + + for (i = 0; i < NR_TRACE_EVENTS; i++) { + stream_printf(stream, "%s [Event ID %u] : state %u\n", + trace_list[i].tp_name, i, trace_list[i].state); + } +} + +static TraceEvent* find_trace_event_by_name(const char *tname) +{ + unsigned int i; + + if (!tname) { + return NULL; + } + + for (i = 0; i < NR_TRACE_EVENTS; i++) { + if (!strcmp(trace_list[i].tp_name, tname)) { + return &trace_list[i]; + } + } + return NULL; /* indicates end of list reached without a match */ +} + +void st_change_trace_event_state(const char *tname, bool tstate) +{ + TraceEvent *tp; + + tp = find_trace_event_by_name(tname); + if (tp) { + tp->state = tstate; + } +} diff --git a/simpletrace.h b/simpletrace.h index 7d0661b720..b0161d1ff4 100644 --- a/simpletrace.h +++ b/simpletrace.h @@ -12,9 +12,16 @@ #define SIMPLETRACE_H #include +#include +#include typedef uint64_t TraceEventID; +typedef struct { + const char *tp_name; + bool state; +} TraceEvent; + void trace0(TraceEventID event); void trace1(TraceEventID event, uint64_t x1); void trace2(TraceEventID event, uint64_t x1, uint64_t x2); @@ -22,5 +29,8 @@ void trace3(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3); void trace4(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4); void trace5(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5); void trace6(TraceEventID event, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6); +void st_print_trace(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)); +void st_print_trace_events(FILE *stream, int (*stream_printf)(FILE *stream, const char *fmt, ...)); +void st_change_trace_event_state(const char *tname, bool tstate); #endif /* SIMPLETRACE_H */ diff --git a/tracetool b/tracetool index 19b1659bc0..2e2e37dbd3 100755 --- a/tracetool +++ b/tracetool @@ -169,22 +169,38 @@ EOF linetoh_end_simple() { - return + cat <