222 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * This is similar to the trace_events.h file, but is to only4 * create custom trace events to be attached to existing tracepoints.5 * Where as the TRACE_EVENT() macro (from trace_events.h) will create6 * both the trace event and the tracepoint it will attach the event to,7 * TRACE_CUSTOM_EVENT() is to create only a custom version of an existing8 * trace event (created by TRACE_EVENT() or DEFINE_EVENT()), and will9 * be placed in the "custom" system.10 */11 12#include <linux/trace_events.h>13 14/* All custom events are placed in the custom group */15#undef TRACE_SYSTEM16#define TRACE_SYSTEM custom17 18#ifndef TRACE_SYSTEM_VAR19#define TRACE_SYSTEM_VAR TRACE_SYSTEM20#endif21 22/* The init stage creates the system string and enum mappings */23 24#include "stages/init.h"25 26#undef TRACE_CUSTOM_EVENT27#define TRACE_CUSTOM_EVENT(name, proto, args, tstruct, assign, print) \28 DECLARE_CUSTOM_EVENT_CLASS(name, \29 PARAMS(proto), \30 PARAMS(args), \31 PARAMS(tstruct), \32 PARAMS(assign), \33 PARAMS(print)); \34 DEFINE_CUSTOM_EVENT(name, name, PARAMS(proto), PARAMS(args));35 36/* Stage 1 creates the structure of the recorded event layout */37 38#include "stages/stage1_struct_define.h"39 40#undef DECLARE_CUSTOM_EVENT_CLASS41#define DECLARE_CUSTOM_EVENT_CLASS(name, proto, args, tstruct, assign, print) \42 struct trace_custom_event_raw_##name { \43 struct trace_entry ent; \44 tstruct \45 char __data[]; \46 }; \47 \48 static struct trace_event_class custom_event_class_##name;49 50#undef DEFINE_CUSTOM_EVENT51#define DEFINE_CUSTOM_EVENT(template, name, proto, args) \52 static struct trace_event_call __used \53 __attribute__((__aligned__(4))) custom_event_##name54 55#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)56 57/* Stage 2 creates the custom class */58 59#include "stages/stage2_data_offsets.h"60 61#undef DECLARE_CUSTOM_EVENT_CLASS62#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \63 struct trace_custom_event_data_offsets_##call { \64 tstruct; \65 };66 67#undef DEFINE_CUSTOM_EVENT68#define DEFINE_CUSTOM_EVENT(template, name, proto, args)69 70#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)71 72/* Stage 3 create the way to print the custom event */73 74#include "stages/stage3_trace_output.h"75 76#undef DECLARE_CUSTOM_EVENT_CLASS77#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \78static notrace enum print_line_t \79trace_custom_raw_output_##call(struct trace_iterator *iter, int flags, \80 struct trace_event *trace_event) \81{ \82 struct trace_seq *s = &iter->seq; \83 struct trace_seq __maybe_unused *p = &iter->tmp_seq; \84 struct trace_custom_event_raw_##call *field; \85 int ret; \86 \87 field = (typeof(field))iter->ent; \88 \89 ret = trace_raw_output_prep(iter, trace_event); \90 if (ret != TRACE_TYPE_HANDLED) \91 return ret; \92 \93 trace_event_printf(iter, print); \94 \95 return trace_handle_return(s); \96} \97static struct trace_event_functions trace_custom_event_type_funcs_##call = { \98 .trace = trace_custom_raw_output_##call, \99};100 101#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)102 103/* Stage 4 creates the offset layout for the fields */104 105#include "stages/stage4_event_fields.h"106 107#undef DECLARE_CUSTOM_EVENT_CLASS108#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, func, print) \109static struct trace_event_fields trace_custom_event_fields_##call[] = { \110 tstruct \111 {} };112 113#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)114 115/* Stage 5 creates the helper function for dynamic fields */116 117#include "stages/stage5_get_offsets.h"118 119#undef DECLARE_CUSTOM_EVENT_CLASS120#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \121static inline notrace int trace_custom_event_get_offsets_##call( \122 struct trace_custom_event_data_offsets_##call *__data_offsets, proto) \123{ \124 int __data_size = 0; \125 int __maybe_unused __item_length; \126 struct trace_custom_event_raw_##call __maybe_unused *entry; \127 \128 tstruct; \129 \130 return __data_size; \131}132 133#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)134 135/* Stage 6 creates the probe function that records the event */136 137#include "stages/stage6_event_callback.h"138 139#undef DECLARE_CUSTOM_EVENT_CLASS140#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \141 \142static notrace void \143trace_custom_event_raw_event_##call(void *__data, proto) \144{ \145 struct trace_event_file *trace_file = __data; \146 struct trace_custom_event_data_offsets_##call __maybe_unused __data_offsets; \147 struct trace_event_buffer fbuffer; \148 struct trace_custom_event_raw_##call *entry; \149 int __data_size; \150 \151 if (trace_trigger_soft_disabled(trace_file)) \152 return; \153 \154 __data_size = trace_custom_event_get_offsets_##call(&__data_offsets, args); \155 \156 entry = trace_event_buffer_reserve(&fbuffer, trace_file, \157 sizeof(*entry) + __data_size); \158 \159 if (!entry) \160 return; \161 \162 tstruct \163 \164 { assign; } \165 \166 trace_event_buffer_commit(&fbuffer); \167}168/*169 * The ftrace_test_custom_probe is compiled out, it is only here as a build time check170 * to make sure that if the tracepoint handling changes, the ftrace probe will171 * fail to compile unless it too is updated.172 */173 174#undef DEFINE_CUSTOM_EVENT175#define DEFINE_CUSTOM_EVENT(template, call, proto, args) \176static inline void ftrace_test_custom_probe_##call(void) \177{ \178 check_trace_callback_type_##call(trace_custom_event_raw_event_##template); \179}180 181#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)182 183/* Stage 7 creates the actual class and event structure for the custom event */184 185#include "stages/stage7_class_define.h"186 187#undef DECLARE_CUSTOM_EVENT_CLASS188#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \189static char custom_print_fmt_##call[] = print; \190static struct trace_event_class __used __refdata custom_event_class_##call = { \191 .system = TRACE_SYSTEM_STRING, \192 .fields_array = trace_custom_event_fields_##call, \193 .fields = LIST_HEAD_INIT(custom_event_class_##call.fields),\194 .raw_init = trace_event_raw_init, \195 .probe = trace_custom_event_raw_event_##call, \196 .reg = trace_event_reg, \197};198 199#undef DEFINE_CUSTOM_EVENT200#define DEFINE_CUSTOM_EVENT(template, call, proto, args) \201 \202static struct trace_event_call __used custom_event_##call = { \203 .name = #call, \204 .class = &custom_event_class_##template, \205 .event.funcs = &trace_custom_event_type_funcs_##template, \206 .print_fmt = custom_print_fmt_##template, \207 .flags = TRACE_EVENT_FL_CUSTOM, \208}; \209static inline int trace_custom_event_##call##_update(struct tracepoint *tp) \210{ \211 if (tp->name && strcmp(tp->name, #call) == 0) { \212 custom_event_##call.tp = tp; \213 custom_event_##call.flags = TRACE_EVENT_FL_TRACEPOINT; \214 return 1; \215 } \216 return 0; \217} \218static struct trace_event_call __used \219__section("_ftrace_events") *__custom_event_##call = &custom_event_##call220 221#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)222