162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This is similar to the trace_events.h file, but is to only
462306a36Sopenharmony_ci * create custom trace events to be attached to existing tracepoints.
562306a36Sopenharmony_ci * Where as the TRACE_EVENT() macro (from trace_events.h) will create
662306a36Sopenharmony_ci * both the trace event and the tracepoint it will attach the event to,
762306a36Sopenharmony_ci * TRACE_CUSTOM_EVENT() is to create only a custom version of an existing
862306a36Sopenharmony_ci * trace event (created by TRACE_EVENT() or DEFINE_EVENT()), and will
962306a36Sopenharmony_ci * be placed in the "custom" system.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/trace_events.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/* All custom events are placed in the custom group */
1562306a36Sopenharmony_ci#undef TRACE_SYSTEM
1662306a36Sopenharmony_ci#define TRACE_SYSTEM custom
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifndef TRACE_SYSTEM_VAR
1962306a36Sopenharmony_ci#define TRACE_SYSTEM_VAR TRACE_SYSTEM
2062306a36Sopenharmony_ci#endif
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* The init stage creates the system string and enum mappings */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include "stages/init.h"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#undef TRACE_CUSTOM_EVENT
2762306a36Sopenharmony_ci#define TRACE_CUSTOM_EVENT(name, proto, args, tstruct, assign, print) \
2862306a36Sopenharmony_ci	DECLARE_CUSTOM_EVENT_CLASS(name,			      \
2962306a36Sopenharmony_ci			     PARAMS(proto),		       \
3062306a36Sopenharmony_ci			     PARAMS(args),		       \
3162306a36Sopenharmony_ci			     PARAMS(tstruct),		       \
3262306a36Sopenharmony_ci			     PARAMS(assign),		       \
3362306a36Sopenharmony_ci			     PARAMS(print));		       \
3462306a36Sopenharmony_ci	DEFINE_CUSTOM_EVENT(name, name, PARAMS(proto), PARAMS(args));
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Stage 1 creates the structure of the recorded event layout */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#include "stages/stage1_struct_define.h"
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
4162306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(name, proto, args, tstruct, assign, print) \
4262306a36Sopenharmony_ci	struct trace_custom_event_raw_##name {				\
4362306a36Sopenharmony_ci		struct trace_entry	ent;				\
4462306a36Sopenharmony_ci		tstruct							\
4562306a36Sopenharmony_ci		char			__data[];			\
4662306a36Sopenharmony_ci	};								\
4762306a36Sopenharmony_ci									\
4862306a36Sopenharmony_ci	static struct trace_event_class custom_event_class_##name;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#undef DEFINE_CUSTOM_EVENT
5162306a36Sopenharmony_ci#define DEFINE_CUSTOM_EVENT(template, name, proto, args)	\
5262306a36Sopenharmony_ci	static struct trace_event_call	__used			\
5362306a36Sopenharmony_ci	__attribute__((__aligned__(4))) custom_event_##name
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Stage 2 creates the custom class */
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#include "stages/stage2_data_offsets.h"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
6262306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print)	\
6362306a36Sopenharmony_ci	struct trace_custom_event_data_offsets_##call {			\
6462306a36Sopenharmony_ci		tstruct;						\
6562306a36Sopenharmony_ci	};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci#undef DEFINE_CUSTOM_EVENT
6862306a36Sopenharmony_ci#define DEFINE_CUSTOM_EVENT(template, name, proto, args)
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* Stage 3 create the way to print the custom event */
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#include "stages/stage3_trace_output.h"
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
7762306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
7862306a36Sopenharmony_cistatic notrace enum print_line_t					\
7962306a36Sopenharmony_citrace_custom_raw_output_##call(struct trace_iterator *iter, int flags,	\
8062306a36Sopenharmony_ci			struct trace_event *trace_event)		\
8162306a36Sopenharmony_ci{									\
8262306a36Sopenharmony_ci	struct trace_seq *s = &iter->seq;				\
8362306a36Sopenharmony_ci	struct trace_seq __maybe_unused *p = &iter->tmp_seq;		\
8462306a36Sopenharmony_ci	struct trace_custom_event_raw_##call *field;			\
8562306a36Sopenharmony_ci	int ret;							\
8662306a36Sopenharmony_ci									\
8762306a36Sopenharmony_ci	field = (typeof(field))iter->ent;				\
8862306a36Sopenharmony_ci									\
8962306a36Sopenharmony_ci	ret = trace_raw_output_prep(iter, trace_event);			\
9062306a36Sopenharmony_ci	if (ret != TRACE_TYPE_HANDLED)					\
9162306a36Sopenharmony_ci		return ret;						\
9262306a36Sopenharmony_ci									\
9362306a36Sopenharmony_ci	trace_event_printf(iter, print);				\
9462306a36Sopenharmony_ci									\
9562306a36Sopenharmony_ci	return trace_handle_return(s);					\
9662306a36Sopenharmony_ci}									\
9762306a36Sopenharmony_cistatic struct trace_event_functions trace_custom_event_type_funcs_##call = { \
9862306a36Sopenharmony_ci	.trace			= trace_custom_raw_output_##call,	\
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* Stage 4 creates the offset layout for the fields */
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci#include "stages/stage4_event_fields.h"
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
10862306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, func, print)	\
10962306a36Sopenharmony_cistatic struct trace_event_fields trace_custom_event_fields_##call[] = {	\
11062306a36Sopenharmony_ci	tstruct								\
11162306a36Sopenharmony_ci	{} };
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Stage 5 creates the helper function for dynamic fields */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#include "stages/stage5_get_offsets.h"
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
12062306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
12162306a36Sopenharmony_cistatic inline notrace int trace_custom_event_get_offsets_##call(	\
12262306a36Sopenharmony_ci	struct trace_custom_event_data_offsets_##call *__data_offsets, proto) \
12362306a36Sopenharmony_ci{									\
12462306a36Sopenharmony_ci	int __data_size = 0;						\
12562306a36Sopenharmony_ci	int __maybe_unused __item_length;				\
12662306a36Sopenharmony_ci	struct trace_custom_event_raw_##call __maybe_unused *entry;	\
12762306a36Sopenharmony_ci									\
12862306a36Sopenharmony_ci	tstruct;							\
12962306a36Sopenharmony_ci									\
13062306a36Sopenharmony_ci	return __data_size;						\
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/* Stage 6 creates the probe function that records the event */
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#include "stages/stage6_event_callback.h"
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
14062306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
14162306a36Sopenharmony_ci									\
14262306a36Sopenharmony_cistatic notrace void							\
14362306a36Sopenharmony_citrace_custom_event_raw_event_##call(void *__data, proto)		\
14462306a36Sopenharmony_ci{									\
14562306a36Sopenharmony_ci	struct trace_event_file *trace_file = __data;			\
14662306a36Sopenharmony_ci	struct trace_custom_event_data_offsets_##call __maybe_unused __data_offsets; \
14762306a36Sopenharmony_ci	struct trace_event_buffer fbuffer;				\
14862306a36Sopenharmony_ci	struct trace_custom_event_raw_##call *entry;			\
14962306a36Sopenharmony_ci	int __data_size;						\
15062306a36Sopenharmony_ci									\
15162306a36Sopenharmony_ci	if (trace_trigger_soft_disabled(trace_file))			\
15262306a36Sopenharmony_ci		return;							\
15362306a36Sopenharmony_ci									\
15462306a36Sopenharmony_ci	__data_size = trace_custom_event_get_offsets_##call(&__data_offsets, args); \
15562306a36Sopenharmony_ci									\
15662306a36Sopenharmony_ci	entry = trace_event_buffer_reserve(&fbuffer, trace_file,	\
15762306a36Sopenharmony_ci				 sizeof(*entry) + __data_size);		\
15862306a36Sopenharmony_ci									\
15962306a36Sopenharmony_ci	if (!entry)							\
16062306a36Sopenharmony_ci		return;							\
16162306a36Sopenharmony_ci									\
16262306a36Sopenharmony_ci	tstruct								\
16362306a36Sopenharmony_ci									\
16462306a36Sopenharmony_ci	{ assign; }							\
16562306a36Sopenharmony_ci									\
16662306a36Sopenharmony_ci	trace_event_buffer_commit(&fbuffer);				\
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci/*
16962306a36Sopenharmony_ci * The ftrace_test_custom_probe is compiled out, it is only here as a build time check
17062306a36Sopenharmony_ci * to make sure that if the tracepoint handling changes, the ftrace probe will
17162306a36Sopenharmony_ci * fail to compile unless it too is updated.
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci#undef DEFINE_CUSTOM_EVENT
17562306a36Sopenharmony_ci#define DEFINE_CUSTOM_EVENT(template, call, proto, args)		\
17662306a36Sopenharmony_cistatic inline void ftrace_test_custom_probe_##call(void)		\
17762306a36Sopenharmony_ci{									\
17862306a36Sopenharmony_ci	check_trace_callback_type_##call(trace_custom_event_raw_event_##template); \
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* Stage 7 creates the actual class and event structure for the custom event */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#include "stages/stage7_class_define.h"
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci#undef DECLARE_CUSTOM_EVENT_CLASS
18862306a36Sopenharmony_ci#define DECLARE_CUSTOM_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
18962306a36Sopenharmony_cistatic char custom_print_fmt_##call[] = print;					\
19062306a36Sopenharmony_cistatic struct trace_event_class __used __refdata custom_event_class_##call = { \
19162306a36Sopenharmony_ci	.system			= TRACE_SYSTEM_STRING,			\
19262306a36Sopenharmony_ci	.fields_array		= trace_custom_event_fields_##call,		\
19362306a36Sopenharmony_ci	.fields			= LIST_HEAD_INIT(custom_event_class_##call.fields),\
19462306a36Sopenharmony_ci	.raw_init		= trace_event_raw_init,			\
19562306a36Sopenharmony_ci	.probe			= trace_custom_event_raw_event_##call,	\
19662306a36Sopenharmony_ci	.reg			= trace_event_reg,			\
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#undef DEFINE_CUSTOM_EVENT
20062306a36Sopenharmony_ci#define DEFINE_CUSTOM_EVENT(template, call, proto, args)		\
20162306a36Sopenharmony_ci									\
20262306a36Sopenharmony_cistatic struct trace_event_call __used custom_event_##call = {		\
20362306a36Sopenharmony_ci	.name			= #call,				\
20462306a36Sopenharmony_ci	.class			= &custom_event_class_##template,	\
20562306a36Sopenharmony_ci	.event.funcs		= &trace_custom_event_type_funcs_##template, \
20662306a36Sopenharmony_ci	.print_fmt		= custom_print_fmt_##template,		\
20762306a36Sopenharmony_ci	.flags			= TRACE_EVENT_FL_CUSTOM,		\
20862306a36Sopenharmony_ci};									\
20962306a36Sopenharmony_cistatic inline int trace_custom_event_##call##_update(struct tracepoint *tp) \
21062306a36Sopenharmony_ci{									\
21162306a36Sopenharmony_ci	if (tp->name && strcmp(tp->name, #call) == 0) {			\
21262306a36Sopenharmony_ci		custom_event_##call.tp = tp;				\
21362306a36Sopenharmony_ci		custom_event_##call.flags = TRACE_EVENT_FL_TRACEPOINT;	\
21462306a36Sopenharmony_ci		return 1;						\
21562306a36Sopenharmony_ci	}								\
21662306a36Sopenharmony_ci	return 0;							\
21762306a36Sopenharmony_ci}									\
21862306a36Sopenharmony_cistatic struct trace_event_call __used					\
21962306a36Sopenharmony_ci__section("_ftrace_events") *__custom_event_##call = &custom_event_##call
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
222