ae402ccb8ba1ac57da6d192af4a1d7fd579632d0
[lttng-tools.git] / src / bin / lttng-sessiond / ust-field-convert.cpp
1 /*
2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "ust-field-convert.hpp"
9
10 #include <common/make-unique.hpp>
11
12 #include <unordered_map>
13
14 namespace lst = lttng::sessiond::trace;
15 namespace lsu = lttng::sessiond::ust;
16 namespace {
17
18 /*
19 * Type enclosing the session information that may be required during the decoding
20 * of the lttng_ust_ctl_field array provided by applications on registration of
21 * an event.
22 */
23 class session_attributes {
24 public:
25 using registry_enum_getter_fn =
26 std::function<lsu::registry_enum::const_rcu_protected_reference(
27 const char *name, uint64_t id)>;
28
29 session_attributes(registry_enum_getter_fn reg_enum_getter,
30 lst::byte_order native_trace_byte_order) :
31 get_registry_enum{reg_enum_getter}, _native_trace_byte_order{native_trace_byte_order}
32 {
33 }
34
35 const registry_enum_getter_fn get_registry_enum;
36 const lst::byte_order _native_trace_byte_order;
37 };
38
39 /* Used to publish fields on which a field being decoded has an implicit dependency. */
40 using publish_field_fn = std::function<void(lst::field::cuptr)>;
41
42 lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
43 const lttng_ust_ctl_field *end,
44 const session_attributes& session_attributes,
45 const lttng_ust_ctl_field **next_ust_ctl_field,
46 publish_field_fn publish_field);
47
48 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
49 const lttng_ust_ctl_field *end,
50 const session_attributes& session_attributes,
51 const lttng_ust_ctl_field **next_ust_ctl_field,
52 publish_field_fn publish_field);
53
54 template <class UstCtlEncodingType>
55 enum lst::null_terminated_string_type::encoding ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding)
56 {
57 static const std::unordered_map<UstCtlEncodingType, enum lst::null_terminated_string_type::encoding>
58 encoding_conversion_map = {
59 {(UstCtlEncodingType) lttng_ust_ctl_encode_ASCII,
60 lst::null_terminated_string_type::encoding::ASCII},
61 {(UstCtlEncodingType) lttng_ust_ctl_encode_UTF8,
62 lst::null_terminated_string_type::encoding::UTF8},
63 };
64
65 const auto encoding_it = encoding_conversion_map.find(encoding);
66 if (encoding_it == encoding_conversion_map.end()) {
67 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
68 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
69 encoding));
70 }
71
72 return encoding_it->second;
73 }
74
75 template <class UstCtlBaseType>
76 enum lst::integer_type::base ust_ctl_base_to_integer_field_base(UstCtlBaseType base)
77 {
78 static const std::unordered_map<UstCtlBaseType, enum lst::integer_type::base>
79 base_conversion_map = {{2, lst::integer_type::base::BINARY},
80 {8, lst::integer_type::base::OCTAL},
81 {10, lst::integer_type::base::DECIMAL},
82 {16, lst::integer_type::base::HEXADECIMAL}};
83
84 const auto base_it = base_conversion_map.find(base);
85 if (base_it == base_conversion_map.end()) {
86 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
87 "Unknown integer base value `{}` encountered when decoding integer field",
88 base));
89 }
90
91 return base_it->second;
92 }
93
94 lst::type::cuptr create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
95 const lttng_ust_ctl_field *end,
96 const session_attributes& session_attributes,
97 const lttng_ust_ctl_field **next_ust_ctl_field)
98 {
99 if (current >= end) {
100 LTTNG_THROW_PROTOCOL_ERROR(
101 fmt::format("End of {} array reached unexpectedly during decoding",
102 typeid(*current)));
103 }
104
105 const auto base = ust_ctl_base_to_integer_field_base(current->type.u.integer.base);
106 const auto signedness = current->type.u.integer.signedness ?
107 lst::integer_type::signedness::SIGNED :
108 lst::integer_type::signedness::UNSIGNED;
109 const auto byte_order = current->type.u.integer.reverse_byte_order ?
110 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
111 session_attributes._native_trace_byte_order;
112
113 *next_ust_ctl_field = current + 1;
114
115 return lttng::make_unique<const lst::integer_type>(current->type.u.integer.alignment,
116 byte_order, current->type.u.integer.size, signedness, base);
117 }
118
119 lst::type::cuptr create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
120 const lttng_ust_ctl_field *end,
121 const session_attributes& session_attributes,
122 const lttng_ust_ctl_field **next_ust_ctl_field)
123 {
124 if (current >= end) {
125 LTTNG_THROW_PROTOCOL_ERROR(
126 fmt::format("End of {} array reached unexpectedly during decoding",
127 typeid(*current)));
128 }
129
130 *next_ust_ctl_field = current + 1;
131
132 const auto byte_order = current->type.u._float.reverse_byte_order ?
133 lst::type::reverse_byte_order(session_attributes._native_trace_byte_order) :
134 session_attributes._native_trace_byte_order;
135
136 try {
137 return lttng::make_unique<const lst::floating_point_type>(
138 current->type.u._float.alignment, byte_order,
139 current->type.u._float.exp_dig, current->type.u._float.mant_dig);
140 } catch (lttng::invalid_argument_error& ex) {
141 LTTNG_THROW_PROTOCOL_ERROR(fmt::format("Invalid floating point attribute in {}: {}",
142 typeid(*current), ex.what()));
143 }
144 }
145
146 lst::type::cuptr create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
147 const lttng_ust_ctl_field *end,
148 const session_attributes& session_attributes,
149 const lttng_ust_ctl_field **next_ust_ctl_field)
150 {
151 if (current >= end) {
152 LTTNG_THROW_PROTOCOL_ERROR(
153 fmt::format("End of {} array reached unexpectedly during decoding",
154 typeid(*current)));
155 }
156
157 uint64_t enumeration_id;
158 const auto& enum_uctl_field = *current;
159 const char *enumeration_name;
160 const auto *enum_container_uctl_type =
161 &current->type.u.legacy.basic.enumeration.container_type;
162
163 if (enum_uctl_field.type.atype == lttng_ust_ctl_atype_enum_nestable) {
164 /* Nestable enumeration fields are followed by their container type. */
165 ++current;
166 if (current >= end) {
167 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
168 "Array of {} is too short to contain nestable enumeration's container",
169 typeid(*current)));
170 }
171
172 if (current->type.atype != lttng_ust_ctl_atype_integer) {
173 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
174 "Invalid type of nestable enum container: type id = {}",
175 current->type.atype));
176 }
177
178 enum_container_uctl_type = &current->type.u.integer;
179 enumeration_id = enum_uctl_field.type.u.enum_nestable.id;
180 enumeration_name = enum_uctl_field.type.u.enum_nestable.name;
181 } else {
182 enumeration_id = enum_uctl_field.type.u.legacy.basic.enumeration.id;
183 enumeration_name = enum_uctl_field.type.u.legacy.basic.enumeration.name;
184 }
185
186 *next_ust_ctl_field = current + 1;
187
188 const auto base = ust_ctl_base_to_integer_field_base(enum_container_uctl_type->base);
189 const auto byte_order = enum_container_uctl_type->reverse_byte_order ?
190 lst::integer_type::reverse_byte_order(
191 session_attributes._native_trace_byte_order) :
192 session_attributes._native_trace_byte_order;
193 const auto signedness = enum_container_uctl_type->signedness ?
194 lst::integer_type::signedness::SIGNED :
195 lst::integer_type::signedness::UNSIGNED;
196
197 if (enum_container_uctl_type->signedness) {
198 const auto& enum_registry = static_cast<const lsu::registry_signed_enum&>(
199 *session_attributes.get_registry_enum(
200 enumeration_name, enumeration_id));
201
202 return lttng::make_unique<const lst::signed_enumeration_type>(
203 enum_container_uctl_type->alignment, byte_order,
204 enum_container_uctl_type->size, signedness, base,
205 enum_registry._mappings);
206 } else {
207 const auto& enum_registry = static_cast<const lsu::registry_unsigned_enum&>(
208 *session_attributes.get_registry_enum(
209 enumeration_name, enumeration_id));
210
211 return lttng::make_unique<const lst::unsigned_enumeration_type>(
212 enum_container_uctl_type->alignment, byte_order,
213 enum_container_uctl_type->size, signedness, base,
214 enum_registry._mappings);
215 }
216 }
217
218 lst::type::cuptr create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
219 const lttng_ust_ctl_field *end,
220 const session_attributes& session_attributes __attribute__((unused)),
221 const lttng_ust_ctl_field **next_ust_ctl_field)
222 {
223 if (current >= end) {
224 LTTNG_THROW_PROTOCOL_ERROR(
225 fmt::format("End of {} array reached unexpectedly during decoding",
226 typeid(*current)));
227 }
228
229 const auto& string_uctl_field = *current;
230 *next_ust_ctl_field = current + 1;
231
232 const auto encoding = ust_ctl_encoding_to_string_field_encoding(
233 string_uctl_field.type.u.string.encoding);
234
235 return lttng::make_unique<const lst::null_terminated_string_type>(1, encoding);
236 }
237
238 lst::type::cuptr create_integer_type_from_ust_ctl_basic_type(
239 const lttng_ust_ctl_basic_type& type, const session_attributes& session_attributes)
240 {
241 /* Checked by caller. */
242 LTTNG_ASSERT(type.atype == lttng_ust_ctl_atype_integer);
243
244 const auto byte_order = type.u.basic.integer.reverse_byte_order ?
245 lst::integer_type::reverse_byte_order(
246 session_attributes._native_trace_byte_order) :
247 session_attributes._native_trace_byte_order;
248 const auto signedness = type.u.basic.integer.signedness ?
249 lst::integer_type::signedness::SIGNED :
250 lst::integer_type::signedness::UNSIGNED;
251 const auto base = ust_ctl_base_to_integer_field_base(type.u.basic.integer.base);
252 const auto size = type.u.basic.integer.size;
253 const auto alignment = type.u.basic.integer.alignment;
254
255 return lttng::make_unique<const lst::integer_type>(
256 alignment, byte_order, size, signedness, base);
257 }
258
259 lst::type::cuptr create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
260 const lttng_ust_ctl_field *end,
261 const session_attributes& session_attributes,
262 const lttng_ust_ctl_field **next_ust_ctl_field)
263 {
264 if (current >= end) {
265 LTTNG_THROW_PROTOCOL_ERROR(
266 fmt::format("End of {} array reached unexpectedly during decoding",
267 typeid(*current)));
268 }
269
270 const auto& array_uctl_field = *current;
271 uint32_t array_alignment, array_length;
272 lst::type::cuptr element_type;
273 nonstd::optional<enum lst::string_type::encoding> element_encoding;
274
275 array_length = array_uctl_field.type.u.legacy.array.length;
276 array_alignment = 0;
277
278 const auto& element_uctl_type = array_uctl_field.type.u.legacy.array.elem_type;
279 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
280 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
281 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
282 element_uctl_type.atype, lttng_ust_ctl_atype_integer));
283 }
284
285 element_type = create_integer_type_from_ust_ctl_basic_type(
286 element_uctl_type, session_attributes);
287 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
288 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
289 /* Element represents a text character. */
290 element_encoding = ust_ctl_encoding_to_string_field_encoding(
291 element_uctl_type.u.basic.integer.encoding);
292 }
293
294 *next_ust_ctl_field = current + 1;
295
296 if (element_encoding) {
297 const auto integer_element_size =
298 static_cast<const lst::integer_type&>(*element_type).size;
299
300 if (integer_element_size != 8) {
301 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
302 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
303 integer_element_size));
304 }
305
306 /* Array is a static-length string. */
307 return lttng::make_unique<lst::static_length_string_type>(
308 array_alignment, *element_encoding, array_length);
309 }
310
311 return lttng::make_unique<lst::static_length_array_type>(
312 array_alignment, std::move(element_type), array_length);
313 }
314
315 lst::type::cuptr create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
316 const lttng_ust_ctl_field *end,
317 const session_attributes& session_attributes,
318 const lttng_ust_ctl_field **next_ust_ctl_field,
319 publish_field_fn publish_field)
320 {
321 if (current >= end) {
322 LTTNG_THROW_PROTOCOL_ERROR(
323 fmt::format("End of {} array reached unexpectedly during decoding",
324 typeid(*current)));
325 }
326
327 const auto& array_uctl_field = *current;
328 uint32_t array_alignment, array_length;
329 lst::type::cuptr element_type;
330 nonstd::optional<enum lst::string_type::encoding> element_encoding;
331
332 array_length = array_uctl_field.type.u.array_nestable.length;
333 array_alignment = array_uctl_field.type.u.array_nestable.alignment;
334
335 /* Nestable array fields are followed by their element type. */
336 const auto& element_uctl_field = *(current + 1);
337
338 /* next_ust_ctl_field is updated as needed. */
339 element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end, session_attributes,
340 next_ust_ctl_field, publish_field);
341 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
342 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
343 /* Element represents a text character. */
344 element_encoding = ust_ctl_encoding_to_string_field_encoding(
345 element_uctl_field.type.u.integer.encoding);
346 }
347
348 if (element_encoding) {
349 const auto integer_element_size =
350 static_cast<const lst::integer_type&>(*element_type).size;
351
352 if (integer_element_size != 8) {
353 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
354 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
355 integer_element_size));
356 }
357
358 /* Array is a static-length string. */
359 return lttng::make_unique<lst::static_length_string_type>(
360 array_alignment, *element_encoding, array_length);
361 }
362
363 return lttng::make_unique<lst::static_length_array_type>(
364 array_alignment, std::move(element_type), array_length);
365 }
366
367 /*
368 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
369 * length as part of the same lttng_ust_ctl_field entry.
370 */
371 lst::type::cuptr create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
372 const lttng_ust_ctl_field *end,
373 const session_attributes& session_attributes,
374 const lttng_ust_ctl_field **next_ust_ctl_field,
375 publish_field_fn publish_field)
376 {
377 if (current >= end) {
378 LTTNG_THROW_PROTOCOL_ERROR(
379 fmt::format("End of {} array reached unexpectedly during decoding",
380 typeid(*current)));
381 }
382
383 const auto& sequence_uctl_field = *current;
384 const auto& element_uctl_type = sequence_uctl_field.type.u.legacy.sequence.elem_type;
385 const auto& length_uctl_type = sequence_uctl_field.type.u.legacy.sequence.length_type;
386 const auto sequence_alignment = 0U;
387
388 if (element_uctl_type.atype != lttng_ust_ctl_atype_integer) {
389 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
390 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
391 element_uctl_type.atype, lttng_ust_ctl_atype_integer));
392 }
393
394 if (length_uctl_type.atype != lttng_ust_ctl_atype_integer) {
395 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
396 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
397 length_uctl_type.atype, lttng_ust_ctl_atype_integer));
398 }
399
400 nonstd::optional<enum lst::string_type::encoding> element_encoding;
401 if (element_uctl_type.atype == lttng_ust_ctl_atype_integer &&
402 element_uctl_type.u.basic.integer.encoding != lttng_ust_ctl_encode_none) {
403 /* Element represents a text character. */
404 element_encoding = ust_ctl_encoding_to_string_field_encoding(
405 element_uctl_type.u.basic.integer.encoding);
406 }
407
408 const auto length_field_name = fmt::format("_{}_length", sequence_uctl_field.name);
409 auto element_type = create_integer_type_from_ust_ctl_basic_type(
410 element_uctl_type, session_attributes);
411 auto length_type = create_integer_type_from_ust_ctl_basic_type(
412 length_uctl_type, session_attributes);
413
414 /* Publish an implicit length field _before_ the sequence field. */
415 publish_field(lttng::make_unique<lst::field>(length_field_name, std::move(length_type)));
416
417 *next_ust_ctl_field = current + 1;
418
419 if (element_encoding) {
420 const auto integer_element_size =
421 static_cast<const lst::integer_type&>(*element_type).size;
422
423 if (integer_element_size != 8) {
424 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
425 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
426 integer_element_size));
427 }
428
429 /* Sequence is a dynamic-length string. */
430 return lttng::make_unique<lst::dynamic_length_string_type>(sequence_alignment,
431 *element_encoding, std::move(length_field_name));
432 }
433
434 return lttng::make_unique<lst::dynamic_length_array_type>(
435 sequence_alignment, std::move(element_type), std::move(length_field_name));
436 }
437
438 lst::type::cuptr create_sequence_nestable_type_from_ust_ctl_fields(
439 const lttng_ust_ctl_field *current,
440 const lttng_ust_ctl_field *end,
441 const session_attributes& session_attributes,
442 const lttng_ust_ctl_field **next_ust_ctl_field,
443 publish_field_fn publish_field)
444 {
445 if (current >= end) {
446 LTTNG_THROW_PROTOCOL_ERROR(
447 fmt::format("End of {} array reached unexpectedly during decoding",
448 typeid(*current)));
449 }
450
451 const auto& sequence_uctl_field = *current;
452 const auto sequence_alignment = sequence_uctl_field.type.u.sequence_nestable.alignment;
453 const auto *length_field_name = sequence_uctl_field.type.u.sequence_nestable.length_name;
454
455 /* Nestable sequence fields are followed by their element type. */
456 const auto& element_uctl_field = *(current + 1);
457
458 nonstd::optional<enum lst::string_type::encoding> element_encoding;
459 if (element_uctl_field.type.atype == lttng_ust_ctl_atype_integer &&
460 element_uctl_field.type.u.integer.encoding != lttng_ust_ctl_encode_none) {
461 /* Element represents a text character. */
462 element_encoding = ust_ctl_encoding_to_string_field_encoding(
463 element_uctl_field.type.u.integer.encoding);
464 }
465
466 /* next_ust_ctl_field is updated as needed. */
467 auto element_type = create_type_from_ust_ctl_fields(&element_uctl_field, end,
468 session_attributes, next_ust_ctl_field, publish_field);
469
470 if (lttng_strnlen(sequence_uctl_field.type.u.sequence_nestable.length_name,
471 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) ==
472 sizeof(sequence_uctl_field.type.u.sequence_nestable.length_name)) {
473 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
474 }
475
476 if (element_encoding) {
477 const auto integer_element_size =
478 static_cast<const lst::integer_type&>(*element_type).size;
479
480 if (integer_element_size != 8) {
481 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
482 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
483 integer_element_size));
484 }
485
486 /* Sqeuence is a dynamic-length string. */
487 return lttng::make_unique<lst::dynamic_length_string_type>(sequence_alignment,
488 *element_encoding, std::move(length_field_name));
489 }
490
491 return lttng::make_unique<lst::dynamic_length_array_type>(
492 sequence_alignment, std::move(element_type), std::move(length_field_name));
493 }
494
495 lst::type::cuptr create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
496 const lttng_ust_ctl_field *end,
497 const session_attributes& session_attributes __attribute__((unused)),
498 const lttng_ust_ctl_field **next_ust_ctl_field)
499 {
500 if (current >= end) {
501 LTTNG_THROW_PROTOCOL_ERROR(
502 fmt::format("End of {} array reached unexpectedly during decoding",
503 typeid(*current)));
504 }
505
506 uint32_t field_count;
507 uint32_t alignment;
508 const auto& structure_uctl_field = *current;
509
510 if (structure_uctl_field.type.atype == lttng_ust_ctl_atype_struct) {
511 field_count = structure_uctl_field.type.u.legacy._struct.nr_fields;
512 alignment = 0;
513 } else {
514 field_count = structure_uctl_field.type.u.struct_nestable.nr_fields;
515 alignment = structure_uctl_field.type.u.struct_nestable.alignment;
516 }
517
518 if (field_count != 0) {
519 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
520 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
521 field_count));
522 }
523
524 *next_ust_ctl_field = current + 1;
525 return lttng::make_unique<lst::structure_type>(alignment, lst::structure_type::fields());
526 }
527
528 lst::type::cuptr create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
529 const lttng_ust_ctl_field *end,
530 const session_attributes& session_attributes,
531 const lttng_ust_ctl_field **next_ust_ctl_field)
532 {
533 if (current >= end) {
534 LTTNG_THROW_PROTOCOL_ERROR(
535 fmt::format("End of {} array reached unexpectedly during decoding",
536 typeid(*current)));
537 }
538
539 const auto& variant_uctl_field = *current;
540 current++;
541
542 uint32_t alignment;
543 uint32_t choice_count;
544 const char *tag_name;
545
546 if (variant_uctl_field.type.atype == lttng_ust_ctl_atype_variant) {
547 alignment = 0;
548 choice_count = variant_uctl_field.type.u.legacy.variant.nr_choices;
549 tag_name = variant_uctl_field.type.u.legacy.variant.tag_name;
550 } else {
551 alignment = variant_uctl_field.type.u.variant_nestable.alignment;
552 choice_count = variant_uctl_field.type.u.variant_nestable.nr_choices;
553 tag_name = variant_uctl_field.type.u.variant_nestable.tag_name;
554 }
555
556 /* Choices follow. next_ust_ctl_field is updated as needed. */
557 lst::variant_type::choices choices;
558 for (unsigned int i = 0; i < choice_count; i++) {
559 create_field_from_ust_ctl_fields(current, end, session_attributes,
560 next_ust_ctl_field, [&choices](lst::field::cuptr field) {
561 choices.emplace_back(std::move(field));
562 });
563
564 current = *next_ust_ctl_field;
565 }
566
567 return lttng::make_unique<lst::variant_type>(alignment, tag_name, std::move(choices));
568 }
569
570 lst::type::cuptr create_type_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
571 const lttng_ust_ctl_field *end,
572 const session_attributes& session_attributes,
573 const lttng_ust_ctl_field **next_ust_ctl_field,
574 publish_field_fn publish_field)
575 {
576 switch (current->type.atype) {
577 case lttng_ust_ctl_atype_integer:
578 return create_integer_type_from_ust_ctl_fields(
579 current, end, session_attributes, next_ust_ctl_field);
580 case lttng_ust_ctl_atype_enum:
581 case lttng_ust_ctl_atype_enum_nestable:
582 return create_enumeration_type_from_ust_ctl_fields(
583 current, end, session_attributes, next_ust_ctl_field);
584 case lttng_ust_ctl_atype_float:
585 return create_floating_point_type_from_ust_ctl_fields(
586 current, end, session_attributes, next_ust_ctl_field);
587 case lttng_ust_ctl_atype_string:
588 return create_string_type_from_ust_ctl_fields(
589 current, end, session_attributes, next_ust_ctl_field);
590 case lttng_ust_ctl_atype_array:
591 return create_array_type_from_ust_ctl_fields(current, end, session_attributes,
592 next_ust_ctl_field);
593 case lttng_ust_ctl_atype_array_nestable:
594 return create_array_nestable_type_from_ust_ctl_fields(current, end,
595 session_attributes, next_ust_ctl_field, publish_field);
596 case lttng_ust_ctl_atype_sequence:
597 return create_sequence_type_from_ust_ctl_fields(current, end, session_attributes,
598 next_ust_ctl_field, publish_field);
599 case lttng_ust_ctl_atype_sequence_nestable:
600 return create_sequence_nestable_type_from_ust_ctl_fields(current, end,
601 session_attributes, next_ust_ctl_field, publish_field);
602 case lttng_ust_ctl_atype_struct:
603 case lttng_ust_ctl_atype_struct_nestable:
604 return create_structure_field_from_ust_ctl_fields(
605 current, end, session_attributes, next_ust_ctl_field);
606 case lttng_ust_ctl_atype_variant:
607 case lttng_ust_ctl_atype_variant_nestable:
608 return create_variant_field_from_ust_ctl_fields(
609 current, end, session_attributes, next_ust_ctl_field);
610 default:
611 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
612 "Unknown {} value `{}` encountered while converting {} to {}",
613 typeid(current->type.atype), current->type.atype, typeid(*current),
614 typeid(lst::type::cuptr::element_type)));
615 }
616 }
617
618 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field *current,
619 const lttng_ust_ctl_field *end,
620 const session_attributes& session_attributes,
621 const lttng_ust_ctl_field **next_ust_ctl_field,
622 publish_field_fn publish_field)
623 {
624 LTTNG_ASSERT(current < end);
625
626 if (lttng_strnlen(current->name, sizeof(current->name)) == sizeof(current->name)) {
627 LTTNG_THROW_PROTOCOL_ERROR(
628 fmt::format("Name of {} is not null-terminated", typeid(*current)));
629 }
630
631 publish_field(lttng::make_unique<lst::field>(current->name,
632 create_type_from_ust_ctl_fields(current, end, session_attributes,
633 next_ust_ctl_field, publish_field)));
634 }
635
636 /*
637 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
638 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
639 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
640 * is consumed.
641 *
642 * Always returns a new field, throws on error.
643 */
644 std::vector<lst::field::cuptr> create_fields_from_ust_ctl_fields(
645 const lsu::registry_session& session,
646 const lttng_ust_ctl_field *current,
647 const lttng_ust_ctl_field *end)
648 {
649 std::vector<lst::field::cuptr> fields;
650 const auto trace_native_byte_order = session.abi.byte_order;
651 const session_attributes session_attributes{
652 [&session](const char *enum_name, uint64_t enum_id) {
653 return ust_registry_lookup_enum_by_id(&session, enum_name, enum_id);
654 },
655 trace_native_byte_order};
656
657 while (current < end) {
658 auto *next_field = current;
659
660 /*
661 * create_field_from_ust_ctl_fields will consume one field at a time.
662 * However, some fields expressed by LTTng-UST's protocol are expended
663 * to multiple event fields (legacy sequence fields implicitly define
664 * their length field).
665 *
666 * The lambda allows the factory functions to push as many fields as
667 * needed depending on the decoded field's type.
668 */
669 create_field_from_ust_ctl_fields(current, end, session_attributes, &next_field,
670 [&fields](lst::field::cuptr field) {
671 fields.emplace_back(std::move(field));
672 });
673
674 current = next_field;
675 }
676
677 return fields;
678 }
679 } /* namespace */
680
681 std::vector<lst::field::cuptr> lsu::create_trace_fields_from_ust_ctl_fields(
682 const lsu::registry_session& session,
683 const lttng_ust_ctl_field *fields,
684 std::size_t field_count)
685 {
686 return create_fields_from_ust_ctl_fields(session, fields, fields + field_count);
687 }
This page took 0.042326 seconds and 3 git commands to generate.