1 /* SPDX-License-Identifier: GPL-2.0 */ 2 3 /* 4 * Note: we intentionally omit include file ifdef protection 5 * This is due to the way trace events work. If a file includes two 6 * trace event headers under one "CREATE_TRACE_POINTS" the first include 7 * will override the DECLARE_RESTRICTED_HOOK and break the second include. 8 */ 9 #ifndef TRACE_HOOKS_VENDORHOOKS_H 10 #define TRACE_HOOKS_VENDORHOOKS_H 11 12 #include <linux/tracepoint.h> 13 14 #if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_VENDOR_HOOKS) 15 16 #define DECLARE_HOOK DECLARE_TRACE 17 18 #ifdef TRACE_HEADER_MULTI_READ 19 20 #define DEFINE_HOOK_FN(_name, _reg, _unreg, proto, args) \ 21 static const char __tpstrtab_##_name[] __section("__tracepoints_strings") = #_name; \ 22 extern struct static_call_key STATIC_CALL_KEY(tp_func_##_name); \ 23 int __traceiter_##_name(void *__data, proto); \ 24 struct tracepoint __tracepoint_##_name __used __section("__tracepoints") = { \ 25 .name = __tpstrtab_##_name, \ 26 .key = STATIC_KEY_INIT_FALSE, \ 27 .static_call_key = &STATIC_CALL_KEY(tp_func_##_name), \ 28 .static_call_tramp = STATIC_CALL_TRAMP_ADDR(tp_func_##_name), \ 29 .iterator = &__traceiter_##_name, \ 30 .regfunc = _reg, \ 31 .unregfunc = _unreg, \ 32 .funcs = NULL}; \ 33 __TRACEPOINT_ENTRY(_name); \ 34 int __traceiter_##_name(void *__data, proto) \ 35 { \ 36 struct tracepoint_func *it_func_ptr; \ 37 void *it_func; \ 38 \ 39 it_func_ptr = (&__tracepoint_##_name)->funcs; \ 40 it_func = (it_func_ptr)->func; \ 41 __data = (it_func_ptr)->data; \ 42 ((void (*)(void *, proto))(it_func))(__data, args); \ 43 WARN_ON(((++it_func_ptr)->func)); \ 44 return 0; \ 45 } \ 46 DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name); 47 48 #undef DECLARE_RESTRICTED_HOOK 49 #define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) DEFINE_HOOK_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args)) 50 51 /* prevent additional recursion */ 52 #undef TRACE_HEADER_MULTI_READ 53 #else /* TRACE_HEADER_MULTI_READ */ 54 55 #ifdef CONFIG_HAVE_STATIC_CALL 56 #define I_DO_RESTRICTED_HOOK_CALL(name, args) \ 57 do { \ 58 struct tracepoint_func *it_func_ptr; \ 59 void *__data; \ 60 it_func_ptr = (&__tracepoint_##name)->funcs; \ 61 if (it_func_ptr) { \ 62 __data = (it_func_ptr)->data; \ 63 static_call(tp_func_##name)(__data, args); \ 64 } \ 65 } while (0) 66 #else 67 #define I_DO_RESTRICTED_HOOK_CALL(name, args) __traceiter_##name(NULL, args) 68 #endif 69 70 #define DO_RESTRICTED_HOOK(name, args, cond) \ 71 do { \ 72 if (!(cond)) \ 73 return; \ 74 \ 75 I_DO_RESTRICTED_HOOK_CALL(name, TP_ARGS(args)); \ 76 } while (0) 77 78 #define I_DECLARE_RESTRICTED_HOOK(name, proto, args, cond, data_proto) \ 79 extern int __traceiter_##name(data_proto); \ 80 DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name); \ 81 extern struct tracepoint __tracepoint_##name; \ 82 static inline void trace_##name(proto) \ 83 { \ 84 if (static_key_false(&__tracepoint_##name.key)) \ 85 DO_RESTRICTED_HOOK(name, TP_ARGS(args), TP_CONDITION(cond)); \ 86 } \ 87 static inline bool trace_##name##_enabled(void) \ 88 { \ 89 return static_key_false(&__tracepoint_##name.key); \ 90 } \ 91 static inline int register_trace_##name(void (*probe)(data_proto), void *data) \ 92 { \ 93 /* only allow a single attachment */ \ 94 if (trace_##name##_enabled()) \ 95 return -EBUSY; \ 96 return tracepoint_probe_register(&__tracepoint_##name, (void *)probe, data); \ 97 } \ 98 /* vendor hooks cannot be unregistered */ 99 100 #undef DECLARE_RESTRICTED_HOOK 101 #define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) \ 102 I_DECLARE_RESTRICTED_HOOK(name, PARAMS(proto), PARAMS(args), cond, PARAMS(void *__data, proto)) 103 104 #endif /* TRACE_HEADER_MULTI_READ */ 105 106 #else /* !CONFIG_TRACEPOINTS || !CONFIG_VENDOR_HOOKS */ 107 /* suppress trace hooks */ 108 #define DECLARE_HOOK DECLARE_EVENT_NOP 109 #define DECLARE_RESTRICTED_HOOK(name, proto, args, cond) DECLARE_EVENT_NOP((name), PARAMS(proto), PARAMS(args)) 110 #endif 111 112 #endif /* TRACE_HOOKS_VENDORHOOKS_H */