diff --git a/docs/tracing.txt b/docs/tracing.txt
index 49e030e..5f86f1a 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -144,6 +144,11 @@ source tree.  It may not be as powerful as platform-specific or third-party
 trace backends but it is portable.  This is the recommended trace backend
 unless you have specific needs for more advanced backends.
 
+==== Enabling trace events from the command line ====
+
+The "-trace events=<file>" command line argument can be used to enable the
+events listed in <file> from the very beginning of the program.
+
 ==== Monitor commands ====
 
 * info trace
diff --git a/qemu-config.c b/qemu-config.c
index 323d3c2..0a00081 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -300,12 +300,15 @@ static QemuOptsList qemu_mon_opts = {
 #ifdef CONFIG_SIMPLE_TRACE
 static QemuOptsList qemu_trace_opts = {
     .name = "trace",
-    .implied_opt_name = "trace",
+    .implied_opt_name = "file",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head),
     .desc = {
         {
             .name = "file",
             .type = QEMU_OPT_STRING,
+        },{
+            .name = "events",
+            .type = QEMU_OPT_STRING,
         },
         { /* end if list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index ef60730..e7b93b5 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2358,13 +2358,23 @@ option will prevent QEMU from loading these configuration files at startup.
 ETEXI
 #ifdef CONFIG_SIMPLE_TRACE
 DEF("trace", HAS_ARG, QEMU_OPTION_trace,
-    "-trace\n"
-    "                Specify a trace file to log traces to\n",
+    "-trace [file=]<file>[,events=<file>]\n"
+    "                specify tracing options\n",
     QEMU_ARCH_ALL)
 STEXI
-@item -trace
+@item -trace [file=]@var{file}[,events=@var{file}]
 @findex -trace
-Specify a trace file to log output traces to.
+
+Specify tracing options.
+
+@table @option
+@item file=@var{file}
+Log output traces to @var{file}.
+@item events=@var{file}
+Immediately enable events listed in @var{file}.
+The file must contain one event name (as listed in the @var{trace-events} file)
+per line.
+@end table
 ETEXI
 #endif
 
diff --git a/vl.c b/vl.c
index c387f2b..5d6b03b 100644
--- a/vl.c
+++ b/vl.c
@@ -1931,7 +1931,7 @@ static int virtcon_parse(const char *devname)
 }
 
 static int debugcon_parse(const char *devname)
-{   
+{
     QemuOpts *opts;
 
     if (!qemu_chr_open("debugcon", devname, NULL)) {
@@ -2039,6 +2039,7 @@ int main(int argc, char **argv, char **envp)
 #endif
     int defconfig = 1;
     const char *trace_file = NULL;
+    const char *trace_events_file = NULL;
 
     atexit(qemu_run_exit_notifiers);
     error_set_progname(argv[0]);
@@ -2112,7 +2113,7 @@ int main(int argc, char **argv, char **envp)
         if (optind >= argc)
             break;
         if (argv[optind][0] != '-') {
-	    hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
+            hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
         } else {
             const QEMUOption *popt;
 
@@ -2174,15 +2175,15 @@ int main(int argc, char **argv, char **envp)
                 break;
             case QEMU_OPTION_drive:
                 drive_def(optarg);
-	        break;
+                break;
             case QEMU_OPTION_set:
                 if (qemu_set_option(optarg) != 0)
                     exit(1);
-	        break;
+                break;
             case QEMU_OPTION_global:
                 if (qemu_global_option(optarg) != 0)
                     exit(1);
-	        break;
+                break;
             case QEMU_OPTION_mtdblock:
                 drive_add(IF_MTD, -1, optarg, MTD_OPTS);
                 break;
@@ -2229,7 +2230,7 @@ int main(int argc, char **argv, char **envp)
                         fprintf(stderr, "qemu: invalid physical CHS format\n");
                         exit(1);
                     }
-		    if (hda_opts != NULL) {
+                    if (hda_opts != NULL) {
                         char num[16];
                         snprintf(num, sizeof(num), "%d", cyls);
                         qemu_opt_set(hda_opts, "cyls", num);
@@ -2431,9 +2432,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_S:
                 autostart = 0;
                 break;
-	    case QEMU_OPTION_k:
-		keyboard_layout = optarg;
-		break;
+            case QEMU_OPTION_k:
+                keyboard_layout = optarg;
+                break;
             case QEMU_OPTION_localtime:
                 rtc_utc = 0;
                 break;
@@ -2616,9 +2617,9 @@ int main(int argc, char **argv, char **envp)
             case QEMU_OPTION_debugcon:
                 add_device_config(DEV_DEBUGCON, optarg);
                 break;
-	    case QEMU_OPTION_loadvm:
-		loadvm = optarg;
-		break;
+            case QEMU_OPTION_loadvm:
+                loadvm = optarg;
+                break;
             case QEMU_OPTION_full_screen:
                 full_screen = 1;
                 break;
@@ -2693,7 +2694,7 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
-	    case QEMU_OPTION_vnc:
+            case QEMU_OPTION_vnc:
 #ifdef CONFIG_VNC
                 display_remote++;
                 vnc_display = optarg;
@@ -2730,11 +2731,11 @@ int main(int argc, char **argv, char **envp)
                     exit(1);
                 }
                 break;
-	    case QEMU_OPTION_option_rom:
-		if (nb_option_roms >= MAX_OPTION_ROMS) {
-		    fprintf(stderr, "Too many option ROMs\n");
-		    exit(1);
-		}
+            case QEMU_OPTION_option_rom:
+                if (nb_option_roms >= MAX_OPTION_ROMS) {
+                    fprintf(stderr, "Too many option ROMs\n");
+                    exit(1);
+                }
                 opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1);
                 option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile");
                 option_rom[nb_option_roms].bootindex =
@@ -2743,25 +2744,25 @@ int main(int argc, char **argv, char **envp)
                     fprintf(stderr, "Option ROM file is not specified\n");
                     exit(1);
                 }
-		nb_option_roms++;
-		break;
+                nb_option_roms++;
+                break;
             case QEMU_OPTION_semihosting:
                 semihosting_enabled = 1;
                 break;
             case QEMU_OPTION_name:
                 qemu_name = qemu_strdup(optarg);
-		 {
-		     char *p = strchr(qemu_name, ',');
-		     if (p != NULL) {
-		        *p++ = 0;
-			if (strncmp(p, "process=", 8)) {
-			    fprintf(stderr, "Unknown subargument %s to -name\n", p);
-			    exit(1);
-			}
-			p += 8;
-			os_set_proc_name(p);
-		     }	
-		 }	
+                 {
+                     char *p = strchr(qemu_name, ',');
+                     if (p != NULL) {
+                        *p++ = 0;
+                        if (strncmp(p, "process=", 8)) {
+                            fprintf(stderr, "Unknown subargument %s to -name\n", p);
+                            exit(1);
+                        }
+                        p += 8;
+                        os_set_proc_name(p);
+                     }
+                 }
                 break;
             case QEMU_OPTION_prom_env:
                 if (nb_prom_envs >= MAX_PROM_ENVS) {
@@ -2833,9 +2834,10 @@ int main(int argc, char **argv, char **envp)
                 break;
 #ifdef CONFIG_SIMPLE_TRACE
             case QEMU_OPTION_trace:
-                opts = qemu_opts_parse(qemu_find_opts("trace"), optarg, 0);
+                opts = qemu_opts_parse(qemu_find_opts("trace"), optarg, 1);
                 if (opts) {
                     trace_file = qemu_opt_get(opts, "file");
+                    trace_events_file = qemu_opt_get(opts, "events");
                 }
                 break;
 #endif
@@ -2887,6 +2889,32 @@ int main(int argc, char **argv, char **envp)
     if (!st_init(trace_file)) {
         fprintf(stderr, "warning: unable to initialize simple trace backend\n");
     }
+    if (trace_events_file) {
+        FILE *trace_events_fp = fopen(trace_events_file, "r");
+        if (!trace_events_fp) {
+            fprintf(stderr, "could not open trace events file '%s': %s\n",
+                    trace_events_file, strerror(errno));
+            exit(1);
+        }
+        char line_buf[1024];
+        char *line;
+        for (line = fgets(line_buf, 1024, trace_events_fp); line != NULL;
+             line = fgets(line_buf, 1024, trace_events_fp)) {
+            int len = strlen(line);
+            if (len > 1) {              /* skip empty lines */
+                line[len - 1] = '\0';
+                if (!st_change_trace_event_state(line, true)) {
+                    fprintf(stderr, "trace event '%s' does not exist\n", line);
+                    exit(1);
+                }
+            }
+        }
+        if (fclose(trace_events_fp) != 0) {
+            fprintf(stderr, "error closing file '%s': %s\n",
+                    trace_events_file, strerror(errno));
+            exit(1);
+        }
+    }
 
     /* If no data_dir is specified then try to find it relative to the
        executable path.  */
