LIBTRACEFS(3)
π LIBTRACEFS(3) β kprobes, kretprobes & main character energy β¨
okay so this is a page from the libtracefs Manual, and bestie, it's all about making kprobes happen. sit down, hydrate, let's go π«Ά
πΈ NAME πΈ
tracefs_kprobe_alloc, tracefs_kretprobe_alloc, tracefs_kprobe_raw, tracefs_kretprobe_raw, tracefs_kprobe_destroy β the whole friend group tbh: 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 π¦
the alloc girlies π
tracefs_kprobe_alloc() allocates a brand-new kprobe context. and likeβ¦ it does not configure the kprobe in the system. it's giving "dressed up, nowhere to go" π. to actually put it in the system you pass the returned descriptor into tracefs_dynevent_create(3). the new kprobe will land in the system group (or kprobes if system is NULL) and get the name of event (or addr if event is NULL). the kprobe gets inserted at addr β that's a function name, with or without an offset, or a plain address β and format defines the format of the kprobe. for the deep lore, go read the Linux documentation file under: Documentation/trace/kprobetrace.rst π
tracefs_kretprobe_alloc() is literally the same as tracefs_kprobe_alloc, except it allocates a context for a kretprobe. it has one extra parameter, which is optional: max β the maxactive count. kretprobe deets live in Documentation/trace/kprobetrace.rst too. no cap π§
the raw ones π₯
tracefs_kprobe_raw() will create a kprobe event, for real for real. if system is NULL, the default "kprobes" is used for the group (the event system). otherwise, if system is specified, the kprobe gets created under the group with that name. event is the name of the kprobe event to create. addr can be a function, a function and offset, or a kernel address β that's where the kprobe gets inserted in the kernel. and format is the kprobe format as specified as FETCHARGS in the Linux kernel source in the Documentation/trace/kprobetrace.rst document. iconic behavior π
tracefs_kretprobe_raw() is the same as tracefs_kprobe_raw(), except β plot twist β 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.
the destroyer π
tracefs_kprobe_destroy() will destroy a specific kprobe or kretprobe created by tracefs_kprobe_raw() or tracefs_kretprobe_raw() β using the same parameters. same energy, reverse direction π«Ά
β RETURN VALUE β
tracefs_kprobe_raw() and tracefs_kretprobe_raw() return 0 on success, or -1 on error. and if a parsing error happens on tracefs_kprobe_raw() or tracefs_kretprobe_raw(), you can hit up tracefs_error_last(3) to retrieve the error message explaining the parsing issue. she'll tell you what went wrong π
tracefs_kprobe_alloc() and tracefs_kretprobe_alloc() return a pointer to an allocated tracefs_dynevent structure describing the probe. that 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. it's a vibe, not a syscall π
tracefs_kprobe_destroy() returns 0 on success, or -1 on error if it was not able to successfully destroy (or find) the kprobe or kretprobe. rough out here π
π 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 kernelENOMEMβ memory allocation error
tracefs_kprobe_raw(), tracefs_kretprobe_raw(), tracefs_kprobe_alloc(), and tracefs_kretprobe_alloc() can fail with the following errors too:
EBADMSGβ ifaddrisNULLEINVALβ most likely a parsing error occurred (usetracefs_error_last(3)to possibly see what that error was)
other errors may also happen, caused by internal system calls. yeah, the kernel has layers π§
π EXAMPLE π
this one's a whole meal, bestie. it's all verbatim, don't touch it π½οΈ
#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. don't forget her, she's the plug π
π SEE ALSO π
libtracefs(3), libtraceevent(3), trace-cmd(1)
π AUTHOR π
- Steven Rostedt
<rostedt@goodmis.org[1]> - Tzvetomir Stoyanov
<tz.stoyanov@gmail.com[2]> - sameeruddin shaik
<sameeruddin.shaik8@gmail.com[3]>
π₯ REPORTING BUGS π₯
report bugs to <linux-trace-devel@vger.kernel.org[4]> β they want to hear from you, fr fr π«Ά
πΈ 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 π¦
rostedt@goodmis.orgmailto:rostedt@goodmis.orgtz.stoyanov@gmail.commailto:tz.stoyanov@gmail.comsameeruddin.shaik8@gmail.commailto:sameeruddin.shaik8@gmail.comlinux-trace-devel@vger.kernel.orgmailto:linux-trace-devel@vger.kernel.org
and that's the whole page, bestie π this was libtracefs version 1.8.4, dated 10/21/2026 β screenshot it, cite it, slay it π
β¨ periodt.
π¦ where this page comes from
- arch rolling: libtracefs 1.8.4-1 Β· GPL-2.0-only AND LGPL-2.1-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms