2 * Copyright (C) 2020, Matthias Weckbecker <matthias@weckbecker.name>
4 * License: GNU GPL, version 2 or later.
5 * See the COPYING file in the top-level directory.
15 #include <qemu-plugin.h>
17 QEMU_PLUGIN_EXPORT
int qemu_plugin_version
= QEMU_PLUGIN_VERSION
;
26 static GHashTable
*statistics
;
28 static SyscallStats
*get_or_create_entry(int64_t num
)
31 (SyscallStats
*) g_hash_table_lookup(statistics
, GINT_TO_POINTER(num
));
34 entry
= g_new0(SyscallStats
, 1);
36 g_hash_table_insert(statistics
, GINT_TO_POINTER(num
), (gpointer
) entry
);
42 static void vcpu_syscall(qemu_plugin_id_t id
, unsigned int vcpu_index
,
43 int64_t num
, uint64_t a1
, uint64_t a2
,
44 uint64_t a3
, uint64_t a4
, uint64_t a5
,
45 uint64_t a6
, uint64_t a7
, uint64_t a8
)
50 entry
= get_or_create_entry(num
);
52 g_mutex_unlock(&lock
);
54 g_autofree gchar
*out
= g_strdup_printf("syscall #%" PRIi64
"\n", num
);
55 qemu_plugin_outs(out
);
59 static void vcpu_syscall_ret(qemu_plugin_id_t id
, unsigned int vcpu_idx
,
60 int64_t num
, int64_t ret
)
66 /* Should always return an existent entry. */
67 entry
= get_or_create_entry(num
);
71 g_mutex_unlock(&lock
);
73 g_autofree gchar
*out
= g_strdup_printf(
74 "syscall #%" PRIi64
" returned -> %" PRIi64
"\n", num
, ret
);
75 qemu_plugin_outs(out
);
79 static void print_entry(gpointer val
, gpointer user_data
)
81 SyscallStats
*entry
= (SyscallStats
*) val
;
82 int64_t syscall_num
= entry
->num
;
83 g_autofree gchar
*out
= g_strdup_printf(
84 "%-13" PRIi64
"%-6" PRIi64
" %" PRIi64
"\n",
85 syscall_num
, entry
->calls
, entry
->errors
);
86 qemu_plugin_outs(out
);
89 static gint
comp_func(gconstpointer ea
, gconstpointer eb
)
91 SyscallStats
*ent_a
= (SyscallStats
*) ea
;
92 SyscallStats
*ent_b
= (SyscallStats
*) eb
;
94 return ent_a
->calls
> ent_b
->calls
? -1 : 1;
97 /* ************************************************************************* */
98 static void plugin_exit(qemu_plugin_id_t id
, void *p
)
105 GList
*entries
= g_hash_table_get_values(statistics
);
106 entries
= g_list_sort(entries
, comp_func
);
107 qemu_plugin_outs("syscall no. calls errors\n");
109 g_list_foreach(entries
, print_entry
, NULL
);
111 g_list_free(entries
);
112 g_hash_table_destroy(statistics
);
113 g_mutex_unlock(&lock
);
116 QEMU_PLUGIN_EXPORT
int qemu_plugin_install(qemu_plugin_id_t id
,
117 const qemu_info_t
*info
,
118 int argc
, char **argv
)
120 bool do_print
= false;
122 for (int i
= 0; i
< argc
; i
++) {
124 g_auto(GStrv
) tokens
= g_strsplit(opt
, "=", 2);
126 if (g_strcmp0(tokens
[0], "print") == 0) {
127 if (!qemu_plugin_bool_parse(tokens
[0], tokens
[1], &do_print
)) {
128 fprintf(stderr
, "boolean argument parsing failed: %s\n", opt
);
131 fprintf(stderr
, "unsupported argument: %s\n", argv
[i
]);
137 statistics
= g_hash_table_new_full(NULL
, g_direct_equal
, NULL
, g_free
);
140 qemu_plugin_register_vcpu_syscall_cb(id
, vcpu_syscall
);
141 qemu_plugin_register_vcpu_syscall_ret_cb(id
, vcpu_syscall_ret
);
142 qemu_plugin_register_atexit_cb(id
, plugin_exit
, NULL
);