Split trace.h into API/ABI sub-headers
[libside.git] / include / side / trace.h
CommitLineData
67337c4a
MD
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>
25ea4c79 14#include <stdbool.h>
441235e7 15#include <stddef.h>
67337c4a
MD
16#include <side/macros.h>
17#include <side/endian.h>
18
19/*
551d8244 20 * SIDE stands for "Software Instrumentation Dynamically Enabled"
67337c4a 21 *
2e197497 22 * This is an instrumentation ABI for Linux user-space, which exposes an
67337c4a
MD
23 * instrumentation type system and facilities allowing a kernel or
24 * user-space tracer to consume user-space instrumentation.
25 *
2e197497 26 * This instrumentation ABI exposes 3 type systems:
67337c4a
MD
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.
2e197497
MD
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.
b2a84b9f 78 * * Each union part of the ABI has an explicit size defined by a
2e197497
MD
79 * side_padding() member. Each structure and union have a static
80 * assert validating its size.
b2a84b9f
MD
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".
2e197497
MD
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 *
441235e7 98 * * Event descriptions can be extended by adding fields at the end of
b2a84b9f
MD
99 * the structure. The "struct side_event_description" is a structure
100 * with flexible size which must not be used within arrays.
67337c4a
MD
101 */
102
b2a84b9f 103#define SIDE_EVENT_STATE_ABI_VERSION 0
67337c4a 104
57553dfd
MD
105#include <side/event-description-abi.h>
106#include <side/type-argument-abi.h>
107#include <side/instrumentation-c-api.h>
67337c4a
MD
108
109enum 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
0d747f98
MD
118/*
119 * This structure is _not_ packed to allow atomic operations on its
b2a84b9f
MD
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.
0d747f98 123 */
b2a84b9f 124
0d747f98 125struct side_event_state {
b2a84b9f
MD
126 uint32_t version; /* Event state ABI version. */
127};
128
129struct side_event_state_0 {
130 struct side_event_state p; /* Required first field. */
f60d8121
MD
131 uint32_t enabled;
132 side_ptr_t(const struct side_callback) callbacks;
133 side_ptr_t(struct side_event_description) desc;
0d747f98
MD
134};
135
67337c4a
MD
136#ifdef __cplusplus
137extern "C" {
138#endif
139
2e197497
MD
140struct 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
67337c4a
MD
153extern const struct side_callback side_empty_callback;
154
0d747f98 155void side_call(const struct side_event_state *state,
67337c4a 156 const struct side_arg_vec *side_arg_vec);
0d747f98 157void side_call_variadic(const struct side_event_state *state,
67337c4a
MD
158 const struct side_arg_vec *side_arg_vec,
159 const struct side_arg_dynamic_struct *var_struct);
160
161struct side_events_register_handle *side_events_register(struct side_event_description **events,
162 uint32_t nr_events);
163void 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 */
171typedef void (*side_tracer_callback_func)(const struct side_event_description *desc,
172 const struct side_arg_vec *side_arg_vec,
173 void *priv);
174typedef 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
179int side_tracer_callback_register(struct side_event_description *desc,
180 side_tracer_callback_func call,
181 void *priv);
182int side_tracer_callback_variadic_register(struct side_event_description *desc,
183 side_tracer_callback_variadic_func call_variadic,
184 void *priv);
185int side_tracer_callback_unregister(struct side_event_description *desc,
186 side_tracer_callback_func call,
187 void *priv);
188int side_tracer_callback_variadic_unregister(struct side_event_description *desc,
189 side_tracer_callback_variadic_func call_variadic,
190 void *priv);
191
192enum 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. */
198struct 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);
202void 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 */
208void side_init(void) __attribute__((constructor));
209void 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 */
222extern struct side_event_description * __start_side_event_description_ptr[]
223 __attribute__((weak, visibility("hidden")));
224extern struct side_event_description * __stop_side_event_description_ptr[]
225 __attribute__((weak, visibility("hidden")));
226int side_event_description_ptr_registered
227 __attribute__((weak, visibility("hidden")));
228struct side_events_register_handle *side_events_handle
229 __attribute__((weak, visibility("hidden")));
230
231static void
232side_event_description_ptr_init(void)
233 __attribute__((no_instrument_function))
234 __attribute__((constructor));
235static void
236side_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
244static void
245side_event_description_ptr_exit(void)
246 __attribute__((no_instrument_function))
247 __attribute__((destructor));
248static void
249side_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.045448 seconds and 4 git commands to generate.