Using the TRACE_EVENT() macro (Part 1)
https://lwn.net/Articles/379903/
Using the TRACE_EVENT() macro (Part 2)
https://lwn.net/Articles/381064/
Using the TRACE_EVENT() macro (Part 3)
https://lwn.net/Articles/383362/
include/trace/events/
一个宏TRACE_EVENT 可以展开成多种形式,定义不同函数、结构体、变量。
原理是,包含一次头文件,然后头文件内部的递归调用,每次递归时把原来的宏取消(#undef),再次定义成新的(#define)
printk.h的展开结果:(使用make kernel/printk/printk.i)
extern struct tracepoint __tracepoint_console;
static inline void trace_console(const char *text, size_t len)
{
if (static_key_false(&__tracepoint_console.key))
do { struct tracepoint_func *it_func_ptr;
void *it_func; void *__data;
if (!((((*({ (void)(0); ({ do { const void *__vpp_verify = (typeof((&cpu_number) + 0))((void *)0);
(void)__vpp_verify; } while (0); (typeof(*(&cpu_number)) *)(&cpu_number); }); }))) == 0)))
return; ;
rcu_read_lock_sched_notrace();
it_func_ptr = ({ typeof(*((&__tracepoint_console)->funcs)) *________p1 = (typeof(*((&__tracepoint_console)->funcs)) *)({ typeof(((&__tracepoint_console)->funcs)) _________p1 = READ_ONCE(((&__tracepoint_console)->funcs));
do { } while(0); (_________p1); }); do { } while (0); ; ((typeof(*((&__tracepoint_console)->funcs)) *)(________p1)); });
if (it_func_ptr)
{
do { it_func = (it_func_ptr)->func;
__data = (it_func_ptr)->data;
((void(*)(void *__data, const char *text, size_t len))(it_func))(__data, text, len);
} while ((++it_func_ptr)->func);
}
rcu_read_unlock_sched_notrace(); ; }
while (0);
if ((0 || 0) && ((((*({ (void)(0); ({ do { const void *__vpp_verify = (typeof((&cpu_number) + 0))
((void *)0); (void)__vpp_verify; } while (0); (typeof(*(&cpu_number)) *)(&cpu_number); }); }))) == 0)))
{
rcu_read_lock_sched_notrace();
({ typeof(*(__tracepoint_console.funcs)) *________p1 =
(typeof(*(__tracepoint_console.funcs)) *)({ typeof((__tracepoint_console.funcs)) _________p1 = READ_ONCE((__tracepoint_console.funcs));
do { } while(0); (_________p1); }); do { } while (0); ; ((typeof(*(__tracepoint_console.funcs)) *)(________p1)); });
rcu_read_unlock_sched_notrace();
}
}
static inline void trace_console_rcuidle(const char *text, size_t len)
{
if (static_key_false(&__tracepoint_console.key))
do {
struct tracepoint_func *it_func_ptr;
void *it_func;
void *__data;
if (!((((*({ (void)(0); ({ do { const void *__vpp_verify = (typeof((&cpu_number) + 0))
((void *)0); (void)__vpp_verify; } while (0); (typeof(*(&cpu_number)) *)(&cpu_number); }); }))) == 0)))
return;
rcu_irq_enter();
rcu_read_lock_sched_notrace();
it_func_ptr = ({ typeof(*((&__tracepoint_console)->funcs)) *________p1 =
(typeof(*((&__tracepoint_console)->funcs)) *)({ typeof(((&__tracepoint_console)->funcs)) _________p1 =
READ_ONCE(((&__tracepoint_console)->funcs)); do { } while(0); (_________p1); }); do { } while (0); ;
((typeof(*((&__tracepoint_console)->funcs)) *)(________p1)); });
if (it_func_ptr)
{
do { it_func = (it_func_ptr)->func; __data =
(it_func_ptr)->data; ((void(*)(void *__data, const char *text, size_t len))(it_func))(__data, text, len); } while ((++it_func_ptr)->func);
}
rcu_read_unlock_sched_notrace();
rcu_irq_exit();
}while (0);
}
static inline int register_trace_console(void (*probe)(void *__data, const char *text, size_t len), void *data)
{
return tracepoint_probe_register(&__tracepoint_console, (void *)probe, data);
}
static inline int register_trace_prio_console(void (*probe)(void *__data, const char *text, size_t len), void *data, int prio)
{
return tracepoint_probe_register_prio(&__tracepoint_console, (void *)probe, data, prio);
}
static inline int unregister_trace_console(void (*probe)(void *__data, const char *text, size_t len), void *data)
{ return tracepoint_probe_unregister(&__tracepoint_console, (void *)probe, data); }
static inline void check_trace_callback_type_console(void (*cb)(void *__data, const char *text, size_t len))
{ }
static inline bool trace_console_enabled(void)
{ return static_key_false(&__tracepoint_console.key); }
static const char __tpstrtab_console[] __attribute__((section("__tracepoints_strings"))) = "console";
struct tracepoint __tracepoint_console __attribute__((section("__tracepoints"))) =
{ __tpstrtab_console,
{ .enabled = ATOMIC_INIT(0) },
((void *)0),
((void *)0),
((void *)0)
};
static struct tracepoint * const __tracepoint_ptr_console __used __attribute__((section("__tracepoints_ptrs"))) = &__tracepoint_console;;
static const char str__printk__trace_system_name[] = "printk";
struct trace_event_raw_console {
struct trace_entry ent;
u32 __data_loc_msg; trace_event_data_offsets_console.msg
char __data[0];
};
static struct trace_event_class event_class_console;;
static struct trace_event_call __used __attribute__((__aligned__(4))) event_console;
struct trace_event_data_offsets_console {
u32 msg;
};; ;
static notrace enum print_line_t
trace_raw_output_console(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_event_raw_console *field;
int ret;
field = (typeof(field))iter->ent;
ret = trace_raw_output_prep(iter, trace_event);
if (ret != TRACE_TYPE_HANDLED)
return ret;
trace_seq_printf(s, "%s" "\n", (char *)((void *)field + (field->__data_loc_msg & 0xffff)));
return trace_handle_return(s);
}
static struct trace_event_functions trace_event_type_funcs_console = {
.trace = trace_raw_output_console,
};;
static int notrace __attribute__ ((__section__(".init.text"))) notrace trace_event_define_fields_console(struct trace_event_call *event_call)
{
struct trace_event_raw_console field;
int ret;
ret = trace_define_field(event_call,
"__data_loc " "char" "[]",
"msg",
((size_t)&((typeof(field) *)0)->__data_loc_msg), /* offset */
sizeof(field.__data_loc_msg), /* size */
(((char)(-1)) < (char)1), /* is_signed */
FILTER_OTHER);; /* filter_type */
return ret;
}; ;
static inline notrace int trace_event_get_offsets_console(struct trace_event_data_offsets_console *__data_offsets, const char *text, size_t len)
{
int __data_size = 0;
int __maybe_unused __item_length;
struct trace_event_raw_console __maybe_unused *entry;
__item_length = (len + 1) * sizeof(char);
__data_offsets->msg = __data_size + ((size_t)&((typeof(*entry) *)0)->__data);
__data_offsets->msg |= __item_length << 16;
__data_size += __item_length;;
return __data_size;
}; ;
static notrace void trace_event_raw_event_console(void *__data, const char *text, size_t len)
{
struct trace_event_file *trace_file = __data;
struct trace_event_data_offsets_console __maybe_unused __data_offsets;
struct trace_event_buffer fbuffer;
struct trace_event_raw_console *entry;
int __data_size;
if (trace_trigger_soft_disabled(trace_file))
return;
__data_size = trace_event_get_offsets_console(&__data_offsets, text, len);
entry = trace_event_buffer_reserve(&fbuffer, trace_file, sizeof(*entry) + __data_size);
if (!entry)
return;
entry->__data_loc_msg = __data_offsets.msg;
{ memcpy(((void *)entry + (entry->__data_loc_msg & 0xffff)), text, len);
((char *)((void *)entry + (entry->__data_loc_msg & 0xffff)))[len] = 0;; }
trace_event_buffer_commit(&fbuffer);
};
static inline void ftrace_test_probe_console(void)
{
check_trace_callback_type_console(trace_event_raw_event_console);
};
static notrace void perf_trace_console(void *__data, const char *text, size_t len);;
static char print_fmt_console[] = "\"" "%s" "\", " "__get_str(msg)";
static struct trace_event_class __used __attribute__ ((__section__(".ref.data"))) event_class_console = {
.system = str__printk__trace_system_name,
.define_fields = trace_event_define_fields_console,
.fields = { &(event_class_console.fields), &(event_class_console.fields) },
.probe = trace_event_raw_event_console,
.reg = trace_event_reg,
.perf_probe = perf_trace_console,
};;
static struct trace_event_call __used event_console = {
.class = &event_class_console,
{
.tp = &__tracepoint_console,
},
.event.funcs = &trace_event_type_funcs_console,
.print_fmt = print_fmt_console,
.flags = TRACE_EVENT_FL_TRACEPOINT,
};
static struct trace_event_call __used __attribute__((section("_ftrace_events"))) *__event_console = &event_console;