Commit | Line | Data |
---|---|---|
1c324e59 MD |
1 | /* |
2 | * Copyright (c) 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
3 | * | |
4 | * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED | |
5 | * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. | |
6 | * | |
7 | * Permission is hereby granted to use or copy this program | |
8 | * for any purpose, provided the above notices are retained on all copies. | |
9 | * Permission to modify the code and to distribute modified code is granted, | |
10 | * provided the above notices are retained, and a notice that the code was | |
11 | * modified is included with the above copyright notice. | |
12 | */ | |
13 | ||
14 | #include <stdio.h> | |
15 | #include <urcu/compiler.h> | |
16 | #include <lttng/ust-events.h> | |
1c324e59 | 17 | #include <lttng/ringbuffer-config.h> |
44c72f10 | 18 | #include <string.h> |
1c324e59 MD |
19 | |
20 | /* | |
21 | * Macro declarations used for all stages. | |
22 | */ | |
23 | ||
24 | #undef ctf_integer | |
25 | #define ctf_integer(_type, _item, _src) \ | |
26 | ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 10) | |
27 | ||
28 | #undef ctf_integer_hex | |
29 | #define ctf_integer_hex(_type, _item, _src) \ | |
30 | ctf_integer_ext(_type, _item, _src, BYTE_ORDER, 16) | |
31 | ||
32 | #undef ctf_integer_network | |
33 | #define ctf_integer_network(_type, _item, _src) \ | |
34 | ctf_integer_ext(_type, _item, _src, BIG_ENDIAN, 10) | |
35 | ||
36 | #undef ctf_integer_network_hex | |
37 | #define ctf_integer_network_hex(_type, _item, _src) \ | |
38 | ctf_integer_ext(_type, _item, _src, BIG_ENDIAN, 16) | |
39 | ||
40 | /* ctf_float is redefined at each step */ | |
41 | ||
42 | #undef ctf_array | |
43 | #define ctf_array(_type, _item, _src, _length) \ | |
44 | ctf_array_encoded(_type, _item, _src, _length, none) | |
45 | ||
46 | #undef ctf_array_text | |
47 | #define ctf_array_text(_type, _item, _src, _length) \ | |
48 | ctf_array_encoded(_type, _item, _src, _length, UTF8) | |
49 | ||
50 | #undef ctf_sequence | |
51 | #define ctf_sequence(_type, _item, _src, _length_type, _src_length) \ | |
52 | ctf_sequence_encoded(_type, _item, _src, \ | |
53 | _length_type, _src_length, none) | |
54 | ||
55 | #undef ctf_sequence_text | |
56 | #define ctf_sequence_text(_type, _item, _src, _length_type, _src_length) \ | |
57 | ctf_sequence_encoded(_type, _item, _src, \ | |
58 | _length_type, _src_length, UTF8) | |
59 | ||
60 | /* ctf_string is redefined at each step */ | |
61 | ||
62 | /* | |
63 | * TRACEPOINT_EVENT_CLASS declares a class of tracepoints receiving the | |
64 | * same arguments and having the same field layout. | |
65 | * | |
66 | * TRACEPOINT_EVENT_INSTANCE declares an instance of a tracepoint, with | |
67 | * its own provider and name. It refers to a class (template). | |
68 | * | |
69 | * TRACEPOINT_EVENT declared both a class and an instance and does a | |
70 | * direct mapping from the instance to the class. | |
71 | */ | |
72 | ||
73 | #undef TRACEPOINT_EVENT | |
74 | #define TRACEPOINT_EVENT(_provider, _name, _args, _fields) \ | |
75 | TRACEPOINT_EVENT_CLASS(_provider, _name, \ | |
76 | _TP_PARAMS(_args), \ | |
77 | _TP_PARAMS(_fields)) \ | |
78 | TRACEPOINT_EVENT_INSTANCE(_provider, _name, _name, \ | |
79 | _TP_PARAMS(args)) | |
80 | ||
81 | /* Helpers */ | |
82 | #define _TP_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) | |
83 | ||
84 | #define _tp_max_t(type, x, y) \ | |
85 | ({ \ | |
86 | type __max1 = (x); \ | |
87 | type __max2 = (y); \ | |
88 | __max1 > __max2 ? __max1: __max2; \ | |
89 | }) | |
90 | ||
91 | /* | |
92 | * Stage 0 of tracepoint event generation. | |
93 | * | |
94 | * Check that each TRACEPOINT_EVENT provider argument match the | |
95 | * TRACEPOINT_PROVIDER by creating dummy callbacks. | |
96 | */ | |
97 | ||
98 | /* Reset all macros within TRACEPOINT_EVENT */ | |
99 | #include <lttng/ust-tracepoint-event-reset.h> | |
100 | ||
101 | static inline | |
102 | void _TP_COMBINE_TOKENS(__tracepoint_provider_mismatch_, TRACEPOINT_PROVIDER)(void) | |
103 | { | |
104 | } | |
105 | ||
106 | #undef TRACEPOINT_EVENT_CLASS | |
107 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
108 | __tracepoint_provider_mismatch_##_provider(); | |
109 | ||
110 | #undef TRACEPOINT_EVENT_INSTANCE | |
111 | #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ | |
112 | __tracepoint_provider_mismatch_##_provider(); | |
113 | ||
114 | static __attribute__((unused)) | |
115 | void _TP_COMBINE_TOKENS(__tracepoint_provider_check_, TRACEPOINT_PROVIDER)(void) | |
116 | { | |
117 | #include TRACEPOINT_INCLUDE | |
118 | } | |
119 | ||
120 | /* | |
121 | * Stage 1 of tracepoint event generation. | |
122 | * | |
123 | * Create event field type metadata section. | |
124 | * Each event produce an array of fields. | |
125 | */ | |
126 | ||
127 | /* Reset all macros within TRACEPOINT_EVENT */ | |
128 | #include <lttng/ust-tracepoint-event-reset.h> | |
129 | ||
130 | #undef ctf_integer_ext | |
131 | #define ctf_integer_ext(_type, _item, _src, _byte_order, _base) \ | |
132 | { \ | |
133 | .name = #_item, \ | |
134 | .type = __type_integer(_type, _byte_order, _base, none),\ | |
135 | }, | |
136 | ||
137 | #undef ctf_float | |
138 | #define ctf_float(_type, _item, _src) \ | |
139 | { \ | |
140 | .name = #_item, \ | |
141 | .type = __type_float(_type), \ | |
142 | }, | |
143 | ||
144 | #undef ctf_array_encoded | |
145 | #define ctf_array_encoded(_type, _item, _src, _length, _encoding) \ | |
146 | { \ | |
147 | .name = #_item, \ | |
148 | .type = \ | |
149 | { \ | |
150 | .atype = atype_array, \ | |
151 | .u.array = \ | |
152 | { \ | |
153 | .length = _length, \ | |
154 | .elem_type = __type_integer(_type, BYTE_ORDER, 10, _encoding), \ | |
155 | }, \ | |
156 | }, \ | |
157 | }, | |
158 | ||
159 | #undef ctf_sequence_encoded | |
160 | #define ctf_sequence_encoded(_type, _item, _src, \ | |
161 | _length_type, _src_length, _encoding) \ | |
162 | { \ | |
163 | .name = #_item, \ | |
164 | .type = \ | |
165 | { \ | |
166 | .atype = atype_sequence, \ | |
167 | .u.sequence = \ | |
168 | { \ | |
169 | .length_type = __type_integer(_length_type, BYTE_ORDER, 10, none), \ | |
170 | .elem_type = __type_integer(_type, BYTE_ORDER, 10, _encoding), \ | |
171 | }, \ | |
172 | }, \ | |
173 | }, | |
174 | ||
175 | #undef ctf_string | |
176 | #define ctf_string(_item, _src) \ | |
177 | { \ | |
178 | .name = #_item, \ | |
179 | .type = \ | |
180 | { \ | |
181 | .atype = atype_string, \ | |
182 | .u.basic.string.encoding = lttng_encode_UTF8, \ | |
183 | }, \ | |
184 | }, | |
185 | ||
186 | #undef TP_FIELDS | |
187 | #define TP_FIELDS(args...) args /* Only one used in this phase */ | |
188 | ||
189 | #undef TRACEPOINT_EVENT_CLASS | |
190 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
191 | static const struct lttng_event_field __event_fields___##_provider##___##_name[] = { \ | |
192 | _fields \ | |
193 | }; | |
194 | ||
195 | #include TRACEPOINT_INCLUDE | |
196 | ||
197 | /* | |
198 | * Stage 2 of tracepoint event generation. | |
199 | * | |
200 | * Create probe callback prototypes. | |
201 | */ | |
202 | ||
203 | /* Reset all macros within TRACEPOINT_EVENT */ | |
204 | #include <lttng/ust-tracepoint-event-reset.h> | |
205 | ||
206 | #undef TP_ARGS | |
207 | #define TP_ARGS(args...) args | |
208 | ||
209 | #undef TRACEPOINT_EVENT_CLASS | |
210 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
211 | static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args)); | |
212 | ||
213 | #include TRACEPOINT_INCLUDE | |
214 | ||
215 | /* | |
216 | * Stage 3 of tracepoint event generation. | |
217 | * | |
218 | * Create an array of events. | |
219 | */ | |
220 | ||
221 | /* Reset all macros within TRACEPOINT_EVENT */ | |
222 | #include <lttng/ust-tracepoint-event-reset.h> | |
223 | ||
224 | #undef TRACEPOINT_EVENT_INSTANCE | |
225 | #define TRACEPOINT_EVENT_INSTANCE(_provider, _template, _name, _args) \ | |
226 | { \ | |
227 | .fields = __event_fields___##_provider##___##_template,\ | |
228 | .name = #_provider ":" #_name, \ | |
229 | .probe_callback = (void *) &__event_probe__##_provider##___##_template,\ | |
230 | .nr_fields = _TP_ARRAY_SIZE(__event_fields___##_provider##___##_template), \ | |
231 | }, | |
232 | ||
233 | static const struct lttng_event_desc _TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER)[] = { | |
234 | #include TRACEPOINT_INCLUDE | |
235 | }; | |
236 | ||
237 | ||
238 | /* | |
239 | * Stage 4 of tracepoint event generation. | |
240 | * | |
241 | * Create a toplevel descriptor for the whole probe. | |
242 | */ | |
243 | ||
244 | /* non-const because list head will be modified when registered. */ | |
245 | static struct lttng_probe_desc _TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER) = { | |
246 | .event_desc = _TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER), | |
247 | .nr_events = _TP_ARRAY_SIZE(_TP_COMBINE_TOKENS(__event_desc___, TRACEPOINT_PROVIDER)), | |
248 | }; | |
249 | ||
250 | /* | |
251 | * Stage 5 of tracepoint event generation. | |
252 | * | |
253 | * Create static inline function that calculates event size. | |
254 | */ | |
255 | ||
256 | /* Reset all macros within TRACEPOINT_EVENT */ | |
257 | #include <lttng/ust-tracepoint-event-reset.h> | |
258 | ||
259 | #undef ctf_integer_ext | |
260 | #define ctf_integer_ext(_type, _item, _src, _byte_order, _base) \ | |
261 | __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ | |
262 | __event_len += sizeof(_type); | |
263 | ||
264 | #undef ctf_float | |
265 | #define ctf_float(_type, _item, _src) \ | |
266 | __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ | |
267 | __event_len += sizeof(_type); | |
268 | ||
269 | #undef ctf_array_encoded | |
270 | #define ctf_array_encoded(_type, _item, _src, _length, _encoding) \ | |
271 | __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ | |
272 | __event_len += sizeof(_type) * (_length); | |
273 | ||
274 | #undef ctf_sequence_encoded | |
275 | #define ctf_sequence_encoded(_type, _item, _src, _length_type, \ | |
276 | _src_length, _encoding) \ | |
277 | __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_length_type)); \ | |
278 | __event_len += sizeof(_length_type); \ | |
279 | __event_len += lib_ring_buffer_align(__event_len, lttng_alignof(_type)); \ | |
280 | __dynamic_len[__dynamic_len_idx] = (_src_length); \ | |
281 | __event_len += sizeof(_type) * __dynamic_len[__dynamic_len_idx]; \ | |
282 | __dynamic_len_idx++; | |
283 | ||
284 | #undef ctf_string | |
285 | #define ctf_string(_item, _src) \ | |
286 | __event_len += __dynamic_len[__dynamic_len_idx++] = strlen(_src) + 1; | |
287 | ||
288 | #undef TP_ARGS | |
289 | #define TP_ARGS(args...) args | |
290 | ||
291 | #undef TP_FIELDS | |
292 | #define TP_FIELDS(args...) args | |
293 | ||
294 | #undef TRACEPOINT_EVENT_CLASS | |
295 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
296 | static inline size_t __event_get_size__##_provider##___##_name(size_t *__dynamic_len, _TP_ARGS_DATA_PROTO(_args)) \ | |
297 | { \ | |
298 | size_t __event_len = 0; \ | |
299 | unsigned int __dynamic_len_idx = 0; \ | |
300 | \ | |
301 | if (0) \ | |
302 | (void) __dynamic_len_idx; /* don't warn if unused */ \ | |
303 | _fields \ | |
304 | return __event_len; \ | |
305 | } | |
306 | ||
307 | #include TRACEPOINT_INCLUDE | |
308 | ||
309 | /* | |
310 | * Stage 6 of tracepoint event generation. | |
311 | * | |
312 | * Create static inline function that calculates event payload alignment. | |
313 | */ | |
314 | ||
315 | /* Reset all macros within TRACEPOINT_EVENT */ | |
316 | #include <lttng/ust-tracepoint-event-reset.h> | |
317 | ||
318 | #undef ctf_integer_ext | |
319 | #define ctf_integer_ext(_type, _item, _src, _byte_order, _base) \ | |
320 | __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); | |
321 | ||
322 | #undef ctf_float | |
323 | #define ctf_float(_type, _item, _src) \ | |
324 | __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); | |
325 | ||
326 | #undef ctf_array_encoded | |
327 | #define ctf_array_encoded(_type, _item, _src, _length, _encoding) \ | |
328 | __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); | |
329 | ||
330 | #undef ctf_sequence_encoded | |
331 | #define ctf_sequence_encoded(_type, _item, _src, _length_type, \ | |
332 | _src_length, _encoding) \ | |
333 | __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_length_type)); \ | |
334 | __event_align = _tp_max_t(size_t, __event_align, lttng_alignof(_type)); | |
335 | ||
336 | #undef ctf_string | |
337 | #define ctf_string(_item, _src) | |
338 | ||
339 | #undef TP_ARGS | |
340 | #define TP_ARGS(args...) args | |
341 | ||
342 | #undef TP_FIELDS | |
343 | #define TP_FIELDS(args...) args | |
344 | ||
345 | #undef TRACEPOINT_EVENT_CLASS | |
346 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
347 | static inline \ | |
348 | size_t __event_get_align__##_provider##___##_name(_TP_ARGS_PROTO(_args)) \ | |
349 | { \ | |
350 | size_t __event_align = 1; \ | |
351 | _fields \ | |
352 | return __event_align; \ | |
353 | } | |
354 | ||
355 | #include TRACEPOINT_INCLUDE | |
356 | ||
357 | ||
358 | /* | |
359 | * Stage 7 of tracepoint event generation. | |
360 | * | |
361 | * Create the probe function. This function calls event size calculation | |
362 | * and writes event data into the buffer. | |
363 | */ | |
364 | ||
365 | /* Reset all macros within TRACEPOINT_EVENT */ | |
366 | #include <lttng/ust-tracepoint-event-reset.h> | |
367 | ||
368 | #undef ctf_integer_ext | |
369 | #define ctf_integer_ext(_type, _item, _src, _byte_order, _base) \ | |
370 | { \ | |
371 | _type __tmp = (_src); \ | |
372 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__tmp));\ | |
373 | __chan->ops->event_write(&__ctx, &__tmp, sizeof(__tmp));\ | |
374 | } | |
375 | ||
376 | #undef ctf_float | |
377 | #define ctf_float(_type, _item, _src) \ | |
378 | { \ | |
379 | _type __tmp = (_src); \ | |
380 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(__tmp));\ | |
381 | __chan->ops->event_write(&__ctx, &__tmp, sizeof(__tmp));\ | |
382 | } | |
383 | ||
384 | #undef ctf_array_encoded | |
385 | #define ctf_array_encoded(_type, _item, _src, _length, _encoding) \ | |
386 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_type)); \ | |
387 | __chan->ops->event_write(&__ctx, _src, sizeof(_type) * (_length)); | |
388 | ||
389 | #undef ctf_sequence_encoded | |
390 | #define ctf_sequence_encoded(_type, _item, _src, _length_type, \ | |
391 | _src_length, _encoding) \ | |
392 | { \ | |
393 | _length_type __tmpl = __dynamic_len[__dynamic_len_idx]; \ | |
394 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_length_type));\ | |
395 | __chan->ops->event_write(&__ctx, &__tmpl, sizeof(_length_type));\ | |
396 | } \ | |
397 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(_type)); \ | |
398 | __chan->ops->event_write(&__ctx, _src, \ | |
399 | sizeof(_type) * __get_dynamic_len(dest)); | |
400 | ||
401 | #undef ctf_string | |
402 | #define ctf_string(_item, _src) \ | |
403 | lib_ring_buffer_align_ctx(&__ctx, lttng_alignof(*(_src))); \ | |
404 | __chan->ops->event_write(&__ctx, _src, __get_dynamic_len(dest)); | |
405 | ||
406 | /* Beware: this get len actually consumes the len value */ | |
407 | #undef __get_dynamic_len | |
408 | #define __get_dynamic_len(field) __dynamic_len[__dynamic_len_idx++] | |
409 | ||
410 | #undef TP_ARGS | |
411 | #define TP_ARGS(args...) args | |
412 | ||
413 | #undef TP_FIELDS | |
414 | #define TP_FIELDS(args...) args | |
415 | ||
416 | #undef TRACEPOINT_EVENT_CLASS | |
417 | #define TRACEPOINT_EVENT_CLASS(_provider, _name, _args, _fields) \ | |
418 | static void __event_probe__##_provider##___##_name(_TP_ARGS_DATA_PROTO(_args))\ | |
419 | { \ | |
f280cb51 | 420 | struct ltt_event *__event = __tp_data; \ |
1c324e59 | 421 | struct ltt_channel *__chan = __event->chan; \ |
f280cb51 | 422 | struct lttng_ust_lib_ring_buffer_ctx __ctx; \ |
1c324e59 MD |
423 | size_t __event_len, __event_align; \ |
424 | size_t __dynamic_len_idx = 0; \ | |
425 | size_t __dynamic_len[_TP_ARRAY_SIZE(__event_fields___##_provider##___##_name)]; \ | |
426 | int __ret; \ | |
427 | \ | |
428 | if (0) \ | |
429 | (void) __dynamic_len_idx; /* don't warn if unused */ \ | |
430 | if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->session->active))) \ | |
431 | return; \ | |
432 | if (caa_unlikely(!CMM_ACCESS_ONCE(__chan->enabled))) \ | |
433 | return; \ | |
434 | if (caa_unlikely(!CMM_ACCESS_ONCE(__event->enabled))) \ | |
435 | return; \ | |
436 | __event_len = __event_get_size__##_provider##___##_name(__dynamic_len,\ | |
437 | _TP_ARGS_DATA_VAR(_args)); \ | |
438 | __event_align = __event_get_align__##_provider##___##_name(_TP_ARGS_VAR(_args)); \ | |
439 | lib_ring_buffer_ctx_init(&__ctx, __chan->chan, __event, __event_len, \ | |
440 | __event_align, -1, __chan->handle); \ | |
441 | __ret = __chan->ops->event_reserve(&__ctx, __event->id); \ | |
442 | if (__ret < 0) \ | |
443 | return; \ | |
444 | _fields \ | |
445 | __chan->ops->event_commit(&__ctx); \ | |
446 | } | |
447 | ||
448 | #include TRACEPOINT_INCLUDE | |
449 | ||
450 | #undef __get_dynamic_len | |
451 | ||
452 | /* | |
453 | * Stage 8 of tracepoint event generation. | |
454 | * | |
455 | * Register/unregister probes at module load/unload. | |
456 | */ | |
457 | ||
458 | /* Reset all macros within TRACEPOINT_EVENT */ | |
459 | #include <lttng/ust-tracepoint-event-reset.h> | |
460 | ||
461 | static void __attribute__((constructor)) | |
462 | _TP_COMBINE_TOKENS(__lttng_events_init__, TRACEPOINT_PROVIDER)(void) | |
463 | { | |
464 | int ret; | |
465 | ||
466 | ret = ltt_probe_register(&_TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER)); | |
467 | assert(!ret); | |
468 | } | |
469 | ||
470 | static void __attribute__((destructor)) | |
471 | _TP_COMBINE_TOKENS(__lttng_events_exit__, TRACEPOINT_PROVIDER)(void) | |
472 | { | |
473 | ltt_probe_unregister(&_TP_COMBINE_TOKENS(__probe_desc___, TRACEPOINT_PROVIDER)); | |
474 | } |