forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
7.1 KiB
221 lines
7.1 KiB
/* 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)
|
|
|