summaryrefslogtreecommitdiffstats
path: root/Documentation/libtraceevent-kvm-plugin.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/libtraceevent-kvm-plugin.txt')
-rw-r--r--Documentation/libtraceevent-kvm-plugin.txt252
1 files changed, 252 insertions, 0 deletions
diff --git a/Documentation/libtraceevent-kvm-plugin.txt b/Documentation/libtraceevent-kvm-plugin.txt
new file mode 100644
index 0000000..a02e786
--- /dev/null
+++ b/Documentation/libtraceevent-kvm-plugin.txt
@@ -0,0 +1,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/