|
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | +/* |
| 3 | + * This is similar to the trace_events.h file, but is to only |
| 4 | + * create custom trace events to be attached to existing tracepoints. |
| 5 | + * Where as the TRACE_EVENT() macro (from trace_events.h) will create |
| 6 | + * 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 existing |
| 8 | + * trace event (created by TRACE_EVENT() or DEFINE_EVENT()), and will |
| 9 | + * 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_SYSTEM |
| 16 | +#define TRACE_SYSTEM custom |
| 17 | + |
| 18 | +#ifndef TRACE_SYSTEM_VAR |
| 19 | +#define TRACE_SYSTEM_VAR TRACE_SYSTEM |
| 20 | +#endif |
| 21 | + |
| 22 | +/* The init stage creates the system string and enum mappings */ |
| 23 | + |
| 24 | +#include "stages/init.h" |
| 25 | + |
| 26 | +#undef TRACE_CUSTOM_EVENT |
| 27 | +#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_defines.h" |
| 39 | + |
| 40 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 41 | +#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_EVENT |
| 51 | +#define DEFINE_CUSTOM_EVENT(template, name, proto, args) \ |
| 52 | + static struct trace_event_call __used \ |
| 53 | + __attribute__((__aligned__(4))) custom_event_##name |
| 54 | + |
| 55 | +#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
| 56 | + |
| 57 | +/* Stage 2 creates the custom class */ |
| 58 | + |
| 59 | +#include "stages/stage2_defines.h" |
| 60 | + |
| 61 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 62 | +#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_EVENT |
| 68 | +#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_defines.h" |
| 75 | + |
| 76 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 77 | +#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
| 78 | +static notrace enum print_line_t \ |
| 79 | +trace_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 | +} \ |
| 97 | +static 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_defines.h" |
| 106 | + |
| 107 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 108 | +#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, func, print) \ |
| 109 | +static 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_defines.h" |
| 118 | + |
| 119 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 120 | +#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
| 121 | +static 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_defines.h" |
| 138 | + |
| 139 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 140 | +#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
| 141 | + \ |
| 142 | +static notrace void \ |
| 143 | +trace_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 check |
| 170 | + * to make sure that if the tracepoint handling changes, the ftrace probe will |
| 171 | + * fail to compile unless it too is updated. |
| 172 | + */ |
| 173 | + |
| 174 | +#undef DEFINE_CUSTOM_EVENT |
| 175 | +#define DEFINE_CUSTOM_EVENT(template, call, proto, args) \ |
| 176 | +static 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_defines.h" |
| 186 | + |
| 187 | +#undef DECLARE_CUSTOM_EVENT_CLASS |
| 188 | +#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ |
| 189 | +static char custom_print_fmt_##call[] = print; \ |
| 190 | +static 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_EVENT |
| 200 | +#define DEFINE_CUSTOM_EVENT(template, call, proto, args) \ |
| 201 | + \ |
| 202 | +static 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 | +}; \ |
| 209 | +static 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 | +} \ |
| 218 | +static struct trace_event_call __used \ |
| 219 | +__section("_ftrace_events") *__custom_event_##call = &custom_event_##call |
| 220 | + |
| 221 | +#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) |
0 commit comments