diff --git a/hmp-commands.hx b/hmp-commands.hx index d9f6c037dc..328709dc8d 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1782,6 +1782,8 @@ show balloon information show device tree @item info qdm show qdev device model list +@item info qom-tree +show object composition tree @item info roms show roms @item info tpm diff --git a/include/monitor/qdev.h b/include/monitor/qdev.h index 5eb4a1171e..719075283c 100644 --- a/include/monitor/qdev.h +++ b/include/monitor/qdev.h @@ -8,6 +8,7 @@ void hmp_info_qtree(Monitor *mon, const QDict *qdict); void hmp_info_qdm(Monitor *mon, const QDict *qdict); +void hmp_info_qom_tree(Monitor *mon, const QDict *dict); int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); diff --git a/monitor.c b/monitor.c index 8b703f97be..42116a942e 100644 --- a/monitor.c +++ b/monitor.c @@ -2889,6 +2889,13 @@ static mon_cmd_t info_cmds[] = { .help = "show qdev device model list", .mhandler.cmd = hmp_info_qdm, }, + { + .name = "qom-tree", + .args_type = "path:s?", + .params = "[path]", + .help = "show QOM composition tree", + .mhandler.cmd = hmp_info_qom_tree, + }, { .name = "roms", .args_type = "", diff --git a/qdev-monitor.c b/qdev-monitor.c index 5d30ac534c..1d87f573e8 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -678,6 +678,63 @@ void hmp_info_qdm(Monitor *mon, const QDict *qdict) qdev_print_devinfos(true); } +typedef struct QOMCompositionState { + Monitor *mon; + int indent; +} QOMCompositionState; + +static void print_qom_composition(Monitor *mon, Object *obj, int indent); + +static int print_qom_composition_child(Object *obj, void *opaque) +{ + QOMCompositionState *s = opaque; + + print_qom_composition(s->mon, obj, s->indent); + + return 0; +} + +static void print_qom_composition(Monitor *mon, Object *obj, int indent) +{ + QOMCompositionState s = { + .mon = mon, + .indent = indent + 2, + }; + char *name; + + if (obj == object_get_root()) { + name = g_strdup(""); + } else { + name = object_get_canonical_path_component(obj); + } + monitor_printf(mon, "%*s/%s (%s)\n", indent, "", name, + object_get_typename(obj)); + g_free(name); + object_child_foreach(obj, print_qom_composition_child, &s); +} + +void hmp_info_qom_tree(Monitor *mon, const QDict *dict) +{ + const char *path = qdict_get_try_str(dict, "path"); + Object *obj; + bool ambiguous = false; + + if (path) { + obj = object_resolve_path(path, &ambiguous); + if (!obj) { + monitor_printf(mon, "Path '%s' could not be resolved.\n", path); + return; + } + if (ambiguous) { + monitor_printf(mon, "Warning: Path '%s' is ambiguous.\n", path); + return; + } + } else { + obj = qdev_get_machine(); + } + print_qom_composition(mon, obj, 0); +} + int do_device_add(Monitor *mon, const QDict *qdict, QObject **ret_data) { Error *local_err = NULL;