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