# tracefs_kprobe_alloc

## NAME



           tracefs_kprobe_alloc, tracefs_kretprobe_alloc, tracefs_kprobe_raw,
           tracefs_kretprobe_raw, tracefs_kprobe_destroy - Allocate, get,
           create, and remove kprobes
    


## SYNOPSIS



           **#include <tracefs.h>**
    
           struct tracefs_dynevent *
           **tracefs_kprobe_alloc**(const char *_system_ , const char *_event_ ,
                                  const char *_addr_ , const char *_format_);
           struct tracefs_dynevent *
           **tracefs_kretprobe_alloc**(const char *_system_ , const char *_event_ ,
                                     const char *_addr_ , const char *_format_ , unsigned int _max_);
           int **tracefs_kprobe_raw**(const char *_system_ , const char *_event_ ,
                                    const char *_addr_ , const char *_format_);
           int **tracefs_kretprobe_raw**(const char *_system_ , const char *_event_ ,
                                       const char *_addr_ , const char *_format_);
           int **tracefs_kprobe_destroy**(const char *_system_ , const char *_event_ ,
                                      const char *_addr_ , const char *_format_ , bool _force_);
    


## DESCRIPTION



           **tracefs_kprobe_alloc**() allocates a new kprobe context. The kbrobe
           is not configured in the system. The kprobe can be added to the
           system by passing in the returned descriptor into
           tracefs_dynevent_create(3). The new kprobe will be in the _system_
           group (or kprobes if _system_ is NULL) and have the name of _event_
           (or _addr_ if _event_ is NULL). The kprobe will be inserted to _addr_
           (function name, with or without offset, or a address), and the
           _format_ will define the format of the kprobe. See the Linux
           documentation file under: Documentation/trace/kprobetrace.rst
    
           **tracefs_kretprobe_alloc**() is the same as **tracefs_kprobe_alloc** , but
           allocates context for kretprobe. It has one additional parameter,
           which is optional, _max_ - maxactive count. See description of
           kretprobes in the Documentation/trace/kprobetrace.rst file.
    
           **tracefs_kprobe_raw**() will create a kprobe event. If _system_ is
           NULL, then the default "kprobes" is used for the group (event
           system). Otherwise if _system_ is specified then the kprobe will be
           created under the group by that name. The _event_ is the name of the
           kprobe event to create. The _addr_ can be a function, a function and
           offset, or a kernel address. This is where the location of the
           kprobe will be inserted in the kernel. The _format_ is the kprobe
           format as specified as FETCHARGS in the Linux kernel source in the
           Documentation/trace/kprobetrace.rst document.
    
           **tracefs_kretprobe_raw**() is the same as **tracefs_kprobe_raw()** ,
           except that it creates a kretprobe instead of a kprobe. The
           difference is also described in the Linux kernel source in the
           Documentation/trace/kprobetrace.rst file.
    
           **tracefs_kprobe_destroy**() will destroy a specific kprobe or
           kretprobe created by **tracefs_kprobe_raw**() or
           **tracefs_kretprobe_raw**() with the same parameters.
    


## RETURN VALUE



           **tracefs_kprobe_raw**() and **tracefs_kretprobe_raw**() return 0 on
           success, or -1 on error. If a parsing error occurs on
           **tracefs_kprobe_raw**() or **tracefs_kretprobe_raw**() then
           tracefs_error_last(3) may be used to retrieve the error message
           explaining the parsing issue.
    
           The **tracefs_kprobe_alloc**() and **tracefs_kretprobe_alloc**() APIs
           return a pointer to an allocated tracefs_dynevent structure,
           describing the probe. This pointer must be freed by
           tracefs_dynevent_free(3). Note, this only allocates a descriptor
           representing the kprobe. It does not modify the running system.
    
           The **tracefs_kprobe_destroy**() returns 0 on success or -1 on error
           if it was not able to successful destory (or find) the kprobe or
           kretprobe.
    


## ERRORS



           The following errors are for all the above calls:
    
           **EPERM** Not run as root user
    
           **ENODEV** Kprobe events are not configured for the running kernel.
    
           **ENOMEM** Memory allocation error.
    
           **tracefs_kprobe_raw**(), **tracefs_kretprobe_raw**(),
           **tracefs_kprobe_alloc**(), and **tracefs_kretprobe_alloc**() can fail
           with the following errors:
    
           **EBADMSG** if _addr_ is NULL.
    
           **EINVAL** Most likely a parsing error occurred (use
           tracefs_error_last(3) to possibly see what that error was).
    
           Other errors may also happen caused by internal system calls.
    


## EXAMPLE



               #include <stdlib.h>
               #include <unistd.h>
               #include <sys/wait.h>
    
               #include <tracefs.h>
    
               static struct tep_event *open_event;
               static struct tep_format_field *file_field;
    
               static struct tep_event *openret_event;
               static struct tep_format_field *ret_field;
    
               static int callback(struct tep_event *event, struct tep_record *record,
                                   int cpu, void *data)
               {
                       struct trace_seq seq;
    
                       trace_seq_init(&seq);
                       tep_print_event(event->tep, &seq, record, "%d-%s: ", TEP_PRINT_PID, TEP_PRINT_COMM);
    
                       if (event->id == open_event->id) {
                               trace_seq_puts(&seq, "open file='");
                               tep_print_field(&seq, record->data, file_field);
                               trace_seq_puts(&seq, "'\n");
                       } else if (event->id == openret_event->id) {
                               unsigned long long ret;
                               tep_read_number_field(ret_field, record->data, &ret);
                               trace_seq_printf(&seq, "open ret=%lld\n", ret);
                       } else {
                               goto out;
                       }
    
                       trace_seq_terminate(&seq);
                       trace_seq_do_printf(&seq);
               out:
                       trace_seq_destroy(&seq);
    
                       return 0;
               }
    
               static pid_t run_exec(char **argv, char **env)
               {
                       pid_t pid;
    
                       pid = fork();
                       if (pid)
                               return pid;
    
                       execve(argv[0], argv, env);
                       perror("exec");
                       exit(-1);
               }
    
               const char *mykprobe = "my_kprobes";
    
               enum kprobe_type {
                       KPROBE,
                       KRETPROBE,
               };
    
               static void __kprobe_create(enum kprobe_type type, const char *event,
                                           const char *addr, const char *fmt)
               {
                       char *err;
                       int r;
    
                       if (type == KPROBE)
                               r = tracefs_kprobe_raw(mykprobe, event, addr, fmt);
                       else
                               r = tracefs_kretprobe_raw(mykprobe, event, addr, fmt);
                       if (r < 0) {
                               err = tracefs_error_last(NULL);
                               perror("Failed to create kprobe:");
                               if (err && strlen(err))
                                       fprintf(stderr, "%s\n", err);
                       }
               }
    
               static void kprobe_create(const char *event, const char *addr,
                                         const char *fmt)
               {
                       __kprobe_create(KPROBE, event, addr, fmt);
               }
    
               static void kretprobe_create(const char *event, const char *addr,
                                            const char *fmt)
               {
                       __kprobe_create(KRETPROBE, event, addr, fmt);
               }
    
               int main (int argc, char **argv, char **env)
               {
                       struct tracefs_instance *instance;
                       struct tep_handle *tep;
                       const char *sysnames[] = { mykprobe, NULL };
                       pid_t pid;
    
                       if (argc < 2) {
                               printf("usage: %s command\n", argv[0]);
                               exit(-1);
                       }
    
                       instance = tracefs_instance_create("exec_open");
                       if (!instance) {
                               perror("creating instance");
                               exit(-1);
                       }
    
                       tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
    
                       kprobe_create("open", "do_sys_openat2",
                                     "file=+0($arg2):ustring flags=+0($arg3):x64 mode=+8($arg3):x64\n");
    
                       kretprobe_create("openret", "do_sys_openat2", "ret=%ax");
    
                       tep = tracefs_local_events_system(NULL, sysnames);
                       if (!tep) {
                               perror("reading events");
                               exit(-1);
                       }
                       open_event = tep_find_event_by_name(tep, mykprobe, "open");
                       file_field = tep_find_field(open_event, "file");
    
                       openret_event = tep_find_event_by_name(tep, mykprobe, "openret");
                       ret_field = tep_find_field(openret_event, "ret");
    
                       tracefs_event_enable(instance, mykprobe, NULL);
                       pid = run_exec(&argv[1], env);
    
                       /* Let the child start to run */
                       sched_yield();
    
                       do {
                               tracefs_load_cmdlines(NULL, tep);
                               tracefs_iterate_raw_events(tep, instance, NULL, 0, callback, NULL);
                       } while (waitpid(pid, NULL, WNOHANG) != pid);
    
                       /* Will disable the events */
                       tracefs_dynevent_destroy_all(TRACEFS_DYNEVENT_KPROBE | TRACEFS_DYNEVENT_KRETPROBE, true);
                       tracefs_instance_destroy(instance);
                       tep_free(tep);
    
                       return 0;
               }
    


## FILES



               **tracefs.h**
                       Header file to include in order to have access to the library APIs.
               **-ltracefs**
                       Linker switch to add when building a program that uses the library.
    


## LICENSE



           libtracefs is Free Software licensed under the GNU LGPL 2.1
    


## RESOURCES



           **https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/ **
    


## COPYING



           Copyright (C) 2021 VMware, Inc. Free use of this software is
           granted under the terms of the GNU Public License (GPL).
    


## NOTES



            1. rostedt@goodmis.org
               mailto:rostedt@goodmis.org
    
            2. tz.stoyanov@gmail.com
               mailto:tz.stoyanov@gmail.com
    
            3. sameeruddin.shaik8@gmail.com
               mailto:sameeruddin.shaik8@gmail.com
    
            4. linux-trace-devel@vger.kernel.org
               mailto:linux-trace-devel@vger.kernel.org
    


* * *