Rename dynamic type field
[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 <side/macros.h>
14
15 /* SIDE stands for "Static Instrumentation Dynamically Enabled" */
16
17 struct side_arg_vec;
18 struct side_arg_vec_description;
19 struct side_arg_dynamic_vec;
20 struct side_arg_dynamic_vec_vla;
21 struct side_type_description;
22 struct side_event_field;
23 struct side_tracer_visitor_ctx;
24 struct side_tracer_dynamic_struct_visitor_ctx;
25 struct side_tracer_dynamic_vla_visitor_ctx;
26
27 enum side_type {
28 SIDE_TYPE_U8,
29 SIDE_TYPE_U16,
30 SIDE_TYPE_U32,
31 SIDE_TYPE_U64,
32 SIDE_TYPE_S8,
33 SIDE_TYPE_S16,
34 SIDE_TYPE_S32,
35 SIDE_TYPE_S64,
36
37 SIDE_TYPE_STRING,
38
39 SIDE_TYPE_STRUCT,
40 SIDE_TYPE_ARRAY,
41 SIDE_TYPE_VLA,
42 SIDE_TYPE_VLA_VISITOR,
43
44 SIDE_TYPE_ARRAY_U8,
45 SIDE_TYPE_ARRAY_U16,
46 SIDE_TYPE_ARRAY_U32,
47 SIDE_TYPE_ARRAY_U64,
48 SIDE_TYPE_ARRAY_S8,
49 SIDE_TYPE_ARRAY_S16,
50 SIDE_TYPE_ARRAY_S32,
51 SIDE_TYPE_ARRAY_S64,
52
53 SIDE_TYPE_VLA_U8,
54 SIDE_TYPE_VLA_U16,
55 SIDE_TYPE_VLA_U32,
56 SIDE_TYPE_VLA_U64,
57 SIDE_TYPE_VLA_S8,
58 SIDE_TYPE_VLA_S16,
59 SIDE_TYPE_VLA_S32,
60 SIDE_TYPE_VLA_S64,
61
62 SIDE_TYPE_DYNAMIC,
63 };
64
65 enum side_dynamic_type {
66 SIDE_DYNAMIC_TYPE_NULL,
67
68 SIDE_DYNAMIC_TYPE_U8,
69 SIDE_DYNAMIC_TYPE_U16,
70 SIDE_DYNAMIC_TYPE_U32,
71 SIDE_DYNAMIC_TYPE_U64,
72 SIDE_DYNAMIC_TYPE_S8,
73 SIDE_DYNAMIC_TYPE_S16,
74 SIDE_DYNAMIC_TYPE_S32,
75 SIDE_DYNAMIC_TYPE_S64,
76
77 SIDE_DYNAMIC_TYPE_STRING,
78
79 SIDE_DYNAMIC_TYPE_STRUCT,
80 SIDE_DYNAMIC_TYPE_STRUCT_VISITOR,
81
82 SIDE_DYNAMIC_TYPE_VLA,
83 SIDE_DYNAMIC_TYPE_VLA_VISITOR,
84 };
85
86 enum side_loglevel {
87 SIDE_LOGLEVEL_EMERG = 0,
88 SIDE_LOGLEVEL_ALERT = 1,
89 SIDE_LOGLEVEL_CRIT = 2,
90 SIDE_LOGLEVEL_ERR = 3,
91 SIDE_LOGLEVEL_WARNING = 4,
92 SIDE_LOGLEVEL_NOTICE = 5,
93 SIDE_LOGLEVEL_INFO = 6,
94 SIDE_LOGLEVEL_DEBUG = 7,
95 };
96
97 enum side_visitor_status {
98 SIDE_VISITOR_STATUS_OK = 0,
99 SIDE_VISITOR_STATUS_ERROR = -1,
100 };
101
102 typedef enum side_visitor_status (*side_visitor)(
103 const struct side_tracer_visitor_ctx *tracer_ctx,
104 void *app_ctx);
105 typedef enum side_visitor_status (*side_dynamic_struct_visitor)(
106 const struct side_tracer_dynamic_struct_visitor_ctx *tracer_ctx,
107 void *app_ctx);
108 typedef enum side_visitor_status (*side_dynamic_vla_visitor)(
109 const struct side_tracer_dynamic_vla_visitor_ctx *tracer_ctx,
110 void *app_ctx);
111
112 struct side_type_description {
113 enum side_type type;
114 //TODO: we should add something like a list of user attributes (namespaced strings)
115 union {
116 struct {
117 uint32_t nr_fields;
118 const struct side_event_field *fields;
119 } side_struct;
120 struct {
121 uint32_t length;
122 const struct side_type_description *elem_type;
123 } side_array;
124 struct {
125 const struct side_type_description *elem_type;
126 } side_vla;
127 struct {
128 const struct side_type_description *elem_type;
129 side_visitor visitor;
130 } side_vla_visitor;
131 } u;
132 };
133
134 struct side_event_field {
135 const char *field_name;
136 struct side_type_description side_type;
137 };
138
139 struct side_event_description {
140 uint32_t version;
141 uint32_t enabled;
142 uint32_t loglevel; /* enum side_loglevel */
143 uint32_t nr_fields;
144 const char *provider_name;
145 const char *event_name;
146 const struct side_event_field *fields;
147 };
148
149 struct side_arg_dynamic_vec_vla {
150 const struct side_arg_dynamic_vec *sav;
151 uint32_t len;
152 };
153
154 struct side_arg_dynamic_vec {
155 enum side_dynamic_type dynamic_type;
156 union {
157 uint8_t side_u8;
158 uint16_t side_u16;
159 uint32_t side_u32;
160 uint64_t side_u64;
161 int8_t side_s8;
162 int16_t side_s16;
163 int32_t side_s32;
164 int64_t side_s64;
165
166 const char *string;
167
168 const struct side_arg_dynamic_event_struct *side_dynamic_struct;
169 struct {
170 void *app_dynamic_visitor_ctx;
171 side_dynamic_struct_visitor visitor;
172 } side_dynamic_struct_visitor;
173
174 const struct side_arg_dynamic_vec_vla *side_dynamic_vla;
175 struct {
176 void *app_dynamic_visitor_ctx;
177 side_dynamic_vla_visitor visitor;
178 } side_dynamic_vla_visitor;
179 } u;
180 };
181
182 struct side_arg_dynamic_event_field {
183 const char *field_name;
184 const struct side_arg_dynamic_vec elem;
185 //TODO: we should add something like a list of user attributes (namespaced strings)
186 };
187
188 struct side_arg_dynamic_event_struct {
189 const struct side_arg_dynamic_event_field *fields;
190 uint32_t len;
191 };
192
193 struct side_arg_vec {
194 enum side_type type;
195 union {
196 uint8_t side_u8;
197 uint16_t side_u16;
198 uint32_t side_u32;
199 uint64_t side_u64;
200 int8_t side_s8;
201 int16_t side_s16;
202 int32_t side_s32;
203 int64_t side_s64;
204
205 const char *string;
206 const struct side_arg_vec_description *side_struct;
207 const struct side_arg_vec_description *side_array;
208 const struct side_arg_vec_description *side_vla;
209 void *side_vla_app_visitor_ctx;
210
211 void *side_array_fixint;
212 struct {
213 void *p;
214 uint32_t length;
215 } side_vla_fixint;
216
217 struct side_arg_dynamic_vec dynamic;
218 } u;
219 };
220
221 struct side_arg_vec_description {
222 const struct side_arg_vec *sav;
223 uint32_t len;
224 };
225
226 /* The visitor pattern is a double-dispatch visitor. */
227 struct side_tracer_visitor_ctx {
228 enum side_visitor_status (*write_elem)(
229 const struct side_tracer_visitor_ctx *tracer_ctx,
230 const struct side_arg_vec *elem);
231 void *priv; /* Private tracer context. */
232 };
233
234 struct side_tracer_dynamic_struct_visitor_ctx {
235 enum side_visitor_status (*write_field)(
236 const struct side_tracer_dynamic_struct_visitor_ctx *tracer_ctx,
237 const struct side_arg_dynamic_event_struct *dynamic_struct);
238 void *priv; /* Private tracer context. */
239 };
240
241 struct side_tracer_dynamic_vla_visitor_ctx {
242 enum side_visitor_status (*write_elem)(
243 const struct side_tracer_dynamic_vla_visitor_ctx *tracer_ctx,
244 const struct side_arg_dynamic_vec *elem);
245 void *priv; /* Private tracer context. */
246 };
247
248 #define side_type_decl(_type) { .type = _type }
249
250 #define side_field(_name, _type) \
251 { \
252 .field_name = _name, \
253 .side_type = side_type_decl(_type), \
254 }
255
256 #define side_type_struct_decl(_fields) \
257 { \
258 .type = SIDE_TYPE_STRUCT, \
259 .u = { \
260 .side_struct = { \
261 .nr_fields = SIDE_ARRAY_SIZE(SIDE_PARAM(_fields)), \
262 .fields = _fields, \
263 }, \
264 }, \
265 }
266 #define side_field_struct(_name, _fields) \
267 { \
268 .field_name = _name, \
269 .side_type = side_type_struct_decl(SIDE_PARAM(_fields)), \
270 }
271
272 #define side_type_array_decl(_elem_type, _length) \
273 { \
274 .type = SIDE_TYPE_ARRAY, \
275 .u = { \
276 .side_array = { \
277 .length = _length, \
278 .elem_type = _elem_type, \
279 }, \
280 }, \
281 }
282 #define side_field_array(_name, _elem_type, _length) \
283 { \
284 .field_name = _name, \
285 .side_type = side_type_array_decl(_elem_type, _length), \
286 }
287
288 #define side_type_vla_decl(_elem_type) \
289 { \
290 .type = SIDE_TYPE_VLA, \
291 .u = { \
292 .side_vla = { \
293 .elem_type = _elem_type, \
294 }, \
295 }, \
296 }
297 #define side_field_vla(_name, _elem_type) \
298 { \
299 .field_name = _name, \
300 .side_type = side_type_vla_decl(_elem_type), \
301 }
302
303 #define side_type_vla_visitor_decl(_elem_type, _visitor) \
304 { \
305 .type = SIDE_TYPE_VLA_VISITOR, \
306 .u = { \
307 .side_vla_visitor = { \
308 .elem_type = SIDE_PARAM(_elem_type), \
309 .visitor = _visitor, \
310 }, \
311 }, \
312 }
313 #define side_field_vla_visitor(_name, _elem_type, _visitor) \
314 { \
315 .field_name = _name, \
316 .side_type = side_type_vla_visitor_decl(SIDE_PARAM(_elem_type), _visitor), \
317 }
318
319 #define side_elem(...) \
320 SIDE_COMPOUND_LITERAL(const struct side_type_description, __VA_ARGS__)
321
322 #define side_elem_type(...) \
323 side_elem(side_type_decl(__VA_ARGS__))
324
325 #define side_field_list(...) \
326 SIDE_COMPOUND_LITERAL(const struct side_event_field, __VA_ARGS__)
327
328 #define side_arg_u8(val) { .type = SIDE_TYPE_U8, .u = { .side_u8 = (val) } }
329 #define side_arg_u16(val) { .type = SIDE_TYPE_U16, .u = { .side_u16 = (val) } }
330 #define side_arg_u32(val) { .type = SIDE_TYPE_U32, .u = { .side_u32 = (val) } }
331 #define side_arg_u64(val) { .type = SIDE_TYPE_U64, .u = { .side_u64 = (val) } }
332 #define side_arg_s8(val) { .type = SIDE_TYPE_S8, .u = { .side_s8 = (val) } }
333 #define side_arg_s16(val) { .type = SIDE_TYPE_S16, .u = { .side_s16 = (val) } }
334 #define side_arg_s32(val) { .type = SIDE_TYPE_S32, .u = { .side_s32 = (val) } }
335 #define side_arg_s64(val) { .type = SIDE_TYPE_S64, .u = { .side_s64 = (val) } }
336 #define side_arg_string(val) { .type = SIDE_TYPE_STRING, .u = { .string = (val) } }
337 #define side_arg_struct(_side_type) { .type = SIDE_TYPE_STRUCT, .u = { .side_struct = (_side_type) } }
338 #define side_arg_array(_side_type) { .type = SIDE_TYPE_ARRAY, .u = { .side_array = (_side_type) } }
339 #define side_arg_vla(_side_type) { .type = SIDE_TYPE_VLA, .u = { .side_vla = (_side_type) } }
340 #define side_arg_vla_visitor(_ctx) { .type = SIDE_TYPE_VLA_VISITOR, .u = { .side_vla_app_visitor_ctx = (_ctx) } }
341
342 #define side_arg_array_u8(_ptr) { .type = SIDE_TYPE_ARRAY_U8, .u = { .side_array_fixint = (_ptr) } }
343 #define side_arg_array_u16(_ptr) { .type = SIDE_TYPE_ARRAY_U16, .u = { .side_array_fixint = (_ptr) } }
344 #define side_arg_array_u32(_ptr) { .type = SIDE_TYPE_ARRAY_U32, .u = { .side_array_fixint = (_ptr) } }
345 #define side_arg_array_u64(_ptr) { .type = SIDE_TYPE_ARRAY_U64, .u = { .side_array_fixint = (_ptr) } }
346 #define side_arg_array_s8(_ptr) { .type = SIDE_TYPE_ARRAY_S8, .u = { .side_array_fixint = (_ptr) } }
347 #define side_arg_array_s16(_ptr) { .type = SIDE_TYPE_ARRAY_S16, .u = { .side_array_fixint = (_ptr) } }
348 #define side_arg_array_s32(_ptr) { .type = SIDE_TYPE_ARRAY_S32, .u = { .side_array_fixint = (_ptr) } }
349 #define side_arg_array_s64(_ptr) { .type = SIDE_TYPE_ARRAY_S64, .u = { .side_array_fixint = (_ptr) } }
350
351 #define side_arg_vla_u8(_ptr, _length) { .type = SIDE_TYPE_VLA_U8, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } }
352 #define side_arg_vla_u16(_ptr, _length) { .type = SIDE_TYPE_VLA_U16, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
353 #define side_arg_vla_u32(_ptr, _length) { .type = SIDE_TYPE_VLA_U32, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
354 #define side_arg_vla_u64(_ptr, _length) { .type = SIDE_TYPE_VLA_U64, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
355 #define side_arg_vla_s8(_ptr, _length) { .type = SIDE_TYPE_VLA_S8, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
356 #define side_arg_vla_s16(_ptr, _length) { .type = SIDE_TYPE_VLA_S16, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
357 #define side_arg_vla_s32(_ptr, _length) { .type = SIDE_TYPE_VLA_S32, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
358 #define side_arg_vla_s64(_ptr, _length) { .type = SIDE_TYPE_VLA_S64, .u = { .side_vla_fixint = { .p = (_ptr), .length = (_length) } } }
359
360 #define side_arg_dynamic(dynamic_arg_type) \
361 { \
362 .type = SIDE_TYPE_DYNAMIC, \
363 .u = { \
364 .dynamic = dynamic_arg_type, \
365 }, \
366 }
367
368 #define side_arg_dynamic_null(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_NULL }
369
370 #define side_arg_dynamic_u8(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_U8, .u = { .side_u8 = (val) } }
371 #define side_arg_dynamic_u16(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_U16, .u = { .side_u16 = (val) } }
372 #define side_arg_dynamic_u32(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_U32, .u = { .side_u32 = (val) } }
373 #define side_arg_dynamic_u64(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_U64, .u = { .side_u64 = (val) } }
374 #define side_arg_dynamic_s8(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_S8, .u = { .side_s8 = (val) } }
375 #define side_arg_dynamic_s16(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_S16, .u = { .side_s16 = (val) } }
376 #define side_arg_dynamic_s32(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_S32, .u = { .side_s32 = (val) } }
377 #define side_arg_dynamic_s64(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_S64, .u = { .side_s64 = (val) } }
378 #define side_arg_dynamic_string(val) { .dynamic_type = SIDE_DYNAMIC_TYPE_STRING, .u = { .string = (val) } }
379
380 #define side_arg_dynamic_vla(_vla) { .dynamic_type = SIDE_DYNAMIC_TYPE_VLA, .u = { .side_dynamic_vla = (_vla) } }
381 #define side_arg_dynamic_vla_visitor(_dynamic_vla_visitor, _ctx) \
382 { \
383 .dynamic_type = SIDE_DYNAMIC_TYPE_VLA_VISITOR, \
384 .app_dynamic_visitor_ctx = _ctx, \
385 .u = { \
386 .vla_visitor = _dynamic_vla_visitor, \
387 }, \
388 }
389
390 #define side_arg_dynamic_struct(_struct) { .dynamic_type = SIDE_DYNAMIC_TYPE_STRUCT, .u = { .side_dynamic_struct = (_struct) } }
391 #define side_arg_dynamic_struct_visitor(_dynamic_struct_visitor, _ctx) \
392 { \
393 .dynamic_type = SIDE_DYNAMIC_TYPE_STRUCT_VISITOR, \
394 .app_dynamic_visitor_ctx = _ctx, \
395 .u = { \
396 .struct_visitor = _dynamic_struct_visitor, \
397 }, \
398 }
399
400 #define side_arg_dynamic_define_vec(_identifier, _sav) \
401 const struct side_arg_dynamic_vec _identifier##_vec[] = { _sav }; \
402 const struct side_arg_dynamic_vec_vla _identifier = { \
403 .sav = _identifier##_vec, \
404 .len = SIDE_ARRAY_SIZE(_identifier##_vec), \
405 }
406
407 #define side_arg_dynamic_define_struct(_identifier, _struct_fields) \
408 const struct side_arg_dynamic_event_field _identifier##_fields[] = { _struct_fields }; \
409 const struct side_arg_dynamic_event_struct _identifier = { \
410 .fields = _identifier##_fields, \
411 .len = SIDE_ARRAY_SIZE(_identifier##_fields), \
412 }
413
414 #define side_arg_define_vec(_identifier, _sav) \
415 const struct side_arg_vec _identifier##_vec[] = { _sav }; \
416 const struct side_arg_vec_description _identifier = { \
417 .sav = _identifier##_vec, \
418 .len = SIDE_ARRAY_SIZE(_identifier##_vec), \
419 }
420
421 #define side_arg_dynamic_field(_name, _elem) \
422 { \
423 .field_name = _name, \
424 .elem = _elem, \
425 }
426
427 #define side_arg_list(...) __VA_ARGS__
428
429 #define side_event_cond(desc) if (side_unlikely((desc)->enabled))
430
431 #define side_event_call(desc, _sav) \
432 { \
433 const struct side_arg_vec side_sav[] = { _sav }; \
434 const struct side_arg_vec_description sav_desc = { \
435 .sav = side_sav, \
436 .len = SIDE_ARRAY_SIZE(side_sav), \
437 }; \
438 tracer_call(desc, &sav_desc); \
439 }
440
441 #define side_event(desc, sav) \
442 side_event_cond(desc) \
443 side_event_call(desc, SIDE_PARAM(sav))
444
445 #define side_event_call_variadic(desc, _sav, _var_fields) \
446 { \
447 const struct side_arg_vec side_sav[] = { _sav }; \
448 const struct side_arg_vec_description sav_desc = { \
449 .sav = side_sav, \
450 .len = SIDE_ARRAY_SIZE(side_sav), \
451 }; \
452 const struct side_arg_dynamic_event_field side_fields[] = { _var_fields }; \
453 const struct side_arg_dynamic_event_struct var_struct = { \
454 .fields = side_fields, \
455 .len = SIDE_ARRAY_SIZE(side_fields), \
456 }; \
457 tracer_call_variadic(desc, &sav_desc, &var_struct); \
458 }
459
460 #define side_event_variadic(desc, sav, var) \
461 side_event_cond(desc) \
462 side_event_call_variadic(desc, SIDE_PARAM(sav), SIDE_PARAM(var))
463
464 #define side_define_event(_identifier, _provider, _event, _loglevel, _fields) \
465 struct side_event_description _identifier = { \
466 .version = 0, \
467 .enabled = 0, \
468 .loglevel = _loglevel, \
469 .nr_fields = SIDE_ARRAY_SIZE(SIDE_PARAM(_fields)), \
470 .provider_name = _provider, \
471 .event_name = _event, \
472 .fields = _fields, \
473 }
474
475 #define side_declare_event(_identifier) \
476 struct side_event_description _identifier
477
478 #endif /* _SIDE_TRACE_H */
This page took 0.039114 seconds and 5 git commands to generate.