• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */