1 // SPDX-License-Identifier: MIT
3 * Copyright 2022 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
16 #include <side/macros.h>
17 #include <side/endian.h>
20 * SIDE stands for "Software Instrumentation Dynamically Enabled"
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.
26 * This instrumentation ABI exposes 3 type systems:
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.
37 * This is the most expressive of the 3 type systems, althrough not the
38 * fastest due to the extra copy of the arguments.
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.
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.
52 * This type system is has the least overhead of the 3 type systems.
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.
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.
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.
70 * The extensibility scheme for the SIDE ABI is as follows:
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".
90 * Handling of unknown types by the tracers:
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.
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.
103 #define SIDE_EVENT_STATE_ABI_VERSION 0
105 #include <side/abi/event-description.h>
106 #include <side/abi/type-argument.h>
107 #include <side/instrumentation-c-api.h>
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,
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.
125 struct side_event_state
{
126 uint32_t version
; /* Event state ABI version. */
129 struct side_event_state_0
{
130 struct side_event_state p
; /* Required first field. */
132 side_ptr_t(const struct side_callback
) callbacks
;
133 side_ptr_t(struct side_event_description
) desc
;
140 struct side_callback
{
142 void (*call
)(const struct side_event_description
*desc
,
143 const struct side_arg_vec
*side_arg_vec
,
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
,
153 extern const struct side_callback side_empty_callback
;
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
);
161 struct side_events_register_handle
*side_events_register(struct side_event_description
**events
,
163 void side_events_unregister(struct side_events_register_handle
*handle
);
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
171 typedef void (*side_tracer_callback_func
)(const struct side_event_description
*desc
,
172 const struct side_arg_vec
*side_arg_vec
,
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
,
179 int side_tracer_callback_register(struct side_event_description
*desc
,
180 side_tracer_callback_func call
,
182 int side_tracer_callback_variadic_register(struct side_event_description
*desc
,
183 side_tracer_callback_variadic_func call_variadic
,
185 int side_tracer_callback_unregister(struct side_event_description
*desc
,
186 side_tracer_callback_func call
,
188 int side_tracer_callback_variadic_unregister(struct side_event_description
*desc
,
189 side_tracer_callback_variadic_func call_variadic
,
192 enum side_tracer_notification
{
193 SIDE_TRACER_NOTIFICATION_INSERT_EVENTS
,
194 SIDE_TRACER_NOTIFICATION_REMOVE_EVENTS
,
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
),
202 void side_tracer_event_notification_unregister(struct side_tracer_handle
*handle
);
205 * Explicit hooks to initialize/finalize the side instrumentation
206 * library. Those are also library constructor/destructor.
208 void side_init(void) __attribute__((constructor
));
209 void side_exit(void) __attribute__((destructor
));
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.
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).
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")));
232 side_event_description_ptr_init(void)
233 __attribute__((no_instrument_function
))
234 __attribute__((constructor
));
236 side_event_description_ptr_init(void)
238 if (side_event_description_ptr_registered
++)
240 side_events_handle
= side_events_register(__start_side_event_description_ptr
,
241 __stop_side_event_description_ptr
- __start_side_event_description_ptr
);
245 side_event_description_ptr_exit(void)
246 __attribute__((no_instrument_function
))
247 __attribute__((destructor
));
249 side_event_description_ptr_exit(void)
251 if (--side_event_description_ptr_registered
)
253 side_events_unregister(side_events_handle
);
254 side_events_handle
= NULL
;
261 #endif /* _SIDE_TRACE_H */