root/include/trace/trace_custom_events.h
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * This is similar to the trace_events.h file, but is to only
 * create custom trace events to be attached to existing tracepoints.
 * Where as the TRACE_EVENT() macro (from trace_events.h) will create
 * both the trace event and the tracepoint it will attach the event to,
 * TRACE_CUSTOM_EVENT() is to create only a custom version of an existing
 * trace event (created by TRACE_EVENT() or DEFINE_EVENT()), and will
 * be placed in the "custom" system.
 */

#include <linux/trace_events.h>

/* All custom events are placed in the custom group */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM custom

#ifndef TRACE_SYSTEM_VAR
#define TRACE_SYSTEM_VAR TRACE_SYSTEM
#endif

/* The init stage creates the system string and enum mappings */

#include "stages/init.h"

#undef TRACE_CUSTOM_EVENT
#define TRACE_CUSTOM_EVENT(name, proto, args, tstruct, assign, print) \
        DECLARE_CUSTOM_EVENT_CLASS(name,                              \
                             PARAMS(proto),                    \
                             PARAMS(args),                     \
                             PARAMS(tstruct),                  \
                             PARAMS(assign),                   \
                             PARAMS(print));                   \
        DEFINE_CUSTOM_EVENT(name, name, PARAMS(proto), PARAMS(args));

/* Stage 1 creates the structure of the recorded event layout */

#include "stages/stage1_struct_define.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
        struct trace_custom_event_raw_##name {                          \
                struct trace_entry      ent;                            \
                tstruct                                                 \
                char                    __data[];                       \
        };                                                              \
                                                                        \
        static struct trace_event_class custom_event_class_##name;

#undef DEFINE_CUSTOM_EVENT
#define DEFINE_CUSTOM_EVENT(template, name, proto, args)        \
        static struct trace_event_call  __used                  \
        __attribute__((__aligned__(4))) custom_event_##name

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 2 creates the custom class */

#include "stages/stage2_data_offsets.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print)   \
        struct trace_custom_event_data_offsets_##call {                 \
                tstruct;                                                \
        };

#undef DEFINE_CUSTOM_EVENT
#define DEFINE_CUSTOM_EVENT(template, name, proto, args)

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 3 create the way to print the custom event */

#include "stages/stage3_trace_output.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static notrace enum print_line_t                                        \
trace_custom_raw_output_##call(struct trace_iterator *iter, int flags,  \
                        struct trace_event *trace_event)                \
{                                                                       \
        struct trace_seq *s = &iter->seq;                               \
        struct trace_seq __maybe_unused *p = &iter->tmp_seq;            \
        struct trace_custom_event_raw_##call *field;                    \
        int ret;                                                        \
                                                                        \
        field = (typeof(field))iter->ent;                               \
                                                                        \
        ret = trace_raw_output_prep(iter, trace_event);                 \
        if (ret != TRACE_TYPE_HANDLED)                                  \
                return ret;                                             \
                                                                        \
        trace_event_printf(iter, print);                                \
                                                                        \
        return trace_handle_return(s);                                  \
}                                                                       \
static struct trace_event_functions trace_custom_event_type_funcs_##call = { \
        .trace                  = trace_custom_raw_output_##call,       \
};

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 4 creates the offset layout for the fields */

#include "stages/stage4_event_fields.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, func, print)     \
static struct trace_event_fields trace_custom_event_fields_##call[] = { \
        tstruct                                                         \
        {} };

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 5 creates the helper function for dynamic fields */

#include "stages/stage5_get_offsets.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static inline notrace int trace_custom_event_get_offsets_##call(        \
        struct trace_custom_event_data_offsets_##call *__data_offsets, proto) \
{                                                                       \
        int __data_size = 0;                                            \
        int __maybe_unused __item_length;                               \
        struct trace_custom_event_raw_##call __maybe_unused *entry;     \
                                                                        \
        tstruct;                                                        \
                                                                        \
        return __data_size;                                             \
}

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 6 creates the probe function that records the event */

#include "stages/stage6_event_callback.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
                                                                        \
static notrace void                                                     \
trace_custom_event_raw_event_##call(void *__data, proto)                \
{                                                                       \
        struct trace_event_file *trace_file = __data;                   \
        struct trace_custom_event_data_offsets_##call __maybe_unused __data_offsets; \
        struct trace_event_buffer fbuffer;                              \
        struct trace_custom_event_raw_##call *entry;                    \
        int __data_size;                                                \
                                                                        \
        if (trace_trigger_soft_disabled(trace_file))                    \
                return;                                                 \
                                                                        \
        __data_size = trace_custom_event_get_offsets_##call(&__data_offsets, args); \
                                                                        \
        entry = trace_event_buffer_reserve(&fbuffer, trace_file,        \
                                 sizeof(*entry) + __data_size);         \
                                                                        \
        if (!entry)                                                     \
                return;                                                 \
                                                                        \
        tstruct                                                         \
                                                                        \
        { assign; }                                                     \
                                                                        \
        trace_event_buffer_commit(&fbuffer);                            \
}
/*
 * The ftrace_test_custom_probe is compiled out, it is only here as a build time check
 * to make sure that if the tracepoint handling changes, the ftrace probe will
 * fail to compile unless it too is updated.
 */

#undef DEFINE_CUSTOM_EVENT
#define DEFINE_CUSTOM_EVENT(template, call, proto, args)                \
static inline void ftrace_test_custom_probe_##call(void)                \
{                                                                       \
        check_trace_callback_type_##call(trace_custom_event_raw_event_##template); \
}

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)

/* Stage 7 creates the actual class and event structure for the custom event */

#include "stages/stage7_class_define.h"

#undef DECLARE_CUSTOM_EVENT_CLASS
#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static char custom_print_fmt_##call[] = print;                                  \
static struct trace_event_class __used __refdata custom_event_class_##call = { \
        .system                 = TRACE_SYSTEM_STRING,                  \
        .fields_array           = trace_custom_event_fields_##call,             \
        .fields                 = LIST_HEAD_INIT(custom_event_class_##call.fields),\
        .raw_init               = trace_event_raw_init,                 \
        .probe                  = trace_custom_event_raw_event_##call,  \
        .reg                    = trace_event_reg,                      \
};

#undef DEFINE_CUSTOM_EVENT
#define DEFINE_CUSTOM_EVENT(template, call, proto, args)                \
                                                                        \
static struct trace_event_call __used custom_event_##call = {           \
        .name                   = #call,                                \
        .class                  = &custom_event_class_##template,       \
        .event.funcs            = &trace_custom_event_type_funcs_##template, \
        .print_fmt              = custom_print_fmt_##template,          \
        .flags                  = TRACE_EVENT_FL_CUSTOM,                \
};                                                                      \
static inline int trace_custom_event_##call##_update(struct tracepoint *tp) \
{                                                                       \
        if (tp->name && strcmp(tp->name, #call) == 0) {                 \
                custom_event_##call.tp = tp;                            \
                custom_event_##call.flags = TRACE_EVENT_FL_TRACEPOINT;  \
                return 1;                                               \
        }                                                               \
        return 0;                                                       \
}                                                                       \
static struct trace_event_call __used                                   \
__section("_ftrace_events") *__custom_event_##call = &custom_event_##call

#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)