2 * Copyright (C) 2022 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
8 #include "ust-field-convert.hpp"
10 #include <common/make-unique.hpp>
12 #include <unordered_map>
14 namespace lst
= lttng::sessiond::trace
;
15 namespace lsu
= lttng::sessiond::ust
;
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
23 class session_attributes
{
25 using registry_enum_getter_fn
=
26 std::function
<lsu::registry_enum::const_rcu_protected_reference(
27 const char *name
, uint64_t id
)>;
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
}
35 const registry_enum_getter_fn get_registry_enum
;
36 const lst::byte_order _native_trace_byte_order
;
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
)>;
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 lst::field_location::root lookup_root
,
48 lst::field_location::elements
& current_field_location_elements
);
50 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
51 const lttng_ust_ctl_field
*end
,
52 const session_attributes
& session_attributes
,
53 const lttng_ust_ctl_field
**next_ust_ctl_field
,
54 publish_field_fn publish_field
,
55 lst::field_location::root lookup_root
,
56 lst::field_location::elements
& current_field_location_elements
);
58 template <class UstCtlEncodingType
>
59 enum lst::null_terminated_string_type::encoding
ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding
)
61 static const std::unordered_map
<UstCtlEncodingType
, enum lst::null_terminated_string_type::encoding
>
62 encoding_conversion_map
= {
63 {(UstCtlEncodingType
) lttng_ust_ctl_encode_ASCII
,
64 lst::null_terminated_string_type::encoding::ASCII
},
65 {(UstCtlEncodingType
) lttng_ust_ctl_encode_UTF8
,
66 lst::null_terminated_string_type::encoding::UTF8
},
69 const auto encoding_it
= encoding_conversion_map
.find(encoding
);
70 if (encoding_it
== encoding_conversion_map
.end()) {
71 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
72 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
76 return encoding_it
->second
;
79 template <class UstCtlBaseType
>
80 enum lst::integer_type::base
ust_ctl_base_to_integer_field_base(UstCtlBaseType base
)
82 static const std::unordered_map
<UstCtlBaseType
, enum lst::integer_type::base
>
83 base_conversion_map
= {{2, lst::integer_type::base::BINARY
},
84 {8, lst::integer_type::base::OCTAL
},
85 {10, lst::integer_type::base::DECIMAL
},
86 {16, lst::integer_type::base::HEXADECIMAL
}};
88 const auto base_it
= base_conversion_map
.find(base
);
89 if (base_it
== base_conversion_map
.end()) {
90 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
91 "Unknown integer base value `{}` encountered when decoding integer field",
95 return base_it
->second
;
98 lst::type::cuptr
create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
99 const lttng_ust_ctl_field
*end
,
100 const session_attributes
& session_attributes
,
101 const lttng_ust_ctl_field
**next_ust_ctl_field
)
103 if (current
>= end
) {
104 LTTNG_THROW_PROTOCOL_ERROR(
105 fmt::format("End of {} array reached unexpectedly during decoding",
109 const auto base
= ust_ctl_base_to_integer_field_base(current
->type
.u
.integer
.base
);
110 const auto signedness
= current
->type
.u
.integer
.signedness
?
111 lst::integer_type::signedness::SIGNED
:
112 lst::integer_type::signedness::UNSIGNED
;
113 const auto byte_order
= current
->type
.u
.integer
.reverse_byte_order
?
114 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
115 session_attributes
._native_trace_byte_order
;
117 *next_ust_ctl_field
= current
+ 1;
119 return lttng::make_unique
<const lst::integer_type
>(current
->type
.u
.integer
.alignment
,
120 byte_order
, current
->type
.u
.integer
.size
, signedness
, base
);
123 lst::type::cuptr
create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
124 const lttng_ust_ctl_field
*end
,
125 const session_attributes
& session_attributes
,
126 const lttng_ust_ctl_field
**next_ust_ctl_field
)
128 if (current
>= end
) {
129 LTTNG_THROW_PROTOCOL_ERROR(
130 fmt::format("End of {} array reached unexpectedly during decoding",
134 *next_ust_ctl_field
= current
+ 1;
136 const auto byte_order
= current
->type
.u
._float
.reverse_byte_order
?
137 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
138 session_attributes
._native_trace_byte_order
;
141 return lttng::make_unique
<const lst::floating_point_type
>(
142 current
->type
.u
._float
.alignment
, byte_order
,
143 current
->type
.u
._float
.exp_dig
, current
->type
.u
._float
.mant_dig
);
144 } catch (lttng::invalid_argument_error
& ex
) {
145 LTTNG_THROW_PROTOCOL_ERROR(fmt::format("Invalid floating point attribute in {}: {}",
146 typeid(*current
), ex
.what()));
150 lst::type::cuptr
create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
151 const lttng_ust_ctl_field
*end
,
152 const session_attributes
& session_attributes
,
153 const lttng_ust_ctl_field
**next_ust_ctl_field
)
155 if (current
>= end
) {
156 LTTNG_THROW_PROTOCOL_ERROR(
157 fmt::format("End of {} array reached unexpectedly during decoding",
161 uint64_t enumeration_id
;
162 const auto& enum_uctl_field
= *current
;
163 const char *enumeration_name
;
164 const auto *enum_container_uctl_type
=
165 ¤t
->type
.u
.legacy
.basic
.enumeration
.container_type
;
167 if (enum_uctl_field
.type
.atype
== lttng_ust_ctl_atype_enum_nestable
) {
168 /* Nestable enumeration fields are followed by their container type. */
170 if (current
>= end
) {
171 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
172 "Array of {} is too short to contain nestable enumeration's container",
176 if (current
->type
.atype
!= lttng_ust_ctl_atype_integer
) {
177 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
178 "Invalid type of nestable enum container: type id = {}",
179 current
->type
.atype
));
182 enum_container_uctl_type
= ¤t
->type
.u
.integer
;
183 enumeration_id
= enum_uctl_field
.type
.u
.enum_nestable
.id
;
184 enumeration_name
= enum_uctl_field
.type
.u
.enum_nestable
.name
;
186 enumeration_id
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.id
;
187 enumeration_name
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.name
;
190 *next_ust_ctl_field
= current
+ 1;
192 const auto base
= ust_ctl_base_to_integer_field_base(enum_container_uctl_type
->base
);
193 const auto byte_order
= enum_container_uctl_type
->reverse_byte_order
?
194 lst::integer_type::reverse_byte_order(
195 session_attributes
._native_trace_byte_order
) :
196 session_attributes
._native_trace_byte_order
;
197 const auto signedness
= enum_container_uctl_type
->signedness
?
198 lst::integer_type::signedness::SIGNED
:
199 lst::integer_type::signedness::UNSIGNED
;
201 if (signedness
== lst::integer_type::signedness::SIGNED
) {
202 const auto& enum_registry
= static_cast<const lsu::registry_signed_enum
&>(
203 *session_attributes
.get_registry_enum(
204 enumeration_name
, enumeration_id
));
206 return lttng::make_unique
<const lst::signed_enumeration_type
>(
207 enum_container_uctl_type
->alignment
, byte_order
,
208 enum_container_uctl_type
->size
, base
,
209 enum_registry
._mappings
);
211 const auto& enum_registry
= static_cast<const lsu::registry_unsigned_enum
&>(
212 *session_attributes
.get_registry_enum(
213 enumeration_name
, enumeration_id
));
215 return lttng::make_unique
<const lst::unsigned_enumeration_type
>(
216 enum_container_uctl_type
->alignment
, byte_order
,
217 enum_container_uctl_type
->size
, base
,
218 enum_registry
._mappings
);
222 lst::type::cuptr
create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
223 const lttng_ust_ctl_field
*end
,
224 const session_attributes
& session_attributes
__attribute__((unused
)),
225 const lttng_ust_ctl_field
**next_ust_ctl_field
)
227 if (current
>= end
) {
228 LTTNG_THROW_PROTOCOL_ERROR(
229 fmt::format("End of {} array reached unexpectedly during decoding",
233 const auto& string_uctl_field
= *current
;
234 *next_ust_ctl_field
= current
+ 1;
236 const auto encoding
= ust_ctl_encoding_to_string_field_encoding(
237 string_uctl_field
.type
.u
.string
.encoding
);
239 return lttng::make_unique
<const lst::null_terminated_string_type
>(1, encoding
);
242 lst::type::cuptr
create_integer_type_from_ust_ctl_basic_type(
243 const lttng_ust_ctl_basic_type
& type
, const session_attributes
& session_attributes
)
245 /* Checked by caller. */
246 LTTNG_ASSERT(type
.atype
== lttng_ust_ctl_atype_integer
);
248 const auto byte_order
= type
.u
.basic
.integer
.reverse_byte_order
?
249 lst::integer_type::reverse_byte_order(
250 session_attributes
._native_trace_byte_order
) :
251 session_attributes
._native_trace_byte_order
;
252 const auto signedness
= type
.u
.basic
.integer
.signedness
?
253 lst::integer_type::signedness::SIGNED
:
254 lst::integer_type::signedness::UNSIGNED
;
255 const auto base
= ust_ctl_base_to_integer_field_base(type
.u
.basic
.integer
.base
);
256 const auto size
= type
.u
.basic
.integer
.size
;
257 const auto alignment
= type
.u
.basic
.integer
.alignment
;
259 return lttng::make_unique
<const lst::integer_type
>(
260 alignment
, byte_order
, size
, signedness
, base
);
263 lst::type::cuptr
create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
264 const lttng_ust_ctl_field
*end
,
265 const session_attributes
& session_attributes
,
266 const lttng_ust_ctl_field
**next_ust_ctl_field
)
268 if (current
>= end
) {
269 LTTNG_THROW_PROTOCOL_ERROR(
270 fmt::format("End of {} array reached unexpectedly during decoding",
274 const auto& array_uctl_field
= *current
;
275 uint32_t array_alignment
, array_length
;
276 lst::type::cuptr element_type
;
277 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
279 array_length
= array_uctl_field
.type
.u
.legacy
.array
.length
;
282 const auto& element_uctl_type
= array_uctl_field
.type
.u
.legacy
.array
.elem_type
;
283 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
284 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
285 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
286 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
289 element_type
= create_integer_type_from_ust_ctl_basic_type(
290 element_uctl_type
, session_attributes
);
291 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
292 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
293 /* Element represents a text character. */
294 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
295 element_uctl_type
.u
.basic
.integer
.encoding
);
298 *next_ust_ctl_field
= current
+ 1;
300 if (element_encoding
) {
301 const auto integer_element_size
=
302 static_cast<const lst::integer_type
&>(*element_type
).size
;
304 if (integer_element_size
!= 8) {
305 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
306 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
307 integer_element_size
));
310 /* Array is a static-length string. */
311 return lttng::make_unique
<lst::static_length_string_type
>(
312 array_alignment
, *element_encoding
, array_length
);
315 return lttng::make_unique
<lst::static_length_array_type
>(
316 array_alignment
, std::move(element_type
), array_length
);
319 lst::type::cuptr
create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
320 const lttng_ust_ctl_field
*end
,
321 const session_attributes
& session_attributes
,
322 const lttng_ust_ctl_field
**next_ust_ctl_field
,
323 publish_field_fn publish_field
,
324 lst::field_location::root lookup_root
,
325 lst::field_location::elements
¤t_field_location_elements
)
327 if (current
>= end
) {
328 LTTNG_THROW_PROTOCOL_ERROR(
329 fmt::format("End of {} array reached unexpectedly during decoding",
333 const auto& array_uctl_field
= *current
;
334 uint32_t array_alignment
, array_length
;
335 lst::type::cuptr element_type
;
336 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
338 array_length
= array_uctl_field
.type
.u
.array_nestable
.length
;
339 array_alignment
= array_uctl_field
.type
.u
.array_nestable
.alignment
;
341 /* Nestable array fields are followed by their element type. */
342 const auto& element_uctl_field
= *(current
+ 1);
344 /* next_ust_ctl_field is updated as needed. */
345 element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
, session_attributes
,
346 next_ust_ctl_field
, publish_field
, lookup_root
,
347 current_field_location_elements
);
348 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
349 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
350 /* Element represents a text character. */
351 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
352 element_uctl_field
.type
.u
.integer
.encoding
);
355 if (element_encoding
) {
356 const auto integer_element_size
=
357 static_cast<const lst::integer_type
&>(*element_type
).size
;
359 if (integer_element_size
!= 8) {
360 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
361 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
362 integer_element_size
));
365 /* Array is a static-length string. */
366 return lttng::make_unique
<lst::static_length_string_type
>(
367 array_alignment
, *element_encoding
, array_length
);
370 return lttng::make_unique
<lst::static_length_array_type
>(
371 array_alignment
, std::move(element_type
), array_length
);
375 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
376 * length as part of the same lttng_ust_ctl_field entry.
378 lst::type::cuptr
create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
379 const lttng_ust_ctl_field
*end
,
380 const session_attributes
& session_attributes
,
381 const lttng_ust_ctl_field
**next_ust_ctl_field
,
382 publish_field_fn publish_field
,
383 lst::field_location::root lookup_root
,
384 lst::field_location::elements
¤t_field_location_elements
)
386 if (current
>= end
) {
387 LTTNG_THROW_PROTOCOL_ERROR(
388 fmt::format("End of {} array reached unexpectedly during decoding",
392 const auto& sequence_uctl_field
= *current
;
393 const auto& element_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.elem_type
;
394 const auto& length_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.length_type
;
395 const auto sequence_alignment
= 0U;
397 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
398 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
399 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
400 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
403 if (length_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
404 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
405 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
406 length_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
409 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
410 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
411 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
412 /* Element represents a text character. */
413 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
414 element_uctl_type
.u
.basic
.integer
.encoding
);
417 const auto length_field_name
= fmt::format("_{}_length", sequence_uctl_field
.name
);
418 auto element_type
= create_integer_type_from_ust_ctl_basic_type(
419 element_uctl_type
, session_attributes
);
420 auto length_type
= create_integer_type_from_ust_ctl_basic_type(
421 length_uctl_type
, session_attributes
);
423 lst::field_location::elements length_field_location_elements
=
424 current_field_location_elements
;
425 length_field_location_elements
.emplace_back(length_field_name
);
427 const lst::field_location length_field_location
{
428 lookup_root
, std::move(length_field_location_elements
)};
430 /* Publish an implicit length field _before_ the sequence field. */
431 publish_field(lttng::make_unique
<lst::field
>(std::move(length_field_name
), std::move(length_type
)));
433 *next_ust_ctl_field
= current
+ 1;
435 if (element_encoding
) {
436 const auto integer_element_size
=
437 static_cast<const lst::integer_type
&>(*element_type
).size
;
439 if (integer_element_size
!= 8) {
440 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
441 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
442 integer_element_size
));
445 /* Sequence is a dynamic-length string. */
446 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
447 *element_encoding
, std::move(length_field_location
));
450 return lttng::make_unique
<lst::dynamic_length_array_type
>(sequence_alignment
,
451 std::move(element_type
), std::move(length_field_location
));
454 lst::type::cuptr
create_sequence_nestable_type_from_ust_ctl_fields(
455 const lttng_ust_ctl_field
*current
,
456 const lttng_ust_ctl_field
*end
,
457 const session_attributes
& session_attributes
,
458 const lttng_ust_ctl_field
**next_ust_ctl_field
,
459 publish_field_fn publish_field
,
460 lst::field_location::root lookup_root
,
461 lst::field_location::elements
¤t_field_location_elements
)
463 if (current
>= end
) {
464 LTTNG_THROW_PROTOCOL_ERROR(
465 fmt::format("End of {} array reached unexpectedly during decoding",
469 const auto& sequence_uctl_field
= *current
;
470 const auto sequence_alignment
= sequence_uctl_field
.type
.u
.sequence_nestable
.alignment
;
471 const auto *length_field_name
= sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
;
473 /* Nestable sequence fields are followed by their element type. */
474 const auto& element_uctl_field
= *(current
+ 1);
476 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
477 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
478 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
479 /* Element represents a text character. */
480 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
481 element_uctl_field
.type
.u
.integer
.encoding
);
484 /* next_ust_ctl_field is updated as needed. */
485 auto element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
,
486 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_root
,
487 current_field_location_elements
);
489 if (lttng_strnlen(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
,
490 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) ==
491 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) {
492 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
496 lst::field_location::elements length_field_location_elements
=
497 current_field_location_elements
;
498 length_field_location_elements
.emplace_back(std::move(length_field_name
));
500 const lst::field_location length_field_location
{
501 lookup_root
, std::move(length_field_location_elements
)};
503 if (element_encoding
) {
504 const auto integer_element_size
=
505 static_cast<const lst::integer_type
&>(*element_type
).size
;
507 if (integer_element_size
!= 8) {
508 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
509 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
510 integer_element_size
));
513 /* Sqeuence is a dynamic-length string. */
514 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
515 *element_encoding
, std::move(length_field_location
));
518 return lttng::make_unique
<lst::dynamic_length_array_type
>(sequence_alignment
,
519 std::move(element_type
), std::move(length_field_location
));
522 lst::type::cuptr
create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
523 const lttng_ust_ctl_field
*end
,
524 const session_attributes
& session_attributes
__attribute__((unused
)),
525 const lttng_ust_ctl_field
**next_ust_ctl_field
)
527 if (current
>= end
) {
528 LTTNG_THROW_PROTOCOL_ERROR(
529 fmt::format("End of {} array reached unexpectedly during decoding",
533 uint32_t field_count
;
535 const auto& structure_uctl_field
= *current
;
537 if (structure_uctl_field
.type
.atype
== lttng_ust_ctl_atype_struct
) {
538 field_count
= structure_uctl_field
.type
.u
.legacy
._struct
.nr_fields
;
541 field_count
= structure_uctl_field
.type
.u
.struct_nestable
.nr_fields
;
542 alignment
= structure_uctl_field
.type
.u
.struct_nestable
.alignment
;
545 if (field_count
!= 0) {
546 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
547 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
551 *next_ust_ctl_field
= current
+ 1;
552 return lttng::make_unique
<lst::structure_type
>(alignment
, lst::structure_type::fields());
555 lst::type::cuptr
create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
556 const lttng_ust_ctl_field
*end
,
557 const session_attributes
& session_attributes
,
558 const lttng_ust_ctl_field
**next_ust_ctl_field
,
559 lst::field_location::root lookup_root
,
560 lst::field_location::elements
¤t_field_location_elements
)
562 if (current
>= end
) {
563 LTTNG_THROW_PROTOCOL_ERROR(
564 fmt::format("End of {} array reached unexpectedly during decoding",
568 const auto& variant_uctl_field
= *current
;
572 uint32_t choice_count
;
573 const char *tag_name
;
575 if (variant_uctl_field
.type
.atype
== lttng_ust_ctl_atype_variant
) {
577 choice_count
= variant_uctl_field
.type
.u
.legacy
.variant
.nr_choices
;
578 tag_name
= variant_uctl_field
.type
.u
.legacy
.variant
.tag_name
;
580 alignment
= variant_uctl_field
.type
.u
.variant_nestable
.alignment
;
581 choice_count
= variant_uctl_field
.type
.u
.variant_nestable
.nr_choices
;
582 tag_name
= variant_uctl_field
.type
.u
.variant_nestable
.tag_name
;
585 lst::field_location::elements selector_field_location_elements
=
586 current_field_location_elements
;
587 selector_field_location_elements
.emplace_back(tag_name
);
589 const lst::field_location selector_field_location
{
590 lookup_root
, std::move(selector_field_location_elements
)};
592 /* Choices follow. next_ust_ctl_field is updated as needed. */
593 lst::variant_type::choices choices
;
594 for (unsigned int i
= 0; i
< choice_count
; i
++) {
595 create_field_from_ust_ctl_fields(
596 current
, end
, session_attributes
, next_ust_ctl_field
,
597 [&choices
](lst::field::cuptr field
) {
598 choices
.emplace_back(std::move(field
));
600 lookup_root
, current_field_location_elements
);
602 current
= *next_ust_ctl_field
;
605 return lttng::make_unique
<lst::variant_type
>(
606 alignment
, std::move(selector_field_location
), std::move(choices
));
609 lst::type::cuptr
create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
610 const lttng_ust_ctl_field
*end
,
611 const session_attributes
& session_attributes
,
612 const lttng_ust_ctl_field
**next_ust_ctl_field
,
613 publish_field_fn publish_field
,
614 lst::field_location::root lookup_root
,
615 lst::field_location::elements
¤t_field_location_elements
)
617 switch (current
->type
.atype
) {
618 case lttng_ust_ctl_atype_integer
:
619 return create_integer_type_from_ust_ctl_fields(
620 current
, end
, session_attributes
, next_ust_ctl_field
);
621 case lttng_ust_ctl_atype_enum
:
622 case lttng_ust_ctl_atype_enum_nestable
:
623 return create_enumeration_type_from_ust_ctl_fields(
624 current
, end
, session_attributes
, next_ust_ctl_field
);
625 case lttng_ust_ctl_atype_float
:
626 return create_floating_point_type_from_ust_ctl_fields(
627 current
, end
, session_attributes
, next_ust_ctl_field
);
628 case lttng_ust_ctl_atype_string
:
629 return create_string_type_from_ust_ctl_fields(
630 current
, end
, session_attributes
, next_ust_ctl_field
);
631 case lttng_ust_ctl_atype_array
:
632 return create_array_type_from_ust_ctl_fields(current
, end
, session_attributes
,
634 case lttng_ust_ctl_atype_array_nestable
:
635 return create_array_nestable_type_from_ust_ctl_fields(current
, end
,
636 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_root
,
637 current_field_location_elements
);
638 case lttng_ust_ctl_atype_sequence
:
639 return create_sequence_type_from_ust_ctl_fields(current
, end
, session_attributes
,
640 next_ust_ctl_field
, publish_field
, lookup_root
,
641 current_field_location_elements
);
642 case lttng_ust_ctl_atype_sequence_nestable
:
643 return create_sequence_nestable_type_from_ust_ctl_fields(current
, end
,
644 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_root
,
645 current_field_location_elements
);
646 case lttng_ust_ctl_atype_struct
:
647 case lttng_ust_ctl_atype_struct_nestable
:
648 return create_structure_field_from_ust_ctl_fields(
649 current
, end
, session_attributes
, next_ust_ctl_field
);
650 case lttng_ust_ctl_atype_variant
:
651 case lttng_ust_ctl_atype_variant_nestable
:
652 return create_variant_field_from_ust_ctl_fields(current
, end
, session_attributes
,
653 next_ust_ctl_field
, lookup_root
, current_field_location_elements
);
655 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
656 "Unknown {} value `{}` encountered while converting {} to {}",
657 typeid(current
->type
.atype
), current
->type
.atype
, typeid(*current
),
658 typeid(lst::type::cuptr::element_type
)));
662 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
663 const lttng_ust_ctl_field
*end
,
664 const session_attributes
& session_attributes
,
665 const lttng_ust_ctl_field
**next_ust_ctl_field
,
666 publish_field_fn publish_field
,
667 lst::field_location::root lookup_root
,
668 lst::field_location::elements
& current_field_location_elements
)
670 LTTNG_ASSERT(current
< end
);
672 if (lttng_strnlen(current
->name
, sizeof(current
->name
)) == sizeof(current
->name
)) {
673 LTTNG_THROW_PROTOCOL_ERROR(
674 fmt::format("Name of {} is not null-terminated", typeid(*current
)));
677 publish_field(lttng::make_unique
<lst::field
>(current
->name
,
678 create_type_from_ust_ctl_fields(current
, end
, session_attributes
,
679 next_ust_ctl_field
, publish_field
,
681 current_field_location_elements
)));
685 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
686 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
687 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
690 * Always returns a new field, throws on error.
692 std::vector
<lst::field::cuptr
> create_fields_from_ust_ctl_fields(
693 const lsu::registry_session
& session
,
694 const lttng_ust_ctl_field
*current
,
695 const lttng_ust_ctl_field
*end
,
696 lst::field_location::root lookup_root
)
698 std::vector
<lst::field::cuptr
> fields
;
699 const auto trace_native_byte_order
= session
.abi
.byte_order
;
700 const session_attributes session_attributes
{
701 [&session
](const char *enum_name
, uint64_t enum_id
) {
702 return session
.get_enumeration(enum_name
, enum_id
);
704 trace_native_byte_order
};
705 /* Location of field being created. */
706 lst::field_location::elements current_field_location_elements
;
708 while (current
< end
) {
709 auto *next_field
= current
;
712 * create_field_from_ust_ctl_fields will consume one field at a time.
713 * However, some fields expressed by LTTng-UST's protocol are expended
714 * to multiple event fields (legacy sequence fields implicitly define
715 * their length field).
717 * The lambda allows the factory functions to push as many fields as
718 * needed depending on the decoded field's type.
720 create_field_from_ust_ctl_fields(current
, end
, session_attributes
, &next_field
,
721 [&fields
](lst::field::cuptr field
) {
722 fields
.emplace_back(std::move(field
));
725 current_field_location_elements
);
727 current
= next_field
;
734 std::vector
<lst::field::cuptr
> lsu::create_trace_fields_from_ust_ctl_fields(
735 const lsu::registry_session
& session
,
736 const lttng_ust_ctl_field
*fields
,
737 std::size_t field_count
,
738 lst::field_location::root lookup_root
)
740 return create_fields_from_ust_ctl_fields(session
, fields
, fields
+ field_count
, lookup_root
);