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
;
193 const auto signedness
= enum_container_uctl_type
->signedness
?
194 lst::integer_type::signedness::SIGNED
:
195 lst::integer_type::signedness::UNSIGNED
;
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
));
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
);
207 const auto& enum_registry
= static_cast<const lsu::registry_unsigned_enum
&>(
208 *session_attributes
.get_registry_enum(
209 enumeration_name
, enumeration_id
));
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
);
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
)
223 if (current
>= end
) {
224 LTTNG_THROW_PROTOCOL_ERROR(
225 fmt::format("End of {} array reached unexpectedly during decoding",
229 const auto& string_uctl_field
= *current
;
230 *next_ust_ctl_field
= current
+ 1;
232 const auto encoding
= ust_ctl_encoding_to_string_field_encoding(
233 string_uctl_field
.type
.u
.string
.encoding
);
235 return lttng::make_unique
<const lst::null_terminated_string_type
>(1, encoding
);
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
)
241 /* Checked by caller. */
242 LTTNG_ASSERT(type
.atype
== lttng_ust_ctl_atype_integer
);
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
;
255 return lttng::make_unique
<const lst::integer_type
>(
256 alignment
, byte_order
, size
, signedness
, base
);
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
)
264 if (current
>= end
) {
265 LTTNG_THROW_PROTOCOL_ERROR(
266 fmt::format("End of {} array reached unexpectedly during decoding",
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
;
275 array_length
= array_uctl_field
.type
.u
.legacy
.array
.length
;
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
));
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
);
294 *next_ust_ctl_field
= current
+ 1;
296 if (element_encoding
) {
297 const auto integer_element_size
=
298 static_cast<const lst::integer_type
&>(*element_type
).size
;
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
));
306 /* Array is a static-length string. */
307 return lttng::make_unique
<lst::static_length_string_type
>(
308 array_alignment
, *element_encoding
, array_length
);
311 return lttng::make_unique
<lst::static_length_array_type
>(
312 array_alignment
, std::move(element_type
), array_length
);
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
)
321 if (current
>= end
) {
322 LTTNG_THROW_PROTOCOL_ERROR(
323 fmt::format("End of {} array reached unexpectedly during decoding",
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
;
332 array_length
= array_uctl_field
.type
.u
.array_nestable
.length
;
333 array_alignment
= array_uctl_field
.type
.u
.array_nestable
.alignment
;
335 /* Nestable array fields are followed by their element type. */
336 const auto& element_uctl_field
= *(current
+ 1);
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
);
348 if (element_encoding
) {
349 const auto integer_element_size
=
350 static_cast<const lst::integer_type
&>(*element_type
).size
;
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
));
358 /* Array is a static-length string. */
359 return lttng::make_unique
<lst::static_length_string_type
>(
360 array_alignment
, *element_encoding
, array_length
);
363 return lttng::make_unique
<lst::static_length_array_type
>(
364 array_alignment
, std::move(element_type
), array_length
);
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.
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
)
377 if (current
>= end
) {
378 LTTNG_THROW_PROTOCOL_ERROR(
379 fmt::format("End of {} array reached unexpectedly during decoding",
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;
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
));
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
));
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
);
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
);
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
)));
417 *next_ust_ctl_field
= current
+ 1;
419 if (element_encoding
) {
420 const auto integer_element_size
=
421 static_cast<const lst::integer_type
&>(*element_type
).size
;
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
));
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
));
434 return lttng::make_unique
<lst::dynamic_length_array_type
>(
435 sequence_alignment
, std::move(element_type
), std::move(length_field_name
));
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
)
445 if (current
>= end
) {
446 LTTNG_THROW_PROTOCOL_ERROR(
447 fmt::format("End of {} array reached unexpectedly during decoding",
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
;
455 /* Nestable sequence fields are followed by their element type. */
456 const auto& element_uctl_field
= *(current
+ 1);
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
);
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
);
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");
476 if (element_encoding
) {
477 const auto integer_element_size
=
478 static_cast<const lst::integer_type
&>(*element_type
).size
;
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
));
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
));
491 return lttng::make_unique
<lst::dynamic_length_array_type
>(
492 sequence_alignment
, std::move(element_type
), std::move(length_field_name
));
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
)
500 if (current
>= end
) {
501 LTTNG_THROW_PROTOCOL_ERROR(
502 fmt::format("End of {} array reached unexpectedly during decoding",
506 uint32_t field_count
;
508 const auto& structure_uctl_field
= *current
;
510 if (structure_uctl_field
.type
.atype
== lttng_ust_ctl_atype_struct
) {
511 field_count
= structure_uctl_field
.type
.u
.legacy
._struct
.nr_fields
;
514 field_count
= structure_uctl_field
.type
.u
.struct_nestable
.nr_fields
;
515 alignment
= structure_uctl_field
.type
.u
.struct_nestable
.alignment
;
518 if (field_count
!= 0) {
519 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
520 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
524 *next_ust_ctl_field
= current
+ 1;
525 return lttng::make_unique
<lst::structure_type
>(alignment
, lst::structure_type::fields());
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
)
533 if (current
>= end
) {
534 LTTNG_THROW_PROTOCOL_ERROR(
535 fmt::format("End of {} array reached unexpectedly during decoding",
539 const auto& variant_uctl_field
= *current
;
543 uint32_t choice_count
;
544 const char *tag_name
;
546 if (variant_uctl_field
.type
.atype
== lttng_ust_ctl_atype_variant
) {
548 choice_count
= variant_uctl_field
.type
.u
.legacy
.variant
.nr_choices
;
549 tag_name
= variant_uctl_field
.type
.u
.legacy
.variant
.tag_name
;
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
;
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
));
564 current
= *next_ust_ctl_field
;
567 return lttng::make_unique
<lst::variant_type
>(alignment
, tag_name
, std::move(choices
));
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
)
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
,
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
);
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
)));
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
)
624 LTTNG_ASSERT(current
< end
);
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
)));
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
)));
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
642 * Always returns a new field, throws on error.
644 std::vector
<lst::field::cuptr
> create_fields_from_ust_ctl_fields(
645 const ust_registry_session
& session
,
646 const lttng_ust_ctl_field
*current
,
647 const lttng_ust_ctl_field
*end
)
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
);
655 trace_native_byte_order
};
657 while (current
< end
) {
658 auto *next_field
= current
;
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).
666 * The lambda allows the factory functions to push as many fields as
667 * needed depending on the decoded field's type.
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
));
674 current
= next_field
;
681 std::vector
<lst::field::cuptr
> lsu::create_trace_fields_from_ust_ctl_fields(
682 const ust_registry_session
& session
,
683 const lttng_ust_ctl_field
*fields
,
684 std::size_t field_count
)
686 return create_fields_from_ust_ctl_fields(session
, fields
, fields
+ field_count
);