Skip to content

Commit a93f835

Browse files
author
Vasiliev Ivan
committed
added documentation and example plugins
1 parent 1217baf commit a93f835

File tree

7 files changed

+246
-1
lines changed

7 files changed

+246
-1
lines changed

docs/plugins.txt

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
Copyright (C) 2015 ISP RAS
2+
3+
4+
Using plugins
5+
-------------
6+
7+
You should run configure with parameter "--enable-plugins". After that just run make
8+
and make install as usual
9+
10+
To load a plugin with name "example_name" you should:
11+
* Stop qemu with "stop" command
12+
* Then execute "load_plugin example_name" command
13+
* Then happily continue the work of stopped qemu, you should be fine
14+
(sidenote: all commands should be executed via monitor)
15+
16+
You can also execute "list_plugins" to see the list of loaded plugins, and
17+
"stop_plugin example_name" to stop plugin, as the name suggests.
18+
19+
Writing plugins
20+
-------------
21+
22+
All plugins should be located in path_to_qemu/plugins/plugins_src/ and be written in pure C.
23+
24+
Every plugin should have mandatory parts (for reference check existing plugins):
25+
* Structure "init_info". Here you can identify which signals your plugin would provide,
26+
dependencies on other plugins, and os_version. If plugin generates signals, then
27+
they MUST be mentioned in "signals_list" field, otherwise automatic loading of plugins
28+
wouldn't work and needed plugins will have to be loaded manually.
29+
* Function "pi_start". Here you can subscribe to signals, define specific monitor commands
30+
for your plugin, register helper functions, and fill the table of functions that this plugin
31+
is providing in a straight-forward way, not through signals mechanism.
32+
Other parts of plugin are not obligatory, but are containing plugins' functionality.
33+
34+
Basically, you perform instrumentation by subscribing to specific signal and providing
35+
function that will process gotten data. This would be performed during translation; if you
36+
want to process data during actual execution, you should use helper functions (look at function
37+
"tcg_context_register_helper" and "tcg_gen_callN").
38+
39+
To make plugin actually buildable, you should add corresponding info to plugins_src/Makefile
40+
and plugins_src/Makefile.plugins (again, check how it is done for existing plugins for
41+
reference).
42+
43+
Use of signal-subscriber mechanism
44+
-------------
45+
46+
To exchange the data between qemu and plugins, and between plugins themselves, we introduce
47+
signal-subsctiber mechanism. It works as following: firstly one of plugins registers signals
48+
which would be generated by it. Other plugin, that wishes to be notificated every time
49+
those signals emit, should subscribe to needed signals and set which function would process
50+
gotten data. At some place, that is specified in your plugin, a signal would be generated and
51+
data would be transfered to QEMU, which in it's turn would forward gotten data to all plugins,
52+
that were subscribed to this signal.
53+
54+
How exactly these should be used:
55+
* First of all signals that would be provided by plugin should be mentioned in "init_info"
56+
structure (signal groups, to be more specific).
57+
* In "pi_start" those signals should be registered via "plugin_reg_signal(s1)"
58+
function, where s1 is a string identificator that identifies the group of signals (i.e.
59+
"syscalls"). This function will return pointer to "Signal_info", which should be used for
60+
signal generation.
61+
* To generate a signal you should use function "plugin_gen_signal(si, s2, data, env)",
62+
where si - is Signal_info that you got after signal registration, s2 - is a string
63+
identificator that identifies specific signal inside of group (i.e. "file_open"), data -
64+
data casted to void*, basically the useful info that signal is providing, and env -
65+
CPUArchState* var, that is widely used for analyses. The pair of s1 and s2 (signals group
66+
and specific signal inside of it) should be unique to your signal, and currently, this
67+
should be tracked by programmer himself.
68+
* To subscribe to a signal you should use a plugin_subscribe(func, s1, s2) function, where
69+
func - name of the function, that will process the signal, and s1 and s2 - are string ids,
70+
same as above. When you will try to subscribe to signal, mechanism would check whether
71+
corresponding plugins has already been loaded, and if not, would try to find and load them.
72+
That's exactly the reason why you should have all your signals mentioned in init_info
73+
structure, because that's the place where loader would look for them. If you wouldn't
74+
define signals there, you would have to load needed plugins (providers) by hand.
75+
* It also worth mentioning, that if you set "dependencies" in init_info structure, system
76+
will try to find and load mentioned dependency-plugins on load of your plugin.
77+
78+
79+
List of qemu-provided callbacks
80+
-------------
81+
82+
I hope names are self-explanatory:
83+
84+
PLUGIN_QEMU_BEFORE_GEN_TB,
85+
PLUGIN_QEMU_INSTR_TRANSLATE,
86+
PLUGIN_QEMU_EXCEPTION,
87+
PLUGIN_QEMU_EXCEPTION_HANDLER,
88+
PLUGIN_QEMU_INSTRUCTION_EXCEPTION,
89+
PLUGIN_QEMU_INTERRUPT,
90+
PLUGIN_QEMU_TLB_SET_PAGE,
91+
PLUGIN_QEMU_CPU_PAUSED,
92+
PLUGIN_QEMU_PAGE_DIR_UPD,
93+
PLUGIN_QEMU_CPUS_STOPPED

plugins/plugins_src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export PLUGIN_PREFIX
77

88
PLUGINS :=
99
PLUGINS += contexts
10+
PLUGINS += example1 example2
1011
ifeq ($(TARGET_NAME), $(filter $(TARGET_NAME), i386 x86_64))
1112
PLUGINS += syscalls_windows_xp syscalls_windows_7 syscalls_windows_8 syscalls_windows_8.1
1213
PLUGINS += syscalls_linux

plugins/plugins_src/Makefile.plugins

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ PLUGIN_DIR := $(PLUGIN_PREFIX)$(PLUGIN)/
2222
# List of the files in the plugins
2323
contexts-files := contexts.o
2424

25+
example1-files := example1.o
26+
example2-files := example2.o
27+
2528
syscalls_linux-flags := -DGUEST_OS_LINUX
2629
syscalls_linux-files := syscalls_linux.o syscall_lin.o guest_string.o syscall_processing.o
2730

plugins/plugins_src/example1.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include "qemu/osdep.h"
2+
#include "qapi/error.h"
3+
#include "plugins/plugin.h"
4+
5+
//there could be some unused includes, but im too lazy to check this atm
6+
#include "exec/cpu_ldst.h"
7+
8+
#include "tcg/tcg.h"
9+
#include "tcg/tcg-op.h"
10+
#include "exec/helper-proto.h"
11+
#include <exec/helper-head.h>
12+
#include "exec/exec-all.h"
13+
14+
#include "example1.h"
15+
16+
static SignalInfo *cb;
17+
static uint64_t scount;
18+
19+
const struct pi_info init_info =
20+
{
21+
.signals_list = (const char *[]){"test",NULL},
22+
.dependencies = (const char *[]){"contexts", NULL},
23+
.os_ver = NULL
24+
};
25+
26+
static void after_exec_opc(void)
27+
{
28+
//qemu_log_mask(LOG_GUEST_ERROR, "System call again \n");
29+
char data[] = "And I am a signal from helper. Isn't it great?\n";
30+
plugin_gen_signal(cb, "HELPER", data, NULL);
31+
}
32+
33+
static void decode_instr(void *data, CPUArchState *env)
34+
{
35+
scount++;
36+
if(!(scount % 10000))
37+
{
38+
char data[] = "10 000 instructions has passed. Impressive! \n";
39+
plugin_gen_signal(cb, "EVERY_10000", data, env);
40+
tcg_gen_callN(&tcg_ctx, after_exec_opc, dh_retvar(void), 0, NULL);
41+
}
42+
}
43+
44+
static void cpus_paused(const PluginInterface *pi)
45+
{
46+
fprintf(pi->output,"number of instructions = %" PRIu64 "\n",
47+
scount);
48+
}
49+
50+
static void unload_signal(void)
51+
{
52+
plugin_del_signal(cb);
53+
plugin_del_subscriber(decode_instr, "qemu", "PLUGIN_QEMU_INSTR_TRANSLATE");
54+
}
55+
56+
static void test_print_function_wout_params(void)
57+
{
58+
fprintf(stderr, "Test function wout paramenters successfuly executed \n");
59+
}
60+
static void test_print_function_w_params(int p1, int p2)
61+
{
62+
fprintf(stderr, "Test function with parameters successfuly executed; param1 = %d & param2 =%d \n", p1,p2);
63+
}
64+
65+
void pi_start(PluginInterface *pi)
66+
{
67+
scount = 0;
68+
cb = plugin_reg_signal("test");
69+
70+
plugin_subscribe(decode_instr, "qemu", "PLUGIN_QEMU_INSTR_TRANSLATE");
71+
72+
tcg_context_register_helper(
73+
&tcg_ctx,
74+
after_exec_opc,
75+
"after_exec_opc",
76+
0,
77+
dh_sizemask(void, 0)
78+
);
79+
80+
static const struct SSS funcs = { .f1 = test_print_function_wout_params, .f2 = test_print_function_w_params};
81+
82+
pi->exit = cpus_paused;
83+
pi->unload_signal = unload_signal;
84+
pi->funcs = &funcs;
85+
}
86+

plugins/plugins_src/example1.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef EXAMPLE1_H
2+
#define EXAMPLE1_H
3+
4+
typedef void (* temp_func_wout_params)(void);
5+
typedef void (* temp_func_w_params)(int p1, int p2);
6+
7+
struct SSS { temp_func_wout_params f1; temp_func_w_params f2; };
8+
9+
#endif

plugins/plugins_src/example2.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#include "qemu/osdep.h"
2+
#include "qapi/error.h"
3+
#include "plugins/plugin.h"
4+
5+
#include "tcg/tcg.h"
6+
#include "tcg/tcg-op.h"
7+
#include "exec/helper-proto.h"
8+
#include <exec/helper-head.h>
9+
#include "exec/exec-all.h"
10+
#include "exec/cpu_ldst.h"
11+
12+
#include "example1.h"
13+
14+
const struct pi_info init_info =
15+
{
16+
.signals_list = (const char *[]){NULL},
17+
.dependencies = (const char *[]){NULL},
18+
.os_ver = NULL
19+
};
20+
21+
static void test_f(void* data, CPUArchState *env)
22+
{
23+
char *str = data;
24+
fprintf(stderr, "what is it? - %s ",
25+
str);
26+
}
27+
28+
static void cpus_stopped(const PluginInterface *pi)
29+
{
30+
fprintf(pi->output,"Example2 plugin has stopped\n");
31+
}
32+
33+
static void unload_signal(void)
34+
{
35+
plugin_del_subscriber(test_f, "test", "EVERY_10000");
36+
plugin_del_subscriber(test_f, "test", "HELPER");
37+
}
38+
39+
void pi_start(PluginInterface *pi)
40+
{
41+
plugin_subscribe(test_f, "test", "EVERY_10000");
42+
plugin_subscribe(test_f, "test", "HELPER");
43+
44+
struct SSS *funcs= (struct SSS*)plugin_get_functions_list("example1");
45+
if(funcs != NULL)
46+
{
47+
funcs->f1();
48+
funcs->f2(1, 2);
49+
}
50+
51+
pi->exit = cpus_stopped;
52+
pi->unload_signal = unload_signal;
53+
}
54+

plugins/plugins_src/syscalls_windows.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ void pi_start(PluginInterface *pi)
116116
pi->exit = cpus_exit;
117117
cb = plugin_reg_signal("syscall");
118118
plugin_subscribe(decode_instr, "qemu", "PLUGIN_QEMU_INSTR_TRANSLATE");
119-
//tcg_plugin_subscribe(syscall_exception, "qemu", "PLUGIN_QEMU_EXCEPTION");
120119
plugin_subscribe(syscall_tlb_add_page, "qemu", "PLUGIN_QEMU_TLB_SET_PAGE");
121120
tcg_context_register_helper(
122121
&tcg_ctx,

0 commit comments

Comments
 (0)