222 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			222 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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)
 |