| /* 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) |