tep_plugin_kvm_get_func(3) — Linux manual page

NAME | SYNOPSIS | DESCRIPTION | RETURN VALUE | EXAMPLE | FILES | SEE ALSO | REPORTING BUGS | LICENSE | RESOURCES | NOTES | COLOPHON

LIBTRACEEVENT(3)          libtraceevent Manual          LIBTRACEEVENT(3)

NAME         top

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

SYNOPSIS         top

       #include <event-parse.h>

       const char *tep_plugin_kvm_get_func(struct tep_event *event,
                                           struct tep_record *record,
                                           unsigned long long *paddr);
       void tep_plugin_kvm_put_func(const char *func);

DESCRIPTION         top

       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         top

       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:

           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:

           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         top

           #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         top

           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         top

       libtraceevent(3), trace-cmd(1)

REPORTING BUGS         top

       Report bugs to <[email protected][1]>

LICENSE         top

       libtraceevent is Free Software licensed under the GNU LGPL 2.1

RESOURCES         top

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

NOTES         top

        1. [email protected]
           mailto:[email protected]

COLOPHON         top

       This page is part of the libtraceevent (Linux kernel trace event
       library) project.  Information about the project can be found at
       ⟨https://www.trace-cmd.org/⟩.  If you have a bug report for this
       manual page, see ⟨https://www.trace-cmd.org/⟩.  This page was
       obtained from the project's upstream Git repository
       ⟨https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git⟩
       on 2024-06-14.  (At that time, the date of the most recent commit
       that was found in the repository was 2024-05-17.)  If you
       discover any rendering problems in this HTML version of the page,
       or you believe there is a better or more up-to-date source for
       the page, or you have corrections or improvements to the
       information in this COLOPHON (which is not part of the original
       manual page), send a mail to [email protected]

libtraceevent 1.7.3            09/24/2023               LIBTRACEEVENT(3)