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>
15 namespace lst
= lttng::sessiond::trace
;
16 namespace lsu
= lttng::sessiond::ust
;
20 * Type enclosing the session information that may be required during the decoding
21 * of the lttng_ust_ctl_field array provided by applications on registration of
24 class session_attributes
{
26 using registry_enum_getter_fn
=
27 std::function
<lsu::registry_enum::const_rcu_protected_reference(
28 const char *name
, uint64_t id
)>;
30 session_attributes(registry_enum_getter_fn reg_enum_getter
,
31 lst::byte_order native_trace_byte_order
) :
32 get_registry_enum
{reg_enum_getter
}, _native_trace_byte_order
{native_trace_byte_order
}
36 const registry_enum_getter_fn get_registry_enum
;
37 const lst::byte_order _native_trace_byte_order
;
40 /* Used to publish fields on which a field being decoded has an implicit dependency. */
41 using publish_field_fn
= std::function
<void(lst::field::uptr
)>;
43 /* Look-up field from a field location. */
44 using lookup_field_fn
= std::function
<const lst::field
&(const lst::field_location
&)>;
46 lst::type::cuptr
create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
47 const lttng_ust_ctl_field
*end
,
48 const session_attributes
& session_attributes
,
49 const lttng_ust_ctl_field
**next_ust_ctl_field
,
50 publish_field_fn publish_field
,
51 lookup_field_fn lookup_field
,
52 lst::field_location::root lookup_root
,
53 lst::field_location::elements
& current_field_location_elements
,
54 lsu::ctl_field_quirks quirks
);
56 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
57 const lttng_ust_ctl_field
*end
,
58 const session_attributes
& session_attributes
,
59 const lttng_ust_ctl_field
**next_ust_ctl_field
,
60 publish_field_fn publish_field
,
61 lookup_field_fn lookup_field
,
62 lst::field_location::root lookup_root
,
63 lst::field_location::elements
& current_field_location_elements
,
64 lsu::ctl_field_quirks quirks
);
66 template <class UstCtlEncodingType
>
67 enum lst::null_terminated_string_type::encoding
ust_ctl_encoding_to_string_field_encoding(UstCtlEncodingType encoding
)
69 static const std::unordered_map
<UstCtlEncodingType
, enum lst::null_terminated_string_type::encoding
>
70 encoding_conversion_map
= {
71 {(UstCtlEncodingType
) lttng_ust_ctl_encode_ASCII
,
72 lst::null_terminated_string_type::encoding::ASCII
},
73 {(UstCtlEncodingType
) lttng_ust_ctl_encode_UTF8
,
74 lst::null_terminated_string_type::encoding::UTF8
},
77 const auto encoding_it
= encoding_conversion_map
.find(encoding
);
78 if (encoding_it
== encoding_conversion_map
.end()) {
79 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
80 "Unknown lttng_ust_ctl_string_encodings value `{}` encountered when decoding integer field",
84 return encoding_it
->second
;
87 template <class UstCtlBaseType
>
88 enum lst::integer_type::base
ust_ctl_base_to_integer_field_base(UstCtlBaseType base
)
90 static const std::unordered_map
<UstCtlBaseType
, enum lst::integer_type::base
>
91 base_conversion_map
= {{2, lst::integer_type::base::BINARY
},
92 {8, lst::integer_type::base::OCTAL
},
93 {10, lst::integer_type::base::DECIMAL
},
94 {16, lst::integer_type::base::HEXADECIMAL
}};
96 const auto base_it
= base_conversion_map
.find(base
);
97 if (base_it
== base_conversion_map
.end()) {
98 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
99 "Unknown integer base value `{}` encountered when decoding integer field",
103 return base_it
->second
;
106 lst::type::cuptr
create_integer_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
107 const lttng_ust_ctl_field
*end
,
108 const session_attributes
& session_attributes
,
109 const lttng_ust_ctl_field
**next_ust_ctl_field
,
110 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
112 if (current
>= end
) {
113 LTTNG_THROW_PROTOCOL_ERROR(
114 fmt::format("End of {} array reached unexpectedly during decoding",
118 const auto base
= ust_ctl_base_to_integer_field_base(current
->type
.u
.integer
.base
);
119 const auto signedness
= current
->type
.u
.integer
.signedness
?
120 lst::integer_type::signedness::SIGNED
:
121 lst::integer_type::signedness::UNSIGNED
;
122 const auto byte_order
= current
->type
.u
.integer
.reverse_byte_order
?
123 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
124 session_attributes
._native_trace_byte_order
;
126 *next_ust_ctl_field
= current
+ 1;
128 return lttng::make_unique
<const lst::integer_type
>(current
->type
.u
.integer
.alignment
,
129 byte_order
, current
->type
.u
.integer
.size
, signedness
, base
);
132 lst::type::cuptr
create_floating_point_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
133 const lttng_ust_ctl_field
*end
,
134 const session_attributes
& session_attributes
,
135 const lttng_ust_ctl_field
**next_ust_ctl_field
,
136 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
138 if (current
>= end
) {
139 LTTNG_THROW_PROTOCOL_ERROR(
140 fmt::format("End of {} array reached unexpectedly during decoding",
144 *next_ust_ctl_field
= current
+ 1;
146 const auto byte_order
= current
->type
.u
._float
.reverse_byte_order
?
147 lst::type::reverse_byte_order(session_attributes
._native_trace_byte_order
) :
148 session_attributes
._native_trace_byte_order
;
151 return lttng::make_unique
<const lst::floating_point_type
>(
152 current
->type
.u
._float
.alignment
, byte_order
,
153 current
->type
.u
._float
.exp_dig
, current
->type
.u
._float
.mant_dig
);
154 } catch (lttng::invalid_argument_error
& ex
) {
155 LTTNG_THROW_PROTOCOL_ERROR(fmt::format("Invalid floating point attribute in {}: {}",
156 typeid(*current
), ex
.what()));
160 lst::type::cuptr
create_enumeration_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
161 const lttng_ust_ctl_field
*end
,
162 const session_attributes
& session_attributes
,
163 const lttng_ust_ctl_field
**next_ust_ctl_field
,
164 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
166 if (current
>= end
) {
167 LTTNG_THROW_PROTOCOL_ERROR(
168 fmt::format("End of {} array reached unexpectedly during decoding",
172 uint64_t enumeration_id
;
173 const auto& enum_uctl_field
= *current
;
174 const char *enumeration_name
;
175 const auto *enum_container_uctl_type
=
176 ¤t
->type
.u
.legacy
.basic
.enumeration
.container_type
;
178 if (enum_uctl_field
.type
.atype
== lttng_ust_ctl_atype_enum_nestable
) {
179 /* Nestable enumeration fields are followed by their container type. */
181 if (current
>= end
) {
182 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
183 "Array of {} is too short to contain nestable enumeration's container",
187 if (current
->type
.atype
!= lttng_ust_ctl_atype_integer
) {
188 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
189 "Invalid type of nestable enum container: type id = {}",
190 current
->type
.atype
));
193 enum_container_uctl_type
= ¤t
->type
.u
.integer
;
194 enumeration_id
= enum_uctl_field
.type
.u
.enum_nestable
.id
;
195 enumeration_name
= enum_uctl_field
.type
.u
.enum_nestable
.name
;
197 enumeration_id
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.id
;
198 enumeration_name
= enum_uctl_field
.type
.u
.legacy
.basic
.enumeration
.name
;
201 *next_ust_ctl_field
= current
+ 1;
203 const auto base
= ust_ctl_base_to_integer_field_base(enum_container_uctl_type
->base
);
204 const auto byte_order
= enum_container_uctl_type
->reverse_byte_order
?
205 lst::integer_type::reverse_byte_order(
206 session_attributes
._native_trace_byte_order
) :
207 session_attributes
._native_trace_byte_order
;
208 const auto signedness
= enum_container_uctl_type
->signedness
?
209 lst::integer_type::signedness::SIGNED
:
210 lst::integer_type::signedness::UNSIGNED
;
212 if (signedness
== lst::integer_type::signedness::SIGNED
) {
213 const auto& enum_registry
= static_cast<const lsu::registry_signed_enum
&>(
214 *session_attributes
.get_registry_enum(
215 enumeration_name
, enumeration_id
));
217 return lttng::make_unique
<const lst::signed_enumeration_type
>(
218 enum_container_uctl_type
->alignment
, byte_order
,
219 enum_container_uctl_type
->size
, base
,
220 enum_registry
._mappings
);
222 const auto& enum_registry
= static_cast<const lsu::registry_unsigned_enum
&>(
223 *session_attributes
.get_registry_enum(
224 enumeration_name
, enumeration_id
));
226 return lttng::make_unique
<const lst::unsigned_enumeration_type
>(
227 enum_container_uctl_type
->alignment
, byte_order
,
228 enum_container_uctl_type
->size
, base
,
229 enum_registry
._mappings
);
233 lst::type::cuptr
create_string_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
234 const lttng_ust_ctl_field
*end
,
235 const session_attributes
& session_attributes
__attribute__((unused
)),
236 const lttng_ust_ctl_field
**next_ust_ctl_field
,
237 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
239 if (current
>= end
) {
240 LTTNG_THROW_PROTOCOL_ERROR(
241 fmt::format("End of {} array reached unexpectedly during decoding",
245 const auto& string_uctl_field
= *current
;
246 *next_ust_ctl_field
= current
+ 1;
248 const auto encoding
= ust_ctl_encoding_to_string_field_encoding(
249 string_uctl_field
.type
.u
.string
.encoding
);
251 return lttng::make_unique
<const lst::null_terminated_string_type
>(1, encoding
);
254 lst::type::cuptr
create_integer_type_from_ust_ctl_basic_type(
255 const lttng_ust_ctl_basic_type
& type
, const session_attributes
& session_attributes
)
257 /* Checked by caller. */
258 LTTNG_ASSERT(type
.atype
== lttng_ust_ctl_atype_integer
);
260 const auto byte_order
= type
.u
.basic
.integer
.reverse_byte_order
?
261 lst::integer_type::reverse_byte_order(
262 session_attributes
._native_trace_byte_order
) :
263 session_attributes
._native_trace_byte_order
;
264 const auto signedness
= type
.u
.basic
.integer
.signedness
?
265 lst::integer_type::signedness::SIGNED
:
266 lst::integer_type::signedness::UNSIGNED
;
267 const auto base
= ust_ctl_base_to_integer_field_base(type
.u
.basic
.integer
.base
);
268 const auto size
= type
.u
.basic
.integer
.size
;
269 const auto alignment
= type
.u
.basic
.integer
.alignment
;
271 return lttng::make_unique
<const lst::integer_type
>(
272 alignment
, byte_order
, size
, signedness
, base
);
275 lst::type::cuptr
create_array_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
276 const lttng_ust_ctl_field
*end
,
277 const session_attributes
& session_attributes
,
278 const lttng_ust_ctl_field
**next_ust_ctl_field
,
279 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
281 if (current
>= end
) {
282 LTTNG_THROW_PROTOCOL_ERROR(
283 fmt::format("End of {} array reached unexpectedly during decoding",
287 const auto& array_uctl_field
= *current
;
288 uint32_t array_alignment
, array_length
;
289 lst::type::cuptr element_type
;
290 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
292 array_length
= array_uctl_field
.type
.u
.legacy
.array
.length
;
295 const auto& element_uctl_type
= array_uctl_field
.type
.u
.legacy
.array
.elem_type
;
296 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
297 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
298 "Unexpected legacy array element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
299 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
302 element_type
= create_integer_type_from_ust_ctl_basic_type(
303 element_uctl_type
, session_attributes
);
304 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
305 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
306 /* Element represents a text character. */
307 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
308 element_uctl_type
.u
.basic
.integer
.encoding
);
311 *next_ust_ctl_field
= current
+ 1;
313 if (element_encoding
) {
314 const auto integer_element_size
=
315 static_cast<const lst::integer_type
&>(*element_type
).size
;
317 if (integer_element_size
!= 8) {
318 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
319 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
320 integer_element_size
));
323 /* Array is a static-length string. */
324 return lttng::make_unique
<lst::static_length_string_type
>(
325 array_alignment
, *element_encoding
, array_length
);
328 return lttng::make_unique
<lst::static_length_array_type
>(
329 array_alignment
, std::move(element_type
), array_length
);
332 lst::type::cuptr
create_array_nestable_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
333 const lttng_ust_ctl_field
*end
,
334 const session_attributes
& session_attributes
,
335 const lttng_ust_ctl_field
**next_ust_ctl_field
,
336 publish_field_fn publish_field
,
337 lookup_field_fn lookup_field
,
338 lst::field_location::root lookup_root
,
339 lst::field_location::elements
¤t_field_location_elements
,
340 lsu::ctl_field_quirks quirks
)
342 if (current
>= end
) {
343 LTTNG_THROW_PROTOCOL_ERROR(
344 fmt::format("End of {} array reached unexpectedly during decoding",
348 const auto& array_uctl_field
= *current
;
349 uint32_t array_alignment
, array_length
;
350 lst::type::cuptr element_type
;
351 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
353 array_length
= array_uctl_field
.type
.u
.array_nestable
.length
;
354 array_alignment
= array_uctl_field
.type
.u
.array_nestable
.alignment
;
356 /* Nestable array fields are followed by their element type. */
357 const auto& element_uctl_field
= *(current
+ 1);
359 /* next_ust_ctl_field is updated as needed. */
360 element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
, session_attributes
,
361 next_ust_ctl_field
, publish_field
, lookup_field
, lookup_root
,
362 current_field_location_elements
, quirks
);
363 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
364 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
365 /* Element represents a text character. */
366 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
367 element_uctl_field
.type
.u
.integer
.encoding
);
370 if (element_encoding
) {
371 const auto integer_element_size
=
372 static_cast<const lst::integer_type
&>(*element_type
).size
;
374 if (integer_element_size
!= 8) {
375 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
376 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
377 integer_element_size
));
380 /* Array is a static-length string. */
381 return lttng::make_unique
<lst::static_length_string_type
>(
382 array_alignment
, *element_encoding
, array_length
);
385 return lttng::make_unique
<lst::static_length_array_type
>(
386 array_alignment
, std::move(element_type
), array_length
);
390 * For legacy sequence types, LTTng-UST expresses both the sequence and sequence
391 * length as part of the same lttng_ust_ctl_field entry.
393 lst::type::cuptr
create_sequence_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
394 const lttng_ust_ctl_field
*end
,
395 const session_attributes
& session_attributes
,
396 const lttng_ust_ctl_field
**next_ust_ctl_field
,
397 publish_field_fn publish_field
,
398 lst::field_location::root lookup_root
,
399 lst::field_location::elements
¤t_field_location_elements
,
400 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
402 if (current
>= end
) {
403 LTTNG_THROW_PROTOCOL_ERROR(
404 fmt::format("End of {} array reached unexpectedly during decoding",
408 const auto& sequence_uctl_field
= *current
;
409 const auto& element_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.elem_type
;
410 const auto& length_uctl_type
= sequence_uctl_field
.type
.u
.legacy
.sequence
.length_type
;
411 const auto sequence_alignment
= 0U;
413 if (element_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
414 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
415 "Unexpected legacy sequence element type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
416 element_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
419 if (length_uctl_type
.atype
!= lttng_ust_ctl_atype_integer
) {
420 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
421 "Unexpected legacy sequence length field type: atype = {}, expected atype = lttng_ust_ctl_atype_integer ({})",
422 length_uctl_type
.atype
, lttng_ust_ctl_atype_integer
));
425 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
426 if (element_uctl_type
.atype
== lttng_ust_ctl_atype_integer
&&
427 element_uctl_type
.u
.basic
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
428 /* Element represents a text character. */
429 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
430 element_uctl_type
.u
.basic
.integer
.encoding
);
433 const auto length_field_name
= fmt::format("_{}_length", sequence_uctl_field
.name
);
434 auto element_type
= create_integer_type_from_ust_ctl_basic_type(
435 element_uctl_type
, session_attributes
);
436 auto length_type
= create_integer_type_from_ust_ctl_basic_type(
437 length_uctl_type
, session_attributes
);
439 lst::field_location::elements length_field_location_elements
=
440 current_field_location_elements
;
441 length_field_location_elements
.emplace_back(length_field_name
);
443 const lst::field_location length_field_location
{
444 lookup_root
, std::move(length_field_location_elements
)};
446 /* Publish an implicit length field _before_ the sequence field. */
447 publish_field(lttng::make_unique
<lst::field
>(std::move(length_field_name
), std::move(length_type
)));
449 *next_ust_ctl_field
= current
+ 1;
451 if (element_encoding
) {
452 const auto integer_element_size
=
453 static_cast<const lst::integer_type
&>(*element_type
).size
;
455 if (integer_element_size
!= 8) {
456 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
457 "Unexpected legacy array element type: integer has encoding but size is not 8: size = {}",
458 integer_element_size
));
461 /* Sequence is a dynamic-length string. */
462 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
463 *element_encoding
, std::move(length_field_location
));
466 return lttng::make_unique
<lst::dynamic_length_array_type
>(sequence_alignment
,
467 std::move(element_type
), std::move(length_field_location
));
470 lst::type::cuptr
create_sequence_nestable_type_from_ust_ctl_fields(
471 const lttng_ust_ctl_field
*current
,
472 const lttng_ust_ctl_field
*end
,
473 const session_attributes
& session_attributes
,
474 const lttng_ust_ctl_field
**next_ust_ctl_field
,
475 publish_field_fn publish_field
,
476 lookup_field_fn lookup_field
,
477 lst::field_location::root lookup_root
,
478 lst::field_location::elements
¤t_field_location_elements
,
479 lsu::ctl_field_quirks quirks
)
481 if (current
>= end
) {
482 LTTNG_THROW_PROTOCOL_ERROR(
483 fmt::format("End of {} array reached unexpectedly during decoding",
487 const auto& sequence_uctl_field
= *current
;
488 const auto sequence_alignment
= sequence_uctl_field
.type
.u
.sequence_nestable
.alignment
;
489 const auto *length_field_name
= sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
;
491 /* Nestable sequence fields are followed by their element type. */
492 const auto& element_uctl_field
= *(current
+ 1);
494 nonstd::optional
<enum lst::string_type::encoding
> element_encoding
;
495 if (element_uctl_field
.type
.atype
== lttng_ust_ctl_atype_integer
&&
496 element_uctl_field
.type
.u
.integer
.encoding
!= lttng_ust_ctl_encode_none
) {
497 /* Element represents a text character. */
498 element_encoding
= ust_ctl_encoding_to_string_field_encoding(
499 element_uctl_field
.type
.u
.integer
.encoding
);
502 /* next_ust_ctl_field is updated as needed. */
503 auto element_type
= create_type_from_ust_ctl_fields(&element_uctl_field
, end
,
504 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_field
,
505 lookup_root
, current_field_location_elements
, quirks
);
507 if (lttng_strnlen(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
,
508 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) ==
509 sizeof(sequence_uctl_field
.type
.u
.sequence_nestable
.length_name
)) {
510 LTTNG_THROW_PROTOCOL_ERROR("Sequence length field name is not null terminated");
513 lst::field_location::elements length_field_location_elements
=
514 current_field_location_elements
;
515 length_field_location_elements
.emplace_back(std::move(length_field_name
));
517 const lst::field_location length_field_location
{
518 lookup_root
, std::move(length_field_location_elements
)};
520 /* Validate existence of length field (throws if not found). */
521 const auto &length_field
= lookup_field(length_field_location
);
522 const auto *integer_selector_field
=
523 dynamic_cast<const lst::integer_type
*>(&length_field
.get_type());
524 if (!integer_selector_field
) {
525 LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from sequence: expected integer or enumeration");
528 if (element_encoding
) {
529 const auto integer_element_size
=
530 static_cast<const lst::integer_type
&>(*element_type
).size
;
532 if (integer_element_size
!= 8) {
533 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
534 "Unexpected array element type: integer has encoding but size is not 8: size = {}",
535 integer_element_size
));
538 /* Sqeuence is a dynamic-length string. */
539 return lttng::make_unique
<lst::dynamic_length_string_type
>(sequence_alignment
,
540 *element_encoding
, std::move(length_field_location
));
543 return lttng::make_unique
<lst::dynamic_length_array_type
>(sequence_alignment
,
544 std::move(element_type
), std::move(length_field_location
));
547 lst::type::cuptr
create_structure_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
548 const lttng_ust_ctl_field
*end
,
549 const session_attributes
& session_attributes
__attribute__((unused
)),
550 const lttng_ust_ctl_field
**next_ust_ctl_field
,
551 lsu::ctl_field_quirks quirks
__attribute__((unused
)))
553 if (current
>= end
) {
554 LTTNG_THROW_PROTOCOL_ERROR(
555 fmt::format("End of {} array reached unexpectedly during decoding",
559 uint32_t field_count
;
561 const auto& structure_uctl_field
= *current
;
563 if (structure_uctl_field
.type
.atype
== lttng_ust_ctl_atype_struct
) {
564 field_count
= structure_uctl_field
.type
.u
.legacy
._struct
.nr_fields
;
567 field_count
= structure_uctl_field
.type
.u
.struct_nestable
.nr_fields
;
568 alignment
= structure_uctl_field
.type
.u
.struct_nestable
.alignment
;
571 if (field_count
!= 0) {
572 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
573 "Only empty structures are supported by LTTng-UST: nr_fields = {}",
577 *next_ust_ctl_field
= current
+ 1;
578 return lttng::make_unique
<lst::structure_type
>(alignment
, lst::structure_type::fields());
581 template <class VariantSelectorMappingIntegerType
>
582 typename
lst::variant_type
<VariantSelectorMappingIntegerType
>::choices
create_typed_variant_choices(
583 const lttng_ust_ctl_field
*current
,
584 const lttng_ust_ctl_field
*end
,
585 const session_attributes
& session_attributes
,
586 const lttng_ust_ctl_field
**next_ust_ctl_field
,
587 lookup_field_fn lookup_field
,
588 lst::field_location::root lookup_root
,
589 lst::field_location::elements
& current_field_location_elements
,
590 unsigned int choice_count
,
591 const lst::field
& selector_field
,
592 lsu::ctl_field_quirks quirks
)
594 typename
lst::variant_type
<VariantSelectorMappingIntegerType
>::choices choices
;
595 const auto& typed_enumeration
= static_cast<
596 const lst::typed_enumeration_type
<VariantSelectorMappingIntegerType
>&>(
597 selector_field
.get_type());
599 for (unsigned int i
= 0; i
< choice_count
; i
++) {
600 create_field_from_ust_ctl_fields(
601 current
, end
, session_attributes
, next_ust_ctl_field
,
602 [&choices
, typed_enumeration
, &selector_field
, quirks
](
603 lst::field::uptr field
) {
605 * Find the enumeration mapping that matches the
608 const auto mapping_it
= std::find_if(
609 typed_enumeration
.mappings_
->begin(),
610 typed_enumeration
.mappings_
->end(),
611 [&field
, quirks
](const typename
std::remove_reference
<
612 decltype(typed_enumeration
)>::type::
614 if (static_cast<bool>(quirks
& lsu::ctl_field_quirks::UNDERSCORE_PREFIXED_VARIANT_TAG_MAPPINGS
)) {
616 * Check if they match with
617 * a prepended underscore
618 * and, if not, perform the
621 if ((std::string("_") + field
->name
) == mapping
.name
) {
626 return mapping
.name
== field
->name
;
629 if (mapping_it
== typed_enumeration
.mappings_
->end()) {
630 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
631 "Invalid variant choice: `{}` does not match any mapping in `{}` enumeration",
632 field
->name
, selector_field
.name
));
635 choices
.emplace_back(*mapping_it
, field
->move_type());
637 lookup_field
, lookup_root
, current_field_location_elements
, quirks
);
639 current
= *next_ust_ctl_field
;
645 lst::type::cuptr
create_variant_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
646 const lttng_ust_ctl_field
*end
,
647 const session_attributes
& session_attributes
,
648 const lttng_ust_ctl_field
**next_ust_ctl_field
,
649 lookup_field_fn lookup_field
,
650 lst::field_location::root lookup_root
,
651 lst::field_location::elements
¤t_field_location_elements
,
652 lsu::ctl_field_quirks quirks
)
654 if (current
>= end
) {
655 LTTNG_THROW_PROTOCOL_ERROR(
656 fmt::format("End of {} array reached unexpectedly during decoding",
660 const auto& variant_uctl_field
= *current
;
664 uint32_t choice_count
;
665 const char *tag_name
;
667 if (variant_uctl_field
.type
.atype
== lttng_ust_ctl_atype_variant
) {
669 choice_count
= variant_uctl_field
.type
.u
.legacy
.variant
.nr_choices
;
670 tag_name
= variant_uctl_field
.type
.u
.legacy
.variant
.tag_name
;
672 alignment
= variant_uctl_field
.type
.u
.variant_nestable
.alignment
;
673 choice_count
= variant_uctl_field
.type
.u
.variant_nestable
.nr_choices
;
674 tag_name
= variant_uctl_field
.type
.u
.variant_nestable
.tag_name
;
677 lst::field_location::elements selector_field_location_elements
=
678 current_field_location_elements
;
679 selector_field_location_elements
.emplace_back(tag_name
);
681 const lst::field_location selector_field_location
{
682 lookup_root
, std::move(selector_field_location_elements
)};
684 /* Validate existence of selector field (throws if not found). */
685 const auto &selector_field
= lookup_field(selector_field_location
);
686 const auto *enumeration_selector_type
=
687 dynamic_cast<const lst::enumeration_type
*>(&selector_field
.get_type());
688 if (!enumeration_selector_type
) {
689 LTTNG_THROW_PROTOCOL_ERROR("Invalid selector field type referenced from variant: expected enumeration");
692 const bool selector_is_signed
= enumeration_selector_type
->signedness_
==
693 lst::integer_type::signedness::SIGNED
;
695 /* Choices follow. next_ust_ctl_field is updated as needed. */
696 if (selector_is_signed
) {
697 lst::variant_type
<lst::signed_enumeration_type::mapping::range_t::range_integer_t
>::
698 choices choices
= create_typed_variant_choices
<int64_t>(current
,
699 end
, session_attributes
, next_ust_ctl_field
,
700 lookup_field
, lookup_root
,
701 current_field_location_elements
, choice_count
,
702 selector_field
, quirks
);
704 return lttng::make_unique
<lst::variant_type
<int64_t>>(
705 alignment
, std::move(selector_field_location
), std::move(choices
));
707 lst::variant_type
<lst::unsigned_enumeration_type::mapping::range_t::range_integer_t
>::
708 choices choices
= create_typed_variant_choices
<uint64_t>(current
,
709 end
, session_attributes
, next_ust_ctl_field
,
710 lookup_field
, lookup_root
,
711 current_field_location_elements
, choice_count
,
712 selector_field
, quirks
);
714 return lttng::make_unique
<lst::variant_type
<uint64_t>>(
715 alignment
, std::move(selector_field_location
), std::move(choices
));
719 lst::type::cuptr
create_type_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
720 const lttng_ust_ctl_field
*end
,
721 const session_attributes
& session_attributes
,
722 const lttng_ust_ctl_field
**next_ust_ctl_field
,
723 publish_field_fn publish_field
,
724 lookup_field_fn lookup_field
,
725 lst::field_location::root lookup_root
,
726 lst::field_location::elements
& current_field_location_elements
,
727 lsu::ctl_field_quirks quirks
)
729 switch (current
->type
.atype
) {
730 case lttng_ust_ctl_atype_integer
:
731 return create_integer_type_from_ust_ctl_fields(
732 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
733 case lttng_ust_ctl_atype_enum
:
734 case lttng_ust_ctl_atype_enum_nestable
:
735 return create_enumeration_type_from_ust_ctl_fields(
736 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
737 case lttng_ust_ctl_atype_float
:
738 return create_floating_point_type_from_ust_ctl_fields(
739 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
740 case lttng_ust_ctl_atype_string
:
741 return create_string_type_from_ust_ctl_fields(
742 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
743 case lttng_ust_ctl_atype_array
:
744 return create_array_type_from_ust_ctl_fields(
745 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
746 case lttng_ust_ctl_atype_array_nestable
:
747 return create_array_nestable_type_from_ust_ctl_fields(current
, end
,
748 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_field
,
749 lookup_root
, current_field_location_elements
, quirks
);
750 case lttng_ust_ctl_atype_sequence
:
751 return create_sequence_type_from_ust_ctl_fields(current
, end
, session_attributes
,
752 next_ust_ctl_field
, publish_field
, lookup_root
,
753 current_field_location_elements
, quirks
);
754 case lttng_ust_ctl_atype_sequence_nestable
:
755 return create_sequence_nestable_type_from_ust_ctl_fields(current
, end
,
756 session_attributes
, next_ust_ctl_field
, publish_field
, lookup_field
,
757 lookup_root
, current_field_location_elements
, quirks
);
758 case lttng_ust_ctl_atype_struct
:
759 case lttng_ust_ctl_atype_struct_nestable
:
760 return create_structure_field_from_ust_ctl_fields(
761 current
, end
, session_attributes
, next_ust_ctl_field
, quirks
);
762 case lttng_ust_ctl_atype_variant
:
763 case lttng_ust_ctl_atype_variant_nestable
:
764 return create_variant_field_from_ust_ctl_fields(current
, end
, session_attributes
,
765 next_ust_ctl_field
, lookup_field
, lookup_root
,
766 current_field_location_elements
, quirks
);
768 LTTNG_THROW_PROTOCOL_ERROR(fmt::format(
769 "Unknown {} value `{}` encountered while converting {} to {}",
770 typeid(current
->type
.atype
), current
->type
.atype
, typeid(*current
),
771 typeid(lst::type::cuptr::element_type
)));
775 void create_field_from_ust_ctl_fields(const lttng_ust_ctl_field
*current
,
776 const lttng_ust_ctl_field
*end
,
777 const session_attributes
& session_attributes
,
778 const lttng_ust_ctl_field
**next_ust_ctl_field
,
779 publish_field_fn publish_field
,
780 lookup_field_fn lookup_field
,
781 lst::field_location::root lookup_root
,
782 lst::field_location::elements
& current_field_location_elements
,
783 lsu::ctl_field_quirks quirks
)
785 LTTNG_ASSERT(current
< end
);
787 if (lttng_strnlen(current
->name
, sizeof(current
->name
)) == sizeof(current
->name
)) {
788 LTTNG_THROW_PROTOCOL_ERROR(
789 fmt::format("Name of {} is not null-terminated", typeid(*current
)));
792 publish_field(lttng::make_unique
<lst::field
>(current
->name
,
793 create_type_from_ust_ctl_fields(current
, end
, session_attributes
,
794 next_ust_ctl_field
, publish_field
, lookup_field
,
795 lookup_root
, current_field_location_elements
, quirks
)));
798 std::vector
<lst::field::cuptr
>::iterator
lookup_field_in_vector(
799 std::vector
<lst::field::cuptr
>& fields
, const lst::field_location
& location
)
801 if (location
.elements_
.size() != 1) {
802 LTTNG_THROW_ERROR(fmt::format(
803 "Unexpected field location received during field look-up: location = {}",
808 * In the context of fields received from LTTng-UST, field
809 * look-up is extremely naive as the protocol can only
810 * express empty structures. It is safe to assume that
811 * location has a depth of 1 and directly refers to a field
812 * in the 'fields' vector.
814 const auto field_it
= std::find_if(fields
.begin(), fields
.end(),
815 [location
](lst::field::cuptr
&field
) {
816 return field
->name
== location
.elements_
[0];
819 if (field_it
== fields
.end()) {
820 LTTNG_THROW_PROTOCOL_ERROR(
821 fmt::format("Failed to look-up field: location = {}", location
));
828 * `lttng_ust_ctl_field`s can be nested, in which case creating a field will consume
829 * more than one lttng_ust_ctl_field. create_field_from_ust_ctl_fields returns the
830 * position of the next lttng_ust_ctl_field to consume or `end` when the last field
833 * Always returns a new field, throws on error.
835 std::vector
<lst::field::cuptr
> create_fields_from_ust_ctl_fields(
836 const lsu::registry_session
& session
,
837 const lttng_ust_ctl_field
*current
,
838 const lttng_ust_ctl_field
*end
,
839 lst::field_location::root lookup_root
,
840 lsu::ctl_field_quirks quirks
)
842 std::vector
<lst::field::cuptr
> fields
;
843 const auto trace_native_byte_order
= session
.abi
.byte_order
;
844 const session_attributes session_attributes
{
845 [&session
](const char *enum_name
, uint64_t enum_id
) {
846 return session
.enumeration(enum_name
, enum_id
);
848 trace_native_byte_order
};
849 /* Location of field being created. */
850 lst::field_location::elements current_field_location_elements
;
852 while (current
< end
) {
853 auto *next_field
= current
;
856 * create_field_from_ust_ctl_fields will consume one field at a time.
857 * However, some fields expressed by LTTng-UST's protocol are expended
858 * to multiple event fields (legacy sequence fields implicitly define
859 * their length field).
861 * The lambda allows the factory functions to push as many fields as
862 * needed depending on the decoded field's type.
864 create_field_from_ust_ctl_fields(
865 current
, end
, session_attributes
, &next_field
,
866 [&fields
](lst::field::cuptr field
) {
867 /* Publishing a field simply adds it to the converted
869 fields
.emplace_back(std::move(field
));
871 [&fields
](const lst::field_location
& location
)
872 -> lookup_field_fn::result_type
{
873 /* Resolve location to a previously-constructed field. */
874 return **lookup_field_in_vector(fields
, location
);
876 lookup_root
, current_field_location_elements
, quirks
);
878 current
= next_field
;
885 std::vector
<lst::field::cuptr
> lsu::create_trace_fields_from_ust_ctl_fields(
886 const lsu::registry_session
& session
,
887 const lttng_ust_ctl_field
*fields
,
888 std::size_t field_count
,
889 lst::field_location::root lookup_root
,
890 lsu::ctl_field_quirks quirks
)
892 return create_fields_from_ust_ctl_fields(
893 session
, fields
, fields
+ field_count
, lookup_root
, quirks
);