xref: /aosp_15_r20/external/libtraceevent/Documentation/libtraceevent-kvm-plugin.txt (revision 436bf2bcd5202612ffffe471bbcc1f277cc8d28e)
1libtraceevent(3)
2================
3
4NAME
5----
6tep_plugin_kvm_get_func, tep_plugin_kvm_put_func - Add function name for instruction pointer of kvm plugin
7
8SYNOPSIS
9--------
10[verse]
11--
12*#include <event-parse.h>*
13
14const char pass:[*]*tep_plugin_kvm_get_func*(struct tep_event pass:[*]event,
15				    struct tep_record pass:[*]record,
16				    unsigned long long pass:[*]paddr);
17void *tep_plugin_kvm_put_func*(const char pass:[*]func);
18--
19
20DESCRIPTION
21-----------
22The functions *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()*
23are not to be called by an application, but instead are to be defined by
24an application.
25
26Certain events (like kvm_exit and kvm_entry) have the instruction pointer
27of where in the guest the context changed from guest to host. As the host
28only knows the instruction pointer and does not have information about what
29function in the guest that instruction pointer belongs to, it can only print
30the address.
31
32But the application may have more information about the guest, and know where
33the guest was when the exit occurred, and also even know the function name
34of that address.
35
36The KVM plugin for libtraceevent is called on these events, and then calls
37*tep_plugin_kvm_get_func()* to see if that function can resolve the instruction
38pointer address to a real function name. If the return is non NULL, it will
39print the function in the output for that event.
40
41These functions are currently defined as weak functions within the plugin, as
42to not require them to be defined elsewhere. For an application to override
43the weak function, it will need to define the function in a file that gets
44compiled with *-rdynamic*. That will tell the dynamic linker to examine that
45object file and use function names to resolve weak functions in other shared
46objects (in this case the KVM plugin shared object).
47
48If the application defines *tep_plugin_kvm_get_func()*, it must use the above
49prototype. The _event_ will hold the KVM event that has the instruction pointer
50field. The _record_ will be the instance of that event. The application's function
51does not need to use these parameters, but they may be useful for finding the
52function name for the address. The _paddr_ is a pointer to a 64 bit value (where
53only 32 bits may be used on 32 bit machines). This value is the instruction
54pointer to look up. If the application knows the start address of the function
55as well, it can set _paddr_ to that address, and the KVM plugin will also
56append a "+offset" to the function name where the offset is the original
57value in _paddr_ minus the value in _paddr_ when it is called. Finally,
58the application should return the function name as a nul terminated string
59if one is found.
60
61If the returned string of *tep_plugin_kvm_get_func()* was allocated, the KVM plugin
62will call *tep_plugin_kvm_put_func()* when it is through with it, passing the
63value returned by *tep_plugin_kvm_get_func()* as _func_. This allows the application
64to free it if necessary.
65
66RETURN VALUE
67------------
68The *tep_plugin_kvm_get_func()* is not to be called by the application but instead
69is to be defined by the application. It should return a nul terminated string representing
70the function for the given instruction pointer passed to it by reference in _paddr_. It
71can then optionally update the _paddr_ to a value that holds the start of the function.
72The string returned may be freed by the *tep_plugin_kvm_put_func()* that the application
73should define to clean up the string.
74
75The below example needs to be compiled with the *-rdynamic* flag so that the dynamic
76linker can resolve the *tep_plugin_kvm_get_func()* and *tep_plugin_kvm_put_func()* functions.
77
78When run against a trace.dat file produced by *trace-cmd(1)* recording the kvm_exit and
79kvm_entry events on a guest, and then the guest's /proc/kallsyms file is passed as the
80second parameter, the output produced will look something like:
81
82[source,c]
83--
84CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 exit native_apic_mem_write+0x2 info 10b0 0
85CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8 enter native_apic_mem_write+0x8
86--
87
88But without those callbacks, it would look like:
89
90[source,c]
91--
92CPU 0/KVM-20407 83156.177626 [000] kvm_exit     reason APIC_ACCESS rip 0xffffffffb0056ee2 info 10b0 0
93CPU 0/KVM-20407 83156.177632 [000] kvm_entry     vcpu 0 rip 0xffffffffb0056ee8
94--
95
96EXAMPLE
97-------
98[source,c]
99--
100#include <stdio.h>
101#include <stdlib.h>
102#include <event-parse.h>
103#include <trace-cmd.h>
104#include <sys/stat.h>
105
106static struct tep_handle *tep;
107
108const char *tep_plugin_kvm_get_func(struct tep_event *event, struct tep_record *record,
109				    unsigned long long *paddr)
110{
111	const char *func;
112	char *event_func;
113	char *ename;
114
115	func = tep_find_function(tep, *paddr);
116	if (!func)
117		return NULL;
118
119	if (strcmp(event->name, "kvm_exit") == 0)
120		ename = "exit";
121	else
122		ename = "enter";
123
124	/*
125	 * Normally, passing back func directly is sufficient and then
126	 * tep_plugin_kvm_put_func() would not be required. But this example
127	 * is showing how to handle allocation of the returned string.
128	 */
129	event_func = malloc(strlen(ename) + strlen(func) + 2);
130	if (!event_func)
131		return NULL;
132	sprintf(event_func, "%s %s", ename, func);
133
134	*paddr = tep_find_function_address(tep, *paddr);
135
136	return event_func;
137}
138
139void tep_plugin_kvm_put_func(const char *func)
140{
141	char *f = (char *)func;
142
143	free(f);
144}
145
146static int show_event(struct tracecmd_input *handle, struct tep_event *event,
147		      struct tep_record *record, int cpu, void *data)
148{
149	static struct trace_seq seq;
150	tep = data;
151
152	if (!seq.buffer)
153		trace_seq_init(&seq);
154
155	trace_seq_reset(&seq);
156	tep_print_event(tracecmd_get_tep(handle), &seq, record,
157			"%s-%d\t%6.1000d [%03d] %s\t%s\n",
158			TEP_PRINT_COMM, TEP_PRINT_PID,
159			TEP_PRINT_TIME, TEP_PRINT_CPU,
160			TEP_PRINT_NAME, TEP_PRINT_INFO);
161	trace_seq_terminate(&seq);
162	trace_seq_do_printf(&seq);
163	return 0;
164}
165
166int main(int argc, char **argv)
167{
168	struct tracecmd_input *handle;
169	struct tep_handle *guest_tep;
170	struct stat st;
171	FILE *fp;
172	char *buf;
173
174	if (argc < 3) {
175		printf("usage: trace.dat guest_kallsyms_file\n");
176		exit(-1);
177	}
178
179	handle = tracecmd_open(argv[1], 0);
180	if (!handle) {
181		perror(argv[1]);
182		exit(-1);
183	}
184
185	/* Just for kallsyms parsing */
186	guest_tep = tep_alloc();
187	if (!guest_tep)
188		exit(-1);
189
190	if (stat(argv[2], &st) < 0) {
191		perror(argv[2]);
192		exit(-1);
193	}
194
195	buf = malloc(st.st_size + 1);
196	if (!buf)
197		exit(-1);
198
199	fp = fopen(argv[2], "r");
200	if (!fp) {
201		perror(argv[2]);
202		exit(-1);
203	}
204
205	if (fread(buf, st.st_size, 1, fp) < 0) {
206		perror(argv[2]);
207		exit(-1);
208	}
209
210	buf[st.st_size] = '\0';
211
212	if (tep_parse_kallsyms(guest_tep, buf) < 0) {
213		printf("Failed to parse %s\n", argv[2]);
214		exit(-1);
215	}
216	free(buf);
217
218	tracecmd_follow_event(handle, "kvm", "kvm_exit", show_event, guest_tep);
219	tracecmd_follow_event(handle, "kvm", "kvm_entry", show_event, guest_tep);
220
221	tracecmd_iterate_events(handle, NULL, 0, NULL, NULL);
222
223	tep_free(guest_tep);
224	tracecmd_close(handle);
225}
226--
227
228FILES
229-----
230[verse]
231--
232*event-parse.h*
233	Header file to include in order to have access to the library APIs.
234*-ltraceevent*
235	Linker switch to add when building a program that uses the library.
236--
237
238SEE ALSO
239--------
240*libtraceevent*(3), *trace-cmd*(1)
241
242REPORTING BUGS
243--------------
244Report bugs to  <[email protected]>
245
246LICENSE
247-------
248libtraceevent is Free Software licensed under the GNU LGPL 2.1
249
250RESOURCES
251---------
252https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/
253