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);

DESCRIPTION

tracefs_kprobe_alloc() allocates a new kprobe context. The kbrobe is not configured in the system. 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.

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.

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.

SEE ALSO

libtracefs(3), libtraceevent(3), trace-cmd(1)

AUTHOR

Steven Rostedt <rostedt@goodmis.org>
Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
sameeruddin shaik <sameeruddin.shaik8@gmail.com>

REPORTING BUGS

LICENSE

libtracefs is Free Software licensed under the GNU LGPL 2.1

RESOURCES

COPYING

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