diff options
Diffstat (limited to 'Documentation/libtraceevent-kvm-plugin.txt')
-rw-r--r-- | Documentation/libtraceevent-kvm-plugin.txt | 252 |
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/ |