SoW-2020-0002: Trace Hit Counters: Implement key-addressed counters as a new LTTng...
[deliverable/lttng-modules.git] / src / lttng-trigger-notification.c
1 /* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * lttng-trigger-notification.c
4 *
5 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
6 */
7
8 #include <linux/bug.h>
9
10 #include <lttng/lttng-bytecode.h>
11 #include <lttng/events.h>
12 #include <lttng/msgpack.h>
13 #include <lttng/trigger-notification.h>
14
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
21 struct lttng_trigger_notification {
22 int notification_fd;
23 uint64_t trigger_id;
24 uint8_t capture_buf[CAPTURE_BUFFER_SIZE];
25 struct lttng_msgpack_writer writer;
26 bool has_captures;
27 };
28
29 static
30 int 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
87 end:
88 return ret;
89 }
90
91 static
92 int64_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
140 static
141 uint64_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
189 int 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);
252 end:
253 return ret;
254 }
255
256 static
257 int notification_append_capture(
258 struct lttng_trigger_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 }
305 end:
306 return ret;
307 }
308
309 static
310 int notification_append_empty_capture(
311 struct lttng_trigger_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
320 static
321 int notification_init(struct lttng_trigger_notification *notif,
322 struct lttng_trigger *trigger)
323 {
324 struct lttng_msgpack_writer *writer = &notif->writer;
325 int ret = 0;
326
327 notif->has_captures = false;
328
329 if (trigger->num_captures > 0) {
330 lttng_msgpack_writer_init(writer, notif->capture_buf,
331 CAPTURE_BUFFER_SIZE);
332
333 ret = lttng_msgpack_begin_array(writer, trigger->num_captures);
334 if (ret) {
335 WARN_ON_ONCE(1);
336 goto end;
337 }
338
339 notif->has_captures = true;
340 }
341
342 end:
343 return ret;
344 }
345
346 static
347 void record_error(struct lttng_trigger *trigger)
348 {
349
350 struct lttng_trigger_group *trigger_group = trigger->group;
351 size_t dimension_index[1];
352 int ret;
353
354 dimension_index[0] = trigger->error_counter_index;
355
356 ret = trigger_group->error_counter->ops->counter_add(
357 trigger_group->error_counter->counter,
358 dimension_index, 1);
359 if (ret)
360 WARN_ON_ONCE(1);
361 }
362
363 static
364 void notification_send(struct lttng_trigger_notification *notif,
365 struct lttng_trigger *trigger)
366 {
367 struct lttng_trigger_group *trigger_group = trigger->group;
368 struct lib_ring_buffer_ctx ctx;
369 struct lttng_kernel_trigger_notification kernel_notif;
370 size_t capture_buffer_content_len, reserve_size;
371 int ret;
372
373 reserve_size = sizeof(kernel_notif);
374 kernel_notif.id = trigger->id;
375
376 if (notif->has_captures) {
377 capture_buffer_content_len = notif->writer.write_pos - notif->writer.buffer;
378 } else {
379 capture_buffer_content_len = 0;
380 }
381
382 WARN_ON_ONCE(capture_buffer_content_len > CAPTURE_BUFFER_SIZE);
383
384 reserve_size += capture_buffer_content_len;
385 kernel_notif.capture_buf_size = capture_buffer_content_len;
386
387 lib_ring_buffer_ctx_init(&ctx, trigger_group->chan, NULL, reserve_size,
388 lttng_alignof(kernel_notif), -1);
389 ret = trigger_group->ops->event_reserve(&ctx, 0);
390 if (ret < 0) {
391 record_error(trigger);
392 return;
393 }
394
395 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(kernel_notif));
396
397 /* Write the notif structure. */
398 trigger_group->ops->event_write(&ctx, &kernel_notif,
399 sizeof(kernel_notif));
400
401 /*
402 * Write the capture buffer. No need to realigned as the below is a raw
403 * char* buffer.
404 */
405 trigger_group->ops->event_write(&ctx, &notif->capture_buf,
406 capture_buffer_content_len);
407
408 trigger_group->ops->event_commit(&ctx);
409 irq_work_queue(&trigger_group->wakeup_pending);
410 }
411
412 void lttng_trigger_notification_send(struct lttng_trigger *trigger,
413 struct lttng_probe_ctx *lttng_probe_ctx,
414 const char *stack_data)
415 {
416 struct lttng_trigger_notification notif = {0};
417 int ret;
418
419 if (unlikely(!READ_ONCE(trigger->enabled)))
420 return;
421
422 ret = notification_init(&notif, trigger);
423 if (ret) {
424 WARN_ON_ONCE(1);
425 goto end;
426 }
427
428 if (unlikely(!list_empty(&trigger->capture_bytecode_runtime_head))) {
429 struct lttng_bytecode_runtime *capture_bc_runtime;
430
431 /*
432 * Iterate over all the capture bytecodes. If the interpreter
433 * functions returns successfully, append the value of the
434 * `output` parameter to the capture buffer. If the interpreter
435 * fails, append an empty capture to the buffer.
436 */
437 list_for_each_entry(capture_bc_runtime,
438 &trigger->capture_bytecode_runtime_head, node) {
439 struct lttng_interpreter_output output;
440
441 if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime,
442 lttng_probe_ctx, stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG)
443 ret = notification_append_capture(&notif, &output);
444 else
445 ret = notification_append_empty_capture(&notif);
446
447 if (ret)
448 printk(KERN_WARNING "Error appending capture to notification");
449 }
450 }
451
452 /*
453 * Send the notification (including the capture buffer) to the
454 * sessiond.
455 */
456 notification_send(&notif, trigger);
457 end:
458 return;
459 }
This page took 0.059295 seconds and 5 git commands to generate.