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/exception.hpp>
11 #include <common/make-unique.hpp>
13 #include <unordered_map>
16 namespace lst
= lttng::sessiond::trace
;
17 namespace lsu
= lttng::sessiond::ust
;
20 * fmtlib helper that must be under the same namespace as lttng_ust_ctl_abstract_types
23 static int format_as(lttng_ust_ctl_abstract_types type
)
25 return fmt::underlying(type
);
30 * Type enclosing the session information that may be required during the decoding
31 * of the lttng_ust_ctl_field array provided by applications on registration of
34 class session_attributes
{
36 using registry_enum_getter_fn
=
37 std::function
<lsu::registry_enum::const_rcu_protected_reference(const char *name
,
40 session_attributes(registry_enum_getter_fn reg_enum_getter
,
41 lst::byte_order native_trace_byte_order
) :
42 get_registry_enum
{ std::move(reg_enum_getter
) },
43 _native_trace_byte_order
{ native_trace_byte_order
}
47 const registry_enum_getter_fn get_registry_enum
;
48 const lst::byte_order _native_trace_byte_order
;
51 /* Used to publish fields on which a field being decoded has an implicit dependency. */
52 using publish_field_fn
= std::function
<void(lst::field::uptr
)>;
54 /* Look-up field from a field location. */
55 using lookup_field_fn
= std::function
<const lst::field
&(const lst::field_location
&)>;
58 create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
59 const lttng_ust_ctl_field
*end
,
60 const session_attributes
& session_attributes
,
61 const lttng_ust_ctl_field
**next_ust_ctl_field
,
62 const publish_field_fn
& publish_field
,
63 const lookup_field_fn
& lookup_field
,
64 lst::field_location::root lookup_root
,
65 lst::field_location::elements
& current_field_location_elements
,
66 lsu::ctl_field_quirks quirks
);
68 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
69 const lttng_ust_ctl_field
*end
,
70 const session_attributes
& session_attributes
,
71 const lttng_ust_ctl_field
**next_ust_ctl_field
,
72 const publish_field_fn
& publish_field
,
73 const lookup_field_fn
& lookup_field
,
74 lst::field_location::root lookup_root
,
75 lst::field_location::elements
& current_field_location_elements
,
76 lsu::ctl_field_quirks quirks
);
78 template <class UstCtlEncodingType
>
79 enum lst::null_terminated_string_type::encoding
80 ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding
)
82 static const std::unordered_map
<UstCtlEncodingType
,
83 enum lst::null_terminated_string_type::encoding
>
84 encoding_conversion_map
= {
85 { (UstCtlEncodingType
) lttng_ust_ctl_encode_ASCII
,
86 lst::null_terminated_string_type::encoding::ASCII
},
87 { (UstCtlEncodingType
) lttng_ust_ctl_encode_UTF8
,
88 lst::null_terminated_string_type::encoding::UTF8
},
91 const auto encoding_it
= encoding_conversion_map
.find(encoding
);
92 if (encoding_it
== encoding_conversion_map
.end()) {
93 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
94 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
98 return encoding_it
->second
;
101 template <class UstCtlBaseType
>
102 enum lst::integer_type::base
ust_ctl_base_to_integer_field_base(UstCtlBaseType base
)
104 static const std::unordered_map
<UstCtlBaseType
, enum lst::integer_type::base
>
105 base_conversion_map
= { { 2, lst::integer_type::base::BINARY
},
106 { 8, lst::integer_type::base::OCTAL
},
107 { 10, lst::integer_type::base::DECIMAL
},
108 { 16, lst::integer_type::base::HEXADECIMAL
} };
110 const auto base_it
= base_conversion_map
.find(base
);
111 if (base_it
== base_conversion_map
.end()) {
112 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
113 "Unknown integer base value `{}` encountered when decoding integer field",
117 return base_it
->second
;
121 create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
122 const lttng_ust_ctl_field
*end
,
123 const session_attributes
& session_attributes
,
124 const lttng_ust_ctl_field
**next_ust_ctl_field
,
125 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
127 if (current
>= end
) {
128 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
129 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
132 const auto base
= ust_ctl_base_to_integer_field_base(current
->type
.u
.integer
.base
);
133 const auto signedness
= current
->type
.u
.integer
.signedness
?
134 lst::integer_type::signedness::SIGNED
:
135 lst::integer_type::signedness::UNSIGNED
;
136 const auto byte_order
= current
->type
.u
.integer
.reverse_byte_order
?
137 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
138 session_attributes
._native_trace_byte_order
;
140 *next_ust_ctl_field
= current
+ 1;
142 return lttng::make_unique
<const lst::integer_type
>(current
->type
.u
.integer
.alignment
,
144 current
->type
.u
.integer
.size
,
150 create_floating_point_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
,
154 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
156 if (current
>= end
) {
157 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
158 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
161 *next_ust_ctl_field
= current
+ 1;
163 const auto byte_order
= current
->type
.u
._float
.reverse_byte_order
?
164 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
165 session_attributes
._native_trace_byte_order
;
168 return lttng::make_unique
<const lst::floating_point_type
>(
169 current
->type
.u
._float
.alignment
,
171 current
->type
.u
._float
.exp_dig
,
172 current
->type
.u
._float
.mant_dig
);
173 } catch (lttng::invalid_argument_error
& ex
) {
174 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
175 "Invalid floating point attribute in {}: {}", typeid(*current
), ex
.what()));
180 create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
181 const lttng_ust_ctl_field
*end
,
182 const session_attributes
& session_attributes
,
183 const lttng_ust_ctl_field
**next_ust_ctl_field
,
184 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
186 if (current
>= end
) {
187 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
188 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
191 uint64_t enumeration_id
;
192 const auto& enum_uctl_field
= *current
;
193 const char *enumeration_name
;
194 const auto *enum_container_uctl_type
=
195 ¤t
->type
.u
.legacy
.basic
.enumeration
.container_type
;
197 if (enum_uctl_field
.type
.atype
== lttng_ust_ctl_atype_enum_nestable
) {
198 /* Nestable enumeration fields are followed by their container type. */
200 if (current
>= end
) {
201 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
202 "Array of {} is too short to contain nestable enumeration's container",
206 if (current
->type
.atype
!= lttng_ust_ctl_atype_integer
) {
207 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
208 "Invalid type of nestable enum container: type id = {}",
209 current
->type
.atype
));
212 enum_container_uctl_type
= ¤t
->type
.u
.integer
;
213 enumeration_id
= enum_uctl_field
.type
.u
.enum_nestable
.id
;
214 enumeration_name
= enum_uctl_field
.type
.u
.enum_nestable
.name
;
216 enumeration_id
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.id
;
217 enumeration_name
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.name
;
220 *next_ust_ctl_field
= current
+ 1;
222 const auto base
= ust_ctl_base_to_integer_field_base(enum_container_uctl_type
->base
);
223 const auto byte_order
= enum_container_uctl_type
->reverse_byte_order
?
224 lst::integer_type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
225 session_attributes
._native_trace_byte_order
;
226 const auto signedness
= enum_container_uctl_type
->signedness
?
227 lst::integer_type::signedness::SIGNED
:
228 lst::integer_type::signedness::UNSIGNED
;
230 if (signedness
== lst::integer_type::signedness::SIGNED
) {
231 const auto& enum_registry
= static_cast<const lsu::registry_signed_enum
&>(
232 *session_attributes
.get_registry_enum(enumeration_name
, enumeration_id
));
234 return lttng::make_unique
<const lst::signed_enumeration_type
>(
235 enum_container_uctl_type
->alignment
,
237 enum_container_uctl_type
->size
,
239 enum_registry
._mappings
);
241 const auto& enum_registry
= static_cast<const lsu::registry_unsigned_enum
&>(
242 *session_attributes
.get_registry_enum(enumeration_name
, enumeration_id
));
244 return lttng::make_unique
<const lst::unsigned_enumeration_type
>(
245 enum_container_uctl_type
->alignment
,
247 enum_container_uctl_type
->size
,
249 enum_registry
._mappings
);
254 create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
255 const lttng_ust_ctl_field
*end
,
256 const session_attributes
& session_attributes
257 __attribute__((unused
)),
258 const lttng_ust_ctl_field
**next_ust_ctl_field
,
259 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
261 if (current
>= end
) {
262 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
263 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
266 const auto& string_uctl_field
= *current
;
267 *next_ust_ctl_field
= current
+ 1;
269 const auto encoding
=
270 ust_ctl_encoding_to_string_field_encoding(string_uctl_field
.type
.u
.string
.encoding
);
272 return lttng::make_unique
<const lst::null_terminated_string_type
>(1, encoding
);
276 create_integer_type_from_ust_ctl_basic_type(const lttng_ust_ctl_basic_type
& type
,
277 const session_attributes
& session_attributes
)
279 /* Checked by caller. */
280 LTTNG_ASSERT(type
.atype
== lttng_ust_ctl_atype_integer
);
282 const auto byte_order
= type
.u
.basic
.integer
.reverse_byte_order
?
283 lst::integer_type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
284 session_attributes
._native_trace_byte_order
;
285 const auto signedness
= type
.u
.basic
.integer
.signedness
?
286 lst::integer_type::signedness::SIGNED
:
287 lst::integer_type::signedness::UNSIGNED
;
288 const auto base
= ust_ctl_base_to_integer_field_base(type
.u
.basic
.integer
.base
);
289 const auto size
= type
.u
.basic
.integer
.size
;
290 const auto alignment
= type
.u
.basic
.integer
.alignment
;
292 return lttng::make_unique
<const lst::integer_type
>(
293 alignment
, byte_order
, size
, signedness
, base
);
297 create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
298 const lttng_ust_ctl_field
*end
,
299 const session_attributes
& session_attributes
,
300 const lttng_ust_ctl_field
**next_ust_ctl_field
,
301 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
303 if (current
>= end
) {
304 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
305 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
308 const auto& array_uctl_field
= *current
;
309 uint32_t array_alignment
, array_length
;
310 lst::type::cuptr element_type
;
311 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
313 array_length
= array_uctl_field
.type
.u
.legacy
.array
.length
;
316 const auto& element_uctl_type
= array_uctl_field
.type
.u
.legacy
.array
.elem_type
;
317 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
318 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
319 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
320 element_uctl_type
.atype
,
321 lttng_ust_ctl_atype_integer
));
325 create_integer_type_from_ust_ctl_basic_type(element_uctl_type
, session_attributes
);
326 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
327 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
328 /* Element represents a text character. */
329 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
330 element_uctl_type
.u
.basic
.integer
.encoding
);
333 *next_ust_ctl_field
= current
+ 1;
335 if (element_encoding
) {
336 const auto integer_element_size
=
337 static_cast<const lst::integer_type
&>(*element_type
).size
;
339 if (integer_element_size
!= 8) {
340 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
341 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
342 integer_element_size
));
345 /* Array is a static-length string. */
346 return lttng::make_unique
<lst::static_length_string_type
>(
347 array_alignment
, *element_encoding
, array_length
);
350 return lttng::make_unique
<lst::static_length_array_type
>(
351 array_alignment
, std::move(element_type
), array_length
);
354 lst::type::cuptr
create_array_nestable_type_from_ust_ctl_fields(
355 const lttng_ust_ctl_field
*current
,
356 const lttng_ust_ctl_field
*end
,
357 const session_attributes
& session_attributes
,
358 const lttng_ust_ctl_field
**next_ust_ctl_field
,
359 const publish_field_fn
& publish_field
,
360 const lookup_field_fn
& lookup_field
,
361 lst::field_location::root lookup_root
,
362 lst::field_location::elements
& current_field_location_elements
,
363 lsu::ctl_field_quirks quirks
)
365 if (current
>= end
) {
366 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
367 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
370 const auto& array_uctl_field
= *current
;
371 uint32_t array_alignment
, array_length
;
372 lst::type::cuptr element_type
;
373 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
375 array_length
= array_uctl_field
.type
.u
.array_nestable
.length
;
376 array_alignment
= array_uctl_field
.type
.u
.array_nestable
.alignment
;
378 /* Nestable array fields are followed by their element type. */
379 const auto& element_uctl_field
= *(current
+ 1);
381 /* next_ust_ctl_field is updated as needed. */
382 element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
,
389 current_field_location_elements
,
391 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
392 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
393 /* Element represents a text character. */
394 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
395 element_uctl_field
.type
.u
.integer
.encoding
);
398 if (element_encoding
) {
399 const auto integer_element_size
=
400 static_cast<const lst::integer_type
&>(*element_type
).size
;
402 if (integer_element_size
!= 8) {
403 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
404 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
405 integer_element_size
));
408 /* Array is a static-length string. */
409 return lttng::make_unique
<lst::static_length_string_type
>(
410 array_alignment
, *element_encoding
, array_length
);
413 return lttng::make_unique
<lst::static_length_array_type
>(
414 array_alignment
, std::move(element_type
), array_length
);
418 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
419 * length as part of the same lttng_ust_ctl_field entry.
421 lst::type::cuptr
create_sequence_type_from_ust_ctl_fields(
422 const lttng_ust_ctl_field
*current
,
423 const lttng_ust_ctl_field
*end
,
424 const session_attributes
& session_attributes
,
425 const lttng_ust_ctl_field
**next_ust_ctl_field
,
426 const publish_field_fn
& publish_field
,
427 lst::field_location::root lookup_root
,
428 lst::field_location::elements
& current_field_location_elements
,
429 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
431 if (current
>= end
) {
432 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
433 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
436 const auto& sequence_uctl_field
= *current
;
437 const auto& element_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.elem_type
;
438 const auto& length_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.length_type
;
439 const auto sequence_alignment
= 0U;
441 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
442 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
443 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
444 element_uctl_type
.atype
,
445 lttng_ust_ctl_atype_integer
));
448 if (length_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
449 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
450 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
451 length_uctl_type
.atype
,
452 lttng_ust_ctl_atype_integer
));
455 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
456 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
457 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
458 /* Element represents a text character. */
459 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
460 element_uctl_type
.u
.basic
.integer
.encoding
);
463 auto length_field_name
= lttng::format("_{}_length", sequence_uctl_field
.name
);
465 create_integer_type_from_ust_ctl_basic_type(element_uctl_type
, session_attributes
);
467 create_integer_type_from_ust_ctl_basic_type(length_uctl_type
, session_attributes
);
469 lst::field_location::elements length_field_location_elements
=
470 current_field_location_elements
;
471 length_field_location_elements
.emplace_back(length_field_name
);
473 lst::field_location length_field_location
{ lookup_root
,
474 std::move(length_field_location_elements
) };
476 /* Publish an implicit length field _before_ the sequence field. */
477 publish_field(lttng::make_unique
<lst::field
>(std::move(length_field_name
),
478 std::move(length_type
)));
480 *next_ust_ctl_field
= current
+ 1;
482 if (element_encoding
) {
483 const auto integer_element_size
=
484 static_cast<const lst::integer_type
&>(*element_type
).size
;
486 if (integer_element_size
!= 8) {
487 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
488 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
489 integer_element_size
));
492 /* Sequence is a dynamic-length string. */
493 return lttng::make_unique
<lst::dynamic_length_string_type
>(
494 sequence_alignment
, *element_encoding
, std::move(length_field_location
));
497 return lttng::make_unique
<lst::dynamic_length_array_type
>(
498 sequence_alignment
, std::move(element_type
), std::move(length_field_location
));
501 lst::type::cuptr
create_sequence_nestable_type_from_ust_ctl_fields(
502 const lttng_ust_ctl_field
*current
,
503 const lttng_ust_ctl_field
*end
,
504 const session_attributes
& session_attributes
,
505 const lttng_ust_ctl_field
**next_ust_ctl_field
,
506 const publish_field_fn
& publish_field
,
507 const lookup_field_fn
& lookup_field
,
508 lst::field_location::root lookup_root
,
509 lst::field_location::elements
& current_field_location_elements
,
510 lsu::ctl_field_quirks quirks
)
512 if (current
>= end
) {
513 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
514 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
517 const auto& sequence_uctl_field
= *current
;
518 const auto sequence_alignment
= sequence_uctl_field
.type
.u
.sequence_nestable
.alignment
;
519 const auto *length_field_name
= sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
;
521 /* Nestable sequence fields are followed by their element type. */
522 const auto& element_uctl_field
= *(current
+ 1);
524 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
525 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
526 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
527 /* Element represents a text character. */
528 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
529 element_uctl_field
.type
.u
.integer
.encoding
);
532 /* next_ust_ctl_field is updated as needed. */
533 auto element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
,
540 current_field_location_elements
,
543 if (lttng_strnlen(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
,
544 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) ==
545 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) {
546 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
549 lst::field_location::elements length_field_location_elements
=
550 current_field_location_elements
;
551 length_field_location_elements
.emplace_back(length_field_name
);
553 lst::field_location length_field_location
{ lookup_root
,
554 std::move(length_field_location_elements
) };
556 /* Validate existence of length field (throws if not found). */
557 const auto& length_field
= lookup_field(length_field_location
);
558 const auto *integer_selector_field
=
559 dynamic_cast<const lst::integer_type
*>(&length_field
.get_type());
560 if (!integer_selector_field
) {
561 LTTNG_THROW_PROTOCOL_ERROR(
562 "Invalid selector field type referenced from sequence: expected integer or enumeration");
565 if (element_encoding
) {
566 const auto integer_element_size
=
567 static_cast<const lst::integer_type
&>(*element_type
).size
;
569 if (integer_element_size
!= 8) {
570 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
571 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
572 integer_element_size
));
575 /* Sqeuence is a dynamic-length string. */
576 return lttng::make_unique
<lst::dynamic_length_string_type
>(
577 sequence_alignment
, *element_encoding
, std::move(length_field_location
));
580 return lttng::make_unique
<lst::dynamic_length_array_type
>(
581 sequence_alignment
, std::move(element_type
), std::move(length_field_location
));
585 create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
586 const lttng_ust_ctl_field
*end
,
587 const session_attributes
& session_attributes
588 __attribute__((unused
)),
589 const lttng_ust_ctl_field
**next_ust_ctl_field
,
590 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
592 if (current
>= end
) {
593 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
594 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
597 uint32_t field_count
;
599 const auto& structure_uctl_field
= *current
;
601 if (structure_uctl_field
.type
.atype
== lttng_ust_ctl_atype_struct
) {
602 field_count
= structure_uctl_field
.type
.u
.legacy
._struct
.nr_fields
;
605 field_count
= structure_uctl_field
.type
.u
.struct_nestable
.nr_fields
;
606 alignment
= structure_uctl_field
.type
.u
.struct_nestable
.alignment
;
609 if (field_count
!= 0) {
610 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
611 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
615 *next_ust_ctl_field
= current
+ 1;
616 return lttng::make_unique
<lst::structure_type
>(alignment
, lst::structure_type::fields());
619 template <class VariantSelectorMappingIntegerType
>
620 typename
lst::variant_type
<VariantSelectorMappingIntegerType
>::choices
621 create_typed_variant_choices(const lttng_ust_ctl_field
*current
,
622 const lttng_ust_ctl_field
*end
,
623 const session_attributes
& session_attributes
,
624 const lttng_ust_ctl_field
**next_ust_ctl_field
,
625 lookup_field_fn lookup_field
,
626 lst::field_location::root lookup_root
,
627 lst::field_location::elements
& current_field_location_elements
,
628 unsigned int choice_count
,
629 const lst::field
& selector_field
,
630 lsu::ctl_field_quirks quirks
)
632 typename
lst::variant_type
<VariantSelectorMappingIntegerType
>::choices choices
;
633 const auto& typed_enumeration
=
634 static_cast<const lst::typed_enumeration_type
<VariantSelectorMappingIntegerType
>&>(
635 selector_field
.get_type());
637 for (unsigned int i
= 0; i
< choice_count
; i
++) {
638 create_field_from_ust_ctl_fields(
643 [&choices
, &typed_enumeration
, &selector_field
, quirks
](
644 lst::field::uptr field
) {
646 * Find the enumeration mapping that matches the
649 const auto mapping_it
= std::find_if(
650 typed_enumeration
.mappings_
->begin(),
651 typed_enumeration
.mappings_
->end(),
653 quirks
](const typename
std::remove_reference
<
654 decltype(typed_enumeration
)>::type::mapping
&
656 if (static_cast<bool>(
658 lsu::ctl_field_quirks::
659 UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS
)) {
661 * Check if they match with
662 * a prepended underscore
663 * and, if not, perform the
666 if ((std::string("_") + field
->name
) ==
672 return mapping
.name
== field
->name
;
675 if (mapping_it
== typed_enumeration
.mappings_
->end()) {
676 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
677 "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration",
679 selector_field
.name
));
682 choices
.emplace_back(*mapping_it
, field
->move_type());
686 current_field_location_elements
,
689 current
= *next_ust_ctl_field
;
695 lst::type::cuptr
create_variant_field_from_ust_ctl_fields(
696 const lttng_ust_ctl_field
*current
,
697 const lttng_ust_ctl_field
*end
,
698 const session_attributes
& session_attributes
,
699 const lttng_ust_ctl_field
**next_ust_ctl_field
,
700 const lookup_field_fn
& lookup_field
,
701 lst::field_location::root lookup_root
,
702 lst::field_location::elements
& current_field_location_elements
,
703 lsu::ctl_field_quirks quirks
)
705 if (current
>= end
) {
706 LTTNG_THROW_PROTOCOL_ERROR(lttng::format(
707 "End of {} array reached unexpectedly during decoding", typeid(*current
)));
710 const auto& variant_uctl_field
= *current
;
714 uint32_t choice_count
;
715 const char *tag_name
;
717 if (variant_uctl_field
.type
.atype
== lttng_ust_ctl_atype_variant
) {
719 choice_count
= variant_uctl_field
.type
.u
.legacy
.variant
.nr_choices
;
720 tag_name
= variant_uctl_field
.type
.u
.legacy
.variant
.tag_name
;
722 alignment
= variant_uctl_field
.type
.u
.variant_nestable
.alignment
;
723 choice_count
= variant_uctl_field
.type
.u
.variant_nestable
.nr_choices
;
724 tag_name
= variant_uctl_field
.type
.u
.variant_nestable
.tag_name
;
727 lst::field_location::elements selector_field_location_elements
=
728 current_field_location_elements
;
729 selector_field_location_elements
.emplace_back(tag_name
);
731 lst::field_location selector_field_location
{ lookup_root
,
732 std::move(selector_field_location_elements
) };
734 /* Validate existence of selector field (throws if not found). */
735 const auto& selector_field
= lookup_field(selector_field_location
);
736 const auto *enumeration_selector_type
=
737 dynamic_cast<const lst::enumeration_type
*>(&selector_field
.get_type());
738 if (!enumeration_selector_type
) {
739 LTTNG_THROW_PROTOCOL_ERROR(
740 "Invalid selector field type referenced from variant: expected enumeration");
743 const bool selector_is_signed
= enumeration_selector_type
->signedness_
==
744 lst::integer_type::signedness::SIGNED
;
746 /* Choices follow. next_ust_ctl_field is updated as needed. */
747 if (selector_is_signed
) {
748 lst::variant_type
<lst::signed_enumeration_type::mapping::range_t::range_integer_t
>::
749 choices choices
= create_typed_variant_choices
<int64_t>(
756 current_field_location_elements
,
761 return lttng::make_unique
<lst::variant_type
<int64_t>>(
762 alignment
, std::move(selector_field_location
), std::move(choices
));
765 lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::choices
766 choices
= create_typed_variant_choices
<uint64_t>(
773 current_field_location_elements
,
778 return lttng::make_unique
<lst::variant_type
<uint64_t>>(
779 alignment
, std::move(selector_field_location
), std::move(choices
));
784 create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
785 const lttng_ust_ctl_field
*end
,
786 const session_attributes
& session_attributes
,
787 const lttng_ust_ctl_field
**next_ust_ctl_field
,
788 const publish_field_fn
& publish_field
,
789 const lookup_field_fn
& lookup_field
,
790 lst::field_location::root lookup_root
,
791 lst::field_location::elements
& current_field_location_elements
,
792 lsu::ctl_field_quirks quirks
)
794 switch (current
->type
.atype
) {
795 case lttng_ust_ctl_atype_integer
:
796 return create_integer_type_from_ust_ctl_fields(
797 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
798 case lttng_ust_ctl_atype_enum
:
799 case lttng_ust_ctl_atype_enum_nestable
:
800 return create_enumeration_type_from_ust_ctl_fields(
801 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
802 case lttng_ust_ctl_atype_float
:
803 return create_floating_point_type_from_ust_ctl_fields(
804 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
805 case lttng_ust_ctl_atype_string
:
806 return create_string_type_from_ust_ctl_fields(
807 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
808 case lttng_ust_ctl_atype_array
:
809 return create_array_type_from_ust_ctl_fields(
810 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
811 case lttng_ust_ctl_atype_array_nestable
:
812 return create_array_nestable_type_from_ust_ctl_fields(
820 current_field_location_elements
,
822 case lttng_ust_ctl_atype_sequence
:
823 return create_sequence_type_from_ust_ctl_fields(current
,
829 current_field_location_elements
,
831 case lttng_ust_ctl_atype_sequence_nestable
:
832 return create_sequence_nestable_type_from_ust_ctl_fields(
840 current_field_location_elements
,
842 case lttng_ust_ctl_atype_struct
:
843 case lttng_ust_ctl_atype_struct_nestable
:
844 return create_structure_field_from_ust_ctl_fields(
845 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
846 case lttng_ust_ctl_atype_variant
:
847 case lttng_ust_ctl_atype_variant_nestable
:
848 return create_variant_field_from_ust_ctl_fields(current
,
854 current_field_location_elements
,
857 LTTNG_THROW_PROTOCOL_ERROR(
858 lttng::format("Unknown {} value `{}` encountered while converting {} to {}",
859 typeid(current
->type
.atype
),
862 typeid(lst::type::cuptr::element_type
)));
866 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
867 const lttng_ust_ctl_field
*end
,
868 const session_attributes
& session_attributes
,
869 const lttng_ust_ctl_field
**next_ust_ctl_field
,
870 const publish_field_fn
& publish_field
,
871 const lookup_field_fn
& lookup_field
,
872 lst::field_location::root lookup_root
,
873 lst::field_location::elements
& current_field_location_elements
,
874 lsu::ctl_field_quirks quirks
)
876 LTTNG_ASSERT(current
< end
);
878 if (lttng_strnlen(current
->name
, sizeof(current
->name
)) == sizeof(current
->name
)) {
879 LTTNG_THROW_PROTOCOL_ERROR(
880 lttng::format("Name of {} is not null-terminated", typeid(*current
)));
883 publish_field(lttng::make_unique
<lst::field
>(
885 create_type_from_ust_ctl_fields(current
,
892 current_field_location_elements
,
896 std::vector
<lst::field::cuptr
>::iterator
897 lookup_field_in_vector(std::vector
<lst::field::cuptr
>& fields
, const lst::field_location
& location
)
899 if (location
.elements_
.size() != 1) {
900 LTTNG_THROW_ERROR(lttng::format(
901 "Unexpected field location received during field look-up: location = {}",
906 * In the context of fields received from LTTng-UST, field
907 * look-up is extremely naive as the protocol can only
908 * express empty structures. It is safe to assume that
909 * location has a depth of 1 and directly refers to a field
910 * in the 'fields' vector.
912 const auto field_it
=
913 std::find_if(fields
.begin(), fields
.end(), [location
](lst::field::cuptr
& field
) {
914 return field
->name
== location
.elements_
[0];
917 if (field_it
== fields
.end()) {
918 LTTNG_THROW_PROTOCOL_ERROR(
919 lttng::format("Failed to look-up field: location = {}", location
));
926 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
927 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
928 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
931 * Always returns a new field, throws on error.
933 std::vector
<lst::field::cuptr
>
934 create_fields_from_ust_ctl_fields(const lsu::registry_session
& session
,
935 const lttng_ust_ctl_field
*current
,
936 const lttng_ust_ctl_field
*end
,
937 lst::field_location::root lookup_root
,
938 lsu::ctl_field_quirks quirks
)
940 std::vector
<lst::field::cuptr
> fields
;
941 const auto trace_native_byte_order
= session
.abi
.byte_order
;
942 const session_attributes session_attributes
{
943 [&session
](const char *enum_name
, uint64_t enum_id
) {
944 return session
.enumeration(enum_name
, enum_id
);
946 trace_native_byte_order
948 /* Location of field being created. */
949 lst::field_location::elements current_field_location_elements
;
951 while (current
< end
) {
952 auto *next_field
= current
;
955 * create_field_from_ust_ctl_fields will consume one field at a time.
956 * However, some fields expressed by LTTng-UST's protocol are expended
957 * to multiple event fields (legacy sequence fields implicitly define
958 * their length field).
960 * The lambda allows the factory functions to push as many fields as
961 * needed depending on the decoded field's type.
963 create_field_from_ust_ctl_fields(
968 [&fields
](lst::field::cuptr field
) {
969 /* Publishing a field simply adds it to the converted
971 fields
.emplace_back(std::move(field
));
973 [&fields
](const lst::field_location
& location
)
974 -> lookup_field_fn::result_type
{
975 /* Resolve location to a previously-constructed field. */
976 return **lookup_field_in_vector(fields
, location
);
979 current_field_location_elements
,
982 current
= next_field
;
989 std::vector
<lst::field::cuptr
>
990 lsu::create_trace_fields_from_ust_ctl_fields(const lsu::registry_session
& session
,
991 const lttng_ust_ctl_field
*fields
,
992 std::size_t field_count
,
993 lst::field_location::root lookup_root
,
994 lsu::ctl_field_quirks quirks
)
996 return create_fields_from_ust_ctl_fields(
997 session
, fields
, fields
+ field_count
, lookup_root
, quirks
);