LIBTRACEEVENT(3)

πŸ’– LIBTRACEEVENT(3) β€” the kbuffer girlies' guide πŸ’–

okay so bestie, welcome to the libtraceevent manual, section 3 🫢 this is the one about the kbuffer crew β€” the lil' squad that helps you parse the raw sub buffers of the Linux kernel tracing ring buffer. no cap, it's giving "I read raw kernel data for breakfast" energy πŸ’…


✨ NAME ✨

kbuffer_alloc, kbuffer_dup, kbuffer_free, kbuffer_load_subbuffer, kbuffer_subbuffer, kbuffer_refresh, kbuffer_subbuffer_size, kbuffer_start_of_data β€” creating a kbuffer element so you can parse the Linux kernel tracing ring buffer πŸ¦‹


🌸 SYNOPSIS 🌸

#include <kbuffer.h>

enum kbuffer_endian {
        KBUFFER_ENDIAN_BIG,
        KBUFFER_ENDIAN_LITTLE,
        KBUFFER_ENDIAN_SAME_AS_HOST,
};

enum kbuffer_long_size {
        KBUFFER_LSIZE_4,
        KBUFFER_LSIZE_8,
        KBUFFER_LSIZE_SAME_AS_HOST,
};

struct kbuffer;
struct tep_handle;

struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
struct kbuffer *kbuffer_dup(struct kbuffer *kbuf);
void kbuffer_free(struct kbuffer *kbuf);
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
int kbuffer_subbuffer_size(struct kbuffer *kbuf);
int kbuffer_refresh(struct kbuffer *kbuf);
int kbuffer_start_of_data(struct kbuffer *kbuf);
void *kbuffer_subbuffer(struct kbuffer *_kbuf);

πŸ’œ DESCRIPTION πŸ’œ

so these functions create a kbuffer handle that you use to parse the raw sub buffers of the Linux kernel tracing ring buffer 🌈 the ring buffer lives in the tracefs directory, and you can grab it with tracefs_instance_get_file(3) at per_cpu/cpuX/trace_pipe_raw β€” where X gets swapped out for the per-CPU number of whatever ring buffer you're looking at πŸ‘‘ and yeah, the kernel's ring buffer is split up per CPU, so you have to retrieve the raw ring buffer per CPU too. no shortcuts, bestie, that's just how it is πŸ’…

kbuffer_alloc() creates a descriptor you can use to manage a sub buffer read by the ring buffer ✨ the size parameter says what the word size is for the given buffer β€” and ooh, plot twist, this also works when you're reading raw data from a machine that is not the machine calling this function 😳 the endian parameter is the endianness of the machine.

if endian is set to KBUFFER_ENDIAN_SAME_AS_HOST, then the endian gets set to match the host's endianness β€” which is super handy when your app is reading the ring buffer data straight off the same machine it's running on πŸŽ€

if size is set to KBUFFER_LSIZE_SAME_AS_HOST: if the word size is 8, the kbuffer descriptor gets set to long size of 8. but if the size is 4, then it goes and does a uname(2) call, and if the machine field has the string "64" in it, it gets set to 8 byte long size and not 4 byte πŸ‘€ this is because the ring buffer long size depends on the kernel, not user space. lowkey a whole thing but slay.

kbuffer_dup() duplicates an existing kbuffer structure into a freshly allocated new one πŸ’– it keeps all the properties of the kbuf you passed in, including pointing to the same subbuffer that was loaded in the kbuf. and bestie, you must free it with kbuffer_free().

kbuffer_free() frees the resources that kbuffer_alloc() created 🫢

kbuffer_load_subbuffer() takes a subbuffer, which is a raw data blob from the tracefs trace_pipe_raw file 🌟 the Linux tracing ring buffer is broken up into sub buffers β€” each sub buffer is a standalone data segment that has all the info needed to split out the individual events and time stamps. that sub buffer is exactly what kbuffer uses to walk the events. iconic.

kbuffer_subbuffer_size() returns the location of the end of the last event on the sub-buffer πŸ¦‹ heads up: it does not return the size of the sub-buffer itself.

kbuffer_refresh() is for when more writes happened on the loaded kbuffer, and the size needs refreshing so you can actually read the new events written since the last kbuffer_load_subbuffer() was called on it ✨

⚠️ ok warning time: no memory barriers are implemented with this function, and any synchronization with the writer is the application's responsibility. that's on you, bestie 😭

kbuffer_start_of_data() returns the offset of where the actual data load of the sub-buffer begins 🌸

kbuffer_subbuffer() returns the pointer to the currently loaded subbuffer β€” i.e., the last subbuffer loaded by kbuffer_load_subbuffer() πŸ’œ if no subbuffer was loaded, NULL is returned.


⭐ RETURN VALUE ⭐

  • kbuffer_alloc() β€” returns an allocated kbuffer descriptor, or NULL on error πŸ™ˆ the returned descriptor must be freed with kbuffer_free().
  • kbuffer_load_subbuffer() β€” returns 0 on success and -1 on error.
  • kbuffer_subbuffer_size() β€” returns the index on the subbuffer where the end of the last event is located πŸ‘‘
  • kbuffer_start_of_data() β€” returns the offset of where the data begins on the sub-buffer loaded in kbuf.
  • kbuffer_subbuffer() β€” returns the last subbuffer loaded into kbuf by kbuffer_load_subbuffer(), or NULL if none was loaded.
  • kbuffer_refresh() β€” returns 0 on success, and -1 if kbuf is NULL or it doesn't have a subbuffer loaded via kbuffer_load_subbuffer() πŸ’€

πŸŽ€ EXAMPLE πŸŽ€

here's the whole vibe in code, bestie β€” go off:

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/stat.h>

    #include <kbuffer.h>

    int main (int argc, char **argv)
    {
            unsigned long long ts;
            struct kbuffer *kbuf;
            struct stat st;
            char *buf;
            void *event;
            int ret;
            int fd;
            int i = 0;

            if (argc < 2) {
                    printf("usage: %s raw-subbuffer-page\n", argv[0]);
                    printf(" Try: dd count=1 bs=4096 if=/sys/kernel/tracing/per_cpu/cpu0/trace_pipe_raw of=/tmp/file\n");
                    exit(0);
            }

            if (stat(argv[1], &st) < 0) {
                    perror("stat");
                    exit(-1);
            }

            buf = malloc(st.st_size);
            if (!buf) {
                    perror("Allocating buffer");
                    exit(-1);
            }

            fd = open(argv[1], O_RDONLY);
            if (fd < 0) {
                    perror(argv[1]);
                    exit(-1);
            }

            ret = read(fd, buf, st.st_size);
            if (ret < 0) {
                    perror("Reading buffer");
                    exit(-1);
            }
            close(fd);

            kbuf = kbuffer_alloc(KBUFFER_ENDIAN_SAME_AS_HOST,
                                 KBUFFER_LSIZE_SAME_AS_HOST);
            if (!kbuf) {
                    perror("Creating kbuffer");
                    exit(-1);
            }
            ret = kbuffer_load_subbuffer(kbuf, buf);
            if (ret < 0) {
                    perror("Loading sub bufer");
                    exit(-1);
            }

            if (kbuffer_subbuffer_size(kbuf) > st.st_size) {
                    fprintf(stderr, "kbuffer is bigger than raw size %d > %ld\n",
                            kbuffer_subbuffer_size(kbuf), st.st_size);
                    exit(-1);
            }

            printf("Kbuffer data starts at %d\n", kbuffer_start_of_data(kbuf));
            do {
                    event = kbuffer_read_event(kbuf, &ts);
                    if (event) {
                            printf(" event %3d ts:%lld\n", i++, ts);
                            event = kbuffer_next_event(kbuf, NULL);
                    }
            } while (event);

            if (!event)
                    printf("Finished sub buffer\n");

            kbuffer_free(kbuf);

            return 0;
    }

πŸ¦‹ FILES πŸ¦‹

  • event-parse.h β€” the header file you include so you have access to the library APIs πŸ’–
  • -ltraceevent β€” the linker switch you add when building a program that uses the library ✨

🌈 SEE ALSO 🌈

libtraceevent(3), trace-cmd(1) β€” go read those too, iykyk πŸ’…


πŸ‘‘ AUTHOR πŸ‘‘

Steven Rostedt <rostedt@goodmis.org[1]> β€” author of libtraceevent 🌟 absolute legend, main character energy fr fr.


πŸ’€ REPORTING BUGS πŸ’€

found a bug? don't be shy β€” report bugs to <linux-trace-devel@vger.kernel.org[2]> πŸ™ˆ


🌸 LICENSE 🌸

libtraceevent is Free Software, licensed under the GNU LGPL 2.1 πŸ’œ


⭐ RESOURCES ⭐

https://git.kernel.org/pub/scm/libs/libtrace/libtraceevent.git/ β€” the source, go peek πŸŽ€


πŸ“ NOTES πŸ“

  1. rostedt@goodmis.org mailto:rostedt@goodmis.org
  2. linux-trace-devel@vger.kernel.org mailto:linux-trace-devel@vger.kernel.org

okay that's the whole page bestie 🫢 no cap, you're now officially a kbuffer girlie. this was libtraceevent version 1.9.0, dated 06/15/2026 β€” and yes, it still goes by LIBTRACEEVENT(3) in the man page headers, slay πŸ’…βœ¨ go parse some ring buffers, you got this πŸ’–

πŸ“¦ where this page comes from