aboutsummaryrefslogtreecommitdiff
path: root/Documentation/libtraceevent-kvm-plugin.txt
blob: a02e7866e93b93140cfc752876b067aff926b899 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
libtraceevent(3)
================

NAME
----
tep_plugin_kvm_get_func, tep_plugin_kvm_put_func - Add function name for instruction pointer of kvm plugin

SYNOPSIS
--------
[verse]
--
*#include <event-parse.h>*

const char pass:[*]*tep_plugin_kvm_get_func*(struct tep_event pass:[*]event,
				    struct tep_record pass:[*]record,
				    unsigned long long pass:[*]paddr);
void *tep_plugin_kvm_put_func*(const char pass:[*]func);
--

DESCRIPTION
-----------
The functions *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()*
are not to be called by an application, but instead are to be defined by
an application.

Certain events (like kvm_exit and kvm_entry) have the instruction pointer
of where in the guest the context changed from guest to host. As the host
only knows the instruction pointer and does not have information about what
function in the guest that instruction pointer belongs to, it can only print
the address.

But the application may have more information about the guest, and know where
the guest was when the exit occurred, and also even know the function name
of that address.

The KVM plugin for libtraceevent is called on these events, and then calls
*tep_plugin_kvm_get_func()* to see if that function can resolve the instruction
pointer address to a real function name. If the return is non NULL, it will
print the function in the output for that event.

These functions are currently defined as weak functions within the plugin, as
to not require them to be defined elsewhere. For an application to override
the weak function, it will need to define the function in a file that gets
compiled with *-rdynamic*. That will tell the dynamic linker to examine that
object file and use function names to resolve weak functions in other shared
objects (in this case the KVM plugin shared object).

If the application defines *tep_plugin_kvm_get_func()*, it must use the above
prototype. The _event_ will hold the KVM event that has the instruction pointer
field. The _record_ will be the instance of that event. The application's function
does not need to use these parameters, but they may be useful for finding the
function name for the address. The _paddr_ is a pointer to a 64 bit value (where
only 32 bits may be used on 32 bit machines). This value is the instruction
pointer to look up. If the application knows the start address of the function
as well, it can set _paddr_ to that address, and the KVM plugin will also
append a "+offset" to the function name where the offset is the original
value in _paddr_ minus the value in _paddr_ when it is called. Finally,
the application should return the function name as a nul terminated string
if one is found.

If the returned string of *tep_plugin_kvm_get_func()* was allocated, the KVM plugin
will call *tep_plugin_kvm_put_func()* when it is through with it, passing the
value returned by *tep_plugin_kvm_get_func()* as _func_. This allows the application
to free it if necessary.

RETURN VALUE
------------
The *tep_plugin_kvm_get_func()* is not to be called by the application but instead
is to be defined by the application. It should return a nul terminated string representing
the function for the given instruction pointer passed to it by reference in _paddr_. It
can then optionally update the _paddr_ to a value that holds the start of the function.
The string returned may be freed by the *tep_plugin_kvm_put_func()* that the application
should define to clean up the string.

The below example needs to be compiled with the *-rdynamic* flag so that the dynamic
linker can resolve the *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()* functions.

When run against a trace.dat file produced by *trace-cmd(1)* recording the kvm_exit and
kvm_entry events on a guest, and then the guest's /proc/kallsyms file is passed as the
second parameter, the output produced will look something like:

[source,c]
--
CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 exit native_apic_mem_write+0x2 info 10b0 0
CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8 enter native_apic_mem_write+0x8
--

But without those callbacks, it would look like:

[source,c]
--
CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 info 10b0 0
CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8
--

EXAMPLE
-------
[source,c]
--
#include <stdio.h>
#include <stdlib.h>
#include <event-parse.h>
#include <trace-cmd.h>
#include <sys/stat.h>

static struct tep_handle *tep;

const char *tep_plugin_kvm_get_func(struct tep_event *event, struct tep_record *record,
				    unsigned long long *paddr)
{
	const char *func;
	char *event_func;
	char *ename;

	func = tep_find_function(tep, *paddr);
	if (!func)
		return NULL;

	if (strcmp(event->name, "kvm_exit") == 0)
		ename = "exit";
	else
		ename = "enter";

	/*
	 * Normally, passing back func directly is sufficient and then
	 * tep_plugin_kvm_put_func() would not be required. But this example
	 * is showing how to handle allocation of the returned string.
	 */
	event_func = malloc(strlen(ename) + strlen(func) + 2);
	if (!event_func)
		return NULL;
	sprintf(event_func, "%s %s", ename, func);

	*paddr = tep_find_function_address(tep, *paddr);

	return event_func;
}

void tep_plugin_kvm_put_func(const char *func)
{
	char *f = (char *)func;

	free(f);
}

static int show_event(struct tracecmd_input *handle, struct tep_event *event,
		      struct tep_record *record, int cpu, void *data)
{
	static struct trace_seq seq;
	tep = data;

	if (!seq.buffer)
		trace_seq_init(&seq);

	trace_seq_reset(&seq);
	tep_print_event(tracecmd_get_tep(handle), &seq, record,
			"%s-%d\t%6.1000d [%03d] %s\t%s\n",
			TEP_PRINT_COMM, TEP_PRINT_PID,
			TEP_PRINT_TIME, TEP_PRINT_CPU,
			TEP_PRINT_NAME, TEP_PRINT_INFO);
	trace_seq_terminate(&seq);
	trace_seq_do_printf(&seq);
	return 0;
}

int main(int argc, char **argv)
{
	struct tracecmd_input *handle;
	struct tep_handle *guest_tep;
	struct stat st;
	FILE *fp;
	char *buf;

	if (argc < 3) {
		printf("usage: trace.dat guest_kallsyms_file\n");
		exit(-1);
	}

	handle = tracecmd_open(argv[1], 0);
	if (!handle) {
		perror(argv[1]);
		exit(-1);
	}

	/* Just for kallsyms parsing */
	guest_tep = tep_alloc();
	if (!guest_tep)
		exit(-1);

	if (stat(argv[2], &st) < 0) {
		perror(argv[2]);
		exit(-1);
	}

	buf = malloc(st.st_size + 1);
	if (!buf)
		exit(-1);

	fp = fopen(argv[2], "r");
	if (!fp) {
		perror(argv[2]);
		exit(-1);
	}

	if (fread(buf, st.st_size, 1, fp) < 0) {
		perror(argv[2]);
		exit(-1);
	}

	buf[st.st_size] = '\0';

	if (tep_parse_kallsyms(guest_tep, buf) < 0) {
		printf("Failed to parse %s\n", argv[2]);
		exit(-1);
	}
	free(buf);

	tracecmd_follow_event(handle, "kvm", "kvm_exit", show_event, guest_tep);
	tracecmd_follow_event(handle, "kvm", "kvm_entry", show_event, guest_tep);

	tracecmd_iterate_events(handle, NULL, 0, NULL, NULL);

	tep_free(guest_tep);
	tracecmd_close(handle);
}
--

FILES
-----
[verse]
--
*event-parse.h*
	Header file to include in order to have access to the library APIs.
*-ltraceevent*
	Linker switch to add when building a program that uses the library.
--

SEE ALSO
--------
*libtraceevent*(3), *trace-cmd*(1)

REPORTING BUGS
--------------
Report bugs to  <linux-trace-devel@vger.kernel.org>

LICENSE
-------
libtraceevent is Free Software licensed under the GNU LGPL 2.1

RESOURCES
---------
https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/