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
);
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
);
54 template <class UstCtlEncodingType
>
55 enum lst::null_terminated_string_type::encoding
ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding
)
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
},
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",
72 return encoding_it
->second
;
75 template <class UstCtlBaseType
>
76 enum lst::integer_type::base
ust_ctl_base_to_integer_field_base(UstCtlBaseType base
)
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
}};
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",
91 return base_it
->second
;
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
)
100 LTTNG_THROW_PROTOCOL_ERROR(
101 fmt::format("End of {} array reached unexpectedly during decoding",
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
;
113 *next_ust_ctl_field
= current
+ 1;
115 return lttng::make_unique
<const lst::integer_type
>(current
->type
.u
.integer
.alignment
,
116 byte_order
, current
->type
.u
.integer
.size
, signedness
, base
);
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
)
124 if (current
>= end
) {
125 LTTNG_THROW_PROTOCOL_ERROR(
126 fmt::format("End of {} array reached unexpectedly during decoding",
130 *next_ust_ctl_field
= current
+ 1;
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
;
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()));
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
)
151 if (current
>= end
) {
152 LTTNG_THROW_PROTOCOL_ERROR(
153 fmt::format("End of {} array reached unexpectedly during decoding",
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 ¤t
->type
.u
.legacy
.basic
.enumeration
.container_type
;
163 if (enum_uctl_field
.type
.atype
== lttng_ust_ctl_atype_enum_nestable
) {
164 /* Nestable enumeration fields are followed by their container type. */
166 if (current
>= end
) {
167 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
168 "Array of {} is too short to contain nestable enumeration's container",
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
));
178 enum_container_uctl_type
= ¤t
->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
;
182 enumeration_id
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.id
;
183 enumeration_name
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.name
;
186 *next_ust_ctl_field
= current
+ 1;
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
;
194 if (enum_container_uctl_type
->signedness
) {
195 const auto& enum_registry
= static_cast<const lsu::registry_signed_enum
&>(
196 *session_attributes
.get_registry_enum(
197 enumeration_name
, enumeration_id
));
199 return lttng::make_unique
<const lst::signed_enumeration_type
>(
200 enum_container_uctl_type
->alignment
, byte_order
,
201 enum_container_uctl_type
->size
, base
,
202 enum_registry
._mappings
);
204 const auto& enum_registry
= static_cast<const lsu::registry_unsigned_enum
&>(
205 *session_attributes
.get_registry_enum(
206 enumeration_name
, enumeration_id
));
208 return lttng::make_unique
<const lst::unsigned_enumeration_type
>(
209 enum_container_uctl_type
->alignment
, byte_order
,
210 enum_container_uctl_type
->size
, base
,
211 enum_registry
._mappings
);
215 lst::type::cuptr
create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
216 const lttng_ust_ctl_field
*end
,
217 const session_attributes
& session_attributes
__attribute__((unused
)),
218 const lttng_ust_ctl_field
**next_ust_ctl_field
)
220 if (current
>= end
) {
221 LTTNG_THROW_PROTOCOL_ERROR(
222 fmt::format("End of {} array reached unexpectedly during decoding",
226 const auto& string_uctl_field
= *current
;
227 *next_ust_ctl_field
= current
+ 1;
229 const auto encoding
= ust_ctl_encoding_to_string_field_encoding(
230 string_uctl_field
.type
.u
.string
.encoding
);
232 return lttng::make_unique
<const lst::null_terminated_string_type
>(1, encoding
);
235 lst::type::cuptr
create_integer_type_from_ust_ctl_basic_type(
236 const lttng_ust_ctl_basic_type
& type
, const session_attributes
& session_attributes
)
238 /* Checked by caller. */
239 LTTNG_ASSERT(type
.atype
== lttng_ust_ctl_atype_integer
);
241 const auto byte_order
= type
.u
.basic
.integer
.reverse_byte_order
?
242 lst::integer_type::reverse_byte_order(
243 session_attributes
._native_trace_byte_order
) :
244 session_attributes
._native_trace_byte_order
;
245 const auto signedness
= type
.u
.basic
.integer
.signedness
?
246 lst::integer_type::signedness::SIGNED
:
247 lst::integer_type::signedness::UNSIGNED
;
248 const auto base
= ust_ctl_base_to_integer_field_base(type
.u
.basic
.integer
.base
);
249 const auto size
= type
.u
.basic
.integer
.size
;
250 const auto alignment
= type
.u
.basic
.integer
.alignment
;
252 return lttng::make_unique
<const lst::integer_type
>(
253 alignment
, byte_order
, size
, signedness
, base
);
256 lst::type::cuptr
create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
257 const lttng_ust_ctl_field
*end
,
258 const session_attributes
& session_attributes
,
259 const lttng_ust_ctl_field
**next_ust_ctl_field
)
261 if (current
>= end
) {
262 LTTNG_THROW_PROTOCOL_ERROR(
263 fmt::format("End of {} array reached unexpectedly during decoding",
267 const auto& array_uctl_field
= *current
;
268 uint32_t array_alignment
, array_length
;
269 lst::type::cuptr element_type
;
270 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
272 array_length
= array_uctl_field
.type
.u
.legacy
.array
.length
;
275 const auto& element_uctl_type
= array_uctl_field
.type
.u
.legacy
.array
.elem_type
;
276 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
277 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
278 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
279 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
282 element_type
= create_integer_type_from_ust_ctl_basic_type(
283 element_uctl_type
, session_attributes
);
284 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
285 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
286 /* Element represents a text character. */
287 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
288 element_uctl_type
.u
.basic
.integer
.encoding
);
291 *next_ust_ctl_field
= current
+ 1;
293 if (element_encoding
) {
294 const auto integer_element_size
=
295 static_cast<const lst::integer_type
&>(*element_type
).size
;
297 if (integer_element_size
!= 8) {
298 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
299 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
300 integer_element_size
));
303 /* Array is a static-length string. */
304 return lttng::make_unique
<lst::static_length_string_type
>(
305 array_alignment
, *element_encoding
, array_length
);
308 return lttng::make_unique
<lst::static_length_array_type
>(
309 array_alignment
, std::move(element_type
), array_length
);
312 lst::type::cuptr
create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
313 const lttng_ust_ctl_field
*end
,
314 const session_attributes
& session_attributes
,
315 const lttng_ust_ctl_field
**next_ust_ctl_field
,
316 publish_field_fn publish_field
)
318 if (current
>= end
) {
319 LTTNG_THROW_PROTOCOL_ERROR(
320 fmt::format("End of {} array reached unexpectedly during decoding",
324 const auto& array_uctl_field
= *current
;
325 uint32_t array_alignment
, array_length
;
326 lst::type::cuptr element_type
;
327 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
329 array_length
= array_uctl_field
.type
.u
.array_nestable
.length
;
330 array_alignment
= array_uctl_field
.type
.u
.array_nestable
.alignment
;
332 /* Nestable array fields are followed by their element type. */
333 const auto& element_uctl_field
= *(current
+ 1);
335 /* next_ust_ctl_field is updated as needed. */
336 element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
, session_attributes
,
337 next_ust_ctl_field
, publish_field
);
338 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
339 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
340 /* Element represents a text character. */
341 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
342 element_uctl_field
.type
.u
.integer
.encoding
);
345 if (element_encoding
) {
346 const auto integer_element_size
=
347 static_cast<const lst::integer_type
&>(*element_type
).size
;
349 if (integer_element_size
!= 8) {
350 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
351 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
352 integer_element_size
));
355 /* Array is a static-length string. */
356 return lttng::make_unique
<lst::static_length_string_type
>(
357 array_alignment
, *element_encoding
, array_length
);
360 return lttng::make_unique
<lst::static_length_array_type
>(
361 array_alignment
, std::move(element_type
), array_length
);
365 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
366 * length as part of the same lttng_ust_ctl_field entry.
368 lst::type::cuptr
create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
369 const lttng_ust_ctl_field
*end
,
370 const session_attributes
& session_attributes
,
371 const lttng_ust_ctl_field
**next_ust_ctl_field
,
372 publish_field_fn publish_field
)
374 if (current
>= end
) {
375 LTTNG_THROW_PROTOCOL_ERROR(
376 fmt::format("End of {} array reached unexpectedly during decoding",
380 const auto& sequence_uctl_field
= *current
;
381 const auto& element_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.elem_type
;
382 const auto& length_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.length_type
;
383 const auto sequence_alignment
= 0U;
385 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
386 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
387 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
388 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
391 if (length_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
392 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
393 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
394 length_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
397 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
398 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
399 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
400 /* Element represents a text character. */
401 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
402 element_uctl_type
.u
.basic
.integer
.encoding
);
405 const auto length_field_name
= fmt::format("_{}_length", sequence_uctl_field
.name
);
406 auto element_type
= create_integer_type_from_ust_ctl_basic_type(
407 element_uctl_type
, session_attributes
);
408 auto length_type
= create_integer_type_from_ust_ctl_basic_type(
409 length_uctl_type
, session_attributes
);
411 /* Publish an implicit length field _before_ the sequence field. */
412 publish_field(lttng::make_unique
<lst::field
>(length_field_name
, std::move(length_type
)));
414 *next_ust_ctl_field
= current
+ 1;
416 if (element_encoding
) {
417 const auto integer_element_size
=
418 static_cast<const lst::integer_type
&>(*element_type
).size
;
420 if (integer_element_size
!= 8) {
421 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
422 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
423 integer_element_size
));
426 /* Sequence is a dynamic-length string. */
427 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
428 *element_encoding
, std::move(length_field_name
));
431 return lttng::make_unique
<lst::dynamic_length_array_type
>(
432 sequence_alignment
, std::move(element_type
), std::move(length_field_name
));
435 lst::type::cuptr
create_sequence_nestable_type_from_ust_ctl_fields(
436 const lttng_ust_ctl_field
*current
,
437 const lttng_ust_ctl_field
*end
,
438 const session_attributes
& session_attributes
,
439 const lttng_ust_ctl_field
**next_ust_ctl_field
,
440 publish_field_fn publish_field
)
442 if (current
>= end
) {
443 LTTNG_THROW_PROTOCOL_ERROR(
444 fmt::format("End of {} array reached unexpectedly during decoding",
448 const auto& sequence_uctl_field
= *current
;
449 const auto sequence_alignment
= sequence_uctl_field
.type
.u
.sequence_nestable
.alignment
;
450 const auto *length_field_name
= sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
;
452 /* Nestable sequence fields are followed by their element type. */
453 const auto& element_uctl_field
= *(current
+ 1);
455 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
456 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
457 element_uctl_field
.type
.u
.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_field
.type
.u
.integer
.encoding
);
463 /* next_ust_ctl_field is updated as needed. */
464 auto element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
,
465 session_attributes
, next_ust_ctl_field
, publish_field
);
467 if (lttng_strnlen(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
,
468 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) ==
469 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) {
470 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
473 if (element_encoding
) {
474 const auto integer_element_size
=
475 static_cast<const lst::integer_type
&>(*element_type
).size
;
477 if (integer_element_size
!= 8) {
478 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
479 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
480 integer_element_size
));
483 /* Sqeuence is a dynamic-length string. */
484 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
485 *element_encoding
, std::move(length_field_name
));
488 return lttng::make_unique
<lst::dynamic_length_array_type
>(
489 sequence_alignment
, std::move(element_type
), std::move(length_field_name
));
492 lst::type::cuptr
create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
493 const lttng_ust_ctl_field
*end
,
494 const session_attributes
& session_attributes
__attribute__((unused
)),
495 const lttng_ust_ctl_field
**next_ust_ctl_field
)
497 if (current
>= end
) {
498 LTTNG_THROW_PROTOCOL_ERROR(
499 fmt::format("End of {} array reached unexpectedly during decoding",
503 uint32_t field_count
;
505 const auto& structure_uctl_field
= *current
;
507 if (structure_uctl_field
.type
.atype
== lttng_ust_ctl_atype_struct
) {
508 field_count
= structure_uctl_field
.type
.u
.legacy
._struct
.nr_fields
;
511 field_count
= structure_uctl_field
.type
.u
.struct_nestable
.nr_fields
;
512 alignment
= structure_uctl_field
.type
.u
.struct_nestable
.alignment
;
515 if (field_count
!= 0) {
516 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
517 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
521 *next_ust_ctl_field
= current
+ 1;
522 return lttng::make_unique
<lst::structure_type
>(alignment
, lst::structure_type::fields());
525 lst::type::cuptr
create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
526 const lttng_ust_ctl_field
*end
,
527 const session_attributes
& session_attributes
,
528 const lttng_ust_ctl_field
**next_ust_ctl_field
)
530 if (current
>= end
) {
531 LTTNG_THROW_PROTOCOL_ERROR(
532 fmt::format("End of {} array reached unexpectedly during decoding",
536 const auto& variant_uctl_field
= *current
;
540 uint32_t choice_count
;
541 const char *tag_name
;
543 if (variant_uctl_field
.type
.atype
== lttng_ust_ctl_atype_variant
) {
545 choice_count
= variant_uctl_field
.type
.u
.legacy
.variant
.nr_choices
;
546 tag_name
= variant_uctl_field
.type
.u
.legacy
.variant
.tag_name
;
548 alignment
= variant_uctl_field
.type
.u
.variant_nestable
.alignment
;
549 choice_count
= variant_uctl_field
.type
.u
.variant_nestable
.nr_choices
;
550 tag_name
= variant_uctl_field
.type
.u
.variant_nestable
.tag_name
;
553 /* Choices follow. next_ust_ctl_field is updated as needed. */
554 lst::variant_type::choices choices
;
555 for (unsigned int i
= 0; i
< choice_count
; i
++) {
556 create_field_from_ust_ctl_fields(current
, end
, session_attributes
,
557 next_ust_ctl_field
, [&choices
](lst::field::cuptr field
) {
558 choices
.emplace_back(std::move(field
));
561 current
= *next_ust_ctl_field
;
564 return lttng::make_unique
<lst::variant_type
>(alignment
, tag_name
, std::move(choices
));
567 lst::type::cuptr
create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
568 const lttng_ust_ctl_field
*end
,
569 const session_attributes
& session_attributes
,
570 const lttng_ust_ctl_field
**next_ust_ctl_field
,
571 publish_field_fn publish_field
)
573 switch (current
->type
.atype
) {
574 case lttng_ust_ctl_atype_integer
:
575 return create_integer_type_from_ust_ctl_fields(
576 current
, end
, session_attributes
, next_ust_ctl_field
);
577 case lttng_ust_ctl_atype_enum
:
578 case lttng_ust_ctl_atype_enum_nestable
:
579 return create_enumeration_type_from_ust_ctl_fields(
580 current
, end
, session_attributes
, next_ust_ctl_field
);
581 case lttng_ust_ctl_atype_float
:
582 return create_floating_point_type_from_ust_ctl_fields(
583 current
, end
, session_attributes
, next_ust_ctl_field
);
584 case lttng_ust_ctl_atype_string
:
585 return create_string_type_from_ust_ctl_fields(
586 current
, end
, session_attributes
, next_ust_ctl_field
);
587 case lttng_ust_ctl_atype_array
:
588 return create_array_type_from_ust_ctl_fields(current
, end
, session_attributes
,
590 case lttng_ust_ctl_atype_array_nestable
:
591 return create_array_nestable_type_from_ust_ctl_fields(current
, end
,
592 session_attributes
, next_ust_ctl_field
, publish_field
);
593 case lttng_ust_ctl_atype_sequence
:
594 return create_sequence_type_from_ust_ctl_fields(current
, end
, session_attributes
,
595 next_ust_ctl_field
, publish_field
);
596 case lttng_ust_ctl_atype_sequence_nestable
:
597 return create_sequence_nestable_type_from_ust_ctl_fields(current
, end
,
598 session_attributes
, next_ust_ctl_field
, publish_field
);
599 case lttng_ust_ctl_atype_struct
:
600 case lttng_ust_ctl_atype_struct_nestable
:
601 return create_structure_field_from_ust_ctl_fields(
602 current
, end
, session_attributes
, next_ust_ctl_field
);
603 case lttng_ust_ctl_atype_variant
:
604 case lttng_ust_ctl_atype_variant_nestable
:
605 return create_variant_field_from_ust_ctl_fields(
606 current
, end
, session_attributes
, next_ust_ctl_field
);
608 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
609 "Unknown {} value `{}` encountered while converting {} to {}",
610 typeid(current
->type
.atype
), current
->type
.atype
, typeid(*current
),
611 typeid(lst::type::cuptr::element_type
)));
615 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
616 const lttng_ust_ctl_field
*end
,
617 const session_attributes
& session_attributes
,
618 const lttng_ust_ctl_field
**next_ust_ctl_field
,
619 publish_field_fn publish_field
)
621 LTTNG_ASSERT(current
< end
);
623 if (lttng_strnlen(current
->name
, sizeof(current
->name
)) == sizeof(current
->name
)) {
624 LTTNG_THROW_PROTOCOL_ERROR(
625 fmt::format("Name of {} is not null-terminated", typeid(*current
)));
628 publish_field(lttng::make_unique
<lst::field
>(current
->name
,
629 create_type_from_ust_ctl_fields(current
, end
, session_attributes
,
630 next_ust_ctl_field
, publish_field
)));
634 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
635 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
636 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
639 * Always returns a new field, throws on error.
641 std::vector
<lst::field::cuptr
> create_fields_from_ust_ctl_fields(
642 const lsu::registry_session
& session
,
643 const lttng_ust_ctl_field
*current
,
644 const lttng_ust_ctl_field
*end
)
646 std::vector
<lst::field::cuptr
> fields
;
647 const auto trace_native_byte_order
= session
.abi
.byte_order
;
648 const session_attributes session_attributes
{
649 [&session
](const char *enum_name
, uint64_t enum_id
) {
650 return session
.get_enumeration(enum_name
, enum_id
);
652 trace_native_byte_order
};
654 while (current
< end
) {
655 auto *next_field
= current
;
658 * create_field_from_ust_ctl_fields will consume one field at a time.
659 * However, some fields expressed by LTTng-UST's protocol are expended
660 * to multiple event fields (legacy sequence fields implicitly define
661 * their length field).
663 * The lambda allows the factory functions to push as many fields as
664 * needed depending on the decoded field's type.
666 create_field_from_ust_ctl_fields(current
, end
, session_attributes
, &next_field
,
667 [&fields
](lst::field::cuptr field
) {
668 fields
.emplace_back(std::move(field
));
671 current
= next_field
;
678 std::vector
<lst::field::cuptr
> lsu::create_trace_fields_from_ust_ctl_fields(
679 const lsu::registry_session
& session
,
680 const lttng_ust_ctl_field
*fields
,
681 std::size_t field_count
)
683 return create_fields_from_ust_ctl_fields(session
, fields
, fields
+ field_count
);