Move ABI headers under side/abi/
[libside.git] / include / side / trace.h
1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 */
5
6 #ifndef _SIDE_TRACE_H
7 #define _SIDE_TRACE_H
8
9 #include <stdint.h>
10 #include <inttypes.h>
11 #include <stdlib.h>
12 #include <stdio.h>
13 #include <math.h>
14 #include <stdbool.h>
15 #include <stddef.h>
16 #include <side/macros.h>
17 #include <side/endian.h>
18
19 /*
20 * SIDE stands for "Software Instrumentation Dynamically Enabled"
21 *
22 * This is an instrumentation ABI for Linux user-space, which exposes an
23 * instrumentation type system and facilities allowing a kernel or
24 * user-space tracer to consume user-space instrumentation.
25 *
26 * This instrumentation ABI exposes 3 type systems:
27 *
28 * * Stack-copy type system: This is the core type system which can
29 * represent all supported types and into which all other type systems
30 * can be nested. This type system requires that every type is
31 * statically or dynamically declared and then registered, thus giving
32 * tracers a complete description of the events and their associated
33 * fields before the associated instrumentation is invoked. The
34 * application needs to copy each argument (side_arg_...()) onto the
35 * stack when calling the instrumentation.
36 *
37 * This is the most expressive of the 3 type systems, althrough not the
38 * fastest due to the extra copy of the arguments.
39 *
40 * * Data-gathering type system: This type system requires every type to
41 * be statically or dynamically declared and registered, but does not
42 * require the application to copy its arguments onto the stack.
43 * Instead, the type description contains all the required information
44 * to fetch the data from the application memory. The only argument
45 * required from the instrumentation is the base pointer from which
46 * the data should be fetched.
47 *
48 * This type system can be used as an event field, or nested within
49 * the stack-copy type system. Nesting of gather-vla within
50 * gather-array and gather-vla types is not allowed.
51 *
52 * This type system is has the least overhead of the 3 type systems.
53 *
54 * * Dynamic type system: This type system receives both type
55 * description and actual data onto the stack at runtime. It has more
56 * overhead that the 2 other type systems, but does not require a
57 * prior registration of event field description. This makes it useful
58 * for seldom used types which are not performance critical, but for
59 * which registering each individual events would needlessly grow the
60 * number of events to declare and register.
61 *
62 * Another use-case for this type system is for use by dynamically
63 * typed language runtimes, where the field type is only known when
64 * the instrumentation is called.
65 *
66 * Those dynamic types can be either used as arguments to a variadic
67 * field list, or as on-stack instrumentation argument for a static
68 * type SIDE_TYPE_DYNAMIC place holder in the stack-copy type system.
69 *
70 * The extensibility scheme for the SIDE ABI is as follows:
71 *
72 * * Existing field types are never changed nor extended. Field types
73 * can be added to the ABI by reserving a label within
74 * enum side_type_label.
75 * * Existing attribute types are never changed nor extended. Attribute
76 * types can be added to the ABI by reserving a label within
77 * enum side_attr_type.
78 * * Each union part of the ABI has an explicit size defined by a
79 * side_padding() member. Each structure and union have a static
80 * assert validating its size.
81 * * If the semantic of the existing event description or type fields
82 * change, the SIDE_EVENT_DESCRIPTION_ABI_VERSION should be increased.
83 * * If the semantic of the "struct side_event_state_N" fields change,
84 * the SIDE_EVENT_STATE_ABI_VERSION should be increased. The
85 * "struct side_event_state_N" is not extensible and must have its
86 * ABI version increased whenever it is changed. Note that increasing
87 * the version of SIDE_EVENT_DESCRIPTION_ABI_VERSION is not necessary
88 * when changing the layout of "struct side_event_state_N".
89 *
90 * Handling of unknown types by the tracers:
91 *
92 * * A tracer may choose to support only a subset of the types supported
93 * by libside. When encountering an unknown or unsupported type, the
94 * tracer has the option to either disallow the entire event or skip
95 * over the unknown type, both at event registration and when
96 * receiving the side_call arguments.
97 *
98 * * Event descriptions can be extended by adding fields at the end of
99 * the structure. The "struct side_event_description" is a structure
100 * with flexible size which must not be used within arrays.
101 */
102
103 #define SIDE_EVENT_STATE_ABI_VERSION 0
104
105 #include <side/abi/event-description.h>
106 #include <side/abi/type-argument.h>
107 #include <side/instrumentation-c-api.h>
108
109 enum side_error {
110 SIDE_ERROR_OK = 0,
111 SIDE_ERROR_INVAL = 1,
112 SIDE_ERROR_EXIST = 2,
113 SIDE_ERROR_NOMEM = 3,
114 SIDE_ERROR_NOENT = 4,
115 SIDE_ERROR_EXITING = 5,
116 };
117
118 /*
119 * This structure is _not_ packed to allow atomic operations on its
120 * fields. Changes to this structure must bump the "Event state ABI
121 * version" and tracers _must_ learn how to deal with this ABI,
122 * otherwise they should reject the event.
123 */
124
125 struct side_event_state {
126 uint32_t version; /* Event state ABI version. */
127 };
128
129 struct side_event_state_0 {
130 struct side_event_state p; /* Required first field. */
131 uint32_t enabled;
132 side_ptr_t(const struct side_callback) callbacks;
133 side_ptr_t(struct side_event_description) desc;
134 };
135
136 #ifdef __cplusplus
137 extern "C" {
138 #endif
139
140 struct side_callback {
141 union {
142 void (*call)(const struct side_event_description *desc,
143 const struct side_arg_vec *side_arg_vec,
144 void *priv);
145 void (*call_variadic)(const struct side_event_description *desc,
146 const struct side_arg_vec *side_arg_vec,
147 const struct side_arg_dynamic_struct *var_struct,
148 void *priv);
149 } SIDE_PACKED u;
150 void *priv;
151 } SIDE_PACKED;
152
153 extern const struct side_callback side_empty_callback;
154
155 void side_call(const struct side_event_state *state,
156 const struct side_arg_vec *side_arg_vec);
157 void side_call_variadic(const struct side_event_state *state,
158 const struct side_arg_vec *side_arg_vec,
159 const struct side_arg_dynamic_struct *var_struct);
160
161 struct side_events_register_handle *side_events_register(struct side_event_description **events,
162 uint32_t nr_events);
163 void side_events_unregister(struct side_events_register_handle *handle);
164
165 /*
166 * Userspace tracer registration API. This allows userspace tracers to
167 * register event notification callbacks to be notified of the currently
168 * registered instrumentation, and to register their callbacks to
169 * specific events.
170 */
171 typedef void (*side_tracer_callback_func)(const struct side_event_description *desc,
172 const struct side_arg_vec *side_arg_vec,
173 void *priv);
174 typedef void (*side_tracer_callback_variadic_func)(const struct side_event_description *desc,
175 const struct side_arg_vec *side_arg_vec,
176 const struct side_arg_dynamic_struct *var_struct,
177 void *priv);
178
179 int side_tracer_callback_register(struct side_event_description *desc,
180 side_tracer_callback_func call,
181 void *priv);
182 int side_tracer_callback_variadic_register(struct side_event_description *desc,
183 side_tracer_callback_variadic_func call_variadic,
184 void *priv);
185 int side_tracer_callback_unregister(struct side_event_description *desc,
186 side_tracer_callback_func call,
187 void *priv);
188 int side_tracer_callback_variadic_unregister(struct side_event_description *desc,
189 side_tracer_callback_variadic_func call_variadic,
190 void *priv);
191
192 enum side_tracer_notification {
193 SIDE_TRACER_NOTIFICATION_INSERT_EVENTS,
194 SIDE_TRACER_NOTIFICATION_REMOVE_EVENTS,
195 };
196
197 /* Callback is invoked with side library internal lock held. */
198 struct side_tracer_handle *side_tracer_event_notification_register(
199 void (*cb)(enum side_tracer_notification notif,
200 struct side_event_description **events, uint32_t nr_events, void *priv),
201 void *priv);
202 void side_tracer_event_notification_unregister(struct side_tracer_handle *handle);
203
204 /*
205 * Explicit hooks to initialize/finalize the side instrumentation
206 * library. Those are also library constructor/destructor.
207 */
208 void side_init(void) __attribute__((constructor));
209 void side_exit(void) __attribute__((destructor));
210
211 /*
212 * The following constructors/destructors perform automatic registration
213 * of the declared side events. Those may have to be called explicitly
214 * in a statically linked library.
215 */
216
217 /*
218 * These weak symbols, the constructor, and destructor take care of
219 * registering only _one_ instance of the side instrumentation per
220 * shared-ojbect (or for the whole main program).
221 */
222 extern struct side_event_description * __start_side_event_description_ptr[]
223 __attribute__((weak, visibility("hidden")));
224 extern struct side_event_description * __stop_side_event_description_ptr[]
225 __attribute__((weak, visibility("hidden")));
226 int side_event_description_ptr_registered
227 __attribute__((weak, visibility("hidden")));
228 struct side_events_register_handle *side_events_handle
229 __attribute__((weak, visibility("hidden")));
230
231 static void
232 side_event_description_ptr_init(void)
233 __attribute__((no_instrument_function))
234 __attribute__((constructor));
235 static void
236 side_event_description_ptr_init(void)
237 {
238 if (side_event_description_ptr_registered++)
239 return;
240 side_events_handle = side_events_register(__start_side_event_description_ptr,
241 __stop_side_event_description_ptr - __start_side_event_description_ptr);
242 }
243
244 static void
245 side_event_description_ptr_exit(void)
246 __attribute__((no_instrument_function))
247 __attribute__((destructor));
248 static void
249 side_event_description_ptr_exit(void)
250 {
251 if (--side_event_description_ptr_registered)
252 return;
253 side_events_unregister(side_events_handle);
254 side_events_handle = NULL;
255 }
256
257 #ifdef __cplusplus
258 }
259 #endif
260
261 #endif /* _SIDE_TRACE_H */
This page took 0.038765 seconds and 4 git commands to generate.