- Parse -target with QEMU_OPTION_nouserconfig, right after
  MODULE_INIT_TARGET_INFO, because later init depends on TargetInfo.
- target_info_qom_set_target() takes Error **errp. A name comes from
  -target or from argv0 (qemu-system-aarch64). qemu-system with no
  suffix and no -target fails; use -target ? to list names.
- Fuzz passes TARGET_NAME instead of relying on a unique TargetInfo.

Signed-off-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Yonggang Luo <[email protected]>
---
 include/qemu/target-info-qom.h |  3 +-
 qemu-options.hx                |  8 ++++
 system/vl.c                    | 36 ++++++++++++----
 target-info-qom.c              | 77 ++++++++++++++++++++++++++++++----
 tests/qtest/fuzz/fuzz.c        |  2 +-
 5 files changed, 110 insertions(+), 16 deletions(-)

diff --git a/include/qemu/target-info-qom.h b/include/qemu/target-info-qom.h
index 842cf241e0a..9e56383ea6b 100644
--- a/include/qemu/target-info-qom.h
+++ b/include/qemu/target-info-qom.h
@@ -10,6 +10,7 @@
 #define QEMU_TARGET_INFO_QOM_H
 
 #include "qemu/target-info-impl.h"
+#include "qapi/error.h"
 #include "qom/object.h"
 
 #define TYPE_TARGET_INFO "target-info"
@@ -40,7 +41,7 @@ typedef struct TargetInfoQomClass {
 
 OBJECT_DECLARE_TYPE(TargetInfoQom, TargetInfoQomClass, TARGET_INFO)
 
-void target_info_qom_set_target(void);
+void target_info_qom_set_target(const char *name, Error **errp);
 
 /**
  * get_machine_types_available:
diff --git a/qemu-options.hx b/qemu-options.hx
index 34970fffc94..824807be1d8 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -24,6 +24,14 @@ SRST
     Display version information and exit
 ERST
 
+DEF("target", HAS_ARG, QEMU_OPTION_target, \
+    "-target target  selects the target architecture ('-target help' for 
list)\n",
+    QEMU_ARCH_ALL)
+SRST
+``-target target``
+    Selects target architecture ('-target help' for list)
+ERST
+
 DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop=value[,...]]\n"
     "                selects emulated machine ('-machine help' for list)\n"
diff --git a/system/vl.c b/system/vl.c
index 4b1fcd2031f..28c5741c385 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -281,6 +281,15 @@ static QemuOptsList qemu_accel_opts = {
     },
 };
 
+static QemuOptsList qemu_target_opts = {
+    .name = "target",
+    .implied_opt_name = "target",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_target_opts.head),
+    .desc = {
+        { /* end of list */ },
+    },
+};
+
 static QemuOptsList qemu_boot_opts = {
     .name = "boot-opts",
     .implied_opt_name = "order",
@@ -2856,6 +2865,7 @@ void qemu_init(int argc, char **argv)
     const char *optarg;
     MachineClass *machine_class;
     bool userconfig = true;
+    const char *target_name_option = NULL;
     FILE *vmstate_dump_file = NULL;
 
     qemu_add_opts(&qemu_drive_opts);
@@ -2889,6 +2899,7 @@ void qemu_init(int argc, char **argv)
     qemu_add_opts(&qemu_semihosting_config_opts);
     qemu_add_opts(&qemu_fw_cfg_opts);
     qemu_add_opts(&qemu_action_opts);
+    qemu_add_opts(&qemu_target_opts);
     qemu_add_run_with_opts();
     module_call_init(MODULE_INIT_OPTS);
 
@@ -2898,13 +2909,6 @@ void qemu_init(int argc, char **argv)
     os_setup_limits();
 
     module_call_init(MODULE_INIT_TARGET_INFO);
-    target_info_qom_set_target();
-
-    module_init_info(qemu_modinfo);
-    module_allow_arch(target_name());
-
-    qemu_init_subsystems();
-
     /* first pass of option parsing */
     optind = 1;
     while (optind < argc) {
@@ -2919,10 +2923,25 @@ void qemu_init(int argc, char **argv)
             case QEMU_OPTION_nouserconfig:
                 userconfig = false;
                 break;
+            case QEMU_OPTION_target:
+                target_name_option = optarg;
+                break;
             }
         }
     }
 
+    /*
+     * Identify target: first from option, then from argv[0].
+     * This happens even before handling --help option, because it may contain
+     * entries that are target specific.
+     */
+    target_info_qom_set_target(target_name_option, &error_fatal);
+
+    module_init_info(qemu_modinfo);
+    module_allow_arch(target_name());
+
+    qemu_init_subsystems();
+
     machine_opts_dict = qdict_new();
     if (userconfig) {
         qemu_read_default_config_file(&error_fatal);
@@ -2946,6 +2965,9 @@ void qemu_init(int argc, char **argv)
                 exit(1);
             }
             switch(popt->index) {
+            case QEMU_OPTION_target:
+                /* handled previously, ignore it here */
+                break;
             case QEMU_OPTION_cpu:
                 /* hw initialization will check this */
                 cpu_option = optarg;
diff --git a/target-info-qom.c b/target-info-qom.c
index 68ad734049c..5f7af028749 100644
--- a/target-info-qom.c
+++ b/target-info-qom.c
@@ -7,6 +7,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "qemu/help_option.h"
 #include "qapi/error.h"
 #include "qom/object.h"
 #include "qemu/target-info-impl.h"
@@ -87,16 +88,78 @@ const TargetInfo *target_info(void)
     return target_info_ptr;
 }
 
-void target_info_qom_set_target(void)
+static void set_target_info(const TargetInfo *chosen)
 {
-    g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false);
+    target_info_ptr = chosen;
+}
+
+static void list_targets_available(void)
+{
+    printf("List of targets available:\n");
+    g_autoptr(GSList) targets = object_class_get_list_sorted(TYPE_TARGET_INFO, 
false);
+    for (GSList *elem = targets; elem; elem = elem->next) {
+        const TargetInfo *ti = TARGET_INFO_CLASS(elem->data)->target_info;
+
+        printf("- %s\n", ti->target_name);
+    }
+}
+
+static bool target_info_matches_name(const TargetInfo *ti, const char *name)
+{
+    return !strcmp(name, ti->target_name);
+}
+
+/* qemu-system-aarch64[.exe] -> aarch64; qemu-system[.exe] -> NULL. */
+static const char *target_from_argv0(char *base)
+{
+    if (g_str_has_prefix(base, "qemu-system-")) {
+        return base + strlen("qemu-system-");
+    }
+    return NULL;
+}
 
+void target_info_qom_set_target(const char *name, Error **errp)
+{
+    g_autoptr(GSList) targets = object_class_get_list(TYPE_TARGET_INFO, false);
+    g_autofree char *prg_base = NULL;
     size_t num_found = g_slist_length(targets);
-    if (num_found != 1) {
-        error_setg(&error_fatal, num_found == 0 ?
-                                 "no target-info is available" :
-                                 "more than one target-info is available");
+
+    if (num_found == 0) {
+        error_setg(errp, "no target-info is available");
+        return;
+    }
+
+    if (!name) {
+        const char *prg = g_get_prgname();
+        if (prg && prg[0]) {
+            char *dot;
+
+            prg_base = g_path_get_basename(prg);
+            dot = strrchr(prg_base, '.');
+            if (dot && g_ascii_strcasecmp(dot, ".exe") == 0) {
+                *dot = '\0';
+            }
+            name = target_from_argv0(prg_base);
+        }
+    }
+
+    if (name) {
+        if (is_help_option(name)) {
+            list_targets_available();
+            exit(0);
+        }
+        for (GSList *elem = targets; elem; elem = elem->next) {
+            const TargetInfo *ti = TARGET_INFO_CLASS(elem->data)->target_info;
+            if (target_info_matches_name(ti, name)) {
+                set_target_info(ti);
+                return;
+            }
+        }
+        error_setg(errp, "target '%s' is not available, "
+                   "use -target ? to list available targets", name);
+        return;
     }
 
-    target_info_ptr = TARGET_INFO_CLASS(targets->data)->target_info;
+    error_setg(errp, "no target specified, "
+               "use -target ? to list available targets");
 }
diff --git a/tests/qtest/fuzz/fuzz.c b/tests/qtest/fuzz/fuzz.c
index a3a131c80f8..c992fab4079 100644
--- a/tests/qtest/fuzz/fuzz.c
+++ b/tests/qtest/fuzz/fuzz.c
@@ -174,7 +174,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char 
***envp)
     /* Initialize qgraph and modules */
     qos_graph_init();
     module_call_init(MODULE_INIT_TARGET_INFO);
-    target_info_qom_set_target();
+    target_info_qom_set_target(fuzz_arch, &error_fatal);
     module_call_init(MODULE_INIT_FUZZ_TARGET);
     module_call_init(MODULE_INIT_QOM);
     module_call_init(MODULE_INIT_LIBQOS);
-- 
2.52.0.windows.1


Reply via email to