Commit | Line | Data |
---|---|---|
21f58fb7 FD |
1 | /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only) |
2 | * | |
3 | * lttng-event-notifier-notification.c | |
4 | * | |
5 | * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com> | |
6 | */ | |
7 | ||
42f3ef8c FD |
8 | #include <linux/bug.h> |
9 | ||
10 | #include <lttng/lttng-bytecode.h> | |
21f58fb7 | 11 | #include <lttng/events.h> |
42f3ef8c | 12 | #include <lttng/msgpack.h> |
21f58fb7 FD |
13 | #include <lttng/event-notifier-notification.h> |
14 | ||
99d223ad | 15 | /* |
e699ee6c MD |
16 | * The capture buffer size needs to be below 1024 bytes to avoid the |
17 | * frame to be larger than the 1024 limit enforced by the kernel. If we | |
18 | * ever need to increase it, we will need to use a memory allocation | |
19 | * scheme which allows allocating temporary memory chunks from the | |
20 | * instrumentation sites. This could be done by adapting lttng | |
21 | * tp-mempool to become nmi-safe and lock-free. | |
99d223ad FD |
22 | */ |
23 | #define CAPTURE_BUFFER_SIZE 512 | |
24 | ||
25 | struct lttng_event_notifier_notification { | |
26 | int notification_fd; | |
27 | uint64_t event_notifier_token; | |
28 | uint8_t capture_buf[CAPTURE_BUFFER_SIZE]; | |
29 | struct lttng_msgpack_writer writer; | |
30 | bool has_captures; | |
31 | }; | |
32 | ||
42f3ef8c FD |
33 | static |
34 | int capture_enum(struct lttng_msgpack_writer *writer, | |
35 | struct lttng_interpreter_output *output) | |
36 | { | |
37 | int ret; | |
38 | ||
39 | /* | |
40 | * Enums are captured as a map containing 2 key-value pairs. Such as: | |
41 | * - type: enum | |
42 | * value: 177 | |
43 | */ | |
44 | ret = lttng_msgpack_begin_map(writer, 2); | |
45 | if (ret) { | |
46 | WARN_ON_ONCE(1); | |
47 | goto end; | |
48 | } | |
49 | ||
50 | ret = lttng_msgpack_write_str(writer, "type"); | |
51 | if (ret) { | |
52 | WARN_ON_ONCE(1); | |
53 | goto end; | |
54 | } | |
55 | ||
56 | ret = lttng_msgpack_write_str(writer, "enum"); | |
57 | if (ret) { | |
58 | WARN_ON_ONCE(1); | |
59 | goto end; | |
60 | } | |
61 | ||
62 | ret = lttng_msgpack_write_str(writer, "value"); | |
63 | if (ret) { | |
64 | WARN_ON_ONCE(1); | |
65 | goto end; | |
66 | } | |
67 | ||
68 | switch (output->type) { | |
69 | case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM: | |
70 | ret = lttng_msgpack_write_signed_integer(writer, output->u.s); | |
71 | if (ret) { | |
72 | WARN_ON_ONCE(1); | |
73 | goto end; | |
74 | } | |
75 | break; | |
76 | case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM: | |
77 | ret = lttng_msgpack_write_signed_integer(writer, output->u.u); | |
78 | if (ret) { | |
79 | WARN_ON_ONCE(1); | |
80 | goto end; | |
81 | } | |
82 | break; | |
83 | default: | |
84 | WARN_ON(1); | |
85 | } | |
86 | ||
87 | ret = lttng_msgpack_end_map(writer); | |
88 | if (ret) | |
89 | WARN_ON_ONCE(1); | |
90 | ||
91 | end: | |
92 | return ret; | |
93 | } | |
94 | ||
95 | static | |
96 | int64_t capture_sequence_element_signed(uint8_t *ptr, | |
97 | const struct lttng_integer_type *type) | |
98 | { | |
99 | int64_t value = 0; | |
100 | unsigned int size = type->size; | |
101 | bool byte_order_reversed = type->reverse_byte_order; | |
102 | ||
103 | switch (size) { | |
104 | case 8: | |
105 | value = *ptr; | |
106 | break; | |
107 | case 16: | |
108 | { | |
109 | int16_t tmp; | |
110 | tmp = *(int16_t *) ptr; | |
111 | if (byte_order_reversed) | |
112 | __swab16s(&tmp); | |
113 | ||
114 | value = tmp; | |
115 | break; | |
116 | } | |
117 | case 32: | |
118 | { | |
119 | int32_t tmp; | |
120 | tmp = *(int32_t *) ptr; | |
121 | if (byte_order_reversed) | |
122 | __swab32s(&tmp); | |
123 | ||
124 | value = tmp; | |
125 | break; | |
126 | } | |
127 | case 64: | |
128 | { | |
129 | int64_t tmp; | |
130 | tmp = *(int64_t *) ptr; | |
131 | if (byte_order_reversed) | |
132 | __swab64s(&tmp); | |
133 | ||
134 | value = tmp; | |
135 | break; | |
136 | } | |
137 | default: | |
138 | WARN_ON(1); | |
139 | } | |
140 | ||
141 | return value; | |
142 | } | |
143 | ||
144 | static | |
145 | uint64_t capture_sequence_element_unsigned(uint8_t *ptr, | |
146 | const struct lttng_integer_type *type) | |
147 | { | |
148 | uint64_t value = 0; | |
149 | unsigned int size = type->size; | |
150 | bool byte_order_reversed = type->reverse_byte_order; | |
151 | ||
152 | switch (size) { | |
153 | case 8: | |
154 | value = *ptr; | |
155 | break; | |
156 | case 16: | |
157 | { | |
158 | uint16_t tmp; | |
159 | tmp = *(uint16_t *) ptr; | |
160 | if (byte_order_reversed) | |
161 | __swab16s(&tmp); | |
162 | ||
163 | value = tmp; | |
164 | break; | |
165 | } | |
166 | case 32: | |
167 | { | |
168 | uint32_t tmp; | |
169 | tmp = *(uint32_t *) ptr; | |
170 | if (byte_order_reversed) | |
171 | __swab32s(&tmp); | |
172 | ||
173 | value = tmp; | |
174 | break; | |
175 | } | |
176 | case 64: | |
177 | { | |
178 | uint64_t tmp; | |
179 | tmp = *(uint64_t *) ptr; | |
180 | if (byte_order_reversed) | |
181 | __swab64s(&tmp); | |
182 | ||
183 | value = tmp; | |
184 | break; | |
185 | } | |
186 | default: | |
187 | WARN_ON(1); | |
188 | } | |
189 | ||
190 | return value; | |
191 | } | |
192 | ||
42f3ef8c FD |
193 | int capture_sequence(struct lttng_msgpack_writer *writer, |
194 | struct lttng_interpreter_output *output) | |
195 | { | |
196 | const struct lttng_integer_type *integer_type = NULL; | |
197 | const struct lttng_type *nested_type; | |
198 | uint8_t *ptr; | |
199 | bool signedness; | |
200 | int ret, i; | |
201 | ||
202 | ret = lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem); | |
203 | if (ret) { | |
204 | WARN_ON_ONCE(1); | |
205 | goto end; | |
206 | } | |
207 | ||
208 | ptr = (uint8_t *) output->u.sequence.ptr; | |
209 | nested_type = output->u.sequence.nested_type; | |
210 | switch (nested_type->atype) { | |
211 | case atype_integer: | |
212 | integer_type = &nested_type->u.integer; | |
213 | break; | |
214 | case atype_enum_nestable: | |
215 | /* Treat enumeration as an integer. */ | |
216 | integer_type = &nested_type->u.enum_nestable.container_type->u.integer; | |
217 | break; | |
218 | default: | |
219 | /* Capture of array of non-integer are not supported. */ | |
220 | WARN_ON(1); | |
221 | } | |
222 | signedness = integer_type->signedness; | |
223 | for (i = 0; i < output->u.sequence.nr_elem; i++) { | |
224 | if (signedness) { | |
225 | ret = lttng_msgpack_write_signed_integer(writer, | |
226 | capture_sequence_element_signed(ptr, integer_type)); | |
227 | if (ret) { | |
228 | WARN_ON_ONCE(1); | |
229 | goto end; | |
230 | } | |
231 | } else { | |
232 | ret = lttng_msgpack_write_unsigned_integer(writer, | |
233 | capture_sequence_element_unsigned(ptr, integer_type)); | |
234 | if (ret) { | |
235 | WARN_ON_ONCE(1); | |
236 | goto end; | |
237 | } | |
238 | } | |
239 | ||
240 | /* | |
241 | * We assume that alignment is smaller or equal to the size. | |
242 | * This currently holds true but if it changes in the future, | |
243 | * we will want to change the pointer arithmetics below to | |
244 | * take into account that the next element might be further | |
245 | * away. | |
246 | */ | |
247 | WARN_ON(integer_type->alignment > integer_type->size); | |
248 | ||
249 | /* Size is in number of bits. */ | |
250 | ptr += (integer_type->size / CHAR_BIT) ; | |
251 | } | |
252 | ||
253 | ret = lttng_msgpack_end_array(writer); | |
254 | if (ret) | |
255 | WARN_ON_ONCE(1); | |
256 | end: | |
257 | return ret; | |
258 | } | |
259 | ||
99d223ad FD |
260 | static |
261 | int notification_append_capture( | |
262 | struct lttng_event_notifier_notification *notif, | |
263 | struct lttng_interpreter_output *output) | |
264 | { | |
265 | struct lttng_msgpack_writer *writer = ¬if->writer; | |
266 | int ret = 0; | |
267 | ||
268 | switch (output->type) { | |
269 | case LTTNG_INTERPRETER_TYPE_S64: | |
270 | ret = lttng_msgpack_write_signed_integer(writer, output->u.s); | |
271 | if (ret) { | |
272 | WARN_ON_ONCE(1); | |
273 | goto end; | |
274 | } | |
275 | break; | |
276 | case LTTNG_INTERPRETER_TYPE_U64: | |
277 | ret = lttng_msgpack_write_unsigned_integer(writer, output->u.u); | |
278 | if (ret) { | |
279 | WARN_ON_ONCE(1); | |
280 | goto end; | |
281 | } | |
282 | break; | |
283 | case LTTNG_INTERPRETER_TYPE_STRING: | |
284 | ret = lttng_msgpack_write_str(writer, output->u.str.str); | |
285 | if (ret) { | |
286 | WARN_ON_ONCE(1); | |
287 | goto end; | |
288 | } | |
289 | break; | |
290 | case LTTNG_INTERPRETER_TYPE_SEQUENCE: | |
291 | ret = capture_sequence(writer, output); | |
292 | if (ret) { | |
293 | WARN_ON_ONCE(1); | |
294 | goto end; | |
295 | } | |
296 | break; | |
297 | case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM: | |
298 | case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM: | |
299 | ret = capture_enum(writer, output); | |
300 | if (ret) { | |
301 | WARN_ON_ONCE(1); | |
302 | goto end; | |
303 | } | |
304 | break; | |
305 | default: | |
306 | ret = -1; | |
307 | WARN_ON(1); | |
308 | } | |
309 | end: | |
310 | return ret; | |
311 | } | |
312 | ||
313 | static | |
314 | int notification_append_empty_capture( | |
315 | struct lttng_event_notifier_notification *notif) | |
316 | { | |
317 | int ret = lttng_msgpack_write_nil(¬if->writer); | |
318 | if (ret) | |
319 | WARN_ON_ONCE(1); | |
320 | ||
321 | return ret; | |
322 | } | |
323 | ||
324 | static | |
325 | int notification_init(struct lttng_event_notifier_notification *notif, | |
326 | struct lttng_event_notifier *event_notifier) | |
327 | { | |
328 | struct lttng_msgpack_writer *writer = ¬if->writer; | |
329 | int ret = 0; | |
330 | ||
331 | notif->has_captures = false; | |
332 | ||
333 | if (event_notifier->num_captures > 0) { | |
334 | lttng_msgpack_writer_init(writer, notif->capture_buf, | |
335 | CAPTURE_BUFFER_SIZE); | |
336 | ||
337 | ret = lttng_msgpack_begin_array(writer, event_notifier->num_captures); | |
338 | if (ret) { | |
339 | WARN_ON_ONCE(1); | |
340 | goto end; | |
341 | } | |
342 | ||
343 | notif->has_captures = true; | |
344 | } | |
345 | ||
346 | end: | |
347 | return ret; | |
348 | } | |
349 | ||
99f52fcc FD |
350 | static |
351 | void record_error(struct lttng_event_notifier *event_notifier) | |
352 | { | |
353 | ||
354 | struct lttng_event_notifier_group *event_notifier_group = event_notifier->group; | |
355 | size_t dimension_index[1]; | |
356 | int ret; | |
357 | ||
358 | dimension_index[0] = event_notifier->error_counter_index; | |
359 | ||
360 | ret = event_notifier_group->error_counter->ops->counter_add( | |
361 | event_notifier_group->error_counter->counter, | |
362 | dimension_index, 1); | |
363 | if (ret) | |
364 | WARN_ON_ONCE(1); | |
365 | } | |
366 | ||
99d223ad FD |
367 | static |
368 | void notification_send(struct lttng_event_notifier_notification *notif, | |
369 | struct lttng_event_notifier *event_notifier) | |
21f58fb7 FD |
370 | { |
371 | struct lttng_event_notifier_group *event_notifier_group = event_notifier->group; | |
372 | struct lib_ring_buffer_ctx ctx; | |
99d223ad FD |
373 | struct lttng_kernel_event_notifier_notification kernel_notif; |
374 | size_t capture_buffer_content_len, reserve_size; | |
21f58fb7 FD |
375 | int ret; |
376 | ||
99d223ad FD |
377 | reserve_size = sizeof(kernel_notif); |
378 | kernel_notif.token = event_notifier->user_token; | |
21f58fb7 | 379 | |
99d223ad FD |
380 | if (notif->has_captures) { |
381 | capture_buffer_content_len = notif->writer.write_pos - notif->writer.buffer; | |
382 | } else { | |
383 | capture_buffer_content_len = 0; | |
384 | } | |
385 | ||
386 | WARN_ON_ONCE(capture_buffer_content_len > CAPTURE_BUFFER_SIZE); | |
387 | ||
388 | reserve_size += capture_buffer_content_len; | |
389 | kernel_notif.capture_buf_size = capture_buffer_content_len; | |
390 | ||
391 | lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL, reserve_size, | |
392 | lttng_alignof(kernel_notif), -1); | |
21f58fb7 FD |
393 | ret = event_notifier_group->ops->event_reserve(&ctx, 0); |
394 | if (ret < 0) { | |
99f52fcc | 395 | record_error(event_notifier); |
21f58fb7 FD |
396 | return; |
397 | } | |
99d223ad FD |
398 | |
399 | lib_ring_buffer_align_ctx(&ctx, lttng_alignof(kernel_notif)); | |
400 | ||
401 | /* Write the notif structure. */ | |
402 | event_notifier_group->ops->event_write(&ctx, &kernel_notif, | |
403 | sizeof(kernel_notif)); | |
404 | ||
405 | /* | |
406 | * Write the capture buffer. No need to realigned as the below is a raw | |
407 | * char* buffer. | |
408 | */ | |
409 | event_notifier_group->ops->event_write(&ctx, ¬if->capture_buf, | |
410 | capture_buffer_content_len); | |
411 | ||
21f58fb7 FD |
412 | event_notifier_group->ops->event_commit(&ctx); |
413 | irq_work_queue(&event_notifier_group->wakeup_pending); | |
414 | } | |
99d223ad FD |
415 | |
416 | void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier, | |
417 | struct lttng_probe_ctx *lttng_probe_ctx, | |
418 | const char *stack_data) | |
419 | { | |
420 | struct lttng_event_notifier_notification notif = { 0 }; | |
421 | int ret; | |
422 | ||
423 | if (unlikely(!READ_ONCE(event_notifier->enabled))) | |
424 | return; | |
425 | ||
426 | ret = notification_init(¬if, event_notifier); | |
427 | if (ret) { | |
428 | WARN_ON_ONCE(1); | |
429 | goto end; | |
430 | } | |
431 | ||
432 | if (unlikely(!list_empty(&event_notifier->capture_bytecode_runtime_head))) { | |
433 | struct lttng_bytecode_runtime *capture_bc_runtime; | |
434 | ||
435 | /* | |
436 | * Iterate over all the capture bytecodes. If the interpreter | |
437 | * functions returns successfully, append the value of the | |
438 | * `output` parameter to the capture buffer. If the interpreter | |
439 | * fails, append an empty capture to the buffer. | |
440 | */ | |
441 | list_for_each_entry(capture_bc_runtime, | |
442 | &event_notifier->capture_bytecode_runtime_head, node) { | |
443 | struct lttng_interpreter_output output; | |
444 | ||
445 | if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime, | |
446 | lttng_probe_ctx, stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG) | |
447 | ret = notification_append_capture(¬if, &output); | |
448 | else | |
449 | ret = notification_append_empty_capture(¬if); | |
450 | ||
451 | if (ret) | |
452 | printk(KERN_WARNING "Error appending capture to notification"); | |
453 | } | |
454 | } | |
455 | ||
456 | /* | |
457 | * Send the notification (including the capture buffer) to the | |
458 | * sessiond. | |
459 | */ | |
460 | notification_send(¬if, event_notifier); | |
461 | end: | |
462 | return; | |
463 | } |